diff mbox

[2/2] Early LTO debug -- main part

Message ID alpine.LSU.2.11.1610211312360.2258@t29.fhfr.qr
State New
Headers show

Commit Message

Richard Biener Oct. 21, 2016, 11:26 a.m. UTC
This is the main part of the early LTO debug support.  The main parts
of the changes are to dwarf2out.c where most of the changes are related
to the fact that we eventually have to output debug info twice, once
for the early LTO part and once for the fat part of the object file.

Bootstrapped and tested on x86_64-unknown-linux-gnu with ASAN and TSAN
extra FAILs (see PR78063, a libbacktrace missing feature or libsanitizer
being too pessimistic).  There's an extra

XPASS: gcc.dg/guality/inline-params.c   -O2 -flto -fuse-linker-plugin 
-fno-fat-lto-objects  execution test

the previously reported extra VLA guality FAILs are gone.

I've compared testresults with -flto -g added for all languages and
only see expected differences (libstdc++ pretty printers now work,
most scan-assembler-times debug testcases fail because we have everything
twice now).

See https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01842.html for
the last posting of this patch which has a high-level overview of
Early LTO debug.  You may want to refer to the slides I presented
at the GNU Cauldron as well.

Thanks,
Richard.

2016-10-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.
        (compute_section_prefix_1): Split out worker to distinguish
        the comdat from the LTO case.
        (compute_section_prefix): Wrap old comdat case 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.
        (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.
        (gen_subprogram_die): Adjust the check for whether we face
        a concrete instance DIE for an inline we can reuse for the
        late LTO case.  Likewise 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.
        (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.
        (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.

Cleanups we can do (and need) when removing the "old" LTO path and add
the early LTO path.

        (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.

        * 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.
	(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.
        * lto-streamer.h (struct dref_entry): Declare.
        (dref_queue): Likewise.

        * 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.

        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.
diff mbox

Patch

Index: early-lto-debug/gcc/dwarf2out.c
===================================================================
--- early-lto-debug.orig/gcc/dwarf2out.c	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/dwarf2out.c	2016-10-21 12:24:42.095686608 +0200
@@ -161,6 +161,7 @@  static GTY(()) section *debug_aranges_se
 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;
@@ -2487,6 +2488,10 @@  static void dwarf2out_begin_function (tr
 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.  */
 
@@ -2521,6 +2526,8 @@  const struct gcc_debug_hooks dwarf2_debu
   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
@@ -2562,6 +2569,8 @@  const struct gcc_debug_hooks dwarf2_line
   debug_nothing_tree,		         /* late_global_decl */
   debug_nothing_tree_int,		 /* type_decl */
   debug_nothing_tree_tree_tree_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 */
@@ -2689,6 +2698,9 @@  typedef struct GTY((chain_circular ("%h.
   /* 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.  */
@@ -3493,12 +3505,24 @@  new_addr_loc_descr (rtx addr, enum dtpre
 #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
@@ -3511,18 +3535,33 @@  new_addr_loc_descr (rtx addr, enum dtpre
 #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
@@ -3545,12 +3584,21 @@  new_addr_loc_descr (rtx addr, enum dtpre
 #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
@@ -4152,6 +4200,24 @@  set_indirect_string (struct indirect_str
     }
 }
 
+/* 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.  */
 
@@ -5157,6 +5223,186 @@  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 C++ FE (at least) fails to
+       set DECL_CONTEXT properly.  Simply globalize stuff
+       in this case.  For example
+       __dso_handle created via iostream line 74 col 25.  */
+    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:
+      /* ???  LANG issue - DW_TAG_module for fortran.  Either look
+	 at the input language (if we have enough DECL_CONTEXT to follow)
+	 or use a bit in tree_decl_with_vis to record the distinction.  */
+      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
@@ -5642,7 +5888,11 @@  print_dw_val (dw_val_node *val, bool rec
 			       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);
@@ -6935,7 +7185,7 @@  static unsigned int comdat_symbol_number
    children, and set comdat_symbol_id accordingly.  */
 
 static void
-compute_section_prefix (dw_die_ref unit_die)
+compute_section_prefix_1 (dw_die_ref unit_die, bool comdat_p)
 {
   const char *die_name = get_AT_string (unit_die, DW_AT_name);
   const char *base = die_name ? lbasename (die_name) : "anonymous";
@@ -6954,7 +7204,11 @@  compute_section_prefix (dw_die_ref unit_
   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);
@@ -6964,7 +7218,15 @@  compute_section_prefix (dw_die_ref unit_
       p += 2;
     }
 
-  comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
+  unit_die->die_id.die_symbol = xstrdup (name);
+  unit_die->comdat_type_p = comdat_p;
+}
+
+static void
+compute_section_prefix (dw_die_ref unit_die)
+{
+  compute_section_prefix_1 (unit_die, true);
+  comdat_symbol_id = unit_die->die_id.die_symbol;
   comdat_symbol_number = 0;
 }
 
@@ -9224,7 +9486,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)",
@@ -9403,8 +9669,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
@@ -9590,7 +9868,7 @@  output_comp_unit (dw_die_ref die, int ou
   calc_die_sizes (die);
 
   oldsym = die->die_id.die_symbol;
-  if (oldsym)
+  if (oldsym && die->comdat_type_p)
     {
       tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
 
@@ -9606,6 +9884,33 @@  output_comp_unit (dw_die_ref die, int ou
       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.
+     ???  We could simply use the symbol as it would be output by output_die
+     and account for the extra offset produced by the CU header which has fixed
+     size.  OTOH it currently only supports linkonce globals which would
+     be less than ideal?.  */
+  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 ();
   output_die (die);
@@ -13331,6 +13636,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)
@@ -18791,7 +19099,20 @@  add_abstract_origin_attribute (dw_die_re
     }
 
   if (DECL_P (origin))
-    origin_die = lookup_decl_die (origin);
+    {
+      dw_die_ref c;
+      origin_die = lookup_decl_die (origin);
+      /* "Unwrap" the decls DIE which we put in the imported unit context.
+          ???  If we finish dwarf2out_function_decl refactoring we can
+	  do this in a better way from the start and only lazily emit
+	  the early DIE references.  */
+      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;
+    }
   else if (TYPE_P (origin))
     origin_die = lookup_type_die (origin);
   else if (TREE_CODE (origin) == BLOCK)
@@ -19346,7 +19667,12 @@  gen_array_type_die (tree type, dw_die_re
       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_5.f90).
+	 The proper way is to handle it like VLAs though it is told
+	 that DW_AT_string_length does not support this.  */
+      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));
@@ -19801,7 +20127,9 @@  gen_formal_parameter_die (tree node, tre
 	 thing.  */
       if (parm_die && parm_die->die_parent != context_die)
 	{
-	  if (!DECL_ABSTRACT_P (node))
+	  /* ???  The DIE parent is the "abstract" copy and the context_die
+	     is the specification "copy".  */
+	  if (!DECL_ABSTRACT_P (node) && !in_lto_p)
 	    {
 	      /* This can happen when creating an inlined instance, in
 		 which case we need to create a new DIE that will get
@@ -20075,7 +20403,6 @@  gen_type_die_for_member (tree type, tree
 /* 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
@@ -20148,151 +20475,45 @@  set_decl_origin_self (tree decl)
     }
 }
 
-/* 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))
     /* 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))
     {
-      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_declared_inlined);
+      else
+	add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_not_inlined);
+    }
+  else
+    {
+      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;
-
-  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;
+  if (DECL_DECLARED_INLINE_P (decl)
+      && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
+    add_AT_flag (old_die, DW_AT_artificial, 1);
 }
 
 /* Helper function of premark_used_types() which gets called through
@@ -20513,7 +20734,12 @@  gen_subprogram_die (tree decl, dw_die_re
       if (old_die && old_die->die_parent == NULL)
 	add_child_die (context_die, old_die);
 
-      if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin))
+      dw_die_ref c;
+      if (old_die
+	  && (c = get_AT_ref (old_die, DW_AT_abstract_origin))
+	  /* ???  In LTO all origin DIEs still refer to the early
+	     debug copy.  Detect that.  */
+	  && get_AT (c, DW_AT_inline))
 	{
 	  /* If we have a DW_AT_abstract_origin we have a working
 	     cached version.  */
@@ -20581,7 +20807,9 @@  gen_subprogram_die (tree decl, dw_die_re
 	   || (old_die->die_parent
 	       && old_die->die_parent->die_tag == DW_TAG_module)
 	   || context_die == NULL)
-	   && (DECL_ARTIFICIAL (decl)
+	  /* ???  This all (and above) should probably be simply
+	     a ! early_dwarf check somehow.  */
+	   && ((DECL_ARTIFICIAL (decl) || in_lto_p)
 	       || (get_AT_file (old_die, DW_AT_decl_file) == file_index
 		   && (get_AT_unsigned (old_die, DW_AT_decl_line)
 		       == (unsigned) s.line))))
@@ -21410,6 +21638,24 @@  gen_variable_die (tree decl, tree origin
 	  /* 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;
 	}
     }
@@ -21781,12 +22027,6 @@  gen_inlined_subroutine_die (tree stmt, d
   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
@@ -23319,7 +23559,20 @@  process_scope_var (tree stmt, tree decl,
 					     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 (in_lto_p
+	      && die && die->die_parent == NULL)
+	    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)
@@ -23731,6 +23984,9 @@  gen_decl_die (tree decl, tree origin, st
 
       /* 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.  */
+      /* ???  We have output an abstract instance early already and
+         could just re-use that.  This is how LTO treats all functions
+	 for example.  */
       else if (cgraph_function_possibly_inlined_p (decl)
 	       && ! DECL_ABSTRACT_P (decl)
 	       && ! class_or_namespace_scope_p (context_die)
@@ -23744,7 +24000,9 @@  gen_decl_die (tree decl, tree origin, st
 	}
 
       /* Otherwise we're emitting the primary DIE for this decl.  */
-      else if (debug_info_level > DINFO_LEVEL_TERSE)
+      else if (debug_info_level > DINFO_LEVEL_TERSE
+	       /* Do not generate stray type DIEs in late LTO dumping.  */
+	       && early_dwarf)
 	{
 	  /* Before we describe the FUNCTION_DECL itself, make sure that we
 	     have its containing type.  */
@@ -23811,20 +24069,37 @@  gen_decl_die (tree decl, tree origin, st
       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 (! (decl ? lookup_decl_die (decl) : NULL)
+	  /* ???  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.  */
+	  || (/* in_lto_p && */
+	      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
@@ -23934,6 +24209,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);
@@ -23956,7 +24241,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);
@@ -25314,7 +25601,8 @@  output_macinfo_op (macinfo_entry *ref)
     case DW_MACRO_GNU_transparent_include:
       dw2_asm_output_data (1, ref->code, "Transparent include");
       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:
@@ -25488,7 +25776,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);
@@ -25513,9 +25801,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 ? debug_line_section_label
-                              : debug_skeleton_line_section_label),
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_label,
                              debug_line_section, NULL);
     }
 
@@ -25570,6 +25856,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;
 
@@ -25590,11 +25880,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;
@@ -25614,94 +25906,186 @@  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)
-    {
-      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,
+  /* As we may get called multiple times have a generation count for labels.  */
+  static unsigned generation = 0;
+
+  if (early_lto_debug)
+    {
+      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
+					? 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
+    {
+      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);
-    }
-  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 (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 ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
-      debug_macinfo_section = get_section (debug_macinfo_section_name,
+	  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 ? 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);
-  debug_ranges_section = get_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 (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);
   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
 			       ? 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.  */
@@ -27899,6 +28283,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.  */
 
@@ -27924,6 +28324,47 @@  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 (),
+		   dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros);
+
+      /* 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;
@@ -27934,7 +28375,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.  */
@@ -28180,7 +28621,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");
     }
 
@@ -28315,6 +28757,118 @@  dwarf2out_early_finish (const char *file
 
   /* 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);
+
+  /* ???  Mostly duplicated from dwarf2out_finish.  */
+
+  /* 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 (),
+		   dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
+		   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);
+
+  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_section_prefix_1 (comp_unit_die (), false);
+
+  /* Output the main compilation unit.  We always need it if only for
+     the CU symbol.  */
+  output_comp_unit (comp_unit_die (), true);
+
+  /* Output the abbreviation table.  */
+  if (abbrev_die_table_in_use != 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: early-lto-debug/gcc/debug.h
===================================================================
--- early-lto-debug.orig/gcc/debug.h	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/debug.h	2016-10-21 09:16:45.521070306 +0200
@@ -146,6 +146,14 @@  struct gcc_debug_hooks
   void (* imported_module_or_decl) (tree decl, tree name,
 				    tree context, bool child);
 
+  /* 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);
@@ -205,6 +213,10 @@  extern void debug_nothing_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: early-lto-debug/gcc/debug.c
===================================================================
--- early-lto-debug.orig/gcc/debug.c	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/debug.c	2016-10-21 09:16:45.521070306 +0200
@@ -48,6 +48,8 @@  const struct gcc_debug_hooks do_nothing_
   debug_nothing_tree,	         	 /* late_global_decl */
   debug_nothing_tree_int,		 /* type_decl */
   debug_nothing_tree_tree_tree_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 */
@@ -138,3 +140,16 @@  debug_nothing_tree_int (tree decl ATTRIB
 			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: early-lto-debug/gcc/dbxout.c
===================================================================
--- early-lto-debug.orig/gcc/dbxout.c	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/dbxout.c	2016-10-21 09:16:45.521070306 +0200
@@ -371,6 +371,8 @@  const struct gcc_debug_hooks dbx_debug_h
   dbxout_late_global_decl,		 /* late_global_decl */
   dbxout_type_decl,			 /* type_decl */
   debug_nothing_tree_tree_tree_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 */
@@ -411,6 +413,8 @@  const struct gcc_debug_hooks xcoff_debug
   dbxout_late_global_decl,		 /* late_global_decl */
   dbxout_type_decl,			 /* type_decl */
   debug_nothing_tree_tree_tree_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: early-lto-debug/gcc/sdbout.c
===================================================================
--- early-lto-debug.orig/gcc/sdbout.c	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/sdbout.c	2016-10-21 09:16:45.521070306 +0200
@@ -300,6 +300,8 @@  const struct gcc_debug_hooks sdb_debug_h
   sdbout_late_global_decl,		 /* late_global_decl */
   sdbout_symbol,			 /* type_decl */
   debug_nothing_tree_tree_tree_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: early-lto-debug/gcc/lto/lto.c
===================================================================
--- early-lto-debug.orig/gcc/lto/lto.c	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/lto/lto.c	2016-10-21 09:16:45.525070353 +0200
@@ -1628,6 +1628,9 @@  unify_scc (struct data_in *data_in, unsi
 	      free_node (scc->entries[i]);
 	    }
 
+	  /* Drop DIE references.  */
+	  dref_queue.truncate (0);
+
 	  break;
 	}
 
@@ -1703,8 +1706,7 @@  lto_read_decls (struct lto_file_decl_dat
 						     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.  */
@@ -1743,16 +1745,6 @@  lto_read_decls (struct lto_file_decl_dat
 	      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
@@ -1768,6 +1760,14 @@  lto_read_decls (struct lto_file_decl_dat
 		    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;
 	}
@@ -1947,7 +1947,12 @@  lto_section_with_id (const char *name, u
   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: early-lto-debug/gcc/lto-streamer-in.c
===================================================================
--- early-lto-debug.orig/gcc/lto-streamer-in.c	2016-10-21 09:12:46.534320925 +0200
+++ early-lto-debug/gcc/lto-streamer-in.c	2016-10-21 09:16:45.525070353 +0200
@@ -41,6 +41,7 @@  along with GCC; see the file COPYING3.
 #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 dat
   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);
@@ -1274,6 +1285,10 @@  lto_input_variable_constructor (struct l
 }
 
 
+/* 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.  */
 
@@ -1294,6 +1309,23 @@  lto_read_tree_1 (struct lto_input_block
       && 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);
+	}
+    }
+
 #ifdef LTO_STREAMER_DEBUG
   /* Remove the mapping to RESULT's original address set by
      streamer_alloc_tree.  */
@@ -1444,6 +1476,13 @@  lto_input_tree (struct lto_input_block *
     {
       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: early-lto-debug/gcc/lto-streamer-out.c
===================================================================
--- early-lto-debug.orig/gcc/lto-streamer-out.c	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/lto-streamer-out.c	2016-10-21 09:16:45.525070353 +0200
@@ -40,6 +40,7 @@  along with GCC; see the file COPYING3.
 #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 *o
 			 (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
@@ -765,6 +786,7 @@  DFS::DFS_write_tree_body (struct output_
 	 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)
@@ -2059,6 +2081,17 @@  output_function (struct cgraph_node *nod
   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: early-lto-debug/gcc/lto-streamer.h
===================================================================
--- early-lto-debug.orig/gcc/lto-streamer.h	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/lto-streamer.h	2016-10-21 09:16:45.525070353 +0200
@@ -1225,4 +1225,14 @@  DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, typ
 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: early-lto-debug/gcc/lto-wrapper.c
===================================================================
--- early-lto-debug.orig/gcc/lto-wrapper.c	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/lto-wrapper.c	2016-10-21 09:16:45.525070353 +0200
@@ -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]);
@@ -940,6 +943,67 @@  find_and_merge_options (int fd, off_t fi
   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
@@ -964,8 +1028,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");
@@ -984,6 +1050,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)
@@ -1026,7 +1093,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);
     }
@@ -1087,6 +1154,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;
@@ -1276,18 +1354,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;
     }
@@ -1436,6 +1601,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: early-lto-debug/gcc/tree-streamer-in.c
===================================================================
--- early-lto-debug.orig/gcc/tree-streamer-in.c	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/tree-streamer-in.c	2016-10-21 09:16:45.529070399 +0200
@@ -706,10 +706,7 @@  lto_input_ts_decl_common_tree_pointers (
   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: early-lto-debug/gcc/tree-streamer-out.c
===================================================================
--- early-lto-debug.orig/gcc/tree-streamer-out.c	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/tree-streamer-out.c	2016-10-21 09:16:45.529070399 +0200
@@ -583,10 +583,7 @@  write_ts_decl_common_tree_pointers (stru
      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: early-lto-debug/gcc/config/darwin.c
===================================================================
--- early-lto-debug.orig/gcc/config/darwin.c	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/config/darwin.c	2016-10-21 09:16:45.529070399 +0200
@@ -1919,7 +1919,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.  */
 
@@ -1961,7 +1962,9 @@  darwin_asm_named_section (const char *na
       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);
 }
@@ -2739,19 +2742,37 @@  static GTY (()) vec<dwarf_sect_used_entr
 
 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
@@ -2769,7 +2790,6 @@  darwin_asm_dwarf_section (const char *na
 	  }
       }
 
-  fprintf (asm_out_file, "\t.section %s\n", name);
   if (!found)
     {
       dwarf_sect_used_entry e;
@@ -2822,14 +2842,24 @@  darwin_asm_output_dwarf_offset (FILE *fi
 				HOST_WIDE_INT offset, section *base)
 {
   char sname[64];
-  int namelen;
+  int namelen, extra = 0;
+  bool is_for_lto;
+  const char *lto_add = "";
+
+  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);
 
-  gcc_assert (base->common.flags & SECTION_NAMED);
-  gcc_assert (strncmp (base->named.name, "__DWARF,", 8) == 0);
-  gcc_assert (strchr (base->named.name + 8, ','));
-
-  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: early-lto-debug/gcc/config/darwin.h
===================================================================
--- early-lto-debug.orig/gcc/config/darwin.h	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/config/darwin.h	2016-10-21 09:16:45.529070399 +0200
@@ -420,7 +420,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: early-lto-debug/gcc/vmsdbgout.c
===================================================================
--- early-lto-debug.orig/gcc/vmsdbgout.c	2016-10-20 14:22:30.911519875 +0200
+++ early-lto-debug/gcc/vmsdbgout.c	2016-10-21 09:16:45.529070399 +0200
@@ -196,6 +196,8 @@  const struct gcc_debug_hooks vmsdbg_debu
    vmsdbgout_late_global_decl,
    vmsdbgout_type_decl,		  /* type_decl */
    debug_nothing_tree_tree_tree_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 */