📄 gdbstub.c
字号:
ptr += 4; env->LO = tswapl(*(uint32_t *)ptr); ptr += 4; env->HI = tswapl(*(uint32_t *)ptr); ptr += 4; env->CP0_BadVAddr = tswapl(*(uint32_t *)ptr); ptr += 4; env->CP0_Cause = tswapl(*(uint32_t *)ptr); ptr += 4; env->PC = tswapl(*(uint32_t *)ptr); ptr += 4;}#elif defined (TARGET_SH4)static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf){ uint32_t *ptr = (uint32_t *)mem_buf; int i;#define SAVE(x) *ptr++=tswapl(x) for (i = 0; i < 16; i++) SAVE(env->gregs[i]); SAVE (env->pc); SAVE (env->pr); SAVE (env->gbr); SAVE (env->vbr); SAVE (env->mach); SAVE (env->macl); SAVE (env->sr); SAVE (0); /* TICKS */ SAVE (0); /* STALLS */ SAVE (0); /* CYCLES */ SAVE (0); /* INSTS */ SAVE (0); /* PLR */ return ((uint8_t *)ptr - mem_buf);}static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size){ uint32_t *ptr = (uint32_t *)mem_buf; int i;#define LOAD(x) (x)=*ptr++; for (i = 0; i < 16; i++) LOAD(env->gregs[i]); LOAD (env->pc); LOAD (env->pr); LOAD (env->gbr); LOAD (env->vbr); LOAD (env->mach); LOAD (env->macl); LOAD (env->sr);}#elsestatic int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf){ return 0;}static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size){}#endifstatic int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf){ const char *p; int ch, reg_size, type; char buf[4096]; uint8_t mem_buf[2000]; uint32_t *registers; uint32_t addr, len; #ifdef DEBUG_GDB printf("command='%s'\n", line_buf);#endif p = line_buf; ch = *p++; switch(ch) { case '?': /* TODO: Make this return the correct value for user-mode. */ snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); put_packet(s, buf); break; case 'c': if (*p != '\0') { addr = strtoul(p, (char **)&p, 16);#if defined(TARGET_I386) env->eip = addr;#elif defined (TARGET_PPC) env->nip = addr;#elif defined (TARGET_SPARC) env->pc = addr; env->npc = addr + 4;#elif defined (TARGET_ARM) env->regs[15] = addr;#elif defined (TARGET_SH4) env->pc = addr;#endif }#ifdef CONFIG_USER_ONLY s->running_state = 1;#else vm_start();#endif return RS_IDLE; case 's': if (*p != '\0') { addr = strtoul(p, (char **)&p, 16);#if defined(TARGET_I386) env->eip = addr;#elif defined (TARGET_PPC) env->nip = addr;#elif defined (TARGET_SPARC) env->pc = addr; env->npc = addr + 4;#elif defined (TARGET_ARM) env->regs[15] = addr;#elif defined (TARGET_SH4) env->pc = addr;#endif } cpu_single_step(env, 1);#ifdef CONFIG_USER_ONLY s->running_state = 1;#else vm_start();#endif return RS_IDLE; case 'g': reg_size = cpu_gdb_read_registers(env, mem_buf); memtohex(buf, mem_buf, reg_size); put_packet(s, buf); break; case 'G': registers = (void *)mem_buf; len = strlen(p) / 2; hextomem((uint8_t *)registers, p, len); cpu_gdb_write_registers(env, mem_buf, len); put_packet(s, "OK"); break; case 'm': addr = strtoul(p, (char **)&p, 16); if (*p == ',') p++; len = strtoul(p, NULL, 16); if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) { put_packet (s, "E14"); } else { memtohex(buf, mem_buf, len); put_packet(s, buf); } break; case 'M': addr = strtoul(p, (char **)&p, 16); if (*p == ',') p++; len = strtoul(p, (char **)&p, 16); if (*p == ':') p++; hextomem(mem_buf, p, len); if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0) put_packet(s, "E14"); else put_packet(s, "OK"); break; case 'Z': type = strtoul(p, (char **)&p, 16); if (*p == ',') p++; addr = strtoul(p, (char **)&p, 16); if (*p == ',') p++; len = strtoul(p, (char **)&p, 16); if (type == 0 || type == 1) { if (cpu_breakpoint_insert(env, addr) < 0) goto breakpoint_error; put_packet(s, "OK"); } else { breakpoint_error: put_packet(s, "E22"); } break; case 'z': type = strtoul(p, (char **)&p, 16); if (*p == ',') p++; addr = strtoul(p, (char **)&p, 16); if (*p == ',') p++; len = strtoul(p, (char **)&p, 16); if (type == 0 || type == 1) { cpu_breakpoint_remove(env, addr); put_packet(s, "OK"); } else { goto breakpoint_error; } break; default: // unknown_command: /* put empty packet */ buf[0] = '\0'; put_packet(s, buf); break; } return RS_IDLE;}extern void tb_flush(CPUState *env);#ifndef CONFIG_USER_ONLYstatic 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(s->env, 0); if (reason == EXCP_DEBUG) { tb_flush(s->env); ret = SIGTRAP; } else if (reason == EXCP_INTERRUPT) { ret = SIGINT; } else { ret = 0; } snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(s, buf);}#endifstatic void gdb_read_byte(GDBState *s, int ch){ CPUState *env = s->env; int i, csum; char reply[1];#ifndef CONFIG_USER_ONLY if (vm_running) { /* when the CPU is running, we cannot do anything except stop it when receiving a char */ vm_stop(EXCP_INTERRUPT); } else #endif { 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, env, s->line_buf); } break; } }}#ifdef CONFIG_USER_ONLYintgdb_handlesig (CPUState *env, int sig){ GDBState *s; char buf[256]; int n; if (gdbserver_fd < 0) return sig; s = &gdbserver_state; /* disable single step if it was enabled */ cpu_single_step(env, 0); tb_flush(env); if (sig != 0) { snprintf(buf, sizeof(buf), "S%02x", sig); put_packet(s, buf); } sig = 0; s->state = RS_IDLE; s->running_state = 0; while (s->running_state == 0) { n = read (s->fd, buf, 256); if (n > 0) { int 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 connection before continuing. */ return sig; } } return sig;}/* Tell the remote gdb that the process has exited. */void gdb_exit(CPUState *env, int code){ GDBState *s; char buf[4]; if (gdbserver_fd < 0) return; s = &gdbserver_state; snprintf(buf, sizeof(buf), "W%02x", code); put_packet(s, buf);}#elsestatic void gdb_read(void *opaque){ GDBState *s = opaque; int i, size; uint8_t buf[4096]; size = read(s->fd, buf, sizeof(buf)); 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); vm_start(); } else { for(i = 0; i < size; i++) gdb_read_byte(s, buf[i]); }}#endifstatic void gdb_accept(void *opaque){ 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, IPPROTO_TCP, TCP_NODELAY, &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; fcntl(fd, F_SETFL, O_NONBLOCK);#ifndef CONFIG_USER_ONLY /* 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){ 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; }#ifndef CONFIG_USER_ONLY fcntl(fd, F_SETFL, O_NONBLOCK);#endif return fd;}int gdbserver_start(int port){ gdbserver_fd = gdbserver_open(port); if (gdbserver_fd < 0) return -1; /* accept connections */#ifdef CONFIG_USER_ONLY gdb_accept (NULL);#else qemu_set_fd_handler(gdbserver_fd, gdb_accept, NULL, NULL);#endif return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -