/* 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
+
/* 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;
+
/* 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;
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. */
static inline char *
stripattributes (const char *s)
{
- char *stripped = xmalloc (strlen (s) + 2);
+ char *stripped = XNEWVEC (char, strlen (s) + 2);
char *p = stripped;
*p++ = '*';
{
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;
/* 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;
}
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)
+/* 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));
+ }
+}
+
/* 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. */
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);
+ switch_to_section (get_section (DEBUG_FRAME_SECTION, SECTION_DEBUG, NULL));
ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
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)
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
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;
cfa->offset = ptr->dw_loc_oprnd1.v.val_unsigned;
break;
default:
- internal_error ("DW_LOC_OP %s not implemented\n",
+ internal_error ("DW_LOC_OP %s not implemented",
dwarf_stack_op_name (ptr->dw_loc_opc));
}
}
/* 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 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);
static tree
decl_ultimate_origin (tree decl)
{
+ if (!CODE_CONTAINS_STRUCT (TREE_CODE (decl), TS_DECL_COMMON))
+ return NULL_TREE;
+
/* output_inline_function sets DECL_ABSTRACT_ORIGIN for all the
nodes in the function to point to themselves; ignore that if
we're trying to output the abstract instance of this function. */
/* 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;
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;
+ have_location_lists = true;
}
static inline dw_loc_list_ref
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;
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)",
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);
/* 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
+ regno = LEAF_REG_REMAP (regno);
+#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
+ reg = LEAF_REG_REMAP (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
return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 1);
case VAR_DECL:
- if (DECL_THREAD_LOCAL (loc))
+ if (DECL_THREAD_LOCAL_P (loc))
{
rtx rtl;
/* 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);
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 (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;
}
}
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)));
}
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);
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,
dw_die_ref old_die = lookup_decl_die (decl);
int declaration = (DECL_EXTERNAL (decl)
+ /* If DECL is COMDAT and has not actually been
+ emitted, we cannot take its address; there
+ might end up being no definition anywhere in
+ the program. For example, consider the C++
+ test case:
+
+ template <class T>
+ struct S { static const int i = 7; };
+
+ template <class T>
+ const int S<T>::i;
+
+ int f() { return S<int>::i; }
+
+ Here, S<int>::i is not DECL_EXTERNAL, but no
+ definition is required, so the compiler will
+ not emit a definition. */
+ || (TREE_CODE (decl) == VAR_DECL
+ && DECL_COMDAT (decl) && !TREE_ASM_WRITTEN (decl))
|| class_or_namespace_scope_p (context_die));
if (origin != NULL)
}
}
+/* A helper function for gen_inlined_subroutine_die. Add source coordinate
+ attributes to the DIE for a block STMT, to describe where the inlined
+ function was called from. This is similar to add_src_coords_attributes. */
+
+static inline void
+add_call_src_coords_attributes (tree stmt, dw_die_ref die)
+{
+ expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt));
+ unsigned file_index = lookup_filename (s.file);
+
+ add_AT_unsigned (die, DW_AT_call_file, file_index);
+ add_AT_unsigned (die, DW_AT_call_line, s.line);
+}
+
/* A helper function for gen_lexical_block_die and gen_inlined_subroutine_die.
Add low_pc and high_pc attributes to the DIE for a block STMT. */
add_abstract_origin_attribute (subr_die, decl);
add_high_low_attributes (stmt, subr_die);
+ add_call_src_coords_attributes (stmt, subr_die);
decls_for_scope (stmt, subr_die, depth);
current_function_has_inlines = 1;
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);
declarations. We have to check DECL_INITIAL instead. That's because
the C front-end supports some weird semantics for "extern inline"
function definitions. These can get inlined within the current
- translation unit (an thus, we need to generate Dwarf info for their
+ translation unit (and thus, we need to generate Dwarf info for their
abstract instances so that the Dwarf info for the concrete inlined
instances can have something to refer to) but the compiler never
generates any out-of-lines instances of such things (despite the fact
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;
}
+/* If the assembler will construct the file table, then translate the compiler
+ internal file table number into the assembler file table number, and emit
+ a .file directive if we haven't already emitted one yet. The file table
+ numbers are different because we prune debug info for unused variables and
+ types, which may include filenames. */
+
static int
maybe_emit_file (int fileno)
{
return fileno;
}
+/* Initialize the compiler internal file table. */
+
static void
init_file_table (void)
{
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);
+
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);
}
Make sure that it will get emitted. */
prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
}
- else if (a->dw_attr == DW_AT_decl_file)
+ else if (a->dw_attr == DW_AT_decl_file || a->dw_attr == DW_AT_call_file)
{
/* A reference to a file. Make sure the file name is emitted. */
a->dw_attr_val.v.val_unsigned =
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);
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");
}