#define DWARF_OFFSET_SIZE 4
#endif
+/* The size in bytes of a DWARF 4 type signature. */
+
+#ifndef DWARF_TYPE_SIGNATURE_SIZE
+#define DWARF_TYPE_SIGNATURE_SIZE 8
+#endif
+
/* According to the (draft) DWARF 3 specification, the initial length
should either be 4 or 12 bytes. When it's 12 bytes, the first 4
bytes are 0xffffffff, followed by the length stored in the next 8
static GTY(()) VEC(deferred_locations, gc) *deferred_locations_list;
+DEF_VEC_P(dw_die_ref);
+DEF_VEC_ALLOC_P(dw_die_ref,heap);
+
/* Each DIE may have a series of attribute/value pairs. Values
can take on several forms. The forms that are used in this
implementation are listed below. */
dw_val_class_lineptr,
dw_val_class_str,
dw_val_class_macptr,
- dw_val_class_file
+ dw_val_class_file,
+ dw_val_class_data8
};
/* Describe a floating point constant value, or a vector constant value. */
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;
+ unsigned char GTY ((tag ("dw_val_class_data8"))) val_data8[8];
}
GTY ((desc ("%1.val_class"))) v;
}
typedef struct pubname_struct *pubname_ref;
typedef struct dw_ranges_struct *dw_ranges_ref;
typedef struct dw_ranges_by_label_struct *dw_ranges_by_label_ref;
+typedef struct comdat_type_struct *comdat_type_node_ref;
/* Each entry in the line_info_table maintains the file and
line number associated with the label generated for that
typedef struct GTY((chain_circular ("%h.die_sib"))) die_struct {
enum dwarf_tag die_tag;
- char *die_symbol;
+ union die_symbol_or_type_node
+ {
+ char * GTY ((tag ("0"))) die_symbol;
+ comdat_type_node_ref GTY ((tag ("1"))) die_type_node;
+ }
+ GTY ((desc ("dwarf_version >= 4"))) die_id;
VEC(dw_attr_node,gc) * die_attr;
dw_die_ref die_parent;
dw_die_ref die_child;
const char *end;
};
+/* The comdat type node structure. */
+typedef struct GTY(()) comdat_type_struct
+{
+ dw_die_ref root_die;
+ dw_die_ref type_die;
+ char signature[DWARF_TYPE_SIGNATURE_SIZE];
+ struct comdat_type_struct *next;
+}
+comdat_type_node;
+
/* The limbo die list structure. */
typedef struct GTY(()) limbo_die_struct {
dw_die_ref die;
}
limbo_die_node;
+typedef struct GTY(()) skeleton_chain_struct
+{
+ dw_die_ref old_die;
+ dw_die_ref new_die;
+ struct skeleton_chain_struct *parent;
+}
+skeleton_chain_node;
+
/* How to start an assembler comment. */
#ifndef ASM_COMMENT_START
#define ASM_COMMENT_START ";#"
#define DWARF_COMPILE_UNIT_HEADER_SIZE \
(DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 3)
+/* Fixed size portion of the DWARF comdat type unit header. */
+#define DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE \
+ (DWARF_COMPILE_UNIT_HEADER_SIZE + DWARF_TYPE_SIGNATURE_SIZE \
+ + DWARF_OFFSET_SIZE)
+
/* Fixed size portion of public names info. */
#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
/* Record the root of the DIE's built for the current compilation unit. */
static GTY(()) dw_die_ref comp_unit_die;
+/* A list of type DIEs that have been separated into comdat sections. */
+static GTY(()) comdat_type_node *comdat_type_list;
+
/* A list of DIEs with a NULL parent waiting to be relocated. */
static GTY(()) limbo_die_node *limbo_die_list;
HOST_WIDE_INT, unsigned HOST_WIDE_INT);
static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int,
unsigned int, unsigned char *);
+static void add_AT_data8 (dw_die_ref, enum dwarf_attribute, unsigned char *);
static hashval_t debug_str_do_hash (const void *);
static int debug_str_eq (const void *, const void *);
static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *);
static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
static void attr_checksum (dw_attr_ref, struct md5_ctx *, int *);
static void die_checksum (dw_die_ref, struct md5_ctx *, int *);
+static void checksum_sleb128 (HOST_WIDE_INT, struct md5_ctx *);
+static void checksum_uleb128 (unsigned HOST_WIDE_INT, struct md5_ctx *);
+static void loc_checksum_ordered (dw_loc_descr_ref, struct md5_ctx *);
+static void attr_checksum_ordered (enum dwarf_tag, dw_attr_ref,
+ struct md5_ctx *, int *);
+struct checksum_attributes;
+static void collect_checksum_attributes (struct checksum_attributes *, dw_die_ref);
+static void die_checksum_ordered (dw_die_ref, struct md5_ctx *, int *);
+static void checksum_die_context (dw_die_ref, struct md5_ctx *);
+static void generate_type_signature (dw_die_ref, comdat_type_node *);
static int same_loc_p (dw_loc_descr_ref, dw_loc_descr_ref, int *);
static int same_dw_val_p (const dw_val_node *, const dw_val_node *, int *);
static int same_attr_p (dw_attr_ref, dw_attr_ref, int *);
static int is_symbol_die (dw_die_ref);
static void assign_symbol_names (dw_die_ref);
static void break_out_includes (dw_die_ref);
+static int is_declaration_die (dw_die_ref);
+static int should_move_die_to_comdat (dw_die_ref);
+static dw_die_ref clone_as_declaration (dw_die_ref);
+static dw_die_ref clone_die (dw_die_ref);
+static dw_die_ref clone_tree (dw_die_ref);
+static void copy_declaration_context (dw_die_ref, dw_die_ref);
+static void generate_skeleton_ancestor_tree (skeleton_chain_node *);
+static void generate_skeleton_bottom_up (skeleton_chain_node *);
+static dw_die_ref generate_skeleton (dw_die_ref);
+static dw_die_ref remove_child_or_replace_with_skeleton (dw_die_ref,
+ dw_die_ref);
+static void break_out_comdat_types (dw_die_ref);
+static dw_die_ref copy_ancestor_tree (dw_die_ref, dw_die_ref, htab_t);
+static void copy_decls_walk (dw_die_ref, dw_die_ref, htab_t);
+static void copy_decls_for_unworthy_types (dw_die_ref);
+
static hashval_t htab_cu_hash (const void *);
static int htab_cu_eq (const void *, const void *);
static void htab_cu_del (void *);
static void output_die (dw_die_ref);
static void output_compilation_unit_header (void);
static void output_comp_unit (dw_die_ref, int);
+static void output_comdat_type_unit (comdat_type_node *);
static const char *dwarf2_name (tree, int);
static void add_pubname (tree, dw_die_ref);
static void add_pubname_string (const char *, dw_die_ref);
return "DW_TAG_condition";
case DW_TAG_shared_type:
return "DW_TAG_shared_type";
+ case DW_TAG_type_unit:
+ return "DW_TAG_type_unit";
case DW_TAG_GNU_template_parameter_pack:
return "DW_TAG_GNU_template_parameter_pack";
case DW_TAG_GNU_formal_parameter_pack:
case DW_AT_call_line:
return "DW_AT_call_line";
+ case DW_AT_signature:
+ return "DW_AT_signature";
+
case DW_AT_MIPS_fde:
return "DW_AT_MIPS_fde";
case DW_AT_MIPS_loop_begin:
add_dwarf_attr (die, &attr);
}
+/* Add an 8-byte data attribute value to a DIE. */
+
+static inline void
+add_AT_data8 (dw_die_ref die, enum dwarf_attribute attr_kind,
+ unsigned char data8[8])
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_data8;
+ memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
+ add_dwarf_attr (die, &attr);
+}
+
/* Hash and equality functions for debug_str_hash. */
static hashval_t
child->die_parent->die_child = prev;
}
+/* Replace OLD_CHILD with NEW_CHILD. PREV must have the property that
+ PREV->DIE_SIB == OLD_CHILD. Does not alter OLD_CHILD. */
+
+static void
+replace_child (dw_die_ref old_child, dw_die_ref new_child, dw_die_ref prev)
+{
+ dw_die_ref parent = old_child->die_parent;
+
+ gcc_assert (parent == prev->die_parent);
+ gcc_assert (prev->die_sib == old_child);
+
+ new_child->die_parent = parent;
+ if (prev == old_child)
+ {
+ gcc_assert (parent->die_child == old_child);
+ new_child->die_sib = new_child;
+ }
+ else
+ {
+ prev->die_sib = new_child;
+ new_child->die_sib = old_child->die_sib;
+ }
+ if (old_child->die_parent->die_child == old_child)
+ old_child->die_parent->die_child = new_child;
+}
+
+/* Move all children from OLD_PARENT to NEW_PARENT. */
+
+static void
+move_all_children (dw_die_ref old_parent, dw_die_ref new_parent)
+{
+ dw_die_ref c;
+ new_parent->die_child = old_parent->die_child;
+ old_parent->die_child = NULL;
+ FOR_EACH_CHILD (new_parent, c, c->die_parent = new_parent);
+}
+
/* Remove child DIE whose die_tag is TAG. Do nothing if no child
matches TAG. */
fprintf (outfile, "%*s", print_indent, "");
}
+/* Print a type signature in hex. */
+
+static inline void
+print_signature (FILE *outfile, char *sig)
+{
+ int i;
+
+ for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+ fprintf (outfile, "%02x", sig[i] & 0xff);
+}
+
/* Print the information associated with a given DIE, and its children.
This routine is a debugging aid only. */
print_spaces (outfile);
fprintf (outfile, " abbrev id: %lu", die->die_abbrev);
fprintf (outfile, " offset: %ld\n", die->die_offset);
+ if (dwarf_version >= 4 && die->die_id.die_type_node)
+ {
+ print_spaces (outfile);
+ fprintf (outfile, " signature: ");
+ print_signature (outfile, die->die_id.die_type_node->signature);
+ fprintf (outfile, "\n");
+ }
for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
case dw_val_class_die_ref:
if (AT_ref (a) != NULL)
{
- if (AT_ref (a)->die_symbol)
- fprintf (outfile, "die -> label: %s", AT_ref (a)->die_symbol);
+ if (dwarf_version >= 4 && AT_ref (a)->die_id.die_type_node)
+ {
+ fprintf (outfile, "die -> signature: ");
+ print_signature (outfile,
+ AT_ref (a)->die_id.die_type_node->signature);
+ }
+ else if (dwarf_version < 4 && AT_ref (a)->die_id.die_symbol)
+ fprintf (outfile, "die -> label: %s",
+ AT_ref (a)->die_id.die_symbol);
else
fprintf (outfile, "die -> %ld", AT_ref (a)->die_offset);
}
fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename,
AT_file (a)->emitted_number);
break;
+ case dw_val_class_data8:
+ {
+ int i;
+
+ for (i = 0; i < 8; i++)
+ fprintf (outfile, "%02x", a->dw_attr_val.v.val_data8[i]);
+ break;
+ }
default:
break;
}
CHECKSUM_STRING (AT_file (at)->filename);
break;
+ case dw_val_class_data8:
+ CHECKSUM (at->dw_attr_val.v.val_data8);
+ break;
+
default:
break;
}
#undef CHECKSUM
#undef CHECKSUM_STRING
-/* Do the location expressions look same? */
-static inline int
-same_loc_p (dw_loc_descr_ref loc1, dw_loc_descr_ref loc2, int *mark)
+/* For DWARF-4 types, include the trailing NULL when checksumming strings. */
+#define CHECKSUM(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx)
+#define CHECKSUM_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO) + 1, ctx)
+#define CHECKSUM_SLEB128(FOO) checksum_sleb128 ((FOO), ctx)
+#define CHECKSUM_ULEB128(FOO) checksum_uleb128 ((FOO), ctx)
+#define CHECKSUM_ATTR(FOO) \
+ if (FOO) attr_checksum_ordered (die->die_tag, (FOO), ctx, mark)
+
+/* Calculate the checksum of a number in signed LEB128 format. */
+
+static void
+checksum_sleb128 (HOST_WIDE_INT value, struct md5_ctx *ctx)
{
- 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);
+ unsigned char byte;
+ bool more;
+
+ while (1)
+ {
+ byte = (value & 0x7f);
+ value >>= 7;
+ more = !((value == 0 && (byte & 0x40) == 0)
+ || (value == -1 && (byte & 0x40) != 0));
+ if (more)
+ byte |= 0x80;
+ CHECKSUM (byte);
+ if (!more)
+ break;
+ }
}
-/* Do the values look the same? */
-static int
-same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
+/* Calculate the checksum of a number in unsigned LEB128 format. */
+
+static void
+checksum_uleb128 (unsigned HOST_WIDE_INT value, struct md5_ctx *ctx)
{
- dw_loc_descr_ref loc1, loc2;
- rtx r1, r2;
+ while (1)
+ {
+ unsigned char byte = (value & 0x7f);
+ value >>= 7;
+ if (value != 0)
+ /* More bytes to follow. */
+ byte |= 0x80;
+ CHECKSUM (byte);
+ if (value == 0)
+ break;
+ }
+}
- if (v1->val_class != v2->val_class)
- return 0;
+/* Checksum the context of the DIE. This adds the names of any
+ surrounding namespaces or structures to the checksum. */
- switch (v1->val_class)
+static void
+checksum_die_context (dw_die_ref die, struct md5_ctx *ctx)
+{
+ const char *name;
+ dw_die_ref spec;
+ int tag = die->die_tag;
+
+ if (tag != DW_TAG_namespace
+ && tag != DW_TAG_structure_type
+ && tag != DW_TAG_class_type)
+ return;
+
+ name = get_AT_string (die, DW_AT_name);
+
+ spec = get_AT_ref (die, DW_AT_specification);
+ if (spec != NULL)
+ die = spec;
+
+ if (die->die_parent != NULL)
+ checksum_die_context (die->die_parent, ctx);
+
+ CHECKSUM_ULEB128 ('C');
+ CHECKSUM_ULEB128 (tag);
+ if (name != NULL)
+ CHECKSUM_STRING (name);
+}
+
+/* Calculate the checksum of a location expression. */
+
+static inline void
+loc_checksum_ordered (dw_loc_descr_ref loc, struct md5_ctx *ctx)
+{
+ /* Special case for lone DW_OP_plus_uconst: checksum as if the location
+ were emitted as a DW_FORM_sdata instead of a location expression. */
+ if (loc->dw_loc_opc == DW_OP_plus_uconst && loc->dw_loc_next == NULL)
+ {
+ CHECKSUM_ULEB128 (DW_FORM_sdata);
+ CHECKSUM_SLEB128 ((HOST_WIDE_INT) loc->dw_loc_oprnd1.v.val_unsigned);
+ return;
+ }
+
+ /* Otherwise, just checksum the raw location expression. */
+ while (loc != NULL)
+ {
+ CHECKSUM_ULEB128 (loc->dw_loc_opc);
+ CHECKSUM (loc->dw_loc_oprnd1);
+ CHECKSUM (loc->dw_loc_oprnd2);
+ loc = loc->dw_loc_next;
+ }
+}
+
+/* Calculate the checksum of an attribute. */
+
+static void
+attr_checksum_ordered (enum dwarf_tag tag, dw_attr_ref at,
+ struct md5_ctx *ctx, int *mark)
+{
+ dw_loc_descr_ref loc;
+ rtx r;
+
+ if (AT_class (at) == dw_val_class_die_ref)
+ {
+ dw_die_ref target_die = AT_ref (at);
+
+ /* For pointer and reference types, we checksum only the (qualified)
+ name of the target type (if there is a name). For friend entries,
+ we checksum only the (qualified) name of the target type or function.
+ This allows the checksum to remain the same whether the target type
+ is complete or not. */
+ if ((at->dw_attr == DW_AT_type
+ && (tag == DW_TAG_pointer_type
+ || tag == DW_TAG_reference_type
+ || tag == DW_TAG_ptr_to_member_type))
+ || (at->dw_attr == DW_AT_friend
+ && tag == DW_TAG_friend))
+ {
+ dw_attr_ref name_attr = get_AT (target_die, DW_AT_name);
+
+ if (name_attr != NULL)
+ {
+ dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification);
+
+ if (decl == NULL)
+ decl = target_die;
+ CHECKSUM_ULEB128 ('N');
+ CHECKSUM_ULEB128 (at->dw_attr);
+ if (decl->die_parent != NULL)
+ checksum_die_context (decl->die_parent, ctx);
+ CHECKSUM_ULEB128 ('E');
+ CHECKSUM_STRING (AT_string (name_attr));
+ return;
+ }
+ }
+
+ /* For all other references to another DIE, we check to see if the
+ target DIE has already been visited. If it has, we emit a
+ backward reference; if not, we descend recursively. */
+ if (target_die->die_mark > 0)
+ {
+ CHECKSUM_ULEB128 ('R');
+ CHECKSUM_ULEB128 (at->dw_attr);
+ CHECKSUM_ULEB128 (target_die->die_mark);
+ }
+ else
+ {
+ dw_die_ref decl = get_AT_ref (target_die, DW_AT_specification);
+
+ if (decl == NULL)
+ decl = target_die;
+ target_die->die_mark = ++(*mark);
+ CHECKSUM_ULEB128 ('T');
+ CHECKSUM_ULEB128 (at->dw_attr);
+ if (decl->die_parent != NULL)
+ checksum_die_context (decl->die_parent, ctx);
+ die_checksum_ordered (target_die, ctx, mark);
+ }
+ return;
+ }
+
+ CHECKSUM_ULEB128 ('A');
+ CHECKSUM_ULEB128 (at->dw_attr);
+
+ switch (AT_class (at))
{
case dw_val_class_const:
- return v1->v.val_int == v2->v.val_int;
+ CHECKSUM_ULEB128 (DW_FORM_sdata);
+ CHECKSUM_SLEB128 (at->dw_attr_val.v.val_int);
+ break;
+
case dw_val_class_unsigned_const:
- return v1->v.val_unsigned == v2->v.val_unsigned;
+ CHECKSUM_ULEB128 (DW_FORM_sdata);
+ CHECKSUM_SLEB128 ((int) at->dw_attr_val.v.val_unsigned);
+ break;
+
case dw_val_class_const_double:
- return v1->v.val_double.high == v2->v.val_double.high
- && v1->v.val_double.low == v2->v.val_double.low;
+ CHECKSUM_ULEB128 (DW_FORM_block);
+ CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_double));
+ CHECKSUM (at->dw_attr_val.v.val_double);
+ break;
+
case dw_val_class_vec:
- if (v1->v.val_vec.length != v2->v.val_vec.length
- || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
- return 0;
- if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array,
- v1->v.val_vec.length * v1->v.val_vec.elt_size))
- return 0;
- return 1;
+ CHECKSUM_ULEB128 (DW_FORM_block);
+ CHECKSUM_ULEB128 (sizeof (at->dw_attr_val.v.val_vec));
+ CHECKSUM (at->dw_attr_val.v.val_vec);
+ break;
+
case dw_val_class_flag:
- return v1->v.val_flag == v2->v.val_flag;
+ CHECKSUM_ULEB128 (DW_FORM_flag);
+ CHECKSUM_ULEB128 (at->dw_attr_val.v.val_flag ? 1 : 0);
+ break;
+
case dw_val_class_str:
- return !strcmp(v1->v.val_str->str, v2->v.val_str->str);
+ CHECKSUM_ULEB128 (DW_FORM_string);
+ CHECKSUM_STRING (AT_string (at));
+ break;
case dw_val_class_addr:
- r1 = v1->v.val_addr;
- r2 = v2->v.val_addr;
- if (GET_CODE (r1) != GET_CODE (r2))
- return 0;
- return !rtx_equal_p (r1, r2);
+ r = AT_addr (at);
+ gcc_assert (GET_CODE (r) == SYMBOL_REF);
+ CHECKSUM_ULEB128 (DW_FORM_string);
+ CHECKSUM_STRING (XSTR (r, 0));
+ break;
case dw_val_class_offset:
- return v1->v.val_offset == v2->v.val_offset;
+ CHECKSUM_ULEB128 (DW_FORM_sdata);
+ CHECKSUM_ULEB128 (at->dw_attr_val.v.val_offset);
+ break;
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);
+ for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
+ loc_checksum_ordered (loc, ctx);
+ break;
case dw_val_class_fde_ref:
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
- return 1;
+ break;
case dw_val_class_file:
- return v1->v.val_file == v2->v.val_file;
+ CHECKSUM_ULEB128 (DW_FORM_string);
+ CHECKSUM_STRING (AT_file (at)->filename);
+ break;
+
+ case dw_val_class_data8:
+ CHECKSUM (at->dw_attr_val.v.val_data8);
+ break;
default:
- return 1;
+ break;
}
}
-/* Do the attributes look the same? */
-
-static int
-same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
-{
- if (at1->dw_attr != at2->dw_attr)
- return 0;
-
- /* 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);
-}
+struct checksum_attributes
+{
+ dw_attr_ref at_name;
+ dw_attr_ref at_type;
+ dw_attr_ref at_friend;
+ dw_attr_ref at_accessibility;
+ dw_attr_ref at_address_class;
+ dw_attr_ref at_allocated;
+ dw_attr_ref at_artificial;
+ dw_attr_ref at_associated;
+ dw_attr_ref at_binary_scale;
+ dw_attr_ref at_bit_offset;
+ dw_attr_ref at_bit_size;
+ dw_attr_ref at_bit_stride;
+ dw_attr_ref at_byte_size;
+ dw_attr_ref at_byte_stride;
+ dw_attr_ref at_const_value;
+ dw_attr_ref at_containing_type;
+ dw_attr_ref at_count;
+ dw_attr_ref at_data_location;
+ dw_attr_ref at_data_member_location;
+ dw_attr_ref at_decimal_scale;
+ dw_attr_ref at_decimal_sign;
+ dw_attr_ref at_default_value;
+ dw_attr_ref at_digit_count;
+ dw_attr_ref at_discr;
+ dw_attr_ref at_discr_list;
+ dw_attr_ref at_discr_value;
+ dw_attr_ref at_encoding;
+ dw_attr_ref at_endianity;
+ dw_attr_ref at_explicit;
+ dw_attr_ref at_is_optional;
+ dw_attr_ref at_location;
+ dw_attr_ref at_lower_bound;
+ dw_attr_ref at_mutable;
+ dw_attr_ref at_ordering;
+ dw_attr_ref at_picture_string;
+ dw_attr_ref at_prototyped;
+ dw_attr_ref at_small;
+ dw_attr_ref at_segment;
+ dw_attr_ref at_string_length;
+ dw_attr_ref at_threads_scaled;
+ dw_attr_ref at_upper_bound;
+ dw_attr_ref at_use_location;
+ dw_attr_ref at_use_UTF8;
+ dw_attr_ref at_variable_parameter;
+ dw_attr_ref at_virtuality;
+ dw_attr_ref at_visibility;
+ dw_attr_ref at_vtable_elem_location;
+};
-/* Do the dies look the same? */
+/* Collect the attributes that we will want to use for the checksum. */
-static int
-same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
+static void
+collect_checksum_attributes (struct checksum_attributes *attrs, dw_die_ref die)
{
- dw_die_ref c1, c2;
- dw_attr_ref a1;
+ dw_attr_ref a;
unsigned ix;
- /* 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;
-
- if (VEC_length (dw_attr_node, die1->die_attr)
- != VEC_length (dw_attr_node, die2->die_attr))
- return 0;
-
- for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++)
- if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark))
- return 0;
-
- c1 = die1->die_child;
- c2 = die2->die_child;
- if (! c1)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
- 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;
+ switch (a->dw_attr)
+ {
+ case DW_AT_name:
+ attrs->at_name = a;
+ break;
+ case DW_AT_type:
+ attrs->at_type = a;
+ break;
+ case DW_AT_friend:
+ attrs->at_friend = a;
+ break;
+ case DW_AT_accessibility:
+ attrs->at_accessibility = a;
+ break;
+ case DW_AT_address_class:
+ attrs->at_address_class = a;
+ break;
+ case DW_AT_allocated:
+ attrs->at_allocated = a;
+ break;
+ case DW_AT_artificial:
+ attrs->at_artificial = a;
+ break;
+ case DW_AT_associated:
+ attrs->at_associated = a;
+ break;
+ case DW_AT_binary_scale:
+ attrs->at_binary_scale = a;
+ break;
+ case DW_AT_bit_offset:
+ attrs->at_bit_offset = a;
+ break;
+ case DW_AT_bit_size:
+ attrs->at_bit_size = a;
+ break;
+ case DW_AT_bit_stride:
+ attrs->at_bit_stride = a;
+ break;
+ case DW_AT_byte_size:
+ attrs->at_byte_size = a;
+ break;
+ case DW_AT_byte_stride:
+ attrs->at_byte_stride = a;
+ break;
+ case DW_AT_const_value:
+ attrs->at_const_value = a;
+ break;
+ case DW_AT_containing_type:
+ attrs->at_containing_type = a;
+ break;
+ case DW_AT_count:
+ attrs->at_count = a;
+ break;
+ case DW_AT_data_location:
+ attrs->at_data_location = a;
+ break;
+ case DW_AT_data_member_location:
+ attrs->at_data_member_location = a;
+ break;
+ case DW_AT_decimal_scale:
+ attrs->at_decimal_scale = a;
+ break;
+ case DW_AT_decimal_sign:
+ attrs->at_decimal_sign = a;
+ break;
+ case DW_AT_default_value:
+ attrs->at_default_value = a;
+ break;
+ case DW_AT_digit_count:
+ attrs->at_digit_count = a;
+ break;
+ case DW_AT_discr:
+ attrs->at_discr = a;
+ break;
+ case DW_AT_discr_list:
+ attrs->at_discr_list = a;
+ break;
+ case DW_AT_discr_value:
+ attrs->at_discr_value = a;
+ break;
+ case DW_AT_encoding:
+ attrs->at_encoding = a;
+ break;
+ case DW_AT_endianity:
+ attrs->at_endianity = a;
+ break;
+ case DW_AT_explicit:
+ attrs->at_explicit = a;
+ break;
+ case DW_AT_is_optional:
+ attrs->at_is_optional = a;
+ break;
+ case DW_AT_location:
+ attrs->at_location = a;
+ break;
+ case DW_AT_lower_bound:
+ attrs->at_lower_bound = a;
+ break;
+ case DW_AT_mutable:
+ attrs->at_mutable = a;
+ break;
+ case DW_AT_ordering:
+ attrs->at_ordering = a;
+ break;
+ case DW_AT_picture_string:
+ attrs->at_picture_string = a;
+ break;
+ case DW_AT_prototyped:
+ attrs->at_prototyped = a;
+ break;
+ case DW_AT_small:
+ attrs->at_small = a;
+ break;
+ case DW_AT_segment:
+ attrs->at_segment = a;
+ break;
+ case DW_AT_string_length:
+ attrs->at_string_length = a;
+ break;
+ case DW_AT_threads_scaled:
+ attrs->at_threads_scaled = a;
+ break;
+ case DW_AT_upper_bound:
+ attrs->at_upper_bound = a;
+ break;
+ case DW_AT_use_location:
+ attrs->at_use_location = a;
+ break;
+ case DW_AT_use_UTF8:
+ attrs->at_use_UTF8 = a;
+ break;
+ case DW_AT_variable_parameter:
+ attrs->at_variable_parameter = a;
+ break;
+ case DW_AT_virtuality:
+ attrs->at_virtuality = a;
+ break;
+ case DW_AT_visibility:
+ attrs->at_visibility = a;
+ break;
+ case DW_AT_vtable_elem_location:
+ attrs->at_vtable_elem_location = a;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/* Calculate the checksum of a DIE, using an ordered subset of attributes. */
+
+static void
+die_checksum_ordered (dw_die_ref die, struct md5_ctx *ctx, int *mark)
+{
+ dw_die_ref c;
+ dw_die_ref decl;
+ struct checksum_attributes attrs;
+
+ CHECKSUM_ULEB128 ('D');
+ CHECKSUM_ULEB128 (die->die_tag);
+
+ memset (&attrs, 0, sizeof (attrs));
+
+ decl = get_AT_ref (die, DW_AT_specification);
+ if (decl != NULL)
+ collect_checksum_attributes (&attrs, decl);
+ collect_checksum_attributes (&attrs, die);
+
+ CHECKSUM_ATTR (attrs.at_name);
+ CHECKSUM_ATTR (attrs.at_accessibility);
+ CHECKSUM_ATTR (attrs.at_address_class);
+ CHECKSUM_ATTR (attrs.at_allocated);
+ CHECKSUM_ATTR (attrs.at_artificial);
+ CHECKSUM_ATTR (attrs.at_associated);
+ CHECKSUM_ATTR (attrs.at_binary_scale);
+ CHECKSUM_ATTR (attrs.at_bit_offset);
+ CHECKSUM_ATTR (attrs.at_bit_size);
+ CHECKSUM_ATTR (attrs.at_bit_stride);
+ CHECKSUM_ATTR (attrs.at_byte_size);
+ CHECKSUM_ATTR (attrs.at_byte_stride);
+ CHECKSUM_ATTR (attrs.at_const_value);
+ CHECKSUM_ATTR (attrs.at_containing_type);
+ CHECKSUM_ATTR (attrs.at_count);
+ CHECKSUM_ATTR (attrs.at_data_location);
+ CHECKSUM_ATTR (attrs.at_data_member_location);
+ CHECKSUM_ATTR (attrs.at_decimal_scale);
+ CHECKSUM_ATTR (attrs.at_decimal_sign);
+ CHECKSUM_ATTR (attrs.at_default_value);
+ CHECKSUM_ATTR (attrs.at_digit_count);
+ CHECKSUM_ATTR (attrs.at_discr);
+ CHECKSUM_ATTR (attrs.at_discr_list);
+ CHECKSUM_ATTR (attrs.at_discr_value);
+ CHECKSUM_ATTR (attrs.at_encoding);
+ CHECKSUM_ATTR (attrs.at_endianity);
+ CHECKSUM_ATTR (attrs.at_explicit);
+ CHECKSUM_ATTR (attrs.at_is_optional);
+ CHECKSUM_ATTR (attrs.at_location);
+ CHECKSUM_ATTR (attrs.at_lower_bound);
+ CHECKSUM_ATTR (attrs.at_mutable);
+ CHECKSUM_ATTR (attrs.at_ordering);
+ CHECKSUM_ATTR (attrs.at_picture_string);
+ CHECKSUM_ATTR (attrs.at_prototyped);
+ CHECKSUM_ATTR (attrs.at_small);
+ CHECKSUM_ATTR (attrs.at_segment);
+ CHECKSUM_ATTR (attrs.at_string_length);
+ CHECKSUM_ATTR (attrs.at_threads_scaled);
+ CHECKSUM_ATTR (attrs.at_upper_bound);
+ CHECKSUM_ATTR (attrs.at_use_location);
+ CHECKSUM_ATTR (attrs.at_use_UTF8);
+ CHECKSUM_ATTR (attrs.at_variable_parameter);
+ CHECKSUM_ATTR (attrs.at_virtuality);
+ CHECKSUM_ATTR (attrs.at_visibility);
+ CHECKSUM_ATTR (attrs.at_vtable_elem_location);
+ CHECKSUM_ATTR (attrs.at_type);
+ CHECKSUM_ATTR (attrs.at_friend);
+
+ /* Checksum the child DIEs, except for nested types and member functions. */
+ c = die->die_child;
+ if (c) do {
+ dw_attr_ref name_attr;
+
+ c = c->die_sib;
+ name_attr = get_AT (c, DW_AT_name);
+ if ((is_type_die (c) || c->die_tag == DW_TAG_subprogram)
+ && name_attr != NULL)
+ {
+ CHECKSUM_ULEB128 ('S');
+ CHECKSUM_ULEB128 (c->die_tag);
+ CHECKSUM_STRING (AT_string (name_attr));
+ }
+ else
+ {
+ /* Mark this DIE so it gets processed when unmarking. */
+ if (c->die_mark == 0)
+ c->die_mark = -1;
+ die_checksum_ordered (c, ctx, mark);
+ }
+ } while (c != die->die_child);
+
+ CHECKSUM_ULEB128 (0);
+}
+
+#undef CHECKSUM
+#undef CHECKSUM_STRING
+#undef CHECKSUM_ATTR
+#undef CHECKSUM_LEB128
+#undef CHECKSUM_ULEB128
+
+/* Generate the type signature for DIE. This is computed by generating an
+ MD5 checksum over the DIE's tag, its relevant attributes, and its
+ children. Attributes that are references to other DIEs are processed
+ by recursion, using the MARK field to prevent infinite recursion.
+ If the DIE is nested inside a namespace or another type, we also
+ need to include that context in the signature. The lower 64 bits
+ of the resulting MD5 checksum comprise the signature. */
+
+static void
+generate_type_signature (dw_die_ref die, comdat_type_node *type_node)
+{
+ int mark;
+ const char *name;
+ unsigned char checksum[16];
+ struct md5_ctx ctx;
+ dw_die_ref decl;
+
+ name = get_AT_string (die, DW_AT_name);
+ decl = get_AT_ref (die, DW_AT_specification);
+
+ /* First, compute a signature for just the type name (and its surrounding
+ context, if any. This is stored in the type unit DIE for link-time
+ ODR (one-definition rule) checking. */
+
+ if (is_cxx() && name != NULL)
+ {
+ md5_init_ctx (&ctx);
+
+ /* Checksum the names of surrounding namespaces and structures. */
+ if (decl != NULL && decl->die_parent != NULL)
+ checksum_die_context (decl->die_parent, &ctx);
+
+ md5_process_bytes (&die->die_tag, sizeof (die->die_tag), &ctx);
+ md5_process_bytes (name, strlen (name) + 1, &ctx);
+ md5_finish_ctx (&ctx, checksum);
+
+ add_AT_data8 (type_node->root_die, DW_AT_GNU_odr_signature, &checksum[8]);
+ }
+
+ /* Next, compute the complete type signature. */
+
+ md5_init_ctx (&ctx);
+ mark = 1;
+ die->die_mark = mark;
+
+ /* Checksum the names of surrounding namespaces and structures. */
+ if (decl != NULL && decl->die_parent != NULL)
+ checksum_die_context (decl->die_parent, &ctx);
+
+ /* Checksum the DIE and its children. */
+ die_checksum_ordered (die, &ctx, &mark);
+ unmark_all_dies (die);
+ md5_finish_ctx (&ctx, checksum);
+
+ /* Store the signature in the type node and link the type DIE and the
+ type node together. */
+ memcpy (type_node->signature, &checksum[16 - DWARF_TYPE_SIGNATURE_SIZE],
+ DWARF_TYPE_SIGNATURE_SIZE);
+ die->die_id.die_type_node = type_node;
+ type_node->type_die = die;
+
+ /* If the DIE is a specification, link its declaration to the type node
+ as well. */
+ if (decl != NULL)
+ decl->die_id.die_type_node = type_node;
+}
+
+/* Do the location expressions look same? */
+static inline int
+same_loc_p (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 (const dw_val_node *v1, const dw_val_node *v2, int *mark)
+{
+ dw_loc_descr_ref loc1, loc2;
+ rtx r1, r2;
+
+ 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_const_double:
+ return v1->v.val_double.high == v2->v.val_double.high
+ && v1->v.val_double.low == v2->v.val_double.low;
+ case dw_val_class_vec:
+ if (v1->v.val_vec.length != v2->v.val_vec.length
+ || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
+ return 0;
+ if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array,
+ v1->v.val_vec.length * v1->v.val_vec.elt_size))
+ 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(v1->v.val_str->str, v2->v.val_str->str);
+
+ case dw_val_class_addr:
+ r1 = v1->v.val_addr;
+ r2 = v2->v.val_addr;
+ if (GET_CODE (r1) != GET_CODE (r2))
+ return 0;
+ return !rtx_equal_p (r1, r2);
+
+ 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_lineptr:
+ case dw_val_class_macptr:
+ return 1;
+
+ case dw_val_class_file:
+ return v1->v.val_file == v2->v.val_file;
+
+ case dw_val_class_data8:
+ return !memcmp (v1->v.val_data8, v2->v.val_data8, 8);
+
+ default:
+ return 1;
+ }
+}
+
+/* Do the attributes look the same? */
+
+static int
+same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
+{
+ if (at1->dw_attr != at2->dw_attr)
+ return 0;
+
+ /* 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);
+}
+
+/* Do the dies look the same? */
+
+static int
+same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
+{
+ dw_die_ref c1, c2;
+ dw_attr_ref a1;
+ unsigned ix;
+
+ /* 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;
+
+ if (VEC_length (dw_attr_node, die1->die_attr)
+ != VEC_length (dw_attr_node, die2->die_attr))
+ return 0;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++)
+ if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark))
+ return 0;
+
+ 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;
}
}
p += 2;
}
- comdat_symbol_id = unit_die->die_symbol = xstrdup (name);
+ comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
comdat_symbol_number = 0;
}
{
dw_die_ref t = get_AT_ref (c, DW_AT_type);
- return t ? is_comdat_die (t) : 0;
- }
+ return t ? is_comdat_die (t) : 0;
+ }
+
+ return is_type_die (c);
+}
+
+/* Returns 1 iff C is the sort of DIE that might be referred to from another
+ compilation unit. */
+
+static int
+is_symbol_die (dw_die_ref c)
+{
+ return (is_type_die (c)
+ || is_declaration_die (c)
+ || c->die_tag == DW_TAG_namespace
+ || c->die_tag == DW_TAG_module);
+}
+
+static char *
+gen_internal_sym (const char *prefix)
+{
+ char buf[256];
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++);
+ return xstrdup (buf);
+}
+
+/* Assign symbols to all worthy DIEs under DIE. */
+
+static void
+assign_symbol_names (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ if (is_symbol_die (die))
+ {
+ if (comdat_symbol_id)
+ {
+ char *p = XALLOCAVEC (char, strlen (comdat_symbol_id) + 64);
+
+ sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX,
+ comdat_symbol_id, comdat_symbol_number++);
+ die->die_id.die_symbol = xstrdup (p);
+ }
+ else
+ die->die_id.die_symbol = gen_internal_sym ("LDIE");
+ }
+
+ FOR_EACH_CHILD (die, c, 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 (const void *of)
+{
+ const struct cu_hash_table_entry *const entry =
+ (const struct cu_hash_table_entry *) of;
+
+ return htab_hash_string (entry->cu->die_id.die_symbol);
+}
+
+static int
+htab_cu_eq (const void *of1, const void *of2)
+{
+ const struct cu_hash_table_entry *const entry1 =
+ (const struct cu_hash_table_entry *) of1;
+ const struct die_struct *const entry2 = (const struct die_struct *) of2;
+
+ return !strcmp (entry1->cu->die_id.die_symbol, entry2->die_id.die_symbol);
+}
+
+static void
+htab_cu_del (void *what)
+{
+ struct cu_hash_table_entry *next,
+ *entry = (struct cu_hash_table_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 (dw_die_ref cu, htab_t htable, unsigned int *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_id.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 = XCNEW (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 (dw_die_ref cu, htab_t htable, unsigned int 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_id.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. */
+
+static void
+break_out_includes (dw_die_ref die)
+{
+ dw_die_ref c;
+ dw_die_ref unit = NULL;
+ limbo_die_node *node, **pnode;
+ htab_t cu_hash_table;
+
+ 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
+ to make sure that we leave every include file we enter. */
+ gcc_assert (!unit);
+#endif
+
+ assign_symbol_names (die);
+ 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);
+}
+
+/* Return non-zero if this DIE is a declaration. */
+
+static int
+is_declaration_die (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 (a->dw_attr == DW_AT_declaration)
+ return 1;
+
+ return 0;
+}
+
+/* Return non-zero if this is a type DIE that should be moved to a
+ COMDAT .debug_types section. */
+
+static int
+should_move_die_to_comdat (dw_die_ref die)
+{
+ switch (die->die_tag)
+ {
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_union_type:
+ /* Don't move declarations or inlined instances. */
+ if (is_declaration_die (die) || get_AT (die, DW_AT_abstract_origin))
+ return 0;
+ return 1;
+ case DW_TAG_array_type:
+ case DW_TAG_interface_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_string_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_set_type:
+ case DW_TAG_subrange_type:
+ case DW_TAG_base_type:
+ case DW_TAG_const_type:
+ case DW_TAG_file_type:
+ case DW_TAG_packed_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_typedef:
+ default:
+ return 0;
+ }
+}
+
+/* Make a clone of DIE. */
+
+static dw_die_ref
+clone_die (dw_die_ref die)
+{
+ dw_die_ref clone;
+ dw_attr_ref a;
+ unsigned ix;
+
+ clone = GGC_CNEW (die_node);
+ clone->die_tag = die->die_tag;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ add_dwarf_attr (clone, a);
+
+ return clone;
+}
+
+/* Make a clone of the tree rooted at DIE. */
+
+static dw_die_ref
+clone_tree (dw_die_ref die)
+{
+ dw_die_ref c;
+ dw_die_ref clone = clone_die (die);
+
+ FOR_EACH_CHILD (die, c, add_child_die (clone, clone_tree(c)));
+
+ return clone;
+}
+
+/* Make a clone of DIE as a declaration. */
+
+static dw_die_ref
+clone_as_declaration (dw_die_ref die)
+{
+ dw_die_ref clone;
+ dw_die_ref decl;
+ dw_attr_ref a;
+ unsigned ix;
+
+ /* If the DIE is already a declaration, just clone it. */
+ if (is_declaration_die (die))
+ return clone_die (die);
+
+ /* If the DIE is a specification, just clone its declaration DIE. */
+ decl = get_AT_ref (die, DW_AT_specification);
+ if (decl != NULL)
+ return clone_die (decl);
+
+ clone = GGC_CNEW (die_node);
+ clone->die_tag = die->die_tag;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ {
+ /* We don't want to copy over all attributes.
+ For example we don't want DW_AT_byte_size because otherwise we will no
+ longer have a declaration and GDB will treat it as a definition. */
+
+ switch (a->dw_attr)
+ {
+ case DW_AT_artificial:
+ case DW_AT_containing_type:
+ case DW_AT_external:
+ case DW_AT_name:
+ case DW_AT_type:
+ case DW_AT_virtuality:
+ case DW_AT_MIPS_linkage_name:
+ add_dwarf_attr (clone, a);
+ break;
+ case DW_AT_byte_size:
+ default:
+ break;
+ }
+ }
+
+ if (die->die_id.die_type_node)
+ add_AT_die_ref (clone, DW_AT_signature, die);
+
+ add_AT_flag (clone, DW_AT_declaration, 1);
+ return clone;
+}
+
+/* Copy the declaration context to the new compile unit DIE. This includes
+ any surrounding namespace or type declarations. If the DIE has an
+ AT_specification attribute, it also includes attributes and children
+ attached to the specification. */
+
+static void
+copy_declaration_context (dw_die_ref unit, dw_die_ref die)
+{
+ dw_die_ref decl;
+ dw_die_ref new_decl;
+
+ decl = get_AT_ref (die, DW_AT_specification);
+ if (decl == NULL)
+ decl = die;
+ else
+ {
+ unsigned ix;
+ dw_die_ref c;
+ dw_attr_ref a;
+
+ /* Copy the type node pointer from the new DIE to the original
+ declaration DIE so we can forward references later. */
+ decl->die_id.die_type_node = die->die_id.die_type_node;
+
+ remove_AT (die, DW_AT_specification);
+
+ for (ix = 0; VEC_iterate (dw_attr_node, decl->die_attr, ix, a); ix++)
+ {
+ if (a->dw_attr != DW_AT_name
+ && a->dw_attr != DW_AT_declaration
+ && a->dw_attr != DW_AT_external)
+ add_dwarf_attr (die, a);
+ }
+
+ FOR_EACH_CHILD (decl, c, add_child_die (die, clone_tree(c)));
+ }
+
+ if (decl->die_parent != NULL
+ && decl->die_parent->die_tag != DW_TAG_compile_unit
+ && decl->die_parent->die_tag != DW_TAG_type_unit)
+ {
+ new_decl = copy_ancestor_tree (unit, decl, NULL);
+ if (new_decl != NULL)
+ {
+ remove_AT (new_decl, DW_AT_signature);
+ add_AT_specification (die, new_decl);
+ }
+ }
+}
+
+/* Generate the skeleton ancestor tree for the given NODE, then clone
+ the DIE and add the clone into the tree. */
+
+static void
+generate_skeleton_ancestor_tree (skeleton_chain_node *node)
+{
+ if (node->new_die != NULL)
+ return;
+
+ node->new_die = clone_as_declaration (node->old_die);
+
+ if (node->parent != NULL)
+ {
+ generate_skeleton_ancestor_tree (node->parent);
+ add_child_die (node->parent->new_die, node->new_die);
+ }
+}
+
+/* Generate a skeleton tree of DIEs containing any declarations that are
+ found in the original tree. We traverse the tree looking for declaration
+ DIEs, and construct the skeleton from the bottom up whenever we find one. */
+
+static void
+generate_skeleton_bottom_up (skeleton_chain_node *parent)
+{
+ skeleton_chain_node node;
+ dw_die_ref c;
+ dw_die_ref first;
+ dw_die_ref prev = NULL;
+ dw_die_ref next = NULL;
+
+ node.parent = parent;
- return is_type_die (c);
+ first = c = parent->old_die->die_child;
+ if (c)
+ next = c->die_sib;
+ if (c) do {
+ if (prev == NULL || prev->die_sib == c)
+ prev = c;
+ c = next;
+ next = (c == first ? NULL : c->die_sib);
+ node.old_die = c;
+ node.new_die = NULL;
+ if (is_declaration_die (c))
+ {
+ /* Clone the existing DIE, move the original to the skeleton
+ tree (which is in the main CU), and put the clone, with
+ all the original's children, where the original came from. */
+ dw_die_ref clone = clone_die (c);
+ move_all_children (c, clone);
+
+ replace_child (c, clone, prev);
+ generate_skeleton_ancestor_tree (parent);
+ add_child_die (parent->new_die, c);
+ node.new_die = c;
+ c = clone;
+ }
+ generate_skeleton_bottom_up (&node);
+ } while (next != NULL);
}
-/* Returns 1 iff C is the sort of DIE that might be referred to from another
- compilation unit. */
+/* Wrapper function for generate_skeleton_bottom_up. */
-static int
-is_symbol_die (dw_die_ref c)
+static dw_die_ref
+generate_skeleton (dw_die_ref die)
{
- return (is_type_die (c)
- || (get_AT (c, DW_AT_declaration)
- && !get_AT (c, DW_AT_specification))
- || c->die_tag == DW_TAG_namespace
- || c->die_tag == DW_TAG_module);
+ skeleton_chain_node node;
+
+ node.old_die = die;
+ node.new_die = NULL;
+ node.parent = NULL;
+
+ /* If this type definition is nested inside another type,
+ always leave at least a declaration in its place. */
+ if (die->die_parent != NULL && is_type_die (die->die_parent))
+ node.new_die = clone_as_declaration (die);
+
+ generate_skeleton_bottom_up (&node);
+ return node.new_die;
}
-static char *
-gen_internal_sym (const char *prefix)
+/* Remove the DIE from its parent, possibly replacing it with a cloned
+ declaration. The original DIE will be moved to a new compile unit
+ so that existing references to it follow it to the new location. If
+ any of the original DIE's descendants is a declaration, we need to
+ replace the original DIE with a skeleton tree and move the
+ declarations back into the skeleton tree. */
+
+static dw_die_ref
+remove_child_or_replace_with_skeleton (dw_die_ref child, dw_die_ref prev)
{
- char buf[256];
+ dw_die_ref skeleton;
- ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++);
- return xstrdup (buf);
+ skeleton = generate_skeleton (child);
+ if (skeleton == NULL)
+ remove_child_with_prev (child, prev);
+ else
+ {
+ skeleton->die_id.die_type_node = child->die_id.die_type_node;
+ replace_child (child, skeleton, prev);
+ }
+
+ return skeleton;
}
-/* Assign symbols to all worthy DIEs under DIE. */
+/* Traverse the DIE and set up additional .debug_types sections for each
+ type worthy of being placed in a COMDAT section. */
static void
-assign_symbol_names (dw_die_ref die)
+break_out_comdat_types (dw_die_ref die)
{
dw_die_ref c;
+ dw_die_ref first;
+ dw_die_ref prev = NULL;
+ dw_die_ref next = NULL;
+ dw_die_ref unit = NULL;
- if (is_symbol_die (die))
- {
- if (comdat_symbol_id)
- {
- char *p = XALLOCAVEC (char, strlen (comdat_symbol_id) + 64);
+ first = c = die->die_child;
+ if (c)
+ next = c->die_sib;
+ if (c) do {
+ if (prev == NULL || prev->die_sib == c)
+ prev = c;
+ c = next;
+ next = (c == first ? NULL : c->die_sib);
+ if (should_move_die_to_comdat (c))
+ {
+ dw_die_ref replacement;
+ comdat_type_node_ref type_node;
- sprintf (p, "%s.%s.%x", DIE_LABEL_PREFIX,
- comdat_symbol_id, comdat_symbol_number++);
- die->die_symbol = xstrdup (p);
- }
- else
- die->die_symbol = gen_internal_sym ("LDIE");
- }
+ /* Create a new type unit DIE as the root for the new tree, and
+ add it to the list of comdat types. */
+ unit = new_die (DW_TAG_type_unit, NULL, NULL);
+ add_AT_unsigned (unit, DW_AT_language,
+ get_AT_unsigned (comp_unit_die, DW_AT_language));
+ type_node = GGC_CNEW (comdat_type_node);
+ type_node->root_die = unit;
+ type_node->next = comdat_type_list;
+ comdat_type_list = type_node;
- FOR_EACH_CHILD (die, c, assign_symbol_names (c));
+ /* Generate the type signature. */
+ generate_type_signature (c, type_node);
+
+ /* Copy the declaration context, attributes, and children of the
+ declaration into the new compile unit DIE. */
+ copy_declaration_context (unit, c);
+
+ /* Remove this DIE from the main CU. */
+ replacement = remove_child_or_replace_with_skeleton (c, prev);
+
+ /* Break out nested types into their own type units. */
+ break_out_comdat_types (c);
+
+ /* Add the DIE to the new compunit. */
+ add_child_die (unit, c);
+
+ if (replacement != NULL)
+ c = replacement;
+ }
+ else if (c->die_tag == DW_TAG_namespace
+ || c->die_tag == DW_TAG_class_type
+ || c->die_tag == DW_TAG_structure_type
+ || c->die_tag == DW_TAG_union_type)
+ {
+ /* Look for nested types that can be broken out. */
+ break_out_comdat_types (c);
+ }
+ } while (next != NULL);
}
-struct cu_hash_table_entry
+/* Structure to map a DIE in one CU to its copy in a comdat type unit. */
+
+struct decl_table_entry
{
- dw_die_ref cu;
- unsigned min_comdat_num, max_comdat_num;
- struct cu_hash_table_entry *next;
+ dw_die_ref orig;
+ dw_die_ref copy;
};
-/* Routines to manipulate hash table of CUs. */
+/* Routines to manipulate hash table of copied declarations. */
+
static hashval_t
-htab_cu_hash (const void *of)
+htab_decl_hash (const void *of)
{
- const struct cu_hash_table_entry *const entry =
- (const struct cu_hash_table_entry *) of;
+ const struct decl_table_entry *const entry =
+ (const struct decl_table_entry *) of;
- return htab_hash_string (entry->cu->die_symbol);
+ return htab_hash_pointer (entry->orig);
}
static int
-htab_cu_eq (const void *of1, const void *of2)
+htab_decl_eq (const void *of1, const void *of2)
{
- const struct cu_hash_table_entry *const entry1 =
- (const struct cu_hash_table_entry *) of1;
+ const struct decl_table_entry *const entry1 =
+ (const struct decl_table_entry *) of1;
const struct die_struct *const entry2 = (const struct die_struct *) of2;
- return !strcmp (entry1->cu->die_symbol, entry2->die_symbol);
+ return entry1->orig == entry2;
}
static void
-htab_cu_del (void *what)
+htab_decl_del (void *what)
{
- struct cu_hash_table_entry *next,
- *entry = (struct cu_hash_table_entry *) what;
+ struct decl_table_entry *entry = (struct decl_table_entry *) what;
- while (entry)
- {
- next = entry->next;
- free (entry);
- entry = next;
- }
+ free (entry);
}
-/* Check whether we have already seen this CU and set up SYM_NUM
- accordingly. */
-static int
-check_duplicate_cu (dw_die_ref cu, htab_t htable, unsigned int *sym_num)
-{
- struct cu_hash_table_entry dummy;
- struct cu_hash_table_entry **slot, *entry, *last = &dummy;
-
- dummy.max_comdat_num = 0;
+/* Copy DIE and its ancestors, up to, but not including, the compile unit
+ or type unit entry, to a new tree. Adds the new tree to UNIT and returns
+ a pointer to the copy of DIE. If DECL_TABLE is provided, it is used
+ to check if the ancestor has already been copied into UNIT. */
- slot = (struct cu_hash_table_entry **)
- htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol),
- INSERT);
- entry = *slot;
+static dw_die_ref
+copy_ancestor_tree (dw_die_ref unit, dw_die_ref die, htab_t decl_table)
+{
+ dw_die_ref parent = die->die_parent;
+ dw_die_ref new_parent = unit;
+ dw_die_ref copy;
+ void **slot = NULL;
+ struct decl_table_entry *entry = NULL;
- for (; entry; last = entry, entry = entry->next)
+ if (decl_table)
{
- if (same_die_p_wrap (cu, entry->cu))
- break;
+ /* Check if the entry has already been copied to UNIT. */
+ slot = htab_find_slot_with_hash (decl_table, die,
+ htab_hash_pointer (die), INSERT);
+ if (*slot != HTAB_EMPTY_ENTRY)
+ {
+ entry = (struct decl_table_entry *) *slot;
+ return entry->copy;
+ }
+
+ /* Record in DECL_TABLE that DIE has been copied to UNIT. */
+ entry = XCNEW (struct decl_table_entry);
+ entry->orig = die;
+ entry->copy = NULL;
+ *slot = entry;
}
- if (entry)
+ if (parent != NULL)
{
- *sym_num = entry->min_comdat_num;
- return 1;
+ dw_die_ref spec = get_AT_ref (parent, DW_AT_specification);
+ if (spec != NULL)
+ parent = spec;
+ if (parent->die_tag != DW_TAG_compile_unit
+ && parent->die_tag != DW_TAG_type_unit)
+ new_parent = copy_ancestor_tree (unit, parent, decl_table);
}
- entry = XCNEW (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 (dw_die_ref cu, htab_t htable, unsigned int sym_num)
-{
- struct cu_hash_table_entry **slot, *entry;
+ copy = clone_as_declaration (die);
+ add_child_die (new_parent, copy);
- slot = (struct cu_hash_table_entry **)
- htab_find_slot_with_hash (htable, cu, htab_hash_string (cu->die_symbol),
- NO_INSERT);
- entry = *slot;
+ if (decl_table != NULL)
+ {
+ /* Make sure the copy is marked as part of the type unit. */
+ copy->die_mark = 1;
+ /* Record the pointer to the copy. */
+ entry->copy = copy;
+ }
- entry->max_comdat_num = sym_num;
+ return copy;
}
-/* 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. */
+/* Walk the DIE and its children, looking for references to incomplete
+ or trivial types that are unmarked (i.e., that are not in the current
+ type_unit). */
static void
-break_out_includes (dw_die_ref die)
+copy_decls_walk (dw_die_ref unit, dw_die_ref die, htab_t decl_table)
{
dw_die_ref c;
- dw_die_ref unit = NULL;
- limbo_die_node *node, **pnode;
- htab_t cu_hash_table;
+ dw_attr_ref a;
+ unsigned ix;
- 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;
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ {
+ if (AT_class (a) == dw_val_class_die_ref)
+ {
+ dw_die_ref targ = AT_ref (a);
+ comdat_type_node_ref type_node = targ->die_id.die_type_node;
+ void **slot;
+ struct decl_table_entry *entry;
- /* This DIE is for a secondary CU; remove it from the main one. */
- remove_child_with_prev (c, prev);
+ if (targ->die_mark != 0 || type_node != NULL)
+ continue;
- if (c->die_tag == DW_TAG_GNU_BINCL)
- unit = push_new_compile_unit (unit, c);
- else if (c->die_tag == DW_TAG_GNU_EINCL)
- unit = pop_compile_unit (unit);
- else
- add_child_die (unit, c);
- c = next;
- if (c == die->die_child)
- break;
- }
- } while (c != die->die_child);
+ slot = htab_find_slot_with_hash (decl_table, targ,
+ htab_hash_pointer (targ), INSERT);
-#if 0
- /* We can only use this in debugging, since the frontend doesn't check
- to make sure that we leave every include file we enter. */
- gcc_assert (!unit);
-#endif
+ if (*slot != HTAB_EMPTY_ENTRY)
+ {
+ /* TARG has already been copied, so we just need to
+ modify the reference to point to the copy. */
+ entry = (struct decl_table_entry *) *slot;
+ a->dw_attr_val.v.val_die_ref.die = entry->copy;
+ }
+ else
+ {
+ dw_die_ref parent = unit;
+ dw_die_ref copy = clone_tree (targ);
+
+ /* Make sure the cloned tree is marked as part of the
+ type unit. */
+ mark_dies (copy);
+
+ /* Record in DECL_TABLE that TARG has been copied.
+ Need to do this now, before the recursive call,
+ because DECL_TABLE may be expanded and SLOT
+ would no longer be a valid pointer. */
+ entry = XCNEW (struct decl_table_entry);
+ entry->orig = targ;
+ entry->copy = copy;
+ *slot = entry;
+
+ /* If TARG has surrounding context, copy its ancestor tree
+ into the new type unit. */
+ if (targ->die_parent != NULL
+ && targ->die_parent->die_tag != DW_TAG_compile_unit
+ && targ->die_parent->die_tag != DW_TAG_type_unit)
+ parent = copy_ancestor_tree (unit, targ->die_parent,
+ decl_table);
+
+ add_child_die (parent, copy);
+ a->dw_attr_val.v.val_die_ref.die = copy;
+
+ /* Make sure the newly-copied DIE is walked. If it was
+ installed in a previously-added context, it won't
+ get visited otherwise. */
+ if (parent != unit)
+ copy_decls_walk (unit, parent, decl_table);
+ }
+ }
+ }
- assign_symbol_names (die);
- 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;
+ FOR_EACH_CHILD (die, c, copy_decls_walk (unit, c, decl_table));
+}
- 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);
+/* Copy declarations for "unworthy" types into the new comdat section.
+ Incomplete types, modified types, and certain other types aren't broken
+ out into comdat sections of their own, so they don't have a signature,
+ and we need to copy the declaration into the same section so that we
+ don't have an external reference. */
+
+static void
+copy_decls_for_unworthy_types (dw_die_ref unit)
+{
+ htab_t decl_table;
+
+ mark_dies (unit);
+ decl_table = htab_create (10, htab_decl_hash, htab_decl_eq, htab_decl_del);
+ copy_decls_walk (unit, unit, decl_table);
+ htab_delete (decl_table);
+ unmark_dies (unit);
}
/* Traverse the DIE and add a sibling attribute if it may have the
if (AT_class (a) == dw_val_class_die_ref
&& AT_ref (a)->die_mark == 0)
{
- gcc_assert (AT_ref (a)->die_symbol);
+ gcc_assert (dwarf_version >= 4 || AT_ref (a)->die_id.die_symbol);
set_AT_ref_external (a, 1);
}
size += 1;
break;
case dw_val_class_die_ref:
- /* In DWARF2, DW_FORM_ref_addr is sized by target address length,
- whereas in DWARF3 it's always sized as an offset. */
- if (AT_ref_external (a) && dwarf_version == 2)
- size += DWARF2_ADDR_SIZE;
+ if (AT_ref_external (a))
+ {
+ /* In DWARF4, we use DW_FORM_sig8; for earlier versions
+ we use DW_FORM_ref_addr. In DWARF2, DW_FORM_ref_addr
+ is sized by target address length, whereas in DWARF3
+ it's always sized as an offset. */
+ if (dwarf_version >= 4)
+ size += DWARF_TYPE_SIGNATURE_SIZE;
+ else if (dwarf_version == 2)
+ size += DWARF2_ADDR_SIZE;
+ else
+ size += DWARF_OFFSET_SIZE;
+ }
else
size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_file:
size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file));
break;
+ case dw_val_class_data8:
+ size += 8;
+ break;
default:
gcc_unreachable ();
}
{
dw_die_ref c;
- gcc_assert (die->die_mark);
+ if (dwarf_version < 4)
+ gcc_assert (die->die_mark);
die->die_mark = 0;
FOR_EACH_CHILD (die, c, unmark_dies (c));
return DW_FORM_flag;
case dw_val_class_die_ref:
if (AT_ref_external (a))
- return DW_FORM_ref_addr;
+ return dwarf_version >= 4 ? DW_FORM_sig8 : DW_FORM_ref_addr;
else
return DW_FORM_ref;
case dw_val_class_fde_ref:
gcc_unreachable ();
}
+ case dw_val_class_data8:
+ return DW_FORM_data8;
+
default:
gcc_unreachable ();
}
static inline void
output_die_symbol (dw_die_ref die)
{
- char *sym = die->die_symbol;
+ char *sym = die->die_id.die_symbol;
if (sym == 0)
return;
list_head->ll_symbol);
}
+/* Output a type signature. */
+
+static inline void
+output_signature (const char *sig, const char *name)
+{
+ int i;
+
+ for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+ dw2_asm_output_data (1, sig[i], "%s", name);
+}
+
/* Output the DIE and its attributes. Called recursively to generate
the definitions of each child DIE. */
/* If someone in another CU might refer to us, set up a symbol for
them to point to. */
- if (die->die_symbol)
+ if (dwarf_version < 4 && die->die_id.die_symbol)
output_die_symbol (die);
dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)",
case dw_val_class_die_ref:
if (AT_ref_external (a))
{
- char *sym = AT_ref (a)->die_symbol;
- int size;
-
- gcc_assert (sym);
+ if (dwarf_version >= 4)
+ {
+ comdat_type_node_ref type_node =
+ AT_ref (a)->die_id.die_type_node;
- /* In DWARF2, DW_FORM_ref_addr is sized by target address
- length, whereas in DWARF3 it's always sized as an offset. */
- if (dwarf_version == 2)
- size = DWARF2_ADDR_SIZE;
+ gcc_assert (type_node);
+ output_signature (type_node->signature, name);
+ }
else
- size = DWARF_OFFSET_SIZE;
- dw2_asm_output_offset (size, sym, debug_info_section, "%s", name);
+ {
+ char *sym = AT_ref (a)->die_id.die_symbol;
+ int size;
+
+ gcc_assert (sym);
+ /* In DWARF2, DW_FORM_ref_addr is sized by target address
+ length, whereas in DWARF3 it's always sized as an
+ offset. */
+ if (dwarf_version == 2)
+ size = DWARF2_ADDR_SIZE;
+ else
+ size = DWARF_OFFSET_SIZE;
+ dw2_asm_output_offset (size, sym, debug_info_section, "%s",
+ name);
+ }
}
else
{
break;
}
+ case dw_val_class_data8:
+ {
+ int i;
+
+ for (i = 0; i < 8; i++)
+ dw2_asm_output_data (1, a->dw_attr_val.v.val_data8[i],
+ "%s", name);
+ break;
+ }
+
default:
gcc_unreachable ();
}
static void
output_compilation_unit_header (void)
{
+ int ver = dwarf_version;
+
+ /* Don't mark the output as DWARF-4 until we make full use of the
+ version 4 extensions, and gdb supports them. For now, -gdwarf-4
+ selects only a few extensions from the DWARF-4 spec. */
+ if (ver > 3)
+ ver = 3;
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,
next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
"Length of Compilation Unit Info");
- dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+ dw2_asm_output_data (2, ver, "DWARF version number");
dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
debug_abbrev_section,
"Offset Into Abbrev. Section");
next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
calc_die_sizes (die);
- oldsym = die->die_symbol;
+ oldsym = die->die_id.die_symbol;
if (oldsym)
{
tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym);
secname = tmp;
- die->die_symbol = NULL;
+ die->die_id.die_symbol = NULL;
switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
}
else
if (oldsym)
{
unmark_dies (die);
- die->die_symbol = oldsym;
+ die->die_id.die_symbol = oldsym;
}
}
+/* Output a comdat type unit DIE and its children. */
+
+static void
+output_comdat_type_unit (comdat_type_node *node)
+{
+ const char *secname;
+ char *tmp;
+ int i;
+#if defined (OBJECT_FORMAT_ELF)
+ tree comdat_key;
+#endif
+
+ /* First mark all the DIEs in this CU so we know which get local refs. */
+ mark_dies (node->root_die);
+
+ build_abbrev_table (node->root_die);
+
+ /* Initialize the beginning DIE offset - and calculate sizes/offsets. */
+ next_die_offset = DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE;
+ calc_die_sizes (node->root_die);
+
+#if defined (OBJECT_FORMAT_ELF)
+ secname = ".debug_types";
+ tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
+ sprintf (tmp, "wt.");
+ for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+ sprintf (tmp + 3 + i * 2, "%02x", node->signature[i] & 0xff);
+ comdat_key = get_identifier (tmp);
+ targetm.asm_out.named_section (secname,
+ SECTION_DEBUG | SECTION_LINKONCE,
+ comdat_key);
+#else
+ tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
+ sprintf (tmp, ".gnu.linkonce.wt.");
+ for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
+ sprintf (tmp + 17 + i * 2, "%02x", node->signature[i] & 0xff);
+ secname = tmp;
+ switch_to_section (get_section (secname, SECTION_DEBUG, NULL));
+#endif
+
+ /* Output debugging information. */
+ output_compilation_unit_header ();
+ output_signature (node->signature, "Type Signature");
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, node->type_die->die_offset,
+ "Offset to Type DIE");
+ output_die (node->root_die);
+
+ unmark_dies (node->root_die);
+}
+
/* Return the DWARF2/3 pubname associated with a decl. */
static const char *
long line_delta;
unsigned long current_file;
unsigned long function;
+ int ver = dwarf_version;
+
+ /* Don't mark the output as DWARF-4 until we make full use of the
+ version 4 extensions, and gdb supports them. For now, -gdwarf-4
+ selects only a few extensions from the DWARF-4 spec. */
+ if (ver > 3)
+ ver = 3;
ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
"Length of Source Line Info");
ASM_OUTPUT_LABEL (asm_out_file, l1);
- dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+ dw2_asm_output_data (2, ver, "DWARF Version");
dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
ASM_OUTPUT_LABEL (asm_out_file, p1);
static void
dwarf2out_start_source_file (unsigned int lineno, const char *filename)
{
- if (flag_eliminate_dwarf2_dups)
+ if (flag_eliminate_dwarf2_dups && dwarf_version < 4)
{
/* Record the beginning of the file for break_out_includes. */
dw_die_ref bincl_die;
static void
dwarf2out_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED)
{
- if (flag_eliminate_dwarf2_dups)
+ if (flag_eliminate_dwarf2_dups && dwarf_version < 4)
/* Record the end of the file for break_out_includes. */
new_die (DW_TAG_GNU_EINCL, comp_unit_die, NULL);
if (a->dw_attr_val.val_class == dw_val_class_die_ref)
{
/* A reference to another DIE.
- Make sure that it will get emitted. */
- prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
+ Make sure that it will get emitted.
+ If it was broken out into a comdat group, don't follow it. */
+ if (dwarf_version < 4
+ || a->dw_attr == DW_AT_specification
+ || a->dw_attr_val.v.val_die_ref.die->die_id.die_type_node == NULL)
+ prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
}
/* Set the string's refcount to 0 so that prune_unused_types_mark
accounts properly for it. */
die->die_mark = 2;
/* 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)
+ kids get marked, even if they're types. If we're
+ breaking out types into comdat sections, do this
+ for all type definitions. */
+ if (die->die_tag == DW_TAG_array_type
+ || (dwarf_version >= 4
+ && is_type_die (die) && ! is_declaration_die (die)))
FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1));
else
FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
{
unsigned int i;
limbo_die_node *node;
+ comdat_type_node *ctnode;
pubname_ref pub;
#if ENABLE_ASSERT_CHECKING
verify_marks_clear (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
verify_marks_clear (node->die);
+ for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+ verify_marks_clear (ctnode->root_die);
#endif /* ENABLE_ASSERT_CHECKING */
/* Mark types that are used in global variables. */
prune_unused_types_walk (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
prune_unused_types_walk (node->die);
+ for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+ {
+ prune_unused_types_walk (ctnode->root_die);
+ prune_unused_types_mark (ctnode->type_die, 1);
+ }
/* Also set the mark on nodes referenced from the
pubname_table or arange_table. */
prune_unused_types_prune (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
prune_unused_types_prune (node->die);
+ for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+ prune_unused_types_prune (ctnode->root_die);
/* Leave the marks clear. */
prune_unmark_dies (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
prune_unmark_dies (node->die);
+ for (ctnode = comdat_type_list; ctnode; ctnode = ctnode->next)
+ prune_unmark_dies (ctnode->root_die);
}
/* Set the parameter to true if there are any relative pathnames in
return 1;
}
+/* Routines to manipulate hash table of comdat type units. */
+
+static hashval_t
+htab_ct_hash (const void *of)
+{
+ hashval_t h;
+ const comdat_type_node *const type_node = (const comdat_type_node *) of;
+
+ memcpy (&h, type_node->signature, sizeof (h));
+ return h;
+}
+
+static int
+htab_ct_eq (const void *of1, const void *of2)
+{
+ const comdat_type_node *const type_node_1 = (const comdat_type_node *) of1;
+ const comdat_type_node *const type_node_2 = (const comdat_type_node *) of2;
+
+ return (! memcmp (type_node_1->signature, type_node_2->signature,
+ DWARF_TYPE_SIGNATURE_SIZE));
+}
+
/* Move a DW_AT_MIPS_linkage_name attribute just added to dw_die_ref
to the location it would have been added, should we know its
DECL_ASSEMBLER_NAME when we added other attributes. This will
dwarf2out_finish (const char *filename)
{
limbo_die_node *node, *next_node;
+ comdat_type_node *ctnode;
+ htab_t comdat_type_table;
dw_die_ref die = 0;
unsigned int i;
/* Generate separate CUs for each of the include files we've seen.
They will go into limbo_die_list. */
- if (flag_eliminate_dwarf2_dups)
+ if (flag_eliminate_dwarf2_dups && dwarf_version < 4)
break_out_includes (comp_unit_die);
+ /* Generate separate COMDAT sections for type DIEs. */
+ if (dwarf_version >= 4)
+ {
+ break_out_comdat_types (comp_unit_die);
+
+ /* Each new type_unit DIE was added to the limbo die list when created.
+ Since these have all been added to comdat_type_list, clear the
+ limbo die list. */
+ limbo_die_list = NULL;
+
+ /* For each new comdat type unit, copy declarations for incomplete
+ types to make the new unit self-contained (i.e., no direct
+ references to the main compile unit). */
+ for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
+ copy_decls_for_unworthy_types (ctnode->root_die);
+ copy_decls_for_unworthy_types (comp_unit_die);
+
+ /* In the process of copying declarations from one unit to another,
+ we may have left some declarations behind that are no longer
+ referenced. Prune them. */
+ prune_unused_types ();
+ }
+
/* Traverse the DIE's and add add sibling attributes to those DIE's
that have children. */
add_sibling_attributes (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
add_sibling_attributes (node->die);
+ for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
+ add_sibling_attributes (ctnode->root_die);
/* Output a terminator label for the .text section. */
switch_to_section (text_section);
for (node = limbo_die_list; node; node = node->next)
output_comp_unit (node->die, 0);
+ comdat_type_table = htab_create (100, htab_ct_hash, htab_ct_eq, NULL);
+ for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
+ {
+ void **slot = htab_find_slot (comdat_type_table, ctnode, INSERT);
+
+ /* Don't output duplicate types. */
+ if (*slot != HTAB_EMPTY_ENTRY)
+ continue;
+
+ /* Add a pointer to the line table for the main compilation unit
+ so that the debugger can make sense of DW_AT_decl_file
+ attributes. */
+ if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
+ debug_line_section_label);
+
+ output_comdat_type_unit (ctnode);
+ *slot = ctnode;
+ }
+ htab_delete (comdat_type_table);
+
/* Output the main compilation unit if non-empty or if .debug_macinfo
has been emitted. */
output_comp_unit (comp_unit_die, debug_info_level >= DINFO_LEVEL_VERBOSE);