/* Output Dwarf2 format symbol table information from GCC.
Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007 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).
static GTY(()) section *debug_line_section;
static GTY(()) section *debug_loc_section;
static GTY(()) section *debug_pubnames_section;
+static GTY(()) section *debug_pubtypes_section;
static GTY(()) section *debug_str_section;
static GTY(()) section *debug_ranges_section;
static GTY(()) section *debug_frame_section;
return stripped;
}
+/* MEM is a memory reference for the register size table, each element of
+ which has mode MODE. Initialize column C as a return address column. */
+
+static void
+init_return_column_size (enum machine_mode mode, rtx mem, unsigned int c)
+{
+ HOST_WIDE_INT offset = c * GET_MODE_SIZE (mode);
+ HOST_WIDE_INT size = GET_MODE_SIZE (Pmode);
+ emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
+}
+
/* Generate code to initialize the register size table. */
void
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
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)
size = GET_MODE_SIZE (save_mode);
if (offset < 0)
continue;
-
+
emit_move_insn (adjust_address (mem, mode, offset),
gen_int_mode (size, mode));
}
}
+ if (!wrote_return_column)
+ init_return_column_size (mode, mem, DWARF_FRAME_RETURN_COLUMN);
+
#ifdef DWARF_ALT_FRAME_RETURN_COLUMN
- gcc_assert (wrote_return_column);
- i = DWARF_ALT_FRAME_RETURN_COLUMN;
- wrote_return_column = false;
-#else
- i = DWARF_FRAME_RETURN_COLUMN;
+ init_return_column_size (mode, mem, DWARF_ALT_FRAME_RETURN_COLUMN);
#endif
- if (! wrote_return_column)
- {
- enum machine_mode save_mode = Pmode;
- HOST_WIDE_INT offset = i * GET_MODE_SIZE (mode);
- HOST_WIDE_INT size = GET_MODE_SIZE (save_mode);
- emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
- }
+ targetm.init_dwarf_reg_sizes_extra (address);
}
/* Convert a DWARF call frame info. operation to its string name */
{
dw_cfi_ref xcfi;
- fde->dw_fde_current_label = label = xstrdup (label);
+ label = xstrdup (label);
/* Set the location counter to the new label. */
xcfi = new_cfi ();
- xcfi->dw_cfi_opc = DW_CFA_advance_loc4;
+ /* If we have a current label, advance from there, otherwise
+ set the location directly using set_loc. */
+ xcfi->dw_cfi_opc = fde->dw_fde_current_label
+ ? DW_CFA_advance_loc4
+ : DW_CFA_set_loc;
xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
add_cfi (&fde->dw_fde_cfi, xcfi);
+
+ fde->dw_fde_current_label = label;
}
add_cfi (&fde->dw_fde_cfi, cfi);
much extra space it needs to pop off the stack. */
static void
-dwarf2out_stack_adjust (rtx insn, bool after_p ATTRIBUTE_UNUSED)
+dwarf2out_stack_adjust (rtx insn, bool after_p)
{
HOST_WIDE_INT offset;
const char *label;
if (prologue_epilogue_contains (insn) || sibcall_epilogue_contains (insn))
return;
- if (BARRIER_P (insn))
+ /* 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))
{
/* 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)
cfa.base_offset = -cfa_temp.offset
cfa_temp.offset -= mode_size(mem)
- Rule 15:
- (set <reg> {unspec, unspec_volatile})
- effects: target-dependent */
+ Rule 15:
+ (set <reg> {unspec, unspec_volatile})
+ effects: target-dependent */
static void
dwarf2out_frame_debug_expr (rtx expr, const char *label)
{
int par_index;
int limit = XVECLEN (expr, 0);
+ rtx elem;
+
+ /* PARALLELs have strict read-modify-write semantics, so we
+ ought to evaluate every rvalue before changing any lvalue.
+ It's cumbersome to do that in general, but there's an
+ easy approximation that is enough for all current users:
+ handle register saves before register assignments. */
+ if (GET_CODE (expr) == PARALLEL)
+ for (par_index = 0; par_index < limit; par_index++)
+ {
+ elem = XVECEXP (expr, 0, par_index);
+ if (GET_CODE (elem) == SET
+ && MEM_P (SET_DEST (elem))
+ && (RTX_FRAME_RELATED_P (elem) || par_index == 0))
+ dwarf2out_frame_debug_expr (elem, label);
+ }
for (par_index = 0; par_index < limit; par_index++)
- if (GET_CODE (XVECEXP (expr, 0, par_index)) == SET
- && (RTX_FRAME_RELATED_P (XVECEXP (expr, 0, par_index))
- || par_index == 0))
- dwarf2out_frame_debug_expr (XVECEXP (expr, 0, par_index), label);
-
+ {
+ elem = XVECEXP (expr, 0, par_index);
+ if (GET_CODE (elem) == SET
+ && (!MEM_P (SET_DEST (elem)) || GET_CODE (expr) == SEQUENCE)
+ && (RTX_FRAME_RELATED_P (elem) || par_index == 0))
+ dwarf2out_frame_debug_expr (elem, label);
+ }
return;
}
/* 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');
+ 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));
else
dw2_asm_output_addr (DWARF2_ADDR_SIZE,
cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
+ fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
break;
case DW_CFA_advance_loc1:
&& for_eh)
for (i = 0; i < fde_table_in_use; i++)
if ((fde_table[i].nothrow || fde_table[i].all_throwers_are_sibcalls)
- && !fde_table[i].uses_eh_lsda
+ && !fde_table[i].uses_eh_lsda
&& ! DECL_WEAK (fde_table[i].decl))
targetm.asm_out.unwind_label (asm_out_file, fde_table[i].decl,
for_eh, /* empty */ 1);
for (i = 0; i < fde_table_in_use; i++)
if (fde_table[i].uses_eh_lsda)
any_eh_needed = any_lsda_needed = true;
- else if (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
+ else if (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
any_eh_needed = true;
else if (! fde_table[i].nothrow
&& ! fde_table[i].all_throwers_are_sibcalls)
if (for_eh)
switch_to_eh_frame_section ();
else
- switch_to_section (debug_frame_section);
+ {
+ 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);
{
*p++ = 'P';
augmentation_size += 1 + size_of_encoded_value (per_encoding);
+ assemble_external_libcall (eh_personality_libfunc);
}
if (any_lsda_needed)
{
"FDE initial location");
if (fde->dw_fde_switched_sections)
{
- rtx sym_ref2 = gen_rtx_SYMBOL_REF (Pmode,
+ rtx sym_ref2 = gen_rtx_SYMBOL_REF (Pmode,
fde->dw_fde_unlikely_section_label);
- rtx sym_ref3= gen_rtx_SYMBOL_REF (Pmode,
+ rtx sym_ref3= gen_rtx_SYMBOL_REF (Pmode,
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_addr (DWARF2_ADDR_SIZE,
fde->dw_fde_unlikely_section_label,
"FDE initial location");
- dw2_asm_output_delta (DWARF2_ADDR_SIZE,
+ dw2_asm_output_delta (DWARF2_ADDR_SIZE,
fde->dw_fde_unlikely_section_end_label,
fde->dw_fde_unlikely_section_label,
"FDE address range");
fde = &fde_table[fde_table_in_use++];
fde->decl = current_function_decl;
fde->dw_fde_begin = dup_label;
- fde->dw_fde_current_label = NULL;
+ fde->dw_fde_current_label = dup_label;
fde->dw_fde_hot_section_label = NULL;
fde->dw_fde_hot_section_end_label = NULL;
fde->dw_fde_unlikely_section_label = NULL;
/* And now, the subset of the debugging information support code necessary
for emitting location expressions. */
+/* Data about a single source file. */
+struct dwarf_file_data GTY(())
+{
+ const char * filename;
+ int emitted_number;
+};
+
/* We need some way to distinguish DW_OP_addr with a direct symbol
relocation from DW_OP_addr with a dtp-relative symbol relocation. */
#define INTERNAL_DW_OP_tls_addr (0x100 + DW_OP_addr)
dw_val_class_lbl_id,
dw_val_class_lineptr,
dw_val_class_str,
- dw_val_class_macptr
+ dw_val_class_macptr,
+ dw_val_class_file
};
/* Describe a double word constant value. */
struct indirect_string_node * GTY ((tag ("dw_val_class_str"))) val_str;
char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id;
unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag;
+ struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file;
}
GTY ((desc ("%1.val_class"))) v;
}
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;
DEF_VEC_O(dw_attr_node);
DEF_VEC_ALLOC_O(dw_attr_node,gc);
-/* The Debugging Information Entry (DIE) structure */
+/* 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(())
{
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(())
{
dw_die_ref die;
- char *name;
+ const char *name;
}
pubname_entry;
+DEF_VEC_O(pubname_entry);
+DEF_VEC_ALLOC_O(pubname_entry, gc);
+
struct dw_ranges_struct GTY(())
{
int block_num;
/* Fixed size portion of the address range info. */
#define DWARF_ARANGES_HEADER_SIZE \
(DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \
- DWARF2_ADDR_SIZE * 2) \
+ DWARF2_ADDR_SIZE * 2) \
- DWARF_INITIAL_LENGTH_SIZE)
/* Size of padding portion in the address range info. It must be
aligned to twice the pointer size. */
#define DWARF_ARANGES_PAD_SIZE \
(DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \
- DWARF2_ADDR_SIZE * 2) \
+ DWARF2_ADDR_SIZE * 2) \
- (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4))
/* Use assembler line directives if available. */
static GTY(()) limbo_die_node *limbo_die_list;
/* Filenames referenced by this compilation unit. */
-static GTY(()) varray_type file_table;
-static GTY(()) varray_type file_table_emitted;
-static GTY(()) size_t file_table_last_lookup_index;
+static GTY((param_is (struct dwarf_file_data))) htab_t file_table;
/* A hash table of references to DIE's that describe declarations.
The key is a DECL_UID() which is a unique number identifying each decl. */
/* A pointer to the base of a table that contains a list of publicly
accessible names. */
-static GTY ((length ("pubname_table_allocated"))) pubname_ref pubname_table;
+static GTY (()) VEC (pubname_entry, gc) * pubname_table;
-/* Number of elements currently allocated for pubname_table. */
-static GTY(()) unsigned pubname_table_allocated;
-
-/* Number of elements in pubname_table currently in use. */
-static GTY(()) unsigned pubname_table_in_use;
-
-/* Size (in elements) of increments by which we may expand the
- pubname_table. */
-#define PUBNAME_TABLE_INCREMENT 64
+/* A pointer to the base of a table that contains a list of publicly
+ accessible types. */
+static GTY (()) VEC (pubname_entry, gc) * pubtype_table;
/* Array of dies for which we should generate .debug_arange info. */
static GTY((length ("arange_table_allocated"))) dw_die_ref *arange_table;
static int comp_unit_has_inlines;
#endif
-/* Number of file tables emitted in maybe_emit_file(). */
-static GTY(()) int emitcount = 0;
+/* The last file entry emitted by maybe_emit_file(). */
+static GTY(()) struct dwarf_file_data * last_emitted_file;
/* Number of internal labels generated by gen_internal_sym(). */
static GTY(()) int label_num;
+/* Cached result of previous call to lookup_filename. */
+static GTY(()) struct dwarf_file_data * file_table_last_lookup;
+
#ifdef DWARF2_DEBUGGING_INFO
/* Offset from the "steady-state frame pointer" to the frame base,
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 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 void mark_dies (dw_die_ref);
static void unmark_dies (dw_die_ref);
static void unmark_all_dies (dw_die_ref);
-static unsigned long size_of_pubnames (void);
+static unsigned long size_of_pubnames (VEC (pubname_entry,gc) *);
static unsigned long size_of_aranges (void);
static enum dwarf_form value_format (dw_attr_ref);
static void output_value_format (dw_attr_ref);
static void output_comp_unit (dw_die_ref, int);
static const char *dwarf2_name (tree, int);
static void add_pubname (tree, dw_die_ref);
-static void output_pubnames (void);
+static void add_pubtype (tree, dw_die_ref);
+static void output_pubnames (VEC (pubname_entry,gc) *);
static void add_arange (tree, dw_die_ref);
static void output_aranges (void);
static unsigned int add_ranges (tree);
static void output_line_info (void);
static void output_file_names (void);
static dw_die_ref base_type_die (tree);
-static tree root_type (tree);
static int is_base_type (tree);
static bool is_subrange_type (tree);
static dw_die_ref subrange_type_die (tree, dw_die_ref);
static dw_die_ref force_type_die (tree);
static dw_die_ref setup_namespace_context (tree, dw_die_ref);
static void declare_in_namespace (tree, dw_die_ref);
-static unsigned lookup_filename (const char *);
-static void init_file_table (void);
+static struct dwarf_file_data * lookup_filename (const char *);
static void retry_incomplete_types (void);
static void gen_type_die_for_member (tree, tree, dw_die_ref);
static void splice_child_die (dw_die_ref, dw_die_ref);
static void prune_unused_types_walk_attribs (dw_die_ref);
static void prune_unused_types_prune (dw_die_ref);
static void prune_unused_types (void);
-static int maybe_emit_file (int);
+static int maybe_emit_file (struct dwarf_file_data *fd);
/* Section names used to hold DWARF debugging information. */
#ifndef DEBUG_INFO_SECTION
static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char cold_text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
-static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
}
while (lookahead != NULL && lookahead != ret_val);
-
+
/* The block's abstract origin chain may not be the *ultimate* origin of
the block. It could lead to a DECL that has an abstract origin set.
If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
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)
/* 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);
slot = htab_find_slot_with_hash (debug_str_hash, str,
htab_hash_string (str), INSERT);
if (*slot == NULL)
- *slot = ggc_alloc_cleared (sizeof (struct indirect_string_node));
- node = (struct indirect_string_node *) *slot;
- node->str = ggc_strdup (str);
+ {
+ node = (struct indirect_string_node *)
+ ggc_alloc_cleared (sizeof (struct indirect_string_node));
+ node->str = ggc_strdup (str);
+ *slot = node;
+ }
+ else
+ node = (struct indirect_string_node *) *slot;
+
node->refcount++;
attr.dw_attr = attr_kind;
add_dwarf_attr (die, &attr);
}
+/* Get the RTX from to an address DIE attribute. */
+
static inline rtx
AT_addr (dw_attr_ref a)
{
return a->dw_attr_val.v.val_addr;
}
+/* Add a file attribute value to a DIE. */
+
+static inline void
+add_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind,
+ struct dwarf_file_data *fd)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_file;
+ attr.dw_attr_val.v.val_file = fd;
+ add_dwarf_attr (die, &attr);
+}
+
+/* Get the dwarf_file_data from a file DIE attribute. */
+
+static inline struct dwarf_file_data *
+AT_file (dw_attr_ref a)
+{
+ gcc_assert (a && AT_class (a) == dw_val_class_file);
+ return a->dw_attr_val.v.val_file;
+}
+
/* Add a label identifier attribute value to a DIE. */
static inline void
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 a ? AT_ref (a) : NULL;
}
+static inline struct dwarf_file_data *
+get_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_ref a = get_AT (die, attr_kind);
+
+ return a ? AT_file (a) : NULL;
+}
+
/* Return TRUE if the language is C or C++. */
static inline bool
is_cxx (void)
{
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 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
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
if (a->dw_attr == attr_kind)
{
- free_AT (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--;
+
/* VEC_ordered_remove should help reduce the number of abbrevs
that are needed. */
VEC_ordered_remove (dw_attr_node, die->die_attr, ix);
}
}
-/* 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, by removing its children and
- anything associated with its attributes. DIEs are garbage
- collected, so there is no actual freeing to do; the only real work is
- to decrease string reference counts. */
+/* Remove child DIE whose die_tag is TAG. Do nothing if no child
+ matches TAG. */
static void
-free_die (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;
- unsigned ix;
-
- child_die = child_die->die_sib;
-
- for (ix = 0; VEC_iterate (dw_attr_node, tmp_die->die_attr, ix, a); ix++)
- free_AT (a);
+ dw_die_ref c;
- free_die (tmp_die);
- }
+ 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. */
|| (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. */
else
fprintf (outfile, "<null>");
break;
+ case dw_val_class_file:
+ fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename,
+ AT_file (a)->emitted_number);
+ break;
default:
break;
}
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)
for (i = 1; i < line_info_table_in_use; i++)
{
line_info = &line_info_table[i];
- fprintf (outfile, "%5d: ", i);
- fprintf (outfile, "%-20s",
- VARRAY_CHAR_PTR (file_table, line_info->dw_file_num));
- fprintf (outfile, "%6ld", line_info->dw_line_num);
- fprintf (outfile, "\n");
+ fprintf (outfile, "%5d: %4ld %6ld\n", i,
+ line_info->dw_file_num,
+ line_info->dw_line_num);
}
fprintf (outfile, "\n\n");
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;
-
- 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. */
CHECKSUM (at->dw_attr);
- /* We don't care about differences in file numbering. */
- if (at->dw_attr == DW_AT_decl_file
- /* Or that this was compiled with a different compiler snapshot; if
- the output is the same, that's what matters. */
- || at->dw_attr == DW_AT_producer)
+ /* We don't care that this was compiled with a different compiler
+ snapshot; if the output is the same, that's what matters. */
+ if (at->dw_attr == DW_AT_producer)
return;
switch (AT_class (at))
case dw_val_class_macptr:
break;
+ case dw_val_class_file:
+ CHECKSUM_STRING (AT_file (at)->filename);
+ break;
+
default:
break;
}
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_macptr:
return 1;
+ case dw_val_class_file:
+ return v1->v.val_file == v2->v.val_file;
+
default:
return 1;
}
if (at1->dw_attr != at2->dw_attr)
return 0;
- /* We don't care about differences in file numbering. */
- if (at1->dw_attr == DW_AT_decl_file
- /* Or that this was compiled with a different compiler snapshot; if
- the output is the same, that's what matters. */
- || at1->dw_attr == DW_AT_producer)
+ /* We don't care that this was compiled with a different compiler
+ snapshot; if the output is the same, that's what matters. */
+ if (at1->dw_attr == DW_AT_producer)
return 1;
return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
if (VEC_length (dw_attr_node, die1->die_attr)
!= VEC_length (dw_attr_node, die2->die_attr))
return 0;
-
+
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;
- 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))
- 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;
}
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
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;
+ 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;
- 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;
+ /* 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);
- 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;
- }
- }
+ 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. */
if (AT_class (a) == dw_val_class_loc_list)
output_loc_list (AT_loc_list (a));
- for (c = die->die_child; c != NULL; c = c->die_sib)
- output_location_lists (c);
-
+ FOR_EACH_CHILD (die, c, output_location_lists (c));
}
/* The format of each DIE (and its attribute value pairs) is encoded in an
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++)
{
abbrev_a = VEC_index (dw_attr_node, abbrev->die_attr, ix);
}
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. */
else
size += strlen (a->dw_attr_val.v.val_str->str) + 1;
break;
+ case dw_val_class_file:
+ size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file));
+ break;
default:
gcc_unreachable ();
}
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. */
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 (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 the size of the .debug_pubnames table generated for the
- compilation unit. */
+/* Return the size of the .debug_pubnames or .debug_pubtypes table
+ generated for the compilation unit. */
static unsigned long
-size_of_pubnames (void)
+size_of_pubnames (VEC (pubname_entry, gc) * names)
{
unsigned long size;
unsigned i;
+ pubname_ref p;
size = DWARF_PUBNAMES_HEADER_SIZE;
- for (i = 0; i < pubname_table_in_use; i++)
- {
- pubname_ref p = &pubname_table[i];
- size += DWARF_OFFSET_SIZE + strlen (p->name) + 1;
- }
+ for (i = 0; VEC_iterate (pubname_entry, names, i, p); i++)
+ if (names != pubtype_table
+ || p->die->die_offset != 0
+ || !flag_eliminate_unused_debug_types)
+ size += strlen (p->name) + DWARF_OFFSET_SIZE + 1;
size += DWARF_OFFSET_SIZE;
return size;
return DW_FORM_data;
case dw_val_class_str:
return AT_string_form (a);
+ case dw_val_class_file:
+ switch (constant_size (maybe_emit_file (a->dw_attr_val.v.val_file)))
+ {
+ case 1:
+ return DW_FORM_data1;
+ case 2:
+ return DW_FORM_data2;
+ case 4:
+ return DW_FORM_data4;
+ default:
+ gcc_unreachable ();
+ }
default:
gcc_unreachable ();
fde->dw_fde_unlikely_section_label = cfun->cold_section_label;
fde->dw_fde_unlikely_section_end_label = cfun->cold_section_end_label;
have_multiple_function_sections = true;
+
+ /* Reset the current label on switching text sections, so that we
+ don't attempt to advance_loc4 between labels in different sections. */
+ fde->dw_fde_current_label = NULL;
}
/* Output the location list given to us. */
dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
break;
+ case dw_val_class_file:
+ {
+ int f = maybe_emit_file (a->dw_attr_val.v.val_file);
+
+ dw2_asm_output_data (constant_size (f), f, "%s (%s)", name,
+ a->dw_attr_val.v.val_file->filename);
+ break;
+ }
+
default:
gcc_unreachable ();
}
}
- 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)
dw2_asm_output_data (4, 0xffffffff,
"Initial length escape value indicating 64-bit DWARF extension");
dw2_asm_output_data (DWARF_OFFSET_SIZE,
- next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
+ next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
"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,
}
}
-/* 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. */
static void
add_pubname (tree decl, dw_die_ref die)
{
- pubname_ref p;
+ pubname_entry e;
if (! TREE_PUBLIC (decl))
return;
- if (pubname_table_in_use == pubname_table_allocated)
+ e.die = die;
+ e.name = xstrdup (dwarf2_name (decl, 1));
+ VEC_safe_push (pubname_entry, gc, pubname_table, &e);
+}
+
+/* Add a new entry to .debug_pubtypes if appropriate. */
+
+static void
+add_pubtype (tree decl, dw_die_ref die)
+{
+ pubname_entry e;
+
+ e.name = NULL;
+ if ((TREE_PUBLIC (decl)
+ || die->die_parent == comp_unit_die)
+ && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
{
- pubname_table_allocated += PUBNAME_TABLE_INCREMENT;
- pubname_table
- = ggc_realloc (pubname_table,
- (pubname_table_allocated * sizeof (pubname_entry)));
- memset (pubname_table + pubname_table_in_use, 0,
- PUBNAME_TABLE_INCREMENT * sizeof (pubname_entry));
- }
+ e.die = die;
+ if (TYPE_P (decl))
+ {
+ if (TYPE_NAME (decl))
+ {
+ if (TREE_CODE (TYPE_NAME (decl)) == IDENTIFIER_NODE)
+ e.name = IDENTIFIER_POINTER (TYPE_NAME (decl));
+ else if (TREE_CODE (TYPE_NAME (decl)) == TYPE_DECL
+ && DECL_NAME (TYPE_NAME (decl)))
+ e.name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl)));
+ else
+ e.name = xstrdup ((const char *) get_AT_string (die, DW_AT_name));
+ }
+ }
+ else
+ e.name = xstrdup (dwarf2_name (decl, 1));
- p = &pubname_table[pubname_table_in_use++];
- p->die = die;
- p->name = xstrdup (dwarf2_name (decl, 1));
+ /* If we don't have a name for the type, there's no point in adding
+ it to the table. */
+ if (e.name && e.name[0] != '\0')
+ VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
+ }
}
/* Output the public names table used to speed up access to externally
- visible names. For now, only generate entries for externally
- visible procedures. */
+ visible names; or the public types table used to find type definitions. */
static void
-output_pubnames (void)
+output_pubnames (VEC (pubname_entry, gc) * names)
{
unsigned i;
- unsigned long pubnames_length = size_of_pubnames ();
+ unsigned long pubnames_length = size_of_pubnames (names);
+ pubname_ref pub;
if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
dw2_asm_output_data (4, 0xffffffff,
"Initial length escape value indicating 64-bit DWARF extension");
- dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
- "Length of Public Names Info");
+ if (names == pubname_table)
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
+ "Length of Public Names Info");
+ else
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
+ "Length of Public Type 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,
dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
"Compilation Unit Length");
- for (i = 0; i < pubname_table_in_use; i++)
+ for (i = 0; VEC_iterate (pubname_entry, names, i, pub); i++)
{
- pubname_ref pub = &pubname_table[i];
-
/* We shouldn't see pubnames for DIEs outside of the main CU. */
- gcc_assert (pub->die->die_mark);
+ if (names == pubname_table)
+ gcc_assert (pub->die->die_mark);
- dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
- "DIE offset");
+ if (names != pubtype_table
+ || pub->die->die_offset != 0
+ || !flag_eliminate_unused_debug_types)
+ {
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
+ "DIE offset");
- dw2_asm_output_nstring (pub->name, -1, "external name");
+ dw2_asm_output_nstring (pub->name, -1, "external name");
+ }
}
dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL);
text_section_label, "Length");
if (flag_reorder_blocks_and_partition)
{
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
"Address");
dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
cold_text_section_label, "Length");
/* Data structure containing information about input files. */
struct file_info
{
- char *path; /* Complete file name. */
- char *fname; /* File name part. */
+ const char *path; /* Complete file name. */
+ const char *fname; /* File name part. */
int length; /* Length of entire string. */
- int file_idx; /* Index in input file table. */
+ struct dwarf_file_data * file_idx; /* Index in input file table. */
int dir_idx; /* Index in directory table. */
};
files. */
struct dir_info
{
- char *path; /* Path including directory name. */
+ const char *path; /* Path including directory name. */
int length; /* Path length. */
int prefix; /* Index of directory entry which is a prefix. */
int count; /* Number of files in this directory. */
int dir_idx; /* Index of directory used as base. */
- int used; /* Used in the end? */
};
/* Callback function for file_info comparison. We sort by looking at
}
}
+struct file_name_acquire_data
+{
+ struct file_info *files;
+ int used_files;
+ int max_files;
+};
+
+/* Traversal function for the hash table. */
+
+static int
+file_name_acquire (void ** slot, void *data)
+{
+ struct file_name_acquire_data *fnad = data;
+ struct dwarf_file_data *d = *slot;
+ struct file_info *fi;
+ const char *f;
+
+ gcc_assert (fnad->max_files >= d->emitted_number);
+
+ if (! d->emitted_number)
+ return 1;
+
+ gcc_assert (fnad->max_files != fnad->used_files);
+
+ fi = fnad->files + fnad->used_files++;
+
+ /* Skip all leading "./". */
+ f = d->filename;
+ while (f[0] == '.' && IS_DIR_SEPARATOR (f[1]))
+ f += 2;
+
+ /* Create a new array entry. */
+ fi->path = f;
+ fi->length = strlen (f);
+ fi->file_idx = d;
+
+ /* Search for the file name part. */
+ f = strrchr (f, DIR_SEPARATOR);
+#if defined (DIR_SEPARATOR_2)
+ {
+ char *g = strrchr (fi->path, DIR_SEPARATOR_2);
+
+ if (g != NULL)
+ {
+ if (f == NULL || f < g)
+ f = g;
+ }
+ }
+#endif
+
+ fi->fname = f == NULL ? fi->path : f + 1;
+ return 1;
+}
+
/* Output the directory table and the file name table. We try to minimize
the total amount of memory needed. A heuristic is used to avoid large
slowdowns with many input files. */
static void
output_file_names (void)
{
+ struct file_name_acquire_data fnad;
+ int numfiles;
struct file_info *files;
struct dir_info *dirs;
int *saved;
int *savehere;
int *backmap;
- size_t ndirs;
+ int ndirs;
int idx_offset;
- size_t i;
+ int i;
int idx;
- /* Handle the case where file_table is empty. */
- if (VARRAY_ACTIVE_SIZE (file_table) <= 1)
+ if (!last_emitted_file)
{
dw2_asm_output_data (1, 0, "End directory table");
dw2_asm_output_data (1, 0, "End file name table");
return;
}
- /* Allocate the various arrays we need. */
- files = alloca (VARRAY_ACTIVE_SIZE (file_table) * sizeof (struct file_info));
- dirs = alloca (VARRAY_ACTIVE_SIZE (file_table) * sizeof (struct dir_info));
-
- /* Sort the file names. */
- for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
- {
- char *f;
-
- /* Skip all leading "./". */
- f = VARRAY_CHAR_PTR (file_table, i);
- while (f[0] == '.' && f[1] == '/')
- f += 2;
+ numfiles = last_emitted_file->emitted_number;
- /* Create a new array entry. */
- files[i].path = f;
- files[i].length = strlen (f);
- files[i].file_idx = i;
+ /* Allocate the various arrays we need. */
+ files = alloca (numfiles * sizeof (struct file_info));
+ dirs = alloca (numfiles * sizeof (struct dir_info));
- /* Search for the file name part. */
- f = strrchr (f, '/');
- files[i].fname = f == NULL ? files[i].path : f + 1;
- }
+ fnad.files = files;
+ fnad.used_files = 0;
+ fnad.max_files = numfiles;
+ htab_traverse (file_table, file_name_acquire, &fnad);
+ gcc_assert (fnad.used_files == fnad.max_files);
- qsort (files + 1, VARRAY_ACTIVE_SIZE (file_table) - 1,
- sizeof (files[0]), file_info_cmp);
+ qsort (files, numfiles, sizeof (files[0]), file_info_cmp);
/* Find all the different directories used. */
- dirs[0].path = files[1].path;
- dirs[0].length = files[1].fname - files[1].path;
+ dirs[0].path = files[0].path;
+ dirs[0].length = files[0].fname - files[0].path;
dirs[0].prefix = -1;
dirs[0].count = 1;
dirs[0].dir_idx = 0;
- dirs[0].used = 0;
- files[1].dir_idx = 0;
+ files[0].dir_idx = 0;
ndirs = 1;
- for (i = 2; i < VARRAY_ACTIVE_SIZE (file_table); i++)
+ for (i = 1; i < numfiles; i++)
if (files[i].fname - files[i].path == dirs[ndirs - 1].length
&& memcmp (dirs[ndirs - 1].path, files[i].path,
dirs[ndirs - 1].length) == 0)
}
else
{
- size_t j;
+ int j;
/* This is a new directory. */
dirs[ndirs].path = files[i].path;
dirs[ndirs].length = files[i].fname - files[i].path;
dirs[ndirs].count = 1;
dirs[ndirs].dir_idx = ndirs;
- dirs[ndirs].used = 0;
files[i].dir_idx = ndirs;
/* Search for a prefix. */
memset (saved, '\0', ndirs * sizeof (saved[0]));
for (i = 0; i < ndirs; i++)
{
- size_t j;
+ int j;
int total;
/* We can always save some space for the current directory. But this
if (k == (int) i)
{
- /* Yes it is. We can possibly safe some memory but
+ /* Yes it is. We can possibly save some memory by
writing the filenames in dirs[j] relative to
dirs[i]. */
savehere[j] = dirs[i].length;
}
}
- /* Check whether we can safe enough to justify adding the dirs[i]
+ /* Check whether we can save enough to justify adding the dirs[i]
directory. */
if (total > dirs[i].length + 1)
{
}
}
- /* We have to emit them in the order they appear in the file_table array
- since the index is used in the debug info generation. To do this
- efficiently we generate a back-mapping of the indices first. */
- backmap = alloca (VARRAY_ACTIVE_SIZE (file_table) * sizeof (int));
- for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
- {
- backmap[files[i].file_idx] = i;
-
- /* Mark this directory as used. */
- dirs[dirs[files[i].dir_idx].dir_idx].used = 1;
- }
-
- /* That was it. We are ready to emit the information. First emit the
- directory name table. We have to make sure the first actually emitted
- directory name has index one; zero is reserved for the current working
- directory. Make sure we do not confuse these indices with the one for the
- constructed table (even though most of the time they are identical). */
+ /* Emit the directory name table. */
idx = 1;
idx_offset = dirs[0].length > 0 ? 1 : 0;
for (i = 1 - idx_offset; i < ndirs; i++)
- if (dirs[i].used != 0)
- {
- dirs[i].used = idx++;
- dw2_asm_output_nstring (dirs[i].path, dirs[i].length - 1,
- "Directory Entry: 0x%x", dirs[i].used);
- }
+ dw2_asm_output_nstring (dirs[i].path, dirs[i].length - 1,
+ "Directory Entry: 0x%x", i + idx_offset);
dw2_asm_output_data (1, 0, "End directory table");
- /* Correct the index for the current working directory entry if it
- exists. */
- if (idx_offset == 0)
- dirs[0].used = 0;
+ /* We have to emit them in the order of emitted_number since that's
+ used in the debug info generation. To do this efficiently we
+ generate a back-mapping of the indices first. */
+ backmap = alloca (numfiles * sizeof (int));
+ for (i = 0; i < numfiles; i++)
+ backmap[files[i].file_idx->emitted_number - 1] = i;
/* Now write all the file names. */
- for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
+ for (i = 0; i < numfiles; i++)
{
int file_idx = backmap[i];
int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
- "File Entry: 0x%lx", (unsigned long) i);
+ "File Entry: 0x%x", (unsigned) i + 1);
/* Include directory index. */
- dw2_asm_output_data_uleb128 (dirs[dir_idx].used, NULL);
+ dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
/* Modification time. */
dw2_asm_output_data_uleb128 (0, NULL);
{
current_file = line_info->dw_file_num;
dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
- dw2_asm_output_data_uleb128 (current_file, "(\"%s\")",
- VARRAY_CHAR_PTR (file_table,
- current_file));
+ dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
}
/* Emit debug info for the current line number, choosing the encoding
{
current_file = line_info->dw_file_num;
dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
- dw2_asm_output_data_uleb128 (current_file, "(\"%s\")",
- VARRAY_CHAR_PTR (file_table,
- current_file));
+ dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
}
/* Emit debug info for the current line number, choosing the encoding
return base_type_result;
}
-/* Given a pointer to an arbitrary ..._TYPE tree node, return a pointer to
- the Dwarf "root" type for the given input type. The Dwarf "root" type of
- a given type is generally the same as the given type, except that if the
- given type is a pointer or reference type, then the root type of the given
- type is the root type of the "basis" type for the pointer or reference
- type. (This definition of the "root" type is recursive.) Also, the root
- type of a `const' qualified type or a `volatile' qualified type is the
- root type of the given type without the qualifiers. */
-
-static tree
-root_type (tree type)
-{
- if (TREE_CODE (type) == ERROR_MARK)
- return error_mark_node;
-
- switch (TREE_CODE (type))
- {
- case ERROR_MARK:
- return error_mark_node;
-
- case POINTER_TYPE:
- case REFERENCE_TYPE:
- return type_main_variant (root_type (TREE_TYPE (type)));
-
- default:
- return type_main_variant (type);
- }
-}
-
/* Given a pointer to an arbitrary ..._TYPE tree node, return nonzero if the
given input type is a Dwarf "fundamental" type. Otherwise return null. */
&& tree_int_cst_equal (TYPE_MAX_VALUE (type), TYPE_MAX_VALUE (subtype)))
{
/* The type and its subtype have the same representation. If in
- addition the two types also have the same name, then the given
- type is not a subrange type, but rather a plain base type. */
+ addition the two types also have the same name, then the given
+ type is not a subrange type, but rather a plain base type. */
/* FIXME: brobecker/2004-03-22:
- Sizetype INTEGER_CSTs nodes are canonicalized. It should
- therefore be sufficient to check the TYPE_SIZE node pointers
- rather than checking the actual size. Unfortunately, we have
- found some cases, such as in the Ada "integer" type, where
- this is not the case. Until this problem is solved, we need to
- keep checking the actual size. */
+ Sizetype INTEGER_CSTs nodes are canonicalized. It should
+ therefore be sufficient to check the TYPE_SIZE node pointers
+ rather than checking the actual size. Unfortunately, we have
+ found some cases, such as in the Ada "integer" type, where
+ this is not the case. Until this problem is solved, we need to
+ keep checking the actual size. */
tree type_name = TYPE_NAME (type);
tree subtype_name = TYPE_NAME (subtype);
if (type_name != NULL && TREE_CODE (type_name) == TYPE_DECL)
- type_name = DECL_NAME (type_name);
+ type_name = DECL_NAME (type_name);
if (subtype_name != NULL && TREE_CODE (subtype_name) == TYPE_DECL)
- subtype_name = DECL_NAME (subtype_name);
+ subtype_name = DECL_NAME (subtype_name);
if (type_name == subtype_name)
- return false;
+ return false;
}
return true;
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. */
+ so we need to generate a size attribute for the subrange type. */
add_AT_unsigned (subrange_die, DW_AT_byte_size, size_in_bytes);
}
if (TYPE_MIN_VALUE (type) != NULL)
add_bound_info (subrange_die, DW_AT_lower_bound,
- TYPE_MIN_VALUE (type));
+ TYPE_MIN_VALUE (type));
if (TYPE_MAX_VALUE (type) != NULL)
add_bound_info (subrange_die, DW_AT_upper_bound,
- TYPE_MAX_VALUE (type));
+ TYPE_MAX_VALUE (type));
return subrange_die;
}
= 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)
{
if (mod_type_die)
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)
{
/* For a named type, use the typedef. */
gen_type_die (qualified_type, context_die);
return lookup_type_die (qualified_type);
}
- else if (DECL_ORIGINAL_TYPE (name)
- && (is_const_type < TYPE_READONLY (dtype)
- || is_volatile_type < TYPE_VOLATILE (dtype)))
+ else if (is_const_type < TYPE_READONLY (dtype)
+ || is_volatile_type < TYPE_VOLATILE (dtype)
+ || (is_const_type <= TYPE_READONLY (dtype)
+ && is_volatile_type <= TYPE_VOLATILE (dtype)
+ && DECL_ORIGINAL_TYPE (name) != type))
/* cv-unqualified version of named type. Just use the unnamed
type to which it refers. */
return modified_type_die (DECL_ORIGINAL_TYPE (name),
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);
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
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. */
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);
gcc_assert (regno < FIRST_PSEUDO_REGISTER);
#ifdef LEAF_REG_REMAP
- regno = LEAF_REG_REMAP (regno);
+ if (current_function_uses_only_leaf_regs)
+ {
+ int leaf_reg = LEAF_REG_REMAP (regno);
+ if (leaf_reg != -1)
+ regno = (unsigned) leaf_reg;
+ }
#endif
return DBX_REGISTER_NUMBER (regno);
reg = REGNO (rtl);
#ifdef LEAF_REG_REMAP
- reg = LEAF_REG_REMAP (reg);
+ if (current_function_uses_only_leaf_regs)
+ {
+ int 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)];
}
gcc_assert (elim == (frame_pointer_needed ? hard_frame_pointer_rtx
: stack_pointer_rtx));
- offset += frame_pointer_fb_offset;
+ offset += frame_pointer_fb_offset;
- return new_loc_descr (DW_OP_fbreg, offset, 0);
+ return new_loc_descr (DW_OP_fbreg, offset, 0);
}
}
&& GET_CODE (XEXP (rtl, 1)) == CONST_INT)));
}
+/* Return a descriptor that describes the concatenation of N locations
+ used to form the address of a memory location. */
+
+static dw_loc_descr_ref
+concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode)
+{
+ unsigned int i;
+ dw_loc_descr_ref cc_loc_result = NULL;
+ unsigned int n = XVECLEN (concatn, 0);
+
+ for (i = 0; i < n; ++i)
+ {
+ dw_loc_descr_ref ref;
+ rtx x = XVECEXP (concatn, 0, i);
+
+ ref = mem_loc_descriptor (x, mode);
+ if (ref == NULL)
+ return NULL;
+
+ add_loc_descr (&cc_loc_result, ref);
+ add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
+ }
+
+ return cc_loc_result;
+}
+
/* The following routine converts the RTL for a variable or parameter
(resident in memory) into an equivalent Dwarf representation of a
mechanism for getting the address of that same variable onto the top of a
mem_loc_result = int_loc_descriptor (INTVAL (rtl));
break;
+ case CONCATN:
+ mem_loc_result = concatn_mem_loc_descriptor (rtl, mode);
+ break;
+
default:
gcc_unreachable ();
}
return cc_loc_result;
}
+/* Return a descriptor that describes the concatenation of N
+ locations. */
+
+static dw_loc_descr_ref
+concatn_loc_descriptor (rtx concatn)
+{
+ unsigned int i;
+ dw_loc_descr_ref cc_loc_result = NULL;
+ unsigned int n = XVECLEN (concatn, 0);
+
+ for (i = 0; i < n; ++i)
+ {
+ dw_loc_descr_ref ref;
+ rtx x = XVECEXP (concatn, 0, i);
+
+ ref = loc_descriptor (x);
+ if (ref == NULL)
+ return NULL;
+
+ add_loc_descr (&cc_loc_result, ref);
+ add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
+ }
+
+ return cc_loc_result;
+}
+
/* Output a proper Dwarf location descriptor for a variable or parameter
which is either allocated in a register or in a memory location. For a
register, we just generate an OP_REG and the register number. For a
loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
break;
+ case CONCATN:
+ loc_result = concatn_loc_descriptor (rtl);
+ break;
+
case VAR_LOCATION:
/* Single part. */
if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
rtx rtl;
/* If this is not defined, we have no way to emit the data. */
- if (!targetm.asm_out.output_dwarf_dtprel)
+ if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
return 0;
/* The way DW_OP_GNU_push_tls_address is specified, we can only
/* FALLTHRU */
case RESULT_DECL:
+ case FUNCTION_DECL:
{
rtx rtl = rtl_for_decl_location (loc);
if (rtl == NULL_RTX)
return 0;
- else if (GET_CODE (rtl) == CONST_INT)
+ else if (GET_CODE (rtl) == CONST_INT)
{
HOST_WIDE_INT val = INTVAL (rtl);
if (TYPE_UNSIGNED (TREE_TYPE (loc)))
case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
case SAVE_EXPR:
- case MODIFY_EXPR:
- return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), want_address);
+ case GIMPLE_MODIFY_STMT:
+ return loc_descriptor_from_tree_1 (GENERIC_TREE_OPERAND (loc, 0),
+ want_address);
case COMPONENT_REF:
case BIT_FIELD_REF:
case MIN_EXPR:
case MAX_EXPR:
{
- const enum tree_code code =
- TREE_CODE (loc) == MIN_EXPR ? GT_EXPR : LT_EXPR;
+ const enum tree_code code =
+ TREE_CODE (loc) == MIN_EXPR ? GT_EXPR : LT_EXPR;
- loc = build3 (COND_EXPR, TREE_TYPE (loc),
+ loc = build3 (COND_EXPR, TREE_TYPE (loc),
build2 (code, integer_type_node,
TREE_OPERAND (loc, 0), TREE_OPERAND (loc, 1)),
- TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
+ TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
}
/* ... fall through ... */
break;
case FIX_TRUNC_EXPR:
- case FIX_CEIL_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_ROUND_EXPR:
return 0;
default:
/* Leave front-end specific codes as simply unknown. This comes
up, for instance, with the C STMT_EXPR. */
if ((unsigned int) TREE_CODE (loc)
- >= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
+ >= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
return 0;
#ifdef ENABLE_CHECKING
return (TREE_CODE (decl) != ERROR_MARK) ? DECL_ALIGN (decl) : BITS_PER_WORD;
}
+/* Return the result of rounding T up to ALIGN. */
+
+static inline HOST_WIDE_INT
+round_up_to_align (HOST_WIDE_INT t, unsigned int align)
+{
+ /* We must be careful if T is negative because HOST_WIDE_INT can be
+ either "above" or "below" unsigned int as per the C promotion
+ rules, depending on the host, thus making the signedness of the
+ direct multiplication and division unpredictable. */
+ unsigned HOST_WIDE_INT u = (unsigned HOST_WIDE_INT) t;
+
+ u += align - 1;
+ u /= align;
+ u *= align;
+
+ return (HOST_WIDE_INT) u;
+}
+
/* Given a pointer to a FIELD_DECL, compute and return the byte offset of the
lowest addressed byte of the "containing object" for the given FIELD_DECL,
or return 0 if we are unable to determine what that offset is, either
object_offset_in_bits = deepest_bitpos - type_size_in_bits;
/* Round up to type_align by default. This works best for bitfields. */
- object_offset_in_bits += type_align_in_bits - 1;
- object_offset_in_bits /= type_align_in_bits;
- object_offset_in_bits *= type_align_in_bits;
+ object_offset_in_bits
+ = round_up_to_align (object_offset_in_bits, type_align_in_bits);
if (object_offset_in_bits > bitpos_int)
{
object_offset_in_bits = deepest_bitpos - type_size_in_bits;
/* Round up to decl_align instead. */
- object_offset_in_bits += decl_align_in_bits - 1;
- object_offset_in_bits /= decl_align_in_bits;
- object_offset_in_bits *= decl_align_in_bits;
+ object_offset_in_bits
+ = round_up_to_align (object_offset_in_bits, decl_align_in_bits);
}
return object_offset_in_bits / BITS_PER_UNIT;
reference_to_unused (tree * tp, int * walk_subtrees,
void * data ATTRIBUTE_UNUSED)
{
- if (! EXPR_P (*tp) && ! CONSTANT_CLASS_P (*tp))
+ if (! EXPR_P (*tp) && ! GIMPLE_STMT_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
+ else if (!flag_unit_at_a_time)
return NULL_TREE;
+ else if (!cgraph_global_info_ready
+ && (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL))
+ gcc_unreachable ();
+ else if (DECL_P (*tp) && TREE_CODE (*tp) == VAR_DECL)
+ {
+ struct varpool_node *node = varpool_node (*tp);
+ if (!node->needed)
+ return *tp;
+ }
+ else if (DECL_P (*tp) && TREE_CODE (*tp) == FUNCTION_DECL
+ && (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp)))
+ {
+ struct cgraph_node *node = cgraph_node (*tp);
+ if (!node->output)
+ return *tp;
+ }
+
+ return NULL_TREE;
}
/* Generate an RTL constant from a decl initializer INIT with decl type TYPE,
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))
+ /* Other aggregates, and complex values, could be represented using
+ CONCAT: FIXME! */
+ else if (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
+ ;
+ /* Vectors only work if their mode is supported by the target.
+ FIXME: generic vectors ought to work too. */
+ else if (TREE_CODE (type) == VECTOR_TYPE && TYPE_MODE (type) == BLKmode)
;
/* If the initializer is something that we know will expand into an
immediate RTL constant, expand it now. We must be careful not to
gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL);
-
+
/* See if we possibly have multiple locations for this variable. */
loc_list = lookup_decl_loc (decl);
rtx varloc;
/* Now that we know what section we are using for a base,
- actually construct the list of locations.
+ actually construct the list of locations.
The first location information is what is passed to the
function that creates the location list, and the remaining
locations just get added on to that list.
/* Try to get some constant RTL for this decl, and use that as the value of
the location. */
-
+
rtl = rtl_for_decl_location (decl);
if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING))
{
add_const_value_attribute (die, rtl);
return;
}
-
+
/* 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. */
for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
switch (cfi->dw_cfi_opc)
{
+ case DW_CFA_set_loc:
case DW_CFA_advance_loc1:
case DW_CFA_advance_loc2:
case DW_CFA_advance_loc4:
if (TYPE_P (fn))
fn = TYPE_STUB_DECL (fn);
-
+
fn = decl_function_context (fn);
if (fn)
dwarf2out_abstract_function (fn);
add_src_coords_attributes (dw_die_ref die, tree decl)
{
expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
- unsigned file_index = lookup_filename (s.file);
- add_AT_unsigned (die, DW_AT_decl_file, file_index);
+ add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file));
add_AT_unsigned (die, DW_AT_decl_line, s.line);
}
involved. */
else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& ! DECL_IGNORED_P (TYPE_NAME (type)))
- t = DECL_NAME (TYPE_NAME (type));
+ {
+ /* We want to be extra verbose. Don't call dwarf_name if
+ DECL_NAME isn't set. The default hook for decl_printable_name
+ doesn't like that, and in this context it's correct to return
+ 0, instead of "<anonymous>" or the like. */
+ if (DECL_NAME (TYPE_NAME (type)))
+ name = lang_hooks.dwarf_name (TYPE_NAME (type), 2);
+ }
/* Now get the name as a string, or invent one. */
- if (t != 0)
+ if (!name && t != 0)
name = IDENTIFIER_POINTER (t);
}
#endif
add_type_attribute (array_die, element_type, 0, 0, context_die);
+
+ if (get_AT (array_die, DW_AT_name))
+ add_pubtype (type, array_die);
}
#if 0
else
add_AT_flag (type_die, DW_AT_declaration, 1);
+ if (get_AT (type_die, DW_AT_name))
+ add_pubtype (type, type_die);
+
return type_die;
}
{
dw_die_ref old_die;
tree save_fn;
+ struct function *save_cfun;
tree context;
int was_abstract = DECL_ABSTRACT (decl);
/* Pretend we've just finished compiling this function. */
save_fn = current_function_decl;
+ save_cfun = cfun;
current_function_decl = decl;
+ cfun = DECL_STRUCT_FUNCTION (decl);
set_decl_abstract_flags (decl, 1);
dwarf2out_decl (decl);
set_decl_abstract_flags (decl, 0);
current_function_decl = save_fn;
+ cfun = save_cfun;
+}
+
+/* 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
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
else if (old_die)
{
expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
- unsigned file_index = lookup_filename (s.file);
+ struct dwarf_file_data * file_index = lookup_filename (s.file);
if (!get_AT_flag (old_die, DW_AT_declaration)
/* We can have a normal definition following an inline one in the
apply; we just use the old DIE. */
if ((old_die->die_parent == comp_unit_die || context_die == NULL)
&& (DECL_ARTIFICIAL (decl)
- || (get_AT_unsigned (old_die, DW_AT_decl_file) == file_index
+ || (get_AT_file (old_die, DW_AT_decl_file) == file_index
&& (get_AT_unsigned (old_die, DW_AT_decl_line)
== (unsigned) s.line))))
{
{
subr_die = new_die (DW_TAG_subprogram, context_die, decl);
add_AT_specification (subr_die, old_die);
- if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
- add_AT_unsigned (subr_die, DW_AT_decl_file, file_index);
- if (get_AT_unsigned (old_die, DW_AT_decl_line)
- != (unsigned) s.line)
- add_AT_unsigned
- (subr_die, DW_AT_decl_line, s.line);
+ if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
+ add_AT_file (subr_die, DW_AT_decl_file, file_index);
+ if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
+ add_AT_unsigned (subr_die, DW_AT_decl_line, s.line);
}
}
else
{
if (DECL_DECLARED_INLINE_P (decl))
{
- if (cgraph_function_possibly_inlined_p (decl))
+ if (cgraph_function_possibly_inlined_p (decl))
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
else
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_not_inlined);
else
{
if (cgraph_function_possibly_inlined_p (decl))
- add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
+ add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
else
- add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_not_inlined);
+ add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_not_inlined);
}
equate_decl_number_to_die (decl, subr_die);
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
current_function_funcdef_no);
add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
-
+
add_pubname (decl, subr_die);
add_arange (decl, subr_die);
}
/* 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
+ 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);
the program. For example, consider the C++
test case:
- template <class T>
- struct S { static const int i = 7; };
+ template <class T>
+ struct S { static const int i = 7; };
+
+ template <class T>
+ const int S<T>::i;
- template <class T>
- const int S<T>::i;
+ int f() { return S<int>::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. */
+ not emit a definition. */
|| (TREE_CODE (decl) == VAR_DECL
&& DECL_COMDAT (decl) && !TREE_ASM_WRITTEN (decl))
|| class_or_namespace_scope_p (context_die));
if (DECL_NAME (decl))
{
expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
- unsigned file_index = lookup_filename (s.file);
+ struct dwarf_file_data * file_index = lookup_filename (s.file);
- if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
- add_AT_unsigned (var_die, DW_AT_decl_file, file_index);
-
- if (get_AT_unsigned (old_die, DW_AT_decl_line)
- != (unsigned) s.line)
+ if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
+ add_AT_file (var_die, DW_AT_decl_file, file_index);
+ if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
add_AT_unsigned (var_die, DW_AT_decl_line, s.line);
}
}
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_file (die, DW_AT_call_file, lookup_filename (s.file));
add_AT_unsigned (die, DW_AT_call_line, s.line);
}
+
+/* If STMT's abstract origin is a function declaration and STMT's
+ first subblock's abstract origin is the function's outermost block,
+ then we're looking at the main entry point. */
+static bool
+is_inlined_entry_point (tree stmt)
+{
+ tree decl, block;
+
+ if (!stmt || TREE_CODE (stmt) != BLOCK)
+ return false;
+
+ decl = block_ultimate_origin (stmt);
+
+ if (!decl || TREE_CODE (decl) != FUNCTION_DECL)
+ return false;
+
+ block = BLOCK_SUBBLOCKS (stmt);
+
+ if (block)
+ {
+ if (TREE_CODE (block) != BLOCK)
+ return false;
+
+ block = block_ultimate_origin (block);
+ }
+
+ return block == DECL_INITIAL (decl);
+}
+
/* 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. */
{
tree chain;
+ if (is_inlined_entry_point (stmt))
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
+ BLOCK_NUMBER (stmt));
+ add_AT_lbl_id (die, DW_AT_entry_pc, label);
+ }
+
add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
chain = BLOCK_FRAGMENT_CHAIN (stmt);
{
add_name_attribute (die, filename);
/* Don't add cwd for <built-in>. */
- if (filename[0] != DIR_SEPARATOR && filename[0] != '<')
+ if (!IS_ABSOLUTE_PATH (filename) && filename[0] != '<')
add_comp_dir_attribute (die);
}
&& ! decl_function_context (TYPE_STUB_DECL (type)))
VEC_safe_push (tree, gc, incomplete_types, type);
}
+
+ if (get_AT (type_die, DW_AT_name))
+ add_pubtype (type, type_die);
}
/* Generate a DIE for a subroutine _type_. */
add_prototyped_attribute (subr_die, type);
add_type_attribute (subr_die, return_type, 0, 0, context_die);
gen_formal_types_die (type, subr_die);
+
+ if (get_AT (subr_die, DW_AT_name))
+ add_pubtype (type, subr_die);
}
/* Generate a DIE for a type definition. */
if (DECL_ABSTRACT (decl))
equate_decl_number_to_die (decl, type_die);
+
+ if (get_AT (type_die, DW_AT_name))
+ add_pubtype (decl, type_die);
}
/* Generate a type description DIE. */
}
if (TREE_CODE (type) == ENUMERAL_TYPE)
- gen_enumeration_type_die (type, context_die);
+ {
+ /* This might have been written out by the call to
+ declare_in_namespace. */
+ if (!TREE_ASM_WRITTEN (type))
+ gen_enumeration_type_die (type, context_die);
+ }
else
gen_struct_or_union_type_die (type, context_die);
if (debug_info_level > DINFO_LEVEL_TERSE)
/* We are not in terse mode so *any* local declaration counts
as being a "significant" one. */
- must_output_die = (BLOCK_VARS (stmt) != NULL
- && (TREE_USED (stmt)
+ must_output_die = (BLOCK_VARS (stmt) != NULL
+ && (TREE_USED (stmt)
|| TREE_ASM_WRITTEN (stmt)
|| BLOCK_ABSTRACT (stmt)));
else
for (decl = BLOCK_VARS (stmt); decl != NULL; decl = TREE_CHAIN (decl))
{
dw_die_ref die;
-
+
if (TREE_CODE (decl) == FUNCTION_DECL)
die = lookup_decl_die (decl);
else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl))
die = lookup_type_die (TREE_TYPE (decl));
else
die = NULL;
-
+
if (die != NULL && die->die_parent == NULL)
add_child_die (context_die, die);
/* Do not produce debug information for static variables since
these might be optimized out. We are called for these later
- in cgraph_varpool_analyze_pending_decls. */
+ in varpool_analyze_pending_decls. */
if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
;
else
return decl_die;
}
-/* Returns the DIE for TYPE. A DIE is always returned. */
+/* Returns the DIE for TYPE, that must not be a base type. A DIE is
+ always returned. */
static dw_die_ref
force_type_die (tree type)
{
dw_die_ref imported_die, at_import_die;
dw_die_ref scope_die;
- unsigned file_index;
expanded_location xloc;
if (debug_info_level <= DINFO_LEVEL_TERSE)
/* For TYPE_DECL or CONST_DECL, lookup TREE_TYPE. */
if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
- at_import_die = force_type_die (TREE_TYPE (decl));
+ {
+ if (is_base_type (TREE_TYPE (decl)))
+ at_import_die = base_type_die (TREE_TYPE (decl));
+ else
+ at_import_die = force_type_die (TREE_TYPE (decl));
+ }
else
{
at_import_die = lookup_decl_die (decl);
imported_die = new_die (DW_TAG_imported_declaration, scope_die, context);
xloc = expand_location (input_location);
- file_index = lookup_filename (xloc.file);
- add_AT_unsigned (imported_die, DW_AT_decl_file, file_index);
+ add_AT_file (imported_die, DW_AT_decl_file, lookup_filename (xloc.file));
add_AT_unsigned (imported_die, DW_AT_decl_line, xloc.line);
add_AT_die_ref (imported_die, DW_AT_import, at_import_die);
}
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
if (lookup_decl_die (decl) != NULL)
- return;
+ return;
break;
case TYPE_DECL:
return 1;
}
+/* Hash table routines for file_hash. */
+
+static int
+file_table_eq (const void *p1_p, const void *p2_p)
+{
+ const struct dwarf_file_data * p1 = p1_p;
+ const char * p2 = p2_p;
+ return strcmp (p1->filename, p2) == 0;
+}
+
+static hashval_t
+file_table_hash (const void *p_p)
+{
+ const struct dwarf_file_data * p = p_p;
+ return htab_hash_string (p->filename);
+}
+
/* Lookup FILE_NAME (in the list of filenames that we know about here in
dwarf2out.c) and return its "index". The index of each (known) filename is
just a unique number which is associated with only that one filename. We
the index of the filename was looked up last. This handles the majority of
all searches. */
-static unsigned
+static struct dwarf_file_data *
lookup_filename (const char *file_name)
{
- size_t i, n;
- char *save_file_name;
+ void ** slot;
+ struct dwarf_file_data * created;
/* Check to see if the file name that was searched on the previous
call matches this file name. If so, return the index. */
- if (file_table_last_lookup_index != 0)
- {
- const char *last
- = VARRAY_CHAR_PTR (file_table, file_table_last_lookup_index);
- if (strcmp (file_name, last) == 0)
- return file_table_last_lookup_index;
- }
+ if (file_table_last_lookup
+ && (file_name == file_table_last_lookup->filename
+ || strcmp (file_table_last_lookup->filename, file_name) == 0))
+ return file_table_last_lookup;
/* Didn't match the previous lookup, search the table. */
- n = VARRAY_ACTIVE_SIZE (file_table);
- for (i = 1; i < n; i++)
- if (strcmp (file_name, VARRAY_CHAR_PTR (file_table, i)) == 0)
- {
- file_table_last_lookup_index = i;
- return i;
- }
+ slot = htab_find_slot_with_hash (file_table, file_name,
+ htab_hash_string (file_name), INSERT);
+ if (*slot)
+ return *slot;
- /* Add the new entry to the end of the filename table. */
- file_table_last_lookup_index = n;
- save_file_name = (char *) ggc_strdup (file_name);
- VARRAY_PUSH_CHAR_PTR (file_table, save_file_name);
- VARRAY_PUSH_UINT (file_table_emitted, 0);
-
- /* If the assembler is emitting the file table, and we aren't eliminating
- unused debug types, then we must emit .file here. If we are eliminating
- unused debug types, then this will be done by the maybe_emit_file call in
- prune_unused_types_walk_attribs. */
-
- if (DWARF2_ASM_LINE_DEBUG_INFO && ! flag_eliminate_unused_debug_types)
- return maybe_emit_file (i);
-
- return i;
+ created = ggc_alloc (sizeof (struct dwarf_file_data));
+ created->filename = file_name;
+ created->emitted_number = 0;
+ *slot = created;
+ return created;
}
/* If the assembler will construct the file table, then translate the compiler
types, which may include filenames. */
static int
-maybe_emit_file (int fileno)
+maybe_emit_file (struct dwarf_file_data * fd)
{
- if (DWARF2_ASM_LINE_DEBUG_INFO && fileno > 0)
+ if (! fd->emitted_number)
{
- if (!VARRAY_UINT (file_table_emitted, fileno))
+ if (last_emitted_file)
+ fd->emitted_number = last_emitted_file->emitted_number + 1;
+ else
+ fd->emitted_number = 1;
+ last_emitted_file = fd;
+
+ if (DWARF2_ASM_LINE_DEBUG_INFO)
{
- VARRAY_UINT (file_table_emitted, fileno) = ++emitcount;
- fprintf (asm_out_file, "\t.file %u ",
- VARRAY_UINT (file_table_emitted, fileno));
- output_quoted_string (asm_out_file,
- VARRAY_CHAR_PTR (file_table, fileno));
+ fprintf (asm_out_file, "\t.file %u ", fd->emitted_number);
+ output_quoted_string (asm_out_file, fd->filename);
fputc ('\n', asm_out_file);
}
- return VARRAY_UINT (file_table_emitted, fileno);
}
- else
- return fileno;
-}
-/* Initialize the compiler internal file table. */
-
-static void
-init_file_table (void)
-{
- /* Allocate the initial hunk of the file_table. */
- VARRAY_CHAR_PTR_INIT (file_table, 64, "file_table");
- VARRAY_UINT_INIT (file_table_emitted, 64, "file_table_emitted");
-
- /* Skip the first entry - file numbers begin at 1. */
- VARRAY_PUSH_CHAR_PTR (file_table, NULL);
- VARRAY_PUSH_UINT (file_table_emitted, 0);
- file_table_last_lookup_index = 0;
+ return fd->emitted_number;
}
/* Called by the final INSN scan whenever we see a var location. We
last_insn = loc_note;
last_label = newloc->label;
decl = NOTE_VAR_LOCATION_DECL (loc_note);
- if (DECL_DEBUG_EXPR_IS_FROM (decl) && DECL_DEBUG_EXPR (decl)
- && DECL_P (DECL_DEBUG_EXPR (decl)))
- decl = DECL_DEBUG_EXPR (decl);
add_var_loc_to_decl (decl, newloc);
}
dwarf2out_begin_function (tree fun)
{
htab_empty (decl_loc_table);
-
+
if (function_section (fun) != text_section)
have_multiple_function_sections = true;
}
if (debug_info_level >= DINFO_LEVEL_NORMAL
&& line != 0)
{
+ int file_num = maybe_emit_file (lookup_filename (filename));
+
switch_to_section (current_function_section ());
/* If requested, emit something human-readable. */
if (DWARF2_ASM_LINE_DEBUG_INFO)
{
- unsigned file_num = lookup_filename (filename);
-
- file_num = maybe_emit_file (file_num);
-
/* Emit the .loc directive understood by GNU as. */
fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
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,
- separate_line_info_table_in_use);
+ targetm.asm_out.internal_label (asm_out_file,
+ SEPARATE_LINE_CODE_LABEL,
+ separate_line_info_table_in_use);
/* Expand the line info table if necessary. */
if (separate_line_info_table_in_use
/* Add the new entry at the end of the line_info_table. */
line_info
= &separate_line_info_table[separate_line_info_table_in_use++];
- line_info->dw_file_num = lookup_filename (filename);
+ line_info->dw_file_num = file_num;
line_info->dw_line_num = line;
line_info->function = current_function_funcdef_no;
}
/* Add the new entry at the end of the line_info_table. */
line_info = &line_info_table[line_info_table_in_use++];
- line_info->dw_file_num = lookup_filename (filename);
+ line_info->dw_file_num = file_num;
line_info->dw_line_num = line;
}
}
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
- int fileno;
+ int file_num = maybe_emit_file (lookup_filename (filename));
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);
- fileno = maybe_emit_file (lookup_filename (filename));
- dw2_asm_output_data_uleb128 (fileno, "Filename we just started");
+ dw2_asm_output_data_uleb128 (file_num, "file %s", filename);
}
}
static void
dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
{
- init_file_table ();
+ /* Allocate the file_table. */
+ file_table = htab_create_ggc (50, file_table_hash,
+ file_table_eq, NULL);
/* Allocate the decl_die_table. */
decl_die_table = htab_create_ggc (10, decl_die_table_hash,
/* Zero-th entry is allocated, but unused. */
line_info_table_in_use = 1;
+ /* Allocate the pubtypes and pubnames vectors. */
+ pubname_table = VEC_alloc (pubname_entry, gc, 32);
+ pubtype_table = VEC_alloc (pubname_entry, gc, 32);
+
/* Generate the initial DIE for the .debug section. Note that the (string)
value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE
will (typically) be a relative pathname and that this pathname should be
SECTION_DEBUG, NULL);
debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
SECTION_DEBUG, NULL);
+#ifdef DEBUG_PUBTYPES_SECTION
+ debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+ SECTION_DEBUG, NULL);
+#endif
debug_str_section = get_section (DEBUG_STR_SECTION,
DEBUG_STR_SECTION_FLAGS, NULL);
debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
DEBUG_ABBREV_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
- ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
+ ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
COLD_TEXT_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
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. */
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 || 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 =
- 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;
}
}
prune_unused_types_walk_attribs (die);
/* If this node is a specification,
- also mark the definition, if it exists. */
+ also mark the definition, if it exists. */
if (get_AT_flag (die, DW_AT_declaration) && die->die_definition)
- prune_unused_types_mark (die->die_definition, 1);
+ prune_unused_types_mark (die->die_definition, 1);
}
if (dokids && die->die_mark != 2)
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));
}
}
if (die->die_mark)
return;
- switch (die->die_tag) {
- case DW_TAG_const_type:
- case DW_TAG_packed_type:
- case DW_TAG_pointer_type:
- case DW_TAG_reference_type:
- case DW_TAG_volatile_type:
- case DW_TAG_typedef:
- case DW_TAG_array_type:
- case DW_TAG_structure_type:
- case DW_TAG_union_type:
- case DW_TAG_class_type:
- case DW_TAG_friend:
- case DW_TAG_variant_part:
- case DW_TAG_enumeration_type:
- case DW_TAG_subroutine_type:
- case DW_TAG_string_type:
- case DW_TAG_set_type:
- case DW_TAG_subrange_type:
- case DW_TAG_ptr_to_member_type:
- case DW_TAG_file_type:
- /* It's a type node --- don't mark it. */
- return;
+ switch (die->die_tag)
+ {
+ case DW_TAG_const_type:
+ case DW_TAG_packed_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_typedef:
+ case DW_TAG_array_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ case DW_TAG_friend:
+ case DW_TAG_variant_part:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_string_type:
+ case DW_TAG_set_type:
+ 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;
- default:
- /* Mark everything else. */
- break;
+ default:
+ /* Mark everything else. */
+ break;
}
die->die_mark = 1;
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);
+ prune_unused_types_update_strings (die);
- 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_prune (c);
+ } while (c != die->die_child);
}
{
unsigned int i;
limbo_die_node *node;
+ pubname_ref pub;
- /* 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);
/* Also set the mark on nodes referenced from the
pubname_table or arange_table. */
- for (i = 0; i < pubname_table_in_use; i++)
- prune_unused_types_mark (pubname_table[i].die, 1);
+ for (i = 0; VEC_iterate (pubname_entry, pubname_table, i, pub); i++)
+ prune_unused_types_mark (pub->die, 1);
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);
prune_unmark_dies (node->die);
}
+/* Set the parameter to true if there are any relative pathnames in
+ the file table. */
+static int
+file_table_relative_p (void ** slot, void *param)
+{
+ bool *p = param;
+ struct dwarf_file_data *d = *slot;
+ if (d->emitted_number && !IS_ABSOLUTE_PATH (d->filename))
+ {
+ *p = true;
+ return 0;
+ }
+ return 1;
+}
+
/* Output stuff that dwarf requires at the end of every file,
and generate the DWARF-2 debugging info. */
/* Add the name for the main input file now. We delayed this from
dwarf2out_init to avoid complications with PCH. */
add_name_attribute (comp_unit_die, filename);
- if (filename[0] != DIR_SEPARATOR)
+ if (!IS_ABSOLUTE_PATH (filename))
add_comp_dir_attribute (comp_unit_die);
else if (get_AT (comp_unit_die, DW_AT_comp_dir) == NULL)
{
- size_t i;
- for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
- if (VARRAY_CHAR_PTR (file_table, i)[0] != DIR_SEPARATOR
- /* Don't add cwd for <built-in>. */
- && VARRAY_CHAR_PTR (file_table, i)[0] != '<')
- {
- add_comp_dir_attribute (comp_unit_die);
- break;
- }
+ bool p = false;
+ htab_traverse (file_table, file_table_relative_p, &p);
+ if (p)
+ add_comp_dir_attribute (comp_unit_die);
}
/* Traverse the limbo die list, and add parent/child links. The only
else if (TYPE_P (node->created_for))
context = TYPE_CONTEXT (node->created_for);
- gcc_assert (context && TREE_CODE (context) == FUNCTION_DECL);
+ gcc_assert (context
+ && (TREE_CODE (context) == FUNCTION_DECL
+ || TREE_CODE (context) == NAMESPACE_DECL));
origin = lookup_decl_die (context);
if (origin)
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 ();
targetm.asm_out.internal_label (asm_out_file, COLD_END_LABEL, 0);
}
- /* Output the source line correspondence table. We must do this
- even if there is no line information. Otherwise, on an empty
- translation unit, we will generate a present, but empty,
- .debug_info section. IRIX 6.5 `nm' will then complain when
- examining the file. */
- if (! DWARF2_ASM_LINE_DEBUG_INFO)
- {
- switch_to_section (debug_line_section);
- output_line_info ();
- }
-
/* We can only use the low/high_pc attributes if all of the code was
in .text. */
if (!have_multiple_function_sections)
output_abbrev_section ();
/* Output public names table if necessary. */
- if (pubname_table_in_use)
+ if (!VEC_empty (pubname_entry, pubname_table))
{
switch_to_section (debug_pubnames_section);
- output_pubnames ();
+ output_pubnames (pubname_table);
+ }
+
+#ifdef DEBUG_PUBTYPES_SECTION
+ /* Output public types table if necessary. */
+ if (!VEC_empty (pubname_entry, pubtype_table))
+ {
+ switch_to_section (debug_pubtypes_section);
+ output_pubnames (pubtype_table);
}
+#endif
/* Output the address range information. We only put functions in the arange
table, so don't write it out if we don't have any. */
output_ranges ();
}
+ /* Output the source line correspondence table. We must do this
+ even if there is no line information. Otherwise, on an empty
+ translation unit, we will generate a present, but empty,
+ .debug_info section. IRIX 6.5 `nm' will then complain when
+ examining the file. This is done late so that any filenames
+ used by the debug_info section are marked as 'used'. */
+ if (! DWARF2_ASM_LINE_DEBUG_INFO)
+ {
+ switch_to_section (debug_line_section);
+ output_line_info ();
+ }
+
/* Have to end the macro section. */
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{