* Powerpc skip prologue
@ 2008-07-28 20:59 Aleksandar Ristovski
2008-08-09 14:17 ` Joel Brobecker
0 siblings, 1 reply; 6+ messages in thread
From: Aleksandar Ristovski @ 2008-07-28 20:59 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1015 bytes --]
Hello,
GDB assumes the gpr registers will be saved starting from a rN register up to r31. This assumption doesn't seem to be right. See this: http://sourceware.org/ml/gdb-patches/2007-12/msg00111.html
and this: http://sourceware.org/ml/gdb/2008-07/msg00279.html
So I devised a micro-patch for handling the saved gprs. I based it on the Daniel's observations and my own, by disassembling several functions - they appear to have prologue that will save several general purpose registers in the ascending register index order, but not up to r31. For example, r30 only, or r28,r29 etc.
Unfortunately, I can only test this on our (Neutrino) powerpc targets.
(No ChangeLog since I can not claim this is a final and correct solution in compliance with the ABI. If it turns out that ABI allows for saving registers non-sequentially or out-of order, e.g. r28, r30, r29, then this is not good and we need a more thorough patch that would allow for such situations).
Thanks,
Aleksandar Ristovski
QNX Software Systems
[-- Attachment #2: rs6000-tdep.c.prologueissue.diff --]
[-- Type: text/plain, Size: 1533 bytes --]
Index: gdb/rs6000-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v
retrieving revision 1.318
diff -u -p -r1.318 rs6000-tdep.c
--- gdb/rs6000-tdep.c 15 Jul 2008 18:32:06 -0000 1.318
+++ gdb/rs6000-tdep.c 28 Jul 2008 20:49:24 -0000
@@ -117,6 +117,7 @@ struct rs6000_framedata
by which we decrement sp to allocate
the frame */
int saved_gpr; /* smallest # of saved gpr */
+ int saved_gpr_max; /* Largest # of saved gpr */
int saved_fpr; /* smallest # of saved fpr */
int saved_vr; /* smallest # of saved vr */
int saved_ev; /* smallest # of saved ev */
@@ -1197,6 +1198,7 @@ skip_prologue (struct gdbarch *gdbarch,
memset (fdata, 0, sizeof (struct rs6000_framedata));
fdata->saved_gpr = -1;
+ fdata->saved_gpr_max = -1;
fdata->saved_fpr = -1;
fdata->saved_vr = -1;
fdata->saved_ev = -1;
@@ -1282,6 +1284,8 @@ skip_prologue (struct gdbarch *gdbarch,
op &= ~3UL;
fdata->gpr_offset = SIGNED_SHORT (op) + offset;
}
+ if (fdata->saved_gpr_max < reg)
+ fdata->saved_gpr_max = reg;
continue;
}
@@ -2571,7 +2575,7 @@ rs6000_frame_cache (struct frame_info *t
{
int i;
CORE_ADDR gpr_addr = cache->base + fdata.gpr_offset;
- for (i = fdata.saved_gpr; i < ppc_num_gprs; i++)
+ for (i = fdata.saved_gpr; i <= fdata.saved_gpr_max; i++)
{
cache->saved_regs[tdep->ppc_gp0_regnum + i].addr = gpr_addr;
gpr_addr += wordsize;
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: Powerpc skip prologue 2008-07-28 20:59 Powerpc skip prologue Aleksandar Ristovski @ 2008-08-09 14:17 ` Joel Brobecker 2008-08-09 16:12 ` Daniel Jacobowitz 0 siblings, 1 reply; 6+ messages in thread From: Joel Brobecker @ 2008-08-09 14:17 UTC (permalink / raw) To: Aleksandar Ristovski; +Cc: gdb-patches, Jerome Guitton [-- Attachment #1: Type: text/plain, Size: 1072 bytes --] > GDB assumes the gpr registers will be saved starting from a rN register up > to r31. This assumption doesn't seem to be right. See this: > http://sourceware.org/ml/gdb-patches/2007-12/msg00111.html and this: > http://sourceware.org/ml/gdb/2008-07/msg00279.html > > So I devised a micro-patch for handling the saved gprs. I just realized that we faced the same problem and forgot to submit the patch to the FSF. The ABI doesn't say anything about requiring that a sequence of registers be saved, which is why we introduced the use of a map rather than just save the lowest/highest register number. I propose to commit the following in a week unless there are comments/ objections: 2008-08-09 Jerome Guitton <guitton@adacore.com> * rs6000-tdep.c (rs6000_framedata): Add new field. (SET_REG_IN_MAP, GET_REG_IN_MAP): New macros. (skip_prologue): Update register map when a register is saved. (rs6000_frame_cache): Only set register address if the corresponding register has been saved. Tested on ppc-aix. Cheers, -- Joel [-- Attachment #2: rs6000-tdep.diff --] [-- Type: text/plain, Size: 2563 bytes --] Index: rs6000-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v retrieving revision 1.318 diff -u -p -r1.318 rs6000-tdep.c --- rs6000-tdep.c 15 Jul 2008 18:32:06 -0000 1.318 +++ rs6000-tdep.c 9 Aug 2008 14:12:58 -0000 @@ -117,6 +117,9 @@ struct rs6000_framedata by which we decrement sp to allocate the frame */ int saved_gpr; /* smallest # of saved gpr */ + unsigned int saved_gpr_map; /* saved gpr map; for any reg in gprs, + iff bit "# of reg" of saved_gprs_map is 1 + then reg is saved */ int saved_fpr; /* smallest # of saved fpr */ int saved_vr; /* smallest # of saved vr */ int saved_ev; /* smallest # of saved ev */ @@ -1042,6 +1045,9 @@ ppc_deal_with_atomic_sequence (struct fr #define GET_SRC_REG(x) (((x) >> 21) & 0x1f) +#define SET_REG_IN_MAP(map,x) ((map |= 1 << x)) +#define GET_REG_IN_MAP(map,x) ((map & (1 << x))) + /* Limit the number of skipped non-prologue instructions, as the examining of the prologue is expensive. */ static int max_skip_non_prologue_insns = 10; @@ -1155,6 +1161,7 @@ bl_to_blrl_insn_p (CORE_ADDR pc, int ins - offset is the initial size of this stack frame --- the amount by which we decrement the sp to allocate the frame. - saved_gpr is the number of the first saved gpr. + - saved_gpr_map is the map of saved gprs. - saved_fpr is the number of the first saved fpr. - saved_vr is the number of the first saved vr. - saved_ev is the number of the first saved ev. @@ -1197,6 +1204,7 @@ skip_prologue (struct gdbarch *gdbarch, memset (fdata, 0, sizeof (struct rs6000_framedata)); fdata->saved_gpr = -1; + fdata->saved_gpr_map = 0; fdata->saved_fpr = -1; fdata->saved_vr = -1; fdata->saved_ev = -1; @@ -1275,6 +1283,7 @@ skip_prologue (struct gdbarch *gdbarch, { reg = GET_SRC_REG (op); + SET_REG_IN_MAP (fdata->saved_gpr_map, reg); if (fdata->saved_gpr == -1 || fdata->saved_gpr > reg) { fdata->saved_gpr = reg; @@ -2573,7 +2582,8 @@ rs6000_frame_cache (struct frame_info *t 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 (GET_REG_IN_MAP (fdata.saved_gpr_map,i)) + cache->saved_regs[tdep->ppc_gp0_regnum + i].addr = gpr_addr; gpr_addr += wordsize; } } ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Powerpc skip prologue 2008-08-09 14:17 ` Joel Brobecker @ 2008-08-09 16:12 ` Daniel Jacobowitz 2008-08-10 2:45 ` Joel Brobecker 0 siblings, 1 reply; 6+ messages in thread From: Daniel Jacobowitz @ 2008-08-09 16:12 UTC (permalink / raw) To: Joel Brobecker; +Cc: Aleksandar Ristovski, gdb-patches, Jerome Guitton On Sat, Aug 09, 2008 at 06:16:51PM +0400, Joel Brobecker wrote: > I just realized that we faced the same problem and forgot to submit > the patch to the FSF. The ABI doesn't say anything about requiring > that a sequence of registers be saved, which is why we introduced > the use of a map rather than just save the lowest/highest register > number. > > I propose to commit the following in a week unless there are comments/ > objections: > > 2008-08-09 Jerome Guitton <guitton@adacore.com> > > * rs6000-tdep.c (rs6000_framedata): Add new field. > (SET_REG_IN_MAP, GET_REG_IN_MAP): New macros. > (skip_prologue): Update register map when a register is saved. > (rs6000_frame_cache): Only set register address if the corresponding > register has been saved. Could you test an alternative for me? The patch from my December message, but without rs6000_force_frame_sniffer, the rs6000_gdbarch_init change, or the new testcase. I believe that will cover the same cases as your patch, plus several others. This is a slightly larger portion of the patch than Aleksandar reposted earlier. Ref: http://sourceware.org/ml/gdb-patches/2007-12/msg00111.html Patch attached. -- Daniel Jacobowitz CodeSourcery 2008-08-09 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. * gdb.arch/powerpc-prologue.exp: Correct saved registers. Index: rs6000-tdep.c =================================================================== RCS file: /scratch/gcc/repos/src/src/gdb/rs6000-tdep.c,v retrieving revision 1.300 diff -u -p -r1.300 rs6000-tdep.c --- rs6000-tdep.c 19 Nov 2007 05:06:24 -0000 1.300 +++ rs6000-tdep.c 6 Dec 2007 20:09:33 -0000 @@ -118,17 +118,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 */ }; @@ -838,6 +841,7 @@ insn_changes_sp_or_jumps (unsigned long 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; @@ -865,6 +869,17 @@ rs6000_in_function_epilogue_p (struct gd 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; } @@ -1283,6 +1298,7 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l fdata->alloca_reg = -1; fdata->frameless = 1; fdata->nosavedpc = 1; + fdata->lr_register = -1; for (;; pc += 4) { @@ -1324,7 +1340,7 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l 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; @@ -1355,6 +1371,10 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l { 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; @@ -1446,6 +1466,7 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l else if (op == 0x48000005) { /* bl .+4 used in -mrelocatable */ + fdata->used_bl = 1; continue; } @@ -1470,7 +1491,10 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l /* 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 @@ -1496,8 +1520,9 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l 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) @@ -1758,11 +1783,15 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l 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 */ @@ -1815,6 +1844,9 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l } #endif /* 0 */ + if (pc == lim_pc && lr_reg >= 0) + fdata->lr_register = lr_reg; + fdata->offset = -fdata->offset; return last_prologue_pc; } @@ -2954,7 +2986,8 @@ rs6000_frame_cache (struct frame_info *n } /* 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) { @@ -2962,7 +2995,8 @@ rs6000_frame_cache (struct frame_info *n 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; } } @@ -3009,6 +3043,8 @@ rs6000_frame_cache (struct frame_info *n 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]; Index: testsuite/gdb.arch/powerpc-prologue.exp =================================================================== RCS file: /scratch/gcc/repos/src/src/gdb/testsuite/gdb.arch/powerpc-prologue.exp,v retrieving revision 1.4 diff -u -p -r1.4 powerpc-prologue.exp --- testsuite/gdb.arch/powerpc-prologue.exp 23 Aug 2007 18:14:16 -0000 1.4 +++ testsuite/gdb.arch/powerpc-prologue.exp 6 Dec 2007 21:39:53 -0000 @@ -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" ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Powerpc skip prologue 2008-08-09 16:12 ` Daniel Jacobowitz @ 2008-08-10 2:45 ` Joel Brobecker 2008-08-18 10:10 ` Joel Brobecker 0 siblings, 1 reply; 6+ messages in thread From: Joel Brobecker @ 2008-08-10 2:45 UTC (permalink / raw) To: Aleksandar Ristovski, gdb-patches, Jerome Guitton > Could you test an alternative for me? The patch from my December > message, but without rs6000_force_frame_sniffer, the > rs6000_gdbarch_init change, or the new testcase. I believe that will > cover the same cases as your patch, plus several others. This is a > slightly larger portion of the patch than Aleksandar reposted earlier. Sure! > 2008-08-09 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. > > * gdb.arch/powerpc-prologue.exp: Correct saved registers. This tested OK on ppc-linux :-). -- Joel ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Powerpc skip prologue 2008-08-10 2:45 ` Joel Brobecker @ 2008-08-18 10:10 ` Joel Brobecker 2008-08-18 12:35 ` Daniel Jacobowitz 0 siblings, 1 reply; 6+ messages in thread From: Joel Brobecker @ 2008-08-18 10:10 UTC (permalink / raw) To: Aleksandar Ristovski, gdb-patches, Jerome Guitton Hi Daniel, > > 2008-08-09 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. > > > > * gdb.arch/powerpc-prologue.exp: Correct saved registers. > > This tested OK on ppc-linux :-). Can we commit this change? I don't mind at all doing it for you, but I thought that doing it unilaterally was bad form :). -- Joel ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Powerpc skip prologue 2008-08-18 10:10 ` Joel Brobecker @ 2008-08-18 12:35 ` Daniel Jacobowitz 0 siblings, 0 replies; 6+ messages in thread From: Daniel Jacobowitz @ 2008-08-18 12:35 UTC (permalink / raw) To: Joel Brobecker; +Cc: Aleksandar Ristovski, gdb-patches, Jerome Guitton On Mon, Aug 18, 2008 at 02:09:54PM +0400, Joel Brobecker wrote: > Can we commit this change? I don't mind at all doing it for you, but > I thought that doing it unilaterally was bad form :). Checked in now. I haven't decided what to do with the remainder of the original patch - I'll think about it. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2008-08-18 12:35 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2008-07-28 20:59 Powerpc skip prologue Aleksandar Ristovski 2008-08-09 14:17 ` Joel Brobecker 2008-08-09 16:12 ` Daniel Jacobowitz 2008-08-10 2:45 ` Joel Brobecker 2008-08-18 10:10 ` Joel Brobecker 2008-08-18 12:35 ` Daniel Jacobowitz
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox