]> xenbits.xensource.com Git - people/aperard/qemu-dm.git/commitdiff
Gdbstub: Fix back-trace on SPARC32
authorFabien Chouteau <chouteau@adacore.com>
Thu, 8 Sep 2011 10:48:16 +0000 (12:48 +0200)
committerBlue Swirl <blauwirbel@gmail.com>
Sat, 10 Sep 2011 18:12:35 +0000 (18:12 +0000)
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>
gdbstub.c
target-sparc/cpu.h
target-sparc/helper.c

index 933088578a4f3d012630cfa63d97632a154e12fa..90683a46c3d3ae5996c0a4b047e30233aa890c27 100644 (file)
--- a/gdbstub.c
+++ b/gdbstub.c
 #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.
index 8654f26a4ee358f4d912cd36e201c0c1c8999b7f..19de5ba3345b46faaf948b6461279319f3b7a54f 100644 (file)
@@ -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);
 
index 1fe1f074efa5b70d86ac0273c30271ca1940f4f8..c80531a16c24aeeb49eb453b872e99e9afa7a071 100644 (file)
@@ -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