diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/class.c | 2 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 5 | ||||
-rw-r--r-- | gcc/cp/lex.c | 15 | ||||
-rw-r--r-- | gcc/dwarf2.h | 4 | ||||
-rw-r--r-- | gcc/dwarf2out.c | 611 | ||||
-rw-r--r-- | gcc/flags.h | 4 | ||||
-rw-r--r-- | gcc/toplev.c | 31 | ||||
-rw-r--r-- | gcc/toplev.h | 1 | ||||
-rw-r--r-- | gcc/tree.c | 34 | ||||
-rw-r--r-- | gcc/tree.h | 1 |
11 files changed, 650 insertions, 65 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8f0617f..c9224cf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2000-08-28 Jason Merrill <jason@redhat.com> + + * lex.c (file_name_nondirectory): Move to toplev.c. + + * cp-tree.h (LOCAL_CLASS_P): New macro. + * class.c (finish_struct_1): Use it. + 2000-08-27 Alex Samuel <samuel@codesourcery.com> * mangle.c (CLASSTYPE_TEMPLATE_ID_P): Remove unexplained voodoo. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 2834154..dfbdc94 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5200,7 +5200,7 @@ finish_struct_1 (t) maybe_suppress_debug_info (t); /* Finish debugging output for this type. */ - rest_of_type_compilation (t, toplevel_bindings_p ()); + rest_of_type_compilation (t, ! LOCAL_CLASS_P (t)); } /* When T was built up, the member declarations were added in reverse diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index aa77ab1..cc50469 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2224,6 +2224,11 @@ struct lang_decl (DECL_CONTEXT (NODE) \ && TREE_CODE (DECL_CONTEXT (NODE)) == FUNCTION_DECL) +/* 1 iff NODE is function-local, but for types. */ +#define LOCAL_CLASS_P(NODE) \ + (TYPE_CONTEXT (NODE) \ + && TREE_CODE (TYPE_CONTEXT (NODE)) == FUNCTION_DECL) + /* For a NAMESPACE_DECL: the list of using namespace directives The PURPOSE is the used namespace, the value is the namespace that is the common ancestor. */ diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index 964bd56..94679b4 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -96,21 +96,6 @@ static int is_extended_char PARAMS ((int)); static int is_extended_char_1 PARAMS ((int)); static void init_operators PARAMS ((void)); -/* Given a file name X, return the nondirectory portion. - Keep in mind that X can be computed more than once. */ -char * -file_name_nondirectory (x) - const char *x; -{ - char *tmp = (char *) rindex (x, '/'); - if (DIR_SEPARATOR != '/' && ! tmp) - tmp = (char *) rindex (x, DIR_SEPARATOR); - if (tmp) - return (char *) (tmp + 1); - else - return (char *) x; -} - /* This obstack is needed to hold text. It is not safe to use TOKEN_BUFFER because `check_newline' calls `yylex'. */ struct obstack inline_text_obstack; diff --git a/gcc/dwarf2.h b/gcc/dwarf2.h index 2e2b9fe..5b60828 100644 --- a/gcc/dwarf2.h +++ b/gcc/dwarf2.h @@ -88,7 +88,9 @@ enum dwarf_tag /* GNU extensions */ DW_TAG_format_label = 0x4101, /* for FORTRAN 77 and Fortran 90 */ DW_TAG_function_template = 0x4102, /* for C++ */ - DW_TAG_class_template = 0x4103 /* for C++ */ + DW_TAG_class_template = 0x4103, /* for C++ */ + DW_TAG_GNU_BINCL = 0x4104, + DW_TAG_GNU_EINCL = 0x4105 }; #define DW_TAG_lo_user 0x4080 diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index cc121e1..69e0395 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -23,9 +23,6 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* TODO: Implement .debug_str handling, and share entries somehow. - Eliminate duplicates by putting common info in a separate section - to be collected by the linker and referring to it with - DW_FORM_ref_addr. Emit .debug_line header even when there are no functions, since the file numbers are used by .debug_info. Alternately, leave out locations for types and decls. @@ -56,6 +53,7 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "varray.h" #include "ggc.h" +#include "md5.h" #include "tm_p.h" /* Decide whether we want to emit frame unwind information for the current @@ -303,6 +301,7 @@ static void def_cfa_1 PARAMS ((const char *, dw_cfa_location *)); #define FDE_AFTER_SIZE_LABEL "LSFDE" #define FDE_END_LABEL "LEFDE" #define FDE_LENGTH_LABEL "LLFDE" +#define DIE_LABEL_PREFIX "DW" /* Definitions of defaults for various types of primitive assembly language output operations. These may be overridden from within the tm.h file, @@ -2124,7 +2123,10 @@ typedef struct dw_val_struct long unsigned val_unsigned; dw_long_long_const val_long_long; dw_float_const val_float; - dw_die_ref val_die_ref; + struct { + dw_die_ref die; + int external; + } val_die_ref; unsigned val_fde_index; char *val_str; char *val_lbl_id; @@ -2995,6 +2997,7 @@ dw_attr_node; typedef struct die_struct { enum dwarf_tag die_tag; + char *die_symbol; dw_attr_ref die_attr; dw_die_ref die_parent; dw_die_ref die_child; @@ -3338,20 +3341,38 @@ static void equate_decl_number_to_die PARAMS ((tree, dw_die_ref)); static void print_spaces PARAMS ((FILE *)); static void print_die PARAMS ((dw_die_ref, FILE *)); static void print_dwarf_line_table PARAMS ((FILE *)); +static void reverse_die_lists PARAMS ((dw_die_ref)); +static void reverse_all_dies PARAMS ((dw_die_ref)); +static dw_die_ref push_new_compile_unit PARAMS ((dw_die_ref, dw_die_ref)); +static dw_die_ref pop_compile_unit PARAMS ((dw_die_ref)); +static void loc_checksum PARAMS ((dw_loc_descr_ref, struct md5_ctx *)); +static void attr_checksum PARAMS ((dw_attr_ref, struct md5_ctx *)); +static void die_checksum PARAMS ((dw_die_ref, struct md5_ctx *)); +static void compute_section_prefix PARAMS ((dw_die_ref)); +static int is_type_die PARAMS ((dw_die_ref)); +static int is_comdat_die PARAMS ((dw_die_ref)); +static int is_symbol_die PARAMS ((dw_die_ref)); +static char *gen_internal_sym PARAMS ((void)); +static void assign_symbol_names PARAMS ((dw_die_ref)); +static void break_out_includes PARAMS ((dw_die_ref)); static void add_sibling_attributes PARAMS ((dw_die_ref)); static void build_abbrev_table PARAMS ((dw_die_ref)); static unsigned long size_of_string PARAMS ((const char *)); static int constant_size PARAMS ((long unsigned)); static unsigned long size_of_die PARAMS ((dw_die_ref)); static void calc_die_sizes PARAMS ((dw_die_ref)); +static void clear_die_sizes PARAMS ((dw_die_ref)); static unsigned long size_of_line_prolog PARAMS ((void)); static unsigned long size_of_pubnames PARAMS ((void)); static unsigned long size_of_aranges PARAMS ((void)); static enum dwarf_form value_format PARAMS ((dw_attr_ref)); static void output_value_format PARAMS ((dw_attr_ref)); static void output_abbrev_section PARAMS ((void)); +static void output_die_symbol PARAMS ((dw_die_ref)); +static void output_symbolic_ref PARAMS ((dw_die_ref)); static void output_die PARAMS ((dw_die_ref)); static void output_compilation_unit_header PARAMS ((void)); +static void output_comp_unit PARAMS ((dw_die_ref)); static const char *dwarf2_name PARAMS ((tree, int)); static void add_pubname PARAMS ((tree, dw_die_ref)); static void output_pubnames PARAMS ((void)); @@ -3441,7 +3462,6 @@ static void gen_type_die_for_member PARAMS ((tree, tree, dw_die_ref)); static void gen_abstract_function PARAMS ((tree)); static rtx save_rtx PARAMS ((rtx)); static void splice_child_die PARAMS ((dw_die_ref, dw_die_ref)); -static void reverse_die_lists PARAMS ((dw_die_ref)); /* Section names used to hold DWARF debugging information. */ #ifndef DEBUG_INFO_SECTION @@ -3728,6 +3748,10 @@ dwarf_tag_name (tag) return "DW_TAG_function_template"; case DW_TAG_class_template: return "DW_TAG_class_template"; + case DW_TAG_GNU_BINCL: + return "DW_TAG_GNU_BINCL"; + case DW_TAG_GNU_EINCL: + return "DW_TAG_GNU_EINCL"; default: return "DW_TAG_<unknown>"; } @@ -4079,7 +4103,7 @@ decl_class_context (decl) } /* Add an attribute/value pair to a DIE. We build the lists up in reverse - addition order, and correct that in add_sibling_attributes. */ + addition order, and correct that in reverse_all_dies. */ static inline void add_dwarf_attr (die, attr) @@ -4264,7 +4288,8 @@ add_AT_die_ref (die, attr_kind, targ_die) attr->dw_attr_next = NULL; attr->dw_attr = attr_kind; attr->dw_attr_val.val_class = dw_val_class_die_ref; - attr->dw_attr_val.v.val_die_ref = targ_die; + attr->dw_attr_val.v.val_die_ref.die = targ_die; + attr->dw_attr_val.v.val_die_ref.external = 0; add_dwarf_attr (die, attr); } @@ -4274,11 +4299,34 @@ AT_ref (a) register dw_attr_ref a; { if (a && AT_class (a) == dw_val_class_die_ref) - return a->dw_attr_val.v.val_die_ref; + return a->dw_attr_val.v.val_die_ref.die; abort (); } +static inline int AT_ref_external PARAMS ((dw_attr_ref)); +static inline int +AT_ref_external (a) + register dw_attr_ref a; +{ + if (a && AT_class (a) == dw_val_class_die_ref) + return a->dw_attr_val.v.val_die_ref.external; + + return 0; +} + +static inline void set_AT_ref_external PARAMS ((dw_attr_ref, int)); +static inline void +set_AT_ref_external (a, i) + register dw_attr_ref a; + int i; +{ + if (a && AT_class (a) == dw_val_class_die_ref) + a->dw_attr_val.v.val_die_ref.external = i; + else + abort (); +} + /* Add an FDE reference attribute value to a DIE. */ static inline void @@ -4611,7 +4659,7 @@ remove_children (die) } /* Add a child DIE below its parent. We build the lists up in reverse - addition order, and correct that in add_sibling_attributes. */ + addition order, and correct that in reverse_all_dies. */ static inline void add_child_die (die, child_die) @@ -4677,6 +4725,7 @@ new_die (tag_value, parent_die) die->die_parent = NULL; die->die_sib = NULL; die->die_attr = NULL; + die->die_symbol = NULL; if (parent_die != NULL) add_child_die (parent_die, die); @@ -4822,7 +4871,12 @@ print_die (die, outfile) break; case dw_val_class_die_ref: if (AT_ref (a) != NULL) - fprintf (outfile, "die -> %lu", AT_ref (a)->die_offset); + { + if (AT_ref (a)->die_offset == 0) + fprintf (outfile, "die -> label: %s", AT_ref (a)->die_symbol); + else + fprintf (outfile, "die -> %lu", AT_ref (a)->die_offset); + } else fprintf (outfile, "die -> <null>"); break; @@ -4851,6 +4905,8 @@ print_die (die, outfile) print_indent -= 4; } + if (print_indent == 0) + fprintf (outfile, "\n"); } /* Print the contents of the source code line number correspondence table. @@ -4925,20 +4981,379 @@ reverse_die_lists (die) die->die_child = cp; } -/* Traverse the DIE, reverse its lists of attributes and children, and - add a sibling attribute if it may have the effect of speeding up - access to siblings. To save some space, avoid generating sibling - attributes for DIE's without children. */ +/* reverse_die_lists only reverses the single die you pass it. Since + we used to reverse all dies in add_sibling_attributes, which runs + through all the dies, it would reverse all the dies. Now, however, + since we don't call reverse_die_lists in add_sibling_attributes, we + need a routine to recursively reverse all the dies. This is that + routine. */ static void -add_sibling_attributes (die) +reverse_all_dies (die) register dw_die_ref die; { register dw_die_ref c; reverse_die_lists (die); - if (die != comp_unit_die && die->die_sib && die->die_child != NULL) + for (c = die->die_child; c; c = c->die_sib) + reverse_all_dies (c); +} + +/* Start a new compilation unit DIE for an include file. OLD_UNIT is + the CU for the enclosing include file, if any. BINCL_DIE is the + DW_TAG_GNU_BINCL DIE that marks the start of the DIEs for this + include file. */ + +static dw_die_ref +push_new_compile_unit (old_unit, bincl_die) + dw_die_ref old_unit, bincl_die; +{ + const char *filename = get_AT_string (bincl_die, DW_AT_name); + dw_die_ref new_unit = gen_compile_unit_die (filename); + new_unit->die_sib = old_unit; + return new_unit; +} + +/* Close an include-file CU and reopen the enclosing one. */ + +static dw_die_ref +pop_compile_unit (old_unit) + dw_die_ref old_unit; +{ + dw_die_ref new_unit = old_unit->die_sib; + old_unit->die_sib = NULL; + return new_unit; +} + +#define PROCESS(FOO) md5_process_bytes (&(FOO), sizeof (FOO), ctx) +#define PROCESS_STRING(FOO) md5_process_bytes ((FOO), strlen (FOO), ctx) + +/* Calculate the checksum of a location expression. */ + +static inline void +loc_checksum (loc, ctx) + dw_loc_descr_ref loc; + struct md5_ctx *ctx; +{ + PROCESS (loc->dw_loc_opc); + PROCESS (loc->dw_loc_oprnd1); + PROCESS (loc->dw_loc_oprnd2); +} + +/* Calculate the checksum of an attribute. */ + +static void +attr_checksum (at, ctx) + dw_attr_ref at; + struct md5_ctx *ctx; +{ + dw_loc_descr_ref loc; + rtx r; + + PROCESS (at->dw_attr); + + /* We don't care about differences in file numbering. */ + if (at->dw_attr == DW_AT_decl_file) + return; + + switch (AT_class (at)) + { + case dw_val_class_const: + PROCESS (at->dw_attr_val.v.val_int); + break; + case dw_val_class_unsigned_const: + PROCESS (at->dw_attr_val.v.val_unsigned); + break; + case dw_val_class_long_long: + PROCESS (at->dw_attr_val.v.val_long_long); + break; + case dw_val_class_float: + PROCESS (at->dw_attr_val.v.val_float); + break; + case dw_val_class_flag: + PROCESS (at->dw_attr_val.v.val_flag); + break; + + case dw_val_class_str: + PROCESS_STRING (AT_string (at)); + break; + case dw_val_class_addr: + r = AT_addr (at); + switch (GET_CODE (r)) + { + case SYMBOL_REF: + PROCESS_STRING (XSTR (r, 0)); + break; + + default: + abort (); + } + break; + + case dw_val_class_loc: + for (loc = AT_loc (at); loc; loc = loc->dw_loc_next) + loc_checksum (loc, ctx); + break; + + case dw_val_class_die_ref: + if (AT_ref (at)->die_offset) + PROCESS (AT_ref (at)->die_offset); + /* FIXME else use target die name or something. */ + + case dw_val_class_fde_ref: + case dw_val_class_lbl_id: + case dw_val_class_lbl_offset: + + default: + break; + } +} + +/* Calculate the checksum of a DIE. */ + +static void +die_checksum (die, ctx) + dw_die_ref die; + struct md5_ctx *ctx; +{ + dw_die_ref c; + dw_attr_ref a; + + PROCESS (die->die_tag); + + for (a = die->die_attr; a; a = a->dw_attr_next) + attr_checksum (a, ctx); + + for (c = die->die_child; c; c = c->die_sib) + die_checksum (c, ctx); +} + +#undef PROCESS +#undef PROCESS_STRING + +/* The prefix to attach to symbols on DIEs in the current comdat debug + info section. */ +static char *comdat_symbol_id; + +/* The index of the current symbol within the current comdat CU. */ +static unsigned int comdat_symbol_number; + +/* Calculate the MD5 checksum of the compilation unit DIE UNIT_DIE and its + children, and set comdat_symbol_id accordingly. */ + +static void +compute_section_prefix (unit_die) + dw_die_ref unit_die; +{ + char *p, *name; + int i; + unsigned char checksum[16]; + struct md5_ctx ctx; + + md5_init_ctx (&ctx); + die_checksum (unit_die, &ctx); + md5_finish_ctx (&ctx, checksum); + + p = file_name_nondirectory (get_AT_string (unit_die, DW_AT_name)); + name = (char *) alloca (strlen (p) + 64); + sprintf (name, "%s.", p); + + clean_symbol_name (name); + + p = name + strlen (name); + for (i = 0; i < 4; ++i) + { + sprintf (p, "%.2x", checksum[i]); + p += 2; + } + + comdat_symbol_id = unit_die->die_symbol = xstrdup (name); + comdat_symbol_number = 0; +} + +/* Returns nonzero iff DIE represents a type, in the sense of TYPE_P. */ + +static int +is_type_die (die) + dw_die_ref die; +{ + switch (die->die_tag) + { + case DW_TAG_array_type: + case DW_TAG_class_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_reference_type: + case DW_TAG_string_type: + case DW_TAG_structure_type: + case DW_TAG_subroutine_type: + case DW_TAG_union_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: + return 1; + default: + return 0; + } +} + +/* Returns 1 iff C is the sort of DIE that should go into a COMDAT CU. + Basically, we want to choose the bits that are likely to be shared between + compilations (types) and leave out the bits that are specific to individual + compilations (functions). */ + +static int +is_comdat_die (c) + dw_die_ref c; +{ +#if 1 + /* I think we want to leave base types and __vtbl_ptr_type in the + main CU, as we do for stabs. The advantage is a greater + likelihood of sharing between objects that don't include headers + in the same order (and therefore would put the base types in a + different comdat). jason 8/28/00 */ + if (c->die_tag == DW_TAG_base_type) + return 0; + + if (c->die_tag == DW_TAG_pointer_type + || c->die_tag == DW_TAG_reference_type + || c->die_tag == DW_TAG_const_type + || c->die_tag == DW_TAG_volatile_type) + { + dw_die_ref t = get_AT_ref (c, DW_AT_type); + return t ? is_comdat_die (t) : 0; + } +#endif + + 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 (c) + dw_die_ref c; +{ + if (is_type_die (c)) + return 1; + if (get_AT (c, DW_AT_declaration) + && ! get_AT (c, DW_AT_specification)) + return 1; + return 0; +} + +static char * +gen_internal_sym () +{ + char buf[256]; + static int label_num; + ASM_GENERATE_INTERNAL_LABEL (buf, "LDIE", label_num++); + return xstrdup (buf); +} + +/* Assign symbols to all worthy DIEs under DIE. */ + +static void +assign_symbol_names (die) + register dw_die_ref die; +{ + register dw_die_ref c; + + if (is_symbol_die (die)) + { + if (comdat_symbol_id) + { + char *p = alloca (strlen (comdat_symbol_id) + 64); + 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 (); + } + + for (c = die->die_child; c != NULL; c = c->die_sib) + assign_symbol_names (c); +} + +/* 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 (die) + register dw_die_ref die; +{ + dw_die_ref *ptr; + register dw_die_ref unit = NULL; + limbo_die_node *node; + + for (ptr = &(die->die_child); *ptr; ) + { + register dw_die_ref c = *ptr; + + if (c->die_tag == DW_TAG_GNU_BINCL + || c->die_tag == DW_TAG_GNU_EINCL + || (unit && is_comdat_die (c))) + { + /* This DIE is for a secondary CU; remove it from the main one. */ + *ptr = c->die_sib; + + if (c->die_tag == DW_TAG_GNU_BINCL) + { + unit = push_new_compile_unit (unit, c); + free_die (c); + } + else if (c->die_tag == DW_TAG_GNU_EINCL) + { + unit = pop_compile_unit (unit); + free_die (c); + } + else + add_child_die (unit, c); + } + else + { + /* Leave this DIE in the main CU. */ + ptr = &(c->die_sib); + continue; + } + } + +#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. */ + if (unit != NULL) + abort (); +#endif + + assign_symbol_names (die); + for (node = limbo_die_list; node; node = node->next) + { + compute_section_prefix (node->die); + assign_symbol_names (node->die); + } +} + +/* Traverse the DIE and add a sibling attribute if it may have the + effect of speeding up access to siblings. To save some space, + avoid generating sibling attributes for DIE's without children. */ + +static void +add_sibling_attributes (die) + register dw_die_ref die; +{ + register dw_die_ref c; + + if (die->die_tag != DW_TAG_compile_unit + && die->die_sib && die->die_child != NULL) /* Add the sibling link to the front of the attribute list. */ add_AT_die_ref (die, DW_AT_sibling, die->die_sib); @@ -4960,6 +5375,20 @@ build_abbrev_table (die) register unsigned long n_alloc; register dw_die_ref c; register dw_attr_ref d_attr, a_attr; + + /* Scan the DIE references, and mark as external any that refer to + DIEs from other CUs (i.e. those with cleared die_offset). */ + for (d_attr = die->die_attr; d_attr; d_attr = d_attr->dw_attr_next) + { + if (AT_class (d_attr) == dw_val_class_die_ref + && AT_ref (d_attr)->die_offset == 0) + { + if (AT_ref (d_attr)->die_symbol == 0) + abort (); + set_AT_ref_external (d_attr, 1); + } + } + for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) { register dw_die_ref abbrev = abbrev_die_table[abbrev_id]; @@ -5130,6 +5559,20 @@ calc_die_sizes (die) next_die_offset += 1; } +/* Clear the offsets and sizes for a die and its children. We do this so + that we know whether or not a reference needs to use FORM_ref_addr; only + DIEs in the same CU will have non-zero offsets available. */ + +static void +clear_die_sizes (die) + dw_die_ref die; +{ + register dw_die_ref c; + die->die_offset = 0; + for (c = die->die_child; c; c = c->die_sib) + clear_die_sizes (c); +} + /* Return the size of the line information prolog generated for the compilation unit. */ @@ -5250,7 +5693,10 @@ value_format (a) case dw_val_class_flag: return DW_FORM_flag; case dw_val_class_die_ref: - return DW_FORM_ref; + if (AT_ref_external (a)) + return DW_FORM_ref_addr; + else + return DW_FORM_ref; case dw_val_class_fde_ref: return DW_FORM_data; case dw_val_class_lbl_id: @@ -5333,6 +5779,39 @@ output_abbrev_section () fprintf (asm_out_file, "\t%s\t0\n", ASM_BYTE_OP); } +/* Output a symbol we can use to refer to this DIE from another CU. */ + +static inline void +output_die_symbol (die) + register dw_die_ref die; +{ + char *sym = die->die_symbol; + + if (sym == 0) + return; + + if (strncmp (sym, DIE_LABEL_PREFIX, sizeof (DIE_LABEL_PREFIX) - 1) == 0) + /* We make these global, not weak; if the target doesn't support + .linkonce, it doesn't support combining the sections, so debugging + will break. */ + ASM_GLOBALIZE_LABEL (asm_out_file, sym); + ASM_OUTPUT_LABEL (asm_out_file, sym); +} + +/* Output a symbolic (i.e. FORM_ref_addr) reference to TARGET_DIE. */ + +static inline void +output_symbolic_ref (target_die) + dw_die_ref target_die; +{ + char *sym = target_die->die_symbol; + + if (sym == 0) + abort (); + + ASM_OUTPUT_DWARF_OFFSET (asm_out_file, sym); +} + /* Output the DIE and its attributes. Called recursively to generate the definitions of each child DIE. */ @@ -5344,6 +5823,11 @@ output_die (die) register dw_die_ref c; register unsigned long size; + /* If someone in another CU might refer to us, set up a symbol for + them to point to. */ + if (die->die_symbol) + output_die_symbol (die); + output_uleb128 (die->die_abbrev); if (flag_debug_asm) fprintf (asm_out_file, " (DIE (0x%lx) %s)", @@ -5457,7 +5941,10 @@ output_die (die) break; case dw_val_class_die_ref: - ASM_OUTPUT_DWARF_DATA (asm_out_file, AT_ref (a)->die_offset); + if (AT_ref_external (a)) + output_symbolic_ref (AT_ref (a)); + else + ASM_OUTPUT_DWARF_DATA (asm_out_file, AT_ref (a)->die_offset); break; case dw_val_class_fde_ref: @@ -5547,6 +6034,44 @@ output_compilation_unit_header () fputc ('\n', asm_out_file); } +/* Output the compilation unit DIE and its children. */ + +static void +output_comp_unit (die) + dw_die_ref die; +{ + char *secname; + + if (die->die_child == 0) + return; + + /* Initialize the beginning DIE offset - and calculate sizes/offsets. */ + next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE; + calc_die_sizes (die); + + build_abbrev_table (die); + + if (die->die_symbol) + { + secname = (char *) alloca (strlen (die->die_symbol) + 24); + sprintf (secname, ".gnu.linkonce.wi.%s", die->die_symbol); + die->die_symbol = NULL; + } + else + secname = (char *) DEBUG_INFO_SECTION; + + /* Output debugging information. */ + fputc ('\n', asm_out_file); + ASM_OUTPUT_SECTION (asm_out_file, secname); + output_compilation_unit_header (); + output_die (die); + + /* Leave the sizes on the main CU, since we do it last and we use the + sizes in output_pubnames. */ + if (die->die_symbol) + clear_die_sizes (die); +} + /* The DWARF2 pubname for a nested thingy looks like "A::f". The output of decl_printable_name for C++ looks like "A::f(int)". Let's drop the argument list, and maybe the scope. */ @@ -5622,6 +6147,10 @@ output_pubnames () { register pubname_ref pub = &pubname_table[i]; + /* We shouldn't see pubnames for DIEs outside of the main CU. */ + if (pub->die->die_offset == 0) + abort (); + ASM_OUTPUT_DWARF_DATA (asm_out_file, pub->die->die_offset); if (flag_debug_asm) fprintf (asm_out_file, "\t%s DIE offset", ASM_COMMENT_START); @@ -5735,6 +6264,10 @@ output_aranges () { dw_die_ref die = arange_table[i]; + /* We shouldn't see aranges for DIEs outside of the main CU. */ + if (die->die_offset == 0) + abort (); + if (die->die_tag == DW_TAG_subprogram) ASM_OUTPUT_DWARF_ADDR (asm_out_file, get_AT_low_pc (die)); else @@ -10134,6 +10667,12 @@ void dwarf2out_start_source_file (filename) register const char *filename ATTRIBUTE_UNUSED; { + if (flag_eliminate_dwarf2_dups) + { + /* Record the beginning of the file for break_out_includes. */ + dw_die_ref bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die); + add_AT_string (bincl_die, DW_AT_name, filename); + } } /* Record the end of a source file, for later output @@ -10142,6 +10681,11 @@ dwarf2out_start_source_file (filename) void dwarf2out_end_source_file () { + if (flag_eliminate_dwarf2_dups) + { + /* Record the end of the file for break_out_includes. */ + new_die (DW_TAG_GNU_EINCL, comp_unit_die); + } } /* Called from check_newline in c-parse.y. The `buffer' parameter contains @@ -10291,9 +10835,19 @@ dwarf2out_finish () emit full debugging info for them. */ retry_incomplete_types (); - /* Traverse the DIE's, reverse their lists of attributes and children, - and add add sibling attributes to those DIE's that have children. */ + /* We need to reverse all the dies before break_out_includes, or + we'll see the end of an include file before the beginning. */ + reverse_all_dies (comp_unit_die); + + /* Generate separate CUs for each of the include files we've seen. + They will go into limbo_die_list. */ + break_out_includes (comp_unit_die); + + /* 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); /* Output a terminator label for the .text section. */ fputc ('\n', asm_out_file); @@ -10339,22 +10893,17 @@ dwarf2out_finish () add_AT_unsigned (die, DW_AT_macro_info, 0); #endif + /* Output all of the compilation units. We put the main one last so that + the offsets are available to output_pubnames. */ + for (node = limbo_die_list; node; node = node->next) + output_comp_unit (node->die); + output_comp_unit (comp_unit_die); + /* Output the abbreviation table. */ fputc ('\n', asm_out_file); ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION); - build_abbrev_table (comp_unit_die); output_abbrev_section (); - /* Initialize the beginning DIE offset - and calculate sizes/offsets. */ - next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE; - calc_die_sizes (comp_unit_die); - - /* Output debugging information. */ - fputc ('\n', asm_out_file); - ASM_OUTPUT_SECTION (asm_out_file, DEBUG_INFO_SECTION); - output_compilation_unit_header (); - output_die (comp_unit_die); - if (pubname_table_in_use) { /* Output public names table. */ diff --git a/gcc/flags.h b/gcc/flags.h index de5b099..a294c37 100644 --- a/gcc/flags.h +++ b/gcc/flags.h @@ -577,3 +577,7 @@ extern enum graph_dump_types graph_dump_format; string identifying the compiler. */ extern int flag_no_ident; + +/* Nonzero means we should do dwarf2 duplicate elimination. */ + +extern int flag_eliminate_dwarf2_dups; diff --git a/gcc/toplev.c b/gcc/toplev.c index bbe752d..0d5d4f2 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -422,6 +422,10 @@ tree (*lang_expand_constant) PARAMS ((tree)) = 0; void (*incomplete_decl_finalize_hook) PARAMS ((tree)) = 0; +/* Nonzero if doing dwarf2 duplicate elimination. */ + +int flag_eliminate_dwarf2_dups = 0; + /* Nonzero if generating code to do profiling. */ int profile_flag = 0; @@ -944,6 +948,8 @@ const char *user_label_prefix; lang_independent_options f_options[] = { + {"eliminate-dwarf2-dups", &flag_eliminate_dwarf2_dups, 1, + "Perform DWARF2 duplicate elimination"}, {"float-store", &flag_float_store, 1, "Do not store floats in registers" }, {"volatile", &flag_volatile, 1, @@ -1656,6 +1662,21 @@ strip_off_ending (name, len) } } +/* Given a file name X, return the nondirectory portion. */ + +char * +file_name_nondirectory (x) + const char *x; +{ + char *tmp = (char *) rindex (x, '/'); + if (DIR_SEPARATOR != '/' && ! tmp) + tmp = (char *) rindex (x, DIR_SEPARATOR); + if (tmp) + return (char *) (tmp + 1); + else + return (char *) x; +} + /* Output a quoted string. */ void @@ -2561,6 +2582,10 @@ rest_of_type_compilation (type, toplev) if (write_symbols == SDB_DEBUG) sdbout_symbol (TYPE_STUB_DECL (type), !toplev); #endif +#ifdef DWARF2_DEBUGGING_INFO + if (write_symbols == DWARF2_DEBUG && toplev) + dwarf2out_decl (TYPE_STUB_DECL (type)); +#endif timevar_pop (TV_SYMOUT); } @@ -4973,8 +4998,7 @@ debug_start_source_file (filename) dwarfout_start_new_source_file (filename); #endif /* DWARF_DEBUGGING_INFO */ #ifdef DWARF2_DEBUGGING_INFO - if (debug_info_level == DINFO_LEVEL_VERBOSE - && write_symbols == DWARF2_DEBUG) + if (write_symbols == DWARF2_DEBUG) dwarf2out_start_source_file (filename); #endif /* DWARF2_DEBUGGING_INFO */ #ifdef SDB_DEBUGGING_INFO @@ -5000,8 +5024,7 @@ debug_end_source_file (lineno) dwarfout_resume_previous_source_file (lineno); #endif /* DWARF_DEBUGGING_INFO */ #ifdef DWARF2_DEBUGGING_INFO - if (debug_info_level == DINFO_LEVEL_VERBOSE - && write_symbols == DWARF2_DEBUG) + if (write_symbols == DWARF2_DEBUG) dwarf2out_end_source_file (); #endif /* DWARF2_DEBUGGING_INFO */ #ifdef SDB_DEBUGGING_INFO diff --git a/gcc/toplev.h b/gcc/toplev.h index d61c5bf..fdfa673 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -35,6 +35,7 @@ extern int read_integral_parameter PARAMS ((const char *, const char *, const int)); extern int count_error PARAMS ((int)); extern void strip_off_ending PARAMS ((char *, int)); +extern char *file_name_nondirectory PARAMS ((const char *)); extern void print_time PARAMS ((const char *, long)); extern void debug_start_source_file PARAMS ((const char *)); extern void debug_end_source_file PARAMS ((unsigned)); @@ -5386,6 +5386,26 @@ append_random_chars (template) template[6] = '\0'; } +/* P is a string that will be used in a symbol. Mask out any characters + that are not valid in that context. */ + +void +clean_symbol_name (p) + char *p; +{ + for (; *p; p++) + if (! ( ISDIGIT(*p) +#ifndef NO_DOLLAR_IN_LABEL /* this for `$'; unlikely, but... -- kr */ + || *p == '$' +#endif +#ifndef NO_DOT_IN_LABEL /* this for `.'; unlikely, but... */ + || *p == '.' +#endif + || ISUPPER(*p) + || ISLOWER(*p))) + *p = '_'; +} + /* Generate a name for a function unique to this translation unit. TYPE is some string to identify the purpose of this function to the linker or collect2. */ @@ -5431,19 +5451,7 @@ get_file_function_name_long (type) /* Don't need to pull weird characters out of global names. */ if (p != first_global_object_name) - { - for (q = buf+11; *q; q++) - if (! ( ISDIGIT(*q) -#ifndef NO_DOLLAR_IN_LABEL /* this for `$'; unlikely, but... -- kr */ - || *q == '$' -#endif -#ifndef NO_DOT_IN_LABEL /* this for `.'; unlikely, but... */ - || *q == '.' -#endif - || ISUPPER(*q) - || ISLOWER(*q))) - *q = '_'; - } + clean_symbol_name (buf + 11); return get_identifier (buf); } @@ -2435,6 +2435,7 @@ extern tree builtin_function PARAMS ((const char *, tree, int, /* In tree.c */ extern char *perm_calloc PARAMS ((int, long)); +extern void clean_symbol_name PARAMS ((char *)); extern tree get_file_function_name PARAMS ((int)); extern tree get_file_function_name_long PARAMS ((const char *)); extern tree get_set_constructor_bits PARAMS ((tree, char *, int)); |