mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-17 07:53:51 +08:00
gdb/riscv: Improve non-dwarf stack unwinding
This commit improves the prologue scanning stack unwinder, to better support AUIPC, LUI, and more variants of ADD and ADDI. This allows unwinding over frames containing large local variables, where the frame size does not fit into a single instruction immediate, and is first loaded into a temporary register, before being added to the stack pointer. A new test is added that tests this behaviour. As there's nothing truely RiscV specific about this test I've added it into gdb.base, but as this depends on target specific code to perform the unwind it is possible that some targets might fail this new test. gdb/ChangeLog: * riscv-tdep.c (riscv_insn::decode): Decode c.lui. (riscv_scan_prologue): Split handling of AUIPC, LUI, ADD, ADDI, and NOP. gdb/testsuite/ChangeLog: * gdb.base/large-frame-1.c: New file. * gdb.base/large-frame-2.c: New file. * gdb.base/large-frame.exp: New file. * gdb.base/large-frame.h: New file.
This commit is contained in:
@ -1227,7 +1227,11 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc)
|
||||
m_imm.s = EXTRACT_RVC_ADDI4SPN_IMM (ival);
|
||||
}
|
||||
else if (is_c_lui_insn (ival))
|
||||
m_opcode = OTHER;
|
||||
{
|
||||
m_opcode = LUI;
|
||||
m_rd = decode_register_index (ival, OP_SH_CRS1S);
|
||||
m_imm.s = EXTRACT_RVC_LUI_IMM (ival);
|
||||
}
|
||||
/* C_SD and C_FSW have the same opcode. C_SD is RV64 and RV128 only,
|
||||
and C_FSW is RV32 only. */
|
||||
else if (xlen != 4 && is_c_sd_insn (ival))
|
||||
@ -1359,28 +1363,41 @@ riscv_scan_prologue (struct gdbarch *gdbarch,
|
||||
gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
|
||||
regs[insn.rd ()] = pv_add_constant (regs[insn.rs1 ()], 0);
|
||||
}
|
||||
else if ((insn.rd () == RISCV_GP_REGNUM
|
||||
&& (insn.opcode () == riscv_insn::AUIPC
|
||||
|| insn.opcode () == riscv_insn::LUI
|
||||
|| (insn.opcode () == riscv_insn::ADDI
|
||||
&& insn.rs1 () == RISCV_GP_REGNUM)
|
||||
|| (insn.opcode () == riscv_insn::ADD
|
||||
&& (insn.rs1 () == RISCV_GP_REGNUM
|
||||
|| insn.rs2 () == RISCV_GP_REGNUM))))
|
||||
|| (insn.opcode () == riscv_insn::ADDI
|
||||
&& insn.rd () == RISCV_ZERO_REGNUM
|
||||
&& insn.rs1 () == RISCV_ZERO_REGNUM
|
||||
&& insn.imm_signed () == 0))
|
||||
else if ((insn.opcode () == riscv_insn::ADDI
|
||||
&& insn.rd () == RISCV_ZERO_REGNUM
|
||||
&& insn.rs1 () == RISCV_ZERO_REGNUM
|
||||
&& insn.imm_signed () == 0))
|
||||
{
|
||||
/* Handle: auipc gp, n
|
||||
or: addi gp, gp, n
|
||||
or: add gp, gp, reg
|
||||
or: add gp, reg, gp
|
||||
or: lui gp, n
|
||||
or: add x0, x0, 0 (NOP) */
|
||||
/* These instructions are part of the prologue, but we don't need
|
||||
to do anything special to handle them. */
|
||||
/* Handle: add x0, x0, 0 (NOP) */
|
||||
}
|
||||
else if (insn.opcode () == riscv_insn::AUIPC)
|
||||
{
|
||||
gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
|
||||
regs[insn.rd ()] = pv_constant (cur_pc + insn.imm_signed ());
|
||||
}
|
||||
else if (insn.opcode () == riscv_insn::LUI)
|
||||
{
|
||||
/* Handle: lui REG, n
|
||||
Where REG is not gp register. */
|
||||
gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
|
||||
regs[insn.rd ()] = pv_constant (insn.imm_signed ());
|
||||
}
|
||||
else if (insn.opcode () == riscv_insn::ADDI)
|
||||
{
|
||||
/* Handle: addi REG1, REG2, IMM */
|
||||
gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
|
||||
gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
|
||||
regs[insn.rd ()]
|
||||
= pv_add_constant (regs[insn.rs1 ()], insn.imm_signed ());
|
||||
}
|
||||
else if (insn.opcode () == riscv_insn::ADD)
|
||||
{
|
||||
/* Handle: addi REG1, REG2, IMM */
|
||||
gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
|
||||
gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
|
||||
gdb_assert (insn.rs2 () < RISCV_NUM_INTEGER_REGS);
|
||||
regs[insn.rd ()] = pv_add (regs[insn.rs1 ()], regs[insn.rs2 ()]);
|
||||
}
|
||||
else
|
||||
{
|
||||
end_prologue_addr = cur_pc;
|
||||
|
Reference in New Issue
Block a user