Commit 4046d9130ebf3fb4dbb3fa49dfc7e23df7e59d87
1 parent
f7499989
Use standard character device interface for gdbstub.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2363 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
118 additions
and
78 deletions
gdbstub.c
| @@ -53,25 +53,28 @@ enum RSState { | @@ -53,25 +53,28 @@ enum RSState { | ||
| 53 | RS_CHKSUM1, | 53 | RS_CHKSUM1, |
| 54 | RS_CHKSUM2, | 54 | RS_CHKSUM2, |
| 55 | }; | 55 | }; |
| 56 | -/* XXX: This is not thread safe. Do we care? */ | ||
| 57 | -static int gdbserver_fd = -1; | ||
| 58 | - | ||
| 59 | typedef struct GDBState { | 56 | typedef struct GDBState { |
| 60 | CPUState *env; /* current CPU */ | 57 | CPUState *env; /* current CPU */ |
| 61 | enum RSState state; /* parsing state */ | 58 | enum RSState state; /* parsing state */ |
| 62 | - int fd; | ||
| 63 | char line_buf[4096]; | 59 | char line_buf[4096]; |
| 64 | int line_buf_index; | 60 | int line_buf_index; |
| 65 | int line_csum; | 61 | int line_csum; |
| 62 | + char last_packet[4100]; | ||
| 63 | + int last_packet_len; | ||
| 66 | #ifdef CONFIG_USER_ONLY | 64 | #ifdef CONFIG_USER_ONLY |
| 65 | + int fd; | ||
| 67 | int running_state; | 66 | int running_state; |
| 67 | +#else | ||
| 68 | + CharDriverState *chr; | ||
| 68 | #endif | 69 | #endif |
| 69 | } GDBState; | 70 | } GDBState; |
| 70 | 71 | ||
| 71 | #ifdef CONFIG_USER_ONLY | 72 | #ifdef CONFIG_USER_ONLY |
| 73 | +/* XXX: This is not thread safe. Do we care? */ | ||
| 74 | +static int gdbserver_fd = -1; | ||
| 75 | + | ||
| 72 | /* XXX: remove this hack. */ | 76 | /* XXX: remove this hack. */ |
| 73 | static GDBState gdbserver_state; | 77 | static GDBState gdbserver_state; |
| 74 | -#endif | ||
| 75 | 78 | ||
| 76 | static int get_char(GDBState *s) | 79 | static int get_char(GDBState *s) |
| 77 | { | 80 | { |
| @@ -91,9 +94,11 @@ static int get_char(GDBState *s) | @@ -91,9 +94,11 @@ static int get_char(GDBState *s) | ||
| 91 | } | 94 | } |
| 92 | return ch; | 95 | return ch; |
| 93 | } | 96 | } |
| 97 | +#endif | ||
| 94 | 98 | ||
| 95 | static void put_buffer(GDBState *s, const uint8_t *buf, int len) | 99 | static void put_buffer(GDBState *s, const uint8_t *buf, int len) |
| 96 | { | 100 | { |
| 101 | +#ifdef CONFIG_USER_ONLY | ||
| 97 | int ret; | 102 | int ret; |
| 98 | 103 | ||
| 99 | while (len > 0) { | 104 | while (len > 0) { |
| @@ -106,6 +111,9 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len) | @@ -106,6 +111,9 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len) | ||
| 106 | len -= ret; | 111 | len -= ret; |
| 107 | } | 112 | } |
| 108 | } | 113 | } |
| 114 | +#else | ||
| 115 | + qemu_chr_write(s->chr, buf, len); | ||
| 116 | +#endif | ||
| 109 | } | 117 | } |
| 110 | 118 | ||
| 111 | static inline int fromhex(int v) | 119 | static inline int fromhex(int v) |
| @@ -154,33 +162,39 @@ static void hextomem(uint8_t *mem, const char *buf, int len) | @@ -154,33 +162,39 @@ static void hextomem(uint8_t *mem, const char *buf, int len) | ||
| 154 | /* return -1 if error, 0 if OK */ | 162 | /* return -1 if error, 0 if OK */ |
| 155 | static int put_packet(GDBState *s, char *buf) | 163 | static int put_packet(GDBState *s, char *buf) |
| 156 | { | 164 | { |
| 157 | - char buf1[3]; | ||
| 158 | - int len, csum, ch, i; | 165 | + int len, csum, i; |
| 166 | + char *p; | ||
| 159 | 167 | ||
| 160 | #ifdef DEBUG_GDB | 168 | #ifdef DEBUG_GDB |
| 161 | printf("reply='%s'\n", buf); | 169 | printf("reply='%s'\n", buf); |
| 162 | #endif | 170 | #endif |
| 163 | 171 | ||
| 164 | for(;;) { | 172 | for(;;) { |
| 165 | - buf1[0] = '$'; | ||
| 166 | - put_buffer(s, buf1, 1); | 173 | + p = s->last_packet; |
| 174 | + *(p++) = '$'; | ||
| 167 | len = strlen(buf); | 175 | len = strlen(buf); |
| 168 | - put_buffer(s, buf, len); | 176 | + memcpy(p, buf, len); |
| 177 | + p += len; | ||
| 169 | csum = 0; | 178 | csum = 0; |
| 170 | for(i = 0; i < len; i++) { | 179 | for(i = 0; i < len; i++) { |
| 171 | csum += buf[i]; | 180 | csum += buf[i]; |
| 172 | } | 181 | } |
| 173 | - buf1[0] = '#'; | ||
| 174 | - buf1[1] = tohex((csum >> 4) & 0xf); | ||
| 175 | - buf1[2] = tohex((csum) & 0xf); | 182 | + *(p++) = '#'; |
| 183 | + *(p++) = tohex((csum >> 4) & 0xf); | ||
| 184 | + *(p++) = tohex((csum) & 0xf); | ||
| 176 | 185 | ||
| 177 | - put_buffer(s, buf1, 3); | 186 | + s->last_packet_len = p - s->last_packet; |
| 187 | + put_buffer(s, s->last_packet, s->last_packet_len); | ||
| 178 | 188 | ||
| 179 | - ch = get_char(s); | ||
| 180 | - if (ch < 0) | 189 | +#ifdef CONFIG_USER_ONLY |
| 190 | + i = get_char(s); | ||
| 191 | + if (i < 0) | ||
| 181 | return -1; | 192 | return -1; |
| 182 | - if (ch == '+') | 193 | + if (i == '+') |
| 183 | break; | 194 | break; |
| 195 | +#else | ||
| 196 | + break; | ||
| 197 | +#endif | ||
| 184 | } | 198 | } |
| 185 | return 0; | 199 | return 0; |
| 186 | } | 200 | } |
| @@ -864,6 +878,26 @@ static void gdb_read_byte(GDBState *s, int ch) | @@ -864,6 +878,26 @@ static void gdb_read_byte(GDBState *s, int ch) | ||
| 864 | char reply[1]; | 878 | char reply[1]; |
| 865 | 879 | ||
| 866 | #ifndef CONFIG_USER_ONLY | 880 | #ifndef CONFIG_USER_ONLY |
| 881 | + if (s->last_packet_len) { | ||
| 882 | + /* Waiting for a response to the last packet. If we see the start | ||
| 883 | + of a new command then abandon the previous response. */ | ||
| 884 | + if (ch == '-') { | ||
| 885 | +#ifdef DEBUG_GDB | ||
| 886 | + printf("Got NACK, retransmitting\n"); | ||
| 887 | +#endif | ||
| 888 | + put_buffer(s, s->last_packet, s->last_packet_len); | ||
| 889 | + } | ||
| 890 | +#ifdef DEBUG_GDB | ||
| 891 | + else if (ch == '+') | ||
| 892 | + printf("Got ACK\n"); | ||
| 893 | + else | ||
| 894 | + printf("Got '%c' when expecting ACK/NACK\n", ch); | ||
| 895 | +#endif | ||
| 896 | + if (ch == '+' || ch == '$') | ||
| 897 | + s->last_packet_len = 0; | ||
| 898 | + if (ch != '$') | ||
| 899 | + return; | ||
| 900 | + } | ||
| 867 | if (vm_running) { | 901 | if (vm_running) { |
| 868 | /* when the CPU is running, we cannot do anything except stop | 902 | /* when the CPU is running, we cannot do anything except stop |
| 869 | it when receiving a char */ | 903 | it when receiving a char */ |
| @@ -972,30 +1006,6 @@ void gdb_exit(CPUState *env, int code) | @@ -972,30 +1006,6 @@ void gdb_exit(CPUState *env, int code) | ||
| 972 | put_packet(s, buf); | 1006 | put_packet(s, buf); |
| 973 | } | 1007 | } |
| 974 | 1008 | ||
| 975 | -#else | ||
| 976 | -static void gdb_read(void *opaque) | ||
| 977 | -{ | ||
| 978 | - GDBState *s = opaque; | ||
| 979 | - int i, size; | ||
| 980 | - uint8_t buf[4096]; | ||
| 981 | - | ||
| 982 | - size = recv(s->fd, buf, sizeof(buf), 0); | ||
| 983 | - if (size < 0) | ||
| 984 | - return; | ||
| 985 | - if (size == 0) { | ||
| 986 | - /* end of connection */ | ||
| 987 | - qemu_del_vm_stop_handler(gdb_vm_stopped, s); | ||
| 988 | - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); | ||
| 989 | - qemu_free(s); | ||
| 990 | - if (autostart) | ||
| 991 | - vm_start(); | ||
| 992 | - } else { | ||
| 993 | - for(i = 0; i < size; i++) | ||
| 994 | - gdb_read_byte(s, buf[i]); | ||
| 995 | - } | ||
| 996 | -} | ||
| 997 | - | ||
| 998 | -#endif | ||
| 999 | 1009 | ||
| 1000 | static void gdb_accept(void *opaque) | 1010 | static void gdb_accept(void *opaque) |
| 1001 | { | 1011 | { |
| @@ -1019,32 +1029,12 @@ static void gdb_accept(void *opaque) | @@ -1019,32 +1029,12 @@ static void gdb_accept(void *opaque) | ||
| 1019 | val = 1; | 1029 | val = 1; |
| 1020 | setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); | 1030 | setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); |
| 1021 | 1031 | ||
| 1022 | -#ifdef CONFIG_USER_ONLY | ||
| 1023 | s = &gdbserver_state; | 1032 | s = &gdbserver_state; |
| 1024 | memset (s, 0, sizeof (GDBState)); | 1033 | memset (s, 0, sizeof (GDBState)); |
| 1025 | -#else | ||
| 1026 | - s = qemu_mallocz(sizeof(GDBState)); | ||
| 1027 | - if (!s) { | ||
| 1028 | - close(fd); | ||
| 1029 | - return; | ||
| 1030 | - } | ||
| 1031 | -#endif | ||
| 1032 | s->env = first_cpu; /* XXX: allow to change CPU */ | 1034 | s->env = first_cpu; /* XXX: allow to change CPU */ |
| 1033 | s->fd = fd; | 1035 | s->fd = fd; |
| 1034 | 1036 | ||
| 1035 | -#ifdef CONFIG_USER_ONLY | ||
| 1036 | fcntl(fd, F_SETFL, O_NONBLOCK); | 1037 | fcntl(fd, F_SETFL, O_NONBLOCK); |
| 1037 | -#else | ||
| 1038 | - socket_set_nonblock(fd); | ||
| 1039 | - | ||
| 1040 | - /* stop the VM */ | ||
| 1041 | - vm_stop(EXCP_INTERRUPT); | ||
| 1042 | - | ||
| 1043 | - /* start handling I/O */ | ||
| 1044 | - qemu_set_fd_handler(s->fd, gdb_read, NULL, s); | ||
| 1045 | - /* when the VM is stopped, the following callback is called */ | ||
| 1046 | - qemu_add_vm_stop_handler(gdb_vm_stopped, s); | ||
| 1047 | -#endif | ||
| 1048 | } | 1038 | } |
| 1049 | 1039 | ||
| 1050 | static int gdbserver_open(int port) | 1040 | static int gdbserver_open(int port) |
| @@ -1075,9 +1065,6 @@ static int gdbserver_open(int port) | @@ -1075,9 +1065,6 @@ static int gdbserver_open(int port) | ||
| 1075 | perror("listen"); | 1065 | perror("listen"); |
| 1076 | return -1; | 1066 | return -1; |
| 1077 | } | 1067 | } |
| 1078 | -#ifndef CONFIG_USER_ONLY | ||
| 1079 | - socket_set_nonblock(fd); | ||
| 1080 | -#endif | ||
| 1081 | return fd; | 1068 | return fd; |
| 1082 | } | 1069 | } |
| 1083 | 1070 | ||
| @@ -1087,10 +1074,52 @@ int gdbserver_start(int port) | @@ -1087,10 +1074,52 @@ int gdbserver_start(int port) | ||
| 1087 | if (gdbserver_fd < 0) | 1074 | if (gdbserver_fd < 0) |
| 1088 | return -1; | 1075 | return -1; |
| 1089 | /* accept connections */ | 1076 | /* accept connections */ |
| 1090 | -#ifdef CONFIG_USER_ONLY | ||
| 1091 | gdb_accept (NULL); | 1077 | gdb_accept (NULL); |
| 1078 | + return 0; | ||
| 1079 | +} | ||
| 1092 | #else | 1080 | #else |
| 1093 | - qemu_set_fd_handler(gdbserver_fd, gdb_accept, NULL, NULL); | ||
| 1094 | -#endif | 1081 | +static int gdb_chr_can_recieve(void *opaque) |
| 1082 | +{ | ||
| 1083 | + return 1; | ||
| 1084 | +} | ||
| 1085 | + | ||
| 1086 | +static void gdb_chr_recieve(void *opaque, const uint8_t *buf, int size) | ||
| 1087 | +{ | ||
| 1088 | + GDBState *s = opaque; | ||
| 1089 | + int i; | ||
| 1090 | + | ||
| 1091 | + for (i = 0; i < size; i++) { | ||
| 1092 | + gdb_read_byte(s, buf[i]); | ||
| 1093 | + } | ||
| 1094 | +} | ||
| 1095 | + | ||
| 1096 | +static void gdb_chr_event(void *opaque, int event) | ||
| 1097 | +{ | ||
| 1098 | + switch (event) { | ||
| 1099 | + case CHR_EVENT_RESET: | ||
| 1100 | + vm_stop(EXCP_INTERRUPT); | ||
| 1101 | + break; | ||
| 1102 | + default: | ||
| 1103 | + break; | ||
| 1104 | + } | ||
| 1105 | +} | ||
| 1106 | + | ||
| 1107 | +int gdbserver_start(CharDriverState *chr) | ||
| 1108 | +{ | ||
| 1109 | + GDBState *s; | ||
| 1110 | + | ||
| 1111 | + if (!chr) | ||
| 1112 | + return -1; | ||
| 1113 | + | ||
| 1114 | + s = qemu_mallocz(sizeof(GDBState)); | ||
| 1115 | + if (!s) { | ||
| 1116 | + return -1; | ||
| 1117 | + } | ||
| 1118 | + s->env = first_cpu; /* XXX: allow to change CPU */ | ||
| 1119 | + s->chr = chr; | ||
| 1120 | + qemu_chr_add_handlers(chr, gdb_chr_can_recieve, gdb_chr_recieve, | ||
| 1121 | + gdb_chr_event, s); | ||
| 1122 | + qemu_add_vm_stop_handler(gdb_vm_stopped, s); | ||
| 1095 | return 0; | 1123 | return 0; |
| 1096 | } | 1124 | } |
| 1125 | +#endif |
gdbstub.h
| @@ -6,7 +6,9 @@ | @@ -6,7 +6,9 @@ | ||
| 6 | #ifdef CONFIG_USER_ONLY | 6 | #ifdef CONFIG_USER_ONLY |
| 7 | int gdb_handlesig (CPUState *, int); | 7 | int gdb_handlesig (CPUState *, int); |
| 8 | void gdb_exit(CPUState *, int); | 8 | void gdb_exit(CPUState *, int); |
| 9 | -#endif | ||
| 10 | int gdbserver_start(int); | 9 | int gdbserver_start(int); |
| 10 | +#else | ||
| 11 | +int gdbserver_start(CharDriverState *chr); | ||
| 12 | +#endif | ||
| 11 | 13 | ||
| 12 | #endif | 14 | #endif |
qemu-doc.texi
| @@ -631,7 +631,8 @@ non graphical mode. | @@ -631,7 +631,8 @@ non graphical mode. | ||
| 631 | @item -s | 631 | @item -s |
| 632 | Wait gdb connection to port 1234 (@pxref{gdb_usage}). | 632 | Wait gdb connection to port 1234 (@pxref{gdb_usage}). |
| 633 | @item -p port | 633 | @item -p port |
| 634 | -Change gdb connection port. | 634 | +Change gdb connection port. @var{port} can be either a decimal number |
| 635 | +to specify a TCP port, or a host device (same devices as the serial port). | ||
| 635 | @item -S | 636 | @item -S |
| 636 | Do not start CPU at startup (you must type 'c' in the monitor). | 637 | Do not start CPU at startup (you must type 'c' in the monitor). |
| 637 | @item -d | 638 | @item -d |
vl.c
| @@ -6496,7 +6496,8 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type) | @@ -6496,7 +6496,8 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type) | ||
| 6496 | int main(int argc, char **argv) | 6496 | int main(int argc, char **argv) |
| 6497 | { | 6497 | { |
| 6498 | #ifdef CONFIG_GDBSTUB | 6498 | #ifdef CONFIG_GDBSTUB |
| 6499 | - int use_gdbstub, gdbstub_port; | 6499 | + int use_gdbstub; |
| 6500 | + char gdbstub_port_name[128]; | ||
| 6500 | #endif | 6501 | #endif |
| 6501 | int i, cdrom_index; | 6502 | int i, cdrom_index; |
| 6502 | int snapshot, linux_boot; | 6503 | int snapshot, linux_boot; |
| @@ -6564,7 +6565,7 @@ int main(int argc, char **argv) | @@ -6564,7 +6565,7 @@ int main(int argc, char **argv) | ||
| 6564 | bios_size = BIOS_SIZE; | 6565 | bios_size = BIOS_SIZE; |
| 6565 | #ifdef CONFIG_GDBSTUB | 6566 | #ifdef CONFIG_GDBSTUB |
| 6566 | use_gdbstub = 0; | 6567 | use_gdbstub = 0; |
| 6567 | - gdbstub_port = DEFAULT_GDBSTUB_PORT; | 6568 | + sprintf(gdbstub_port_name, "%d", DEFAULT_GDBSTUB_PORT); |
| 6568 | #endif | 6569 | #endif |
| 6569 | snapshot = 0; | 6570 | snapshot = 0; |
| 6570 | nographic = 0; | 6571 | nographic = 0; |
| @@ -6808,7 +6809,7 @@ int main(int argc, char **argv) | @@ -6808,7 +6809,7 @@ int main(int argc, char **argv) | ||
| 6808 | use_gdbstub = 1; | 6809 | use_gdbstub = 1; |
| 6809 | break; | 6810 | break; |
| 6810 | case QEMU_OPTION_p: | 6811 | case QEMU_OPTION_p: |
| 6811 | - gdbstub_port = atoi(optarg); | 6812 | + pstrcpy(gdbstub_port_name, sizeof(gdbstub_port_name), optarg); |
| 6812 | break; | 6813 | break; |
| 6813 | #endif | 6814 | #endif |
| 6814 | case QEMU_OPTION_L: | 6815 | case QEMU_OPTION_L: |
| @@ -7216,13 +7217,19 @@ int main(int argc, char **argv) | @@ -7216,13 +7217,19 @@ int main(int argc, char **argv) | ||
| 7216 | 7217 | ||
| 7217 | #ifdef CONFIG_GDBSTUB | 7218 | #ifdef CONFIG_GDBSTUB |
| 7218 | if (use_gdbstub) { | 7219 | if (use_gdbstub) { |
| 7219 | - if (gdbserver_start(gdbstub_port) < 0) { | ||
| 7220 | - fprintf(stderr, "Could not open gdbserver socket on port %d\n", | ||
| 7221 | - gdbstub_port); | 7220 | + CharDriverState *chr; |
| 7221 | + int port; | ||
| 7222 | + | ||
| 7223 | + port = atoi(gdbstub_port_name); | ||
| 7224 | + if (port != 0) | ||
| 7225 | + sprintf(gdbstub_port_name, "tcp::%d,nowait,nodelay,server", port); | ||
| 7226 | + chr = qemu_chr_open(gdbstub_port_name); | ||
| 7227 | + if (!chr) { | ||
| 7228 | + fprintf(stderr, "qemu: could not open gdbstub device '%s'\n", | ||
| 7229 | + gdbstub_port_name); | ||
| 7222 | exit(1); | 7230 | exit(1); |
| 7223 | - } else { | ||
| 7224 | - printf("Waiting gdb connection on port %d\n", gdbstub_port); | ||
| 7225 | } | 7231 | } |
| 7232 | + gdbserver_start(chr); | ||
| 7226 | } else | 7233 | } else |
| 7227 | #endif | 7234 | #endif |
| 7228 | if (loadvm) | 7235 | if (loadvm) |
vl.h
| @@ -84,7 +84,6 @@ static inline char *realpath(const char *path, char *resolved_path) | @@ -84,7 +84,6 @@ static inline char *realpath(const char *path, char *resolved_path) | ||
| 84 | 84 | ||
| 85 | #include "audio/audio.h" | 85 | #include "audio/audio.h" |
| 86 | #include "cpu.h" | 86 | #include "cpu.h" |
| 87 | -#include "gdbstub.h" | ||
| 88 | 87 | ||
| 89 | #endif /* !defined(QEMU_TOOL) */ | 88 | #endif /* !defined(QEMU_TOOL) */ |
| 90 | 89 | ||
| @@ -1364,6 +1363,8 @@ pflash_t *pflash_register (target_ulong base, ram_addr_t off, | @@ -1364,6 +1363,8 @@ pflash_t *pflash_register (target_ulong base, ram_addr_t off, | ||
| 1364 | uint16_t id0, uint16_t id1, | 1363 | uint16_t id0, uint16_t id1, |
| 1365 | uint16_t id2, uint16_t id3); | 1364 | uint16_t id2, uint16_t id3); |
| 1366 | 1365 | ||
| 1366 | +#include "gdbstub.h" | ||
| 1367 | + | ||
| 1367 | #endif /* defined(QEMU_TOOL) */ | 1368 | #endif /* defined(QEMU_TOOL) */ |
| 1368 | 1369 | ||
| 1369 | /* monitor.c */ | 1370 | /* monitor.c */ |