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;
{
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)
/* 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:
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);
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(())
{
}
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;
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;
-
-/* 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;
+static GTY (()) VEC (pubname_entry, gc) * pubname_table;
-/* 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 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
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)
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
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
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);
-
- free_die (tmp_die);
- }
+ dw_die_ref c;
+
+ c = die->die_child;
+ if (c) do {
+ dw_die_ref prev = c;
+ c = c->die_sib;
+ while (c->die_tag == tag)
+ {
+ remove_child_with_prev (c, prev);
+ /* Might have removed every child. */
+ if (c == c->die_sib)
+ return;
+ c = c->die_sib;
+ }
+ } while (c != die->die_child);
}
-/* Add a child DIE below its parent. We build the lists up in reverse
- addition order, and correct that in reverse_all_dies. */
+/* Add a CHILD_DIE as the last child of DIE. */
-static inline void
+static void
add_child_die (dw_die_ref die, dw_die_ref child_die)
{
- if (die != NULL && child_die != NULL)
- {
- gcc_assert (die != child_die);
+ /* FIXME this should probably be an assert. */
+ if (! die || ! child_die)
+ return;
+ gcc_assert (die != child_die);
- child_die->die_parent = die;
- child_die->die_sib = die->die_child;
- die->die_child = child_die;
+ child_die->die_parent = die;
+ if (die->die_child)
+ {
+ child_die->die_sib = die->die_child->die_sib;
+ die->die_child->die_sib = child_die;
}
+ else
+ child_die->die_sib = child_die;
+ die->die_child = child_die;
}
/* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
- is the specification, to the front of PARENT's list of children. */
+ is the specification, to the end of PARENT's list of children.
+ This is done by removing and re-adding it. */
static void
splice_child_die (dw_die_ref parent, dw_die_ref child)
{
- dw_die_ref *p;
+ dw_die_ref p;
/* We want the declaration DIE from inside the class, not the
specification DIE at toplevel. */
gcc_assert (child->die_parent == parent
|| (child->die_parent
== get_AT_ref (parent, DW_AT_specification)));
-
- for (p = &(child->die_parent->die_child); *p; p = &((*p)->die_sib))
- if (*p == child)
+
+ for (p = child->die_parent->die_child; ; p = p->die_sib)
+ if (p->die_sib == child)
{
- *p = child->die_sib;
+ remove_child_with_prev (child, p);
break;
}
- child->die_parent = parent;
- child->die_sib = parent->die_child;
- parent->die_child = child;
+ add_child_die (parent, child);
}
/* Return a pointer to a newly created DIE node. */
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 (!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;
-
- if (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
- || (unit && is_comdat_die (c)))
- {
- /* This DIE is for a secondary CU; remove it from the main one. */
- *ptr = c->die_sib;
-
- if (c->die_tag == DW_TAG_GNU_BINCL)
- {
- unit = push_new_compile_unit (unit, c);
- free_die (c);
- }
- else if (c->die_tag == DW_TAG_GNU_EINCL)
- {
- unit = pop_compile_unit (unit);
- free_die (c);
- }
- else
- add_child_die (unit, c);
- }
- else
- {
- /* Leave this DIE in the main CU. */
- ptr = &(c->die_sib);
- continue;
- }
- }
+ c = die->die_child;
+ if (c) do {
+ dw_die_ref prev = c;
+ c = c->die_sib;
+ while (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
+ || (unit && is_comdat_die (c)))
+ {
+ dw_die_ref next = c->die_sib;
+
+ /* This DIE is for a secondary CU; remove it from the main one. */
+ remove_child_with_prev (c, prev);
+
+ if (c->die_tag == DW_TAG_GNU_BINCL)
+ unit = push_new_compile_unit (unit, c);
+ else if (c->die_tag == DW_TAG_GNU_EINCL)
+ unit = pop_compile_unit (unit);
+ else
+ add_child_die (unit, c);
+ c = next;
+ if (c == die->die_child)
+ break;
+ }
+ } while (c != die->die_child);
#if 0
/* We can only use this in debugging, since the frontend doesn't check
{
dw_die_ref c;
- if (die->die_tag != DW_TAG_compile_unit
- && die->die_sib && die->die_child != NULL)
- /* Add the sibling link to the front of the attribute list. */
+ if (! die->die_child)
+ return;
+
+ if (die->die_parent && die != die->die_parent->die_child)
add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
- for (c = die->die_child; c != NULL; c = c->die_sib)
- add_sibling_attributes (c);
+ FOR_EACH_CHILD (die, c, add_sibling_attributes (c));
}
/* Output all location lists for the DIE and its children. */
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
}
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)
}
}
-/* 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);
+ /* We shouldn't see pubnames for DIEs outside of the main CU. */
+ 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);
/* 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
gcc_assert (regno < FIRST_PSEUDO_REGISTER);
#ifdef LEAF_REG_REMAP
- regno = LEAF_REG_REMAP (regno);
+ {
+ int leaf_reg;
+
+ 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);
+ {
+ int leaf_reg;
+
+ leaf_reg = LEAF_REG_REMAP (reg);
+ if (leaf_reg != -1)
+ reg = (unsigned) leaf_reg;
+ }
#endif
gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
/* FALLTHRU */
case RESULT_DECL:
+ case FUNCTION_DECL:
{
rtx rtl = rtl_for_decl_location (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:
break;
case FIX_TRUNC_EXPR:
- case FIX_CEIL_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_ROUND_EXPR:
return 0;
default:
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)
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
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:
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);
}
#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
int declaration = (current_function_decl != decl
|| class_or_namespace_scope_p (context_die));
- premark_used_types();
+ 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
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_NAME (decl))
{
expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
- unsigned 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);
+ struct dwarf_file_data * file_index = lookup_filename (s.file);
- 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);
}
{
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. */
{
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)
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);
}
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;
- }
-
- /* 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);
+ slot = htab_find_slot_with_hash (file_table, file_name,
+ htab_hash_string (file_name), INSERT);
+ if (*slot)
+ return *slot;
- 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);
}
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,
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;
}
}
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:
- if (die->die_perennial_p)
- break;
+ 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;
+ /* 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
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. */
if (fde_table_in_use)
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)
{