X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/a107170537abdfec7221c1e0d424c82f5faf2ebe..4020db0475b3e527b3bdc97dff873c2be9da2698:/gdbstub.c diff --git a/gdbstub.c b/gdbstub.c index 0e5a3f5bf9..8abcb8a451 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -317,6 +317,8 @@ static GDBState *gdbserver_state; bool gdb_has_xml; +int semihosting_target = SEMIHOSTING_TARGET_AUTO; + #ifdef CONFIG_USER_ONLY /* XXX: This is not thread safe. Do we care? */ static int gdbserver_fd = -1; @@ -351,10 +353,19 @@ static enum { GDB_SYS_DISABLED, } gdb_syscall_mode; -/* If gdb is connected when the first semihosting syscall occurs then use - remote gdb syscalls. Otherwise use native file IO. */ +/* Decide if either remote gdb syscalls or native file IO should be used. */ int use_gdb_syscalls(void) { + if (semihosting_target == SEMIHOSTING_TARGET_NATIVE) { + /* -semihosting-config target=native */ + return false; + } else if (semihosting_target == SEMIHOSTING_TARGET_GDB) { + /* -semihosting-config target=gdb */ + return true; + } + + /* -semihosting-config target=auto */ + /* On the first call check if gdb is connected and remember. */ if (gdb_syscall_mode == GDB_SYS_UNKNOWN) { gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED : GDB_SYS_DISABLED); @@ -368,9 +379,6 @@ static inline void gdb_continue(GDBState *s) #ifdef CONFIG_USER_ONLY s->running_state = 1; #else - if (runstate_check(RUN_STATE_GUEST_PANICKED)) { - runstate_set(RUN_STATE_DEBUG); - } if (!runstate_needs_reset()) { vm_start(); } @@ -628,17 +636,28 @@ void gdb_register_coprocessor(CPUState *cpu, } #ifndef CONFIG_USER_ONLY -static const int xlat_gdb_type[] = { - [GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE, - [GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ, - [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS, -}; +/* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */ +static inline int xlat_gdb_type(CPUState *cpu, int gdbtype) +{ + static const int xlat[] = { + [GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE, + [GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ, + [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS, + }; + + CPUClass *cc = CPU_GET_CLASS(cpu); + int cputype = xlat[gdbtype]; + + if (cc->gdb_stop_before_watchpoint) { + cputype |= BP_STOP_BEFORE_ACCESS; + } + return cputype; +} #endif static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type) { CPUState *cpu; - CPUArchState *env; int err = 0; if (kvm_enabled()) { @@ -649,10 +668,10 @@ static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type) case GDB_BREAKPOINT_SW: case GDB_BREAKPOINT_HW: CPU_FOREACH(cpu) { - env = cpu->env_ptr; - err = cpu_breakpoint_insert(env, addr, BP_GDB, NULL); - if (err) + err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL); + if (err) { break; + } } return err; #ifndef CONFIG_USER_ONLY @@ -660,11 +679,11 @@ static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type) case GDB_WATCHPOINT_READ: case GDB_WATCHPOINT_ACCESS: CPU_FOREACH(cpu) { - env = cpu->env_ptr; - err = cpu_watchpoint_insert(env, addr, len, xlat_gdb_type[type], - NULL); - if (err) + err = cpu_watchpoint_insert(cpu, addr, len, + xlat_gdb_type(cpu, type), NULL); + if (err) { break; + } } return err; #endif @@ -676,7 +695,6 @@ static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type) static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type) { CPUState *cpu; - CPUArchState *env; int err = 0; if (kvm_enabled()) { @@ -687,10 +705,10 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type) case GDB_BREAKPOINT_SW: case GDB_BREAKPOINT_HW: CPU_FOREACH(cpu) { - env = cpu->env_ptr; - err = cpu_breakpoint_remove(env, addr, BP_GDB); - if (err) + err = cpu_breakpoint_remove(cpu, addr, BP_GDB); + if (err) { break; + } } return err; #ifndef CONFIG_USER_ONLY @@ -698,8 +716,8 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type) case GDB_WATCHPOINT_READ: case GDB_WATCHPOINT_ACCESS: CPU_FOREACH(cpu) { - env = cpu->env_ptr; - err = cpu_watchpoint_remove(env, addr, len, xlat_gdb_type[type]); + err = cpu_watchpoint_remove(cpu, addr, len, + xlat_gdb_type(cpu, type)); if (err) break; } @@ -713,7 +731,6 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type) static void gdb_breakpoint_remove_all(void) { CPUState *cpu; - CPUArchState *env; if (kvm_enabled()) { kvm_remove_all_breakpoints(gdbserver_state->c_cpu); @@ -721,10 +738,9 @@ static void gdb_breakpoint_remove_all(void) } CPU_FOREACH(cpu) { - env = cpu->env_ptr; - cpu_breakpoint_remove_all(env, BP_GDB); + cpu_breakpoint_remove_all(cpu, BP_GDB); #ifndef CONFIG_USER_ONLY - cpu_watchpoint_remove_all(env, BP_GDB); + cpu_watchpoint_remove_all(cpu, BP_GDB); #endif } } @@ -818,7 +834,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) action = *p++; signal = 0; if (action == 'C' || action == 'S') { - signal = strtoul(p, (char **)&p, 16); + signal = gdb_signal_to_target(strtoul(p, (char **)&p, 16)); + if (signal == -1) { + signal = 0; + } } else if (action != 'c' && action != 's') { res = 0; break; @@ -1089,8 +1108,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) } #ifdef CONFIG_USER_ONLY else if (strncmp(p, "Offsets", 7) == 0) { - CPUArchState *env = s->c_cpu->env_ptr; - TaskState *ts = env->opaque; + TaskState *ts = s->c_cpu->opaque; snprintf(buf, sizeof(buf), "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx @@ -1208,8 +1226,8 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state) } switch (state) { case RUN_STATE_DEBUG: - if (env->watchpoint_hit) { - switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) { + if (cpu->watchpoint_hit) { + switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) { case BP_MEM_READ: type = "r"; break; @@ -1223,8 +1241,8 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state) snprintf(buf, sizeof(buf), "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";", GDB_SIGNAL_TRAP, cpu_index(cpu), type, - env->watchpoint_hit->vaddr); - env->watchpoint_hit = NULL; + (target_ulong)cpu->watchpoint_hit->vaddr); + cpu->watchpoint_hit = NULL; goto send_packet; } tb_flush(env); @@ -1425,15 +1443,17 @@ void gdb_exit(CPUArchState *env, int code) if (gdbserver_fd < 0 || s->fd < 0) { return; } +#else + if (!s->chr) { + return; + } #endif snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code); put_packet(s, buf); #ifndef CONFIG_USER_ONLY - if (s->chr) { - qemu_chr_delete(s->chr); - } + qemu_chr_delete(s->chr); #endif } @@ -1597,13 +1617,16 @@ int gdbserver_start(int port) /* Disable gdb stub for child processes. */ void gdbserver_fork(CPUArchState *env) { + CPUState *cpu = ENV_GET_CPU(env); GDBState *s = gdbserver_state; - if (gdbserver_fd < 0 || s->fd < 0) - return; + + if (gdbserver_fd < 0 || s->fd < 0) { + return; + } close(s->fd); s->fd = -1; - cpu_breakpoint_remove_all(env, BP_GDB); - cpu_watchpoint_remove_all(env, BP_GDB); + cpu_breakpoint_remove_all(cpu, BP_GDB); + cpu_watchpoint_remove_all(cpu, BP_GDB); } #else static int gdb_chr_can_receive(void *opaque) @@ -1714,7 +1737,7 @@ int gdbserver_start(const char *device) qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL); /* Initialize a monitor terminal for gdb */ - mon_chr = g_malloc0(sizeof(*mon_chr)); + mon_chr = qemu_chr_alloc(); mon_chr->chr_write = gdb_monitor_write; monitor_init(mon_chr, 0); } else {