[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