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:
Andrew Burgess
2018-09-12 17:35:08 +01:00
parent 853924149d
commit d354055e6e
7 changed files with 189 additions and 21 deletions

View File

@ -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;