gdb: riscv_scan_prologue: handle LD and LW instructions
authorLancelot SIX <lsix@lancelotsix.com>
Mon, 2 Aug 2021 22:53:07 +0000 (22:53 +0000)
committerLancelot SIX <lsix@lancelotsix.com>
Thu, 12 Aug 2021 23:13:30 +0000 (23:13 +0000)
commita35606d9014c3968446d009485a21bbe96d45063
treeece5180e8ffa1b586f42a66b6eeda48e6bd54f2f
parent6a33fa0efec5aa87230a84bcab3c097237dd7f90
gdb: riscv_scan_prologue: handle LD and LW instructions

While working on the testsuite, I ended up noticing that GDB fails to
produce a full backtrace from a thread waiting in pthread_join.  When
selecting the waiting thread and using the 'bt' command, the following
result can be observed:

(gdb) bt
#0  0x0000003ff7fccd20 in __futex_abstimed_wait_common64 () from /lib/riscv64-linux-gnu/libpthread.so.0
#1  0x0000003ff7fc43da in __pthread_clockjoin_ex () from /lib/riscv64-linux-gnu/libpthread.so.0
Backtrace stopped: frame did not save the PC

On my platform, I do not have debug symbols for glibc, so I need to rely
on prologue analysis in order to unwind stack.

Here is what the function prologue looks like:

(gdb) disassemble __pthread_clockjoin_ex
Dump of assembler code for function __pthread_clockjoin_ex:
   0x0000003ff7fc42de <+0>:     addi    sp,sp,-144
   0x0000003ff7fc42e0 <+2>:     sd      s5,88(sp)
   0x0000003ff7fc42e2 <+4>:     auipc   s5,0xd
   0x0000003ff7fc42e6 <+8>:     ld      s5,-2(s5) # 0x3ff7fd12e0
   0x0000003ff7fc42ea <+12>:    ld      a5,0(s5)
   0x0000003ff7fc42ee <+16>:    sd      ra,136(sp)
   0x0000003ff7fc42f0 <+18>:    sd      s0,128(sp)
   0x0000003ff7fc42f2 <+20>:    sd      s1,120(sp)
   0x0000003ff7fc42f4 <+22>:    sd      s2,112(sp)
   0x0000003ff7fc42f6 <+24>:    sd      s3,104(sp)
   0x0000003ff7fc42f8 <+26>:    sd      s4,96(sp)
   0x0000003ff7fc42fa <+28>:    sd      s6,80(sp)
   0x0000003ff7fc42fc <+30>:    sd      s7,72(sp)
   0x0000003ff7fc42fe <+32>:    sd      s8,64(sp)
   0x0000003ff7fc4300 <+34>:    sd      s9,56(sp)
   0x0000003ff7fc4302 <+36>:    sd      a5,40(sp)

As far as prologue analysis is concerned, the most interesting part is
done at address 0x0000003ff7fc42ee (<+16>): 'sd ra,136(sp)'. This stores
the RA (return address) register on the stack, which is the information
we are looking for in order to identify the caller.

In the current implementation of the prologue scanner, GDB stops when
hitting 0x0000003ff7fc42e6 (<+8>) because it does not know what to do
with the 'ld' instruction.  GDB thinks it reached the end of the
prologue but have not yet reached the important part, which explain
GDB's inability to unwind past this point.

The section of the prologue starting at <+4> until <+12> is used to load
the stack canary[1], which will then be placed on the stack at <+36> at
the end of the prologue.

In order to have the prologue properly handled, this commit proposes to
add support for the ld instruction in the RISC-V prologue scanner.
I guess riscv32 would use lw in such situation so this patch also adds
support for this instruction.

With this patch applied, gdb is now able to unwind past pthread_join:

(gdb) bt
#0  0x0000003ff7fccd20 in __futex_abstimed_wait_common64 () from /lib/riscv64-linux-gnu/libpthread.so.0
#1  0x0000003ff7fc43da in __pthread_clockjoin_ex () from /lib/riscv64-linux-gnu/libpthread.so.0
#2  0x0000002aaaaaa88e in bar() ()
#3  0x0000002aaaaaa8c4 in foo() ()
#4  0x0000002aaaaaa8da in main ()

I have had a look to see if I could reproduce this easily, but in my
simple testcases using '-fstack-protector-all', the canary is loaded
after the RA register is saved.  I do not have a reliable way of
generating a prologue similar to the problematic one so I forged one
instead.

The testsuite have been run on riscv64 ubuntu 21.01 with no regression
observed.

[1] https://en.wikipedia.org/wiki/Buffer_overflow_protection#Canaries
gdb/riscv-tdep.c
gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw-foo.s [new file with mode: 0644]
gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw.exp [new file with mode: 0644]
gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld.c [new file with mode: 0644]