[RFA patch] PR18749: epilogue not tracked in dwarf2 unwind-info
Michael Matz
matz@suse.de
Mon Jun 12 20:07:00 GMT 2006
Hi,
I'm trying to fix PR18749, which is about the fact that dwarf2out.c
doesn't look at epilogues at all, which makes the CFA be wrong during the
epilogue, as no adjustments there (like pops, or additions to the stack
pointer) are tracked.
There are two things which need to be solved:
1) looking at the epilogue at all, and tracking its effects
2) supporting epilogues in the middle of a function
I'd like to know what people think of my attempt(s) to solve this.
For 1) I chose to only support jump-less epilogues. That means I can
simply save the whole state before the epilogue, and restore it completely
afterwards. (I did not look into using
DW_CFA_remember_state/restore_state)
For 2) I see two solutions: a) Marking all epilogue insns as
RTX_FRAME_RELATED_P, and b) looking at the unmarked epilogue instructions
for stack adjustments (via dwarf2out_stack_adjust(), which is done only on
non-ACCUMULATE_OUTGOING_ARGS currently).
a) theoretically is more precise, as also register restores could be
tracked. But it would need some more support in
dwarf2out.c:dwarf2out_frame_debug_expr, and hence would complicate the
already non-trivial set of rules. And of course this solution would
require changes in the backends to actually also mark the epilogue
instructions.
b) would be enough to solve the bug report, in that it correctly would
track the CFA address, should it change by stack adjustments in the
epilogue. It would leave some entries in the regs table in the unwind
context pointing below the CFA, though, because register restores can't be
tracked in this way. (One could trivially nullify any entries becoming
invalid).
I've attached a preliminary and unclean patch to do 1) and 2b) and seek
some feedback on them.
On this testcase:
int func (int arg, int t) {
int i, arr[1024];
if (t)
for (i = 0; i < arg; ++i)
arr[i] = func (arg - 1, t);
else
arg = 1;
return arr[arg/2];
}
I now get this readelf -wF output (with -O2 on x86_64):
00000018 00000024 0000001c FDE cie=00000000 pc=00000000..0000009e
LOC CFA r3 r6 r12 r13 r14 ra
00000000 r7+8 u u u u u c-8
00000016 r7+8 c-48 c-40 c-32 u c-16 c-8
00000025 r7+4144 c-48 c-40 c-32 c-24 c-16 c-8
00000092 r7+8 c-48 c-40 c-32 c-24 c-16 c-8
00000093 r7+4144 c-48 c-40 c-32 c-24 c-16 c-8
Without the patch the last two rows would be missing, which means the CFA
would be incorrect during the epilogue. (here there's only one insn after
the adjustment in the epilogue, so it's no that interesting, but with -Os
it get's more interesting).
At first I actually implemented 2a) on i386/x86_64, with the necessary
backend changes, and some required support in dwarf2out.c. But it was
quite some more work, and even then wasn't complete at all, so I thought
asking here is better before putting more work into that way, when perhaps
the simple one would do.
Advices, thoughts?
Ciao,
Michael.
Index: dwarf2out.c
===================================================================
--- dwarf2out.c (revision 114560)
+++ dwarf2out.c (working copy)
@@ -1079,6 +1079,8 @@ stack_adjust_offset (rtx pattern)
make a note of it if it does. EH uses this information to find out how
much extra space it needs to pop off the stack. */
+extern int prologue_contains (rtx insn);
+
static void
dwarf2out_stack_adjust (rtx insn, bool after_p ATTRIBUTE_UNUSED)
{
@@ -1090,7 +1092,7 @@ dwarf2out_stack_adjust (rtx insn, bool a
with this function. Proper support would require all frame-related
insns to be marked, and to be able to handle saving state around
epilogues textually in the middle of the function. */
- if (prologue_epilogue_contains (insn) || sibcall_epilogue_contains (insn))
+ if (prologue_contains (insn))
return;
if (BARRIER_P (insn))
@@ -1695,6 +1697,12 @@ dwarf2out_frame_debug_expr (rtx expr, co
targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1));
return;
+ /* A restore probably. */
+ case MEM:
+ /* XXX implement this. Especially handle the effects on
+ the CFA if popping insns are used. */
+ break;
+
default:
gcc_unreachable ();
}
@@ -1847,6 +1855,10 @@ dwarf2out_frame_debug_expr (rtx expr, co
If AFTER_P is false, we're being called before the insn is emitted,
otherwise after. Call instructions get invoked twice. */
+extern int epilogue_contains (rtx insn);
+dw_cfa_location save_cfa, save_cfa_store, save_cfa_temp;
+int have_saved_cfa;
+
void
dwarf2out_frame_debug (rtx insn, bool after_p)
{
@@ -1876,15 +1888,41 @@ dwarf2out_frame_debug (rtx insn, bool af
regs_saved_in_regs[i].saved_in_reg = NULL_RTX;
}
num_regs_saved_in_regs = 0;
+ have_saved_cfa = 0;
return;
}
+ if (have_saved_cfa && BARRIER_P (insn))
+ {
+ label = dwarf2out_cfi_label ();
+ cfa = save_cfa;
+ cfa_store = save_cfa_store;
+ cfa_temp = save_cfa_temp;
+ have_saved_cfa = 0;
+ def_cfa_1 (label, &cfa);
+ }
+
+ /* Make sure that we don't jump out of the epilogue, once we have
+ entered it. Accept the final return, of course. */
+ gcc_assert (!have_saved_cfa || !JUMP_P (insn) || returnjump_p (insn));
+
if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn))
flush_queued_reg_saves ();
+ if (!have_saved_cfa
+ && (epilogue_contains (insn) || sibcall_epilogue_contains (insn)))
+ {
+ save_cfa = cfa;
+ save_cfa_store = cfa_store;
+ save_cfa_temp = cfa_temp;
+ have_saved_cfa = 1;
+ }
+
if (! RTX_FRAME_RELATED_P (insn))
{
- if (!ACCUMULATE_OUTGOING_ARGS)
+ if (!ACCUMULATE_OUTGOING_ARGS
+ || epilogue_contains (insn)
+ || sibcall_epilogue_contains (insn))
dwarf2out_stack_adjust (insn, after_p);
return;
}
Index: function.c
===================================================================
--- function.c (revision 114560)
+++ function.c (working copy)
@@ -4681,6 +4681,22 @@ contains (rtx insn, VEC(int,heap) **vec)
}
int
+prologue_contains (rtx insn)
+{
+ if (contains (insn, &prologue))
+ return 1;
+ return 0;
+}
+
+int
+epilogue_contains (rtx insn)
+{
+ if (contains (insn, &epilogue))
+ return 1;
+ return 0;
+}
+
+int
prologue_epilogue_contains (rtx insn)
{
if (contains (insn, &prologue))
More information about the Gcc-patches
mailing list