diff options
-rw-r--r-- | gdbstub.c | 163 | ||||
-rw-r--r-- | gdbstub.h | 4 | ||||
-rw-r--r-- | qemu-doc.texi | 3 | ||||
-rw-r--r-- | vl.c | 23 | ||||
-rw-r--r-- | vl.h | 3 |
5 files changed, 118 insertions, 78 deletions
@@ -53,25 +53,28 @@ enum RSState { RS_CHKSUM1, RS_CHKSUM2, }; -/* XXX: This is not thread safe. Do we care? */ -static int gdbserver_fd = -1; - typedef struct GDBState { CPUState *env; /* current CPU */ enum RSState state; /* parsing state */ - int fd; char line_buf[4096]; int line_buf_index; int line_csum; + char last_packet[4100]; + int last_packet_len; #ifdef CONFIG_USER_ONLY + int fd; int running_state; +#else + CharDriverState *chr; #endif } GDBState; #ifdef CONFIG_USER_ONLY +/* XXX: This is not thread safe. Do we care? */ +static int gdbserver_fd = -1; + /* XXX: remove this hack. */ static GDBState gdbserver_state; -#endif static int get_char(GDBState *s) { @@ -91,9 +94,11 @@ static int get_char(GDBState *s) } return ch; } +#endif static void put_buffer(GDBState *s, const uint8_t *buf, int len) { +#ifdef CONFIG_USER_ONLY int ret; while (len > 0) { @@ -106,6 +111,9 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len) len -= ret; } } +#else + qemu_chr_write(s->chr, buf, len); +#endif } static inline int fromhex(int v) @@ -154,33 +162,39 @@ static void hextomem(uint8_t *mem, const char *buf, int len) /* return -1 if error, 0 if OK */ static int put_packet(GDBState *s, char *buf) { - char buf1[3]; - int len, csum, ch, i; + int len, csum, i; + char *p; #ifdef DEBUG_GDB printf("reply='%s'\n", buf); #endif for(;;) { - buf1[0] = '$'; - put_buffer(s, buf1, 1); + p = s->last_packet; + *(p++) = '$'; len = strlen(buf); - put_buffer(s, buf, len); + memcpy(p, buf, len); + p += len; csum = 0; for(i = 0; i < len; i++) { csum += buf[i]; } - buf1[0] = '#'; - buf1[1] = tohex((csum >> 4) & 0xf); - buf1[2] = tohex((csum) & 0xf); + *(p++) = '#'; + *(p++) = tohex((csum >> 4) & 0xf); + *(p++) = tohex((csum) & 0xf); - put_buffer(s, buf1, 3); + s->last_packet_len = p - s->last_packet; + put_buffer(s, s->last_packet, s->last_packet_len); - ch = get_char(s); - if (ch < 0) +#ifdef CONFIG_USER_ONLY + i = get_char(s); + if (i < 0) return -1; - if (ch == '+') + if (i == '+') break; +#else + break; +#endif } return 0; } @@ -864,6 +878,26 @@ static void gdb_read_byte(GDBState *s, int ch) char reply[1]; #ifndef CONFIG_USER_ONLY + if (s->last_packet_len) { + /* Waiting for a response to the last packet. If we see the start + of a new command then abandon the previous response. */ + if (ch == '-') { +#ifdef DEBUG_GDB + printf("Got NACK, retransmitting\n"); +#endif + put_buffer(s, s->last_packet, s->last_packet_len); + } +#ifdef DEBUG_GDB + else if (ch == '+') + printf("Got ACK\n"); + else + printf("Got '%c' when expecting ACK/NACK\n", ch); +#endif + if (ch == '+' || ch == '$') + s->last_packet_len = 0; + if (ch != '$') + return; + } if (vm_running) { /* when the CPU is running, we cannot do anything except stop it when receiving a char */ @@ -972,30 +1006,6 @@ void gdb_exit(CPUState *env, int code) put_packet(s, buf); } -#else -static void gdb_read(void *opaque) -{ - GDBState *s = opaque; - int i, size; - uint8_t buf[4096]; - - size = recv(s->fd, buf, sizeof(buf), 0); - if (size < 0) - return; - if (size == 0) { - /* end of connection */ - qemu_del_vm_stop_handler(gdb_vm_stopped, s); - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); - qemu_free(s); - if (autostart) - vm_start(); - } else { - for(i = 0; i < size; i++) - gdb_read_byte(s, buf[i]); - } -} - -#endif static void gdb_accept(void *opaque) { @@ -1019,32 +1029,12 @@ static void gdb_accept(void *opaque) val = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); -#ifdef CONFIG_USER_ONLY s = &gdbserver_state; memset (s, 0, sizeof (GDBState)); -#else - s = qemu_mallocz(sizeof(GDBState)); - if (!s) { - close(fd); - return; - } -#endif s->env = first_cpu; /* XXX: allow to change CPU */ s->fd = fd; -#ifdef CONFIG_USER_ONLY fcntl(fd, F_SETFL, O_NONBLOCK); -#else - socket_set_nonblock(fd); - - /* stop the VM */ - vm_stop(EXCP_INTERRUPT); - - /* start handling I/O */ - qemu_set_fd_handler(s->fd, gdb_read, NULL, s); - /* when the VM is stopped, the following callback is called */ - qemu_add_vm_stop_handler(gdb_vm_stopped, s); -#endif } static int gdbserver_open(int port) @@ -1075,9 +1065,6 @@ static int gdbserver_open(int port) perror("listen"); return -1; } -#ifndef CONFIG_USER_ONLY - socket_set_nonblock(fd); -#endif return fd; } @@ -1087,10 +1074,52 @@ int gdbserver_start(int port) if (gdbserver_fd < 0) return -1; /* accept connections */ -#ifdef CONFIG_USER_ONLY gdb_accept (NULL); + return 0; +} #else - qemu_set_fd_handler(gdbserver_fd, gdb_accept, NULL, NULL); -#endif +static int gdb_chr_can_recieve(void *opaque) +{ + return 1; +} + +static void gdb_chr_recieve(void *opaque, const uint8_t *buf, int size) +{ + GDBState *s = opaque; + int i; + + for (i = 0; i < size; i++) { + gdb_read_byte(s, buf[i]); + } +} + +static void gdb_chr_event(void *opaque, int event) +{ + switch (event) { + case CHR_EVENT_RESET: + vm_stop(EXCP_INTERRUPT); + break; + default: + break; + } +} + +int gdbserver_start(CharDriverState *chr) +{ + GDBState *s; + + if (!chr) + return -1; + + s = qemu_mallocz(sizeof(GDBState)); + if (!s) { + return -1; + } + s->env = first_cpu; /* XXX: allow to change CPU */ + s->chr = chr; + qemu_chr_add_handlers(chr, gdb_chr_can_recieve, gdb_chr_recieve, + gdb_chr_event, s); + qemu_add_vm_stop_handler(gdb_vm_stopped, s); return 0; } +#endif @@ -6,7 +6,9 @@ #ifdef CONFIG_USER_ONLY int gdb_handlesig (CPUState *, int); void gdb_exit(CPUState *, int); -#endif int gdbserver_start(int); +#else +int gdbserver_start(CharDriverState *chr); +#endif #endif diff --git a/qemu-doc.texi b/qemu-doc.texi index 4b9c5f4cd4..0874f4c045 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -631,7 +631,8 @@ non graphical mode. @item -s Wait gdb connection to port 1234 (@pxref{gdb_usage}). @item -p port -Change gdb connection port. +Change gdb connection port. @var{port} can be either a decimal number +to specify a TCP port, or a host device (same devices as the serial port). @item -S Do not start CPU at startup (you must type 'c' in the monitor). @item -d @@ -6496,7 +6496,8 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type) int main(int argc, char **argv) { #ifdef CONFIG_GDBSTUB - int use_gdbstub, gdbstub_port; + int use_gdbstub; + char gdbstub_port_name[128]; #endif int i, cdrom_index; int snapshot, linux_boot; @@ -6564,7 +6565,7 @@ int main(int argc, char **argv) bios_size = BIOS_SIZE; #ifdef CONFIG_GDBSTUB use_gdbstub = 0; - gdbstub_port = DEFAULT_GDBSTUB_PORT; + sprintf(gdbstub_port_name, "%d", DEFAULT_GDBSTUB_PORT); #endif snapshot = 0; nographic = 0; @@ -6808,7 +6809,7 @@ int main(int argc, char **argv) use_gdbstub = 1; break; case QEMU_OPTION_p: - gdbstub_port = atoi(optarg); + pstrcpy(gdbstub_port_name, sizeof(gdbstub_port_name), optarg); break; #endif case QEMU_OPTION_L: @@ -7216,13 +7217,19 @@ int main(int argc, char **argv) #ifdef CONFIG_GDBSTUB if (use_gdbstub) { - if (gdbserver_start(gdbstub_port) < 0) { - fprintf(stderr, "Could not open gdbserver socket on port %d\n", - gdbstub_port); + CharDriverState *chr; + int port; + + port = atoi(gdbstub_port_name); + if (port != 0) + sprintf(gdbstub_port_name, "tcp::%d,nowait,nodelay,server", port); + chr = qemu_chr_open(gdbstub_port_name); + if (!chr) { + fprintf(stderr, "qemu: could not open gdbstub device '%s'\n", + gdbstub_port_name); exit(1); - } else { - printf("Waiting gdb connection on port %d\n", gdbstub_port); } + gdbserver_start(chr); } else #endif if (loadvm) @@ -84,7 +84,6 @@ static inline char *realpath(const char *path, char *resolved_path) #include "audio/audio.h" #include "cpu.h" -#include "gdbstub.h" #endif /* !defined(QEMU_TOOL) */ @@ -1364,6 +1363,8 @@ pflash_t *pflash_register (target_ulong base, ram_addr_t off, uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3); +#include "gdbstub.h" + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ |