gdb/riscv: read frame base register as unsigned in the unwinder
authorAndrew Burgess <andrew.burgess@embecosm.com>
Tue, 27 Oct 2020 15:31:53 +0000 (15:31 +0000)
committerAndrew Burgess <andrew.burgess@embecosm.com>
Mon, 2 Nov 2020 09:07:05 +0000 (09:07 +0000)
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 = <not saved>
   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
gdb/riscv-tdep.c

index 8457c754ed0f6d41d0b3249dc659a1e6eb8cb482..98715c905149813ad7b51bff33e0cb20ffb58c2a 100644 (file)
@@ -1,3 +1,9 @@
+2020-11-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+           Craig Blackmore   <craig.blackmore@embecosm.com>
+
+       * riscv-tdep.c (riscv_frame_cache): Read the frame base register
+       as an unsigned value.
+
 2020-11-01  Tom Tromey  <tom@tromey.com>
 
        * dbxread.c (dbx_end_psymtab): Update.
index 2c4eeab720be469d08634527911e3c81161d3162..e18f953eb131668b7d6f205a3d013169dceaa967 100644 (file)
@@ -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",