From 44520db10b1b92f272348ab7028e7afc68ac3edf Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Thu, 8 Sep 2011 12:48:16 +0200 Subject: [PATCH] Gdbstub: Fix back-trace on SPARC32 Gdb expects all registers windows to be flushed in ram, which is not the case in Qemu. Therefore the back-trace generation doesn't work. This patch adds a function to handle reads (and only read) in stack frames as if windows were flushed. Signed-off-by: Fabien Chouteau Signed-off-by: Blue Swirl --- gdbstub.c | 16 +++++++-- target-sparc/cpu.h | 7 ++++ target-sparc/helper.c | 84 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 3 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 933088578a..90683a46c3 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -41,6 +41,15 @@ #include "qemu_socket.h" #include "kvm.h" +#ifndef TARGET_CPU_MEMORY_RW_DEBUG +static inline int target_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write) +{ + return cpu_memory_rw_debug(env, addr, buf, len, is_write); +} +#else +/* target_memory_rw_debug() defined in cpu.h */ +#endif enum { GDB_SIGNAL_0 = 0, @@ -2109,7 +2118,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) if (*p == ',') p++; len = strtoull(p, NULL, 16); - if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) { + if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) { put_packet (s, "E14"); } else { memtohex(buf, mem_buf, len); @@ -2124,10 +2133,11 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) if (*p == ':') p++; hextomem(mem_buf, p, len); - if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) + if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) { put_packet(s, "E14"); - else + } else { put_packet(s, "OK"); + } break; case 'p': /* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable. diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 8654f26a4e..19de5ba334 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -495,6 +495,13 @@ int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev); void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env); +#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) +int target_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write); +#define TARGET_CPU_MEMORY_RW_DEBUG +#endif + + /* translate.c */ void gen_intermediate_code_init(CPUSPARCState *env); diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 1fe1f074ef..c80531a16c 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -358,6 +358,90 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) } } +#if !defined(CONFIG_USER_ONLY) + +/* Gdb expects all registers windows to be flushed in ram. This function handles + * reads (and only reads) in stack frames as if windows were flushed. We assume + * that the sparc ABI is followed. + */ +int target_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write) +{ + int i; + int len1; + int cwp = env->cwp; + + if (!is_write) { + for (i = 0; i < env->nwindows; i++) { + int off; + target_ulong fp = env->regbase[cwp * 16 + 22]; + + /* Assume fp == 0 means end of frame. */ + if (fp == 0) { + break; + } + + cwp = cpu_cwp_inc(env, cwp + 1); + + /* Invalid window ? */ + if (env->wim & (1 << cwp)) { + break; + } + + /* According to the ABI, the stack is growing downward. */ + if (addr + len < fp) { + break; + } + + /* Not in this frame. */ + if (addr > fp + 64) { + continue; + } + + /* Handle access before this window. */ + if (addr < fp) { + len1 = fp - addr; + if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) { + return -1; + } + addr += len1; + len -= len1; + buf += len1; + } + + /* Access byte per byte to registers. Not very efficient but speed + * is not critical. + */ + off = addr - fp; + len1 = 64 - off; + + if (len1 > len) { + len1 = len; + } + + for (; len1; len1--) { + int reg = cwp * 16 + 8 + (off >> 2); + union { + uint32_t v; + uint8_t c[4]; + } u; + u.v = cpu_to_be32(env->regbase[reg]); + *buf++ = u.c[off & 3]; + addr++; + len--; + off++; + } + + if (len == 0) { + return 0; + } + } + } + return cpu_memory_rw_debug(env, addr, buf, len, is_write); +} + +#endif /* !defined(CONFIG_USER_ONLY) */ + #else /* !TARGET_SPARC64 */ // 41 bit physical address space