/* Output Dwarf2 format symbol table information from GCC.
Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Contributed by Gary Funck (gary@intrepid.com).
Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
Extensively modified by Jason Merrill (jason@cygnus.com).
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
+
+/* Map register numbers held in the call frame info that gcc has
+ collected using DWARF_FRAME_REGNUM to those that should be output in
+ .debug_frame and .eh_frame. */
+#ifndef DWARF2_FRAME_REG_OUT
+#define DWARF2_FRAME_REG_OUT(REGNO, FOR_EH) (REGNO)
+#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
);
}
#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
#endif
-/* Various versions of targetm.eh_frame_section. Note these must appear
- outside the DWARF2_DEBUGGING_INFO || DWARF2_UNWIND_INFO macro guards. */
-
-/* Version of targetm.eh_frame_section for systems with named sections. */
-void
-named_section_eh_frame_section (void)
-{
-#ifdef EH_FRAME_SECTION_NAME
- int flags;
-
- if (EH_TABLES_CAN_BE_READ_ONLY)
- {
- int fde_encoding;
- int per_encoding;
- int lsda_encoding;
-
- fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
- per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
- lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
- flags = (! flag_pic
- || ((fde_encoding & 0x70) != DW_EH_PE_absptr
- && (fde_encoding & 0x70) != DW_EH_PE_aligned
- && (per_encoding & 0x70) != DW_EH_PE_absptr
- && (per_encoding & 0x70) != DW_EH_PE_aligned
- && (lsda_encoding & 0x70) != DW_EH_PE_absptr
- && (lsda_encoding & 0x70) != DW_EH_PE_aligned))
- ? 0 : SECTION_WRITE;
- }
- else
- flags = SECTION_WRITE;
- named_section_flags (EH_FRAME_SECTION_NAME, flags);
-#endif
-}
-
-/* Version of targetm.eh_frame_section for systems using collect2. */
-void
-collect2_eh_frame_section (void)
-{
- tree label = get_file_function_name ('F');
-
- data_section ();
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
- targetm.asm_out.globalize_label (asm_out_file, IDENTIFIER_POINTER (label));
- ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
-}
-
-/* Default version of targetm.eh_frame_section. */
-void
-default_eh_frame_section (void)
-{
-#ifdef EH_FRAME_SECTION_NAME
- named_section_eh_frame_section ();
-#else
- collect2_eh_frame_section ();
-#endif
-}
-
-DEF_VEC_P(rtx);
-DEF_VEC_ALLOC_P(rtx,gc);
-
/* Array of RTXes referenced by the debugging information, which therefore
must be kept around forever. */
static GTY(()) VEC(rtx,gc) *used_rtx_array;
define type declaration DIE's. */
static GTY(()) VEC(tree,gc) *decl_scope_table;
+/* Pointers to various DWARF2 sections. */
+static GTY(()) section *debug_info_section;
+static GTY(()) section *debug_abbrev_section;
+static GTY(()) section *debug_aranges_section;
+static GTY(()) section *debug_macinfo_section;
+static GTY(()) section *debug_line_section;
+static GTY(()) section *debug_loc_section;
+static GTY(()) section *debug_pubnames_section;
+static GTY(()) section *debug_str_section;
+static GTY(()) section *debug_ranges_section;
+static GTY(()) section *debug_frame_section;
+
/* How to start an assembler comment. */
#ifndef ASM_COMMENT_START
#define ASM_COMMENT_START ";#"
typedef union dw_cfi_oprnd_struct GTY(())
{
- unsigned long GTY ((tag ("dw_cfi_oprnd_reg_num"))) dw_cfi_reg_num;
+ unsigned int GTY ((tag ("dw_cfi_oprnd_reg_num"))) dw_cfi_reg_num;
HOST_WIDE_INT GTY ((tag ("dw_cfi_oprnd_offset"))) dw_cfi_offset;
const char * GTY ((tag ("dw_cfi_oprnd_addr"))) dw_cfi_addr;
struct dw_loc_descr_struct * GTY ((tag ("dw_cfi_oprnd_loc"))) dw_cfi_loc;
of this structure. */
typedef struct cfa_loc GTY(())
{
- unsigned long reg;
HOST_WIDE_INT offset;
HOST_WIDE_INT base_offset;
+ unsigned int reg;
int indirect; /* 1 if CFA is accessed via a dereference. */
} dw_cfa_location;
#endif
#endif
+/* CIE identifier. */
+#if HOST_BITS_PER_WIDE_INT >= 64
+#define DWARF_CIE_ID \
+ (unsigned HOST_WIDE_INT) (DWARF_OFFSET_SIZE == 4 ? DW_CIE_ID : DW64_CIE_ID)
+#else
+#define DWARF_CIE_ID DW_CIE_ID
+#endif
+
/* A pointer to the base of a table that contains frame description
information for each routine. */
static GTY((length ("fde_table_allocated"))) dw_fde_ref fde_table;
static void get_cfa_from_loc_descr (dw_cfa_location *,
struct dw_loc_descr_struct *);
static struct dw_loc_descr_struct *build_cfa_loc
- (dw_cfa_location *);
+ (dw_cfa_location *, HOST_WIDE_INT);
static void def_cfa_1 (const char *, dw_cfa_location *);
/* How to start an assembler comment. */
#ifndef DWARF_FRAME_REGNUM
#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
#endif
-
-/* The offset from the incoming value of %sp to the top of the stack frame
- for the current function. */
-#ifndef INCOMING_FRAME_SP_OFFSET
-#define INCOMING_FRAME_SP_OFFSET 0
-#endif
\f
/* Hook used by __throw. */
rtx
expand_builtin_dwarf_sp_column (void)
{
- return GEN_INT (DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM));
+ unsigned int dwarf_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM);
+ return GEN_INT (DWARF2_FRAME_REG_OUT (dwarf_regnum, 1));
}
/* Return a pointer to a copy of the section string name S with all
static inline char *
stripattributes (const char *s)
{
- char *stripped = xmalloc (strlen (s) + 2);
+ char *stripped = XNEWVEC (char, strlen (s) + 2);
char *p = stripped;
*p++ = '*';
void
expand_builtin_init_dwarf_reg_sizes (tree address)
{
- int i;
+ unsigned int i;
enum machine_mode mode = TYPE_MODE (char_type_node);
- rtx addr = expand_expr (address, NULL_RTX, VOIDmode, 0);
+ rtx addr = expand_normal (address);
rtx mem = gen_rtx_MEM (BLKmode, addr);
bool wrote_return_column = false;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (DWARF_FRAME_REGNUM (i) < DWARF_FRAME_REGISTERS)
- {
- HOST_WIDE_INT offset = DWARF_FRAME_REGNUM (i) * GET_MODE_SIZE (mode);
- enum machine_mode save_mode = reg_raw_mode[i];
- HOST_WIDE_INT size;
-
- if (HARD_REGNO_CALL_PART_CLOBBERED (i, save_mode))
- save_mode = choose_hard_reg_mode (i, 1, true);
- if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN)
- {
- if (save_mode == VOIDmode)
- continue;
- wrote_return_column = true;
- }
- size = GET_MODE_SIZE (save_mode);
- if (offset < 0)
- continue;
-
- emit_move_insn (adjust_address (mem, mode, offset),
- gen_int_mode (size, mode));
- }
+ {
+ int rnum = DWARF2_FRAME_REG_OUT (DWARF_FRAME_REGNUM (i), 1);
+
+ if (rnum < DWARF_FRAME_REGISTERS)
+ {
+ HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (mode);
+ enum machine_mode save_mode = reg_raw_mode[i];
+ HOST_WIDE_INT size;
+
+ if (HARD_REGNO_CALL_PART_CLOBBERED (i, save_mode))
+ save_mode = choose_hard_reg_mode (i, 1, true);
+ if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN)
+ {
+ if (save_mode == VOIDmode)
+ continue;
+ wrote_return_column = true;
+ }
+ size = GET_MODE_SIZE (save_mode);
+ if (offset < 0)
+ continue;
+
+ emit_move_insn (adjust_address (mem, mode, offset),
+ gen_int_mode (size, mode));
+ }
+ }
#ifdef DWARF_ALT_FRAME_RETURN_COLUMN
gcc_assert (wrote_return_column);
/* Subroutine of lookup_cfa. */
-static inline void
+static void
lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc)
{
switch (cfi->dw_cfi_opc)
case DW_CFA_def_cfa_offset:
loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset;
break;
+ case DW_CFA_def_cfa_offset_sf:
+ loc->offset
+ = cfi->dw_cfi_oprnd1.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT;
+ break;
case DW_CFA_def_cfa_register:
loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
break;
loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset;
break;
+ case DW_CFA_def_cfa_sf:
+ loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
+ loc->offset
+ = cfi->dw_cfi_oprnd2.dw_cfi_offset * DWARF_CIE_DATA_ALIGNMENT;
+ break;
case DW_CFA_def_cfa_expression:
get_cfa_from_loc_descr (loc, cfi->dw_cfi_oprnd1.dw_cfi_loc);
break;
{
dw_cfi_ref cfi;
- loc->reg = (unsigned long) -1;
+ loc->reg = INVALID_REGNUM;
loc->offset = 0;
loc->indirect = 0;
loc->base_offset = 0;
def_cfa_1 (label, &loc);
}
+/* Determine if two dw_cfa_location structures define the same data. */
+
+static bool
+cfa_equal_p (const dw_cfa_location *loc1, const dw_cfa_location *loc2)
+{
+ return (loc1->reg == loc2->reg
+ && loc1->offset == loc2->offset
+ && loc1->indirect == loc2->indirect
+ && (loc1->indirect == 0
+ || loc1->base_offset == loc2->base_offset));
+}
+
/* This routine does the actual work. The CFA is now calculated from
the dw_cfa_location structure. */
lookup_cfa (&old_cfa);
/* If nothing changed, no need to issue any call frame instructions. */
- if (loc.reg == old_cfa.reg && loc.offset == old_cfa.offset
- && loc.indirect == old_cfa.indirect
- && (loc.indirect == 0 || loc.base_offset == old_cfa.base_offset))
+ if (cfa_equal_p (&loc, &old_cfa))
return;
cfi = new_cfi ();
if (loc.reg == old_cfa.reg && !loc.indirect)
{
- /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction,
- indicating the CFA register did not change but the offset
- did. */
- cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
- cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
+ /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating
+ the CFA register did not change but the offset did. */
+ if (loc.offset < 0)
+ {
+ HOST_WIDE_INT f_offset = loc.offset / DWARF_CIE_DATA_ALIGNMENT;
+ gcc_assert (f_offset * DWARF_CIE_DATA_ALIGNMENT == loc.offset);
+
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf;
+ cfi->dw_cfi_oprnd1.dw_cfi_offset = f_offset;
+ }
+ else
+ {
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
+ cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
+ }
}
#ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */
- else if (loc.offset == old_cfa.offset && old_cfa.reg != (unsigned long) -1
+ else if (loc.offset == old_cfa.offset
+ && old_cfa.reg != INVALID_REGNUM
&& !loc.indirect)
{
/* Construct a "DW_CFA_def_cfa_register <register>" instruction,
/* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
indicating the CFA register has changed to <register> with
the specified offset. */
- cfi->dw_cfi_opc = DW_CFA_def_cfa;
- cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
- cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
+ if (loc.offset < 0)
+ {
+ HOST_WIDE_INT f_offset = loc.offset / DWARF_CIE_DATA_ALIGNMENT;
+ gcc_assert (f_offset * DWARF_CIE_DATA_ALIGNMENT == loc.offset);
+
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
+ cfi->dw_cfi_oprnd2.dw_cfi_offset = f_offset;
+ }
+ else
+ {
+ cfi->dw_cfi_opc = DW_CFA_def_cfa;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
+ cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
+ }
}
else
{
struct dw_loc_descr_struct *loc_list;
cfi->dw_cfi_opc = DW_CFA_def_cfa_expression;
- loc_list = build_cfa_loc (&loc);
+ loc_list = build_cfa_loc (&loc, 0);
cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list;
}
much extra space it needs to pop off the stack. */
static void
-dwarf2out_stack_adjust (rtx insn, bool after_p)
+dwarf2out_stack_adjust (rtx insn, bool after_p ATTRIBUTE_UNUSED)
{
HOST_WIDE_INT offset;
const char *label;
if (prologue_epilogue_contains (insn) || sibcall_epilogue_contains (insn))
return;
- /* If only calls can throw, and we have a frame pointer,
- save up adjustments until we see the CALL_INSN. */
- if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM)
- {
- if (CALL_P (insn) && !after_p)
- {
- /* Extract the size of the args from the CALL rtx itself. */
- insn = PATTERN (insn);
- if (GET_CODE (insn) == PARALLEL)
- insn = XVECEXP (insn, 0, 0);
- if (GET_CODE (insn) == SET)
- insn = SET_SRC (insn);
- gcc_assert (GET_CODE (insn) == CALL);
- dwarf2out_args_size ("", INTVAL (XEXP (insn, 1)));
- }
- return;
- }
-
- if (CALL_P (insn) && !after_p)
- {
- if (!flag_asynchronous_unwind_tables)
- dwarf2out_args_size ("", args_size);
- return;
- }
- else if (BARRIER_P (insn))
+ if (BARRIER_P (insn))
{
/* When we see a BARRIER, we know to reset args_size to 0. Usually
the compiler will have already emitted a stack adjustment, but
if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i));
}
+ else if (GET_CODE (insn) == CALL_INSN)
+ offset = 0;
else
return;
+ /* We handle this separately because we want stack adjustments in a
+ CALL_INSN to be handled. */;
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ /* If only calls can throw, adjust args_size only at call sites. */
+ if (!flag_asynchronous_unwind_tables)
+ dwarf2out_args_size ("", args_size);
+ }
+
if (offset == 0)
return;
if (args_size < 0)
args_size = 0;
+ /* If only calls can throw and we have a frame pointer, we'll save
+ up adjustments until we see the CALL_INSN. We used to return
+ early and derive args_size from NARGS in the CALL_INSN itself,
+ but that doesn't compute the right value if we have nested call
+ expansions, e.g., stack adjustments for a call have already been
+ emitted, and then we issue another call to compute an argument
+ for the enclosing call (i.e., bar (foo ())). */
+ if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM)
+ return;
+
label = dwarf2out_cfi_label ();
def_cfa_1 (label, &cfa);
if (flag_asynchronous_unwind_tables)
return false;
}
+/* Entry point for saving the first register into the second. */
+
+void
+dwarf2out_reg_save_reg (const char *label, rtx reg, rtx sreg)
+{
+ size_t i;
+ unsigned int regno, sregno;
+
+ for (i = 0; i < num_regs_saved_in_regs; i++)
+ if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (reg))
+ break;
+ if (i == num_regs_saved_in_regs)
+ {
+ gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
+ num_regs_saved_in_regs++;
+ }
+ regs_saved_in_regs[i].orig_reg = reg;
+ regs_saved_in_regs[i].saved_in_reg = sreg;
+
+ regno = DWARF_FRAME_REGNUM (REGNO (reg));
+ sregno = DWARF_FRAME_REGNUM (REGNO (sreg));
+ reg_save (label, regno, sregno, 0);
+}
+
/* What register, if any, is currently saved in REG? */
static rtx
else
{
/* Saving a register in a register. */
- gcc_assert (call_used_regs [REGNO (dest)]
- && (!fixed_regs [REGNO (dest)]
- /* For the SPARC and its register window. */
- || DWARF_FRAME_REGNUM (REGNO (src))
- == DWARF_FRAME_RETURN_COLUMN));
+ gcc_assert (!fixed_regs [REGNO (dest)]
+ /* For the SPARC and its register window. */
+ || (DWARF_FRAME_REGNUM (REGNO (src))
+ == DWARF_FRAME_RETURN_COLUMN));
queue_reg_save (label, src, dest, 0);
}
break;
case UNSPEC_VOLATILE:
gcc_assert (targetm.dwarf_handle_frame_unspec);
targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1));
- break;
+ return;
default:
gcc_unreachable ();
{
int regno;
- gcc_assert (GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT);
+ gcc_assert (GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT
+ && REG_P (XEXP (XEXP (dest, 0), 0)));
offset = INTVAL (XEXP (XEXP (dest, 0), 1));
if (GET_CODE (XEXP (dest, 0)) == MINUS)
offset = -offset;
#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
-/* Map register numbers held in the call frame info that gcc has
- collected using DWARF_FRAME_REGNUM to those that should be output in
- .debug_frame and .eh_frame. */
-#ifndef DWARF2_FRAME_REG_OUT
-#define DWARF2_FRAME_REG_OUT(REGNO, FOR_EH) (REGNO)
+/* Switch to eh_frame_section. If we don't have an eh_frame_section,
+ switch to the data section instead, and write out a synthetic label
+ for collect2. */
+
+static void
+switch_to_eh_frame_section (void)
+{
+ tree label;
+
+#ifdef EH_FRAME_SECTION_NAME
+ if (eh_frame_section == 0)
+ {
+ int flags;
+
+ if (EH_TABLES_CAN_BE_READ_ONLY)
+ {
+ int fde_encoding;
+ int per_encoding;
+ int lsda_encoding;
+
+ fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1,
+ /*global=*/0);
+ per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2,
+ /*global=*/1);
+ lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0,
+ /*global=*/0);
+ flags = ((! flag_pic
+ || ((fde_encoding & 0x70) != DW_EH_PE_absptr
+ && (fde_encoding & 0x70) != DW_EH_PE_aligned
+ && (per_encoding & 0x70) != DW_EH_PE_absptr
+ && (per_encoding & 0x70) != DW_EH_PE_aligned
+ && (lsda_encoding & 0x70) != DW_EH_PE_absptr
+ && (lsda_encoding & 0x70) != DW_EH_PE_aligned))
+ ? 0 : SECTION_WRITE);
+ }
+ else
+ flags = SECTION_WRITE;
+ eh_frame_section = get_section (EH_FRAME_SECTION_NAME, flags, NULL);
+ }
#endif
+ if (eh_frame_section)
+ switch_to_section (eh_frame_section);
+ else
+ {
+ /* We have no special eh_frame section. Put the information in
+ the data section and emit special labels to guide collect2. */
+ switch_to_section (data_section);
+ label = get_file_function_name ('F');
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+ targetm.asm_out.globalize_label (asm_out_file,
+ IDENTIFIER_POINTER (label));
+ ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+ }
+}
+
/* Output a Call Frame Information opcode and its operand(s). */
static void
dw2_asm_output_encoded_addr_rtx (
ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0),
gen_rtx_SYMBOL_REF (Pmode, cfi->dw_cfi_oprnd1.dw_cfi_addr),
- NULL);
+ false, NULL);
else
dw2_asm_output_addr (DWARF2_ADDR_SIZE,
cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
app_enable ();
if (for_eh)
- targetm.asm_out.eh_frame_section ();
+ switch_to_eh_frame_section ();
else
- named_section_flags (DEBUG_FRAME_SECTION, SECTION_DEBUG);
+ {
+ if (!debug_frame_section)
+ debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+ SECTION_DEBUG, NULL);
+ switch_to_section (debug_frame_section);
+ }
ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
/* Output the CIE. */
ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
"Length of Common Information Entry");
ASM_OUTPUT_LABEL (asm_out_file, l1);
/* Now that the CIE pointer is PC-relative for EH,
use 0 to identify the CIE. */
dw2_asm_output_data ((for_eh ? 4 : DWARF_OFFSET_SIZE),
- (for_eh ? 0 : DW_CIE_ID),
+ (for_eh ? 0 : DWARF_CIE_ID),
"CIE Identifier Tag");
dw2_asm_output_data (1, DW_CIE_VERSION, "CIE Version");
dw2_asm_output_data (1, per_encoding, "Personality (%s)",
eh_data_format_name (per_encoding));
dw2_asm_output_encoded_addr_rtx (per_encoding,
- eh_personality_libfunc, NULL);
+ eh_personality_libfunc,
+ true, NULL);
}
if (any_lsda_needed)
targetm.asm_out.internal_label (asm_out_file, FDE_LABEL, for_eh + i * 2);
ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i * 2);
ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i * 2);
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
"FDE Length");
ASM_OUTPUT_LABEL (asm_out_file, l1);
dw2_asm_output_delta (4, l1, section_start_label, "FDE CIE offset");
else
dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label,
- "FDE CIE offset");
+ debug_frame_section, "FDE CIE offset");
if (for_eh)
{
SYMBOL_REF_FLAGS (sym_ref) |= SYMBOL_FLAG_LOCAL;
dw2_asm_output_encoded_addr_rtx (fde_encoding,
sym_ref,
+ false,
"FDE initial location");
if (fde->dw_fde_switched_sections)
{
fde->dw_fde_hot_section_label);
SYMBOL_REF_FLAGS (sym_ref2) |= SYMBOL_FLAG_LOCAL;
SYMBOL_REF_FLAGS (sym_ref3) |= SYMBOL_FLAG_LOCAL;
- dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref3,
+ dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref3, false,
"FDE initial location");
dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
fde->dw_fde_hot_section_end_label,
fde->dw_fde_hot_section_label,
"FDE address range");
- dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref2,
+ dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref2, false,
"FDE initial location");
dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
fde->dw_fde_unlikely_section_end_label,
fde->funcdef_number);
dw2_asm_output_encoded_addr_rtx (
lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1),
- "Language Specific Data Area");
+ false, "Language Specific Data Area");
}
else
{
return;
#endif
- function_section (current_function_decl);
+ switch_to_section (function_section (current_function_decl));
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
current_function_funcdef_no);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
/* 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
}
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
dw_val_class_die_ref,
dw_val_class_fde_ref,
dw_val_class_lbl_id,
- dw_val_class_lbl_offset,
- dw_val_class_str
+ dw_val_class_lineptr,
+ dw_val_class_str,
+ dw_val_class_macptr
};
/* Describe a double word constant value. */
static unsigned long
size_of_locs (dw_loc_descr_ref loc)
{
+ dw_loc_descr_ref l;
unsigned long size;
- for (size = 0; loc != NULL; loc = loc->dw_loc_next)
+ /* If there are no skip or bra opcodes, don't fill in the dw_loc_addr
+ field, to avoid writing to a PCH file. */
+ for (size = 0, l = loc; l != NULL; l = l->dw_loc_next)
+ {
+ if (l->dw_loc_opc == DW_OP_skip || l->dw_loc_opc == DW_OP_bra)
+ break;
+ size += size_of_loc_descr (l);
+ }
+ if (! l)
+ return size;
+
+ for (size = 0, l = loc; l != NULL; l = l->dw_loc_next)
{
- loc->dw_loc_addr = size;
- size += size_of_loc_descr (loc);
+ l->dw_loc_addr = size;
+ size += size_of_loc_descr (l);
}
return size;
output_loc_sequence (loc);
}
-/* This function builds a dwarf location descriptor sequence from
- a dw_cfa_location. */
+/* This function builds a dwarf location descriptor sequence from a
+ dw_cfa_location, adding the given OFFSET to the result of the
+ expression. */
static struct dw_loc_descr_struct *
-build_cfa_loc (dw_cfa_location *cfa)
+build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset)
{
struct dw_loc_descr_struct *head, *tmp;
- gcc_assert (cfa->indirect);
+ offset += cfa->offset;
- if (cfa->base_offset)
+ if (cfa->indirect)
{
- if (cfa->reg <= 31)
- head = new_loc_descr (DW_OP_breg0 + cfa->reg, cfa->base_offset, 0);
+ if (cfa->base_offset)
+ {
+ if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_breg0 + cfa->reg, cfa->base_offset, 0);
+ else
+ head = new_loc_descr (DW_OP_bregx, cfa->reg, cfa->base_offset);
+ }
+ else if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
else
- head = new_loc_descr (DW_OP_bregx, cfa->reg, cfa->base_offset);
+ head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
+
+ head->dw_loc_oprnd1.val_class = dw_val_class_const;
+ tmp = new_loc_descr (DW_OP_deref, 0, 0);
+ add_loc_descr (&head, tmp);
+ if (offset != 0)
+ {
+ tmp = new_loc_descr (DW_OP_plus_uconst, offset, 0);
+ add_loc_descr (&head, tmp);
+ }
}
- else if (cfa->reg <= 31)
- head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
else
- head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
-
- head->dw_loc_oprnd1.val_class = dw_val_class_const;
- tmp = new_loc_descr (DW_OP_deref, 0, 0);
- add_loc_descr (&head, tmp);
- if (cfa->offset != 0)
{
- tmp = new_loc_descr (DW_OP_plus_uconst, cfa->offset, 0);
- add_loc_descr (&head, tmp);
+ if (offset == 0)
+ if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
+ else
+ head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
+ else if (cfa->reg <= 31)
+ head = new_loc_descr (DW_OP_breg0 + cfa->reg, offset, 0);
+ else
+ head = new_loc_descr (DW_OP_bregx, cfa->reg, offset);
}
return head;
typedef struct dw_attr_struct GTY(())
{
enum dwarf_attribute dw_attr;
- dw_attr_ref dw_attr_next;
dw_val_node dw_attr_val;
}
dw_attr_node;
-/* The Debugging Information Entry (DIE) structure */
+DEF_VEC_O(dw_attr_node);
+DEF_VEC_ALLOC_O(dw_attr_node,gc);
+
+/* The Debugging Information Entry (DIE) structure. DIEs form a tree.
+ The children of each node form a circular list linked by
+ die_sib. die_child points to the node *before* the "first" child node. */
typedef struct die_struct GTY(())
{
enum dwarf_tag die_tag;
char *die_symbol;
- dw_attr_ref die_attr;
+ VEC(dw_attr_node,gc) * die_attr;
dw_die_ref die_parent;
dw_die_ref die_child;
dw_die_ref die_sib;
dw_offset die_offset;
unsigned long die_abbrev;
int die_mark;
+ /* Die is used and must not be pruned as unused. */
+ int die_perennial_p;
unsigned int decl_id;
}
die_node;
+/* Evaluate 'expr' while 'c' is set to each child of DIE in order. */
+#define FOR_EACH_CHILD(die, c, expr) do { \
+ c = die->die_child; \
+ if (c) do { \
+ c = c->die_sib; \
+ expr; \
+ } while (c != die->die_child); \
+} while (0)
+
/* The pubname structure */
typedef struct pubname_struct GTY(())
/* Number of elements in line_info_table currently in use. */
static GTY(()) unsigned line_info_table_in_use;
+/* True if the compilation unit places functions in more than one section. */
+static GTY(()) bool have_multiple_function_sections = false;
+
/* A pointer to the base of a table that contains line information
for each source code line outside of .text in the compilation unit. */
static GTY ((length ("separate_line_info_table_allocated")))
#define RANGES_TABLE_INCREMENT 64
/* Whether we have location lists that need outputting */
-static GTY(()) unsigned have_location_lists;
+static GTY(()) bool have_location_lists;
/* Unique label counter. */
static GTY(()) unsigned int loclabel_num;
#ifdef DWARF2_DEBUGGING_INFO
+/* Offset from the "steady-state frame pointer" to the frame base,
+ within the current function. */
+static HOST_WIDE_INT frame_pointer_fb_offset;
+
/* Forward declarations for functions defined in this file. */
static int is_pseudo_reg (rtx);
static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx);
static inline rtx AT_addr (dw_attr_ref);
static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
-static void add_AT_lbl_offset (dw_die_ref, enum dwarf_attribute, const char *);
+static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
+static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
unsigned HOST_WIDE_INT);
static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
static bool is_ada (void);
static void remove_AT (dw_die_ref, enum dwarf_attribute);
static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
-static inline void free_die (dw_die_ref);
-static void remove_children (dw_die_ref);
static void add_child_die (dw_die_ref, dw_die_ref);
static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
static dw_die_ref lookup_type_die (tree);
static void print_spaces (FILE *);
static void print_die (dw_die_ref, FILE *);
static void print_dwarf_line_table (FILE *);
-static void reverse_die_lists (dw_die_ref);
-static void reverse_all_dies (dw_die_ref);
static dw_die_ref push_new_compile_unit (dw_die_ref, dw_die_ref);
static dw_die_ref pop_compile_unit (dw_die_ref);
static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int);
static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx);
static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
-static dw_loc_descr_ref based_loc_descr (unsigned, HOST_WIDE_INT, bool);
+static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT);
static int is_based_loc (rtx);
-static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode, bool);
+static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode);
static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx);
-static dw_loc_descr_ref loc_descriptor (rtx, bool);
+static dw_loc_descr_ref loc_descriptor (rtx);
static dw_loc_descr_ref loc_descriptor_from_tree_1 (tree, int);
static dw_loc_descr_ref loc_descriptor_from_tree (tree);
static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
static void gen_field_die (tree, dw_die_ref);
static void gen_ptr_to_mbr_type_die (tree, dw_die_ref);
static dw_die_ref gen_compile_unit_die (const char *);
-static void gen_string_type_die (tree, dw_die_ref);
static void gen_inheritance_die (tree, tree, dw_die_ref);
static void gen_member_die (tree, dw_die_ref);
static void gen_struct_or_union_type_die (tree, dw_die_ref);
return context;
}
\f
-/* Add an attribute/value pair to a DIE. We build the lists up in reverse
- addition order, and correct that in reverse_all_dies. */
+/* Add an attribute/value pair to a DIE. */
static inline void
add_dwarf_attr (dw_die_ref die, dw_attr_ref attr)
{
- if (die != NULL && attr != NULL)
- {
- attr->dw_attr_next = die->die_attr;
- die->die_attr = attr;
- }
+ /* Maybe this should be an assert? */
+ if (die == NULL)
+ return;
+
+ if (die->die_attr == NULL)
+ die->die_attr = VEC_alloc (dw_attr_node, gc, 1);
+ VEC_safe_push (dw_attr_node, gc, die->die_attr, attr);
}
static inline enum dw_val_class
static inline void
add_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int flag)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_flag;
- attr->dw_attr_val.v.val_flag = flag;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_flag;
+ attr.dw_attr_val.v.val_flag = flag;
+ add_dwarf_attr (die, &attr);
}
static inline unsigned
static inline void
add_AT_int (dw_die_ref die, enum dwarf_attribute attr_kind, HOST_WIDE_INT int_val)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_const;
- attr->dw_attr_val.v.val_int = int_val;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_const;
+ attr.dw_attr_val.v.val_int = int_val;
+ add_dwarf_attr (die, &attr);
}
static inline HOST_WIDE_INT
add_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind,
unsigned HOST_WIDE_INT unsigned_val)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_unsigned_const;
- attr->dw_attr_val.v.val_unsigned = unsigned_val;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
+ attr.dw_attr_val.v.val_unsigned = unsigned_val;
+ add_dwarf_attr (die, &attr);
}
static inline unsigned HOST_WIDE_INT
add_AT_long_long (dw_die_ref die, enum dwarf_attribute attr_kind,
long unsigned int val_hi, long unsigned int val_low)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_long_long;
- attr->dw_attr_val.v.val_long_long.hi = val_hi;
- attr->dw_attr_val.v.val_long_long.low = val_low;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_long_long;
+ attr.dw_attr_val.v.val_long_long.hi = val_hi;
+ attr.dw_attr_val.v.val_long_long.low = val_low;
+ add_dwarf_attr (die, &attr);
}
/* Add a floating point attribute value to a DIE and return it. */
add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind,
unsigned int length, unsigned int elt_size, unsigned char *array)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_vec;
- attr->dw_attr_val.v.val_vec.length = length;
- attr->dw_attr_val.v.val_vec.elt_size = elt_size;
- attr->dw_attr_val.v.val_vec.array = array;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_vec;
+ attr.dw_attr_val.v.val_vec.length = length;
+ attr.dw_attr_val.v.val_vec.elt_size = elt_size;
+ attr.dw_attr_val.v.val_vec.array = array;
+ add_dwarf_attr (die, &attr);
}
/* Hash and equality functions for debug_str_hash. */
static inline void
add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
struct indirect_string_node *node;
void **slot;
node->str = ggc_strdup (str);
node->refcount++;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_str;
- attr->dw_attr_val.v.val_str = node;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_str;
+ attr.dw_attr_val.v.val_str = node;
+ add_dwarf_attr (die, &attr);
}
static inline const char *
/* If we cannot expect the linker to merge strings in .debug_str
section, only put it into .debug_str if it is worth even in this
single module. */
- if ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) == 0
+ if ((debug_str_section->common.flags & SECTION_MERGE) == 0
&& (len - DWARF_OFFSET_SIZE) * node->refcount <= len)
return node->form = DW_FORM_string;
static inline void
add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_die)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_die_ref;
- attr->dw_attr_val.v.val_die_ref.die = targ_die;
- attr->dw_attr_val.v.val_die_ref.external = 0;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_die_ref;
+ attr.dw_attr_val.v.val_die_ref.die = targ_die;
+ attr.dw_attr_val.v.val_die_ref.external = 0;
+ add_dwarf_attr (die, &attr);
}
/* Add an AT_specification attribute to a DIE, and also make the back
static inline void
add_AT_fde_ref (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int targ_fde)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_fde_ref;
- attr->dw_attr_val.v.val_fde_index = targ_fde;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_fde_ref;
+ attr.dw_attr_val.v.val_fde_index = targ_fde;
+ add_dwarf_attr (die, &attr);
}
/* Add a location description attribute value to a DIE. */
static inline void
add_AT_loc (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_descr_ref loc)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_loc;
- attr->dw_attr_val.v.val_loc = loc;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_loc;
+ attr.dw_attr_val.v.val_loc = loc;
+ add_dwarf_attr (die, &attr);
}
static inline dw_loc_descr_ref
static inline void
add_AT_loc_list (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_list_ref loc_list)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_loc_list;
- attr->dw_attr_val.v.val_loc_list = loc_list;
- add_dwarf_attr (die, attr);
- have_location_lists = 1;
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_loc_list;
+ attr.dw_attr_val.v.val_loc_list = loc_list;
+ add_dwarf_attr (die, &attr);
+ have_location_lists = true;
}
static inline dw_loc_list_ref
static inline void
add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_addr;
- attr->dw_attr_val.v.val_addr = addr;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_addr;
+ attr.dw_attr_val.v.val_addr = addr;
+ add_dwarf_attr (die, &attr);
}
static inline rtx
static inline void
add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_lbl_id;
+ attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
+ add_dwarf_attr (die, &attr);
+}
+
+/* Add a section offset attribute value to a DIE, an offset into the
+ debug_line section. */
+
+static inline void
+add_AT_lineptr (dw_die_ref die, enum dwarf_attribute attr_kind,
+ const char *label)
+{
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_lbl_id;
- attr->dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_lineptr;
+ attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
+ add_dwarf_attr (die, &attr);
}
-/* Add a section offset attribute value to a DIE. */
+/* Add a section offset attribute value to a DIE, an offset into the
+ debug_macinfo section. */
static inline void
-add_AT_lbl_offset (dw_die_ref die, enum dwarf_attribute attr_kind, const char *label)
+add_AT_macptr (dw_die_ref die, enum dwarf_attribute attr_kind,
+ const char *label)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_lbl_offset;
- attr->dw_attr_val.v.val_lbl_id = xstrdup (label);
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_macptr;
+ attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
+ add_dwarf_attr (die, &attr);
}
/* Add an offset attribute value to a DIE. */
add_AT_offset (dw_die_ref die, enum dwarf_attribute attr_kind,
unsigned HOST_WIDE_INT offset)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_offset;
- attr->dw_attr_val.v.val_offset = offset;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_offset;
+ attr.dw_attr_val.v.val_offset = offset;
+ add_dwarf_attr (die, &attr);
}
/* Add an range_list attribute value to a DIE. */
add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
long unsigned int offset)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_range_list;
- attr->dw_attr_val.v.val_offset = offset;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_range_list;
+ attr.dw_attr_val.v.val_offset = offset;
+ add_dwarf_attr (die, &attr);
}
static inline const char *
AT_lbl (dw_attr_ref a)
{
gcc_assert (a && (AT_class (a) == dw_val_class_lbl_id
- || AT_class (a) == dw_val_class_lbl_offset));
+ || AT_class (a) == dw_val_class_lineptr
+ || AT_class (a) == dw_val_class_macptr));
return a->dw_attr_val.v.val_lbl_id;
}
get_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a;
+ unsigned ix;
dw_die_ref spec = NULL;
- if (die != NULL)
- {
- for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
- if (a->dw_attr == attr_kind)
- return a;
- else if (a->dw_attr == DW_AT_specification
- || a->dw_attr == DW_AT_abstract_origin)
- spec = AT_ref (a);
+ if (! die)
+ return NULL;
- if (spec)
- return get_AT (spec, attr_kind);
- }
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (a->dw_attr == attr_kind)
+ return a;
+ else if (a->dw_attr == DW_AT_specification
+ || a->dw_attr == DW_AT_abstract_origin)
+ spec = AT_ref (a);
+
+ if (spec)
+ return get_AT (spec, attr_kind);
return NULL;
}
{
unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
- return (lang == DW_LANG_C || lang == DW_LANG_C89
- || lang == DW_LANG_C_plus_plus);
+ return (lang == DW_LANG_C || lang == DW_LANG_C89 || lang == DW_LANG_ObjC
+ || lang == DW_LANG_C99
+ || lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus);
}
/* Return TRUE if the language is C++. */
static inline bool
is_cxx (void)
{
- return (get_AT_unsigned (comp_unit_die, DW_AT_language)
- == DW_LANG_C_plus_plus);
+ unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+ return lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus;
}
/* Return TRUE if the language is Fortran. */
return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
}
-/* Free up the memory used by A. */
-
-static inline void free_AT (dw_attr_ref);
-static inline void
-free_AT (dw_attr_ref a)
-{
- if (AT_class (a) == dw_val_class_str)
- if (a->dw_attr_val.v.val_str->refcount)
- a->dw_attr_val.v.val_str->refcount--;
-}
-
/* Remove the specified attribute if present. */
static void
remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
{
- dw_attr_ref *p;
- dw_attr_ref removed = NULL;
+ dw_attr_ref a;
+ unsigned ix;
- if (die != NULL)
- {
- for (p = &(die->die_attr); *p; p = &((*p)->dw_attr_next))
- if ((*p)->dw_attr == attr_kind)
- {
- removed = *p;
- *p = (*p)->dw_attr_next;
- break;
- }
+ if (! die)
+ return;
- if (removed != 0)
- free_AT (removed);
- }
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (a->dw_attr == attr_kind)
+ {
+ if (AT_class (a) == dw_val_class_str)
+ if (a->dw_attr_val.v.val_str->refcount)
+ a->dw_attr_val.v.val_str->refcount--;
+
+ /* VEC_ordered_remove should help reduce the number of abbrevs
+ that are needed. */
+ VEC_ordered_remove (dw_attr_node, die->die_attr, ix);
+ return;
+ }
}
-/* Remove child die whose die_tag is specified tag. */
+/* Remove CHILD from its parent. PREV must have the property that
+ PREV->DIE_SIB == CHILD. Does not alter CHILD. */
static void
-remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
+remove_child_with_prev (dw_die_ref child, dw_die_ref prev)
{
- dw_die_ref current, prev, next;
- current = die->die_child;
- prev = NULL;
- while (current != NULL)
+ gcc_assert (child->die_parent == prev->die_parent);
+ gcc_assert (prev->die_sib == child);
+ if (prev == child)
{
- if (current->die_tag == tag)
- {
- next = current->die_sib;
- if (prev == NULL)
- die->die_child = next;
- else
- prev->die_sib = next;
- free_die (current);
- current = next;
- }
- else
- {
- prev = current;
- current = current->die_sib;
- }
+ gcc_assert (child->die_parent->die_child == child);
+ prev = NULL;
}
+ else
+ prev->die_sib = child->die_sib;
+ if (child->die_parent->die_child == child)
+ child->die_parent->die_child = prev;
}
-/* Free up the memory used by DIE. */
-
-static inline void
-free_die (dw_die_ref die)
-{
- remove_children (die);
-}
-
-/* Discard the children of this DIE. */
+/* Remove child DIE whose die_tag is TAG. Do nothing if no child
+ matches TAG. */
static void
-remove_children (dw_die_ref die)
+remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
{
- dw_die_ref child_die = die->die_child;
-
- die->die_child = NULL;
-
- while (child_die != NULL)
- {
- dw_die_ref tmp_die = child_die;
- dw_attr_ref a;
-
- child_die = child_die->die_sib;
-
- for (a = tmp_die->die_attr; a != NULL;)
- {
- dw_attr_ref tmp_a = a;
-
- a = a->dw_attr_next;
- free_AT (tmp_a);
- }
-
- free_die (tmp_die);
- }
+ dw_die_ref c;
+
+ c = die->die_child;
+ if (c) do {
+ dw_die_ref prev = c;
+ c = c->die_sib;
+ while (c->die_tag == tag)
+ {
+ remove_child_with_prev (c, prev);
+ /* Might have removed every child. */
+ if (c == c->die_sib)
+ return;
+ c = c->die_sib;
+ }
+ } while (c != die->die_child);
}
-/* Add a child DIE below its parent. We build the lists up in reverse
- addition order, and correct that in reverse_all_dies. */
+/* Add a CHILD_DIE as the last child of DIE. */
-static inline void
+static void
add_child_die (dw_die_ref die, dw_die_ref child_die)
{
- if (die != NULL && child_die != NULL)
- {
- gcc_assert (die != child_die);
+ /* FIXME this should probably be an assert. */
+ if (! die || ! child_die)
+ return;
+ gcc_assert (die != child_die);
- child_die->die_parent = die;
- child_die->die_sib = die->die_child;
- die->die_child = child_die;
+ child_die->die_parent = die;
+ if (die->die_child)
+ {
+ child_die->die_sib = die->die_child->die_sib;
+ die->die_child->die_sib = child_die;
}
+ else
+ child_die->die_sib = child_die;
+ die->die_child = child_die;
}
/* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
- is the specification, to the front of PARENT's list of children. */
+ is the specification, to the end of PARENT's list of children.
+ This is done by removing and re-adding it. */
static void
splice_child_die (dw_die_ref parent, dw_die_ref child)
{
- dw_die_ref *p;
+ dw_die_ref p;
/* We want the declaration DIE from inside the class, not the
specification DIE at toplevel. */
gcc_assert (child->die_parent == parent
|| (child->die_parent
== get_AT_ref (parent, DW_AT_specification)));
-
- for (p = &(child->die_parent->die_child); *p; p = &((*p)->die_sib))
- if (*p == child)
+
+ for (p = child->die_parent->die_child; ; p = p->die_sib)
+ if (p->die_sib == child)
{
- *p = child->die_sib;
+ remove_child_with_prev (child, p);
break;
}
- child->die_parent = parent;
- child->die_sib = parent->die_child;
- parent->die_child = child;
+ add_child_die (parent, child);
}
/* Return a pointer to a newly created DIE node. */
{
dw_attr_ref a;
dw_die_ref c;
+ unsigned ix;
print_spaces (outfile);
fprintf (outfile, "DIE %4lu: %s\n",
fprintf (outfile, " abbrev id: %lu", die->die_abbrev);
fprintf (outfile, " offset: %lu\n", die->die_offset);
- for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
print_spaces (outfile);
fprintf (outfile, " %s: ", dwarf_attr_name (a->dw_attr));
fprintf (outfile, "die -> <null>");
break;
case dw_val_class_lbl_id:
- case dw_val_class_lbl_offset:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
fprintf (outfile, "label: %s", AT_lbl (a));
break;
case dw_val_class_str:
if (die->die_child != NULL)
{
print_indent += 4;
- for (c = die->die_child; c != NULL; c = c->die_sib)
- print_die (c, outfile);
-
+ FOR_EACH_CHILD (die, c, print_die (c, outfile));
print_indent -= 4;
}
if (print_indent == 0)
print_dwarf_line_table (stderr);
}
\f
-/* We build up the lists of children and attributes by pushing new ones
- onto the beginning of the list. Reverse the lists for DIE so that
- they are in order of addition. */
-
-static void
-reverse_die_lists (dw_die_ref die)
-{
- dw_die_ref c, cp, cn;
- dw_attr_ref a, ap, an;
-
- for (a = die->die_attr, ap = 0; a; a = an)
- {
- an = a->dw_attr_next;
- a->dw_attr_next = ap;
- ap = a;
- }
-
- die->die_attr = ap;
-
- for (c = die->die_child, cp = 0; c; c = cn)
- {
- cn = c->die_sib;
- c->die_sib = cp;
- cp = c;
- }
-
- die->die_child = cp;
-}
-
-/* reverse_die_lists only reverses the single die you pass it. Since we used to
- reverse all dies in add_sibling_attributes, which runs through all the dies,
- it would reverse all the dies. Now, however, since we don't call
- reverse_die_lists in add_sibling_attributes, we need a routine to
- recursively reverse all the dies. This is that routine. */
-
-static void
-reverse_all_dies (dw_die_ref die)
-{
- dw_die_ref c;
-
- reverse_die_lists (die);
-
- for (c = die->die_child; c; c = c->die_sib)
- reverse_all_dies (c);
-}
-
/* Start a new compilation unit DIE for an include file. OLD_UNIT is the CU
for the enclosing include file, if any. BINCL_DIE is the DW_TAG_GNU_BINCL
DIE that marks the start of the DIEs for this include file. */
case dw_val_class_fde_ref:
case dw_val_class_lbl_id:
- case dw_val_class_lbl_offset:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
break;
default:
{
dw_die_ref c;
dw_attr_ref a;
+ unsigned ix;
/* To avoid infinite recursion. */
if (die->die_mark)
CHECKSUM (die->die_tag);
- for (a = die->die_attr; a; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
attr_checksum (a, ctx, mark);
- for (c = die->die_child; c; c = c->die_sib)
- die_checksum (c, ctx, mark);
+ FOR_EACH_CHILD (die, c, die_checksum (c, ctx, mark));
}
#undef CHECKSUM
case dw_val_class_fde_ref:
case dw_val_class_lbl_id:
- case dw_val_class_lbl_offset:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
return 1;
default:
same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
{
dw_die_ref c1, c2;
- dw_attr_ref a1, a2;
+ dw_attr_ref a1;
+ unsigned ix;
/* To avoid infinite recursion. */
if (die1->die_mark)
if (die1->die_tag != die2->die_tag)
return 0;
- for (a1 = die1->die_attr, a2 = die2->die_attr;
- a1 && a2;
- a1 = a1->dw_attr_next, a2 = a2->dw_attr_next)
- if (!same_attr_p (a1, a2, mark))
- return 0;
- if (a1 || a2)
+ if (VEC_length (dw_attr_node, die1->die_attr)
+ != VEC_length (dw_attr_node, die2->die_attr))
return 0;
-
- for (c1 = die1->die_child, c2 = die2->die_child;
- c1 && c2;
- c1 = c1->die_sib, c2 = c2->die_sib)
- if (!same_die_p (c1, c2, mark))
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++)
+ if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark))
return 0;
- if (c1 || c2)
- return 0;
+
+ c1 = die1->die_child;
+ c2 = die2->die_child;
+ if (! c1)
+ {
+ if (c2)
+ return 0;
+ }
+ else
+ for (;;)
+ {
+ if (!same_die_p (c1, c2, mark))
+ return 0;
+ c1 = c1->die_sib;
+ c2 = c2->die_sib;
+ if (c1 == die1->die_child)
+ {
+ if (c2 == die2->die_child)
+ break;
+ else
+ return 0;
+ }
+ }
return 1;
}
{
return (is_type_die (c)
|| (get_AT (c, DW_AT_declaration)
- && !get_AT (c, DW_AT_specification)));
+ && !get_AT (c, DW_AT_specification))
+ || c->die_tag == DW_TAG_namespace);
}
static char *
die->die_symbol = gen_internal_sym ("LDIE");
}
- for (c = die->die_child; c != NULL; c = c->die_sib)
- assign_symbol_names (c);
+ FOR_EACH_CHILD (die, c, assign_symbol_names (c));
}
struct cu_hash_table_entry
return 1;
}
- entry = xcalloc (1, sizeof (struct cu_hash_table_entry));
+ entry = XCNEW (struct cu_hash_table_entry);
entry->cu = cu;
entry->min_comdat_num = *sym_num = last->max_comdat_num;
entry->next = *slot;
static void
break_out_includes (dw_die_ref die)
{
- dw_die_ref *ptr;
+ dw_die_ref c;
dw_die_ref unit = NULL;
limbo_die_node *node, **pnode;
htab_t cu_hash_table;
- for (ptr = &(die->die_child); *ptr;)
- {
- dw_die_ref c = *ptr;
-
- if (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
- || (unit && is_comdat_die (c)))
- {
- /* This DIE is for a secondary CU; remove it from the main one. */
- *ptr = c->die_sib;
-
- if (c->die_tag == DW_TAG_GNU_BINCL)
- {
- unit = push_new_compile_unit (unit, c);
- free_die (c);
- }
- else if (c->die_tag == DW_TAG_GNU_EINCL)
- {
- unit = pop_compile_unit (unit);
- free_die (c);
- }
- else
- add_child_die (unit, c);
- }
- else
- {
- /* Leave this DIE in the main CU. */
- ptr = &(c->die_sib);
- continue;
- }
- }
+ c = die->die_child;
+ if (c) do {
+ dw_die_ref prev = c;
+ c = c->die_sib;
+ while (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
+ || (unit && is_comdat_die (c)))
+ {
+ dw_die_ref next = c->die_sib;
+
+ /* This DIE is for a secondary CU; remove it from the main one. */
+ remove_child_with_prev (c, prev);
+
+ if (c->die_tag == DW_TAG_GNU_BINCL)
+ unit = push_new_compile_unit (unit, c);
+ else if (c->die_tag == DW_TAG_GNU_EINCL)
+ unit = pop_compile_unit (unit);
+ else
+ add_child_die (unit, c);
+ c = next;
+ if (c == die->die_child)
+ break;
+ }
+ } while (c != die->die_child);
#if 0
/* We can only use this in debugging, since the frontend doesn't check
{
dw_die_ref c;
- if (die->die_tag != DW_TAG_compile_unit
- && die->die_sib && die->die_child != NULL)
- /* Add the sibling link to the front of the attribute list. */
+ if (! die->die_child)
+ return;
+
+ if (die->die_parent && die != die->die_parent->die_child)
add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
- for (c = die->die_child; c != NULL; c = c->die_sib)
- add_sibling_attributes (c);
+ FOR_EACH_CHILD (die, c, add_sibling_attributes (c));
}
/* Output all location lists for the DIE and its children. */
output_location_lists (dw_die_ref die)
{
dw_die_ref c;
- dw_attr_ref d_attr;
-
- for (d_attr = die->die_attr; d_attr; d_attr = d_attr->dw_attr_next)
- if (AT_class (d_attr) == dw_val_class_loc_list)
- output_loc_list (AT_loc_list (d_attr));
+ dw_attr_ref a;
+ unsigned ix;
- for (c = die->die_child; c != NULL; c = c->die_sib)
- output_location_lists (c);
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (AT_class (a) == dw_val_class_loc_list)
+ output_loc_list (AT_loc_list (a));
+ FOR_EACH_CHILD (die, c, output_location_lists (c));
}
/* The format of each DIE (and its attribute value pairs) is encoded in an
unsigned long abbrev_id;
unsigned int n_alloc;
dw_die_ref c;
- dw_attr_ref d_attr, a_attr;
+ dw_attr_ref a;
+ unsigned ix;
/* Scan the DIE references, and mark as external any that refer to
DIEs from other CUs (i.e. those which are not marked). */
- for (d_attr = die->die_attr; d_attr; d_attr = d_attr->dw_attr_next)
- if (AT_class (d_attr) == dw_val_class_die_ref
- && AT_ref (d_attr)->die_mark == 0)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (AT_class (a) == dw_val_class_die_ref
+ && AT_ref (a)->die_mark == 0)
{
- gcc_assert (AT_ref (d_attr)->die_symbol);
+ gcc_assert (AT_ref (a)->die_symbol);
- set_AT_ref_external (d_attr, 1);
+ set_AT_ref_external (a, 1);
}
for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
{
dw_die_ref abbrev = abbrev_die_table[abbrev_id];
-
- if (abbrev->die_tag == die->die_tag)
+ dw_attr_ref die_a, abbrev_a;
+ unsigned ix;
+ bool ok = true;
+
+ if (abbrev->die_tag != die->die_tag)
+ continue;
+ if ((abbrev->die_child != NULL) != (die->die_child != NULL))
+ continue;
+
+ if (VEC_length (dw_attr_node, abbrev->die_attr)
+ != VEC_length (dw_attr_node, die->die_attr))
+ continue;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, die_a); ix++)
{
- if ((abbrev->die_child != NULL) == (die->die_child != NULL))
+ abbrev_a = VEC_index (dw_attr_node, abbrev->die_attr, ix);
+ if ((abbrev_a->dw_attr != die_a->dw_attr)
+ || (value_format (abbrev_a) != value_format (die_a)))
{
- a_attr = abbrev->die_attr;
- d_attr = die->die_attr;
-
- while (a_attr != NULL && d_attr != NULL)
- {
- if ((a_attr->dw_attr != d_attr->dw_attr)
- || (value_format (a_attr) != value_format (d_attr)))
- break;
-
- a_attr = a_attr->dw_attr_next;
- d_attr = d_attr->dw_attr_next;
- }
-
- if (a_attr == NULL && d_attr == NULL)
- break;
+ ok = false;
+ break;
}
}
+ if (ok)
+ break;
}
if (abbrev_id >= abbrev_die_table_in_use)
}
die->die_abbrev = abbrev_id;
- for (c = die->die_child; c != NULL; c = c->die_sib)
- build_abbrev_table (c);
+ FOR_EACH_CHILD (die, c, build_abbrev_table (c));
}
\f
/* Return the power-of-two number of bytes necessary to represent VALUE. */
{
unsigned long size = 0;
dw_attr_ref a;
+ unsigned ix;
size += size_of_uleb128 (die->die_abbrev);
- for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
switch (AT_class (a))
{
case dw_val_class_lbl_id:
size += DWARF2_ADDR_SIZE;
break;
- case dw_val_class_lbl_offset:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_str:
die->die_offset = next_die_offset;
next_die_offset += size_of_die (die);
- for (c = die->die_child; c != NULL; c = c->die_sib)
- calc_die_sizes (c);
+ FOR_EACH_CHILD (die, c, calc_die_sizes (c));
if (die->die_child != NULL)
/* Count the null byte used to terminate sibling lists. */
gcc_assert (!die->die_mark);
die->die_mark = 1;
- for (c = die->die_child; c; c = c->die_sib)
- mark_dies (c);
+ FOR_EACH_CHILD (die, c, mark_dies (c));
}
/* Clear the marks for a die and its children. */
gcc_assert (die->die_mark);
die->die_mark = 0;
- for (c = die->die_child; c; c = c->die_sib)
- unmark_dies (c);
+ FOR_EACH_CHILD (die, c, unmark_dies (c));
}
/* Clear the marks for a die, its children and referred dies. */
{
dw_die_ref c;
dw_attr_ref a;
+ unsigned ix;
if (!die->die_mark)
return;
die->die_mark = 0;
- for (c = die->die_child; c; c = c->die_sib)
- unmark_all_dies (c);
+ FOR_EACH_CHILD (die, c, unmark_all_dies (c));
- for (a = die->die_attr; a; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
if (AT_class (a) == dw_val_class_die_ref)
unmark_all_dies (AT_ref (a));
}
return DW_FORM_addr;
case dw_val_class_range_list:
case dw_val_class_offset:
+ case dw_val_class_loc_list:
switch (DWARF_OFFSET_SIZE)
{
case 4:
default:
gcc_unreachable ();
}
- case dw_val_class_loc_list:
- /* FIXME: Could be DW_FORM_data8, with a > 32 bit size
- .debug_loc section */
- return DW_FORM_data4;
case dw_val_class_loc:
switch (constant_size (size_of_locs (AT_loc (a))))
{
return DW_FORM_data;
case dw_val_class_lbl_id:
return DW_FORM_addr;
- case dw_val_class_lbl_offset:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
return DW_FORM_data;
case dw_val_class_str:
return AT_string_form (a);
{
unsigned long abbrev_id;
- dw_attr_ref a_attr;
-
for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
{
dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+ unsigned ix;
+ dw_attr_ref a_attr;
dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
else
dw2_asm_output_data (1, DW_children_no, "DW_children_no");
- for (a_attr = abbrev->die_attr; a_attr != NULL;
- a_attr = a_attr->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
+ ix++)
{
dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
dwarf_attr_name (a_attr->dw_attr));
fde->dw_fde_hot_section_end_label = cfun->hot_section_end_label;
fde->dw_fde_unlikely_section_label = cfun->cold_section_label;
fde->dw_fde_unlikely_section_end_label = cfun->cold_section_end_label;
- separate_line_info_table_in_use++;
+ have_multiple_function_sections = true;
}
/* Output the location list given to us. */
for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
{
unsigned long size;
- if (separate_line_info_table_in_use == 0)
+ if (!have_multiple_function_sections)
{
dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
"Location list begin address (%s)",
dw_attr_ref a;
dw_die_ref c;
unsigned long size;
+ unsigned ix;
/* If someone in another CU might refer to us, set up a symbol for
them to point to. */
dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)",
die->die_offset, dwarf_tag_name (die->die_tag));
- for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
const char *name = dwarf_attr_name (a->dw_attr);
sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
a->dw_attr_val.v.val_offset);
dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
- "%s", name);
+ debug_ranges_section, "%s", name);
*p = '\0';
}
break;
char *sym = AT_loc_list (a)->ll_symbol;
gcc_assert (sym);
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, "%s", name);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
+ "%s", name);
}
break;
char *sym = AT_ref (a)->die_symbol;
gcc_assert (sym);
- dw2_asm_output_offset (DWARF2_ADDR_SIZE, sym, "%s", name);
+ dw2_asm_output_offset (DWARF2_ADDR_SIZE, sym, debug_info_section,
+ "%s", name);
}
else
{
ASM_GENERATE_INTERNAL_LABEL (l1, FDE_LABEL,
a->dw_attr_val.v.val_fde_index * 2);
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, l1, "%s", name);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, l1, debug_frame_section,
+ "%s", name);
}
break;
dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
break;
- case dw_val_class_lbl_offset:
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a), "%s", name);
+ case dw_val_class_lineptr:
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
+ debug_line_section, "%s", name);
+ break;
+
+ case dw_val_class_macptr:
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
+ debug_macinfo_section, "%s", name);
break;
case dw_val_class_str:
if (AT_string_form (a) == DW_FORM_strp)
dw2_asm_output_offset (DWARF_OFFSET_SIZE,
a->dw_attr_val.v.val_str->label,
+ debug_str_section,
"%s: \"%s\"", name, AT_string (a));
else
dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
}
}
- for (c = die->die_child; c != NULL; c = c->die_sib)
- output_die (c);
+ FOR_EACH_CHILD (die, c, output_die (c));
/* Add null byte to terminate sibling list. */
if (die->die_child != NULL)
"Length of Compilation Unit Info");
dw2_asm_output_data (2, DWARF_VERSION, "DWARF version number");
dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
+ debug_abbrev_section,
"Offset Into Abbrev. Section");
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
}
sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym);
secname = tmp;
die->die_symbol = NULL;
+ switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
}
else
- secname = (const char *) DEBUG_INFO_SECTION;
+ switch_to_section (debug_info_section);
/* Output debugging information. */
- named_section_flags (secname, SECTION_DEBUG);
output_compilation_unit_header ();
output_die (die);
}
}
-/* The DWARF2 pubname for a nested thingy looks like "A::f". The
- output of lang_hooks.decl_printable_name for C++ looks like
- "A::f(int)". Let's drop the argument list, and maybe the scope. */
+/* Return the DWARF2/3 pubname associated with a decl. */
static const char *
dwarf2_name (tree decl, int scope)
{
- return lang_hooks.decl_printable_name (decl, scope ? 1 : 0);
+ return lang_hooks.dwarf_name (decl, scope ? 1 : 0);
}
/* Add a new entry to .debug_pubnames if appropriate. */
"Length of Public Names Info");
dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+ debug_info_section,
"Offset of Compilation Unit Info");
dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
"Compilation Unit Length");
"Length of Address Ranges Info");
dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+ debug_info_section,
"Offset of Compilation Unit Info");
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
/* If all code is in the text section, then the compilation
unit base address defaults to DW_AT_low_pc, which is the
base of the text section. */
- if (separate_line_info_table_in_use == 0)
+ if (!have_multiple_function_sections)
{
dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
text_section_label,
current_file = 1;
current_line = 1;
- if (cfun
- && (last_text_section == in_unlikely_executed_text
- || (last_text_section == in_named
- && last_text_section_name == cfun->unlikely_text_section_name)))
+ if (cfun && in_cold_section_p)
strcpy (prev_line_label, cfun->cold_section_label);
else
strcpy (prev_line_label, text_section_label);
base_type_die (tree type)
{
dw_die_ref base_type_result;
- const char *type_name;
enum dwarf_type encoding;
- tree name = TYPE_NAME (type);
if (TREE_CODE (type) == ERROR_MARK || TREE_CODE (type) == VOID_TYPE)
return 0;
- if (name)
- {
- if (TREE_CODE (name) == TYPE_DECL)
- name = DECL_NAME (name);
-
- type_name = IDENTIFIER_POINTER (name);
- }
- else
- type_name = "__unknown__";
-
switch (TREE_CODE (type))
{
case INTEGER_TYPE:
- /* Carefully distinguish the C character types, without messing
- up if the language is not C. Note that we check only for the names
- that contain spaces; other names might occur by coincidence in other
- languages. */
- if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE
- && (type == char_type_node
- || ! strcmp (type_name, "signed char")
- || ! strcmp (type_name, "unsigned char"))))
+ if (TYPE_STRING_FLAG (type))
{
if (TYPE_UNSIGNED (type))
- encoding = DW_ATE_unsigned;
+ encoding = DW_ATE_unsigned_char;
else
- encoding = DW_ATE_signed;
- break;
+ encoding = DW_ATE_signed_char;
}
- /* else fall through. */
-
- case CHAR_TYPE:
- /* GNU Pascal/Ada CHAR type. Not used in C. */
- if (TYPE_UNSIGNED (type))
- encoding = DW_ATE_unsigned_char;
+ else if (TYPE_UNSIGNED (type))
+ encoding = DW_ATE_unsigned;
else
- encoding = DW_ATE_signed_char;
+ encoding = DW_ATE_signed;
break;
case REAL_TYPE:
- encoding = DW_ATE_float;
+ if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
+ encoding = DW_ATE_decimal_float;
+ else
+ encoding = DW_ATE_float;
break;
/* Dwarf2 doesn't know anything about complex ints, so use
}
base_type_result = new_die (DW_TAG_base_type, comp_unit_die, type);
- if (demangle_name_func)
- type_name = (*demangle_name_func) (type_name);
- add_AT_string (base_type_result, DW_AT_name, type_name);
+ /* This probably indicates a bug. */
+ if (! TYPE_NAME (type))
+ add_name_attribute (base_type_result, "__unknown__");
+
add_AT_unsigned (base_type_result, DW_AT_byte_size,
int_size_in_bytes (type));
add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
case REAL_TYPE:
case COMPLEX_TYPE:
case BOOLEAN_TYPE:
- case CHAR_TYPE:
return 1;
case ARRAY_TYPE:
static dw_die_ref
subrange_type_die (tree type, dw_die_ref context_die)
{
- dw_die_ref subtype_die;
dw_die_ref subrange_die;
- tree name = TYPE_NAME (type);
const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type);
- tree subtype = TREE_TYPE (type);
if (context_die == NULL)
context_die = comp_unit_die;
- if (TREE_CODE (subtype) == ENUMERAL_TYPE)
- subtype_die = gen_enumeration_type_die (subtype, context_die);
- else
- subtype_die = base_type_die (subtype);
-
subrange_die = new_die (DW_TAG_subrange_type, context_die, type);
- if (name != NULL)
- {
- if (TREE_CODE (name) == TYPE_DECL)
- name = DECL_NAME (name);
- add_name_attribute (subrange_die, IDENTIFIER_POINTER (name));
- }
-
- if (int_size_in_bytes (subtype) != size_in_bytes)
+ if (int_size_in_bytes (TREE_TYPE (type)) != size_in_bytes)
{
/* The size of the subrange type and its base type do not match,
so we need to generate a size attribute for the subrange type. */
if (TYPE_MAX_VALUE (type) != NULL)
add_bound_info (subrange_die, DW_AT_upper_bound,
TYPE_MAX_VALUE (type));
- add_AT_die_ref (subrange_die, DW_AT_type, subtype_die);
return subrange_die;
}
dw_die_ref context_die)
{
enum tree_code code = TREE_CODE (type);
- dw_die_ref mod_type_die = NULL;
+ dw_die_ref mod_type_die;
dw_die_ref sub_die = NULL;
tree item_type = NULL;
-
- if (code != ERROR_MARK)
+ tree qualified_type;
+ tree name;
+
+ if (code == ERROR_MARK)
+ return NULL;
+
+ /* See if we already have the appropriately qualified variant of
+ this type. */
+ qualified_type
+ = get_qualified_type (type,
+ ((is_const_type ? TYPE_QUAL_CONST : 0)
+ | (is_volatile_type ? TYPE_QUAL_VOLATILE : 0)));
+
+ /* If we do, then we can just use its DIE, if it exists. */
+ if (qualified_type)
{
- tree qualified_type;
-
- /* See if we already have the appropriately qualified variant of
- this type. */
- qualified_type
- = get_qualified_type (type,
- ((is_const_type ? TYPE_QUAL_CONST : 0)
- | (is_volatile_type
- ? TYPE_QUAL_VOLATILE : 0)));
-
- /* If we do, then we can just use its DIE, if it exists. */
- if (qualified_type)
- {
- mod_type_die = lookup_type_die (qualified_type);
- if (mod_type_die)
- return mod_type_die;
- }
-
- /* Handle C typedef types. */
- if (qualified_type && TYPE_NAME (qualified_type)
- && TREE_CODE (TYPE_NAME (qualified_type)) == TYPE_DECL
- && DECL_ORIGINAL_TYPE (TYPE_NAME (qualified_type)))
- {
- tree type_name = TYPE_NAME (qualified_type);
- tree dtype = TREE_TYPE (type_name);
-
- if (qualified_type == dtype)
- {
- /* For a named type, use the typedef. */
- gen_type_die (qualified_type, context_die);
- mod_type_die = lookup_type_die (qualified_type);
- }
- else if (is_const_type < TYPE_READONLY (dtype)
- || is_volatile_type < TYPE_VOLATILE (dtype))
- /* cv-unqualified version of named type. Just use the unnamed
- type to which it refers. */
- mod_type_die
- = modified_type_die (DECL_ORIGINAL_TYPE (type_name),
- is_const_type, is_volatile_type,
- context_die);
-
- /* Else cv-qualified version of named type; fall through. */
- }
-
+ mod_type_die = lookup_type_die (qualified_type);
if (mod_type_die)
- /* OK. */
- ;
- else if (is_const_type)
- {
- mod_type_die = new_die (DW_TAG_const_type, comp_unit_die, type);
- sub_die = modified_type_die (type, 0, is_volatile_type, context_die);
- }
- else if (is_volatile_type)
- {
- mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die, type);
- sub_die = modified_type_die (type, 0, 0, context_die);
- }
- else if (code == POINTER_TYPE)
- {
- mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die, type);
- add_AT_unsigned (mod_type_die, DW_AT_byte_size,
- simple_type_size_in_bits (type) / BITS_PER_UNIT);
-#if 0
- add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
-#endif
- item_type = TREE_TYPE (type);
- }
- else if (code == REFERENCE_TYPE)
+ return mod_type_die;
+ }
+
+ name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
+
+ /* Handle C typedef types. */
+ if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name))
+ {
+ tree dtype = TREE_TYPE (name);
+
+ if (qualified_type == dtype)
{
- mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die, type);
- add_AT_unsigned (mod_type_die, DW_AT_byte_size,
- simple_type_size_in_bits (type) / BITS_PER_UNIT);
-#if 0
- add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
-#endif
- item_type = TREE_TYPE (type);
+ /* For a named type, use the typedef. */
+ gen_type_die (qualified_type, context_die);
+ return lookup_type_die (qualified_type);
}
- else if (is_subrange_type (type))
- mod_type_die = subrange_type_die (type, context_die);
- else if (is_base_type (type))
- mod_type_die = base_type_die (type);
+ else if (DECL_ORIGINAL_TYPE (name)
+ && (is_const_type < TYPE_READONLY (dtype)
+ || is_volatile_type < TYPE_VOLATILE (dtype)))
+ /* cv-unqualified version of named type. Just use the unnamed
+ type to which it refers. */
+ return modified_type_die (DECL_ORIGINAL_TYPE (name),
+ is_const_type, is_volatile_type,
+ context_die);
+ /* Else cv-qualified version of named type; fall through. */
+ }
+
+ if (is_const_type)
+ {
+ mod_type_die = new_die (DW_TAG_const_type, comp_unit_die, type);
+ sub_die = modified_type_die (type, 0, is_volatile_type, context_die);
+ }
+ else if (is_volatile_type)
+ {
+ mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die, type);
+ sub_die = modified_type_die (type, 0, 0, context_die);
+ }
+ else if (code == POINTER_TYPE)
+ {
+ mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die, type);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size,
+ simple_type_size_in_bits (type) / BITS_PER_UNIT);
+ item_type = TREE_TYPE (type);
+ }
+ else if (code == REFERENCE_TYPE)
+ {
+ mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die, type);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size,
+ simple_type_size_in_bits (type) / BITS_PER_UNIT);
+ item_type = TREE_TYPE (type);
+ }
+ else if (is_subrange_type (type))
+ {
+ mod_type_die = subrange_type_die (type, context_die);
+ item_type = TREE_TYPE (type);
+ }
+ else if (is_base_type (type))
+ mod_type_die = base_type_die (type);
+ else
+ {
+ gen_type_die (type, context_die);
+
+ /* We have to get the type_main_variant here (and pass that to the
+ `lookup_type_die' routine) because the ..._TYPE node we have
+ might simply be a *copy* of some original type node (where the
+ copy was created to help us keep track of typedef names) and
+ that copy might have a different TYPE_UID from the original
+ ..._TYPE node. */
+ if (TREE_CODE (type) != VECTOR_TYPE)
+ return lookup_type_die (type_main_variant (type));
else
- {
- gen_type_die (type, context_die);
-
- /* We have to get the type_main_variant here (and pass that to the
- `lookup_type_die' routine) because the ..._TYPE node we have
- might simply be a *copy* of some original type node (where the
- copy was created to help us keep track of typedef names) and
- that copy might have a different TYPE_UID from the original
- ..._TYPE node. */
- if (TREE_CODE (type) != VECTOR_TYPE)
- mod_type_die = lookup_type_die (type_main_variant (type));
- else
- /* Vectors have the debugging information in the type,
- not the main variant. */
- mod_type_die = lookup_type_die (type);
- gcc_assert (mod_type_die);
- }
-
- /* We want to equate the qualified type to the die below. */
- type = qualified_type;
+ /* Vectors have the debugging information in the type,
+ not the main variant. */
+ return lookup_type_die (type);
+ }
+
+ /* Builtin types don't have a DECL_ORIGINAL_TYPE. For those,
+ don't output a DW_TAG_typedef, since there isn't one in the
+ user's program; just attach a DW_AT_name to the type. */
+ if (name
+ && (TREE_CODE (name) != TYPE_DECL || TREE_TYPE (name) == qualified_type))
+ {
+ if (TREE_CODE (name) == TYPE_DECL)
+ /* Could just call add_name_and_src_coords_attributes here,
+ but since this is a builtin type it doesn't have any
+ useful source coordinates anyway. */
+ name = DECL_NAME (name);
+ add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
}
+
+ if (qualified_type)
+ equate_type_number_to_die (qualified_type, mod_type_die);
- if (type)
- equate_type_number_to_die (type, mod_type_die);
if (item_type)
/* We must do this after the equate_type_number_to_die call, in case
this is a recursive type. This ensures that the modified_type_die
gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+#ifdef LEAF_REG_REMAP
+ {
+ int leaf_reg;
+
+ leaf_reg = LEAF_REG_REMAP (regno);
+ if (leaf_reg != -1)
+ regno = (unsigned) leaf_reg;
+ }
+#endif
+
return DBX_REGISTER_NUMBER (regno);
}
static dw_loc_descr_ref
reg_loc_descriptor (rtx rtl)
{
- unsigned reg;
rtx regs;
if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
return 0;
- reg = dbx_reg_number (rtl);
regs = targetm.dwarf_register_span (rtl);
- if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1
- || regs)
+ if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
return multiple_reg_loc_descriptor (rtl, regs);
else
- return one_reg_loc_descriptor (reg);
+ return one_reg_loc_descriptor (dbx_reg_number (rtl));
}
/* Return a location descriptor that designates a machine register for
unsigned reg;
dw_loc_descr_ref loc_result = NULL;
- reg = dbx_reg_number (rtl);
+ reg = REGNO (rtl);
+#ifdef LEAF_REG_REMAP
+ {
+ int leaf_reg;
+
+ leaf_reg = LEAF_REG_REMAP (reg);
+ if (leaf_reg != -1)
+ reg = (unsigned) leaf_reg;
+ }
+#endif
+ gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
/* Simple, contiguous registers. */
{
dw_loc_descr_ref t;
- t = one_reg_loc_descriptor (reg);
+ t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg));
add_loc_descr (&loc_result, t);
add_loc_descr_op_piece (&loc_result, size);
++reg;
/* Return a location descriptor that designates a base+offset location. */
static dw_loc_descr_ref
-based_loc_descr (unsigned int reg, HOST_WIDE_INT offset, bool can_use_fbreg)
-{
- dw_loc_descr_ref loc_result;
- /* For the "frame base", we use the frame pointer or stack pointer
- registers, since the RTL for local variables is relative to one of
- them. */
- unsigned fp_reg = DBX_REGISTER_NUMBER (frame_pointer_needed
- ? HARD_FRAME_POINTER_REGNUM
- : STACK_POINTER_REGNUM);
-
- if (reg == fp_reg && can_use_fbreg)
- loc_result = new_loc_descr (DW_OP_fbreg, offset, 0);
- else if (reg <= 31)
- loc_result = new_loc_descr (DW_OP_breg0 + reg, offset, 0);
- else
- loc_result = new_loc_descr (DW_OP_bregx, reg, offset);
+based_loc_descr (rtx reg, HOST_WIDE_INT offset)
+{
+ unsigned int regno;
- return loc_result;
+ /* We only use "frame base" when we're sure we're talking about the
+ post-prologue local stack frame. We do this by *not* running
+ register elimination until this point, and recognizing the special
+ argument pointer and soft frame pointer rtx's. */
+ if (reg == arg_pointer_rtx || reg == frame_pointer_rtx)
+ {
+ rtx elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+
+ if (elim != reg)
+ {
+ if (GET_CODE (elim) == PLUS)
+ {
+ offset += INTVAL (XEXP (elim, 1));
+ elim = XEXP (elim, 0);
+ }
+ gcc_assert (elim == (frame_pointer_needed ? hard_frame_pointer_rtx
+ : stack_pointer_rtx));
+ offset += frame_pointer_fb_offset;
+
+ return new_loc_descr (DW_OP_fbreg, offset, 0);
+ }
+ }
+
+ regno = dbx_reg_number (reg);
+ if (regno <= 31)
+ return new_loc_descr (DW_OP_breg0 + regno, offset, 0);
+ else
+ return new_loc_descr (DW_OP_bregx, regno, offset);
}
/* Return true if this RTL expression describes a base+offset calculation. */
MODE is the mode of the memory reference, needed to handle some
autoincrement addressing modes.
- CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the location
- list for RTL. We can't use it when we are emitting location list for
- virtual variable frame_base_decl (i.e. a location list for DW_AT_frame_base)
- which describes how frame base changes when !frame_pointer_needed.
+ CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the
+ location list for RTL.
Return 0 if we can't represent the location. */
static dw_loc_descr_ref
-mem_loc_descriptor (rtx rtl, enum machine_mode mode, bool can_use_fbreg)
+mem_loc_descriptor (rtx rtl, enum machine_mode mode)
{
dw_loc_descr_ref mem_loc_result = NULL;
enum dwarf_location_atom op;
up an entire register. For now, just assume that it is
legitimate to make the Dwarf info refer to the whole register which
contains the given subreg. */
- rtl = SUBREG_REG (rtl);
+ rtl = XEXP (rtl, 0);
/* ... fall through ... */
memory) so DWARF consumers need to be aware of the subtle
distinction between OP_REG and OP_BASEREG. */
if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
- mem_loc_result = based_loc_descr (dbx_reg_number (rtl), 0,
- can_use_fbreg);
+ mem_loc_result = based_loc_descr (rtl, 0);
break;
case MEM:
- mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
- can_use_fbreg);
+ mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
if (mem_loc_result != 0)
add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
break;
case PLUS:
plus:
if (is_based_loc (rtl))
- mem_loc_result = based_loc_descr (dbx_reg_number (XEXP (rtl, 0)),
- INTVAL (XEXP (rtl, 1)),
- can_use_fbreg);
+ mem_loc_result = based_loc_descr (XEXP (rtl, 0),
+ INTVAL (XEXP (rtl, 1)));
else
{
- mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode,
- can_use_fbreg);
+ mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode);
if (mem_loc_result == 0)
break;
else
{
add_loc_descr (&mem_loc_result,
- mem_loc_descriptor (XEXP (rtl, 1), mode,
- can_use_fbreg));
+ mem_loc_descriptor (XEXP (rtl, 1), mode));
add_loc_descr (&mem_loc_result,
new_loc_descr (DW_OP_plus, 0, 0));
}
do_binop:
{
- dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
- can_use_fbreg);
- dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
- can_use_fbreg);
+ dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode);
+ dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode);
if (op0 == 0 || op1 == 0)
break;
concat_loc_descriptor (rtx x0, rtx x1)
{
dw_loc_descr_ref cc_loc_result = NULL;
- dw_loc_descr_ref x0_ref = loc_descriptor (x0, false);
- dw_loc_descr_ref x1_ref = loc_descriptor (x1, false);
+ dw_loc_descr_ref x0_ref = loc_descriptor (x0);
+ dw_loc_descr_ref x1_ref = loc_descriptor (x1);
if (x0_ref == 0 || x1_ref == 0)
return 0;
If we don't know how to describe it, return 0. */
static dw_loc_descr_ref
-loc_descriptor (rtx rtl, bool can_use_fbreg)
+loc_descriptor (rtx rtl)
{
dw_loc_descr_ref loc_result = NULL;
break;
case MEM:
- loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
- can_use_fbreg);
+ loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
break;
case CONCAT:
/* Single part. */
if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
{
- loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), can_use_fbreg);
+ loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0));
break;
}
int i;
/* Create the first one, so we have something to add to. */
- loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
- can_use_fbreg);
+ loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0));
mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
for (i = 1; i < num_elem; i++)
{
dw_loc_descr_ref temp;
- temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
- can_use_fbreg);
+ temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0));
add_loc_descr (&loc_result, temp);
mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
{
dw_loc_descr_ref ret, ret1;
int have_address = 0;
- int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
enum dwarf_location_atom op;
/* ??? Most of the time we do not take proper care for sign/zero
/* Certain constructs can only be represented at top-level. */
if (want_address == 2)
- return loc_descriptor (rtl, false);
+ return loc_descriptor (rtl);
mode = GET_MODE (rtl);
if (MEM_P (rtl))
rtl = XEXP (rtl, 0);
have_address = 1;
}
- ret = mem_loc_descriptor (rtl, mode, false);
+ ret = mem_loc_descriptor (rtl, mode);
}
}
break;
HOST_WIDE_INT bitsize, bitpos, bytepos;
enum machine_mode mode;
int volatilep;
+ int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
&unsignedp, &volatilep, false);
return 0;
mode = GET_MODE (rtl);
rtl = XEXP (rtl, 0);
- ret = mem_loc_descriptor (rtl, mode, false);
+ ret = mem_loc_descriptor (rtl, mode);
have_address = 1;
break;
}
goto do_binop;
case RSHIFT_EXPR:
- op = (unsignedp ? DW_OP_shr : DW_OP_shra);
+ op = (TYPE_UNSIGNED (TREE_TYPE (loc)) ? DW_OP_shr : DW_OP_shra);
goto do_binop;
case PLUS_EXPR:
return 0;
/* If we've got an address and don't want one, dereference. */
- if (!want_address && have_address)
+ if (!want_address && have_address && ret)
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
{
enum machine_mode mode = GET_MODE (rtl);
- if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+ if (SCALAR_FLOAT_MODE_P (mode))
{
unsigned int length = GET_MODE_SIZE (mode);
unsigned char *array = ggc_alloc (length);
}
+/* Determine whether the evaluation of EXPR references any variables
+ or functions which aren't otherwise used (and therefore may not be
+ output). */
+static tree
+reference_to_unused (tree * tp, int * walk_subtrees,
+ void * data ATTRIBUTE_UNUSED)
+{
+ if (! EXPR_P (*tp) && ! CONSTANT_CLASS_P (*tp))
+ *walk_subtrees = 0;
+
+ if (DECL_P (*tp) && ! TREE_PUBLIC (*tp) && ! TREE_USED (*tp)
+ && ! TREE_ASM_WRITTEN (*tp))
+ return *tp;
+ else
+ return NULL_TREE;
+}
+
/* Generate an RTL constant from a decl initializer INIT with decl type TYPE,
for use in a later add_const_value_attribute call. */
rtl = gen_rtx_CONST_STRING (VOIDmode,
ggc_strdup (TREE_STRING_POINTER (init)));
}
+ /* Although DWARF could easily handle other kinds of aggregates, we
+ have no way to represent such values as RTL constants, so skip
+ those. */
+ else if (AGGREGATE_TYPE_P (type))
+ ;
/* If the initializer is something that we know will expand into an
- immediate RTL constant, expand it now. Expanding anything else
- tends to produce unresolved symbols; see debug/5770 and c++/6381. */
- /* Aggregate, vector, and complex types may contain constructors that may
- result in code being generated when expand_expr is called, so we can't
- handle them here. Integer and float are useful and safe types to handle
- here. */
- else if ((INTEGRAL_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (type))
- && initializer_constant_valid_p (init, type) == null_pointer_node)
+ immediate RTL constant, expand it now. We must be careful not to
+ reference variables which won't be output. */
+ else if (initializer_constant_valid_p (init, type)
+ && ! walk_tree (&init, reference_to_unused, NULL, NULL))
{
rtl = expand_expr (init, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
plus_constant (XEXP (rtl, 0), rsize-dsize));
}
- if (rtl != NULL_RTX)
- {
- rtl = eliminate_regs (rtl, 0, NULL_RTX);
-#ifdef LEAF_REG_REMAP
- if (current_function_uses_only_leaf_regs)
- leaf_renumber_regs_insn (rtl);
-#endif
- }
-
/* A variable with no DECL_RTL but a DECL_INITIAL is a compile-time constant,
and will have been substituted directly into all expressions that use it.
C does not have such a concept, but C++ and other languages do. */
- else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
+ if (!rtl && TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
rtl = rtl_for_decl_init (DECL_INITIAL (decl), TREE_TYPE (decl));
if (rtl)
return rtl;
}
-/* Return true if DECL's containing function has a frame base attribute.
- Return false otherwise. */
+/* We need to figure out what section we should use as the base for the
+ address ranges where a given location is valid.
+ 1. If this particular DECL has a section associated with it, use that.
+ 2. If this function has a section associated with it, use that.
+ 3. Otherwise, use the text section.
+ XXX: If you split a variable across multiple sections, we won't notice. */
-static bool
-containing_function_has_frame_base (tree decl)
+static const char *
+secname_for_decl (tree decl)
{
- tree declcontext = decl_function_context (decl);
- dw_die_ref context;
- dw_attr_ref attr;
-
- if (!declcontext)
- return false;
+ const char *secname;
- context = lookup_decl_die (declcontext);
- if (!context)
- return false;
+ if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
+ {
+ tree sectree = DECL_SECTION_NAME (decl);
+ secname = TREE_STRING_POINTER (sectree);
+ }
+ else if (current_function_decl && DECL_SECTION_NAME (current_function_decl))
+ {
+ tree sectree = DECL_SECTION_NAME (current_function_decl);
+ secname = TREE_STRING_POINTER (sectree);
+ }
+ else if (cfun && in_cold_section_p)
+ secname = cfun->cold_section_label;
+ else
+ secname = text_section_label;
- for (attr = context->die_attr; attr; attr = attr->dw_attr_next)
- if (attr->dw_attr == DW_AT_frame_base)
- return true;
- return false;
+ return secname;
}
-
+
/* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value
data attribute for a variable or a parameter. We generate the
DW_AT_const_value attribute only in those cases where the given variable
rtx rtl;
dw_loc_descr_ref descr;
var_loc_list *loc_list;
- bool can_use_fb;
struct var_loc_node *node;
if (TREE_CODE (decl) == ERROR_MARK)
return;
gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL);
- can_use_fb = containing_function_has_frame_base (decl);
-
/* See if we possibly have multiple locations for this variable. */
loc_list = lookup_decl_loc (decl);
differ. */
if (loc_list && loc_list->first != loc_list->last)
{
- const char *secname;
- const char *endname;
+ const char *endname, *secname;
dw_loc_list_ref list;
rtx varloc;
- /* We need to figure out what section we should use as the base
- for the address ranges where a given location is valid.
- 1. If this particular DECL has a section associated with it,
- use that.
- 2. If this function has a section associated with it, use
- that.
- 3. Otherwise, use the text section.
- XXX: If you split a variable across multiple sections, this
- won't notice. */
-
- if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl))
- {
- tree sectree = DECL_SECTION_NAME (decl);
- secname = TREE_STRING_POINTER (sectree);
- }
- else if (current_function_decl
- && DECL_SECTION_NAME (current_function_decl))
- {
- tree sectree = DECL_SECTION_NAME (current_function_decl);
- secname = TREE_STRING_POINTER (sectree);
- }
- else if (cfun
- && (last_text_section == in_unlikely_executed_text
- || (last_text_section == in_named
- && last_text_section_name ==
- cfun->unlikely_text_section_name)))
- secname = cfun->cold_section_label;
- else
- secname = text_section_label;
-
/* Now that we know what section we are using for a base,
actually construct the list of locations.
The first location information is what is passed to the
node = loc_list->first;
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
- list = new_loc_list (loc_descriptor (varloc, can_use_fb),
+ secname = secname_for_decl (decl);
+
+ list = new_loc_list (loc_descriptor (varloc),
node->label, node->next->label, secname, 1);
node = node->next;
/* The variable has a location between NODE->LABEL and
NODE->NEXT->LABEL. */
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
- add_loc_descr_to_loc_list (&list,
- loc_descriptor (varloc,
- can_use_fb),
+ add_loc_descr_to_loc_list (&list, loc_descriptor (varloc),
node->label, node->next->label, secname);
}
current_function_funcdef_no);
endname = ggc_strdup (label_id);
}
- add_loc_descr_to_loc_list (&list,
- loc_descriptor (varloc,
- can_use_fb),
+ add_loc_descr_to_loc_list (&list, loc_descriptor (varloc),
node->label, endname, secname);
}
return;
}
- /* We couldn't get any rtl, and we had no >1 element location list, so try
- directly generating the location description from the tree. */
- descr = loc_descriptor_from_tree (decl);
- if (descr)
- {
- add_AT_location_description (die, attr, descr);
- return;
- }
-
- /* Lastly, if we have tried to generate the location otherwise, and it
+ /* If we have tried to generate the location otherwise, and it
didn't work out (we wouldn't be here if we did), and we have a one entry
location list, try generating a location from that. */
if (loc_list && loc_list->first)
{
node = loc_list->first;
- descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note),
- can_use_fb);
+ descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note));
if (descr)
- add_AT_location_description (die, attr, descr);
+ {
+ add_AT_location_description (die, attr, descr);
+ return;
+ }
+ }
+
+ /* We couldn't get any rtl, so try directly generating the location
+ description from the tree. */
+ descr = loc_descriptor_from_tree (decl);
+ if (descr)
+ {
+ add_AT_location_description (die, attr, descr);
+ return;
}
+ /* None of that worked, so it must not really have a location;
+ try adding a constant value attribute from the DECL_INITIAL. */
+ tree_add_const_value_attribute (die, decl);
}
/* If we don't have a copy of this variable in memory for some reason (such
add_const_value_attribute (var_die, rtl);
}
+/* 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. OFFSET is a constant to be added to all CFA
+ expressions. */
+
+static dw_loc_list_ref
+convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset)
+{
+ dw_fde_ref fde;
+ dw_loc_list_ref list, *list_tail;
+ dw_cfi_ref cfi;
+ dw_cfa_location last_cfa, next_cfa;
+ const char *start_label, *last_label, *section;
+
+ fde = &fde_table[fde_table_in_use - 1];
+
+ section = secname_for_decl (current_function_decl);
+ list_tail = &list;
+ list = NULL;
+
+ next_cfa.reg = INVALID_REGNUM;
+ next_cfa.offset = 0;
+ next_cfa.indirect = 0;
+ next_cfa.base_offset = 0;
+
+ start_label = fde->dw_fde_begin;
+
+ /* ??? Bald assumption that the CIE opcode list does not contain
+ advance opcodes. */
+ for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
+ lookup_cfa_1 (cfi, &next_cfa);
+
+ last_cfa = next_cfa;
+ last_label = start_label;
+
+ for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
+ switch (cfi->dw_cfi_opc)
+ {
+ case DW_CFA_advance_loc1:
+ case DW_CFA_advance_loc2:
+ case DW_CFA_advance_loc4:
+ if (!cfa_equal_p (&last_cfa, &next_cfa))
+ {
+ *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
+ start_label, last_label, section,
+ list == NULL);
+
+ list_tail = &(*list_tail)->dw_loc_next;
+ last_cfa = next_cfa;
+ start_label = last_label;
+ }
+ last_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+ break;
+
+ case DW_CFA_advance_loc:
+ /* The encoding is complex enough that we should never emit this. */
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
+ /* We don't handle these two in this function. It would be possible
+ if it were to be required. */
+ gcc_unreachable ();
+
+ default:
+ lookup_cfa_1 (cfi, &next_cfa);
+ break;
+ }
+
+ if (!cfa_equal_p (&last_cfa, &next_cfa))
+ {
+ *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
+ start_label, last_label, section,
+ list == NULL);
+ list_tail = &(*list_tail)->dw_loc_next;
+ start_label = last_label;
+ }
+ *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
+ start_label, fde->dw_fde_end, section,
+ list == NULL);
+
+ return list;
+}
+
+/* Compute a displacement from the "steady-state frame pointer" to the
+ frame base (often the same as the CFA), and store it in
+ frame_pointer_fb_offset. OFFSET is added to the displacement
+ before the latter is negated. */
+
+static void
+compute_frame_pointer_to_fb_displacement (HOST_WIDE_INT offset)
+{
+ rtx reg, elim;
+
+#ifdef FRAME_POINTER_CFA_OFFSET
+ reg = frame_pointer_rtx;
+ offset += FRAME_POINTER_CFA_OFFSET (current_function_decl);
+#else
+ reg = arg_pointer_rtx;
+ offset += ARG_POINTER_CFA_OFFSET (current_function_decl);
+#endif
+
+ elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+ if (GET_CODE (elim) == PLUS)
+ {
+ offset += INTVAL (XEXP (elim, 1));
+ elim = XEXP (elim, 0);
+ }
+ gcc_assert (elim == (frame_pointer_needed ? hard_frame_pointer_rtx
+ : stack_pointer_rtx));
+
+ frame_pointer_fb_offset = -offset;
+}
+
/* Generate a DW_AT_name attribute given some string value to be included as
the value of the attribute. */
if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
&& TREE_PUBLIC (decl)
&& DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
- && !DECL_ABSTRACT (decl))
+ && !DECL_ABSTRACT (decl)
+ && !(TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)))
add_AT_string (die, DW_AT_MIPS_linkage_name,
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
}
current_function_decl = save_fn;
}
+/* Helper function of premark_used_types() which gets called through
+ htab_traverse_resize().
+
+ Marks the DIE of a given type in *SLOT as perennial, so it never gets
+ marked as unused by prune_unused_types. */
+static int
+premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+ tree type;
+ dw_die_ref die;
+
+ type = *slot;
+ die = lookup_type_die (type);
+ if (die != NULL)
+ die->die_perennial_p = 1;
+ return 1;
+}
+
+/* Mark all members of used_types_hash as perennial. */
+static void
+premark_used_types (void)
+{
+ if (cfun && cfun->used_types_hash)
+ htab_traverse (cfun->used_types_hash, premark_used_types_helper, NULL);
+}
+
/* Generate a DIE to represent a declared function (either file-scope or
block-local). */
char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
tree origin = decl_ultimate_origin (decl);
dw_die_ref subr_die;
- rtx fp_reg;
tree fn_arg_types;
tree outer_scope;
dw_die_ref old_die = lookup_decl_die (decl);
int declaration = (current_function_decl != decl
|| class_or_namespace_scope_p (context_die));
+ premark_used_types();
+
/* It is possible to have both DECL_ABSTRACT and DECLARATION be true if we
started to generate the abstract instance of an inline, decided to output
its containing class, and proceeded to emit the declaration of the inline
gcc_assert (!old_die);
}
+ /* Now that the C++ front end lazily declares artificial member fns, we
+ might need to retrofit the declaration into its class. */
+ if (!declaration && !origin && !old_die
+ && DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))
+ && !class_or_namespace_scope_p (context_die)
+ && debug_info_level > DINFO_LEVEL_TERSE)
+ old_die = force_decl_die (decl);
+
if (origin != NULL)
{
gcc_assert (!declaration || local_scope_p (context_die));
Note that force_decl_die() forces function declaration die. It is
later reused to represent definition. */
- equate_decl_number_to_die (decl, subr_die);
+ equate_decl_number_to_die (decl, subr_die);
}
}
else if (DECL_ABSTRACT (decl))
}
else if (!DECL_EXTERNAL (decl))
{
+ HOST_WIDE_INT cfa_fb_offset;
+
if (!old_die || !get_AT (old_die, DW_AT_inline))
equate_decl_number_to_die (decl, subr_die);
add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde);
#endif
- /* Define the "frame base" location for this routine. We use the
- frame pointer or stack pointer registers, since the RTL for local
- variables is relative to one of them. */
- if (frame_base_decl && lookup_decl_loc (frame_base_decl) != NULL)
- {
- add_location_or_const_value_attribute (subr_die, frame_base_decl,
- DW_AT_frame_base);
- }
- else
- {
- 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));
- }
+ cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
+
+ /* 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,
+ (2) With dwarf3, there exists a one-byte encoding that allows us
+ to reference the .debug_frame data by proxy, but failing that,
+ (3) We can at least reuse the code inspection and interpretation
+ code that determines the CFA position at various points in the
+ function. */
+ /* ??? Use some command-line or configury switch to enable the use
+ of dwarf3 DW_OP_call_frame_cfa. At present there are no dwarf
+ consumers that understand it; fall back to "pure" dwarf2 and
+ convert the CFA data into a location list. */
+ {
+ dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset);
+ if (list->dw_loc_next)
+ add_AT_loc_list (subr_die, DW_AT_frame_base, list);
+ else
+ add_AT_loc (subr_die, DW_AT_frame_base, list->expr);
+ }
+
+ /* Compute a displacement from the "steady-state frame pointer" to
+ the CFA. The former is what all stack slots and argument slots
+ will reference in the rtl; the later is what we've told the
+ debugger about. We'll need to adjust all frame_base references
+ by this displacement. */
+ compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
if (cfun->static_chain_decl)
add_AT_location_description (subr_die, DW_AT_static_link,
language = DW_LANG_Pascal83;
else if (strcmp (language_string, "GNU Java") == 0)
language = DW_LANG_Java;
+ else if (strcmp (language_string, "GNU Objective-C") == 0)
+ language = DW_LANG_ObjC;
+ else if (strcmp (language_string, "GNU Objective-C++") == 0)
+ language = DW_LANG_ObjC_plus_plus;
else
language = DW_LANG_C89;
return die;
}
-/* Generate a DIE for a string type. */
-
-static void
-gen_string_type_die (tree type, dw_die_ref context_die)
-{
- dw_die_ref type_die
- = new_die (DW_TAG_string_type, scope_die_for (type, context_die), type);
-
- equate_type_number_to_die (type, type_die);
-
- /* ??? Fudge the string length attribute for now.
- TODO: add string length info. */
-#if 0
- string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type)));
- bound_representation (upper_bound, 0, 'u');
-#endif
-}
-
/* Generate the DIE for a base class. */
static void
break;
case ARRAY_TYPE:
- if (TYPE_STRING_FLAG (type) && TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE)
- {
- gen_type_die (TREE_TYPE (type), context_die);
- gen_string_type_die (type, context_die);
- }
- else
- gen_array_type_die (type, context_die);
+ gen_array_type_die (type, context_die);
break;
case VECTOR_TYPE:
case REAL_TYPE:
case COMPLEX_TYPE:
case BOOLEAN_TYPE:
- case CHAR_TYPE:
/* No DIEs needed for fundamental types. */
break;
else
context_die = comp_unit_die;
+ decl_die = lookup_decl_die (decl);
+ if (decl_die)
+ return decl_die;
+
switch (TREE_CODE (decl))
{
case FUNCTION_DECL:
{
dw_die_ref context_die;
if (TYPE_CONTEXT (type))
- if (TYPE_P (TYPE_CONTEXT (type)))
- context_die = force_type_die (TYPE_CONTEXT (type));
- else
- context_die = force_decl_die (TYPE_CONTEXT (type));
+ {
+ if (TYPE_P (TYPE_CONTEXT (type)))
+ context_die = force_type_die (TYPE_CONTEXT (type));
+ else
+ context_die = force_decl_die (TYPE_CONTEXT (type));
+ }
else
context_die = comp_unit_die;
+ type_die = lookup_type_die (type);
+ if (type_die)
+ return type_die;
gen_type_die (type, context_die);
type_die = lookup_type_die (type);
gcc_assert (type_die);
}
}
\f
-/* Add Ada "use" clause information for SGI Workshop debugger. */
-
-void
-dwarf2out_add_library_unit_info (const char *filename, const char *context_list)
-{
- unsigned int file_index;
-
- if (filename != NULL)
- {
- dw_die_ref unit_die = new_die (DW_TAG_module, comp_unit_die, NULL);
- tree context_list_decl
- = build_decl (LABEL_DECL, get_identifier (context_list),
- void_type_node);
-
- TREE_PUBLIC (context_list_decl) = TRUE;
- add_name_attribute (unit_die, context_list);
- file_index = lookup_filename (filename);
- add_AT_unsigned (unit_die, DW_AT_decl_file, file_index);
- add_pubname (context_list_decl, unit_die);
- }
-}
-
/* Output debug information for global decl DECL. Called from toplev.c after
compilation proper has finished. */
{
/* OK, we need to generate one for `bool' so GDB knows what type
comparisons have. */
- if ((get_AT_unsigned (comp_unit_die, DW_AT_language)
- == DW_LANG_C_plus_plus)
+ if (is_cxx ()
&& TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE
&& ! DECL_IGNORED_P (decl))
modified_type_die (TREE_TYPE (decl), 0, 0, NULL);
dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
unsigned int blocknum)
{
- current_function_section (current_function_decl);
+ switch_to_section (current_function_section ());
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
}
static void
dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
{
- current_function_section (current_function_decl);
+ switch_to_section (current_function_section ());
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
}
prune_unused_types_walk_attribs. */
if (DWARF2_ASM_LINE_DEBUG_INFO && ! flag_eliminate_unused_debug_types)
- maybe_emit_file (i);
+ return maybe_emit_file (i);
return i;
}
newloc->var_loc_note = loc_note;
newloc->next = NULL;
- if (cfun
- && (last_text_section == in_unlikely_executed_text
- || (last_text_section == in_named
- && last_text_section_name == cfun->unlikely_text_section_name)))
+ if (cfun && in_cold_section_p)
newloc->section_label = cfun->cold_section_label;
else
newloc->section_label = text_section_label;
/* We need to reset the locations at the beginning of each
function. We can't do this in the end_function hook, because the
- declarations that use the locations won't have been outputted when
- that hook is called. */
+ declarations that use the locations won't have been output when
+ that hook is called. Also compute have_multiple_function_sections here. */
static void
-dwarf2out_begin_function (tree unused ATTRIBUTE_UNUSED)
+dwarf2out_begin_function (tree fun)
{
htab_empty (decl_loc_table);
+
+ if (function_section (fun) != text_section)
+ have_multiple_function_sections = true;
}
/* Output a label to mark the beginning of a source code line entry
if (debug_info_level >= DINFO_LEVEL_NORMAL
&& line != 0)
{
- current_function_section (current_function_decl);
+ switch_to_section (current_function_section ());
/* If requested, emit something human-readable. */
if (flag_debug_asm)
/* Indicate that line number info exists. */
line_info_table_in_use++;
-
- /* Indicate that multiple line number tables exist. */
- if (DECL_SECTION_NAME (current_function_decl))
- separate_line_info_table_in_use++;
}
- else if (DECL_SECTION_NAME (current_function_decl))
+ else if (function_section (current_function_decl) != text_section)
{
dw_separate_line_info_ref line_info;
targetm.asm_out.internal_label (asm_out_file, SEPARATE_LINE_CODE_LABEL,
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
- named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
+ int fileno;
+
+ switch_to_section (debug_macinfo_section);
dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
lineno);
- maybe_emit_file (lookup_filename (filename));
- dw2_asm_output_data_uleb128 (lookup_filename (filename),
- "Filename we just started");
+
+ fileno = maybe_emit_file (lookup_filename (filename));
+ dw2_asm_output_data_uleb128 (fileno, "Filename we just started");
}
}
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
- named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_macinfo_section);
dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
}
}
{
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
- named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_macinfo_section);
dw2_asm_output_data (1, DW_MACINFO_define, "Define macro");
dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
dw2_asm_output_nstring (buffer, -1, "The macro");
{
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
- named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_macinfo_section);
dw2_asm_output_data (1, DW_MACINFO_undef, "Undefine macro");
dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
dw2_asm_output_nstring (buffer, -1, "The macro");
used_rtx_array = VEC_alloc (rtx, gc, 32);
+ debug_info_section = get_section (DEBUG_INFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_macinfo_section = get_section (DEBUG_MACINFO_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_line_section = get_section (DEBUG_LINE_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_loc_section = get_section (DEBUG_LOC_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_str_section = get_section (DEBUG_STR_SECTION,
+ DEBUG_STR_SECTION_FLAGS, NULL);
+ debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
+ SECTION_DEBUG, NULL);
+ debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+ SECTION_DEBUG, NULL);
+
ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
DEBUG_ABBREV_SECTION_LABEL, 0);
DEBUG_LINE_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
DEBUG_RANGES_SECTION_LABEL, 0);
- named_section_flags (DEBUG_ABBREV_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_abbrev_section);
ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
- named_section_flags (DEBUG_INFO_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_info_section);
ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
- named_section_flags (DEBUG_LINE_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_line_section);
ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
- named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_macinfo_section);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
DEBUG_MACINFO_SECTION_LABEL, 0);
ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
}
- text_section ();
+ switch_to_section (text_section);
ASM_OUTPUT_LABEL (asm_out_file, text_section_label);
if (flag_reorder_blocks_and_partition)
{
- unlikely_text_section ();
+ switch_to_section (unlikely_text_section ());
ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label);
}
}
if (node->form == DW_FORM_strp)
{
- named_section_flags (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS);
+ switch_to_section (debug_str_section);
ASM_OUTPUT_LABEL (asm_out_file, node->label);
assemble_string (node->str, strlen (node->str) + 1);
}
return 1;
}
+#if ENABLE_ASSERT_CHECKING
+/* Verify that all marks are clear. */
+static void
+verify_marks_clear (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ gcc_assert (! die->die_mark);
+ FOR_EACH_CHILD (die, c, verify_marks_clear (c));
+}
+#endif /* ENABLE_ASSERT_CHECKING */
/* Clear the marks for a die and its children.
Be cool if the mark isn't set. */
prune_unmark_dies (dw_die_ref die)
{
dw_die_ref c;
- die->die_mark = 0;
- for (c = die->die_child; c; c = c->die_sib)
- prune_unmark_dies (c);
+
+ if (die->die_mark)
+ die->die_mark = 0;
+ FOR_EACH_CHILD (die, c, prune_unmark_dies (c));
}
-
/* Given DIE that we're marking as used, find any other dies
it references as attributes and mark them as used. */
prune_unused_types_walk_attribs (dw_die_ref die)
{
dw_attr_ref a;
+ unsigned ix;
- for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
if (a->dw_attr_val.val_class == dw_val_class_die_ref)
{
a->dw_attr_val.v.val_unsigned =
maybe_emit_file (a->dw_attr_val.v.val_unsigned);
}
+ /* Set the string's refcount to 0 so that prune_unused_types_mark
+ accounts properly for it. */
+ if (AT_class (a) == dw_val_class_str)
+ a->dw_attr_val.v.val_str->refcount = 0;
}
}
Remember that we've walked the kids. */
die->die_mark = 2;
- /* Walk them. */
- for (c = die->die_child; c; c = c->die_sib)
- {
- /* If this is an array type, we need to make sure our
- kids get marked, even if they're types. */
- if (die->die_tag == DW_TAG_array_type)
- prune_unused_types_mark (c, 1);
- else
- prune_unused_types_walk (c);
- }
+ /* If this is an array type, we need to make sure our
+ kids get marked, even if they're types. */
+ if (die->die_tag == DW_TAG_array_type)
+ FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1));
+ else
+ FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
}
}
case DW_TAG_subrange_type:
case DW_TAG_ptr_to_member_type:
case DW_TAG_file_type:
+ if (die->die_perennial_p)
+ break;
+
/* It's a type node --- don't mark it. */
return;
prune_unused_types_walk_attribs (die);
/* Mark children. */
- for (c = die->die_child; c; c = c->die_sib)
- prune_unused_types_walk (c);
+ FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
}
+/* Increment the string counts on strings referred to from DIE's
+ attributes. */
+
+static void
+prune_unused_types_update_strings (dw_die_ref die)
+{
+ dw_attr_ref a;
+ unsigned ix;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (AT_class (a) == dw_val_class_str)
+ {
+ struct indirect_string_node *s = a->dw_attr_val.v.val_str;
+ s->refcount++;
+ /* Avoid unnecessarily putting strings that are used less than
+ twice in the hash table. */
+ if (s->refcount
+ == ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) ? 1 : 2))
+ {
+ void ** slot;
+ slot = htab_find_slot_with_hash (debug_str_hash, s->str,
+ htab_hash_string (s->str),
+ INSERT);
+ gcc_assert (*slot == NULL);
+ *slot = s;
+ }
+ }
+}
/* Remove from the tree DIE any dies that aren't marked. */
static void
prune_unused_types_prune (dw_die_ref die)
{
- dw_die_ref c, p, n;
+ dw_die_ref c;
gcc_assert (die->die_mark);
- p = NULL;
- for (c = die->die_child; c; c = n)
- {
- n = c->die_sib;
- if (c->die_mark)
- {
- prune_unused_types_prune (c);
- p = c;
- }
- else
+ if (! die->die_child)
+ return;
+
+ c = die->die_child;
+ do {
+ dw_die_ref prev = c;
+ for (c = c->die_sib; ! c->die_mark; c = c->die_sib)
+ if (c == die->die_child)
{
- if (p)
- p->die_sib = n;
+ /* No marked children between 'prev' and the end of the list. */
+ if (prev == c)
+ /* No marked children at all. */
+ die->die_child = NULL;
else
- die->die_child = n;
- free_die (c);
+ {
+ prev->die_sib = c->die_sib;
+ die->die_child = prev;
+ }
+ return;
}
- }
+
+ if (c != prev->die_sib)
+ prev->die_sib = c;
+ prune_unused_types_update_strings (c);
+ prune_unused_types_prune (c);
+ } while (c != die->die_child);
}
unsigned int i;
limbo_die_node *node;
- /* Clear all the marks. */
- prune_unmark_dies (comp_unit_die);
+#if ENABLE_ASSERT_CHECKING
+ /* All the marks should already be clear. */
+ verify_marks_clear (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
- prune_unmark_dies (node->die);
+ verify_marks_clear (node->die);
+#endif /* ENABLE_ASSERT_CHECKING */
/* Set the mark on nodes that are actually used. */
prune_unused_types_walk (comp_unit_die);
for (i = 0; i < arange_table_in_use; i++)
prune_unused_types_mark (arange_table[i], 1);
- /* Get rid of nodes that aren't marked. */
+ /* Get rid of nodes that aren't marked; and update the string counts. */
+ if (debug_str_hash)
+ htab_empty (debug_str_hash);
prune_unused_types_prune (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
prune_unused_types_prune (node->die);
emit full debugging info for them. */
retry_incomplete_types ();
- /* We need to reverse all the dies before break_out_includes, or
- we'll see the end of an include file before the beginning. */
- reverse_all_dies (comp_unit_die);
-
if (flag_eliminate_unused_debug_types)
prune_unused_types ();
add_sibling_attributes (node->die);
/* Output a terminator label for the .text section. */
- text_section ();
+ switch_to_section (text_section);
targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
if (flag_reorder_blocks_and_partition)
{
- unlikely_text_section ();
+ switch_to_section (unlikely_text_section ());
targetm.asm_out.internal_label (asm_out_file, COLD_END_LABEL, 0);
}
examining the file. */
if (! DWARF2_ASM_LINE_DEBUG_INFO)
{
- named_section_flags (DEBUG_LINE_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_line_section);
output_line_info ();
}
- /* Output location list section if necessary. */
- if (have_location_lists)
- {
- /* Output the location lists info. */
- named_section_flags (DEBUG_LOC_SECTION, SECTION_DEBUG);
- ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
- DEBUG_LOC_SECTION_LABEL, 0);
- ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
- output_location_lists (die);
- have_location_lists = 0;
- }
-
/* We can only use the low/high_pc attributes if all of the code was
in .text. */
- if (separate_line_info_table_in_use == 0)
+ if (!have_multiple_function_sections)
{
add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, text_section_label);
add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
else if (have_location_lists || ranges_table_in_use)
add_AT_addr (comp_unit_die, DW_AT_entry_pc, const0_rtx);
+ /* Output location list section if necessary. */
+ if (have_location_lists)
+ {
+ /* Output the location lists info. */
+ switch_to_section (debug_loc_section);
+ ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
+ DEBUG_LOC_SECTION_LABEL, 0);
+ ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
+ output_location_lists (die);
+ }
+
if (debug_info_level >= DINFO_LEVEL_NORMAL)
- add_AT_lbl_offset (comp_unit_die, DW_AT_stmt_list,
- debug_line_section_label);
+ add_AT_lineptr (comp_unit_die, DW_AT_stmt_list,
+ debug_line_section_label);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
- add_AT_lbl_offset (comp_unit_die, DW_AT_macro_info, macinfo_section_label);
+ add_AT_macptr (comp_unit_die, DW_AT_macro_info, macinfo_section_label);
/* Output all of the compilation units. We put the main one last so that
the offsets are available to output_pubnames. */
output_comp_unit (comp_unit_die, 0);
/* Output the abbreviation table. */
- named_section_flags (DEBUG_ABBREV_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_abbrev_section);
output_abbrev_section ();
/* Output public names table if necessary. */
if (pubname_table_in_use)
{
- named_section_flags (DEBUG_PUBNAMES_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_pubnames_section);
output_pubnames ();
}
table, so don't write it out if we don't have any. */
if (fde_table_in_use)
{
- named_section_flags (DEBUG_ARANGES_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_aranges_section);
output_aranges ();
}
/* Output ranges section if necessary. */
if (ranges_table_in_use)
{
- named_section_flags (DEBUG_RANGES_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_ranges_section);
ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label);
output_ranges ();
}
/* Have to end the macro section. */
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
- named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
+ switch_to_section (debug_macinfo_section);
dw2_asm_output_data (1, 0, "End compilation unit");
}