Commit 15b3fbeb by Cary Coutant Committed by Cary Coutant

Add support for comdat type sections for DWARF v4.

	Add support for comdat type sections for DWARF v4.  Merge from dwarf4
	branch.
	* dwarf2out.c (DWARF_TYPE_SIGNATURE_SIZE): New constant.
	(dw_die_ref): Define vector type.
	(enum dw_val_class): Add dw_val_class_data8.
	(struct dw_val_struct): Add v.val_data8.
	(comdat_type_node_ref): New type.
	(struct die_struct): Move die_symbol into a union; add new field
	die_type_node.  Change all uses.
	(comdat_type_node): New type.
	(skeleton_chain_node): New type.
	(DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE): New constant.
	(comdat_type_list): New variable.
	(dwarf_tag_name): Add DW_TAG_type_unit.
	(dwarf_attr_name): Add DW_AT_signature.
	(add_AT_data8): New function.
	(replace_child): New function.
	(move_all_children): New function.
	(print_signature): New function.
	(print_die): Print signature information; add dw_val_class_data8.
	(attr_checksum): Support dw_val_class_data8.
	(CHECKSUM_STRING): Redefine for DWARF-4 to include
	trailing NULL byte.
	(CHECKSUM_SLEB128, CHECKSUM_ULEB128): New macros.
	(checksum_sleb128, checksum_uleb128): New functions.
	(checksum_die_context): New function.
	(loc_checksum_ordered): New function.
	(attr_checksum_ordered): New function.
	(struct checksum_attributes): New structure.
	(collect_checksum_attributes): New function.
	(die_checksum_ordered): New function.
	(generate_type_signature): New function.
	(same_dw_val_p): Add dw_val_class_data8.
	(is_symbol_die): Use new is_declaration_die function.
	(is_declaration_die): New function.
	(should_move_die_to_comdat): New function.
	(clone_die): New function.
	(clone_tree): New function.
	(clone_as_declaration): New function.
	(copy_declaration_context): New function.
	(generate_skeleton_ancestor_tree): New function.
	(generate_skeleton_bottom_up): New function.
	(generate_skeleton): New function.
	(remove_child_or_replace_with_skeleton): New function.
	(break_out_comdat_types): New function.
	(struct decl_table_entry): New type.
	(htab_decl_hash): New function.
	(htab_decl_eq): New function.
	(htab_decl_del): New function.
	(copy_ancestor_tree): New function.
	(copy_decls_walk): New function.
	(copy_decls_for_unworthy_types): New function.
	(build_abbrev_table): Don't assert on missing die_symbol when doing
	comdat type sections.
	(size_of_die): Use DW_FORM_sig8 for external references; Add
	dw_val_class_data8.
	(unmark_dies): Don't assert for unmarked dies when doing comdat
	type sections.
	(value_format): Support DW_FORM_sig8 and dw_val_class_data8.
	(output_signature): New function.
	(output_die): Likewise.
	(output_compilation_unit_header): Mark output as DWARF version 3
	even if generating DWARF 4.
	(output_comdat_type_unit): New function.
	(output_line_info): Mark output as DWARF version 3 even if generating
	DWARF 4.
	(dwarf2out_start_source_file): Don't do eliminate_dwarf2_dups with
	DWARF-4.
	(dwarf2out_end_source_file): Likewise.
	(prune_unused_types_walk_attribs): Don't follow references into
	comdat type sections.
	(prune_unused_types_mark): When generating type units, do not mark
	children of non-defining declarations of types; do mark children of
	type entries.
	(prune_unused_types): Process comdat type sections.
	(htab_ct_hash): New function.
	(htab_ct_eq): New function.
	(dwarf2out_finish): Move types to comdat sections when using DWARF-4.
	Add a pointer to the line table from type unit entries so
	DW_AT_decl_file has meaning.
	* varasm.c (default_elf_asm_named_section): Use identifier name as
	comdat key instead of lang hook.

From-SVN: r152421
parent e9cfc9b5
2009-10-02 Cary Coutant <ccoutant@google.com>
Add support for comdat type sections for DWARF v4. Merge from dwarf4
branch.
* dwarf2out.c (DWARF_TYPE_SIGNATURE_SIZE): New constant.
(dw_die_ref): Define vector type.
(enum dw_val_class): Add dw_val_class_data8.
(struct dw_val_struct): Add v.val_data8.
(comdat_type_node_ref): New type.
(struct die_struct): Move die_symbol into a union; add new field
die_type_node. Change all uses.
(comdat_type_node): New type.
(skeleton_chain_node): New type.
(DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE): New constant.
(comdat_type_list): New variable.
(dwarf_tag_name): Add DW_TAG_type_unit.
(dwarf_attr_name): Add DW_AT_signature.
(add_AT_data8): New function.
(replace_child): New function.
(move_all_children): New function.
(print_signature): New function.
(print_die): Print signature information; add dw_val_class_data8.
(attr_checksum): Support dw_val_class_data8.
(CHECKSUM_STRING): Redefine for DWARF-4 to include
trailing NULL byte.
(CHECKSUM_SLEB128, CHECKSUM_ULEB128): New macros.
(checksum_sleb128, checksum_uleb128): New functions.
(checksum_die_context): New function.
(loc_checksum_ordered): New function.
(attr_checksum_ordered): New function.
(struct checksum_attributes): New structure.
(collect_checksum_attributes): New function.
(die_checksum_ordered): New function.
(generate_type_signature): New function.
(same_dw_val_p): Add dw_val_class_data8.
(is_symbol_die): Use new is_declaration_die function.
(is_declaration_die): New function.
(should_move_die_to_comdat): New function.
(clone_die): New function.
(clone_tree): New function.
(clone_as_declaration): New function.
(copy_declaration_context): New function.
(generate_skeleton_ancestor_tree): New function.
(generate_skeleton_bottom_up): New function.
(generate_skeleton): New function.
(remove_child_or_replace_with_skeleton): New function.
(break_out_comdat_types): New function.
(struct decl_table_entry): New type.
(htab_decl_hash): New function.
(htab_decl_eq): New function.
(htab_decl_del): New function.
(copy_ancestor_tree): New function.
(copy_decls_walk): New function.
(copy_decls_for_unworthy_types): New function.
(build_abbrev_table): Don't assert on missing die_symbol when doing
comdat type sections.
(size_of_die): Use DW_FORM_sig8 for external references; Add
dw_val_class_data8.
(unmark_dies): Don't assert for unmarked dies when doing comdat
type sections.
(value_format): Support DW_FORM_sig8 and dw_val_class_data8.
(output_signature): New function.
(output_die): Likewise.
(output_compilation_unit_header): Mark output as DWARF version 3
even if generating DWARF 4.
(output_comdat_type_unit): New function.
(output_line_info): Mark output as DWARF version 3 even if generating
DWARF 4.
(dwarf2out_start_source_file): Don't do eliminate_dwarf2_dups with
DWARF-4.
(dwarf2out_end_source_file): Likewise.
(prune_unused_types_walk_attribs): Don't follow references into
comdat type sections.
(prune_unused_types_mark): When generating type units, do not mark
children of non-defining declarations of types; do mark children of
type entries.
(prune_unused_types): Process comdat type sections.
(htab_ct_hash): New function.
(htab_ct_eq): New function.
(dwarf2out_finish): Move types to comdat sections when using DWARF-4.
Add a pointer to the line table from type unit entries so
DW_AT_decl_file has meaning.
* varasm.c (default_elf_asm_named_section): Use identifier name as
comdat key instead of lang hook.
2009-10-02 Neil Vachharajani <nvachhar@google.com>
* gcov-io.c (gcov_open): Open files read-only when MODE < 0
......@@ -348,6 +348,12 @@ dw_fde_node;
#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
......@@ -4155,6 +4161,9 @@ DEF_VEC_ALLOC_O(deferred_locations,gc);
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. */
......@@ -4177,7 +4186,8 @@ enum dw_val_class
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. */
......@@ -4214,6 +4224,7 @@ typedef struct GTY(()) dw_val_struct {
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;
}
......@@ -5464,6 +5475,7 @@ typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref;
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
......@@ -5504,7 +5516,12 @@ DEF_VEC_ALLOC_O(dw_attr_node,gc);
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;
......@@ -5550,6 +5567,16 @@ struct GTY(()) dw_ranges_by_label_struct {
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;
......@@ -5558,6 +5585,14 @@ typedef struct GTY(()) limbo_die_struct {
}
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 ";#"
......@@ -5591,6 +5626,11 @@ limbo_die_node;
#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)
......@@ -5641,6 +5681,9 @@ static unsigned long next_die_offset;
/* 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;
......@@ -5832,6 +5875,7 @@ static void add_AT_double (dw_die_ref, enum dwarf_attribute,
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 *);
......@@ -5894,6 +5938,16 @@ static dw_die_ref pop_compile_unit (dw_die_ref);
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 *);
......@@ -5905,6 +5959,22 @@ static int is_comdat_die (dw_die_ref);
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 *);
......@@ -5928,6 +5998,7 @@ static void output_die_symbol (dw_die_ref);
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);
......@@ -6352,6 +6423,8 @@ dwarf_tag_name (unsigned int tag)
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:
......@@ -6534,6 +6607,9 @@ dwarf_attr_name (unsigned int attr)
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:
......@@ -6794,6 +6870,20 @@ add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind,
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
......@@ -7347,6 +7437,43 @@ remove_child_with_prev (dw_die_ref child, dw_die_ref prev)
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. */
......@@ -7589,6 +7716,17 @@ print_spaces (FILE *outfile)
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. */
......@@ -7605,6 +7743,13 @@ print_die (dw_die_ref die, FILE *outfile)
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++)
{
......@@ -7650,8 +7795,15 @@ print_die (dw_die_ref die, FILE *outfile)
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);
}
......@@ -7673,6 +7825,14 @@ print_die (dw_die_ref die, FILE *outfile)
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;
}
......@@ -7837,6 +7997,10 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
CHECKSUM_STRING (AT_file (at)->filename);
break;
case dw_val_class_data8:
CHECKSUM (at->dw_attr_val.v.val_data8);
break;
default:
break;
}
......@@ -7870,143 +8034,766 @@ die_checksum (dw_die_ref die, struct md5_ctx *ctx, int *mark)
#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;
}
}
......@@ -8067,7 +8854,7 @@ compute_section_prefix (dw_die_ref unit_die)
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;
}
......@@ -8126,213 +8913,751 @@ is_comdat_die (dw_die_ref c)
{
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
......@@ -8389,7 +9714,7 @@ build_abbrev_table (dw_die_ref die)
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);
}
......@@ -8519,10 +9844,19 @@ size_of_die (dw_die_ref die)
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;
......@@ -8545,6 +9879,9 @@ size_of_die (dw_die_ref die)
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 ();
}
......@@ -8596,7 +9933,8 @@ unmark_dies (dw_die_ref die)
{
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));
......@@ -8764,7 +10102,7 @@ value_format (dw_attr_ref a)
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:
......@@ -8789,6 +10127,9 @@ value_format (dw_attr_ref a)
gcc_unreachable ();
}
case dw_val_class_data8:
return DW_FORM_data8;
default:
gcc_unreachable ();
}
......@@ -8848,7 +10189,7 @@ output_abbrev_section (void)
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;
......@@ -8950,6 +10291,17 @@ output_loc_list (dw_loc_list_ref list_head)
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. */
......@@ -8963,7 +10315,7 @@ output_die (dw_die_ref 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)",
......@@ -9085,18 +10437,30 @@ output_die (dw_die_ref die)
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
{
......@@ -9150,6 +10514,16 @@ output_die (dw_die_ref die)
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 ();
}
......@@ -9169,13 +10543,20 @@ output_die (dw_die_ref die)
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");
......@@ -9207,14 +10588,14 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
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
......@@ -9229,10 +10610,60 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
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 *
......@@ -9950,6 +11381,13 @@ output_line_info (void)
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);
......@@ -9963,7 +11401,7 @@ output_line_info (void)
"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);
......@@ -18457,7 +19895,7 @@ dwarf2out_source_line (unsigned int line, const char *filename,
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;
......@@ -18484,7 +19922,7 @@ dwarf2out_start_source_file (unsigned int lineno, const char *filename)
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);
......@@ -18708,8 +20146,12 @@ prune_unused_types_walk_attribs (dw_die_ref die)
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. */
......@@ -18753,8 +20195,12 @@ prune_unused_types_mark (dw_die_ref die, int dokids)
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));
......@@ -18958,6 +20404,7 @@ prune_unused_types (void)
{
unsigned int i;
limbo_die_node *node;
comdat_type_node *ctnode;
pubname_ref pub;
#if ENABLE_ASSERT_CHECKING
......@@ -18965,6 +20412,8 @@ prune_unused_types (void)
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. */
......@@ -18974,6 +20423,11 @@ prune_unused_types (void)
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. */
......@@ -18990,11 +20444,15 @@ prune_unused_types (void)
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
......@@ -19012,6 +20470,28 @@ file_table_relative_p (void ** slot, void *param)
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
......@@ -19147,6 +20627,8 @@ static void
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;
......@@ -19254,14 +20736,39 @@ dwarf2out_finish (const char *filename)
/* 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);
......@@ -19344,6 +20851,27 @@ dwarf2out_finish (const char *filename)
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);
......
......@@ -5997,8 +5997,13 @@ default_elf_asm_named_section (const char *name, unsigned int flags,
if (flags & SECTION_ENTSIZE)
fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
fprintf (asm_out_file, ",%s,comdat",
IDENTIFIER_POINTER (DECL_COMDAT_GROUP (decl)));
{
if (TREE_CODE (decl) == IDENTIFIER_NODE)
fprintf (asm_out_file, ",%s,comdat", IDENTIFIER_POINTER (decl));
else
fprintf (asm_out_file, ",%s,comdat",
IDENTIFIER_POINTER (DECL_COMDAT_GROUP (decl)));
}
}
putc ('\n', asm_out_file);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment