This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Fix PR debug/24444: incorrect frame base in IA64 prologues
- From: Alexandre Oliva <aoliva at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: rth at redhat dot com, jakub at redhat dot com
- Date: Fri, 03 Feb 2006 06:33:55 -0200
- Subject: Fix PR debug/24444: incorrect frame base in IA64 prologues
The attached patches, for trunk and 4.1 branch respectively (only line
offset differences), fix the portion of the debug info regression
introduced in revision -r103983 that was not fixed with Jim Wilson's
patch for bug 24444.
With this patch, we switch to using the CFA as the frame base on all
targets, even those that do not use DWARF2 frame or unwind info (like
IA64). The bug report says ARM might suffer from the same problem,
because it also has its own internal unwind info, but I could not find
any such problem on arm-linux-gnu or arm-eabi: the latter emits DWARF2
frame info in addition to its own unwind info, so debug info is
correct within the prologue as much as it is in steady state.
This was not the case of IA64, since it did not want frame info
either, given that its unwind info is sufficiently complete for
debuggers to use.
I had to tweak a little bit the definitions of DWARF2_FRAME_INFO, so
as to avoid emitting frame info for IA64 while still computing the
info needed to determine the CFA offsets. I also arranged for
DWARF2_UNWIND_INFO's run-time value to be tested at places where we'd
formerly only test for a definition, so target could now switch it on
or off depending on command-line options.
We used to emit a separate region for the epilogue, between the SP
restore and the return, but that's mainly useless since they're
normally neighbors. No other targets emit separate regions for that
part of the epilogue, so I left the code to do so disabled in my
patch, but it could be easily enabled, should someone want to restore
the ability to set a breakpoint on the return instruction and still
print the values of variables et al, by changing a simple macro
definition.
The patch also fixes the definition of ARG_POINTER_CFA_OFFSET for
IA64; it was not taking into account the fact that ARG_POINTER is past
the red zone, whereas CFA is not.
This patch is past stage2 on ia64 and x86_64, both trunk and 4.1
branches, and I've verified that the intended debug info regression
fix is present, namely, compiling with optimization a function with a
large number of arguments, some of which are passed on the stack, and
setting a breakpoint on the function's entry point, the values of all
arguments are printed correctly by gdb. Before the patch, arguments
passed on the stack would not have the correct values.
Without optimization, the patch brings little to no improvement, since
the debug info we emit for the arguments refer to copies of the
incoming arguments, allocated in the function's own stack frame, so at
the prologue they are not initialized yet. We get incorrect values
for *all* incoming arguments.
Ok for trunk and branch if bootstrap and testing completes
successfully on both platforms?
Index: gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
PR debug/24444
* config/ia64/ia64.c: Include debug.h.
(MAX_ARTIFICIAL_LABEL_BYTES): New.
(ia64_label_after_insn, ia64_dwarf2out_def_steady_cfa): New.
(IA64_CHANGE_CFA_IN_EPILOGUE): Define to 0.
(process_epilogue, process_set, process_for_unwind_directive):
Output unwind info only if requested. Add CFA info if requested.
Add new arguments as needed. Adjust callers.
* config/ia64/ia64.h (ARG_POINTER_CFA_OFFSET): Override
incorrect default.
(DWARF2_FRAME_INFO): Define to zero.
* config/ia64/t-ia64 (ia64.o): Depend on debug.h.
* dwarf2out.c (DWARF2_FRAME_INFO): Define default.
(dwarf2out_do_frame): Require nonzero DWARF2_UNWIND_INFO for
-funwind-tables and -fexceptions to enable frame info.
(dwarf2out_frame_init): Define initial CFA even if
DWARF2_UNWIND_INFO is disabled. Call initial_return_save if
DWARF2_UNWIND_INFO is nonzero, not just defined.
(dwarf2out_frame_finish): Output non-EH call frame info only
if DWARF2_FRAME_INFO is nonzero.
(convert_cfa_to_loc_list,
compute_frame_pointer_to_cfa_displacement): Define even if
unwind info is not supported.
(gen_subprogram_die): Use the above unconditionally. Remove
legacy alternate code.
* toplev.c (compile_file): Compile in call to
dwarf2out_frame_finish if DWARF2_DEBUGGING_INFO is defined.
(lang_dependent_init): Ditto for dwarf2out_frame_init.
Index: gcc/config/ia64/ia64.c
===================================================================
--- gcc/config/ia64/ia64.c.orig 2005-12-16 14:40:47.000000000 -0200
+++ gcc/config/ia64/ia64.c 2006-02-03 04:28:33.000000000 -0200
@@ -53,6 +53,7 @@ Boston, MA 02110-1301, USA. */
#include "cfglayout.h"
#include "tree-gimple.h"
#include "intl.h"
+#include "debug.h"
/* This is used for communication between ASM_OUTPUT_LABEL and
ASM_OUTPUT_LABELREF. */
@@ -190,8 +191,8 @@ static void final_emit_insn_group_barrie
static void emit_predicate_relation_info (void);
static void ia64_reorg (void);
static bool ia64_in_small_data_p (tree);
-static void process_epilogue (void);
-static int process_set (FILE *, rtx);
+static void process_epilogue (FILE *, rtx, bool, bool);
+static int process_set (FILE *, rtx, rtx, bool, bool);
static bool ia64_assemble_integer (rtx, unsigned int, int);
static void ia64_output_function_prologue (FILE *, HOST_WIDE_INT);
@@ -7971,29 +7972,84 @@ static bool last_block;
static bool need_copy_state;
+#ifndef MAX_ARTIFICIAL_LABEL_BYTES
+# define MAX_ARTIFICIAL_LABEL_BYTES 30
+#endif
+
+/* Emit a debugging label after a call-frame-related insn. We'd
+ rather output the label right away, but we'd have to output it
+ after, not before, the instruction, and the instruction has not
+ been output yet. So we emit the label after the insn, delete it to
+ avoid introducing basic blocks, and mark it as preserved, such that
+ it is still output, given that it is referenced in debug info. */
+
+static const char *
+ia64_emit_deleted_label_after_insn (rtx insn)
+{
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ rtx lb = gen_label_rtx ();
+ rtx label_insn = emit_label_after (lb, insn);
+
+ LABEL_PRESERVE_P (lb) = 1;
+
+ delete_insn (label_insn);
+
+ ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (label_insn));
+
+ return xstrdup (label);
+}
+
+/* Define the CFA after INSN with the steady-state definition. */
+
+static void
+ia64_dwarf2out_def_steady_cfa (rtx insn)
+{
+ rtx fp = frame_pointer_needed
+ ? hard_frame_pointer_rtx
+ : stack_pointer_rtx;
+
+ dwarf2out_def_cfa
+ (ia64_emit_deleted_label_after_insn (insn),
+ REGNO (fp),
+ ia64_initial_elimination_offset
+ (REGNO (arg_pointer_rtx), REGNO (fp))
+ + ARG_POINTER_CFA_OFFSET (current_function_decl));
+}
+
+/* The generic dwarf2 frame debug info generator does not define a
+ separate region for the very end of the epilogue, so refrain from
+ doing so in the IA64-specific code as well. */
+
+#define IA64_CHANGE_CFA_IN_EPILOGUE 0
+
/* The function emits unwind directives for the start of an epilogue. */
static void
-process_epilogue (void)
+process_epilogue (FILE *asm_out_file, rtx insn, bool unwind, bool frame)
{
/* If this isn't the last block of the function, then we need to label the
current state, and copy it back in at the start of the next block. */
if (!last_block)
{
- fprintf (asm_out_file, "\t.label_state %d\n",
- ++cfun->machine->state_num);
+ if (unwind)
+ fprintf (asm_out_file, "\t.label_state %d\n",
+ ++cfun->machine->state_num);
need_copy_state = true;
}
- fprintf (asm_out_file, "\t.restore sp\n");
+ if (unwind)
+ fprintf (asm_out_file, "\t.restore sp\n");
+ if (IA64_CHANGE_CFA_IN_EPILOGUE && frame)
+ dwarf2out_def_cfa (ia64_emit_deleted_label_after_insn (insn),
+ STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
}
/* This function processes a SET pattern looking for specific patterns
which result in emitting an assembly directive required for unwinding. */
static int
-process_set (FILE *asm_out_file, rtx pat)
+process_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame)
{
rtx src = SET_SRC (pat);
rtx dest = SET_DEST (pat);
@@ -8009,8 +8065,11 @@ process_set (FILE *asm_out_file, rtx pat
/* If this is the final destination for ar.pfs, then this must
be the alloc in the prologue. */
if (dest_regno == current_frame_info.reg_save_ar_pfs)
- fprintf (asm_out_file, "\t.save ar.pfs, r%d\n",
- ia64_dbx_register_number (dest_regno));
+ {
+ if (unwind)
+ fprintf (asm_out_file, "\t.save ar.pfs, r%d\n",
+ ia64_dbx_register_number (dest_regno));
+ }
else
{
/* This must be an alloc before a sibcall. We must drop the
@@ -8021,8 +8080,9 @@ process_set (FILE *asm_out_file, rtx pat
sp" now. */
if (current_frame_info.total_size == 0 && !frame_pointer_needed)
/* if haven't done process_epilogue() yet, do it now */
- process_epilogue ();
- fprintf (asm_out_file, "\t.prologue\n");
+ process_epilogue (asm_out_file, insn, unwind, frame);
+ if (unwind)
+ fprintf (asm_out_file, "\t.prologue\n");
}
return 1;
}
@@ -8038,16 +8098,22 @@ process_set (FILE *asm_out_file, rtx pat
gcc_assert (op0 == dest && GET_CODE (op1) == CONST_INT);
if (INTVAL (op1) < 0)
- fprintf (asm_out_file, "\t.fframe "HOST_WIDE_INT_PRINT_DEC"\n",
- -INTVAL (op1));
+ {
+ gcc_assert (!frame_pointer_needed);
+ if (unwind)
+ fprintf (asm_out_file, "\t.fframe "HOST_WIDE_INT_PRINT_DEC"\n",
+ -INTVAL (op1));
+ if (frame)
+ ia64_dwarf2out_def_steady_cfa (insn);
+ }
else
- process_epilogue ();
+ process_epilogue (asm_out_file, insn, unwind, frame);
}
else
{
gcc_assert (GET_CODE (src) == REG
&& REGNO (src) == HARD_FRAME_POINTER_REGNUM);
- process_epilogue ();
+ process_epilogue (asm_out_file, insn, unwind, frame);
}
return 1;
@@ -8064,33 +8130,40 @@ process_set (FILE *asm_out_file, rtx pat
case BR_REG (0):
/* Saving return address pointer. */
gcc_assert (dest_regno == current_frame_info.reg_save_b0);
- fprintf (asm_out_file, "\t.save rp, r%d\n",
- ia64_dbx_register_number (dest_regno));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save rp, r%d\n",
+ ia64_dbx_register_number (dest_regno));
return 1;
case PR_REG (0):
gcc_assert (dest_regno == current_frame_info.reg_save_pr);
- fprintf (asm_out_file, "\t.save pr, r%d\n",
- ia64_dbx_register_number (dest_regno));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save pr, r%d\n",
+ ia64_dbx_register_number (dest_regno));
return 1;
case AR_UNAT_REGNUM:
gcc_assert (dest_regno == current_frame_info.reg_save_ar_unat);
- fprintf (asm_out_file, "\t.save ar.unat, r%d\n",
- ia64_dbx_register_number (dest_regno));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save ar.unat, r%d\n",
+ ia64_dbx_register_number (dest_regno));
return 1;
case AR_LC_REGNUM:
gcc_assert (dest_regno == current_frame_info.reg_save_ar_lc);
- fprintf (asm_out_file, "\t.save ar.lc, r%d\n",
- ia64_dbx_register_number (dest_regno));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save ar.lc, r%d\n",
+ ia64_dbx_register_number (dest_regno));
return 1;
case STACK_POINTER_REGNUM:
gcc_assert (dest_regno == HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed);
- fprintf (asm_out_file, "\t.vframe r%d\n",
- ia64_dbx_register_number (dest_regno));
+ if (unwind)
+ fprintf (asm_out_file, "\t.vframe r%d\n",
+ ia64_dbx_register_number (dest_regno));
+ if (frame)
+ ia64_dwarf2out_def_steady_cfa (insn);
return 1;
default:
@@ -8135,35 +8208,41 @@ process_set (FILE *asm_out_file, rtx pat
{
case BR_REG (0):
gcc_assert (!current_frame_info.reg_save_b0);
- fprintf (asm_out_file, "\t%s rp, %ld\n", saveop, off);
+ if (unwind)
+ fprintf (asm_out_file, "\t%s rp, %ld\n", saveop, off);
return 1;
case PR_REG (0):
gcc_assert (!current_frame_info.reg_save_pr);
- fprintf (asm_out_file, "\t%s pr, %ld\n", saveop, off);
+ if (unwind)
+ fprintf (asm_out_file, "\t%s pr, %ld\n", saveop, off);
return 1;
case AR_LC_REGNUM:
gcc_assert (!current_frame_info.reg_save_ar_lc);
- fprintf (asm_out_file, "\t%s ar.lc, %ld\n", saveop, off);
+ if (unwind)
+ fprintf (asm_out_file, "\t%s ar.lc, %ld\n", saveop, off);
return 1;
case AR_PFS_REGNUM:
gcc_assert (!current_frame_info.reg_save_ar_pfs);
- fprintf (asm_out_file, "\t%s ar.pfs, %ld\n", saveop, off);
+ if (unwind)
+ fprintf (asm_out_file, "\t%s ar.pfs, %ld\n", saveop, off);
return 1;
case AR_UNAT_REGNUM:
gcc_assert (!current_frame_info.reg_save_ar_unat);
- fprintf (asm_out_file, "\t%s ar.unat, %ld\n", saveop, off);
+ if (unwind)
+ fprintf (asm_out_file, "\t%s ar.unat, %ld\n", saveop, off);
return 1;
case GR_REG (4):
case GR_REG (5):
case GR_REG (6):
case GR_REG (7):
- fprintf (asm_out_file, "\t.save.g 0x%x\n",
- 1 << (src_regno - GR_REG (4)));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save.g 0x%x\n",
+ 1 << (src_regno - GR_REG (4)));
return 1;
case BR_REG (1):
@@ -8171,24 +8250,27 @@ process_set (FILE *asm_out_file, rtx pat
case BR_REG (3):
case BR_REG (4):
case BR_REG (5):
- fprintf (asm_out_file, "\t.save.b 0x%x\n",
- 1 << (src_regno - BR_REG (1)));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save.b 0x%x\n",
+ 1 << (src_regno - BR_REG (1)));
return 1;
case FR_REG (2):
case FR_REG (3):
case FR_REG (4):
case FR_REG (5):
- fprintf (asm_out_file, "\t.save.f 0x%x\n",
- 1 << (src_regno - FR_REG (2)));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save.f 0x%x\n",
+ 1 << (src_regno - FR_REG (2)));
return 1;
case FR_REG (16): case FR_REG (17): case FR_REG (18): case FR_REG (19):
case FR_REG (20): case FR_REG (21): case FR_REG (22): case FR_REG (23):
case FR_REG (24): case FR_REG (25): case FR_REG (26): case FR_REG (27):
case FR_REG (28): case FR_REG (29): case FR_REG (30): case FR_REG (31):
- fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n",
- 1 << (src_regno - FR_REG (12)));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n",
+ 1 << (src_regno - FR_REG (12)));
return 1;
default:
@@ -8205,8 +8287,11 @@ process_set (FILE *asm_out_file, rtx pat
void
process_for_unwind_directive (FILE *asm_out_file, rtx insn)
{
- if (flag_unwind_tables
- || (flag_exceptions && !USING_SJLJ_EXCEPTIONS))
+ bool unwind = (flag_unwind_tables
+ || (flag_exceptions && !USING_SJLJ_EXCEPTIONS));
+ bool frame = dwarf2out_do_frame ();
+
+ if (unwind || frame)
{
rtx pat;
@@ -8218,9 +8303,14 @@ process_for_unwind_directive (FILE *asm_
/* Restore unwind state from immediately before the epilogue. */
if (need_copy_state)
{
- fprintf (asm_out_file, "\t.body\n");
- fprintf (asm_out_file, "\t.copy_state %d\n",
- cfun->machine->state_num);
+ if (unwind)
+ {
+ fprintf (asm_out_file, "\t.body\n");
+ fprintf (asm_out_file, "\t.copy_state %d\n",
+ cfun->machine->state_num);
+ }
+ if (IA64_CHANGE_CFA_IN_EPILOGUE && frame)
+ ia64_dwarf2out_def_steady_cfa (insn);
need_copy_state = false;
}
}
@@ -8237,7 +8327,7 @@ process_for_unwind_directive (FILE *asm_
switch (GET_CODE (pat))
{
case SET:
- process_set (asm_out_file, pat);
+ process_set (asm_out_file, pat, insn, unwind, frame);
break;
case PARALLEL:
@@ -8248,7 +8338,7 @@ process_for_unwind_directive (FILE *asm_
{
rtx x = XVECEXP (pat, 0, par_index);
if (GET_CODE (x) == SET)
- process_set (asm_out_file, x);
+ process_set (asm_out_file, x, insn, unwind, frame);
}
break;
}
Index: gcc/config/ia64/ia64.h
===================================================================
--- gcc/config/ia64/ia64.h.orig 2006-02-03 03:09:18.000000000 -0200
+++ gcc/config/ia64/ia64.h 2006-02-03 04:04:03.000000000 -0200
@@ -981,6 +981,12 @@ enum reg_class
On some machines it may depend on the data type of the function. */
#define FIRST_PARM_OFFSET(FUNDECL) 0
+/* The CFA is defined as the SP at the call site, so we have to take
+ into account that the first argument pointer is
+ STACK_POINTER_OFFSET bytes off the stack pointer. */
+#define ARG_POINTER_CFA_OFFSET(FNDECL) \
+ (FIRST_PARM_OFFSET (FNDECL) - STACK_POINTER_OFFSET)
+
/* A C expression whose value is RTL representing the value of the return
address for the frame COUNT steps up from the current frame, after the
prologue. */
@@ -1867,6 +1873,12 @@ do { \
#define DWARF2_DEBUGGING_INFO 1
+/* We do not want call-frame info to be output, since debuggers are
+ supposed to use the target unwind info. Leave this undefined it
+ TARGET_UNWIND_INFO might ever be false. */
+
+#define DWARF2_FRAME_INFO 0
+
#define DWARF2_ASM_LINE_DEBUG_INFO (TARGET_DWARF2_ASM)
/* Use tags for debug info labels, so that they don't break instruction
Index: gcc/config/ia64/t-ia64
===================================================================
--- gcc/config/ia64/t-ia64.orig 2006-02-03 03:09:18.000000000 -0200
+++ gcc/config/ia64/t-ia64 2006-02-03 04:04:03.000000000 -0200
@@ -50,3 +50,5 @@ ia64-c.o: $(srcdir)/config/ia64/ia64-c.c
# genattrtab generates very long string literals.
insn-attrtab.o-warn = -Wno-error
+
+ia64.o: debug.h
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c.orig 2006-02-03 03:45:15.000000000 -0200
+++ gcc/dwarf2out.c 2006-02-03 05:41:31.000000000 -0200
@@ -90,20 +90,31 @@ static void dwarf2out_source_line (unsig
DW_CFA_... = DWARF2 CFA call frame instruction
DW_TAG_... = DWARF2 DIE tag */
+#ifndef DWARF2_FRAME_INFO
+# ifdef DWARF2_DEBUGGING_INFO
+# define DWARF2_FRAME_INFO \
+ (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
+# else
+# define DWARF2_FRAME_INFO 0
+# endif
+#endif
+
/* Decide whether we want to emit frame unwind information for the current
translation unit. */
int
dwarf2out_do_frame (void)
{
+ /* We want to emit correct CFA location expressions or lists, so we
+ have to return true if we're going to output debug info, even if
+ we're not going to output frame or unwind info. */
return (write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG
-#ifdef DWARF2_FRAME_INFO
|| DWARF2_FRAME_INFO
-#endif
#ifdef DWARF2_UNWIND_INFO
- || flag_unwind_tables
- || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)
+ || (DWARF2_UNWIND_INFO
+ && (flag_unwind_tables
+ || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)))
#endif
);
}
@@ -2586,10 +2597,12 @@ dwarf2out_frame_init (void)
/* Generate the CFA instructions common to all FDE's. Do it now for the
sake of lookup_cfa. */
-#ifdef DWARF2_UNWIND_INFO
/* On entry, the Canonical Frame Address is at SP. */
dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
- initial_return_save (INCOMING_RETURN_ADDR_RTX);
+
+#ifdef DWARF2_UNWIND_INFO
+ if (DWARF2_UNWIND_INFO)
+ initial_return_save (INCOMING_RETURN_ADDR_RTX);
#endif
}
@@ -2597,12 +2610,7 @@ void
dwarf2out_frame_finish (void)
{
/* Output call frame information. */
- if (write_symbols == DWARF2_DEBUG
- || write_symbols == VMS_AND_DWARF2_DEBUG
-#ifdef DWARF2_FRAME_INFO
- || DWARF2_FRAME_INFO
-#endif
- )
+ if (DWARF2_FRAME_INFO)
output_call_frame_info (0);
#ifndef TARGET_UNWIND_INFO
@@ -10326,7 +10334,6 @@ tree_add_const_value_attribute (dw_die_r
add_const_value_attribute (var_die, rtl);
}
-#ifdef DWARF2_UNWIND_INFO
/* Convert the CFI instructions for the current function into a location
list. This is used for DW_AT_frame_base when we targeting a dwarf2
consumer that does not support the dwarf3 DW_OP_call_frame_cfa. */
@@ -10433,7 +10440,6 @@ compute_frame_pointer_to_cfa_displacemen
frame_pointer_cfa_offset = -offset;
}
-#endif
/* Generate a DW_AT_name attribute given some string value to be included as
the value of the attribute. */
@@ -11668,7 +11674,6 @@ gen_subprogram_die (tree decl, dw_die_re
add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde);
#endif
-#ifdef DWARF2_UNWIND_INFO
/* We define the "frame base" as the function's CFA. This is more
convenient for several reasons: (1) It's stable across the prologue
and epilogue, which makes it better than just a frame pointer,
@@ -11695,17 +11700,6 @@ gen_subprogram_die (tree decl, dw_die_re
debugger about. We'll need to adjust all frame_base references
by this displacement. */
compute_frame_pointer_to_cfa_displacement ();
-#else
- /* For targets which support DWARF2, but not DWARF2 call-frame info,
- we just use the stack pointer or frame pointer. */
- /* ??? Should investigate getting better info via callbacks, or else
- by interpreting the IA-64 unwind info. */
- {
- rtx fp_reg
- = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
- add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
- }
-#endif
if (cfun->static_chain_decl)
add_AT_location_description (subr_die, DW_AT_static_link,
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c.orig 2006-02-03 03:45:15.000000000 -0200
+++ gcc/toplev.c 2006-02-03 04:04:03.000000000 -0200
@@ -1028,7 +1028,7 @@ compile_file (void)
/* Do dbx symbols. */
timevar_push (TV_SYMOUT);
-#ifdef DWARF2_UNWIND_INFO
+#if defined DWARF2_DEBUGGING_INFO || defined DWARF2_UNWIND_INFO
if (dwarf2out_do_frame ())
dwarf2out_frame_finish ();
#endif
@@ -1868,7 +1868,7 @@ lang_dependent_init (const char *name)
predefined types. */
timevar_push (TV_SYMOUT);
-#ifdef DWARF2_UNWIND_INFO
+#if defined DWARF2_DEBUGGING_INFO || defined DWARF2_UNWIND_INFO
if (dwarf2out_do_frame ())
dwarf2out_frame_init ();
#endif
Index: gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
PR debug/24444
* config/ia64/ia64.c: Include debug.h.
(MAX_ARTIFICIAL_LABEL_BYTES): New.
(ia64_label_after_insn, ia64_dwarf2out_def_steady_cfa): New.
(IA64_CHANGE_CFA_IN_EPILOGUE): Define to 0.
(process_epilogue, process_set, process_for_unwind_directive):
Output unwind info only if requested. Add CFA info if requested.
Add new arguments as needed. Adjust callers.
* config/ia64/ia64.h (ARG_POINTER_CFA_OFFSET): Override
incorrect default.
(DWARF2_FRAME_INFO): Define to zero.
* config/ia64/t-ia64 (ia64.o): Depend on debug.h.
* dwarf2out.c (DWARF2_FRAME_INFO): Define default.
(dwarf2out_do_frame): Require nonzero DWARF2_UNWIND_INFO for
-funwind-tables and -fexceptions to enable frame info.
(dwarf2out_frame_init): Define initial CFA even if
DWARF2_UNWIND_INFO is disabled. Call initial_return_save if
DWARF2_UNWIND_INFO is nonzero, not just defined.
(dwarf2out_frame_finish): Output non-EH call frame info only
if DWARF2_FRAME_INFO is nonzero.
(convert_cfa_to_loc_list,
compute_frame_pointer_to_cfa_displacement): Define even if
unwind info is not supported.
(gen_subprogram_die): Use the above unconditionally. Remove
legacy alternate code.
* toplev.c (compile_file): Compile in call to
dwarf2out_frame_finish if DWARF2_DEBUGGING_INFO is defined.
(lang_dependent_init): Ditto for dwarf2out_frame_init.
Index: gcc/config/ia64/ia64.c
===================================================================
--- gcc/config/ia64/ia64.c.orig 2005-12-02 18:13:36.000000000 -0200
+++ gcc/config/ia64/ia64.c 2006-02-03 04:35:36.000000000 -0200
@@ -53,6 +53,7 @@ Boston, MA 02110-1301, USA. */
#include "cfglayout.h"
#include "tree-gimple.h"
#include "intl.h"
+#include "debug.h"
/* This is used for communication between ASM_OUTPUT_LABEL and
ASM_OUTPUT_LABELREF. */
@@ -190,8 +191,8 @@ static void final_emit_insn_group_barrie
static void emit_predicate_relation_info (void);
static void ia64_reorg (void);
static bool ia64_in_small_data_p (tree);
-static void process_epilogue (void);
-static int process_set (FILE *, rtx);
+static void process_epilogue (FILE *, rtx, bool, bool);
+static int process_set (FILE *, rtx, rtx, bool, bool);
static bool ia64_assemble_integer (rtx, unsigned int, int);
static void ia64_output_function_prologue (FILE *, HOST_WIDE_INT);
@@ -7971,29 +7972,84 @@ static bool last_block;
static bool need_copy_state;
+#ifndef MAX_ARTIFICIAL_LABEL_BYTES
+# define MAX_ARTIFICIAL_LABEL_BYTES 30
+#endif
+
+/* Emit a debugging label after a call-frame-related insn. We'd
+ rather output the label right away, but we'd have to output it
+ after, not before, the instruction, and the instruction has not
+ been output yet. So we emit the label after the insn, delete it to
+ avoid introducing basic blocks, and mark it as preserved, such that
+ it is still output, given that it is referenced in debug info. */
+
+static const char *
+ia64_emit_deleted_label_after_insn (rtx insn)
+{
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ rtx lb = gen_label_rtx ();
+ rtx label_insn = emit_label_after (lb, insn);
+
+ LABEL_PRESERVE_P (lb) = 1;
+
+ delete_insn (label_insn);
+
+ ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (label_insn));
+
+ return xstrdup (label);
+}
+
+/* Define the CFA after INSN with the steady-state definition. */
+
+static void
+ia64_dwarf2out_def_steady_cfa (rtx insn)
+{
+ rtx fp = frame_pointer_needed
+ ? hard_frame_pointer_rtx
+ : stack_pointer_rtx;
+
+ dwarf2out_def_cfa
+ (ia64_emit_deleted_label_after_insn (insn),
+ REGNO (fp),
+ ia64_initial_elimination_offset
+ (REGNO (arg_pointer_rtx), REGNO (fp))
+ + ARG_POINTER_CFA_OFFSET (current_function_decl));
+}
+
+/* The generic dwarf2 frame debug info generator does not define a
+ separate region for the very end of the epilogue, so refrain from
+ doing so in the IA64-specific code as well. */
+
+#define IA64_CHANGE_CFA_IN_EPILOGUE 0
+
/* The function emits unwind directives for the start of an epilogue. */
static void
-process_epilogue (void)
+process_epilogue (FILE *asm_out_file, rtx insn, bool unwind, bool frame)
{
/* If this isn't the last block of the function, then we need to label the
current state, and copy it back in at the start of the next block. */
if (!last_block)
{
- fprintf (asm_out_file, "\t.label_state %d\n",
- ++cfun->machine->state_num);
+ if (unwind)
+ fprintf (asm_out_file, "\t.label_state %d\n",
+ ++cfun->machine->state_num);
need_copy_state = true;
}
- fprintf (asm_out_file, "\t.restore sp\n");
+ if (unwind)
+ fprintf (asm_out_file, "\t.restore sp\n");
+ if (IA64_CHANGE_CFA_IN_EPILOGUE && frame)
+ dwarf2out_def_cfa (ia64_emit_deleted_label_after_insn (insn),
+ STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
}
/* This function processes a SET pattern looking for specific patterns
which result in emitting an assembly directive required for unwinding. */
static int
-process_set (FILE *asm_out_file, rtx pat)
+process_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame)
{
rtx src = SET_SRC (pat);
rtx dest = SET_DEST (pat);
@@ -8009,8 +8065,11 @@ process_set (FILE *asm_out_file, rtx pat
/* If this is the final destination for ar.pfs, then this must
be the alloc in the prologue. */
if (dest_regno == current_frame_info.reg_save_ar_pfs)
- fprintf (asm_out_file, "\t.save ar.pfs, r%d\n",
- ia64_dbx_register_number (dest_regno));
+ {
+ if (unwind)
+ fprintf (asm_out_file, "\t.save ar.pfs, r%d\n",
+ ia64_dbx_register_number (dest_regno));
+ }
else
{
/* This must be an alloc before a sibcall. We must drop the
@@ -8021,8 +8080,9 @@ process_set (FILE *asm_out_file, rtx pat
sp" now. */
if (current_frame_info.total_size == 0 && !frame_pointer_needed)
/* if haven't done process_epilogue() yet, do it now */
- process_epilogue ();
- fprintf (asm_out_file, "\t.prologue\n");
+ process_epilogue (asm_out_file, insn, unwind, frame);
+ if (unwind)
+ fprintf (asm_out_file, "\t.prologue\n");
}
return 1;
}
@@ -8038,16 +8098,22 @@ process_set (FILE *asm_out_file, rtx pat
gcc_assert (op0 == dest && GET_CODE (op1) == CONST_INT);
if (INTVAL (op1) < 0)
- fprintf (asm_out_file, "\t.fframe "HOST_WIDE_INT_PRINT_DEC"\n",
- -INTVAL (op1));
+ {
+ gcc_assert (!frame_pointer_needed);
+ if (unwind)
+ fprintf (asm_out_file, "\t.fframe "HOST_WIDE_INT_PRINT_DEC"\n",
+ -INTVAL (op1));
+ if (frame)
+ ia64_dwarf2out_def_steady_cfa (insn);
+ }
else
- process_epilogue ();
+ process_epilogue (asm_out_file, insn, unwind, frame);
}
else
{
gcc_assert (GET_CODE (src) == REG
&& REGNO (src) == HARD_FRAME_POINTER_REGNUM);
- process_epilogue ();
+ process_epilogue (asm_out_file, insn, unwind, frame);
}
return 1;
@@ -8064,33 +8130,40 @@ process_set (FILE *asm_out_file, rtx pat
case BR_REG (0):
/* Saving return address pointer. */
gcc_assert (dest_regno == current_frame_info.reg_save_b0);
- fprintf (asm_out_file, "\t.save rp, r%d\n",
- ia64_dbx_register_number (dest_regno));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save rp, r%d\n",
+ ia64_dbx_register_number (dest_regno));
return 1;
case PR_REG (0):
gcc_assert (dest_regno == current_frame_info.reg_save_pr);
- fprintf (asm_out_file, "\t.save pr, r%d\n",
- ia64_dbx_register_number (dest_regno));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save pr, r%d\n",
+ ia64_dbx_register_number (dest_regno));
return 1;
case AR_UNAT_REGNUM:
gcc_assert (dest_regno == current_frame_info.reg_save_ar_unat);
- fprintf (asm_out_file, "\t.save ar.unat, r%d\n",
- ia64_dbx_register_number (dest_regno));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save ar.unat, r%d\n",
+ ia64_dbx_register_number (dest_regno));
return 1;
case AR_LC_REGNUM:
gcc_assert (dest_regno == current_frame_info.reg_save_ar_lc);
- fprintf (asm_out_file, "\t.save ar.lc, r%d\n",
- ia64_dbx_register_number (dest_regno));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save ar.lc, r%d\n",
+ ia64_dbx_register_number (dest_regno));
return 1;
case STACK_POINTER_REGNUM:
gcc_assert (dest_regno == HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed);
- fprintf (asm_out_file, "\t.vframe r%d\n",
- ia64_dbx_register_number (dest_regno));
+ if (unwind)
+ fprintf (asm_out_file, "\t.vframe r%d\n",
+ ia64_dbx_register_number (dest_regno));
+ if (frame)
+ ia64_dwarf2out_def_steady_cfa (insn);
return 1;
default:
@@ -8135,35 +8208,41 @@ process_set (FILE *asm_out_file, rtx pat
{
case BR_REG (0):
gcc_assert (!current_frame_info.reg_save_b0);
- fprintf (asm_out_file, "\t%s rp, %ld\n", saveop, off);
+ if (unwind)
+ fprintf (asm_out_file, "\t%s rp, %ld\n", saveop, off);
return 1;
case PR_REG (0):
gcc_assert (!current_frame_info.reg_save_pr);
- fprintf (asm_out_file, "\t%s pr, %ld\n", saveop, off);
+ if (unwind)
+ fprintf (asm_out_file, "\t%s pr, %ld\n", saveop, off);
return 1;
case AR_LC_REGNUM:
gcc_assert (!current_frame_info.reg_save_ar_lc);
- fprintf (asm_out_file, "\t%s ar.lc, %ld\n", saveop, off);
+ if (unwind)
+ fprintf (asm_out_file, "\t%s ar.lc, %ld\n", saveop, off);
return 1;
case AR_PFS_REGNUM:
gcc_assert (!current_frame_info.reg_save_ar_pfs);
- fprintf (asm_out_file, "\t%s ar.pfs, %ld\n", saveop, off);
+ if (unwind)
+ fprintf (asm_out_file, "\t%s ar.pfs, %ld\n", saveop, off);
return 1;
case AR_UNAT_REGNUM:
gcc_assert (!current_frame_info.reg_save_ar_unat);
- fprintf (asm_out_file, "\t%s ar.unat, %ld\n", saveop, off);
+ if (unwind)
+ fprintf (asm_out_file, "\t%s ar.unat, %ld\n", saveop, off);
return 1;
case GR_REG (4):
case GR_REG (5):
case GR_REG (6):
case GR_REG (7):
- fprintf (asm_out_file, "\t.save.g 0x%x\n",
- 1 << (src_regno - GR_REG (4)));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save.g 0x%x\n",
+ 1 << (src_regno - GR_REG (4)));
return 1;
case BR_REG (1):
@@ -8171,24 +8250,27 @@ process_set (FILE *asm_out_file, rtx pat
case BR_REG (3):
case BR_REG (4):
case BR_REG (5):
- fprintf (asm_out_file, "\t.save.b 0x%x\n",
- 1 << (src_regno - BR_REG (1)));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save.b 0x%x\n",
+ 1 << (src_regno - BR_REG (1)));
return 1;
case FR_REG (2):
case FR_REG (3):
case FR_REG (4):
case FR_REG (5):
- fprintf (asm_out_file, "\t.save.f 0x%x\n",
- 1 << (src_regno - FR_REG (2)));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save.f 0x%x\n",
+ 1 << (src_regno - FR_REG (2)));
return 1;
case FR_REG (16): case FR_REG (17): case FR_REG (18): case FR_REG (19):
case FR_REG (20): case FR_REG (21): case FR_REG (22): case FR_REG (23):
case FR_REG (24): case FR_REG (25): case FR_REG (26): case FR_REG (27):
case FR_REG (28): case FR_REG (29): case FR_REG (30): case FR_REG (31):
- fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n",
- 1 << (src_regno - FR_REG (12)));
+ if (unwind)
+ fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n",
+ 1 << (src_regno - FR_REG (12)));
return 1;
default:
@@ -8205,8 +8287,11 @@ process_set (FILE *asm_out_file, rtx pat
void
process_for_unwind_directive (FILE *asm_out_file, rtx insn)
{
- if (flag_unwind_tables
- || (flag_exceptions && !USING_SJLJ_EXCEPTIONS))
+ bool unwind = (flag_unwind_tables
+ || (flag_exceptions && !USING_SJLJ_EXCEPTIONS));
+ bool frame = dwarf2out_do_frame ();
+
+ if (unwind || frame)
{
rtx pat;
@@ -8218,9 +8303,14 @@ process_for_unwind_directive (FILE *asm_
/* Restore unwind state from immediately before the epilogue. */
if (need_copy_state)
{
- fprintf (asm_out_file, "\t.body\n");
- fprintf (asm_out_file, "\t.copy_state %d\n",
- cfun->machine->state_num);
+ if (unwind)
+ {
+ fprintf (asm_out_file, "\t.body\n");
+ fprintf (asm_out_file, "\t.copy_state %d\n",
+ cfun->machine->state_num);
+ }
+ if (IA64_CHANGE_CFA_IN_EPILOGUE && frame)
+ ia64_dwarf2out_def_steady_cfa (insn);
need_copy_state = false;
}
}
@@ -8237,7 +8327,7 @@ process_for_unwind_directive (FILE *asm_
switch (GET_CODE (pat))
{
case SET:
- process_set (asm_out_file, pat);
+ process_set (asm_out_file, pat, insn, unwind, frame);
break;
case PARALLEL:
@@ -8248,7 +8338,7 @@ process_for_unwind_directive (FILE *asm_
{
rtx x = XVECEXP (pat, 0, par_index);
if (GET_CODE (x) == SET)
- process_set (asm_out_file, x);
+ process_set (asm_out_file, x, insn, unwind, frame);
}
break;
}
Index: gcc/config/ia64/ia64.h
===================================================================
--- gcc/config/ia64/ia64.h.orig 2006-02-03 03:09:18.000000000 -0200
+++ gcc/config/ia64/ia64.h 2006-02-03 04:18:50.000000000 -0200
@@ -981,6 +981,12 @@ enum reg_class
On some machines it may depend on the data type of the function. */
#define FIRST_PARM_OFFSET(FUNDECL) 0
+/* The CFA is defined as the SP at the call site, so we have to take
+ into account that the first argument pointer is
+ STACK_POINTER_OFFSET bytes off the stack pointer. */
+#define ARG_POINTER_CFA_OFFSET(FNDECL) \
+ (FIRST_PARM_OFFSET (FNDECL) - STACK_POINTER_OFFSET)
+
/* A C expression whose value is RTL representing the value of the return
address for the frame COUNT steps up from the current frame, after the
prologue. */
@@ -1867,6 +1873,12 @@ do { \
#define DWARF2_DEBUGGING_INFO 1
+/* We do not want call-frame info to be output, since debuggers are
+ supposed to use the target unwind info. Leave this undefined it
+ TARGET_UNWIND_INFO might ever be false. */
+
+#define DWARF2_FRAME_INFO 0
+
#define DWARF2_ASM_LINE_DEBUG_INFO (TARGET_DWARF2_ASM)
/* Use tags for debug info labels, so that they don't break instruction
Index: gcc/config/ia64/t-ia64
===================================================================
--- gcc/config/ia64/t-ia64.orig 2006-02-03 03:09:18.000000000 -0200
+++ gcc/config/ia64/t-ia64 2006-02-03 04:18:50.000000000 -0200
@@ -50,3 +50,5 @@ ia64-c.o: $(srcdir)/config/ia64/ia64-c.c
# genattrtab generates very long string literals.
insn-attrtab.o-warn = -Wno-error
+
+ia64.o: debug.h
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c.orig 2006-01-25 15:04:42.000000000 -0200
+++ gcc/dwarf2out.c 2006-02-03 05:41:57.000000000 -0200
@@ -90,20 +90,31 @@ static void dwarf2out_source_line (unsig
DW_CFA_... = DWARF2 CFA call frame instruction
DW_TAG_... = DWARF2 DIE tag */
+#ifndef DWARF2_FRAME_INFO
+# ifdef DWARF2_DEBUGGING_INFO
+# define DWARF2_FRAME_INFO \
+ (write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
+# else
+# define DWARF2_FRAME_INFO 0
+# endif
+#endif
+
/* Decide whether we want to emit frame unwind information for the current
translation unit. */
int
dwarf2out_do_frame (void)
{
+ /* We want to emit correct CFA location expressions or lists, so we
+ have to return true if we're going to output debug info, even if
+ we're not going to output frame or unwind info. */
return (write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG
-#ifdef DWARF2_FRAME_INFO
|| DWARF2_FRAME_INFO
-#endif
#ifdef DWARF2_UNWIND_INFO
- || flag_unwind_tables
- || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)
+ || (DWARF2_UNWIND_INFO
+ && (flag_unwind_tables
+ || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)))
#endif
);
}
@@ -2575,10 +2586,12 @@ dwarf2out_frame_init (void)
/* Generate the CFA instructions common to all FDE's. Do it now for the
sake of lookup_cfa. */
-#ifdef DWARF2_UNWIND_INFO
/* On entry, the Canonical Frame Address is at SP. */
dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
- initial_return_save (INCOMING_RETURN_ADDR_RTX);
+
+#ifdef DWARF2_UNWIND_INFO
+ if (DWARF2_UNWIND_INFO)
+ initial_return_save (INCOMING_RETURN_ADDR_RTX);
#endif
}
@@ -2586,12 +2599,7 @@ void
dwarf2out_frame_finish (void)
{
/* Output call frame information. */
- if (write_symbols == DWARF2_DEBUG
- || write_symbols == VMS_AND_DWARF2_DEBUG
-#ifdef DWARF2_FRAME_INFO
- || DWARF2_FRAME_INFO
-#endif
- )
+ if (DWARF2_FRAME_INFO)
output_call_frame_info (0);
#ifndef TARGET_UNWIND_INFO
@@ -10332,7 +10340,6 @@ tree_add_const_value_attribute (dw_die_r
add_const_value_attribute (var_die, rtl);
}
-#ifdef DWARF2_UNWIND_INFO
/* Convert the CFI instructions for the current function into a location
list. This is used for DW_AT_frame_base when we targeting a dwarf2
consumer that does not support the dwarf3 DW_OP_call_frame_cfa. */
@@ -10439,7 +10446,6 @@ compute_frame_pointer_to_cfa_displacemen
frame_pointer_cfa_offset = -offset;
}
-#endif
/* Generate a DW_AT_name attribute given some string value to be included as
the value of the attribute. */
@@ -11674,7 +11680,6 @@ gen_subprogram_die (tree decl, dw_die_re
add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde);
#endif
-#ifdef DWARF2_UNWIND_INFO
/* We define the "frame base" as the function's CFA. This is more
convenient for several reasons: (1) It's stable across the prologue
and epilogue, which makes it better than just a frame pointer,
@@ -11701,17 +11706,6 @@ gen_subprogram_die (tree decl, dw_die_re
debugger about. We'll need to adjust all frame_base references
by this displacement. */
compute_frame_pointer_to_cfa_displacement ();
-#else
- /* For targets which support DWARF2, but not DWARF2 call-frame info,
- we just use the stack pointer or frame pointer. */
- /* ??? Should investigate getting better info via callbacks, or else
- by interpreting the IA-64 unwind info. */
- {
- rtx fp_reg
- = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
- add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
- }
-#endif
if (cfun->static_chain_decl)
add_AT_location_description (subr_die, DW_AT_static_link,
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c.orig 2006-01-26 16:20:39.000000000 -0200
+++ gcc/toplev.c 2006-02-03 04:18:51.000000000 -0200
@@ -1020,7 +1020,7 @@ compile_file (void)
/* Do dbx symbols. */
timevar_push (TV_SYMOUT);
-#ifdef DWARF2_UNWIND_INFO
+#if defined DWARF2_DEBUGGING_INFO || defined DWARF2_UNWIND_INFO
if (dwarf2out_do_frame ())
dwarf2out_frame_finish ();
#endif
@@ -1860,7 +1860,7 @@ lang_dependent_init (const char *name)
predefined types. */
timevar_push (TV_SYMOUT);
-#ifdef DWARF2_UNWIND_INFO
+#if defined DWARF2_DEBUGGING_INFO || defined DWARF2_UNWIND_INFO
if (dwarf2out_do_frame ())
dwarf2out_frame_init ();
#endif
--
Alexandre Oliva http://www.lsd.ic.unicamp.br/~oliva/
Secretary for FSF Latin America http://www.fsfla.org/
Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org}