1 /* 2 * Target specific user-mode handling 3 * 4 * Copyright (c) 2003-2005 Fabrice Bellard 5 * Copyright (c) 2022 Linaro Ltd 6 * 7 * SPDX-License-Identifier: LGPL-2.0+ 8 */ 9 10 #include "qemu/osdep.h" 11 #include "exec/gdbstub.h" 12 #include "gdbstub/commands.h" 13 #include "qemu.h" 14 #include "internals.h" 15 #ifdef CONFIG_LINUX 16 #include "linux-user/loader.h" 17 #include "linux-user/qemu.h" 18 #endif 19 20 /* 21 * Map target signal numbers to GDB protocol signal numbers and vice 22 * versa. For user emulation's currently supported systems, we can 23 * assume most signals are defined. 24 */ 25 26 static int gdb_signal_table[] = { 27 0, 28 TARGET_SIGHUP, 29 TARGET_SIGINT, 30 TARGET_SIGQUIT, 31 TARGET_SIGILL, 32 TARGET_SIGTRAP, 33 TARGET_SIGABRT, 34 -1, /* SIGEMT */ 35 TARGET_SIGFPE, 36 TARGET_SIGKILL, 37 TARGET_SIGBUS, 38 TARGET_SIGSEGV, 39 TARGET_SIGSYS, 40 TARGET_SIGPIPE, 41 TARGET_SIGALRM, 42 TARGET_SIGTERM, 43 TARGET_SIGURG, 44 TARGET_SIGSTOP, 45 TARGET_SIGTSTP, 46 TARGET_SIGCONT, 47 TARGET_SIGCHLD, 48 TARGET_SIGTTIN, 49 TARGET_SIGTTOU, 50 TARGET_SIGIO, 51 TARGET_SIGXCPU, 52 TARGET_SIGXFSZ, 53 TARGET_SIGVTALRM, 54 TARGET_SIGPROF, 55 TARGET_SIGWINCH, 56 -1, /* SIGLOST */ 57 TARGET_SIGUSR1, 58 TARGET_SIGUSR2, 59 #ifdef TARGET_SIGPWR 60 TARGET_SIGPWR, 61 #else 62 -1, 63 #endif 64 -1, /* SIGPOLL */ 65 -1, 66 -1, 67 -1, 68 -1, 69 -1, 70 -1, 71 -1, 72 -1, 73 -1, 74 -1, 75 -1, 76 #ifdef __SIGRTMIN 77 __SIGRTMIN + 1, 78 __SIGRTMIN + 2, 79 __SIGRTMIN + 3, 80 __SIGRTMIN + 4, 81 __SIGRTMIN + 5, 82 __SIGRTMIN + 6, 83 __SIGRTMIN + 7, 84 __SIGRTMIN + 8, 85 __SIGRTMIN + 9, 86 __SIGRTMIN + 10, 87 __SIGRTMIN + 11, 88 __SIGRTMIN + 12, 89 __SIGRTMIN + 13, 90 __SIGRTMIN + 14, 91 __SIGRTMIN + 15, 92 __SIGRTMIN + 16, 93 __SIGRTMIN + 17, 94 __SIGRTMIN + 18, 95 __SIGRTMIN + 19, 96 __SIGRTMIN + 20, 97 __SIGRTMIN + 21, 98 __SIGRTMIN + 22, 99 __SIGRTMIN + 23, 100 __SIGRTMIN + 24, 101 __SIGRTMIN + 25, 102 __SIGRTMIN + 26, 103 __SIGRTMIN + 27, 104 __SIGRTMIN + 28, 105 __SIGRTMIN + 29, 106 __SIGRTMIN + 30, 107 __SIGRTMIN + 31, 108 -1, /* SIGCANCEL */ 109 __SIGRTMIN, 110 __SIGRTMIN + 32, 111 __SIGRTMIN + 33, 112 __SIGRTMIN + 34, 113 __SIGRTMIN + 35, 114 __SIGRTMIN + 36, 115 __SIGRTMIN + 37, 116 __SIGRTMIN + 38, 117 __SIGRTMIN + 39, 118 __SIGRTMIN + 40, 119 __SIGRTMIN + 41, 120 __SIGRTMIN + 42, 121 __SIGRTMIN + 43, 122 __SIGRTMIN + 44, 123 __SIGRTMIN + 45, 124 __SIGRTMIN + 46, 125 __SIGRTMIN + 47, 126 __SIGRTMIN + 48, 127 __SIGRTMIN + 49, 128 __SIGRTMIN + 50, 129 __SIGRTMIN + 51, 130 __SIGRTMIN + 52, 131 __SIGRTMIN + 53, 132 __SIGRTMIN + 54, 133 __SIGRTMIN + 55, 134 __SIGRTMIN + 56, 135 __SIGRTMIN + 57, 136 __SIGRTMIN + 58, 137 __SIGRTMIN + 59, 138 __SIGRTMIN + 60, 139 __SIGRTMIN + 61, 140 __SIGRTMIN + 62, 141 __SIGRTMIN + 63, 142 __SIGRTMIN + 64, 143 __SIGRTMIN + 65, 144 __SIGRTMIN + 66, 145 __SIGRTMIN + 67, 146 __SIGRTMIN + 68, 147 __SIGRTMIN + 69, 148 __SIGRTMIN + 70, 149 __SIGRTMIN + 71, 150 __SIGRTMIN + 72, 151 __SIGRTMIN + 73, 152 __SIGRTMIN + 74, 153 __SIGRTMIN + 75, 154 __SIGRTMIN + 76, 155 __SIGRTMIN + 77, 156 __SIGRTMIN + 78, 157 __SIGRTMIN + 79, 158 __SIGRTMIN + 80, 159 __SIGRTMIN + 81, 160 __SIGRTMIN + 82, 161 __SIGRTMIN + 83, 162 __SIGRTMIN + 84, 163 __SIGRTMIN + 85, 164 __SIGRTMIN + 86, 165 __SIGRTMIN + 87, 166 __SIGRTMIN + 88, 167 __SIGRTMIN + 89, 168 __SIGRTMIN + 90, 169 __SIGRTMIN + 91, 170 __SIGRTMIN + 92, 171 __SIGRTMIN + 93, 172 __SIGRTMIN + 94, 173 __SIGRTMIN + 95, 174 -1, /* SIGINFO */ 175 -1, /* UNKNOWN */ 176 -1, /* DEFAULT */ 177 -1, 178 -1, 179 -1, 180 -1, 181 -1, 182 -1 183 #endif 184 }; 185 186 int gdb_signal_to_target(int sig) 187 { 188 if (sig < ARRAY_SIZE(gdb_signal_table)) { 189 return gdb_signal_table[sig]; 190 } else { 191 return -1; 192 } 193 } 194 195 int gdb_target_signal_to_gdb(int sig) 196 { 197 int i; 198 for (i = 0; i < ARRAY_SIZE(gdb_signal_table); i++) { 199 if (gdb_signal_table[i] == sig) { 200 return i; 201 } 202 } 203 return GDB_SIGNAL_UNKNOWN; 204 } 205 206 int gdb_get_cpu_index(CPUState *cpu) 207 { 208 TaskState *ts = get_task_state(cpu); 209 return ts ? ts->ts_tid : -1; 210 } 211 212 /* 213 * User-mode specific command helpers 214 */ 215 216 void gdb_handle_query_offsets(GArray *params, void *user_ctx) 217 { 218 TaskState *ts; 219 220 ts = get_task_state(gdbserver_state.c_cpu); 221 g_string_printf(gdbserver_state.str_buf, 222 "Text=" TARGET_ABI_FMT_lx 223 ";Data=" TARGET_ABI_FMT_lx 224 ";Bss=" TARGET_ABI_FMT_lx, 225 ts->info->code_offset, 226 ts->info->data_offset, 227 ts->info->data_offset); 228 gdb_put_strbuf(); 229 } 230 231 #if defined(CONFIG_LINUX) 232 /* Partial user only duplicate of helper in gdbstub.c */ 233 static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr, 234 uint8_t *buf, int len, bool is_write) 235 { 236 CPUClass *cc; 237 cc = CPU_GET_CLASS(cpu); 238 if (cc->memory_rw_debug) { 239 return cc->memory_rw_debug(cpu, addr, buf, len, is_write); 240 } 241 return cpu_memory_rw_debug(cpu, addr, buf, len, is_write); 242 } 243 244 void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx) 245 { 246 TaskState *ts; 247 unsigned long offset, len, saved_auxv, auxv_len; 248 249 if (params->len < 2) { 250 gdb_put_packet("E22"); 251 return; 252 } 253 254 offset = gdb_get_cmd_param(params, 0)->val_ul; 255 len = gdb_get_cmd_param(params, 1)->val_ul; 256 ts = get_task_state(gdbserver_state.c_cpu); 257 saved_auxv = ts->info->saved_auxv; 258 auxv_len = ts->info->auxv_len; 259 260 if (offset >= auxv_len) { 261 gdb_put_packet("E00"); 262 return; 263 } 264 265 if (len > (MAX_PACKET_LENGTH - 5) / 2) { 266 len = (MAX_PACKET_LENGTH - 5) / 2; 267 } 268 269 if (len < auxv_len - offset) { 270 g_string_assign(gdbserver_state.str_buf, "m"); 271 } else { 272 g_string_assign(gdbserver_state.str_buf, "l"); 273 len = auxv_len - offset; 274 } 275 276 g_byte_array_set_size(gdbserver_state.mem_buf, len); 277 if (target_memory_rw_debug(gdbserver_state.g_cpu, saved_auxv + offset, 278 gdbserver_state.mem_buf->data, len, false)) { 279 gdb_put_packet("E14"); 280 return; 281 } 282 283 gdb_memtox(gdbserver_state.str_buf, 284 (const char *)gdbserver_state.mem_buf->data, len); 285 gdb_put_packet_binary(gdbserver_state.str_buf->str, 286 gdbserver_state.str_buf->len, true); 287 } 288 #endif 289 290 static const char *get_filename_param(GArray *params, int i) 291 { 292 const char *hex_filename = gdb_get_cmd_param(params, i)->data; 293 gdb_hextomem(gdbserver_state.mem_buf, hex_filename, 294 strlen(hex_filename) / 2); 295 g_byte_array_append(gdbserver_state.mem_buf, (const guint8 *)"", 1); 296 return (const char *)gdbserver_state.mem_buf->data; 297 } 298 299 static void hostio_reply_with_data(const void *buf, size_t n) 300 { 301 g_string_printf(gdbserver_state.str_buf, "F%zx;", n); 302 gdb_memtox(gdbserver_state.str_buf, buf, n); 303 gdb_put_packet_binary(gdbserver_state.str_buf->str, 304 gdbserver_state.str_buf->len, true); 305 } 306 307 void gdb_handle_v_file_open(GArray *params, void *user_ctx) 308 { 309 const char *filename = get_filename_param(params, 0); 310 uint64_t flags = gdb_get_cmd_param(params, 1)->val_ull; 311 uint64_t mode = gdb_get_cmd_param(params, 2)->val_ull; 312 313 #ifdef CONFIG_LINUX 314 int fd = do_guest_openat(cpu_env(gdbserver_state.g_cpu), 0, filename, 315 flags, mode, false); 316 #else 317 int fd = open(filename, flags, mode); 318 #endif 319 if (fd < 0) { 320 g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno); 321 } else { 322 g_string_printf(gdbserver_state.str_buf, "F%d", fd); 323 } 324 gdb_put_strbuf(); 325 } 326 327 void gdb_handle_v_file_close(GArray *params, void *user_ctx) 328 { 329 int fd = gdb_get_cmd_param(params, 0)->val_ul; 330 331 if (close(fd) == -1) { 332 g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno); 333 gdb_put_strbuf(); 334 return; 335 } 336 337 gdb_put_packet("F00"); 338 } 339 340 void gdb_handle_v_file_pread(GArray *params, void *user_ctx) 341 { 342 int fd = gdb_get_cmd_param(params, 0)->val_ul; 343 size_t count = gdb_get_cmd_param(params, 1)->val_ull; 344 off_t offset = gdb_get_cmd_param(params, 2)->val_ull; 345 346 size_t bufsiz = MIN(count, BUFSIZ); 347 g_autofree char *buf = g_try_malloc(bufsiz); 348 if (buf == NULL) { 349 gdb_put_packet("E12"); 350 return; 351 } 352 353 ssize_t n = pread(fd, buf, bufsiz, offset); 354 if (n < 0) { 355 g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno); 356 gdb_put_strbuf(); 357 return; 358 } 359 hostio_reply_with_data(buf, n); 360 } 361 362 void gdb_handle_v_file_readlink(GArray *params, void *user_ctx) 363 { 364 const char *filename = get_filename_param(params, 0); 365 366 g_autofree char *buf = g_try_malloc(BUFSIZ); 367 if (buf == NULL) { 368 gdb_put_packet("E12"); 369 return; 370 } 371 372 #ifdef CONFIG_LINUX 373 ssize_t n = do_guest_readlink(filename, buf, BUFSIZ); 374 #else 375 ssize_t n = readlink(filename, buf, BUFSIZ); 376 #endif 377 if (n < 0) { 378 g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno); 379 gdb_put_strbuf(); 380 return; 381 } 382 hostio_reply_with_data(buf, n); 383 } 384 385 void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx) 386 { 387 uint32_t pid = gdb_get_cmd_param(params, 0)->val_ul; 388 uint32_t offset = gdb_get_cmd_param(params, 1)->val_ul; 389 uint32_t length = gdb_get_cmd_param(params, 2)->val_ul; 390 391 GDBProcess *process = gdb_get_process(pid); 392 if (!process) { 393 gdb_put_packet("E00"); 394 return; 395 } 396 397 CPUState *cpu = gdb_get_first_cpu_in_process(process); 398 if (!cpu) { 399 gdb_put_packet("E00"); 400 return; 401 } 402 403 TaskState *ts = get_task_state(cpu); 404 if (!ts || !ts->bprm || !ts->bprm->filename) { 405 gdb_put_packet("E00"); 406 return; 407 } 408 409 size_t total_length = strlen(ts->bprm->filename); 410 if (offset > total_length) { 411 gdb_put_packet("E00"); 412 return; 413 } 414 if (offset + length > total_length) { 415 length = total_length - offset; 416 } 417 418 g_string_printf(gdbserver_state.str_buf, "l%.*s", length, 419 ts->bprm->filename + offset); 420 gdb_put_strbuf(); 421 } 422 423 int gdb_target_sigtrap(void) 424 { 425 return TARGET_SIGTRAP; 426 } 427