X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=gdbstub.c;h=bca9b1e2a647005e792a6e23a7b4819671e931f6;hb=7ef4da1c3a753888e2678388150f1b846b025168;hp=5dc93c45706ca8470425a1b8cc820475ca166c11;hpb=1fddef4b1ba3bf14d36472475019a4a6acd4d976;p=qemu diff --git a/gdbstub.c b/gdbstub.c index 5dc93c4..bca9b1e 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -1,7 +1,7 @@ /* * gdb server stub * - * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003-2005 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -42,17 +42,20 @@ enum RSState { RS_GETLINE, RS_CHKSUM1, RS_CHKSUM2, - RS_CONTINUE }; /* XXX: This is not thread safe. Do we care? */ static int gdbserver_fd = -1; typedef struct GDBState { - enum RSState state; + CPUState *env; /* current CPU */ + enum RSState state; /* parsing state */ int fd; char line_buf[4096]; int line_buf_index; int line_csum; +#ifdef CONFIG_USER_ONLY + int running_state; +#endif } GDBState; #ifdef CONFIG_USER_ONLY @@ -251,14 +254,14 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) } /* nip, msr, ccr, lnk, ctr, xer, mq */ registers[96] = tswapl(env->nip); - registers[97] = tswapl(_load_msr(env)); + registers[97] = tswapl(do_load_msr(env)); tmp = 0; for (i = 0; i < 8; i++) tmp |= env->crf[i] << (32 - ((i + 1) * 4)); registers[98] = tswapl(tmp); registers[99] = tswapl(env->lr); registers[100] = tswapl(env->ctr); - registers[101] = tswapl(_load_xer(env)); + registers[101] = tswapl(do_load_xer(env)); registers[102] = 0; return 103 * 4; @@ -280,22 +283,22 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } /* nip, msr, ccr, lnk, ctr, xer, mq */ env->nip = tswapl(registers[96]); - _store_msr(env, tswapl(registers[97])); + do_store_msr(env, tswapl(registers[97])); registers[98] = tswapl(registers[98]); for (i = 0; i < 8; i++) env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF; env->lr = tswapl(registers[99]); env->ctr = tswapl(registers[100]); - _store_xer(env, tswapl(registers[101])); + do_store_xer(env, tswapl(registers[101])); } #elif defined (TARGET_SPARC) static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { - uint32_t *registers = (uint32_t *)mem_buf, tmp; + target_ulong *registers = (target_ulong *)mem_buf; int i; /* fill in g0..g7 */ - for(i = 0; i < 7; i++) { + for(i = 0; i < 8; i++) { registers[i] = tswapl(env->gregs[i]); } /* fill in register window */ @@ -306,10 +309,15 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) for (i = 0; i < 32; i++) { registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i])); } +#ifndef TARGET_SPARC64 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ registers[64] = tswapl(env->y); - tmp = GET_PSR(env); - registers[65] = tswapl(tmp); + { + target_ulong tmp; + + tmp = GET_PSR(env); + registers[65] = tswapl(tmp); + } registers[66] = tswapl(env->wim); registers[67] = tswapl(env->tbr); registers[68] = tswapl(env->pc); @@ -317,13 +325,24 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) registers[70] = tswapl(env->fsr); registers[71] = 0; /* csr */ registers[72] = 0; - - return 73 * 4; + return 73 * sizeof(target_ulong); +#else + for (i = 0; i < 32; i += 2) { + registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i])); + } + registers[81] = tswapl(env->pc); + registers[82] = tswapl(env->npc); + registers[83] = tswapl(env->tstate[env->tl]); + registers[84] = tswapl(env->fsr); + registers[85] = tswapl(env->fprs); + registers[86] = tswapl(env->y); + return 87 * sizeof(target_ulong); +#endif } static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) { - uint32_t *registers = (uint32_t *)mem_buf; + target_ulong *registers = (target_ulong *)mem_buf; int i; /* fill in g0..g7 */ @@ -332,12 +351,13 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } /* fill in register window */ for(i = 0; i < 24; i++) { - env->regwptr[i] = tswapl(registers[i]); + env->regwptr[i] = tswapl(registers[i + 8]); } /* fill in fprs */ for (i = 0; i < 32; i++) { *((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]); } +#ifndef TARGET_SPARC64 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ env->y = tswapl(registers[64]); PUT_PSR(env, tswapl(registers[65])); @@ -346,6 +366,20 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->pc = tswapl(registers[68]); env->npc = tswapl(registers[69]); env->fsr = tswapl(registers[70]); +#else + for (i = 0; i < 32; i += 2) { + uint64_t tmp; + tmp = tswapl(registers[i/2 + 64]) << 32; + tmp |= tswapl(registers[i/2 + 64 + 1]); + *((uint64_t *)&env->fpr[i]) = tmp; + } + env->pc = tswapl(registers[81]); + env->npc = tswapl(registers[82]); + env->tstate[env->tl] = tswapl(registers[83]); + env->fsr = tswapl(registers[84]); + env->fprs = tswapl(registers[85]); + env->y = tswapl(registers[86]); +#endif } #elif defined (TARGET_ARM) static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) @@ -365,7 +399,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) memset (ptr, 0, 8 * 12 + 4); ptr += 8 * 12 + 4; /* CPSR (4 bytes). */ - *(uint32_t *)ptr = tswapl (env->cpsr); + *(uint32_t *)ptr = tswapl (cpsr_read(env)); ptr += 4; return ptr - mem_buf; @@ -385,7 +419,112 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } /* Ignore FPA regs and scr. */ ptr += 8 * 12 + 4; - env->cpsr = tswapl(*(uint32_t *)ptr); + cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff); +} +#elif defined (TARGET_MIPS) +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + int i; + uint8_t *ptr; + + ptr = mem_buf; + for (i = 0; i < 32; i++) + { + *(uint32_t *)ptr = tswapl(env->gpr[i]); + ptr += 4; + } + + *(uint32_t *)ptr = tswapl(env->CP0_Status); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->LO); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->HI); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->CP0_BadVAddr); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->CP0_Cause); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->PC); + ptr += 4; + + /* 32 FP registers, fsr, fir, fp. Not yet implemented. */ + + return ptr - mem_buf; +} + +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + int i; + uint8_t *ptr; + + ptr = mem_buf; + for (i = 0; i < 32; i++) + { + env->gpr[i] = tswapl(*(uint32_t *)ptr); + ptr += 4; + } + + env->CP0_Status = tswapl(*(uint32_t *)ptr); + 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); } #else static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) @@ -429,9 +568,18 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #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 } - return RS_CONTINUE; +#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); @@ -442,10 +590,19 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #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); - return RS_CONTINUE; +#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); @@ -463,10 +620,12 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) if (*p == ',') p++; len = strtoul(p, NULL, 16); - if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) - memset(mem_buf, 0, len); - memtohex(buf, mem_buf, len); - put_packet(s, buf); + 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); @@ -477,7 +636,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) p++; hextomem(mem_buf, p, len); if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0) - put_packet(s, "ENN"); + put_packet(s, "E14"); else put_packet(s, "OK"); break; @@ -495,7 +654,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) put_packet(s, "OK"); } else { breakpoint_error: - put_packet(s, "ENN"); + put_packet(s, "E22"); } break; case 'z': @@ -533,21 +692,24 @@ static void gdb_vm_stopped(void *opaque, int reason) int ret; /* disable single step if it was enable */ - cpu_single_step(cpu_single_env, 0); + cpu_single_step(s->env, 0); if (reason == EXCP_DEBUG) { - tb_flush(cpu_single_env); + tb_flush(s->env); ret = SIGTRAP; - } - else + } else if (reason == EXCP_INTERRUPT) { + ret = SIGINT; + } else { ret = 0; + } snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(s, buf); } #endif -static void gdb_read_byte(GDBState *s, CPUState *env, int ch) +static void gdb_read_byte(GDBState *s, int ch) { + CPUState *env = s->env; int i, csum; char reply[1]; @@ -556,8 +718,9 @@ static void gdb_read_byte(GDBState *s, CPUState *env, int ch) /* when the CPU is running, we cannot do anything except stop it when receiving a char */ vm_stop(EXCP_INTERRUPT); - } else { + } else #endif + { switch(s->state) { case RS_IDLE: if (ch == '$') { @@ -595,16 +758,8 @@ static void gdb_read_byte(GDBState *s, CPUState *env, int ch) s->state = gdb_handle_packet(s, env, s->line_buf); } break; - case RS_CONTINUE: -#ifndef CONFIG_USER_ONLY - vm_start(); - s->state = RS_IDLE; -#endif - break; } -#ifndef CONFIG_USER_ONLY } -#endif } #ifdef CONFIG_USER_ONLY @@ -630,18 +785,17 @@ gdb_handlesig (CPUState *env, int sig) put_packet(s, buf); } - /* TODO: How do we terminate this loop? */ sig = 0; s->state = RS_IDLE; - while (s->state != RS_CONTINUE) - { + 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, env, buf[i]); + gdb_read_byte (s, buf[i]); } else if (n == 0 || errno != EAGAIN) { @@ -649,34 +803,50 @@ gdb_handlesig (CPUState *env, int sig) connection before continuing. */ return sig; } - } + } return sig; } -#else -static int gdb_can_read(void *opaque) + +/* Tell the remote gdb that the process has exited. */ +void gdb_exit(CPUState *env, int code) { - return 256; + 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_read(void *opaque, const uint8_t *buf, int size) +#else +static void gdb_read(void *opaque) { GDBState *s = opaque; - int i; + 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_del_fd_read_handler(s->fd); + 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, cpu_single_env, buf[i]); + gdb_read_byte(s, buf[i]); } } #endif -static void gdb_accept(void *opaque, const uint8_t *buf, int size) +static void gdb_accept(void *opaque) { GDBState *s; struct sockaddr_in sockaddr; @@ -708,6 +878,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) return; } #endif + s->env = first_cpu; /* XXX: allow to change CPU */ s->fd = fd; fcntl(fd, F_SETFL, O_NONBLOCK); @@ -717,7 +888,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) vm_stop(EXCP_INTERRUPT); /* start handling I/O */ - qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s); + 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 @@ -764,9 +935,9 @@ int gdbserver_start(int port) return -1; /* accept connections */ #ifdef CONFIG_USER_ONLY - gdb_accept (NULL, NULL, 0); + gdb_accept (NULL); #else - qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL); + qemu_set_fd_handler(gdbserver_fd, gdb_accept, NULL, NULL); #endif return 0; }