xtensa: gdbstub: fix backtracing and stack unwinding
This fixes GDB backtracing by forcibly spilling all registers, and faking values for WINDOWSTART and WINDOWBASE. This is effectively telling GDB that only A0-A3 and AR0-AR3 contain active data and other physical registers do not. GDB then must rely on spilled values on stack. Otherwise, GDB will try to look at all AR* registers for previous frame(s). Since we do not save all AR* register values, there is nothing for GDB to look at, and thus failing to unwind stack. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
parent
c7841ce472
commit
733305293a
2 changed files with 25 additions and 26 deletions
|
@ -178,11 +178,20 @@ static void read_sreg(struct gdb_ctx *ctx, struct xtensa_register *reg)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if XCHAL_HAVE_WINDOWED
|
#if XCHAL_HAVE_WINDOWED
|
||||||
|
/*
|
||||||
|
* Returning 0 for WINDOWBASE and 1 for WINDOWSTART. This is
|
||||||
|
* effectively telling GDB that only A0-A3 and AR0-AR3 contain
|
||||||
|
* active data and other physical registers do not. GDB then
|
||||||
|
* must rely on spilled values on stack. Otherwise, GDB will try
|
||||||
|
* to look at all AR* registers for previous frame(s). Since we
|
||||||
|
* do not save all AR* register values, there is nothing for
|
||||||
|
* GDB to look at, and thus failing to unwind stack.
|
||||||
|
*/
|
||||||
case WINDOWBASE:
|
case WINDOWBASE:
|
||||||
val = get_one_sreg(WINDOWBASE);
|
val = 0;
|
||||||
break;
|
break;
|
||||||
case WINDOWSTART:
|
case WINDOWSTART:
|
||||||
val = get_one_sreg(WINDOWSTART);
|
val = 1;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if XCHAL_NUM_INTLEVELS > 0
|
#if XCHAL_NUM_INTLEVELS > 0
|
||||||
|
@ -426,6 +435,16 @@ static void copy_to_ctx(struct gdb_ctx *ctx, const struct arch_esf *stack)
|
||||||
{
|
{
|
||||||
struct xtensa_register *reg;
|
struct xtensa_register *reg;
|
||||||
int idx, num_laddr_regs;
|
int idx, num_laddr_regs;
|
||||||
|
int32_t a0save;
|
||||||
|
|
||||||
|
/* Need to spill all registers so their values are on the stack instead of
|
||||||
|
* the physical register file. This is required for GDB backtracing to
|
||||||
|
* walk through stack.
|
||||||
|
*/
|
||||||
|
__asm__ volatile("mov %0, a0;"
|
||||||
|
"call0 xtensa_spill_reg_windows;"
|
||||||
|
"mov a0, %0"
|
||||||
|
: "=r"(a0save));
|
||||||
|
|
||||||
const uint32_t *bsa = *(const int **)stack;
|
const uint32_t *bsa = *(const int **)stack;
|
||||||
|
|
||||||
|
@ -470,26 +489,13 @@ static void copy_to_ctx(struct gdb_ctx *ctx, const struct arch_esf *stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if XCHAL_HAVE_WINDOWED
|
#if XCHAL_HAVE_WINDOWED
|
||||||
uint8_t a0_idx, ar_idx, wb_start;
|
uint8_t a0_idx, ar_idx;
|
||||||
|
|
||||||
wb_start = (uint8_t)xtensa_gdb_ctx.regs[xtensa_gdb_ctx.wb_idx].val;
|
/* Copied the logical registers A0-A15 to physical registers AR0-AR15. */
|
||||||
|
|
||||||
/*
|
|
||||||
* Copied the logical registers A0-A15 to physical registers (AR*)
|
|
||||||
* according to WINDOWBASE.
|
|
||||||
*/
|
|
||||||
for (idx = 0; idx < num_laddr_regs; idx++) {
|
for (idx = 0; idx < num_laddr_regs; idx++) {
|
||||||
/* Index to register description array for A */
|
/* Index to register description array for A and AR */
|
||||||
a0_idx = xtensa_gdb_ctx.a0_idx + idx;
|
a0_idx = xtensa_gdb_ctx.a0_idx + idx;
|
||||||
|
ar_idx = xtensa_gdb_ctx.ar_idx + idx;
|
||||||
/* Find the start of window (== WINDOWBASE * 4) */
|
|
||||||
ar_idx = wb_start * 4;
|
|
||||||
/* Which logical register we are working on... */
|
|
||||||
ar_idx += idx;
|
|
||||||
/* Wrap around A64 (or A32) -> A0 */
|
|
||||||
ar_idx %= XCHAL_NUM_AREGS;
|
|
||||||
/* Index to register description array for AR */
|
|
||||||
ar_idx += xtensa_gdb_ctx.ar_idx;
|
|
||||||
|
|
||||||
xtensa_gdb_ctx.regs[ar_idx].val = xtensa_gdb_ctx.regs[a0_idx].val;
|
xtensa_gdb_ctx.regs[ar_idx].val = xtensa_gdb_ctx.regs[a0_idx].val;
|
||||||
xtensa_gdb_ctx.regs[ar_idx].seqno = xtensa_gdb_ctx.regs[a0_idx].seqno;
|
xtensa_gdb_ctx.regs[ar_idx].seqno = xtensa_gdb_ctx.regs[a0_idx].seqno;
|
||||||
|
@ -955,10 +961,6 @@ void arch_gdb_init(void)
|
||||||
/* AR0: 0x0100 */
|
/* AR0: 0x0100 */
|
||||||
xtensa_gdb_ctx.ar_idx = idx;
|
xtensa_gdb_ctx.ar_idx = idx;
|
||||||
break;
|
break;
|
||||||
case (XTREG_GRP_SPECIAL + WINDOWBASE):
|
|
||||||
/* WINDOWBASE (Special Register) */
|
|
||||||
xtensa_gdb_ctx.wb_idx = idx;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
|
@ -102,9 +102,6 @@ struct gdb_ctx {
|
||||||
|
|
||||||
/** Index in register descriptions of AR0 register */
|
/** Index in register descriptions of AR0 register */
|
||||||
uint8_t ar_idx;
|
uint8_t ar_idx;
|
||||||
|
|
||||||
/** Index in register descriptions of WINDOWBASE register */
|
|
||||||
uint8_t wb_idx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue