📄 gdbstub.c.svn-base
字号:
} } break; 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 = strtoull(p, (char **)&p, 16); if (*p == ',') p++; len = strtoull(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 = strtoull(p, (char **)&p, 16); if (*p == ',') p++; len = strtoull(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 = strtoull(p, (char **)&p, 16); if (*p == ',') p++; len = strtoull(p, (char **)&p, 16); if (type == 0 || type == 1) { if (cpu_breakpoint_insert(env, addr) < 0) goto breakpoint_error; put_packet(s, "OK");#ifndef CONFIG_USER_ONLY } else if (type == 2) { if (cpu_watchpoint_insert(env, addr) < 0) goto breakpoint_error; put_packet(s, "OK");#endif } else { breakpoint_error: put_packet(s, "E22"); } break; case 'z': type = strtoul(p, (char **)&p, 16); if (*p == ',') p++; addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; len = strtoull(p, (char **)&p, 16); if (type == 0 || type == 1) { cpu_breakpoint_remove(env, addr); put_packet(s, "OK");#ifndef CONFIG_USER_ONLY } else if (type == 2) { cpu_watchpoint_remove(env, addr); put_packet(s, "OK");#endif } else { goto breakpoint_error; } break;#ifdef CONFIG_LINUX_USER case 'q': if (strncmp(p, "Offsets", 7) == 0) { TaskState *ts = env->opaque; sprintf(buf, "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx ";Bss=" TARGET_ABI_FMT_lx, ts->info->code_offset, ts->info->data_offset, ts->info->data_offset); put_packet(s, buf); break; } /* Fall through. */#endif 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; if (s->state == RS_SYSCALL) return; /* disable single step if it was enable */ cpu_single_step(s->env, 0); if (reason == EXCP_DEBUG) { if (s->env->watchpoint_hit) { snprintf(buf, sizeof(buf), "T%02xwatch:" TARGET_FMT_lx ";", SIGTRAP, s->env->watchpoint[s->env->watchpoint_hit - 1].vaddr); put_packet(s, buf); s->env->watchpoint_hit = 0; return; } 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);}#endif/* Send a gdb syscall request. This accepts limited printf-style format specifiers, specifically: %x - target_ulong argument printed in hex. %lx - 64-bit argument printed in hex. %s - string pointer (target_ulong) and length (int) pair. */void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...){ va_list va; char buf[256]; char *p; target_ulong addr; uint64_t i64; GDBState *s; s = gdb_syscall_state; if (!s) return; gdb_current_syscall_cb = cb; s->state = RS_SYSCALL;#ifndef CONFIG_USER_ONLY vm_stop(EXCP_DEBUG);#endif s->state = RS_IDLE; va_start(va, fmt); p = buf; *(p++) = 'F'; while (*fmt) { if (*fmt == '%') { fmt++; switch (*fmt++) { case 'x': addr = va_arg(va, target_ulong); p += sprintf(p, TARGET_FMT_lx, addr); break; case 'l': if (*(fmt++) != 'x') goto bad_format; i64 = va_arg(va, uint64_t); p += sprintf(p, "%" PRIx64, i64); break; case 's': addr = va_arg(va, target_ulong); p += sprintf(p, TARGET_FMT_lx "/%x", addr, va_arg(va, int)); break; default: bad_format: fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n", fmt - 1); break; } } else { *(p++) = *(fmt++); } } *p = 0; va_end(va); put_packet(s, buf);#ifdef CONFIG_USER_ONLY gdb_handlesig(s->env, 0);#else cpu_interrupt(s->env, CPU_INTERRUPT_EXIT);#endif}static void gdb_read_byte(GDBState *s, int ch){ CPUState *env = s->env; int i, csum; uint8_t reply;#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, (uint8_t *)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 */ 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 = '-'; put_buffer(s, &reply, 1); s->state = RS_IDLE; } else { reply = '+'; put_buffer(s, &reply, 1); s->state = gdb_handle_packet(s, env, s->line_buf); } break; default: abort(); } }}#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);}static 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, (char *)&val, sizeof(val)); s = &gdbserver_state; memset (s, 0, sizeof (GDBState)); s->env = first_cpu; /* XXX: allow to change CPU */ s->fd = fd; gdb_syscall_state = s; fcntl(fd, F_SETFL, O_NONBLOCK);}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, (char *)&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; } return fd;}int gdbserver_start(int port){ gdbserver_fd = gdbserver_open(port); if (gdbserver_fd < 0) return -1; /* accept connections */ gdb_accept (NULL); return 0;}#elsestatic int gdb_chr_can_receive(void *opaque){ return 1;}static void gdb_chr_receive(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); gdb_syscall_state = opaque; break; default: break; }}int gdbserver_start(const char *port){ GDBState *s; char gdbstub_port_name[128]; int port_num; char *p; CharDriverState *chr; if (!port || !*port) 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; } chr = qemu_chr_open(port); 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_receive, gdb_chr_receive, gdb_chr_event, s); qemu_add_vm_stop_handler(gdb_vm_stopped, s); return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -