From e1f57067b162cba9f39e087726c7a2f2cfaae96f Mon Sep 17 00:00:00 2001 From: Andrew Burgess Date: Tue, 27 Oct 2020 15:31:53 +0000 Subject: [PATCH] gdb/riscv: read frame base register as unsigned in the unwinder I noticed an issue with the RISC-V prologue scanning stack unwinder. We currently read the frame base register (either $sp or $fp) as a signed value. This means that the frame_id's stack_addr field will be a signed value. In other contexts though these registers are data pointers, and so are unsigned. There's not many places where this mismatch actually shows though, but I did find one place. Consider this GDB session: (gdb) maintenance set dwarf unwinders off (gdb) set backtrace past-main on ... (gdb) b main Breakpoint 1 at 0x20400344: file main.c, line 86. (gdb) run ... (gdb) bt #0 main () at main.c:86 #1 0x2040005c in _start () at start.S:59 Backtrace stopped: frame did not save the PC (gdb) info frame 1 Stack frame at 0x80000a1c: pc = 0x2040005c in _start (start.S:59); saved pc = Outermost frame: frame did not save the PC caller of frame at 0x80000a1c source language asm. Arglist at 0x80000a1c, args: Locals at 0x80000a1c, Previous frame's sp is 0x80000a1c (gdb) frame address 0x80000a1c No frame at address 0x80000a1c. (gdb) frame address 0xffffffff80000a1c #1 0x2040005c in _start () at start.S:59 59 call main Notice that the 'info frame 1' reports that the frame is at '0x80000a1c', this is the unsigned frame base value, but when I try to select a frame using this address I can't. The reason is that the frame_id for frame #1 actually has the unsigned (and hence sign-extended) stack_addr value. When I use the sign extended address I can correctly select the frame. I propose changing the prologue scanning unwinder to read the frame base as unsigned. After this in the above case I can now do this: (gdb) frame address 0x80000a1c #1 0x2040005c in _start () at start.S:59 59 call main (gdb) frame address 0xffffffff80000a1c No frame at address 0xffffffff80000a1c. Which I think makes more sense. This issue causes failures in gdb.base/frame-selection.exp if you compile for RV32 with a linker script that places the stack in the correct location, which are resolved by this patch. gdb/ChangeLog: * riscv-tdep.c (riscv_frame_cache): Read the frame base register as an unsigned value. --- gdb/ChangeLog | 6 ++++++ gdb/riscv-tdep.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8457c754ed0..98715c90514 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2020-11-02 Andrew Burgess + Craig Blackmore + + * riscv-tdep.c (riscv_frame_cache): Read the frame base register + as an unsigned value. + 2020-11-01 Tom Tromey * dbxread.c (dbx_end_psymtab): Update. diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index 2c4eeab720b..e18f953eb13 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -2942,7 +2942,7 @@ riscv_frame_cache (struct frame_info *this_frame, void **this_cache) /* We can now calculate the frame base address. */ cache->frame_base - = (get_frame_register_signed (this_frame, cache->frame_base_reg) + = (get_frame_register_unsigned (this_frame, cache->frame_base_reg) + cache->frame_base_offset); if (riscv_debug_unwinder) fprintf_unfiltered (gdb_stdlog, "Frame base is %s ($%s + 0x%x)\n", -- 2.30.2