re PR go/78628 (GO fails to build a translation unit decl)
authorRichard Biener <rguenther@suse.de>
Mon, 21 Aug 2017 10:29:00 +0000 (10:29 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Mon, 21 Aug 2017 10:29:00 +0000 (10:29 +0000)
2017-08-21  Richard Biener  <rguenther@suse.de>

include/
* simple-object.h (simple_object_copy_lto_debug_sections): New
function.

libiberty/
* simple-object-common.h (struct simple_object_functions): Add
copy_lto_debug_sections hook.
* simple-object.c: Include fcntl.h.
(handle_lto_debug_sections): New helper function.
(simple_object_copy_lto_debug_sections): New function copying
early LTO debug sections to regular debug sections in a new file.
(simple_object_start_write): Handle NULL segment_name.
* simple-object-coff.c (simple_object_coff_functions): Adjust
for not implemented copy_lto_debug_sections hook.
* simple-object-mach-o.c (simple_object_mach_o_functions): Likewise.
* simple-object-xcoff.c (simple_object_xcoff_functions): Likewise.
* simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL,
SHT_GROUP): Add various sectopn header types.
(SHF_EXCLUDE): Add flag.
(Elf32_External_Sym, Elf64_External_Sym): Add symbol struct.
(ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors.
(STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types.
(STV_DEFAULT): Add symbol visibility.
(SHN_COMMON): Add special section index name.
(struct simple_object_elf_write): New.
(simple_object_elf_start_write): Adjust for new private data.
(simple_object_elf_write_shdr): Pass in values for all fields
we write.
(simple_object_elf_write_to_file): Adjust.  Copy from recorded
section headers if requested.
(simple_object_elf_release_write): Release private data.
(simple_object_elf_copy_lto_debug_sections): Copy and rename sections
as denoted by PFN and all their dependences, symbols and relocations
to the empty destination file.
(simple_object_elf_functions): Adjust for copy_lto_debug_sections hook.

        gcc/
        * debug.h (struct gcc_debug_hooks): Add die_ref_for_decl and
        register_external_die hooks.
        (debug_false_tree_charstarstar_uhwistar): Declare.
        (debug_nothing_tree_charstar_uhwi): Likewise.
        * debug.c (do_nothing_debug_hooks): Adjust.
        (debug_false_tree_charstarstar_uhwistar): New do nothing.
        (debug_nothing_tree_charstar_uhwi): Likewise.
        * dbxout.c (dbx_debug_hooks): Adjust.
        (xcoff_debug_hooks): Likewise.
        * sdbout.c (sdb_debug_hooks): Likewise.
        * vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
        * dwarf2out.c (macinfo_label_base): New global.
(dwarf2out_register_external_die): New function for the
register_external_die hook.
        (dwarf2out_die_ref_for_decl): Likewise for die_ref_for_decl.
        (dwarf2_debug_hooks): Use them.
        (dwarf2_lineno_debug_hooks): Adjust.
        (struct die_struct): Add with_offset flag.
        (DEBUG_LTO_DWO_INFO_SECTION, DEBUG_LTO_INFO_SECTION,
        DEBUG_LTO_DWO_ABBREV_SECTION, DEBUG_LTO_ABBREV_SECTION,
        DEBUG_LTO_DWO_MACINFO_SECTION, DEBUG_LTO_MACINFO_SECTION,
        DEBUG_LTO_DWO_MACRO_SECTION, DEBUG_LTO_MACRO_SECTION,
        DEBUG_LTO_LINE_SECTION, DEBUG_LTO_DWO_STR_OFFSETS_SECTION,
        DEBUG_LTO_STR_DWO_SECTION, DEBUG_STR_LTO_SECTION): New macros
        defining section names for the early LTO debug variants.
(reset_indirect_string): New helper.
        (add_AT_external_die_ref): Helper for dwarf2out_register_external_die.
        (print_dw_val): Add support for offsetted symbol references.
(get_ultimate_context): Split out from is_cxx.
(is_cxx): Use get_ultimate_context.
(is_fortran): Add decl overload.
        (compute_comp_unit_symbol): Split out worker from
compute_section_prefix.
        (compute_section_prefix): Call compute_comp_unit_symbol and
set comdat_type_p here.
        (output_die): Skip DIE symbol output for the LTO added one.
        Handle DIE symbol references with offset.
        (output_comp_unit): Guard section name mangling properly.
        For LTO debug sections emit a symbol at the section beginning
        which we use to refer to its DIEs.
        (add_abstract_origin_attribute): For DIEs registered via
        dwarf2out_register_external_die directly refer to the early
        DIE rather than indirectly through the shadow one we created.
Remove obsolete call to dwarf2out_abstract_function for
non-function/block origins.
        (gen_array_type_die): When generating early LTO debug do
        not emit DW_AT_string_length.
        (gen_formal_parameter_die): Do not re-create DIEs for PARM_DECLs
        late when in LTO.  As suggested place a gcc_unreachable for
the DECL_ABSTRACT_P case.
        (gen_subprogram_die): Avoid another specification DIE
        for early built declarations/definitions for the late LTO case.
        (gen_variable_die): Add type references for late duplicated VLA dies
        when in late LTO.
        (gen_inlined_subroutine_die): Do not call dwarf2out_abstract_function,
        we have the abstract instance already.
        (process_scope_var): Adjust decl DIE contexts in LTO which
        first puts them in limbo.
        (gen_decl_die): Do not generate type DIEs late apart from
        types for VLAs or for decls we do not yet have a DIE.  Do not
call dwarf2out_abstract_function late.
        (dwarf2out_early_global_decl): Make sure to create DIEs
        for abstract instances of a decl first.
        (dwarf2out_late_global_decl): Adjust comment.
        (output_macinfo_op): With multiple macro sections use
macinfo_label_base to distinguish labels.
        (output_macinfo): Likewise.  Update macinfo_label_base.
Pass in the line info label.
(note_variable_value_in_expr): When generating LTO resolve
all variable values here by generating DIEs as needed.
        (init_sections_and_labels): Add early LTO debug flag parameter
        and generate different sections and names if set.  Add generation
        counter for the labels so we can have multiple of them.
        (reset_dies): Helper to allow DIEs to be output multiple times.
        (dwarf2out_finish): When outputting DIEs to the fat part of an
LTO object first reset DIEs.
        (dwarf2out_early_finish): Output early DIEs when generating LTO.
(modified_type_die): Check for decl_ultimate_origin being self
before recursing.
(gen_type_die_with_usage): Likewise.
(gen_typedef_die): Allow decl_ultimate_origin being self.
        (set_decl_abstract_flags): Remove.
        (set_block_abstract_flags): Likewise.
        (dwarf2out_abstract_function): Treat the early generated DIEs
        as the abstract copy and only add DW_AT_inline and
        DW_AT_artificial here and call set_decl_origin_self.
If the DIE has an abstract origin don't do anything.
* tree.c (free_lang_data): Build a dummy TRANSLATION_UNIT_DECL
if we have none yet (Go fails to build one, PR78628).
(variably_modified_type_p): Prevent endless recursion for Ada
cyclic pointer types.
        * lto-streamer-in.c: Include debug.h.
        (dref_queue): New global.
        (lto_read_tree_1): Stream in DIE references.
        (lto_input_tree): Register DIE references.
(input_function): Stream DECL_DEBUG_ARGS.
        * lto-streamer-out.c: Include debug.h.
        (lto_write_tree_1): Output DIE references.
        (DFS::DFS_write_tree_body): Follow DECL_ABSTRACT_ORIGIN.
Force a TRANSLATION_UNIT_DECL DECL_CONTEXT for file-scope decls.
(output_function): Stream DECL_DEBUG_ARGS.
        * tree-streamer-in.c (lto_input_ts_decl_common_tree_pointers):
        Stream DECL_ABSTRACT_ORIGIN.
        * tree-streamer-out.c (write_ts_decl_common_tree_pointers): Likewise.
(write_ts_decl_minimal_tree_pointers): Force a TRANSLATION_UNIT_DECL
DECL_CONTEXT for file-scope decls.
        * lto-streamer.h (struct dref_entry): Declare.
        (dref_queue): Likewise.
* cfgexpand.c (pass_expand::execute): Do not call the
outlining_inline_function hook here.
        * lto-wrapper.c (debug_obj): New global.
        (tool_cleanup): Unlink it if required.
        (debug_objcopy): New function.
        (run_gcc): Handle early debug sections in the IL files by
        extracting them to separate files, partially linkin them and
        feeding the result back as result to the linker.

        * config/darwin.h (DEBUG_LTO_INFO_SECTION, DEBUG_LTO_ABBREV_SECTION,
        DEBUG_LTO_MACINFO_SECTION, DEBUG_LTO_LINE_SECTION,
        DEBUG_STR_LTO_SECTION, DEBUG_LTO_MACRO_SECTION): Put early debug
        sections into a separate segment.
        * config/darwin.c (darwin_asm_named_section): Handle __GNU_DWARF_LTO
        segments.
        (darwin_asm_dwarf_section): Likewise.
        (darwin_asm_output_dwarf_offset): Likewise.

* config/i386/i386.c (make_resolver_func): Set DECL_IGNORED_P.

        lto/
        * lto.c (unify_scc): Truncate DIE reference queue for dropped SCCs.
        (lto_read_decls): Process TRANSLATION_UNIT_DECLs.  Remove
        TYPE_DECL debug processing, register DIE references from
        prevailing SCCs with the debug machinery.
        (lto_section_with_id): Handle LTO debug sections.

libstdc++/
* testsuite/libstdc++-prettyprinters/prettyprinters.exp: Run all
tests with -flto as well if supported.

        testsuite/
* c-c++-common/asan/global-overflow-1.c: Adjust diagnostic location
regex to handle the LTO case.
* c-c++-common/asan/heap-overflow-1.c: Likewise.
* c-c++-common/asan/misalign-1.c: Likewise.
* c-c++-common/asan/misalign-2.c: Likewise.
* c-c++-common/asan/null-deref-1.c: Likewise.
* c-c++-common/asan/stack-overflow-1.c: Likewise.
* c-c++-common/asan/strncpy-overflow-1.c: Likewise.
* c-c++-common/asan/use-after-free-1.c: Likewise.
* c-c++-common/asan/alloca_big_alignment.c: Likewise.
* c-c++-common/asan/alloca_detect_custom_size.c: Likewise.
* c-c++-common/asan/alloca_overflow_partial.c: Likewise.
* c-c++-common/asan/alloca_overflow_right.c: Likewise.
* c-c++-common/asan/alloca_underflow_left.c: Likewise.
* g++.dg/asan/large-func-test-1.C: Likewise.
* gfortran.dg/save_6.f90: Add -flto -g variant of save_5.f90.

From-SVN: r251220

47 files changed:
gcc/ChangeLog
gcc/cfgexpand.c
gcc/config/darwin.c
gcc/config/darwin.h
gcc/config/i386/i386.c
gcc/dbxout.c
gcc/debug.c
gcc/debug.h
gcc/dwarf2out.c
gcc/lto-streamer-in.c
gcc/lto-streamer-out.c
gcc/lto-streamer.h
gcc/lto-wrapper.c
gcc/lto/ChangeLog
gcc/lto/lto.c
gcc/sdbout.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/asan/alloca_big_alignment.c
gcc/testsuite/c-c++-common/asan/alloca_detect_custom_size.c
gcc/testsuite/c-c++-common/asan/alloca_overflow_partial.c
gcc/testsuite/c-c++-common/asan/alloca_overflow_right.c
gcc/testsuite/c-c++-common/asan/alloca_underflow_left.c
gcc/testsuite/c-c++-common/asan/global-overflow-1.c
gcc/testsuite/c-c++-common/asan/heap-overflow-1.c
gcc/testsuite/c-c++-common/asan/misalign-1.c
gcc/testsuite/c-c++-common/asan/misalign-2.c
gcc/testsuite/c-c++-common/asan/null-deref-1.c
gcc/testsuite/c-c++-common/asan/stack-overflow-1.c
gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c
gcc/testsuite/c-c++-common/asan/use-after-free-1.c
gcc/testsuite/g++.dg/asan/large-func-test-1.C
gcc/testsuite/gfortran.dg/save_6.f90 [new file with mode: 0644]
gcc/tree-streamer-in.c
gcc/tree-streamer-out.c
gcc/tree.c
gcc/vmsdbgout.c
include/ChangeLog
include/simple-object.h
libiberty/ChangeLog
libiberty/simple-object-coff.c
libiberty/simple-object-common.h
libiberty/simple-object-elf.c
libiberty/simple-object-mach-o.c
libiberty/simple-object-xcoff.c
libiberty/simple-object.c
libstdc++-v3/ChangeLog
libstdc++-v3/testsuite/libstdc++-prettyprinters/prettyprinters.exp

index 4d27ba57e64a4bf5a96e346afafc1a85bcf46bff..3c3e9ffb3a200d447feb28df535973bf090c878f 100644 (file)
@@ -1,3 +1,131 @@
+2017-08-21  Richard Biener  <rguenther@suse.de>
+
+        * debug.h (struct gcc_debug_hooks): Add die_ref_for_decl and
+        register_external_die hooks.
+        (debug_false_tree_charstarstar_uhwistar): Declare.
+        (debug_nothing_tree_charstar_uhwi): Likewise.
+        * debug.c (do_nothing_debug_hooks): Adjust.
+        (debug_false_tree_charstarstar_uhwistar): New do nothing.
+        (debug_nothing_tree_charstar_uhwi): Likewise.
+        * dbxout.c (dbx_debug_hooks): Adjust.
+        (xcoff_debug_hooks): Likewise.
+        * sdbout.c (sdb_debug_hooks): Likewise.
+        * vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
+        * dwarf2out.c (macinfo_label_base): New global.
+       (dwarf2out_register_external_die): New function for the
+       register_external_die hook.
+        (dwarf2out_die_ref_for_decl): Likewise for die_ref_for_decl.
+        (dwarf2_debug_hooks): Use them.
+        (dwarf2_lineno_debug_hooks): Adjust.
+        (struct die_struct): Add with_offset flag.
+        (DEBUG_LTO_DWO_INFO_SECTION, DEBUG_LTO_INFO_SECTION,
+        DEBUG_LTO_DWO_ABBREV_SECTION, DEBUG_LTO_ABBREV_SECTION,
+        DEBUG_LTO_DWO_MACINFO_SECTION, DEBUG_LTO_MACINFO_SECTION,
+        DEBUG_LTO_DWO_MACRO_SECTION, DEBUG_LTO_MACRO_SECTION,
+        DEBUG_LTO_LINE_SECTION, DEBUG_LTO_DWO_STR_OFFSETS_SECTION,
+        DEBUG_LTO_STR_DWO_SECTION, DEBUG_STR_LTO_SECTION): New macros
+        defining section names for the early LTO debug variants.
+       (reset_indirect_string): New helper.
+        (add_AT_external_die_ref): Helper for dwarf2out_register_external_die.
+        (print_dw_val): Add support for offsetted symbol references.
+       (get_ultimate_context): Split out from is_cxx.
+       (is_cxx): Use get_ultimate_context.
+       (is_fortran): Add decl overload.
+        (compute_comp_unit_symbol): Split out worker from
+       compute_section_prefix.
+        (compute_section_prefix): Call compute_comp_unit_symbol and
+       set comdat_type_p here.
+        (output_die): Skip DIE symbol output for the LTO added one.
+        Handle DIE symbol references with offset.
+        (output_comp_unit): Guard section name mangling properly.
+        For LTO debug sections emit a symbol at the section beginning
+        which we use to refer to its DIEs.
+        (add_abstract_origin_attribute): For DIEs registered via
+        dwarf2out_register_external_die directly refer to the early
+        DIE rather than indirectly through the shadow one we created.
+       Remove obsolete call to dwarf2out_abstract_function for
+       non-function/block origins.
+        (gen_array_type_die): When generating early LTO debug do
+        not emit DW_AT_string_length.
+        (gen_formal_parameter_die): Do not re-create DIEs for PARM_DECLs
+        late when in LTO.  As suggested place a gcc_unreachable for
+       the DECL_ABSTRACT_P case.
+        (gen_subprogram_die): Avoid another specification DIE
+        for early built declarations/definitions for the late LTO case.
+        (gen_variable_die): Add type references for late duplicated VLA dies
+        when in late LTO.
+        (gen_inlined_subroutine_die): Do not call dwarf2out_abstract_function,
+        we have the abstract instance already.
+        (process_scope_var): Adjust decl DIE contexts in LTO which
+        first puts them in limbo.
+        (gen_decl_die): Do not generate type DIEs late apart from
+        types for VLAs or for decls we do not yet have a DIE.  Do not
+       call dwarf2out_abstract_function late.
+        (dwarf2out_early_global_decl): Make sure to create DIEs
+        for abstract instances of a decl first.
+        (dwarf2out_late_global_decl): Adjust comment.
+        (output_macinfo_op): With multiple macro sections use
+       macinfo_label_base to distinguish labels.
+        (output_macinfo): Likewise.  Update macinfo_label_base.
+       Pass in the line info label.
+       (note_variable_value_in_expr): When generating LTO resolve
+       all variable values here by generating DIEs as needed.
+        (init_sections_and_labels): Add early LTO debug flag parameter
+        and generate different sections and names if set.  Add generation
+        counter for the labels so we can have multiple of them.
+        (reset_dies): Helper to allow DIEs to be output multiple times.
+        (dwarf2out_finish): When outputting DIEs to the fat part of an
+       LTO object first reset DIEs.
+        (dwarf2out_early_finish): Output early DIEs when generating LTO.
+       (modified_type_die): Check for decl_ultimate_origin being self
+       before recursing.
+       (gen_type_die_with_usage): Likewise.
+       (gen_typedef_die): Allow decl_ultimate_origin being self.
+        (set_decl_abstract_flags): Remove.
+        (set_block_abstract_flags): Likewise.
+        (dwarf2out_abstract_function): Treat the early generated DIEs
+        as the abstract copy and only add DW_AT_inline and
+        DW_AT_artificial here and call set_decl_origin_self.
+       If the DIE has an abstract origin don't do anything.
+       * tree.c (free_lang_data): Build a dummy TRANSLATION_UNIT_DECL
+       if we have none yet (Go fails to build one, PR78628).
+       (variably_modified_type_p): Prevent endless recursion for Ada
+       cyclic pointer types.
+        * lto-streamer-in.c: Include debug.h.
+        (dref_queue): New global.
+        (lto_read_tree_1): Stream in DIE references.
+        (lto_input_tree): Register DIE references.
+       (input_function): Stream DECL_DEBUG_ARGS.
+        * lto-streamer-out.c: Include debug.h.
+        (lto_write_tree_1): Output DIE references.
+        (DFS::DFS_write_tree_body): Follow DECL_ABSTRACT_ORIGIN.
+       Force a TRANSLATION_UNIT_DECL DECL_CONTEXT for file-scope decls.
+       (output_function): Stream DECL_DEBUG_ARGS.
+        * tree-streamer-in.c (lto_input_ts_decl_common_tree_pointers):
+        Stream DECL_ABSTRACT_ORIGIN.
+        * tree-streamer-out.c (write_ts_decl_common_tree_pointers): Likewise.
+       (write_ts_decl_minimal_tree_pointers): Force a TRANSLATION_UNIT_DECL
+       DECL_CONTEXT for file-scope decls.
+        * lto-streamer.h (struct dref_entry): Declare.
+        (dref_queue): Likewise.
+       * cfgexpand.c (pass_expand::execute): Do not call the
+       outlining_inline_function hook here.
+        * lto-wrapper.c (debug_obj): New global.
+        (tool_cleanup): Unlink it if required.
+        (debug_objcopy): New function.
+        (run_gcc): Handle early debug sections in the IL files by
+        extracting them to separate files, partially linkin them and
+        feeding the result back as result to the linker.
+        * config/darwin.h (DEBUG_LTO_INFO_SECTION, DEBUG_LTO_ABBREV_SECTION,
+        DEBUG_LTO_MACINFO_SECTION, DEBUG_LTO_LINE_SECTION,
+        DEBUG_STR_LTO_SECTION, DEBUG_LTO_MACRO_SECTION): Put early debug
+        sections into a separate segment.
+        * config/darwin.c (darwin_asm_named_section): Handle __GNU_DWARF_LTO
+        segments.
+        (darwin_asm_dwarf_section): Likewise.
+        (darwin_asm_output_dwarf_offset): Likewise.
+       * config/i386/i386.c (make_resolver_func): Set DECL_IGNORED_P.
+
 2017-08-21  Richard Sandiford  <richard.sandiford@linaro.org>
            Alan Hayward  <alan.hayward@arm.com>
            David Sherwood  <david.sherwood@arm.com>
index 7f0130d0365f885fe04e01def7d6b9163f37837d..573f0c751adfc941d078249138c803e0c97d7e33 100644 (file)
@@ -6529,12 +6529,6 @@ pass_expand::execute (function *fun)
          TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (parent)) = 1;
     }
 
-  /* We are now committed to emitting code for this function.  Do any
-     preparation, such as emitting abstract debug info for the inline
-     before it gets mangled by optimization.  */
-  if (cgraph_function_possibly_inlined_p (current_function_decl))
-    (*debug_hooks->outlining_inline_function) (current_function_decl);
-
   TREE_ASM_WRITTEN (current_function_decl) = 1;
 
   /* After expanding, the return labels are no longer needed. */
index 949db25c6500345bc66856a1ce9280143200fd71..b6dad70df0ab5a2a54e32cb69907b3d9ebcf4d4e 100644 (file)
@@ -1960,7 +1960,8 @@ darwin_asm_lto_end (void)
 }
 
 static void
-darwin_asm_dwarf_section (const char *name, unsigned int flags, tree decl);
+darwin_asm_dwarf_section (const char *name, unsigned int flags,
+                         tree decl, bool is_for_lto);
 
 /*  Called for the TARGET_ASM_NAMED_SECTION hook.  */
 
@@ -2002,7 +2003,9 @@ darwin_asm_named_section (const char *name,
       vec_safe_push (lto_section_names, e);
    }
   else if (strncmp (name, "__DWARF,", 8) == 0)
-    darwin_asm_dwarf_section (name, flags, decl);
+    darwin_asm_dwarf_section (name, flags, decl, false);
+  else if (strncmp (name, "__GNU_DWARF_LTO,", 16) == 0)
+    darwin_asm_dwarf_section (name, flags, decl, true);
   else
     fprintf (asm_out_file, "\t.section %s\n", name);
 }
@@ -2784,19 +2787,37 @@ static GTY (()) vec<dwarf_sect_used_entry, va_gc> *dwarf_sect_names_table;
 
 static void
 darwin_asm_dwarf_section (const char *name, unsigned int flags,
-                         tree ARG_UNUSED (decl))
+                         tree ARG_UNUSED (decl), bool is_for_lto)
 {
   unsigned i;
-  int namelen;
-  const char * sname;
+  int namelen, extra = 0;
+  const char *sect, *lto_add = "";
+  char sname[64];
   dwarf_sect_used_entry *ref;
   bool found = false;
-  gcc_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
-                   == (SECTION_DEBUG | SECTION_NAMED));
-  /* We know that the name starts with __DWARF,  */
-  sname = name + 8;
-  namelen = strchr (sname, ',') - sname;
-  gcc_assert (namelen);
+
+  gcc_checking_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
+                       == (SECTION_DEBUG | SECTION_NAMED));
+
+  /* We know that the name starts with __DWARF, or __GNU_DAWRF_LTO  */
+  sect = strchr (name, ',') + 1;
+  namelen = strchr (sect, ',') - sect;
+  gcc_checking_assert (namelen);
+
+  /* The section switch is output as written...  */
+  fprintf (asm_out_file, "\t.section %s\n", name);
+
+  /* ... but the string we keep to make section start labels needs
+     adjustment for lto cases.  */
+  if (is_for_lto)
+    {
+      lto_add = "_lto";
+      extra = 4;
+    }
+
+  snprintf (sname, 64, "%.*s%.*s", namelen, sect, extra, lto_add);
+  namelen += extra;
+
   if (dwarf_sect_names_table == NULL)
     vec_alloc (dwarf_sect_names_table, 16);
   else
@@ -2814,7 +2835,6 @@ darwin_asm_dwarf_section (const char *name, unsigned int flags,
          }
       }
 
-  fprintf (asm_out_file, "\t.section %s\n", name);
   if (!found)
     {
       dwarf_sect_used_entry e;
@@ -2867,14 +2887,24 @@ darwin_asm_output_dwarf_offset (FILE *file, int size, const char * lab,
                                HOST_WIDE_INT offset, section *base)
 {
   char sname[64];
-  int namelen;
+  int namelen, extra = 0;
+  bool is_for_lto;
+  const char *lto_add = "";
 
-  gcc_assert (base->common.flags & SECTION_NAMED);
-  gcc_assert (strncmp (base->named.name, "__DWARF,", 8) == 0);
-  gcc_assert (strchr (base->named.name + 8, ','));
+  gcc_checking_assert (base->common.flags & SECTION_NAMED);
+  is_for_lto = strncmp (base->named.name, "__GNU_DWARF_LTO,", 16) == 0;
+  gcc_checking_assert (is_for_lto
+                      || strncmp (base->named.name, "__DWARF,", 8) == 0);
+  const char *name = strchr (base->named.name, ',') + 1;
+  gcc_checking_assert (name);
 
-  namelen = strchr (base->named.name + 8, ',') - (base->named.name + 8);
-  sprintf (sname, "*Lsection%.*s", namelen, base->named.name + 8);
+  namelen = strchr (name, ',') - (name);
+  if (is_for_lto)
+    {
+      lto_add = "_lto";
+      extra = 4;
+    }
+  snprintf (sname, 64, "*Lsection%.*s%.*s", namelen, name, extra, lto_add);
   darwin_asm_output_dwarf_delta (file, size, lab, sname, offset);
 }
 
index a8397cd2331875edf41dd45fd46cdf04bf73723d..6cec8deb8cdb0661c99e4ce251ba83f9818689a4 100644 (file)
@@ -445,7 +445,14 @@ extern GTY(()) int darwin_ms_struct;
 #define DEBUG_PUBTYPES_SECTION "__DWARF,__debug_pubtypes,regular,debug"
 #define DEBUG_STR_SECTION      "__DWARF,__debug_str,regular,debug"
 #define DEBUG_RANGES_SECTION   "__DWARF,__debug_ranges,regular,debug"
-#define DEBUG_MACRO_SECTION    "__DWARF,__debug_macro,regular,debug"
+#define DEBUG_MACRO_SECTION     "__DWARF,__debug_macro,regular,debug"
+
+#define DEBUG_LTO_INFO_SECTION   "__GNU_DWARF_LTO,__debug_info,regular,debug"
+#define DEBUG_LTO_ABBREV_SECTION  "__GNU_DWARF_LTO,__debug_abbrev,regular,debug"
+#define DEBUG_LTO_MACINFO_SECTION "__GNU_DWARF_LTO,__debug_macinfo,regular,debug"
+#define DEBUG_LTO_LINE_SECTION   "__GNU_DWARF_LTO,__debug_line,regular,debug"
+#define DEBUG_LTO_STR_SECTION    "__GNU_DWARF_LTO,__debug_str,regular,debug"
+#define DEBUG_LTO_MACRO_SECTION   "__GNU_DWARF_LTO,__debug_macro,regular,debug"
 
 #define TARGET_WANT_DEBUG_PUB_SECTIONS true
 
index a7bb7f9d629d8155e3ddd071417e6c7b9be58a75..e67f6412acdcb58c126b7e6451942e832d23baca 100644 (file)
@@ -33984,7 +33984,7 @@ make_resolver_func (const tree default_decl,
   DECL_NAME (decl) = decl_name;
   TREE_USED (decl) = 1;
   DECL_ARTIFICIAL (decl) = 1;
-  DECL_IGNORED_P (decl) = 0;
+  DECL_IGNORED_P (decl) = 1;
   TREE_PUBLIC (decl) = 0;
   DECL_UNINLINABLE (decl) = 1;
 
index 3d9268c3d1d725fa8594603a72431e412bdadf24..ea7c97ccb31852e1a997187ff39a61db8ef867e3 100644 (file)
@@ -372,6 +372,8 @@ const struct gcc_debug_hooks dbx_debug_hooks =
   dbxout_late_global_decl,              /* late_global_decl */
   dbxout_type_decl,                     /* type_decl */
   debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */
+  debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */
+  debug_nothing_tree_charstar_uhwi,      /* register_external_die */
   debug_nothing_tree,                   /* deferred_inline_function */
   debug_nothing_tree,                   /* outlining_inline_function */
   debug_nothing_rtx_code_label,                 /* label */
@@ -412,6 +414,8 @@ const struct gcc_debug_hooks xcoff_debug_hooks =
   dbxout_late_global_decl,              /* late_global_decl */
   dbxout_type_decl,                     /* type_decl */
   debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */
+  debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */
+  debug_nothing_tree_charstar_uhwi,      /* register_external_die */
   debug_nothing_tree,                   /* deferred_inline_function */
   debug_nothing_tree,                   /* outlining_inline_function */
   debug_nothing_rtx_code_label,                 /* label */
index d68c30ff2b9a7d90be1759eae5647c693c898ca5..4db94c3e675d29e7d8c97c8397e4c0dcd7c49a84 100644 (file)
@@ -48,6 +48,8 @@ const struct gcc_debug_hooks do_nothing_debug_hooks =
   debug_nothing_tree,                   /* late_global_decl */
   debug_nothing_tree_int,               /* type_decl */
   debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */
+  debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */
+  debug_nothing_tree_charstar_uhwi,      /* register_external_die */
   debug_nothing_tree,                   /* deferred_inline_function */
   debug_nothing_tree,                   /* outlining_inline_function */
   debug_nothing_rtx_code_label,                 /* label */
@@ -147,3 +149,16 @@ debug_nothing_tree_int (tree decl ATTRIBUTE_UNUSED,
                        int local ATTRIBUTE_UNUSED)
 {
 }
+
+bool
+debug_false_tree_charstarstar_uhwistar (tree, const char **,
+                                       unsigned HOST_WIDE_INT *)
+{
+  return false;
+}
+
+void
+debug_nothing_tree_charstar_uhwi (tree, const char *,
+                                 unsigned HOST_WIDE_INT)
+{
+}
index bfb72213631a0c6bd27eaf5cfaed7ae24b8c977e..915420baded59dec8cd83f0ecb4a95486769e6ef 100644 (file)
@@ -148,6 +148,14 @@ struct gcc_debug_hooks
                                    tree context, bool child,
                                    bool implicit);
 
+  /* Return true if a DIE for the tree is available and return a symbol
+     and offset that can be used to refer to it externally.  */
+  bool (* die_ref_for_decl) (tree, const char **, unsigned HOST_WIDE_INT *);
+
+  /* Early debug information for the tree is available at symbol plus
+     offset externally.  */
+  void (* register_external_die) (tree, const char *, unsigned HOST_WIDE_INT);
+
   /* DECL is an inline function, whose body is present, but which is
      not being output at this point.  */
   void (* deferred_inline_function) (tree decl);
@@ -212,6 +220,10 @@ extern void debug_nothing_tree_tree_tree_bool_bool (tree, tree, tree,
 extern bool debug_true_const_tree (const_tree);
 extern void debug_nothing_rtx_insn (rtx_insn *);
 extern void debug_nothing_rtx_code_label (rtx_code_label *);
+extern bool debug_false_tree_charstarstar_uhwistar (tree, const char **,
+                                                   unsigned HOST_WIDE_INT *);
+extern void debug_nothing_tree_charstar_uhwi (tree, const char *,
+                                             unsigned HOST_WIDE_INT);
 
 /* Hooks for various debug formats.  */
 extern const struct gcc_debug_hooks do_nothing_debug_hooks;
index 917ab9fa58a3e772f422f3d276b83a7846beaddb..764fd36bc8260e47e2f8e755dfaf69da667a9ec7 100644 (file)
@@ -164,6 +164,7 @@ static GTY(()) section *debug_aranges_section;
 static GTY(()) section *debug_addr_section;
 static GTY(()) section *debug_macinfo_section;
 static const char *debug_macinfo_section_name;
+static unsigned macinfo_label_base = 1;
 static GTY(()) section *debug_line_section;
 static GTY(()) section *debug_skeleton_line_section;
 static GTY(()) section *debug_loc_section;
@@ -2692,6 +2693,10 @@ static void dwarf2out_begin_function (tree);
 static void dwarf2out_end_function (unsigned int);
 static void dwarf2out_register_main_translation_unit (tree unit);
 static void dwarf2out_set_name (tree, tree);
+static void dwarf2out_register_external_die (tree decl, const char *sym,
+                                            unsigned HOST_WIDE_INT off);
+static bool dwarf2out_die_ref_for_decl (tree decl, const char **sym,
+                                       unsigned HOST_WIDE_INT *off);
 
 /* The debug hooks structure.  */
 
@@ -2726,6 +2731,8 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_late_global_decl,
   dwarf2out_type_decl,         /* type_decl */
   dwarf2out_imported_module_or_decl,
+  dwarf2out_die_ref_for_decl,
+  dwarf2out_register_external_die,
   debug_nothing_tree,          /* deferred_inline_function */
   /* The DWARF 2 backend tries to reduce debugging bloat by not
      emitting the abstract description of inline functions until
@@ -2767,6 +2774,8 @@ const struct gcc_debug_hooks dwarf2_lineno_debug_hooks =
   debug_nothing_tree,                   /* late_global_decl */
   debug_nothing_tree_int,               /* type_decl */
   debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */
+  debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */
+  debug_nothing_tree_charstar_uhwi,      /* register_external_die */
   debug_nothing_tree,                   /* deferred_inline_function */
   debug_nothing_tree,                   /* outlining_inline_function */
   debug_nothing_rtx_code_label,                 /* label */
@@ -2895,6 +2904,9 @@ typedef struct GTY((chain_circular ("%h.die_sib"), for_user)) die_struct {
   /* Die is used and must not be pruned as unused.  */
   BOOL_BITFIELD die_perennial_p : 1;
   BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
+  /* For an external ref to die_symbol if die_offset contains an extra
+     offset to that symbol.  */
+  BOOL_BITFIELD with_offset : 1;
   /* Whether this DIE was removed from the DIE tree, for example via
      prune_unused_types.  We don't consider those present from the
      DIE lookup routines.  */
@@ -3698,12 +3710,24 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
 #ifndef DEBUG_DWO_INFO_SECTION
 #define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
 #endif
+#ifndef DEBUG_LTO_DWO_INFO_SECTION
+#define DEBUG_LTO_DWO_INFO_SECTION ".gnu.debuglto_.debug_info.dwo"
+#endif
+#ifndef DEBUG_LTO_INFO_SECTION
+#define DEBUG_LTO_INFO_SECTION ".gnu.debuglto_.debug_info"
+#endif
 #ifndef DEBUG_ABBREV_SECTION
 #define DEBUG_ABBREV_SECTION   ".debug_abbrev"
 #endif
 #ifndef DEBUG_DWO_ABBREV_SECTION
 #define DEBUG_DWO_ABBREV_SECTION ".debug_abbrev.dwo"
 #endif
+#ifndef DEBUG_LTO_DWO_ABBREV_SECTION
+#define DEBUG_LTO_DWO_ABBREV_SECTION ".gnu.debuglto_.debug_abbrev.dwo"
+#endif
+#ifndef DEBUG_LTO_ABBREV_SECTION
+#define DEBUG_LTO_ABBREV_SECTION ".gnu.debuglto_.debug_abbrev"
+#endif
 #ifndef DEBUG_ARANGES_SECTION
 #define DEBUG_ARANGES_SECTION  ".debug_aranges"
 #endif
@@ -3716,18 +3740,33 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
 #ifndef DEBUG_DWO_MACINFO_SECTION
 #define DEBUG_DWO_MACINFO_SECTION      ".debug_macinfo.dwo"
 #endif
+#ifndef DEBUG_LTO_DWO_MACINFO_SECTION
+#define DEBUG_LTO_DWO_MACINFO_SECTION  ".gnu.debuglto_.debug_macinfo.dwo"
+#endif
+#ifndef DEBUG_LTO_MACINFO_SECTION
+#define DEBUG_LTO_MACINFO_SECTION      ".gnu.debuglto_.debug_macinfo"
+#endif
 #ifndef DEBUG_DWO_MACRO_SECTION
 #define DEBUG_DWO_MACRO_SECTION        ".debug_macro.dwo"
 #endif
 #ifndef DEBUG_MACRO_SECTION
 #define DEBUG_MACRO_SECTION    ".debug_macro"
 #endif
+#ifndef DEBUG_LTO_DWO_MACRO_SECTION
+#define DEBUG_LTO_DWO_MACRO_SECTION    ".gnu.debuglto_.debug_macro.dwo"
+#endif
+#ifndef DEBUG_LTO_MACRO_SECTION
+#define DEBUG_LTO_MACRO_SECTION ".gnu.debuglto_.debug_macro"
+#endif
 #ifndef DEBUG_LINE_SECTION
 #define DEBUG_LINE_SECTION     ".debug_line"
 #endif
 #ifndef DEBUG_DWO_LINE_SECTION
 #define DEBUG_DWO_LINE_SECTION ".debug_line.dwo"
 #endif
+#ifndef DEBUG_LTO_LINE_SECTION
+#define DEBUG_LTO_LINE_SECTION ".gnu.debuglto_.debug_line.dwo"
+#endif
 #ifndef DEBUG_LOC_SECTION
 #define DEBUG_LOC_SECTION      ".debug_loc"
 #endif
@@ -3756,12 +3795,21 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
 #ifndef DEBUG_DWO_STR_OFFSETS_SECTION
 #define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo"
 #endif
+#ifndef DEBUG_LTO_DWO_STR_OFFSETS_SECTION
+#define DEBUG_LTO_DWO_STR_OFFSETS_SECTION ".gnu.debuglto_.debug_str_offsets.dwo"
+#endif
 #ifndef DEBUG_STR_DWO_SECTION
 #define DEBUG_STR_DWO_SECTION   ".debug_str.dwo"
 #endif
+#ifndef DEBUG_LTO_STR_DWO_SECTION
+#define DEBUG_LTO_STR_DWO_SECTION ".gnu.debuglto_.debug_str.dwo"
+#endif
 #ifndef DEBUG_STR_SECTION
 #define DEBUG_STR_SECTION  ".debug_str"
 #endif
+#ifndef DEBUG_LTO_STR_SECTION
+#define DEBUG_LTO_STR_SECTION ".gnu.debuglto_.debug_str"
+#endif
 #ifndef DEBUG_RANGES_SECTION
 #define DEBUG_RANGES_SECTION   ".debug_ranges"
 #endif
@@ -3786,6 +3834,10 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
 /* Section flags for .debug_str.dwo section.  */
 #define DEBUG_STR_DWO_SECTION_FLAGS (SECTION_DEBUG | SECTION_EXCLUDE)
 
+/* Attribute used to refer to the macro section.  */
+#define DEBUG_MACRO_ATTRIBUTE (dwarf_version >= 5 ? DW_AT_macros \
+                  : dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros)
+
 /* Labels we insert at beginning sections we can reference instead of
    the section names themselves.  */
 
@@ -4374,6 +4426,24 @@ set_indirect_string (struct indirect_string_node *node)
     }
 }
 
+/* A helper function for dwarf2out_finish, called to reset indirect
+   string decisions done for early LTO dwarf output before fat object
+   dwarf output.  */
+
+int
+reset_indirect_string (indirect_string_node **h, void *)
+{
+  struct indirect_string_node *node = *h;
+  if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index)
+    {
+      free (node->label);
+      node->label = NULL;
+      node->form = (dwarf_form) 0;
+      node->index = 0;
+    }
+  return 1;
+}
+
 /* Find out whether a string should be output inline in DIE
    or out-of-line in .debug_str section.  */
 
@@ -5019,6 +5089,21 @@ get_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind)
   return a ? AT_file (a) : NULL;
 }
 
+/* Returns the ultimate TRANSLATION_UNIT_DECL context of DECL or NULL.  */
+
+static const_tree
+get_ultimate_context (const_tree decl)
+{
+  while (decl && TREE_CODE (decl) != TRANSLATION_UNIT_DECL)
+    {
+      if (TREE_CODE (decl) == BLOCK)
+       decl = BLOCK_SUPERCONTEXT (decl);
+      else
+       decl = get_containing_scope (decl);
+    }
+  return decl;
+}
+
 /* Return TRUE if the language is C++.  */
 
 static inline bool
@@ -5037,14 +5122,7 @@ is_cxx (const_tree decl)
 {
   if (in_lto_p)
     {
-      const_tree context = decl;
-      while (context && TREE_CODE (context) != TRANSLATION_UNIT_DECL)
-       {
-         if (TREE_CODE (context) == BLOCK)
-           context = BLOCK_SUPERCONTEXT (context);
-         else
-           context = get_containing_scope (context);
-       }
+      const_tree context = get_ultimate_context (decl);
       if (context && TRANSLATION_UNIT_LANGUAGE (context))
        return strncmp (TRANSLATION_UNIT_LANGUAGE (context), "GNU C++", 7) == 0;
     }
@@ -5065,6 +5143,21 @@ is_fortran (void)
          || lang == DW_LANG_Fortran08);
 }
 
+static inline bool
+is_fortran (const_tree decl)
+{
+  if (in_lto_p)
+    {
+      const_tree context = get_ultimate_context (decl);
+      if (context && TRANSLATION_UNIT_LANGUAGE (context))
+       return (strncmp (TRANSLATION_UNIT_LANGUAGE (context),
+                        "GNU Fortran", 11) == 0
+               || strcmp (TRANSLATION_UNIT_LANGUAGE (context),
+                          "GNU F77") == 0);
+    }
+  return is_fortran ();
+}
+
 /* Return TRUE if the language is Ada.  */
 
 static inline bool
@@ -5409,6 +5502,184 @@ lookup_decl_die (tree decl)
   return *die;
 }
 
+
+/* For DECL which might have early dwarf output query a SYMBOL + OFFSET
+   style reference.  Return true if we found one refering to a DIE for
+   DECL, otherwise return false.  */
+
+static bool
+dwarf2out_die_ref_for_decl (tree decl, const char **sym,
+                           unsigned HOST_WIDE_INT *off)
+{
+  dw_die_ref die;
+
+  if (flag_wpa && !decl_die_table)
+    return false;
+
+  if (TREE_CODE (decl) == BLOCK)
+    die = BLOCK_DIE (decl);
+  else
+    die = lookup_decl_die (decl);
+  if (!die)
+    return false;
+
+  /* During WPA stage we currently use DIEs to store the
+     decl <-> label + offset map.  That's quite inefficient but it
+     works for now.  */
+  if (flag_wpa)
+    {
+      dw_die_ref ref = get_AT_ref (die, DW_AT_abstract_origin);
+      if (!ref)
+       {
+         gcc_assert (die == comp_unit_die ());
+         return false;
+       }
+      *off = ref->die_offset;
+      *sym = ref->die_id.die_symbol;
+      return true;
+    }
+
+  /* Similar to get_ref_die_offset_label, but using the "correct"
+     label.  */
+  *off = die->die_offset;
+  while (die->die_parent)
+    die = die->die_parent;
+  /* For the containing CU DIE we compute a die_symbol in
+     compute_section_prefix.  */
+  gcc_assert (die->die_tag == DW_TAG_compile_unit
+             && die->die_id.die_symbol != NULL);
+  *sym = die->die_id.die_symbol;
+  return true;
+}
+
+/* Add a reference of kind ATTR_KIND to a DIE at SYMBOL + OFFSET to DIE.  */
+
+static void
+add_AT_external_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind,
+                        const char *symbol, HOST_WIDE_INT offset)
+{
+  /* Create a fake DIE that contains the reference.  Don't use
+     new_die because we don't want to end up in the limbo list.  */
+  dw_die_ref ref = ggc_cleared_alloc<die_node> ();
+  ref->die_tag = die->die_tag;
+  ref->die_id.die_symbol = IDENTIFIER_POINTER (get_identifier (symbol));
+  ref->die_offset = offset;
+  ref->with_offset = 1;
+  add_AT_die_ref (die, attr_kind, ref);
+}
+
+/* Create a DIE for DECL if required and add a reference to a DIE
+   at SYMBOL + OFFSET which contains attributes dumped early.  */
+
+static void
+dwarf2out_register_external_die (tree decl, const char *sym,
+                                unsigned HOST_WIDE_INT off)
+{
+  if (debug_info_level == DINFO_LEVEL_NONE)
+    return;
+
+  if (flag_wpa && !decl_die_table)
+    decl_die_table = hash_table<decl_die_hasher>::create_ggc (1000);
+
+  dw_die_ref die
+    = TREE_CODE (decl) == BLOCK ? BLOCK_DIE (decl) : lookup_decl_die (decl);
+  gcc_assert (!die);
+
+  tree ctx;
+  dw_die_ref parent = NULL;
+  /* Need to lookup a DIE for the decls context - the containing
+     function or translation unit.  */
+  if (TREE_CODE (decl) == BLOCK)
+    {
+      ctx = BLOCK_SUPERCONTEXT (decl);
+      /* ???  We do not output DIEs for all scopes thus skip as
+        many DIEs as needed.  */
+      while (TREE_CODE (ctx) == BLOCK
+            && !BLOCK_DIE (ctx))
+       ctx = BLOCK_SUPERCONTEXT (ctx);
+    }
+  else
+    ctx = DECL_CONTEXT (decl);
+  while (ctx && TYPE_P (ctx))
+    ctx = TYPE_CONTEXT (ctx);
+  if (ctx)
+    {
+      if (TREE_CODE (ctx) == BLOCK)
+       parent = BLOCK_DIE (ctx);
+      else if (TREE_CODE (ctx) == TRANSLATION_UNIT_DECL
+              /* Keep the 1:1 association during WPA.  */
+              && !flag_wpa)
+       /* Otherwise all late annotations go to the main CU which
+          imports the original CUs.  */
+       parent = comp_unit_die ();
+      else if (TREE_CODE (ctx) == FUNCTION_DECL
+              && TREE_CODE (decl) != PARM_DECL
+              && TREE_CODE (decl) != BLOCK)
+       /* Leave function local entities parent determination to when
+          we process scope vars.  */
+       ;
+      else
+       parent = lookup_decl_die (ctx);
+    }
+  else
+    /* In some cases the FEs fail to set DECL_CONTEXT properly.
+       Handle this case gracefully by globalizing stuff.  */
+    parent = comp_unit_die ();
+  /* Create a DIE "stub".  */
+  switch (TREE_CODE (decl))
+    {
+    case TRANSLATION_UNIT_DECL:
+      if (! flag_wpa)
+       {
+         die = comp_unit_die ();
+         dw_die_ref import = new_die (DW_TAG_imported_unit, die, NULL_TREE);
+         add_AT_external_die_ref (import, DW_AT_import, sym, off);
+         /* We re-target all CU decls to the LTRANS CU DIE, so no need
+            to create a DIE for the original CUs.  */
+         return;
+       }
+      /* Keep the 1:1 association during WPA.  */
+      die = new_die (DW_TAG_compile_unit, NULL, decl);
+      break;
+    case NAMESPACE_DECL:
+      if (is_fortran (decl))
+       die = new_die (DW_TAG_module, parent, decl);
+      else
+       die = new_die (DW_TAG_namespace, parent, decl);
+      break;
+    case FUNCTION_DECL:
+      die = new_die (DW_TAG_subprogram, parent, decl);
+      break;
+    case VAR_DECL:
+      die = new_die (DW_TAG_variable, parent, decl);
+      break;
+    case RESULT_DECL:
+      die = new_die (DW_TAG_variable, parent, decl);
+      break;
+    case PARM_DECL:
+      die = new_die (DW_TAG_formal_parameter, parent, decl);
+      break;
+    case CONST_DECL:
+      die = new_die (DW_TAG_constant, parent, decl);
+      break;
+    case LABEL_DECL:
+      die = new_die (DW_TAG_label, parent, decl);
+      break;
+    case BLOCK:
+      die = new_die (DW_TAG_lexical_block, parent, decl);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  if (TREE_CODE (decl) == BLOCK)
+    BLOCK_DIE (decl) = die;
+  else
+    equate_decl_number_to_die (decl, die);
+
+  /* Add a reference to the DIE providing early debug at $sym + off.  */
+  add_AT_external_die_ref (die, DW_AT_abstract_origin, sym, off);
+}
+
 /* Returns a hash value for X (which really is a var_loc_list).  */
 
 inline hashval_t
@@ -5896,7 +6167,11 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile)
                               die->die_id.die_type_node->signature);
            }
          else if (die->die_id.die_symbol)
-           fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
+           {
+             fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
+             if (die->with_offset)
+               fprintf (outfile, " + %ld", die->die_offset);
+           }
          else
            fprintf (outfile, "die -> %ld", die->die_offset);
          fprintf (outfile, " (%p)", (void *) die);
@@ -7209,10 +7484,10 @@ static const char *comdat_symbol_id;
 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.  */
+   children, and set die_symbol.  */
 
 static void
-compute_section_prefix (dw_die_ref unit_die)
+compute_comp_unit_symbol (dw_die_ref unit_die)
 {
   const char *die_name = get_AT_string (unit_die, DW_AT_name);
   const char *base = die_name ? lbasename (die_name) : "anonymous";
@@ -7231,7 +7506,11 @@ compute_section_prefix (dw_die_ref unit_die)
   unmark_all_dies (unit_die);
   md5_finish_ctx (&ctx, checksum);
 
-  sprintf (name, "%s.", base);
+  /* When we this for comp_unit_die () we have a DW_AT_name that might
+     not start with a letter but with anything valid for filenames and
+     clean_symbol_name doesn't fix that up.  Prepend 'g' if the first
+     character is not a letter.  */
+  sprintf (name, "%s%s.", ISALPHA (*base) ? "" : "g", base);
   clean_symbol_name (name);
 
   p = name + strlen (name);
@@ -7241,7 +7520,15 @@ compute_section_prefix (dw_die_ref unit_die)
       p += 2;
     }
 
-  comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
+  unit_die->die_id.die_symbol = xstrdup (name);
+}
+
+static void
+compute_section_prefix (dw_die_ref unit_die)
+{
+  compute_comp_unit_symbol (unit_die);
+  unit_die->comdat_type_p = true;
+  comdat_symbol_id = unit_die->die_id.die_symbol;
   comdat_symbol_number = 0;
 }
 
@@ -9967,7 +10254,11 @@ 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->comdat_type_p && die->die_id.die_symbol)
+  if (! die->comdat_type_p && die->die_id.die_symbol
+      /* Don't output the symbol twice.  For LTO we want the label
+         on the section beginning, not on the actual DIE.  */
+      && (!flag_generate_lto
+         || die->die_tag != DW_TAG_compile_unit))
     output_die_symbol (die);
 
   dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
@@ -10160,8 +10451,20 @@ output_die (dw_die_ref die)
                    size = DWARF2_ADDR_SIZE;
                  else
                    size = DWARF_OFFSET_SIZE;
-                 dw2_asm_output_offset (size, sym, debug_info_section, "%s",
-                                        name);
+                 /* ???  We cannot unconditionally output die_offset if
+                    non-zero - at least -feliminate-dwarf2-dups will
+                    create references to those DIEs via symbols.  And we
+                    do not clear its DIE offset after outputting it
+                    (and the label refers to the actual DIEs, not the
+                    DWARF CU unit header which is when using label + offset
+                    would be the correct thing to do).
+                    ???  This is the reason for the with_offset flag.  */
+                 if (AT_ref (a)->with_offset)
+                   dw2_asm_output_offset (size, sym, AT_ref (a)->die_offset,
+                                          debug_info_section, "%s", name);
+                 else
+                   dw2_asm_output_offset (size, sym, debug_info_section, "%s",
+                                          name);
                }
            }
          else
@@ -10387,7 +10690,7 @@ output_comp_unit (dw_die_ref die, int output_if_empty,
   calc_die_sizes (die);
 
   oldsym = die->die_id.die_symbol;
-  if (oldsym)
+  if (oldsym && die->comdat_type_p)
     {
       tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
 
@@ -10403,6 +10706,29 @@ output_comp_unit (dw_die_ref die, int output_if_empty,
       info_section_emitted = true;
     }
 
+  /* For LTO cross unit DIE refs we want a symbol on the start of the
+     debuginfo section, not on the CU DIE.  */
+  if (flag_generate_lto && oldsym)
+    {
+      /* ???  No way to get visibility assembled without a decl.  */
+      tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                             get_identifier (oldsym), char_type_node);
+      TREE_PUBLIC (decl) = true;
+      TREE_STATIC (decl) = true;
+      DECL_ARTIFICIAL (decl) = true;
+      DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+      DECL_VISIBILITY_SPECIFIED (decl) = true;
+      targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN);
+#ifdef ASM_WEAKEN_LABEL
+      /* We prefer a .weak because that handles duplicates from duplicate
+         archive members in a graceful way.  */
+      ASM_WEAKEN_LABEL (asm_out_file, oldsym);
+#else
+      targetm.asm_out.globalize_label (asm_out_file, oldsym);
+#endif
+      ASM_OUTPUT_LABEL (asm_out_file, oldsym);
+    }
+
   /* Output debugging information.  */
   output_compilation_unit_header (dwo_id
                                  ? DW_UT_split_compile : DW_UT_compile);
@@ -12511,7 +12837,7 @@ modified_type_die (tree type, int cv_quals, bool reverse,
          /* Typedef variants that have an abstract origin don't get their own
             type DIE (see gen_typedef_die), so fall back on the ultimate
             abstract origin instead.  */
-         if (origin != NULL)
+         if (origin != NULL && origin != name)
            return modified_type_die (TREE_TYPE (origin), cv_quals, reverse,
                                      context_die);
 
@@ -14528,6 +14854,9 @@ parameter_ref_descriptor (rtx rtl)
   if (dwarf_strict)
     return NULL;
   gcc_assert (TREE_CODE (DEBUG_PARAMETER_REF_DECL (rtl)) == PARM_DECL);
+  /* With LTO during LTRANS we get the late DIE that refers to the early
+     DIE, thus we add another indirection here.  This seems to confuse
+     gdb enough to make gcc.dg/guality/pr68860-1.c FAIL with LTO.  */
   ref = lookup_decl_die (DEBUG_PARAMETER_REF_DECL (rtl));
   ret = new_loc_descr (DW_OP_GNU_parameter_ref, 0, 0);
   if (ref)
@@ -20199,27 +20528,19 @@ add_abstract_origin_attribute (dw_die_ref die, tree origin)
 {
   dw_die_ref origin_die = NULL;
 
-  if (TREE_CODE (origin) != FUNCTION_DECL
-      && TREE_CODE (origin) != BLOCK)
+  if (DECL_P (origin))
     {
-      /* We may have gotten separated from the block for the inlined
-        function, if we're in an exception handler or some such; make
-        sure that the abstract function has been written out.
-
-        Doing this for nested functions is wrong, however; functions are
-        distinct units, and our context might not even be inline.  */
-      tree fn = origin;
-
-      if (TYPE_P (fn))
-       fn = TYPE_STUB_DECL (fn);
-
-      fn = decl_function_context (fn);
-      if (fn)
-       dwarf2out_abstract_function (fn);
+      dw_die_ref c;
+      origin_die = lookup_decl_die (origin);
+      /* "Unwrap" the decls DIE which we put in the imported unit context.
+         We are looking for the abstract copy here.  */
+      if (in_lto_p
+         && origin_die
+         && (c = get_AT_ref (origin_die, DW_AT_abstract_origin))
+         /* ???  Identify this better.  */
+         && c->with_offset)
+       origin_die = c;
     }
-
-  if (DECL_P (origin))
-    origin_die = lookup_decl_die (origin);
   else if (TYPE_P (origin))
     origin_die = lookup_type_die (origin);
   else if (TREE_CODE (origin) == BLOCK)
@@ -20778,7 +21099,10 @@ gen_array_type_die (tree type, dw_die_ref context_die)
       size = int_size_in_bytes (type);
       if (size >= 0)
        add_AT_unsigned (array_die, DW_AT_byte_size, size);
-      else if (TYPE_DOMAIN (type) != NULL_TREE
+      /* ???  We can't annotate types late, but for LTO we may not
+        generate a location early either (gfortran.dg/save_6.f90).  */
+      else if (! (early_dwarf && flag_generate_lto)
+              && TYPE_DOMAIN (type) != NULL_TREE
               && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE)
        {
          tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
@@ -21188,8 +21512,11 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
       parm_die = lookup_decl_die (node);
 
       /* If the contexts differ, we may not be talking about the same
-        thing.  */
-      if (parm_die && parm_die->die_parent != context_die)
+        thing.
+        ???  When in LTO the DIE parent is the "abstract" copy and the
+        context_die is the specification "copy".  But this whole block
+        should eventually be no longer needed.  */
+      if (parm_die && parm_die->die_parent != context_die && !in_lto_p)
        {
          if (!DECL_ABSTRACT_P (node))
            {
@@ -21199,18 +21526,7 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
              parm_die = NULL;
            }
          else
-           {
-             /* FIXME: Reuse DIE even with a differing context.
-
-                This can happen when calling
-                dwarf2out_abstract_function to build debug info for
-                the abstract instance of a function for which we have
-                already generated a DIE in
-                dwarf2out_early_global_decl.
-
-                Once we remove dwarf2out_abstract_function, we should
-                have a call to gcc_unreachable here.  */
-           }
+           gcc_unreachable ();
        }
 
       if (parm_die && parm_die->die_parent == NULL)
@@ -21465,7 +21781,6 @@ gen_type_die_for_member (tree type, tree member, dw_die_ref context_die)
 /* Forward declare these functions, because they are mutually recursive
   with their set_block_* pairing functions.  */
 static void set_decl_origin_self (tree);
-static void set_decl_abstract_flags (tree, vec<tree> &);
 
 /* Given a pointer to some BLOCK node, if the BLOCK_ABSTRACT_ORIGIN for the
    given BLOCK node is NULL, set the BLOCK_ABSTRACT_ORIGIN for the node so
@@ -21538,151 +21853,48 @@ set_decl_origin_self (tree decl)
     }
 }
 \f
-/* Given a pointer to some BLOCK node, set the BLOCK_ABSTRACT flag to 1
-   and if it wasn't 1 before, push it to abstract_vec vector.
-   For all local decls and all local sub-blocks (recursively) do it
-   too.  */
-
-static void
-set_block_abstract_flags (tree stmt, vec<tree> &abstract_vec)
-{
-  tree local_decl;
-  tree subblock;
-  unsigned int i;
-
-  if (!BLOCK_ABSTRACT (stmt))
-    {
-      abstract_vec.safe_push (stmt);
-      BLOCK_ABSTRACT (stmt) = 1;
-    }
-
-  for (local_decl = BLOCK_VARS (stmt);
-       local_decl != NULL_TREE;
-       local_decl = DECL_CHAIN (local_decl))
-    if (! DECL_EXTERNAL (local_decl))
-      set_decl_abstract_flags (local_decl, abstract_vec);
-
-  for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
-    {
-      local_decl = BLOCK_NONLOCALIZED_VAR (stmt, i);
-      if ((VAR_P (local_decl) && !TREE_STATIC (local_decl))
-         || TREE_CODE (local_decl) == PARM_DECL)
-       set_decl_abstract_flags (local_decl, abstract_vec);
-    }
-
-  for (subblock = BLOCK_SUBBLOCKS (stmt);
-       subblock != NULL_TREE;
-       subblock = BLOCK_CHAIN (subblock))
-    set_block_abstract_flags (subblock, abstract_vec);
-}
-
-/* Given a pointer to some ..._DECL node, set DECL_ABSTRACT_P flag on it
-   to 1 and if it wasn't 1 before, push to abstract_vec vector.
-   In the case where the decl is a FUNCTION_DECL also set the abstract
-   flags for all of the parameters, local vars, local
-   blocks and sub-blocks (recursively).  */
-
-static void
-set_decl_abstract_flags (tree decl, vec<tree> &abstract_vec)
-{
-  if (!DECL_ABSTRACT_P (decl))
-    {
-      abstract_vec.safe_push (decl);
-      DECL_ABSTRACT_P (decl) = 1;
-    }
-
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      tree arg;
-
-      for (arg = DECL_ARGUMENTS (decl); arg; arg = DECL_CHAIN (arg))
-       if (!DECL_ABSTRACT_P (arg))
-         {
-           abstract_vec.safe_push (arg);
-           DECL_ABSTRACT_P (arg) = 1;
-         }
-      if (DECL_INITIAL (decl) != NULL_TREE
-         && DECL_INITIAL (decl) != error_mark_node)
-       set_block_abstract_flags (DECL_INITIAL (decl), abstract_vec);
-    }
-}
-
-/* Generate the DWARF2 info for the "abstract" instance of a function which we
-   may later generate inlined and/or out-of-line instances of.
-
-   FIXME: In the early-dwarf world, this function, and most of the
-          DECL_ABSTRACT code should be obsoleted.  The early DIE _is_
-          the abstract instance.  All we would need to do is annotate
-          the early DIE with the appropriate DW_AT_inline in late
-          dwarf (perhaps in gen_inlined_subroutine_die).
-
-         However, we can't do this yet, because LTO streaming of DIEs
-         has not been implemented yet.  */
+/* Mark the early DIE for DECL as the abstract instance.  */
 
 static void
 dwarf2out_abstract_function (tree decl)
 {
   dw_die_ref old_die;
-  tree save_fn;
-  tree context;
-  hash_table<decl_loc_hasher> *old_decl_loc_table;
-  hash_table<dw_loc_list_hasher> *old_cached_dw_loc_list_table;
-  int old_call_site_count, old_tail_call_site_count;
-  struct call_arg_loc_node *old_call_arg_locations;
 
   /* Make sure we have the actual abstract inline, not a clone.  */
   decl = DECL_ORIGIN (decl);
 
+  if (DECL_IGNORED_P (decl))
+    return;
+
   old_die = lookup_decl_die (decl);
-  if (old_die && get_AT (old_die, DW_AT_inline))
+  /* With early debug we always have an old DIE.  */
+  gcc_assert (old_die != NULL);
+  if (get_AT (old_die, DW_AT_inline)
+      || get_AT (old_die, DW_AT_abstract_origin))
     /* We've already generated the abstract instance.  */
     return;
 
-  /* We can be called while recursively when seeing block defining inlined subroutine
-     DIE.  Be sure to not clobber the outer location table nor use it or we would
-     get locations in abstract instantces.  */
-  old_decl_loc_table = decl_loc_table;
-  decl_loc_table = NULL;
-  old_cached_dw_loc_list_table = cached_dw_loc_list_table;
-  cached_dw_loc_list_table = NULL;
-  old_call_arg_locations = call_arg_locations;
-  call_arg_locations = NULL;
-  old_call_site_count = call_site_count;
-  call_site_count = -1;
-  old_tail_call_site_count = tail_call_site_count;
-  tail_call_site_count = -1;
-
-  /* Be sure we've emitted the in-class declaration DIE (if any) first, so
-     we don't get confused by DECL_ABSTRACT_P.  */
-  if (debug_info_level > DINFO_LEVEL_TERSE)
+  /* Go ahead and put DW_AT_inline on the DIE.  */
+  if (DECL_DECLARED_INLINE_P (decl))
+    {
+      if (cgraph_function_possibly_inlined_p (decl))
+       add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_inlined);
+      else
+       add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_not_inlined);
+    }
+  else
     {
-      context = decl_class_context (decl);
-      if (context)
-       gen_type_die_for_member
-         (context, decl, decl_function_context (decl) ? NULL : comp_unit_die ());
+      if (cgraph_function_possibly_inlined_p (decl))
+       add_AT_unsigned (old_die, DW_AT_inline, DW_INL_inlined);
+      else
+       add_AT_unsigned (old_die, DW_AT_inline, DW_INL_not_inlined);
     }
 
-  /* Pretend we've just finished compiling this function.  */
-  save_fn = current_function_decl;
-  current_function_decl = decl;
+  if (DECL_DECLARED_INLINE_P (decl)
+      && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
+    add_AT_flag (old_die, DW_AT_artificial, 1);
 
-  auto_vec<tree, 64> abstract_vec;
-  set_decl_abstract_flags (decl, abstract_vec);
-  dwarf2out_decl (decl);
-  unsigned int i;
-  tree t;
-  FOR_EACH_VEC_ELT (abstract_vec, i, t)
-    if (TREE_CODE (t) == BLOCK)
-      BLOCK_ABSTRACT (t) = 0;
-    else
-      DECL_ABSTRACT_P (t) = 0;
-
-  current_function_decl = save_fn;
-  decl_loc_table = old_decl_loc_table;
-  cached_dw_loc_list_table = old_cached_dw_loc_list_table;
-  call_arg_locations = old_call_arg_locations;
-  call_site_count = old_call_site_count;
-  tail_call_site_count = old_tail_call_site_count;
+  set_decl_origin_self (decl);
 }
 
 /* Helper function of premark_used_types() which gets called through
@@ -21894,7 +22106,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       && debug_info_level > DINFO_LEVEL_TERSE)
     old_die = force_decl_die (decl);
 
-  /* An inlined instance, tag a new DIE with DW_AT_abstract_origin.  */
+  /* A concrete instance, tag a new DIE with DW_AT_abstract_origin.  */
   if (origin != NULL)
     {
       gcc_assert (!declaration || local_scope_p (context_die));
@@ -21973,6 +22185,10 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
               && old_die->die_parent->die_tag == DW_TAG_module)
           || context_die == NULL)
           && (DECL_ARTIFICIAL (decl)
+              /* The location attributes may be in the abstract origin
+                 which in the case of LTO might be not available to
+                 look at.  */
+              || get_AT (old_die, DW_AT_abstract_origin)
               || (get_AT_file (old_die, DW_AT_decl_file) == file_index
                   && (get_AT_unsigned (old_die, DW_AT_decl_line)
                       == (unsigned) s.line)
@@ -22839,6 +23055,24 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
          /* If a DIE was dumped early, it still needs location info.
             Skip to where we fill the location bits.  */
          var_die = old_die;
+
+         /* ???  In LTRANS we cannot annotate early created variably
+            modified type DIEs without copying them and adjusting all
+            references to them.  Thus we dumped them again, also add a
+            reference to them.  */
+         tree type = TREE_TYPE (decl_or_origin);
+         if (in_lto_p
+             && variably_modified_type_p
+                  (type, decl_function_context (decl_or_origin)))
+           {
+             if (decl_by_reference_p (decl_or_origin))
+               add_type_attribute (var_die, TREE_TYPE (type),
+                                   TYPE_UNQUALIFIED, false, context_die);
+             else
+               add_type_attribute (var_die, type, decl_quals (decl_or_origin),
+                                   false, context_die);
+           }
+
          goto gen_variable_die_location;
        }
     }
@@ -23239,12 +23473,6 @@ gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die)
   gcc_checking_assert (DECL_ABSTRACT_P (decl)
                       || cgraph_function_possibly_inlined_p (decl));
 
-  /* Emit info for the abstract instance first, if we haven't yet.  We
-     must emit this even if the block is abstract, otherwise when we
-     emit the block below (or elsewhere), we may end up trying to emit
-     a die whose origin die hasn't been emitted, and crashing.  */
-  dwarf2out_abstract_function (decl);
-
   if (! BLOCK_ABSTRACT (stmt))
     {
       dw_die_ref subr_die
@@ -24317,7 +24545,8 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
   /* As we avoid creating DIEs for local typedefs (see decl_ultimate_origin
      checks in process_scope_var and modified_type_die), this should be called
      only for original types.  */
-  gcc_assert (decl_ultimate_origin (decl) == NULL);
+  gcc_assert (decl_ultimate_origin (decl) == NULL
+             || decl_ultimate_origin (decl) == decl);
 
   TREE_ASM_WRITTEN (decl) = 1;
   type_die = new_die (DW_TAG_typedef, context_die, decl);
@@ -24492,7 +24721,7 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
 
       tree name = TYPE_NAME (type);
       tree origin = decl_ultimate_origin (name);
-      if (origin != NULL)
+      if (origin != NULL && origin != name)
        {
          gen_decl_die (origin, NULL, NULL, context_die);
          return;
@@ -24850,7 +25079,22 @@ process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
                                             stmt, context_die);
     }
   else
-    gen_decl_die (decl, origin, NULL, context_die);
+    {
+      if (decl && DECL_P (decl))
+       {
+         die = lookup_decl_die (decl);
+
+         /* Early created DIEs do not have a parent as the decls refer
+            to the function as DECL_CONTEXT rather than the BLOCK.  */
+         if (die && die->die_parent == NULL)
+           {
+             gcc_assert (in_lto_p);
+             add_child_die (context_die, die);
+           }
+       }
+
+      gen_decl_die (decl, origin, NULL, context_die);
+    }
 }
 
 /* Generate all of the decls declared within a given scope and (recursively)
@@ -25261,14 +25505,19 @@ gen_decl_die (tree decl, tree origin, struct vlr_context *ctx,
        /* This is only a declaration.  */;
 #endif
 
+      /* We should have abstract copies already and should not generate
+        stray type DIEs in late LTO dumping.  */
+      if (! early_dwarf)
+       ;
+
       /* If we're emitting a clone, emit info for the abstract instance.  */
-      if (origin || DECL_ORIGIN (decl) != decl)
+      else if (origin || DECL_ORIGIN (decl) != decl)
        dwarf2out_abstract_function (origin
                                     ? DECL_ORIGIN (origin)
                                     : DECL_ABSTRACT_ORIGIN (decl));
 
-      /* If we're emitting an out-of-line copy of an inline function,
-        emit info for the abstract instance and set up to refer to it.  */
+      /* If we're emitting a possibly inlined function emit it as
+         abstract instance.  */
       else if (cgraph_function_possibly_inlined_p (decl)
               && ! DECL_ABSTRACT_P (decl)
               && ! class_or_namespace_scope_p (context_die)
@@ -25276,10 +25525,7 @@ gen_decl_die (tree decl, tree origin, struct vlr_context *ctx,
                  a declaration.  We must avoid setting DECL_ABSTRACT_ORIGIN in
                  that case, because that works only if we have a die.  */
               && DECL_INITIAL (decl) != NULL_TREE)
-       {
-         dwarf2out_abstract_function (decl);
-         set_decl_origin_self (decl);
-       }
+       dwarf2out_abstract_function (decl);
 
       /* Otherwise we're emitting the primary DIE for this decl.  */
       else if (debug_info_level > DINFO_LEVEL_TERSE)
@@ -25349,20 +25595,36 @@ gen_decl_die (tree decl, tree origin, struct vlr_context *ctx,
       if (debug_info_level <= DINFO_LEVEL_TERSE)
        break;
 
-      /* Output any DIEs that are needed to specify the type of this data
-        object.  */
-      if (decl_by_reference_p (decl_or_origin))
-       gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
-      else
-       gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+      /* Avoid generating stray type DIEs during late dwarf dumping.
+         All types have been dumped early.  */
+      if (early_dwarf
+         /* ???  But in LTRANS we cannot annotate early created variably
+            modified type DIEs without copying them and adjusting all
+            references to them.  Dump them again as happens for inlining
+            which copies both the decl and the types.  */
+         /* ???  And even non-LTO needs to re-visit type DIEs to fill
+            in VLA bound information for example.  */
+         || (decl && variably_modified_type_p (TREE_TYPE (decl),
+                                               current_function_decl)))
+       {
+         /* Output any DIEs that are needed to specify the type of this data
+            object.  */
+         if (decl_by_reference_p (decl_or_origin))
+           gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
+         else
+           gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+       }
 
-      /* And its containing type.  */
-      class_origin = decl_class_context (decl_or_origin);
-      if (class_origin != NULL_TREE)
-       gen_type_die_for_member (class_origin, decl_or_origin, context_die);
+      if (early_dwarf)
+       {
+         /* And its containing type.  */
+         class_origin = decl_class_context (decl_or_origin);
+         if (class_origin != NULL_TREE)
+           gen_type_die_for_member (class_origin, decl_or_origin, context_die);
 
-      /* And its containing namespace.  */
-      context_die = declare_in_namespace (decl_or_origin, context_die);
+         /* And its containing namespace.  */
+         context_die = declare_in_namespace (decl_or_origin, context_die);
+       }
 
       /* Now output the DIE to represent the data object itself.  This gets
         complicated because of the possibility that the VAR_DECL really
@@ -25392,10 +25654,23 @@ gen_decl_die (tree decl, tree origin, struct vlr_context *ctx,
       break;
 
     case PARM_DECL:
-      if (DECL_BY_REFERENCE (decl_or_origin))
-       gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
-      else
-       gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+      /* Avoid generating stray type DIEs during late dwarf dumping.
+         All types have been dumped early.  */
+      if (early_dwarf
+         /* ???  But in LTRANS we cannot annotate early created variably
+            modified type DIEs without copying them and adjusting all
+            references to them.  Dump them again as happens for inlining
+            which copies both the decl and the types.  */
+         /* ???  And even non-LTO needs to re-visit type DIEs to fill
+            in VLA bound information for example.  */
+         || (decl && variably_modified_type_p (TREE_TYPE (decl),
+                                               current_function_decl)))
+       {
+         if (DECL_BY_REFERENCE (decl_or_origin))
+           gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die);
+         else
+           gen_type_die (TREE_TYPE (decl_or_origin), context_die);
+       }
       return gen_formal_parameter_die (decl, origin,
                                       true /* Emit name attribute.  */,
                                       context_die);
@@ -25467,6 +25742,16 @@ dwarf2out_early_global_decl (tree decl)
              dwarf2out_decl (context);
            }
 
+         /* Emit an abstract origin of a function first.  This happens
+            with C++ constructor clones for example and makes
+            dwarf2out_abstract_function happy which requires the early
+            DIE of the abstract instance to be present.  */
+         if (DECL_ABSTRACT_ORIGIN (decl))
+           {
+             current_function_decl = DECL_ABSTRACT_ORIGIN (decl);
+             dwarf2out_decl (DECL_ABSTRACT_ORIGIN (decl));
+           }
+
          current_function_decl = decl;
        }
       dwarf2out_decl (decl);
@@ -25488,7 +25773,9 @@ dwarf2out_late_global_decl (tree decl)
     {
       dw_die_ref die = lookup_decl_die (decl);
 
-      /* We have to generate early debug late for LTO.  */
+      /* We may have to generate early debug late for LTO in case debug
+         was not enabled at compile-time or the target doesn't support
+        the LTO early debug scheme.  */
       if (! die && in_lto_p)
        {
          dwarf2out_decl (decl);
@@ -26842,7 +27129,8 @@ output_macinfo_op (macinfo_entry *ref)
     case DW_MACRO_import:
       dw2_asm_output_data (1, ref->code, "Import");
       ASM_GENERATE_INTERNAL_LABEL (label,
-                                  DEBUG_MACRO_SECTION_LABEL, ref->lineno);
+                                  DEBUG_MACRO_SECTION_LABEL,
+                                  ref->lineno + macinfo_label_base);
       dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL);
       break;
     default:
@@ -27016,7 +27304,7 @@ save_macinfo_strings (void)
 /* Output macinfo section(s).  */
 
 static void
-output_macinfo (void)
+output_macinfo (const char *debug_line_label, bool early_lto_debug)
 {
   unsigned i;
   unsigned long length = vec_safe_length (macinfo_table);
@@ -27036,7 +27324,7 @@ output_macinfo (void)
 
   /* AIX Assembler inserts the length, so adjust the reference to match the
      offset expected by debuggers.  */
-  strcpy (dl_section_ref, debug_line_section_label);
+  strcpy (dl_section_ref, debug_line_label);
   if (XCOFF_DEBUGGING_INFO)
     strcat (dl_section_ref, DWARF_INITIAL_LENGTH_SIZE_STR);
 
@@ -27049,9 +27337,7 @@ output_macinfo (void)
        dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present");
       else
        dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present");
-      dw2_asm_output_offset (DWARF_OFFSET_SIZE,
-                             (!dwarf_split_debug_info ? dl_section_ref
-                              : debug_skeleton_line_section_label),
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_label,
                              debug_line_section, NULL);
     }
 
@@ -27105,6 +27391,10 @@ output_macinfo (void)
   if (!macinfo_htab)
     return;
 
+  /* Save the number of transparent includes so we can adjust the
+     label number for the fat LTO object DWARF.  */
+  unsigned macinfo_label_base_adj = macinfo_htab->elements ();
+
   delete macinfo_htab;
   macinfo_htab = NULL;
 
@@ -27124,11 +27414,13 @@ output_macinfo (void)
          dw2_asm_output_data (1, 0, "End compilation unit");
          targetm.asm_out.named_section (debug_macinfo_section_name,
                                         SECTION_DEBUG
-                                        | SECTION_LINKONCE,
+                                        | SECTION_LINKONCE
+                                        | (early_lto_debug
+                                           ? SECTION_EXCLUDE : 0),
                                         comdat_key);
          ASM_GENERATE_INTERNAL_LABEL (label,
                                       DEBUG_MACRO_SECTION_LABEL,
-                                      ref->lineno);
+                                      ref->lineno + macinfo_label_base);
          ASM_OUTPUT_LABEL (asm_out_file, label);
          ref->code = 0;
          ref->info = NULL;
@@ -27149,109 +27441,192 @@ output_macinfo (void)
       default:
        gcc_unreachable ();
       }
+
+  macinfo_label_base += macinfo_label_base_adj;
 }
 
-/* Initialize the various sections and labels for dwarf output.  */
+/* Initialize the various sections and labels for dwarf output and prefix
+   them with PREFIX if non-NULL.  */
 
 static void
-init_sections_and_labels (void)
+init_sections_and_labels (bool early_lto_debug)
 {
-  if (!dwarf_split_debug_info)
+  /* As we may get called multiple times have a generation count for labels.  */
+  static unsigned generation = 0;
+
+  if (early_lto_debug)
     {
-      debug_info_section = get_section (DEBUG_INFO_SECTION,
-                                        SECTION_DEBUG, NULL);
-      debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
-                                          SECTION_DEBUG, NULL);
-      debug_loc_section = get_section (dwarf_version >= 5
-                                      ? DEBUG_LOCLISTS_SECTION
-                                      : DEBUG_LOC_SECTION,
-                                       SECTION_DEBUG, NULL);
-      debug_macinfo_section_name
-       = (dwarf_strict && dwarf_version < 5)
-         ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION;
-      debug_macinfo_section = get_section (debug_macinfo_section_name,
-                                          SECTION_DEBUG, NULL);
+      if (!dwarf_split_debug_info)
+       {
+         debug_info_section = get_section (DEBUG_LTO_INFO_SECTION,
+                                           SECTION_DEBUG | SECTION_EXCLUDE,
+                                           NULL);
+         debug_abbrev_section = get_section (DEBUG_LTO_ABBREV_SECTION,
+                                             SECTION_DEBUG | SECTION_EXCLUDE,
+                                             NULL);
+         debug_macinfo_section_name = ((dwarf_strict && dwarf_version < 5)
+                                       ? DEBUG_LTO_MACINFO_SECTION
+                                       : DEBUG_LTO_MACRO_SECTION);
+         debug_macinfo_section = get_section (debug_macinfo_section_name,
+                                              SECTION_DEBUG
+                                              | SECTION_EXCLUDE, NULL);
+         /* For macro info we have to refer to a debug_line section, so similar
+            to split-dwarf emit a skeleton one for early debug.  */
+         debug_skeleton_line_section
+           = get_section (DEBUG_LTO_LINE_SECTION,
+                          SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+         ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+                                      DEBUG_SKELETON_LINE_SECTION_LABEL,
+                                      generation);
+       }
+      else
+       {
+         /* ???  Which of the following do we need early?  */
+         debug_info_section = get_section (DEBUG_LTO_DWO_INFO_SECTION,
+                                           SECTION_DEBUG | SECTION_EXCLUDE,
+                                           NULL);
+         debug_abbrev_section = get_section (DEBUG_LTO_DWO_ABBREV_SECTION,
+                                             SECTION_DEBUG | SECTION_EXCLUDE,
+                                             NULL);
+         debug_skeleton_info_section = get_section (DEBUG_LTO_INFO_SECTION,
+                                                    SECTION_DEBUG
+                                                    | SECTION_EXCLUDE, NULL);
+         debug_skeleton_abbrev_section = get_section (DEBUG_LTO_ABBREV_SECTION,
+                                                      SECTION_DEBUG
+                                                      | SECTION_EXCLUDE, NULL);
+         ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
+                                      DEBUG_SKELETON_ABBREV_SECTION_LABEL,
+                                      generation);
+
+         /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
+            the main .o, but the skeleton_line goes into the split off dwo.  */
+         debug_skeleton_line_section
+           = get_section (DEBUG_LTO_LINE_SECTION,
+                          SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+         ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+                                      DEBUG_SKELETON_LINE_SECTION_LABEL,
+                                      generation);
+         debug_str_offsets_section
+           = get_section (DEBUG_LTO_DWO_STR_OFFSETS_SECTION,
+                          SECTION_DEBUG | SECTION_EXCLUDE,
+                          NULL);
+         ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
+                                      DEBUG_SKELETON_INFO_SECTION_LABEL,
+                                      generation);
+         debug_str_dwo_section = get_section (DEBUG_LTO_STR_DWO_SECTION,
+                                              DEBUG_STR_DWO_SECTION_FLAGS, NULL);
+         debug_macinfo_section_name
+           = (dwarf_strict
+              ? DEBUG_LTO_DWO_MACINFO_SECTION : DEBUG_LTO_DWO_MACRO_SECTION);
+         debug_macinfo_section = get_section (debug_macinfo_section_name,
+                                              SECTION_DEBUG | SECTION_EXCLUDE,
+                                              NULL);
+       }
+      debug_str_section = get_section (DEBUG_LTO_STR_SECTION,
+                                      DEBUG_STR_SECTION_FLAGS
+                                      | SECTION_EXCLUDE, NULL);
     }
   else
     {
-      debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
-                                        SECTION_DEBUG | SECTION_EXCLUDE, NULL);
-      debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
-                                          SECTION_DEBUG | SECTION_EXCLUDE,
-                                          NULL);
-      debug_addr_section = get_section (DEBUG_ADDR_SECTION,
-                                        SECTION_DEBUG, NULL);
-      debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
-                                                 SECTION_DEBUG, NULL);
-      debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
-                                                   SECTION_DEBUG, NULL);
-      ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
-                                  DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0);
-
-      /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
-         the main .o, but the skeleton_line goes into the split off dwo.  */
-      debug_skeleton_line_section
-        = get_section (DEBUG_DWO_LINE_SECTION,
-                      SECTION_DEBUG | SECTION_EXCLUDE, NULL);
-      ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
-                                   DEBUG_SKELETON_LINE_SECTION_LABEL, 0);
-      debug_str_offsets_section = get_section (DEBUG_DWO_STR_OFFSETS_SECTION,
-                                               SECTION_DEBUG | SECTION_EXCLUDE,
-                                               NULL);
-      ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
-                                   DEBUG_SKELETON_INFO_SECTION_LABEL, 0);
-      debug_loc_section = get_section (dwarf_version >= 5
-                                      ? DEBUG_DWO_LOCLISTS_SECTION
-                                      : DEBUG_DWO_LOC_SECTION,
-                                       SECTION_DEBUG | SECTION_EXCLUDE, NULL);
-      debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
-                                           DEBUG_STR_DWO_SECTION_FLAGS, NULL);
-      debug_macinfo_section_name
-       = (dwarf_strict && dwarf_version < 5)
-         ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
-      debug_macinfo_section = get_section (debug_macinfo_section_name,
+      if (!dwarf_split_debug_info)
+       {
+         debug_info_section = get_section (DEBUG_INFO_SECTION,
+                                           SECTION_DEBUG, NULL);
+         debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+                                             SECTION_DEBUG, NULL);
+         debug_loc_section = get_section (DEBUG_LOC_SECTION,
+                                          SECTION_DEBUG, NULL);
+         debug_macinfo_section_name
+             = dwarf_strict ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION;
+         debug_macinfo_section = get_section (debug_macinfo_section_name,
+                                              SECTION_DEBUG, NULL);
+       }
+      else
+       {
+         debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
+                                           SECTION_DEBUG | SECTION_EXCLUDE,
+                                           NULL);
+         debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
+                                             SECTION_DEBUG | SECTION_EXCLUDE,
+                                             NULL);
+         debug_addr_section = get_section (DEBUG_ADDR_SECTION,
+                                           SECTION_DEBUG, NULL);
+         debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
+                                                    SECTION_DEBUG, NULL);
+         debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
+                                                      SECTION_DEBUG, NULL);
+         ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
+                                      DEBUG_SKELETON_ABBREV_SECTION_LABEL,
+                                      generation);
+
+         /* Somewhat confusing detail: The skeleton_[abbrev|info] sections
+            stay in the main .o, but the skeleton_line goes into the
+            split off dwo.  */
+         debug_skeleton_line_section
+             = get_section (DEBUG_DWO_LINE_SECTION,
+                            SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+         ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
+                                      DEBUG_SKELETON_LINE_SECTION_LABEL,
+                                      generation);
+         debug_str_offsets_section
+           = get_section (DEBUG_DWO_STR_OFFSETS_SECTION,
+                          SECTION_DEBUG | SECTION_EXCLUDE, NULL);
+         ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
+                                      DEBUG_SKELETON_INFO_SECTION_LABEL,
+                                      generation);
+         debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
                                           SECTION_DEBUG | SECTION_EXCLUDE,
                                           NULL);
-    }
-  debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
-                                      SECTION_DEBUG, NULL);
-  debug_line_section = get_section (DEBUG_LINE_SECTION,
-                                   SECTION_DEBUG, NULL);
-  debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
-                                       SECTION_DEBUG, NULL);
-  debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+         debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
+                                              DEBUG_STR_DWO_SECTION_FLAGS,
+                                              NULL);
+         debug_macinfo_section_name
+           = (dwarf_strict && dwarf_version < 5)
+             ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
+         debug_macinfo_section = get_section (debug_macinfo_section_name,
+                                              SECTION_DEBUG | SECTION_EXCLUDE,
+                                              NULL);
+       }
+      debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
+                                          SECTION_DEBUG, NULL);
+      debug_line_section = get_section (DEBUG_LINE_SECTION,
                                        SECTION_DEBUG, NULL);
-  debug_str_section = get_section (DEBUG_STR_SECTION,
-                                  DEBUG_STR_SECTION_FLAGS, NULL);
-  if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
-    debug_line_str_section = get_section (DEBUG_LINE_STR_SECTION,
-                                         DEBUG_STR_SECTION_FLAGS, NULL);
-
-  debug_ranges_section = get_section (dwarf_version >= 5
-                                     ? DEBUG_RNGLISTS_SECTION
-                                     : DEBUG_RANGES_SECTION,
-                                     SECTION_DEBUG, NULL);
-  debug_frame_section = get_section (DEBUG_FRAME_SECTION,
-                                    SECTION_DEBUG, NULL);
+      debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
+                                           SECTION_DEBUG, NULL);
+      debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+                                           SECTION_DEBUG, NULL);
+      debug_str_section = get_section (DEBUG_STR_SECTION,
+                                      DEBUG_STR_SECTION_FLAGS, NULL);
+      debug_ranges_section = get_section (dwarf_version >= 5
+                                         ? DEBUG_RNGLISTS_SECTION
+                                         : DEBUG_RANGES_SECTION,
+                                         SECTION_DEBUG, NULL);
+      debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+                                        SECTION_DEBUG, NULL);
+    }
 
   ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
-                              DEBUG_ABBREV_SECTION_LABEL, 0);
+                              DEBUG_ABBREV_SECTION_LABEL, generation);
   ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
-                              DEBUG_INFO_SECTION_LABEL, 0);
+                              DEBUG_INFO_SECTION_LABEL, generation);
+  info_section_emitted = false;
   ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
-                              DEBUG_LINE_SECTION_LABEL, 0);
+                              DEBUG_LINE_SECTION_LABEL, generation);
   ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
-                              DEBUG_RANGES_SECTION_LABEL, 0);
+                              DEBUG_RANGES_SECTION_LABEL, generation);
   if (dwarf_version >= 5 && dwarf_split_debug_info)
     ASM_GENERATE_INTERNAL_LABEL (ranges_base_label,
-                                DEBUG_RANGES_SECTION_LABEL, 1);
+                                DEBUG_RANGES_SECTION_LABEL, 2 + generation);
   ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
-                               DEBUG_ADDR_SECTION_LABEL, 0);
+                               DEBUG_ADDR_SECTION_LABEL, generation);
   ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
                               (dwarf_strict && dwarf_version < 5)
                               ? DEBUG_MACINFO_SECTION_LABEL
-                              : DEBUG_MACRO_SECTION_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0);
+                              : DEBUG_MACRO_SECTION_LABEL, generation);
+  ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL,
+                              generation);
+
+  ++generation;
 }
 
 /* Set up for Dwarf output at the start of compilation.  */
@@ -29598,6 +29973,22 @@ flush_limbo_die_list (void)
     }
 }
 
+/* Reset DIEs so we can output them again.  */
+
+static void
+reset_dies (dw_die_ref die)
+{
+  dw_die_ref c;
+
+  /* Remove stuff we re-generate.  */
+  die->die_mark = 0;
+  die->die_offset = 0;
+  die->die_abbrev = 0;
+  remove_AT (die, DW_AT_sibling);
+
+  FOR_EACH_CHILD (die, c, reset_dies (c));
+}
+
 /* Output stuff that dwarf requires at the end of every file,
    and generate the DWARF-2 debugging info.  */
 
@@ -29625,6 +30016,46 @@ dwarf2out_finish (const char *)
 
   gen_remaining_tmpl_value_param_die_attribute ();
 
+  if (flag_generate_lto)
+    {
+      gcc_assert (flag_fat_lto_objects);
+
+      /* Prune stuff so that dwarf2out_finish runs successfully
+        for the fat part of the object.  */
+      reset_dies (comp_unit_die ());
+      for (limbo_die_node *node = cu_die_list; node; node = node->next)
+       reset_dies (node->die);
+
+      hash_table<comdat_type_hasher> comdat_type_table (100);
+      for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
+       {
+         comdat_type_node **slot
+             = comdat_type_table.find_slot (ctnode, INSERT);
+
+         /* Don't reset types twice.  */
+         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_TERSE)
+           reset_dies (ctnode->root_die);
+
+         *slot = ctnode;
+       }
+
+      /* Reset die CU symbol so we don't output it twice.  */
+      comp_unit_die ()->die_id.die_symbol = NULL;
+
+      /* Remove DW_AT_macro from the early output.  */
+      if (have_macinfo)
+       remove_AT (comp_unit_die (), DEBUG_MACRO_ATTRIBUTE);
+
+      /* Remove indirect string decisions.  */
+      debug_str_hash->traverse<void *, reset_indirect_string> (NULL);
+    }
+
 #if ENABLE_ASSERT_CHECKING
   {
     dw_die_ref die = comp_unit_die (), c;
@@ -29635,7 +30066,7 @@ dwarf2out_finish (const char *)
   move_marked_base_types ();
 
   /* Initialize sections and labels used for actual assembler output.  */
-  init_sections_and_labels ();
+  init_sections_and_labels (false);
 
   /* Traverse the DIE's and add sibling attributes to those DIE's that
      have children.  */
@@ -29736,9 +30167,7 @@ dwarf2out_finish (const char *)
                    dl_section_ref);
 
   if (have_macinfo)
-    add_AT_macptr (comp_unit_die (),
-                  dwarf_version >= 5 ? DW_AT_macros
-                  : dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
+    add_AT_macptr (comp_unit_die (), DEBUG_MACRO_ATTRIBUTE,
                   macinfo_section_label);
 
   if (dwarf_split_debug_info)
@@ -29943,7 +30372,8 @@ dwarf2out_finish (const char *)
     {
       switch_to_section (debug_macinfo_section);
       ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
-      output_macinfo ();
+      output_macinfo (!dwarf_split_debug_info ? debug_line_section_label
+                     : debug_skeleton_line_section_label, false);
       dw2_asm_output_data (1, 0, "End compilation unit");
     }
 
@@ -30164,6 +30594,20 @@ note_variable_value_in_expr (dw_die_ref die, dw_loc_descr_ref loc)
       {
        tree decl = loc->dw_loc_oprnd1.v.val_decl_ref;
        dw_die_ref ref = lookup_decl_die (decl);
+       if (! ref && flag_generate_lto)
+         {
+           /* ???  This is somewhat a hack because we do not create DIEs
+              for variables not in BLOCK trees early but when generating
+              early LTO output we need the dw_val_class_decl_ref to be
+              fully resolved.  For fat LTO objects we'd also like to
+              undo this after LTO dwarf output.  */
+           gcc_assert (DECL_CONTEXT (decl));
+           dw_die_ref ctx = lookup_decl_die (DECL_CONTEXT (decl));
+           gcc_assert (ctx != NULL);
+           gen_decl_die (decl, NULL_TREE, NULL, ctx);
+           ref = lookup_decl_die (decl);
+           gcc_assert (ref != NULL);
+         }
        if (ref)
          {
            loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
@@ -30374,6 +30818,119 @@ dwarf2out_early_finish (const char *filename)
 
   /* The early debug phase is now finished.  */
   early_dwarf_finished = true;
+
+  /* Do not generate DWARF assembler now when not producing LTO bytecode.  */
+  if (!flag_generate_lto)
+    return;
+
+  /* Now as we are going to output for LTO initialize sections and labels
+     to the LTO variants.  We don't need a random-seed postfix as other
+     LTO sections as linking the LTO debug sections into one in a partial
+     link is fine.  */
+  init_sections_and_labels (true);
+
+  /* The output below is modeled after dwarf2out_finish with all
+     location related output removed and some LTO specific changes.
+     Some refactoring might make both smaller and easier to match up.  */
+
+  /* Traverse the DIE's and add add sibling attributes to those DIE's
+     that have children.  */
+  add_sibling_attributes (comp_unit_die ());
+  for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+    add_sibling_attributes (node->die);
+  for (comdat_type_node *ctnode = comdat_type_list;
+       ctnode != NULL; ctnode = ctnode->next)
+    add_sibling_attributes (ctnode->root_die);
+
+  if (have_macinfo)
+    add_AT_macptr (comp_unit_die (), DEBUG_MACRO_ATTRIBUTE,
+                  macinfo_section_label);
+
+  save_macinfo_strings ();
+
+  /* Output all of the compilation units.  We put the main one last so that
+     the offsets are available to output_pubnames.  */
+  for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+    output_comp_unit (node->die, 0, NULL);
+
+  hash_table<comdat_type_hasher> comdat_type_table (100);
+  for (comdat_type_node *ctnode = comdat_type_list;
+       ctnode != NULL; ctnode = ctnode->next)
+    {
+      comdat_type_node **slot = comdat_type_table.find_slot (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_TERSE)
+        add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
+                        (!dwarf_split_debug_info
+                         ? debug_line_section_label
+                         : debug_skeleton_line_section_label));
+
+      output_comdat_type_unit (ctnode);
+      *slot = ctnode;
+    }
+
+  /* The AT_pubnames attribute needs to go in all skeleton dies, including
+     both the main_cu and all skeleton TUs.  Making this call unconditional
+     would end up either adding a second copy of the AT_pubnames attribute, or
+     requiring a special case in add_top_level_skeleton_die_attrs.  */
+  if (!dwarf_split_debug_info)
+    add_AT_pubnames (comp_unit_die ());
+
+  /* Stick a unique symbol to the main debuginfo section.  */
+  compute_comp_unit_symbol (comp_unit_die ());
+
+  /* Output the main compilation unit.  We always need it if only for
+     the CU symbol.  */
+  output_comp_unit (comp_unit_die (), true, NULL);
+
+  /* Output the abbreviation table.  */
+  if (vec_safe_length (abbrev_die_table) != 1)
+    {
+      switch_to_section (debug_abbrev_section);
+      ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
+      output_abbrev_section ();
+    }
+
+  /* Have to end the macro section.  */
+  if (have_macinfo)
+    {
+      /* We have to save macinfo state if we need to output it again
+        for the FAT part of the object.  */
+      vec<macinfo_entry, va_gc> *saved_macinfo_table = macinfo_table;
+      if (flag_fat_lto_objects)
+       macinfo_table = macinfo_table->copy ();
+
+      switch_to_section (debug_macinfo_section);
+      ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
+      output_macinfo (debug_skeleton_line_section_label, true);
+      dw2_asm_output_data (1, 0, "End compilation unit");
+
+      /* Emit a skeleton debug_line section.  */
+      switch_to_section (debug_skeleton_line_section);
+      ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
+      output_line_info (true);
+
+      if (flag_fat_lto_objects)
+       {
+         vec_free (macinfo_table);
+         macinfo_table = saved_macinfo_table;
+       }
+    }
+
+
+  /* If we emitted any indirect strings, output the string table too.  */
+  if (debug_str_hash || skeleton_debug_str_hash)
+    output_indirect_strings ();
+
+  /* Switch back to the text section.  */
+  switch_to_section (text_section);
 }
 
 /* Reset all state within dwarf2out.c so that we can rerun the compiler
index 5710e8f126db7a53653d8c19d844a9fccbb8be00..ee85efc9754b0cd76dea6439eddc2d095ae5bc0b 100644 (file)
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "except.h"
 #include "cgraph.h"
 #include "cfgloop.h"
+#include "debug.h"
 
 
 struct freeing_string_slot_hasher : string_slot_hasher
@@ -1038,6 +1039,16 @@ input_function (tree fn_decl, struct data_in *data_in,
   DECL_RESULT (fn_decl) = stream_read_tree (ib, data_in);
   DECL_ARGUMENTS (fn_decl) = streamer_read_chain (ib, data_in);
 
+  /* Read debug args if available.  */
+  unsigned n_debugargs = streamer_read_uhwi (ib);
+  if (n_debugargs)
+    {
+      vec<tree, va_gc> **debugargs = decl_debug_args_insert (fn_decl);
+      vec_safe_grow (*debugargs, n_debugargs);
+      for (unsigned i = 0; i < n_debugargs; ++i)
+       (**debugargs)[i] = stream_read_tree (ib, data_in);
+    }
+
   /* Read the tree of lexical scopes for the function.  */
   DECL_INITIAL (fn_decl) = stream_read_tree (ib, data_in);
   unsigned block_leaf_count = streamer_read_uhwi (ib);
@@ -1322,6 +1333,10 @@ lto_input_variable_constructor (struct lto_file_decl_data *file_data,
 }
 
 
+/* Queue of acummulated decl -> DIE mappings.  Similar to locations those
+   are only applied to prevailing tree nodes during tree merging.  */
+vec<dref_entry> dref_queue;
+
 /* Read the physical representation of a tree node EXPR from
    input block IB using the per-file context in DATA_IN.  */
 
@@ -1341,6 +1356,23 @@ lto_read_tree_1 (struct lto_input_block *ib, struct data_in *data_in, tree expr)
       && TREE_CODE (expr) != FUNCTION_DECL
       && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
     DECL_INITIAL (expr) = stream_read_tree (ib, data_in);
+
+  /* Stream references to early generated DIEs.  Keep in sync with the
+     trees handled in dwarf2out_register_external_die.  */
+  if ((DECL_P (expr)
+       && TREE_CODE (expr) != FIELD_DECL
+       && TREE_CODE (expr) != DEBUG_EXPR_DECL
+       && TREE_CODE (expr) != TYPE_DECL)
+      || TREE_CODE (expr) == BLOCK)
+    {
+      const char *str = streamer_read_string (data_in, ib);
+      if (str)
+       {
+         unsigned HOST_WIDE_INT off = streamer_read_uhwi (ib);
+         dref_entry e = { expr, str, off };
+         dref_queue.safe_push (e);
+       }
+    }
 }
 
 /* Read the physical representation of a tree node with tag TAG from
@@ -1486,6 +1518,13 @@ lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
     {
       unsigned len, entry_len;
       lto_input_scc (ib, data_in, &len, &entry_len);
+
+      /* Register DECLs with the debuginfo machinery.  */
+      while (!dref_queue.is_empty ())
+       {
+         dref_entry e = dref_queue.pop ();
+         debug_hooks->register_external_die (e.decl, e.sym, e.off);
+       }
     }
   return lto_input_tree_1 (ib, data_in, tag, 0);
 }
index 5988af52b2adb52d25ad2b26eb743cb49cb20ca7..944502be3f8aef9408c81cbf7beb48f738c7fa1d 100644 (file)
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "builtins.h"
 #include "gomp-constants.h"
+#include "debug.h"
 
 
 static void lto_write_tree (struct output_block*, tree, bool);
@@ -406,6 +407,26 @@ lto_write_tree_1 (struct output_block *ob, tree expr, bool ref_p)
                         (ob->decl_state->symtab_node_encoder, expr);
       stream_write_tree (ob, initial, ref_p);
     }
+
+  /* Stream references to early generated DIEs.  Keep in sync with the
+     trees handled in dwarf2out_die_ref_for_decl.  */
+  if ((DECL_P (expr)
+       && TREE_CODE (expr) != FIELD_DECL
+       && TREE_CODE (expr) != DEBUG_EXPR_DECL
+       && TREE_CODE (expr) != TYPE_DECL)
+      || TREE_CODE (expr) == BLOCK)
+    {
+      const char *sym;
+      unsigned HOST_WIDE_INT off;
+      if (debug_info_level > DINFO_LEVEL_NONE
+         && debug_hooks->die_ref_for_decl (expr, &sym, &off))
+       {
+         streamer_write_string (ob, ob->main_stream, sym, true);
+         streamer_write_uhwi (ob, off);
+       }
+      else
+       streamer_write_string (ob, ob->main_stream, NULL, true);
+    }
 }
 
 /* Write a physical representation of tree node EXPR to output block
@@ -745,7 +766,11 @@ DFS::DFS_write_tree_body (struct output_block *ob,
        ;
       else
        DFS_follow_tree_edge (DECL_NAME (expr));
-      DFS_follow_tree_edge (DECL_CONTEXT (expr));
+      if (TREE_CODE (expr) != TRANSLATION_UNIT_DECL
+         && ! DECL_CONTEXT (expr))
+       DFS_follow_tree_edge ((*all_translation_units)[0]);
+      else
+       DFS_follow_tree_edge (DECL_CONTEXT (expr));
     }
 
   if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
@@ -765,6 +790,7 @@ DFS::DFS_write_tree_body (struct output_block *ob,
         declarations which should be eliminated by decl merging. Be sure none
         leaks to this point.  */
       gcc_assert (DECL_ABSTRACT_ORIGIN (expr) != error_mark_node);
+      DFS_follow_tree_edge (DECL_ABSTRACT_ORIGIN (expr));
 
       if ((VAR_P (expr)
           || TREE_CODE (expr) == PARM_DECL)
@@ -2057,6 +2083,17 @@ output_function (struct cgraph_node *node)
   stream_write_tree (ob, DECL_RESULT (function), true);
   streamer_write_chain (ob, DECL_ARGUMENTS (function), true);
 
+  /* Output debug args if available. */
+  vec<tree, va_gc> **debugargs = decl_debug_args_lookup (function);
+  if (! debugargs)
+    streamer_write_uhwi (ob, 0);
+  else
+    {
+      streamer_write_uhwi (ob, (*debugargs)->length ());
+      for (unsigned i = 0; i < (*debugargs)->length (); ++i)
+       stream_write_tree (ob, (**debugargs)[i], true);
+    }
+
   /* Output DECL_INITIAL for the function, which contains the tree of
      lexical scopes.  */
   stream_write_tree (ob, DECL_INITIAL (function), true);
index 7cf4b0b5fe96538e6df6a5bb3b600da817638ab4..cd33df8f392829f9e0c7eb761d75fd90adcde860 100644 (file)
@@ -1212,4 +1212,14 @@ DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, type_decl)
 DEFINE_DECL_STREAM_FUNCS (NAMESPACE_DECL, namespace_decl)
 DEFINE_DECL_STREAM_FUNCS (LABEL_DECL, label_decl)
 
+/* Entry for the delayed registering of decl -> DIE references.  */
+struct dref_entry {
+    tree decl;
+    const char *sym;
+    unsigned HOST_WIDE_INT off;
+};
+
+extern vec<dref_entry> dref_queue;
+
+
 #endif /* GCC_LTO_STREAMER_H  */
index 5e75a4fa48cef999fd34c8bdcdcd42bf807d62af..841362a91e2ab23e62d07ab4cc3cf569a3a482c2 100644 (file)
@@ -70,6 +70,7 @@ static char **output_names;
 static char **offload_names;
 static char *offload_objects_file_name;
 static char *makefile;
+static char *debug_obj;
 
 const char tool_name[] = "lto-wrapper";
 
@@ -88,6 +89,8 @@ tool_cleanup (bool)
     maybe_unlink (offload_objects_file_name);
   if (makefile)
     maybe_unlink (makefile);
+  if (debug_obj)
+    maybe_unlink (debug_obj);
   for (i = 0; i < nr; ++i)
     {
       maybe_unlink (input_names[i]);
@@ -960,6 +963,67 @@ find_and_merge_options (int fd, off_t file_offset, const char *prefix,
   return true;
 }
 
+/* Copy early debug info sections from INFILE to a new file whose name
+   is returned.  Return NULL on error.  */
+
+const char *
+debug_objcopy (const char *infile)
+{
+  const char *outfile;
+  const char *errmsg;
+  int err;
+
+  const char *p;
+  off_t inoff = 0;
+  long loffset;
+  int consumed;
+  if ((p = strrchr (infile, '@'))
+      && p != infile
+      && sscanf (p, "@%li%n", &loffset, &consumed) >= 1
+      && strlen (p) == (unsigned int) consumed)
+    {
+      char *fname = xstrdup (infile);
+      fname[p - infile] = '\0';
+      infile = fname;
+      inoff = (off_t) loffset;
+    }
+  int infd = open (infile, O_RDONLY);
+  if (infd == -1)
+    return NULL;
+  simple_object_read *inobj = simple_object_start_read (infd, inoff,
+                                                       "__GNU_LTO",
+                                                       &errmsg, &err);
+  if (!inobj)
+    return NULL;
+
+  off_t off, len;
+  if (simple_object_find_section (inobj, ".gnu.debuglto_.debug_info",
+                                 &off, &len, &errmsg, &err) != 1)
+    {
+      if (errmsg)
+       fatal_error (0, "%s: %s\n", errmsg, xstrerror (err));
+
+      simple_object_release_read (inobj);
+      close (infd);
+      return NULL;
+    }
+
+  outfile = make_temp_file ("debugobjtem");
+  errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err);
+  if (errmsg)
+    {
+      unlink_if_ordinary (outfile);
+      fatal_error (0, "%s: %s\n", errmsg, xstrerror (err));
+    }
+
+  simple_object_release_read (inobj);
+  close (infd);
+
+  return outfile;
+}
+
+
+
 /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
 
 static void
@@ -984,8 +1048,10 @@ run_gcc (unsigned argc, char *argv[])
   int new_head_argc;
   bool have_lto = false;
   bool have_offload = false;
-  unsigned lto_argc = 0;
-  char **lto_argv;
+  unsigned lto_argc = 0, ltoobj_argc = 0;
+  char **lto_argv, **ltoobj_argv;
+  bool skip_debug = false;
+  unsigned n_debugobj;
 
   /* Get the driver and options.  */
   collect_gcc = getenv ("COLLECT_GCC");
@@ -1004,6 +1070,7 @@ run_gcc (unsigned argc, char *argv[])
   /* Allocate array for input object files with LTO IL,
      and for possible preceding arguments.  */
   lto_argv = XNEWVEC (char *, argc);
+  ltoobj_argv = XNEWVEC (char *, argc);
 
   /* Look at saved options in the IL files.  */
   for (i = 1; i < argc; ++i)
@@ -1046,7 +1113,7 @@ run_gcc (unsigned argc, char *argv[])
                                  collect_gcc))
        {
          have_lto = true;
-         lto_argv[lto_argc++] = argv[i];
+         ltoobj_argv[ltoobj_argc++] = argv[i];
        }
       close (fd);
     }
@@ -1107,6 +1174,17 @@ run_gcc (unsigned argc, char *argv[])
        }
     }
 
+  /* Output lto-wrapper invocation command.  */
+  if (verbose)
+    {
+      for (i = 0; i < argc; ++i)
+       {
+         fputs (argv[i], stderr);
+         fputc (' ', stderr);
+       }
+      fputc ('\n', stderr);
+    }
+
   if (no_partition)
     {
       lto_mode = LTO_MODE_LTO;
@@ -1296,18 +1374,105 @@ cont1:
         obstack_ptr_grow (&argv_obstack, "-fwpa");
     }
 
-  /* Append the input objects and possible preceding arguments.  */
+  /* Append input arguments.  */
   for (i = 0; i < lto_argc; ++i)
     obstack_ptr_grow (&argv_obstack, lto_argv[i]);
+  /* Append the input objects.  */
+  for (i = 0; i < ltoobj_argc; ++i)
+    obstack_ptr_grow (&argv_obstack, ltoobj_argv[i]);
   obstack_ptr_grow (&argv_obstack, NULL);
 
   new_argv = XOBFINISH (&argv_obstack, const char **);
   argv_ptr = &new_argv[new_head_argc];
   fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
 
+  /* Handle early generated debug information.  At compile-time
+     we output early DWARF debug info into .gnu.debuglto_ prefixed
+     sections.  LTRANS object DWARF debug info refers to that.
+     So we need to transfer the .gnu.debuglto_ sections to the final
+     link.  Ideally the linker plugin interface would allow us to
+     not claim those sections and instruct the linker to keep
+     them, renaming them in the process.  For now we extract and
+     rename those sections via a simple-object interface to produce
+     regular objects containing only the early debug info.  We
+     then partially link those to a single early debug info object
+     and pass that as additional output back to the linker plugin.  */
+
+  /* Prepare the partial link to gather the compile-time generated
+     debug-info into a single input for the final link.  */
+  debug_obj = make_temp_file ("debugobj");
+  obstack_ptr_grow (&argv_obstack, collect_gcc);
+  for (i = 1; i < decoded_options_count; ++i)
+    {
+      /* Retain linker choice and -B.  */
+      if (decoded_options[i].opt_index == OPT_B
+         || decoded_options[i].opt_index == OPT_fuse_ld_bfd
+         || decoded_options[i].opt_index == OPT_fuse_ld_gold)
+       append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+      /* Retain all target options, this preserves -m32 for example.  */
+      if (cl_options[decoded_options[i].opt_index].flags & CL_TARGET)
+       append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+      /* Recognize -g0.  */
+      if (decoded_options[i].opt_index == OPT_g
+         && strcmp (decoded_options[i].arg, "0") == 0)
+       skip_debug = true;
+    }
+  obstack_ptr_grow (&argv_obstack, "-r");
+  obstack_ptr_grow (&argv_obstack, "-nostdlib");
+  obstack_ptr_grow (&argv_obstack, "-o");
+  obstack_ptr_grow (&argv_obstack, debug_obj);
+
+  /* Copy the early generated debug info from the objects to temporary
+     files and append those to the partial link commandline.  */
+  n_debugobj = 0;
+  if (! skip_debug)
+    for (i = 0; i < ltoobj_argc; ++i)
+      {
+       const char *tem;
+       if ((tem = debug_objcopy (ltoobj_argv[i])))
+         {
+           obstack_ptr_grow (&argv_obstack, tem);
+           n_debugobj++;
+         }
+      }
+
+  /* Link them all into a single object.  Ideally this would reduce
+     disk space usage mainly due to .debug_str merging but unfortunately
+     GNU ld doesn't perform this with -r.  */
+  if (n_debugobj)
+    {
+      obstack_ptr_grow (&argv_obstack, NULL);
+      const char **debug_link_argv = XOBFINISH (&argv_obstack, const char **);
+      fork_execute (debug_link_argv[0],
+                   CONST_CAST (char **, debug_link_argv), false);
+
+      /* And dispose the temporaries.  */
+      for (i = 0; debug_link_argv[i]; ++i)
+       ;
+      for (--i; i > 0; --i)
+       {
+         if (strcmp (debug_link_argv[i], debug_obj) == 0)
+           break;
+         maybe_unlink (debug_link_argv[i]);
+       }
+    }
+  else
+    {
+      unlink_if_ordinary (debug_obj);
+      free (debug_obj);
+      debug_obj = NULL;
+      skip_debug = true;
+    }
+
   if (lto_mode == LTO_MODE_LTO)
     {
       printf ("%s\n", flto_out);
+      if (!skip_debug)
+       {
+         printf ("%s\n", debug_obj);
+         free (debug_obj);
+         debug_obj = NULL;
+       }
       free (flto_out);
       flto_out = NULL;
     }
@@ -1456,6 +1621,12 @@ cont:
          for (i = 0; i < nr; ++i)
            maybe_unlink (input_names[i]);
        }
+      if (!skip_debug)
+       {
+         printf ("%s\n", debug_obj);
+         free (debug_obj);
+         debug_obj = NULL;
+       }
       for (i = 0; i < nr; ++i)
        {
          fputs (output_names[i], stdout);
index eb2a5daad999e719bf1047f0fbde5cde22e2a66e..6171530e24149a605a33c662c95c2c628f072652 100644 (file)
@@ -1,3 +1,11 @@
+2017-08-21  Richard Biener  <rguenther@suse.de>
+
+        * lto.c (unify_scc): Truncate DIE reference queue for dropped SCCs.
+        (lto_read_decls): Process TRANSLATION_UNIT_DECLs.  Remove
+        TYPE_DECL debug processing, register DIE references from
+        prevailing SCCs with the debug machinery.
+        (lto_section_with_id): Handle LTO debug sections.
+
 2017-08-16  Nathan Sidwell  <nathan@acm.org>
 
        * lto.c (mentions_vars_p_type): Use TYPE_LANG_SLOT_1.
index 2064423418df13d84fbc0d4c5e31c5726e5de541..182607b6fa4b52a4962e43e06acd98325baafa7e 100644 (file)
@@ -1633,6 +1633,9 @@ unify_scc (struct data_in *data_in, unsigned from,
              free_node (scc->entries[i]);
            }
 
+         /* Drop DIE references.  */
+         dref_queue.truncate (0);
+
          break;
        }
 
@@ -1708,8 +1711,7 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
                                                     from);
          if (len == 1
              && (TREE_CODE (first) == IDENTIFIER_NODE
-                 || TREE_CODE (first) == INTEGER_CST
-                 || TREE_CODE (first) == TRANSLATION_UNIT_DECL))
+                 || TREE_CODE (first) == INTEGER_CST))
            continue;
 
          /* Try to unify the SCC with already existing ones.  */
@@ -1748,16 +1750,6 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
              if (TREE_CODE (t) == INTEGER_CST
                  && !TREE_OVERFLOW (t))
                cache_integer_cst (t);
-             /* Register TYPE_DECLs with the debuginfo machinery.  */
-             if (!flag_wpa
-                 && TREE_CODE (t) == TYPE_DECL)
-               {
-                 /* Dwarf2out needs location information.
-                    TODO: Moving this out of the streamer loop may noticealy
-                    improve ltrans linemap memory use.  */
-                 data_in->location_cache.apply_location_cache ();
-                 debug_hooks->type_decl (t, !DECL_FILE_SCOPE_P (t));
-               }
              if (!flag_ltrans)
                {
                  /* Register variables and functions with the
@@ -1773,6 +1765,14 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
                    vec_safe_push (tree_with_vars, t);
                }
            }
+
+         /* Register DECLs with the debuginfo machinery.  */
+         while (!dref_queue.is_empty ())
+           {
+             dref_entry e = dref_queue.pop ();
+             debug_hooks->register_external_die (e.decl, e.sym, e.off);
+           }
+
          if (seen_type)
            num_type_scc_trees += len;
        }
@@ -1952,7 +1952,12 @@ lto_section_with_id (const char *name, unsigned HOST_WIDE_INT *id)
   if (strncmp (name, section_name_prefix, strlen (section_name_prefix)))
     return 0;
   s = strrchr (name, '.');
-  return s && sscanf (s, "." HOST_WIDE_INT_PRINT_HEX_PURE, id) == 1;
+  if (!s)
+    return 0;
+  /* If the section is not suffixed with an ID return.  */
+  if ((size_t)(s - name) == strlen (section_name_prefix))
+    return 0;
+  return sscanf (s, "." HOST_WIDE_INT_PRINT_HEX_PURE, id) == 1;
 }
 
 /* Create file_data of each sub file id */
index a67f9d64cb16911a31372d4af44ba73a7f134ee9..8fcb97712172def20d28435e0df0501f7b738c71 100644 (file)
@@ -302,6 +302,8 @@ const struct gcc_debug_hooks sdb_debug_hooks =
   sdbout_late_global_decl,              /* late_global_decl */
   sdbout_symbol,                        /* type_decl */
   debug_nothing_tree_tree_tree_bool_bool,/* imported_module_or_decl */
+  debug_false_tree_charstarstar_uhwistar,/* die_ref_for_decl */
+  debug_nothing_tree_charstar_uhwi,      /* register_external_die */
   debug_nothing_tree,                   /* deferred_inline_function */
   debug_nothing_tree,                   /* outlining_inline_function */
   sdbout_label,                                 /* label */
index 35d0be15c0e106a502708b949ea0035d1fe1bca5..731c812826a626ea9f8bff049f62f0298ab25424 100644 (file)
@@ -1,3 +1,22 @@
+2017-08-21  Richard Biener  <rguenther@suse.de>
+
+       * c-c++-common/asan/global-overflow-1.c: Adjust diagnostic location
+       regex to handle the LTO case.
+       * c-c++-common/asan/heap-overflow-1.c: Likewise.
+       * c-c++-common/asan/misalign-1.c: Likewise.
+       * c-c++-common/asan/misalign-2.c: Likewise.
+       * c-c++-common/asan/null-deref-1.c: Likewise.
+       * c-c++-common/asan/stack-overflow-1.c: Likewise.
+       * c-c++-common/asan/strncpy-overflow-1.c: Likewise.
+       * c-c++-common/asan/use-after-free-1.c: Likewise.
+       * c-c++-common/asan/alloca_big_alignment.c: Likewise.
+       * c-c++-common/asan/alloca_detect_custom_size.c: Likewise.
+       * c-c++-common/asan/alloca_overflow_partial.c: Likewise.
+       * c-c++-common/asan/alloca_overflow_right.c: Likewise.
+       * c-c++-common/asan/alloca_underflow_left.c: Likewise.
+       * g++.dg/asan/large-func-test-1.C: Likewise.
+       * gfortran.dg/save_6.f90: Add -flto -g variant of save_5.f90.
+
 2017-08-21  Richard Biener  <rguenther@suse.de>
 
        PR middle-end/81884
index 54f03b8e301be83b2614f39fc2caf5cb2bc0f59a..9cad57e8531a46fd72e92b5ca757726881b5f6ab 100644 (file)
@@ -17,6 +17,6 @@ int main() {
 }
 
 /* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_big_alignment.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_big_alignment.c:11|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r\]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
 /* { dg-output "\[^\n\r]*in foo.*alloca_big_alignment.c.*(\n|\r\n|\r)" */
index 609dafe7bd84e02c8f9f4807488ea53111c4e91f..830bad93cf038b59b47b67d3196ad38ab9906ec5 100644 (file)
@@ -22,6 +22,6 @@ int main(int argc, char **argv) {
 }
 
 /* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_detect_custom_size.c:16|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_detect_custom_size.c:16|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
 /* { dg-output "\[^\n\r]*in foo.*alloca_detect_custom_size.c.*(\n|\r\n|\r)" */
index 9f4d0780bff3b24ef1a1c0000000c749835f8a17..52282411bf5e2fd8bbd711ab81ab1bbb2354b8e3 100644 (file)
@@ -17,6 +17,6 @@ int main(int argc, char **argv) {
 }
 
 /* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_partial.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_partial.c:11|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
 /* { dg-output "\[^\n\r]*in foo.*alloca_overflow_partial.c.*(\n|\r\n|\r)" */
index 085fdae350b6787d4046315ccb712dc0b19eabee..4c4355bc59bd9299332ea56c68359a6bb621a18a 100644 (file)
@@ -17,6 +17,6 @@ int main(int argc, char **argv) {
 }
 
 /* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_right.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_right.c:11|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
 /* { dg-output "\[^\n\r]*in foo.*alloca_overflow_right.c.*(\n|\r\n|\r)" */
index fe2abe11461869b1e047cf625eaaa62d63d836a4..030098012145d4a6e8a4892aed2b8a99b431ecdc 100644 (file)
@@ -17,6 +17,6 @@ int main(int argc, char **argv) {
 }
 
 /* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_underflow_left.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_underflow_left.c:11|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
 /* { dg-output "\[^\n\r]*in foo.*alloca_underflow_left.c.*(\n|\r\n|\r)" */
index 8dd75df10bf2cca19e5d1b87b2a75d47605334ba..1092a3166816b1d6731bb1cf14828be1880f2b3f 100644 (file)
@@ -23,6 +23,6 @@ int main() {
 }
 
 /* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*global-overflow-1.c:20|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r).*" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*global-overflow-1.c:20|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r).*" } */
 /* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of global variable" } */
 /* { dg-output ".*YYY\[^\n\r]* of size 10\[^\n\r]*(\n|\r\n|\r)" } */
index 0377a6cf468c83a9c44d31a68632df76a0d08910..7ef048e636f7d2578dd3f5c6019a4fbdab9afa33 100644 (file)
@@ -24,8 +24,8 @@ int main(int argc, char **argv) {
 }
 
 /* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*heap-overflow-1.c:21|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*heap-overflow-1.c:21|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*0x\[0-9a-f\]+ is located 0 bytes to the right of 10-byte region\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*heap-overflow-1.c:19|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*heap-overflow-1.c:19|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
index c38acd564aae93f220be1cd1c1cf97b294a1e7fc..5cd605ac045407cdaf69814aa04c78ff7158a91d 100644 (file)
@@ -39,5 +39,5 @@ main ()
 /* { dg-output "ERROR: AddressSanitizer:\[^\n\r]*on address\[^\n\r]*" } */
 /* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*misalign-1.c:1\[01]|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*misalign-1.c:3\[45]|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*misalign-1.c:1\[01]|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*misalign-1.c:3\[45]|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
index 099a3b8e2c8bbc26b4209e6100ab7268915155dc..a6ed49bac0537b6a10004582dd5fe7f3f0a42cd0 100644 (file)
@@ -39,5 +39,5 @@ main ()
 /* { dg-output "ERROR: AddressSanitizer:\[^\n\r]*on address\[^\n\r]*" } */
 /* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*baz(\[^\n\r]*misalign-2.c:2\[23]|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*misalign-2.c:3\[45]|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*baz(\[^\n\r]*misalign-2.c:2\[23]|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*misalign-2.c:3\[45]|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
index f4f8f37a795a53d2ed24cbed9c5c21db2f702020..bae016d6419c38fca9d056e44d39973d06c6c813 100644 (file)
@@ -18,5 +18,5 @@ int main()
 
 /* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address\[^\n\r]*" } */
 /* { dg-output "0x\[0-9a-f\]+ \[^\n\r]*pc 0x\[0-9a-f\]+.*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in \[^\n\r]*NullDeref\[^\n\r]* (\[^\n\r]*null-deref-1.c:10|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*null-deref-1.c:15|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in \[^\n\r]*NullDeref\[^\n\r]* (\[^\n\r]*null-deref-1.c:10|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*null-deref-1.c:15|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
index 34d6aab48e61ebdc48ac4b4381412caf674af419..7eab79c65140b3710b205d51e47d1236a3acf2a5 100644 (file)
@@ -18,6 +18,6 @@ int main() {
 }
 
 /* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*stack-overflow-1.c:16|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*stack-overflow-1.c:16|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
 /* { dg-output "\[^\n\r]*in main.*stack-overflow-1.c.*(\n|\r\n|\r)" */
index 45759ae8e9562b725c33d82000d688fd8dfc41d7..a9c9b1828880340e26d2cdeba291cdf9f581fec1 100644 (file)
@@ -14,8 +14,8 @@ int main(int argc, char **argv) {
 
 /* { dg-output "WRITE of size \[0-9\]* at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*strncpy-overflow-1.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*strncpy-overflow-1.c:11|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*strncpy-overflow-1.c:10|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*strncpy-overflow-1.c:10|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
index 75d8f9faa2d8b2a290a5ae7d9869218873746ac2..4894db2450ffbbfbc68b142ab5b909bfe402b2d4 100644 (file)
@@ -12,11 +12,11 @@ int main() {
 /* { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address\[^\n\r]*" } */
 /* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:9|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:9|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*0x\[0-9a-f\]+ is located 5 bytes inside of 10-byte region .0x\[0-9a-f\]+,0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*freed by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:8|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:8|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*previously allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:7|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*use-after-free-1.c:7|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
index 0c1b6ce0c616d7505fa21fb05913fdf32ce942d4..b42c09e3b0d949544285183b4e536d1f9a0bfdeb 100644 (file)
@@ -38,7 +38,7 @@ int main() {
 // { dg-output "ERROR: AddressSanitizer:? heap-buffer-overflow on address\[^\n\r]*" }
 // { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" }
 // { dg-output "\[^\n\r]*READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" }
-// { dg-output "    #0 0x\[0-9a-f\]+ +(in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" }
+// { dg-output "    #0 0x\[0-9a-f\]+ +(in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[^\n\r]*:0|\[^\n\r]*\\+0x\[0-9a-z\]*)|\[(\]).*(\n|\r\n|\r)" }
 // { dg-output "\[^\n\r]*0x\[0-9a-f\]+ is located 44 bytes to the right of 400-byte region.*(\n|\r\n|\r)" }
 // { dg-output "\[^\n\r]*allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" }
 // { dg-output "    #0( 0x\[0-9a-f\]+ +(in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
diff --git a/gcc/testsuite/gfortran.dg/save_6.f90 b/gcc/testsuite/gfortran.dg/save_6.f90
new file mode 100644 (file)
index 0000000..0dcec29
--- /dev/null
@@ -0,0 +1,54 @@
+! { dg-do run }
+! { dg-require-effective-target lto }
+! { dg-options "-fno-automatic -flto -g" }
+!
+! PR fortran/55733
+!
+! Check that -fno-automatic makes the local variable SAVEd
+! Check that -flto -g works
+!
+
+! Scalar allocatable
+subroutine foo(i)
+  integer :: i
+  integer, allocatable :: j
+  if (i == 1) j = 42
+  if (.not. allocated (j)) call abort ()
+  if (j /= 42) call abort ()
+end
+
+! Deferred-length string scalar
+subroutine bar()
+  logical, save :: first = .true.
+  character(len=:), allocatable :: str
+  if (first) then
+    first = .false.
+    if (allocated (str)) call abort ()
+    str = "ABCDEF"
+  end if
+  if (.not. allocated (str)) call abort ()
+  if (len (str) /= 6) call abort ()
+  if (str(1:6) /= "ABCDEF") call abort ()
+end subroutine bar
+
+! Deferred-length string array
+subroutine bar_array()
+  logical, save :: first = .true.
+  character(len=:), allocatable :: str
+  if (first) then
+    first = .false.
+    if (allocated (str)) call abort ()
+    str = "ABCDEF"
+  end if
+  if (.not. allocated (str)) call abort ()
+  if (len (str) /= 6) call abort ()
+  if (str(1:6) /= "ABCDEF") call abort ()
+end subroutine bar_array
+
+call foo(1)
+call foo(2)
+call bar()
+call bar_array()
+call bar()
+call bar_array()
+end
index 4a49d924e7b7c6e5953a8a459a20f2619dc6d71b..8d47547967e8ce4301a4b3cae77b30ef815c9982 100644 (file)
@@ -691,10 +691,7 @@ lto_input_ts_decl_common_tree_pointers (struct lto_input_block *ib,
   DECL_SIZE (expr) = stream_read_tree (ib, data_in);
   DECL_SIZE_UNIT (expr) = stream_read_tree (ib, data_in);
   DECL_ATTRIBUTES (expr) = stream_read_tree (ib, data_in);
-
-  /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
-     for early inlining so drop it on the floor instead of ICEing in
-     dwarf2out.c.  */
+  DECL_ABSTRACT_ORIGIN (expr) = stream_read_tree (ib, data_in);
 
   if ((VAR_P (expr) || TREE_CODE (expr) == PARM_DECL)
       && DECL_HAS_VALUE_EXPR_P (expr))
index 32b23461dfdfe607c45d52625f6195191e647472..7f52d455f5e4ea7d24ed761feb5ed8a829796119 100644 (file)
@@ -566,7 +566,11 @@ write_ts_decl_minimal_tree_pointers (struct output_block *ob, tree expr,
     stream_write_tree (ob, NULL_TREE, ref_p);
   else
     stream_write_tree (ob, DECL_NAME (expr), ref_p);
-  stream_write_tree (ob, DECL_CONTEXT (expr), ref_p);
+  if (TREE_CODE (expr) != TRANSLATION_UNIT_DECL
+      && ! DECL_CONTEXT (expr))
+    stream_write_tree (ob, (*all_translation_units)[0], ref_p);
+  else
+    stream_write_tree (ob, DECL_CONTEXT (expr), ref_p);
 }
 
 
@@ -585,10 +589,7 @@ write_ts_decl_common_tree_pointers (struct output_block *ob, tree expr,
      special handling in LTO, it must be handled by streamer hooks.  */
 
   stream_write_tree (ob, DECL_ATTRIBUTES (expr), ref_p);
-
-  /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
-     for early inlining so drop it on the floor instead of ICEing in
-     dwarf2out.c.  */
+  stream_write_tree (ob, DECL_ABSTRACT_ORIGIN (expr), ref_p);
 
   if ((VAR_P (expr) || TREE_CODE (expr) == PARM_DECL)
       && DECL_HAS_VALUE_EXPR_P (expr))
index d118b3ae977f6d8a5523f8fd5eb84fa67abe6ac1..07523a69956b093be67548e7be981b436b564809 100644 (file)
@@ -5662,6 +5662,10 @@ free_lang_data (void)
       || (!flag_generate_lto && !flag_generate_offload))
     return 0;
 
+  /* Provide a dummy TRANSLATION_UNIT_DECL if the FE failed to provide one.  */
+  if (vec_safe_is_empty (all_translation_units))
+    build_translation_unit_decl (NULL_TREE);
+
   /* Allocate and assign alias sets to the standard integer types
      while the slots are still in the way the frontends generated them.  */
   for (i = 0; i < itk_none; ++i)
@@ -8598,8 +8602,16 @@ variably_modified_type_p (tree type, tree fn)
     case POINTER_TYPE:
     case REFERENCE_TYPE:
     case VECTOR_TYPE:
+      /* Ada can have pointer types refering to themselves indirectly.  */
+      if (TREE_VISITED (type))
+       return false;
+      TREE_VISITED (type) = true;
       if (variably_modified_type_p (TREE_TYPE (type), fn))
-       return true;
+       {
+         TREE_VISITED (type) = false;
+         return true;
+       }
+      TREE_VISITED (type) = false;
       break;
 
     case FUNCTION_TYPE:
index 42300e2d538c0ef68369cdb3e4c93cd661f2c064..580dd2840162ae7c599e4ea9a17d59bef9bda46c 100644 (file)
@@ -198,6 +198,8 @@ const struct gcc_debug_hooks vmsdbg_debug_hooks
    vmsdbgout_late_global_decl,
    vmsdbgout_type_decl,                  /* type_decl */
    debug_nothing_tree_tree_tree_bool_bool, /* imported_module_or_decl */
+   debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+   debug_nothing_tree_charstar_uhwi, /* register_external_die */
    debug_nothing_tree,           /* deferred_inline_function */
    vmsdbgout_abstract_function,
    debug_nothing_rtx_code_label,  /* label */
index bbcc87d418b7be4e2fb5b6e0fdccd242739e15b5..2171290e4b80ab6b1bf3a1d1df120f6bc13c1f41 100644 (file)
@@ -1,3 +1,8 @@
+2017-08-21  Richard Biener  <rguenther@suse.de>
+
+       * simple-object.h (simple_object_copy_lto_debug_sections): New
+       function.
+
 2017-07-02  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * dwarf2.def (DW_IDX_compile_unit, DW_IDX_type_unit, DW_IDX_die_offset)
index 8a8439bdb1a56af5379b5cfb0e5e5d3a082282ed..f1bf88ba998520d98ca32ccbd37133bb4774b6d1 100644 (file)
@@ -197,6 +197,14 @@ simple_object_write_to_file (simple_object_write *simple_object,
 extern void
 simple_object_release_write (simple_object_write *);
 
+/* Copy LTO debug sections from SRC_OBJECT to DEST.
+   If an error occurs, return the errno value in ERR and an error string.  */
+
+extern const char *
+simple_object_copy_lto_debug_sections (simple_object_read *src_object,
+                                      const char *dest,
+                                      int *err);
+
 #ifdef __cplusplus
 }
 #endif
index 027aa56c88df1a7eff54db04ab53bf1c97316b86..48ee098f3d70670984a88486fa41f0ded4f882a2 100644 (file)
@@ -1,3 +1,36 @@
+2017-08-21  Richard Biener  <rguenther@suse.de>
+
+       * simple-object-common.h (struct simple_object_functions): Add
+       copy_lto_debug_sections hook.
+       * simple-object.c: Include fcntl.h.
+       (handle_lto_debug_sections): New helper function.
+       (simple_object_copy_lto_debug_sections): New function copying
+       early LTO debug sections to regular debug sections in a new file.
+       (simple_object_start_write): Handle NULL segment_name.
+       * simple-object-coff.c (simple_object_coff_functions): Adjust
+       for not implemented copy_lto_debug_sections hook.
+       * simple-object-mach-o.c (simple_object_mach_o_functions): Likewise.
+       * simple-object-xcoff.c (simple_object_xcoff_functions): Likewise.
+       * simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL,
+       SHT_GROUP): Add various sectopn header types.
+       (SHF_EXCLUDE): Add flag.
+       (Elf32_External_Sym, Elf64_External_Sym): Add symbol struct.
+       (ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors.
+       (STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types.
+       (STV_DEFAULT): Add symbol visibility.
+       (SHN_COMMON): Add special section index name.
+       (struct simple_object_elf_write): New.
+       (simple_object_elf_start_write): Adjust for new private data.
+       (simple_object_elf_write_shdr): Pass in values for all fields
+       we write.
+       (simple_object_elf_write_to_file): Adjust.  Copy from recorded
+       section headers if requested.
+       (simple_object_elf_release_write): Release private data.
+       (simple_object_elf_copy_lto_debug_sections): Copy and rename sections
+       as denoted by PFN and all their dependences, symbols and relocations
+       to the empty destination file.
+       (simple_object_elf_functions): Adjust for copy_lto_debug_sections hook.
+
 2017-07-02  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * dwarfnames.c (DW_FIRST_IDX, DW_END_IDX, DW_IDX, DW_IDX_DUP): New.
index 0283b15c8033fd5f75739d642b7e1ded2447d86e..54d430dad9b65c73e0d13a9cc2f3cc098498d81d 100644 (file)
@@ -800,5 +800,6 @@ const struct simple_object_functions simple_object_coff_functions =
   simple_object_coff_release_attributes,
   simple_object_coff_start_write,
   simple_object_coff_write_to_file,
-  simple_object_coff_release_write
+  simple_object_coff_release_write,
+  NULL
 };
index cda4038c9d79a7d59fc3b21fbc84e34da5944966..733bdd0e7b6341dcdc666fd9b7b9b37ab6bfe39e 100644 (file)
@@ -141,6 +141,12 @@ struct simple_object_functions
 
   /* Release the private data for an simple_object_write.  */
   void (*release_write) (void *);
+
+  /* Copy LTO debug sections.  */
+  const char *(*copy_lto_debug_sections) (simple_object_read *sobj,
+                                         simple_object_write *dobj,
+                                         int (*pfn) (const char **),
+                                         int *err);
 };
 
 /* The known object file formats.  */
index a733e4b1a2af788d85ff02473e838d2b4844a73b..56336264ce92181dd217680c6e865e44c84291fc 100644 (file)
@@ -122,9 +122,12 @@ typedef struct {
 
 /* Special section index values.  */
 
+#define SHN_UNDEF      0               /* Undefined section */
 #define SHN_LORESERVE  0xFF00          /* Begin range of reserved indices */
+#define SHN_COMMON     0xFFF2  /* Associated symbol is in common */
 #define SHN_XINDEX     0xFFFF          /* Section index is held elsewhere */
 
+
 /* 32-bit ELF program header.  */
 
 typedef struct {
@@ -183,8 +186,57 @@ typedef struct {
 
 /* Values for sh_type field.  */
 
+#define SHT_NULL       0               /* Section header table entry unused */
 #define SHT_PROGBITS   1               /* Program data */
+#define SHT_SYMTAB     2               /* Link editing symbol table */
 #define SHT_STRTAB     3               /* A string table */
+#define SHT_RELA       4               /* Relocation entries with addends */
+#define SHT_REL                9               /* Relocation entries, no addends */
+#define SHT_GROUP      17              /* Section contains a section group */
+
+/* Values for sh_flags field.  */
+
+#define SHF_EXCLUDE    0x80000000      /* Link editor is to exclude this
+                                          section from executable and
+                                          shared library that it builds
+                                          when those objects are not to be
+                                          further relocated.  */
+/* Symbol table entry.  */
+
+typedef struct
+{
+  unsigned char st_name[4];                /* Symbol name (string tbl index) */
+  unsigned char st_value[4];               /* Symbol value */
+  unsigned char st_size[4];                /* Symbol size */
+  unsigned char st_info;                /* Symbol type and binding */
+  unsigned char st_other;               /* Symbol visibility */
+  unsigned char st_shndx[2];               /* Section index */
+} Elf32_External_Sym;
+
+typedef struct
+{
+  unsigned char st_name[4];                /* Symbol name (string tbl index) */
+  unsigned char st_info;                /* Symbol type and binding */
+  unsigned char st_other;               /* Symbol visibility */
+  unsigned char st_shndx[2];               /* Section index */
+  unsigned char st_value[8];               /* Symbol value */
+  unsigned char st_size[8];                /* Symbol size */
+} Elf64_External_Sym;
+
+#define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
+#define ELF_ST_TYPE(val)              ((val) & 0xf)
+#define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
+
+#define STT_NOTYPE     0       /* Symbol type is unspecified */
+#define STT_OBJECT     1       /* Symbol is a data object */
+#define STT_FUNC       2       /* Symbol is a code object */
+#define STT_TLS                6       /* Thread local data object */
+#define STT_GNU_IFUNC  10      /* Symbol is an indirect code object */
+
+#define STB_LOCAL      0       /* Local symbol */
+#define STB_GLOBAL     1       /* Global symbol */
+
+#define STV_DEFAULT    0       /* Visibility is specified by binding type */
 
 /* Functions to fetch and store different ELF types, depending on the
    endianness and size.  */
@@ -348,6 +400,14 @@ struct simple_object_elf_attributes
   unsigned int flags;
 };
 
+/* Private data for an simple_object_write.  */
+
+struct simple_object_elf_write
+{
+  struct simple_object_elf_attributes attrs;
+  unsigned char *shdrs;
+};
+
 /* See if we have an ELF file.  */
 
 static void *
@@ -675,12 +735,13 @@ simple_object_elf_start_write (void *attributes_data,
 {
   struct simple_object_elf_attributes *attrs =
     (struct simple_object_elf_attributes *) attributes_data;
-  struct simple_object_elf_attributes *ret;
+  struct simple_object_elf_write *ret;
 
   /* We're just going to record the attributes, but we need to make a
      copy because the user may delete them.  */
-  ret = XNEW (struct simple_object_elf_attributes);
-  *ret = *attrs;
+  ret = XNEW (struct simple_object_elf_write);
+  ret->attrs = *attrs;
+  ret->shdrs = NULL;
   return ret;
 }
 
@@ -766,8 +827,11 @@ static int
 simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
                              off_t offset, unsigned int sh_name,
                              unsigned int sh_type, unsigned int sh_flags,
+                             off_t sh_addr,
                              unsigned int sh_offset, unsigned int sh_size,
-                             unsigned int sh_link, unsigned int sh_addralign,
+                             unsigned int sh_link, unsigned int sh_info,
+                             unsigned int sh_addralign,
+                             unsigned int sh_entsize,
                              const char **errmsg, int *err)
 {
   struct simple_object_elf_attributes *attrs =
@@ -788,12 +852,13 @@ simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
-  /* sh_info left as zero.  */
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
-  /* sh_entsize left as zero.  */
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Word, sh_entsize);
 
   return simple_object_internal_write (descriptor, offset, buf, shdr_size,
                                       errmsg, err);
@@ -811,8 +876,9 @@ static const char *
 simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
                                 int *err)
 {
-  struct simple_object_elf_attributes *attrs =
-    (struct simple_object_elf_attributes *) sobj->data;
+  struct simple_object_elf_write *eow =
+    (struct simple_object_elf_write *) sobj->data;
+  struct simple_object_elf_attributes *attrs = &eow->attrs;
   unsigned char cl;
   size_t ehdr_size;
   size_t shdr_size;
@@ -825,6 +891,7 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
   unsigned int first_sh_link;
   size_t sh_name;
   unsigned char zero;
+  unsigned secnum;
 
   if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
     return errmsg;
@@ -862,21 +929,54 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
   else
     first_sh_link = shnum - 1;
   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
-                                    0, 0, 0, 0, first_sh_size, first_sh_link,
-                                    0, &errmsg, err))
+                                    0, 0, 0, 0, 0, first_sh_size, first_sh_link,
+                                    0, 0, 0, &errmsg, err))
     return errmsg;
 
   shdr_offset += shdr_size;
 
   sh_name = 1;
+  secnum = 0;
   for (section = sobj->sections; section != NULL; section = section->next)
     {
       size_t mask;
       size_t new_sh_offset;
       size_t sh_size;
       struct simple_object_write_section_buffer *buffer;
+      unsigned int sh_type = SHT_PROGBITS;
+      unsigned int sh_flags = 0;
+      off_t sh_addr = 0;
+      unsigned int sh_link = 0;
+      unsigned int sh_info = 0;
+      unsigned int sh_addralign = 1U << section->align;
+      unsigned int sh_entsize = 0;
+      if (eow->shdrs)
+       {
+         sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+                                    eow->shdrs + secnum * shdr_size,
+                                    sh_type, Elf_Word);
+         sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+                                     eow->shdrs + secnum * shdr_size,
+                                     sh_flags, Elf_Addr);
+         sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+                                    eow->shdrs + secnum * shdr_size,
+                                    sh_addr, Elf_Addr);
+         sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+                                    eow->shdrs + secnum * shdr_size,
+                                    sh_link, Elf_Word);
+         sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+                                    eow->shdrs + secnum * shdr_size,
+                                    sh_info, Elf_Word);
+         sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+                                         eow->shdrs + secnum * shdr_size,
+                                         sh_addralign, Elf_Addr);
+         sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+                                       eow->shdrs + secnum * shdr_size,
+                                       sh_entsize, Elf_Word);
+         secnum++;
+       }
 
-      mask = (1U << section->align) - 1;
+      mask = sh_addralign - 1;
       new_sh_offset = sh_offset + mask;
       new_sh_offset &= ~ mask;
       while (new_sh_offset > sh_offset)
@@ -906,8 +1006,10 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
        }
 
       if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
-                                        sh_name, SHT_PROGBITS, 0, sh_offset,
-                                        sh_size, 0, 1U << section->align,
+                                        sh_name, sh_type, sh_flags,
+                                        sh_addr, sh_offset,
+                                        sh_size, sh_link, sh_info,
+                                        sh_addralign, sh_entsize,
                                         &errmsg, err))
        return errmsg;
 
@@ -917,9 +1019,9 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
     }
 
   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
-                                    sh_name, SHT_STRTAB, 0, sh_offset,
-                                    sh_name + strlen (".shstrtab") + 1, 0,
-                                    1, &errmsg, err))
+                                    sh_name, SHT_STRTAB, 0, 0, sh_offset,
+                                    sh_name + strlen (".shstrtab") + 1, 0, 0,
+                                    1, 0, &errmsg, err))
     return errmsg;
 
   /* .shstrtab has a leading zero byte.  */
@@ -954,9 +1056,354 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
 static void
 simple_object_elf_release_write (void *data)
 {
+  struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
+  if (eow->shdrs)
+    XDELETE (eow->shdrs);
   XDELETE (data);
 }
 
+/* Copy all sections in an ELF file.  */
+
+static const char *
+simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
+                                          simple_object_write *dobj,
+                                          int (*pfn) (const char **),
+                                          int *err)
+{
+  struct simple_object_elf_read *eor =
+    (struct simple_object_elf_read *) sobj->data;
+  const struct elf_type_functions *type_functions = eor->type_functions;
+  struct simple_object_elf_write *eow =
+    (struct simple_object_elf_write *) dobj->data;
+  unsigned char ei_class = eor->ei_class;
+  size_t shdr_size;
+  unsigned int shnum;
+  unsigned char *shdrs;
+  const char *errmsg;
+  unsigned char *shstrhdr;
+  size_t name_size;
+  off_t shstroff;
+  unsigned char *names;
+  unsigned int i;
+  int *pfnret;
+  const char **pfnname;
+
+  shdr_size = (ei_class == ELFCLASS32
+              ? sizeof (Elf32_External_Shdr)
+              : sizeof (Elf64_External_Shdr));
+
+  /* Read the section headers.  We skip section 0, which is not a
+     useful section.  */
+
+  shnum = eor->shnum;
+  shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+
+  if (!simple_object_internal_read (sobj->descriptor,
+                                   sobj->offset + eor->shoff + shdr_size,
+                                   shdrs,
+                                   shdr_size * (shnum - 1),
+                                   &errmsg, err))
+    {
+      XDELETEVEC (shdrs);
+      return errmsg;
+    }
+
+  /* Read the section names.  */
+
+  shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
+  name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                              shstrhdr, sh_size, Elf_Addr);
+  shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                             shstrhdr, sh_offset, Elf_Addr);
+  names = XNEWVEC (unsigned char, name_size);
+  if (!simple_object_internal_read (sobj->descriptor,
+                                   sobj->offset + shstroff,
+                                   names, name_size, &errmsg, err))
+    {
+      XDELETEVEC (names);
+      XDELETEVEC (shdrs);
+      return errmsg;
+    }
+
+  eow->shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+  pfnret = XNEWVEC (int, shnum);
+  pfnname = XNEWVEC (const char *, shnum);
+
+  /* First perform the callbacks to know which sections to preserve and
+     what name to use for those.  */
+  for (i = 1; i < shnum; ++i)
+    {
+      unsigned char *shdr;
+      unsigned int sh_name;
+      const char *name;
+      int ret;
+
+      shdr = shdrs + (i - 1) * shdr_size;
+      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                shdr, sh_name, Elf_Word);
+      if (sh_name >= name_size)
+       {
+         *err = 0;
+         XDELETEVEC (names);
+         XDELETEVEC (shdrs);
+         return "ELF section name out of range";
+       }
+
+      name = (const char *) names + sh_name;
+
+      ret = (*pfn) (&name);
+      pfnret[i - 1] = ret == 1 ? 0 : -1;
+      pfnname[i - 1] = name;
+    }
+
+  /* Mark sections as preserved that are required by to be preserved
+     sections.  */
+  for (i = 1; i < shnum; ++i)
+    {
+      unsigned char *shdr;
+      unsigned int sh_type, sh_info, sh_link;
+      off_t offset;
+      off_t length;
+
+      shdr = shdrs + (i - 1) * shdr_size;
+      sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                shdr, sh_type, Elf_Word);
+      sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                shdr, sh_info, Elf_Word);
+      sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                shdr, sh_link, Elf_Word);
+      if (sh_type == SHT_GROUP)
+       {
+         /* Mark groups containing copied sections.  */
+         unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                             shdr, sh_entsize, Elf_Addr);
+         unsigned char *ent, *buf;
+         int keep = 0;
+         offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                   shdr, sh_offset, Elf_Addr);
+         length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                   shdr, sh_size, Elf_Addr);
+         buf = XNEWVEC (unsigned char, length);
+         if (!simple_object_internal_read (sobj->descriptor,
+                                           sobj->offset + offset, buf,
+                                           (size_t) length, &errmsg, err))
+           {
+             XDELETEVEC (buf);
+             XDELETEVEC (names);
+             XDELETEVEC (shdrs);
+             return errmsg;
+           }
+         for (ent = buf + entsize; ent < buf + length; ent += entsize)
+           {
+             unsigned sec = type_functions->fetch_Elf_Word (ent);
+             if (pfnret[sec - 1] == 0)
+               keep = 1;
+           }
+         if (keep)
+           {
+             pfnret[sh_link - 1] = 0;
+             pfnret[i - 1] = 0;
+           }
+       }
+      if (sh_type == SHT_RELA
+         || sh_type == SHT_REL)
+       {
+         /* Mark relocation sections and symtab of copied sections.  */
+         if (pfnret[sh_info - 1] == 0)
+           {
+             pfnret[sh_link - 1] = 0;
+             pfnret[i - 1] = 0;
+           }
+       }
+      if (sh_type == SHT_SYMTAB)
+       {
+         /* Mark strings sections of copied symtabs.  */
+         if (pfnret[i - 1] == 0)
+           pfnret[sh_link - 1] = 0;
+       }
+    }
+
+  /* Then perform the actual copying.  */
+  for (i = 1; i < shnum; ++i)
+    {
+      unsigned char *shdr;
+      unsigned int sh_name, sh_type;
+      const char *name;
+      off_t offset;
+      off_t length;
+      int ret;
+      const char *errmsg;
+      simple_object_write_section *dest;
+      off_t flags;
+      unsigned char *buf;
+
+      shdr = shdrs + (i - 1) * shdr_size;
+      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                shdr, sh_name, Elf_Word);
+      if (sh_name >= name_size)
+       {
+         *err = 0;
+         XDELETEVEC (names);
+         XDELETEVEC (shdrs);
+         return "ELF section name out of range";
+       }
+
+      name = (const char *) names + sh_name;
+      offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                               shdr, sh_offset, Elf_Addr);
+      length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                               shdr, sh_size, Elf_Addr);
+      sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                shdr, sh_type, Elf_Word);
+
+      ret = pfnret[i - 1];
+      name = ret == 0 ? pfnname[i - 1] : "";
+
+      dest = simple_object_write_create_section (dobj, name, 0, &errmsg, err);
+      if (dest == NULL)
+       {
+         XDELETEVEC (names);
+         XDELETEVEC (shdrs);
+         return errmsg;
+       }
+
+      /* Record the SHDR of the source.  */
+      memcpy (eow->shdrs + (i - 1) * shdr_size, shdr, shdr_size);
+      shdr = eow->shdrs + (i - 1) * shdr_size;
+
+      /* Copy the data.
+        ???  This is quite wasteful and ideally would be delayed until
+        write_to_file ().  Thus it questions the interfacing
+        which eventually should contain destination creation plus
+        writing.  */
+      /* Keep empty sections for sections we should discard.  This avoids
+         the need to rewrite section indices in symtab and relocation
+        sections.  */
+      if (ret == 0)
+       {
+         buf = XNEWVEC (unsigned char, length);
+         if (!simple_object_internal_read (sobj->descriptor,
+                                           sobj->offset + offset, buf,
+                                           (size_t) length, &errmsg, err))
+           {
+             XDELETEVEC (buf);
+             XDELETEVEC (names);
+             XDELETEVEC (shdrs);
+             return errmsg;
+           }
+
+         /* If we are processing .symtab purge __gnu_lto_v1 and
+            __gnu_lto_slim symbols from it.  */
+         if (sh_type == SHT_SYMTAB)
+           {
+             unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                                 shdr, sh_entsize, Elf_Addr);
+             unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                                shdr, sh_link, Elf_Word);
+             unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size;
+             off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                             strshdr, sh_offset, Elf_Addr);
+             size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                                             strshdr, sh_size, Elf_Addr);
+             char *strings = XNEWVEC (char, strsz);
+             unsigned char *ent;
+             simple_object_internal_read (sobj->descriptor,
+                                          sobj->offset + stroff,
+                                          (unsigned char *)strings,
+                                          strsz, &errmsg, err);
+             for (ent = buf; ent < buf + length; ent += entsize)
+               {
+                 unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
+                                                      Sym, ent,
+                                                      st_shndx, Elf_Half);
+                 unsigned char *st_info;
+                 unsigned char *st_other;
+                 int discard = 0;
+                 if (ei_class == ELFCLASS32)
+                   {
+                     st_info = &((Elf32_External_Sym *)ent)->st_info;
+                     st_other = &((Elf32_External_Sym *)ent)->st_other;
+                   }
+                 else
+                   {
+                     st_info = &((Elf64_External_Sym *)ent)->st_info;
+                     st_other = &((Elf64_External_Sym *)ent)->st_other;
+                   }
+                 /* Eliminate all COMMONs - this includes __gnu_lto_v1
+                    and __gnu_lto_slim which otherwise cause endless
+                    LTO plugin invocation.  */
+                 if (st_shndx == SHN_COMMON)
+                   /* Setting st_name to "" seems to work to purge
+                      COMMON symbols (in addition to setting their
+                      size to zero).  */
+                   discard = 1;
+                 /* We also need to remove symbols refering to sections
+                    we'll eventually remove as with fat LTO objects
+                    we otherwise get duplicate symbols at final link
+                    (with GNU ld, gold is fine and ignores symbols in
+                    sections marked as EXCLUDE).  ld/20513  */
+                 else if (st_shndx != SHN_UNDEF
+                          && st_shndx < shnum
+                          && pfnret[st_shndx - 1] == -1)
+                   discard = 1;
+
+                 if (discard)
+                   {
+                     /* Make discarded symbols undefined and unnamed.  */
+                     ELF_SET_FIELD (type_functions, ei_class, Sym,
+                                    ent, st_name, Elf_Word, 0);
+                     ELF_SET_FIELD (type_functions, ei_class, Sym,
+                                    ent, st_value, Elf_Addr, 0);
+                     ELF_SET_FIELD (type_functions, ei_class, Sym,
+                                    ent, st_size, Elf_Word, 0);
+                     ELF_SET_FIELD (type_functions, ei_class, Sym,
+                                    ent, st_shndx, Elf_Half, SHN_UNDEF);
+                     *st_info = ELF_ST_INFO (ELF_ST_BIND (*st_info),
+                                             STT_NOTYPE);
+                     *st_other = STV_DEFAULT;
+                   }
+               }
+             XDELETEVEC (strings);
+           }
+
+         errmsg = simple_object_write_add_data (dobj, dest,
+                                                buf, length, 1, err);
+         XDELETEVEC (buf);
+         if (errmsg)
+           {
+             XDELETEVEC (names);
+             XDELETEVEC (shdrs);
+             return errmsg;
+           }
+       }
+      else
+       {
+         /* For deleted sections mark the section header table entry as
+            unused.  That allows the link editor to remove it in a partial
+            link.  */
+         ELF_SET_FIELD (type_functions, ei_class, Shdr,
+                        shdr, sh_type, Elf_Addr, SHT_NULL);
+       }
+
+      flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+                              shdr, sh_flags, Elf_Addr);
+      if (ret == 0)
+       flags &= ~SHF_EXCLUDE;
+      else if (ret == -1)
+       flags |= SHF_EXCLUDE;
+      ELF_SET_FIELD (type_functions, ei_class, Shdr,
+                    shdr, sh_flags, Elf_Addr, flags);
+    }
+
+  XDELETEVEC (names);
+  XDELETEVEC (shdrs);
+  XDELETEVEC (pfnret);
+  XDELETEVEC (pfnname);
+
+  return NULL;
+}
+
+
 /* The ELF functions.  */
 
 const struct simple_object_functions simple_object_elf_functions =
@@ -969,5 +1416,6 @@ const struct simple_object_functions simple_object_elf_functions =
   simple_object_elf_release_attributes,
   simple_object_elf_start_write,
   simple_object_elf_write_to_file,
-  simple_object_elf_release_write
+  simple_object_elf_release_write,
+  simple_object_elf_copy_lto_debug_sections
 };
index bbadf5d83307fa7b4024e9f572918bb989d386db..b90fca88b2368d27191be5618e312bda645033a9 100644 (file)
@@ -1374,5 +1374,6 @@ const struct simple_object_functions simple_object_mach_o_functions =
   simple_object_mach_o_release_attributes,
   simple_object_mach_o_start_write,
   simple_object_mach_o_write_to_file,
-  simple_object_mach_o_release_write
+  simple_object_mach_o_release_write,
+  NULL
 };
index 7be1bf33fe3d1d277366172f7f656c7845b4c88e..2adebe37107f68180a9ca649377513786ecd1694 100644 (file)
@@ -1006,5 +1006,6 @@ const struct simple_object_functions simple_object_xcoff_functions =
   simple_object_xcoff_release_attributes,
   simple_object_xcoff_start_write,
   simple_object_xcoff_write_to_file,
-  simple_object_xcoff_release_write
+  simple_object_xcoff_release_write,
+  NULL
 };
index 8ea9cf129fd6711319c31f899ec9e8f5e4560e80..553e90f50480bc8af2b3cb95d2338630bac117e2 100644 (file)
@@ -22,6 +22,7 @@ Boston, MA 02110-1301, USA.  */
 #include "simple-object.h"
 
 #include <errno.h>
+#include <fcntl.h>
 
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
@@ -249,6 +250,86 @@ simple_object_find_section (simple_object_read *sobj, const char *name,
   return 1;
 }
 
+/* Callback to identify and rename LTO debug sections by name.
+   Returns 1 if NAME is a LTO debug section, 0 if not.  */
+
+static int
+handle_lto_debug_sections (const char **name)
+{
+  /* ???  So we can't use .gnu.lto_ prefixed sections as the assembler
+     complains about bogus section flags.  Which means we need to arrange
+     for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
+     fat lto object tooling work for the fat part).  */
+  /* ???  For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
+     sections.  */
+  /* Copy LTO debug sections and rename them to their non-LTO name.  */
+  if (strncmp (*name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
+    {
+      *name = *name + sizeof (".gnu.debuglto_") - 1;
+      return 1;
+    }
+  else if (strncmp (*name, ".gnu.lto_.debug_", sizeof (".gnu.lto_.debug_") -1) == 0)
+    {
+      *name = *name + sizeof (".gnu.lto_") - 1;
+      return 1;
+    }
+  return 0;
+}
+
+/* Copy LTO debug sections.  */
+
+const char *
+simple_object_copy_lto_debug_sections (simple_object_read *sobj,
+                                      const char *dest, int *err)
+{
+  const char *errmsg;
+  simple_object_write *dest_sobj;
+  simple_object_attributes *attrs;
+  int outfd;
+
+  if (! sobj->functions->copy_lto_debug_sections)
+    {
+      *err = EINVAL;
+      return "simple_object_copy_lto_debug_sections not implemented";
+    }
+
+  attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
+  if (! attrs)
+    return errmsg;
+  dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
+  simple_object_release_attributes (attrs);
+  if (! dest_sobj)
+    return errmsg;
+
+  errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj,
+                                                    handle_lto_debug_sections,
+                                                    err);
+  if (errmsg)
+    {
+      simple_object_release_write (dest_sobj);
+      return errmsg;
+    }
+
+  outfd = creat (dest, 00777);
+  if (outfd == -1)
+    {
+      *err = errno;
+      simple_object_release_write (dest_sobj);
+      return "open failed";
+    }
+
+  errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
+  close (outfd);
+  if (errmsg)
+    {
+      simple_object_release_write (dest_sobj);
+      return errmsg;
+    }
+
+  simple_object_release_write (dest_sobj);
+  return NULL;
+}
+
 /* Fetch attributes.  */
 
 simple_object_attributes *
@@ -315,7 +396,7 @@ simple_object_start_write (simple_object_attributes *attrs,
     return NULL;
   ret = XNEW (simple_object_write);
   ret->functions = attrs->functions;
-  ret->segment_name = xstrdup (segment_name);
+  ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
   ret->sections = NULL;
   ret->last_section = NULL;
   ret->data = data;
index 5dbd173dc28e96a8f78836cb04ed320f58426e43..9f5bfa0db6eb8d2ef1963b4f6504c4af28af7126 100644 (file)
@@ -1,3 +1,8 @@
+2017-08-21  Richard Biener  <rguenther@suse.de>
+
+       * testsuite/libstdc++-prettyprinters/prettyprinters.exp: Run all
+       tests with -flto as well if supported.
+
 2017-08-20  Martin Sebor  <msebor@redhat.com>
 
        PR c/81854
index 2132e1f8a70eae21d561a9fe2b983fc80e4f9834..5232e983ab45777bc1d5a08fe3c531586a18e2ae 100644 (file)
@@ -15,6 +15,7 @@
 # <http://www.gnu.org/licenses/>.
 
 load_lib gdb-test.exp
+load_lib target-supports.exp
 
 dg-init
 v3-build_support
@@ -46,6 +47,14 @@ global PCH_CXXFLAGS
 gdb-dg-runtest [lsort [glob $srcdir/$subdir/*.cc]] \
   "" "$DEFAULT_CXXFLAGS $PCH_CXXFLAGS"
 
+if { [check_effective_target_lto] } {
+  append cxxflags " -flto"
+  # work around sourceware.org 20882
+  regsub {^(.*)-Wl,--gc-sections(.*)$} $cxxldflags {\1\2} cxxldflags
+  gdb-dg-runtest [lsort [glob $srcdir/$subdir/*.cc]] \
+    "" "$DEFAULT_CXXFLAGS -flto $PCH_CXXFLAGS"
+}
+
 if [info exists guality_gdb_name] {
     unsetenv GUALITY_GDB_NAME
 }