Loading Makefile.target +2 −2 Original line number Diff line number Diff line Loading @@ -166,7 +166,7 @@ SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a # cpu emulator library LIBOBJS=exec.o translate-all.o cpu-exec.o gdbstub.o \ LIBOBJS=exec.o translate-all.o cpu-exec.o\ translate.o op.o ifeq ($(TARGET_ARCH), i386) Loading Loading @@ -219,7 +219,7 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o block.o monitor.o \ VL_OBJS=vl.o osdep.o block.o monitor.o gdbstub.o \ ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o ifeq ($(TARGET_ARCH), ppc) Loading cpu-all.h +0 −7 Original line number Diff line number Diff line Loading @@ -611,8 +611,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #endif /* SINGLE_CPU_DEFINES */ #define DEFAULT_GDBSTUB_PORT 1234 void cpu_abort(CPUState *env, const char *fmt, ...); extern CPUState *cpu_single_env; extern int code_copy_enabled; Loading Loading @@ -722,9 +720,4 @@ static inline void cpu_physical_memory_set_dirty(target_ulong addr) void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end); /* gdb stub API */ extern int gdbstub_fd; CPUState *cpu_gdbstub_get_env(void *opaque); int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port); #endif /* CPU_ALL_H */ gdbstub.c +289 −230 Original line number Diff line number Diff line Loading @@ -26,70 +26,36 @@ #include <netinet/in.h> #include <netinet/tcp.h> #include <signal.h> #include <fcntl.h> #include "cpu.h" #include "exec-all.h" #include "vl.h" //#define DEBUG_GDB int gdbstub_fd = -1; enum RSState { RS_IDLE, RS_GETLINE, RS_CHKSUM1, RS_CHKSUM2, }; /* return 0 if OK */ static int gdbstub_open(int port) { struct sockaddr_in sockaddr; socklen_t len; int fd, val, ret; static int gdbserver_fd; fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; } typedef struct GDBState { enum RSState state; int fd; char line_buf[4096]; int line_buf_index; int line_csum; } GDBState; /* allow fast reuse */ val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); sockaddr.sin_addr.s_addr = 0; ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); if (ret < 0) { perror("bind"); return -1; } ret = listen(fd, 0); if (ret < 0) { perror("listen"); return -1; } /* now wait for one connection */ for(;;) { len = sizeof(sockaddr); gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len); if (gdbstub_fd < 0 && errno != EINTR) { perror("accept"); return -1; } else if (gdbstub_fd >= 0) { break; } } /* set short latency */ val = 1; setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val)); return 0; } static int get_char(void) static int get_char(GDBState *s) { uint8_t ch; int ret; for(;;) { ret = read(gdbstub_fd, &ch, 1); ret = read(s->fd, &ch, 1); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return -1; Loading @@ -102,12 +68,12 @@ static int get_char(void) return ch; } static void put_buffer(const uint8_t *buf, int len) static void put_buffer(GDBState *s, const uint8_t *buf, int len) { int ret; while (len > 0) { ret = write(gdbstub_fd, buf, len); ret = write(s->fd, buf, len); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return; Loading Loading @@ -161,59 +127,8 @@ static void hextomem(uint8_t *mem, const char *buf, int len) } } /* return -1 if error or EOF */ static int get_packet(char *buf, int buf_size) { int ch, len, csum, csum1; char reply[1]; for(;;) { for(;;) { ch = get_char(); if (ch < 0) return -1; if (ch == '$') break; } len = 0; csum = 0; for(;;) { ch = get_char(); if (ch < 0) return -1; if (ch == '#') break; if (len > buf_size - 1) return -1; buf[len++] = ch; csum += ch; } buf[len] = '\0'; ch = get_char(); if (ch < 0) return -1; csum1 = fromhex(ch) << 4; ch = get_char(); if (ch < 0) return -1; csum1 |= fromhex(ch); if ((csum & 0xff) != csum1) { reply[0] = '-'; put_buffer(reply, 1); } else { reply[0] = '+'; put_buffer(reply, 1); break; } } #ifdef DEBUG_GDB printf("command='%s'\n", buf); #endif return len; } /* return -1 if error, 0 if OK */ static int put_packet(char *buf) static int put_packet(GDBState *s, char *buf) { char buf1[3]; int len, csum, ch, i; Loading @@ -224,9 +139,9 @@ static int put_packet(char *buf) for(;;) { buf1[0] = '$'; put_buffer(buf1, 1); put_buffer(s, buf1, 1); len = strlen(buf); put_buffer(buf, len); put_buffer(s, buf, len); csum = 0; for(i = 0; i < len; i++) { csum += buf[i]; Loading @@ -235,9 +150,9 @@ static int put_packet(char *buf) buf1[1] = tohex((csum >> 4) & 0xf); buf1[2] = tohex((csum) & 0xf); put_buffer(buf1, 3); put_buffer(s, buf1, 3); ch = get_char(); ch = get_char(s); if (ch < 0) return -1; if (ch == '+') Loading Loading @@ -387,51 +302,38 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) #endif /* port = 0 means default port */ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) static int gdb_handle_packet(GDBState *s, const char *line_buf) { CPUState *env; CPUState *env = cpu_single_env; const char *p; int ret, ch, reg_size, type; int ch, reg_size, type; char buf[4096]; uint8_t mem_buf[2000]; uint32_t *registers; uint32_t addr, len; printf("Waiting gdb connection on port %d\n", port); if (gdbstub_open(port) < 0) return -1; printf("Connected\n"); for(;;) { ret = get_packet(buf, sizeof(buf)); if (ret < 0) break; p = buf; #ifdef DEBUG_GDB printf("command='%s'\n", line_buf); #endif p = line_buf; ch = *p++; switch(ch) { case '?': snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); put_packet(buf); put_packet(s, buf); break; case 'c': if (*p != '\0') { addr = strtoul(p, (char **)&p, 16); env = cpu_gdbstub_get_env(opaque); #if defined(TARGET_I386) env->eip = addr; #elif defined (TARGET_PPC) env->nip = addr; #endif } ret = main_loop(opaque); if (ret == EXCP_DEBUG) ret = SIGTRAP; else ret = 0; snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(buf); vm_start(); break; case 's': env = cpu_gdbstub_get_env(opaque); if (*p != '\0') { addr = strtoul(p, (char **)&p, 16); #if defined(TARGET_I386) Loading @@ -441,31 +343,21 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) #endif } cpu_single_step(env, 1); ret = main_loop(opaque); cpu_single_step(env, 0); if (ret == EXCP_DEBUG) ret = SIGTRAP; else ret = 0; snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(buf); vm_start(); break; case 'g': env = cpu_gdbstub_get_env(opaque); reg_size = cpu_gdb_read_registers(env, mem_buf); memtohex(buf, mem_buf, reg_size); put_packet(buf); put_packet(s, buf); break; case 'G': env = cpu_gdbstub_get_env(opaque); registers = (void *)mem_buf; len = strlen(p) / 2; hextomem((uint8_t *)registers, p, len); cpu_gdb_write_registers(env, mem_buf, len); put_packet("OK"); put_packet(s, "OK"); break; case 'm': env = cpu_gdbstub_get_env(opaque); addr = strtoul(p, (char **)&p, 16); if (*p == ',') p++; Loading @@ -473,10 +365,9 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) memset(mem_buf, 0, len); memtohex(buf, mem_buf, len); put_packet(buf); put_packet(s, buf); break; case 'M': env = cpu_gdbstub_get_env(opaque); addr = strtoul(p, (char **)&p, 16); if (*p == ',') p++; Loading @@ -485,9 +376,9 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) p++; hextomem(mem_buf, p, len); if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0) put_packet("ENN"); put_packet(s, "ENN"); else put_packet("OK"); put_packet(s, "OK"); break; case 'Z': type = strtoul(p, (char **)&p, 16); Loading @@ -498,13 +389,12 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) p++; len = strtoul(p, (char **)&p, 16); if (type == 0 || type == 1) { env = cpu_gdbstub_get_env(opaque); if (cpu_breakpoint_insert(env, addr) < 0) goto breakpoint_error; put_packet("OK"); put_packet(s, "OK"); } else { breakpoint_error: put_packet("ENN"); put_packet(s, "ENN"); } break; case 'z': Loading @@ -516,9 +406,8 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) p++; len = strtoul(p, (char **)&p, 16); if (type == 0 || type == 1) { env = cpu_gdbstub_get_env(opaque); cpu_breakpoint_remove(env, addr); put_packet("OK"); put_packet(s, "OK"); } else { goto breakpoint_error; } Loading @@ -527,9 +416,179 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) // unknown_command: /* put empty packet */ buf[0] = '\0'; put_packet(buf); put_packet(s, buf); break; } return RS_IDLE; } static void gdb_vm_stopped(void *opaque, int reason) { GDBState *s = opaque; char buf[256]; int ret; /* disable single step if it was enable */ cpu_single_step(cpu_single_env, 0); if (reason == EXCP_DEBUG) ret = SIGTRAP; else ret = 0; snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(s, buf); } static void gdb_read_byte(GDBState *s, int ch) { int i, csum; char reply[1]; if (vm_running) { /* when the CPU is running, we cannot do anything except stop it when receiving a char */ vm_stop(EXCP_INTERRUPT); } else { switch(s->state) { case RS_IDLE: if (ch == '$') { s->line_buf_index = 0; s->state = RS_GETLINE; } break; case RS_GETLINE: if (ch == '#') { s->state = RS_CHKSUM1; } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) { s->state = RS_IDLE; } else { s->line_buf[s->line_buf_index++] = ch; } break; case RS_CHKSUM1: s->line_buf[s->line_buf_index] = '\0'; s->line_csum = fromhex(ch) << 4; s->state = RS_CHKSUM2; break; case RS_CHKSUM2: s->line_csum |= fromhex(ch); csum = 0; for(i = 0; i < s->line_buf_index; i++) { csum += s->line_buf[i]; } if (s->line_csum != (csum & 0xff)) { reply[0] = '-'; put_buffer(s, reply, 1); s->state = RS_IDLE; } else { reply[0] = '+'; put_buffer(s, reply, 1); s->state = gdb_handle_packet(s, s->line_buf); } break; } } } static int gdb_can_read(void *opaque) { return 256; } static void gdb_read(void *opaque, const uint8_t *buf, int size) { GDBState *s = opaque; int i; if (size == 0) { /* end of connection */ qemu_del_vm_stop_handler(gdb_vm_stopped, s); qemu_del_fd_read_handler(s->fd); qemu_free(s); vm_start(); } else { for(i = 0; i < size; i++) gdb_read_byte(s, buf[i]); } } static void gdb_accept(void *opaque, const uint8_t *buf, int size) { GDBState *s; struct sockaddr_in sockaddr; socklen_t len; int val, fd; for(;;) { len = sizeof(sockaddr); fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len); if (fd < 0 && errno != EINTR) { perror("accept"); return; } else if (fd >= 0) { break; } } /* set short latency */ val = 1; setsockopt(fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val)); s = qemu_mallocz(sizeof(GDBState)); if (!s) { close(fd); return; } s->fd = fd; fcntl(fd, F_SETFL, O_NONBLOCK); /* stop the VM */ vm_stop(EXCP_INTERRUPT); /* start handling I/O */ qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s); /* when the VM is stopped, the following callback is called */ qemu_add_vm_stop_handler(gdb_vm_stopped, s); } static int gdbserver_open(int port) { struct sockaddr_in sockaddr; int fd, val, ret; fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; } /* allow fast reuse */ val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); sockaddr.sin_addr.s_addr = 0; ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); if (ret < 0) { perror("bind"); return -1; } ret = listen(fd, 0); if (ret < 0) { perror("listen"); return -1; } fcntl(fd, F_SETFL, O_NONBLOCK); return fd; } int gdbserver_start(int port) { gdbserver_fd = gdbserver_open(port); if (gdbserver_fd < 0) return -1; /* accept connections */ qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL); return 0; } Loading
Makefile.target +2 −2 Original line number Diff line number Diff line Loading @@ -166,7 +166,7 @@ SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a # cpu emulator library LIBOBJS=exec.o translate-all.o cpu-exec.o gdbstub.o \ LIBOBJS=exec.o translate-all.o cpu-exec.o\ translate.o op.o ifeq ($(TARGET_ARCH), i386) Loading Loading @@ -219,7 +219,7 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o block.o monitor.o \ VL_OBJS=vl.o osdep.o block.o monitor.o gdbstub.o \ ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o ifeq ($(TARGET_ARCH), ppc) Loading
cpu-all.h +0 −7 Original line number Diff line number Diff line Loading @@ -611,8 +611,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #endif /* SINGLE_CPU_DEFINES */ #define DEFAULT_GDBSTUB_PORT 1234 void cpu_abort(CPUState *env, const char *fmt, ...); extern CPUState *cpu_single_env; extern int code_copy_enabled; Loading Loading @@ -722,9 +720,4 @@ static inline void cpu_physical_memory_set_dirty(target_ulong addr) void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end); /* gdb stub API */ extern int gdbstub_fd; CPUState *cpu_gdbstub_get_env(void *opaque); int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port); #endif /* CPU_ALL_H */
gdbstub.c +289 −230 Original line number Diff line number Diff line Loading @@ -26,70 +26,36 @@ #include <netinet/in.h> #include <netinet/tcp.h> #include <signal.h> #include <fcntl.h> #include "cpu.h" #include "exec-all.h" #include "vl.h" //#define DEBUG_GDB int gdbstub_fd = -1; enum RSState { RS_IDLE, RS_GETLINE, RS_CHKSUM1, RS_CHKSUM2, }; /* return 0 if OK */ static int gdbstub_open(int port) { struct sockaddr_in sockaddr; socklen_t len; int fd, val, ret; static int gdbserver_fd; fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; } typedef struct GDBState { enum RSState state; int fd; char line_buf[4096]; int line_buf_index; int line_csum; } GDBState; /* allow fast reuse */ val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); sockaddr.sin_addr.s_addr = 0; ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); if (ret < 0) { perror("bind"); return -1; } ret = listen(fd, 0); if (ret < 0) { perror("listen"); return -1; } /* now wait for one connection */ for(;;) { len = sizeof(sockaddr); gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len); if (gdbstub_fd < 0 && errno != EINTR) { perror("accept"); return -1; } else if (gdbstub_fd >= 0) { break; } } /* set short latency */ val = 1; setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val)); return 0; } static int get_char(void) static int get_char(GDBState *s) { uint8_t ch; int ret; for(;;) { ret = read(gdbstub_fd, &ch, 1); ret = read(s->fd, &ch, 1); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return -1; Loading @@ -102,12 +68,12 @@ static int get_char(void) return ch; } static void put_buffer(const uint8_t *buf, int len) static void put_buffer(GDBState *s, const uint8_t *buf, int len) { int ret; while (len > 0) { ret = write(gdbstub_fd, buf, len); ret = write(s->fd, buf, len); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return; Loading Loading @@ -161,59 +127,8 @@ static void hextomem(uint8_t *mem, const char *buf, int len) } } /* return -1 if error or EOF */ static int get_packet(char *buf, int buf_size) { int ch, len, csum, csum1; char reply[1]; for(;;) { for(;;) { ch = get_char(); if (ch < 0) return -1; if (ch == '$') break; } len = 0; csum = 0; for(;;) { ch = get_char(); if (ch < 0) return -1; if (ch == '#') break; if (len > buf_size - 1) return -1; buf[len++] = ch; csum += ch; } buf[len] = '\0'; ch = get_char(); if (ch < 0) return -1; csum1 = fromhex(ch) << 4; ch = get_char(); if (ch < 0) return -1; csum1 |= fromhex(ch); if ((csum & 0xff) != csum1) { reply[0] = '-'; put_buffer(reply, 1); } else { reply[0] = '+'; put_buffer(reply, 1); break; } } #ifdef DEBUG_GDB printf("command='%s'\n", buf); #endif return len; } /* return -1 if error, 0 if OK */ static int put_packet(char *buf) static int put_packet(GDBState *s, char *buf) { char buf1[3]; int len, csum, ch, i; Loading @@ -224,9 +139,9 @@ static int put_packet(char *buf) for(;;) { buf1[0] = '$'; put_buffer(buf1, 1); put_buffer(s, buf1, 1); len = strlen(buf); put_buffer(buf, len); put_buffer(s, buf, len); csum = 0; for(i = 0; i < len; i++) { csum += buf[i]; Loading @@ -235,9 +150,9 @@ static int put_packet(char *buf) buf1[1] = tohex((csum >> 4) & 0xf); buf1[2] = tohex((csum) & 0xf); put_buffer(buf1, 3); put_buffer(s, buf1, 3); ch = get_char(); ch = get_char(s); if (ch < 0) return -1; if (ch == '+') Loading Loading @@ -387,51 +302,38 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) #endif /* port = 0 means default port */ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) static int gdb_handle_packet(GDBState *s, const char *line_buf) { CPUState *env; CPUState *env = cpu_single_env; const char *p; int ret, ch, reg_size, type; int ch, reg_size, type; char buf[4096]; uint8_t mem_buf[2000]; uint32_t *registers; uint32_t addr, len; printf("Waiting gdb connection on port %d\n", port); if (gdbstub_open(port) < 0) return -1; printf("Connected\n"); for(;;) { ret = get_packet(buf, sizeof(buf)); if (ret < 0) break; p = buf; #ifdef DEBUG_GDB printf("command='%s'\n", line_buf); #endif p = line_buf; ch = *p++; switch(ch) { case '?': snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); put_packet(buf); put_packet(s, buf); break; case 'c': if (*p != '\0') { addr = strtoul(p, (char **)&p, 16); env = cpu_gdbstub_get_env(opaque); #if defined(TARGET_I386) env->eip = addr; #elif defined (TARGET_PPC) env->nip = addr; #endif } ret = main_loop(opaque); if (ret == EXCP_DEBUG) ret = SIGTRAP; else ret = 0; snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(buf); vm_start(); break; case 's': env = cpu_gdbstub_get_env(opaque); if (*p != '\0') { addr = strtoul(p, (char **)&p, 16); #if defined(TARGET_I386) Loading @@ -441,31 +343,21 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) #endif } cpu_single_step(env, 1); ret = main_loop(opaque); cpu_single_step(env, 0); if (ret == EXCP_DEBUG) ret = SIGTRAP; else ret = 0; snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(buf); vm_start(); break; case 'g': env = cpu_gdbstub_get_env(opaque); reg_size = cpu_gdb_read_registers(env, mem_buf); memtohex(buf, mem_buf, reg_size); put_packet(buf); put_packet(s, buf); break; case 'G': env = cpu_gdbstub_get_env(opaque); registers = (void *)mem_buf; len = strlen(p) / 2; hextomem((uint8_t *)registers, p, len); cpu_gdb_write_registers(env, mem_buf, len); put_packet("OK"); put_packet(s, "OK"); break; case 'm': env = cpu_gdbstub_get_env(opaque); addr = strtoul(p, (char **)&p, 16); if (*p == ',') p++; Loading @@ -473,10 +365,9 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) memset(mem_buf, 0, len); memtohex(buf, mem_buf, len); put_packet(buf); put_packet(s, buf); break; case 'M': env = cpu_gdbstub_get_env(opaque); addr = strtoul(p, (char **)&p, 16); if (*p == ',') p++; Loading @@ -485,9 +376,9 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) p++; hextomem(mem_buf, p, len); if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0) put_packet("ENN"); put_packet(s, "ENN"); else put_packet("OK"); put_packet(s, "OK"); break; case 'Z': type = strtoul(p, (char **)&p, 16); Loading @@ -498,13 +389,12 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) p++; len = strtoul(p, (char **)&p, 16); if (type == 0 || type == 1) { env = cpu_gdbstub_get_env(opaque); if (cpu_breakpoint_insert(env, addr) < 0) goto breakpoint_error; put_packet("OK"); put_packet(s, "OK"); } else { breakpoint_error: put_packet("ENN"); put_packet(s, "ENN"); } break; case 'z': Loading @@ -516,9 +406,8 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) p++; len = strtoul(p, (char **)&p, 16); if (type == 0 || type == 1) { env = cpu_gdbstub_get_env(opaque); cpu_breakpoint_remove(env, addr); put_packet("OK"); put_packet(s, "OK"); } else { goto breakpoint_error; } Loading @@ -527,9 +416,179 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) // unknown_command: /* put empty packet */ buf[0] = '\0'; put_packet(buf); put_packet(s, buf); break; } return RS_IDLE; } static void gdb_vm_stopped(void *opaque, int reason) { GDBState *s = opaque; char buf[256]; int ret; /* disable single step if it was enable */ cpu_single_step(cpu_single_env, 0); if (reason == EXCP_DEBUG) ret = SIGTRAP; else ret = 0; snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(s, buf); } static void gdb_read_byte(GDBState *s, int ch) { int i, csum; char reply[1]; if (vm_running) { /* when the CPU is running, we cannot do anything except stop it when receiving a char */ vm_stop(EXCP_INTERRUPT); } else { switch(s->state) { case RS_IDLE: if (ch == '$') { s->line_buf_index = 0; s->state = RS_GETLINE; } break; case RS_GETLINE: if (ch == '#') { s->state = RS_CHKSUM1; } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) { s->state = RS_IDLE; } else { s->line_buf[s->line_buf_index++] = ch; } break; case RS_CHKSUM1: s->line_buf[s->line_buf_index] = '\0'; s->line_csum = fromhex(ch) << 4; s->state = RS_CHKSUM2; break; case RS_CHKSUM2: s->line_csum |= fromhex(ch); csum = 0; for(i = 0; i < s->line_buf_index; i++) { csum += s->line_buf[i]; } if (s->line_csum != (csum & 0xff)) { reply[0] = '-'; put_buffer(s, reply, 1); s->state = RS_IDLE; } else { reply[0] = '+'; put_buffer(s, reply, 1); s->state = gdb_handle_packet(s, s->line_buf); } break; } } } static int gdb_can_read(void *opaque) { return 256; } static void gdb_read(void *opaque, const uint8_t *buf, int size) { GDBState *s = opaque; int i; if (size == 0) { /* end of connection */ qemu_del_vm_stop_handler(gdb_vm_stopped, s); qemu_del_fd_read_handler(s->fd); qemu_free(s); vm_start(); } else { for(i = 0; i < size; i++) gdb_read_byte(s, buf[i]); } } static void gdb_accept(void *opaque, const uint8_t *buf, int size) { GDBState *s; struct sockaddr_in sockaddr; socklen_t len; int val, fd; for(;;) { len = sizeof(sockaddr); fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len); if (fd < 0 && errno != EINTR) { perror("accept"); return; } else if (fd >= 0) { break; } } /* set short latency */ val = 1; setsockopt(fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val)); s = qemu_mallocz(sizeof(GDBState)); if (!s) { close(fd); return; } s->fd = fd; fcntl(fd, F_SETFL, O_NONBLOCK); /* stop the VM */ vm_stop(EXCP_INTERRUPT); /* start handling I/O */ qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s); /* when the VM is stopped, the following callback is called */ qemu_add_vm_stop_handler(gdb_vm_stopped, s); } static int gdbserver_open(int port) { struct sockaddr_in sockaddr; int fd, val, ret; fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; } /* allow fast reuse */ val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); sockaddr.sin_addr.s_addr = 0; ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); if (ret < 0) { perror("bind"); return -1; } ret = listen(fd, 0); if (ret < 0) { perror("listen"); return -1; } fcntl(fd, F_SETFL, O_NONBLOCK); return fd; } int gdbserver_start(int port) { gdbserver_fd = gdbserver_open(port); if (gdbserver_fd < 0) return -1; /* accept connections */ qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL); return 0; }