#include "target.h"
#include "langhooks.h"
#include "hashtable.h"
+#include "hashtab.h"
#ifdef DWARF2_DEBUGGING_INFO
static void dwarf2out_source_line PARAMS ((unsigned int, const char *));
/* Record the root of the DIE's built for the current compilation unit. */
static dw_die_ref comp_unit_die;
+/* We need special handling in dwarf2out_start_source_file if it is
+ first one. */
+static int is_main_source;
+
/* A list of DIEs with a NULL parent waiting to be relocated. */
static limbo_die_node *limbo_die_list = 0;
static void loc_checksum PARAMS ((dw_loc_descr_ref,
struct md5_ctx *));
static void attr_checksum PARAMS ((dw_attr_ref,
- struct md5_ctx *));
+ struct md5_ctx *,
+ int *));
static void die_checksum PARAMS ((dw_die_ref,
- struct md5_ctx *));
+ struct md5_ctx *,
+ int *));
+static int same_loc_p PARAMS ((dw_loc_descr_ref,
+ dw_loc_descr_ref, int *));
+static int same_dw_val_p PARAMS ((dw_val_node *, dw_val_node *,
+ int *));
+static int same_attr_p PARAMS ((dw_attr_ref, dw_attr_ref, int *));
+static int same_die_p PARAMS ((dw_die_ref, dw_die_ref, int *));
+static int same_die_p_wrap PARAMS ((dw_die_ref, dw_die_ref));
static void compute_section_prefix PARAMS ((dw_die_ref));
static int is_type_die PARAMS ((dw_die_ref));
static int is_comdat_die PARAMS ((dw_die_ref));
static int is_symbol_die PARAMS ((dw_die_ref));
static void assign_symbol_names PARAMS ((dw_die_ref));
static void break_out_includes PARAMS ((dw_die_ref));
+static hashval_t htab_cu_hash PARAMS ((const void *));
+static int htab_cu_eq PARAMS ((const void *, const void *));
+static void htab_cu_del PARAMS ((void *));
+static int check_duplicate_cu PARAMS ((dw_die_ref, htab_t, unsigned *));
+static void record_comdat_symbol_number PARAMS ((dw_die_ref, htab_t, unsigned));
static void add_sibling_attributes PARAMS ((dw_die_ref));
static void build_abbrev_table PARAMS ((dw_die_ref));
static void output_location_lists PARAMS ((dw_die_ref));
static void calc_die_sizes PARAMS ((dw_die_ref));
static void mark_dies PARAMS ((dw_die_ref));
static void unmark_dies PARAMS ((dw_die_ref));
+static void unmark_all_dies PARAMS ((dw_die_ref));
static unsigned long size_of_pubnames PARAMS ((void));
static unsigned long size_of_aranges PARAMS ((void));
static enum dwarf_form value_format PARAMS ((dw_attr_ref));
static void output_die_symbol PARAMS ((dw_die_ref));
static void output_die PARAMS ((dw_die_ref));
static void output_compilation_unit_header PARAMS ((void));
-static void output_comp_unit PARAMS ((dw_die_ref));
+static void output_comp_unit PARAMS ((dw_die_ref, int));
static const char *dwarf2_name PARAMS ((tree, int));
static void add_pubname PARAMS ((tree, dw_die_ref));
static void output_pubnames PARAMS ((void));
/* Calculate the checksum of an attribute. */
static void
-attr_checksum (at, ctx)
+attr_checksum (at, ctx, mark)
dw_attr_ref at;
struct md5_ctx *ctx;
+ int *mark;
{
dw_loc_descr_ref loc;
rtx r;
break;
case dw_val_class_die_ref:
- if (AT_ref (at)->die_offset)
- CHECKSUM (AT_ref (at)->die_offset);
- /* FIXME else use target die name or something. */
+ die_checksum (AT_ref (at), ctx, mark);
+ break;
case dw_val_class_fde_ref:
case dw_val_class_lbl_id:
/* Calculate the checksum of a DIE. */
static void
-die_checksum (die, ctx)
+die_checksum (die, ctx, mark)
dw_die_ref die;
struct md5_ctx *ctx;
+ int *mark;
{
dw_die_ref c;
dw_attr_ref a;
+ /* To avoid infinite recursion. */
+ if (die->die_mark)
+ {
+ CHECKSUM (die->die_mark);
+ return;
+ }
+ die->die_mark = ++(*mark);
+
CHECKSUM (die->die_tag);
for (a = die->die_attr; a; a = a->dw_attr_next)
- attr_checksum (a, ctx);
+ attr_checksum (a, ctx, mark);
for (c = die->die_child; c; c = c->die_sib)
- die_checksum (c, ctx);
+ die_checksum (c, ctx, mark);
}
#undef CHECKSUM
#undef CHECKSUM_STRING
+/* Do the location expressions look same? */
+static inline int
+same_loc_p (loc1, loc2, mark)
+ dw_loc_descr_ref loc1;
+ dw_loc_descr_ref loc2;
+ int *mark;
+{
+ return loc1->dw_loc_opc == loc2->dw_loc_opc
+ && same_dw_val_p (&loc1->dw_loc_oprnd1, &loc2->dw_loc_oprnd1, mark)
+ && same_dw_val_p (&loc1->dw_loc_oprnd2, &loc2->dw_loc_oprnd2, mark);
+}
+
+/* Do the values look the same? */
+static int
+same_dw_val_p (v1, v2, mark)
+ dw_val_node *v1;
+ dw_val_node *v2;
+ int *mark;
+{
+ dw_loc_descr_ref loc1, loc2;
+ rtx r1, r2;
+ unsigned i;
+
+ if (v1->val_class != v2->val_class)
+ return 0;
+
+ switch (v1->val_class)
+ {
+ case dw_val_class_const:
+ return v1->v.val_int == v2->v.val_int;
+ case dw_val_class_unsigned_const:
+ return v1->v.val_unsigned == v2->v.val_unsigned;
+ case dw_val_class_long_long:
+ return v1->v.val_long_long.hi == v2->v.val_long_long.hi
+ && v1->v.val_long_long.low == v2->v.val_long_long.low;
+ case dw_val_class_float:
+ if (v1->v.val_float.length != v2->v.val_float.length)
+ return 0;
+ for (i = 0; i < v1->v.val_float.length; i++)
+ if (v1->v.val_float.array[i] != v2->v.val_float.array[i])
+ return 0;
+ return 1;
+ case dw_val_class_flag:
+ return v1->v.val_flag == v2->v.val_flag;
+ case dw_val_class_str:
+ return !strcmp((const char *) HT_STR (&v1->v.val_str->id),
+ (const char *) HT_STR (&v2->v.val_str->id));
+
+ case dw_val_class_addr:
+ r1 = v1->v.val_addr;
+ r2 = v2->v.val_addr;
+ if (GET_CODE (r1) != GET_CODE (r2))
+ return 0;
+ switch (GET_CODE (r1))
+ {
+ case SYMBOL_REF:
+ return !strcmp (XSTR (r1, 0), XSTR (r2, 0));
+
+ default:
+ abort ();
+ }
+
+ case dw_val_class_offset:
+ return v1->v.val_offset == v2->v.val_offset;
+
+ case dw_val_class_loc:
+ for (loc1 = v1->v.val_loc, loc2 = v2->v.val_loc;
+ loc1 && loc2;
+ loc1 = loc1->dw_loc_next, loc2 = loc2->dw_loc_next)
+ if (!same_loc_p (loc1, loc2, mark))
+ return 0;
+ return !loc1 && !loc2;
+
+ case dw_val_class_die_ref:
+ return same_die_p (v1->v.val_die_ref.die, v2->v.val_die_ref.die, mark);
+
+ case dw_val_class_fde_ref:
+ case dw_val_class_lbl_id:
+ case dw_val_class_lbl_offset:
+ return 1;
+
+ default:
+ return 1;
+ }
+}
+
+/* Do the attributes look the same? */
+
+static int
+same_attr_p (at1, at2, mark)
+ dw_attr_ref at1;
+ dw_attr_ref at2;
+ int *mark;
+{
+ 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)
+ return 1;
+
+ return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
+}
+
+/* Do the dies look the same? */
+
+static int
+same_die_p (die1, die2, mark)
+ dw_die_ref die1;
+ dw_die_ref die2;
+ int *mark;
+{
+ dw_die_ref c1, c2;
+ dw_attr_ref a1, a2;
+
+ /* To avoid infinite recursion. */
+ if (die1->die_mark)
+ return die1->die_mark == die2->die_mark;
+ die1->die_mark = die2->die_mark = ++(*mark);
+
+ if (die1->die_tag != die2->die_tag)
+ return 0;
+
+ for (a1 = die1->die_attr, a2 = die2->die_attr;
+ a1 && a2;
+ a1 = a1->dw_attr_next, a2 = a2->dw_attr_next)
+ if (!same_attr_p (a1, a2, mark))
+ return 0;
+ if (a1 || a2)
+ 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;
+
+ return 1;
+}
+
+/* Do the dies look the same? Wrapper around same_die_p. */
+
+static int
+same_die_p_wrap (die1, die2)
+ dw_die_ref die1;
+ dw_die_ref die2;
+{
+ int mark = 0;
+ int ret = same_die_p (die1, die2, &mark);
+
+ unmark_all_dies (die1);
+ unmark_all_dies (die2);
+
+ return ret;
+}
+
/* The prefix to attach to symbols on DIEs in the current comdat debug
info section. */
static char *comdat_symbol_id;
compute_section_prefix (unit_die)
dw_die_ref unit_die;
{
- const char *base = lbasename (get_AT_string (unit_die, DW_AT_name));
+ const char *die_name = get_AT_string (unit_die, DW_AT_name);
+ const char *base = die_name ? lbasename (die_name) : "anonymous";
char *name = (char *) alloca (strlen (base) + 64);
char *p;
- int i;
+ int i, mark;
unsigned char checksum[16];
struct md5_ctx ctx;
the name filename of the unit. */
md5_init_ctx (&ctx);
- die_checksum (unit_die, &ctx);
+ mark = 0;
+ die_checksum (unit_die, &ctx, &mark);
+ unmark_all_dies (unit_die);
md5_finish_ctx (&ctx, checksum);
sprintf (name, "%s.", base);
case DW_TAG_file_type:
case DW_TAG_packed_type:
case DW_TAG_volatile_type:
+ case DW_TAG_typedef:
return 1;
default:
return 0;
assign_symbol_names (c);
}
+struct cu_hash_table_entry
+{
+ dw_die_ref cu;
+ unsigned min_comdat_num, max_comdat_num;
+ struct cu_hash_table_entry *next;
+};
+
+/* Routines to manipulate hash table of CUs. */
+static hashval_t
+htab_cu_hash (of)
+ const void *of;
+{
+ const struct cu_hash_table_entry *entry = of;
+
+ return htab_hash_string (entry->cu->die_symbol);
+}
+
+static int
+htab_cu_eq (of1, of2)
+ const void *of1;
+ const void *of2;
+{
+ const struct cu_hash_table_entry *entry1 = of1;
+ const struct die_struct *entry2 = of2;
+
+ return !strcmp (entry1->cu->die_symbol, entry2->die_symbol);
+}
+
+static void
+htab_cu_del (what)
+ void *what;
+{
+ struct cu_hash_table_entry *next, *entry = what;
+
+ while (entry)
+ {
+ next = entry->next;
+ free (entry);
+ entry = next;
+ }
+}
+
+/* Check whether we have already seen this CU and set up SYM_NUM
+ accordingly. */
+static int
+check_duplicate_cu (cu, htable, sym_num)
+ dw_die_ref cu;
+ htab_t htable;
+ unsigned *sym_num;
+{
+ struct cu_hash_table_entry dummy;
+ struct cu_hash_table_entry **slot, *entry, *last = &dummy;
+
+ dummy.max_comdat_num = 0;
+
+ slot = (struct cu_hash_table_entry **)
+ htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol),
+ INSERT);
+ entry = *slot;
+
+ for (; entry; last = entry, entry = entry->next)
+ {
+ if (same_die_p_wrap (cu, entry->cu))
+ break;
+ }
+
+ if (entry)
+ {
+ *sym_num = entry->min_comdat_num;
+ return 1;
+ }
+
+ entry = xcalloc (1, sizeof (struct cu_hash_table_entry));
+ entry->cu = cu;
+ entry->min_comdat_num = *sym_num = last->max_comdat_num;
+ entry->next = *slot;
+ *slot = entry;
+
+ return 0;
+}
+
+/* Record SYM_NUM to record of CU in HTABLE. */
+static void
+record_comdat_symbol_number (cu, htable, sym_num)
+ dw_die_ref cu;
+ htab_t htable;
+ unsigned sym_num;
+{
+ struct cu_hash_table_entry **slot, *entry;
+
+ slot = (struct cu_hash_table_entry **)
+ htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol),
+ NO_INSERT);
+ entry = *slot;
+
+ entry->max_comdat_num = sym_num;
+}
+
/* Traverse the DIE (which is always comp_unit_die), and set up
additional compilation units for each of the include files we see
bracketed by BINCL/EINCL. */
{
dw_die_ref *ptr;
dw_die_ref unit = NULL;
- limbo_die_node *node;
+ limbo_die_node *node, **pnode;
+ htab_t cu_hash_table;
for (ptr = &(die->die_child); *ptr;)
{
#endif
assign_symbol_names (die);
- for (node = limbo_die_list; node; node = node->next)
+ cu_hash_table = htab_create (10, htab_cu_hash, htab_cu_eq, htab_cu_del);
+ for (node = limbo_die_list, pnode = &limbo_die_list;
+ node;
+ node = node->next)
{
+ int is_dupl;
+
compute_section_prefix (node->die);
+ is_dupl = check_duplicate_cu (node->die, cu_hash_table,
+ &comdat_symbol_number);
assign_symbol_names (node->die);
+ if (is_dupl)
+ *pnode = node->next;
+ else
+ {
+ pnode = &node->next;
+ record_comdat_symbol_number (node->die, cu_hash_table,
+ comdat_symbol_number);
+ }
}
+ htab_delete (cu_hash_table);
}
/* Traverse the DIE and add a sibling attribute if it may have the
{
dw_die_ref c;
+ if (die->die_mark)
+ abort ();
+
die->die_mark = 1;
for (c = die->die_child; c; c = c->die_sib)
mark_dies (c);
{
dw_die_ref c;
+ if (!die->die_mark)
+ abort ();
+
die->die_mark = 0;
for (c = die->die_child; c; c = c->die_sib)
unmark_dies (c);
}
+/* Clear the marks for a die, its children and referred dies. */
+
+static void
+unmark_all_dies (die)
+ dw_die_ref die;
+{
+ dw_die_ref c;
+ dw_attr_ref a;
+
+ if (!die->die_mark)
+ return;
+ die->die_mark = 0;
+
+ for (c = die->die_child; c; c = c->die_sib)
+ unmark_all_dies (c);
+
+ for (a = die->die_attr; a; a = a->dw_attr_next)
+ 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. */
/* Output the compilation unit DIE and its children. */
static void
-output_comp_unit (die)
+output_comp_unit (die, output_if_empty)
dw_die_ref die;
+ int output_if_empty;
{
const char *secname;
+ char *oldsym, *tmp;
+
+ /* Unless we are outputting main CU, we may throw away empty ones. */
+ if (!output_if_empty && die->die_child == NULL)
+ return;
/* Even if there are no children of this DIE, we must output the information
about the compilation unit. Otherwise, on an empty translation unit, we
next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
calc_die_sizes (die);
- if (die->die_symbol)
+ oldsym = die->die_symbol;
+ if (oldsym)
{
- char *tmp = (char *) alloca (strlen (die->die_symbol) + 24);
+ tmp = (char *) alloca (strlen (oldsym) + 24);
- sprintf (tmp, ".gnu.linkonce.wi.%s", die->die_symbol);
+ sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym);
secname = tmp;
die->die_symbol = NULL;
}
/* Leave the marks on the main CU, so we can check them in
output_pubnames. */
- if (die->die_symbol)
- unmark_dies (die);
+ if (oldsym)
+ {
+ unmark_dies (die);
+ die->die_symbol = oldsym;
+ }
}
/* The DWARF2 pubname for a nested thingy looks like "A::f". The
unsigned int lineno;
const char *filename;
{
- if (flag_eliminate_dwarf2_dups)
+ if (flag_eliminate_dwarf2_dups && !is_main_source)
{
/* Record the beginning of the file for break_out_includes. */
- dw_die_ref bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die, NULL);
+ dw_die_ref bincl_die;
+
+ bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die, NULL);
add_AT_string (bincl_die, DW_AT_name, filename);
}
+ is_main_source = 0;
+
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
taken as being relative to the directory from which the compiler was
invoked when the given (base) source file was compiled. */
comp_unit_die = gen_compile_unit_die (main_input_filename);
+ is_main_source = 1;
VARRAY_TREE_INIT (incomplete_types, 64, "incomplete_types");
/* Output all of the compilation units. We put the main one last so that
the offsets are available to output_pubnames. */
for (node = limbo_die_list; node; node = node->next)
- output_comp_unit (node->die);
+ output_comp_unit (node->die, 0);
- output_comp_unit (comp_unit_die);
+ output_comp_unit (comp_unit_die, 0);
/* Output the abbreviation table. */
named_section_flags (DEBUG_ABBREV_SECTION, SECTION_DEBUG);