X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=gdbstub.c;h=3f062be9f3b3381ed680b84edbc097a32f3d49a1;hb=b5dc7732e1cc2fb549e48b7b5d664f2c79628e2e;hp=28f9b440c9a8f68bd40fa34275cc63360d6560a5;hpb=3b46e6242767a2c770c0aba0a6595e9511623c92;p=mirror_qemu.git diff --git a/gdbstub.c b/gdbstub.c index 28f9b440c9..3f062be9f3 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -29,7 +29,10 @@ #include "qemu.h" #else -#include "vl.h" +#include "qemu-common.h" +#include "qemu-char.h" +#include "sysemu.h" +#include "gdbstub.h" #endif #include "qemu_socket.h" @@ -60,8 +63,9 @@ typedef struct GDBState { char line_buf[4096]; int line_buf_index; int line_csum; - char last_packet[4100]; + uint8_t last_packet[4100]; int last_packet_len; + int signal; #ifdef CONFIG_USER_ONLY int fd; int running_state; @@ -70,6 +74,11 @@ typedef struct GDBState { #endif } GDBState; +/* By default use no IRQs and no timers while single stepping so as to + * make single stepping like an ICE HW step. + */ +static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER; + #ifdef CONFIG_USER_ONLY /* XXX: This is not thread safe. Do we care? */ static int gdbserver_fd = -1; @@ -85,9 +94,13 @@ static int get_char(GDBState *s) for(;;) { ret = recv(s->fd, &ch, 1, 0); if (ret < 0) { + if (errno == ECONNRESET) + s->fd = -1; if (errno != EINTR && errno != EAGAIN) return -1; } else if (ret == 0) { + close(s->fd); + s->fd = -1; return -1; } else { break; @@ -118,6 +131,16 @@ int use_gdb_syscalls(void) return gdb_syscall_mode == GDB_SYS_ENABLED; } +/* Resume execution. */ +static inline void gdb_continue(GDBState *s) +{ +#ifdef CONFIG_USER_ONLY + s->running_state = 1; +#else + vm_start(); +#endif +} + static void put_buffer(GDBState *s, const uint8_t *buf, int len) { #ifdef CONFIG_USER_ONLY @@ -185,7 +208,7 @@ static void hextomem(uint8_t *mem, const char *buf, int len) static int put_packet(GDBState *s, char *buf) { int len, csum, i; - char *p; + uint8_t *p; #ifdef DEBUG_GDB printf("reply='%s'\n", buf); @@ -206,7 +229,7 @@ static int put_packet(GDBState *s, char *buf) *(p++) = tohex((csum) & 0xf); s->last_packet_len = p - s->last_packet; - put_buffer(s, s->last_packet, s->last_packet_len); + put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len); #ifdef CONFIG_USER_ONLY i = get_char(s); @@ -223,64 +246,172 @@ static int put_packet(GDBState *s, char *buf) #if defined(TARGET_I386) +#ifdef TARGET_X86_64 +static const uint8_t gdb_x86_64_regs[16] = { + R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP, + 8, 9, 10, 11, 12, 13, 14, 15, +}; +#endif + static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { - uint32_t *registers = (uint32_t *)mem_buf; - int i, fpus; - - for(i = 0; i < 8; i++) { - registers[i] = env->regs[i]; + int i, fpus, nb_regs; + uint8_t *p; + + p = mem_buf; +#ifdef TARGET_X86_64 + if (env->hflags & HF_CS64_MASK) { + nb_regs = 16; + for(i = 0; i < 16; i++) { + *(uint64_t *)p = tswap64(env->regs[gdb_x86_64_regs[i]]); + p += 8; + } + *(uint64_t *)p = tswap64(env->eip); + p += 8; + } else +#endif + { + nb_regs = 8; + for(i = 0; i < 8; i++) { + *(uint32_t *)p = tswap32(env->regs[i]); + p += 4; + } + *(uint32_t *)p = tswap32(env->eip); + p += 4; } - registers[8] = env->eip; - registers[9] = env->eflags; - registers[10] = env->segs[R_CS].selector; - registers[11] = env->segs[R_SS].selector; - registers[12] = env->segs[R_DS].selector; - registers[13] = env->segs[R_ES].selector; - registers[14] = env->segs[R_FS].selector; - registers[15] = env->segs[R_GS].selector; - /* XXX: convert floats */ + + *(uint32_t *)p = tswap32(env->eflags); + p += 4; + *(uint32_t *)p = tswap32(env->segs[R_CS].selector); + p += 4; + *(uint32_t *)p = tswap32(env->segs[R_SS].selector); + p += 4; + *(uint32_t *)p = tswap32(env->segs[R_DS].selector); + p += 4; + *(uint32_t *)p = tswap32(env->segs[R_ES].selector); + p += 4; + *(uint32_t *)p = tswap32(env->segs[R_FS].selector); + p += 4; + *(uint32_t *)p = tswap32(env->segs[R_GS].selector); + p += 4; for(i = 0; i < 8; i++) { - memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10); + /* XXX: convert floats */ +#ifdef USE_X86LDOUBLE + memcpy(p, &env->fpregs[i], 10); +#else + memset(p, 0, 10); +#endif + p += 10; } - registers[36] = env->fpuc; + *(uint32_t *)p = tswap32(env->fpuc); /* fctrl */ + p += 4; fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - registers[37] = fpus; - registers[38] = 0; /* XXX: convert tags */ - registers[39] = 0; /* fiseg */ - registers[40] = 0; /* fioff */ - registers[41] = 0; /* foseg */ - registers[42] = 0; /* fooff */ - registers[43] = 0; /* fop */ - - for(i = 0; i < 16; i++) - tswapls(®isters[i]); - for(i = 36; i < 44; i++) - tswapls(®isters[i]); - return 44 * 4; + *(uint32_t *)p = tswap32(fpus); /* fstat */ + p += 4; + *(uint32_t *)p = 0; /* ftag */ + p += 4; + *(uint32_t *)p = 0; /* fiseg */ + p += 4; + *(uint32_t *)p = 0; /* fioff */ + p += 4; + *(uint32_t *)p = 0; /* foseg */ + p += 4; + *(uint32_t *)p = 0; /* fooff */ + p += 4; + *(uint32_t *)p = 0; /* fop */ + p += 4; + for(i = 0; i < nb_regs; i++) { + *(uint64_t *)p = tswap64(env->xmm_regs[i].XMM_Q(0)); + p += 8; + *(uint64_t *)p = tswap64(env->xmm_regs[i].XMM_Q(1)); + p += 8; + } + *(uint32_t *)p = tswap32(env->mxcsr); + p += 4; + return p - mem_buf; } -static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +static inline void cpu_gdb_load_seg(CPUState *env, const uint8_t **pp, + int sreg) { - uint32_t *registers = (uint32_t *)mem_buf; - int i; + const uint8_t *p; + uint32_t sel; + p = *pp; + sel = tswap32(*(uint32_t *)p); + p += 4; + if (sel != env->segs[sreg].selector) { +#if defined(CONFIG_USER_ONLY) + cpu_x86_load_seg(env, sreg, sel); +#else + /* XXX: do it with a debug function which does not raise an + exception */ +#endif + } + *pp = p; +} - for(i = 0; i < 8; i++) { - env->regs[i] = tswapl(registers[i]); +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + const uint8_t *p = mem_buf; + int i, nb_regs; + uint16_t fpus; + +#ifdef TARGET_X86_64 + if (env->hflags & HF_CS64_MASK) { + nb_regs = 16; + for(i = 0; i < 16; i++) { + env->regs[gdb_x86_64_regs[i]] = tswap64(*(uint64_t *)p); + p += 8; + } + env->eip = tswap64(*(uint64_t *)p); + p += 8; + } else +#endif + { + nb_regs = 8; + for(i = 0; i < 8; i++) { + env->regs[i] = tswap32(*(uint32_t *)p); + p += 4; + } + env->eip = tswap32(*(uint32_t *)p); + p += 4; } - env->eip = tswapl(registers[8]); - env->eflags = tswapl(registers[9]); -#if defined(CONFIG_USER_ONLY) -#define LOAD_SEG(index, sreg)\ - if (tswapl(registers[index]) != env->segs[sreg].selector)\ - cpu_x86_load_seg(env, sreg, tswapl(registers[index])); - LOAD_SEG(10, R_CS); - LOAD_SEG(11, R_SS); - LOAD_SEG(12, R_DS); - LOAD_SEG(13, R_ES); - LOAD_SEG(14, R_FS); - LOAD_SEG(15, R_GS); + env->eflags = tswap32(*(uint32_t *)p); + p += 4; + cpu_gdb_load_seg(env, &p, R_CS); + cpu_gdb_load_seg(env, &p, R_SS); + cpu_gdb_load_seg(env, &p, R_DS); + cpu_gdb_load_seg(env, &p, R_ES); + cpu_gdb_load_seg(env, &p, R_FS); + cpu_gdb_load_seg(env, &p, R_GS); + + /* FPU state */ + for(i = 0; i < 8; i++) { + /* XXX: convert floats */ +#ifdef USE_X86LDOUBLE + memcpy(&env->fpregs[i], p, 10); #endif + p += 10; + } + env->fpuc = tswap32(*(uint32_t *)p); /* fctrl */ + p += 4; + fpus = tswap32(*(uint32_t *)p); + p += 4; + env->fpstt = (fpus >> 11) & 7; + env->fpus = fpus & ~0x3800; + p += 4 * 6; + + if (size >= ((p - mem_buf) + 16 * nb_regs + 4)) { + /* SSE state */ + for(i = 0; i < nb_regs; i++) { + env->xmm_regs[i].XMM_Q(0) = tswap64(*(uint64_t *)p); + p += 8; + env->xmm_regs[i].XMM_Q(1) = tswap64(*(uint64_t *)p); + p += 8; + } + env->mxcsr = tswap32(*(uint32_t *)p); + p += 4; + } } #elif defined (TARGET_PPC) @@ -300,7 +431,7 @@ 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(do_load_msr(env)); + registers[97] = tswapl(env->msr); tmp = 0; for (i = 0; i < 8; i++) tmp |= env->crf[i] << (32 - ((i + 1) * 4)); @@ -329,7 +460,7 @@ 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]); - do_store_msr(env, tswapl(registers[97])); + ppc_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; @@ -338,40 +469,49 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) ppc_store_xer(env, tswapl(registers[101])); } #elif defined (TARGET_SPARC) +#ifdef TARGET_ABI32 +#define tswap_abi(val) tswap32(val &0xffffffff) +#else +#define tswap_abi(val) tswapl(val) +#endif static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { +#ifdef TARGET_ABI32 + abi_ulong *registers = (abi_ulong *)mem_buf; +#else target_ulong *registers = (target_ulong *)mem_buf; +#endif int i; /* fill in g0..g7 */ for(i = 0; i < 8; i++) { - registers[i] = tswapl(env->gregs[i]); + registers[i] = tswap_abi(env->gregs[i]); } /* fill in register window */ for(i = 0; i < 24; i++) { - registers[i + 8] = tswapl(env->regwptr[i]); + registers[i + 8] = tswap_abi(env->regwptr[i]); } -#ifndef TARGET_SPARC64 +#if !defined(TARGET_SPARC64) || defined(TARGET_ABI32) /* fill in fprs */ for (i = 0; i < 32; i++) { - registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i])); + registers[i + 32] = tswap_abi(*((uint32_t *)&env->fpr[i])); } /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ - registers[64] = tswapl(env->y); + registers[64] = tswap_abi(env->y); { - target_ulong tmp; + uint32_t tmp; - tmp = GET_PSR(env); - registers[65] = tswapl(tmp); + tmp = GET_PSR(env); + registers[65] = tswap32(tmp); } - registers[66] = tswapl(env->wim); - registers[67] = tswapl(env->tbr); - registers[68] = tswapl(env->pc); - registers[69] = tswapl(env->npc); - registers[70] = tswapl(env->fsr); + registers[66] = tswap_abi(env->wim); + registers[67] = tswap_abi(env->tbr); + registers[68] = tswap_abi(env->pc); + registers[69] = tswap_abi(env->npc); + registers[70] = tswap_abi(env->fsr); registers[71] = 0; /* csr */ registers[72] = 0; - return 73 * sizeof(target_ulong); + return 73 * sizeof(uint32_t); #else /* fill in fprs */ for (i = 0; i < 64; i += 2) { @@ -396,30 +536,34 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) { +#ifdef TARGET_ABI32 + abi_ulong *registers = (abi_ulong *)mem_buf; +#else target_ulong *registers = (target_ulong *)mem_buf; +#endif int i; /* fill in g0..g7 */ for(i = 0; i < 7; i++) { - env->gregs[i] = tswapl(registers[i]); + env->gregs[i] = tswap_abi(registers[i]); } /* fill in register window */ for(i = 0; i < 24; i++) { - env->regwptr[i] = tswapl(registers[i + 8]); + env->regwptr[i] = tswap_abi(registers[i + 8]); } -#ifndef TARGET_SPARC64 +#if !defined(TARGET_SPARC64) || defined(TARGET_ABI32) /* fill in fprs */ for (i = 0; i < 32; i++) { - *((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]); + *((uint32_t *)&env->fpr[i]) = tswap_abi(registers[i + 32]); } /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ - env->y = tswapl(registers[64]); - PUT_PSR(env, tswapl(registers[65])); - env->wim = tswapl(registers[66]); - env->tbr = tswapl(registers[67]); - env->pc = tswapl(registers[68]); - env->npc = tswapl(registers[69]); - env->fsr = tswapl(registers[70]); + env->y = tswap_abi(registers[64]); + PUT_PSR(env, tswap_abi(registers[65])); + env->wim = tswap_abi(registers[66]); + env->tbr = tswap_abi(registers[67]); + env->pc = tswap_abi(registers[68]); + env->npc = tswap_abi(registers[69]); + env->fsr = tswap_abi(registers[70]); #else for (i = 0; i < 64; i += 2) { uint64_t tmp; @@ -443,6 +587,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->y = tswapl(registers[69]); #endif } +#undef tswap_abi #elif defined (TARGET_ARM) static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { @@ -559,45 +704,60 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) ptr = mem_buf; for (i = 0; i < 32; i++) { - *(target_ulong *)ptr = tswapl(env->gpr[i][env->current_tc]); + *(target_ulong *)ptr = tswapl(env->active_tc.gpr[i]); ptr += sizeof(target_ulong); } - *(target_ulong *)ptr = tswapl(env->CP0_Status); + *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Status); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->LO[0][env->current_tc]); + *(target_ulong *)ptr = tswapl(env->active_tc.LO[0]); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->HI[0][env->current_tc]); + *(target_ulong *)ptr = tswapl(env->active_tc.HI[0]); ptr += sizeof(target_ulong); *(target_ulong *)ptr = tswapl(env->CP0_BadVAddr); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->CP0_Cause); + *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Cause); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->PC[env->current_tc]); + *(target_ulong *)ptr = tswapl(env->active_tc.PC); ptr += sizeof(target_ulong); if (env->CP0_Config1 & (1 << CP0C1_FP)) { for (i = 0; i < 32; i++) { - *(target_ulong *)ptr = tswapl(env->fpu->fpr[i].fs[FP_ENDIAN_IDX]); + if (env->CP0_Status & (1 << CP0St_FR)) + *(target_ulong *)ptr = tswapl(env->fpu->fpr[i].d); + else + *(target_ulong *)ptr = tswap32(env->fpu->fpr[i].w[FP_ENDIAN_IDX]); ptr += sizeof(target_ulong); } - *(target_ulong *)ptr = tswapl(env->fpu->fcr31); + *(target_ulong *)ptr = (int32_t)tswap32(env->fpu->fcr31); + ptr += sizeof(target_ulong); + + *(target_ulong *)ptr = (int32_t)tswap32(env->fpu->fcr0); ptr += sizeof(target_ulong); + } + + /* "fp", pseudo frame pointer. Not yet implemented in gdb. */ + *(target_ulong *)ptr = 0; + ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->fpu->fcr0); + /* Registers for embedded use, we just pad them. */ + for (i = 0; i < 16; i++) + { + *(target_ulong *)ptr = 0; ptr += sizeof(target_ulong); } - /* 32 FP registers, fsr, fir, fp. Not yet implemented. */ - /* what's 'fp' mean here? */ + /* Processor ID. */ + *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_PRid); + ptr += sizeof(target_ulong); return ptr - mem_buf; } @@ -621,17 +781,17 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) ptr = mem_buf; for (i = 0; i < 32; i++) { - env->gpr[i][env->current_tc] = tswapl(*(target_ulong *)ptr); + env->active_tc.gpr[i] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); } env->CP0_Status = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); - env->LO[0][env->current_tc] = tswapl(*(target_ulong *)ptr); + env->active_tc.LO[0] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); - env->HI[0][env->current_tc] = tswapl(*(target_ulong *)ptr); + env->active_tc.HI[0] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); env->CP0_BadVAddr = tswapl(*(target_ulong *)ptr); @@ -640,22 +800,24 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->CP0_Cause = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); - env->PC[env->current_tc] = tswapl(*(target_ulong *)ptr); + env->active_tc.PC = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); if (env->CP0_Config1 & (1 << CP0C1_FP)) { for (i = 0; i < 32; i++) { - env->fpu->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr); + if (env->CP0_Status & (1 << CP0St_FR)) + env->fpu->fpr[i].d = tswapl(*(target_ulong *)ptr); + else + env->fpu->fpr[i].w[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); } - env->fpu->fcr31 = tswapl(*(target_ulong *)ptr) & 0x0183FFFF; + env->fpu->fcr31 = tswapl(*(target_ulong *)ptr) & 0xFF83FFFF; ptr += sizeof(target_ulong); - env->fpu->fcr0 = tswapl(*(target_ulong *)ptr); - ptr += sizeof(target_ulong); + /* The remaining registers are assumed to be read-only. */ /* set rounding mode */ RESTORE_ROUNDING_MODE; @@ -728,6 +890,66 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) for (i = 0; i < 8; i++) LOAD(env->gregs[i]); for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]); } +#elif defined (TARGET_CRIS) + +static int cris_save_32 (unsigned char *d, uint32_t value) +{ + *d++ = (value); + *d++ = (value >>= 8); + *d++ = (value >>= 8); + *d++ = (value >>= 8); + return 4; +} +static int cris_save_16 (unsigned char *d, uint32_t value) +{ + *d++ = (value); + *d++ = (value >>= 8); + return 2; +} +static int cris_save_8 (unsigned char *d, uint32_t value) +{ + *d++ = (value); + return 1; +} + +/* FIXME: this will bug on archs not supporting unaligned word accesses. */ +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + uint8_t *ptr = mem_buf; + uint8_t srs; + int i; + + for (i = 0; i < 16; i++) + ptr += cris_save_32 (ptr, env->regs[i]); + + srs = env->pregs[PR_SRS]; + + ptr += cris_save_8 (ptr, env->pregs[0]); + ptr += cris_save_8 (ptr, env->pregs[1]); + ptr += cris_save_32 (ptr, env->pregs[2]); + ptr += cris_save_8 (ptr, srs); + ptr += cris_save_16 (ptr, env->pregs[4]); + + for (i = 5; i < 16; i++) + ptr += cris_save_32 (ptr, env->pregs[i]); + + ptr += cris_save_32 (ptr, env->pc); + + for (i = 0; i < 16; i++) + ptr += cris_save_32 (ptr, env->sregs[srs][i]); + + 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->regs[i]); + LOAD (env->pc); +} #else static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { @@ -745,7 +967,7 @@ static 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]; + uint8_t mem_buf[4096]; uint32_t *registers; target_ulong addr, len; @@ -759,6 +981,12 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) /* TODO: Make this return the correct value for user-mode. */ snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); put_packet(s, buf); + /* Remove all the breakpoints when this query is issued, + * because gdb is doing and initial connect and the state + * should be cleaned up. + */ + cpu_breakpoint_remove_all(env); + cpu_watchpoint_remove_all(env); break; case 'c': if (*p != '\0') { @@ -775,15 +1003,28 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #elif defined (TARGET_SH4) env->pc = addr; #elif defined (TARGET_MIPS) - env->PC[env->current_tc] = addr; + env->active_tc.PC = addr; +#elif defined (TARGET_CRIS) + env->pc = addr; #endif } -#ifdef CONFIG_USER_ONLY - s->running_state = 1; -#else - vm_start(); -#endif + gdb_continue(s); return RS_IDLE; + case 'C': + s->signal = strtoul(p, (char **)&p, 16); + gdb_continue(s); + return RS_IDLE; + case 'k': + /* Kill the target */ + fprintf(stderr, "\nQEMU: Terminated via GDBstub\n"); + exit(0); + case 'D': + /* Detach packet */ + cpu_breakpoint_remove_all(env); + cpu_watchpoint_remove_all(env); + gdb_continue(s); + put_packet(s, "OK"); + break; case 's': if (*p != '\0') { addr = strtoull(p, (char **)&p, 16); @@ -799,15 +1040,13 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #elif defined (TARGET_SH4) env->pc = addr; #elif defined (TARGET_MIPS) - env->PC[env->current_tc] = addr; + env->active_tc.PC = addr; +#elif defined (TARGET_CRIS) + env->pc = addr; #endif } - cpu_single_step(env, 1); -#ifdef CONFIG_USER_ONLY - s->running_state = 1; -#else - vm_start(); -#endif + cpu_single_step(env, sstep_flags); + gdb_continue(s); return RS_IDLE; case 'F': { @@ -829,11 +1068,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) if (type == 'C') { put_packet(s, "T02"); } else { -#ifdef CONFIG_USER_ONLY - s->running_state = 1; -#else - vm_start(); -#endif + gdb_continue(s); } } break; @@ -882,21 +1117,37 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) if (*p == ',') p++; len = strtoull(p, (char **)&p, 16); - if (type == 0 || type == 1) { + switch (type) { + case 0: + case 1: if (cpu_breakpoint_insert(env, addr) < 0) goto breakpoint_error; put_packet(s, "OK"); + break; #ifndef CONFIG_USER_ONLY - } else if (type == 2) { - if (cpu_watchpoint_insert(env, addr) < 0) + case 2: + type = PAGE_WRITE; + goto insert_watchpoint; + case 3: + type = PAGE_READ; + goto insert_watchpoint; + case 4: + type = PAGE_READ | PAGE_WRITE; + insert_watchpoint: + if (cpu_watchpoint_insert(env, addr, type) < 0) goto breakpoint_error; put_packet(s, "OK"); + break; #endif - } else { - breakpoint_error: - put_packet(s, "E22"); + default: + put_packet(s, ""); + break; } break; + breakpoint_error: + put_packet(s, "E22"); + break; + case 'z': type = strtoul(p, (char **)&p, 16); if (*p == ',') @@ -909,31 +1160,56 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) cpu_breakpoint_remove(env, addr); put_packet(s, "OK"); #ifndef CONFIG_USER_ONLY - } else if (type == 2) { + } else if (type >= 2 || type <= 4) { cpu_watchpoint_remove(env, addr); put_packet(s, "OK"); #endif } else { - goto breakpoint_error; + put_packet(s, ""); } break; -#ifdef CONFIG_LINUX_USER case 'q': - if (strncmp(p, "Offsets", 7) == 0) { + case 'Q': + /* parse any 'q' packets here */ + if (!strcmp(p,"qemu.sstepbits")) { + /* Query Breakpoint bit definitions */ + sprintf(buf,"ENABLE=%x,NOIRQ=%x,NOTIMER=%x", + SSTEP_ENABLE, + SSTEP_NOIRQ, + SSTEP_NOTIMER); + put_packet(s, buf); + break; + } else if (strncmp(p,"qemu.sstep",10) == 0) { + /* Display or change the sstep_flags */ + p += 10; + if (*p != '=') { + /* Display current setting */ + sprintf(buf,"0x%x", sstep_flags); + put_packet(s, buf); + break; + } + p++; + type = strtoul(p, (char **)&p, 16); + sstep_flags = type; + put_packet(s, "OK"); + break; + } +#ifdef CONFIG_LINUX_USER + else if (strncmp(p, "Offsets", 7) == 0) { TaskState *ts = env->opaque; sprintf(buf, - "Text=" TARGET_FMT_lx ";Data=" TARGET_FMT_lx ";Bss=" TARGET_FMT_lx, + "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 + /* Fall through. */ default: - // unknown_command: /* put empty packet */ buf[0] = '\0'; put_packet(s, buf); @@ -1046,7 +1322,7 @@ static void gdb_read_byte(GDBState *s, int ch) { CPUState *env = s->env; int i, csum; - char reply[1]; + uint8_t reply; #ifndef CONFIG_USER_ONLY if (s->last_packet_len) { @@ -1056,7 +1332,7 @@ static void gdb_read_byte(GDBState *s, int ch) #ifdef DEBUG_GDB printf("Got NACK, retransmitting\n"); #endif - put_buffer(s, s->last_packet, s->last_packet_len); + put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len); } #ifdef DEBUG_GDB else if (ch == '+') @@ -1104,12 +1380,12 @@ static void gdb_read_byte(GDBState *s, int ch) csum += s->line_buf[i]; } if (s->line_csum != (csum & 0xff)) { - reply[0] = '-'; - put_buffer(s, reply, 1); + reply = '-'; + put_buffer(s, &reply, 1); s->state = RS_IDLE; } else { - reply[0] = '+'; - put_buffer(s, reply, 1); + reply = '+'; + put_buffer(s, &reply, 1); s->state = gdb_handle_packet(s, env, s->line_buf); } break; @@ -1127,10 +1403,9 @@ gdb_handlesig (CPUState *env, int sig) char buf[256]; int n; - if (gdbserver_fd < 0) - return sig; - s = &gdbserver_state; + if (gdbserver_fd < 0 || s->fd < 0) + return sig; /* disable single step if it was enabled */ cpu_single_step(env, 0); @@ -1141,6 +1416,10 @@ gdb_handlesig (CPUState *env, int sig) snprintf(buf, sizeof(buf), "S%02x", sig); put_packet(s, buf); } + /* put_packet() might have detected that the peer terminated the + connection. */ + if (s->fd < 0) + return sig; sig = 0; s->state = RS_IDLE; @@ -1161,6 +1440,8 @@ gdb_handlesig (CPUState *env, int sig) return sig; } } + sig = s->signal; + s->signal = 0; return sig; } @@ -1170,10 +1451,9 @@ void gdb_exit(CPUState *env, int code) GDBState *s; char buf[4]; - if (gdbserver_fd < 0) - return; - s = &gdbserver_state; + if (gdbserver_fd < 0 || s->fd < 0) + return; snprintf(buf, sizeof(buf), "W%02x", code); put_packet(s, buf);