* rs6000-tdep.c (struct rs6000_framedata): Add gpr_mask, used_bl,

lr_register.
	(rs6000_in_function_epilogue_p): Check for bctr.
	(skip_prologue): Initialize lr_register.  Set lr_reg to a register
	number.  Set gpr_mask and used_bl.  Continue scanning while some
	expected registers are not saved.  Set lr_register if LR is not
	stored.
	(rs6000_frame_cache): Handle gpr_mask and lr_register.

	* gdb.arch/powerpc-prologue.exp: Correct saved registers.
This commit is contained in:
Daniel Jacobowitz 2008-08-18 12:32:47 +00:00
parent c2d805c8d5
commit 46a9b8ed1b
4 changed files with 59 additions and 8 deletions

View File

@ -1,3 +1,14 @@
2008-08-18 Daniel Jacobowitz <dan@codesourcery.com>
* rs6000-tdep.c (struct rs6000_framedata): Add gpr_mask, used_bl,
lr_register.
(rs6000_in_function_epilogue_p): Check for bctr.
(skip_prologue): Initialize lr_register. Set lr_reg to a register
number. Set gpr_mask and used_bl. Continue scanning while some
expected registers are not saved. Set lr_register if LR is not
stored.
(rs6000_frame_cache): Handle gpr_mask and lr_register.
2008-08-17 Tom Tromey <tromey@redhat.com>
PR gdb/1535:

View File

@ -129,17 +129,20 @@ struct rs6000_framedata
by which we decrement sp to allocate
the frame */
int saved_gpr; /* smallest # of saved gpr */
unsigned int gpr_mask; /* Each bit is an individual saved GPR. */
int saved_fpr; /* smallest # of saved fpr */
int saved_vr; /* smallest # of saved vr */
int saved_ev; /* smallest # of saved ev */
int alloca_reg; /* alloca register number (frame ptr) */
char frameless; /* true if frameless functions. */
char nosavedpc; /* true if pc not saved. */
char used_bl; /* true if link register clobbered */
int gpr_offset; /* offset of saved gprs from prev sp */
int fpr_offset; /* offset of saved fprs from prev sp */
int vr_offset; /* offset of saved vrs from prev sp */
int ev_offset; /* offset of saved evs from prev sp */
int lr_offset; /* offset of saved lr */
int lr_register; /* register of saved lr, if trustworthy */
int cr_offset; /* offset of saved cr */
int vrsave_offset; /* offset of saved vrsave register */
};
@ -870,6 +873,7 @@ insn_changes_sp_or_jumps (unsigned long insn)
static int
rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
bfd_byte insn_buf[PPC_INSN_SIZE];
CORE_ADDR scan_pc, func_start, func_end, epilogue_start, epilogue_end;
unsigned long insn;
@ -897,6 +901,17 @@ rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
insn = extract_unsigned_integer (insn_buf, PPC_INSN_SIZE);
if (insn == 0x4e800020)
break;
/* Assume a bctr is a tail call unless it points strictly within
this function. */
if (insn == 0x4e800420)
{
CORE_ADDR ctr = get_frame_register_unsigned (curfrm,
tdep->ppc_ctr_regnum);
if (ctr > func_start && ctr < func_end)
return 0;
else
break;
}
if (insn_changes_sp_or_jumps (insn))
return 0;
}
@ -1316,6 +1331,7 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
fdata->alloca_reg = -1;
fdata->frameless = 1;
fdata->nosavedpc = 1;
fdata->lr_register = -1;
for (;; pc += 4)
{
@ -1357,7 +1373,7 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
remember just the first one, but skip over additional
ones. */
if (lr_reg == -1)
lr_reg = (op & 0x03e00000);
lr_reg = (op & 0x03e00000) >> 21;
if (lr_reg == 0)
r0_contains_arg = 0;
continue;
@ -1388,6 +1404,10 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
{
reg = GET_SRC_REG (op);
if ((op & 0xfc1f0000) == 0xbc010000)
fdata->gpr_mask |= ~((1U << reg) - 1);
else
fdata->gpr_mask |= 1U << reg;
if (fdata->saved_gpr == -1 || fdata->saved_gpr > reg)
{
fdata->saved_gpr = reg;
@ -1479,6 +1499,7 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
else if (op == 0x48000005)
{ /* bl .+4 used in
-mrelocatable */
fdata->used_bl = 1;
continue;
}
@ -1503,7 +1524,10 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
/* If the return address has already been saved, we can skip
calls to blrl (for PIC). */
if (lr_reg != -1 && bl_to_blrl_insn_p (pc, op))
continue;
{
fdata->used_bl = 1;
continue;
}
/* Don't skip over the subroutine call if it is not within
the first three instructions of the prologue and either
@ -1529,8 +1553,9 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
if (op == 0x4def7b82 || op == 0) /* crorc 15, 15, 15 */
break; /* don't skip over
this branch */
continue;
fdata->used_bl = 1;
continue;
}
/* update stack pointer */
else if ((op & 0xfc1f0000) == 0x94010000)
@ -1791,11 +1816,15 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
else
{
unsigned int all_mask = ~((1U << fdata->saved_gpr) - 1);
/* Not a recognized prologue instruction.
Handle optimizer code motions into the prologue by continuing
the search if we have no valid frame yet or if the return
address is not yet saved in the frame. */
if (fdata->frameless == 0 && fdata->nosavedpc == 0)
address is not yet saved in the frame. Also skip instructions
if some of the GPRs expected to be saved are not yet saved. */
if (fdata->frameless == 0 && fdata->nosavedpc == 0
&& (fdata->gpr_mask & all_mask) == all_mask)
break;
if (op == 0x4e800020 /* blr */
@ -1848,6 +1877,9 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc,
}
#endif /* 0 */
if (pc == lim_pc && lr_reg >= 0)
fdata->lr_register = lr_reg;
fdata->offset = -fdata->offset;
return last_prologue_pc;
}
@ -2892,7 +2924,8 @@ rs6000_frame_cache (struct frame_info *this_frame, void **this_cache)
}
/* if != -1, fdata.saved_gpr is the smallest number of saved_gpr.
All gpr's from saved_gpr to gpr31 are saved. */
All gpr's from saved_gpr to gpr31 are saved (except during the
prologue). */
if (fdata.saved_gpr >= 0)
{
@ -2900,7 +2933,8 @@ rs6000_frame_cache (struct frame_info *this_frame, void **this_cache)
CORE_ADDR gpr_addr = cache->base + fdata.gpr_offset;
for (i = fdata.saved_gpr; i < ppc_num_gprs; i++)
{
cache->saved_regs[tdep->ppc_gp0_regnum + i].addr = gpr_addr;
if (fdata.gpr_mask & (1U << i))
cache->saved_regs[tdep->ppc_gp0_regnum + i].addr = gpr_addr;
gpr_addr += wordsize;
}
}
@ -2947,6 +2981,8 @@ rs6000_frame_cache (struct frame_info *this_frame, void **this_cache)
holds the LR. */
if (fdata.lr_offset != 0)
cache->saved_regs[tdep->ppc_lr_regnum].addr = cache->base + fdata.lr_offset;
else if (fdata.lr_register != -1)
cache->saved_regs[tdep->ppc_lr_regnum].realreg = fdata.lr_register;
/* The PC is found in the link register. */
cache->saved_regs[gdbarch_pc_regnum (gdbarch)] =
cache->saved_regs[tdep->ppc_lr_regnum];

View File

@ -1,3 +1,7 @@
2008-08-18 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.arch/powerpc-prologue.exp: Correct saved registers.
2008-08-17 Tom Tromey <tromey@redhat.com>
* gdb.base/help.exp (help catch): Rewrite.

View File

@ -84,5 +84,5 @@ gdb_test "backtrace 10" \
"backtrace in optimized"
gdb_test "info frame" \
".*Saved registers:.*r30 at.*r31 at.*pc at.*lr at.*" \
".*Saved registers:.*r30 at.*pc at.*lr at.*" \
"saved registers in optimized"