X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=gdbstub.c;h=e8ab0b2992581ff9cd058aab62654fc2a76ef3a4;hb=8b7acc79b9adb4dda6cc867b90e3a1e873f4f7e8;hp=8a2f80c7d15c4827e6f9cbc4bc9198a16749fe3a;hpb=d0ff8d056d3aab93b4a7b7910f938652c2febc77;p=qemu.git diff --git a/gdbstub.c b/gdbstub.c index 8a2f80c7d..e8ab0b299 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -40,7 +40,6 @@ #include "cpu.h" #include "qemu/sockets.h" #include "sysemu/kvm.h" -#include "qemu/bitops.h" static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr, uint8_t *buf, int len, bool is_write) @@ -316,10 +315,7 @@ static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER; static GDBState *gdbserver_state; -/* This is an ugly hack to cope with both new and old gdb. - If gdb sends qXfer:features:read then assume we're talking to a newish - gdb that understands target descriptions. */ -static int gdb_has_xml; +bool gdb_has_xml; #ifdef CONFIG_USER_ONLY /* XXX: This is not thread safe. Do we care? */ @@ -372,9 +368,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(); } @@ -489,194 +482,6 @@ static int put_packet(GDBState *s, const char *buf) return put_packet_binary(s, buf, strlen(buf)); } -/* The GDB remote protocol transfers values in target byte order. This means - we can use the raw memory access routines to access the value buffer. - Conveniently, these also handle the case where the buffer is mis-aligned. - */ -#define GET_REG8(val) do { \ - stb_p(mem_buf, val); \ - return 1; \ - } while(0) -#define GET_REG16(val) do { \ - stw_p(mem_buf, val); \ - return 2; \ - } while(0) -#define GET_REG32(val) do { \ - stl_p(mem_buf, val); \ - return 4; \ - } while(0) -#define GET_REG64(val) do { \ - stq_p(mem_buf, val); \ - return 8; \ - } while(0) - -#if TARGET_LONG_BITS == 64 -#define GET_REGL(val) GET_REG64(val) -#define ldtul_p(addr) ldq_p(addr) -#else -#define GET_REGL(val) GET_REG32(val) -#define ldtul_p(addr) ldl_p(addr) -#endif - -#if defined(TARGET_I386) - -#include "target-i386/gdbstub.c" - -#elif defined (TARGET_PPC) - -#if defined (TARGET_PPC64) -#define GDB_CORE_XML "power64-core.xml" -#else -#define GDB_CORE_XML "power-core.xml" -#endif - -#include "target-ppc/gdbstub.c" - -#elif defined (TARGET_SPARC) - -#include "target-sparc/gdbstub.c" - -#elif defined (TARGET_ARM) - -#define GDB_CORE_XML "arm-core.xml" - -#include "target-arm/gdbstub.c" - -#elif defined (TARGET_M68K) - -#define GDB_CORE_XML "cf-core.xml" - -#include "target-m68k/gdbstub.c" - -#elif defined (TARGET_MIPS) - -#include "target-mips/gdbstub.c" - -#elif defined(TARGET_OPENRISC) - -#include "target-openrisc/gdbstub.c" - -#elif defined (TARGET_SH4) - -#include "target-sh4/gdbstub.c" - -#elif defined (TARGET_MICROBLAZE) - -#include "target-microblaze/gdbstub.c" - -#elif defined (TARGET_CRIS) - -#include "target-cris/gdbstub.c" - -#elif defined (TARGET_ALPHA) - -#include "target-alpha/gdbstub.c" - -#elif defined (TARGET_S390X) - -#include "target-s390x/gdbstub.c" - -#elif defined (TARGET_LM32) - -#include "target-lm32/gdbstub.c" - -#elif defined(TARGET_XTENSA) - -static int cpu_gdb_read_register(CPUXtensaState *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); - - case 1: /*ar*/ - xtensa_sync_phys_from_window(env); - GET_REG32(env->phys_regs[(reg->targno & 0xff) % env->config->nareg]); - - case 2: /*SR*/ - GET_REG32(env->sregs[reg->targno & 0xff]); - - case 3: /*UR*/ - GET_REG32(env->uregs[reg->targno & 0xff]); - - case 4: /*f*/ - GET_REG32(float32_val(env->fregs[reg->targno & 0x0f])); - - case 8: /*a*/ - GET_REG32(env->regs[reg->targno & 0x0f]); - - default: - qemu_log("%s from reg %d of unsupported type %d\n", - __func__, n, reg->type); - return 0; - } -} - -static int cpu_gdb_write_register(CPUXtensaState *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 4: /*f*/ - env->fregs[reg->targno & 0x0f] = make_float32(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 - -static int cpu_gdb_read_register(CPUArchState *env, uint8_t *mem_buf, int n) -{ - return 0; -} - -static int cpu_gdb_write_register(CPUArchState *env, uint8_t *mem_buf, int n) -{ - return 0; -} - -#endif - -#ifdef GDB_CORE_XML /* Encode data using the encoding for 'x' packets. */ static int memtox(char *buf, const char *mem, int len) { @@ -698,7 +503,8 @@ static int memtox(char *buf, const char *mem, int len) return p - buf; } -static const char *get_feature_xml(const char *p, const char **newp) +static const char *get_feature_xml(const char *p, const char **newp, + CPUClass *cc) { size_t len; int i; @@ -722,7 +528,7 @@ static const char *get_feature_xml(const char *p, const char **newp) "" "" "", - GDB_CORE_XML); + cc->gdb_core_xml_file); for (r = cpu->gdb_regs; r; r = r->next) { pstrcat(target_xml, sizeof(target_xml), "gdb_num_core_regs) { - return cpu_gdb_read_register(env, mem_buf, reg); + return cc->gdb_read_register(cpu, mem_buf, reg); } for (r = cpu->gdb_regs; r; r = r->next) { @@ -767,7 +572,7 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) GDBRegisterState *r; if (reg < cc->gdb_num_core_regs) { - return cpu_gdb_write_register(env, mem_buf, reg); + return cc->gdb_write_register(cpu, mem_buf, reg); } for (r = cpu->gdb_regs; r; r = r->next) { @@ -813,6 +618,8 @@ void gdb_register_coprocessor(CPUState *cpu, if (g_pos != s->base_reg) { fprintf(stderr, "Error: Bad gdb register numbering for '%s'\n" "Expected %d got %d\n", xml, g_pos, s->base_reg); + } else { + cpu->gdb_num_g_regs = cpu->gdb_num_regs; } } } @@ -838,7 +645,7 @@ static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type) switch (type) { case GDB_BREAKPOINT_SW: case GDB_BREAKPOINT_HW: - for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { + CPU_FOREACH(cpu) { env = cpu->env_ptr; err = cpu_breakpoint_insert(env, addr, BP_GDB, NULL); if (err) @@ -849,7 +656,7 @@ static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type) case GDB_WATCHPOINT_WRITE: case GDB_WATCHPOINT_READ: case GDB_WATCHPOINT_ACCESS: - for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { + CPU_FOREACH(cpu) { env = cpu->env_ptr; err = cpu_watchpoint_insert(env, addr, len, xlat_gdb_type[type], NULL); @@ -876,7 +683,7 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type) switch (type) { case GDB_BREAKPOINT_SW: case GDB_BREAKPOINT_HW: - for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { + CPU_FOREACH(cpu) { env = cpu->env_ptr; err = cpu_breakpoint_remove(env, addr, BP_GDB); if (err) @@ -887,7 +694,7 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type) case GDB_WATCHPOINT_WRITE: case GDB_WATCHPOINT_READ: case GDB_WATCHPOINT_ACCESS: - for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { + CPU_FOREACH(cpu) { env = cpu->env_ptr; err = cpu_watchpoint_remove(env, addr, len, xlat_gdb_type[type]); if (err) @@ -910,7 +717,7 @@ static void gdb_breakpoint_remove_all(void) return; } - for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { + CPU_FOREACH(cpu) { env = cpu->env_ptr; cpu_breakpoint_remove_all(env, BP_GDB); #ifndef CONFIG_USER_ONLY @@ -934,7 +741,7 @@ static CPUState *find_cpu(uint32_t thread_id) { CPUState *cpu; - for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { + CPU_FOREACH(cpu) { if (cpu_index(cpu) == thread_id) { return cpu; } @@ -946,6 +753,7 @@ static CPUState *find_cpu(uint32_t thread_id) static int gdb_handle_packet(GDBState *s, const char *line_buf) { CPUState *cpu; + CPUClass *cc; const char *p; uint32_t thread; int ch, reg_size, type, res; @@ -1093,7 +901,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) case 'g': cpu_synchronize_state(s->g_cpu); len = 0; - for (addr = 0; addr < s->g_cpu->gdb_num_regs; addr++) { + for (addr = 0; addr < s->g_cpu->gdb_num_g_regs; addr++) { reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr); len += reg_size; } @@ -1105,7 +913,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) registers = mem_buf; len = strlen(p) / 2; hextomem((uint8_t *)registers, p, len); - for (addr = 0; addr < s->g_cpu->gdb_num_regs && len > 0; addr++) { + for (addr = 0; addr < s->g_cpu->gdb_num_g_regs && len > 0; addr++) { reg_size = gdb_write_register(s->g_cpu, registers, addr); len -= reg_size; registers += reg_size; @@ -1259,7 +1067,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) if (s->query_cpu) { snprintf(buf, sizeof(buf), "m%x", cpu_index(s->query_cpu)); put_packet(s, buf); - s->query_cpu = s->query_cpu->next_cpu; + s->query_cpu = CPU_NEXT(s->query_cpu); } else put_packet(s, "l"); break; @@ -1308,20 +1116,25 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) #endif /* !CONFIG_USER_ONLY */ if (strncmp(p, "Supported", 9) == 0) { snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH); -#ifdef GDB_CORE_XML - pstrcat(buf, sizeof(buf), ";qXfer:features:read+"); -#endif + cc = CPU_GET_CLASS(first_cpu); + if (cc->gdb_core_xml_file != NULL) { + pstrcat(buf, sizeof(buf), ";qXfer:features:read+"); + } put_packet(s, buf); break; } -#ifdef GDB_CORE_XML if (strncmp(p, "Xfer:features:read:", 19) == 0) { const char *xml; target_ulong total_len; - gdb_has_xml = 1; + cc = CPU_GET_CLASS(first_cpu); + if (cc->gdb_core_xml_file == NULL) { + goto unknown_command; + } + + gdb_has_xml = true; p += 19; - xml = get_feature_xml(p, &p); + xml = get_feature_xml(p, &p, cc); if (!xml) { snprintf(buf, sizeof(buf), "E00"); put_packet(s, buf); @@ -1353,7 +1166,6 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) put_packet_binary(s, buf, len + 1); break; } -#endif /* Unrecognised 'q' command. */ goto unknown_command; @@ -1728,7 +1540,7 @@ static void gdb_accept(void) s->c_cpu = first_cpu; s->g_cpu = first_cpu; s->fd = fd; - gdb_has_xml = 0; + gdb_has_xml = false; gdbserver_state = s; @@ -1738,7 +1550,7 @@ static void gdb_accept(void) static int gdbserver_open(int port) { struct sockaddr_in sockaddr; - int fd, val, ret; + int fd, ret; fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { @@ -1749,9 +1561,7 @@ static int gdbserver_open(int port) fcntl(fd, F_SETFD, FD_CLOEXEC); #endif - /* allow fast reuse */ - val = 1; - qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + socket_set_fast_reuse(fd); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); @@ -1814,7 +1624,7 @@ static void gdb_chr_event(void *opaque, int event) switch (event) { case CHR_EVENT_OPENED: vm_stop(RUN_STATE_PAUSED); - gdb_has_xml = 0; + gdb_has_xml = false; break; default: break;