This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [RFA patch] PR18749: epilogue not tracked in dwarf2 unwind-info
- From: "Ulrich Weigand" <uweigand at de dot ibm dot com>
- To: matz at suse dot de, froydnj at cs dot rice dot edu
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Fri, 30 Jun 2006 07:48:08 +0200 (CEST)
- Subject: Re: [RFA patch] PR18749: epilogue not tracked in dwarf2 unwind-info
Daniel Jacobowitz wrote:
> On Mon, Jun 12, 2006 at 10:07:40PM +0200, Michael Matz wrote:
> > 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.
>
> Just FYI, there's also:
> http://gcc.gnu.org/ml/gcc-patches/2006-02/msg01091.html
If you're interested in yet another attempt, here's a version I've been
working on a couple of years ago, but never got around to cleaning up
for submitting ...
Bye,
Ulrich
Index: gcc/cfglayout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.c,v
retrieving revision 1.75
diff -c -p -r1.75 cfglayout.c
*** gcc/cfglayout.c 28 Sep 2004 07:59:42 -0000 1.75
--- gcc/cfglayout.c 21 Oct 2004 21:22:33 -0000
*************** insn_locators_initialize (void)
*** 319,325 ****
if (!prologue_locator && file_name)
prologue_locator = loc;
if (!next)
! epilogue_locator = loc;
if (active)
INSN_LOCATOR (insn) = loc;
}
--- 319,325 ----
if (!prologue_locator && file_name)
prologue_locator = loc;
if (!next)
! epilogue_locator = loc + 1;
if (active)
INSN_LOCATOR (insn) = loc;
}
Index: gcc/dwarf2out.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dwarf2out.c,v
retrieving revision 1.556
diff -c -p -r1.556 dwarf2out.c
*** gcc/dwarf2out.c 14 Oct 2004 23:30:18 -0000 1.556
--- gcc/dwarf2out.c 21 Oct 2004 21:22:35 -0000
*************** lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_loc
*** 677,686 ****
}
}
! /* Find the previous value for the CFA. */
static void
! lookup_cfa (dw_cfa_location *loc)
{
dw_cfi_ref cfi;
--- 677,687 ----
}
}
! /* Find the value of the CFA immediately before NEXT. If NEXT is NULL,
! find the current CFA value. */
static void
! lookup_cfa_before (dw_cfi_ref next, dw_cfa_location *loc)
{
dw_cfi_ref cfi;
*************** lookup_cfa (dw_cfa_location *loc)
*** 695,705 ****
if (fde_table_in_use)
{
dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
! for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
! lookup_cfa_1 (cfi, loc);
}
}
/* The current rule for calculating the DWARF2 canonical frame address. */
static dw_cfa_location cfa;
--- 696,717 ----
if (fde_table_in_use)
{
dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
! for (cfi = fde->dw_fde_cfi; cfi != next; cfi = cfi->dw_cfi_next)
! {
! gcc_assert (cfi);
! lookup_cfa_1 (cfi, loc);
! }
}
}
+ /* Find the previous value for the CFA. */
+
+ static void
+ lookup_cfa (dw_cfa_location *loc)
+ {
+ lookup_cfa_before (NULL, loc);
+ }
+
/* The current rule for calculating the DWARF2 canonical frame address. */
static dw_cfa_location cfa;
*************** reg_save (const char *label, unsigned in
*** 848,853 ****
--- 860,883 ----
add_fde_cfi (label, cfi);
}
+ /* Add the CFI for restoring a register to its initial value.
+ REG is the CFA column number, LABEL is passed to add_fde_cfi. */
+
+ static void
+ reg_restore (const char *label, unsigned int reg)
+ {
+ dw_cfi_ref cfi = new_cfi ();
+
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+
+ if (reg & ~0x3f)
+ cfi->dw_cfi_opc = DW_CFA_restore_extended;
+ else
+ cfi->dw_cfi_opc = DW_CFA_restore;
+
+ add_fde_cfi (label, cfi);
+ }
+
/* Add the CFI for saving a register window. LABEL is passed to reg_save.
This CFI tells the unwinder that it needs to restore the window registers
from the previous frame's window save area.
*************** dwarf2out_stack_adjust (rtx insn)
*** 1122,1127 ****
--- 1152,1251 ----
dwarf2out_args_size (label, args_size);
}
+ /* Remember current CFI state. */
+
+ static dw_cfi_ref *
+ dwarf2out_remember_state (void)
+ {
+ dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
+ dw_cfi_ref *p;
+
+ /* Find the end of the chain. */
+ for (p = &fde->dw_fde_cfi; (*p) != NULL; p = &(*p)->dw_cfi_next)
+ ;
+
+ return p;
+ }
+
+ /* Restore at current PC the state as of STATE (as returned by
+ dwarf2out_remember_state). */
+
+ static void
+ dwarf2out_restore_state (dw_cfi_ref *state)
+ {
+ const char *label = dwarf2out_cfi_label ();
+ bool need_restore = false;
+ dw_cfa_location cfa;
+ dw_cfi_ref cfi;
+
+ /* Check whether we had any register state changes between STATE
+ and the current PC. */
+ for (cfi = *state; cfi; cfi = cfi->dw_cfi_next)
+ switch (cfi->dw_cfi_opc)
+ {
+ /* These don't change any state. */
+ case DW_CFA_nop:
+ case DW_CFA_set_loc:
+ case DW_CFA_advance_loc1:
+ case DW_CFA_advance_loc2:
+ case DW_CFA_advance_loc4:
+ case DW_CFA_MIPS_advance_loc8:
+ break;
+
+ /* We'll restore the CFA separately. */
+ case DW_CFA_def_cfa:
+ case DW_CFA_def_cfa_sf:
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_def_cfa_offset:
+ case DW_CFA_def_cfa_offset_sf:
+ case DW_CFA_def_cfa_expression:
+ break;
+
+ /* These mean we'll have to restore register state. */
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_register:
+ case DW_CFA_offset:
+ case DW_CFA_offset_extended:
+ case DW_CFA_offset_extended_sf:
+ case DW_CFA_restore:
+ case DW_CFA_restore_extended:
+ case DW_CFA_expression:
+ need_restore = true;
+ break;
+
+ /* ??? We should handle these. */
+ case DW_CFA_GNU_window_save:
+ case DW_CFA_GNU_args_size:
+ gcc_unreachable ();
+
+ /* We never generate nested remember/restore state pairs. */
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
+ default:
+ gcc_unreachable ();
+ }
+
+ /* If required, save and restore register state. */
+ if (need_restore)
+ {
+ /* Insert 'remember state' at STATE ... */
+ cfi = new_cfi ();
+ cfi->dw_cfi_opc = DW_CFA_remember_state;
+ cfi->dw_cfi_next = *state;
+ *state = cfi;
+
+ /* ... and 'restore state' at current PC. */
+ cfi = new_cfi ();
+ cfi->dw_cfi_opc = DW_CFA_restore_state;
+ add_fde_cfi (label, cfi);
+ }
+
+ /* Look up the CFA as of STATE, and reset the current CFA. */
+ lookup_cfa_before (*state, &cfa);
+ def_cfa_1 (label, &cfa);
+ }
+
#endif
/* We delay emitting a register save until either (a) we reach the end
*************** static GTY(()) size_t num_regs_saved_in_
*** 1155,1161 ****
static const char *last_reg_save_label;
/* Add an entry to QUEUED_REG_SAVES saying that REG is now saved at
! SREG, or if SREG is NULL then it is saved at OFFSET to the CFA. */
static void
queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset)
--- 1279,1287 ----
static const char *last_reg_save_label;
/* Add an entry to QUEUED_REG_SAVES saying that REG is now saved at
! SREG, or if SREG is NULL then it is saved at OFFSET to the CFA.
! If SREG is const0_rtx, REG is now restored to its original value
! at function entry. */
static void
queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset)
*************** flush_queued_reg_saves (void)
*** 1198,1204 ****
for (i = 0; i < num_regs_saved_in_regs; i++)
if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (q->reg))
break;
! if (q->saved_reg && i == num_regs_saved_in_regs)
{
gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
num_regs_saved_in_regs++;
--- 1324,1331 ----
for (i = 0; i < num_regs_saved_in_regs; i++)
if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (q->reg))
break;
! if (q->saved_reg && q->saved_reg != const0_rtx
! && i == num_regs_saved_in_regs)
{
gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
num_regs_saved_in_regs++;
*************** flush_queued_reg_saves (void)
*** 1206,1220 ****
if (i != num_regs_saved_in_regs)
{
regs_saved_in_regs[i].orig_reg = q->reg;
! regs_saved_in_regs[i].saved_in_reg = q->saved_reg;
}
reg = DWARF_FRAME_REGNUM (REGNO (q->reg));
! if (q->saved_reg)
! sreg = DWARF_FRAME_REGNUM (REGNO (q->saved_reg));
else
! sreg = INVALID_REGNUM;
! reg_save (last_reg_save_label, reg, sreg, q->cfa_offset);
}
queued_reg_saves = NULL;
--- 1333,1355 ----
if (i != num_regs_saved_in_regs)
{
regs_saved_in_regs[i].orig_reg = q->reg;
! regs_saved_in_regs[i].saved_in_reg =
! q->saved_reg != const0_rtx ? q->saved_reg : NULL_RTX;
}
reg = DWARF_FRAME_REGNUM (REGNO (q->reg));
!
! if (q->saved_reg != const0_rtx)
! {
! if (q->saved_reg)
! sreg = DWARF_FRAME_REGNUM (REGNO (q->saved_reg));
! else
! sreg = INVALID_REGNUM;
!
! reg_save (last_reg_save_label, reg, sreg, q->cfa_offset);
! }
else
! reg_restore (last_reg_save_label, reg);
}
queued_reg_saves = NULL;
*************** dwarf2out_frame_debug_expr (rtx expr, co
*** 1490,1495 ****
--- 1625,1636 ----
cfa_temp.reg = cfa.reg;
cfa_temp.offset = cfa.offset;
}
+ else if (REGNO (dest) == REGNO (src))
+ {
+ /* This is a marker for an epilogue insn that restores a
+ register to its initial value at function entry. */
+ queue_reg_save (label, dest, const0_rtx, 0);
+ }
else
{
/* Saving a register in a register. */
*************** dwarf2out_frame_debug_expr (rtx expr, co
*** 1772,1779 ****
void
dwarf2out_frame_debug (rtx insn)
{
const char *label;
! rtx src;
if (insn == NULL_RTX)
{
--- 1913,1921 ----
void
dwarf2out_frame_debug (rtx insn)
{
+ static dw_cfi_ref *epilogue_state;
const char *label;
! rtx src, next;
if (insn == NULL_RTX)
{
*************** dwarf2out_frame_debug (rtx insn)
*** 1798,1809 ****
--- 1940,1961 ----
regs_saved_in_regs[i].saved_in_reg = NULL_RTX;
}
num_regs_saved_in_regs = 0;
+ epilogue_state = NULL;
return;
}
if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn))
flush_queued_reg_saves ();
+ /* If we run into the end of the epilogue, and we had emitted CFI for it,
+ restore CFA and register state for instructions after the epilogue. */
+ if (BARRIER_P (insn) && epilogue_state
+ && (next = next_active_insn (insn)) != NULL_RTX)
+ {
+ dwarf2out_restore_state (epilogue_state);
+ epilogue_state = NULL;
+ }
+
if (! RTX_FRAME_RELATED_P (insn))
{
if (!ACCUMULATE_OUTGOING_ARGS)
*************** dwarf2out_frame_debug (rtx insn)
*** 1812,1817 ****
--- 1964,1974 ----
return;
}
+ /* If we start emitting CFI for epilogue instructions, remember the
+ start of the epilogue so we can restore the state later. */
+ if (!epilogue_state && INSN_LOCATOR (insn) == epilogue_locator)
+ epilogue_state = dwarf2out_remember_state ();
+
label = dwarf2out_cfi_label ();
src = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
if (src)
*************** dw_cfi_oprnd1_desc (enum dwarf_call_fram
*** 1834,1839 ****
--- 1991,1998 ----
switch (cfi)
{
case DW_CFA_nop:
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
case DW_CFA_GNU_window_save:
return dw_cfi_oprnd_unused;
*************** dw_cfi_oprnd1_desc (enum dwarf_call_fram
*** 1849,1854 ****
--- 2008,2014 ----
case DW_CFA_def_cfa:
case DW_CFA_offset_extended_sf:
case DW_CFA_def_cfa_sf:
+ case DW_CFA_restore:
case DW_CFA_restore_extended:
case DW_CFA_undefined:
case DW_CFA_same_value:
*************** output_cfi (dw_cfi_ref cfi, dw_fde_ref f
*** 2007,2012 ****
--- 2167,2174 ----
dw2_asm_output_data_sleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL);
break;
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
case DW_CFA_GNU_window_save:
break;
Index: gcc/emit-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.420
diff -c -p -r1.420 emit-rtl.c
*** gcc/emit-rtl.c 18 Oct 2004 01:56:03 -0000 1.420
--- gcc/emit-rtl.c 21 Oct 2004 21:22:35 -0000
*************** emit_copy_of_insn_after (rtx insn, rtx a
*** 5527,5532 ****
--- 5527,5533 ----
{
case INSN:
new = emit_insn_after (copy_insn (PATTERN (insn)), after);
+ RTX_FRAME_RELATED_P (new) = RTX_FRAME_RELATED_P (insn);
break;
case JUMP_INSN:
Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.194
diff -c -p -r1.194 s390.c
*** gcc/config/s390/s390.c 14 Oct 2004 18:32:04 -0000 1.194
--- gcc/config/s390/s390.c 21 Oct 2004 21:22:38 -0000
*************** restore_gprs (rtx base, int offset, int
*** 6624,6636 ****
insn = gen_movdi (gen_rtx_REG (Pmode, first), addr);
else
insn = gen_movsi (gen_rtx_REG (Pmode, first), addr);
! return insn;
}
- insn = gen_load_multiple (gen_rtx_REG (Pmode, first),
- addr,
- GEN_INT (last - first + 1));
return insn;
}
--- 6624,6651 ----
insn = gen_movdi (gen_rtx_REG (Pmode, first), addr);
else
insn = gen_movsi (gen_rtx_REG (Pmode, first), addr);
+ }
+ else
+ insn = gen_load_multiple (gen_rtx_REG (Pmode, first), addr,
+ GEN_INT (last - first + 1));
+
+ /* Generate DWARF-2 CFI annotations to restore the CFA for use within the
+ epilogue. */
+
+ if (first <= STACK_POINTER_REGNUM && STACK_POINTER_REGNUM <= last)
+ {
+ rtx fp, note;
! fp = frame_pointer_needed? hard_frame_pointer_rtx : stack_pointer_rtx;
! note = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
! plus_constant (fp, cfun_frame_layout.frame_size));
!
! REG_NOTES (insn) =
! gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, note, REG_NOTES (insn));
!
! RTX_FRAME_RELATED_P (insn) = 1;
}
return insn;
}
*************** s390_emit_epilogue (bool sibcall)
*** 7007,7012 ****
--- 7022,7029 ----
if (TARGET_64BIT)
{
+ rtx insn;
+
if (cfun_save_high_fprs_p)
{
next_offset = cfun_frame_layout.f8_offset;
*************** s390_emit_epilogue (bool sibcall)
*** 7014,7026 ****
{
if (cfun_fpr_bit_p (i - 16))
{
! restore_fpr (frame_pointer,
! offset + next_offset, i);
next_offset += 8;
}
}
}
-
}
else
{
--- 7031,7048 ----
{
if (cfun_fpr_bit_p (i - 16))
{
! insn = restore_fpr (frame_pointer, offset + next_offset, i);
! RTX_FRAME_RELATED_P (insn) = 1;
! REG_NOTES (insn) =
! gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
! gen_rtx_SET (VOIDmode,
! gen_rtx_REG (DFmode, i),
! gen_rtx_REG (DFmode, i)),
! REG_NOTES (insn));
next_offset += 8;
}
}
}
}
else
{
--
Dr. Ulrich Weigand
Linux on zSeries Development
Ulrich.Weigand@de.ibm.com