gdbstub.c: Getting closer to upstream. Change-Id: Icb2c92375e48dda780d776dab4faf723bc57aa7e
diff --git a/gdbstub.c b/gdbstub.c index c684d9a..f44f547 100644 --- a/gdbstub.c +++ b/gdbstub.c
@@ -28,13 +28,12 @@ #include <fcntl.h> #include "qemu.h" -#include "hw/hw.h" #else +#include "cpu.h" #include "monitor/monitor.h" #include "sysemu/char.h" #include "sysemu/sysemu.h" #include "exec/gdbstub.h" -#include "exec/exec-all.h" #endif #define MAX_PACKET_LENGTH 4096 @@ -46,7 +45,12 @@ enum { GDB_SIGNAL_0 = 0, GDB_SIGNAL_INT = 2, + GDB_SIGNAL_QUIT = 3, GDB_SIGNAL_TRAP = 5, + GDB_SIGNAL_ABRT = 6, + GDB_SIGNAL_ALRM = 14, + GDB_SIGNAL_IO = 23, + GDB_SIGNAL_XCPU = 24, GDB_SIGNAL_UNKNOWN = 143 }; @@ -274,9 +278,9 @@ RS_SYSCALL, }; typedef struct GDBState { - CPUArchState *c_cpu; /* current CPU for step/continue ops */ - CPUArchState *g_cpu; /* current CPU for other ops */ - CPUArchState *query_cpu; /* for q{f|s}ThreadInfo */ + CPUState *c_cpu; /* current CPU for step/continue ops */ + CPUState *g_cpu; /* current CPU for other ops */ + CPUState *query_cpu; /* for q{f|s}ThreadInfo */ enum RSState state; /* parsing state */ char line_buf[MAX_PACKET_LENGTH]; int line_buf_index; @@ -291,6 +295,8 @@ CharDriverState *chr; CharDriverState *mon_chr; #endif + char syscall_buf[256]; + gdb_syscall_complete_cb current_syscall_cb; } GDBState; /* By default use no IRQs and no timers while single stepping so as to @@ -300,10 +306,7 @@ 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? */ @@ -315,7 +318,7 @@ int ret; for(;;) { - ret = recv(s->fd, &ch, 1, 0); + ret = qemu_recv(s->fd, &ch, 1, 0); if (ret < 0) { if (errno == ECONNRESET) s->fd = -1; @@ -333,7 +336,6 @@ } #endif -static gdb_syscall_complete_cb gdb_current_syscall_cb; static enum { GDB_SYS_UNKNOWN, @@ -1355,6 +1357,7 @@ /* Generate the XML description for this CPU. */ if (!target_xml[0]) { GDBRegisterState *r; + CPUState *cpu = first_cpu; snprintf(target_xml, sizeof(target_xml), "<?xml version=\"1.0\"?>" @@ -1363,7 +1366,7 @@ "<xi:include href=\"%s\"/>", GDB_CORE_XML); - for (r = QTAILQ_FIRST(&cpus)->gdb_regs; r; r = r->next) { + for (r = cpu->gdb_regs; r; r = r->next) { pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\""); pstrcat(target_xml, sizeof(target_xml), r->xml); pstrcat(target_xml, sizeof(target_xml), "\"/>"); @@ -1381,13 +1384,14 @@ } #endif -static int gdb_read_register(CPUArchState *env, uint8_t *mem_buf, int reg) +static int gdb_read_register(CPUState *cpu, uint8_t *mem_buf, int reg) { + CPUArchState *env = cpu->env_ptr; GDBRegisterState *r; - CPUState *cpu = ENV_GET_CPU(env); - if (reg < NUM_CORE_REGS) + if (reg < NUM_CORE_REGS) { return cpu_gdb_read_register(env, mem_buf, reg); + } for (r = cpu->gdb_regs; r; r = r->next) { if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { @@ -1397,13 +1401,14 @@ return 0; } -static int gdb_write_register(CPUArchState *env, uint8_t *mem_buf, int reg) +static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) { + CPUArchState *env = cpu->env_ptr; GDBRegisterState *r; - CPUState *cpu = ENV_GET_CPU(env); - if (reg < NUM_CORE_REGS) + if (reg < NUM_CORE_REGS) { return cpu_gdb_write_register(env, mem_buf, reg); + } for (r = cpu->gdb_regs; r; r = r->next) { if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { @@ -1466,16 +1471,18 @@ CPUState *cpu; int err = 0; - if (kvm_enabled()) - return kvm_insert_breakpoint(ENV_GET_CPU(gdbserver_state->c_cpu), addr, len, type); + if (kvm_enabled()) { + return kvm_insert_breakpoint(gdbserver_state->c_cpu, addr, len, type); + } switch (type) { case GDB_BREAKPOINT_SW: case GDB_BREAKPOINT_HW: CPU_FOREACH(cpu) { err = cpu_breakpoint_insert(cpu->env_ptr, addr, BP_GDB, NULL); - if (err) + if (err) { break; + } } return err; #ifndef CONFIG_USER_ONLY @@ -1500,16 +1507,18 @@ CPUState *cpu; int err = 0; - if (kvm_enabled()) - return kvm_remove_breakpoint(ENV_GET_CPU(gdbserver_state->c_cpu), addr, len, type); + if (kvm_enabled()) { + return kvm_remove_breakpoint(gdbserver_state->c_cpu, addr, len, type); + } switch (type) { case GDB_BREAKPOINT_SW: case GDB_BREAKPOINT_HW: CPU_FOREACH(cpu) { err = cpu_breakpoint_remove(cpu->env_ptr, addr, BP_GDB); - if (err) + if (err) { break; + } } return err; #ifndef CONFIG_USER_ONLY @@ -1533,7 +1542,7 @@ CPUState *cpu; if (kvm_enabled()) { - kvm_remove_all_breakpoints(ENV_GET_CPU(gdbserver_state->c_cpu)); + kvm_remove_all_breakpoints(gdbserver_state->c_cpu); return; } @@ -1547,45 +1556,37 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc) { + CPUArchState *env = s->c_cpu->env_ptr; #if defined(TARGET_I386) - s->c_cpu->eip = pc; - cpu_synchronize_state(ENV_GET_CPU(s->c_cpu), 1); + env->eip = pc; + cpu_synchronize_state(s->c_cpu, 1); #elif defined (TARGET_PPC) - s->c_cpu->nip = pc; + env->nip = pc; #elif defined (TARGET_SPARC) - s->c_cpu->pc = pc; - s->c_cpu->npc = pc + 4; + env->pc = pc; + env->npc = pc + 4; #elif defined (TARGET_ARM) - s->c_cpu->regs[15] = pc; + env->regs[15] = pc; #elif defined (TARGET_SH4) - s->c_cpu->pc = pc; + env->pc = pc; #elif defined (TARGET_MIPS) - s->c_cpu->active_tc.PC = pc; + env->active_tc.PC = pc; #elif defined (TARGET_MICROBLAZE) - s->c_cpu->sregs[SR_PC] = pc; + env->sregs[SR_PC] = pc; #elif defined (TARGET_CRIS) - s->c_cpu->pc = pc; + env->pc = pc; #elif defined (TARGET_ALPHA) - s->c_cpu->pc = pc; + env->pc = pc; #endif } -static inline int gdb_id(CPUState *cpu) -{ -#if defined(CONFIG_USER_ONLY) && defined(USE_NPTL) - return cpu->host_tid; -#else - return cpu->cpu_index + 1; -#endif -} - -static CPUArchState *find_cpu(uint32_t thread_id) +static CPUState *find_cpu(uint32_t thread_id) { CPUState *cpu; CPU_FOREACH(cpu) { - if (gdb_id(cpu) == thread_id) { - return cpu->env_ptr; + if (cpu_index(cpu) == thread_id) { + return cpu; } } @@ -1594,7 +1595,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) { - CPUArchState *env; + CPUState *cpu; const char *p; uint32_t thread; int ch, reg_size, type, res; @@ -1612,7 +1613,7 @@ case '?': /* TODO: Make this return the correct value for user-mode. */ snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP, - gdb_id(ENV_GET_CPU(s->c_cpu))); + cpu_index(s->c_cpu)); put_packet(s, buf); /* Remove all the breakpoints when this query is issued, * because gdb is doing and initial connect and the state @@ -1635,12 +1636,15 @@ gdb_continue(s); return RS_IDLE; case 'k': +#ifdef CONFIG_USER_ONLY /* Kill the target */ fprintf(stderr, "\nQEMU: Terminated via GDBstub\n"); exit(0); +#endif case 'D': /* Detach packet */ gdb_breakpoint_remove_all(); + gdb_syscall_mode = GDB_SYS_DISABLED; gdb_continue(s); put_packet(s, "OK"); break; @@ -1649,7 +1653,7 @@ addr = strtoull(p, (char **)&p, 16); gdb_set_cpu_pc(s, addr); } - cpu_single_step(ENV_GET_CPU(s->c_cpu), sstep_flags); + cpu_single_step(s->c_cpu, sstep_flags); gdb_continue(s); return RS_IDLE; case 'F': @@ -1667,8 +1671,10 @@ if (*p == ',') p++; type = *p; - if (gdb_current_syscall_cb) - gdb_current_syscall_cb(ENV_GET_CPU(s->c_cpu), ret, err); + if (s->current_syscall_cb) { + s->current_syscall_cb(s->c_cpu, ret, err); + s->current_syscall_cb = NULL; + } if (type == 'C') { put_packet(s, "T02"); } else { @@ -1677,7 +1683,7 @@ } break; case 'g': - cpu_synchronize_state(ENV_GET_CPU(s->g_cpu), 0); + cpu_synchronize_state(s->g_cpu, 0); len = 0; for (addr = 0; addr < num_g_regs; addr++) { reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr); @@ -1687,6 +1693,7 @@ put_packet(s, buf); break; case 'G': + cpu_synchronize_state(s->g_cpu, 1); registers = mem_buf; len = strlen(p) / 2; hextomem((uint8_t *)registers, p, len); @@ -1695,7 +1702,6 @@ len -= reg_size; registers += reg_size; } - cpu_synchronize_state(ENV_GET_CPU(s->g_cpu), 1); put_packet(s, "OK"); break; case 'm': @@ -1703,7 +1709,7 @@ if (*p == ',') p++; len = strtoull(p, NULL, 16); - if (cpu_memory_rw_debug(ENV_GET_CPU(s->g_cpu), addr, mem_buf, len, 0) != 0) { + if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) { put_packet (s, "E14"); } else { memtohex(buf, mem_buf, len); @@ -1718,10 +1724,11 @@ if (*p == ':') p++; hextomem(mem_buf, p, len); - if (cpu_memory_rw_debug(ENV_GET_CPU(s->g_cpu), addr, mem_buf, len, 1) != 0) + if (cpu_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. @@ -1776,18 +1783,18 @@ put_packet(s, "OK"); break; } - env = find_cpu(thread); - if (env == NULL) { + cpu = find_cpu(thread); + if (cpu == NULL) { put_packet(s, "E22"); break; } switch (type) { case 'c': - s->c_cpu = env; + s->c_cpu = cpu; put_packet(s, "OK"); break; case 'g': - s->g_cpu = env; + s->g_cpu = cpu; put_packet(s, "OK"); break; default: @@ -1797,9 +1804,9 @@ break; case 'T': thread = strtoull(p, (char **)&p, 16); - env = find_cpu(thread); + cpu = find_cpu(thread); - if (env != NULL) { + if (cpu != NULL) { put_packet(s, "OK"); } else { put_packet(s, "E22"); @@ -1836,25 +1843,25 @@ put_packet(s, "QC1"); break; } else if (strcmp(p,"fThreadInfo") == 0) { - s->query_cpu = QTAILQ_FIRST(&cpus)->env_ptr; + s->query_cpu = first_cpu; goto report_cpuinfo; } else if (strcmp(p,"sThreadInfo") == 0) { report_cpuinfo: if (s->query_cpu) { - snprintf(buf, sizeof(buf), "m%x", gdb_id(ENV_GET_CPU(s->query_cpu))); + snprintf(buf, sizeof(buf), "m%x", cpu_index(s->query_cpu)); put_packet(s, buf); - s->query_cpu = QTAILQ_NEXT(ENV_GET_CPU(s->query_cpu), node)->env_ptr; + s->query_cpu = CPU_NEXT(s->query_cpu); } else put_packet(s, "l"); break; } else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) { thread = strtoull(p+16, (char **)&p, 16); - env = find_cpu(thread); - if (env != NULL) { - cpu_synchronize_state(ENV_GET_CPU(env), 0); + cpu = find_cpu(thread); + if (cpu != NULL) { + cpu_synchronize_state(cpu, 1); len = snprintf((char *)mem_buf, sizeof(mem_buf), - "CPU#%d [%s]", ENV_GET_CPU(env)->cpu_index, - ENV_GET_CPU(env)->halted ? "halted " : "running"); + "CPU#%d [%s]", cpu->cpu_index, + cpu->halted ? "halted " : "running"); memtohex(buf, mem_buf, len); put_packet(s, buf); } @@ -1902,7 +1909,7 @@ const char *xml; target_ulong total_len; - gdb_has_xml = 1; + gdb_has_xml = true; p += 19; xml = get_feature_xml(p, &p); if (!xml) { @@ -1952,16 +1959,16 @@ void gdb_set_stop_cpu(CPUState *cpu) { - gdbserver_state->c_cpu = cpu->env_ptr; - gdbserver_state->g_cpu = cpu->env_ptr; + gdbserver_state->c_cpu = cpu; + gdbserver_state->g_cpu = cpu; } #ifndef CONFIG_USER_ONLY static void gdb_vm_state_change(void *opaque, int running, int reason) { GDBState *s = gdbserver_state; - CPUArchState *env = s->c_cpu; - CPUState *cpu = ENV_GET_CPU(env); + CPUArchState *env = s->c_cpu->env_ptr; + CPUState *cpu = s->c_cpu; char buf[256]; const char *type; int ret; @@ -1970,9 +1977,6 @@ s->state == RS_INACTIVE || s->state == RS_SYSCALL) return; - /* disable single step if it was enable */ - cpu_single_step(cpu, 0); - if (reason == EXCP_DEBUG) { if (env->watchpoint_hit) { switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) { @@ -1988,19 +1992,23 @@ } snprintf(buf, sizeof(buf), "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";", - GDB_SIGNAL_TRAP, gdb_id(cpu), type, - env->watchpoint_hit->vaddr); - put_packet(s, buf); + GDB_SIGNAL_TRAP, cpu_index(cpu), type, + (target_ulong)env->watchpoint_hit->vaddr); env->watchpoint_hit = NULL; - return; + goto send_packet; } tb_flush(env); ret = GDB_SIGNAL_TRAP; } else { ret = GDB_SIGNAL_INT; } - snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, gdb_id(cpu)); + snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_index(cpu)); + +send_packet: put_packet(s, buf); + + /* disable single step if it was enabled */ + cpu_single_step(cpu, 0); } #endif @@ -2012,8 +2020,8 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) { va_list va; - char buf[256]; char *p; + char *p_end; target_ulong addr; uint64_t i64; GDBState *s; @@ -2021,14 +2029,13 @@ s = gdbserver_state; if (!s) return; - gdb_current_syscall_cb = cb; - s->state = RS_SYSCALL; + s->current_syscall_cb = cb; #ifndef CONFIG_USER_ONLY vm_stop(EXCP_DEBUG); #endif - s->state = RS_IDLE; va_start(va, fmt); - p = buf; + p = s->syscall_buf; + p_end = &s->syscall_buf[sizeof(s->syscall_buf)]; *(p++) = 'F'; while (*fmt) { if (*fmt == '%') { @@ -2036,17 +2043,17 @@ switch (*fmt++) { case 'x': addr = va_arg(va, target_ulong); - p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx, addr); + p += snprintf(p, p_end - p, TARGET_FMT_lx, addr); break; case 'l': if (*(fmt++) != 'x') goto bad_format; i64 = va_arg(va, uint64_t); - p += snprintf(p, &buf[sizeof(buf)] - p, "%" PRIx64, i64); + p += snprintf(p, p_end - p, "%" PRIx64, i64); break; case 's': addr = va_arg(va, target_ulong); - p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx "/%x", + p += snprintf(p, p_end - p, TARGET_FMT_lx "/%x", addr, va_arg(va, int)); break; default: @@ -2061,11 +2068,17 @@ } *p = 0; va_end(va); - put_packet(s, buf); #ifdef CONFIG_USER_ONLY + put_packet(s, s->syscall_buf); gdb_handlesig(s->c_cpu, 0); #else - cpu_exit(ENV_GET_CPU(s->c_cpu)); + /* In this case wait to send the syscall packet until notification that + the CPU has stopped. This must be done because if the packet is sent + now the reply from the syscall request could be received while the CPU + is still in the running state, which can cause packets to be dropped + and state transition 'T' packets to be sent while the syscall is still + being processed. */ + cpu_exit(s->c_cpu); #endif } @@ -2145,6 +2158,32 @@ } } +/* Tell the remote gdb that the process has exited. */ +void gdb_exit(CPUArchState *env, int code) +{ + GDBState *s; + char buf[4]; + + s = gdbserver_state; + if (!s) { + return; + } +#ifdef CONFIG_USER_ONLY + if (gdbserver_fd < 0 || s->fd < 0) { + return; + } +#endif + + snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code); + put_packet(s, buf); + +#ifndef CONFIG_USER_ONLY + if (s->chr) { + qemu_chr_close(s->chr); + s->chr = NULL; + } +#endif +} #ifdef CONFIG_USER_ONLY int gdb_queuesig (void) @@ -2162,43 +2201,43 @@ int gdb_handlesig (CPUState *cpu, int sig) { + CPUArchState *env = cpu->env_ptr; GDBState *s; char buf[256]; int n; s = gdbserver_state; - if (gdbserver_fd < 0 || s->fd < 0) + if (gdbserver_fd < 0 || s->fd < 0) { return sig; + } /* disable single step if it was enabled */ cpu_single_step(cpu, 0); - tb_flush(cpu->env_ptr); + tb_flush(env); - if (sig != 0) - { + if (sig != 0) { snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb (sig)); put_packet(s, buf); } /* put_packet() might have detected that the peer terminated the connection. */ - if (s->fd < 0) + if (s->fd < 0) { return sig; + } sig = 0; s->state = RS_IDLE; s->running_state = 0; while (s->running_state == 0) { n = read (s->fd, buf, 256); - if (n > 0) - { + if (n > 0) { int i; - for (i = 0; i < n; i++) + for (i = 0; i < n; i++) { gdb_read_byte (s, buf[i]); } - else if (n == 0 || errno != EAGAIN) - { - /* XXX: Connection closed. Should probably wait for annother + } else if (n == 0 || errno != EAGAIN) { + /* XXX: Connection closed. Should probably wait for another connection before continuing. */ return sig; } @@ -2208,20 +2247,6 @@ return sig; } -/* Tell the remote gdb that the process has exited. */ -void gdb_exit(CPUState *cpu, int code) -{ - GDBState *s; - char buf[4]; - - s = gdbserver_state; - if (gdbserver_fd < 0 || s->fd < 0) - return; - - snprintf(buf, sizeof(buf), "W%02x", code); - put_packet(s, buf); -} - /* Tell the remote gdb that the process has exited due to SIG. */ void gdb_signalled(CPUState *cpu, int sig) { @@ -2229,8 +2254,9 @@ char buf[4]; s = gdbserver_state; - if (gdbserver_fd < 0 || s->fd < 0) + if (gdbserver_fd < 0 || s->fd < 0) { return; + } snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig)); put_packet(s, buf); @@ -2241,7 +2267,7 @@ GDBState *s; struct sockaddr_in sockaddr; socklen_t len; - int val, fd; + int fd; for(;;) { len = sizeof(sockaddr); @@ -2250,19 +2276,21 @@ perror("accept"); return; } else if (fd >= 0) { +#ifndef _WIN32 + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif break; } } /* set short latency */ - val = 1; - qemu_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); + socket_set_nodelay(fd); s = g_malloc0(sizeof(GDBState)); - s->c_cpu = QTAILQ_FIRST(&cpus); - s->g_cpu = QTAILQ_FIRST(&cpus); + s->c_cpu = first_cpu; + s->g_cpu = first_cpu; s->fd = fd; - gdb_has_xml = 0; + gdb_has_xml = false; gdbserver_state = s; @@ -2272,17 +2300,18 @@ 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) { perror("socket"); return -1; } +#ifndef _WIN32 + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif - /* allow fast reuse */ - val = 1; - qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); + socket_set_fast_reuse(fd); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); @@ -2290,11 +2319,13 @@ ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); if (ret < 0) { perror("bind"); + close(fd); return -1; } ret = listen(fd, 0); if (ret < 0) { perror("listen"); + close(fd); return -1; } return fd; @@ -2314,8 +2345,9 @@ void gdbserver_fork(CPUArchState *env) { GDBState *s = gdbserver_state; - if (gdbserver_fd < 0 || s->fd < 0) + if (gdbserver_fd < 0 || s->fd < 0) { return; + } close(s->fd); s->fd = -1; cpu_breakpoint_remove_all(env, BP_GDB); @@ -2343,7 +2375,7 @@ switch (event) { case CHR_EVENT_OPENED: vm_stop(EXCP_INTERRUPT); - gdb_has_xml = 0; + gdb_has_xml = false; break; default: break; @@ -2382,8 +2414,9 @@ #ifndef _WIN32 static void gdb_sigterm_handler(int signal) { - if (vm_running) + if (vm_running) { vm_stop(EXCP_INTERRUPT); + } } #endif @@ -2437,11 +2470,12 @@ mon_chr = s->mon_chr; memset(s, 0, sizeof(GDBState)); } - s->c_cpu = QTAILQ_FIRST(&cpus)->env_ptr; - s->g_cpu = s->c_cpu; + s->c_cpu = first_cpu; + s->g_cpu = first_cpu; s->chr = chr; s->state = chr ? RS_IDLE : RS_INACTIVE; s->mon_chr = mon_chr; + s->current_syscall_cb = NULL; return 0; }
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 4d122d0..7b9a485 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h
@@ -11,14 +11,12 @@ #define GDB_WATCHPOINT_ACCESS 4 #ifdef NEED_CPU_H -#include "cpu.h" - -typedef void (*gdb_syscall_complete_cb)(CPUState *env, +typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, target_ulong ret, target_ulong err); void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...); int use_gdb_syscalls(void); -void gdb_set_stop_cpu(CPUState *env); +void gdb_set_stop_cpu(CPUState *cpu); void gdb_exit(CPUArchState *, int); #ifdef CONFIG_USER_ONLY int gdb_queuesig (void); @@ -31,6 +29,14 @@ void gdb_register_coprocessor(CPUState *cpu, gdb_reg_cb get_reg, gdb_reg_cb set_reg, int num_regs, const char *xml, int g_pos); +static inline int cpu_index(CPUState *cpu) +{ +#if defined(CONFIG_USER_ONLY) + return cpu->host_tid; +#else + return cpu->cpu_index + 1; +#endif +} #endif @@ -39,5 +45,15 @@ #else int gdbserver_start(const char *port); #endif +/** + * gdb_has_xml: + * 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. + */ +extern bool gdb_has_xml; + +/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ +extern const char *const xml_builtin[][2]; #endif