Ping! Regards Senthil
On Fri, Apr 10, 2015 at 12:19:36PM +0530, Senthil Kumar Selvaraj wrote: > Hi, > > This (rather big) patch is an attempt to generate per function DWARF > information for functions that go into their own sections (through > -ffunction-section or otherwise). This is so that the GNU linker's > garbage collection mechanism can then remove all DWARF information when it > removes an unmarked function section. > > Most of the code for splitting off the debug information was adapted from > Jason's comdat-debug branch, with a few changes to move to the C++ > collection types. > > We started out with section groups, aiming to generate one section group > per function containing DWARF info AND code for the function, so that when > the linker gc's a function, it removes the whole section group. > But it turned out to be difficult to split all DWARF information - data that > goes into debug_ranges, for example, is maintained in a flat list, and we > found it hard to split it per function. > > If not all debug information is in the section group, references from the > "global" DWARF info into the section group results in the section group > itself not getting garbage collected - effectively breaking gc-sections. > > We then figured that the GNU binutils linker removes sections with the > SEC_DEBUGGING flag that are named with the function's text section as the > suffix (see https://www.sourceware.org/ml/binutils/2015-03/msg00326.html), > so > we currently generate sections named to match that, and then let the > linker work its magic. > > At a high level, this is what we do > > 1. In gen_subprogram_die, we see if the fde should go into a separate CU and > if yes, record it in a hash_table. > 2. In dwarf2_out_finish, we check if each subprogram die is in the table, > and > if yes, create a new CU for the die, along with a DW_TAG_imported_unit > die referring to the main CU. The newly created CU die is also > recorded in the hash table. > 3. In output_comp_unit, if the CU is in the hash table, we switch to > .debug_info<function_section_name> instead of debug_info_section. > 4. We do the same thing when generating aranges, pubnames and debug_loc. > > Bootstrapping x86_64-linux for c and c++ works, but there are quite a > few regression test failures. We'll analyze and follow-up on those. > > The formatting style is inconsistent, we'll fix those as well. > > We wanted to put it out before going ahead further. How does this look? > Are there are any major problems with this approach? > > For code like this, > > volatile int x; > void foo() { x--; } > int main() { return x; } > > $ ~/native/install/bin/gcc -ffunction-sections -g3 -Wa,-gdwarf-sections > -fdwarf-sections test.c -c > $ ~/native/install/bin/objdump -h test.o > <snip> > 5 .text.foo 00000016 0000000000000000 0000000000000000 00000050 2**0 > CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE > 6 .text.main 0000001a 0000000000000000 0000000000000000 00000066 2**0 > CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE > 7 .debug_info.text.main 00000044 0000000000000000 0000000000000000 > 00000080 2**0 > CONTENTS, RELOC, READONLY, DEBUGGING > 8 .debug_info.text.foo 00000040 0000000000000000 0000000000000000 > 000000b1 2**0 > CONTENTS, RELOC, READONLY, DEBUGGING > 9 .debug_info 0000004d 0000000000000000 0000000000000000 000000e5 2**0 > CONTENTS, RELOC, READONLY, DEBUGGING > 10 .debug_abbrev 0000007f 0000000000000000 0000000000000000 0000011e 2**0 > CONTENTS, READONLY, DEBUGGING > 11 .debug_aranges 00000020 0000000000000000 0000000000000000 00000194 > 2**0 > CONTENTS, RELOC, READONLY, DEBUGGING > 12 .debug_aranges.text.main 00000030 0000000000000000 0000000000000000 > 000001b3 2**0 > CONTENTS, RELOC, READONLY, DEBUGGING > 13 .debug_aranges.text.foo 00000030 0000000000000000 0000000000000000 > 000001d6 2**0 > CONTENTS, RELOC, READONLY, DEBUGGING > 14 .debug_ranges 00000070 0000000000000000 0000000000000000 000001f9 2**0 > CONTENTS, RELOC, READONLY, DEBUGGING > > Linking and dumping debug info shows that there is no debug info for > foo (which would have been gc'ed by the linker) > > $ ~/native/install/bin/gcc -Wl,--gc-sections test.o -Wl,-Map=test.map > $ cat test.map > <snip> > Discarded input sections > > <snip> > .text.foo 0x0000000000000000 0x16 test.o > .debug_info.text.foo > 0x0000000000000000 0x40 test.o > .debug_aranges.text.foo > 0x0000000000000000 0x30 test.o > .note.GNU-stack > 0x0000000000000000 0x0 test.o > .debug_line.text.foo > 0x0000000000000000 0x12 test.o > </snip> > > $ ~/native/install/bin/objdump -Wi a.out > Contents of the .debug_info section: > > Compilation Unit @ offset 0x0: > Length: 0x40 (32-bit) > Version: 4 > Abbrev Offset: 0x0 > Pointer Size: 8 > <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit) > <c> DW_AT_producer : (indirect string, offset: 0x567): GNU C11 5.0.0 > 20150331 (experimental) -mtune=generic -march=x86-64 -g3 -ffunction-sections > -fdwarf-sections > <10> DW_AT_language : 12 (ANSI C99) > <11> DW_AT_ranges : 0x30 > <15> DW_AT_low_pc : 0x0 > <1d> DW_AT_GNU_macros : 0x0 > <1><21>: Abbrev Number: 2 (DW_TAG_imported_unit) > <22> DW_AT_import : <0x4f> [Abbrev Number: 5] > <1><26>: Abbrev Number: 3 (DW_TAG_subprogram) > <27> DW_AT_external : 1 > <27> DW_AT_name : (indirect string, offset: 0x1928): main > <2b> DW_AT_decl_file : 1 > <2c> DW_AT_decl_line : 3 > <2d> DW_AT_type : <0x71> > <31> DW_AT_low_pc : 0x400476 > <39> DW_AT_high_pc : 0x1a > <41> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa) > <43> DW_AT_GNU_all_call_sites: 1 > <1><43>: Abbrev Number: 0 > Compilation Unit @ offset 0x44: > Length: 0x49 (32-bit) > Version: 4 > Abbrev Offset: 0x0 > Pointer Size: 8 > <0><4f>: Abbrev Number: 5 (DW_TAG_compile_unit) > <50> DW_AT_producer : (indirect string, offset: 0x567): GNU C11 > 5.0.0 20150331 (experimental) -mtune=generic -march=x86-64 -g3 > -ffunction-sections -fdwarf-sections > <54> DW_AT_language : 12 (ANSI C99) > <55> DW_AT_name : (indirect string, offset: 0x40b): test.c > <59> DW_AT_comp_dir : (indirect string, offset: 0x19): /home/saaadhu > <5d> DW_AT_ranges : 0x0 > <61> DW_AT_low_pc : 0x0 > <69> DW_AT_stmt_list : 0x0 > <6d> DW_AT_GNU_macros : 0x0 > <1><71>: Abbrev Number: 6 (DW_TAG_base_type) > <72> DW_AT_byte_size : 4 > <73> DW_AT_encoding : 5 (signed) > <74> DW_AT_name : int > <1><78>: Abbrev Number: 7 (DW_TAG_variable) > <79> DW_AT_name : x > <7b> DW_AT_decl_file : 1 > <7c> DW_AT_decl_line : 1 > <7d> DW_AT_type : <0x8b> > <81> DW_AT_external : 1 > <81> DW_AT_location : 9 byte block: 3 54 8 60 0 0 0 0 0 > (DW_OP_addr: 600854) > <1><8b>: Abbrev Number: 8 (DW_TAG_volatile_type) > <8c> DW_AT_type : <0x71> > <1><90>: Abbrev Number: 0 > > Regards > Senthil > > diff --git a/gcc/common.opt b/gcc/common.opt > index b49ac46..a73d176 100644 > --- a/gcc/common.opt > +++ b/gcc/common.opt > @@ -1277,6 +1277,10 @@ ffunction-sections > Common Report Var(flag_function_sections) > Place each function into its own section > > +fdwarf-sections > +Common Report Var(flag_dwarf_sections) Init(0) > +Place dwarf info for named functions into its own section when using DWARF > v4 debuginfo > + > fgcse > Common Report Var(flag_gcse) Optimization > Perform global common subexpression elimination > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index f9781f4..7e44c7c 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -392,6 +392,7 @@ Objective-C and Objective-C++ Dialects}. > -fearly-inlining -fipa-sra -fexpensive-optimizations -ffat-lto-objects @gol > -ffast-math -ffinite-math-only -ffloat-store -fexcess-precision=@var{style} > @gol > -fforward-propagate -ffp-contract=@var{style} -ffunction-sections @gol > +-fdwarf-sections @gol > -fgcse -fgcse-after-reload -fgcse-las -fgcse-lm -fgraphite-identity @gol > -fgcse-sm -fhoist-adjacent-loads -fif-conversion @gol > -fif-conversion2 -findirect-inlining @gol > @@ -9990,6 +9991,11 @@ You cannot use @command{gprof} on all systems if you > specify this option, and you may have problems with debugging if > you specify both this option and @option{-g}. > > +@item -fdwarf-sections > +@opindex fdwarf-sections > +Place dwarf info for named functions into its own section when using DWARF > +v4 debuginfo. > + > @item -fbranch-target-load-optimize > @opindex fbranch-target-load-optimize > Perform branch target register load optimization before prologue / epilogue > diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c > index 6c8e51f..6b519b8 100644 > --- a/gcc/dwarf2out.c > +++ b/gcc/dwarf2out.c > @@ -244,6 +244,35 @@ struct indirect_string_hasher : > ggc_hasher<indirect_string_node *> > > static GTY (()) hash_table<indirect_string_hasher> *debug_str_hash; > > +/* A set of local types referenced from outside their function. */ > + > +static GTY (()) hash_set<dw_die_ref> *local_type_template_args; > + > +static void > +switch_to_section_for_imported_decl (tree, const char *prefix); > + > +struct GTY((for_user)) imported_unit_node { > + tree decl; > + dw_die_ref die; > +}; > + > +struct imported_unit_hasher : ggc_hasher<imported_unit_node *> > +{ > + typedef dw_die_ref compare_type; > + > + static hashval_t hash (imported_unit_node *x) > + { > + return htab_hash_pointer (x->die); > + } > + static bool equal (imported_unit_node *x1, dw_die_ref x2) > + { > + return x1->die == x2; > + } > +}; > + > +static GTY (()) hash_table<imported_unit_hasher> *imported_unit_hash; > +static tree lookup_imported_unit_key (dw_die_ref); > + > /* With split_debug_info, both the comp_dir and dwo_name go in the > main object file, rather than the dwo, similar to the force_direct > parameter elsewhere but with additional complications: > @@ -290,6 +319,8 @@ static char *stripattributes (const char *); > static void output_call_frame_info (int); > static void dwarf2out_note_section_used (void); > > +static bool should_fde_move_to_imported_unit (dw_fde_ref); > + > /* Personality decl of current unit. Used only when assembler does not > support > personality CFI. */ > static GTY(()) rtx current_unit_personality; > @@ -3153,6 +3184,7 @@ static int is_symbol_die (dw_die_ref); > static inline bool is_template_instantiation (dw_die_ref); > static void assign_symbol_names (dw_die_ref); > static void break_out_includes (dw_die_ref); > +static int is_abstract_die (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); > @@ -3165,6 +3197,8 @@ 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, > dw_die_ref); > +static bool can_use_low_high_pc (); > +static void break_out_functions (dw_die_ref); > static void break_out_comdat_types (dw_die_ref); > static void copy_decls_for_unworthy_types (dw_die_ref); > > @@ -3173,7 +3207,6 @@ static void output_location_lists (dw_die_ref); > static int constant_size (unsigned HOST_WIDE_INT); > static unsigned long size_of_die (dw_die_ref); > static void calc_die_sizes (dw_die_ref); > -static void calc_base_type_die_sizes (void); > static void mark_dies (dw_die_ref); > static void unmark_dies (dw_die_ref); > static void unmark_all_dies (dw_die_ref); > @@ -3194,7 +3227,8 @@ static void add_enumerator_pubname (const char *, > dw_die_ref); > static void add_pubname_string (const char *, dw_die_ref); > static void add_pubtype (tree, dw_die_ref); > static void output_pubnames (vec<pubname_entry, va_gc> *); > -static void output_aranges (unsigned long); > +static inline unsigned get_range_idx (dw_attr_ref); > +static void output_aranges (); > static unsigned int add_ranges_num (int); > static unsigned int add_ranges (const_tree); > static void add_ranges_by_labels (dw_die_ref, const char *, const char *, > @@ -3656,11 +3690,10 @@ get_base_type_offset (dw_die_ref ref) > { > if (ref->die_offset) > return ref->die_offset; > - if (comp_unit_die ()->die_abbrev) > - { > - calc_base_type_die_sizes (); > - gcc_assert (ref->die_offset); > - } > + /* If we're calculating DIE offsets, this needs to be set. It's OK if > + it's unset during optimize_location_lists. */ > + if (next_die_offset) > + gcc_assert (ref->die_offset); > return ref->die_offset; > } > > @@ -6752,6 +6785,12 @@ is_symbol_die (dw_die_ref c) > { > return (is_type_die (c) > || is_declaration_die (c) > + || is_abstract_die (c) > + /* DW_TAG_GNU_call_site can refer to subprograms. */ > + || c->die_tag == DW_TAG_subprogram > + /* DW_TAG_imported_unit can refer to *_unit. */ > + || c->die_tag == DW_TAG_compile_unit > + || c->die_tag == DW_TAG_partial_unit > || c->die_tag == DW_TAG_namespace > || c->die_tag == DW_TAG_module); > } > @@ -6837,7 +6876,8 @@ assign_symbol_names (dw_die_ref die) > { > dw_die_ref c; > > - if (is_symbol_die (die) && !die->comdat_type_p) > + if (is_symbol_die (die) && !die->comdat_type_p && > + !die->die_id.die_symbol) > { > if (comdat_symbol_id) > { > @@ -6999,6 +7039,8 @@ break_out_includes (dw_die_ref die) > node = node->next) > { > int is_dupl; > + if (lookup_imported_unit_key (node->die) != NULL) > + continue; > > compute_section_prefix (node->die); > is_dupl = check_duplicate_cu (node->die, &cu_hash_table, > @@ -7015,6 +7057,100 @@ break_out_includes (dw_die_ref die) > } > } > > +static void > +copy_needed_base_types_loc (dw_die_ref unit, dw_loc_descr_ref loc, > + hash_map<dw_die_ref, dw_die_ref> *map) > +{ > + for (; loc; loc = loc->dw_loc_next) > + { > + dw_die_ref *op, *slot, copy; > + switch (loc->dw_loc_opc) > + { > + case DW_OP_GNU_convert: > + case DW_OP_GNU_reinterpret: > + if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const) > + continue; > + /* else fall through */ > + case DW_OP_GNU_const_type: > + op = &loc->dw_loc_oprnd1.v.val_die_ref.die; > + break; > + case DW_OP_GNU_regval_type: > + case DW_OP_GNU_deref_type: > + op = &loc->dw_loc_oprnd2.v.val_die_ref.die; > + break; > + > + /* DW_OP_GNU_entry_value has a location expression for its > + operand, so recurse. */ > + case DW_OP_GNU_entry_value: > + copy_needed_base_types_loc (unit, loc->dw_loc_oprnd1.v.val_loc, map); > + continue; > + > + default: > + continue; > + } > + > + gcc_assert ((*op)->die_tag == DW_TAG_base_type); > + > + slot = map->get (*op); > + if (slot) > + copy = *slot; > + else > + { > + /* Insert the base type at the beginning of unit's child list > + so that get_base_type_offset works. */ > + copy = ggc_cleared_alloc<die_node> (); > + copy->die_tag = DW_TAG_base_type; > + copy->die_sib = unit->die_child->die_sib; > + unit->die_child->die_sib = copy; > + add_AT_unsigned (copy, DW_AT_byte_size, > + get_AT_unsigned (*op, DW_AT_byte_size)); > + add_AT_unsigned (copy, DW_AT_encoding, > + get_AT_unsigned (*op, DW_AT_encoding)); > + map->put (*op, copy); > + } > + *op = copy; > + } > +} > + > +static void > +copy_needed_base_types_1 (dw_die_ref unit, dw_die_ref die, > + hash_map<dw_die_ref, dw_die_ref> *map) > +{ > + dw_die_ref c; > + dw_attr_ref a; > + unsigned ix; > + FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a) > + { > + switch (AT_class (a)) > + { > + case dw_val_class_loc: > + copy_needed_base_types_loc (unit, AT_loc (a), map); > + break; > + > + case dw_val_class_loc_list: > + { > + dw_loc_list_ref p = AT_loc_list (a); > + for (; p; p = p->dw_loc_next) > + copy_needed_base_types_loc (unit, p->expr, map); > + break; > + } > + > + default: > + break; > + } > + } > + > + FOR_EACH_CHILD (die, c, copy_needed_base_types_1 (unit, c, map)); > +} > + > +static void > +copy_needed_base_types (dw_die_ref unit) > +{ > + hash_map<dw_die_ref, dw_die_ref> *map = new hash_map<dw_die_ref, > dw_die_ref>; > + copy_needed_base_types_1 (unit, unit, map); > + delete map; > +} > + > /* Return non-zero if this DIE is a declaration. */ > > static int > @@ -7030,6 +7166,37 @@ is_declaration_die (dw_die_ref die) > return 0; > } > > +/* Return non-zero if this DIE is part of an abstract inline. That is, if > + it's an inline function or a variable, label or parameter of an inline > + function. */ > + > +static int > +is_abstract_die (dw_die_ref die) > +{ > + switch (die->die_tag) > + { > + case DW_TAG_subprogram: > + case DW_TAG_variable: > + case DW_TAG_label: > + case DW_TAG_formal_parameter: > + break; > + > + default: > + return 0; > + } > + > + for (; die->die_tag != DW_TAG_subprogram; die = die->die_parent) > + { > + if (die->die_tag == DW_TAG_compile_unit > + || die->die_tag == DW_TAG_namespace) > + return 0; > + } > + > + if (get_AT (die, DW_AT_inline)) > + return 1; > + return 0; > +} > + > /* Return non-zero if this DIE is nested inside a subprogram. */ > > static int > @@ -7480,6 +7647,284 @@ remove_child_or_replace_with_skeleton (dw_die_ref > unit, dw_die_ref child, > return skeleton; > } > > + > +static void > +record_imported_unit_key (dw_die_ref die, tree decl) > +{ > + struct imported_unit_node *mp; > + > + if (imported_unit_hash == NULL) > + imported_unit_hash = hash_table<imported_unit_hasher>::create_ggc (10); > + > + imported_unit_node **slot = imported_unit_hash->find_slot_with_hash (die, > + htab_hash_pointer (die), INSERT); > + if (*slot == NULL) > + { > + mp = ggc_cleared_alloc<imported_unit_node> (); > + mp->die = die; > + mp->decl = decl; > + *slot = mp; > + } > +} > + > +static tree > +lookup_imported_unit_key (dw_die_ref die) > +{ > + struct imported_unit_node *mp; > + > + if (imported_unit_hash == NULL) > + return NULL; > + > + mp = imported_unit_hash->find_with_hash (die, htab_hash_pointer (die)); > + > + if (mp) > + return mp->decl; > + else > + return NULL; > +} > + > +static bool > +can_use_low_high_pc () > +{ > + unsigned fde_idx; > + dw_fde_ref fde; > + bool any_non_cu_ranges; > + > + any_non_cu_ranges = (ranges_table_in_use > 0); > + if ((any_non_cu_ranges && have_multiple_function_sections) > + || cold_text_section_used) > + return false; > + > + if (!fde_vec) > + return false; > + > + /* If we don't need AT_ranges for either of those reasons, are there > + any extra function sections that belong to the main CU? */ > + FOR_EACH_VEC_ELT (*fde_vec, fde_idx, fde) > + { > + if (should_fde_move_to_imported_unit (fde)) > + return false; > + } > + > + return true; > +} > + > +static void > +split_out_local_types (dw_die_ref old, dw_die_ref decl, bool decl_is_new) > +{ > + dw_die_ref c, nc; > + dw_die_ref prev = old->die_child; > + > + if (prev) do { > + force_loop: > + c = prev->die_sib; > + > + switch (c->die_tag) > + { > + case DW_TAG_formal_parameter: > + case DW_TAG_template_type_param: > + case DW_TAG_template_value_param: > + case DW_TAG_GNU_template_template_param: > + /* If we're making a new declaration, we need to copy these > + over. */ > + if (decl_is_new) > + { > + nc = new_die (c->die_tag, decl, NULL_TREE); > + if (c->die_tag == DW_TAG_GNU_template_template_param) > + add_AT_string (nc, DW_AT_GNU_template_name, > + get_AT_string (c, DW_AT_GNU_template_name)); > + else > + add_AT_die_ref (nc, DW_AT_type, get_AT_ref (c, DW_AT_type)); > + if (get_AT_flag (c, DW_AT_artificial)) > + add_AT_flag (nc, DW_AT_artificial, 1); > + } > + break; > + > + case DW_TAG_enumeration_type: > + case DW_TAG_class_type: > + case DW_TAG_structure_type: > + /* Types that are used from outside the function need to move > + into the declaration, but we should keep a stub locally for > + name lookup. */ > + if (local_type_template_args->contains (c)) > + { > + nc = ggc_cleared_alloc<die_node> (); > + nc->die_tag = DW_TAG_typedef; > + add_AT_die_ref (nc, DW_AT_type, c); > + replace_child (c, nc, prev); > + add_child_die (decl, c); > + c = nc; > + } > + break; > + > + case DW_TAG_lexical_block: > + /* Recurse into lexical blocks, then leave them in place. */ > + split_out_local_types (c, decl, decl_is_new); > + break; > + > + default: > + /* Unnamed types that are used from outside the function can > + just move. */ > + if (is_type_die (c) && local_type_template_args->contains (c)) > + { > + remove_child_with_prev (c, prev); > + add_child_die (decl, c); > + if (old->die_child == NULL) > + /* We removed the last child from old. */ > + return; > + else > + /* We don't want to advance prev. */ > + goto force_loop; > + } > + /* Everything else should stay in the COMDAT die. */ > + break; > + } > + > + prev = c; > + } > + while (c != old->die_child); > +} > + > +static dw_die_ref > +split_out_function_skeleton (dw_die_ref old) > +{ > + dw_die_ref decl; > + dw_die_ref new_ = NULL; > + > + /* Is there already a declaration DIE we can use? */ > + decl = get_AT_ref (old, DW_AT_specification); > + if (!decl) > + { > + /* Nope, need to make one and move attributes over. */ > + dw_attr_ref a; > + unsigned ix; > + > + decl = new_ = ggc_cleared_alloc<die_node> (); > + new_->die_tag = DW_TAG_subprogram; > + > + add_AT_flag (new_, DW_AT_declaration, 1); > + add_AT_die_ref (old, DW_AT_specification, new_); > + > + FOR_EACH_VEC_SAFE_ELT (old->die_attr, ix, a) > + switch (a->dw_attr) > + { > + case DW_AT_object_pointer: > + case DW_AT_virtuality: > + case DW_AT_accessibility: > + case DW_AT_explicit: > + /* Member function; we should have already had a declaration. */ > + gcc_unreachable (); > + break; > + > + case DW_AT_name: > + case DW_AT_type: > + case DW_AT_artificial: > + case DW_AT_decl_file: > + case DW_AT_decl_line: > + case DW_AT_external: > + case DW_AT_pure: > + case DW_AT_calling_convention: > + case DW_AT_prototyped: > + case DW_AT_elemental: > + case DW_AT_recursive: > + /* Move these to the declaration. */ > + add_dwarf_attr (new_, a); > + old->die_attr->ordered_remove(ix); > + --ix; > + break; > + > + default: > + /* Leave anything else in the definition. */ > + break; > + } > + } > + > + split_out_local_types (old, decl, decl == new_); > + > + return new_; > +} > + > +bool > +gather_local_type_fns_r ( > + const dw_die_ref &slot, > + hash_set<dw_die_ref> *local_type_fns) > +{ > + dw_die_ref die = slot; > + for (die = die->die_parent; die; die = die->die_parent) > + if (die->die_tag == DW_TAG_subprogram) > + break; > + if (die && lookup_imported_unit_key (die)) > + local_type_fns->add (die); > + return true; > +} > + > +static struct hash_set<dw_die_ref> * > +gather_local_type_fns (void) > +{ > + hash_set<dw_die_ref> *local_type_fns; > + if (local_type_template_args == NULL) > + return NULL; > + > + local_type_fns = new hash_set<dw_die_ref>; > + local_type_template_args->traverse<hash_set<dw_die_ref>*, > gather_local_type_fns_r>( > + local_type_fns); > + return local_type_fns; > +} > + > +static void > +break_out_functions (dw_die_ref die) > +{ > + dw_die_ref c, prev; > + bool found = false; > + limbo_die_node *node; > + hash_set<dw_die_ref> *local_type_fns = gather_local_type_fns (); > + > + prev = die->die_child; > + if (prev == NULL) > + return; > + > + do > + { > + tree key; > + c = prev->die_sib; > + if (c->die_tag == DW_TAG_subprogram > + && (key = lookup_imported_unit_key (c))) > + { > + dw_die_ref nc; > + dw_die_ref unit = gen_compile_unit_die (NULL); > + dw_die_ref imp = new_die (DW_TAG_imported_unit, unit, > + NULL_TREE); > + add_AT_die_ref (imp, DW_AT_import, comp_unit_die ()); > + if (local_type_fns > + && local_type_fns->contains (c) > + && (nc = split_out_function_skeleton (c))) > + replace_child (c, nc, prev); > + else > + remove_child_with_prev (c, prev); > + add_child_die (unit, c); > + > + record_imported_unit_key (unit, key); > + found = true; > + } > + else > + prev = c; > + } > + while (die->die_child && (c != die->die_child)); > + > + if (!found) > + return; > + > + assign_symbol_names (die); > + for (node = limbo_die_list; > + node; > + node = node->next) > + if (lookup_imported_unit_key (node->die) != NULL) > + { > + copy_needed_base_types (node->die); > + assign_symbol_names (node->die); > + } > +} > + > /* Traverse the DIE and set up additional .debug_types sections for each > type worthy of being placed in a COMDAT section. */ > > @@ -8164,34 +8609,23 @@ calc_die_sizes (dw_die_ref die) > next_die_offset += 1; > } > > -/* Size just the base type children at the start of the CU. > - This is needed because build_abbrev needs to size locs > - and sizing of type based stack ops needs to know die_offset > - values for the base types. */ > +/* Return the size of the unit starting at DIE, assuming calc_die_sizes has > + already been run. */ > > -static void > -calc_base_type_die_sizes (void) > +static unsigned long > +cu_size (dw_die_ref die) > { > - unsigned long die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE; > - unsigned int i; > - dw_die_ref base_type; > -#if ENABLE_ASSERT_CHECKING > - dw_die_ref prev = comp_unit_die ()->die_child; > -#endif > - > - die_offset += size_of_die (comp_unit_die ()); > - for (i = 0; base_types.iterate (i, &base_type); i++) > + unsigned terminators = 0; > + /* die_child points to the last child of a DIE, so we can find the last > + die by chasing down die_child. */ > + while (die->die_child) > { > -#if ENABLE_ASSERT_CHECKING > - gcc_assert (base_type->die_offset == 0 > - && prev->die_sib == base_type > - && base_type->die_child == NULL > - && base_type->die_abbrev); > - prev = base_type; > -#endif > - base_type->die_offset = die_offset; > - die_offset += size_of_die (base_type); > + ++terminators; > + die = die->die_child; > } > + /* Then add the size of the last die and the null bytes to terminate > + sibling lists. */ > + return die->die_offset + size_of_die (die) + terminators; > } > > /* Set the marks for a die and its children. We do this so > @@ -8289,7 +8723,8 @@ size_of_pubnames (vec<pubname_entry, va_gc> *names) > > size = DWARF_PUBNAMES_HEADER_SIZE; > FOR_EACH_VEC_ELT (*names, i, p) > - if (include_pubname_in_output (names, p)) > + if ((include_pubname_in_output (names, p)) && > + (!lookup_imported_unit_key (p->die))) > size += strlen (p->name) + DWARF_OFFSET_SIZE + 1 + space_for_flags; > > size += DWARF_OFFSET_SIZE; > @@ -8317,7 +8752,8 @@ size_of_aranges (void) > > FOR_EACH_VEC_ELT (*fde_vec, fde_idx, fde) > { > - if (DECL_IGNORED_P (fde->decl)) > + if (DECL_IGNORED_P (fde->decl) || > + should_fde_move_to_imported_unit (fde)) > continue; > if (!fde->in_std_section) > size += 2 * DWARF2_ADDR_SIZE; > @@ -9107,6 +9543,7 @@ output_comp_unit (dw_die_ref die, int output_if_empty) > { > const char *secname, *oldsym; > char *tmp; > + tree key; > > /* Unless we are outputting main CU, we may throw away empty ones. */ > if (!output_if_empty && die->die_child == NULL) > @@ -9129,21 +9566,37 @@ 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_id.die_symbol; > - if (oldsym) > + key = lookup_imported_unit_key (die); > + if (key) > { > - tmp = XALLOCAVEC (char, strlen (oldsym) + 24); > + const char *decl_name; > + switch_to_section_for_imported_decl (key, > + DEBUG_INFO_SECTION); > + decl_name = targetm.strip_name_encoding (IDENTIFIER_POINTER > + (DECL_ASSEMBLER_NAME(key))); > + > + ASM_OUTPUT_DEBUG_LABEL (asm_out_file, decl_name, 0); > > - sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym); > - secname = tmp; > - die->die_id.die_symbol = NULL; > - switch_to_section (get_section (secname, SECTION_DEBUG, NULL)); > + oldsym = die->die_id.die_symbol; > } > else > { > - switch_to_section (debug_info_section); > - ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label); > - info_section_emitted = true; > + oldsym = die->die_id.die_symbol; > + if (oldsym && (imported_unit_hash && imported_unit_hash->elements() == > 0)) > + { > + tmp = XALLOCAVEC (char, strlen (oldsym) + 24); > + > + sprintf (tmp, ".gnu.linkonce.wi.%s", oldsym); > + secname = tmp; > + die->die_id.die_symbol = NULL; > + switch_to_section (get_section (secname, SECTION_DEBUG, NULL)); > + } > + else > + { > + switch_to_section (debug_info_section); > + ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label); > + info_section_emitted = true; > + } > } > > /* Output debugging information. */ > @@ -9516,41 +9969,55 @@ output_pubname (dw_offset die_offset, pubname_entry > *entry) > visible names; or the public types table used to find type definitions. > */ > > static void > -output_pubnames (vec<pubname_entry, va_gc> *names) > +output_pubnames_header (unsigned length, const char *label, > + unsigned long cu_length) > { > - unsigned i; > - unsigned long pubnames_length = size_of_pubnames (names); > - pubname_ref pub; > - > 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, pubnames_length, "Pub Info > Length"); > + dw2_asm_output_data (DWARF_OFFSET_SIZE, length, "Pub Info Length"); > > /* Version number for pubnames/pubtypes is independent of dwarf version. > */ > dw2_asm_output_data (2, 2, "DWARF Version"); > > if (dwarf_split_debug_info) > - dw2_asm_output_offset (DWARF_OFFSET_SIZE, > debug_skeleton_info_section_label, > + dw2_asm_output_offset (DWARF_OFFSET_SIZE, > + debug_skeleton_info_section_label, > debug_skeleton_info_section, > "Offset of Compilation Unit Info"); > else > - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, > - debug_info_section, > + dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, debug_info_section, > "Offset of Compilation Unit Info"); > - dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset, > + dw2_asm_output_data (DWARF_OFFSET_SIZE, cu_length, > "Compilation Unit Length"); > +} > + > +static void > +output_pubnames (vec<pubname_entry, va_gc> *names) > +{ > + unsigned i; > + unsigned long pubnames_length = size_of_pubnames (names); > + pubname_ref pub; > + limbo_die_node *node; > + > + if (names == pubname_table) > + switch_to_section (debug_pubnames_section); > + else > + switch_to_section (debug_pubtypes_section); > + > + output_pubnames_header (pubnames_length, debug_info_section_label, > + next_die_offset); > > FOR_EACH_VEC_ELT (*names, i, pub) > { > + /* Skip imported units, as they have their own CUs. */ > + if (lookup_imported_unit_key (pub->die)) > + continue; > + > if (include_pubname_in_output (names, pub)) > { > dw_offset die_offset = pub->die->die_offset; > > - /* We shouldn't see pubnames for DIEs outside of the main CU. */ > - if (names == pubname_table && pub->die->die_tag != > DW_TAG_enumerator) > - gcc_assert (pub->die->die_mark); > - > /* If we're putting types in their own .debug_types sections, > the .debug_pubtypes table will still point to the compile > unit (not the type unit), so we want to use the offset of > @@ -9570,39 +10037,76 @@ output_pubnames (vec<pubname_entry, va_gc> *names) > } > > dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL); > -} > - > -/* Output public names and types tables if necessary. */ > > -static void > -output_pubtables (void) > -{ > - if (!want_pubnames () || !info_section_emitted) > + if (names == pubtype_table) > return; > > - switch_to_section (debug_pubnames_section); > - output_pubnames (pubname_table); > - /* ??? Only defined by DWARF3, but emitted by Darwin for DWARF2. > - It shouldn't hurt to emit it always, since pure DWARF2 consumers > - simply won't look for the section. */ > - switch_to_section (debug_pubtypes_section); > - output_pubnames (pubtype_table); > + /* Now output the pubnames for each CU. */ > + for (node = limbo_die_list; node; node = node->next) > + { > + dw_die_ref cu = node->die; > + dw_die_ref die; > + tree key = lookup_imported_unit_key (cu); > + char *label; > + const char *name, *decl_name; > + unsigned long size; > + bool found = false; > + > + if (!key) > + continue; > + > + die = cu->die_child->die_sib; > + if (die->die_tag == DW_TAG_imported_unit) > + die = die->die_sib; > + gcc_assert (die->die_tag == DW_TAG_subprogram); > + > + /* Find respective pubname entry. */ > + FOR_EACH_VEC_ELT (*names, i, pub) > + { > + if (die == pub->die) > + { > + found = true; > + break; > + } > + } > + > + gcc_assert (found); > + name = pub->name; > + size = (DWARF_PUBNAMES_HEADER_SIZE + strlen(name) + DWARF_OFFSET_SIZE > + + 1 + DWARF_OFFSET_SIZE); > + > + decl_name = IDENTIFIER_POINTER (DECL_NAME (key)); > + label = XALLOCAVEC (char, strlen (decl_name) + 10); > + ASM_GENERATE_INTERNAL_LABEL (label, decl_name, 0); > + > + switch_to_section_for_imported_decl (key, DEBUG_PUBNAMES_SECTION); > + > + output_pubnames_header (size, label, cu_size (cu)); > + output_pubname (die->die_offset, pub); > + dw2_asm_output_data (DWARF_OFFSET_SIZE, 0 , NULL); > + } > } > > +static inline unsigned > +get_range_idx (dw_attr_ref a) > +{ > + gcc_assert (AT_class (a) == dw_val_class_range_list); > + return a->dw_attr_val.v.val_offset / 2 / DWARF2_ADDR_SIZE; > +} > > /* Output the information that goes into the .debug_aranges table. > Namely, define the beginning and ending address range of the > text section generated for this compilation unit. */ > > static void > -output_aranges (unsigned long aranges_length) > +output_aranges_header (unsigned long length, const char *label) > { > unsigned i; > > 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, aranges_length, > + dw2_asm_output_data (DWARF_OFFSET_SIZE, length, > "Length of Address Ranges Info"); > /* Version number for aranges is still 2, even up to DWARF5. */ > dw2_asm_output_data (2, 2, "DWARF Version"); > @@ -9611,7 +10115,7 @@ output_aranges (unsigned long aranges_length) > debug_skeleton_info_section, > "Offset of Compilation Unit Info"); > else > - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, > + dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, > debug_info_section, > "Offset of Compilation Unit Info"); > dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address"); > @@ -9627,6 +10131,28 @@ output_aranges (unsigned long aranges_length) > for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2) > dw2_asm_output_data (2, 0, NULL); > } > +} > + > +static unsigned > +count_ranges (dw_attr_ref a) > +{ > + unsigned idx, count; > + > + count = 0; > + for (idx = get_range_idx (a); ranges_table[idx].num != 0; ++idx) > + ++count; > + > + return count; > +} > + > +static void > +output_aranges () > +{ > + unsigned long aranges_length = size_of_aranges (); > + limbo_die_node *node; > + > + switch_to_section (debug_aranges_section); > + output_aranges_header (aranges_length, debug_info_section_label); > > /* It is necessary not to output these entries if the sections were > not used; if the sections were not used, the length will be 0 and > @@ -9654,7 +10180,8 @@ output_aranges (unsigned long aranges_length) > > FOR_EACH_VEC_ELT (*fde_vec, fde_idx, fde) > { > - if (DECL_IGNORED_P (fde->decl)) > + if (DECL_IGNORED_P (fde->decl) || > + should_fde_move_to_imported_unit (fde)) > continue; > if (!fde->in_std_section) > { > @@ -9676,6 +10203,72 @@ output_aranges (unsigned long aranges_length) > /* Output the terminator words. */ > dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL); > dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL); > + > + /* Now output the aranges for function CUs. */ > + for (node = limbo_die_list; node; node = node->next) > + { > + dw_die_ref cu = node->die; > + dw_attr_ref a; > + unsigned num_ranges; > + tree key; > + char *label; > + const char *decl_name; > + > + if ((a = get_AT (cu, DW_AT_ranges))) > + num_ranges = count_ranges (a); > + else if ((a = get_AT (cu, DW_AT_low_pc))) > + num_ranges = 1; > + else > + continue; > + > + key = lookup_imported_unit_key (cu); > + if (key) > + { > + switch_to_section_for_imported_decl (key, > + DEBUG_ARANGES_SECTION); > + } > + > + aranges_length = (DWARF_ARANGES_HEADER_SIZE > + + 2 * num_ranges * DWARF2_ADDR_SIZE > + + 2 * DWARF2_ADDR_SIZE); > + > + decl_name = targetm.strip_name_encoding (IDENTIFIER_POINTER > + (DECL_ASSEMBLER_NAME (key))); > + label = XALLOCAVEC (char, strlen (decl_name) + 10); > + ASM_GENERATE_INTERNAL_LABEL (label, decl_name , 0); > + output_aranges_header (aranges_length, label); > + if (a->dw_attr == DW_AT_low_pc) > + { > + const char *start = AT_lbl (a); > + const char *end = get_AT_hi_pc (cu); > + dw2_asm_output_addr (DWARF2_ADDR_SIZE, start, "Address"); > + dw2_asm_output_delta (DWARF2_ADDR_SIZE, end, start, "Length"); > + } > + else > + { > + unsigned idx; > + for (idx = get_range_idx (a); ; ++idx) > + { > + int num = ranges_table[idx].num; > + if (num == 0) > + break; > + else if (num < 0) > + { > + int lab_idx = - num - 1; > + const char *start = ranges_by_label[lab_idx].begin; > + const char *end = ranges_by_label[lab_idx].end; > + dw2_asm_output_addr (DWARF2_ADDR_SIZE, start, "Address"); > + dw2_asm_output_delta (DWARF2_ADDR_SIZE, end, start, > "Length"); > + } > + else > + /* We shouldn't need to handle block ranges here. */ > + gcc_unreachable (); > + } > + } > + /* Output the terminator words. */ > + dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL); > + dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL); > + } > } > > /* Add a new entry to .debug_ranges. Return the offset at which it > @@ -13808,6 +14401,21 @@ secname_for_decl (const_tree decl) > return secname; > } > > +static void > +switch_to_section_for_imported_decl (tree decl, const char *prefix) > +{ > + const char *section_name; > + char *tmp; > + section_name = DECL_SECTION_NAME (decl); > + if (!section_name) > + section_name = function_section (decl)->named.name; > + tmp = XALLOCAVEC (char, strlen (section_name) + > + strlen (prefix) + 1); > + > + sprintf (tmp, "%s%s", prefix, section_name); > + switch_to_section (get_section (tmp, SECTION_DEBUG, NULL)); > +} > + > /* Return true when DECL_BY_REFERENCE is defined and set for DECL. */ > > static bool > @@ -18386,6 +18994,25 @@ gen_call_site_die (tree decl, dw_die_ref subr_die, > return die; > } > > +static bool > +should_fde_move_to_imported_unit (dw_fde_ref fde) > +{ > + dw_die_ref die; > + > + if (!flag_dwarf_sections) > + return false; > + > + if (fde->in_std_section || > + (fde->dw_fde_second_begin && fde->second_in_std_section)) > + return false; > + > + if (!(die = lookup_decl_die (fde->decl))) > + return false; > + > + return !get_AT (die, DW_AT_abstract_origin) && > + !get_AT (die, DW_AT_specification); > +} > + > /* Generate a DIE to represent a declared function (either file-scope or > block-local). */ > > @@ -18732,6 +19359,10 @@ gen_subprogram_die (tree decl, dw_die_ref > context_die) > add_AT_loc (subr_die, DW_AT_frame_base, list->expr); > } > > + if (should_fde_move_to_imported_unit (fun->fde)) > + if (context_die == comp_unit_die ()) > + record_imported_unit_key (subr_die, decl); > + > /* Compute a displacement from the "steady-state frame pointer" to > the CFA. The former is what all stack slots and argument slots > will reference in the rtl; the latter is what we've told the > @@ -24644,6 +25275,9 @@ dwarf2out_finish (const char *filename) > if (flag_eliminate_unused_debug_types) > prune_unused_types (); > > + if (flag_dwarf_sections) > + break_out_functions (comp_unit_die ()); > + > /* Generate separate COMDAT sections for type DIEs. */ > if (use_debug_types) > { > @@ -24699,8 +25333,7 @@ dwarf2out_finish (const char *filename) > > /* We can only use the low/high_pc attributes if all of the code was > in .text. */ > - if (!have_multiple_function_sections > - || (dwarf_version < 3 && dwarf_strict)) > + if (can_use_low_high_pc () || (dwarf_version < 3 && dwarf_strict)) > { > /* Don't add if the CU has no associated code. */ > if (text_section_used) > @@ -24709,9 +25342,9 @@ dwarf2out_finish (const char *filename) > } > else > { > + bool range_list_added = false; > unsigned fde_idx; > dw_fde_ref fde; > - bool range_list_added = false; > > if (text_section_used) > add_ranges_by_labels (main_comp_unit_die, text_section_label, > @@ -24720,6 +25353,8 @@ dwarf2out_finish (const char *filename) > add_ranges_by_labels (main_comp_unit_die, cold_text_section_label, > cold_end_label, &range_list_added, true); > > + if (fde_vec) > + { > FOR_EACH_VEC_ELT (*fde_vec, fde_idx, fde) > { > if (DECL_IGNORED_P (fde->decl)) > @@ -24733,6 +25368,7 @@ dwarf2out_finish (const char *filename) > fde->dw_fde_second_end, &range_list_added, > true); > } > + } > > if (range_list_added) > { > @@ -24749,14 +25385,102 @@ dwarf2out_finish (const char *filename) > } > } > > + /* Also add ranges to the CUs for broken out functions. */ > + for (node = limbo_die_list; node; node = node->next) > + { > + dw_die_ref c = node->die->die_child; > + bool added = false; > + dw_attr_ref a; > + > + if (c == NULL) > + continue; > + c = c->die_sib; > + if (c->die_tag == DW_TAG_imported_unit) > + c = c->die_sib; > + if (c->die_tag != DW_TAG_subprogram) > + continue; > + > + if (c->die_sib && c->die_sib->die_tag == DW_TAG_subprogram) > + { > + /* There are multiple functions in this CU, so we need to add > + ranges for all of them. */ > + dw_die_ref next = c; > + do > + { > + c = next; > + next = c->die_sib; > + if (c->die_tag == DW_TAG_subprogram) > + { > + if ((a = get_AT (c, DW_AT_ranges))) > + { > + /* Copy the ranges from this function. */ > + unsigned idx; int num; > + for (idx = get_range_idx (a); > + (num = ranges_table[idx].num) != 0; > + ++idx) > + { > + if (num < 0) > + { > + int idx2 = - num - 1; > + const char *start = ranges_by_label[idx2].begin; > + const char *end = ranges_by_label[idx2].end; > + add_ranges_by_labels (node->die, start, end, > + &added, true); > + } > + else > + /* We shouldn't need to handle block ranges here. > */ > + gcc_unreachable (); > + } > + } > + else > + add_ranges_by_labels (node->die, get_AT_low_pc (c), > + get_AT_hi_pc (c), &added, true); > + } > + } > + while (c != node->die->die_child); > + /* Set the base address. */ > + add_AT_addr (node->die, DW_AT_low_pc, const0_rtx, true); > + add_ranges (NULL); > + } > + /* We need to use DW_AT_ranges on the CU if any descendant DIE does > + so that we can set up a base address; for now, rather than search > + descendants let's just use it if we used DW_AT_ranges anywhere in > + this translation unit. > + > + FIXME better would be to use low/hi_pc if the function does and > + make any ranges in descendant dies relative to the low_pc. */ > + > + else if (ranges_table_in_use > 0) > + { > + if ((a = get_AT (c, DW_AT_ranges))) > + add_AT_range_list (node->die, DW_AT_ranges, > + a->dw_attr_val.v.val_offset, true); > + else > + add_ranges_by_labels (node->die, get_AT_low_pc (c), > + get_AT_hi_pc (c), &added, true); > + add_AT_addr (node->die, DW_AT_low_pc, const0_rtx, true); > + add_ranges (NULL); > + } > + else > + { > + add_AT_lbl_id (node->die, DW_AT_low_pc, get_AT_low_pc (c)); > + add_AT_lbl_id (node->die, DW_AT_high_pc, get_AT_hi_pc (c)); > + } > + } > if (debug_info_level >= DINFO_LEVEL_TERSE) > add_AT_lineptr (main_comp_unit_die, DW_AT_stmt_list, > debug_line_section_label); > > if (have_macinfo) > - add_AT_macptr (comp_unit_die (), > + { > + add_AT_macptr (comp_unit_die (), > dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros, > macinfo_section_label); > + for (node = limbo_die_list; node; node = node->next) > + add_AT_macptr (node->die, > + dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros, > + macinfo_section_label); > + } > > if (dwarf_split_debug_info) > { > @@ -24777,7 +25501,11 @@ dwarf2out_finish (const char *filename) > } > > if (have_location_lists) > - optimize_location_lists (comp_unit_die ()); > + { > + optimize_location_lists (comp_unit_die ()); > + for (node = limbo_die_list; node; node = node->next) > + optimize_location_lists (node->die); > + } > > save_macinfo_strings (); > > @@ -24875,13 +25603,39 @@ dwarf2out_finish (const char *filename) > /* Output location list section if necessary. */ > if (have_location_lists) > { > + tree key; > /* Output the location lists info. */ > switch_to_section (debug_loc_section); > ASM_OUTPUT_LABEL (asm_out_file, loc_section_label); > output_location_lists (comp_unit_die ()); > + > + for (node = limbo_die_list; node; node = node->next) > + { > + if ((key = lookup_imported_unit_key (node->die))) > + { > + switch_to_section_for_imported_decl (key, > + DEBUG_LOC_SECTION); > + output_location_lists (node->die); > + } > + } > + } > + > + /* Output public names table if necessary. */ > + if (!pubname_table->is_empty() && want_pubnames ()) > + { > + gcc_assert (info_section_emitted); > + output_pubnames (pubname_table); > } > > - output_pubtables (); > + /* Output public types table if necessary. */ > + /* ??? Only defined by DWARF3, but emitted by Darwin for DWARF2. > + It shouldn't hurt to emit it always, since pure DWARF2 consumers > + simply won't look for the section. */ > + if (!pubtype_table->is_empty() && want_pubnames ()) > + { > + gcc_assert (info_section_emitted); > + output_pubnames (pubtype_table); > + } > > /* Output the address range information if a CU (.debug_info section) > was emitted. We output an empty table even if we had no functions > @@ -24890,10 +25644,7 @@ dwarf2out_finish (const char *filename) > generate a table that would have contained data. */ > if (info_section_emitted) > { > - unsigned long aranges_length = size_of_aranges (); > - > - switch_to_section (debug_aranges_section); > - output_aranges (aranges_length); > + output_aranges (); > } > > /* Output ranges section if necessary. */ > @@ -25022,6 +25773,7 @@ dwarf2out_c_finalize (void) > base_types.release (); > XDELETEVEC (producer_string); > producer_string = NULL; > + imported_unit_hash = NULL; > } > > #include "gt-dwarf2out.h" > diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-sections-1.c > b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-sections-1.c > new file mode 100644 > index 0000000..b2d0ee6 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-sections-1.c > @@ -0,0 +1,34 @@ > +/* { dg-do compile } */ > +/* { dg-options "-ffunction-sections -fdwarf-sections -gdwarf-4 -gpubnames" > } */ > +/* { dg-final { scan-assembler-times "\.section\[\t \]\[^\n\]*debug_info" 4 > } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_infomyTextSection" 1 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_info\.text\.bar_func" 1 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_info\.text\.main" 1 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t \]\[^\n\]*debug_aranges" > 4 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_arangesmyTextSection" 1 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_aranges\.text\.bar_func" 1 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_aranges\.text\.main" 1 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_pubnames" 4 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_pubnamesmyTextSection" 1 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_pubnames\.text\.bar_func" 1 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_pubnames\.text\.main" 1 } } */ > + > +int gvar1, i1; > + > +void foo (int i) __attribute__((section ("myTextSection"))); > +void bar () asm ("bar_func"); > + > +void foo (int i) { > + gvar1 += i; > +} > + > +void bar () { > + gvar1 -= 1; > + return; > +} > + > +int main () { > + foo (i1); > + i1++; > + return 1; > +} > diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-sections-2.c > b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-sections-2.c > new file mode 100644 > index 0000000..ae918b7 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/dwarf-sections-2.c > @@ -0,0 +1,28 @@ > +/* { dg-do compile } */ > +/* { dg-options "-fdwarf-sections -gdwarf-4 -gpubnames" } */ > +/* { dg-final { scan-assembler-times "\.section\[\t \]\[^\n\]*debug_info" 2 > } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_info.NonStdSection" 1 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t \]\[^\n\]*debug_aranges" > 2 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_aranges.NonStdSection" 1 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_pubnames" 2 } } */ > +/* { dg-final { scan-assembler-times "\.section\[\t > \]\[^\n\]*debug_pubnames.NonStdSection" 1 } } */ > + > +int gvar1, i1; > + > +void foo (int i) __attribute__((section (".NonStdSection"))); > +void bar () asm ("bar_func"); > + > +void foo (int i) { > + gvar1 += i; > +} > + > +void bar () { > + gvar1 -= 1; > + return; > +} > + > +int main () { > + bar (); > + i1++; > + return 1; > +} > diff --git a/gcc/toplev.c b/gcc/toplev.c > index b06eed3..8548912 100644 > --- a/gcc/toplev.c > +++ b/gcc/toplev.c > @@ -1603,6 +1603,12 @@ process_options (void) > } > } > > + if (flag_dwarf_sections && (dwarf_version < 4)) > + { > + warning (0, "-fdwarf-sections not supported for dwarf version lower > than 4"); > + flag_dwarf_sections = 0; > + } > + > #ifndef HAVE_prefetch > if (flag_prefetch_loop_arrays > 0) > {