mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-02-17 13:10:12 +08:00
gdb: LoongArch: Implement loongarch_scan_prologue()
If can't determine prologue from the symbol table, need to examine instructions. Implement loongarch_scan_prologue() to analyze the function prologue from START_PC to LIMIT_PC, return the address of the first instruction past the prologue. Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
This commit is contained in:
parent
5355776935
commit
6e0d24c448
@ -22,11 +22,131 @@
|
||||
#include "dwarf2/frame.h"
|
||||
#include "elf-bfd.h"
|
||||
#include "frame-unwind.h"
|
||||
#include "gdbcore.h"
|
||||
#include "loongarch-tdep.h"
|
||||
#include "target.h"
|
||||
#include "target-descriptions.h"
|
||||
#include "trad-frame.h"
|
||||
#include "user-regs.h"
|
||||
|
||||
/* Fetch the instruction at PC. */
|
||||
|
||||
static insn_t
|
||||
loongarch_fetch_instruction (CORE_ADDR pc)
|
||||
{
|
||||
size_t insn_len = loongarch_insn_length (0);
|
||||
gdb_byte buf[insn_len];
|
||||
int err;
|
||||
|
||||
err = target_read_memory (pc, buf, insn_len);
|
||||
if (err)
|
||||
memory_error (TARGET_XFER_E_IO, pc);
|
||||
|
||||
return extract_unsigned_integer (buf, insn_len, BFD_ENDIAN_LITTLE);
|
||||
}
|
||||
|
||||
/* Return TRUE if INSN is a branch instruction, otherwise return FALSE. */
|
||||
|
||||
static bool
|
||||
loongarch_insn_is_branch (insn_t insn)
|
||||
{
|
||||
if ((insn & 0xfc000000) == 0x4c000000 /* jirl rd, rj, offs16 */
|
||||
|| (insn & 0xfc000000) == 0x50000000 /* b offs26 */
|
||||
|| (insn & 0xfc000000) == 0x54000000 /* bl offs26 */
|
||||
|| (insn & 0xfc000000) == 0x58000000 /* beq rj, rd, offs16 */
|
||||
|| (insn & 0xfc000000) == 0x5c000000 /* bne rj, rd, offs16 */
|
||||
|| (insn & 0xfc000000) == 0x60000000 /* blt rj, rd, offs16 */
|
||||
|| (insn & 0xfc000000) == 0x64000000 /* bge rj, rd, offs16 */
|
||||
|| (insn & 0xfc000000) == 0x68000000 /* bltu rj, rd, offs16 */
|
||||
|| (insn & 0xfc000000) == 0x6c000000 /* bgeu rj, rd, offs16 */
|
||||
|| (insn & 0xfc000000) == 0x40000000 /* beqz rj, offs21 */
|
||||
|| (insn & 0xfc000000) == 0x44000000) /* bnez rj, offs21 */
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Analyze the function prologue from START_PC to LIMIT_PC.
|
||||
Return the address of the first instruction past the prologue. */
|
||||
|
||||
static CORE_ADDR
|
||||
loongarch_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc,
|
||||
CORE_ADDR limit_pc, struct frame_info *this_frame,
|
||||
struct trad_frame_cache *this_cache)
|
||||
{
|
||||
CORE_ADDR cur_pc = start_pc, prologue_end = 0;
|
||||
loongarch_gdbarch_tdep *tdep = (loongarch_gdbarch_tdep *) gdbarch_tdep (gdbarch);
|
||||
auto regs = tdep->regs;
|
||||
int32_t sp = regs.r + 3;
|
||||
int32_t fp = regs.r + 22;
|
||||
int32_t reg_value[32] = {0};
|
||||
int32_t reg_used[32] = {1, 0};
|
||||
|
||||
while (cur_pc < limit_pc)
|
||||
{
|
||||
insn_t insn = loongarch_fetch_instruction (cur_pc);
|
||||
size_t insn_len = loongarch_insn_length (insn);
|
||||
int32_t rd = loongarch_decode_imm ("0:5", insn, 0);
|
||||
int32_t rj = loongarch_decode_imm ("5:5", insn, 0);
|
||||
int32_t rk = loongarch_decode_imm ("10:5", insn, 0);
|
||||
int32_t si12 = loongarch_decode_imm ("10:12", insn, 1);
|
||||
int32_t si20 = loongarch_decode_imm ("5:20", insn, 1);
|
||||
|
||||
if ((insn & 0xffc00000) == 0x02c00000 /* addi.d sp,sp,si12 */
|
||||
&& rd == sp && rj == sp && si12 < 0)
|
||||
{
|
||||
prologue_end = cur_pc + insn_len;
|
||||
}
|
||||
else if ((insn & 0xffc00000) == 0x02c00000 /* addi.d fp,sp,si12 */
|
||||
&& rd == fp && rj == sp && si12 > 0)
|
||||
{
|
||||
prologue_end = cur_pc + insn_len;
|
||||
}
|
||||
else if ((insn & 0xffc00000) == 0x29c00000 /* st.d rd,sp,si12 */
|
||||
&& rj == sp)
|
||||
{
|
||||
prologue_end = cur_pc + insn_len;
|
||||
}
|
||||
else if ((insn & 0xff000000) == 0x27000000 /* stptr.d rd,sp,si14 */
|
||||
&& rj == sp)
|
||||
{
|
||||
prologue_end = cur_pc + insn_len;
|
||||
}
|
||||
else if ((insn & 0xfe000000) == 0x14000000) /* lu12i.w rd,si20 */
|
||||
{
|
||||
reg_value[rd] = si20 << 12;
|
||||
reg_used[rd] = 1;
|
||||
}
|
||||
else if ((insn & 0xffc00000) == 0x03800000) /* ori rd,rj,si12 */
|
||||
{
|
||||
if (reg_used[rj])
|
||||
{
|
||||
reg_value[rd] = reg_value[rj] | (si12 & 0xfff);
|
||||
reg_used[rd] = 1;
|
||||
}
|
||||
}
|
||||
else if ((insn & 0xffff8000) == 0x00108000 /* add.d sp,sp,rk */
|
||||
&& rd == sp && rj == sp)
|
||||
{
|
||||
if (reg_used[rk] == 1 && reg_value[rk] < 0)
|
||||
{
|
||||
prologue_end = cur_pc + insn_len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (loongarch_insn_is_branch (insn))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
cur_pc += insn_len;
|
||||
}
|
||||
|
||||
if (prologue_end == 0)
|
||||
prologue_end = cur_pc;
|
||||
|
||||
return prologue_end;
|
||||
}
|
||||
|
||||
/* Implement the loongarch_skip_prologue gdbarch method. */
|
||||
|
||||
static CORE_ADDR
|
||||
@ -45,7 +165,17 @@ loongarch_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
|
||||
return std::max (pc, post_prologue_pc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* Can't determine prologue from the symbol table, need to examine
|
||||
instructions. */
|
||||
|
||||
/* Find an upper limit on the function prologue using the debug
|
||||
information. If the debug information could not be used to provide
|
||||
that bound, then use an arbitrary large number as the upper bound. */
|
||||
CORE_ADDR limit_pc = skip_prologue_using_sal (gdbarch, pc);
|
||||
if (limit_pc == 0)
|
||||
limit_pc = pc + 100; /* Arbitrary large number. */
|
||||
|
||||
return loongarch_scan_prologue (gdbarch, pc, limit_pc, nullptr, nullptr);
|
||||
}
|
||||
|
||||
/* Adjust the address downward (direction of stack growth) so that it
|
||||
|
Loading…
Reference in New Issue
Block a user