gdb/riscv: fix regressions in gdb.base/unwind-on-each-insn.exp
authorAndrew Burgess <aburgess@redhat.com>
Mon, 13 Mar 2023 13:17:43 +0000 (13:17 +0000)
committerAndrew Burgess <aburgess@redhat.com>
Mon, 3 Apr 2023 11:35:08 +0000 (12:35 +0100)
commit29caf11836611478a1fb32283b07e6777dfa5c28
treef7006a9189cc81ff88a62375e150b8335439f6c9
parent3ad6e510cd59b77e9f179eb01f0c52bf46fb7c42
gdb/riscv: fix regressions in gdb.base/unwind-on-each-insn.exp

This commit builds on the previous one to fix all the remaining
failures in gdb.base/unwind-on-each-insn.exp for RISC-V.

The problem we have in gdb.base/unwind-on-each-insn.exp is that, when
we are in the function epilogue, the previous frame and stack pointer
values are being restored, and so, the values that we calculated
during the function prologue are no longer suitable.

Here's an example from the function 'bar' in the mentioned test.  This
was compiled for 64-bit RISC-V with compressed instruction support:

  Dump of assembler code for function bar:
     0x000000000001018a <+0>: add sp,sp,-32
     0x000000000001018c <+2>: sd ra,24(sp)
     0x000000000001018e <+4>: sd fp,16(sp)
     0x0000000000010190 <+6>: add fp,sp,32
     0x0000000000010192 <+8>: sd a0,-24(fp)
     0x0000000000010196 <+12>: ld a0,-24(fp)
     0x000000000001019a <+16>: jal 0x10178 <foo>
     0x000000000001019e <+20>: nop
     0x00000000000101a0 <+22>: ld ra,24(sp)
     0x00000000000101a2 <+24>: ld fp,16(sp)
     0x00000000000101a4 <+26>: add sp,sp,32
     0x00000000000101a6 <+28>: ret
  End of assembler dump.

When we are at address 0x101a4 the previous instruction has restored
the frame-pointer, as such GDB's (current) preference for using the
frame-pointer as the frame base address is clearly not going to work.
We need to switch to using the stack-pointer instead.

At address 0x101a6 the previous instruction has restored the
stack-pointer value.  Currently GDB will not understand this and so
will still assume the stack has been decreased by 32 bytes in this
function.

My proposed solution is to extend GDB such that GDB will scan the
instructions at the current $pc looking for this pattern:

  ld    fp,16(sp)
  add   sp,sp,32
  ret

Obviously the immediates can change, but the basic pattern indicates
that the function is in the process of restoring state before
returning.  If GDB sees this pattern then GDB can use the inferior's
position within this instruction sequence to help calculate the
correct frame-id.

With this implemented then gdb.base/unwind-on-each-insn.exp now fully
passes.

Obviously what I've implemented is just a heuristic.  It's not going
to work for every function.  If the compiler reorders the
instructions, or merges the epilogue back into the function body then
GDB is once again going to get the frame-id wrong.

I'm OK with that, we're no worse off that we are right now in that
situation (plus we can always improve the heuristic later).

Remember, this is for debugging code without debug information,
and (in our imagined situation) with more aggressive levels of
optimisation being used.  Obviously GDB is going to struggle in these
situations.

My thinking is, lets get something in place now.  Then, later, if
possible, we might be able to improve the logic to cover more
situations -- if there's an interest in doing so.  But I figure we
need something in place as a starting point.

After this commit gdb.base/unwind-on-each-insn.exp passes with no
failures on RV64.
gdb/riscv-tdep.c