mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-02-10 03:02:30 +00:00
Add support for single register window model on SPARC
2011-06-27 Eric Botcazou <ebotcazou@adacore.com> * sparc-tdep.h (struct sparc_frame_cache): Add frame_offset, saved_regs_mask and copied_regs_mask fields. (sparc_record_save_insn): New prototype. * sparc-tdep.c (sparc_alloc_frame_cache): Initialize the new fields. (sparc_record_save_insn): New function. (sparc_analyze_prologue): Add head comment. Recognize store insns of call-saved registers. Use OFFSET consistently. Recognize flat frames and cache their settings. (sparc32_skip_prologue): Handle flat frames. (sparc_frame_cache): Add frame_offset to the base address. (sparc32_frame_cache): Adjust to new frame description. (sparc32_frame_prev_register): Likewise. * sparc64-tdep.c (sparc64_frame_prev_register): Likewise. * sparc-sol2-tdep.c (sparc32_sol2_sigtramp_frame_cache): Likewise. * sparc64-sol2-tdep.c (sparc64_sol2_sigtramp_frame_cache): Likewise. * sparcnbsd-tdep.c (sparc32nbsd_sigcontext_frame_cache): Force the frame by calling sparc_record_save_insn. * sparc64nbsd-tdep.c (sparc64nbsd_sigcontext_frame_cache): Likewise. * sparcobsd-tdep.c (sparc32obsd_sigtramp_frame_cache): Likewise. * sparc64obsd-tdep.c (sparc64obsd_frame_cache): Likewise.
This commit is contained in:
parent
840c4ae927
commit
369c397ba4
@ -1,3 +1,26 @@
|
||||
2011-06-27 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* sparc-tdep.h (struct sparc_frame_cache): Add frame_offset,
|
||||
saved_regs_mask and copied_regs_mask fields.
|
||||
(sparc_record_save_insn): New prototype.
|
||||
* sparc-tdep.c (sparc_alloc_frame_cache): Initialize the new fields.
|
||||
(sparc_record_save_insn): New function.
|
||||
(sparc_analyze_prologue): Add head comment. Recognize store insns
|
||||
of call-saved registers. Use OFFSET consistently. Recognize flat
|
||||
frames and cache their settings.
|
||||
(sparc32_skip_prologue): Handle flat frames.
|
||||
(sparc_frame_cache): Add frame_offset to the base address.
|
||||
(sparc32_frame_cache): Adjust to new frame description.
|
||||
(sparc32_frame_prev_register): Likewise.
|
||||
* sparc64-tdep.c (sparc64_frame_prev_register): Likewise.
|
||||
* sparc-sol2-tdep.c (sparc32_sol2_sigtramp_frame_cache): Likewise.
|
||||
* sparc64-sol2-tdep.c (sparc64_sol2_sigtramp_frame_cache): Likewise.
|
||||
* sparcnbsd-tdep.c (sparc32nbsd_sigcontext_frame_cache): Force the
|
||||
frame by calling sparc_record_save_insn.
|
||||
* sparc64nbsd-tdep.c (sparc64nbsd_sigcontext_frame_cache): Likewise.
|
||||
* sparcobsd-tdep.c (sparc32obsd_sigtramp_frame_cache): Likewise.
|
||||
* sparc64obsd-tdep.c (sparc64obsd_frame_cache): Likewise.
|
||||
|
||||
2011-06-27 Tristan Gingold <gingold@adacore.com>
|
||||
|
||||
* dwarf2read.c (struct dwarf2_section_info): Replace was_mmapped
|
||||
|
@ -93,7 +93,8 @@ sparc32_sol2_sigtramp_frame_cache (struct frame_info *this_frame,
|
||||
/* The third argument is a pointer to an instance of `ucontext_t',
|
||||
which has a member `uc_mcontext' that contains the saved
|
||||
registers. */
|
||||
regnum = (cache->frameless_p ? SPARC_O2_REGNUM : SPARC_I2_REGNUM);
|
||||
regnum =
|
||||
(cache->copied_regs_mask & 0x04) ? SPARC_I2_REGNUM : SPARC_O2_REGNUM;
|
||||
mcontext_addr = get_frame_register_unsigned (this_frame, regnum) + 40;
|
||||
|
||||
cache->saved_regs[SPARC32_PSR_REGNUM].addr = mcontext_addr + 0 * 4;
|
||||
|
169
gdb/sparc-tdep.c
169
gdb/sparc-tdep.c
@ -592,7 +592,9 @@ sparc_alloc_frame_cache (void)
|
||||
|
||||
/* Frameless until proven otherwise. */
|
||||
cache->frameless_p = 1;
|
||||
|
||||
cache->frame_offset = 0;
|
||||
cache->saved_regs_mask = 0;
|
||||
cache->copied_regs_mask = 0;
|
||||
cache->struct_return_p = 0;
|
||||
|
||||
return cache;
|
||||
@ -784,6 +786,31 @@ sparc_skip_stack_check (const CORE_ADDR start_pc)
|
||||
return start_pc;
|
||||
}
|
||||
|
||||
/* Record the effect of a SAVE instruction on CACHE. */
|
||||
|
||||
void
|
||||
sparc_record_save_insn (struct sparc_frame_cache *cache)
|
||||
{
|
||||
/* The frame is set up. */
|
||||
cache->frameless_p = 0;
|
||||
|
||||
/* The frame pointer contains the CFA. */
|
||||
cache->frame_offset = 0;
|
||||
|
||||
/* The `local' and `in' registers are all saved. */
|
||||
cache->saved_regs_mask = 0xffff;
|
||||
|
||||
/* The `out' registers are all renamed. */
|
||||
cache->copied_regs_mask = 0xff;
|
||||
}
|
||||
|
||||
/* Do a full analysis of the prologue at PC and update CACHE accordingly.
|
||||
Bail out early if CURRENT_PC is reached. Return the address where
|
||||
the analysis stopped.
|
||||
|
||||
We handle both the traditional register window model and the single
|
||||
register window (aka flat) model. */
|
||||
|
||||
CORE_ADDR
|
||||
sparc_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
|
||||
CORE_ADDR current_pc, struct sparc_frame_cache *cache)
|
||||
@ -813,13 +840,40 @@ sparc_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
|
||||
|
||||
insn = sparc_fetch_instruction (pc);
|
||||
|
||||
/* Recognize store insns and record their sources. */
|
||||
while (X_OP (insn) == 3
|
||||
&& (X_OP3 (insn) == 0x4 /* stw */
|
||||
|| X_OP3 (insn) == 0x7 /* std */
|
||||
|| X_OP3 (insn) == 0xe) /* stx */
|
||||
&& X_RS1 (insn) == SPARC_SP_REGNUM)
|
||||
{
|
||||
int regnum = X_RD (insn);
|
||||
|
||||
/* Recognize stores into the corresponding stack slots. */
|
||||
if (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM
|
||||
&& ((X_I (insn)
|
||||
&& X_SIMM13 (insn) == (X_OP3 (insn) == 0xe
|
||||
? (regnum - SPARC_L0_REGNUM) * 8 + BIAS
|
||||
: (regnum - SPARC_L0_REGNUM) * 4))
|
||||
|| (!X_I (insn) && regnum == SPARC_L0_REGNUM)))
|
||||
{
|
||||
cache->saved_regs_mask |= (1 << (regnum - SPARC_L0_REGNUM));
|
||||
if (X_OP3 (insn) == 0x7)
|
||||
cache->saved_regs_mask |= (1 << (regnum + 1 - SPARC_L0_REGNUM));
|
||||
}
|
||||
|
||||
offset += 4;
|
||||
|
||||
insn = sparc_fetch_instruction (pc + offset);
|
||||
}
|
||||
|
||||
/* Recognize a SETHI insn and record its destination. */
|
||||
if (X_OP (insn) == 0 && X_OP2 (insn) == 0x04)
|
||||
{
|
||||
dest = X_RD (insn);
|
||||
offset += 4;
|
||||
|
||||
insn = sparc_fetch_instruction (pc + 4);
|
||||
insn = sparc_fetch_instruction (pc + offset);
|
||||
}
|
||||
|
||||
/* Allow for an arithmetic operation on DEST or %g1. */
|
||||
@ -828,14 +882,62 @@ sparc_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
|
||||
{
|
||||
offset += 4;
|
||||
|
||||
insn = sparc_fetch_instruction (pc + 8);
|
||||
insn = sparc_fetch_instruction (pc + offset);
|
||||
}
|
||||
|
||||
/* Check for the SAVE instruction that sets up the frame. */
|
||||
if (X_OP (insn) == 2 && X_OP3 (insn) == 0x3c)
|
||||
{
|
||||
cache->frameless_p = 0;
|
||||
return pc + offset + 4;
|
||||
sparc_record_save_insn (cache);
|
||||
offset += 4;
|
||||
return pc + offset;
|
||||
}
|
||||
|
||||
/* Check for an arithmetic operation on %sp. */
|
||||
if (X_OP (insn) == 2
|
||||
&& (X_OP3 (insn) == 0 || X_OP3 (insn) == 0x4)
|
||||
&& X_RS1 (insn) == SPARC_SP_REGNUM
|
||||
&& X_RD (insn) == SPARC_SP_REGNUM)
|
||||
{
|
||||
if (X_I (insn))
|
||||
{
|
||||
cache->frame_offset = X_SIMM13 (insn);
|
||||
if (X_OP3 (insn) == 0)
|
||||
cache->frame_offset = -cache->frame_offset;
|
||||
}
|
||||
offset += 4;
|
||||
|
||||
insn = sparc_fetch_instruction (pc + offset);
|
||||
|
||||
/* Check for an arithmetic operation that sets up the frame. */
|
||||
if (X_OP (insn) == 2
|
||||
&& (X_OP3 (insn) == 0 || X_OP3 (insn) == 0x4)
|
||||
&& X_RS1 (insn) == SPARC_SP_REGNUM
|
||||
&& X_RD (insn) == SPARC_FP_REGNUM)
|
||||
{
|
||||
cache->frameless_p = 0;
|
||||
cache->frame_offset = 0;
|
||||
/* We could check that the amount subtracted to %sp above is the
|
||||
same as the one added here, but this seems superfluous. */
|
||||
cache->copied_regs_mask |= 0x40;
|
||||
offset += 4;
|
||||
|
||||
insn = sparc_fetch_instruction (pc + offset);
|
||||
}
|
||||
|
||||
/* Check for a move (or) operation that copies the return register. */
|
||||
if (X_OP (insn) == 2
|
||||
&& X_OP3 (insn) == 0x2
|
||||
&& !X_I (insn)
|
||||
&& X_RS1 (insn) == SPARC_G0_REGNUM
|
||||
&& X_RS2 (insn) == SPARC_O7_REGNUM
|
||||
&& X_RD (insn) == SPARC_I7_REGNUM)
|
||||
{
|
||||
cache->copied_regs_mask |= 0x80;
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
return pc + offset;
|
||||
}
|
||||
|
||||
return pc;
|
||||
@ -878,21 +980,36 @@ sparc32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
|
||||
indeed what GCC seems to be doing. In that case GCC will
|
||||
generate debug information that points to the stack slots instead
|
||||
of the registers, so we should consider the instructions that
|
||||
write out these incoming arguments onto the stack. Of course we
|
||||
only need to do this if we have a stack frame. */
|
||||
write out these incoming arguments onto the stack. */
|
||||
|
||||
while (!cache.frameless_p)
|
||||
while (1)
|
||||
{
|
||||
unsigned long insn = sparc_fetch_instruction (start_pc);
|
||||
|
||||
/* Recognize instructions that store incoming arguments in
|
||||
%i0...%i5 into the corresponding stack slot. */
|
||||
if (X_OP (insn) == 3 && (X_OP3 (insn) & 0x3c) == 0x04 && X_I (insn)
|
||||
&& (X_RD (insn) >= 24 && X_RD (insn) <= 29) && X_RS1 (insn) == 30
|
||||
&& X_SIMM13 (insn) == 68 + (X_RD (insn) - 24) * 4)
|
||||
/* Recognize instructions that store incoming arguments into the
|
||||
corresponding stack slots. */
|
||||
if (X_OP (insn) == 3 && (X_OP3 (insn) & 0x3c) == 0x04
|
||||
&& X_I (insn) && X_RS1 (insn) == SPARC_FP_REGNUM)
|
||||
{
|
||||
start_pc += 4;
|
||||
continue;
|
||||
int regnum = X_RD (insn);
|
||||
|
||||
/* Case of arguments still in %o[0..5]. */
|
||||
if (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O5_REGNUM
|
||||
&& !(cache.copied_regs_mask & (1 << (regnum - SPARC_O0_REGNUM)))
|
||||
&& X_SIMM13 (insn) == 68 + (regnum - SPARC_O0_REGNUM) * 4)
|
||||
{
|
||||
start_pc += 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Case of arguments copied into %i[0..5]. */
|
||||
if (regnum >= SPARC_I0_REGNUM && regnum <= SPARC_I5_REGNUM
|
||||
&& (cache.copied_regs_mask & (1 << (regnum - SPARC_I0_REGNUM)))
|
||||
&& X_SIMM13 (insn) == 68 + (regnum - SPARC_I0_REGNUM) * 4)
|
||||
{
|
||||
start_pc += 4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@ -935,6 +1052,8 @@ sparc_frame_cache (struct frame_info *this_frame, void **this_cache)
|
||||
get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
|
||||
}
|
||||
|
||||
cache->base += cache->frame_offset;
|
||||
|
||||
if (cache->base & 1)
|
||||
cache->base += BIAS;
|
||||
|
||||
@ -983,7 +1102,8 @@ sparc32_frame_cache (struct frame_info *this_frame, void **this_cache)
|
||||
an "unimp" instruction. If it is, then it is a struct-return
|
||||
function. */
|
||||
CORE_ADDR pc;
|
||||
int regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
|
||||
int regnum =
|
||||
(cache->copied_regs_mask & 0x80) ? SPARC_I7_REGNUM : SPARC_O7_REGNUM;
|
||||
|
||||
pc = get_frame_register_unsigned (this_frame, regnum) + 8;
|
||||
if (sparc_is_unimp_insn (pc))
|
||||
@ -1025,7 +1145,8 @@ sparc32_frame_prev_register (struct frame_info *this_frame,
|
||||
if (cache->struct_return_p)
|
||||
pc += 4;
|
||||
|
||||
regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
|
||||
regnum =
|
||||
(cache->copied_regs_mask & 0x80) ? SPARC_I7_REGNUM : SPARC_O7_REGNUM;
|
||||
pc += get_frame_register_unsigned (this_frame, regnum) + 8;
|
||||
return frame_unwind_got_constant (this_frame, regnum, pc);
|
||||
}
|
||||
@ -1045,20 +1166,20 @@ sparc32_frame_prev_register (struct frame_info *this_frame,
|
||||
}
|
||||
}
|
||||
|
||||
/* The previous frame's `local' and `in' registers have been saved
|
||||
/* The previous frame's `local' and `in' registers may have been saved
|
||||
in the register save area. */
|
||||
if (!cache->frameless_p
|
||||
&& regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM)
|
||||
if (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM
|
||||
&& (cache->saved_regs_mask & (1 << (regnum - SPARC_L0_REGNUM))))
|
||||
{
|
||||
CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 4;
|
||||
|
||||
return frame_unwind_got_memory (this_frame, regnum, addr);
|
||||
}
|
||||
|
||||
/* The previous frame's `out' registers are accessible as the
|
||||
current frame's `in' registers. */
|
||||
if (!cache->frameless_p
|
||||
&& regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
|
||||
/* The previous frame's `out' registers may be accessible as the current
|
||||
frame's `in' registers. */
|
||||
if (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM
|
||||
&& (cache->copied_regs_mask & (1 << (regnum - SPARC_O0_REGNUM))))
|
||||
regnum += (SPARC_I0_REGNUM - SPARC_O0_REGNUM);
|
||||
|
||||
return frame_unwind_got_register (this_frame, regnum, regnum);
|
||||
|
@ -146,6 +146,15 @@ struct sparc_frame_cache
|
||||
/* Do we have a frame? */
|
||||
int frameless_p;
|
||||
|
||||
/* The offset from the base register to the CFA. */
|
||||
int frame_offset;
|
||||
|
||||
/* Mask of `local' and `in' registers saved in the register save area. */
|
||||
unsigned short int saved_regs_mask;
|
||||
|
||||
/* Mask of `out' registers copied or renamed to their `in' sibling. */
|
||||
unsigned char copied_regs_mask;
|
||||
|
||||
/* Do we have a Structure, Union or Quad-Precision return value? */
|
||||
int struct_return_p;
|
||||
|
||||
@ -159,6 +168,10 @@ extern unsigned long sparc_fetch_instruction (CORE_ADDR pc);
|
||||
/* Fetch StackGhost Per-Process XOR cookie. */
|
||||
extern ULONGEST sparc_fetch_wcookie (struct gdbarch *gdbarch);
|
||||
|
||||
/* Record the effect of a SAVE instruction on CACHE. */
|
||||
extern void sparc_record_save_insn (struct sparc_frame_cache *cache);
|
||||
|
||||
/* Do a full analysis of the prologue at PC and update CACHE accordingly. */
|
||||
extern CORE_ADDR sparc_analyze_prologue (struct gdbarch *gdbarch,
|
||||
CORE_ADDR pc, CORE_ADDR current_pc,
|
||||
struct sparc_frame_cache *cache);
|
||||
|
@ -67,7 +67,8 @@ sparc64_sol2_sigtramp_frame_cache (struct frame_info *this_frame,
|
||||
/* The third argument is a pointer to an instance of `ucontext_t',
|
||||
which has a member `uc_mcontext' that contains the saved
|
||||
registers. */
|
||||
regnum = (cache->frameless_p ? SPARC_O2_REGNUM : SPARC_I2_REGNUM);
|
||||
regnum =
|
||||
(cache->copied_regs_mask & 0x04) ? SPARC_I2_REGNUM : SPARC_O2_REGNUM;
|
||||
mcontext_addr = get_frame_register_unsigned (this_frame, regnum) + 64;
|
||||
|
||||
cache->saved_regs[SPARC64_CCR_REGNUM].addr = mcontext_addr + 0 * 8;
|
||||
|
@ -520,7 +520,8 @@ sparc64_frame_prev_register (struct frame_info *this_frame, void **this_cache,
|
||||
{
|
||||
CORE_ADDR pc = (regnum == SPARC64_NPC_REGNUM) ? 4 : 0;
|
||||
|
||||
regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
|
||||
regnum =
|
||||
(cache->copied_regs_mask & 0x80) ? SPARC_I7_REGNUM : SPARC_O7_REGNUM;
|
||||
pc += get_frame_register_unsigned (this_frame, regnum) + 8;
|
||||
return frame_unwind_got_constant (this_frame, regnum, pc);
|
||||
}
|
||||
@ -540,20 +541,20 @@ sparc64_frame_prev_register (struct frame_info *this_frame, void **this_cache,
|
||||
}
|
||||
}
|
||||
|
||||
/* The previous frame's `local' and `in' registers have been saved
|
||||
/* The previous frame's `local' and `in' registers may have been saved
|
||||
in the register save area. */
|
||||
if (!cache->frameless_p
|
||||
&& regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM)
|
||||
if (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM
|
||||
&& (cache->saved_regs_mask & (1 << (regnum - SPARC_L0_REGNUM))))
|
||||
{
|
||||
CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 8;
|
||||
|
||||
return frame_unwind_got_memory (this_frame, regnum, addr);
|
||||
}
|
||||
|
||||
/* The previous frame's `out' registers are accessable as the
|
||||
current frame's `in' registers. */
|
||||
if (!cache->frameless_p
|
||||
&& regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
|
||||
/* The previous frame's `out' registers may be accessible as the current
|
||||
frame's `in' registers. */
|
||||
if (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM
|
||||
&& (cache->copied_regs_mask & (1 << (regnum - SPARC_O0_REGNUM))))
|
||||
regnum += (SPARC_I0_REGNUM - SPARC_O0_REGNUM);
|
||||
|
||||
return frame_unwind_got_register (this_frame, regnum, regnum);
|
||||
|
@ -173,7 +173,7 @@ sparc64nbsd_sigcontext_frame_cache (struct frame_info *this_frame,
|
||||
|
||||
/* Since we couldn't find the frame's function, the cache was
|
||||
initialized under the assumption that we're frameless. */
|
||||
cache->frameless_p = 0;
|
||||
sparc_record_save_insn (cache);
|
||||
addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
|
||||
if (addr & 1)
|
||||
addr += BIAS;
|
||||
|
@ -142,7 +142,7 @@ sparc64obsd_frame_cache (struct frame_info *this_frame, void **this_cache)
|
||||
|
||||
/* Since we couldn't find the frame's function, the cache was
|
||||
initialized under the assumption that we're frameless. */
|
||||
cache->frameless_p = 0;
|
||||
sparc_record_save_insn (cache);
|
||||
addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
|
||||
if (addr & 1)
|
||||
addr += BIAS;
|
||||
|
@ -202,7 +202,7 @@ sparc32nbsd_sigcontext_frame_cache (struct frame_info *this_frame,
|
||||
|
||||
/* Since we couldn't find the frame's function, the cache was
|
||||
initialized under the assumption that we're frameless. */
|
||||
cache->frameless_p = 0;
|
||||
sparc_record_save_insn (cache);
|
||||
addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
|
||||
cache->base = addr;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ sparc32obsd_sigtramp_frame_cache (struct frame_info *this_frame,
|
||||
|
||||
/* Since we couldn't find the frame's function, the cache was
|
||||
initialized under the assumption that we're frameless. */
|
||||
cache->frameless_p = 0;
|
||||
sparc_record_save_insn (cache);
|
||||
addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
|
||||
cache->base = addr;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user