X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=gdbstub.c;h=3c34741f97f275de7247d3d7b51e1c68b25fb776;hb=73c632edc4e28d0a8cae3b34abf7ae46fa33bf1e;hp=d54976612f95505bf4a563e515fd937a628a9bbb;hpb=0b8a988c5d34c73815136bb41b10f67009b42a1c;p=qemu diff --git a/gdbstub.c b/gdbstub.c index d549766..3c34741 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -39,6 +39,7 @@ #define MAX_PACKET_LENGTH 4096 #include "qemu_socket.h" +#include "kvm.h" enum { @@ -264,6 +265,7 @@ typedef struct GDBRegisterState { } GDBRegisterState; enum RSState { + RS_INACTIVE, RS_IDLE, RS_GETLINE, RS_CHKSUM1, @@ -332,7 +334,7 @@ static int get_char(GDBState *s) static gdb_syscall_complete_cb gdb_current_syscall_cb; -enum { +static enum { GDB_SYS_UNKNOWN, GDB_SYS_ENABLED, GDB_SYS_DISABLED, @@ -1331,11 +1333,11 @@ static const char *get_feature_xml(const char *p, const char **newp) GDB_CORE_XML); for (r = first_cpu->gdb_regs; r; r = r->next) { - strcat(target_xml, "xml); - strcat(target_xml, "\"/>"); + pstrcat(target_xml, sizeof(target_xml), "xml); + pstrcat(target_xml, sizeof(target_xml), "\"/>"); } - strcat(target_xml, ""); + pstrcat(target_xml, sizeof(target_xml), ""); } return target_xml; } @@ -1418,13 +1420,6 @@ void gdb_register_coprocessor(CPUState * env, } } -/* GDB breakpoint/watchpoint types */ -#define GDB_BREAKPOINT_SW 0 -#define GDB_BREAKPOINT_HW 1 -#define GDB_WATCHPOINT_WRITE 2 -#define GDB_WATCHPOINT_READ 3 -#define GDB_WATCHPOINT_ACCESS 4 - #ifndef CONFIG_USER_ONLY static const int xlat_gdb_type[] = { [GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE, @@ -1438,6 +1433,9 @@ static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type) CPUState *env; int err = 0; + if (kvm_enabled()) + return kvm_insert_breakpoint(gdbserver_state->c_cpu, addr, len, type); + switch (type) { case GDB_BREAKPOINT_SW: case GDB_BREAKPOINT_HW: @@ -1469,6 +1467,9 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type) CPUState *env; int err = 0; + if (kvm_enabled()) + return kvm_remove_breakpoint(gdbserver_state->c_cpu, addr, len, type); + switch (type) { case GDB_BREAKPOINT_SW: case GDB_BREAKPOINT_HW: @@ -1498,6 +1499,11 @@ static void gdb_breakpoint_remove_all(void) { CPUState *env; + if (kvm_enabled()) { + kvm_remove_all_breakpoints(gdbserver_state->c_cpu); + return; + } + for (env = first_cpu; env != NULL; env = env->next_cpu) { cpu_breakpoint_remove_all(env, BP_GDB); #ifndef CONFIG_USER_ONLY @@ -1506,6 +1512,29 @@ static void gdb_breakpoint_remove_all(void) } } +static void gdb_set_cpu_pc(GDBState *s, target_ulong pc) +{ +#if defined(TARGET_I386) + s->c_cpu->eip = pc; + cpu_synchronize_state(s->c_cpu, 1); +#elif defined (TARGET_PPC) + s->c_cpu->nip = pc; +#elif defined (TARGET_SPARC) + s->c_cpu->pc = pc; + s->c_cpu->npc = pc + 4; +#elif defined (TARGET_ARM) + s->c_cpu->regs[15] = pc; +#elif defined (TARGET_SH4) + s->c_cpu->pc = pc; +#elif defined (TARGET_MIPS) + s->c_cpu->active_tc.PC = pc; +#elif defined (TARGET_CRIS) + s->c_cpu->pc = pc; +#elif defined (TARGET_ALPHA) + s->c_cpu->pc = pc; +#endif +} + static int gdb_handle_packet(GDBState *s, const char *line_buf) { CPUState *env; @@ -1536,24 +1565,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) case 'c': if (*p != '\0') { addr = strtoull(p, (char **)&p, 16); -#if defined(TARGET_I386) - s->c_cpu->eip = addr; -#elif defined (TARGET_PPC) - s->c_cpu->nip = addr; -#elif defined (TARGET_SPARC) - s->c_cpu->pc = addr; - s->c_cpu->npc = addr + 4; -#elif defined (TARGET_ARM) - s->c_cpu->regs[15] = addr; -#elif defined (TARGET_SH4) - s->c_cpu->pc = addr; -#elif defined (TARGET_MIPS) - s->c_cpu->active_tc.PC = addr; -#elif defined (TARGET_CRIS) - s->c_cpu->pc = addr; -#elif defined (TARGET_ALPHA) - s->c_cpu->pc = addr; -#endif + gdb_set_cpu_pc(s, addr); } s->signal = 0; gdb_continue(s); @@ -1577,24 +1589,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) case 's': if (*p != '\0') { addr = strtoull(p, (char **)&p, 16); -#if defined(TARGET_I386) - s->c_cpu->eip = addr; -#elif defined (TARGET_PPC) - s->c_cpu->nip = addr; -#elif defined (TARGET_SPARC) - s->c_cpu->pc = addr; - s->c_cpu->npc = addr + 4; -#elif defined (TARGET_ARM) - s->c_cpu->regs[15] = addr; -#elif defined (TARGET_SH4) - s->c_cpu->pc = addr; -#elif defined (TARGET_MIPS) - s->c_cpu->active_tc.PC = addr; -#elif defined (TARGET_CRIS) - s->c_cpu->pc = addr; -#elif defined (TARGET_ALPHA) - s->c_cpu->pc = addr; -#endif + gdb_set_cpu_pc(s, addr); } cpu_single_step(s->c_cpu, sstep_flags); gdb_continue(s); @@ -1624,6 +1619,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) } break; case 'g': + 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); @@ -1641,6 +1637,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) len -= reg_size; registers += reg_size; } + cpu_synchronize_state(s->g_cpu, 1); put_packet(s, "OK"); break; case 'm': @@ -1799,6 +1796,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) thread = strtoull(p+16, (char **)&p, 16); for (env = first_cpu; env != NULL; env = env->next_cpu) if (env->cpu_index + 1 == thread) { + cpu_synchronize_state(env, 0); len = snprintf((char *)mem_buf, sizeof(mem_buf), "CPU#%d [%s]", env->cpu_index, env->halted ? "halted " : "running"); @@ -1840,7 +1838,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) if (strncmp(p, "Supported", 9) == 0) { snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH); #ifdef GDB_CORE_XML - strcat(buf, ";qXfer:features:read+"); + pstrcat(buf, sizeof(buf), ";qXfer:features:read+"); #endif put_packet(s, buf); break; @@ -1914,7 +1912,7 @@ static void gdb_vm_state_change(void *opaque, int running, int reason) int ret; if (running || (reason != EXCP_DEBUG && reason != EXCP_INTERRUPT) || - s->state == RS_SYSCALL) + s->state == RS_INACTIVE || s->state == RS_SYSCALL) return; /* disable single step if it was enable */ @@ -2012,7 +2010,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) #ifdef CONFIG_USER_ONLY gdb_handlesig(s->c_cpu, 0); #else - cpu_interrupt(s->c_cpu, CPU_INTERRUPT_EXIT); + cpu_exit(s->c_cpu); #endif } @@ -2206,8 +2204,6 @@ static void gdb_accept(void) setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); s = qemu_mallocz(sizeof(GDBState)); - - memset (s, 0, sizeof (GDBState)); s->c_cpu = first_cpu; s->g_cpu = first_cpu; s->fd = fd; @@ -2328,42 +2324,69 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len) return len; } -int gdbserver_start(const char *port) +#ifndef _WIN32 +static void gdb_sigterm_handler(int signal) +{ + if (vm_running) + vm_stop(EXCP_INTERRUPT); +} +#endif + +int gdbserver_start(const char *device) { GDBState *s; - char gdbstub_port_name[128]; - int port_num; - char *p; - CharDriverState *chr; + char gdbstub_device_name[128]; + CharDriverState *chr = NULL; + CharDriverState *mon_chr; + + if (!device) + return -1; + if (strcmp(device, "none") != 0) { + if (strstart(device, "tcp:", NULL)) { + /* enforce required TCP attributes */ + snprintf(gdbstub_device_name, sizeof(gdbstub_device_name), + "%s,nowait,nodelay,server", device); + device = gdbstub_device_name; + } +#ifndef _WIN32 + else if (strcmp(device, "stdio") == 0) { + struct sigaction act; - if (!port || !*port) - return -1; + memset(&act, 0, sizeof(act)); + act.sa_handler = gdb_sigterm_handler; + sigaction(SIGINT, &act, NULL); + } +#endif + chr = qemu_chr_open("gdb", device, NULL); + if (!chr) + return -1; - port_num = strtol(port, &p, 10); - if (*p == 0) { - /* A numeric value is interpreted as a port number. */ - snprintf(gdbstub_port_name, sizeof(gdbstub_port_name), - "tcp::%d,nowait,nodelay,server", port_num); - port = gdbstub_port_name; + qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive, + gdb_chr_event, NULL); } - chr = qemu_chr_open("gdb", port, NULL); - if (!chr) - return -1; + s = gdbserver_state; + if (!s) { + s = qemu_mallocz(sizeof(GDBState)); + gdbserver_state = s; - s = qemu_mallocz(sizeof(GDBState)); + qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL); + + /* Initialize a monitor terminal for gdb */ + mon_chr = qemu_mallocz(sizeof(*mon_chr)); + mon_chr->chr_write = gdb_monitor_write; + monitor_init(mon_chr, 0); + } else { + if (s->chr) + qemu_chr_close(s->chr); + mon_chr = s->mon_chr; + memset(s, 0, sizeof(GDBState)); + } s->c_cpu = first_cpu; s->g_cpu = first_cpu; s->chr = chr; - gdbserver_state = s; - qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive, - gdb_chr_event, NULL); - qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL); - - /* Initialize a monitor terminal for gdb */ - s->mon_chr = qemu_mallocz(sizeof(*s->mon_chr)); - s->mon_chr->chr_write = gdb_monitor_write; - monitor_init(s->mon_chr, 0); + s->state = chr ? RS_IDLE : RS_INACTIVE; + s->mon_chr = mon_chr; return 0; }