X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/2b1319c85c94b7defef2ac2191bb50d773c81db4..c59b97aad76ccb9a33c747cae308cc73db7792d8:/gdbstub.c diff --git a/gdbstub.c b/gdbstub.c index 2e112b252d..239f2e0a0e 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA */ #include "config.h" #include "qemu-common.h" @@ -38,18 +38,219 @@ #define MAX_PACKET_LENGTH 4096 #include "qemu_socket.h" -#ifdef _WIN32 -/* XXX: these constants may be independent of the host ones even for Unix */ -#ifndef SIGTRAP -#define SIGTRAP 5 + + +enum { + GDB_SIGNAL_0 = 0, + GDB_SIGNAL_INT = 2, + GDB_SIGNAL_TRAP = 5, + GDB_SIGNAL_UNKNOWN = 143 +}; + +#ifdef CONFIG_USER_ONLY + +/* Map target signal numbers to GDB protocol signal numbers and vice + * versa. For user emulation's currently supported systems, we can + * assume most signals are defined. + */ + +static int gdb_signal_table[] = { + 0, + TARGET_SIGHUP, + TARGET_SIGINT, + TARGET_SIGQUIT, + TARGET_SIGILL, + TARGET_SIGTRAP, + TARGET_SIGABRT, + -1, /* SIGEMT */ + TARGET_SIGFPE, + TARGET_SIGKILL, + TARGET_SIGBUS, + TARGET_SIGSEGV, + TARGET_SIGSYS, + TARGET_SIGPIPE, + TARGET_SIGALRM, + TARGET_SIGTERM, + TARGET_SIGURG, + TARGET_SIGSTOP, + TARGET_SIGTSTP, + TARGET_SIGCONT, + TARGET_SIGCHLD, + TARGET_SIGTTIN, + TARGET_SIGTTOU, + TARGET_SIGIO, + TARGET_SIGXCPU, + TARGET_SIGXFSZ, + TARGET_SIGVTALRM, + TARGET_SIGPROF, + TARGET_SIGWINCH, + -1, /* SIGLOST */ + TARGET_SIGUSR1, + TARGET_SIGUSR2, +#ifdef TARGET_SIGPWR + TARGET_SIGPWR, +#else + -1, #endif -#ifndef SIGINT -#define SIGINT 2 + -1, /* SIGPOLL */ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, +#ifdef __SIGRTMIN + __SIGRTMIN + 1, + __SIGRTMIN + 2, + __SIGRTMIN + 3, + __SIGRTMIN + 4, + __SIGRTMIN + 5, + __SIGRTMIN + 6, + __SIGRTMIN + 7, + __SIGRTMIN + 8, + __SIGRTMIN + 9, + __SIGRTMIN + 10, + __SIGRTMIN + 11, + __SIGRTMIN + 12, + __SIGRTMIN + 13, + __SIGRTMIN + 14, + __SIGRTMIN + 15, + __SIGRTMIN + 16, + __SIGRTMIN + 17, + __SIGRTMIN + 18, + __SIGRTMIN + 19, + __SIGRTMIN + 20, + __SIGRTMIN + 21, + __SIGRTMIN + 22, + __SIGRTMIN + 23, + __SIGRTMIN + 24, + __SIGRTMIN + 25, + __SIGRTMIN + 26, + __SIGRTMIN + 27, + __SIGRTMIN + 28, + __SIGRTMIN + 29, + __SIGRTMIN + 30, + __SIGRTMIN + 31, + -1, /* SIGCANCEL */ + __SIGRTMIN, + __SIGRTMIN + 32, + __SIGRTMIN + 33, + __SIGRTMIN + 34, + __SIGRTMIN + 35, + __SIGRTMIN + 36, + __SIGRTMIN + 37, + __SIGRTMIN + 38, + __SIGRTMIN + 39, + __SIGRTMIN + 40, + __SIGRTMIN + 41, + __SIGRTMIN + 42, + __SIGRTMIN + 43, + __SIGRTMIN + 44, + __SIGRTMIN + 45, + __SIGRTMIN + 46, + __SIGRTMIN + 47, + __SIGRTMIN + 48, + __SIGRTMIN + 49, + __SIGRTMIN + 50, + __SIGRTMIN + 51, + __SIGRTMIN + 52, + __SIGRTMIN + 53, + __SIGRTMIN + 54, + __SIGRTMIN + 55, + __SIGRTMIN + 56, + __SIGRTMIN + 57, + __SIGRTMIN + 58, + __SIGRTMIN + 59, + __SIGRTMIN + 60, + __SIGRTMIN + 61, + __SIGRTMIN + 62, + __SIGRTMIN + 63, + __SIGRTMIN + 64, + __SIGRTMIN + 65, + __SIGRTMIN + 66, + __SIGRTMIN + 67, + __SIGRTMIN + 68, + __SIGRTMIN + 69, + __SIGRTMIN + 70, + __SIGRTMIN + 71, + __SIGRTMIN + 72, + __SIGRTMIN + 73, + __SIGRTMIN + 74, + __SIGRTMIN + 75, + __SIGRTMIN + 76, + __SIGRTMIN + 77, + __SIGRTMIN + 78, + __SIGRTMIN + 79, + __SIGRTMIN + 80, + __SIGRTMIN + 81, + __SIGRTMIN + 82, + __SIGRTMIN + 83, + __SIGRTMIN + 84, + __SIGRTMIN + 85, + __SIGRTMIN + 86, + __SIGRTMIN + 87, + __SIGRTMIN + 88, + __SIGRTMIN + 89, + __SIGRTMIN + 90, + __SIGRTMIN + 91, + __SIGRTMIN + 92, + __SIGRTMIN + 93, + __SIGRTMIN + 94, + __SIGRTMIN + 95, + -1, /* SIGINFO */ + -1, /* UNKNOWN */ + -1, /* DEFAULT */ + -1, + -1, + -1, + -1, + -1, + -1 #endif +}; #else -#include +/* In system mode we only need SIGINT and SIGTRAP; other signals + are not yet supported. */ + +enum { + TARGET_SIGINT = 2, + TARGET_SIGTRAP = 5 +}; + +static int gdb_signal_table[] = { + -1, + -1, + TARGET_SIGINT, + -1, + -1, + TARGET_SIGTRAP +}; #endif +#ifdef CONFIG_USER_ONLY +static int target_signal_to_gdb (int sig) +{ + int i; + for (i = 0; i < ARRAY_SIZE (gdb_signal_table); i++) + if (gdb_signal_table[i] == sig) + return i; + return GDB_SIGNAL_UNKNOWN; +} +#endif + +static int gdb_signal_to_target (int sig) +{ + if (sig < ARRAY_SIZE (gdb_signal_table)) + return gdb_signal_table[sig]; + else + return -1; +} + //#define DEBUG_GDB typedef struct GDBRegisterState { @@ -419,7 +620,17 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int i) #elif defined (TARGET_PPC) +/* Old gdb always expects FP registers. Newer (xml-aware) gdb only + expects whatever the target description contains. Due to a + historical mishap the FP registers appear in between core integer + regs and PC, MSR, CR, and so forth. We hack round this by giving the + FP regs zero size when talking to a newer gdb. */ #define NUM_CORE_REGS 71 +#if defined (TARGET_PPC64) +#define GDB_CORE_XML "power64-core.xml" +#else +#define GDB_CORE_XML "power-core.xml" +#endif static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) { @@ -428,6 +639,8 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) GET_REGL(env->gpr[n]); } else if (n < 64) { /* fprs */ + if (gdb_has_xml) + return 0; stfq_p(mem_buf, env->fpr[n-32]); return 8; } else { @@ -445,7 +658,12 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) case 67: GET_REGL(env->lr); case 68: GET_REGL(env->ctr); case 69: GET_REGL(env->xer); - case 70: GET_REG32(0); /* fpscr */ + case 70: + { + if (gdb_has_xml) + return 0; + GET_REG32(0); /* fpscr */ + } } } return 0; @@ -459,6 +677,8 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) return sizeof(target_ulong); } else if (n < 64) { /* fprs */ + if (gdb_has_xml) + return 0; env->fpr[n-32] = ldfq_p(mem_buf); return 8; } else { @@ -488,6 +708,8 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) return sizeof(target_ulong); case 70: /* fpscr */ + if (gdb_has_xml) + return 0; return 4; } } @@ -499,7 +721,7 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) #define NUM_CORE_REGS 86 #else -#define NUM_CORE_REGS 73 +#define NUM_CORE_REGS 72 #endif #ifdef TARGET_ABI32 @@ -533,7 +755,7 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) case 69: GET_REGA(env->npc); case 70: GET_REGA(env->fsr); case 71: GET_REGA(0); /* csr */ - case 72: GET_REGA(0); + default: GET_REGA(0); } #else if (n < 64) { @@ -1300,7 +1522,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) switch(ch) { case '?': /* TODO: Make this return the correct value for user-mode. */ - snprintf(buf, sizeof(buf), "T%02xthread:%02x;", SIGTRAP, + snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP, s->c_cpu->cpu_index+1); put_packet(s, buf); /* Remove all the breakpoints when this query is issued, @@ -1331,10 +1553,13 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) s->c_cpu->pc = addr; #endif } + s->signal = 0; gdb_continue(s); return RS_IDLE; case 'C': - s->signal = strtoul(p, (char **)&p, 16); + s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16)); + if (s->signal == -1) + s->signal = 0; gdb_continue(s); return RS_IDLE; case 'k': @@ -1663,7 +1888,7 @@ void gdb_set_stop_cpu(CPUState *env) } #ifndef CONFIG_USER_ONLY -static void gdb_vm_stopped(void *opaque, int reason) +static void gdb_vm_state_change(void *opaque, int running, int reason) { GDBState *s = gdbserver_state; CPUState *env = s->c_cpu; @@ -1671,7 +1896,8 @@ static void gdb_vm_stopped(void *opaque, int reason) const char *type; int ret; - if (s->state == RS_SYSCALL) + if (running || (reason != EXCP_DEBUG && reason != EXCP_INTERRUPT) || + s->state == RS_SYSCALL) return; /* disable single step if it was enable */ @@ -1692,18 +1918,16 @@ static void gdb_vm_stopped(void *opaque, int reason) } snprintf(buf, sizeof(buf), "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";", - SIGTRAP, env->cpu_index+1, type, + GDB_SIGNAL_TRAP, env->cpu_index+1, type, env->watchpoint_hit->vaddr); put_packet(s, buf); env->watchpoint_hit = NULL; return; } tb_flush(env); - ret = SIGTRAP; - } else if (reason == EXCP_INTERRUPT) { - ret = SIGINT; + ret = GDB_SIGNAL_TRAP; } else { - ret = 0; + ret = GDB_SIGNAL_INT; } snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, env->cpu_index+1); put_packet(s, buf); @@ -1852,6 +2076,19 @@ static void gdb_read_byte(GDBState *s, int ch) } #ifdef CONFIG_USER_ONLY +int +gdb_queuesig (void) +{ + GDBState *s; + + s = gdbserver_state; + + if (gdbserver_fd < 0 || s->fd < 0) + return 0; + else + return 1; +} + int gdb_handlesig (CPUState *env, int sig) { @@ -1869,7 +2106,7 @@ gdb_handlesig (CPUState *env, int sig) if (sig != 0) { - snprintf(buf, sizeof(buf), "S%02x", sig); + snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb (sig)); put_packet(s, buf); } /* put_packet() might have detected that the peer terminated the @@ -1915,6 +2152,19 @@ void gdb_exit(CPUState *env, int code) put_packet(s, buf); } +/* Tell the remote gdb that the process has exited due to SIG. */ +void gdb_signalled(CPUState *env, int sig) +{ + GDBState *s; + char buf[4]; + + s = gdbserver_state; + if (gdbserver_fd < 0 || s->fd < 0) + return; + + snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig)); + put_packet(s, buf); +} static void gdb_accept(void) { @@ -1939,11 +2189,6 @@ static void gdb_accept(void) setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); s = qemu_mallocz(sizeof(GDBState)); - if (!s) { - errno = ENOMEM; - perror("accept"); - return; - } memset (s, 0, sizeof (GDBState)); s->c_cpu = first_cpu; @@ -2001,7 +2246,7 @@ int gdbserver_start(int port) void gdbserver_fork(CPUState *env) { GDBState *s = gdbserver_state; - if (s->fd < 0) + if (gdbserver_fd < 0 || s->fd < 0) return; close(s->fd); s->fd = -1; @@ -2056,21 +2301,18 @@ int gdbserver_start(const char *port) port = gdbstub_port_name; } - chr = qemu_chr_open("gdb", port); + chr = qemu_chr_open("gdb", port, NULL); if (!chr) return -1; s = qemu_mallocz(sizeof(GDBState)); - if (!s) { - return -1; - } s->c_cpu = first_cpu; s->g_cpu = first_cpu; s->chr = chr; gdbserver_state = s; qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive, gdb_chr_event, NULL); - qemu_add_vm_stop_handler(gdb_vm_stopped, NULL); + qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL); return 0; } #endif