summaryrefslogtreecommitdiff
path: root/target-sparc
diff options
context:
space:
mode:
authorFabien Chouteau <chouteau@adacore.com>2011-09-08 12:48:16 +0200
committerBlue Swirl <blauwirbel@gmail.com>2011-09-10 18:12:35 +0000
commit44520db10b1b92f272348ab7028e7afc68ac3edf (patch)
tree2e39e553803bda9567f1ae46ad53efc222cc0dd0 /target-sparc
parent7d890b4074a415d39f02d3b01e7c40ece1b57087 (diff)
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 <chouteau@adacore.com> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Diffstat (limited to 'target-sparc')
-rw-r--r--target-sparc/cpu.h7
-rw-r--r--target-sparc/helper.c84
2 files changed, 91 insertions, 0 deletions
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