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>
This commit is contained in:
parent
7d890b4074
commit
44520db10b
16
gdbstub.c
16
gdbstub.c
@ -41,6 +41,15 @@
|
|||||||
#include "qemu_socket.h"
|
#include "qemu_socket.h"
|
||||||
#include "kvm.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 {
|
enum {
|
||||||
GDB_SIGNAL_0 = 0,
|
GDB_SIGNAL_0 = 0,
|
||||||
@ -2109,7 +2118,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
|||||||
if (*p == ',')
|
if (*p == ',')
|
||||||
p++;
|
p++;
|
||||||
len = strtoull(p, NULL, 16);
|
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");
|
put_packet (s, "E14");
|
||||||
} else {
|
} else {
|
||||||
memtohex(buf, mem_buf, len);
|
memtohex(buf, mem_buf, len);
|
||||||
@ -2124,10 +2133,11 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
|||||||
if (*p == ':')
|
if (*p == ':')
|
||||||
p++;
|
p++;
|
||||||
hextomem(mem_buf, p, len);
|
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");
|
put_packet(s, "E14");
|
||||||
else
|
} else {
|
||||||
put_packet(s, "OK");
|
put_packet(s, "OK");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
/* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
|
/* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
|
||||||
|
@ -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);
|
target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
|
||||||
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env);
|
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 */
|
/* translate.c */
|
||||||
void gen_intermediate_code_init(CPUSPARCState *env);
|
void gen_intermediate_code_init(CPUSPARCState *env);
|
||||||
|
|
||||||
|
@ -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 */
|
#else /* !TARGET_SPARC64 */
|
||||||
|
|
||||||
// 41 bit physical address space
|
// 41 bit physical address space
|
||||||
|
Loading…
Reference in New Issue
Block a user