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)
{
- loc->dw_loc_addr = size;
- size += size_of_loc_descr (loc);
+ 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)
+ {
+ 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(())
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 *);
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)
}
}
-/* 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;
- 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;
}
-/* Add a child DIE below its parent. We build the lists up in reverse
- addition order, and correct that in reverse_all_dies. */
+/* Remove child DIE whose die_tag is TAG. Do nothing if no child
+ matches TAG. */
-static inline void
+static void
+remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
+{
+ 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 as the last child of DIE. */
+
+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. */
if (die->die_child != NULL)
{
print_indent += 4;
- for (c = die->die_child; c != NULL; c = c->die_sib)
- print_die (c, outfile);
-
+ FOR_EACH_CHILD (die, c, print_die (c, outfile));
print_indent -= 4;
}
if (print_indent == 0)
print_dwarf_line_table (stderr);
}
\f
-/* We build up the lists of children and attributes by pushing new ones
- onto the beginning of the list. Reverse the lists for DIE so that
- they are in order of addition. */
-
-static void
-reverse_die_lists (dw_die_ref die)
-{
- dw_die_ref c, cp, cn;
-
- 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. */
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
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);
- else if (c->die_tag == DW_TAG_GNU_EINCL)
- unit = pop_compile_unit (unit);
- 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. */
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)
}
}
- 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. */
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)];
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
{
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
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);
}
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. */
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));
}
}
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
static void
prune_unused_types_prune (dw_die_ref die)
{
- dw_die_ref *p;
+ dw_die_ref c;
gcc_assert (die->die_mark);
+ prune_unused_types_update_strings (die);
- p = &die->die_child;
- while (*p)
- {
- dw_die_ref c = *p;
- if (c && ! c->die_mark)
- {
- do {
- c = c->die_sib;
- } while (c && ! c->die_mark);
- *p = c;
- }
-
- if (c)
+ 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)
{
- prune_unused_types_update_strings (c);
- prune_unused_types_prune (c);
- p = &c->die_sib;
+ /* No marked children between 'prev' and the end of the list. */
+ if (prev == c)
+ /* No marked children at all. */
+ die->die_child = NULL;
+ else
+ {
+ 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;
- /* 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);
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 ();