aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/riscv-tdep.c33
-rw-r--r--gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw-foo.s74
-rw-r--r--gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld-lw.exp45
-rw-r--r--gdb/testsuite/gdb.arch/riscv64-unwind-prologue-with-ld.c30
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 ();
+}
+