diff options
-rw-r--r-- | gdb/riscv-tdep.c | 33 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw-foo.s | 74 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw.exp | 45 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld.c | 30 |
4 files changed, 182 insertions, 0 deletions
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index b5b0d2d..8b55bc3 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -1409,6 +1409,8 @@ public: LUI, SD, SW, + LD, + LW, /* These are needed for software breakpoint support. */ JAL, JALR, @@ -1519,6 +1521,15 @@ private: m_imm.s = EXTRACT_CITYPE_IMM (ival); } + /* Helper for DECODE, decode 16-bit compressed CL-type instruction. */ + void decode_cl_type_insn (enum opcode opcode, ULONGEST ival) + { + m_opcode = opcode; + m_rd = decode_register_index_short (ival, OP_SH_CRS2S); + m_rs1 = decode_register_index_short (ival, OP_SH_CRS1S); + m_imm.s = EXTRACT_CLTYPE_IMM (ival); + } + /* Helper for DECODE, decode 32-bit S-type instruction. */ void decode_s_type_insn (enum opcode opcode, ULONGEST ival) { @@ -1715,6 +1726,10 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc) decode_r_type_insn (SC, ival); else if (is_ecall_insn (ival)) decode_i_type_insn (ECALL, ival); + else if (is_ld_insn (ival)) + decode_i_type_insn (LD, ival); + else if (is_lw_insn (ival)) + decode_i_type_insn (LW, ival); else /* None of the other fields are valid in this case. */ m_opcode = OTHER; @@ -1783,6 +1798,10 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc) decode_cb_type_insn (BEQ, ival); else if (is_c_bnez_insn (ival)) decode_cb_type_insn (BNE, ival); + else if (is_c_ld_insn (ival)) + decode_cl_type_insn (LD, ival); + else if (is_c_lw_insn (ival)) + decode_cl_type_insn (LW, ival); else /* None of the other fields of INSN are valid in this case. */ m_opcode = OTHER; @@ -1931,6 +1950,20 @@ riscv_scan_prologue (struct gdbarch *gdbarch, gdb_assert (insn.rs2 () < RISCV_NUM_INTEGER_REGS); regs[insn.rd ()] = pv_add (regs[insn.rs1 ()], regs[insn.rs2 ()]); } + else if (insn.opcode () == riscv_insn::LD + || insn.opcode () == riscv_insn::LW) + { + /* Handle: ld reg, offset(rs1) + or: c.ld reg, offset(rs1) + or: lw reg, offset(rs1) + or: c.lw reg, offset(rs1) */ + gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS); + gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS); + regs[insn.rd ()] + = stack.fetch (pv_add_constant (regs[insn.rs1 ()], + insn.imm_signed ()), + (insn.opcode () == riscv_insn::LW ? 4 : 8)); + } else { end_prologue_addr = cur_pc; diff --git a/gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw-foo.s b/gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw-foo.s new file mode 100644 index 0000000..ebc27ff --- /dev/null +++ b/gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw-foo.s @@ -0,0 +1,74 @@ +/* Copyright 2021 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* This testcase contains a function where the 'ld', 'c.ld', 'lw' or 'c.lw' + instruction is used in the prologue before the RA register have been saved + on the stack. + + This mimics a pattern observed in the __pthread_clockjoin_ex function + in libpthread.so.0 (from glibc-2.33-0ubuntu5) where a canary value is + loaded and placed on the stack in order to detect stack smashing. + + The skeleton for this file was generated using the following command: + + gcc -x c -S -c -o - - <<EOT + static long int __canary = 42; + extern int bar (); + int foo () { return bar(); } + EOT + + The result of this command is modified in the following way: + - The prologue is adapted to reserve 16 more bytes on the stack. + - A part that simulates the installation of a canary on the stack is + added. The canary is loaded multiple times to simulate the use of + various instructions that could do the work (ld or c.ld for a 64 bit + canary, lw or c.lw for a 32 bit canary). + - The epilogue is adjusted to be able to return properly. The epilogue + does not check the canary value since this testcase is only interested + in ensuring GDB can scan the prologue. */ + + .option pic + .text + .data + .align 3 + .type __canary, @object + .size __canary, 8 +__canary: + .dword 42 + .text + .align 1 + .globl foo + .type foo, @function +foo: + addi sp,sp,-32 + lla a5,__canary # Load the fake canary address. + lw t4,0(a5) # Load a 32 bit canary (use t4 to force the use of + # the non compressed instruction). + ld t4,0(a5) # Load a 64 bit canary (use t4 to force the use of + # the non compressed instruction). + c.lw a4,0(a5) # Load a 32 bit canary using the compressed insn. + c.ld a4,0(a5) # Load a 64 bit canary using the compressed insn. + sd a4,0(sp) # Place the fake canary on the stack. + sd ra,16(sp) + sd s0,8(sp) + addi s0,sp,32 + call bar@plt + mv a5,a0 + mv a0,a5 + ld ra,16(sp) + ld s0,8(sp) + addi sp,sp,32 + jr ra + .size foo, .-foo diff --git a/gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw.exp b/gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw.exp new file mode 100644 index 0000000..c329d2f --- /dev/null +++ b/gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw.exp @@ -0,0 +1,45 @@ +# Copyright 2021 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# This tests GDB's ability to use the RISC-V prologue scanner in order to +# unwind through a function that uses the 'ld' instruction in its prologue. + +if {![istarget "riscv64-*-*"]} { + verbose "Skipping ${gdb_test_file_name}." + return +} + +standard_testfile riscv64-unwind-prologue-with-ld.c \ + riscv64-unwind-prologue-with-ld-lw-foo.s +if {[prepare_for_testing "failed to prepare" $testfile \ + "$srcfile $srcfile2" nodebug]} { + return -1 +} + +if ![runto_main] then { + fail "can't run to main" + return 0 +} + +gdb_breakpoint "bar" +gdb_continue_to_breakpoint "bar" +gdb_test "bt" \ + [multi_line \ + "#0\[ \t\]*$hex in bar \\\(\\\)" \ + "#1\[ \t\]*$hex in foo \\\(\\\)" \ + "#2\[ \t\]*$hex in main \\\(\\\)"] \ + "Backtrace to the main frame" +gdb_test "finish" "foo \\\(\\\)" "finish bar" +gdb_test "finish" "main \\\(\\\)" "finish foo" diff --git a/gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld.c b/gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld.c new file mode 100644 index 0000000..9ff950d --- /dev/null +++ b/gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld.c @@ -0,0 +1,30 @@ +/* Copyright 2021 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* See riscv64-unwind-prologue-with-ld-foo.s for implementation. */ +extern int foo (void); + +int +bar () +{ + return 0; +} + +int +main () +{ + return foo (); +} + |