diff options
Diffstat (limited to 'gdbstub.c')
| -rw-r--r-- | gdbstub.c | 146 |
1 files changed, 126 insertions, 20 deletions
diff --git a/gdbstub.c b/gdbstub.c index 3b87c27349..12dd100af4 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -41,6 +41,15 @@ #include "qemu_socket.h" #include "kvm.h" +#ifndef TARGET_CPU_MEMORY_RW_DEBUG +static inline int target_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write) +{ + return cpu_memory_rw_debug(env, addr, buf, len, is_write); +} +#else +/* target_memory_rw_debug() defined in cpu.h */ +#endif enum { GDB_SIGNAL_0 = 0, @@ -1541,6 +1550,94 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) } return 4; } +#elif defined(TARGET_XTENSA) + +/* Use num_core_regs to see only non-privileged registers in an unmodified gdb. + * Use num_regs to see all registers. gdb modification is required for that: + * reset bit 0 in the 'flags' field of the registers definitions in the + * gdb/xtensa-config.c inside gdb source tree or inside gdb overlay. + */ +#define NUM_CORE_REGS (env->config->gdb_regmap.num_regs) +#define num_g_regs NUM_CORE_REGS + +static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) +{ + const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n; + + if (n < 0 || n >= env->config->gdb_regmap.num_regs) { + return 0; + } + + switch (reg->type) { + case 9: /*pc*/ + GET_REG32(env->pc); + break; + + case 1: /*ar*/ + xtensa_sync_phys_from_window(env); + GET_REG32(env->phys_regs[(reg->targno & 0xff) % env->config->nareg]); + break; + + case 2: /*SR*/ + GET_REG32(env->sregs[reg->targno & 0xff]); + break; + + case 3: /*UR*/ + GET_REG32(env->uregs[reg->targno & 0xff]); + break; + + case 8: /*a*/ + GET_REG32(env->regs[reg->targno & 0x0f]); + break; + + default: + qemu_log("%s from reg %d of unsupported type %d\n", + __func__, n, reg->type); + return 0; + } +} + +static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) +{ + uint32_t tmp; + const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n; + + if (n < 0 || n >= env->config->gdb_regmap.num_regs) { + return 0; + } + + tmp = ldl_p(mem_buf); + + switch (reg->type) { + case 9: /*pc*/ + env->pc = tmp; + break; + + case 1: /*ar*/ + env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp; + xtensa_sync_window_from_phys(env); + break; + + case 2: /*SR*/ + env->sregs[reg->targno & 0xff] = tmp; + break; + + case 3: /*UR*/ + env->uregs[reg->targno & 0xff] = tmp; + break; + + case 8: /*a*/ + env->regs[reg->targno & 0x0f] = tmp; + break; + + default: + qemu_log("%s to reg %d of unsupported type %d\n", + __func__, n, reg->type); + return 0; + } + + return 4; +} #else #define NUM_CORE_REGS 0 @@ -1557,7 +1654,9 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) #endif +#if !defined(TARGET_XTENSA) static int num_g_regs = NUM_CORE_REGS; +#endif #ifdef GDB_CORE_XML /* Encode data using the encoding for 'x' packets. */ @@ -1654,6 +1753,7 @@ static int gdb_write_register(CPUState *env, uint8_t *mem_buf, int reg) return 0; } +#if !defined(TARGET_XTENSA) /* Register a supplemental set of CPU registers. If g_pos is nonzero it specifies the first register number and these registers are included in a standard "g" packet. Direction is relative to gdb, i.e. get_reg is @@ -1693,6 +1793,7 @@ void gdb_register_coprocessor(CPUState * env, } } } +#endif #ifndef CONFIG_USER_ONLY static const int xlat_gdb_type[] = { @@ -1818,6 +1919,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc) s->c_cpu->psw.addr = pc; #elif defined (TARGET_LM32) s->c_cpu->pc = pc; +#elif defined(TARGET_XTENSA) + s->c_cpu->pc = pc; #endif } @@ -1988,6 +2091,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) break; case 'g': cpu_synchronize_state(s->g_cpu); + env = s->g_cpu; len = 0; for (addr = 0; addr < num_g_regs; addr++) { reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr); @@ -1998,6 +2102,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) break; case 'G': cpu_synchronize_state(s->g_cpu); + env = s->g_cpu; registers = mem_buf; len = strlen(p) / 2; hextomem((uint8_t *)registers, p, len); @@ -2013,7 +2118,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) if (*p == ',') p++; len = strtoull(p, NULL, 16); - if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) { + if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) { put_packet (s, "E14"); } else { memtohex(buf, mem_buf, len); @@ -2028,10 +2133,11 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) if (*p == ':') p++; hextomem(mem_buf, p, len); - if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) + if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) { put_packet(s, "E14"); - else + } else { put_packet(s, "OK"); + } break; case 'p': /* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable. @@ -2267,7 +2373,7 @@ void gdb_set_stop_cpu(CPUState *env) } #ifndef CONFIG_USER_ONLY -static void gdb_vm_state_change(void *opaque, int running, int reason) +static void gdb_vm_state_change(void *opaque, int running, RunState state) { GDBState *s = gdbserver_state; CPUState *env = s->c_cpu; @@ -2278,8 +2384,8 @@ static void gdb_vm_state_change(void *opaque, int running, int reason) if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) { return; } - switch (reason) { - case VMSTOP_DEBUG: + switch (state) { + case RSTATE_DEBUG: if (env->watchpoint_hit) { switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) { case BP_MEM_READ: @@ -2302,25 +2408,25 @@ static void gdb_vm_state_change(void *opaque, int running, int reason) tb_flush(env); ret = GDB_SIGNAL_TRAP; break; - case VMSTOP_USER: + case RSTATE_PAUSED: ret = GDB_SIGNAL_INT; break; - case VMSTOP_SHUTDOWN: + case RSTATE_SHUTDOWN: ret = GDB_SIGNAL_QUIT; break; - case VMSTOP_DISKFULL: + case RSTATE_IO_ERROR: ret = GDB_SIGNAL_IO; break; - case VMSTOP_WATCHDOG: + case RSTATE_WATCHDOG: ret = GDB_SIGNAL_ALRM; break; - case VMSTOP_PANIC: + case RSTATE_PANICKED: ret = GDB_SIGNAL_ABRT; break; - case VMSTOP_SAVEVM: - case VMSTOP_LOADVM: + case RSTATE_SAVEVM: + case RSTATE_RESTORE: return; - case VMSTOP_MIGRATE: + case RSTATE_PRE_MIGRATE: ret = GDB_SIGNAL_XCPU; break; default: @@ -2357,7 +2463,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) gdb_current_syscall_cb = cb; s->state = RS_SYSCALL; #ifndef CONFIG_USER_ONLY - vm_stop(VMSTOP_DEBUG); + vm_stop(RSTATE_DEBUG); #endif s->state = RS_IDLE; va_start(va, fmt); @@ -2428,10 +2534,10 @@ static void gdb_read_byte(GDBState *s, int ch) if (ch != '$') return; } - if (vm_running) { + if (runstate_is_running()) { /* when the CPU is running, we cannot do anything except stop it when receiving a char */ - vm_stop(VMSTOP_USER); + vm_stop(RSTATE_PAUSED); } else #endif { @@ -2693,7 +2799,7 @@ static void gdb_chr_event(void *opaque, int event) { switch (event) { case CHR_EVENT_OPENED: - vm_stop(VMSTOP_USER); + vm_stop(RSTATE_PAUSED); gdb_has_xml = 0; break; default: @@ -2733,8 +2839,8 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len) #ifndef _WIN32 static void gdb_sigterm_handler(int signal) { - if (vm_running) { - vm_stop(VMSTOP_USER); + if (runstate_is_running()) { + vm_stop(RSTATE_PAUSED); } } #endif |