diff mbox

[V2,SPARC] Gdbstub: Fix back-trace on SPARC32

Message ID 1315478896-17536-1-git-send-email-chouteau@adacore.com
State New
Headers show

Commit Message

Fabien Chouteau Sept. 8, 2011, 10:48 a.m. UTC
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>
---

V2:
  * only handle reads in stack frames

 gdbstub.c             |   16 +++++++--
 target-sparc/cpu.h    |    7 ++++
 target-sparc/helper.c |   84 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 104 insertions(+), 3 deletions(-)

Comments

Blue Swirl Sept. 10, 2011, 6:38 p.m. UTC | #1
Thanks, applied.

On Thu, Sep 8, 2011 at 10:48 AM, Fabien Chouteau <chouteau@adacore.com> wrote:
> 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>
> ---
>
> V2:
>  * only handle reads in stack frames
>
>  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 3b87c27..7802c5f 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,
> @@ -2013,7 +2022,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);
> @@ -2028,10 +2037,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 8654f26..19de5ba 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 1fe1f07..c80531a 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
> --
> 1.7.4.1
>
>
diff mbox

Patch

diff --git a/gdbstub.c b/gdbstub.c
index 3b87c27..7802c5f 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,
@@ -2013,7 +2022,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);
@@ -2028,10 +2037,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 8654f26..19de5ba 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 1fe1f07..c80531a 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