Patchwork [Dwarf] Implement split debug info proposal--Updated (issue6305113)

login
register
mail settings
Submitter Sterling Augustine
Date Aug. 27, 2012, 6 p.m.
Message ID <20120827180000.CC1ED160EFD@sterling.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/180255/
State New
Headers show

Comments

Sterling Augustine - Aug. 27, 2012, 6 p.m.
The enclosed patch to implment -gsplit-dwarf addresses Jason's comments as
responded to by myself and Cary.

In particular, it:

1. Adds comments for force_direct and its use
2. Corrects the location of is_unit_die
3. Makes -gsplit-dwarf imply -gdwarf-4
4. Changes DW_LLE_* to DW_LLE_GNU_*
5. Fixes various comments
6. Adds a new enum to cleanup dtprel and the associated logic
7. Fixes the FIXME in output_macinfo_op

However, it does not:

1. Cleanup redundant entries in the .debug_addr--Cary has a patch in progress
   that handles this situation.

   http://codereview.appspot.com/6305113/#msg6 has more discussion.

2. Defer assigning indices to DW_GNU_addr_index entries until output time. We
   see this less than 0.1 percent of the time, and fixing it would require
   a major restructuring of when the size of debug entries are calculated as
   opposed to when they are emitted.  Further, Cary's forthcoming patch in is
   likely to reduce this count even further.


The line length issues were not real, as a unified diff adds two spaces to
the line, and a script that doesn't account for that will reject 79 and 80
character line lengths.


Hopefully this addresses all remaining issues. OK for mainline?

Sterling and Cary


include/ChangeLog

2012-08-24  Sterling Augustine <saugustine@google.com>
            Cary Coutant <ccoutant@google.com>

	* dwarf2.def: Fix comment.
	* dwarf2.h (dwarf_location_list_entry_type): New enum with members
	DW_LLE_GNU_end_of_list_entry, DW_LLE_GNU_case_address_selection_entry,
	DW_LLE_GNU_start_end_entry, DW_LLE_GNU_start_length_entry.

gcc/ChangeLog

2012-08-24  Sterling Augustine <saugustine@google.com>
            Cary Coutant <ccoutant@google.com>

	* common.opt (gno-split-dwarf, gsplit-dwarf): New switches.
	* doc/invoke.texi (Debugging Options): Document them.
	* dwarf2out.h (dw_val_struct): New field val_index.
	* dwarf2out.c (debug_skeleton_info_section,
	debug_skeleton_abbrev_section, debug_addr_section,
	debug_skeleton_line_section, debug_str_offsets_section): New sections.
	(indirect_string_node): Add index field.
	(dw_loc_list_node): Add begin_index field.
	(dw_addr_op, new_addr_loc_descr, AT_index, set_AT_index,
	add_addr_table_entry, remove_addr_table_entry, output_range_list_offset,
	output_loc_list_offset, output_attr_index_or_value,
	remove_loc_list_addr_table_entries, output_die_abbrevs,
	add_top_level_skeleton_die_attrs, get_skeleton_type_unit,
	output_skeleton_debug_sections, output_index_strings,
	output_addr_table, index_location_lists, add_indirect_string): New
	functions.
	(DEBUG_DWO_INFO_SECTION, DEBUG_DWO_ABBREV_SECTION, DEBUG_ADDR_SECTION,
	DEBUG_NORM_MACINFO_SECTION, DEBUG_DWO_MACINFO_SECTION,
	DEBUG_DWO_LINE_SECTION, DEBUG_DWO_LOC_SECTION,
	DEBUG_NORM_STR_OFFSETS_SECTION, DEBUG_DWO_STR_SECTION,
	DEBUG_MACRO_SECTION_FLAGS, DEBUG_SKELETON_LINE_SECTION_LABEL,
	DEBUG_SKELETON_INFO_SECTION_LABEL, DEBUG_SKELETON_ABBREV_SECTION_LABEL,
	DEBUG_ADDR_SECTIN_LABEL, SKELETON_COMP_DIE_ABBREV,
	SKELETON_TYPE_DIE_ABBREV): New defines.
	(DEBUG_MACINFO_SECTION, DEBUG_MACRO_SECTION, DEBUG_STR_SECTION
	DEBUG_STR_SECTION_FLAGS): Adjust definitions.
	(TEXT_SECTION_LABEL, COLD_TEXT_SECTION_LABEL, DEBUG_INFO_SECTION_LABEL,
	DEBUG_ABBREV_SECTION_LABEL, DEBUG_LOC_SECTION_LABEL,
	DEBUG_RANGES_SECTION_LABEL, DEBUG_MACINFO_SECTION_LABEL,
	DEBUG_MACRO_SECTION_LABEL): Adjust indentation.
	(debug_skeleton_info_section_label, debug_skeleton_abbrev_section_label,
	debug_addr_section_label, debug_skeleton_line_section_label,
	dw_id_placeholder): New	global variables.
	(add_AT_lbl_id, add_AT_low_high_pc): Add force_direct parameter.
	Adjust calls throughout file.  Handle dwarf_split_debug_info.
	(add_AT_addr). Likewise.  Initialize val_index_field.
	(add_AT_range_list): Add force parameter.  Adjust calls throughout file.
	Initialize val_index field.
	(add_ranges_by_labels): Add and handle force_direct parameter.  Adjust
	calls throughout file.
	(size_of_die): New variable form.  Handle dwarf_split_debug_info and
	call AT_index.
	(value_format): Use AT_class instead of calling val_class directly.
	Handle DW_FORM_addr and dw_val_class_lbl_id appropriately for
	dwarf_split_debug_info and AT_index.
	(output_abbrev_section): Move most code to new function
	output_die_abbrevs.
	(output_loc_list): Handle dwarf_split_debug_info by using
	DW_LLE_start_length_entry and DW_LLE_end_of_list_entry.
	(output_die): Call output_attr_index_or_value, output_range_list_offset,
	Fix format string.  Check val_str->form directly to avoid side effect.
	(add_pubtype): Fix indention.
	(output_comdat_type_unit): Handle dwarf_split_debug_info.
	(output_pubnames): Likewise.
	(output_aranges): Likewise.
	(output_mac_info): Likewise.
	(output_mac_info_op): Check for DW_FORM_GNU_str_index.  Call
	add_indirect_string.
	(output_line_info): New parameter prologue_only.  Adjust calls
	throughout file.
	(dtprel_bool, dtprel_false, dtprel_true): New enum and enumerators.
	(mem_loc_descriptor): Call new_addr_loc_descr.
	(loc_descriptor): Likewise.
	(add_const_value_attribute): Likewise.
	(loc_list_from_tree): Replace first_op and second_op with tls_op.
	Update associated logic.  Call new_addr_loc_descr.
	(dwarf2out_init): Handle dwarf_split_debug_info.  Initialize
	debug_skeleton_info_section, debug_skeleton_abbrev_section,
	debug_addr_section, debug_skeleton_line_section,
	debug_str_offsets_section, debug_skeleton_info_section_label,
	debug_skeleton_abbrev_section_label, debug_addr_section_label and
	debug_skeleton_line_section_label.  Use DEBUG_MACRO_SECTION_FLAGS.
	(new_loc_descr, build_cfa_loc, add_AT_flag, add_AT_int, add_AT_unsigned,
	add_AT_double, add_AT_vec, add_AT_data8, add_AT_string, add_AT_die_ref,
	add_AT_fde_ref, add_AT_loc, add_AT_loc_list, add_AT_file,
	add_AT_vms_delta, add_AT_lineptr, add_AT_macptr, add_AT_offset):
	Initialize val_index field.
	(size_of_loc_descr, output_loc_operands, output_loc_operands_raw,
	resolve_addr_in_expression, hash_loc_operands):	Handle
	DW_OP_GNU_addr_index and DW_OP_GNU_const_index.
	(compare_loc_operands):  Likewise.  Adjust assertion.
	(AT_string_form): Call set_AT_index and add_indirect_string.
	(resolve_addr): New local variable l.  Check val_index.  Call
	remove_addr_table_entry and remove_loc_list_addr_table_entries.
	(dwarf2out_finish): Handle dwarf_split_debug_info.  New variable
	main_comp_unit_die.  Call index_location_lists, add_AT_data8,
	add_AT_lineptr, output_skeleton_debug_sections, output_addr_table.  Move
	call to	ASM_GENERATE_INTERNAL_LABEL to dwarf2out_init.  Call
	ASM_OUTPUT_LABEL for debug_skeleton_line_section_label and
	debug_addr_section_label.  Adjust comment.
	* gcc.c (replace_extension_spec_func):  New function.
	(ASM_FINAL_SPEC): Adjust.
	(static_spec_functions): Add new field for replace-extension.
	(check_live_switch): Adjust comment.  Add case for 'g'.
	* opts.c (finish_options): Set x_debug_generate_pub_sections based on
	x_dwarf_split_debug_info.  Call set_debug_level.
	(common_handle_option): Add case for OPT_gsplit_dwarf.
Sterling Augustine - Sept. 5, 2012, 6:43 p.m.
Hey Jason,

Just wanted to be sure you saw this. I know you're busy, but hopefully
this is on your radar.

Sterling

On Mon, Aug 27, 2012 at 11:00 AM, Sterling Augustine
<saugustine@google.com> wrote:
> The enclosed patch to implment -gsplit-dwarf addresses Jason's comments as
> responded to by myself and Cary.
>
> In particular, it:
>
> 1. Adds comments for force_direct and its use
> 2. Corrects the location of is_unit_die
> 3. Makes -gsplit-dwarf imply -gdwarf-4
> 4. Changes DW_LLE_* to DW_LLE_GNU_*
> 5. Fixes various comments
> 6. Adds a new enum to cleanup dtprel and the associated logic
> 7. Fixes the FIXME in output_macinfo_op
>
> However, it does not:
>
> 1. Cleanup redundant entries in the .debug_addr--Cary has a patch in progress
>    that handles this situation.
>
>    http://codereview.appspot.com/6305113/#msg6 has more discussion.
>
> 2. Defer assigning indices to DW_GNU_addr_index entries until output time. We
>    see this less than 0.1 percent of the time, and fixing it would require
>    a major restructuring of when the size of debug entries are calculated as
>    opposed to when they are emitted.  Further, Cary's forthcoming patch in is
>    likely to reduce this count even further.
>
>
> The line length issues were not real, as a unified diff adds two spaces to
> the line, and a script that doesn't account for that will reject 79 and 80
> character line lengths.
>
>
> Hopefully this addresses all remaining issues. OK for mainline?
>
> Sterling and Cary
>
>
> include/ChangeLog
>
> 2012-08-24  Sterling Augustine <saugustine@google.com>
>             Cary Coutant <ccoutant@google.com>
>
>         * dwarf2.def: Fix comment.
>         * dwarf2.h (dwarf_location_list_entry_type): New enum with members
>         DW_LLE_GNU_end_of_list_entry, DW_LLE_GNU_case_address_selection_entry,
>         DW_LLE_GNU_start_end_entry, DW_LLE_GNU_start_length_entry.
>
> gcc/ChangeLog
>
> 2012-08-24  Sterling Augustine <saugustine@google.com>
>             Cary Coutant <ccoutant@google.com>
>
>         * common.opt (gno-split-dwarf, gsplit-dwarf): New switches.
>         * doc/invoke.texi (Debugging Options): Document them.
>         * dwarf2out.h (dw_val_struct): New field val_index.
>         * dwarf2out.c (debug_skeleton_info_section,
>         debug_skeleton_abbrev_section, debug_addr_section,
>         debug_skeleton_line_section, debug_str_offsets_section): New sections.
>         (indirect_string_node): Add index field.
>         (dw_loc_list_node): Add begin_index field.
>         (dw_addr_op, new_addr_loc_descr, AT_index, set_AT_index,
>         add_addr_table_entry, remove_addr_table_entry, output_range_list_offset,
>         output_loc_list_offset, output_attr_index_or_value,
>         remove_loc_list_addr_table_entries, output_die_abbrevs,
>         add_top_level_skeleton_die_attrs, get_skeleton_type_unit,
>         output_skeleton_debug_sections, output_index_strings,
>         output_addr_table, index_location_lists, add_indirect_string): New
>         functions.
>         (DEBUG_DWO_INFO_SECTION, DEBUG_DWO_ABBREV_SECTION, DEBUG_ADDR_SECTION,
>         DEBUG_NORM_MACINFO_SECTION, DEBUG_DWO_MACINFO_SECTION,
>         DEBUG_DWO_LINE_SECTION, DEBUG_DWO_LOC_SECTION,
>         DEBUG_NORM_STR_OFFSETS_SECTION, DEBUG_DWO_STR_SECTION,
>         DEBUG_MACRO_SECTION_FLAGS, DEBUG_SKELETON_LINE_SECTION_LABEL,
>         DEBUG_SKELETON_INFO_SECTION_LABEL, DEBUG_SKELETON_ABBREV_SECTION_LABEL,
>         DEBUG_ADDR_SECTIN_LABEL, SKELETON_COMP_DIE_ABBREV,
>         SKELETON_TYPE_DIE_ABBREV): New defines.
>         (DEBUG_MACINFO_SECTION, DEBUG_MACRO_SECTION, DEBUG_STR_SECTION
>         DEBUG_STR_SECTION_FLAGS): Adjust definitions.
>         (TEXT_SECTION_LABEL, COLD_TEXT_SECTION_LABEL, DEBUG_INFO_SECTION_LABEL,
>         DEBUG_ABBREV_SECTION_LABEL, DEBUG_LOC_SECTION_LABEL,
>         DEBUG_RANGES_SECTION_LABEL, DEBUG_MACINFO_SECTION_LABEL,
>         DEBUG_MACRO_SECTION_LABEL): Adjust indentation.
>         (debug_skeleton_info_section_label, debug_skeleton_abbrev_section_label,
>         debug_addr_section_label, debug_skeleton_line_section_label,
>         dw_id_placeholder): New global variables.
>         (add_AT_lbl_id, add_AT_low_high_pc): Add force_direct parameter.
>         Adjust calls throughout file.  Handle dwarf_split_debug_info.
>         (add_AT_addr). Likewise.  Initialize val_index_field.
>         (add_AT_range_list): Add force parameter.  Adjust calls throughout file.
>         Initialize val_index field.
>         (add_ranges_by_labels): Add and handle force_direct parameter.  Adjust
>         calls throughout file.
>         (size_of_die): New variable form.  Handle dwarf_split_debug_info and
>         call AT_index.
>         (value_format): Use AT_class instead of calling val_class directly.
>         Handle DW_FORM_addr and dw_val_class_lbl_id appropriately for
>         dwarf_split_debug_info and AT_index.
>         (output_abbrev_section): Move most code to new function
>         output_die_abbrevs.
>         (output_loc_list): Handle dwarf_split_debug_info by using
>         DW_LLE_start_length_entry and DW_LLE_end_of_list_entry.
>         (output_die): Call output_attr_index_or_value, output_range_list_offset,
>         Fix format string.  Check val_str->form directly to avoid side effect.
>         (add_pubtype): Fix indention.
>         (output_comdat_type_unit): Handle dwarf_split_debug_info.
>         (output_pubnames): Likewise.
>         (output_aranges): Likewise.
>         (output_mac_info): Likewise.
>         (output_mac_info_op): Check for DW_FORM_GNU_str_index.  Call
>         add_indirect_string.
>         (output_line_info): New parameter prologue_only.  Adjust calls
>         throughout file.
>         (dtprel_bool, dtprel_false, dtprel_true): New enum and enumerators.
>         (mem_loc_descriptor): Call new_addr_loc_descr.
>         (loc_descriptor): Likewise.
>         (add_const_value_attribute): Likewise.
>         (loc_list_from_tree): Replace first_op and second_op with tls_op.
>         Update associated logic.  Call new_addr_loc_descr.
>         (dwarf2out_init): Handle dwarf_split_debug_info.  Initialize
>         debug_skeleton_info_section, debug_skeleton_abbrev_section,
>         debug_addr_section, debug_skeleton_line_section,
>         debug_str_offsets_section, debug_skeleton_info_section_label,
>         debug_skeleton_abbrev_section_label, debug_addr_section_label and
>         debug_skeleton_line_section_label.  Use DEBUG_MACRO_SECTION_FLAGS.
>         (new_loc_descr, build_cfa_loc, add_AT_flag, add_AT_int, add_AT_unsigned,
>         add_AT_double, add_AT_vec, add_AT_data8, add_AT_string, add_AT_die_ref,
>         add_AT_fde_ref, add_AT_loc, add_AT_loc_list, add_AT_file,
>         add_AT_vms_delta, add_AT_lineptr, add_AT_macptr, add_AT_offset):
>         Initialize val_index field.
>         (size_of_loc_descr, output_loc_operands, output_loc_operands_raw,
>         resolve_addr_in_expression, hash_loc_operands): Handle
>         DW_OP_GNU_addr_index and DW_OP_GNU_const_index.
>         (compare_loc_operands):  Likewise.  Adjust assertion.
>         (AT_string_form): Call set_AT_index and add_indirect_string.
>         (resolve_addr): New local variable l.  Check val_index.  Call
>         remove_addr_table_entry and remove_loc_list_addr_table_entries.
>         (dwarf2out_finish): Handle dwarf_split_debug_info.  New variable
>         main_comp_unit_die.  Call index_location_lists, add_AT_data8,
>         add_AT_lineptr, output_skeleton_debug_sections, output_addr_table.  Move
>         call to ASM_GENERATE_INTERNAL_LABEL to dwarf2out_init.  Call
>         ASM_OUTPUT_LABEL for debug_skeleton_line_section_label and
>         debug_addr_section_label.  Adjust comment.
>         * gcc.c (replace_extension_spec_func):  New function.
>         (ASM_FINAL_SPEC): Adjust.
>         (static_spec_functions): Add new field for replace-extension.
>         (check_live_switch): Adjust comment.  Add case for 'g'.
>         * opts.c (finish_options): Set x_debug_generate_pub_sections based on
>         x_dwarf_split_debug_info.  Call set_debug_level.
>         (common_handle_option): Add case for OPT_gsplit_dwarf.
>
> Index: include/dwarf2.def
> ===================================================================
> --- include/dwarf2.def  (revision 190603)
> +++ include/dwarf2.def  (working copy)
> @@ -586,7 +586,7 @@
>  DW_OP (DW_OP_GNU_reinterpret, 0xf9)
>  /* The GNU parameter ref extension.  */
>  DW_OP (DW_OP_GNU_parameter_ref, 0xfa)
> -/* Extension for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
> +/* Extensions for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
>  DW_OP (DW_OP_GNU_addr_index, 0xfb)
>  DW_OP (DW_OP_GNU_const_index, 0xfc)
>  /* HP extensions.  */
> Index: include/dwarf2.h
> ===================================================================
> --- include/dwarf2.h    (revision 190603)
> +++ include/dwarf2.h    (working copy)
> @@ -259,6 +259,17 @@
>      DW_LNE_HP_SFC_associate = 3
>    };
>
> +/* Type codes for location list entries.
> +   Extension for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
> +
> +enum dwarf_location_list_entry_type
> +  {
> +    DW_LLE_GNU_end_of_list_entry = 0,
> +    DW_LLE_GNU_base_address_selection_entry = 1,
> +    DW_LLE_GNU_start_end_entry = 2,
> +    DW_LLE_GNU_start_length_entry = 3
> +  };
> +
>  #define DW_CIE_ID        0xffffffff
>  #define DW64_CIE_ID      0xffffffffffffffffULL
>  #define DW_CIE_VERSION   1
> Index: gcc/doc/invoke.texi
> ===================================================================
> --- gcc/doc/invoke.texi (revision 190603)
> +++ gcc/doc/invoke.texi (working copy)
> @@ -4803,6 +4803,14 @@
>  The following options are useful when GCC is generated with the
>  capability for more than one debugging format.
>
> +@item -gsplit-dwarf
> +@opindex gsplit-dwarf
> +Separate as much dwarf debugging information as possible into a
> +separate output file with the extension .dwo.  This option allows
> +the build system to avoid linking files with debug information.  To
> +be useful, this option requires a debugger capable of reading .dwo
> +files.
> +
>  @item -ggdb
>  @opindex ggdb
>  Produce debugging information for use by GDB@.  This means to use the
> Index: gcc/gcc.c
> ===================================================================
> --- gcc/gcc.c   (revision 190603)
> +++ gcc/gcc.c   (working copy)
> @@ -267,6 +267,7 @@
>  static const char *compare_debug_self_opt_spec_function (int, const char **);
>  static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
>  static const char *pass_through_libs_spec_func (int, const char **);
> +static const char *replace_extension_spec_func (int, const char **);
>
>  /* The Specs Language
>
> @@ -447,7 +448,7 @@
>  colon in these constructs, except between . or * and the corresponding
>  word.
>
> -The -O, -f, -m, and -W switches are handled specifically in these
> +The -O, -f, -g, -m, and -W switches are handled specifically in these
>  constructs.  If another value of -O or the negated form of a -f, -m, or
>  -W switch is found later in the command line, the earlier switch
>  value is ignored, except with {S*} where S is just one letter; this
> @@ -480,7 +481,14 @@
>  /* config.h can define ASM_FINAL_SPEC to run a post processor after
>     the assembler has run.  */
>  #ifndef ASM_FINAL_SPEC
> -#define ASM_FINAL_SPEC ""
> +#define ASM_FINAL_SPEC \
> +  "%{gsplit-dwarf: \n\
> +       objcopy --extract-dwo \
> +        %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> +        %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
> +       objcopy --strip-dwo \
> +        %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> +    }"
>  #endif
>
>  /* config.h can define CPP_SPEC to provide extra args to the C preprocessor
> @@ -1262,6 +1270,7 @@
>    { "compare-debug-self-opt",  compare_debug_self_opt_spec_function },
>    { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
>    { "pass-through-libs",       pass_through_libs_spec_func },
> +  { "replace-extension",       replace_extension_spec_func },
>  #ifdef EXTRA_SPEC_FUNCTIONS
>    EXTRA_SPEC_FUNCTIONS
>  #endif
> @@ -5803,7 +5812,7 @@
>     on the command line.  PREFIX_LENGTH is the length of XXX in an {XXX*}
>     spec, or -1 if either exact match or %* is used.
>
> -   A -O switch is obsoleted by a later -O switch.  A -f, -m, or -W switch
> +   A -O switch is obsoleted by a later -O switch.  A -f, -g, -m, or -W switch
>     whose value does not begin with "no-" is obsoleted by the same value
>     with the "no-", similarly for a switch with the "no-" prefix.  */
>
> @@ -5840,7 +5849,7 @@
>           }
>        break;
>
> -    case 'W':  case 'f':  case 'm':
> +    case 'W':  case 'f':  case 'm': case 'g':
>        if (! strncmp (name + 1, "no-", 3))
>         {
>           /* We have Xno-YYY, search for XYYY.  */
> @@ -8363,3 +8372,33 @@
>      }
>    return prepended;
>  }
> +
> +/* %:replace-extension spec function.  Replaces the extension of the
> +   first argument with the second argument.  */
> +
> +const char *
> +replace_extension_spec_func (int argc, const char **argv)
> +{
> +  char *name;
> +  char *p;
> +  char *result;
> +  int i;
> +
> +  if (argc != 2)
> +    fatal_error ("too few arguments to %%:replace-extension");
> +
> +  name = xstrdup (argv[0]);
> +
> +  for (i = strlen(name) - 1; i >= 0; i--)
> +    if (IS_DIR_SEPARATOR (name[i]))
> +      break;
> +
> +  p = strrchr (name + i + 1, '.');
> +  if (p != NULL)
> +      *p = '\0';
> +
> +  result = concat (name, argv[1], NULL);
> +
> +  free (name);
> +  return result;
> +}
> Index: gcc/dwarf2out.c
> ===================================================================
> --- gcc/dwarf2out.c     (revision 190603)
> +++ gcc/dwarf2out.c     (working copy)
> @@ -145,14 +145,19 @@
>
>  /* Pointers to various DWARF2 sections.  */
>  static GTY(()) section *debug_info_section;
> +static GTY(()) section *debug_skeleton_info_section;
>  static GTY(()) section *debug_abbrev_section;
> +static GTY(()) section *debug_skeleton_abbrev_section;
>  static GTY(()) section *debug_aranges_section;
> +static GTY(()) section *debug_addr_section;
>  static GTY(()) section *debug_macinfo_section;
>  static GTY(()) section *debug_line_section;
> +static GTY(()) section *debug_skeleton_line_section;
>  static GTY(()) section *debug_loc_section;
>  static GTY(()) section *debug_pubnames_section;
>  static GTY(()) section *debug_pubtypes_section;
>  static GTY(()) section *debug_str_section;
> +static GTY(()) section *debug_str_offsets_section;
>  static GTY(()) section *debug_ranges_section;
>  static GTY(()) section *debug_frame_section;
>
> @@ -195,6 +200,7 @@
>    unsigned int refcount;
>    enum dwarf_form form;
>    char *label;
> +  unsigned int index;
>  };
>
>  static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
> @@ -1201,7 +1207,8 @@
>     their entire life.  */
>  typedef struct GTY(()) dw_loc_list_struct {
>    dw_loc_list_ref dw_loc_next;
> -  const char *begin; /* Label for begin address of range */
> +  const char *begin; /* Label and index for begin address of range */
> +  unsigned int begin_index;
>    const char *end;  /* Label for end address of range */
>    char *ll_symbol; /* Label for beginning of location list.
>                       Only on head of list */
> @@ -1246,8 +1253,10 @@
>
>    descr->dw_loc_opc = op;
>    descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
> +  descr->dw_loc_oprnd1.val_index = -1U;
>    descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
>    descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
> +  descr->dw_loc_oprnd2.val_index = -1U;
>    descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
>
>    return descr;
> @@ -1452,6 +1461,10 @@
>      case DW_OP_addr:
>        size += DWARF2_ADDR_SIZE;
>        break;
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      size += size_of_uleb128 (loc->dw_loc_oprnd1.val_index);
> +      break;
>      case DW_OP_const1u:
>      case DW_OP_const1s:
>        size += 1;
> @@ -1888,6 +1901,12 @@
>         }
>        break;
>
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_index,
> +                                   "(index into .debug_addr)");
> +      break;
> +
>      case DW_OP_GNU_implicit_pointer:
>        {
>         char label[MAX_ARTIFICIAL_LABEL_BYTES
> @@ -2063,6 +2082,8 @@
>    switch (loc->dw_loc_opc)
>      {
>      case DW_OP_addr:
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
>      case DW_OP_implicit_value:
>        /* We cannot output addresses in .cfi_escape, only bytes.  */
>        gcc_unreachable ();
> @@ -2246,6 +2267,7 @@
>      {
>        head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
>        head->dw_loc_oprnd1.val_class = dw_val_class_const;
> +      head->dw_loc_oprnd1.val_index = -1U;
>        tmp = new_loc_descr (DW_OP_deref, 0, 0);
>        add_loc_descr (&head, tmp);
>        if (offset != 0)
> @@ -2875,6 +2897,8 @@
>  static tree decl_class_context (tree);
>  static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
>  static inline enum dw_val_class AT_class (dw_attr_ref);
> +static inline unsigned int AT_index (dw_attr_ref);
> +static inline void set_AT_index (dw_attr_ref, unsigned int);
>  static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned);
>  static inline unsigned AT_flag (dw_attr_ref);
>  static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
> @@ -2902,15 +2926,18 @@
>  static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
>                              dw_loc_list_ref);
>  static inline dw_loc_list_ref AT_loc_list (dw_attr_ref);
> -static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx);
> +static unsigned int add_addr_table_entry (dw_attr_node *);
> +static void remove_addr_table_entry (unsigned int);
> +static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
>  static inline rtx AT_addr (dw_attr_ref);
> -static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
> +static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *,
> +                          bool);
>  static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
>  static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
>  static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
>                            unsigned HOST_WIDE_INT);
>  static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
> -                              unsigned long);
> +                              unsigned long, bool);
>  static inline const char *AT_lbl (dw_attr_ref);
>  static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute);
>  static const char *get_AT_low_pc (dw_die_ref);
> @@ -3005,6 +3032,7 @@
>  static enum dwarf_form value_format (dw_attr_ref);
>  static void output_value_format (dw_attr_ref);
>  static void output_abbrev_section (void);
> +static void output_die_abbrevs (unsigned long, dw_die_ref);
>  static void output_die_symbol (dw_die_ref);
>  static void output_die (dw_die_ref);
>  static void output_compilation_unit_header (void);
> @@ -3020,10 +3048,10 @@
>  static unsigned int add_ranges_num (int);
>  static unsigned int add_ranges (const_tree);
>  static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
> -                                 bool *);
> +                                 bool *, bool);
>  static void output_ranges (void);
>  static dw_line_info_table *new_line_info_table (void);
> -static void output_line_info (void);
> +static void output_line_info (bool);
>  static void output_file_names (void);
>  static dw_die_ref base_type_die (tree);
>  static int is_base_type (tree);
> @@ -3162,36 +3190,130 @@
>  static void schedule_generic_params_dies_gen (tree t);
>  static void gen_scheduled_generic_parms_dies (void);
>
> +/* enum for tracking thread-local variables whose address is really an offset
> +   relative to the TLS pointer, which will need link-time relocation, but will
> +   not need relocation by the DWARF consumer.  */
> +
> +enum dtprel_bool
> +  {
> +    dtprel_false = 0,
> +    dtprel_true = 1
> +  };
> +
> +/* Return the operator to use for an address of a variable.  For dtprel_true, we
> +   use DW_OP_const*.  For regular variables, which need both link-time
> +   relocation and consumer-level relocation (e.g., to account for shared objects
> +   loaded at a random address), we use DW_OP_addr*.  */
> +
> +static inline enum dwarf_location_atom
> +dw_addr_op (enum dtprel_bool dtprel)
> +{
> +  if (dtprel == dtprel_true)
> +    return (dwarf_split_debug_info ? DW_OP_GNU_const_index
> +            : (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u));
> +  else
> +    return (dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr);
> +}
> +
> +/* Return a pointer to a newly allocated address location description.  If
> +   dwarf_split_debug_info is true, then record the address with the appropriate
> +   relocation.  */
> +static inline dw_loc_descr_ref
> +new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
> +{
> +  dw_loc_descr_ref ref = new_loc_descr (dw_addr_op (dtprel), 0, 0);
> +
> +  ref->dw_loc_oprnd1.val_class = dw_val_class_addr;
> +  ref->dw_loc_oprnd1.val_index = -1U;
> +  ref->dw_loc_oprnd1.v.val_addr = addr;
> +  ref->dtprel = dtprel;
> +  if (dwarf_split_debug_info)
> +    {
> +      dw_attr_node attr;
> +
> +      attr.dw_attr = DW_AT_location;
> +      attr.dw_attr_val.val_class = (dtprel == dtprel_true
> +                                    ? dw_val_class_loc : dw_val_class_addr);
> +      attr.dw_attr_val.val_index = -1U;
> +      attr.dw_attr_val.v.val_addr = addr;
> +
> +      ref->dw_loc_oprnd1.val_index = add_addr_table_entry (&attr);
> +    }
> +  return ref;
> +}
> +
>  /* Section names used to hold DWARF debugging information.  */
> +
>  #ifndef DEBUG_INFO_SECTION
>  #define DEBUG_INFO_SECTION     ".debug_info"
>  #endif
> +#ifndef DEBUG_DWO_INFO_SECTION
> +#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
> +#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_ARANGES_SECTION
>  #define DEBUG_ARANGES_SECTION  ".debug_aranges"
>  #endif
> +#ifndef DEBUG_ADDR_SECTION
> +#define DEBUG_ADDR_SECTION     ".debug_addr"
> +#endif
> +#ifndef DEBUG_NORM_MACINFO_SECTION
> +#define DEBUG_NORM_MACINFO_SECTION     ".debug_macinfo"
> +#endif
> +#ifndef DEBUG_DWO_MACINFO_SECTION
> +#define DEBUG_DWO_MACINFO_SECTION      ".debug_macinfo.dwo"
> +#endif
>  #ifndef DEBUG_MACINFO_SECTION
> -#define DEBUG_MACINFO_SECTION  ".debug_macinfo"
> +#define DEBUG_MACINFO_SECTION                                           \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_MACINFO_SECTION) : (DEBUG_DWO_MACINFO_SECTION))
>  #endif
> +#ifndef DEBUG_NORM_MACRO_SECTION
> +#define DEBUG_NORM_MACRO_SECTION ".debug_macro"
> +#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"
> +#define DEBUG_MACRO_SECTION                                             \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_MACRO_SECTION) : (DEBUG_DWO_MACRO_SECTION))
>  #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_LOC_SECTION
>  #define DEBUG_LOC_SECTION      ".debug_loc"
>  #endif
> +#ifndef DEBUG_DWO_LOC_SECTION
> +#define DEBUG_DWO_LOC_SECTION  ".debug_loc.dwo"
> +#endif
>  #ifndef DEBUG_PUBNAMES_SECTION
>  #define DEBUG_PUBNAMES_SECTION ".debug_pubnames"
>  #endif
>  #ifndef DEBUG_PUBTYPES_SECTION
>  #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes"
>  #endif
> +#define DEBUG_NORM_STR_OFFSETS_SECTION ".debug_str_offsets"
> +#define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo"
> +#ifndef DEBUG_STR_OFFSETS_SECTION
> +#define DEBUG_STR_OFFSETS_SECTION                                       \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_STR_OFFSETS_SECTION) : (DEBUG_DWO_STR_OFFSETS_SECTION))
> +#endif
> +#define DEBUG_DWO_STR_SECTION   ".debug_str.dwo"
> +#define DEBUG_NORM_STR_SECTION  ".debug_str"
>  #ifndef DEBUG_STR_SECTION
> -#define DEBUG_STR_SECTION      ".debug_str"
> +#define DEBUG_STR_SECTION                               \
> +  (!dwarf_split_debug_info ? (DEBUG_NORM_STR_SECTION) : (DEBUG_DWO_STR_SECTION))
>  #endif
>  #ifndef DEBUG_RANGES_SECTION
>  #define DEBUG_RANGES_SECTION   ".debug_ranges"
> @@ -3202,44 +3324,63 @@
>  #define TEXT_SECTION_NAME      ".text"
>  #endif
>
> +/* Section flags for .debug_macinfo/.debug_macro section.  */
> +#define DEBUG_MACRO_SECTION_FLAGS \
> +  (dwarf_split_debug_info ? SECTION_DEBUG | SECTION_EXCLUDE : SECTION_DEBUG)
> +
>  /* Section flags for .debug_str section.  */
>  #define DEBUG_STR_SECTION_FLAGS \
> -  (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings              \
> -   ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1       \
> -   : SECTION_DEBUG)
> +  (dwarf_split_debug_info \
> +   ? SECTION_DEBUG | SECTION_EXCLUDE \
> +   : (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings \
> +      ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1        \
> +      : SECTION_DEBUG))
>
>  /* Labels we insert at beginning sections we can reference instead of
>     the section names themselves.  */
>
>  #ifndef TEXT_SECTION_LABEL
> -#define TEXT_SECTION_LABEL             "Ltext"
> +#define TEXT_SECTION_LABEL                 "Ltext"
>  #endif
>  #ifndef COLD_TEXT_SECTION_LABEL
> -#define COLD_TEXT_SECTION_LABEL         "Ltext_cold"
> +#define COLD_TEXT_SECTION_LABEL             "Ltext_cold"
>  #endif
>  #ifndef DEBUG_LINE_SECTION_LABEL
> -#define DEBUG_LINE_SECTION_LABEL       "Ldebug_line"
> +#define DEBUG_LINE_SECTION_LABEL           "Ldebug_line"
>  #endif
> +#ifndef DEBUG_SKELETON_LINE_SECTION_LABEL
> +#define DEBUG_SKELETON_LINE_SECTION_LABEL   "Lskeleton_debug_line"
> +#endif
>  #ifndef DEBUG_INFO_SECTION_LABEL
> -#define DEBUG_INFO_SECTION_LABEL       "Ldebug_info"
> +#define DEBUG_INFO_SECTION_LABEL           "Ldebug_info"
>  #endif
> +#ifndef DEBUG_SKELETON_INFO_SECTION_LABEL
> +#define DEBUG_SKELETON_INFO_SECTION_LABEL   "Lskeleton_debug_info"
> +#endif
>  #ifndef DEBUG_ABBREV_SECTION_LABEL
> -#define DEBUG_ABBREV_SECTION_LABEL     "Ldebug_abbrev"
> +#define DEBUG_ABBREV_SECTION_LABEL         "Ldebug_abbrev"
>  #endif
> +#ifndef DEBUG_SKELETON_ABBREV_SECTION_LABEL
> +#define DEBUG_SKELETON_ABBREV_SECTION_LABEL "Lskeleton_debug_abbrev"
> +#endif
> +#ifndef DEBUG_ADDR_SECTION_LABEL
> +#define DEBUG_ADDR_SECTION_LABEL           "Ldebug_addr"
> +#endif
>  #ifndef DEBUG_LOC_SECTION_LABEL
> -#define DEBUG_LOC_SECTION_LABEL                "Ldebug_loc"
> +#define DEBUG_LOC_SECTION_LABEL                    "Ldebug_loc"
>  #endif
>  #ifndef DEBUG_RANGES_SECTION_LABEL
> -#define DEBUG_RANGES_SECTION_LABEL     "Ldebug_ranges"
> +#define DEBUG_RANGES_SECTION_LABEL         "Ldebug_ranges"
>  #endif
>  #ifndef DEBUG_MACINFO_SECTION_LABEL
> -#define DEBUG_MACINFO_SECTION_LABEL     "Ldebug_macinfo"
> +#define DEBUG_MACINFO_SECTION_LABEL         "Ldebug_macinfo"
>  #endif
>  #ifndef DEBUG_MACRO_SECTION_LABEL
> -#define DEBUG_MACRO_SECTION_LABEL      "Ldebug_macro"
> +#define DEBUG_MACRO_SECTION_LABEL          "Ldebug_macro"
>  #endif
> +#define SKELETON_COMP_DIE_ABBREV 1
> +#define SKELETON_TYPE_DIE_ABBREV 2
>
> -
>  /* Definitions of defaults for formats and names of various special
>     (artificial) labels which may be generated within this file (when the -g
>     options is used and DWARF2_DEBUGGING_INFO is in effect.
> @@ -3252,7 +3393,11 @@
>  static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_addr_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
> @@ -3493,6 +3638,31 @@
>    return a->dw_attr_val.val_class;
>  }
>
> +/* Return the index for any attribute that will be referenced with a
> +   DW_FORM_GNU_addr_index.  Strings have their indices handled differently to
> +   account for reference counting pruning.  */
> +
> +static inline unsigned int
> +AT_index (dw_attr_ref a)
> +{
> +  if (AT_class (a) == dw_val_class_str)
> +    return a->dw_attr_val.v.val_str->index;
> +  else
> +    return a->dw_attr_val.val_index;
> +}
> +
> +/* Set the index for any attribute that will be referenced with a
> +   DW_FORM_GNU_addr_index.  */
> +
> +static inline void
> +set_AT_index (dw_attr_ref a, unsigned int index)
> +{
> +  if (AT_class (a) == dw_val_class_str)
> +    a->dw_attr_val.v.val_str->index = index;
> +  else
> +    a->dw_attr_val.val_index = index;
> +}
> +
>  /* Add a flag value attribute to a DIE.  */
>
>  static inline void
> @@ -3502,6 +3672,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_flag;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_flag = flag;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3522,6 +3693,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_const;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_int = int_val;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3543,6 +3715,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_unsigned = unsigned_val;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3564,6 +3737,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_const_double;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_double.high = high;
>    attr.dw_attr_val.v.val_double.low = low;
>    add_dwarf_attr (die, &attr);
> @@ -3579,6 +3753,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_vec;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_vec.length = length;
>    attr.dw_attr_val.v.val_vec.elt_size = elt_size;
>    attr.dw_attr_val.v.val_vec.array = array;
> @@ -3595,28 +3770,39 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_data8;
> +  attr.dw_attr_val.val_index = -1U;
>    memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  */
> +/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  The parameter force_direct
> +   makes the attribute use DW_AT_addr, rather than DW_AT_GNU_addr_index.  */
> +
>  static inline void
> -add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high)
> +add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high,
> +                   bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = DW_AT_low_pc;
>    attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_low);
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, DW_AT_low_pc), add_addr_table_entry (&attr));
>
>    attr.dw_attr = DW_AT_high_pc;
>    if (dwarf_version < 4)
>      attr.dw_attr_val.val_class = dw_val_class_lbl_id;
>    else
>      attr.dw_attr_val.val_class = dw_val_class_high_pc;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_high);
>    add_dwarf_attr (die, &attr);
> +  if (attr.dw_attr_val.val_class == dw_val_class_lbl_id
> +      && dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, DW_AT_high_pc), add_addr_table_entry (&attr));
>  }
>
>  /* Hash and equality functions for debug_str_hash.  */
> @@ -3673,6 +3859,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_str;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_str = node;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3684,6 +3871,38 @@
>    return a->dw_attr_val.v.val_str->str;
>  }
>
> +/* A vector for a table of strings in the form DW_FORM_GNU_index_str.  */
> +
> +typedef struct indirect_string_node indirect_string_node;
> +DEF_VEC_O(indirect_string_node);
> +DEF_VEC_ALLOC_O(indirect_string_node, gc);
> +static GTY (()) VEC (indirect_string_node, gc) *index_string_table;
> +
> +/* Add a new indirect string to the appropriate tables.  Returns the index of
> +   the new string.  Call this function directly to bypass AT_string_form's logic
> +   to put the string inline in the die. */
> +
> +static unsigned long
> +add_indirect_string (struct indirect_string_node *node, const char *str)
> +{
> +  static unsigned int index_string_count = 0;
> +  ++dw2_string_counter;
> +  node->label = xstrdup (str);
> +
> +  if (!dwarf_split_debug_info)
> +    {
> +      node->form = DW_FORM_strp;
> +      return -1U;
> +    }
> +  else
> +    {
> +      node->form = DW_FORM_GNU_str_index;
> +      index_string_count++;
> +      VEC_safe_push (indirect_string_node, gc, index_string_table, node);
> +      return index_string_count;
> +    }
> +}
> +
>  /* Find out whether a string should be output inline in DIE
>     or out-of-line in .debug_str section.  */
>
> @@ -3716,10 +3935,9 @@
>      return node->form = DW_FORM_string;
>
>    ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
> -  ++dw2_string_counter;
> -  node->label = xstrdup (label);
> +  set_AT_index (a, add_indirect_string (node, label));
>
> -  return node->form = DW_FORM_strp;
> +  return node->form;
>  }
>
>  /* Add a DIE reference attribute value to a DIE.  */
> @@ -3740,6 +3958,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_die_ref;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_die_ref.die = targ_die;
>    attr.dw_attr_val.v.val_die_ref.external = 0;
>    add_dwarf_attr (die, &attr);
> @@ -3798,6 +4017,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_fde_ref;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_fde_index = targ_fde;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3811,6 +4031,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_loc;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_loc = loc;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3829,6 +4050,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_loc_list;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_loc_list = loc_list;
>    add_dwarf_attr (die, &attr);
>    have_location_lists = true;
> @@ -3848,17 +4070,62 @@
>    return &a->dw_attr_val.v.val_loc_list;
>  }
>
> -/* Add an address constant attribute value to a DIE.  */
> +/* A table of entries into the .debug_addr section.  */
>
> +static GTY (()) VEC (dw_attr_node,gc) * addr_index_table;
> +
> +static unsigned int
> +add_addr_table_entry (dw_attr_node *attr)
> +{
> +  gcc_assert (dwarf_split_debug_info);
> +
> +  VEC_safe_push (dw_attr_node, gc, addr_index_table, attr);
> +  return VEC_length (dw_attr_node, addr_index_table) - 1;
> +}
> +
> +/* Remove an entry from the addr table.  Since we have already numbered
> +   all the entries, the best we can do here is null it out.  */
> +
> +static void
> +remove_addr_table_entry (unsigned int i)
> +{
> +  dw_attr_node *attr;
> +
> +  gcc_assert (dwarf_split_debug_info);
> +  gcc_assert (i < VEC_length (dw_attr_node, addr_index_table));
> +
> +  attr = &VEC_index (dw_attr_node, addr_index_table, i);
> +  attr->dw_attr = (enum dwarf_attribute) 0;
> +}
> +
> +/* Given a location list, remove all addresses it refers to from the
> +   address_table.  */
> +
> +static void
> +remove_loc_list_addr_table_entries (dw_loc_descr_ref descr)
> +{
> +  for (; descr; descr = descr->dw_loc_next)
> +    if (descr->dw_loc_oprnd1.val_index != -1U)
> +      remove_addr_table_entry (descr->dw_loc_oprnd1.val_index);
> +}
> +
> +/* Add an address constant attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
> +
>  static inline void
> -add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
> +add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr,
> +            bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_addr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_addr = addr;
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
>  }
>
>  /* Get the RTX from to an address DIE attribute.  */
> @@ -3880,6 +4147,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_file;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_file = fd;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3903,22 +4171,29 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_vms_delta;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1);
>    attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2);
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add a label identifier attribute value to a DIE.  */
> +/* Add a label identifier attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static inline void
> -add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
> +add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind,
> +              const char *lbl_id, bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
>  }
>
>  /* Add a section offset attribute value to a DIE, an offset into the
> @@ -3932,6 +4207,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_lineptr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3947,6 +4223,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_macptr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3961,20 +4238,31 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_offset;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_offset = offset;
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add an range_list attribute value to a DIE.  */
> +/* Add a range_list attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static void
>  add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
> -                  long unsigned int offset)
> +                  long unsigned int offset, bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_range_list;
> +  /* For the range_list attribute, val_index == -1U indicates that we want to
> +     output a relocated reference to the range list entry, while any other
> +     value indicates that we want to output the section-relative offset of the
> +     range list entry. In this case, we're not using the val_index field as a
> +     slot index like we do for references to .debug_addr.  This is used
> +     in output_range_list_offset.  */
> +  attr.dw_attr_val.val_index
> +      = (dwarf_split_debug_info && !force_direct) ? offset : -1U;
>    attr.dw_attr_val.v.val_offset = offset;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -7158,6 +7446,7 @@
>    unsigned long size = 0;
>    dw_attr_ref a;
>    unsigned ix;
> +  enum dwarf_form form;
>
>    size += size_of_uleb128 (die->die_abbrev);
>    FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
> @@ -7165,7 +7454,10 @@
>        switch (AT_class (a))
>         {
>         case dw_val_class_addr:
> -         size += DWARF2_ADDR_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF2_ADDR_SIZE;
>           break;
>         case dw_val_class_offset:
>           size += DWARF_OFFSET_SIZE;
> @@ -7183,10 +7475,13 @@
>           }
>           break;
>         case dw_val_class_loc_list:
> -         size += DWARF_OFFSET_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_range_list:
> -         size += DWARF_OFFSET_SIZE;
> +          size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_const:
>           size += size_of_sleb128 (AT_int (a));
> @@ -7246,15 +7541,21 @@
>           size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_lbl_id:
> -         size += DWARF2_ADDR_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF2_ADDR_SIZE;
>           break;
>         case dw_val_class_lineptr:
>         case dw_val_class_macptr:
> -         size += DWARF_OFFSET_SIZE;
> +          size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_str:
> -         if (AT_string_form (a) == DW_FORM_strp)
> +          form = AT_string_form (a);
> +          if (form == DW_FORM_strp)
>             size += DWARF_OFFSET_SIZE;
> +         else if (form == DW_FORM_GNU_str_index)
> +            size += size_of_uleb128 (AT_index (a));
>           else
>             size += strlen (a->dw_attr_val.v.val_str->str) + 1;
>           break;
> @@ -7439,7 +7740,7 @@
>  static enum dwarf_form
>  value_format (dw_attr_ref a)
>  {
> -  switch (a->dw_attr_val.val_class)
> +  switch (AT_class (a))
>      {
>      case dw_val_class_addr:
>        /* Only very few attributes allow DW_FORM_addr.  */
> @@ -7449,7 +7750,8 @@
>         case DW_AT_high_pc:
>         case DW_AT_entry_pc:
>         case DW_AT_trampoline:
> -         return DW_FORM_addr;
> +          return (dwarf_split_debug_info && AT_index (a) != -1U
> +                 ? DW_FORM_GNU_addr_index : DW_FORM_addr);
>         default:
>           break;
>         }
> @@ -7565,7 +7867,8 @@
>      case dw_val_class_fde_ref:
>        return DW_FORM_data;
>      case dw_val_class_lbl_id:
> -      return DW_FORM_addr;
> +      return (dwarf_split_debug_info && AT_index (a) != -1U
> +             ? DW_FORM_GNU_addr_index : DW_FORM_addr);
>      case dw_val_class_lineptr:
>      case dw_val_class_macptr:
>        return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
> @@ -7613,6 +7916,36 @@
>    dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
>  }
>
> +/* Given a die and id, produce the appropriate abbreviations.  */
> +
> +static void
> +output_die_abbrevs (unsigned long abbrev_id, dw_die_ref abbrev)
> +{
> +  unsigned ix;
> +  dw_attr_ref a_attr;
> +
> +  dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
> +  dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
> +                               dwarf_tag_name (abbrev->die_tag));
> +
> +  if (abbrev->die_child != NULL)
> +    dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
> +  else
> +    dw2_asm_output_data (1, DW_children_no, "DW_children_no");
> +
> +  for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
> +       ix++)
> +    {
> +      dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
> +                                   dwarf_attr_name (a_attr->dw_attr));
> +      output_value_format (a_attr);
> +    }
> +
> +  dw2_asm_output_data (1, 0, NULL);
> +  dw2_asm_output_data (1, 0, NULL);
> +}
> +
> +
>  /* Output the .debug_abbrev section which defines the DIE abbreviation
>     table.  */
>
> @@ -7622,32 +7955,8 @@
>    unsigned long abbrev_id;
>
>    for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
> -    {
> -      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
> -      unsigned ix;
> -      dw_attr_ref a_attr;
> +    output_die_abbrevs (abbrev_id, abbrev_die_table[abbrev_id]);
>
> -      dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
> -      dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
> -                                  dwarf_tag_name (abbrev->die_tag));
> -
> -      if (abbrev->die_child != NULL)
> -       dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
> -      else
> -       dw2_asm_output_data (1, DW_children_no, "DW_children_no");
> -
> -      for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
> -          ix++)
> -       {
> -         dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
> -                                      dwarf_attr_name (a_attr->dw_attr));
> -         output_value_format (a_attr);
> -       }
> -
> -      dw2_asm_output_data (1, 0, NULL);
> -      dw2_asm_output_data (1, 0, NULL);
> -    }
> -
>    /* Terminate the table.  */
>    dw2_asm_output_data (1, 0, NULL);
>  }
> @@ -7683,6 +7992,7 @@
>    dw_loc_list_ref retlist = ggc_alloc_cleared_dw_loc_list_node ();
>
>    retlist->begin = begin;
> +  retlist->begin_index = -1U;
>    retlist->end = end;
>    retlist->expr = expr;
>    retlist->section = section;
> @@ -7727,7 +8037,22 @@
>          in a single range are unlikely very useful.  */
>        if (size > 0xffff)
>         continue;
> -      if (!have_multiple_function_sections)
> +      if (dwarf_split_debug_info)
> +        {
> +          dw2_asm_output_data (1, DW_LLE_GNU_start_length_entry,
> +                               "Location list start/length entry (%s)",
> +                               list_head->ll_symbol);
> +          dw2_asm_output_data_uleb128 (curr->begin_index,
> +                                       "Location list range start index (%s)",
> +                                       curr->begin);
> +          /* The length field is 4 bytes.  If we ever need to support
> +            an 8-byte length, we can add a new DW_LLE code or fall back
> +            to DW_LLE_GNU_start_end_entry.  */
> +          dw2_asm_output_delta (4, curr->end, curr->begin,
> +                               "Location list range length (%s)",
> +                               list_head->ll_symbol);
> +        }
> +      else if (!have_multiple_function_sections)
>         {
>           dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
>                                 "Location list begin address (%s)",
> @@ -7753,14 +8078,85 @@
>        output_loc_sequence (curr->expr, -1);
>      }
>
> -  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> -                      "Location list terminator begin (%s)",
> -                      list_head->ll_symbol);
> -  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> -                      "Location list terminator end (%s)",
> -                      list_head->ll_symbol);
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_data (1, DW_LLE_GNU_end_of_list_entry,
> +                        "Location list terminator (%s)",
> +                        list_head->ll_symbol);
> +  else
> +    {
> +      dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> +                          "Location list terminator begin (%s)",
> +                          list_head->ll_symbol);
> +      dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> +                          "Location list terminator end (%s)",
> +                          list_head->ll_symbol);
> +    }
>  }
>
> +/* Output the offset into the debug_range section.  */
> +
> +static void
> +output_range_list_offset (dw_attr_ref a)
> +{
> +  const char *name = dwarf_attr_name (a->dw_attr);
> +
> +  if (!dwarf_split_debug_info || AT_index (a) == -1U)
> +    {
> +      char *p = strchr (ranges_section_label, '\0');
> +      sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset);
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
> +                             debug_ranges_section, "%s", name);
> +      *p = '\0';
> +    }
> +  else
> +    dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
> +                         "%s (offset from %s)", name, ranges_section_label);
> +}
> +
> +/* Output the offset into the debug_loc section.  */
> +
> +static void
> +output_loc_list_offset (dw_attr_ref a)
> +{
> +  char *sym = AT_loc_list (a)->ll_symbol;
> +
> +  gcc_assert (sym);
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
> +                          "%s", dwarf_attr_name (a->dw_attr));
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
> +                           "%s", dwarf_attr_name (a->dw_attr));
> +}
> +
> +/* Output an attribute's index or value appropriately.  */
> +
> +static void
> +output_attr_index_or_value (dw_attr_ref a)
> +{
> +  const char *name = dwarf_attr_name (a->dw_attr);
> +
> +  if (dwarf_split_debug_info && AT_index (a) != -1U)
> +    {
> +      dw2_asm_output_data_uleb128 (AT_index (a), "%s", name);
> +      return;
> +    }
> +  switch (AT_class (a))
> +    {
> +      case dw_val_class_addr:
> +        dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
> +        break;
> +      case dw_val_class_lbl_id:
> +        dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
> +        break;
> +      case dw_val_class_loc_list:
> +        output_loc_list_offset (a);
> +        break;
> +      default:
> +        gcc_unreachable ();
> +    }
> +}
> +
>  /* Output a type signature.  */
>
>  static inline void
> @@ -7799,7 +8195,7 @@
>        switch (AT_class (a))
>         {
>         case dw_val_class_addr:
> -         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_offset:
> @@ -7808,15 +8204,7 @@
>           break;
>
>         case dw_val_class_range_list:
> -         {
> -           char *p = strchr (ranges_section_label, '\0');
> -
> -           sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
> -                    a->dw_attr_val.v.val_offset);
> -           dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
> -                                  debug_ranges_section, "%s", name);
> -           *p = '\0';
> -         }
> +          output_range_list_offset (a);
>           break;
>
>         case dw_val_class_loc:
> @@ -7872,7 +8260,7 @@
>               }
>
>             dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
> -                                first, name);
> +                                first, "%s", name);
>             dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
>                                  second, NULL);
>           }
> @@ -7919,13 +8307,7 @@
>           break;
>
>         case dw_val_class_loc_list:
> -         {
> -           char *sym = AT_loc_list (a)->ll_symbol;
> -
> -           gcc_assert (sym);
> -           dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
> -                                  "%s", name);
> -         }
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_die_ref:
> @@ -7982,7 +8364,7 @@
>           break;
>
>         case dw_val_class_lbl_id:
> -         dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_lineptr:
> @@ -7996,12 +8378,15 @@
>           break;
>
>         case dw_val_class_str:
> -         if (AT_string_form (a) == DW_FORM_strp)
> +         if (a->dw_attr_val.v.val_str->form == DW_FORM_strp)
>             dw2_asm_output_offset (DWARF_OFFSET_SIZE,
>                                    a->dw_attr_val.v.val_str->label,
>                                    debug_str_section,
>                                    "%s: \"%s\"", name, AT_string (a));
> -         else
> +         else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
> +            dw2_asm_output_data_uleb128 (AT_index (a),
> +                                         "%s: \"%s\"", name, AT_string (a));
> +          else
>             dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
>           break;
>
> @@ -8144,6 +8529,96 @@
>      add_AT_flag (die, DW_AT_GNU_pubnames, 1);
>  }
>
> +/* Helper function to generate top-level dies for skeleton debug_info and
> +   debug_types.  */
> +
> +static void
> +add_top_level_skeleton_die_attrs (dw_die_ref die)
> +{
> +  const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL);
> +  dw_attr_ref attr;
> +
> +  add_comp_dir_attribute (die);
> +  add_AT_string (die, DW_AT_GNU_dwo_name, dwo_file_name);
> +  /* The specification suggests that these attributes be inline to avoid
> +     having a .debug_str section.  We know that they exist in the die because
> +     we just added them.  */
> +  attr = get_AT (die, DW_AT_GNU_dwo_name);
> +  attr->dw_attr_val.v.val_str->form = DW_FORM_string;
> +  attr = get_AT (die, DW_AT_comp_dir);
> +  attr->dw_attr_val.v.val_str->form = DW_FORM_string;
> +
> +  add_AT_pubnames (die);
> +  add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label);
> +}
> +
> +/* Return the single type-unit die for skeleton type units.  */
> +
> +static dw_die_ref
> +get_skeleton_type_unit (void)
> +{
> +  /* For dwarf_split_debug_sections with use_type info, all type units in the
> +     skeleton sections have identical dies (but different headers).  This
> +     single die will be output many times.  */
> +
> +  static dw_die_ref skeleton_type_unit = NULL;
> +
> +  if (skeleton_type_unit == NULL)
> +    {
> +      skeleton_type_unit = new_die (DW_TAG_type_unit, NULL, NULL);
> +      add_top_level_skeleton_die_attrs (skeleton_type_unit);
> +      skeleton_type_unit->die_abbrev = SKELETON_TYPE_DIE_ABBREV;
> +    }
> +  return skeleton_type_unit;
> +}
> +
> +/* Output skeleton debug sections that point to the dwo file.  */
> +
> +static void
> +output_skeleton_debug_sections (dw_die_ref comp_unit)
> +{
> +  /* These attributes will be found in the full debug_info section.  */
> +  remove_AT (comp_unit, DW_AT_producer);
> +  remove_AT (comp_unit, DW_AT_language);
> +
> +  /* Add attributes common to skeleton compile_units and type_units.  */
> +  add_top_level_skeleton_die_attrs (comp_unit);
> +
> +  switch_to_section (debug_skeleton_info_section);
> +  ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_info_section_label);
> +
> +  /* Produce the skeleton compilation-unit header.  This one differs enough from
> +     a normal CU header that it's better not to call output_compilation_unit
> +     header.  */
> +  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
> +    dw2_asm_output_data (4, 0xffffffff,
> +      "Initial length escape value indicating 64-bit DWARF extension");
> +
> +  dw2_asm_output_data (DWARF_OFFSET_SIZE,
> +                      DWARF_COMPILE_UNIT_HEADER_SIZE
> +                       - DWARF_INITIAL_LENGTH_SIZE
> +                       + size_of_die (comp_unit),
> +                      "Length of Compilation Unit Info");
> +  dw2_asm_output_data (2, dwarf_version, "DWARF version number");
> +  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label,
> +                        debug_abbrev_section,
> +                        "Offset Into Abbrev. Section");
> +  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
> +
> +  comp_unit->die_abbrev = SKELETON_COMP_DIE_ABBREV;
> +  output_die (comp_unit);
> +
> +  /* Build the skeleton debug_abbrev section.  */
> +  switch_to_section (debug_skeleton_abbrev_section);
> +  ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_abbrev_section_label);
> +
> +  output_die_abbrevs (SKELETON_COMP_DIE_ABBREV, comp_unit);
> +  if (use_debug_types)
> +    output_die_abbrevs (SKELETON_TYPE_DIE_ABBREV, get_skeleton_type_unit ());
> +
> +  dw2_asm_output_data (1, 0, "end of skeleton .debug_abbrev");
> +}
> +
>  /* Output a comdat type unit DIE and its children.  */
>
>  static void
> @@ -8171,7 +8646,11 @@
>    calc_die_sizes (node->root_die);
>
>  #if defined (OBJECT_FORMAT_ELF)
> -  secname = ".debug_types";
> +  if (!dwarf_split_debug_info)
> +    secname = ".debug_types";
> +  else
> +    secname = ".debug_types.dwo";
> +
>    tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
>    sprintf (tmp, "wt.");
>    for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
> @@ -8180,6 +8659,7 @@
>    targetm.asm_out.named_section (secname,
>                                   SECTION_DEBUG | SECTION_LINKONCE,
>                                   comdat_key);
> +
>  #else
>    tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
>    sprintf (tmp, ".gnu.linkonce.wt.");
> @@ -8197,6 +8677,36 @@
>    output_die (node->root_die);
>
>    unmark_dies (node->root_die);
> +
> +  if (dwarf_split_debug_info)
> +    {
> +      /* Produce the skeleton type-unit header.  */
> +      const char *secname = ".debug_types";
> +
> +      targetm.asm_out.named_section (secname,
> +                                     SECTION_DEBUG | SECTION_LINKONCE,
> +                                     comdat_key);
> +      if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
> +        dw2_asm_output_data (4, 0xffffffff,
> +          "Initial length escape value indicating 64-bit DWARF extension");
> +
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE,
> +                           DWARF_COMPILE_UNIT_HEADER_SIZE
> +                           - DWARF_INITIAL_LENGTH_SIZE
> +                           + size_of_die (get_skeleton_type_unit ())
> +                           + DWARF_TYPE_SIGNATURE_SIZE + DWARF_OFFSET_SIZE,
> +                           "Length of Type Unit Info");
> +      dw2_asm_output_data (2, dwarf_version, "DWARF version number");
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE,
> +                             debug_skeleton_abbrev_section_label,
> +                             debug_abbrev_section,
> +                             "Offset Into Abbrev. Section");
> +      dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
> +      output_signature (node->signature, "Type Signature");
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "Offset to Type DIE");
> +
> +      output_die (get_skeleton_type_unit ());
> +    }
>  }
>
>  /* Return the DWARF2/3 pubname associated with a decl.  */
> @@ -8232,7 +8742,7 @@
>       class_member, it will either be inside the class already, or will have just
>       looked up the class to find the member.  Either way, searching the class is
>       faster than searching the index.  */
> -  if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent))
> +  if ((TREE_PUBLIC (decl) && !class_scope_p (die->die_parent))
>        || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
>      {
>        const char *name = dwarf2_name (decl, 1);
> @@ -8340,9 +8850,14 @@
>                          "Length of Public Type Names Info");
>    /* Version number for pubnames/pubtypes is still 2, even in DWARF3.  */
>    dw2_asm_output_data (2, 2, "DWARF Version");
> -  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> -                        debug_info_section,
> -                        "Offset of Compilation Unit Info");
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
> +                           debug_skeleton_info_section,
> +                           "Offset of Compilation Unit Info");
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> +                           debug_info_section,
> +                           "Offset of Compilation Unit Info");
>    dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
>                        "Compilation Unit Length");
>
> @@ -8403,9 +8918,14 @@
>                        "Length of Address Ranges Info");
>    /* Version number for aranges is still 2, even in DWARF3.  */
>    dw2_asm_output_data (2, 2, "DWARF Version");
> -  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> -                        debug_info_section,
> -                        "Offset of Compilation Unit Info");
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
> +                           debug_skeleton_info_section,
> +                           "Offset of Compilation Unit Info");
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> +                           debug_info_section,
> +                           "Offset of Compilation Unit Info");
>    dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
>    dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
>
> @@ -8502,12 +9022,13 @@
>    return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
>  }
>
> -/* Add a new entry to .debug_ranges corresponding to a pair of
> -   labels.  */
> +/* Add a new entry to .debug_ranges corresponding to a pair of labels.  The
> +   parameter force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static void
>  add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
> -                     bool *added)
> +                     bool *added, bool force_direct)
>  {
>    unsigned int in_use = ranges_by_label_in_use;
>    unsigned int offset;
> @@ -8530,7 +9051,7 @@
>    offset = add_ranges_num (-(int)in_use - 1);
>    if (!*added)
>      {
> -      add_AT_range_list (die, DW_AT_ranges, offset);
> +      add_AT_range_list (die, DW_AT_ranges, offset, force_direct);
>        *added = true;
>      }
>  }
> @@ -9067,7 +9588,7 @@
>     information goes into the .debug_line section.  */
>
>  static void
> -output_line_info (void)
> +output_line_info (bool prologue_only)
>  {
>    char l1[20], l2[20], p1[20], p2[20];
>    int ver = dwarf_version;
> @@ -9137,6 +9658,12 @@
>    /* Write out the information about the files we use.  */
>    output_file_names ();
>    ASM_OUTPUT_LABEL (asm_out_file, p2);
> +  if (prologue_only)
> +    {
> +      /* Output the marker for the end of the line number info.  */
> +      ASM_OUTPUT_LABEL (asm_out_file, l2);
> +      return;
> +    }
>
>    if (separate_line_info)
>      {
> @@ -11437,14 +11964,7 @@
>           if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
>             break;
>
> -         /* We used to emit DW_OP_addr here, but that's wrong, since
> -            DW_OP_addr should be relocated by the debug info consumer,
> -            while DW_OP_GNU_push_tls_address operand should not.  */
> -         temp = new_loc_descr (DWARF2_ADDR_SIZE == 4
> -                               ? DW_OP_const4u : DW_OP_const8u, 0, 0);
> -         temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         temp->dw_loc_oprnd1.v.val_addr = rtl;
> -         temp->dtprel = true;
> +          temp = new_addr_loc_descr (rtl, dtprel_true);
>
>           mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
>           add_loc_descr (&mem_loc_result, temp);
> @@ -11456,9 +11976,7 @@
>         break;
>
>      symref:
> -      mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -      mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +      mem_loc_result = new_addr_loc_descr (rtl, dtprel_false);
>        VEC_safe_push (rtx, gc, used_rtx_array, rtl);
>        break;
>
> @@ -12360,9 +12878,7 @@
>        if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
>           && (dwarf_version >= 4 || !dwarf_strict))
>         {
> -         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +         loc_result = new_addr_loc_descr (rtl, dtprel_false);
>           add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
>           VEC_safe_push (rtx, gc, used_rtx_array, rtl);
>         }
> @@ -13062,9 +13578,8 @@
>        if (DECL_THREAD_LOCAL_P (loc))
>         {
>           rtx rtl;
> -         enum dwarf_location_atom first_op;
> -         enum dwarf_location_atom second_op;
> -         bool dtprel = false;
> +         enum dwarf_location_atom tls_op;
> +         enum dtprel_bool dtprel = dtprel_false;
>
>           if (targetm.have_tls)
>             {
> @@ -13081,9 +13596,8 @@
>                   operand shouldn't be.  */
>               if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
>                 return 0;
> -             first_op = DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u;
> -             dtprel = true;
> -             second_op = DW_OP_GNU_push_tls_address;
> +             dtprel = dtprel_true;
> +             tls_op = DW_OP_GNU_push_tls_address;
>             }
>           else
>             {
> @@ -13095,8 +13609,7 @@
>                  no longer appear in gimple code.  We used the control
>                  variable in specific so that we could pick it up here.  */
>               loc = DECL_VALUE_EXPR (loc);
> -             first_op = DW_OP_addr;
> -             second_op = DW_OP_form_tls_address;
> +             tls_op = DW_OP_form_tls_address;
>             }
>
>           rtl = rtl_for_decl_location (loc);
> @@ -13109,12 +13622,8 @@
>           if (! CONSTANT_P (rtl))
>             return 0;
>
> -         ret = new_loc_descr (first_op, 0, 0);
> -         ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         ret->dw_loc_oprnd1.v.val_addr = rtl;
> -         ret->dtprel = dtprel;
> -
> -         ret1 = new_loc_descr (second_op, 0, 0);
> +          ret = new_addr_loc_descr (rtl, dtprel);
> +         ret1 = new_loc_descr (tls_op, 0, 0);
>           add_loc_descr (&ret, ret1);
>
>           have_address = 1;
> @@ -13159,11 +13668,7 @@
>             return 0;
>           }
>         else if (CONSTANT_P (rtl) && const_ok_for_output (rtl))
> -         {
> -           ret = new_loc_descr (DW_OP_addr, 0, 0);
> -           ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -           ret->dw_loc_oprnd1.v.val_addr = rtl;
> -         }
> +          ret = new_addr_loc_descr (rtl, dtprel_false);
>         else
>           {
>             enum machine_mode mode, mem_mode;
> @@ -14091,9 +14596,7 @@
>           dw_loc_descr_ref loc_result;
>           resolve_one_addr (&rtl, NULL);
>         rtl_addr:
> -         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +         loc_result = new_addr_loc_descr (rtl, dtprel_false);
>           add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
>           add_AT_loc (die, DW_AT_location, loc_result);
>           VEC_safe_push (rtx, gc, used_rtx_array, rtl);
> @@ -15611,7 +16114,7 @@
>    if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
>      {
>        add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
> -                  XEXP (DECL_RTL (decl), 0));
> +                  XEXP (DECL_RTL (decl), 0), false);
>        VEC_safe_push (rtx, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
>      }
>  #endif /* VMS_DEBUGGING_INFO */
> @@ -15632,7 +16135,7 @@
>    add_name_attribute (die, VMS_DEBUG_MAIN_POINTER);
>    ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
>                                current_function_funcdef_no);
> -  add_AT_lbl_id (die, DW_AT_entry_pc, label);
> +  add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
>
>    /* Make it the first child of comp_unit_die ().  */
>    die->die_parent = comp_unit_die ();
> @@ -16223,7 +16726,7 @@
>    if (DECL_ABSTRACT (decl))
>      equate_decl_number_to_die (decl, decl_die);
>    else
> -    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
> +    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl), false);
>  }
>  #endif
>
> @@ -16873,7 +17376,7 @@
>    if (stmt_die == NULL)
>      stmt_die = subr_die;
>    die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
> -  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
> +  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label, false);
>    if (ca_loc->tail_call_p)
>      add_AT_flag (die, DW_AT_GNU_tail_call, 1);
>    if (ca_loc->symbol_ref)
> @@ -16882,7 +17385,7 @@
>        if (tdie)
>         add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
>        else
> -       add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref);
> +       add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref, false);
>      }
>    return die;
>  }
> @@ -17073,7 +17576,8 @@
>           if (fde->dw_fde_begin)
>             {
>               /* We have already generated the labels.  */
> -             add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end);
> +             add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
> +                                 fde->dw_fde_end, false);
>             }
>           else
>             {
> @@ -17084,7 +17588,8 @@
>                                            current_function_funcdef_no);
>               ASM_GENERATE_INTERNAL_LABEL (label_id_high, FUNC_END_LABEL,
>                                            current_function_funcdef_no);
> -             add_AT_low_high_pc (subr_die, label_id_low, label_id_high);
> +             add_AT_low_high_pc (subr_die, label_id_low, label_id_high,
> +                                 false);
>             }
>
>  #if VMS_DEBUGGING_INFO
> @@ -17127,10 +17632,11 @@
>                      alignment offset.  */
>                   bool range_list_added = false;
>                   add_ranges_by_labels (subr_die, fde->dw_fde_begin,
> -                                       fde->dw_fde_end, &range_list_added);
> +                                       fde->dw_fde_end, &range_list_added,
> +                                       false);
>                   add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
>                                         fde->dw_fde_second_end,
> -                                       &range_list_added);
> +                                       &range_list_added, false);
>                   if (range_list_added)
>                     add_ranges (NULL);
>                 }
> @@ -17149,7 +17655,7 @@
>
>                   /* Do the 'primary' section.   */
>                   add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
> -                                     fde->dw_fde_end);
> +                                     fde->dw_fde_end, false);
>
>                   /* Build a minimal DIE for the secondary section.  */
>                   seg_die = new_die (DW_TAG_subprogram,
> @@ -17174,14 +17680,15 @@
>
>                   name = concat ("__second_sect_of_", name, NULL);
>                   add_AT_low_high_pc (seg_die, fde->dw_fde_second_begin,
> -                                     fde->dw_fde_second_end);
> +                                     fde->dw_fde_second_end, false);
>                   add_name_attribute (seg_die, name);
>                   if (want_pubnames ())
>                     add_pubname_string (name, seg_die);
>                 }
>             }
>           else
> -           add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end);
> +           add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end,
> +                               false);
>         }
>
>        cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
> @@ -17622,7 +18129,7 @@
>             {
>               /* Optimize the common case.  */
>               if (single_element_loc_list_p (loc)
> -                 && loc->expr->dw_loc_opc == DW_OP_addr
> +                  && loc->expr->dw_loc_opc == DW_OP_addr
>                   && loc->expr->dw_loc_next == NULL
>                   && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
>                 {
> @@ -17809,7 +18316,7 @@
>           gcc_assert (!INSN_DELETED_P (insn));
>
>           ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
> -         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
> +         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
>         }
>        else if (insn
>                && NOTE_P (insn)
> @@ -17817,7 +18324,7 @@
>                && CODE_LABEL_NUMBER (insn) != -1)
>         {
>           ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn));
> -         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
> +         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
>         }
>      }
>  }
> @@ -17858,7 +18365,7 @@
>         {
>           ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
>                                        BLOCK_NUMBER (stmt));
> -         add_AT_lbl_id (die, DW_AT_entry_pc, label);
> +         add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
>         }
>
>        /* Optimize duplicate .debug_ranges lists or even tails of
> @@ -17906,12 +18413,13 @@
>             ++thiscnt;
>           gcc_assert (supercnt >= thiscnt);
>           add_AT_range_list (die, DW_AT_ranges,
> -                            (off + supercnt - thiscnt)
> -                            * 2 * DWARF2_ADDR_SIZE);
> +                            ((off + supercnt - thiscnt)
> +                             * 2 * DWARF2_ADDR_SIZE),
> +                            false);
>           return;
>         }
>
> -      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
> +      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt), false);
>
>        chain = BLOCK_FRAGMENT_CHAIN (stmt);
>        do
> @@ -17929,7 +18437,7 @@
>                                    BLOCK_NUMBER (stmt));
>        ASM_GENERATE_INTERNAL_LABEL (label_high, BLOCK_END_LABEL,
>                                    BLOCK_NUMBER (stmt));
> -      add_AT_low_high_pc (die, label, label_high);
> +      add_AT_low_high_pc (die, label, label_high, false);
>      }
>  }
>
> @@ -20518,13 +21026,12 @@
>      case DW_MACRO_GNU_define_indirect:
>      case DW_MACRO_GNU_undef_indirect:
>        node = find_AT_string (ref->info);
> -      if (node->form != DW_FORM_strp)
> +      if ((node->form != DW_FORM_string)
> +          && (node->form != DW_FORM_GNU_str_index))
>         {
>           char label[32];
>           ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
> -         ++dw2_string_counter;
> -         node->label = xstrdup (label);
> -         node->form = DW_FORM_strp;
> +          add_indirect_string (node, label);
>         }
>        dw2_asm_output_data (1, ref->code,
>                            ref->code == DW_MACRO_GNU_define_indirect
> @@ -20705,8 +21212,10 @@
>         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, debug_line_section_label,
> -                            debug_line_section, NULL);
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE,
> +                             (!dwarf_split_debug_info ? debug_line_section_label
> +                              : debug_skeleton_line_section_label),
> +                             debug_line_section, NULL);
>      }
>
>    /* In the first loop, it emits the primary .debug_macinfo section
> @@ -20845,26 +21354,60 @@
>
>    used_rtx_array = VEC_alloc (rtx, gc, 32);
>
> -  debug_info_section = get_section (DEBUG_INFO_SECTION,
> -                                   SECTION_DEBUG, NULL);
> -  debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
> -                                     SECTION_DEBUG, NULL);
> +  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_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_aranges_section = get_section (DEBUG_ARANGES_SECTION,
>                                        SECTION_DEBUG, NULL);
>    debug_macinfo_section = get_section (dwarf_strict
>                                        ? DEBUG_MACINFO_SECTION
>                                        : DEBUG_MACRO_SECTION,
> -                                      SECTION_DEBUG, NULL);
> +                                      DEBUG_MACRO_SECTION_FLAGS, NULL);
>    debug_line_section = get_section (DEBUG_LINE_SECTION,
>                                     SECTION_DEBUG, NULL);
> -  debug_loc_section = get_section (DEBUG_LOC_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_STR_SECTION_FLAGS, NULL);
>    debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
>                                       SECTION_DEBUG, NULL);
>    debug_frame_section = get_section (DEBUG_FRAME_SECTION,
> @@ -20884,10 +21427,13 @@
>                                DEBUG_LINE_SECTION_LABEL, 0);
>    ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
>                                DEBUG_RANGES_SECTION_LABEL, 0);
> +  ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
> +                              DEBUG_ADDR_SECTION_LABEL, 0);
>    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);
>
>    if (debug_info_level >= DINFO_LEVEL_VERBOSE)
>      macinfo_table = VEC_alloc (macinfo_entry, gc, 64);
> @@ -20931,6 +21477,83 @@
>    return 1;
>  }
>
> +/* Output the indexed string table.  */
> +
> +static void
> +output_index_strings (void)
> +{
> +  unsigned int i;
> +  unsigned int len = 0;
> +  struct indirect_string_node *node;
> +
> +  gcc_assert (dwarf_split_debug_info);
> +
> +  if (VEC_empty (indirect_string_node, index_string_table))
> +    return;
> +
> +  switch_to_section (debug_str_offsets_section);
> +  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
> +       i++)
> +    {
> +      gcc_assert (node->form == DW_FORM_GNU_str_index);
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE, len,
> +                           "indexed string 0x%x: %s", i, node->str);
> +      len += strlen (node->str) + 1;
> +    }
> +  switch_to_section (debug_str_section);
> +  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
> +       i++)
> +    {
> +      ASM_OUTPUT_LABEL (asm_out_file, node->label);
> +      assemble_string (node->str, strlen (node->str) + 1);
> +    }
> +}
> +
> +/* Write the index table.  */
> +
> +static void
> +output_addr_table (void)
> +{
> +  unsigned int i;
> +  dw_attr_node *node;
> +
> +  if (VEC_empty (dw_attr_node, addr_index_table))
> +    return;
> +
> +  switch_to_section (debug_addr_section);
> +  for (i = 0; VEC_iterate (dw_attr_node, addr_index_table, i, node); i++)
> +    {
> +      const char *name;
> +
> +      if (node->dw_attr == 0)
> +       {
> +         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, "<Removed entry>");
> +         continue;
> +       }
> +
> +      name = dwarf_attr_name (node->dw_attr);
> +      switch (AT_class (node))
> +        {
> +          case dw_val_class_addr:
> +            dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (node),
> +                                     "%s", name);
> +            break;
> +          case dw_val_class_loc:
> +            gcc_assert (targetm.asm_out.output_dwarf_dtprel);
> +            targetm.asm_out.output_dwarf_dtprel (asm_out_file,
> +                                                 DWARF2_ADDR_SIZE,
> +                                                 node->dw_attr_val.v.val_addr);
> +            fputc ('\n', asm_out_file);
> +            break;
> +          case dw_val_class_lbl_id:
> +            dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (node), "%s", name);
> +            break;
> +          default:
> +            gcc_unreachable ();
> +        }
> +    }
> +}
> +
>  #if ENABLE_ASSERT_CHECKING
>  /* Verify that all marks are clear.  */
>
> @@ -21537,6 +22160,17 @@
>         if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
>           return false;
>         break;
> +      case DW_OP_GNU_addr_index:
> +      case DW_OP_GNU_const_index:
> +        {
> +          unsigned int idx = loc->dw_loc_oprnd1.val_index;
> +          dw_attr_node *node = &VEC_index (dw_attr_node, addr_index_table, idx);
> +          if ((loc->dw_loc_opc == DW_OP_GNU_addr_index
> +               || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
> +              && resolve_one_addr (&node->dw_attr_val.v.val_addr, NULL))
> +            return false;
> +        }
> +       break;
>        case DW_OP_const4u:
>        case DW_OP_const8u:
>         if (loc->dtprel
> @@ -21671,11 +22305,15 @@
>                 if (!resolve_addr_in_expr ((*curr)->expr))
>                   {
>                     dw_loc_list_ref next = (*curr)->dw_loc_next;
> +                   dw_loc_descr_ref l = (*curr)->expr;
> +
>                     if (next && (*curr)->ll_symbol)
>                       {
>                         gcc_assert (!next->ll_symbol);
>                         next->ll_symbol = (*curr)->ll_symbol;
>                       }
> +                   if (dwarf_split_debug_info)
> +                     remove_loc_list_addr_table_entries (l);
>                     *curr = next;
>                   }
>                 else
> @@ -21689,6 +22327,8 @@
>             else
>               {
>                 loc->replaced = 1;
> +                if (dwarf_split_debug_info)
> +                  remove_loc_list_addr_table_entries (loc->expr);
>                 loc->dw_loc_next = *start;
>               }
>           }
> @@ -21713,6 +22353,8 @@
>                || l->dw_loc_next != NULL)
>               && !resolve_addr_in_expr (l))
>             {
> +             if (dwarf_split_debug_info)
> +               remove_loc_list_addr_table_entries (l);
>               remove_AT (die, a->dw_attr);
>               ix--;
>             }
> @@ -21724,6 +22366,8 @@
>         if (a->dw_attr == DW_AT_const_value
>             && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL))
>           {
> +           if (AT_index (a) != -1U)
> +             remove_addr_table_entry (AT_index (a));
>             remove_AT (die, a->dw_attr);
>             ix--;
>           }
> @@ -21747,6 +22391,8 @@
>               }
>             else
>               {
> +               if (AT_index (a) != -1U)
> +                 remove_addr_table_entry (AT_index (a));
>                 remove_AT (die, a->dw_attr);
>                 ix--;
>               }
> @@ -21880,6 +22526,19 @@
>         }
>        hash = iterative_hash_rtx (val1->v.val_addr, hash);
>        break;
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      {
> +        dw_attr_ref attr = &VEC_index (dw_attr_node, addr_index_table,
> +                                      val1->val_index);
> +        if (loc->dtprel)
> +         {
> +            unsigned char dtprel = 0xd1;
> +            hash = iterative_hash_object (dtprel, hash);
> +          }
> +        hash = iterative_hash_rtx (attr->dw_attr_val.v.val_addr, hash);
> +      }
> +      break;
>      case DW_OP_GNU_implicit_pointer:
>        hash = iterative_hash_object (val2->v.val_int, hash);
>        break;
> @@ -22061,9 +22720,12 @@
>        return valx1->v.val_int == valy1->v.val_int;
>      case DW_OP_skip:
>      case DW_OP_bra:
> +      /* If splitting debug info, the use of DW_OP_GNU_addr_index
> +        can cause irrelevant differences in dw_loc_addr.  */
>        gcc_assert (valx1->val_class == dw_val_class_loc
>                   && valy1->val_class == dw_val_class_loc
> -                 && x->dw_loc_addr == y->dw_loc_addr);
> +                 && (dwarf_split_debug_info
> +                     || x->dw_loc_addr == y->dw_loc_addr));
>        return valx1->v.val_loc->dw_loc_addr == valy1->v.val_loc->dw_loc_addr;
>      case DW_OP_implicit_value:
>        if (valx1->v.val_unsigned != valy1->v.val_unsigned
> @@ -22094,6 +22756,18 @@
>      case DW_OP_addr:
>      hash_addr:
>        return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr);
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      {
> +        dw_attr_node *attrx1 = &VEC_index (dw_attr_node,
> +                                           addr_index_table,
> +                                           valx1->val_index);
> +        dw_attr_node *attry1 = &VEC_index (dw_attr_node,
> +                                           addr_index_table,
> +                                           valy1->val_index);
> +        return rtx_equal_p (attrx1->dw_attr_val.v.val_addr,
> +                            attry1->dw_attr_val.v.val_addr);
> +      }
>      case DW_OP_GNU_implicit_pointer:
>        return valx1->val_class == dw_val_class_die_ref
>              && valx1->val_class == valy1->val_class
> @@ -22207,7 +22881,7 @@
>         if (*slot == NULL)
>           *slot = (void *) list;
>         else
> -         a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
> +          a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
>        }
>
>    FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab));
> @@ -22223,6 +22897,43 @@
>    optimize_location_lists_1 (die, htab);
>    htab_delete (htab);
>  }
> +
> +
> +/* Recursively assign each location list a unique index into the debug_addr
> +   section.  */
> +
> +static void
> +index_location_lists (dw_die_ref die)
> +{
> +  dw_die_ref c;
> +  dw_attr_ref a;
> +  unsigned ix;
> +
> +  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
> +    if (AT_class (a) == dw_val_class_loc_list)
> +      {
> +        dw_loc_list_ref list = AT_loc_list (a);
> +        dw_loc_list_ref curr;
> +        for (curr = list; curr != NULL; curr = curr->dw_loc_next)
> +          {
> +            dw_attr_node attr;
> +
> +            /* Don't index an entry that has already been indexed
> +              or won't be output.  */
> +            if (curr->begin_index != -1U
> +               || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
> +             continue;
> +
> +            attr.dw_attr = DW_AT_location;
> +            attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +            attr.dw_attr_val.val_index = -1U;
> +            attr.dw_attr_val.v.val_lbl_id = xstrdup (curr->begin);
> +            curr->begin_index = add_addr_table_entry (&attr);
> +          }
> +      }
> +
> +  FOR_EACH_CHILD (die, c, index_location_lists (c));
> +}
>
>  /* Output stuff that dwarf requires at the end of every file,
>     and generate the DWARF-2 debugging info.  */
> @@ -22234,6 +22945,7 @@
>    comdat_type_node *ctnode;
>    htab_t comdat_type_table;
>    unsigned int i;
> +  dw_die_ref main_comp_unit_die;
>
>    /* PCH might result in DW_AT_producer string being restored from the
>       header compilation, fix it up if needed.  */
> @@ -22386,6 +23098,14 @@
>    for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
>      add_sibling_attributes (ctnode->root_die);
>
> +  /* When splitting DWARF info, we put some attributes in the
> +     skeleton compile_unit DIE that remains in the .o, while
> +     most attributes go in the DWO compile_unit_die.  */
> +  if (dwarf_split_debug_info)
> +    main_comp_unit_die = gen_compile_unit_die (NULL);
> +  else
> +    main_comp_unit_die = comp_unit_die ();
> +
>    /* Output a terminator label for the .text section.  */
>    switch_to_section (text_section);
>    targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
> @@ -22402,8 +23122,8 @@
>      {
>        /* Don't add if the CU has no associated code.  */
>        if (text_section_used)
> -       add_AT_low_high_pc (comp_unit_die (), text_section_label,
> -                           text_end_label);
> +       add_AT_low_high_pc (main_comp_unit_die, text_section_label,
> +                           text_end_label, true);
>      }
>    else
>      {
> @@ -22412,22 +23132,24 @@
>        bool range_list_added = false;
>
>        if (text_section_used)
> -       add_ranges_by_labels (comp_unit_die (), text_section_label,
> -                             text_end_label, &range_list_added);
> +       add_ranges_by_labels (main_comp_unit_die, text_section_label,
> +                             text_end_label, &range_list_added, true);
>        if (cold_text_section_used)
> -       add_ranges_by_labels (comp_unit_die (), cold_text_section_label,
> -                             cold_end_label, &range_list_added);
> +       add_ranges_by_labels (main_comp_unit_die, cold_text_section_label,
> +                             cold_end_label, &range_list_added, true);
>
>        FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde)
>         {
>           if (DECL_IGNORED_P (fde->decl))
>             continue;
>           if (!fde->in_std_section)
> -           add_ranges_by_labels (comp_unit_die (), fde->dw_fde_begin,
> -                                 fde->dw_fde_end, &range_list_added);
> +           add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_begin,
> +                                 fde->dw_fde_end, &range_list_added,
> +                                 true);
>           if (fde->dw_fde_second_begin && !fde->second_in_std_section)
> -           add_ranges_by_labels (comp_unit_die (), fde->dw_fde_second_begin,
> -                                 fde->dw_fde_second_end, &range_list_added);
> +           add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_second_begin,
> +                                 fde->dw_fde_second_end, &range_list_added,
> +                                 true);
>         }
>
>        if (range_list_added)
> @@ -22437,16 +23159,16 @@
>              absolute.  Historically, we've emitted the unexpected
>              DW_AT_entry_pc instead of DW_AT_low_pc for this purpose.
>              Emit both to give time for other tools to adapt.  */
> -         add_AT_addr (comp_unit_die (), DW_AT_low_pc, const0_rtx);
> +         add_AT_addr (main_comp_unit_die, DW_AT_low_pc, const0_rtx, true);
>           if (! dwarf_strict && dwarf_version < 4)
> -           add_AT_addr (comp_unit_die (), DW_AT_entry_pc, const0_rtx);
> +           add_AT_addr (main_comp_unit_die, DW_AT_entry_pc, const0_rtx, true);
>
>           add_ranges (NULL);
>         }
>      }
>
>    if (debug_info_level >= DINFO_LEVEL_NORMAL)
> -    add_AT_lineptr (comp_unit_die (), DW_AT_stmt_list,
> +    add_AT_lineptr (main_comp_unit_die, DW_AT_stmt_list,
>                     debug_line_section_label);
>
>    if (have_macinfo)
> @@ -22455,7 +23177,11 @@
>                    macinfo_section_label);
>
>    if (have_location_lists)
> -    optimize_location_lists (comp_unit_die ());
> +    {
> +      optimize_location_lists (comp_unit_die ());
> +      if (dwarf_split_debug_info)
> +        index_location_lists (comp_unit_die ());
> +    }
>
>    /* Output all of the compilation units.  We put the main one last so that
>       the offsets are available to output_pubnames.  */
> @@ -22476,19 +23202,54 @@
>           attributes.  */
>        if (debug_info_level >= DINFO_LEVEL_NORMAL)
>          add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
> -                       debug_line_section_label);
> +                        (!dwarf_split_debug_info
> +                         ? debug_line_section_label
> +                         : debug_skeleton_line_section_label));
>
>        output_comdat_type_unit (ctnode);
>        *slot = ctnode;
>      }
>    htab_delete (comdat_type_table);
>
> -  add_AT_pubnames (comp_unit_die ());
> +  /* 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 ());
>
> +  if (dwarf_split_debug_info)
> +    {
> +      int mark;
> +      unsigned char checksum[16];
> +      struct md5_ctx ctx;
> +
> +      /* Compute a checksum of the comp_unit to use as the dwo_id.  */
> +      md5_init_ctx (&ctx);
> +      mark = 0;
> +      die_checksum (comp_unit_die (), &ctx, &mark);
> +      unmark_all_dies (comp_unit_die ());
> +      md5_finish_ctx (&ctx, checksum);
> +
> +      /* Use the first 8 bytes of the checksum as the dwo_id,
> +        and add it to both comp-unit DIEs.  */
> +      add_AT_data8 (main_comp_unit_die, DW_AT_GNU_dwo_id, checksum);
> +      add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, checksum);
> +
> +      /* Add the base offset of the ranges table to the skeleton
> +        comp-unit DIE.  */
> +      if (ranges_table_in_use)
> +       add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base,
> +                       ranges_section_label);
> +    }
> +
>    /* Output the main compilation unit if non-empty or if .debug_macinfo
>       or .debug_macro will be emitted.  */
>    output_comp_unit (comp_unit_die (), have_macinfo);
>
> +  if (dwarf_split_debug_info && info_section_emitted)
> +    output_skeleton_debug_sections (main_comp_unit_die);
> +
>    /* Output the abbreviation table.  */
>    if (abbrev_die_table_in_use != 1)
>      {
> @@ -22502,8 +23263,6 @@
>      {
>        /* Output the location lists info.  */
>        switch_to_section (debug_loc_section);
> -      ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
> -                                  DEBUG_LOC_SECTION_LABEL, 0);
>        ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
>        output_location_lists (comp_unit_die ());
>      }
> @@ -22554,10 +23313,22 @@
>    switch_to_section (debug_line_section);
>    ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
>    if (! DWARF2_ASM_LINE_DEBUG_INFO)
> -    output_line_info ();
> +    output_line_info (false);
>
> -  /* If we emitted any DW_FORM_strp form attribute, output the string
> -     table too.  */
> +  if (dwarf_split_debug_info && info_section_emitted)
> +    {
> +      switch_to_section (debug_skeleton_line_section);
> +      ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
> +      output_line_info (true);
> +
> +      output_index_strings ();
> +
> +      switch_to_section (debug_addr_section);
> +      ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label);
> +      output_addr_table ();
> +    }
> +
> +  /* If we emitted any indirect strings, output the string table too.  */
>    if (debug_str_hash)
>      htab_traverse (debug_str_hash, output_indirect_string, NULL);
>  }
> Index: gcc/dwarf2out.h
> ===================================================================
> --- gcc/dwarf2out.h     (revision 190603)
> +++ gcc/dwarf2out.h     (working copy)
> @@ -172,6 +172,7 @@
>
>  typedef struct GTY(()) dw_val_struct {
>    enum dw_val_class val_class;
> +  unsigned int val_index;
>    union dw_val_struct_union
>      {
>        rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
> Index: gcc/opts.c
> ===================================================================
> --- gcc/opts.c  (revision 190603)
> +++ gcc/opts.c  (working copy)
> @@ -829,9 +829,14 @@
>    if (opts->x_warn_unused_but_set_parameter == -1)
>      opts->x_warn_unused_but_set_parameter = (opts->x_warn_unused
>                                              && opts->x_extra_warnings);
> +
>    /* Wunused-local-typedefs is enabled by -Wunused or -Wall.  */
>    if (opts->x_warn_unused_local_typedefs == -1)
>      opts->x_warn_unused_local_typedefs = opts->x_warn_unused;
> +
> +  /* The -gsplit-dwarf option requires -gpubnames.  */
> +  if (opts->x_dwarf_split_debug_info)
> +    opts->x_debug_generate_pub_sections = 1;
>  }
>
>  #define LEFT_COLUMN    27
> @@ -1692,6 +1697,13 @@
>        set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc);
>        break;
>
> +    case OPT_gsplit_dwarf:
> +      if (opts->x_dwarf_version < 4)
> +        opts->x_dwarf_version = 4;
> +      set_debug_level (DWARF2_DEBUG, DEFAULT_GDB_EXTENSIONS, "", opts, opts_set,
> +                      loc);
> +      break;
> +
>      case OPT_ggdb:
>        set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc);
>        break;
> Index: gcc/common.opt
> ===================================================================
> --- gcc/common.opt      (revision 190603)
> +++ gcc/common.opt      (working copy)
> @@ -2282,6 +2282,20 @@
>  Common RejectNegative Var(dwarf_record_gcc_switches,1)
>  Record gcc command line switches in DWARF DW_AT_producer.
>
> +gno-split-dwarf
> +Common Driver RejectNegative Var(dwarf_split_debug_info,0) Init(0)
> +Don't generate debug information in separate .dwo files
> +
> +gsplit-dwarf
> +Common Driver RejectNegative Var(dwarf_split_debug_info,1)
> +Generate debug information in separate .dwo files
> +
>  gstabs
>  Common JoinedOrMissing Negative(gstabs+)
>  Generate debug information in STABS format
>
> --
> This patch is available for review at http://codereview.appspot.com/6305113
Sterling Augustine - Sept. 13, 2012, 10:38 p.m.
On Mon, Aug 27, 2012 at 11:00 AM, Sterling Augustine
<saugustine@google.com> wrote:
> The enclosed patch to implment -gsplit-dwarf addresses Jason's comments as
> responded to by myself and Cary.
>
> In particular, it:
>
> 1. Adds comments for force_direct and its use
> 2. Corrects the location of is_unit_die
> 3. Makes -gsplit-dwarf imply -gdwarf-4
> 4. Changes DW_LLE_* to DW_LLE_GNU_*
> 5. Fixes various comments
> 6. Adds a new enum to cleanup dtprel and the associated logic
> 7. Fixes the FIXME in output_macinfo_op
>
> However, it does not:
>
> 1. Cleanup redundant entries in the .debug_addr--Cary has a patch in progress
>    that handles this situation.
>
>    http://codereview.appspot.com/6305113/#msg6 has more discussion.
>
> 2. Defer assigning indices to DW_GNU_addr_index entries until output time. We
>    see this less than 0.1 percent of the time, and fixing it would require
>    a major restructuring of when the size of debug entries are calculated as
>    opposed to when they are emitted.  Further, Cary's forthcoming patch in is
>    likely to reduce this count even further.
>
>
> The line length issues were not real, as a unified diff adds two spaces to
> the line, and a script that doesn't account for that will reject 79 and 80
> character line lengths.
>
>
> Hopefully this addresses all remaining issues. OK for mainline?
>
> Sterling and Cary
>
>
> include/ChangeLog
>
> 2012-08-24  Sterling Augustine <saugustine@google.com>
>             Cary Coutant <ccoutant@google.com>
>
>         * dwarf2.def: Fix comment.
>         * dwarf2.h (dwarf_location_list_entry_type): New enum with members
>         DW_LLE_GNU_end_of_list_entry, DW_LLE_GNU_case_address_selection_entry,
>         DW_LLE_GNU_start_end_entry, DW_LLE_GNU_start_length_entry.
>
> gcc/ChangeLog
>
> 2012-08-24  Sterling Augustine <saugustine@google.com>
>             Cary Coutant <ccoutant@google.com>
>
>         * common.opt (gno-split-dwarf, gsplit-dwarf): New switches.
>         * doc/invoke.texi (Debugging Options): Document them.
>         * dwarf2out.h (dw_val_struct): New field val_index.
>         * dwarf2out.c (debug_skeleton_info_section,
>         debug_skeleton_abbrev_section, debug_addr_section,
>         debug_skeleton_line_section, debug_str_offsets_section): New sections.
>         (indirect_string_node): Add index field.
>         (dw_loc_list_node): Add begin_index field.
>         (dw_addr_op, new_addr_loc_descr, AT_index, set_AT_index,
>         add_addr_table_entry, remove_addr_table_entry, output_range_list_offset,
>         output_loc_list_offset, output_attr_index_or_value,
>         remove_loc_list_addr_table_entries, output_die_abbrevs,
>         add_top_level_skeleton_die_attrs, get_skeleton_type_unit,
>         output_skeleton_debug_sections, output_index_strings,
>         output_addr_table, index_location_lists, add_indirect_string): New
>         functions.
>         (DEBUG_DWO_INFO_SECTION, DEBUG_DWO_ABBREV_SECTION, DEBUG_ADDR_SECTION,
>         DEBUG_NORM_MACINFO_SECTION, DEBUG_DWO_MACINFO_SECTION,
>         DEBUG_DWO_LINE_SECTION, DEBUG_DWO_LOC_SECTION,
>         DEBUG_NORM_STR_OFFSETS_SECTION, DEBUG_DWO_STR_SECTION,
>         DEBUG_MACRO_SECTION_FLAGS, DEBUG_SKELETON_LINE_SECTION_LABEL,
>         DEBUG_SKELETON_INFO_SECTION_LABEL, DEBUG_SKELETON_ABBREV_SECTION_LABEL,
>         DEBUG_ADDR_SECTIN_LABEL, SKELETON_COMP_DIE_ABBREV,
>         SKELETON_TYPE_DIE_ABBREV): New defines.
>         (DEBUG_MACINFO_SECTION, DEBUG_MACRO_SECTION, DEBUG_STR_SECTION
>         DEBUG_STR_SECTION_FLAGS): Adjust definitions.
>         (TEXT_SECTION_LABEL, COLD_TEXT_SECTION_LABEL, DEBUG_INFO_SECTION_LABEL,
>         DEBUG_ABBREV_SECTION_LABEL, DEBUG_LOC_SECTION_LABEL,
>         DEBUG_RANGES_SECTION_LABEL, DEBUG_MACINFO_SECTION_LABEL,
>         DEBUG_MACRO_SECTION_LABEL): Adjust indentation.
>         (debug_skeleton_info_section_label, debug_skeleton_abbrev_section_label,
>         debug_addr_section_label, debug_skeleton_line_section_label,
>         dw_id_placeholder): New global variables.
>         (add_AT_lbl_id, add_AT_low_high_pc): Add force_direct parameter.
>         Adjust calls throughout file.  Handle dwarf_split_debug_info.
>         (add_AT_addr). Likewise.  Initialize val_index_field.
>         (add_AT_range_list): Add force parameter.  Adjust calls throughout file.
>         Initialize val_index field.
>         (add_ranges_by_labels): Add and handle force_direct parameter.  Adjust
>         calls throughout file.
>         (size_of_die): New variable form.  Handle dwarf_split_debug_info and
>         call AT_index.
>         (value_format): Use AT_class instead of calling val_class directly.
>         Handle DW_FORM_addr and dw_val_class_lbl_id appropriately for
>         dwarf_split_debug_info and AT_index.
>         (output_abbrev_section): Move most code to new function
>         output_die_abbrevs.
>         (output_loc_list): Handle dwarf_split_debug_info by using
>         DW_LLE_start_length_entry and DW_LLE_end_of_list_entry.
>         (output_die): Call output_attr_index_or_value, output_range_list_offset,
>         Fix format string.  Check val_str->form directly to avoid side effect.
>         (add_pubtype): Fix indention.
>         (output_comdat_type_unit): Handle dwarf_split_debug_info.
>         (output_pubnames): Likewise.
>         (output_aranges): Likewise.
>         (output_mac_info): Likewise.
>         (output_mac_info_op): Check for DW_FORM_GNU_str_index.  Call
>         add_indirect_string.
>         (output_line_info): New parameter prologue_only.  Adjust calls
>         throughout file.
>         (dtprel_bool, dtprel_false, dtprel_true): New enum and enumerators.
>         (mem_loc_descriptor): Call new_addr_loc_descr.
>         (loc_descriptor): Likewise.
>         (add_const_value_attribute): Likewise.
>         (loc_list_from_tree): Replace first_op and second_op with tls_op.
>         Update associated logic.  Call new_addr_loc_descr.
>         (dwarf2out_init): Handle dwarf_split_debug_info.  Initialize
>         debug_skeleton_info_section, debug_skeleton_abbrev_section,
>         debug_addr_section, debug_skeleton_line_section,
>         debug_str_offsets_section, debug_skeleton_info_section_label,
>         debug_skeleton_abbrev_section_label, debug_addr_section_label and
>         debug_skeleton_line_section_label.  Use DEBUG_MACRO_SECTION_FLAGS.
>         (new_loc_descr, build_cfa_loc, add_AT_flag, add_AT_int, add_AT_unsigned,
>         add_AT_double, add_AT_vec, add_AT_data8, add_AT_string, add_AT_die_ref,
>         add_AT_fde_ref, add_AT_loc, add_AT_loc_list, add_AT_file,
>         add_AT_vms_delta, add_AT_lineptr, add_AT_macptr, add_AT_offset):
>         Initialize val_index field.
>         (size_of_loc_descr, output_loc_operands, output_loc_operands_raw,
>         resolve_addr_in_expression, hash_loc_operands): Handle
>         DW_OP_GNU_addr_index and DW_OP_GNU_const_index.
>         (compare_loc_operands):  Likewise.  Adjust assertion.
>         (AT_string_form): Call set_AT_index and add_indirect_string.
>         (resolve_addr): New local variable l.  Check val_index.  Call
>         remove_addr_table_entry and remove_loc_list_addr_table_entries.
>         (dwarf2out_finish): Handle dwarf_split_debug_info.  New variable
>         main_comp_unit_die.  Call index_location_lists, add_AT_data8,
>         add_AT_lineptr, output_skeleton_debug_sections, output_addr_table.  Move
>         call to ASM_GENERATE_INTERNAL_LABEL to dwarf2out_init.  Call
>         ASM_OUTPUT_LABEL for debug_skeleton_line_section_label and
>         debug_addr_section_label.  Adjust comment.
>         * gcc.c (replace_extension_spec_func):  New function.
>         (ASM_FINAL_SPEC): Adjust.
>         (static_spec_functions): Add new field for replace-extension.
>         (check_live_switch): Adjust comment.  Add case for 'g'.
>         * opts.c (finish_options): Set x_debug_generate_pub_sections based on
>         x_dwarf_split_debug_info.  Call set_debug_level.
>         (common_handle_option): Add case for OPT_gsplit_dwarf.
>
> Index: include/dwarf2.def
> ===================================================================
> --- include/dwarf2.def  (revision 190603)
> +++ include/dwarf2.def  (working copy)
> @@ -586,7 +586,7 @@
>  DW_OP (DW_OP_GNU_reinterpret, 0xf9)
>  /* The GNU parameter ref extension.  */
>  DW_OP (DW_OP_GNU_parameter_ref, 0xfa)
> -/* Extension for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
> +/* Extensions for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
>  DW_OP (DW_OP_GNU_addr_index, 0xfb)
>  DW_OP (DW_OP_GNU_const_index, 0xfc)
>  /* HP extensions.  */
> Index: include/dwarf2.h
> ===================================================================
> --- include/dwarf2.h    (revision 190603)
> +++ include/dwarf2.h    (working copy)
> @@ -259,6 +259,17 @@
>      DW_LNE_HP_SFC_associate = 3
>    };
>
> +/* Type codes for location list entries.
> +   Extension for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
> +
> +enum dwarf_location_list_entry_type
> +  {
> +    DW_LLE_GNU_end_of_list_entry = 0,
> +    DW_LLE_GNU_base_address_selection_entry = 1,
> +    DW_LLE_GNU_start_end_entry = 2,
> +    DW_LLE_GNU_start_length_entry = 3
> +  };
> +
>  #define DW_CIE_ID        0xffffffff
>  #define DW64_CIE_ID      0xffffffffffffffffULL
>  #define DW_CIE_VERSION   1
> Index: gcc/doc/invoke.texi
> ===================================================================
> --- gcc/doc/invoke.texi (revision 190603)
> +++ gcc/doc/invoke.texi (working copy)
> @@ -4803,6 +4803,14 @@
>  The following options are useful when GCC is generated with the
>  capability for more than one debugging format.
>
> +@item -gsplit-dwarf
> +@opindex gsplit-dwarf
> +Separate as much dwarf debugging information as possible into a
> +separate output file with the extension .dwo.  This option allows
> +the build system to avoid linking files with debug information.  To
> +be useful, this option requires a debugger capable of reading .dwo
> +files.
> +
>  @item -ggdb
>  @opindex ggdb
>  Produce debugging information for use by GDB@.  This means to use the
> Index: gcc/gcc.c
> ===================================================================
> --- gcc/gcc.c   (revision 190603)
> +++ gcc/gcc.c   (working copy)
> @@ -267,6 +267,7 @@
>  static const char *compare_debug_self_opt_spec_function (int, const char **);
>  static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
>  static const char *pass_through_libs_spec_func (int, const char **);
> +static const char *replace_extension_spec_func (int, const char **);
>
>  /* The Specs Language
>
> @@ -447,7 +448,7 @@
>  colon in these constructs, except between . or * and the corresponding
>  word.
>
> -The -O, -f, -m, and -W switches are handled specifically in these
> +The -O, -f, -g, -m, and -W switches are handled specifically in these
>  constructs.  If another value of -O or the negated form of a -f, -m, or
>  -W switch is found later in the command line, the earlier switch
>  value is ignored, except with {S*} where S is just one letter; this
> @@ -480,7 +481,14 @@
>  /* config.h can define ASM_FINAL_SPEC to run a post processor after
>     the assembler has run.  */
>  #ifndef ASM_FINAL_SPEC
> -#define ASM_FINAL_SPEC ""
> +#define ASM_FINAL_SPEC \
> +  "%{gsplit-dwarf: \n\
> +       objcopy --extract-dwo \
> +        %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> +        %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
> +       objcopy --strip-dwo \
> +        %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> +    }"
>  #endif
>
>  /* config.h can define CPP_SPEC to provide extra args to the C preprocessor
> @@ -1262,6 +1270,7 @@
>    { "compare-debug-self-opt",  compare_debug_self_opt_spec_function },
>    { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
>    { "pass-through-libs",       pass_through_libs_spec_func },
> +  { "replace-extension",       replace_extension_spec_func },
>  #ifdef EXTRA_SPEC_FUNCTIONS
>    EXTRA_SPEC_FUNCTIONS
>  #endif
> @@ -5803,7 +5812,7 @@
>     on the command line.  PREFIX_LENGTH is the length of XXX in an {XXX*}
>     spec, or -1 if either exact match or %* is used.
>
> -   A -O switch is obsoleted by a later -O switch.  A -f, -m, or -W switch
> +   A -O switch is obsoleted by a later -O switch.  A -f, -g, -m, or -W switch
>     whose value does not begin with "no-" is obsoleted by the same value
>     with the "no-", similarly for a switch with the "no-" prefix.  */
>
> @@ -5840,7 +5849,7 @@
>           }
>        break;
>
> -    case 'W':  case 'f':  case 'm':
> +    case 'W':  case 'f':  case 'm': case 'g':
>        if (! strncmp (name + 1, "no-", 3))
>         {
>           /* We have Xno-YYY, search for XYYY.  */
> @@ -8363,3 +8372,33 @@
>      }
>    return prepended;
>  }
> +
> +/* %:replace-extension spec function.  Replaces the extension of the
> +   first argument with the second argument.  */
> +
> +const char *
> +replace_extension_spec_func (int argc, const char **argv)
> +{
> +  char *name;
> +  char *p;
> +  char *result;
> +  int i;
> +
> +  if (argc != 2)
> +    fatal_error ("too few arguments to %%:replace-extension");
> +
> +  name = xstrdup (argv[0]);
> +
> +  for (i = strlen(name) - 1; i >= 0; i--)
> +    if (IS_DIR_SEPARATOR (name[i]))
> +      break;
> +
> +  p = strrchr (name + i + 1, '.');
> +  if (p != NULL)
> +      *p = '\0';
> +
> +  result = concat (name, argv[1], NULL);
> +
> +  free (name);
> +  return result;
> +}
> Index: gcc/dwarf2out.c
> ===================================================================
> --- gcc/dwarf2out.c     (revision 190603)
> +++ gcc/dwarf2out.c     (working copy)
> @@ -145,14 +145,19 @@
>
>  /* Pointers to various DWARF2 sections.  */
>  static GTY(()) section *debug_info_section;
> +static GTY(()) section *debug_skeleton_info_section;
>  static GTY(()) section *debug_abbrev_section;
> +static GTY(()) section *debug_skeleton_abbrev_section;
>  static GTY(()) section *debug_aranges_section;
> +static GTY(()) section *debug_addr_section;
>  static GTY(()) section *debug_macinfo_section;
>  static GTY(()) section *debug_line_section;
> +static GTY(()) section *debug_skeleton_line_section;
>  static GTY(()) section *debug_loc_section;
>  static GTY(()) section *debug_pubnames_section;
>  static GTY(()) section *debug_pubtypes_section;
>  static GTY(()) section *debug_str_section;
> +static GTY(()) section *debug_str_offsets_section;
>  static GTY(()) section *debug_ranges_section;
>  static GTY(()) section *debug_frame_section;
>
> @@ -195,6 +200,7 @@
>    unsigned int refcount;
>    enum dwarf_form form;
>    char *label;
> +  unsigned int index;
>  };
>
>  static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
> @@ -1201,7 +1207,8 @@
>     their entire life.  */
>  typedef struct GTY(()) dw_loc_list_struct {
>    dw_loc_list_ref dw_loc_next;
> -  const char *begin; /* Label for begin address of range */
> +  const char *begin; /* Label and index for begin address of range */
> +  unsigned int begin_index;
>    const char *end;  /* Label for end address of range */
>    char *ll_symbol; /* Label for beginning of location list.
>                       Only on head of list */
> @@ -1246,8 +1253,10 @@
>
>    descr->dw_loc_opc = op;
>    descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
> +  descr->dw_loc_oprnd1.val_index = -1U;
>    descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
>    descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
> +  descr->dw_loc_oprnd2.val_index = -1U;
>    descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
>
>    return descr;
> @@ -1452,6 +1461,10 @@
>      case DW_OP_addr:
>        size += DWARF2_ADDR_SIZE;
>        break;
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      size += size_of_uleb128 (loc->dw_loc_oprnd1.val_index);
> +      break;
>      case DW_OP_const1u:
>      case DW_OP_const1s:
>        size += 1;
> @@ -1888,6 +1901,12 @@
>         }
>        break;
>
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_index,
> +                                   "(index into .debug_addr)");
> +      break;
> +
>      case DW_OP_GNU_implicit_pointer:
>        {
>         char label[MAX_ARTIFICIAL_LABEL_BYTES
> @@ -2063,6 +2082,8 @@
>    switch (loc->dw_loc_opc)
>      {
>      case DW_OP_addr:
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
>      case DW_OP_implicit_value:
>        /* We cannot output addresses in .cfi_escape, only bytes.  */
>        gcc_unreachable ();
> @@ -2246,6 +2267,7 @@
>      {
>        head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
>        head->dw_loc_oprnd1.val_class = dw_val_class_const;
> +      head->dw_loc_oprnd1.val_index = -1U;
>        tmp = new_loc_descr (DW_OP_deref, 0, 0);
>        add_loc_descr (&head, tmp);
>        if (offset != 0)
> @@ -2875,6 +2897,8 @@
>  static tree decl_class_context (tree);
>  static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
>  static inline enum dw_val_class AT_class (dw_attr_ref);
> +static inline unsigned int AT_index (dw_attr_ref);
> +static inline void set_AT_index (dw_attr_ref, unsigned int);
>  static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned);
>  static inline unsigned AT_flag (dw_attr_ref);
>  static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
> @@ -2902,15 +2926,18 @@
>  static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
>                              dw_loc_list_ref);
>  static inline dw_loc_list_ref AT_loc_list (dw_attr_ref);
> -static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx);
> +static unsigned int add_addr_table_entry (dw_attr_node *);
> +static void remove_addr_table_entry (unsigned int);
> +static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
>  static inline rtx AT_addr (dw_attr_ref);
> -static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
> +static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *,
> +                          bool);
>  static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
>  static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
>  static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
>                            unsigned HOST_WIDE_INT);
>  static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
> -                              unsigned long);
> +                              unsigned long, bool);
>  static inline const char *AT_lbl (dw_attr_ref);
>  static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute);
>  static const char *get_AT_low_pc (dw_die_ref);
> @@ -3005,6 +3032,7 @@
>  static enum dwarf_form value_format (dw_attr_ref);
>  static void output_value_format (dw_attr_ref);
>  static void output_abbrev_section (void);
> +static void output_die_abbrevs (unsigned long, dw_die_ref);
>  static void output_die_symbol (dw_die_ref);
>  static void output_die (dw_die_ref);
>  static void output_compilation_unit_header (void);
> @@ -3020,10 +3048,10 @@
>  static unsigned int add_ranges_num (int);
>  static unsigned int add_ranges (const_tree);
>  static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
> -                                 bool *);
> +                                 bool *, bool);
>  static void output_ranges (void);
>  static dw_line_info_table *new_line_info_table (void);
> -static void output_line_info (void);
> +static void output_line_info (bool);
>  static void output_file_names (void);
>  static dw_die_ref base_type_die (tree);
>  static int is_base_type (tree);
> @@ -3162,36 +3190,130 @@
>  static void schedule_generic_params_dies_gen (tree t);
>  static void gen_scheduled_generic_parms_dies (void);
>
> +/* enum for tracking thread-local variables whose address is really an offset
> +   relative to the TLS pointer, which will need link-time relocation, but will
> +   not need relocation by the DWARF consumer.  */
> +
> +enum dtprel_bool
> +  {
> +    dtprel_false = 0,
> +    dtprel_true = 1
> +  };
> +
> +/* Return the operator to use for an address of a variable.  For dtprel_true, we
> +   use DW_OP_const*.  For regular variables, which need both link-time
> +   relocation and consumer-level relocation (e.g., to account for shared objects
> +   loaded at a random address), we use DW_OP_addr*.  */
> +
> +static inline enum dwarf_location_atom
> +dw_addr_op (enum dtprel_bool dtprel)
> +{
> +  if (dtprel == dtprel_true)
> +    return (dwarf_split_debug_info ? DW_OP_GNU_const_index
> +            : (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u));
> +  else
> +    return (dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr);
> +}
> +
> +/* Return a pointer to a newly allocated address location description.  If
> +   dwarf_split_debug_info is true, then record the address with the appropriate
> +   relocation.  */
> +static inline dw_loc_descr_ref
> +new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
> +{
> +  dw_loc_descr_ref ref = new_loc_descr (dw_addr_op (dtprel), 0, 0);
> +
> +  ref->dw_loc_oprnd1.val_class = dw_val_class_addr;
> +  ref->dw_loc_oprnd1.val_index = -1U;
> +  ref->dw_loc_oprnd1.v.val_addr = addr;
> +  ref->dtprel = dtprel;
> +  if (dwarf_split_debug_info)
> +    {
> +      dw_attr_node attr;
> +
> +      attr.dw_attr = DW_AT_location;
> +      attr.dw_attr_val.val_class = (dtprel == dtprel_true
> +                                    ? dw_val_class_loc : dw_val_class_addr);
> +      attr.dw_attr_val.val_index = -1U;
> +      attr.dw_attr_val.v.val_addr = addr;
> +
> +      ref->dw_loc_oprnd1.val_index = add_addr_table_entry (&attr);
> +    }
> +  return ref;
> +}
> +
>  /* Section names used to hold DWARF debugging information.  */
> +
>  #ifndef DEBUG_INFO_SECTION
>  #define DEBUG_INFO_SECTION     ".debug_info"
>  #endif
> +#ifndef DEBUG_DWO_INFO_SECTION
> +#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
> +#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_ARANGES_SECTION
>  #define DEBUG_ARANGES_SECTION  ".debug_aranges"
>  #endif
> +#ifndef DEBUG_ADDR_SECTION
> +#define DEBUG_ADDR_SECTION     ".debug_addr"
> +#endif
> +#ifndef DEBUG_NORM_MACINFO_SECTION
> +#define DEBUG_NORM_MACINFO_SECTION     ".debug_macinfo"
> +#endif
> +#ifndef DEBUG_DWO_MACINFO_SECTION
> +#define DEBUG_DWO_MACINFO_SECTION      ".debug_macinfo.dwo"
> +#endif
>  #ifndef DEBUG_MACINFO_SECTION
> -#define DEBUG_MACINFO_SECTION  ".debug_macinfo"
> +#define DEBUG_MACINFO_SECTION                                           \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_MACINFO_SECTION) : (DEBUG_DWO_MACINFO_SECTION))
>  #endif
> +#ifndef DEBUG_NORM_MACRO_SECTION
> +#define DEBUG_NORM_MACRO_SECTION ".debug_macro"
> +#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"
> +#define DEBUG_MACRO_SECTION                                             \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_MACRO_SECTION) : (DEBUG_DWO_MACRO_SECTION))
>  #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_LOC_SECTION
>  #define DEBUG_LOC_SECTION      ".debug_loc"
>  #endif
> +#ifndef DEBUG_DWO_LOC_SECTION
> +#define DEBUG_DWO_LOC_SECTION  ".debug_loc.dwo"
> +#endif
>  #ifndef DEBUG_PUBNAMES_SECTION
>  #define DEBUG_PUBNAMES_SECTION ".debug_pubnames"
>  #endif
>  #ifndef DEBUG_PUBTYPES_SECTION
>  #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes"
>  #endif
> +#define DEBUG_NORM_STR_OFFSETS_SECTION ".debug_str_offsets"
> +#define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo"
> +#ifndef DEBUG_STR_OFFSETS_SECTION
> +#define DEBUG_STR_OFFSETS_SECTION                                       \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_STR_OFFSETS_SECTION) : (DEBUG_DWO_STR_OFFSETS_SECTION))
> +#endif
> +#define DEBUG_DWO_STR_SECTION   ".debug_str.dwo"
> +#define DEBUG_NORM_STR_SECTION  ".debug_str"
>  #ifndef DEBUG_STR_SECTION
> -#define DEBUG_STR_SECTION      ".debug_str"
> +#define DEBUG_STR_SECTION                               \
> +  (!dwarf_split_debug_info ? (DEBUG_NORM_STR_SECTION) : (DEBUG_DWO_STR_SECTION))
>  #endif
>  #ifndef DEBUG_RANGES_SECTION
>  #define DEBUG_RANGES_SECTION   ".debug_ranges"
> @@ -3202,44 +3324,63 @@
>  #define TEXT_SECTION_NAME      ".text"
>  #endif
>
> +/* Section flags for .debug_macinfo/.debug_macro section.  */
> +#define DEBUG_MACRO_SECTION_FLAGS \
> +  (dwarf_split_debug_info ? SECTION_DEBUG | SECTION_EXCLUDE : SECTION_DEBUG)
> +
>  /* Section flags for .debug_str section.  */
>  #define DEBUG_STR_SECTION_FLAGS \
> -  (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings              \
> -   ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1       \
> -   : SECTION_DEBUG)
> +  (dwarf_split_debug_info \
> +   ? SECTION_DEBUG | SECTION_EXCLUDE \
> +   : (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings \
> +      ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1        \
> +      : SECTION_DEBUG))
>
>  /* Labels we insert at beginning sections we can reference instead of
>     the section names themselves.  */
>
>  #ifndef TEXT_SECTION_LABEL
> -#define TEXT_SECTION_LABEL             "Ltext"
> +#define TEXT_SECTION_LABEL                 "Ltext"
>  #endif
>  #ifndef COLD_TEXT_SECTION_LABEL
> -#define COLD_TEXT_SECTION_LABEL         "Ltext_cold"
> +#define COLD_TEXT_SECTION_LABEL             "Ltext_cold"
>  #endif
>  #ifndef DEBUG_LINE_SECTION_LABEL
> -#define DEBUG_LINE_SECTION_LABEL       "Ldebug_line"
> +#define DEBUG_LINE_SECTION_LABEL           "Ldebug_line"
>  #endif
> +#ifndef DEBUG_SKELETON_LINE_SECTION_LABEL
> +#define DEBUG_SKELETON_LINE_SECTION_LABEL   "Lskeleton_debug_line"
> +#endif
>  #ifndef DEBUG_INFO_SECTION_LABEL
> -#define DEBUG_INFO_SECTION_LABEL       "Ldebug_info"
> +#define DEBUG_INFO_SECTION_LABEL           "Ldebug_info"
>  #endif
> +#ifndef DEBUG_SKELETON_INFO_SECTION_LABEL
> +#define DEBUG_SKELETON_INFO_SECTION_LABEL   "Lskeleton_debug_info"
> +#endif
>  #ifndef DEBUG_ABBREV_SECTION_LABEL
> -#define DEBUG_ABBREV_SECTION_LABEL     "Ldebug_abbrev"
> +#define DEBUG_ABBREV_SECTION_LABEL         "Ldebug_abbrev"
>  #endif
> +#ifndef DEBUG_SKELETON_ABBREV_SECTION_LABEL
> +#define DEBUG_SKELETON_ABBREV_SECTION_LABEL "Lskeleton_debug_abbrev"
> +#endif
> +#ifndef DEBUG_ADDR_SECTION_LABEL
> +#define DEBUG_ADDR_SECTION_LABEL           "Ldebug_addr"
> +#endif
>  #ifndef DEBUG_LOC_SECTION_LABEL
> -#define DEBUG_LOC_SECTION_LABEL                "Ldebug_loc"
> +#define DEBUG_LOC_SECTION_LABEL                    "Ldebug_loc"
>  #endif
>  #ifndef DEBUG_RANGES_SECTION_LABEL
> -#define DEBUG_RANGES_SECTION_LABEL     "Ldebug_ranges"
> +#define DEBUG_RANGES_SECTION_LABEL         "Ldebug_ranges"
>  #endif
>  #ifndef DEBUG_MACINFO_SECTION_LABEL
> -#define DEBUG_MACINFO_SECTION_LABEL     "Ldebug_macinfo"
> +#define DEBUG_MACINFO_SECTION_LABEL         "Ldebug_macinfo"
>  #endif
>  #ifndef DEBUG_MACRO_SECTION_LABEL
> -#define DEBUG_MACRO_SECTION_LABEL      "Ldebug_macro"
> +#define DEBUG_MACRO_SECTION_LABEL          "Ldebug_macro"
>  #endif
> +#define SKELETON_COMP_DIE_ABBREV 1
> +#define SKELETON_TYPE_DIE_ABBREV 2
>
> -
>  /* Definitions of defaults for formats and names of various special
>     (artificial) labels which may be generated within this file (when the -g
>     options is used and DWARF2_DEBUGGING_INFO is in effect.
> @@ -3252,7 +3393,11 @@
>  static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_addr_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
> @@ -3493,6 +3638,31 @@
>    return a->dw_attr_val.val_class;
>  }
>
> +/* Return the index for any attribute that will be referenced with a
> +   DW_FORM_GNU_addr_index.  Strings have their indices handled differently to
> +   account for reference counting pruning.  */
> +
> +static inline unsigned int
> +AT_index (dw_attr_ref a)
> +{
> +  if (AT_class (a) == dw_val_class_str)
> +    return a->dw_attr_val.v.val_str->index;
> +  else
> +    return a->dw_attr_val.val_index;
> +}
> +
> +/* Set the index for any attribute that will be referenced with a
> +   DW_FORM_GNU_addr_index.  */
> +
> +static inline void
> +set_AT_index (dw_attr_ref a, unsigned int index)
> +{
> +  if (AT_class (a) == dw_val_class_str)
> +    a->dw_attr_val.v.val_str->index = index;
> +  else
> +    a->dw_attr_val.val_index = index;
> +}
> +
>  /* Add a flag value attribute to a DIE.  */
>
>  static inline void
> @@ -3502,6 +3672,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_flag;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_flag = flag;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3522,6 +3693,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_const;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_int = int_val;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3543,6 +3715,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_unsigned = unsigned_val;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3564,6 +3737,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_const_double;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_double.high = high;
>    attr.dw_attr_val.v.val_double.low = low;
>    add_dwarf_attr (die, &attr);
> @@ -3579,6 +3753,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_vec;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_vec.length = length;
>    attr.dw_attr_val.v.val_vec.elt_size = elt_size;
>    attr.dw_attr_val.v.val_vec.array = array;
> @@ -3595,28 +3770,39 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_data8;
> +  attr.dw_attr_val.val_index = -1U;
>    memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  */
> +/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  The parameter force_direct
> +   makes the attribute use DW_AT_addr, rather than DW_AT_GNU_addr_index.  */
> +
>  static inline void
> -add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high)
> +add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high,
> +                   bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = DW_AT_low_pc;
>    attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_low);
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, DW_AT_low_pc), add_addr_table_entry (&attr));
>
>    attr.dw_attr = DW_AT_high_pc;
>    if (dwarf_version < 4)
>      attr.dw_attr_val.val_class = dw_val_class_lbl_id;
>    else
>      attr.dw_attr_val.val_class = dw_val_class_high_pc;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_high);
>    add_dwarf_attr (die, &attr);
> +  if (attr.dw_attr_val.val_class == dw_val_class_lbl_id
> +      && dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, DW_AT_high_pc), add_addr_table_entry (&attr));
>  }
>
>  /* Hash and equality functions for debug_str_hash.  */
> @@ -3673,6 +3859,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_str;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_str = node;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3684,6 +3871,38 @@
>    return a->dw_attr_val.v.val_str->str;
>  }
>
> +/* A vector for a table of strings in the form DW_FORM_GNU_index_str.  */
> +
> +typedef struct indirect_string_node indirect_string_node;
> +DEF_VEC_O(indirect_string_node);
> +DEF_VEC_ALLOC_O(indirect_string_node, gc);
> +static GTY (()) VEC (indirect_string_node, gc) *index_string_table;
> +
> +/* Add a new indirect string to the appropriate tables.  Returns the index of
> +   the new string.  Call this function directly to bypass AT_string_form's logic
> +   to put the string inline in the die. */
> +
> +static unsigned long
> +add_indirect_string (struct indirect_string_node *node, const char *str)
> +{
> +  static unsigned int index_string_count = 0;
> +  ++dw2_string_counter;
> +  node->label = xstrdup (str);
> +
> +  if (!dwarf_split_debug_info)
> +    {
> +      node->form = DW_FORM_strp;
> +      return -1U;
> +    }
> +  else
> +    {
> +      node->form = DW_FORM_GNU_str_index;
> +      index_string_count++;
> +      VEC_safe_push (indirect_string_node, gc, index_string_table, node);
> +      return index_string_count;
> +    }
> +}
> +
>  /* Find out whether a string should be output inline in DIE
>     or out-of-line in .debug_str section.  */
>
> @@ -3716,10 +3935,9 @@
>      return node->form = DW_FORM_string;
>
>    ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
> -  ++dw2_string_counter;
> -  node->label = xstrdup (label);
> +  set_AT_index (a, add_indirect_string (node, label));
>
> -  return node->form = DW_FORM_strp;
> +  return node->form;
>  }
>
>  /* Add a DIE reference attribute value to a DIE.  */
> @@ -3740,6 +3958,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_die_ref;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_die_ref.die = targ_die;
>    attr.dw_attr_val.v.val_die_ref.external = 0;
>    add_dwarf_attr (die, &attr);
> @@ -3798,6 +4017,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_fde_ref;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_fde_index = targ_fde;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3811,6 +4031,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_loc;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_loc = loc;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3829,6 +4050,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_loc_list;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_loc_list = loc_list;
>    add_dwarf_attr (die, &attr);
>    have_location_lists = true;
> @@ -3848,17 +4070,62 @@
>    return &a->dw_attr_val.v.val_loc_list;
>  }
>
> -/* Add an address constant attribute value to a DIE.  */
> +/* A table of entries into the .debug_addr section.  */
>
> +static GTY (()) VEC (dw_attr_node,gc) * addr_index_table;
> +
> +static unsigned int
> +add_addr_table_entry (dw_attr_node *attr)
> +{
> +  gcc_assert (dwarf_split_debug_info);
> +
> +  VEC_safe_push (dw_attr_node, gc, addr_index_table, attr);
> +  return VEC_length (dw_attr_node, addr_index_table) - 1;
> +}
> +
> +/* Remove an entry from the addr table.  Since we have already numbered
> +   all the entries, the best we can do here is null it out.  */
> +
> +static void
> +remove_addr_table_entry (unsigned int i)
> +{
> +  dw_attr_node *attr;
> +
> +  gcc_assert (dwarf_split_debug_info);
> +  gcc_assert (i < VEC_length (dw_attr_node, addr_index_table));
> +
> +  attr = &VEC_index (dw_attr_node, addr_index_table, i);
> +  attr->dw_attr = (enum dwarf_attribute) 0;
> +}
> +
> +/* Given a location list, remove all addresses it refers to from the
> +   address_table.  */
> +
> +static void
> +remove_loc_list_addr_table_entries (dw_loc_descr_ref descr)
> +{
> +  for (; descr; descr = descr->dw_loc_next)
> +    if (descr->dw_loc_oprnd1.val_index != -1U)
> +      remove_addr_table_entry (descr->dw_loc_oprnd1.val_index);
> +}
> +
> +/* Add an address constant attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
> +
>  static inline void
> -add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
> +add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr,
> +            bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_addr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_addr = addr;
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
>  }
>
>  /* Get the RTX from to an address DIE attribute.  */
> @@ -3880,6 +4147,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_file;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_file = fd;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3903,22 +4171,29 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_vms_delta;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1);
>    attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2);
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add a label identifier attribute value to a DIE.  */
> +/* Add a label identifier attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static inline void
> -add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
> +add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind,
> +              const char *lbl_id, bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
>  }
>
>  /* Add a section offset attribute value to a DIE, an offset into the
> @@ -3932,6 +4207,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_lineptr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3947,6 +4223,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_macptr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3961,20 +4238,31 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_offset;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_offset = offset;
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add an range_list attribute value to a DIE.  */
> +/* Add a range_list attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static void
>  add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
> -                  long unsigned int offset)
> +                  long unsigned int offset, bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_range_list;
> +  /* For the range_list attribute, val_index == -1U indicates that we want to
> +     output a relocated reference to the range list entry, while any other
> +     value indicates that we want to output the section-relative offset of the
> +     range list entry. In this case, we're not using the val_index field as a
> +     slot index like we do for references to .debug_addr.  This is used
> +     in output_range_list_offset.  */
> +  attr.dw_attr_val.val_index
> +      = (dwarf_split_debug_info && !force_direct) ? offset : -1U;
>    attr.dw_attr_val.v.val_offset = offset;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -7158,6 +7446,7 @@
>    unsigned long size = 0;
>    dw_attr_ref a;
>    unsigned ix;
> +  enum dwarf_form form;
>
>    size += size_of_uleb128 (die->die_abbrev);
>    FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
> @@ -7165,7 +7454,10 @@
>        switch (AT_class (a))
>         {
>         case dw_val_class_addr:
> -         size += DWARF2_ADDR_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF2_ADDR_SIZE;
>           break;
>         case dw_val_class_offset:
>           size += DWARF_OFFSET_SIZE;
> @@ -7183,10 +7475,13 @@
>           }
>           break;
>         case dw_val_class_loc_list:
> -         size += DWARF_OFFSET_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_range_list:
> -         size += DWARF_OFFSET_SIZE;
> +          size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_const:
>           size += size_of_sleb128 (AT_int (a));
> @@ -7246,15 +7541,21 @@
>           size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_lbl_id:
> -         size += DWARF2_ADDR_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF2_ADDR_SIZE;
>           break;
>         case dw_val_class_lineptr:
>         case dw_val_class_macptr:
> -         size += DWARF_OFFSET_SIZE;
> +          size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_str:
> -         if (AT_string_form (a) == DW_FORM_strp)
> +          form = AT_string_form (a);
> +          if (form == DW_FORM_strp)
>             size += DWARF_OFFSET_SIZE;
> +         else if (form == DW_FORM_GNU_str_index)
> +            size += size_of_uleb128 (AT_index (a));
>           else
>             size += strlen (a->dw_attr_val.v.val_str->str) + 1;
>           break;
> @@ -7439,7 +7740,7 @@
>  static enum dwarf_form
>  value_format (dw_attr_ref a)
>  {
> -  switch (a->dw_attr_val.val_class)
> +  switch (AT_class (a))
>      {
>      case dw_val_class_addr:
>        /* Only very few attributes allow DW_FORM_addr.  */
> @@ -7449,7 +7750,8 @@
>         case DW_AT_high_pc:
>         case DW_AT_entry_pc:
>         case DW_AT_trampoline:
> -         return DW_FORM_addr;
> +          return (dwarf_split_debug_info && AT_index (a) != -1U
> +                 ? DW_FORM_GNU_addr_index : DW_FORM_addr);
>         default:
>           break;
>         }
> @@ -7565,7 +7867,8 @@
>      case dw_val_class_fde_ref:
>        return DW_FORM_data;
>      case dw_val_class_lbl_id:
> -      return DW_FORM_addr;
> +      return (dwarf_split_debug_info && AT_index (a) != -1U
> +             ? DW_FORM_GNU_addr_index : DW_FORM_addr);
>      case dw_val_class_lineptr:
>      case dw_val_class_macptr:
>        return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
> @@ -7613,6 +7916,36 @@
>    dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
>  }
>
> +/* Given a die and id, produce the appropriate abbreviations.  */
> +
> +static void
> +output_die_abbrevs (unsigned long abbrev_id, dw_die_ref abbrev)
> +{
> +  unsigned ix;
> +  dw_attr_ref a_attr;
> +
> +  dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
> +  dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
> +                               dwarf_tag_name (abbrev->die_tag));
> +
> +  if (abbrev->die_child != NULL)
> +    dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
> +  else
> +    dw2_asm_output_data (1, DW_children_no, "DW_children_no");
> +
> +  for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
> +       ix++)
> +    {
> +      dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
> +                                   dwarf_attr_name (a_attr->dw_attr));
> +      output_value_format (a_attr);
> +    }
> +
> +  dw2_asm_output_data (1, 0, NULL);
> +  dw2_asm_output_data (1, 0, NULL);
> +}
> +
> +
>  /* Output the .debug_abbrev section which defines the DIE abbreviation
>     table.  */
>
> @@ -7622,32 +7955,8 @@
>    unsigned long abbrev_id;
>
>    for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
> -    {
> -      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
> -      unsigned ix;
> -      dw_attr_ref a_attr;
> +    output_die_abbrevs (abbrev_id, abbrev_die_table[abbrev_id]);
>
> -      dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
> -      dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
> -                                  dwarf_tag_name (abbrev->die_tag));
> -
> -      if (abbrev->die_child != NULL)
> -       dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
> -      else
> -       dw2_asm_output_data (1, DW_children_no, "DW_children_no");
> -
> -      for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
> -          ix++)
> -       {
> -         dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
> -                                      dwarf_attr_name (a_attr->dw_attr));
> -         output_value_format (a_attr);
> -       }
> -
> -      dw2_asm_output_data (1, 0, NULL);
> -      dw2_asm_output_data (1, 0, NULL);
> -    }
> -
>    /* Terminate the table.  */
>    dw2_asm_output_data (1, 0, NULL);
>  }
> @@ -7683,6 +7992,7 @@
>    dw_loc_list_ref retlist = ggc_alloc_cleared_dw_loc_list_node ();
>
>    retlist->begin = begin;
> +  retlist->begin_index = -1U;
>    retlist->end = end;
>    retlist->expr = expr;
>    retlist->section = section;
> @@ -7727,7 +8037,22 @@
>          in a single range are unlikely very useful.  */
>        if (size > 0xffff)
>         continue;
> -      if (!have_multiple_function_sections)
> +      if (dwarf_split_debug_info)
> +        {
> +          dw2_asm_output_data (1, DW_LLE_GNU_start_length_entry,
> +                               "Location list start/length entry (%s)",
> +                               list_head->ll_symbol);
> +          dw2_asm_output_data_uleb128 (curr->begin_index,
> +                                       "Location list range start index (%s)",
> +                                       curr->begin);
> +          /* The length field is 4 bytes.  If we ever need to support
> +            an 8-byte length, we can add a new DW_LLE code or fall back
> +            to DW_LLE_GNU_start_end_entry.  */
> +          dw2_asm_output_delta (4, curr->end, curr->begin,
> +                               "Location list range length (%s)",
> +                               list_head->ll_symbol);
> +        }
> +      else if (!have_multiple_function_sections)
>         {
>           dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
>                                 "Location list begin address (%s)",
> @@ -7753,14 +8078,85 @@
>        output_loc_sequence (curr->expr, -1);
>      }
>
> -  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> -                      "Location list terminator begin (%s)",
> -                      list_head->ll_symbol);
> -  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> -                      "Location list terminator end (%s)",
> -                      list_head->ll_symbol);
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_data (1, DW_LLE_GNU_end_of_list_entry,
> +                        "Location list terminator (%s)",
> +                        list_head->ll_symbol);
> +  else
> +    {
> +      dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> +                          "Location list terminator begin (%s)",
> +                          list_head->ll_symbol);
> +      dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> +                          "Location list terminator end (%s)",
> +                          list_head->ll_symbol);
> +    }
>  }
>
> +/* Output the offset into the debug_range section.  */
> +
> +static void
> +output_range_list_offset (dw_attr_ref a)
> +{
> +  const char *name = dwarf_attr_name (a->dw_attr);
> +
> +  if (!dwarf_split_debug_info || AT_index (a) == -1U)
> +    {
> +      char *p = strchr (ranges_section_label, '\0');
> +      sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset);
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
> +                             debug_ranges_section, "%s", name);
> +      *p = '\0';
> +    }
> +  else
> +    dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
> +                         "%s (offset from %s)", name, ranges_section_label);
> +}
> +
> +/* Output the offset into the debug_loc section.  */
> +
> +static void
> +output_loc_list_offset (dw_attr_ref a)
> +{
> +  char *sym = AT_loc_list (a)->ll_symbol;
> +
> +  gcc_assert (sym);
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
> +                          "%s", dwarf_attr_name (a->dw_attr));
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
> +                           "%s", dwarf_attr_name (a->dw_attr));
> +}
> +
> +/* Output an attribute's index or value appropriately.  */
> +
> +static void
> +output_attr_index_or_value (dw_attr_ref a)
> +{
> +  const char *name = dwarf_attr_name (a->dw_attr);
> +
> +  if (dwarf_split_debug_info && AT_index (a) != -1U)
> +    {
> +      dw2_asm_output_data_uleb128 (AT_index (a), "%s", name);
> +      return;
> +    }
> +  switch (AT_class (a))
> +    {
> +      case dw_val_class_addr:
> +        dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
> +        break;
> +      case dw_val_class_lbl_id:
> +        dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
> +        break;
> +      case dw_val_class_loc_list:
> +        output_loc_list_offset (a);
> +        break;
> +      default:
> +        gcc_unreachable ();
> +    }
> +}
> +
>  /* Output a type signature.  */
>
>  static inline void
> @@ -7799,7 +8195,7 @@
>        switch (AT_class (a))
>         {
>         case dw_val_class_addr:
> -         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_offset:
> @@ -7808,15 +8204,7 @@
>           break;
>
>         case dw_val_class_range_list:
> -         {
> -           char *p = strchr (ranges_section_label, '\0');
> -
> -           sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
> -                    a->dw_attr_val.v.val_offset);
> -           dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
> -                                  debug_ranges_section, "%s", name);
> -           *p = '\0';
> -         }
> +          output_range_list_offset (a);
>           break;
>
>         case dw_val_class_loc:
> @@ -7872,7 +8260,7 @@
>               }
>
>             dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
> -                                first, name);
> +                                first, "%s", name);
>             dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
>                                  second, NULL);
>           }
> @@ -7919,13 +8307,7 @@
>           break;
>
>         case dw_val_class_loc_list:
> -         {
> -           char *sym = AT_loc_list (a)->ll_symbol;
> -
> -           gcc_assert (sym);
> -           dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
> -                                  "%s", name);
> -         }
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_die_ref:
> @@ -7982,7 +8364,7 @@
>           break;
>
>         case dw_val_class_lbl_id:
> -         dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_lineptr:
> @@ -7996,12 +8378,15 @@
>           break;
>
>         case dw_val_class_str:
> -         if (AT_string_form (a) == DW_FORM_strp)
> +         if (a->dw_attr_val.v.val_str->form == DW_FORM_strp)
>             dw2_asm_output_offset (DWARF_OFFSET_SIZE,
>                                    a->dw_attr_val.v.val_str->label,
>                                    debug_str_section,
>                                    "%s: \"%s\"", name, AT_string (a));
> -         else
> +         else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
> +            dw2_asm_output_data_uleb128 (AT_index (a),
> +                                         "%s: \"%s\"", name, AT_string (a));
> +          else
>             dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
>           break;
>
> @@ -8144,6 +8529,96 @@
>      add_AT_flag (die, DW_AT_GNU_pubnames, 1);
>  }
>
> +/* Helper function to generate top-level dies for skeleton debug_info and
> +   debug_types.  */
> +
> +static void
> +add_top_level_skeleton_die_attrs (dw_die_ref die)
> +{
> +  const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL);
> +  dw_attr_ref attr;
> +
> +  add_comp_dir_attribute (die);
> +  add_AT_string (die, DW_AT_GNU_dwo_name, dwo_file_name);
> +  /* The specification suggests that these attributes be inline to avoid
> +     having a .debug_str section.  We know that they exist in the die because
> +     we just added them.  */
> +  attr = get_AT (die, DW_AT_GNU_dwo_name);
> +  attr->dw_attr_val.v.val_str->form = DW_FORM_string;
> +  attr = get_AT (die, DW_AT_comp_dir);
> +  attr->dw_attr_val.v.val_str->form = DW_FORM_string;
> +
> +  add_AT_pubnames (die);
> +  add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label);
> +}
> +
> +/* Return the single type-unit die for skeleton type units.  */
> +
> +static dw_die_ref
> +get_skeleton_type_unit (void)
> +{
> +  /* For dwarf_split_debug_sections with use_type info, all type units in the
> +     skeleton sections have identical dies (but different headers).  This
> +     single die will be output many times.  */
> +
> +  static dw_die_ref skeleton_type_unit = NULL;
> +
> +  if (skeleton_type_unit == NULL)
> +    {
> +      skeleton_type_unit = new_die (DW_TAG_type_unit, NULL, NULL);
> +      add_top_level_skeleton_die_attrs (skeleton_type_unit);
> +      skeleton_type_unit->die_abbrev = SKELETON_TYPE_DIE_ABBREV;
> +    }
> +  return skeleton_type_unit;
> +}
> +
> +/* Output skeleton debug sections that point to the dwo file.  */
> +
> +static void
> +output_skeleton_debug_sections (dw_die_ref comp_unit)
> +{
> +  /* These attributes will be found in the full debug_info section.  */
> +  remove_AT (comp_unit, DW_AT_producer);
> +  remove_AT (comp_unit, DW_AT_language);
> +
> +  /* Add attributes common to skeleton compile_units and type_units.  */
> +  add_top_level_skeleton_die_attrs (comp_unit);
> +
> +  switch_to_section (debug_skeleton_info_section);
> +  ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_info_section_label);
> +
> +  /* Produce the skeleton compilation-unit header.  This one differs enough from
> +     a normal CU header that it's better not to call output_compilation_unit
> +     header.  */
> +  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
> +    dw2_asm_output_data (4, 0xffffffff,
> +      "Initial length escape value indicating 64-bit DWARF extension");
> +
> +  dw2_asm_output_data (DWARF_OFFSET_SIZE,
> +                      DWARF_COMPILE_UNIT_HEADER_SIZE
> +                       - DWARF_INITIAL_LENGTH_SIZE
> +                       + size_of_die (comp_unit),
> +                      "Length of Compilation Unit Info");
> +  dw2_asm_output_data (2, dwarf_version, "DWARF version number");
> +  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label,
> +                        debug_abbrev_section,
> +                        "Offset Into Abbrev. Section");
> +  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
> +
> +  comp_unit->die_abbrev = SKELETON_COMP_DIE_ABBREV;
> +  output_die (comp_unit);
> +
> +  /* Build the skeleton debug_abbrev section.  */
> +  switch_to_section (debug_skeleton_abbrev_section);
> +  ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_abbrev_section_label);
> +
> +  output_die_abbrevs (SKELETON_COMP_DIE_ABBREV, comp_unit);
> +  if (use_debug_types)
> +    output_die_abbrevs (SKELETON_TYPE_DIE_ABBREV, get_skeleton_type_unit ());
> +
> +  dw2_asm_output_data (1, 0, "end of skeleton .debug_abbrev");
> +}
> +
>  /* Output a comdat type unit DIE and its children.  */
>
>  static void
> @@ -8171,7 +8646,11 @@
>    calc_die_sizes (node->root_die);
>
>  #if defined (OBJECT_FORMAT_ELF)
> -  secname = ".debug_types";
> +  if (!dwarf_split_debug_info)
> +    secname = ".debug_types";
> +  else
> +    secname = ".debug_types.dwo";
> +
>    tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
>    sprintf (tmp, "wt.");
>    for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
> @@ -8180,6 +8659,7 @@
>    targetm.asm_out.named_section (secname,
>                                   SECTION_DEBUG | SECTION_LINKONCE,
>                                   comdat_key);
> +
>  #else
>    tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
>    sprintf (tmp, ".gnu.linkonce.wt.");
> @@ -8197,6 +8677,36 @@
>    output_die (node->root_die);
>
>    unmark_dies (node->root_die);
> +
> +  if (dwarf_split_debug_info)
> +    {
> +      /* Produce the skeleton type-unit header.  */
> +      const char *secname = ".debug_types";
> +
> +      targetm.asm_out.named_section (secname,
> +                                     SECTION_DEBUG | SECTION_LINKONCE,
> +                                     comdat_key);
> +      if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
> +        dw2_asm_output_data (4, 0xffffffff,
> +          "Initial length escape value indicating 64-bit DWARF extension");
> +
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE,
> +                           DWARF_COMPILE_UNIT_HEADER_SIZE
> +                           - DWARF_INITIAL_LENGTH_SIZE
> +                           + size_of_die (get_skeleton_type_unit ())
> +                           + DWARF_TYPE_SIGNATURE_SIZE + DWARF_OFFSET_SIZE,
> +                           "Length of Type Unit Info");
> +      dw2_asm_output_data (2, dwarf_version, "DWARF version number");
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE,
> +                             debug_skeleton_abbrev_section_label,
> +                             debug_abbrev_section,
> +                             "Offset Into Abbrev. Section");
> +      dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
> +      output_signature (node->signature, "Type Signature");
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "Offset to Type DIE");
> +
> +      output_die (get_skeleton_type_unit ());
> +    }
>  }
>
>  /* Return the DWARF2/3 pubname associated with a decl.  */
> @@ -8232,7 +8742,7 @@
>       class_member, it will either be inside the class already, or will have just
>       looked up the class to find the member.  Either way, searching the class is
>       faster than searching the index.  */
> -  if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent))
> +  if ((TREE_PUBLIC (decl) && !class_scope_p (die->die_parent))
>        || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
>      {
>        const char *name = dwarf2_name (decl, 1);
> @@ -8340,9 +8850,14 @@
>                          "Length of Public Type Names Info");
>    /* Version number for pubnames/pubtypes is still 2, even in DWARF3.  */
>    dw2_asm_output_data (2, 2, "DWARF Version");
> -  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> -                        debug_info_section,
> -                        "Offset of Compilation Unit Info");
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
> +                           debug_skeleton_info_section,
> +                           "Offset of Compilation Unit Info");
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> +                           debug_info_section,
> +                           "Offset of Compilation Unit Info");
>    dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
>                        "Compilation Unit Length");
>
> @@ -8403,9 +8918,14 @@
>                        "Length of Address Ranges Info");
>    /* Version number for aranges is still 2, even in DWARF3.  */
>    dw2_asm_output_data (2, 2, "DWARF Version");
> -  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> -                        debug_info_section,
> -                        "Offset of Compilation Unit Info");
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
> +                           debug_skeleton_info_section,
> +                           "Offset of Compilation Unit Info");
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> +                           debug_info_section,
> +                           "Offset of Compilation Unit Info");
>    dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
>    dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
>
> @@ -8502,12 +9022,13 @@
>    return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
>  }
>
> -/* Add a new entry to .debug_ranges corresponding to a pair of
> -   labels.  */
> +/* Add a new entry to .debug_ranges corresponding to a pair of labels.  The
> +   parameter force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static void
>  add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
> -                     bool *added)
> +                     bool *added, bool force_direct)
>  {
>    unsigned int in_use = ranges_by_label_in_use;
>    unsigned int offset;
> @@ -8530,7 +9051,7 @@
>    offset = add_ranges_num (-(int)in_use - 1);
>    if (!*added)
>      {
> -      add_AT_range_list (die, DW_AT_ranges, offset);
> +      add_AT_range_list (die, DW_AT_ranges, offset, force_direct);
>        *added = true;
>      }
>  }
> @@ -9067,7 +9588,7 @@
>     information goes into the .debug_line section.  */
>
>  static void
> -output_line_info (void)
> +output_line_info (bool prologue_only)
>  {
>    char l1[20], l2[20], p1[20], p2[20];
>    int ver = dwarf_version;
> @@ -9137,6 +9658,12 @@
>    /* Write out the information about the files we use.  */
>    output_file_names ();
>    ASM_OUTPUT_LABEL (asm_out_file, p2);
> +  if (prologue_only)
> +    {
> +      /* Output the marker for the end of the line number info.  */
> +      ASM_OUTPUT_LABEL (asm_out_file, l2);
> +      return;
> +    }
>
>    if (separate_line_info)
>      {
> @@ -11437,14 +11964,7 @@
>           if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
>             break;
>
> -         /* We used to emit DW_OP_addr here, but that's wrong, since
> -            DW_OP_addr should be relocated by the debug info consumer,
> -            while DW_OP_GNU_push_tls_address operand should not.  */
> -         temp = new_loc_descr (DWARF2_ADDR_SIZE == 4
> -                               ? DW_OP_const4u : DW_OP_const8u, 0, 0);
> -         temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         temp->dw_loc_oprnd1.v.val_addr = rtl;
> -         temp->dtprel = true;
> +          temp = new_addr_loc_descr (rtl, dtprel_true);
>
>           mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
>           add_loc_descr (&mem_loc_result, temp);
> @@ -11456,9 +11976,7 @@
>         break;
>
>      symref:
> -      mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -      mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +      mem_loc_result = new_addr_loc_descr (rtl, dtprel_false);
>        VEC_safe_push (rtx, gc, used_rtx_array, rtl);
>        break;
>
> @@ -12360,9 +12878,7 @@
>        if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
>           && (dwarf_version >= 4 || !dwarf_strict))
>         {
> -         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +         loc_result = new_addr_loc_descr (rtl, dtprel_false);
>           add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
>           VEC_safe_push (rtx, gc, used_rtx_array, rtl);
>         }
> @@ -13062,9 +13578,8 @@
>        if (DECL_THREAD_LOCAL_P (loc))
>         {
>           rtx rtl;
> -         enum dwarf_location_atom first_op;
> -         enum dwarf_location_atom second_op;
> -         bool dtprel = false;
> +         enum dwarf_location_atom tls_op;
> +         enum dtprel_bool dtprel = dtprel_false;
>
>           if (targetm.have_tls)
>             {
> @@ -13081,9 +13596,8 @@
>                   operand shouldn't be.  */
>               if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
>                 return 0;
> -             first_op = DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u;
> -             dtprel = true;
> -             second_op = DW_OP_GNU_push_tls_address;
> +             dtprel = dtprel_true;
> +             tls_op = DW_OP_GNU_push_tls_address;
>             }
>           else
>             {
> @@ -13095,8 +13609,7 @@
>                  no longer appear in gimple code.  We used the control
>                  variable in specific so that we could pick it up here.  */
>               loc = DECL_VALUE_EXPR (loc);
> -             first_op = DW_OP_addr;
> -             second_op = DW_OP_form_tls_address;
> +             tls_op = DW_OP_form_tls_address;
>             }
>
>           rtl = rtl_for_decl_location (loc);
> @@ -13109,12 +13622,8 @@
>           if (! CONSTANT_P (rtl))
>             return 0;
>
> -         ret = new_loc_descr (first_op, 0, 0);
> -         ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         ret->dw_loc_oprnd1.v.val_addr = rtl;
> -         ret->dtprel = dtprel;
> -
> -         ret1 = new_loc_descr (second_op, 0, 0);
> +          ret = new_addr_loc_descr (rtl, dtprel);
> +         ret1 = new_loc_descr (tls_op, 0, 0);
>           add_loc_descr (&ret, ret1);
>
>           have_address = 1;
> @@ -13159,11 +13668,7 @@
>             return 0;
>           }
>         else if (CONSTANT_P (rtl) && const_ok_for_output (rtl))
> -         {
> -           ret = new_loc_descr (DW_OP_addr, 0, 0);
> -           ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -           ret->dw_loc_oprnd1.v.val_addr = rtl;
> -         }
> +          ret = new_addr_loc_descr (rtl, dtprel_false);
>         else
>           {
>             enum machine_mode mode, mem_mode;
> @@ -14091,9 +14596,7 @@
>           dw_loc_descr_ref loc_result;
>           resolve_one_addr (&rtl, NULL);
>         rtl_addr:
> -         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +         loc_result = new_addr_loc_descr (rtl, dtprel_false);
>           add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
>           add_AT_loc (die, DW_AT_location, loc_result);
>           VEC_safe_push (rtx, gc, used_rtx_array, rtl);
> @@ -15611,7 +16114,7 @@
>    if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
>      {
>        add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
> -                  XEXP (DECL_RTL (decl), 0));
> +                  XEXP (DECL_RTL (decl), 0), false);
>        VEC_safe_push (rtx, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
>      }
>  #endif /* VMS_DEBUGGING_INFO */
> @@ -15632,7 +16135,7 @@
>    add_name_attribute (die, VMS_DEBUG_MAIN_POINTER);
>    ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
>                                current_function_funcdef_no);
> -  add_AT_lbl_id (die, DW_AT_entry_pc, label);
> +  add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
>
>    /* Make it the first child of comp_unit_die ().  */
>    die->die_parent = comp_unit_die ();
> @@ -16223,7 +16726,7 @@
>    if (DECL_ABSTRACT (decl))
>      equate_decl_number_to_die (decl, decl_die);
>    else
> -    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
> +    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl), false);
>  }
>  #endif
>
> @@ -16873,7 +17376,7 @@
>    if (stmt_die == NULL)
>      stmt_die = subr_die;
>    die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
> -  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
> +  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label, false);
>    if (ca_loc->tail_call_p)
>      add_AT_flag (die, DW_AT_GNU_tail_call, 1);
>    if (ca_loc->symbol_ref)
> @@ -16882,7 +17385,7 @@
>        if (tdie)
>         add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
>        else
> -       add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref);
> +       add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref, false);
>      }
>    return die;
>  }
> @@ -17073,7 +17576,8 @@
>           if (fde->dw_fde_begin)
>             {
>               /* We have already generated the labels.  */
> -             add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end);
> +             add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
> +                                 fde->dw_fde_end, false);
>             }
>           else
>             {
> @@ -17084,7 +17588,8 @@
>                                            current_function_funcdef_no);
>               ASM_GENERATE_INTERNAL_LABEL (label_id_high, FUNC_END_LABEL,
>                                            current_function_funcdef_no);
> -             add_AT_low_high_pc (subr_die, label_id_low, label_id_high);
> +             add_AT_low_high_pc (subr_die, label_id_low, label_id_high,
> +                                 false);
>             }
>
>  #if VMS_DEBUGGING_INFO
> @@ -17127,10 +17632,11 @@
>                      alignment offset.  */
>                   bool range_list_added = false;
>                   add_ranges_by_labels (subr_die, fde->dw_fde_begin,
> -                                       fde->dw_fde_end, &range_list_added);
> +                                       fde->dw_fde_end, &range_list_added,
> +                                       false);
>                   add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
>                                         fde->dw_fde_second_end,
> -                                       &range_list_added);
> +                                       &range_list_added, false);
>                   if (range_list_added)
>                     add_ranges (NULL);
>                 }
> @@ -17149,7 +17655,7 @@
>
>                   /* Do the 'primary' section.   */
>                   add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
> -                                     fde->dw_fde_end);
> +                                     fde->dw_fde_end, false);
>
>                   /* Build a minimal DIE for the secondary section.  */
>                   seg_die = new_die (DW_TAG_subprogram,
> @@ -17174,14 +17680,15 @@
>
>                   name = concat ("__second_sect_of_", name, NULL);
>                   add_AT_low_high_pc (seg_die, fde->dw_fde_second_begin,
> -                                     fde->dw_fde_second_end);
> +                                     fde->dw_fde_second_end, false);
>                   add_name_attribute (seg_die, name);
>                   if (want_pubnames ())
>                     add_pubname_string (name, seg_die);
>                 }
>             }
>           else
> -           add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end);
> +           add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end,
> +                               false);
>         }
>
>        cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
> @@ -17622,7 +18129,7 @@
>             {
>               /* Optimize the common case.  */
>               if (single_element_loc_list_p (loc)
> -                 && loc->expr->dw_loc_opc == DW_OP_addr
> +                  && loc->expr->dw_loc_opc == DW_OP_addr
>                   && loc->expr->dw_loc_next == NULL
>                   && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
>                 {
> @@ -17809,7 +18316,7 @@
>           gcc_assert (!INSN_DELETED_P (insn));
>
>           ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
> -         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
> +         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
>         }
>        else if (insn
>                && NOTE_P (insn)
> @@ -17817,7 +18324,7 @@
>                && CODE_LABEL_NUMBER (insn) != -1)
>         {
>           ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn));
> -         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
> +         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
>         }
>      }
>  }
> @@ -17858,7 +18365,7 @@
>         {
>           ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
>                                        BLOCK_NUMBER (stmt));
> -         add_AT_lbl_id (die, DW_AT_entry_pc, label);
> +         add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
>         }
>
>        /* Optimize duplicate .debug_ranges lists or even tails of
> @@ -17906,12 +18413,13 @@
>             ++thiscnt;
>           gcc_assert (supercnt >= thiscnt);
>           add_AT_range_list (die, DW_AT_ranges,
> -                            (off + supercnt - thiscnt)
> -                            * 2 * DWARF2_ADDR_SIZE);
> +                            ((off + supercnt - thiscnt)
> +                             * 2 * DWARF2_ADDR_SIZE),
> +                            false);
>           return;
>         }
>
> -      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
> +      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt), false);
>
>        chain = BLOCK_FRAGMENT_CHAIN (stmt);
>        do
> @@ -17929,7 +18437,7 @@
>                                    BLOCK_NUMBER (stmt));
>        ASM_GENERATE_INTERNAL_LABEL (label_high, BLOCK_END_LABEL,
>                                    BLOCK_NUMBER (stmt));
> -      add_AT_low_high_pc (die, label, label_high);
> +      add_AT_low_high_pc (die, label, label_high, false);
>      }
>  }
>
> @@ -20518,13 +21026,12 @@
>      case DW_MACRO_GNU_define_indirect:
>      case DW_MACRO_GNU_undef_indirect:
>        node = find_AT_string (ref->info);
> -      if (node->form != DW_FORM_strp)
> +      if ((node->form != DW_FORM_string)
> +          && (node->form != DW_FORM_GNU_str_index))
>         {
>           char label[32];
>           ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
> -         ++dw2_string_counter;
> -         node->label = xstrdup (label);
> -         node->form = DW_FORM_strp;
> +          add_indirect_string (node, label);
>         }
>        dw2_asm_output_data (1, ref->code,
>                            ref->code == DW_MACRO_GNU_define_indirect
> @@ -20705,8 +21212,10 @@
>         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, debug_line_section_label,
> -                            debug_line_section, NULL);
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE,
> +                             (!dwarf_split_debug_info ? debug_line_section_label
> +                              : debug_skeleton_line_section_label),
> +                             debug_line_section, NULL);
>      }
>
>    /* In the first loop, it emits the primary .debug_macinfo section
> @@ -20845,26 +21354,60 @@
>
>    used_rtx_array = VEC_alloc (rtx, gc, 32);
>
> -  debug_info_section = get_section (DEBUG_INFO_SECTION,
> -                                   SECTION_DEBUG, NULL);
> -  debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
> -                                     SECTION_DEBUG, NULL);
> +  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_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_aranges_section = get_section (DEBUG_ARANGES_SECTION,
>                                        SECTION_DEBUG, NULL);
>    debug_macinfo_section = get_section (dwarf_strict
>                                        ? DEBUG_MACINFO_SECTION
>                                        : DEBUG_MACRO_SECTION,
> -                                      SECTION_DEBUG, NULL);
> +                                      DEBUG_MACRO_SECTION_FLAGS, NULL);
>    debug_line_section = get_section (DEBUG_LINE_SECTION,
>                                     SECTION_DEBUG, NULL);
> -  debug_loc_section = get_section (DEBUG_LOC_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_STR_SECTION_FLAGS, NULL);
>    debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
>                                       SECTION_DEBUG, NULL);
>    debug_frame_section = get_section (DEBUG_FRAME_SECTION,
> @@ -20884,10 +21427,13 @@
>                                DEBUG_LINE_SECTION_LABEL, 0);
>    ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
>                                DEBUG_RANGES_SECTION_LABEL, 0);
> +  ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
> +                              DEBUG_ADDR_SECTION_LABEL, 0);
>    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);
>
>    if (debug_info_level >= DINFO_LEVEL_VERBOSE)
>      macinfo_table = VEC_alloc (macinfo_entry, gc, 64);
> @@ -20931,6 +21477,83 @@
>    return 1;
>  }
>
> +/* Output the indexed string table.  */
> +
> +static void
> +output_index_strings (void)
> +{
> +  unsigned int i;
> +  unsigned int len = 0;
> +  struct indirect_string_node *node;
> +
> +  gcc_assert (dwarf_split_debug_info);
> +
> +  if (VEC_empty (indirect_string_node, index_string_table))
> +    return;
> +
> +  switch_to_section (debug_str_offsets_section);
> +  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
> +       i++)
> +    {
> +      gcc_assert (node->form == DW_FORM_GNU_str_index);
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE, len,
> +                           "indexed string 0x%x: %s", i, node->str);
> +      len += strlen (node->str) + 1;
> +    }
> +  switch_to_section (debug_str_section);
> +  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
> +       i++)
> +    {
> +      ASM_OUTPUT_LABEL (asm_out_file, node->label);
> +      assemble_string (node->str, strlen (node->str) + 1);
> +    }
> +}
> +
> +/* Write the index table.  */
> +
> +static void
> +output_addr_table (void)
> +{
> +  unsigned int i;
> +  dw_attr_node *node;
> +
> +  if (VEC_empty (dw_attr_node, addr_index_table))
> +    return;
> +
> +  switch_to_section (debug_addr_section);
> +  for (i = 0; VEC_iterate (dw_attr_node, addr_index_table, i, node); i++)
> +    {
> +      const char *name;
> +
> +      if (node->dw_attr == 0)
> +       {
> +         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, "<Removed entry>");
> +         continue;
> +       }
> +
> +      name = dwarf_attr_name (node->dw_attr);
> +      switch (AT_class (node))
> +        {
> +          case dw_val_class_addr:
> +            dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (node),
> +                                     "%s", name);
> +            break;
> +          case dw_val_class_loc:
> +            gcc_assert (targetm.asm_out.output_dwarf_dtprel);
> +            targetm.asm_out.output_dwarf_dtprel (asm_out_file,
> +                                                 DWARF2_ADDR_SIZE,
> +                                                 node->dw_attr_val.v.val_addr);
> +            fputc ('\n', asm_out_file);
> +            break;
> +          case dw_val_class_lbl_id:
> +            dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (node), "%s", name);
> +            break;
> +          default:
> +            gcc_unreachable ();
> +        }
> +    }
> +}
> +
>  #if ENABLE_ASSERT_CHECKING
>  /* Verify that all marks are clear.  */
>
> @@ -21537,6 +22160,17 @@
>         if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
>           return false;
>         break;
> +      case DW_OP_GNU_addr_index:
> +      case DW_OP_GNU_const_index:
> +        {
> +          unsigned int idx = loc->dw_loc_oprnd1.val_index;
> +          dw_attr_node *node = &VEC_index (dw_attr_node, addr_index_table, idx);
> +          if ((loc->dw_loc_opc == DW_OP_GNU_addr_index
> +               || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
> +              && resolve_one_addr (&node->dw_attr_val.v.val_addr, NULL))
> +            return false;
> +        }
> +       break;
>        case DW_OP_const4u:
>        case DW_OP_const8u:
>         if (loc->dtprel
> @@ -21671,11 +22305,15 @@
>                 if (!resolve_addr_in_expr ((*curr)->expr))
>                   {
>                     dw_loc_list_ref next = (*curr)->dw_loc_next;
> +                   dw_loc_descr_ref l = (*curr)->expr;
> +
>                     if (next && (*curr)->ll_symbol)
>                       {
>                         gcc_assert (!next->ll_symbol);
>                         next->ll_symbol = (*curr)->ll_symbol;
>                       }
> +                   if (dwarf_split_debug_info)
> +                     remove_loc_list_addr_table_entries (l);
>                     *curr = next;
>                   }
>                 else
> @@ -21689,6 +22327,8 @@
>             else
>               {
>                 loc->replaced = 1;
> +                if (dwarf_split_debug_info)
> +                  remove_loc_list_addr_table_entries (loc->expr);
>                 loc->dw_loc_next = *start;
>               }
>           }
> @@ -21713,6 +22353,8 @@
>                || l->dw_loc_next != NULL)
>               && !resolve_addr_in_expr (l))
>             {
> +             if (dwarf_split_debug_info)
> +               remove_loc_list_addr_table_entries (l);
>               remove_AT (die, a->dw_attr);
>               ix--;
>             }
> @@ -21724,6 +22366,8 @@
>         if (a->dw_attr == DW_AT_const_value
>             && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL))
>           {
> +           if (AT_index (a) != -1U)
> +             remove_addr_table_entry (AT_index (a));
>             remove_AT (die, a->dw_attr);
>             ix--;
>           }
> @@ -21747,6 +22391,8 @@
>               }
>             else
>               {
> +               if (AT_index (a) != -1U)
> +                 remove_addr_table_entry (AT_index (a));
>                 remove_AT (die, a->dw_attr);
>                 ix--;
>               }
> @@ -21880,6 +22526,19 @@
>         }
>        hash = iterative_hash_rtx (val1->v.val_addr, hash);
>        break;
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      {
> +        dw_attr_ref attr = &VEC_index (dw_attr_node, addr_index_table,
> +                                      val1->val_index);
> +        if (loc->dtprel)
> +         {
> +            unsigned char dtprel = 0xd1;
> +            hash = iterative_hash_object (dtprel, hash);
> +          }
> +        hash = iterative_hash_rtx (attr->dw_attr_val.v.val_addr, hash);
> +      }
> +      break;
>      case DW_OP_GNU_implicit_pointer:
>        hash = iterative_hash_object (val2->v.val_int, hash);
>        break;
> @@ -22061,9 +22720,12 @@
>        return valx1->v.val_int == valy1->v.val_int;
>      case DW_OP_skip:
>      case DW_OP_bra:
> +      /* If splitting debug info, the use of DW_OP_GNU_addr_index
> +        can cause irrelevant differences in dw_loc_addr.  */
>        gcc_assert (valx1->val_class == dw_val_class_loc
>                   && valy1->val_class == dw_val_class_loc
> -                 && x->dw_loc_addr == y->dw_loc_addr);
> +                 && (dwarf_split_debug_info
> +                     || x->dw_loc_addr == y->dw_loc_addr));
>        return valx1->v.val_loc->dw_loc_addr == valy1->v.val_loc->dw_loc_addr;
>      case DW_OP_implicit_value:
>        if (valx1->v.val_unsigned != valy1->v.val_unsigned
> @@ -22094,6 +22756,18 @@
>      case DW_OP_addr:
>      hash_addr:
>        return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr);
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      {
> +        dw_attr_node *attrx1 = &VEC_index (dw_attr_node,
> +                                           addr_index_table,
> +                                           valx1->val_index);
> +        dw_attr_node *attry1 = &VEC_index (dw_attr_node,
> +                                           addr_index_table,
> +                                           valy1->val_index);
> +        return rtx_equal_p (attrx1->dw_attr_val.v.val_addr,
> +                            attry1->dw_attr_val.v.val_addr);
> +      }
>      case DW_OP_GNU_implicit_pointer:
>        return valx1->val_class == dw_val_class_die_ref
>              && valx1->val_class == valy1->val_class
> @@ -22207,7 +22881,7 @@
>         if (*slot == NULL)
>           *slot = (void *) list;
>         else
> -         a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
> +          a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
>        }
>
>    FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab));
> @@ -22223,6 +22897,43 @@
>    optimize_location_lists_1 (die, htab);
>    htab_delete (htab);
>  }
> +
> +
> +/* Recursively assign each location list a unique index into the debug_addr
> +   section.  */
> +
> +static void
> +index_location_lists (dw_die_ref die)
> +{
> +  dw_die_ref c;
> +  dw_attr_ref a;
> +  unsigned ix;
> +
> +  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
> +    if (AT_class (a) == dw_val_class_loc_list)
> +      {
> +        dw_loc_list_ref list = AT_loc_list (a);
> +        dw_loc_list_ref curr;
> +        for (curr = list; curr != NULL; curr = curr->dw_loc_next)
> +          {
> +            dw_attr_node attr;
> +
> +            /* Don't index an entry that has already been indexed
> +              or won't be output.  */
> +            if (curr->begin_index != -1U
> +               || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
> +             continue;
> +
> +            attr.dw_attr = DW_AT_location;
> +            attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +            attr.dw_attr_val.val_index = -1U;
> +            attr.dw_attr_val.v.val_lbl_id = xstrdup (curr->begin);
> +            curr->begin_index = add_addr_table_entry (&attr);
> +          }
> +      }
> +
> +  FOR_EACH_CHILD (die, c, index_location_lists (c));
> +}
>
>  /* Output stuff that dwarf requires at the end of every file,
>     and generate the DWARF-2 debugging info.  */
> @@ -22234,6 +22945,7 @@
>    comdat_type_node *ctnode;
>    htab_t comdat_type_table;
>    unsigned int i;
> +  dw_die_ref main_comp_unit_die;
>
>    /* PCH might result in DW_AT_producer string being restored from the
>       header compilation, fix it up if needed.  */
> @@ -22386,6 +23098,14 @@
>    for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
>      add_sibling_attributes (ctnode->root_die);
>
> +  /* When splitting DWARF info, we put some attributes in the
> +     skeleton compile_unit DIE that remains in the .o, while
> +     most attributes go in the DWO compile_unit_die.  */
> +  if (dwarf_split_debug_info)
> +    main_comp_unit_die = gen_compile_unit_die (NULL);
> +  else
> +    main_comp_unit_die = comp_unit_die ();
> +
>    /* Output a terminator label for the .text section.  */
>    switch_to_section (text_section);
>    targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
> @@ -22402,8 +23122,8 @@
>      {
>        /* Don't add if the CU has no associated code.  */
>        if (text_section_used)
> -       add_AT_low_high_pc (comp_unit_die (), text_section_label,
> -                           text_end_label);
> +       add_AT_low_high_pc (main_comp_unit_die, text_section_label,
> +                           text_end_label, true);
>      }
>    else
>      {
> @@ -22412,22 +23132,24 @@
>        bool range_list_added = false;
>
>        if (text_section_used)
> -       add_ranges_by_labels (comp_unit_die (), text_section_label,
> -                             text_end_label, &range_list_added);
> +       add_ranges_by_labels (main_comp_unit_die, text_section_label,
> +                             text_end_label, &range_list_added, true);
>        if (cold_text_section_used)
> -       add_ranges_by_labels (comp_unit_die (), cold_text_section_label,
> -                             cold_end_label, &range_list_added);
> +       add_ranges_by_labels (main_comp_unit_die, cold_text_section_label,
> +                             cold_end_label, &range_list_added, true);
>
>        FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde)
>         {
>           if (DECL_IGNORED_P (fde->decl))
>             continue;
>           if (!fde->in_std_section)
> -           add_ranges_by_labels (comp_unit_die (), fde->dw_fde_begin,
> -                                 fde->dw_fde_end, &range_list_added);
> +           add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_begin,
> +                                 fde->dw_fde_end, &range_list_added,
> +                                 true);
>           if (fde->dw_fde_second_begin && !fde->second_in_std_section)
> -           add_ranges_by_labels (comp_unit_die (), fde->dw_fde_second_begin,
> -                                 fde->dw_fde_second_end, &range_list_added);
> +           add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_second_begin,
> +                                 fde->dw_fde_second_end, &range_list_added,
> +                                 true);
>         }
>
>        if (range_list_added)
> @@ -22437,16 +23159,16 @@
>              absolute.  Historically, we've emitted the unexpected
>              DW_AT_entry_pc instead of DW_AT_low_pc for this purpose.
>              Emit both to give time for other tools to adapt.  */
> -         add_AT_addr (comp_unit_die (), DW_AT_low_pc, const0_rtx);
> +         add_AT_addr (main_comp_unit_die, DW_AT_low_pc, const0_rtx, true);
>           if (! dwarf_strict && dwarf_version < 4)
> -           add_AT_addr (comp_unit_die (), DW_AT_entry_pc, const0_rtx);
> +           add_AT_addr (main_comp_unit_die, DW_AT_entry_pc, const0_rtx, true);
>
>           add_ranges (NULL);
>         }
>      }
>
>    if (debug_info_level >= DINFO_LEVEL_NORMAL)
> -    add_AT_lineptr (comp_unit_die (), DW_AT_stmt_list,
> +    add_AT_lineptr (main_comp_unit_die, DW_AT_stmt_list,
>                     debug_line_section_label);
>
>    if (have_macinfo)
> @@ -22455,7 +23177,11 @@
>                    macinfo_section_label);
>
>    if (have_location_lists)
> -    optimize_location_lists (comp_unit_die ());
> +    {
> +      optimize_location_lists (comp_unit_die ());
> +      if (dwarf_split_debug_info)
> +        index_location_lists (comp_unit_die ());
> +    }
>
>    /* Output all of the compilation units.  We put the main one last so that
>       the offsets are available to output_pubnames.  */
> @@ -22476,19 +23202,54 @@
>           attributes.  */
>        if (debug_info_level >= DINFO_LEVEL_NORMAL)
>          add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
> -                       debug_line_section_label);
> +                        (!dwarf_split_debug_info
> +                         ? debug_line_section_label
> +                         : debug_skeleton_line_section_label));
>
>        output_comdat_type_unit (ctnode);
>        *slot = ctnode;
>      }
>    htab_delete (comdat_type_table);
>
> -  add_AT_pubnames (comp_unit_die ());
> +  /* 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 ());
>
> +  if (dwarf_split_debug_info)
> +    {
> +      int mark;
> +      unsigned char checksum[16];
> +      struct md5_ctx ctx;
> +
> +      /* Compute a checksum of the comp_unit to use as the dwo_id.  */
> +      md5_init_ctx (&ctx);
> +      mark = 0;
> +      die_checksum (comp_unit_die (), &ctx, &mark);
> +      unmark_all_dies (comp_unit_die ());
> +      md5_finish_ctx (&ctx, checksum);
> +
> +      /* Use the first 8 bytes of the checksum as the dwo_id,
> +        and add it to both comp-unit DIEs.  */
> +      add_AT_data8 (main_comp_unit_die, DW_AT_GNU_dwo_id, checksum);
> +      add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, checksum);
> +
> +      /* Add the base offset of the ranges table to the skeleton
> +        comp-unit DIE.  */
> +      if (ranges_table_in_use)
> +       add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base,
> +                       ranges_section_label);
> +    }
> +
>    /* Output the main compilation unit if non-empty or if .debug_macinfo
>       or .debug_macro will be emitted.  */
>    output_comp_unit (comp_unit_die (), have_macinfo);
>
> +  if (dwarf_split_debug_info && info_section_emitted)
> +    output_skeleton_debug_sections (main_comp_unit_die);
> +
>    /* Output the abbreviation table.  */
>    if (abbrev_die_table_in_use != 1)
>      {
> @@ -22502,8 +23263,6 @@
>      {
>        /* Output the location lists info.  */
>        switch_to_section (debug_loc_section);
> -      ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
> -                                  DEBUG_LOC_SECTION_LABEL, 0);
>        ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
>        output_location_lists (comp_unit_die ());
>      }
> @@ -22554,10 +23313,22 @@
>    switch_to_section (debug_line_section);
>    ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
>    if (! DWARF2_ASM_LINE_DEBUG_INFO)
> -    output_line_info ();
> +    output_line_info (false);
>
> -  /* If we emitted any DW_FORM_strp form attribute, output the string
> -     table too.  */
> +  if (dwarf_split_debug_info && info_section_emitted)
> +    {
> +      switch_to_section (debug_skeleton_line_section);
> +      ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
> +      output_line_info (true);
> +
> +      output_index_strings ();
> +
> +      switch_to_section (debug_addr_section);
> +      ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label);
> +      output_addr_table ();
> +    }
> +
> +  /* If we emitted any indirect strings, output the string table too.  */
>    if (debug_str_hash)
>      htab_traverse (debug_str_hash, output_indirect_string, NULL);
>  }
> Index: gcc/dwarf2out.h
> ===================================================================
> --- gcc/dwarf2out.h     (revision 190603)
> +++ gcc/dwarf2out.h     (working copy)
> @@ -172,6 +172,7 @@
>
>  typedef struct GTY(()) dw_val_struct {
>    enum dw_val_class val_class;
> +  unsigned int val_index;
>    union dw_val_struct_union
>      {
>        rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
> Index: gcc/opts.c
> ===================================================================
> --- gcc/opts.c  (revision 190603)
> +++ gcc/opts.c  (working copy)
> @@ -829,9 +829,14 @@
>    if (opts->x_warn_unused_but_set_parameter == -1)
>      opts->x_warn_unused_but_set_parameter = (opts->x_warn_unused
>                                              && opts->x_extra_warnings);
> +
>    /* Wunused-local-typedefs is enabled by -Wunused or -Wall.  */
>    if (opts->x_warn_unused_local_typedefs == -1)
>      opts->x_warn_unused_local_typedefs = opts->x_warn_unused;
> +
> +  /* The -gsplit-dwarf option requires -gpubnames.  */
> +  if (opts->x_dwarf_split_debug_info)
> +    opts->x_debug_generate_pub_sections = 1;
>  }
>
>  #define LEFT_COLUMN    27
> @@ -1692,6 +1697,13 @@
>        set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc);
>        break;
>
> +    case OPT_gsplit_dwarf:
> +      if (opts->x_dwarf_version < 4)
> +        opts->x_dwarf_version = 4;
> +      set_debug_level (DWARF2_DEBUG, DEFAULT_GDB_EXTENSIONS, "", opts, opts_set,
> +                      loc);
> +      break;
> +
>      case OPT_ggdb:
>        set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc);
>        break;
> Index: gcc/common.opt
> ===================================================================
> --- gcc/common.opt      (revision 190603)
> +++ gcc/common.opt      (working copy)
> @@ -2282,6 +2282,20 @@
>  Common RejectNegative Var(dwarf_record_gcc_switches,1)
>  Record gcc command line switches in DWARF DW_AT_producer.
>
> +gno-split-dwarf
> +Common Driver RejectNegative Var(dwarf_split_debug_info,0) Init(0)
> +Don't generate debug information in separate .dwo files
> +
> +gsplit-dwarf
> +Common Driver RejectNegative Var(dwarf_split_debug_info,1)
> +Generate debug information in separate .dwo files
> +
>  gstabs
>  Common JoinedOrMissing Negative(gstabs+)
>  Generate debug information in STABS format
>
> --
> This patch is available for review at http://codereview.appspot.com/6305113

Ping?
Sterling Augustine - Sept. 18, 2012, 10:27 p.m.
On Mon, Aug 27, 2012 at 11:00 AM, Sterling Augustine
<saugustine@google.com> wrote:
> The enclosed patch to implment -gsplit-dwarf addresses Jason's comments as
> responded to by myself and Cary.
>
> In particular, it:
>
> 1. Adds comments for force_direct and its use
> 2. Corrects the location of is_unit_die
> 3. Makes -gsplit-dwarf imply -gdwarf-4
> 4. Changes DW_LLE_* to DW_LLE_GNU_*
> 5. Fixes various comments
> 6. Adds a new enum to cleanup dtprel and the associated logic
> 7. Fixes the FIXME in output_macinfo_op
>
> However, it does not:
>
> 1. Cleanup redundant entries in the .debug_addr--Cary has a patch in progress
>    that handles this situation.
>
>    http://codereview.appspot.com/6305113/#msg6 has more discussion.
>
> 2. Defer assigning indices to DW_GNU_addr_index entries until output time. We
>    see this less than 0.1 percent of the time, and fixing it would require
>    a major restructuring of when the size of debug entries are calculated as
>    opposed to when they are emitted.  Further, Cary's forthcoming patch in is
>    likely to reduce this count even further.
>
>
> The line length issues were not real, as a unified diff adds two spaces to
> the line, and a script that doesn't account for that will reject 79 and 80
> character line lengths.
>
>
> Hopefully this addresses all remaining issues. OK for mainline?
>
> Sterling and Cary
>
>
> include/ChangeLog
>
> 2012-08-24  Sterling Augustine <saugustine@google.com>
>             Cary Coutant <ccoutant@google.com>
>
>         * dwarf2.def: Fix comment.
>         * dwarf2.h (dwarf_location_list_entry_type): New enum with members
>         DW_LLE_GNU_end_of_list_entry, DW_LLE_GNU_case_address_selection_entry,
>         DW_LLE_GNU_start_end_entry, DW_LLE_GNU_start_length_entry.
>
> gcc/ChangeLog
>
> 2012-08-24  Sterling Augustine <saugustine@google.com>
>             Cary Coutant <ccoutant@google.com>
>
>         * common.opt (gno-split-dwarf, gsplit-dwarf): New switches.
>         * doc/invoke.texi (Debugging Options): Document them.
>         * dwarf2out.h (dw_val_struct): New field val_index.
>         * dwarf2out.c (debug_skeleton_info_section,
>         debug_skeleton_abbrev_section, debug_addr_section,
>         debug_skeleton_line_section, debug_str_offsets_section): New sections.
>         (indirect_string_node): Add index field.
>         (dw_loc_list_node): Add begin_index field.
>         (dw_addr_op, new_addr_loc_descr, AT_index, set_AT_index,
>         add_addr_table_entry, remove_addr_table_entry, output_range_list_offset,
>         output_loc_list_offset, output_attr_index_or_value,
>         remove_loc_list_addr_table_entries, output_die_abbrevs,
>         add_top_level_skeleton_die_attrs, get_skeleton_type_unit,
>         output_skeleton_debug_sections, output_index_strings,
>         output_addr_table, index_location_lists, add_indirect_string): New
>         functions.
>         (DEBUG_DWO_INFO_SECTION, DEBUG_DWO_ABBREV_SECTION, DEBUG_ADDR_SECTION,
>         DEBUG_NORM_MACINFO_SECTION, DEBUG_DWO_MACINFO_SECTION,
>         DEBUG_DWO_LINE_SECTION, DEBUG_DWO_LOC_SECTION,
>         DEBUG_NORM_STR_OFFSETS_SECTION, DEBUG_DWO_STR_SECTION,
>         DEBUG_MACRO_SECTION_FLAGS, DEBUG_SKELETON_LINE_SECTION_LABEL,
>         DEBUG_SKELETON_INFO_SECTION_LABEL, DEBUG_SKELETON_ABBREV_SECTION_LABEL,
>         DEBUG_ADDR_SECTIN_LABEL, SKELETON_COMP_DIE_ABBREV,
>         SKELETON_TYPE_DIE_ABBREV): New defines.
>         (DEBUG_MACINFO_SECTION, DEBUG_MACRO_SECTION, DEBUG_STR_SECTION
>         DEBUG_STR_SECTION_FLAGS): Adjust definitions.
>         (TEXT_SECTION_LABEL, COLD_TEXT_SECTION_LABEL, DEBUG_INFO_SECTION_LABEL,
>         DEBUG_ABBREV_SECTION_LABEL, DEBUG_LOC_SECTION_LABEL,
>         DEBUG_RANGES_SECTION_LABEL, DEBUG_MACINFO_SECTION_LABEL,
>         DEBUG_MACRO_SECTION_LABEL): Adjust indentation.
>         (debug_skeleton_info_section_label, debug_skeleton_abbrev_section_label,
>         debug_addr_section_label, debug_skeleton_line_section_label,
>         dw_id_placeholder): New global variables.
>         (add_AT_lbl_id, add_AT_low_high_pc): Add force_direct parameter.
>         Adjust calls throughout file.  Handle dwarf_split_debug_info.
>         (add_AT_addr). Likewise.  Initialize val_index_field.
>         (add_AT_range_list): Add force parameter.  Adjust calls throughout file.
>         Initialize val_index field.
>         (add_ranges_by_labels): Add and handle force_direct parameter.  Adjust
>         calls throughout file.
>         (size_of_die): New variable form.  Handle dwarf_split_debug_info and
>         call AT_index.
>         (value_format): Use AT_class instead of calling val_class directly.
>         Handle DW_FORM_addr and dw_val_class_lbl_id appropriately for
>         dwarf_split_debug_info and AT_index.
>         (output_abbrev_section): Move most code to new function
>         output_die_abbrevs.
>         (output_loc_list): Handle dwarf_split_debug_info by using
>         DW_LLE_start_length_entry and DW_LLE_end_of_list_entry.
>         (output_die): Call output_attr_index_or_value, output_range_list_offset,
>         Fix format string.  Check val_str->form directly to avoid side effect.
>         (add_pubtype): Fix indention.
>         (output_comdat_type_unit): Handle dwarf_split_debug_info.
>         (output_pubnames): Likewise.
>         (output_aranges): Likewise.
>         (output_mac_info): Likewise.
>         (output_mac_info_op): Check for DW_FORM_GNU_str_index.  Call
>         add_indirect_string.
>         (output_line_info): New parameter prologue_only.  Adjust calls
>         throughout file.
>         (dtprel_bool, dtprel_false, dtprel_true): New enum and enumerators.
>         (mem_loc_descriptor): Call new_addr_loc_descr.
>         (loc_descriptor): Likewise.
>         (add_const_value_attribute): Likewise.
>         (loc_list_from_tree): Replace first_op and second_op with tls_op.
>         Update associated logic.  Call new_addr_loc_descr.
>         (dwarf2out_init): Handle dwarf_split_debug_info.  Initialize
>         debug_skeleton_info_section, debug_skeleton_abbrev_section,
>         debug_addr_section, debug_skeleton_line_section,
>         debug_str_offsets_section, debug_skeleton_info_section_label,
>         debug_skeleton_abbrev_section_label, debug_addr_section_label and
>         debug_skeleton_line_section_label.  Use DEBUG_MACRO_SECTION_FLAGS.
>         (new_loc_descr, build_cfa_loc, add_AT_flag, add_AT_int, add_AT_unsigned,
>         add_AT_double, add_AT_vec, add_AT_data8, add_AT_string, add_AT_die_ref,
>         add_AT_fde_ref, add_AT_loc, add_AT_loc_list, add_AT_file,
>         add_AT_vms_delta, add_AT_lineptr, add_AT_macptr, add_AT_offset):
>         Initialize val_index field.
>         (size_of_loc_descr, output_loc_operands, output_loc_operands_raw,
>         resolve_addr_in_expression, hash_loc_operands): Handle
>         DW_OP_GNU_addr_index and DW_OP_GNU_const_index.
>         (compare_loc_operands):  Likewise.  Adjust assertion.
>         (AT_string_form): Call set_AT_index and add_indirect_string.
>         (resolve_addr): New local variable l.  Check val_index.  Call
>         remove_addr_table_entry and remove_loc_list_addr_table_entries.
>         (dwarf2out_finish): Handle dwarf_split_debug_info.  New variable
>         main_comp_unit_die.  Call index_location_lists, add_AT_data8,
>         add_AT_lineptr, output_skeleton_debug_sections, output_addr_table.  Move
>         call to ASM_GENERATE_INTERNAL_LABEL to dwarf2out_init.  Call
>         ASM_OUTPUT_LABEL for debug_skeleton_line_section_label and
>         debug_addr_section_label.  Adjust comment.
>         * gcc.c (replace_extension_spec_func):  New function.
>         (ASM_FINAL_SPEC): Adjust.
>         (static_spec_functions): Add new field for replace-extension.
>         (check_live_switch): Adjust comment.  Add case for 'g'.
>         * opts.c (finish_options): Set x_debug_generate_pub_sections based on
>         x_dwarf_split_debug_info.  Call set_debug_level.
>         (common_handle_option): Add case for OPT_gsplit_dwarf.
>
> Index: include/dwarf2.def
> ===================================================================
> --- include/dwarf2.def  (revision 190603)
> +++ include/dwarf2.def  (working copy)
> @@ -586,7 +586,7 @@
>  DW_OP (DW_OP_GNU_reinterpret, 0xf9)
>  /* The GNU parameter ref extension.  */
>  DW_OP (DW_OP_GNU_parameter_ref, 0xfa)
> -/* Extension for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
> +/* Extensions for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
>  DW_OP (DW_OP_GNU_addr_index, 0xfb)
>  DW_OP (DW_OP_GNU_const_index, 0xfc)
>  /* HP extensions.  */
> Index: include/dwarf2.h
> ===================================================================
> --- include/dwarf2.h    (revision 190603)
> +++ include/dwarf2.h    (working copy)
> @@ -259,6 +259,17 @@
>      DW_LNE_HP_SFC_associate = 3
>    };
>
> +/* Type codes for location list entries.
> +   Extension for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
> +
> +enum dwarf_location_list_entry_type
> +  {
> +    DW_LLE_GNU_end_of_list_entry = 0,
> +    DW_LLE_GNU_base_address_selection_entry = 1,
> +    DW_LLE_GNU_start_end_entry = 2,
> +    DW_LLE_GNU_start_length_entry = 3
> +  };
> +
>  #define DW_CIE_ID        0xffffffff
>  #define DW64_CIE_ID      0xffffffffffffffffULL
>  #define DW_CIE_VERSION   1
> Index: gcc/doc/invoke.texi
> ===================================================================
> --- gcc/doc/invoke.texi (revision 190603)
> +++ gcc/doc/invoke.texi (working copy)
> @@ -4803,6 +4803,14 @@
>  The following options are useful when GCC is generated with the
>  capability for more than one debugging format.
>
> +@item -gsplit-dwarf
> +@opindex gsplit-dwarf
> +Separate as much dwarf debugging information as possible into a
> +separate output file with the extension .dwo.  This option allows
> +the build system to avoid linking files with debug information.  To
> +be useful, this option requires a debugger capable of reading .dwo
> +files.
> +
>  @item -ggdb
>  @opindex ggdb
>  Produce debugging information for use by GDB@.  This means to use the
> Index: gcc/gcc.c
> ===================================================================
> --- gcc/gcc.c   (revision 190603)
> +++ gcc/gcc.c   (working copy)
> @@ -267,6 +267,7 @@
>  static const char *compare_debug_self_opt_spec_function (int, const char **);
>  static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
>  static const char *pass_through_libs_spec_func (int, const char **);
> +static const char *replace_extension_spec_func (int, const char **);
>
>  /* The Specs Language
>
> @@ -447,7 +448,7 @@
>  colon in these constructs, except between . or * and the corresponding
>  word.
>
> -The -O, -f, -m, and -W switches are handled specifically in these
> +The -O, -f, -g, -m, and -W switches are handled specifically in these
>  constructs.  If another value of -O or the negated form of a -f, -m, or
>  -W switch is found later in the command line, the earlier switch
>  value is ignored, except with {S*} where S is just one letter; this
> @@ -480,7 +481,14 @@
>  /* config.h can define ASM_FINAL_SPEC to run a post processor after
>     the assembler has run.  */
>  #ifndef ASM_FINAL_SPEC
> -#define ASM_FINAL_SPEC ""
> +#define ASM_FINAL_SPEC \
> +  "%{gsplit-dwarf: \n\
> +       objcopy --extract-dwo \
> +        %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> +        %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
> +       objcopy --strip-dwo \
> +        %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> +    }"
>  #endif
>
>  /* config.h can define CPP_SPEC to provide extra args to the C preprocessor
> @@ -1262,6 +1270,7 @@
>    { "compare-debug-self-opt",  compare_debug_self_opt_spec_function },
>    { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
>    { "pass-through-libs",       pass_through_libs_spec_func },
> +  { "replace-extension",       replace_extension_spec_func },
>  #ifdef EXTRA_SPEC_FUNCTIONS
>    EXTRA_SPEC_FUNCTIONS
>  #endif
> @@ -5803,7 +5812,7 @@
>     on the command line.  PREFIX_LENGTH is the length of XXX in an {XXX*}
>     spec, or -1 if either exact match or %* is used.
>
> -   A -O switch is obsoleted by a later -O switch.  A -f, -m, or -W switch
> +   A -O switch is obsoleted by a later -O switch.  A -f, -g, -m, or -W switch
>     whose value does not begin with "no-" is obsoleted by the same value
>     with the "no-", similarly for a switch with the "no-" prefix.  */
>
> @@ -5840,7 +5849,7 @@
>           }
>        break;
>
> -    case 'W':  case 'f':  case 'm':
> +    case 'W':  case 'f':  case 'm': case 'g':
>        if (! strncmp (name + 1, "no-", 3))
>         {
>           /* We have Xno-YYY, search for XYYY.  */
> @@ -8363,3 +8372,33 @@
>      }
>    return prepended;
>  }
> +
> +/* %:replace-extension spec function.  Replaces the extension of the
> +   first argument with the second argument.  */
> +
> +const char *
> +replace_extension_spec_func (int argc, const char **argv)
> +{
> +  char *name;
> +  char *p;
> +  char *result;
> +  int i;
> +
> +  if (argc != 2)
> +    fatal_error ("too few arguments to %%:replace-extension");
> +
> +  name = xstrdup (argv[0]);
> +
> +  for (i = strlen(name) - 1; i >= 0; i--)
> +    if (IS_DIR_SEPARATOR (name[i]))
> +      break;
> +
> +  p = strrchr (name + i + 1, '.');
> +  if (p != NULL)
> +      *p = '\0';
> +
> +  result = concat (name, argv[1], NULL);
> +
> +  free (name);
> +  return result;
> +}
> Index: gcc/dwarf2out.c
> ===================================================================
> --- gcc/dwarf2out.c     (revision 190603)
> +++ gcc/dwarf2out.c     (working copy)
> @@ -145,14 +145,19 @@
>
>  /* Pointers to various DWARF2 sections.  */
>  static GTY(()) section *debug_info_section;
> +static GTY(()) section *debug_skeleton_info_section;
>  static GTY(()) section *debug_abbrev_section;
> +static GTY(()) section *debug_skeleton_abbrev_section;
>  static GTY(()) section *debug_aranges_section;
> +static GTY(()) section *debug_addr_section;
>  static GTY(()) section *debug_macinfo_section;
>  static GTY(()) section *debug_line_section;
> +static GTY(()) section *debug_skeleton_line_section;
>  static GTY(()) section *debug_loc_section;
>  static GTY(()) section *debug_pubnames_section;
>  static GTY(()) section *debug_pubtypes_section;
>  static GTY(()) section *debug_str_section;
> +static GTY(()) section *debug_str_offsets_section;
>  static GTY(()) section *debug_ranges_section;
>  static GTY(()) section *debug_frame_section;
>
> @@ -195,6 +200,7 @@
>    unsigned int refcount;
>    enum dwarf_form form;
>    char *label;
> +  unsigned int index;
>  };
>
>  static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
> @@ -1201,7 +1207,8 @@
>     their entire life.  */
>  typedef struct GTY(()) dw_loc_list_struct {
>    dw_loc_list_ref dw_loc_next;
> -  const char *begin; /* Label for begin address of range */
> +  const char *begin; /* Label and index for begin address of range */
> +  unsigned int begin_index;
>    const char *end;  /* Label for end address of range */
>    char *ll_symbol; /* Label for beginning of location list.
>                       Only on head of list */
> @@ -1246,8 +1253,10 @@
>
>    descr->dw_loc_opc = op;
>    descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
> +  descr->dw_loc_oprnd1.val_index = -1U;
>    descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
>    descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
> +  descr->dw_loc_oprnd2.val_index = -1U;
>    descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
>
>    return descr;
> @@ -1452,6 +1461,10 @@
>      case DW_OP_addr:
>        size += DWARF2_ADDR_SIZE;
>        break;
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      size += size_of_uleb128 (loc->dw_loc_oprnd1.val_index);
> +      break;
>      case DW_OP_const1u:
>      case DW_OP_const1s:
>        size += 1;
> @@ -1888,6 +1901,12 @@
>         }
>        break;
>
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_index,
> +                                   "(index into .debug_addr)");
> +      break;
> +
>      case DW_OP_GNU_implicit_pointer:
>        {
>         char label[MAX_ARTIFICIAL_LABEL_BYTES
> @@ -2063,6 +2082,8 @@
>    switch (loc->dw_loc_opc)
>      {
>      case DW_OP_addr:
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
>      case DW_OP_implicit_value:
>        /* We cannot output addresses in .cfi_escape, only bytes.  */
>        gcc_unreachable ();
> @@ -2246,6 +2267,7 @@
>      {
>        head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
>        head->dw_loc_oprnd1.val_class = dw_val_class_const;
> +      head->dw_loc_oprnd1.val_index = -1U;
>        tmp = new_loc_descr (DW_OP_deref, 0, 0);
>        add_loc_descr (&head, tmp);
>        if (offset != 0)
> @@ -2875,6 +2897,8 @@
>  static tree decl_class_context (tree);
>  static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
>  static inline enum dw_val_class AT_class (dw_attr_ref);
> +static inline unsigned int AT_index (dw_attr_ref);
> +static inline void set_AT_index (dw_attr_ref, unsigned int);
>  static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned);
>  static inline unsigned AT_flag (dw_attr_ref);
>  static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
> @@ -2902,15 +2926,18 @@
>  static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
>                              dw_loc_list_ref);
>  static inline dw_loc_list_ref AT_loc_list (dw_attr_ref);
> -static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx);
> +static unsigned int add_addr_table_entry (dw_attr_node *);
> +static void remove_addr_table_entry (unsigned int);
> +static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
>  static inline rtx AT_addr (dw_attr_ref);
> -static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
> +static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *,
> +                          bool);
>  static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
>  static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
>  static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
>                            unsigned HOST_WIDE_INT);
>  static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
> -                              unsigned long);
> +                              unsigned long, bool);
>  static inline const char *AT_lbl (dw_attr_ref);
>  static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute);
>  static const char *get_AT_low_pc (dw_die_ref);
> @@ -3005,6 +3032,7 @@
>  static enum dwarf_form value_format (dw_attr_ref);
>  static void output_value_format (dw_attr_ref);
>  static void output_abbrev_section (void);
> +static void output_die_abbrevs (unsigned long, dw_die_ref);
>  static void output_die_symbol (dw_die_ref);
>  static void output_die (dw_die_ref);
>  static void output_compilation_unit_header (void);
> @@ -3020,10 +3048,10 @@
>  static unsigned int add_ranges_num (int);
>  static unsigned int add_ranges (const_tree);
>  static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
> -                                 bool *);
> +                                 bool *, bool);
>  static void output_ranges (void);
>  static dw_line_info_table *new_line_info_table (void);
> -static void output_line_info (void);
> +static void output_line_info (bool);
>  static void output_file_names (void);
>  static dw_die_ref base_type_die (tree);
>  static int is_base_type (tree);
> @@ -3162,36 +3190,130 @@
>  static void schedule_generic_params_dies_gen (tree t);
>  static void gen_scheduled_generic_parms_dies (void);
>
> +/* enum for tracking thread-local variables whose address is really an offset
> +   relative to the TLS pointer, which will need link-time relocation, but will
> +   not need relocation by the DWARF consumer.  */
> +
> +enum dtprel_bool
> +  {
> +    dtprel_false = 0,
> +    dtprel_true = 1
> +  };
> +
> +/* Return the operator to use for an address of a variable.  For dtprel_true, we
> +   use DW_OP_const*.  For regular variables, which need both link-time
> +   relocation and consumer-level relocation (e.g., to account for shared objects
> +   loaded at a random address), we use DW_OP_addr*.  */
> +
> +static inline enum dwarf_location_atom
> +dw_addr_op (enum dtprel_bool dtprel)
> +{
> +  if (dtprel == dtprel_true)
> +    return (dwarf_split_debug_info ? DW_OP_GNU_const_index
> +            : (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u));
> +  else
> +    return (dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr);
> +}
> +
> +/* Return a pointer to a newly allocated address location description.  If
> +   dwarf_split_debug_info is true, then record the address with the appropriate
> +   relocation.  */
> +static inline dw_loc_descr_ref
> +new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
> +{
> +  dw_loc_descr_ref ref = new_loc_descr (dw_addr_op (dtprel), 0, 0);
> +
> +  ref->dw_loc_oprnd1.val_class = dw_val_class_addr;
> +  ref->dw_loc_oprnd1.val_index = -1U;
> +  ref->dw_loc_oprnd1.v.val_addr = addr;
> +  ref->dtprel = dtprel;
> +  if (dwarf_split_debug_info)
> +    {
> +      dw_attr_node attr;
> +
> +      attr.dw_attr = DW_AT_location;
> +      attr.dw_attr_val.val_class = (dtprel == dtprel_true
> +                                    ? dw_val_class_loc : dw_val_class_addr);
> +      attr.dw_attr_val.val_index = -1U;
> +      attr.dw_attr_val.v.val_addr = addr;
> +
> +      ref->dw_loc_oprnd1.val_index = add_addr_table_entry (&attr);
> +    }
> +  return ref;
> +}
> +
>  /* Section names used to hold DWARF debugging information.  */
> +
>  #ifndef DEBUG_INFO_SECTION
>  #define DEBUG_INFO_SECTION     ".debug_info"
>  #endif
> +#ifndef DEBUG_DWO_INFO_SECTION
> +#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
> +#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_ARANGES_SECTION
>  #define DEBUG_ARANGES_SECTION  ".debug_aranges"
>  #endif
> +#ifndef DEBUG_ADDR_SECTION
> +#define DEBUG_ADDR_SECTION     ".debug_addr"
> +#endif
> +#ifndef DEBUG_NORM_MACINFO_SECTION
> +#define DEBUG_NORM_MACINFO_SECTION     ".debug_macinfo"
> +#endif
> +#ifndef DEBUG_DWO_MACINFO_SECTION
> +#define DEBUG_DWO_MACINFO_SECTION      ".debug_macinfo.dwo"
> +#endif
>  #ifndef DEBUG_MACINFO_SECTION
> -#define DEBUG_MACINFO_SECTION  ".debug_macinfo"
> +#define DEBUG_MACINFO_SECTION                                           \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_MACINFO_SECTION) : (DEBUG_DWO_MACINFO_SECTION))
>  #endif
> +#ifndef DEBUG_NORM_MACRO_SECTION
> +#define DEBUG_NORM_MACRO_SECTION ".debug_macro"
> +#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"
> +#define DEBUG_MACRO_SECTION                                             \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_MACRO_SECTION) : (DEBUG_DWO_MACRO_SECTION))
>  #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_LOC_SECTION
>  #define DEBUG_LOC_SECTION      ".debug_loc"
>  #endif
> +#ifndef DEBUG_DWO_LOC_SECTION
> +#define DEBUG_DWO_LOC_SECTION  ".debug_loc.dwo"
> +#endif
>  #ifndef DEBUG_PUBNAMES_SECTION
>  #define DEBUG_PUBNAMES_SECTION ".debug_pubnames"
>  #endif
>  #ifndef DEBUG_PUBTYPES_SECTION
>  #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes"
>  #endif
> +#define DEBUG_NORM_STR_OFFSETS_SECTION ".debug_str_offsets"
> +#define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo"
> +#ifndef DEBUG_STR_OFFSETS_SECTION
> +#define DEBUG_STR_OFFSETS_SECTION                                       \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_STR_OFFSETS_SECTION) : (DEBUG_DWO_STR_OFFSETS_SECTION))
> +#endif
> +#define DEBUG_DWO_STR_SECTION   ".debug_str.dwo"
> +#define DEBUG_NORM_STR_SECTION  ".debug_str"
>  #ifndef DEBUG_STR_SECTION
> -#define DEBUG_STR_SECTION      ".debug_str"
> +#define DEBUG_STR_SECTION                               \
> +  (!dwarf_split_debug_info ? (DEBUG_NORM_STR_SECTION) : (DEBUG_DWO_STR_SECTION))
>  #endif
>  #ifndef DEBUG_RANGES_SECTION
>  #define DEBUG_RANGES_SECTION   ".debug_ranges"
> @@ -3202,44 +3324,63 @@
>  #define TEXT_SECTION_NAME      ".text"
>  #endif
>
> +/* Section flags for .debug_macinfo/.debug_macro section.  */
> +#define DEBUG_MACRO_SECTION_FLAGS \
> +  (dwarf_split_debug_info ? SECTION_DEBUG | SECTION_EXCLUDE : SECTION_DEBUG)
> +
>  /* Section flags for .debug_str section.  */
>  #define DEBUG_STR_SECTION_FLAGS \
> -  (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings              \
> -   ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1       \
> -   : SECTION_DEBUG)
> +  (dwarf_split_debug_info \
> +   ? SECTION_DEBUG | SECTION_EXCLUDE \
> +   : (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings \
> +      ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1        \
> +      : SECTION_DEBUG))
>
>  /* Labels we insert at beginning sections we can reference instead of
>     the section names themselves.  */
>
>  #ifndef TEXT_SECTION_LABEL
> -#define TEXT_SECTION_LABEL             "Ltext"
> +#define TEXT_SECTION_LABEL                 "Ltext"
>  #endif
>  #ifndef COLD_TEXT_SECTION_LABEL
> -#define COLD_TEXT_SECTION_LABEL         "Ltext_cold"
> +#define COLD_TEXT_SECTION_LABEL             "Ltext_cold"
>  #endif
>  #ifndef DEBUG_LINE_SECTION_LABEL
> -#define DEBUG_LINE_SECTION_LABEL       "Ldebug_line"
> +#define DEBUG_LINE_SECTION_LABEL           "Ldebug_line"
>  #endif
> +#ifndef DEBUG_SKELETON_LINE_SECTION_LABEL
> +#define DEBUG_SKELETON_LINE_SECTION_LABEL   "Lskeleton_debug_line"
> +#endif
>  #ifndef DEBUG_INFO_SECTION_LABEL
> -#define DEBUG_INFO_SECTION_LABEL       "Ldebug_info"
> +#define DEBUG_INFO_SECTION_LABEL           "Ldebug_info"
>  #endif
> +#ifndef DEBUG_SKELETON_INFO_SECTION_LABEL
> +#define DEBUG_SKELETON_INFO_SECTION_LABEL   "Lskeleton_debug_info"
> +#endif
>  #ifndef DEBUG_ABBREV_SECTION_LABEL
> -#define DEBUG_ABBREV_SECTION_LABEL     "Ldebug_abbrev"
> +#define DEBUG_ABBREV_SECTION_LABEL         "Ldebug_abbrev"
>  #endif
> +#ifndef DEBUG_SKELETON_ABBREV_SECTION_LABEL
> +#define DEBUG_SKELETON_ABBREV_SECTION_LABEL "Lskeleton_debug_abbrev"
> +#endif
> +#ifndef DEBUG_ADDR_SECTION_LABEL
> +#define DEBUG_ADDR_SECTION_LABEL           "Ldebug_addr"
> +#endif
>  #ifndef DEBUG_LOC_SECTION_LABEL
> -#define DEBUG_LOC_SECTION_LABEL                "Ldebug_loc"
> +#define DEBUG_LOC_SECTION_LABEL                    "Ldebug_loc"
>  #endif
>  #ifndef DEBUG_RANGES_SECTION_LABEL
> -#define DEBUG_RANGES_SECTION_LABEL     "Ldebug_ranges"
> +#define DEBUG_RANGES_SECTION_LABEL         "Ldebug_ranges"
>  #endif
>  #ifndef DEBUG_MACINFO_SECTION_LABEL
> -#define DEBUG_MACINFO_SECTION_LABEL     "Ldebug_macinfo"
> +#define DEBUG_MACINFO_SECTION_LABEL         "Ldebug_macinfo"
>  #endif
>  #ifndef DEBUG_MACRO_SECTION_LABEL
> -#define DEBUG_MACRO_SECTION_LABEL      "Ldebug_macro"
> +#define DEBUG_MACRO_SECTION_LABEL          "Ldebug_macro"
>  #endif
> +#define SKELETON_COMP_DIE_ABBREV 1
> +#define SKELETON_TYPE_DIE_ABBREV 2
>
> -
>  /* Definitions of defaults for formats and names of various special
>     (artificial) labels which may be generated within this file (when the -g
>     options is used and DWARF2_DEBUGGING_INFO is in effect.
> @@ -3252,7 +3393,11 @@
>  static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_addr_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
> @@ -3493,6 +3638,31 @@
>    return a->dw_attr_val.val_class;
>  }
>
> +/* Return the index for any attribute that will be referenced with a
> +   DW_FORM_GNU_addr_index.  Strings have their indices handled differently to
> +   account for reference counting pruning.  */
> +
> +static inline unsigned int
> +AT_index (dw_attr_ref a)
> +{
> +  if (AT_class (a) == dw_val_class_str)
> +    return a->dw_attr_val.v.val_str->index;
> +  else
> +    return a->dw_attr_val.val_index;
> +}
> +
> +/* Set the index for any attribute that will be referenced with a
> +   DW_FORM_GNU_addr_index.  */
> +
> +static inline void
> +set_AT_index (dw_attr_ref a, unsigned int index)
> +{
> +  if (AT_class (a) == dw_val_class_str)
> +    a->dw_attr_val.v.val_str->index = index;
> +  else
> +    a->dw_attr_val.val_index = index;
> +}
> +
>  /* Add a flag value attribute to a DIE.  */
>
>  static inline void
> @@ -3502,6 +3672,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_flag;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_flag = flag;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3522,6 +3693,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_const;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_int = int_val;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3543,6 +3715,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_unsigned = unsigned_val;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3564,6 +3737,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_const_double;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_double.high = high;
>    attr.dw_attr_val.v.val_double.low = low;
>    add_dwarf_attr (die, &attr);
> @@ -3579,6 +3753,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_vec;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_vec.length = length;
>    attr.dw_attr_val.v.val_vec.elt_size = elt_size;
>    attr.dw_attr_val.v.val_vec.array = array;
> @@ -3595,28 +3770,39 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_data8;
> +  attr.dw_attr_val.val_index = -1U;
>    memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  */
> +/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  The parameter force_direct
> +   makes the attribute use DW_AT_addr, rather than DW_AT_GNU_addr_index.  */
> +
>  static inline void
> -add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high)
> +add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high,
> +                   bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = DW_AT_low_pc;
>    attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_low);
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, DW_AT_low_pc), add_addr_table_entry (&attr));
>
>    attr.dw_attr = DW_AT_high_pc;
>    if (dwarf_version < 4)
>      attr.dw_attr_val.val_class = dw_val_class_lbl_id;
>    else
>      attr.dw_attr_val.val_class = dw_val_class_high_pc;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_high);
>    add_dwarf_attr (die, &attr);
> +  if (attr.dw_attr_val.val_class == dw_val_class_lbl_id
> +      && dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, DW_AT_high_pc), add_addr_table_entry (&attr));
>  }
>
>  /* Hash and equality functions for debug_str_hash.  */
> @@ -3673,6 +3859,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_str;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_str = node;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3684,6 +3871,38 @@
>    return a->dw_attr_val.v.val_str->str;
>  }
>
> +/* A vector for a table of strings in the form DW_FORM_GNU_index_str.  */
> +
> +typedef struct indirect_string_node indirect_string_node;
> +DEF_VEC_O(indirect_string_node);
> +DEF_VEC_ALLOC_O(indirect_string_node, gc);
> +static GTY (()) VEC (indirect_string_node, gc) *index_string_table;
> +
> +/* Add a new indirect string to the appropriate tables.  Returns the index of
> +   the new string.  Call this function directly to bypass AT_string_form's logic
> +   to put the string inline in the die. */
> +
> +static unsigned long
> +add_indirect_string (struct indirect_string_node *node, const char *str)
> +{
> +  static unsigned int index_string_count = 0;
> +  ++dw2_string_counter;
> +  node->label = xstrdup (str);
> +
> +  if (!dwarf_split_debug_info)
> +    {
> +      node->form = DW_FORM_strp;
> +      return -1U;
> +    }
> +  else
> +    {
> +      node->form = DW_FORM_GNU_str_index;
> +      index_string_count++;
> +      VEC_safe_push (indirect_string_node, gc, index_string_table, node);
> +      return index_string_count;
> +    }
> +}
> +
>  /* Find out whether a string should be output inline in DIE
>     or out-of-line in .debug_str section.  */
>
> @@ -3716,10 +3935,9 @@
>      return node->form = DW_FORM_string;
>
>    ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
> -  ++dw2_string_counter;
> -  node->label = xstrdup (label);
> +  set_AT_index (a, add_indirect_string (node, label));
>
> -  return node->form = DW_FORM_strp;
> +  return node->form;
>  }
>
>  /* Add a DIE reference attribute value to a DIE.  */
> @@ -3740,6 +3958,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_die_ref;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_die_ref.die = targ_die;
>    attr.dw_attr_val.v.val_die_ref.external = 0;
>    add_dwarf_attr (die, &attr);
> @@ -3798,6 +4017,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_fde_ref;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_fde_index = targ_fde;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3811,6 +4031,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_loc;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_loc = loc;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3829,6 +4050,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_loc_list;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_loc_list = loc_list;
>    add_dwarf_attr (die, &attr);
>    have_location_lists = true;
> @@ -3848,17 +4070,62 @@
>    return &a->dw_attr_val.v.val_loc_list;
>  }
>
> -/* Add an address constant attribute value to a DIE.  */
> +/* A table of entries into the .debug_addr section.  */
>
> +static GTY (()) VEC (dw_attr_node,gc) * addr_index_table;
> +
> +static unsigned int
> +add_addr_table_entry (dw_attr_node *attr)
> +{
> +  gcc_assert (dwarf_split_debug_info);
> +
> +  VEC_safe_push (dw_attr_node, gc, addr_index_table, attr);
> +  return VEC_length (dw_attr_node, addr_index_table) - 1;
> +}
> +
> +/* Remove an entry from the addr table.  Since we have already numbered
> +   all the entries, the best we can do here is null it out.  */
> +
> +static void
> +remove_addr_table_entry (unsigned int i)
> +{
> +  dw_attr_node *attr;
> +
> +  gcc_assert (dwarf_split_debug_info);
> +  gcc_assert (i < VEC_length (dw_attr_node, addr_index_table));
> +
> +  attr = &VEC_index (dw_attr_node, addr_index_table, i);
> +  attr->dw_attr = (enum dwarf_attribute) 0;
> +}
> +
> +/* Given a location list, remove all addresses it refers to from the
> +   address_table.  */
> +
> +static void
> +remove_loc_list_addr_table_entries (dw_loc_descr_ref descr)
> +{
> +  for (; descr; descr = descr->dw_loc_next)
> +    if (descr->dw_loc_oprnd1.val_index != -1U)
> +      remove_addr_table_entry (descr->dw_loc_oprnd1.val_index);
> +}
> +
> +/* Add an address constant attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
> +
>  static inline void
> -add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
> +add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr,
> +            bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_addr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_addr = addr;
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
>  }
>
>  /* Get the RTX from to an address DIE attribute.  */
> @@ -3880,6 +4147,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_file;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_file = fd;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3903,22 +4171,29 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_vms_delta;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1);
>    attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2);
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add a label identifier attribute value to a DIE.  */
> +/* Add a label identifier attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static inline void
> -add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
> +add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind,
> +              const char *lbl_id, bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
>  }
>
>  /* Add a section offset attribute value to a DIE, an offset into the
> @@ -3932,6 +4207,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_lineptr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3947,6 +4223,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_macptr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3961,20 +4238,31 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_offset;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_offset = offset;
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add an range_list attribute value to a DIE.  */
> +/* Add a range_list attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static void
>  add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
> -                  long unsigned int offset)
> +                  long unsigned int offset, bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_range_list;
> +  /* For the range_list attribute, val_index == -1U indicates that we want to
> +     output a relocated reference to the range list entry, while any other
> +     value indicates that we want to output the section-relative offset of the
> +     range list entry. In this case, we're not using the val_index field as a
> +     slot index like we do for references to .debug_addr.  This is used
> +     in output_range_list_offset.  */
> +  attr.dw_attr_val.val_index
> +      = (dwarf_split_debug_info && !force_direct) ? offset : -1U;
>    attr.dw_attr_val.v.val_offset = offset;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -7158,6 +7446,7 @@
>    unsigned long size = 0;
>    dw_attr_ref a;
>    unsigned ix;
> +  enum dwarf_form form;
>
>    size += size_of_uleb128 (die->die_abbrev);
>    FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
> @@ -7165,7 +7454,10 @@
>        switch (AT_class (a))
>         {
>         case dw_val_class_addr:
> -         size += DWARF2_ADDR_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF2_ADDR_SIZE;
>           break;
>         case dw_val_class_offset:
>           size += DWARF_OFFSET_SIZE;
> @@ -7183,10 +7475,13 @@
>           }
>           break;
>         case dw_val_class_loc_list:
> -         size += DWARF_OFFSET_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_range_list:
> -         size += DWARF_OFFSET_SIZE;
> +          size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_const:
>           size += size_of_sleb128 (AT_int (a));
> @@ -7246,15 +7541,21 @@
>           size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_lbl_id:
> -         size += DWARF2_ADDR_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF2_ADDR_SIZE;
>           break;
>         case dw_val_class_lineptr:
>         case dw_val_class_macptr:
> -         size += DWARF_OFFSET_SIZE;
> +          size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_str:
> -         if (AT_string_form (a) == DW_FORM_strp)
> +          form = AT_string_form (a);
> +          if (form == DW_FORM_strp)
>             size += DWARF_OFFSET_SIZE;
> +         else if (form == DW_FORM_GNU_str_index)
> +            size += size_of_uleb128 (AT_index (a));
>           else
>             size += strlen (a->dw_attr_val.v.val_str->str) + 1;
>           break;
> @@ -7439,7 +7740,7 @@
>  static enum dwarf_form
>  value_format (dw_attr_ref a)
>  {
> -  switch (a->dw_attr_val.val_class)
> +  switch (AT_class (a))
>      {
>      case dw_val_class_addr:
>        /* Only very few attributes allow DW_FORM_addr.  */
> @@ -7449,7 +7750,8 @@
>         case DW_AT_high_pc:
>         case DW_AT_entry_pc:
>         case DW_AT_trampoline:
> -         return DW_FORM_addr;
> +          return (dwarf_split_debug_info && AT_index (a) != -1U
> +                 ? DW_FORM_GNU_addr_index : DW_FORM_addr);
>         default:
>           break;
>         }
> @@ -7565,7 +7867,8 @@
>      case dw_val_class_fde_ref:
>        return DW_FORM_data;
>      case dw_val_class_lbl_id:
> -      return DW_FORM_addr;
> +      return (dwarf_split_debug_info && AT_index (a) != -1U
> +             ? DW_FORM_GNU_addr_index : DW_FORM_addr);
>      case dw_val_class_lineptr:
>      case dw_val_class_macptr:
>        return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
> @@ -7613,6 +7916,36 @@
>    dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
>  }
>
> +/* Given a die and id, produce the appropriate abbreviations.  */
> +
> +static void
> +output_die_abbrevs (unsigned long abbrev_id, dw_die_ref abbrev)
> +{
> +  unsigned ix;
> +  dw_attr_ref a_attr;
> +
> +  dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
> +  dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
> +                               dwarf_tag_name (abbrev->die_tag));
> +
> +  if (abbrev->die_child != NULL)
> +    dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
> +  else
> +    dw2_asm_output_data (1, DW_children_no, "DW_children_no");
> +
> +  for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
> +       ix++)
> +    {
> +      dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
> +                                   dwarf_attr_name (a_attr->dw_attr));
> +      output_value_format (a_attr);
> +    }
> +
> +  dw2_asm_output_data (1, 0, NULL);
> +  dw2_asm_output_data (1, 0, NULL);
> +}
> +
> +
>  /* Output the .debug_abbrev section which defines the DIE abbreviation
>     table.  */
>
> @@ -7622,32 +7955,8 @@
>    unsigned long abbrev_id;
>
>    for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
> -    {
> -      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
> -      unsigned ix;
> -      dw_attr_ref a_attr;
> +    output_die_abbrevs (abbrev_id, abbrev_die_table[abbrev_id]);
>
> -      dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
> -      dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
> -                                  dwarf_tag_name (abbrev->die_tag));
> -
> -      if (abbrev->die_child != NULL)
> -       dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
> -      else
> -       dw2_asm_output_data (1, DW_children_no, "DW_children_no");
> -
> -      for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
> -          ix++)
> -       {
> -         dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
> -                                      dwarf_attr_name (a_attr->dw_attr));
> -         output_value_format (a_attr);
> -       }
> -
> -      dw2_asm_output_data (1, 0, NULL);
> -      dw2_asm_output_data (1, 0, NULL);
> -    }
> -
>    /* Terminate the table.  */
>    dw2_asm_output_data (1, 0, NULL);
>  }
> @@ -7683,6 +7992,7 @@
>    dw_loc_list_ref retlist = ggc_alloc_cleared_dw_loc_list_node ();
>
>    retlist->begin = begin;
> +  retlist->begin_index = -1U;
>    retlist->end = end;
>    retlist->expr = expr;
>    retlist->section = section;
> @@ -7727,7 +8037,22 @@
>          in a single range are unlikely very useful.  */
>        if (size > 0xffff)
>         continue;
> -      if (!have_multiple_function_sections)
> +      if (dwarf_split_debug_info)
> +        {
> +          dw2_asm_output_data (1, DW_LLE_GNU_start_length_entry,
> +                               "Location list start/length entry (%s)",
> +                               list_head->ll_symbol);
> +          dw2_asm_output_data_uleb128 (curr->begin_index,
> +                                       "Location list range start index (%s)",
> +                                       curr->begin);
> +          /* The length field is 4 bytes.  If we ever need to support
> +            an 8-byte length, we can add a new DW_LLE code or fall back
> +            to DW_LLE_GNU_start_end_entry.  */
> +          dw2_asm_output_delta (4, curr->end, curr->begin,
> +                               "Location list range length (%s)",
> +                               list_head->ll_symbol);
> +        }
> +      else if (!have_multiple_function_sections)
>         {
>           dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
>                                 "Location list begin address (%s)",
> @@ -7753,14 +8078,85 @@
>        output_loc_sequence (curr->expr, -1);
>      }
>
> -  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> -                      "Location list terminator begin (%s)",
> -                      list_head->ll_symbol);
> -  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> -                      "Location list terminator end (%s)",
> -                      list_head->ll_symbol);
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_data (1, DW_LLE_GNU_end_of_list_entry,
> +                        "Location list terminator (%s)",
> +                        list_head->ll_symbol);
> +  else
> +    {
> +      dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> +                          "Location list terminator begin (%s)",
> +                          list_head->ll_symbol);
> +      dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> +                          "Location list terminator end (%s)",
> +                          list_head->ll_symbol);
> +    }
>  }
>
> +/* Output the offset into the debug_range section.  */
> +
> +static void
> +output_range_list_offset (dw_attr_ref a)
> +{
> +  const char *name = dwarf_attr_name (a->dw_attr);
> +
> +  if (!dwarf_split_debug_info || AT_index (a) == -1U)
> +    {
> +      char *p = strchr (ranges_section_label, '\0');
> +      sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset);
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
> +                             debug_ranges_section, "%s", name);
> +      *p = '\0';
> +    }
> +  else
> +    dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
> +                         "%s (offset from %s)", name, ranges_section_label);
> +}
> +
> +/* Output the offset into the debug_loc section.  */
> +
> +static void
> +output_loc_list_offset (dw_attr_ref a)
> +{
> +  char *sym = AT_loc_list (a)->ll_symbol;
> +
> +  gcc_assert (sym);
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
> +                          "%s", dwarf_attr_name (a->dw_attr));
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
> +                           "%s", dwarf_attr_name (a->dw_attr));
> +}
> +
> +/* Output an attribute's index or value appropriately.  */
> +
> +static void
> +output_attr_index_or_value (dw_attr_ref a)
> +{
> +  const char *name = dwarf_attr_name (a->dw_attr);
> +
> +  if (dwarf_split_debug_info && AT_index (a) != -1U)
> +    {
> +      dw2_asm_output_data_uleb128 (AT_index (a), "%s", name);
> +      return;
> +    }
> +  switch (AT_class (a))
> +    {
> +      case dw_val_class_addr:
> +        dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
> +        break;
> +      case dw_val_class_lbl_id:
> +        dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
> +        break;
> +      case dw_val_class_loc_list:
> +        output_loc_list_offset (a);
> +        break;
> +      default:
> +        gcc_unreachable ();
> +    }
> +}
> +
>  /* Output a type signature.  */
>
>  static inline void
> @@ -7799,7 +8195,7 @@
>        switch (AT_class (a))
>         {
>         case dw_val_class_addr:
> -         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_offset:
> @@ -7808,15 +8204,7 @@
>           break;
>
>         case dw_val_class_range_list:
> -         {
> -           char *p = strchr (ranges_section_label, '\0');
> -
> -           sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
> -                    a->dw_attr_val.v.val_offset);
> -           dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
> -                                  debug_ranges_section, "%s", name);
> -           *p = '\0';
> -         }
> +          output_range_list_offset (a);
>           break;
>
>         case dw_val_class_loc:
> @@ -7872,7 +8260,7 @@
>               }
>
>             dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
> -                                first, name);
> +                                first, "%s", name);
>             dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
>                                  second, NULL);
>           }
> @@ -7919,13 +8307,7 @@
>           break;
>
>         case dw_val_class_loc_list:
> -         {
> -           char *sym = AT_loc_list (a)->ll_symbol;
> -
> -           gcc_assert (sym);
> -           dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
> -                                  "%s", name);
> -         }
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_die_ref:
> @@ -7982,7 +8364,7 @@
>           break;
>
>         case dw_val_class_lbl_id:
> -         dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_lineptr:
> @@ -7996,12 +8378,15 @@
>           break;
>
>         case dw_val_class_str:
> -         if (AT_string_form (a) == DW_FORM_strp)
> +         if (a->dw_attr_val.v.val_str->form == DW_FORM_strp)
>             dw2_asm_output_offset (DWARF_OFFSET_SIZE,
>                                    a->dw_attr_val.v.val_str->label,
>                                    debug_str_section,
>                                    "%s: \"%s\"", name, AT_string (a));
> -         else
> +         else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
> +            dw2_asm_output_data_uleb128 (AT_index (a),
> +                                         "%s: \"%s\"", name, AT_string (a));
> +          else
>             dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
>           break;
>
> @@ -8144,6 +8529,96 @@
>      add_AT_flag (die, DW_AT_GNU_pubnames, 1);
>  }
>
> +/* Helper function to generate top-level dies for skeleton debug_info and
> +   debug_types.  */
> +
> +static void
> +add_top_level_skeleton_die_attrs (dw_die_ref die)
> +{
> +  const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL);
> +  dw_attr_ref attr;
> +
> +  add_comp_dir_attribute (die);
> +  add_AT_string (die, DW_AT_GNU_dwo_name, dwo_file_name);
> +  /* The specification suggests that these attributes be inline to avoid
> +     having a .debug_str section.  We know that they exist in the die because
> +     we just added them.  */
> +  attr = get_AT (die, DW_AT_GNU_dwo_name);
> +  attr->dw_attr_val.v.val_str->form = DW_FORM_string;
> +  attr = get_AT (die, DW_AT_comp_dir);
> +  attr->dw_attr_val.v.val_str->form = DW_FORM_string;
> +
> +  add_AT_pubnames (die);
> +  add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label);
> +}
> +
> +/* Return the single type-unit die for skeleton type units.  */
> +
> +static dw_die_ref
> +get_skeleton_type_unit (void)
> +{
> +  /* For dwarf_split_debug_sections with use_type info, all type units in the
> +     skeleton sections have identical dies (but different headers).  This
> +     single die will be output many times.  */
> +
> +  static dw_die_ref skeleton_type_unit = NULL;
> +
> +  if (skeleton_type_unit == NULL)
> +    {
> +      skeleton_type_unit = new_die (DW_TAG_type_unit, NULL, NULL);
> +      add_top_level_skeleton_die_attrs (skeleton_type_unit);
> +      skeleton_type_unit->die_abbrev = SKELETON_TYPE_DIE_ABBREV;
> +    }
> +  return skeleton_type_unit;
> +}
> +
> +/* Output skeleton debug sections that point to the dwo file.  */
> +
> +static void
> +output_skeleton_debug_sections (dw_die_ref comp_unit)
> +{
> +  /* These attributes will be found in the full debug_info section.  */
> +  remove_AT (comp_unit, DW_AT_producer);
> +  remove_AT (comp_unit, DW_AT_language);
> +
> +  /* Add attributes common to skeleton compile_units and type_units.  */
> +  add_top_level_skeleton_die_attrs (comp_unit);
> +
> +  switch_to_section (debug_skeleton_info_section);
> +  ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_info_section_label);
> +
> +  /* Produce the skeleton compilation-unit header.  This one differs enough from
> +     a normal CU header that it's better not to call output_compilation_unit
> +     header.  */
> +  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
> +    dw2_asm_output_data (4, 0xffffffff,
> +      "Initial length escape value indicating 64-bit DWARF extension");
> +
> +  dw2_asm_output_data (DWARF_OFFSET_SIZE,
> +                      DWARF_COMPILE_UNIT_HEADER_SIZE
> +                       - DWARF_INITIAL_LENGTH_SIZE
> +                       + size_of_die (comp_unit),
> +                      "Length of Compilation Unit Info");
> +  dw2_asm_output_data (2, dwarf_version, "DWARF version number");
> +  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label,
> +                        debug_abbrev_section,
> +                        "Offset Into Abbrev. Section");
> +  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
> +
> +  comp_unit->die_abbrev = SKELETON_COMP_DIE_ABBREV;
> +  output_die (comp_unit);
> +
> +  /* Build the skeleton debug_abbrev section.  */
> +  switch_to_section (debug_skeleton_abbrev_section);
> +  ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_abbrev_section_label);
> +
> +  output_die_abbrevs (SKELETON_COMP_DIE_ABBREV, comp_unit);
> +  if (use_debug_types)
> +    output_die_abbrevs (SKELETON_TYPE_DIE_ABBREV, get_skeleton_type_unit ());
> +
> +  dw2_asm_output_data (1, 0, "end of skeleton .debug_abbrev");
> +}
> +
>  /* Output a comdat type unit DIE and its children.  */
>
>  static void
> @@ -8171,7 +8646,11 @@
>    calc_die_sizes (node->root_die);
>
>  #if defined (OBJECT_FORMAT_ELF)
> -  secname = ".debug_types";
> +  if (!dwarf_split_debug_info)
> +    secname = ".debug_types";
> +  else
> +    secname = ".debug_types.dwo";
> +
>    tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
>    sprintf (tmp, "wt.");
>    for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
> @@ -8180,6 +8659,7 @@
>    targetm.asm_out.named_section (secname,
>                                   SECTION_DEBUG | SECTION_LINKONCE,
>                                   comdat_key);
> +
>  #else
>    tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
>    sprintf (tmp, ".gnu.linkonce.wt.");
> @@ -8197,6 +8677,36 @@
>    output_die (node->root_die);
>
>    unmark_dies (node->root_die);
> +
> +  if (dwarf_split_debug_info)
> +    {
> +      /* Produce the skeleton type-unit header.  */
> +      const char *secname = ".debug_types";
> +
> +      targetm.asm_out.named_section (secname,
> +                                     SECTION_DEBUG | SECTION_LINKONCE,
> +                                     comdat_key);
> +      if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
> +        dw2_asm_output_data (4, 0xffffffff,
> +          "Initial length escape value indicating 64-bit DWARF extension");
> +
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE,
> +                           DWARF_COMPILE_UNIT_HEADER_SIZE
> +                           - DWARF_INITIAL_LENGTH_SIZE
> +                           + size_of_die (get_skeleton_type_unit ())
> +                           + DWARF_TYPE_SIGNATURE_SIZE + DWARF_OFFSET_SIZE,
> +                           "Length of Type Unit Info");
> +      dw2_asm_output_data (2, dwarf_version, "DWARF version number");
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE,
> +                             debug_skeleton_abbrev_section_label,
> +                             debug_abbrev_section,
> +                             "Offset Into Abbrev. Section");
> +      dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
> +      output_signature (node->signature, "Type Signature");
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "Offset to Type DIE");
> +
> +      output_die (get_skeleton_type_unit ());
> +    }
>  }
>
>  /* Return the DWARF2/3 pubname associated with a decl.  */
> @@ -8232,7 +8742,7 @@
>       class_member, it will either be inside the class already, or will have just
>       looked up the class to find the member.  Either way, searching the class is
>       faster than searching the index.  */
> -  if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent))
> +  if ((TREE_PUBLIC (decl) && !class_scope_p (die->die_parent))
>        || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
>      {
>        const char *name = dwarf2_name (decl, 1);
> @@ -8340,9 +8850,14 @@
>                          "Length of Public Type Names Info");
>    /* Version number for pubnames/pubtypes is still 2, even in DWARF3.  */
>    dw2_asm_output_data (2, 2, "DWARF Version");
> -  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> -                        debug_info_section,
> -                        "Offset of Compilation Unit Info");
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
> +                           debug_skeleton_info_section,
> +                           "Offset of Compilation Unit Info");
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> +                           debug_info_section,
> +                           "Offset of Compilation Unit Info");
>    dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
>                        "Compilation Unit Length");
>
> @@ -8403,9 +8918,14 @@
>                        "Length of Address Ranges Info");
>    /* Version number for aranges is still 2, even in DWARF3.  */
>    dw2_asm_output_data (2, 2, "DWARF Version");
> -  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> -                        debug_info_section,
> -                        "Offset of Compilation Unit Info");
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
> +                           debug_skeleton_info_section,
> +                           "Offset of Compilation Unit Info");
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> +                           debug_info_section,
> +                           "Offset of Compilation Unit Info");
>    dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
>    dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
>
> @@ -8502,12 +9022,13 @@
>    return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
>  }
>
> -/* Add a new entry to .debug_ranges corresponding to a pair of
> -   labels.  */
> +/* Add a new entry to .debug_ranges corresponding to a pair of labels.  The
> +   parameter force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static void
>  add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
> -                     bool *added)
> +                     bool *added, bool force_direct)
>  {
>    unsigned int in_use = ranges_by_label_in_use;
>    unsigned int offset;
> @@ -8530,7 +9051,7 @@
>    offset = add_ranges_num (-(int)in_use - 1);
>    if (!*added)
>      {
> -      add_AT_range_list (die, DW_AT_ranges, offset);
> +      add_AT_range_list (die, DW_AT_ranges, offset, force_direct);
>        *added = true;
>      }
>  }
> @@ -9067,7 +9588,7 @@
>     information goes into the .debug_line section.  */
>
>  static void
> -output_line_info (void)
> +output_line_info (bool prologue_only)
>  {
>    char l1[20], l2[20], p1[20], p2[20];
>    int ver = dwarf_version;
> @@ -9137,6 +9658,12 @@
>    /* Write out the information about the files we use.  */
>    output_file_names ();
>    ASM_OUTPUT_LABEL (asm_out_file, p2);
> +  if (prologue_only)
> +    {
> +      /* Output the marker for the end of the line number info.  */
> +      ASM_OUTPUT_LABEL (asm_out_file, l2);
> +      return;
> +    }
>
>    if (separate_line_info)
>      {
> @@ -11437,14 +11964,7 @@
>           if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
>             break;
>
> -         /* We used to emit DW_OP_addr here, but that's wrong, since
> -            DW_OP_addr should be relocated by the debug info consumer,
> -            while DW_OP_GNU_push_tls_address operand should not.  */
> -         temp = new_loc_descr (DWARF2_ADDR_SIZE == 4
> -                               ? DW_OP_const4u : DW_OP_const8u, 0, 0);
> -         temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         temp->dw_loc_oprnd1.v.val_addr = rtl;
> -         temp->dtprel = true;
> +          temp = new_addr_loc_descr (rtl, dtprel_true);
>
>           mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
>           add_loc_descr (&mem_loc_result, temp);
> @@ -11456,9 +11976,7 @@
>         break;
>
>      symref:
> -      mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -      mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +      mem_loc_result = new_addr_loc_descr (rtl, dtprel_false);
>        VEC_safe_push (rtx, gc, used_rtx_array, rtl);
>        break;
>
> @@ -12360,9 +12878,7 @@
>        if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
>           && (dwarf_version >= 4 || !dwarf_strict))
>         {
> -         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +         loc_result = new_addr_loc_descr (rtl, dtprel_false);
>           add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
>           VEC_safe_push (rtx, gc, used_rtx_array, rtl);
>         }
> @@ -13062,9 +13578,8 @@
>        if (DECL_THREAD_LOCAL_P (loc))
>         {
>           rtx rtl;
> -         enum dwarf_location_atom first_op;
> -         enum dwarf_location_atom second_op;
> -         bool dtprel = false;
> +         enum dwarf_location_atom tls_op;
> +         enum dtprel_bool dtprel = dtprel_false;
>
>           if (targetm.have_tls)
>             {
> @@ -13081,9 +13596,8 @@
>                   operand shouldn't be.  */
>               if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
>                 return 0;
> -             first_op = DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u;
> -             dtprel = true;
> -             second_op = DW_OP_GNU_push_tls_address;
> +             dtprel = dtprel_true;
> +             tls_op = DW_OP_GNU_push_tls_address;
>             }
>           else
>             {
> @@ -13095,8 +13609,7 @@
>                  no longer appear in gimple code.  We used the control
>                  variable in specific so that we could pick it up here.  */
>               loc = DECL_VALUE_EXPR (loc);
> -             first_op = DW_OP_addr;
> -             second_op = DW_OP_form_tls_address;
> +             tls_op = DW_OP_form_tls_address;
>             }
>
>           rtl = rtl_for_decl_location (loc);
> @@ -13109,12 +13622,8 @@
>           if (! CONSTANT_P (rtl))
>             return 0;
>
> -         ret = new_loc_descr (first_op, 0, 0);
> -         ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         ret->dw_loc_oprnd1.v.val_addr = rtl;
> -         ret->dtprel = dtprel;
> -
> -         ret1 = new_loc_descr (second_op, 0, 0);
> +          ret = new_addr_loc_descr (rtl, dtprel);
> +         ret1 = new_loc_descr (tls_op, 0, 0);
>           add_loc_descr (&ret, ret1);
>
>           have_address = 1;
> @@ -13159,11 +13668,7 @@
>             return 0;
>           }
>         else if (CONSTANT_P (rtl) && const_ok_for_output (rtl))
> -         {
> -           ret = new_loc_descr (DW_OP_addr, 0, 0);
> -           ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -           ret->dw_loc_oprnd1.v.val_addr = rtl;
> -         }
> +          ret = new_addr_loc_descr (rtl, dtprel_false);
>         else
>           {
>             enum machine_mode mode, mem_mode;
> @@ -14091,9 +14596,7 @@
>           dw_loc_descr_ref loc_result;
>           resolve_one_addr (&rtl, NULL);
>         rtl_addr:
> -         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +         loc_result = new_addr_loc_descr (rtl, dtprel_false);
>           add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
>           add_AT_loc (die, DW_AT_location, loc_result);
>           VEC_safe_push (rtx, gc, used_rtx_array, rtl);
> @@ -15611,7 +16114,7 @@
>    if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
>      {
>        add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
> -                  XEXP (DECL_RTL (decl), 0));
> +                  XEXP (DECL_RTL (decl), 0), false);
>        VEC_safe_push (rtx, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
>      }
>  #endif /* VMS_DEBUGGING_INFO */
> @@ -15632,7 +16135,7 @@
>    add_name_attribute (die, VMS_DEBUG_MAIN_POINTER);
>    ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
>                                current_function_funcdef_no);
> -  add_AT_lbl_id (die, DW_AT_entry_pc, label);
> +  add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
>
>    /* Make it the first child of comp_unit_die ().  */
>    die->die_parent = comp_unit_die ();
> @@ -16223,7 +16726,7 @@
>    if (DECL_ABSTRACT (decl))
>      equate_decl_number_to_die (decl, decl_die);
>    else
> -    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
> +    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl), false);
>  }
>  #endif
>
> @@ -16873,7 +17376,7 @@
>    if (stmt_die == NULL)
>      stmt_die = subr_die;
>    die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
> -  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
> +  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label, false);
>    if (ca_loc->tail_call_p)
>      add_AT_flag (die, DW_AT_GNU_tail_call, 1);
>    if (ca_loc->symbol_ref)
> @@ -16882,7 +17385,7 @@
>        if (tdie)
>         add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
>        else
> -       add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref);
> +       add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref, false);
>      }
>    return die;
>  }
> @@ -17073,7 +17576,8 @@
>           if (fde->dw_fde_begin)
>             {
>               /* We have already generated the labels.  */
> -             add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end);
> +             add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
> +                                 fde->dw_fde_end, false);
>             }
>           else
>             {
> @@ -17084,7 +17588,8 @@
>                                            current_function_funcdef_no);
>               ASM_GENERATE_INTERNAL_LABEL (label_id_high, FUNC_END_LABEL,
>                                            current_function_funcdef_no);
> -             add_AT_low_high_pc (subr_die, label_id_low, label_id_high);
> +             add_AT_low_high_pc (subr_die, label_id_low, label_id_high,
> +                                 false);
>             }
>
>  #if VMS_DEBUGGING_INFO
> @@ -17127,10 +17632,11 @@
>                      alignment offset.  */
>                   bool range_list_added = false;
>                   add_ranges_by_labels (subr_die, fde->dw_fde_begin,
> -                                       fde->dw_fde_end, &range_list_added);
> +                                       fde->dw_fde_end, &range_list_added,
> +                                       false);
>                   add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
>                                         fde->dw_fde_second_end,
> -                                       &range_list_added);
> +                                       &range_list_added, false);
>                   if (range_list_added)
>                     add_ranges (NULL);
>                 }
> @@ -17149,7 +17655,7 @@
>
>                   /* Do the 'primary' section.   */
>                   add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
> -                                     fde->dw_fde_end);
> +                                     fde->dw_fde_end, false);
>
>                   /* Build a minimal DIE for the secondary section.  */
>                   seg_die = new_die (DW_TAG_subprogram,
> @@ -17174,14 +17680,15 @@
>
>                   name = concat ("__second_sect_of_", name, NULL);
>                   add_AT_low_high_pc (seg_die, fde->dw_fde_second_begin,
> -                                     fde->dw_fde_second_end);
> +                                     fde->dw_fde_second_end, false);
>                   add_name_attribute (seg_die, name);
>                   if (want_pubnames ())
>                     add_pubname_string (name, seg_die);
>                 }
>             }
>           else
> -           add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end);
> +           add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end,
> +                               false);
>         }
>
>        cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
> @@ -17622,7 +18129,7 @@
>             {
>               /* Optimize the common case.  */
>               if (single_element_loc_list_p (loc)
> -                 && loc->expr->dw_loc_opc == DW_OP_addr
> +                  && loc->expr->dw_loc_opc == DW_OP_addr
>                   && loc->expr->dw_loc_next == NULL
>                   && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
>                 {
> @@ -17809,7 +18316,7 @@
>           gcc_assert (!INSN_DELETED_P (insn));
>
>           ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
> -         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
> +         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
>         }
>        else if (insn
>                && NOTE_P (insn)
> @@ -17817,7 +18324,7 @@
>                && CODE_LABEL_NUMBER (insn) != -1)
>         {
>           ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn));
> -         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
> +         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
>         }
>      }
>  }
> @@ -17858,7 +18365,7 @@
>         {
>           ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
>                                        BLOCK_NUMBER (stmt));
> -         add_AT_lbl_id (die, DW_AT_entry_pc, label);
> +         add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
>         }
>
>        /* Optimize duplicate .debug_ranges lists or even tails of
> @@ -17906,12 +18413,13 @@
>             ++thiscnt;
>           gcc_assert (supercnt >= thiscnt);
>           add_AT_range_list (die, DW_AT_ranges,
> -                            (off + supercnt - thiscnt)
> -                            * 2 * DWARF2_ADDR_SIZE);
> +                            ((off + supercnt - thiscnt)
> +                             * 2 * DWARF2_ADDR_SIZE),
> +                            false);
>           return;
>         }
>
> -      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
> +      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt), false);
>
>        chain = BLOCK_FRAGMENT_CHAIN (stmt);
>        do
> @@ -17929,7 +18437,7 @@
>                                    BLOCK_NUMBER (stmt));
>        ASM_GENERATE_INTERNAL_LABEL (label_high, BLOCK_END_LABEL,
>                                    BLOCK_NUMBER (stmt));
> -      add_AT_low_high_pc (die, label, label_high);
> +      add_AT_low_high_pc (die, label, label_high, false);
>      }
>  }
>
> @@ -20518,13 +21026,12 @@
>      case DW_MACRO_GNU_define_indirect:
>      case DW_MACRO_GNU_undef_indirect:
>        node = find_AT_string (ref->info);
> -      if (node->form != DW_FORM_strp)
> +      if ((node->form != DW_FORM_string)
> +          && (node->form != DW_FORM_GNU_str_index))
>         {
>           char label[32];
>           ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
> -         ++dw2_string_counter;
> -         node->label = xstrdup (label);
> -         node->form = DW_FORM_strp;
> +          add_indirect_string (node, label);
>         }
>        dw2_asm_output_data (1, ref->code,
>                            ref->code == DW_MACRO_GNU_define_indirect
> @@ -20705,8 +21212,10 @@
>         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, debug_line_section_label,
> -                            debug_line_section, NULL);
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE,
> +                             (!dwarf_split_debug_info ? debug_line_section_label
> +                              : debug_skeleton_line_section_label),
> +                             debug_line_section, NULL);
>      }
>
>    /* In the first loop, it emits the primary .debug_macinfo section
> @@ -20845,26 +21354,60 @@
>
>    used_rtx_array = VEC_alloc (rtx, gc, 32);
>
> -  debug_info_section = get_section (DEBUG_INFO_SECTION,
> -                                   SECTION_DEBUG, NULL);
> -  debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
> -                                     SECTION_DEBUG, NULL);
> +  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_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_aranges_section = get_section (DEBUG_ARANGES_SECTION,
>                                        SECTION_DEBUG, NULL);
>    debug_macinfo_section = get_section (dwarf_strict
>                                        ? DEBUG_MACINFO_SECTION
>                                        : DEBUG_MACRO_SECTION,
> -                                      SECTION_DEBUG, NULL);
> +                                      DEBUG_MACRO_SECTION_FLAGS, NULL);
>    debug_line_section = get_section (DEBUG_LINE_SECTION,
>                                     SECTION_DEBUG, NULL);
> -  debug_loc_section = get_section (DEBUG_LOC_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_STR_SECTION_FLAGS, NULL);
>    debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
>                                       SECTION_DEBUG, NULL);
>    debug_frame_section = get_section (DEBUG_FRAME_SECTION,
> @@ -20884,10 +21427,13 @@
>                                DEBUG_LINE_SECTION_LABEL, 0);
>    ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
>                                DEBUG_RANGES_SECTION_LABEL, 0);
> +  ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
> +                              DEBUG_ADDR_SECTION_LABEL, 0);
>    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);
>
>    if (debug_info_level >= DINFO_LEVEL_VERBOSE)
>      macinfo_table = VEC_alloc (macinfo_entry, gc, 64);
> @@ -20931,6 +21477,83 @@
>    return 1;
>  }
>
> +/* Output the indexed string table.  */
> +
> +static void
> +output_index_strings (void)
> +{
> +  unsigned int i;
> +  unsigned int len = 0;
> +  struct indirect_string_node *node;
> +
> +  gcc_assert (dwarf_split_debug_info);
> +
> +  if (VEC_empty (indirect_string_node, index_string_table))
> +    return;
> +
> +  switch_to_section (debug_str_offsets_section);
> +  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
> +       i++)
> +    {
> +      gcc_assert (node->form == DW_FORM_GNU_str_index);
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE, len,
> +                           "indexed string 0x%x: %s", i, node->str);
> +      len += strlen (node->str) + 1;
> +    }
> +  switch_to_section (debug_str_section);
> +  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
> +       i++)
> +    {
> +      ASM_OUTPUT_LABEL (asm_out_file, node->label);
> +      assemble_string (node->str, strlen (node->str) + 1);
> +    }
> +}
> +
> +/* Write the index table.  */
> +
> +static void
> +output_addr_table (void)
> +{
> +  unsigned int i;
> +  dw_attr_node *node;
> +
> +  if (VEC_empty (dw_attr_node, addr_index_table))
> +    return;
> +
> +  switch_to_section (debug_addr_section);
> +  for (i = 0; VEC_iterate (dw_attr_node, addr_index_table, i, node); i++)
> +    {
> +      const char *name;
> +
> +      if (node->dw_attr == 0)
> +       {
> +         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, "<Removed entry>");
> +         continue;
> +       }
> +
> +      name = dwarf_attr_name (node->dw_attr);
> +      switch (AT_class (node))
> +        {
> +          case dw_val_class_addr:
> +            dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (node),
> +                                     "%s", name);
> +            break;
> +          case dw_val_class_loc:
> +            gcc_assert (targetm.asm_out.output_dwarf_dtprel);
> +            targetm.asm_out.output_dwarf_dtprel (asm_out_file,
> +                                                 DWARF2_ADDR_SIZE,
> +                                                 node->dw_attr_val.v.val_addr);
> +            fputc ('\n', asm_out_file);
> +            break;
> +          case dw_val_class_lbl_id:
> +            dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (node), "%s", name);
> +            break;
> +          default:
> +            gcc_unreachable ();
> +        }
> +    }
> +}
> +
>  #if ENABLE_ASSERT_CHECKING
>  /* Verify that all marks are clear.  */
>
> @@ -21537,6 +22160,17 @@
>         if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
>           return false;
>         break;
> +      case DW_OP_GNU_addr_index:
> +      case DW_OP_GNU_const_index:
> +        {
> +          unsigned int idx = loc->dw_loc_oprnd1.val_index;
> +          dw_attr_node *node = &VEC_index (dw_attr_node, addr_index_table, idx);
> +          if ((loc->dw_loc_opc == DW_OP_GNU_addr_index
> +               || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
> +              && resolve_one_addr (&node->dw_attr_val.v.val_addr, NULL))
> +            return false;
> +        }
> +       break;
>        case DW_OP_const4u:
>        case DW_OP_const8u:
>         if (loc->dtprel
> @@ -21671,11 +22305,15 @@
>                 if (!resolve_addr_in_expr ((*curr)->expr))
>                   {
>                     dw_loc_list_ref next = (*curr)->dw_loc_next;
> +                   dw_loc_descr_ref l = (*curr)->expr;
> +
>                     if (next && (*curr)->ll_symbol)
>                       {
>                         gcc_assert (!next->ll_symbol);
>                         next->ll_symbol = (*curr)->ll_symbol;
>                       }
> +                   if (dwarf_split_debug_info)
> +                     remove_loc_list_addr_table_entries (l);
>                     *curr = next;
>                   }
>                 else
> @@ -21689,6 +22327,8 @@
>             else
>               {
>                 loc->replaced = 1;
> +                if (dwarf_split_debug_info)
> +                  remove_loc_list_addr_table_entries (loc->expr);
>                 loc->dw_loc_next = *start;
>               }
>           }
> @@ -21713,6 +22353,8 @@
>                || l->dw_loc_next != NULL)
>               && !resolve_addr_in_expr (l))
>             {
> +             if (dwarf_split_debug_info)
> +               remove_loc_list_addr_table_entries (l);
>               remove_AT (die, a->dw_attr);
>               ix--;
>             }
> @@ -21724,6 +22366,8 @@
>         if (a->dw_attr == DW_AT_const_value
>             && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL))
>           {
> +           if (AT_index (a) != -1U)
> +             remove_addr_table_entry (AT_index (a));
>             remove_AT (die, a->dw_attr);
>             ix--;
>           }
> @@ -21747,6 +22391,8 @@
>               }
>             else
>               {
> +               if (AT_index (a) != -1U)
> +                 remove_addr_table_entry (AT_index (a));
>                 remove_AT (die, a->dw_attr);
>                 ix--;
>               }
> @@ -21880,6 +22526,19 @@
>         }
>        hash = iterative_hash_rtx (val1->v.val_addr, hash);
>        break;
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      {
> +        dw_attr_ref attr = &VEC_index (dw_attr_node, addr_index_table,
> +                                      val1->val_index);
> +        if (loc->dtprel)
> +         {
> +            unsigned char dtprel = 0xd1;
> +            hash = iterative_hash_object (dtprel, hash);
> +          }
> +        hash = iterative_hash_rtx (attr->dw_attr_val.v.val_addr, hash);
> +      }
> +      break;
>      case DW_OP_GNU_implicit_pointer:
>        hash = iterative_hash_object (val2->v.val_int, hash);
>        break;
> @@ -22061,9 +22720,12 @@
>        return valx1->v.val_int == valy1->v.val_int;
>      case DW_OP_skip:
>      case DW_OP_bra:
> +      /* If splitting debug info, the use of DW_OP_GNU_addr_index
> +        can cause irrelevant differences in dw_loc_addr.  */
>        gcc_assert (valx1->val_class == dw_val_class_loc
>                   && valy1->val_class == dw_val_class_loc
> -                 && x->dw_loc_addr == y->dw_loc_addr);
> +                 && (dwarf_split_debug_info
> +                     || x->dw_loc_addr == y->dw_loc_addr));
>        return valx1->v.val_loc->dw_loc_addr == valy1->v.val_loc->dw_loc_addr;
>      case DW_OP_implicit_value:
>        if (valx1->v.val_unsigned != valy1->v.val_unsigned
> @@ -22094,6 +22756,18 @@
>      case DW_OP_addr:
>      hash_addr:
>        return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr);
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      {
> +        dw_attr_node *attrx1 = &VEC_index (dw_attr_node,
> +                                           addr_index_table,
> +                                           valx1->val_index);
> +        dw_attr_node *attry1 = &VEC_index (dw_attr_node,
> +                                           addr_index_table,
> +                                           valy1->val_index);
> +        return rtx_equal_p (attrx1->dw_attr_val.v.val_addr,
> +                            attry1->dw_attr_val.v.val_addr);
> +      }
>      case DW_OP_GNU_implicit_pointer:
>        return valx1->val_class == dw_val_class_die_ref
>              && valx1->val_class == valy1->val_class
> @@ -22207,7 +22881,7 @@
>         if (*slot == NULL)
>           *slot = (void *) list;
>         else
> -         a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
> +          a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
>        }
>
>    FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab));
> @@ -22223,6 +22897,43 @@
>    optimize_location_lists_1 (die, htab);
>    htab_delete (htab);
>  }
> +
> +
> +/* Recursively assign each location list a unique index into the debug_addr
> +   section.  */
> +
> +static void
> +index_location_lists (dw_die_ref die)
> +{
> +  dw_die_ref c;
> +  dw_attr_ref a;
> +  unsigned ix;
> +
> +  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
> +    if (AT_class (a) == dw_val_class_loc_list)
> +      {
> +        dw_loc_list_ref list = AT_loc_list (a);
> +        dw_loc_list_ref curr;
> +        for (curr = list; curr != NULL; curr = curr->dw_loc_next)
> +          {
> +            dw_attr_node attr;
> +
> +            /* Don't index an entry that has already been indexed
> +              or won't be output.  */
> +            if (curr->begin_index != -1U
> +               || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
> +             continue;
> +
> +            attr.dw_attr = DW_AT_location;
> +            attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +            attr.dw_attr_val.val_index = -1U;
> +            attr.dw_attr_val.v.val_lbl_id = xstrdup (curr->begin);
> +            curr->begin_index = add_addr_table_entry (&attr);
> +          }
> +      }
> +
> +  FOR_EACH_CHILD (die, c, index_location_lists (c));
> +}
>
>  /* Output stuff that dwarf requires at the end of every file,
>     and generate the DWARF-2 debugging info.  */
> @@ -22234,6 +22945,7 @@
>    comdat_type_node *ctnode;
>    htab_t comdat_type_table;
>    unsigned int i;
> +  dw_die_ref main_comp_unit_die;
>
>    /* PCH might result in DW_AT_producer string being restored from the
>       header compilation, fix it up if needed.  */
> @@ -22386,6 +23098,14 @@
>    for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
>      add_sibling_attributes (ctnode->root_die);
>
> +  /* When splitting DWARF info, we put some attributes in the
> +     skeleton compile_unit DIE that remains in the .o, while
> +     most attributes go in the DWO compile_unit_die.  */
> +  if (dwarf_split_debug_info)
> +    main_comp_unit_die = gen_compile_unit_die (NULL);
> +  else
> +    main_comp_unit_die = comp_unit_die ();
> +
>    /* Output a terminator label for the .text section.  */
>    switch_to_section (text_section);
>    targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
> @@ -22402,8 +23122,8 @@
>      {
>        /* Don't add if the CU has no associated code.  */
>        if (text_section_used)
> -       add_AT_low_high_pc (comp_unit_die (), text_section_label,
> -                           text_end_label);
> +       add_AT_low_high_pc (main_comp_unit_die, text_section_label,
> +                           text_end_label, true);
>      }
>    else
>      {
> @@ -22412,22 +23132,24 @@
>        bool range_list_added = false;
>
>        if (text_section_used)
> -       add_ranges_by_labels (comp_unit_die (), text_section_label,
> -                             text_end_label, &range_list_added);
> +       add_ranges_by_labels (main_comp_unit_die, text_section_label,
> +                             text_end_label, &range_list_added, true);
>        if (cold_text_section_used)
> -       add_ranges_by_labels (comp_unit_die (), cold_text_section_label,
> -                             cold_end_label, &range_list_added);
> +       add_ranges_by_labels (main_comp_unit_die, cold_text_section_label,
> +                             cold_end_label, &range_list_added, true);
>
>        FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde)
>         {
>           if (DECL_IGNORED_P (fde->decl))
>             continue;
>           if (!fde->in_std_section)
> -           add_ranges_by_labels (comp_unit_die (), fde->dw_fde_begin,
> -                                 fde->dw_fde_end, &range_list_added);
> +           add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_begin,
> +                                 fde->dw_fde_end, &range_list_added,
> +                                 true);
>           if (fde->dw_fde_second_begin && !fde->second_in_std_section)
> -           add_ranges_by_labels (comp_unit_die (), fde->dw_fde_second_begin,
> -                                 fde->dw_fde_second_end, &range_list_added);
> +           add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_second_begin,
> +                                 fde->dw_fde_second_end, &range_list_added,
> +                                 true);
>         }
>
>        if (range_list_added)
> @@ -22437,16 +23159,16 @@
>              absolute.  Historically, we've emitted the unexpected
>              DW_AT_entry_pc instead of DW_AT_low_pc for this purpose.
>              Emit both to give time for other tools to adapt.  */
> -         add_AT_addr (comp_unit_die (), DW_AT_low_pc, const0_rtx);
> +         add_AT_addr (main_comp_unit_die, DW_AT_low_pc, const0_rtx, true);
>           if (! dwarf_strict && dwarf_version < 4)
> -           add_AT_addr (comp_unit_die (), DW_AT_entry_pc, const0_rtx);
> +           add_AT_addr (main_comp_unit_die, DW_AT_entry_pc, const0_rtx, true);
>
>           add_ranges (NULL);
>         }
>      }
>
>    if (debug_info_level >= DINFO_LEVEL_NORMAL)
> -    add_AT_lineptr (comp_unit_die (), DW_AT_stmt_list,
> +    add_AT_lineptr (main_comp_unit_die, DW_AT_stmt_list,
>                     debug_line_section_label);
>
>    if (have_macinfo)
> @@ -22455,7 +23177,11 @@
>                    macinfo_section_label);
>
>    if (have_location_lists)
> -    optimize_location_lists (comp_unit_die ());
> +    {
> +      optimize_location_lists (comp_unit_die ());
> +      if (dwarf_split_debug_info)
> +        index_location_lists (comp_unit_die ());
> +    }
>
>    /* Output all of the compilation units.  We put the main one last so that
>       the offsets are available to output_pubnames.  */
> @@ -22476,19 +23202,54 @@
>           attributes.  */
>        if (debug_info_level >= DINFO_LEVEL_NORMAL)
>          add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
> -                       debug_line_section_label);
> +                        (!dwarf_split_debug_info
> +                         ? debug_line_section_label
> +                         : debug_skeleton_line_section_label));
>
>        output_comdat_type_unit (ctnode);
>        *slot = ctnode;
>      }
>    htab_delete (comdat_type_table);
>
> -  add_AT_pubnames (comp_unit_die ());
> +  /* 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 ());
>
> +  if (dwarf_split_debug_info)
> +    {
> +      int mark;
> +      unsigned char checksum[16];
> +      struct md5_ctx ctx;
> +
> +      /* Compute a checksum of the comp_unit to use as the dwo_id.  */
> +      md5_init_ctx (&ctx);
> +      mark = 0;
> +      die_checksum (comp_unit_die (), &ctx, &mark);
> +      unmark_all_dies (comp_unit_die ());
> +      md5_finish_ctx (&ctx, checksum);
> +
> +      /* Use the first 8 bytes of the checksum as the dwo_id,
> +        and add it to both comp-unit DIEs.  */
> +      add_AT_data8 (main_comp_unit_die, DW_AT_GNU_dwo_id, checksum);
> +      add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, checksum);
> +
> +      /* Add the base offset of the ranges table to the skeleton
> +        comp-unit DIE.  */
> +      if (ranges_table_in_use)
> +       add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base,
> +                       ranges_section_label);
> +    }
> +
>    /* Output the main compilation unit if non-empty or if .debug_macinfo
>       or .debug_macro will be emitted.  */
>    output_comp_unit (comp_unit_die (), have_macinfo);
>
> +  if (dwarf_split_debug_info && info_section_emitted)
> +    output_skeleton_debug_sections (main_comp_unit_die);
> +
>    /* Output the abbreviation table.  */
>    if (abbrev_die_table_in_use != 1)
>      {
> @@ -22502,8 +23263,6 @@
>      {
>        /* Output the location lists info.  */
>        switch_to_section (debug_loc_section);
> -      ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
> -                                  DEBUG_LOC_SECTION_LABEL, 0);
>        ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
>        output_location_lists (comp_unit_die ());
>      }
> @@ -22554,10 +23313,22 @@
>    switch_to_section (debug_line_section);
>    ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
>    if (! DWARF2_ASM_LINE_DEBUG_INFO)
> -    output_line_info ();
> +    output_line_info (false);
>
> -  /* If we emitted any DW_FORM_strp form attribute, output the string
> -     table too.  */
> +  if (dwarf_split_debug_info && info_section_emitted)
> +    {
> +      switch_to_section (debug_skeleton_line_section);
> +      ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
> +      output_line_info (true);
> +
> +      output_index_strings ();
> +
> +      switch_to_section (debug_addr_section);
> +      ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label);
> +      output_addr_table ();
> +    }
> +
> +  /* If we emitted any indirect strings, output the string table too.  */
>    if (debug_str_hash)
>      htab_traverse (debug_str_hash, output_indirect_string, NULL);
>  }
> Index: gcc/dwarf2out.h
> ===================================================================
> --- gcc/dwarf2out.h     (revision 190603)
> +++ gcc/dwarf2out.h     (working copy)
> @@ -172,6 +172,7 @@
>
>  typedef struct GTY(()) dw_val_struct {
>    enum dw_val_class val_class;
> +  unsigned int val_index;
>    union dw_val_struct_union
>      {
>        rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
> Index: gcc/opts.c
> ===================================================================
> --- gcc/opts.c  (revision 190603)
> +++ gcc/opts.c  (working copy)
> @@ -829,9 +829,14 @@
>    if (opts->x_warn_unused_but_set_parameter == -1)
>      opts->x_warn_unused_but_set_parameter = (opts->x_warn_unused
>                                              && opts->x_extra_warnings);
> +
>    /* Wunused-local-typedefs is enabled by -Wunused or -Wall.  */
>    if (opts->x_warn_unused_local_typedefs == -1)
>      opts->x_warn_unused_local_typedefs = opts->x_warn_unused;
> +
> +  /* The -gsplit-dwarf option requires -gpubnames.  */
> +  if (opts->x_dwarf_split_debug_info)
> +    opts->x_debug_generate_pub_sections = 1;
>  }
>
>  #define LEFT_COLUMN    27
> @@ -1692,6 +1697,13 @@
>        set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc);
>        break;
>
> +    case OPT_gsplit_dwarf:
> +      if (opts->x_dwarf_version < 4)
> +        opts->x_dwarf_version = 4;
> +      set_debug_level (DWARF2_DEBUG, DEFAULT_GDB_EXTENSIONS, "", opts, opts_set,
> +                      loc);
> +      break;
> +
>      case OPT_ggdb:
>        set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc);
>        break;
> Index: gcc/common.opt
> ===================================================================
> --- gcc/common.opt      (revision 190603)
> +++ gcc/common.opt      (working copy)
> @@ -2282,6 +2282,20 @@
>  Common RejectNegative Var(dwarf_record_gcc_switches,1)
>  Record gcc command line switches in DWARF DW_AT_producer.
>
> +gno-split-dwarf
> +Common Driver RejectNegative Var(dwarf_split_debug_info,0) Init(0)
> +Don't generate debug information in separate .dwo files
> +
> +gsplit-dwarf
> +Common Driver RejectNegative Var(dwarf_split_debug_info,1)
> +Generate debug information in separate .dwo files
> +
>  gstabs
>  Common JoinedOrMissing Negative(gstabs+)
>  Generate debug information in STABS format
>
> --
> This patch is available for review at http://codereview.appspot.com/6305113

Hey Jason, Any thoughts on this patch?

Sterling
Sterling Augustine - Sept. 24, 2012, 6:22 p.m.
Ping? I'd love to get this in before the 4.8 stage 1 closes.

thanks,

Sterling

On Mon, Aug 27, 2012 at 11:00 AM, Sterling Augustine
<saugustine@google.com> wrote:
> The enclosed patch to implment -gsplit-dwarf addresses Jason's comments as
> responded to by myself and Cary.
>
> In particular, it:
>
> 1. Adds comments for force_direct and its use
> 2. Corrects the location of is_unit_die
> 3. Makes -gsplit-dwarf imply -gdwarf-4
> 4. Changes DW_LLE_* to DW_LLE_GNU_*
> 5. Fixes various comments
> 6. Adds a new enum to cleanup dtprel and the associated logic
> 7. Fixes the FIXME in output_macinfo_op
>
> However, it does not:
>
> 1. Cleanup redundant entries in the .debug_addr--Cary has a patch in progress
>    that handles this situation.
>
>    http://codereview.appspot.com/6305113/#msg6 has more discussion.
>
> 2. Defer assigning indices to DW_GNU_addr_index entries until output time. We
>    see this less than 0.1 percent of the time, and fixing it would require
>    a major restructuring of when the size of debug entries are calculated as
>    opposed to when they are emitted.  Further, Cary's forthcoming patch in is
>    likely to reduce this count even further.
>
>
> The line length issues were not real, as a unified diff adds two spaces to
> the line, and a script that doesn't account for that will reject 79 and 80
> character line lengths.
>
>
> Hopefully this addresses all remaining issues. OK for mainline?
>
> Sterling and Cary
>
>
> include/ChangeLog
>
> 2012-08-24  Sterling Augustine <saugustine@google.com>
>             Cary Coutant <ccoutant@google.com>
>
>         * dwarf2.def: Fix comment.
>         * dwarf2.h (dwarf_location_list_entry_type): New enum with members
>         DW_LLE_GNU_end_of_list_entry, DW_LLE_GNU_case_address_selection_entry,
>         DW_LLE_GNU_start_end_entry, DW_LLE_GNU_start_length_entry.
>
> gcc/ChangeLog
>
> 2012-08-24  Sterling Augustine <saugustine@google.com>
>             Cary Coutant <ccoutant@google.com>
>
>         * common.opt (gno-split-dwarf, gsplit-dwarf): New switches.
>         * doc/invoke.texi (Debugging Options): Document them.
>         * dwarf2out.h (dw_val_struct): New field val_index.
>         * dwarf2out.c (debug_skeleton_info_section,
>         debug_skeleton_abbrev_section, debug_addr_section,
>         debug_skeleton_line_section, debug_str_offsets_section): New sections.
>         (indirect_string_node): Add index field.
>         (dw_loc_list_node): Add begin_index field.
>         (dw_addr_op, new_addr_loc_descr, AT_index, set_AT_index,
>         add_addr_table_entry, remove_addr_table_entry, output_range_list_offset,
>         output_loc_list_offset, output_attr_index_or_value,
>         remove_loc_list_addr_table_entries, output_die_abbrevs,
>         add_top_level_skeleton_die_attrs, get_skeleton_type_unit,
>         output_skeleton_debug_sections, output_index_strings,
>         output_addr_table, index_location_lists, add_indirect_string): New
>         functions.
>         (DEBUG_DWO_INFO_SECTION, DEBUG_DWO_ABBREV_SECTION, DEBUG_ADDR_SECTION,
>         DEBUG_NORM_MACINFO_SECTION, DEBUG_DWO_MACINFO_SECTION,
>         DEBUG_DWO_LINE_SECTION, DEBUG_DWO_LOC_SECTION,
>         DEBUG_NORM_STR_OFFSETS_SECTION, DEBUG_DWO_STR_SECTION,
>         DEBUG_MACRO_SECTION_FLAGS, DEBUG_SKELETON_LINE_SECTION_LABEL,
>         DEBUG_SKELETON_INFO_SECTION_LABEL, DEBUG_SKELETON_ABBREV_SECTION_LABEL,
>         DEBUG_ADDR_SECTIN_LABEL, SKELETON_COMP_DIE_ABBREV,
>         SKELETON_TYPE_DIE_ABBREV): New defines.
>         (DEBUG_MACINFO_SECTION, DEBUG_MACRO_SECTION, DEBUG_STR_SECTION
>         DEBUG_STR_SECTION_FLAGS): Adjust definitions.
>         (TEXT_SECTION_LABEL, COLD_TEXT_SECTION_LABEL, DEBUG_INFO_SECTION_LABEL,
>         DEBUG_ABBREV_SECTION_LABEL, DEBUG_LOC_SECTION_LABEL,
>         DEBUG_RANGES_SECTION_LABEL, DEBUG_MACINFO_SECTION_LABEL,
>         DEBUG_MACRO_SECTION_LABEL): Adjust indentation.
>         (debug_skeleton_info_section_label, debug_skeleton_abbrev_section_label,
>         debug_addr_section_label, debug_skeleton_line_section_label,
>         dw_id_placeholder): New global variables.
>         (add_AT_lbl_id, add_AT_low_high_pc): Add force_direct parameter.
>         Adjust calls throughout file.  Handle dwarf_split_debug_info.
>         (add_AT_addr). Likewise.  Initialize val_index_field.
>         (add_AT_range_list): Add force parameter.  Adjust calls throughout file.
>         Initialize val_index field.
>         (add_ranges_by_labels): Add and handle force_direct parameter.  Adjust
>         calls throughout file.
>         (size_of_die): New variable form.  Handle dwarf_split_debug_info and
>         call AT_index.
>         (value_format): Use AT_class instead of calling val_class directly.
>         Handle DW_FORM_addr and dw_val_class_lbl_id appropriately for
>         dwarf_split_debug_info and AT_index.
>         (output_abbrev_section): Move most code to new function
>         output_die_abbrevs.
>         (output_loc_list): Handle dwarf_split_debug_info by using
>         DW_LLE_start_length_entry and DW_LLE_end_of_list_entry.
>         (output_die): Call output_attr_index_or_value, output_range_list_offset,
>         Fix format string.  Check val_str->form directly to avoid side effect.
>         (add_pubtype): Fix indention.
>         (output_comdat_type_unit): Handle dwarf_split_debug_info.
>         (output_pubnames): Likewise.
>         (output_aranges): Likewise.
>         (output_mac_info): Likewise.
>         (output_mac_info_op): Check for DW_FORM_GNU_str_index.  Call
>         add_indirect_string.
>         (output_line_info): New parameter prologue_only.  Adjust calls
>         throughout file.
>         (dtprel_bool, dtprel_false, dtprel_true): New enum and enumerators.
>         (mem_loc_descriptor): Call new_addr_loc_descr.
>         (loc_descriptor): Likewise.
>         (add_const_value_attribute): Likewise.
>         (loc_list_from_tree): Replace first_op and second_op with tls_op.
>         Update associated logic.  Call new_addr_loc_descr.
>         (dwarf2out_init): Handle dwarf_split_debug_info.  Initialize
>         debug_skeleton_info_section, debug_skeleton_abbrev_section,
>         debug_addr_section, debug_skeleton_line_section,
>         debug_str_offsets_section, debug_skeleton_info_section_label,
>         debug_skeleton_abbrev_section_label, debug_addr_section_label and
>         debug_skeleton_line_section_label.  Use DEBUG_MACRO_SECTION_FLAGS.
>         (new_loc_descr, build_cfa_loc, add_AT_flag, add_AT_int, add_AT_unsigned,
>         add_AT_double, add_AT_vec, add_AT_data8, add_AT_string, add_AT_die_ref,
>         add_AT_fde_ref, add_AT_loc, add_AT_loc_list, add_AT_file,
>         add_AT_vms_delta, add_AT_lineptr, add_AT_macptr, add_AT_offset):
>         Initialize val_index field.
>         (size_of_loc_descr, output_loc_operands, output_loc_operands_raw,
>         resolve_addr_in_expression, hash_loc_operands): Handle
>         DW_OP_GNU_addr_index and DW_OP_GNU_const_index.
>         (compare_loc_operands):  Likewise.  Adjust assertion.
>         (AT_string_form): Call set_AT_index and add_indirect_string.
>         (resolve_addr): New local variable l.  Check val_index.  Call
>         remove_addr_table_entry and remove_loc_list_addr_table_entries.
>         (dwarf2out_finish): Handle dwarf_split_debug_info.  New variable
>         main_comp_unit_die.  Call index_location_lists, add_AT_data8,
>         add_AT_lineptr, output_skeleton_debug_sections, output_addr_table.  Move
>         call to ASM_GENERATE_INTERNAL_LABEL to dwarf2out_init.  Call
>         ASM_OUTPUT_LABEL for debug_skeleton_line_section_label and
>         debug_addr_section_label.  Adjust comment.
>         * gcc.c (replace_extension_spec_func):  New function.
>         (ASM_FINAL_SPEC): Adjust.
>         (static_spec_functions): Add new field for replace-extension.
>         (check_live_switch): Adjust comment.  Add case for 'g'.
>         * opts.c (finish_options): Set x_debug_generate_pub_sections based on
>         x_dwarf_split_debug_info.  Call set_debug_level.
>         (common_handle_option): Add case for OPT_gsplit_dwarf.
>
> Index: include/dwarf2.def
> ===================================================================
> --- include/dwarf2.def  (revision 190603)
> +++ include/dwarf2.def  (working copy)
> @@ -586,7 +586,7 @@
>  DW_OP (DW_OP_GNU_reinterpret, 0xf9)
>  /* The GNU parameter ref extension.  */
>  DW_OP (DW_OP_GNU_parameter_ref, 0xfa)
> -/* Extension for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
> +/* Extensions for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
>  DW_OP (DW_OP_GNU_addr_index, 0xfb)
>  DW_OP (DW_OP_GNU_const_index, 0xfc)
>  /* HP extensions.  */
> Index: include/dwarf2.h
> ===================================================================
> --- include/dwarf2.h    (revision 190603)
> +++ include/dwarf2.h    (working copy)
> @@ -259,6 +259,17 @@
>      DW_LNE_HP_SFC_associate = 3
>    };
>
> +/* Type codes for location list entries.
> +   Extension for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
> +
> +enum dwarf_location_list_entry_type
> +  {
> +    DW_LLE_GNU_end_of_list_entry = 0,
> +    DW_LLE_GNU_base_address_selection_entry = 1,
> +    DW_LLE_GNU_start_end_entry = 2,
> +    DW_LLE_GNU_start_length_entry = 3
> +  };
> +
>  #define DW_CIE_ID        0xffffffff
>  #define DW64_CIE_ID      0xffffffffffffffffULL
>  #define DW_CIE_VERSION   1
> Index: gcc/doc/invoke.texi
> ===================================================================
> --- gcc/doc/invoke.texi (revision 190603)
> +++ gcc/doc/invoke.texi (working copy)
> @@ -4803,6 +4803,14 @@
>  The following options are useful when GCC is generated with the
>  capability for more than one debugging format.
>
> +@item -gsplit-dwarf
> +@opindex gsplit-dwarf
> +Separate as much dwarf debugging information as possible into a
> +separate output file with the extension .dwo.  This option allows
> +the build system to avoid linking files with debug information.  To
> +be useful, this option requires a debugger capable of reading .dwo
> +files.
> +
>  @item -ggdb
>  @opindex ggdb
>  Produce debugging information for use by GDB@.  This means to use the
> Index: gcc/gcc.c
> ===================================================================
> --- gcc/gcc.c   (revision 190603)
> +++ gcc/gcc.c   (working copy)
> @@ -267,6 +267,7 @@
>  static const char *compare_debug_self_opt_spec_function (int, const char **);
>  static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
>  static const char *pass_through_libs_spec_func (int, const char **);
> +static const char *replace_extension_spec_func (int, const char **);
>
>  /* The Specs Language
>
> @@ -447,7 +448,7 @@
>  colon in these constructs, except between . or * and the corresponding
>  word.
>
> -The -O, -f, -m, and -W switches are handled specifically in these
> +The -O, -f, -g, -m, and -W switches are handled specifically in these
>  constructs.  If another value of -O or the negated form of a -f, -m, or
>  -W switch is found later in the command line, the earlier switch
>  value is ignored, except with {S*} where S is just one letter; this
> @@ -480,7 +481,14 @@
>  /* config.h can define ASM_FINAL_SPEC to run a post processor after
>     the assembler has run.  */
>  #ifndef ASM_FINAL_SPEC
> -#define ASM_FINAL_SPEC ""
> +#define ASM_FINAL_SPEC \
> +  "%{gsplit-dwarf: \n\
> +       objcopy --extract-dwo \
> +        %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> +        %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
> +       objcopy --strip-dwo \
> +        %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
> +    }"
>  #endif
>
>  /* config.h can define CPP_SPEC to provide extra args to the C preprocessor
> @@ -1262,6 +1270,7 @@
>    { "compare-debug-self-opt",  compare_debug_self_opt_spec_function },
>    { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
>    { "pass-through-libs",       pass_through_libs_spec_func },
> +  { "replace-extension",       replace_extension_spec_func },
>  #ifdef EXTRA_SPEC_FUNCTIONS
>    EXTRA_SPEC_FUNCTIONS
>  #endif
> @@ -5803,7 +5812,7 @@
>     on the command line.  PREFIX_LENGTH is the length of XXX in an {XXX*}
>     spec, or -1 if either exact match or %* is used.
>
> -   A -O switch is obsoleted by a later -O switch.  A -f, -m, or -W switch
> +   A -O switch is obsoleted by a later -O switch.  A -f, -g, -m, or -W switch
>     whose value does not begin with "no-" is obsoleted by the same value
>     with the "no-", similarly for a switch with the "no-" prefix.  */
>
> @@ -5840,7 +5849,7 @@
>           }
>        break;
>
> -    case 'W':  case 'f':  case 'm':
> +    case 'W':  case 'f':  case 'm': case 'g':
>        if (! strncmp (name + 1, "no-", 3))
>         {
>           /* We have Xno-YYY, search for XYYY.  */
> @@ -8363,3 +8372,33 @@
>      }
>    return prepended;
>  }
> +
> +/* %:replace-extension spec function.  Replaces the extension of the
> +   first argument with the second argument.  */
> +
> +const char *
> +replace_extension_spec_func (int argc, const char **argv)
> +{
> +  char *name;
> +  char *p;
> +  char *result;
> +  int i;
> +
> +  if (argc != 2)
> +    fatal_error ("too few arguments to %%:replace-extension");
> +
> +  name = xstrdup (argv[0]);
> +
> +  for (i = strlen(name) - 1; i >= 0; i--)
> +    if (IS_DIR_SEPARATOR (name[i]))
> +      break;
> +
> +  p = strrchr (name + i + 1, '.');
> +  if (p != NULL)
> +      *p = '\0';
> +
> +  result = concat (name, argv[1], NULL);
> +
> +  free (name);
> +  return result;
> +}
> Index: gcc/dwarf2out.c
> ===================================================================
> --- gcc/dwarf2out.c     (revision 190603)
> +++ gcc/dwarf2out.c     (working copy)
> @@ -145,14 +145,19 @@
>
>  /* Pointers to various DWARF2 sections.  */
>  static GTY(()) section *debug_info_section;
> +static GTY(()) section *debug_skeleton_info_section;
>  static GTY(()) section *debug_abbrev_section;
> +static GTY(()) section *debug_skeleton_abbrev_section;
>  static GTY(()) section *debug_aranges_section;
> +static GTY(()) section *debug_addr_section;
>  static GTY(()) section *debug_macinfo_section;
>  static GTY(()) section *debug_line_section;
> +static GTY(()) section *debug_skeleton_line_section;
>  static GTY(()) section *debug_loc_section;
>  static GTY(()) section *debug_pubnames_section;
>  static GTY(()) section *debug_pubtypes_section;
>  static GTY(()) section *debug_str_section;
> +static GTY(()) section *debug_str_offsets_section;
>  static GTY(()) section *debug_ranges_section;
>  static GTY(()) section *debug_frame_section;
>
> @@ -195,6 +200,7 @@
>    unsigned int refcount;
>    enum dwarf_form form;
>    char *label;
> +  unsigned int index;
>  };
>
>  static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
> @@ -1201,7 +1207,8 @@
>     their entire life.  */
>  typedef struct GTY(()) dw_loc_list_struct {
>    dw_loc_list_ref dw_loc_next;
> -  const char *begin; /* Label for begin address of range */
> +  const char *begin; /* Label and index for begin address of range */
> +  unsigned int begin_index;
>    const char *end;  /* Label for end address of range */
>    char *ll_symbol; /* Label for beginning of location list.
>                       Only on head of list */
> @@ -1246,8 +1253,10 @@
>
>    descr->dw_loc_opc = op;
>    descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
> +  descr->dw_loc_oprnd1.val_index = -1U;
>    descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
>    descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
> +  descr->dw_loc_oprnd2.val_index = -1U;
>    descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
>
>    return descr;
> @@ -1452,6 +1461,10 @@
>      case DW_OP_addr:
>        size += DWARF2_ADDR_SIZE;
>        break;
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      size += size_of_uleb128 (loc->dw_loc_oprnd1.val_index);
> +      break;
>      case DW_OP_const1u:
>      case DW_OP_const1s:
>        size += 1;
> @@ -1888,6 +1901,12 @@
>         }
>        break;
>
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_index,
> +                                   "(index into .debug_addr)");
> +      break;
> +
>      case DW_OP_GNU_implicit_pointer:
>        {
>         char label[MAX_ARTIFICIAL_LABEL_BYTES
> @@ -2063,6 +2082,8 @@
>    switch (loc->dw_loc_opc)
>      {
>      case DW_OP_addr:
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
>      case DW_OP_implicit_value:
>        /* We cannot output addresses in .cfi_escape, only bytes.  */
>        gcc_unreachable ();
> @@ -2246,6 +2267,7 @@
>      {
>        head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
>        head->dw_loc_oprnd1.val_class = dw_val_class_const;
> +      head->dw_loc_oprnd1.val_index = -1U;
>        tmp = new_loc_descr (DW_OP_deref, 0, 0);
>        add_loc_descr (&head, tmp);
>        if (offset != 0)
> @@ -2875,6 +2897,8 @@
>  static tree decl_class_context (tree);
>  static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
>  static inline enum dw_val_class AT_class (dw_attr_ref);
> +static inline unsigned int AT_index (dw_attr_ref);
> +static inline void set_AT_index (dw_attr_ref, unsigned int);
>  static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned);
>  static inline unsigned AT_flag (dw_attr_ref);
>  static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
> @@ -2902,15 +2926,18 @@
>  static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
>                              dw_loc_list_ref);
>  static inline dw_loc_list_ref AT_loc_list (dw_attr_ref);
> -static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx);
> +static unsigned int add_addr_table_entry (dw_attr_node *);
> +static void remove_addr_table_entry (unsigned int);
> +static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
>  static inline rtx AT_addr (dw_attr_ref);
> -static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
> +static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *,
> +                          bool);
>  static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
>  static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
>  static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
>                            unsigned HOST_WIDE_INT);
>  static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
> -                              unsigned long);
> +                              unsigned long, bool);
>  static inline const char *AT_lbl (dw_attr_ref);
>  static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute);
>  static const char *get_AT_low_pc (dw_die_ref);
> @@ -3005,6 +3032,7 @@
>  static enum dwarf_form value_format (dw_attr_ref);
>  static void output_value_format (dw_attr_ref);
>  static void output_abbrev_section (void);
> +static void output_die_abbrevs (unsigned long, dw_die_ref);
>  static void output_die_symbol (dw_die_ref);
>  static void output_die (dw_die_ref);
>  static void output_compilation_unit_header (void);
> @@ -3020,10 +3048,10 @@
>  static unsigned int add_ranges_num (int);
>  static unsigned int add_ranges (const_tree);
>  static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
> -                                 bool *);
> +                                 bool *, bool);
>  static void output_ranges (void);
>  static dw_line_info_table *new_line_info_table (void);
> -static void output_line_info (void);
> +static void output_line_info (bool);
>  static void output_file_names (void);
>  static dw_die_ref base_type_die (tree);
>  static int is_base_type (tree);
> @@ -3162,36 +3190,130 @@
>  static void schedule_generic_params_dies_gen (tree t);
>  static void gen_scheduled_generic_parms_dies (void);
>
> +/* enum for tracking thread-local variables whose address is really an offset
> +   relative to the TLS pointer, which will need link-time relocation, but will
> +   not need relocation by the DWARF consumer.  */
> +
> +enum dtprel_bool
> +  {
> +    dtprel_false = 0,
> +    dtprel_true = 1
> +  };
> +
> +/* Return the operator to use for an address of a variable.  For dtprel_true, we
> +   use DW_OP_const*.  For regular variables, which need both link-time
> +   relocation and consumer-level relocation (e.g., to account for shared objects
> +   loaded at a random address), we use DW_OP_addr*.  */
> +
> +static inline enum dwarf_location_atom
> +dw_addr_op (enum dtprel_bool dtprel)
> +{
> +  if (dtprel == dtprel_true)
> +    return (dwarf_split_debug_info ? DW_OP_GNU_const_index
> +            : (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u));
> +  else
> +    return (dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr);
> +}
> +
> +/* Return a pointer to a newly allocated address location description.  If
> +   dwarf_split_debug_info is true, then record the address with the appropriate
> +   relocation.  */
> +static inline dw_loc_descr_ref
> +new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
> +{
> +  dw_loc_descr_ref ref = new_loc_descr (dw_addr_op (dtprel), 0, 0);
> +
> +  ref->dw_loc_oprnd1.val_class = dw_val_class_addr;
> +  ref->dw_loc_oprnd1.val_index = -1U;
> +  ref->dw_loc_oprnd1.v.val_addr = addr;
> +  ref->dtprel = dtprel;
> +  if (dwarf_split_debug_info)
> +    {
> +      dw_attr_node attr;
> +
> +      attr.dw_attr = DW_AT_location;
> +      attr.dw_attr_val.val_class = (dtprel == dtprel_true
> +                                    ? dw_val_class_loc : dw_val_class_addr);
> +      attr.dw_attr_val.val_index = -1U;
> +      attr.dw_attr_val.v.val_addr = addr;
> +
> +      ref->dw_loc_oprnd1.val_index = add_addr_table_entry (&attr);
> +    }
> +  return ref;
> +}
> +
>  /* Section names used to hold DWARF debugging information.  */
> +
>  #ifndef DEBUG_INFO_SECTION
>  #define DEBUG_INFO_SECTION     ".debug_info"
>  #endif
> +#ifndef DEBUG_DWO_INFO_SECTION
> +#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
> +#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_ARANGES_SECTION
>  #define DEBUG_ARANGES_SECTION  ".debug_aranges"
>  #endif
> +#ifndef DEBUG_ADDR_SECTION
> +#define DEBUG_ADDR_SECTION     ".debug_addr"
> +#endif
> +#ifndef DEBUG_NORM_MACINFO_SECTION
> +#define DEBUG_NORM_MACINFO_SECTION     ".debug_macinfo"
> +#endif
> +#ifndef DEBUG_DWO_MACINFO_SECTION
> +#define DEBUG_DWO_MACINFO_SECTION      ".debug_macinfo.dwo"
> +#endif
>  #ifndef DEBUG_MACINFO_SECTION
> -#define DEBUG_MACINFO_SECTION  ".debug_macinfo"
> +#define DEBUG_MACINFO_SECTION                                           \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_MACINFO_SECTION) : (DEBUG_DWO_MACINFO_SECTION))
>  #endif
> +#ifndef DEBUG_NORM_MACRO_SECTION
> +#define DEBUG_NORM_MACRO_SECTION ".debug_macro"
> +#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"
> +#define DEBUG_MACRO_SECTION                                             \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_MACRO_SECTION) : (DEBUG_DWO_MACRO_SECTION))
>  #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_LOC_SECTION
>  #define DEBUG_LOC_SECTION      ".debug_loc"
>  #endif
> +#ifndef DEBUG_DWO_LOC_SECTION
> +#define DEBUG_DWO_LOC_SECTION  ".debug_loc.dwo"
> +#endif
>  #ifndef DEBUG_PUBNAMES_SECTION
>  #define DEBUG_PUBNAMES_SECTION ".debug_pubnames"
>  #endif
>  #ifndef DEBUG_PUBTYPES_SECTION
>  #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes"
>  #endif
> +#define DEBUG_NORM_STR_OFFSETS_SECTION ".debug_str_offsets"
> +#define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo"
> +#ifndef DEBUG_STR_OFFSETS_SECTION
> +#define DEBUG_STR_OFFSETS_SECTION                                       \
> +  (!dwarf_split_debug_info                                              \
> +   ? (DEBUG_NORM_STR_OFFSETS_SECTION) : (DEBUG_DWO_STR_OFFSETS_SECTION))
> +#endif
> +#define DEBUG_DWO_STR_SECTION   ".debug_str.dwo"
> +#define DEBUG_NORM_STR_SECTION  ".debug_str"
>  #ifndef DEBUG_STR_SECTION
> -#define DEBUG_STR_SECTION      ".debug_str"
> +#define DEBUG_STR_SECTION                               \
> +  (!dwarf_split_debug_info ? (DEBUG_NORM_STR_SECTION) : (DEBUG_DWO_STR_SECTION))
>  #endif
>  #ifndef DEBUG_RANGES_SECTION
>  #define DEBUG_RANGES_SECTION   ".debug_ranges"
> @@ -3202,44 +3324,63 @@
>  #define TEXT_SECTION_NAME      ".text"
>  #endif
>
> +/* Section flags for .debug_macinfo/.debug_macro section.  */
> +#define DEBUG_MACRO_SECTION_FLAGS \
> +  (dwarf_split_debug_info ? SECTION_DEBUG | SECTION_EXCLUDE : SECTION_DEBUG)
> +
>  /* Section flags for .debug_str section.  */
>  #define DEBUG_STR_SECTION_FLAGS \
> -  (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings              \
> -   ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1       \
> -   : SECTION_DEBUG)
> +  (dwarf_split_debug_info \
> +   ? SECTION_DEBUG | SECTION_EXCLUDE \
> +   : (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings \
> +      ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1        \
> +      : SECTION_DEBUG))
>
>  /* Labels we insert at beginning sections we can reference instead of
>     the section names themselves.  */
>
>  #ifndef TEXT_SECTION_LABEL
> -#define TEXT_SECTION_LABEL             "Ltext"
> +#define TEXT_SECTION_LABEL                 "Ltext"
>  #endif
>  #ifndef COLD_TEXT_SECTION_LABEL
> -#define COLD_TEXT_SECTION_LABEL         "Ltext_cold"
> +#define COLD_TEXT_SECTION_LABEL             "Ltext_cold"
>  #endif
>  #ifndef DEBUG_LINE_SECTION_LABEL
> -#define DEBUG_LINE_SECTION_LABEL       "Ldebug_line"
> +#define DEBUG_LINE_SECTION_LABEL           "Ldebug_line"
>  #endif
> +#ifndef DEBUG_SKELETON_LINE_SECTION_LABEL
> +#define DEBUG_SKELETON_LINE_SECTION_LABEL   "Lskeleton_debug_line"
> +#endif
>  #ifndef DEBUG_INFO_SECTION_LABEL
> -#define DEBUG_INFO_SECTION_LABEL       "Ldebug_info"
> +#define DEBUG_INFO_SECTION_LABEL           "Ldebug_info"
>  #endif
> +#ifndef DEBUG_SKELETON_INFO_SECTION_LABEL
> +#define DEBUG_SKELETON_INFO_SECTION_LABEL   "Lskeleton_debug_info"
> +#endif
>  #ifndef DEBUG_ABBREV_SECTION_LABEL
> -#define DEBUG_ABBREV_SECTION_LABEL     "Ldebug_abbrev"
> +#define DEBUG_ABBREV_SECTION_LABEL         "Ldebug_abbrev"
>  #endif
> +#ifndef DEBUG_SKELETON_ABBREV_SECTION_LABEL
> +#define DEBUG_SKELETON_ABBREV_SECTION_LABEL "Lskeleton_debug_abbrev"
> +#endif
> +#ifndef DEBUG_ADDR_SECTION_LABEL
> +#define DEBUG_ADDR_SECTION_LABEL           "Ldebug_addr"
> +#endif
>  #ifndef DEBUG_LOC_SECTION_LABEL
> -#define DEBUG_LOC_SECTION_LABEL                "Ldebug_loc"
> +#define DEBUG_LOC_SECTION_LABEL                    "Ldebug_loc"
>  #endif
>  #ifndef DEBUG_RANGES_SECTION_LABEL
> -#define DEBUG_RANGES_SECTION_LABEL     "Ldebug_ranges"
> +#define DEBUG_RANGES_SECTION_LABEL         "Ldebug_ranges"
>  #endif
>  #ifndef DEBUG_MACINFO_SECTION_LABEL
> -#define DEBUG_MACINFO_SECTION_LABEL     "Ldebug_macinfo"
> +#define DEBUG_MACINFO_SECTION_LABEL         "Ldebug_macinfo"
>  #endif
>  #ifndef DEBUG_MACRO_SECTION_LABEL
> -#define DEBUG_MACRO_SECTION_LABEL      "Ldebug_macro"
> +#define DEBUG_MACRO_SECTION_LABEL          "Ldebug_macro"
>  #endif
> +#define SKELETON_COMP_DIE_ABBREV 1
> +#define SKELETON_TYPE_DIE_ABBREV 2
>
> -
>  /* Definitions of defaults for formats and names of various special
>     (artificial) labels which may be generated within this file (when the -g
>     options is used and DWARF2_DEBUGGING_INFO is in effect.
> @@ -3252,7 +3393,11 @@
>  static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_addr_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
> +static char debug_skeleton_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
>  static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
> @@ -3493,6 +3638,31 @@
>    return a->dw_attr_val.val_class;
>  }
>
> +/* Return the index for any attribute that will be referenced with a
> +   DW_FORM_GNU_addr_index.  Strings have their indices handled differently to
> +   account for reference counting pruning.  */
> +
> +static inline unsigned int
> +AT_index (dw_attr_ref a)
> +{
> +  if (AT_class (a) == dw_val_class_str)
> +    return a->dw_attr_val.v.val_str->index;
> +  else
> +    return a->dw_attr_val.val_index;
> +}
> +
> +/* Set the index for any attribute that will be referenced with a
> +   DW_FORM_GNU_addr_index.  */
> +
> +static inline void
> +set_AT_index (dw_attr_ref a, unsigned int index)
> +{
> +  if (AT_class (a) == dw_val_class_str)
> +    a->dw_attr_val.v.val_str->index = index;
> +  else
> +    a->dw_attr_val.val_index = index;
> +}
> +
>  /* Add a flag value attribute to a DIE.  */
>
>  static inline void
> @@ -3502,6 +3672,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_flag;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_flag = flag;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3522,6 +3693,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_const;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_int = int_val;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3543,6 +3715,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_unsigned = unsigned_val;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3564,6 +3737,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_const_double;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_double.high = high;
>    attr.dw_attr_val.v.val_double.low = low;
>    add_dwarf_attr (die, &attr);
> @@ -3579,6 +3753,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_vec;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_vec.length = length;
>    attr.dw_attr_val.v.val_vec.elt_size = elt_size;
>    attr.dw_attr_val.v.val_vec.array = array;
> @@ -3595,28 +3770,39 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_data8;
> +  attr.dw_attr_val.val_index = -1U;
>    memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  */
> +/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  The parameter force_direct
> +   makes the attribute use DW_AT_addr, rather than DW_AT_GNU_addr_index.  */
> +
>  static inline void
> -add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high)
> +add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high,
> +                   bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = DW_AT_low_pc;
>    attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_low);
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, DW_AT_low_pc), add_addr_table_entry (&attr));
>
>    attr.dw_attr = DW_AT_high_pc;
>    if (dwarf_version < 4)
>      attr.dw_attr_val.val_class = dw_val_class_lbl_id;
>    else
>      attr.dw_attr_val.val_class = dw_val_class_high_pc;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_high);
>    add_dwarf_attr (die, &attr);
> +  if (attr.dw_attr_val.val_class == dw_val_class_lbl_id
> +      && dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, DW_AT_high_pc), add_addr_table_entry (&attr));
>  }
>
>  /* Hash and equality functions for debug_str_hash.  */
> @@ -3673,6 +3859,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_str;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_str = node;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3684,6 +3871,38 @@
>    return a->dw_attr_val.v.val_str->str;
>  }
>
> +/* A vector for a table of strings in the form DW_FORM_GNU_index_str.  */
> +
> +typedef struct indirect_string_node indirect_string_node;
> +DEF_VEC_O(indirect_string_node);
> +DEF_VEC_ALLOC_O(indirect_string_node, gc);
> +static GTY (()) VEC (indirect_string_node, gc) *index_string_table;
> +
> +/* Add a new indirect string to the appropriate tables.  Returns the index of
> +   the new string.  Call this function directly to bypass AT_string_form's logic
> +   to put the string inline in the die. */
> +
> +static unsigned long
> +add_indirect_string (struct indirect_string_node *node, const char *str)
> +{
> +  static unsigned int index_string_count = 0;
> +  ++dw2_string_counter;
> +  node->label = xstrdup (str);
> +
> +  if (!dwarf_split_debug_info)
> +    {
> +      node->form = DW_FORM_strp;
> +      return -1U;
> +    }
> +  else
> +    {
> +      node->form = DW_FORM_GNU_str_index;
> +      index_string_count++;
> +      VEC_safe_push (indirect_string_node, gc, index_string_table, node);
> +      return index_string_count;
> +    }
> +}
> +
>  /* Find out whether a string should be output inline in DIE
>     or out-of-line in .debug_str section.  */
>
> @@ -3716,10 +3935,9 @@
>      return node->form = DW_FORM_string;
>
>    ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
> -  ++dw2_string_counter;
> -  node->label = xstrdup (label);
> +  set_AT_index (a, add_indirect_string (node, label));
>
> -  return node->form = DW_FORM_strp;
> +  return node->form;
>  }
>
>  /* Add a DIE reference attribute value to a DIE.  */
> @@ -3740,6 +3958,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_die_ref;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_die_ref.die = targ_die;
>    attr.dw_attr_val.v.val_die_ref.external = 0;
>    add_dwarf_attr (die, &attr);
> @@ -3798,6 +4017,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_fde_ref;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_fde_index = targ_fde;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3811,6 +4031,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_loc;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_loc = loc;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3829,6 +4050,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_loc_list;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_loc_list = loc_list;
>    add_dwarf_attr (die, &attr);
>    have_location_lists = true;
> @@ -3848,17 +4070,62 @@
>    return &a->dw_attr_val.v.val_loc_list;
>  }
>
> -/* Add an address constant attribute value to a DIE.  */
> +/* A table of entries into the .debug_addr section.  */
>
> +static GTY (()) VEC (dw_attr_node,gc) * addr_index_table;
> +
> +static unsigned int
> +add_addr_table_entry (dw_attr_node *attr)
> +{
> +  gcc_assert (dwarf_split_debug_info);
> +
> +  VEC_safe_push (dw_attr_node, gc, addr_index_table, attr);
> +  return VEC_length (dw_attr_node, addr_index_table) - 1;
> +}
> +
> +/* Remove an entry from the addr table.  Since we have already numbered
> +   all the entries, the best we can do here is null it out.  */
> +
> +static void
> +remove_addr_table_entry (unsigned int i)
> +{
> +  dw_attr_node *attr;
> +
> +  gcc_assert (dwarf_split_debug_info);
> +  gcc_assert (i < VEC_length (dw_attr_node, addr_index_table));
> +
> +  attr = &VEC_index (dw_attr_node, addr_index_table, i);
> +  attr->dw_attr = (enum dwarf_attribute) 0;
> +}
> +
> +/* Given a location list, remove all addresses it refers to from the
> +   address_table.  */
> +
> +static void
> +remove_loc_list_addr_table_entries (dw_loc_descr_ref descr)
> +{
> +  for (; descr; descr = descr->dw_loc_next)
> +    if (descr->dw_loc_oprnd1.val_index != -1U)
> +      remove_addr_table_entry (descr->dw_loc_oprnd1.val_index);
> +}
> +
> +/* Add an address constant attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
> +
>  static inline void
> -add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
> +add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr,
> +            bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_addr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_addr = addr;
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
>  }
>
>  /* Get the RTX from to an address DIE attribute.  */
> @@ -3880,6 +4147,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_file;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_file = fd;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3903,22 +4171,29 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_vms_delta;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1);
>    attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2);
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add a label identifier attribute value to a DIE.  */
> +/* Add a label identifier attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static inline void
> -add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
> +add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind,
> +              const char *lbl_id, bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
>    add_dwarf_attr (die, &attr);
> +  if (dwarf_split_debug_info && !force_direct)
> +    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
>  }
>
>  /* Add a section offset attribute value to a DIE, an offset into the
> @@ -3932,6 +4207,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_lineptr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3947,6 +4223,7 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_macptr;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
>    add_dwarf_attr (die, &attr);
>  }
> @@ -3961,20 +4238,31 @@
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_offset;
> +  attr.dw_attr_val.val_index = -1U;
>    attr.dw_attr_val.v.val_offset = offset;
>    add_dwarf_attr (die, &attr);
>  }
>
> -/* Add an range_list attribute value to a DIE.  */
> +/* Add a range_list attribute value to a DIE.  The parameter
> +   force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static void
>  add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
> -                  long unsigned int offset)
> +                  long unsigned int offset, bool force_direct)
>  {
>    dw_attr_node attr;
>
>    attr.dw_attr = attr_kind;
>    attr.dw_attr_val.val_class = dw_val_class_range_list;
> +  /* For the range_list attribute, val_index == -1U indicates that we want to
> +     output a relocated reference to the range list entry, while any other
> +     value indicates that we want to output the section-relative offset of the
> +     range list entry. In this case, we're not using the val_index field as a
> +     slot index like we do for references to .debug_addr.  This is used
> +     in output_range_list_offset.  */
> +  attr.dw_attr_val.val_index
> +      = (dwarf_split_debug_info && !force_direct) ? offset : -1U;
>    attr.dw_attr_val.v.val_offset = offset;
>    add_dwarf_attr (die, &attr);
>  }
> @@ -7158,6 +7446,7 @@
>    unsigned long size = 0;
>    dw_attr_ref a;
>    unsigned ix;
> +  enum dwarf_form form;
>
>    size += size_of_uleb128 (die->die_abbrev);
>    FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
> @@ -7165,7 +7454,10 @@
>        switch (AT_class (a))
>         {
>         case dw_val_class_addr:
> -         size += DWARF2_ADDR_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF2_ADDR_SIZE;
>           break;
>         case dw_val_class_offset:
>           size += DWARF_OFFSET_SIZE;
> @@ -7183,10 +7475,13 @@
>           }
>           break;
>         case dw_val_class_loc_list:
> -         size += DWARF_OFFSET_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_range_list:
> -         size += DWARF_OFFSET_SIZE;
> +          size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_const:
>           size += size_of_sleb128 (AT_int (a));
> @@ -7246,15 +7541,21 @@
>           size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_lbl_id:
> -         size += DWARF2_ADDR_SIZE;
> +          if (dwarf_split_debug_info && AT_index (a) != -1U)
> +            size += size_of_uleb128 (AT_index (a));
> +          else
> +            size += DWARF2_ADDR_SIZE;
>           break;
>         case dw_val_class_lineptr:
>         case dw_val_class_macptr:
> -         size += DWARF_OFFSET_SIZE;
> +          size += DWARF_OFFSET_SIZE;
>           break;
>         case dw_val_class_str:
> -         if (AT_string_form (a) == DW_FORM_strp)
> +          form = AT_string_form (a);
> +          if (form == DW_FORM_strp)
>             size += DWARF_OFFSET_SIZE;
> +         else if (form == DW_FORM_GNU_str_index)
> +            size += size_of_uleb128 (AT_index (a));
>           else
>             size += strlen (a->dw_attr_val.v.val_str->str) + 1;
>           break;
> @@ -7439,7 +7740,7 @@
>  static enum dwarf_form
>  value_format (dw_attr_ref a)
>  {
> -  switch (a->dw_attr_val.val_class)
> +  switch (AT_class (a))
>      {
>      case dw_val_class_addr:
>        /* Only very few attributes allow DW_FORM_addr.  */
> @@ -7449,7 +7750,8 @@
>         case DW_AT_high_pc:
>         case DW_AT_entry_pc:
>         case DW_AT_trampoline:
> -         return DW_FORM_addr;
> +          return (dwarf_split_debug_info && AT_index (a) != -1U
> +                 ? DW_FORM_GNU_addr_index : DW_FORM_addr);
>         default:
>           break;
>         }
> @@ -7565,7 +7867,8 @@
>      case dw_val_class_fde_ref:
>        return DW_FORM_data;
>      case dw_val_class_lbl_id:
> -      return DW_FORM_addr;
> +      return (dwarf_split_debug_info && AT_index (a) != -1U
> +             ? DW_FORM_GNU_addr_index : DW_FORM_addr);
>      case dw_val_class_lineptr:
>      case dw_val_class_macptr:
>        return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
> @@ -7613,6 +7916,36 @@
>    dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
>  }
>
> +/* Given a die and id, produce the appropriate abbreviations.  */
> +
> +static void
> +output_die_abbrevs (unsigned long abbrev_id, dw_die_ref abbrev)
> +{
> +  unsigned ix;
> +  dw_attr_ref a_attr;
> +
> +  dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
> +  dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
> +                               dwarf_tag_name (abbrev->die_tag));
> +
> +  if (abbrev->die_child != NULL)
> +    dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
> +  else
> +    dw2_asm_output_data (1, DW_children_no, "DW_children_no");
> +
> +  for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
> +       ix++)
> +    {
> +      dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
> +                                   dwarf_attr_name (a_attr->dw_attr));
> +      output_value_format (a_attr);
> +    }
> +
> +  dw2_asm_output_data (1, 0, NULL);
> +  dw2_asm_output_data (1, 0, NULL);
> +}
> +
> +
>  /* Output the .debug_abbrev section which defines the DIE abbreviation
>     table.  */
>
> @@ -7622,32 +7955,8 @@
>    unsigned long abbrev_id;
>
>    for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
> -    {
> -      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
> -      unsigned ix;
> -      dw_attr_ref a_attr;
> +    output_die_abbrevs (abbrev_id, abbrev_die_table[abbrev_id]);
>
> -      dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
> -      dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
> -                                  dwarf_tag_name (abbrev->die_tag));
> -
> -      if (abbrev->die_child != NULL)
> -       dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
> -      else
> -       dw2_asm_output_data (1, DW_children_no, "DW_children_no");
> -
> -      for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
> -          ix++)
> -       {
> -         dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
> -                                      dwarf_attr_name (a_attr->dw_attr));
> -         output_value_format (a_attr);
> -       }
> -
> -      dw2_asm_output_data (1, 0, NULL);
> -      dw2_asm_output_data (1, 0, NULL);
> -    }
> -
>    /* Terminate the table.  */
>    dw2_asm_output_data (1, 0, NULL);
>  }
> @@ -7683,6 +7992,7 @@
>    dw_loc_list_ref retlist = ggc_alloc_cleared_dw_loc_list_node ();
>
>    retlist->begin = begin;
> +  retlist->begin_index = -1U;
>    retlist->end = end;
>    retlist->expr = expr;
>    retlist->section = section;
> @@ -7727,7 +8037,22 @@
>          in a single range are unlikely very useful.  */
>        if (size > 0xffff)
>         continue;
> -      if (!have_multiple_function_sections)
> +      if (dwarf_split_debug_info)
> +        {
> +          dw2_asm_output_data (1, DW_LLE_GNU_start_length_entry,
> +                               "Location list start/length entry (%s)",
> +                               list_head->ll_symbol);
> +          dw2_asm_output_data_uleb128 (curr->begin_index,
> +                                       "Location list range start index (%s)",
> +                                       curr->begin);
> +          /* The length field is 4 bytes.  If we ever need to support
> +            an 8-byte length, we can add a new DW_LLE code or fall back
> +            to DW_LLE_GNU_start_end_entry.  */
> +          dw2_asm_output_delta (4, curr->end, curr->begin,
> +                               "Location list range length (%s)",
> +                               list_head->ll_symbol);
> +        }
> +      else if (!have_multiple_function_sections)
>         {
>           dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
>                                 "Location list begin address (%s)",
> @@ -7753,14 +8078,85 @@
>        output_loc_sequence (curr->expr, -1);
>      }
>
> -  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> -                      "Location list terminator begin (%s)",
> -                      list_head->ll_symbol);
> -  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> -                      "Location list terminator end (%s)",
> -                      list_head->ll_symbol);
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_data (1, DW_LLE_GNU_end_of_list_entry,
> +                        "Location list terminator (%s)",
> +                        list_head->ll_symbol);
> +  else
> +    {
> +      dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> +                          "Location list terminator begin (%s)",
> +                          list_head->ll_symbol);
> +      dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
> +                          "Location list terminator end (%s)",
> +                          list_head->ll_symbol);
> +    }
>  }
>
> +/* Output the offset into the debug_range section.  */
> +
> +static void
> +output_range_list_offset (dw_attr_ref a)
> +{
> +  const char *name = dwarf_attr_name (a->dw_attr);
> +
> +  if (!dwarf_split_debug_info || AT_index (a) == -1U)
> +    {
> +      char *p = strchr (ranges_section_label, '\0');
> +      sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset);
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
> +                             debug_ranges_section, "%s", name);
> +      *p = '\0';
> +    }
> +  else
> +    dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
> +                         "%s (offset from %s)", name, ranges_section_label);
> +}
> +
> +/* Output the offset into the debug_loc section.  */
> +
> +static void
> +output_loc_list_offset (dw_attr_ref a)
> +{
> +  char *sym = AT_loc_list (a)->ll_symbol;
> +
> +  gcc_assert (sym);
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
> +                          "%s", dwarf_attr_name (a->dw_attr));
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
> +                           "%s", dwarf_attr_name (a->dw_attr));
> +}
> +
> +/* Output an attribute's index or value appropriately.  */
> +
> +static void
> +output_attr_index_or_value (dw_attr_ref a)
> +{
> +  const char *name = dwarf_attr_name (a->dw_attr);
> +
> +  if (dwarf_split_debug_info && AT_index (a) != -1U)
> +    {
> +      dw2_asm_output_data_uleb128 (AT_index (a), "%s", name);
> +      return;
> +    }
> +  switch (AT_class (a))
> +    {
> +      case dw_val_class_addr:
> +        dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
> +        break;
> +      case dw_val_class_lbl_id:
> +        dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
> +        break;
> +      case dw_val_class_loc_list:
> +        output_loc_list_offset (a);
> +        break;
> +      default:
> +        gcc_unreachable ();
> +    }
> +}
> +
>  /* Output a type signature.  */
>
>  static inline void
> @@ -7799,7 +8195,7 @@
>        switch (AT_class (a))
>         {
>         case dw_val_class_addr:
> -         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_offset:
> @@ -7808,15 +8204,7 @@
>           break;
>
>         case dw_val_class_range_list:
> -         {
> -           char *p = strchr (ranges_section_label, '\0');
> -
> -           sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
> -                    a->dw_attr_val.v.val_offset);
> -           dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
> -                                  debug_ranges_section, "%s", name);
> -           *p = '\0';
> -         }
> +          output_range_list_offset (a);
>           break;
>
>         case dw_val_class_loc:
> @@ -7872,7 +8260,7 @@
>               }
>
>             dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
> -                                first, name);
> +                                first, "%s", name);
>             dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
>                                  second, NULL);
>           }
> @@ -7919,13 +8307,7 @@
>           break;
>
>         case dw_val_class_loc_list:
> -         {
> -           char *sym = AT_loc_list (a)->ll_symbol;
> -
> -           gcc_assert (sym);
> -           dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
> -                                  "%s", name);
> -         }
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_die_ref:
> @@ -7982,7 +8364,7 @@
>           break;
>
>         case dw_val_class_lbl_id:
> -         dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
> +          output_attr_index_or_value (a);
>           break;
>
>         case dw_val_class_lineptr:
> @@ -7996,12 +8378,15 @@
>           break;
>
>         case dw_val_class_str:
> -         if (AT_string_form (a) == DW_FORM_strp)
> +         if (a->dw_attr_val.v.val_str->form == DW_FORM_strp)
>             dw2_asm_output_offset (DWARF_OFFSET_SIZE,
>                                    a->dw_attr_val.v.val_str->label,
>                                    debug_str_section,
>                                    "%s: \"%s\"", name, AT_string (a));
> -         else
> +         else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
> +            dw2_asm_output_data_uleb128 (AT_index (a),
> +                                         "%s: \"%s\"", name, AT_string (a));
> +          else
>             dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
>           break;
>
> @@ -8144,6 +8529,96 @@
>      add_AT_flag (die, DW_AT_GNU_pubnames, 1);
>  }
>
> +/* Helper function to generate top-level dies for skeleton debug_info and
> +   debug_types.  */
> +
> +static void
> +add_top_level_skeleton_die_attrs (dw_die_ref die)
> +{
> +  const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL);
> +  dw_attr_ref attr;
> +
> +  add_comp_dir_attribute (die);
> +  add_AT_string (die, DW_AT_GNU_dwo_name, dwo_file_name);
> +  /* The specification suggests that these attributes be inline to avoid
> +     having a .debug_str section.  We know that they exist in the die because
> +     we just added them.  */
> +  attr = get_AT (die, DW_AT_GNU_dwo_name);
> +  attr->dw_attr_val.v.val_str->form = DW_FORM_string;
> +  attr = get_AT (die, DW_AT_comp_dir);
> +  attr->dw_attr_val.v.val_str->form = DW_FORM_string;
> +
> +  add_AT_pubnames (die);
> +  add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label);
> +}
> +
> +/* Return the single type-unit die for skeleton type units.  */
> +
> +static dw_die_ref
> +get_skeleton_type_unit (void)
> +{
> +  /* For dwarf_split_debug_sections with use_type info, all type units in the
> +     skeleton sections have identical dies (but different headers).  This
> +     single die will be output many times.  */
> +
> +  static dw_die_ref skeleton_type_unit = NULL;
> +
> +  if (skeleton_type_unit == NULL)
> +    {
> +      skeleton_type_unit = new_die (DW_TAG_type_unit, NULL, NULL);
> +      add_top_level_skeleton_die_attrs (skeleton_type_unit);
> +      skeleton_type_unit->die_abbrev = SKELETON_TYPE_DIE_ABBREV;
> +    }
> +  return skeleton_type_unit;
> +}
> +
> +/* Output skeleton debug sections that point to the dwo file.  */
> +
> +static void
> +output_skeleton_debug_sections (dw_die_ref comp_unit)
> +{
> +  /* These attributes will be found in the full debug_info section.  */
> +  remove_AT (comp_unit, DW_AT_producer);
> +  remove_AT (comp_unit, DW_AT_language);
> +
> +  /* Add attributes common to skeleton compile_units and type_units.  */
> +  add_top_level_skeleton_die_attrs (comp_unit);
> +
> +  switch_to_section (debug_skeleton_info_section);
> +  ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_info_section_label);
> +
> +  /* Produce the skeleton compilation-unit header.  This one differs enough from
> +     a normal CU header that it's better not to call output_compilation_unit
> +     header.  */
> +  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
> +    dw2_asm_output_data (4, 0xffffffff,
> +      "Initial length escape value indicating 64-bit DWARF extension");
> +
> +  dw2_asm_output_data (DWARF_OFFSET_SIZE,
> +                      DWARF_COMPILE_UNIT_HEADER_SIZE
> +                       - DWARF_INITIAL_LENGTH_SIZE
> +                       + size_of_die (comp_unit),
> +                      "Length of Compilation Unit Info");
> +  dw2_asm_output_data (2, dwarf_version, "DWARF version number");
> +  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label,
> +                        debug_abbrev_section,
> +                        "Offset Into Abbrev. Section");
> +  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
> +
> +  comp_unit->die_abbrev = SKELETON_COMP_DIE_ABBREV;
> +  output_die (comp_unit);
> +
> +  /* Build the skeleton debug_abbrev section.  */
> +  switch_to_section (debug_skeleton_abbrev_section);
> +  ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_abbrev_section_label);
> +
> +  output_die_abbrevs (SKELETON_COMP_DIE_ABBREV, comp_unit);
> +  if (use_debug_types)
> +    output_die_abbrevs (SKELETON_TYPE_DIE_ABBREV, get_skeleton_type_unit ());
> +
> +  dw2_asm_output_data (1, 0, "end of skeleton .debug_abbrev");
> +}
> +
>  /* Output a comdat type unit DIE and its children.  */
>
>  static void
> @@ -8171,7 +8646,11 @@
>    calc_die_sizes (node->root_die);
>
>  #if defined (OBJECT_FORMAT_ELF)
> -  secname = ".debug_types";
> +  if (!dwarf_split_debug_info)
> +    secname = ".debug_types";
> +  else
> +    secname = ".debug_types.dwo";
> +
>    tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
>    sprintf (tmp, "wt.");
>    for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
> @@ -8180,6 +8659,7 @@
>    targetm.asm_out.named_section (secname,
>                                   SECTION_DEBUG | SECTION_LINKONCE,
>                                   comdat_key);
> +
>  #else
>    tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
>    sprintf (tmp, ".gnu.linkonce.wt.");
> @@ -8197,6 +8677,36 @@
>    output_die (node->root_die);
>
>    unmark_dies (node->root_die);
> +
> +  if (dwarf_split_debug_info)
> +    {
> +      /* Produce the skeleton type-unit header.  */
> +      const char *secname = ".debug_types";
> +
> +      targetm.asm_out.named_section (secname,
> +                                     SECTION_DEBUG | SECTION_LINKONCE,
> +                                     comdat_key);
> +      if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
> +        dw2_asm_output_data (4, 0xffffffff,
> +          "Initial length escape value indicating 64-bit DWARF extension");
> +
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE,
> +                           DWARF_COMPILE_UNIT_HEADER_SIZE
> +                           - DWARF_INITIAL_LENGTH_SIZE
> +                           + size_of_die (get_skeleton_type_unit ())
> +                           + DWARF_TYPE_SIGNATURE_SIZE + DWARF_OFFSET_SIZE,
> +                           "Length of Type Unit Info");
> +      dw2_asm_output_data (2, dwarf_version, "DWARF version number");
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE,
> +                             debug_skeleton_abbrev_section_label,
> +                             debug_abbrev_section,
> +                             "Offset Into Abbrev. Section");
> +      dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
> +      output_signature (node->signature, "Type Signature");
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "Offset to Type DIE");
> +
> +      output_die (get_skeleton_type_unit ());
> +    }
>  }
>
>  /* Return the DWARF2/3 pubname associated with a decl.  */
> @@ -8232,7 +8742,7 @@
>       class_member, it will either be inside the class already, or will have just
>       looked up the class to find the member.  Either way, searching the class is
>       faster than searching the index.  */
> -  if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent))
> +  if ((TREE_PUBLIC (decl) && !class_scope_p (die->die_parent))
>        || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
>      {
>        const char *name = dwarf2_name (decl, 1);
> @@ -8340,9 +8850,14 @@
>                          "Length of Public Type Names Info");
>    /* Version number for pubnames/pubtypes is still 2, even in DWARF3.  */
>    dw2_asm_output_data (2, 2, "DWARF Version");
> -  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> -                        debug_info_section,
> -                        "Offset of Compilation Unit Info");
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
> +                           debug_skeleton_info_section,
> +                           "Offset of Compilation Unit Info");
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> +                           debug_info_section,
> +                           "Offset of Compilation Unit Info");
>    dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
>                        "Compilation Unit Length");
>
> @@ -8403,9 +8918,14 @@
>                        "Length of Address Ranges Info");
>    /* Version number for aranges is still 2, even in DWARF3.  */
>    dw2_asm_output_data (2, 2, "DWARF Version");
> -  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> -                        debug_info_section,
> -                        "Offset of Compilation Unit Info");
> +  if (dwarf_split_debug_info)
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
> +                           debug_skeleton_info_section,
> +                           "Offset of Compilation Unit Info");
> +  else
> +    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
> +                           debug_info_section,
> +                           "Offset of Compilation Unit Info");
>    dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
>    dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
>
> @@ -8502,12 +9022,13 @@
>    return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
>  }
>
> -/* Add a new entry to .debug_ranges corresponding to a pair of
> -   labels.  */
> +/* Add a new entry to .debug_ranges corresponding to a pair of labels.  The
> +   parameter force_direct makes the attribute use DW_AT_addr, rather than
> +   DW_AT_GNU_addr_index.  */
>
>  static void
>  add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
> -                     bool *added)
> +                     bool *added, bool force_direct)
>  {
>    unsigned int in_use = ranges_by_label_in_use;
>    unsigned int offset;
> @@ -8530,7 +9051,7 @@
>    offset = add_ranges_num (-(int)in_use - 1);
>    if (!*added)
>      {
> -      add_AT_range_list (die, DW_AT_ranges, offset);
> +      add_AT_range_list (die, DW_AT_ranges, offset, force_direct);
>        *added = true;
>      }
>  }
> @@ -9067,7 +9588,7 @@
>     information goes into the .debug_line section.  */
>
>  static void
> -output_line_info (void)
> +output_line_info (bool prologue_only)
>  {
>    char l1[20], l2[20], p1[20], p2[20];
>    int ver = dwarf_version;
> @@ -9137,6 +9658,12 @@
>    /* Write out the information about the files we use.  */
>    output_file_names ();
>    ASM_OUTPUT_LABEL (asm_out_file, p2);
> +  if (prologue_only)
> +    {
> +      /* Output the marker for the end of the line number info.  */
> +      ASM_OUTPUT_LABEL (asm_out_file, l2);
> +      return;
> +    }
>
>    if (separate_line_info)
>      {
> @@ -11437,14 +11964,7 @@
>           if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
>             break;
>
> -         /* We used to emit DW_OP_addr here, but that's wrong, since
> -            DW_OP_addr should be relocated by the debug info consumer,
> -            while DW_OP_GNU_push_tls_address operand should not.  */
> -         temp = new_loc_descr (DWARF2_ADDR_SIZE == 4
> -                               ? DW_OP_const4u : DW_OP_const8u, 0, 0);
> -         temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         temp->dw_loc_oprnd1.v.val_addr = rtl;
> -         temp->dtprel = true;
> +          temp = new_addr_loc_descr (rtl, dtprel_true);
>
>           mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
>           add_loc_descr (&mem_loc_result, temp);
> @@ -11456,9 +11976,7 @@
>         break;
>
>      symref:
> -      mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -      mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +      mem_loc_result = new_addr_loc_descr (rtl, dtprel_false);
>        VEC_safe_push (rtx, gc, used_rtx_array, rtl);
>        break;
>
> @@ -12360,9 +12878,7 @@
>        if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
>           && (dwarf_version >= 4 || !dwarf_strict))
>         {
> -         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +         loc_result = new_addr_loc_descr (rtl, dtprel_false);
>           add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
>           VEC_safe_push (rtx, gc, used_rtx_array, rtl);
>         }
> @@ -13062,9 +13578,8 @@
>        if (DECL_THREAD_LOCAL_P (loc))
>         {
>           rtx rtl;
> -         enum dwarf_location_atom first_op;
> -         enum dwarf_location_atom second_op;
> -         bool dtprel = false;
> +         enum dwarf_location_atom tls_op;
> +         enum dtprel_bool dtprel = dtprel_false;
>
>           if (targetm.have_tls)
>             {
> @@ -13081,9 +13596,8 @@
>                   operand shouldn't be.  */
>               if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
>                 return 0;
> -             first_op = DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u;
> -             dtprel = true;
> -             second_op = DW_OP_GNU_push_tls_address;
> +             dtprel = dtprel_true;
> +             tls_op = DW_OP_GNU_push_tls_address;
>             }
>           else
>             {
> @@ -13095,8 +13609,7 @@
>                  no longer appear in gimple code.  We used the control
>                  variable in specific so that we could pick it up here.  */
>               loc = DECL_VALUE_EXPR (loc);
> -             first_op = DW_OP_addr;
> -             second_op = DW_OP_form_tls_address;
> +             tls_op = DW_OP_form_tls_address;
>             }
>
>           rtl = rtl_for_decl_location (loc);
> @@ -13109,12 +13622,8 @@
>           if (! CONSTANT_P (rtl))
>             return 0;
>
> -         ret = new_loc_descr (first_op, 0, 0);
> -         ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         ret->dw_loc_oprnd1.v.val_addr = rtl;
> -         ret->dtprel = dtprel;
> -
> -         ret1 = new_loc_descr (second_op, 0, 0);
> +          ret = new_addr_loc_descr (rtl, dtprel);
> +         ret1 = new_loc_descr (tls_op, 0, 0);
>           add_loc_descr (&ret, ret1);
>
>           have_address = 1;
> @@ -13159,11 +13668,7 @@
>             return 0;
>           }
>         else if (CONSTANT_P (rtl) && const_ok_for_output (rtl))
> -         {
> -           ret = new_loc_descr (DW_OP_addr, 0, 0);
> -           ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -           ret->dw_loc_oprnd1.v.val_addr = rtl;
> -         }
> +          ret = new_addr_loc_descr (rtl, dtprel_false);
>         else
>           {
>             enum machine_mode mode, mem_mode;
> @@ -14091,9 +14596,7 @@
>           dw_loc_descr_ref loc_result;
>           resolve_one_addr (&rtl, NULL);
>         rtl_addr:
> -         loc_result = new_loc_descr (DW_OP_addr, 0, 0);
> -         loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
> -         loc_result->dw_loc_oprnd1.v.val_addr = rtl;
> +         loc_result = new_addr_loc_descr (rtl, dtprel_false);
>           add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
>           add_AT_loc (die, DW_AT_location, loc_result);
>           VEC_safe_push (rtx, gc, used_rtx_array, rtl);
> @@ -15611,7 +16114,7 @@
>    if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
>      {
>        add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
> -                  XEXP (DECL_RTL (decl), 0));
> +                  XEXP (DECL_RTL (decl), 0), false);
>        VEC_safe_push (rtx, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
>      }
>  #endif /* VMS_DEBUGGING_INFO */
> @@ -15632,7 +16135,7 @@
>    add_name_attribute (die, VMS_DEBUG_MAIN_POINTER);
>    ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
>                                current_function_funcdef_no);
> -  add_AT_lbl_id (die, DW_AT_entry_pc, label);
> +  add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
>
>    /* Make it the first child of comp_unit_die ().  */
>    die->die_parent = comp_unit_die ();
> @@ -16223,7 +16726,7 @@
>    if (DECL_ABSTRACT (decl))
>      equate_decl_number_to_die (decl, decl_die);
>    else
> -    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
> +    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl), false);
>  }
>  #endif
>
> @@ -16873,7 +17376,7 @@
>    if (stmt_die == NULL)
>      stmt_die = subr_die;
>    die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
> -  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
> +  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label, false);
>    if (ca_loc->tail_call_p)
>      add_AT_flag (die, DW_AT_GNU_tail_call, 1);
>    if (ca_loc->symbol_ref)
> @@ -16882,7 +17385,7 @@
>        if (tdie)
>         add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
>        else
> -       add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref);
> +       add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref, false);
>      }
>    return die;
>  }
> @@ -17073,7 +17576,8 @@
>           if (fde->dw_fde_begin)
>             {
>               /* We have already generated the labels.  */
> -             add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end);
> +             add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
> +                                 fde->dw_fde_end, false);
>             }
>           else
>             {
> @@ -17084,7 +17588,8 @@
>                                            current_function_funcdef_no);
>               ASM_GENERATE_INTERNAL_LABEL (label_id_high, FUNC_END_LABEL,
>                                            current_function_funcdef_no);
> -             add_AT_low_high_pc (subr_die, label_id_low, label_id_high);
> +             add_AT_low_high_pc (subr_die, label_id_low, label_id_high,
> +                                 false);
>             }
>
>  #if VMS_DEBUGGING_INFO
> @@ -17127,10 +17632,11 @@
>                      alignment offset.  */
>                   bool range_list_added = false;
>                   add_ranges_by_labels (subr_die, fde->dw_fde_begin,
> -                                       fde->dw_fde_end, &range_list_added);
> +                                       fde->dw_fde_end, &range_list_added,
> +                                       false);
>                   add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
>                                         fde->dw_fde_second_end,
> -                                       &range_list_added);
> +                                       &range_list_added, false);
>                   if (range_list_added)
>                     add_ranges (NULL);
>                 }
> @@ -17149,7 +17655,7 @@
>
>                   /* Do the 'primary' section.   */
>                   add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
> -                                     fde->dw_fde_end);
> +                                     fde->dw_fde_end, false);
>
>                   /* Build a minimal DIE for the secondary section.  */
>                   seg_die = new_die (DW_TAG_subprogram,
> @@ -17174,14 +17680,15 @@
>
>                   name = concat ("__second_sect_of_", name, NULL);
>                   add_AT_low_high_pc (seg_die, fde->dw_fde_second_begin,
> -                                     fde->dw_fde_second_end);
> +                                     fde->dw_fde_second_end, false);
>                   add_name_attribute (seg_die, name);
>                   if (want_pubnames ())
>                     add_pubname_string (name, seg_die);
>                 }
>             }
>           else
> -           add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end);
> +           add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end,
> +                               false);
>         }
>
>        cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
> @@ -17622,7 +18129,7 @@
>             {
>               /* Optimize the common case.  */
>               if (single_element_loc_list_p (loc)
> -                 && loc->expr->dw_loc_opc == DW_OP_addr
> +                  && loc->expr->dw_loc_opc == DW_OP_addr
>                   && loc->expr->dw_loc_next == NULL
>                   && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
>                 {
> @@ -17809,7 +18316,7 @@
>           gcc_assert (!INSN_DELETED_P (insn));
>
>           ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
> -         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
> +         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
>         }
>        else if (insn
>                && NOTE_P (insn)
> @@ -17817,7 +18324,7 @@
>                && CODE_LABEL_NUMBER (insn) != -1)
>         {
>           ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn));
> -         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
> +         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
>         }
>      }
>  }
> @@ -17858,7 +18365,7 @@
>         {
>           ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
>                                        BLOCK_NUMBER (stmt));
> -         add_AT_lbl_id (die, DW_AT_entry_pc, label);
> +         add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
>         }
>
>        /* Optimize duplicate .debug_ranges lists or even tails of
> @@ -17906,12 +18413,13 @@
>             ++thiscnt;
>           gcc_assert (supercnt >= thiscnt);
>           add_AT_range_list (die, DW_AT_ranges,
> -                            (off + supercnt - thiscnt)
> -                            * 2 * DWARF2_ADDR_SIZE);
> +                            ((off + supercnt - thiscnt)
> +                             * 2 * DWARF2_ADDR_SIZE),
> +                            false);
>           return;
>         }
>
> -      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
> +      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt), false);
>
>        chain = BLOCK_FRAGMENT_CHAIN (stmt);
>        do
> @@ -17929,7 +18437,7 @@
>                                    BLOCK_NUMBER (stmt));
>        ASM_GENERATE_INTERNAL_LABEL (label_high, BLOCK_END_LABEL,
>                                    BLOCK_NUMBER (stmt));
> -      add_AT_low_high_pc (die, label, label_high);
> +      add_AT_low_high_pc (die, label, label_high, false);
>      }
>  }
>
> @@ -20518,13 +21026,12 @@
>      case DW_MACRO_GNU_define_indirect:
>      case DW_MACRO_GNU_undef_indirect:
>        node = find_AT_string (ref->info);
> -      if (node->form != DW_FORM_strp)
> +      if ((node->form != DW_FORM_string)
> +          && (node->form != DW_FORM_GNU_str_index))
>         {
>           char label[32];
>           ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
> -         ++dw2_string_counter;
> -         node->label = xstrdup (label);
> -         node->form = DW_FORM_strp;
> +          add_indirect_string (node, label);
>         }
>        dw2_asm_output_data (1, ref->code,
>                            ref->code == DW_MACRO_GNU_define_indirect
> @@ -20705,8 +21212,10 @@
>         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, debug_line_section_label,
> -                            debug_line_section, NULL);
> +      dw2_asm_output_offset (DWARF_OFFSET_SIZE,
> +                             (!dwarf_split_debug_info ? debug_line_section_label
> +                              : debug_skeleton_line_section_label),
> +                             debug_line_section, NULL);
>      }
>
>    /* In the first loop, it emits the primary .debug_macinfo section
> @@ -20845,26 +21354,60 @@
>
>    used_rtx_array = VEC_alloc (rtx, gc, 32);
>
> -  debug_info_section = get_section (DEBUG_INFO_SECTION,
> -                                   SECTION_DEBUG, NULL);
> -  debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
> -                                     SECTION_DEBUG, NULL);
> +  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_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_aranges_section = get_section (DEBUG_ARANGES_SECTION,
>                                        SECTION_DEBUG, NULL);
>    debug_macinfo_section = get_section (dwarf_strict
>                                        ? DEBUG_MACINFO_SECTION
>                                        : DEBUG_MACRO_SECTION,
> -                                      SECTION_DEBUG, NULL);
> +                                      DEBUG_MACRO_SECTION_FLAGS, NULL);
>    debug_line_section = get_section (DEBUG_LINE_SECTION,
>                                     SECTION_DEBUG, NULL);
> -  debug_loc_section = get_section (DEBUG_LOC_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_STR_SECTION_FLAGS, NULL);
>    debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
>                                       SECTION_DEBUG, NULL);
>    debug_frame_section = get_section (DEBUG_FRAME_SECTION,
> @@ -20884,10 +21427,13 @@
>                                DEBUG_LINE_SECTION_LABEL, 0);
>    ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
>                                DEBUG_RANGES_SECTION_LABEL, 0);
> +  ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
> +                              DEBUG_ADDR_SECTION_LABEL, 0);
>    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);
>
>    if (debug_info_level >= DINFO_LEVEL_VERBOSE)
>      macinfo_table = VEC_alloc (macinfo_entry, gc, 64);
> @@ -20931,6 +21477,83 @@
>    return 1;
>  }
>
> +/* Output the indexed string table.  */
> +
> +static void
> +output_index_strings (void)
> +{
> +  unsigned int i;
> +  unsigned int len = 0;
> +  struct indirect_string_node *node;
> +
> +  gcc_assert (dwarf_split_debug_info);
> +
> +  if (VEC_empty (indirect_string_node, index_string_table))
> +    return;
> +
> +  switch_to_section (debug_str_offsets_section);
> +  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
> +       i++)
> +    {
> +      gcc_assert (node->form == DW_FORM_GNU_str_index);
> +      dw2_asm_output_data (DWARF_OFFSET_SIZE, len,
> +                           "indexed string 0x%x: %s", i, node->str);
> +      len += strlen (node->str) + 1;
> +    }
> +  switch_to_section (debug_str_section);
> +  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
> +       i++)
> +    {
> +      ASM_OUTPUT_LABEL (asm_out_file, node->label);
> +      assemble_string (node->str, strlen (node->str) + 1);
> +    }
> +}
> +
> +/* Write the index table.  */
> +
> +static void
> +output_addr_table (void)
> +{
> +  unsigned int i;
> +  dw_attr_node *node;
> +
> +  if (VEC_empty (dw_attr_node, addr_index_table))
> +    return;
> +
> +  switch_to_section (debug_addr_section);
> +  for (i = 0; VEC_iterate (dw_attr_node, addr_index_table, i, node); i++)
> +    {
> +      const char *name;
> +
> +      if (node->dw_attr == 0)
> +       {
> +         dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, "<Removed entry>");
> +         continue;
> +       }
> +
> +      name = dwarf_attr_name (node->dw_attr);
> +      switch (AT_class (node))
> +        {
> +          case dw_val_class_addr:
> +            dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (node),
> +                                     "%s", name);
> +            break;
> +          case dw_val_class_loc:
> +            gcc_assert (targetm.asm_out.output_dwarf_dtprel);
> +            targetm.asm_out.output_dwarf_dtprel (asm_out_file,
> +                                                 DWARF2_ADDR_SIZE,
> +                                                 node->dw_attr_val.v.val_addr);
> +            fputc ('\n', asm_out_file);
> +            break;
> +          case dw_val_class_lbl_id:
> +            dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (node), "%s", name);
> +            break;
> +          default:
> +            gcc_unreachable ();
> +        }
> +    }
> +}
> +
>  #if ENABLE_ASSERT_CHECKING
>  /* Verify that all marks are clear.  */
>
> @@ -21537,6 +22160,17 @@
>         if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
>           return false;
>         break;
> +      case DW_OP_GNU_addr_index:
> +      case DW_OP_GNU_const_index:
> +        {
> +          unsigned int idx = loc->dw_loc_oprnd1.val_index;
> +          dw_attr_node *node = &VEC_index (dw_attr_node, addr_index_table, idx);
> +          if ((loc->dw_loc_opc == DW_OP_GNU_addr_index
> +               || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
> +              && resolve_one_addr (&node->dw_attr_val.v.val_addr, NULL))
> +            return false;
> +        }
> +       break;
>        case DW_OP_const4u:
>        case DW_OP_const8u:
>         if (loc->dtprel
> @@ -21671,11 +22305,15 @@
>                 if (!resolve_addr_in_expr ((*curr)->expr))
>                   {
>                     dw_loc_list_ref next = (*curr)->dw_loc_next;
> +                   dw_loc_descr_ref l = (*curr)->expr;
> +
>                     if (next && (*curr)->ll_symbol)
>                       {
>                         gcc_assert (!next->ll_symbol);
>                         next->ll_symbol = (*curr)->ll_symbol;
>                       }
> +                   if (dwarf_split_debug_info)
> +                     remove_loc_list_addr_table_entries (l);
>                     *curr = next;
>                   }
>                 else
> @@ -21689,6 +22327,8 @@
>             else
>               {
>                 loc->replaced = 1;
> +                if (dwarf_split_debug_info)
> +                  remove_loc_list_addr_table_entries (loc->expr);
>                 loc->dw_loc_next = *start;
>               }
>           }
> @@ -21713,6 +22353,8 @@
>                || l->dw_loc_next != NULL)
>               && !resolve_addr_in_expr (l))
>             {
> +             if (dwarf_split_debug_info)
> +               remove_loc_list_addr_table_entries (l);
>               remove_AT (die, a->dw_attr);
>               ix--;
>             }
> @@ -21724,6 +22366,8 @@
>         if (a->dw_attr == DW_AT_const_value
>             && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL))
>           {
> +           if (AT_index (a) != -1U)
> +             remove_addr_table_entry (AT_index (a));
>             remove_AT (die, a->dw_attr);
>             ix--;
>           }
> @@ -21747,6 +22391,8 @@
>               }
>             else
>               {
> +               if (AT_index (a) != -1U)
> +                 remove_addr_table_entry (AT_index (a));
>                 remove_AT (die, a->dw_attr);
>                 ix--;
>               }
> @@ -21880,6 +22526,19 @@
>         }
>        hash = iterative_hash_rtx (val1->v.val_addr, hash);
>        break;
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      {
> +        dw_attr_ref attr = &VEC_index (dw_attr_node, addr_index_table,
> +                                      val1->val_index);
> +        if (loc->dtprel)
> +         {
> +            unsigned char dtprel = 0xd1;
> +            hash = iterative_hash_object (dtprel, hash);
> +          }
> +        hash = iterative_hash_rtx (attr->dw_attr_val.v.val_addr, hash);
> +      }
> +      break;
>      case DW_OP_GNU_implicit_pointer:
>        hash = iterative_hash_object (val2->v.val_int, hash);
>        break;
> @@ -22061,9 +22720,12 @@
>        return valx1->v.val_int == valy1->v.val_int;
>      case DW_OP_skip:
>      case DW_OP_bra:
> +      /* If splitting debug info, the use of DW_OP_GNU_addr_index
> +        can cause irrelevant differences in dw_loc_addr.  */
>        gcc_assert (valx1->val_class == dw_val_class_loc
>                   && valy1->val_class == dw_val_class_loc
> -                 && x->dw_loc_addr == y->dw_loc_addr);
> +                 && (dwarf_split_debug_info
> +                     || x->dw_loc_addr == y->dw_loc_addr));
>        return valx1->v.val_loc->dw_loc_addr == valy1->v.val_loc->dw_loc_addr;
>      case DW_OP_implicit_value:
>        if (valx1->v.val_unsigned != valy1->v.val_unsigned
> @@ -22094,6 +22756,18 @@
>      case DW_OP_addr:
>      hash_addr:
>        return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr);
> +    case DW_OP_GNU_addr_index:
> +    case DW_OP_GNU_const_index:
> +      {
> +        dw_attr_node *attrx1 = &VEC_index (dw_attr_node,
> +                                           addr_index_table,
> +                                           valx1->val_index);
> +        dw_attr_node *attry1 = &VEC_index (dw_attr_node,
> +                                           addr_index_table,
> +                                           valy1->val_index);
> +        return rtx_equal_p (attrx1->dw_attr_val.v.val_addr,
> +                            attry1->dw_attr_val.v.val_addr);
> +      }
>      case DW_OP_GNU_implicit_pointer:
>        return valx1->val_class == dw_val_class_die_ref
>              && valx1->val_class == valy1->val_class
> @@ -22207,7 +22881,7 @@
>         if (*slot == NULL)
>           *slot = (void *) list;
>         else
> -         a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
> +          a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
>        }
>
>    FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab));
> @@ -22223,6 +22897,43 @@
>    optimize_location_lists_1 (die, htab);
>    htab_delete (htab);
>  }
> +
> +
> +/* Recursively assign each location list a unique index into the debug_addr
> +   section.  */
> +
> +static void
> +index_location_lists (dw_die_ref die)
> +{
> +  dw_die_ref c;
> +  dw_attr_ref a;
> +  unsigned ix;
> +
> +  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
> +    if (AT_class (a) == dw_val_class_loc_list)
> +      {
> +        dw_loc_list_ref list = AT_loc_list (a);
> +        dw_loc_list_ref curr;
> +        for (curr = list; curr != NULL; curr = curr->dw_loc_next)
> +          {
> +            dw_attr_node attr;
> +
> +            /* Don't index an entry that has already been indexed
> +              or won't be output.  */
> +            if (curr->begin_index != -1U
> +               || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
> +             continue;
> +
> +            attr.dw_attr = DW_AT_location;
> +            attr.dw_attr_val.val_class = dw_val_class_lbl_id;
> +            attr.dw_attr_val.val_index = -1U;
> +            attr.dw_attr_val.v.val_lbl_id = xstrdup (curr->begin);
> +            curr->begin_index = add_addr_table_entry (&attr);
> +          }
> +      }
> +
> +  FOR_EACH_CHILD (die, c, index_location_lists (c));
> +}
>
>  /* Output stuff that dwarf requires at the end of every file,
>     and generate the DWARF-2 debugging info.  */
> @@ -22234,6 +22945,7 @@
>    comdat_type_node *ctnode;
>    htab_t comdat_type_table;
>    unsigned int i;
> +  dw_die_ref main_comp_unit_die;
>
>    /* PCH might result in DW_AT_producer string being restored from the
>       header compilation, fix it up if needed.  */
> @@ -22386,6 +23098,14 @@
>    for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
>      add_sibling_attributes (ctnode->root_die);
>
> +  /* When splitting DWARF info, we put some attributes in the
> +     skeleton compile_unit DIE that remains in the .o, while
> +     most attributes go in the DWO compile_unit_die.  */
> +  if (dwarf_split_debug_info)
> +    main_comp_unit_die = gen_compile_unit_die (NULL);
> +  else
> +    main_comp_unit_die = comp_unit_die ();
> +
>    /* Output a terminator label for the .text section.  */
>    switch_to_section (text_section);
>    targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
> @@ -22402,8 +23122,8 @@
>      {
>        /* Don't add if the CU has no associated code.  */
>        if (text_section_used)
> -       add_AT_low_high_pc (comp_unit_die (), text_section_label,
> -                           text_end_label);
> +       add_AT_low_high_pc (main_comp_unit_die, text_section_label,
> +                           text_end_label, true);
>      }
>    else
>      {
> @@ -22412,22 +23132,24 @@
>        bool range_list_added = false;
>
>        if (text_section_used)
> -       add_ranges_by_labels (comp_unit_die (), text_section_label,
> -                             text_end_label, &range_list_added);
> +       add_ranges_by_labels (main_comp_unit_die, text_section_label,
> +                             text_end_label, &range_list_added, true);
>        if (cold_text_section_used)
> -       add_ranges_by_labels (comp_unit_die (), cold_text_section_label,
> -                             cold_end_label, &range_list_added);
> +       add_ranges_by_labels (main_comp_unit_die, cold_text_section_label,
> +                             cold_end_label, &range_list_added, true);
>
>        FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde)
>         {
>           if (DECL_IGNORED_P (fde->decl))
>             continue;
>           if (!fde->in_std_section)
> -           add_ranges_by_labels (comp_unit_die (), fde->dw_fde_begin,
> -                                 fde->dw_fde_end, &range_list_added);
> +           add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_begin,
> +                                 fde->dw_fde_end, &range_list_added,
> +                                 true);
>           if (fde->dw_fde_second_begin && !fde->second_in_std_section)
> -           add_ranges_by_labels (comp_unit_die (), fde->dw_fde_second_begin,
> -                                 fde->dw_fde_second_end, &range_list_added);
> +           add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_second_begin,
> +                                 fde->dw_fde_second_end, &range_list_added,
> +                                 true);
>         }
>
>        if (range_list_added)
> @@ -22437,16 +23159,16 @@
>              absolute.  Historically, we've emitted the unexpected
>              DW_AT_entry_pc instead of DW_AT_low_pc for this purpose.
>              Emit both to give time for other tools to adapt.  */
> -         add_AT_addr (comp_unit_die (), DW_AT_low_pc, const0_rtx);
> +         add_AT_addr (main_comp_unit_die, DW_AT_low_pc, const0_rtx, true);
>           if (! dwarf_strict && dwarf_version < 4)
> -           add_AT_addr (comp_unit_die (), DW_AT_entry_pc, const0_rtx);
> +           add_AT_addr (main_comp_unit_die, DW_AT_entry_pc, const0_rtx, true);
>
>           add_ranges (NULL);
>         }
>      }
>
>    if (debug_info_level >= DINFO_LEVEL_NORMAL)
> -    add_AT_lineptr (comp_unit_die (), DW_AT_stmt_list,
> +    add_AT_lineptr (main_comp_unit_die, DW_AT_stmt_list,
>                     debug_line_section_label);
>
>    if (have_macinfo)
> @@ -22455,7 +23177,11 @@
>                    macinfo_section_label);
>
>    if (have_location_lists)
> -    optimize_location_lists (comp_unit_die ());
> +    {
> +      optimize_location_lists (comp_unit_die ());
> +      if (dwarf_split_debug_info)
> +        index_location_lists (comp_unit_die ());
> +    }
>
>    /* Output all of the compilation units.  We put the main one last so that
>       the offsets are available to output_pubnames.  */
> @@ -22476,19 +23202,54 @@
>           attributes.  */
>        if (debug_info_level >= DINFO_LEVEL_NORMAL)
>          add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
> -                       debug_line_section_label);
> +                        (!dwarf_split_debug_info
> +                         ? debug_line_section_label
> +                         : debug_skeleton_line_section_label));
>
>        output_comdat_type_unit (ctnode);
>        *slot = ctnode;
>      }
>    htab_delete (comdat_type_table);
>
> -  add_AT_pubnames (comp_unit_die ());
> +  /* 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 ());
>
> +  if (dwarf_split_debug_info)
> +    {
> +      int mark;
> +      unsigned char checksum[16];
> +      struct md5_ctx ctx;
> +
> +      /* Compute a checksum of the comp_unit to use as the dwo_id.  */
> +      md5_init_ctx (&ctx);
> +      mark = 0;
> +      die_checksum (comp_unit_die (), &ctx, &mark);
> +      unmark_all_dies (comp_unit_die ());
> +      md5_finish_ctx (&ctx, checksum);
> +
> +      /* Use the first 8 bytes of the checksum as the dwo_id,
> +        and add it to both comp-unit DIEs.  */
> +      add_AT_data8 (main_comp_unit_die, DW_AT_GNU_dwo_id, checksum);
> +      add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, checksum);
> +
> +      /* Add the base offset of the ranges table to the skeleton
> +        comp-unit DIE.  */
> +      if (ranges_table_in_use)
> +       add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base,
> +                       ranges_section_label);
> +    }
> +
>    /* Output the main compilation unit if non-empty or if .debug_macinfo
>       or .debug_macro will be emitted.  */
>    output_comp_unit (comp_unit_die (), have_macinfo);
>
> +  if (dwarf_split_debug_info && info_section_emitted)
> +    output_skeleton_debug_sections (main_comp_unit_die);
> +
>    /* Output the abbreviation table.  */
>    if (abbrev_die_table_in_use != 1)
>      {
> @@ -22502,8 +23263,6 @@
>      {
>        /* Output the location lists info.  */
>        switch_to_section (debug_loc_section);
> -      ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
> -                                  DEBUG_LOC_SECTION_LABEL, 0);
>        ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
>        output_location_lists (comp_unit_die ());
>      }
> @@ -22554,10 +23313,22 @@
>    switch_to_section (debug_line_section);
>    ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
>    if (! DWARF2_ASM_LINE_DEBUG_INFO)
> -    output_line_info ();
> +    output_line_info (false);
>
> -  /* If we emitted any DW_FORM_strp form attribute, output the string
> -     table too.  */
> +  if (dwarf_split_debug_info && info_section_emitted)
> +    {
> +      switch_to_section (debug_skeleton_line_section);
> +      ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
> +      output_line_info (true);
> +
> +      output_index_strings ();
> +
> +      switch_to_section (debug_addr_section);
> +      ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label);
> +      output_addr_table ();
> +    }
> +
> +  /* If we emitted any indirect strings, output the string table too.  */
>    if (debug_str_hash)
>      htab_traverse (debug_str_hash, output_indirect_string, NULL);
>  }
> Index: gcc/dwarf2out.h
> ===================================================================
> --- gcc/dwarf2out.h     (revision 190603)
> +++ gcc/dwarf2out.h     (working copy)
> @@ -172,6 +172,7 @@
>
>  typedef struct GTY(()) dw_val_struct {
>    enum dw_val_class val_class;
> +  unsigned int val_index;
>    union dw_val_struct_union
>      {
>        rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
> Index: gcc/opts.c
> ===================================================================
> --- gcc/opts.c  (revision 190603)
> +++ gcc/opts.c  (working copy)
> @@ -829,9 +829,14 @@
>    if (opts->x_warn_unused_but_set_parameter == -1)
>      opts->x_warn_unused_but_set_parameter = (opts->x_warn_unused
>                                              && opts->x_extra_warnings);
> +
>    /* Wunused-local-typedefs is enabled by -Wunused or -Wall.  */
>    if (opts->x_warn_unused_local_typedefs == -1)
>      opts->x_warn_unused_local_typedefs = opts->x_warn_unused;
> +
> +  /* The -gsplit-dwarf option requires -gpubnames.  */
> +  if (opts->x_dwarf_split_debug_info)
> +    opts->x_debug_generate_pub_sections = 1;
>  }
>
>  #define LEFT_COLUMN    27
> @@ -1692,6 +1697,13 @@
>        set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc);
>        break;
>
> +    case OPT_gsplit_dwarf:
> +      if (opts->x_dwarf_version < 4)
> +        opts->x_dwarf_version = 4;
> +      set_debug_level (DWARF2_DEBUG, DEFAULT_GDB_EXTENSIONS, "", opts, opts_set,
> +                      loc);
> +      break;
> +
>      case OPT_ggdb:
>        set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc);
>        break;
> Index: gcc/common.opt
> ===================================================================
> --- gcc/common.opt      (revision 190603)
> +++ gcc/common.opt      (working copy)
> @@ -2282,6 +2282,20 @@
>  Common RejectNegative Var(dwarf_record_gcc_switches,1)
>  Record gcc command line switches in DWARF DW_AT_producer.
>
> +gno-split-dwarf
> +Common Driver RejectNegative Var(dwarf_split_debug_info,0) Init(0)
> +Don't generate debug information in separate .dwo files
> +
> +gsplit-dwarf
> +Common Driver RejectNegative Var(dwarf_split_debug_info,1)
> +Generate debug information in separate .dwo files
> +
>  gstabs
>  Common JoinedOrMissing Negative(gstabs+)
>  Generate debug information in STABS format
>
> --
> This patch is available for review at http://codereview.appspot.com/6305113

Patch

Index: include/dwarf2.def
===================================================================
--- include/dwarf2.def	(revision 190603)
+++ include/dwarf2.def	(working copy)
@@ -586,7 +586,7 @@ 
 DW_OP (DW_OP_GNU_reinterpret, 0xf9)
 /* The GNU parameter ref extension.  */
 DW_OP (DW_OP_GNU_parameter_ref, 0xfa)
-/* Extension for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
+/* Extensions for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
 DW_OP (DW_OP_GNU_addr_index, 0xfb)
 DW_OP (DW_OP_GNU_const_index, 0xfc)
 /* HP extensions.  */
Index: include/dwarf2.h
===================================================================
--- include/dwarf2.h	(revision 190603)
+++ include/dwarf2.h	(working copy)
@@ -259,6 +259,17 @@ 
     DW_LNE_HP_SFC_associate = 3
   };
 
+/* Type codes for location list entries.
+   Extension for Fission.  See http://gcc.gnu.org/wiki/DebugFission.  */
+
+enum dwarf_location_list_entry_type
+  {
+    DW_LLE_GNU_end_of_list_entry = 0,
+    DW_LLE_GNU_base_address_selection_entry = 1,
+    DW_LLE_GNU_start_end_entry = 2,
+    DW_LLE_GNU_start_length_entry = 3
+  };
+
 #define DW_CIE_ID	  0xffffffff
 #define DW64_CIE_ID	  0xffffffffffffffffULL
 #define DW_CIE_VERSION	  1
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 190603)
+++ gcc/doc/invoke.texi	(working copy)
@@ -4803,6 +4803,14 @@ 
 The following options are useful when GCC is generated with the
 capability for more than one debugging format.
 
+@item -gsplit-dwarf
+@opindex gsplit-dwarf
+Separate as much dwarf debugging information as possible into a
+separate output file with the extension .dwo.  This option allows
+the build system to avoid linking files with debug information.  To
+be useful, this option requires a debugger capable of reading .dwo
+files.
+
 @item -ggdb
 @opindex ggdb
 Produce debugging information for use by GDB@.  This means to use the
Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c	(revision 190603)
+++ gcc/gcc.c	(working copy)
@@ -267,6 +267,7 @@ 
 static const char *compare_debug_self_opt_spec_function (int, const char **);
 static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
 static const char *pass_through_libs_spec_func (int, const char **);
+static const char *replace_extension_spec_func (int, const char **);
 
 /* The Specs Language
 
@@ -447,7 +448,7 @@ 
 colon in these constructs, except between . or * and the corresponding
 word.
 
-The -O, -f, -m, and -W switches are handled specifically in these
+The -O, -f, -g, -m, and -W switches are handled specifically in these
 constructs.  If another value of -O or the negated form of a -f, -m, or
 -W switch is found later in the command line, the earlier switch
 value is ignored, except with {S*} where S is just one letter; this
@@ -480,7 +481,14 @@ 
 /* config.h can define ASM_FINAL_SPEC to run a post processor after
    the assembler has run.  */
 #ifndef ASM_FINAL_SPEC
-#define ASM_FINAL_SPEC ""
+#define ASM_FINAL_SPEC \
+  "%{gsplit-dwarf: \n\
+       objcopy --extract-dwo \
+	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
+	 %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
+       objcopy --strip-dwo \
+	 %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
+    }"
 #endif
 
 /* config.h can define CPP_SPEC to provide extra args to the C preprocessor
@@ -1262,6 +1270,7 @@ 
   { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
   { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
   { "pass-through-libs",	pass_through_libs_spec_func },
+  { "replace-extension",	replace_extension_spec_func },
 #ifdef EXTRA_SPEC_FUNCTIONS
   EXTRA_SPEC_FUNCTIONS
 #endif
@@ -5803,7 +5812,7 @@ 
    on the command line.  PREFIX_LENGTH is the length of XXX in an {XXX*}
    spec, or -1 if either exact match or %* is used.
 
-   A -O switch is obsoleted by a later -O switch.  A -f, -m, or -W switch
+   A -O switch is obsoleted by a later -O switch.  A -f, -g, -m, or -W switch
    whose value does not begin with "no-" is obsoleted by the same value
    with the "no-", similarly for a switch with the "no-" prefix.  */
 
@@ -5840,7 +5849,7 @@ 
 	  }
       break;
 
-    case 'W':  case 'f':  case 'm':
+    case 'W':  case 'f':  case 'm': case 'g':
       if (! strncmp (name + 1, "no-", 3))
 	{
 	  /* We have Xno-YYY, search for XYYY.  */
@@ -8363,3 +8372,33 @@ 
     }
   return prepended;
 }
+
+/* %:replace-extension spec function.  Replaces the extension of the
+   first argument with the second argument.  */
+
+const char *
+replace_extension_spec_func (int argc, const char **argv)
+{
+  char *name;
+  char *p;
+  char *result;
+  int i;
+
+  if (argc != 2)
+    fatal_error ("too few arguments to %%:replace-extension");
+
+  name = xstrdup (argv[0]);
+
+  for (i = strlen(name) - 1; i >= 0; i--)
+    if (IS_DIR_SEPARATOR (name[i]))
+      break;
+
+  p = strrchr (name + i + 1, '.');
+  if (p != NULL)
+      *p = '\0';
+
+  result = concat (name, argv[1], NULL);
+
+  free (name);
+  return result;
+}
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(revision 190603)
+++ gcc/dwarf2out.c	(working copy)
@@ -145,14 +145,19 @@ 
 
 /* Pointers to various DWARF2 sections.  */
 static GTY(()) section *debug_info_section;
+static GTY(()) section *debug_skeleton_info_section;
 static GTY(()) section *debug_abbrev_section;
+static GTY(()) section *debug_skeleton_abbrev_section;
 static GTY(()) section *debug_aranges_section;
+static GTY(()) section *debug_addr_section;
 static GTY(()) section *debug_macinfo_section;
 static GTY(()) section *debug_line_section;
+static GTY(()) section *debug_skeleton_line_section;
 static GTY(()) section *debug_loc_section;
 static GTY(()) section *debug_pubnames_section;
 static GTY(()) section *debug_pubtypes_section;
 static GTY(()) section *debug_str_section;
+static GTY(()) section *debug_str_offsets_section;
 static GTY(()) section *debug_ranges_section;
 static GTY(()) section *debug_frame_section;
 
@@ -195,6 +200,7 @@ 
   unsigned int refcount;
   enum dwarf_form form;
   char *label;
+  unsigned int index;
 };
 
 static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
@@ -1201,7 +1207,8 @@ 
    their entire life.  */
 typedef struct GTY(()) dw_loc_list_struct {
   dw_loc_list_ref dw_loc_next;
-  const char *begin; /* Label for begin address of range */
+  const char *begin; /* Label and index for begin address of range */
+  unsigned int begin_index;
   const char *end;  /* Label for end address of range */
   char *ll_symbol; /* Label for beginning of location list.
 		      Only on head of list */
@@ -1246,8 +1253,10 @@ 
 
   descr->dw_loc_opc = op;
   descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
+  descr->dw_loc_oprnd1.val_index = -1U;
   descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
   descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
+  descr->dw_loc_oprnd2.val_index = -1U;
   descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
 
   return descr;
@@ -1452,6 +1461,10 @@ 
     case DW_OP_addr:
       size += DWARF2_ADDR_SIZE;
       break;
+    case DW_OP_GNU_addr_index:
+    case DW_OP_GNU_const_index:
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.val_index);
+      break;
     case DW_OP_const1u:
     case DW_OP_const1s:
       size += 1;
@@ -1888,6 +1901,12 @@ 
 	}
       break;
 
+    case DW_OP_GNU_addr_index:
+    case DW_OP_GNU_const_index:
+      dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_index,
+                                   "(index into .debug_addr)");
+      break;
+
     case DW_OP_GNU_implicit_pointer:
       {
 	char label[MAX_ARTIFICIAL_LABEL_BYTES
@@ -2063,6 +2082,8 @@ 
   switch (loc->dw_loc_opc)
     {
     case DW_OP_addr:
+    case DW_OP_GNU_addr_index:
+    case DW_OP_GNU_const_index:
     case DW_OP_implicit_value:
       /* We cannot output addresses in .cfi_escape, only bytes.  */
       gcc_unreachable ();
@@ -2246,6 +2267,7 @@ 
     {
       head = new_reg_loc_descr (cfa->reg, cfa->base_offset);
       head->dw_loc_oprnd1.val_class = dw_val_class_const;
+      head->dw_loc_oprnd1.val_index = -1U;
       tmp = new_loc_descr (DW_OP_deref, 0, 0);
       add_loc_descr (&head, tmp);
       if (offset != 0)
@@ -2875,6 +2897,8 @@ 
 static tree decl_class_context (tree);
 static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
 static inline enum dw_val_class AT_class (dw_attr_ref);
+static inline unsigned int AT_index (dw_attr_ref);
+static inline void set_AT_index (dw_attr_ref, unsigned int);
 static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned);
 static inline unsigned AT_flag (dw_attr_ref);
 static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT);
@@ -2902,15 +2926,18 @@ 
 static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
 			     dw_loc_list_ref);
 static inline dw_loc_list_ref AT_loc_list (dw_attr_ref);
-static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx);
+static unsigned int add_addr_table_entry (dw_attr_node *);
+static void remove_addr_table_entry (unsigned int);
+static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
 static inline rtx AT_addr (dw_attr_ref);
-static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
+static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *,
+			   bool);
 static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
 static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
 static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
 			   unsigned HOST_WIDE_INT);
 static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
-			       unsigned long);
+			       unsigned long, bool);
 static inline const char *AT_lbl (dw_attr_ref);
 static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute);
 static const char *get_AT_low_pc (dw_die_ref);
@@ -3005,6 +3032,7 @@ 
 static enum dwarf_form value_format (dw_attr_ref);
 static void output_value_format (dw_attr_ref);
 static void output_abbrev_section (void);
+static void output_die_abbrevs (unsigned long, dw_die_ref);
 static void output_die_symbol (dw_die_ref);
 static void output_die (dw_die_ref);
 static void output_compilation_unit_header (void);
@@ -3020,10 +3048,10 @@ 
 static unsigned int add_ranges_num (int);
 static unsigned int add_ranges (const_tree);
 static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
-				  bool *);
+				  bool *, bool);
 static void output_ranges (void);
 static dw_line_info_table *new_line_info_table (void);
-static void output_line_info (void);
+static void output_line_info (bool);
 static void output_file_names (void);
 static dw_die_ref base_type_die (tree);
 static int is_base_type (tree);
@@ -3162,36 +3190,130 @@ 
 static void schedule_generic_params_dies_gen (tree t);
 static void gen_scheduled_generic_parms_dies (void);
 
+/* enum for tracking thread-local variables whose address is really an offset
+   relative to the TLS pointer, which will need link-time relocation, but will
+   not need relocation by the DWARF consumer.  */
+
+enum dtprel_bool
+  {
+    dtprel_false = 0,
+    dtprel_true = 1
+  };
+
+/* Return the operator to use for an address of a variable.  For dtprel_true, we
+   use DW_OP_const*.  For regular variables, which need both link-time
+   relocation and consumer-level relocation (e.g., to account for shared objects
+   loaded at a random address), we use DW_OP_addr*.  */
+
+static inline enum dwarf_location_atom
+dw_addr_op (enum dtprel_bool dtprel)
+{
+  if (dtprel == dtprel_true)
+    return (dwarf_split_debug_info ? DW_OP_GNU_const_index
+            : (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u));
+  else
+    return (dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr);
+}
+
+/* Return a pointer to a newly allocated address location description.  If
+   dwarf_split_debug_info is true, then record the address with the appropriate
+   relocation.  */
+static inline dw_loc_descr_ref
+new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
+{
+  dw_loc_descr_ref ref = new_loc_descr (dw_addr_op (dtprel), 0, 0);
+
+  ref->dw_loc_oprnd1.val_class = dw_val_class_addr;
+  ref->dw_loc_oprnd1.val_index = -1U;
+  ref->dw_loc_oprnd1.v.val_addr = addr;
+  ref->dtprel = dtprel;
+  if (dwarf_split_debug_info)
+    {
+      dw_attr_node attr;
+
+      attr.dw_attr = DW_AT_location;
+      attr.dw_attr_val.val_class = (dtprel == dtprel_true
+                                    ? dw_val_class_loc : dw_val_class_addr);
+      attr.dw_attr_val.val_index = -1U;
+      attr.dw_attr_val.v.val_addr = addr;
+
+      ref->dw_loc_oprnd1.val_index = add_addr_table_entry (&attr);
+    }
+  return ref;
+}
+
 /* Section names used to hold DWARF debugging information.  */
+
 #ifndef DEBUG_INFO_SECTION
 #define DEBUG_INFO_SECTION	".debug_info"
 #endif
+#ifndef DEBUG_DWO_INFO_SECTION
+#define DEBUG_DWO_INFO_SECTION	".debug_info.dwo"
+#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_ARANGES_SECTION
 #define DEBUG_ARANGES_SECTION	".debug_aranges"
 #endif
+#ifndef DEBUG_ADDR_SECTION
+#define DEBUG_ADDR_SECTION	".debug_addr"
+#endif
+#ifndef DEBUG_NORM_MACINFO_SECTION
+#define DEBUG_NORM_MACINFO_SECTION	".debug_macinfo"
+#endif
+#ifndef DEBUG_DWO_MACINFO_SECTION
+#define DEBUG_DWO_MACINFO_SECTION	".debug_macinfo.dwo"
+#endif
 #ifndef DEBUG_MACINFO_SECTION
-#define DEBUG_MACINFO_SECTION	".debug_macinfo"
+#define DEBUG_MACINFO_SECTION                                           \
+  (!dwarf_split_debug_info                                              \
+   ? (DEBUG_NORM_MACINFO_SECTION) : (DEBUG_DWO_MACINFO_SECTION))
 #endif
+#ifndef DEBUG_NORM_MACRO_SECTION
+#define DEBUG_NORM_MACRO_SECTION ".debug_macro"
+#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"
+#define DEBUG_MACRO_SECTION                                             \
+  (!dwarf_split_debug_info                                              \
+   ? (DEBUG_NORM_MACRO_SECTION) : (DEBUG_DWO_MACRO_SECTION))
 #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_LOC_SECTION
 #define DEBUG_LOC_SECTION	".debug_loc"
 #endif
+#ifndef DEBUG_DWO_LOC_SECTION
+#define DEBUG_DWO_LOC_SECTION	".debug_loc.dwo"
+#endif
 #ifndef DEBUG_PUBNAMES_SECTION
 #define DEBUG_PUBNAMES_SECTION	".debug_pubnames"
 #endif
 #ifndef DEBUG_PUBTYPES_SECTION
 #define DEBUG_PUBTYPES_SECTION	".debug_pubtypes"
 #endif
+#define DEBUG_NORM_STR_OFFSETS_SECTION ".debug_str_offsets"
+#define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo"
+#ifndef DEBUG_STR_OFFSETS_SECTION
+#define DEBUG_STR_OFFSETS_SECTION                                       \
+  (!dwarf_split_debug_info                                              \
+   ? (DEBUG_NORM_STR_OFFSETS_SECTION) : (DEBUG_DWO_STR_OFFSETS_SECTION))
+#endif
+#define DEBUG_DWO_STR_SECTION   ".debug_str.dwo"
+#define DEBUG_NORM_STR_SECTION  ".debug_str"
 #ifndef DEBUG_STR_SECTION
-#define DEBUG_STR_SECTION	".debug_str"
+#define DEBUG_STR_SECTION                               \
+  (!dwarf_split_debug_info ? (DEBUG_NORM_STR_SECTION) : (DEBUG_DWO_STR_SECTION))
 #endif
 #ifndef DEBUG_RANGES_SECTION
 #define DEBUG_RANGES_SECTION	".debug_ranges"
@@ -3202,44 +3324,63 @@ 
 #define TEXT_SECTION_NAME	".text"
 #endif
 
+/* Section flags for .debug_macinfo/.debug_macro section.  */
+#define DEBUG_MACRO_SECTION_FLAGS \
+  (dwarf_split_debug_info ? SECTION_DEBUG | SECTION_EXCLUDE : SECTION_DEBUG)
+
 /* Section flags for .debug_str section.  */
 #define DEBUG_STR_SECTION_FLAGS \
-  (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings		\
-   ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1	\
-   : SECTION_DEBUG)
+  (dwarf_split_debug_info \
+   ? SECTION_DEBUG | SECTION_EXCLUDE \
+   : (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings \
+      ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1        \
+      : SECTION_DEBUG))
 
 /* Labels we insert at beginning sections we can reference instead of
    the section names themselves.  */
 
 #ifndef TEXT_SECTION_LABEL
-#define TEXT_SECTION_LABEL		"Ltext"
+#define TEXT_SECTION_LABEL		    "Ltext"
 #endif
 #ifndef COLD_TEXT_SECTION_LABEL
-#define COLD_TEXT_SECTION_LABEL         "Ltext_cold"
+#define COLD_TEXT_SECTION_LABEL             "Ltext_cold"
 #endif
 #ifndef DEBUG_LINE_SECTION_LABEL
-#define DEBUG_LINE_SECTION_LABEL	"Ldebug_line"
+#define DEBUG_LINE_SECTION_LABEL	    "Ldebug_line"
 #endif
+#ifndef DEBUG_SKELETON_LINE_SECTION_LABEL
+#define DEBUG_SKELETON_LINE_SECTION_LABEL   "Lskeleton_debug_line"
+#endif
 #ifndef DEBUG_INFO_SECTION_LABEL
-#define DEBUG_INFO_SECTION_LABEL	"Ldebug_info"
+#define DEBUG_INFO_SECTION_LABEL	    "Ldebug_info"
 #endif
+#ifndef DEBUG_SKELETON_INFO_SECTION_LABEL
+#define DEBUG_SKELETON_INFO_SECTION_LABEL   "Lskeleton_debug_info"
+#endif
 #ifndef DEBUG_ABBREV_SECTION_LABEL
-#define DEBUG_ABBREV_SECTION_LABEL	"Ldebug_abbrev"
+#define DEBUG_ABBREV_SECTION_LABEL	    "Ldebug_abbrev"
 #endif
+#ifndef DEBUG_SKELETON_ABBREV_SECTION_LABEL
+#define DEBUG_SKELETON_ABBREV_SECTION_LABEL "Lskeleton_debug_abbrev"
+#endif
+#ifndef DEBUG_ADDR_SECTION_LABEL
+#define DEBUG_ADDR_SECTION_LABEL	    "Ldebug_addr"
+#endif
 #ifndef DEBUG_LOC_SECTION_LABEL
-#define DEBUG_LOC_SECTION_LABEL		"Ldebug_loc"
+#define DEBUG_LOC_SECTION_LABEL		    "Ldebug_loc"
 #endif
 #ifndef DEBUG_RANGES_SECTION_LABEL
-#define DEBUG_RANGES_SECTION_LABEL	"Ldebug_ranges"
+#define DEBUG_RANGES_SECTION_LABEL	    "Ldebug_ranges"
 #endif
 #ifndef DEBUG_MACINFO_SECTION_LABEL
-#define DEBUG_MACINFO_SECTION_LABEL     "Ldebug_macinfo"
+#define DEBUG_MACINFO_SECTION_LABEL         "Ldebug_macinfo"
 #endif
 #ifndef DEBUG_MACRO_SECTION_LABEL
-#define DEBUG_MACRO_SECTION_LABEL	"Ldebug_macro"
+#define DEBUG_MACRO_SECTION_LABEL	    "Ldebug_macro"
 #endif
+#define SKELETON_COMP_DIE_ABBREV 1
+#define SKELETON_TYPE_DIE_ABBREV 2
 
-
 /* Definitions of defaults for formats and names of various special
    (artificial) labels which may be generated within this file (when the -g
    options is used and DWARF2_DEBUGGING_INFO is in effect.
@@ -3252,7 +3393,11 @@ 
 static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_skeleton_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_skeleton_abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_addr_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_skeleton_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
@@ -3493,6 +3638,31 @@ 
   return a->dw_attr_val.val_class;
 }
 
+/* Return the index for any attribute that will be referenced with a
+   DW_FORM_GNU_addr_index.  Strings have their indices handled differently to
+   account for reference counting pruning.  */
+
+static inline unsigned int
+AT_index (dw_attr_ref a)
+{
+  if (AT_class (a) == dw_val_class_str)
+    return a->dw_attr_val.v.val_str->index;
+  else
+    return a->dw_attr_val.val_index;
+}
+
+/* Set the index for any attribute that will be referenced with a
+   DW_FORM_GNU_addr_index.  */
+
+static inline void
+set_AT_index (dw_attr_ref a, unsigned int index)
+{
+  if (AT_class (a) == dw_val_class_str)
+    a->dw_attr_val.v.val_str->index = index;
+  else
+    a->dw_attr_val.val_index = index;
+}
+
 /* Add a flag value attribute to a DIE.  */
 
 static inline void
@@ -3502,6 +3672,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_flag;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_flag = flag;
   add_dwarf_attr (die, &attr);
 }
@@ -3522,6 +3693,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_const;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_int = int_val;
   add_dwarf_attr (die, &attr);
 }
@@ -3543,6 +3715,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_unsigned = unsigned_val;
   add_dwarf_attr (die, &attr);
 }
@@ -3564,6 +3737,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_const_double;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_double.high = high;
   attr.dw_attr_val.v.val_double.low = low;
   add_dwarf_attr (die, &attr);
@@ -3579,6 +3753,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_vec;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_vec.length = length;
   attr.dw_attr_val.v.val_vec.elt_size = elt_size;
   attr.dw_attr_val.v.val_vec.array = array;
@@ -3595,28 +3770,39 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_data8;
+  attr.dw_attr_val.val_index = -1U;
   memcpy (attr.dw_attr_val.v.val_data8, data8, 8);
   add_dwarf_attr (die, &attr);
 }
 
-/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  */
+/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE.  The parameter force_direct
+   makes the attribute use DW_AT_addr, rather than DW_AT_GNU_addr_index.  */
+
 static inline void
-add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high)
+add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high,
+		    bool force_direct)
 {
   dw_attr_node attr;
 
   attr.dw_attr = DW_AT_low_pc;
   attr.dw_attr_val.val_class = dw_val_class_lbl_id;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_low);
   add_dwarf_attr (die, &attr);
+  if (dwarf_split_debug_info && !force_direct)
+    set_AT_index (get_AT (die, DW_AT_low_pc), add_addr_table_entry (&attr));
 
   attr.dw_attr = DW_AT_high_pc;
   if (dwarf_version < 4)
     attr.dw_attr_val.val_class = dw_val_class_lbl_id;
   else
     attr.dw_attr_val.val_class = dw_val_class_high_pc;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_high);
   add_dwarf_attr (die, &attr);
+  if (attr.dw_attr_val.val_class == dw_val_class_lbl_id
+      && dwarf_split_debug_info && !force_direct)
+    set_AT_index (get_AT (die, DW_AT_high_pc), add_addr_table_entry (&attr));
 }
 
 /* Hash and equality functions for debug_str_hash.  */
@@ -3673,6 +3859,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_str;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_str = node;
   add_dwarf_attr (die, &attr);
 }
@@ -3684,6 +3871,38 @@ 
   return a->dw_attr_val.v.val_str->str;
 }
 
+/* A vector for a table of strings in the form DW_FORM_GNU_index_str.  */
+
+typedef struct indirect_string_node indirect_string_node;
+DEF_VEC_O(indirect_string_node);
+DEF_VEC_ALLOC_O(indirect_string_node, gc);
+static GTY (()) VEC (indirect_string_node, gc) *index_string_table;
+
+/* Add a new indirect string to the appropriate tables.  Returns the index of
+   the new string.  Call this function directly to bypass AT_string_form's logic
+   to put the string inline in the die. */
+
+static unsigned long
+add_indirect_string (struct indirect_string_node *node, const char *str)
+{
+  static unsigned int index_string_count = 0;
+  ++dw2_string_counter;
+  node->label = xstrdup (str);
+
+  if (!dwarf_split_debug_info)
+    {
+      node->form = DW_FORM_strp;
+      return -1U;
+    }
+  else
+    {
+      node->form = DW_FORM_GNU_str_index;
+      index_string_count++;
+      VEC_safe_push (indirect_string_node, gc, index_string_table, node);
+      return index_string_count;
+    }
+}
+
 /* Find out whether a string should be output inline in DIE
    or out-of-line in .debug_str section.  */
 
@@ -3716,10 +3935,9 @@ 
     return node->form = DW_FORM_string;
 
   ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
-  ++dw2_string_counter;
-  node->label = xstrdup (label);
+  set_AT_index (a, add_indirect_string (node, label));
 
-  return node->form = DW_FORM_strp;
+  return node->form;
 }
 
 /* Add a DIE reference attribute value to a DIE.  */
@@ -3740,6 +3958,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_die_ref;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_die_ref.die = targ_die;
   attr.dw_attr_val.v.val_die_ref.external = 0;
   add_dwarf_attr (die, &attr);
@@ -3798,6 +4017,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_fde_ref;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_fde_index = targ_fde;
   add_dwarf_attr (die, &attr);
 }
@@ -3811,6 +4031,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_loc;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_loc = loc;
   add_dwarf_attr (die, &attr);
 }
@@ -3829,6 +4050,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_loc_list;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_loc_list = loc_list;
   add_dwarf_attr (die, &attr);
   have_location_lists = true;
@@ -3848,17 +4070,62 @@ 
   return &a->dw_attr_val.v.val_loc_list;
 }
 
-/* Add an address constant attribute value to a DIE.  */
+/* A table of entries into the .debug_addr section.  */
 
+static GTY (()) VEC (dw_attr_node,gc) * addr_index_table;
+
+static unsigned int
+add_addr_table_entry (dw_attr_node *attr)
+{
+  gcc_assert (dwarf_split_debug_info);
+
+  VEC_safe_push (dw_attr_node, gc, addr_index_table, attr);
+  return VEC_length (dw_attr_node, addr_index_table) - 1;
+}
+
+/* Remove an entry from the addr table.  Since we have already numbered
+   all the entries, the best we can do here is null it out.  */
+
+static void
+remove_addr_table_entry (unsigned int i)
+{
+  dw_attr_node *attr;
+
+  gcc_assert (dwarf_split_debug_info);
+  gcc_assert (i < VEC_length (dw_attr_node, addr_index_table));
+
+  attr = &VEC_index (dw_attr_node, addr_index_table, i);
+  attr->dw_attr = (enum dwarf_attribute) 0;
+}
+
+/* Given a location list, remove all addresses it refers to from the
+   address_table.  */
+
+static void
+remove_loc_list_addr_table_entries (dw_loc_descr_ref descr)
+{
+  for (; descr; descr = descr->dw_loc_next)
+    if (descr->dw_loc_oprnd1.val_index != -1U)
+      remove_addr_table_entry (descr->dw_loc_oprnd1.val_index);
+}
+
+/* Add an address constant attribute value to a DIE.  The parameter
+   force_direct makes the attribute use DW_AT_addr, rather than
+   DW_AT_GNU_addr_index.  */
+
 static inline void
-add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
+add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr,
+	     bool force_direct)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_addr;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_addr = addr;
   add_dwarf_attr (die, &attr);
+  if (dwarf_split_debug_info && !force_direct)
+    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
 }
 
 /* Get the RTX from to an address DIE attribute.  */
@@ -3880,6 +4147,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_file;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_file = fd;
   add_dwarf_attr (die, &attr);
 }
@@ -3903,22 +4171,29 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_vms_delta;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1);
   attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2);
   add_dwarf_attr (die, &attr);
 }
 
-/* Add a label identifier attribute value to a DIE.  */
+/* Add a label identifier attribute value to a DIE.  The parameter
+   force_direct makes the attribute use DW_AT_addr, rather than
+   DW_AT_GNU_addr_index.  */
 
 static inline void
-add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
+add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind,
+	       const char *lbl_id, bool force_direct)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_lbl_id;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
   add_dwarf_attr (die, &attr);
+  if (dwarf_split_debug_info && !force_direct)
+    set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr));
 }
 
 /* Add a section offset attribute value to a DIE, an offset into the
@@ -3932,6 +4207,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_lineptr;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
   add_dwarf_attr (die, &attr);
 }
@@ -3947,6 +4223,7 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_macptr;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
   add_dwarf_attr (die, &attr);
 }
@@ -3961,20 +4238,31 @@ 
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_offset;
+  attr.dw_attr_val.val_index = -1U;
   attr.dw_attr_val.v.val_offset = offset;
   add_dwarf_attr (die, &attr);
 }
 
-/* Add an range_list attribute value to a DIE.  */
+/* Add a range_list attribute value to a DIE.  The parameter
+   force_direct makes the attribute use DW_AT_addr, rather than
+   DW_AT_GNU_addr_index.  */
 
 static void
 add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
-		   long unsigned int offset)
+		   long unsigned int offset, bool force_direct)
 {
   dw_attr_node attr;
 
   attr.dw_attr = attr_kind;
   attr.dw_attr_val.val_class = dw_val_class_range_list;
+  /* For the range_list attribute, val_index == -1U indicates that we want to
+     output a relocated reference to the range list entry, while any other
+     value indicates that we want to output the section-relative offset of the
+     range list entry. In this case, we're not using the val_index field as a
+     slot index like we do for references to .debug_addr.  This is used
+     in output_range_list_offset.  */
+  attr.dw_attr_val.val_index
+      = (dwarf_split_debug_info && !force_direct) ? offset : -1U;
   attr.dw_attr_val.v.val_offset = offset;
   add_dwarf_attr (die, &attr);
 }
@@ -7158,6 +7446,7 @@ 
   unsigned long size = 0;
   dw_attr_ref a;
   unsigned ix;
+  enum dwarf_form form;
 
   size += size_of_uleb128 (die->die_abbrev);
   FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
@@ -7165,7 +7454,10 @@ 
       switch (AT_class (a))
 	{
 	case dw_val_class_addr:
-	  size += DWARF2_ADDR_SIZE;
+          if (dwarf_split_debug_info && AT_index (a) != -1U)
+            size += size_of_uleb128 (AT_index (a));
+          else
+            size += DWARF2_ADDR_SIZE;
 	  break;
 	case dw_val_class_offset:
 	  size += DWARF_OFFSET_SIZE;
@@ -7183,10 +7475,13 @@ 
 	  }
 	  break;
 	case dw_val_class_loc_list:
-	  size += DWARF_OFFSET_SIZE;
+          if (dwarf_split_debug_info && AT_index (a) != -1U)
+            size += size_of_uleb128 (AT_index (a));
+          else
+            size += DWARF_OFFSET_SIZE;
 	  break;
 	case dw_val_class_range_list:
-	  size += DWARF_OFFSET_SIZE;
+          size += DWARF_OFFSET_SIZE;
 	  break;
 	case dw_val_class_const:
 	  size += size_of_sleb128 (AT_int (a));
@@ -7246,15 +7541,21 @@ 
 	  size += DWARF_OFFSET_SIZE;
 	  break;
 	case dw_val_class_lbl_id:
-	  size += DWARF2_ADDR_SIZE;
+          if (dwarf_split_debug_info && AT_index (a) != -1U)
+            size += size_of_uleb128 (AT_index (a));
+          else
+            size += DWARF2_ADDR_SIZE;
 	  break;
 	case dw_val_class_lineptr:
 	case dw_val_class_macptr:
-	  size += DWARF_OFFSET_SIZE;
+          size += DWARF_OFFSET_SIZE;
 	  break;
 	case dw_val_class_str:
-	  if (AT_string_form (a) == DW_FORM_strp)
+          form = AT_string_form (a);
+          if (form == DW_FORM_strp)
 	    size += DWARF_OFFSET_SIZE;
+	  else if (form == DW_FORM_GNU_str_index)
+            size += size_of_uleb128 (AT_index (a));
 	  else
 	    size += strlen (a->dw_attr_val.v.val_str->str) + 1;
 	  break;
@@ -7439,7 +7740,7 @@ 
 static enum dwarf_form
 value_format (dw_attr_ref a)
 {
-  switch (a->dw_attr_val.val_class)
+  switch (AT_class (a))
     {
     case dw_val_class_addr:
       /* Only very few attributes allow DW_FORM_addr.  */
@@ -7449,7 +7750,8 @@ 
 	case DW_AT_high_pc:
 	case DW_AT_entry_pc:
 	case DW_AT_trampoline:
-	  return DW_FORM_addr;
+          return (dwarf_split_debug_info && AT_index (a) != -1U
+		  ? DW_FORM_GNU_addr_index : DW_FORM_addr);
 	default:
 	  break;
 	}
@@ -7565,7 +7867,8 @@ 
     case dw_val_class_fde_ref:
       return DW_FORM_data;
     case dw_val_class_lbl_id:
-      return DW_FORM_addr;
+      return (dwarf_split_debug_info && AT_index (a) != -1U
+	      ? DW_FORM_GNU_addr_index : DW_FORM_addr);
     case dw_val_class_lineptr:
     case dw_val_class_macptr:
       return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
@@ -7613,6 +7916,36 @@ 
   dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
 }
 
+/* Given a die and id, produce the appropriate abbreviations.  */
+
+static void
+output_die_abbrevs (unsigned long abbrev_id, dw_die_ref abbrev)
+{
+  unsigned ix;
+  dw_attr_ref a_attr;
+
+  dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
+  dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
+                               dwarf_tag_name (abbrev->die_tag));
+
+  if (abbrev->die_child != NULL)
+    dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
+  else
+    dw2_asm_output_data (1, DW_children_no, "DW_children_no");
+
+  for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
+       ix++)
+    {
+      dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
+                                   dwarf_attr_name (a_attr->dw_attr));
+      output_value_format (a_attr);
+    }
+
+  dw2_asm_output_data (1, 0, NULL);
+  dw2_asm_output_data (1, 0, NULL);
+}
+
+
 /* Output the .debug_abbrev section which defines the DIE abbreviation
    table.  */
 
@@ -7622,32 +7955,8 @@ 
   unsigned long abbrev_id;
 
   for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
-    {
-      dw_die_ref abbrev = abbrev_die_table[abbrev_id];
-      unsigned ix;
-      dw_attr_ref a_attr;
+    output_die_abbrevs (abbrev_id, abbrev_die_table[abbrev_id]);
 
-      dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
-      dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
-				   dwarf_tag_name (abbrev->die_tag));
-
-      if (abbrev->die_child != NULL)
-	dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
-      else
-	dw2_asm_output_data (1, DW_children_no, "DW_children_no");
-
-      for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
-	   ix++)
-	{
-	  dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
-				       dwarf_attr_name (a_attr->dw_attr));
-	  output_value_format (a_attr);
-	}
-
-      dw2_asm_output_data (1, 0, NULL);
-      dw2_asm_output_data (1, 0, NULL);
-    }
-
   /* Terminate the table.  */
   dw2_asm_output_data (1, 0, NULL);
 }
@@ -7683,6 +7992,7 @@ 
   dw_loc_list_ref retlist = ggc_alloc_cleared_dw_loc_list_node ();
 
   retlist->begin = begin;
+  retlist->begin_index = -1U;
   retlist->end = end;
   retlist->expr = expr;
   retlist->section = section;
@@ -7727,7 +8037,22 @@ 
 	 in a single range are unlikely very useful.  */
       if (size > 0xffff)
 	continue;
-      if (!have_multiple_function_sections)
+      if (dwarf_split_debug_info)
+        {
+          dw2_asm_output_data (1, DW_LLE_GNU_start_length_entry,
+                               "Location list start/length entry (%s)",
+                               list_head->ll_symbol);
+          dw2_asm_output_data_uleb128 (curr->begin_index,
+                                       "Location list range start index (%s)",
+                                       curr->begin);
+          /* The length field is 4 bytes.  If we ever need to support
+	     an 8-byte length, we can add a new DW_LLE code or fall back
+	     to DW_LLE_GNU_start_end_entry.  */
+          dw2_asm_output_delta (4, curr->end, curr->begin,
+				"Location list range length (%s)",
+				list_head->ll_symbol);
+        }
+      else if (!have_multiple_function_sections)
 	{
 	  dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
 				"Location list begin address (%s)",
@@ -7753,14 +8078,85 @@ 
       output_loc_sequence (curr->expr, -1);
     }
 
-  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
-		       "Location list terminator begin (%s)",
-		       list_head->ll_symbol);
-  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
-		       "Location list terminator end (%s)",
-		       list_head->ll_symbol);
+  if (dwarf_split_debug_info)
+    dw2_asm_output_data (1, DW_LLE_GNU_end_of_list_entry,
+			 "Location list terminator (%s)",
+			 list_head->ll_symbol);
+  else
+    {
+      dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
+			   "Location list terminator begin (%s)",
+			   list_head->ll_symbol);
+      dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
+			   "Location list terminator end (%s)",
+			   list_head->ll_symbol);
+    }
 }
 
+/* Output the offset into the debug_range section.  */
+
+static void
+output_range_list_offset (dw_attr_ref a)
+{
+  const char *name = dwarf_attr_name (a->dw_attr);
+
+  if (!dwarf_split_debug_info || AT_index (a) == -1U)
+    {
+      char *p = strchr (ranges_section_label, '\0');
+      sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset);
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
+                             debug_ranges_section, "%s", name);
+      *p = '\0';
+    }
+  else
+    dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
+                         "%s (offset from %s)", name, ranges_section_label);
+}
+
+/* Output the offset into the debug_loc section.  */
+
+static void
+output_loc_list_offset (dw_attr_ref a)
+{
+  char *sym = AT_loc_list (a)->ll_symbol;
+
+  gcc_assert (sym);
+  if (dwarf_split_debug_info)
+    dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
+                          "%s", dwarf_attr_name (a->dw_attr));
+  else
+    dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
+                           "%s", dwarf_attr_name (a->dw_attr));
+}
+
+/* Output an attribute's index or value appropriately.  */
+
+static void
+output_attr_index_or_value (dw_attr_ref a)
+{
+  const char *name = dwarf_attr_name (a->dw_attr);
+
+  if (dwarf_split_debug_info && AT_index (a) != -1U)
+    {
+      dw2_asm_output_data_uleb128 (AT_index (a), "%s", name);
+      return;
+    }
+  switch (AT_class (a))
+    {
+      case dw_val_class_addr:
+        dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
+        break;
+      case dw_val_class_lbl_id:
+        dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
+        break;
+      case dw_val_class_loc_list:
+        output_loc_list_offset (a);
+        break;
+      default:
+        gcc_unreachable ();
+    }
+}
+
 /* Output a type signature.  */
 
 static inline void
@@ -7799,7 +8195,7 @@ 
       switch (AT_class (a))
 	{
 	case dw_val_class_addr:
-	  dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
+          output_attr_index_or_value (a);
 	  break;
 
 	case dw_val_class_offset:
@@ -7808,15 +8204,7 @@ 
 	  break;
 
 	case dw_val_class_range_list:
-	  {
-	    char *p = strchr (ranges_section_label, '\0');
-
-	    sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
-		     a->dw_attr_val.v.val_offset);
-	    dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
-				   debug_ranges_section, "%s", name);
-	    *p = '\0';
-	  }
+          output_range_list_offset (a);
 	  break;
 
 	case dw_val_class_loc:
@@ -7872,7 +8260,7 @@ 
 	      }
 
 	    dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
-				 first, name);
+				 first, "%s", name);
 	    dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR,
 				 second, NULL);
 	  }
@@ -7919,13 +8307,7 @@ 
 	  break;
 
 	case dw_val_class_loc_list:
-	  {
-	    char *sym = AT_loc_list (a)->ll_symbol;
-
-	    gcc_assert (sym);
-	    dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
-				   "%s", name);
-	  }
+          output_attr_index_or_value (a);
 	  break;
 
 	case dw_val_class_die_ref:
@@ -7982,7 +8364,7 @@ 
 	  break;
 
 	case dw_val_class_lbl_id:
-	  dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
+          output_attr_index_or_value (a);
 	  break;
 
 	case dw_val_class_lineptr:
@@ -7996,12 +8378,15 @@ 
 	  break;
 
 	case dw_val_class_str:
-	  if (AT_string_form (a) == DW_FORM_strp)
+	  if (a->dw_attr_val.v.val_str->form == DW_FORM_strp)
 	    dw2_asm_output_offset (DWARF_OFFSET_SIZE,
 				   a->dw_attr_val.v.val_str->label,
 				   debug_str_section,
 				   "%s: \"%s\"", name, AT_string (a));
-	  else
+	  else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
+            dw2_asm_output_data_uleb128 (AT_index (a),
+                                         "%s: \"%s\"", name, AT_string (a));
+          else
 	    dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
 	  break;
 
@@ -8144,6 +8529,96 @@ 
     add_AT_flag (die, DW_AT_GNU_pubnames, 1);
 }
 
+/* Helper function to generate top-level dies for skeleton debug_info and
+   debug_types.  */
+
+static void
+add_top_level_skeleton_die_attrs (dw_die_ref die)
+{
+  const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL);
+  dw_attr_ref attr;
+
+  add_comp_dir_attribute (die);
+  add_AT_string (die, DW_AT_GNU_dwo_name, dwo_file_name);
+  /* The specification suggests that these attributes be inline to avoid
+     having a .debug_str section.  We know that they exist in the die because
+     we just added them.  */
+  attr = get_AT (die, DW_AT_GNU_dwo_name);
+  attr->dw_attr_val.v.val_str->form = DW_FORM_string;
+  attr = get_AT (die, DW_AT_comp_dir);
+  attr->dw_attr_val.v.val_str->form = DW_FORM_string;
+
+  add_AT_pubnames (die);
+  add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label);
+}
+
+/* Return the single type-unit die for skeleton type units.  */
+
+static dw_die_ref
+get_skeleton_type_unit (void)
+{
+  /* For dwarf_split_debug_sections with use_type info, all type units in the
+     skeleton sections have identical dies (but different headers).  This
+     single die will be output many times.  */
+
+  static dw_die_ref skeleton_type_unit = NULL;
+
+  if (skeleton_type_unit == NULL)
+    {
+      skeleton_type_unit = new_die (DW_TAG_type_unit, NULL, NULL);
+      add_top_level_skeleton_die_attrs (skeleton_type_unit);
+      skeleton_type_unit->die_abbrev = SKELETON_TYPE_DIE_ABBREV;
+    }
+  return skeleton_type_unit;
+}
+
+/* Output skeleton debug sections that point to the dwo file.  */
+
+static void
+output_skeleton_debug_sections (dw_die_ref comp_unit)
+{
+  /* These attributes will be found in the full debug_info section.  */
+  remove_AT (comp_unit, DW_AT_producer);
+  remove_AT (comp_unit, DW_AT_language);
+
+  /* Add attributes common to skeleton compile_units and type_units.  */
+  add_top_level_skeleton_die_attrs (comp_unit);
+
+  switch_to_section (debug_skeleton_info_section);
+  ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_info_section_label);
+
+  /* Produce the skeleton compilation-unit header.  This one differs enough from
+     a normal CU header that it's better not to call output_compilation_unit
+     header.  */
+  if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+    dw2_asm_output_data (4, 0xffffffff,
+      "Initial length escape value indicating 64-bit DWARF extension");
+
+  dw2_asm_output_data (DWARF_OFFSET_SIZE,
+		       DWARF_COMPILE_UNIT_HEADER_SIZE
+                       - DWARF_INITIAL_LENGTH_SIZE
+                       + size_of_die (comp_unit),
+		       "Length of Compilation Unit Info");
+  dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label,
+			 debug_abbrev_section,
+			 "Offset Into Abbrev. Section");
+  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+
+  comp_unit->die_abbrev = SKELETON_COMP_DIE_ABBREV;
+  output_die (comp_unit);
+
+  /* Build the skeleton debug_abbrev section.  */
+  switch_to_section (debug_skeleton_abbrev_section);
+  ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_abbrev_section_label);
+
+  output_die_abbrevs (SKELETON_COMP_DIE_ABBREV, comp_unit);
+  if (use_debug_types)
+    output_die_abbrevs (SKELETON_TYPE_DIE_ABBREV, get_skeleton_type_unit ());
+
+  dw2_asm_output_data (1, 0, "end of skeleton .debug_abbrev");
+}
+
 /* Output a comdat type unit DIE and its children.  */
 
 static void
@@ -8171,7 +8646,11 @@ 
   calc_die_sizes (node->root_die);
 
 #if defined (OBJECT_FORMAT_ELF)
-  secname = ".debug_types";
+  if (!dwarf_split_debug_info)
+    secname = ".debug_types";
+  else
+    secname = ".debug_types.dwo";
+
   tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
   sprintf (tmp, "wt.");
   for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
@@ -8180,6 +8659,7 @@ 
   targetm.asm_out.named_section (secname,
                                  SECTION_DEBUG | SECTION_LINKONCE,
                                  comdat_key);
+
 #else
   tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
   sprintf (tmp, ".gnu.linkonce.wt.");
@@ -8197,6 +8677,36 @@ 
   output_die (node->root_die);
 
   unmark_dies (node->root_die);
+
+  if (dwarf_split_debug_info)
+    {
+      /* Produce the skeleton type-unit header.  */
+      const char *secname = ".debug_types";
+
+      targetm.asm_out.named_section (secname,
+                                     SECTION_DEBUG | SECTION_LINKONCE,
+                                     comdat_key);
+      if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+        dw2_asm_output_data (4, 0xffffffff,
+          "Initial length escape value indicating 64-bit DWARF extension");
+
+      dw2_asm_output_data (DWARF_OFFSET_SIZE,
+                           DWARF_COMPILE_UNIT_HEADER_SIZE
+                           - DWARF_INITIAL_LENGTH_SIZE
+                           + size_of_die (get_skeleton_type_unit ())
+                           + DWARF_TYPE_SIGNATURE_SIZE + DWARF_OFFSET_SIZE,
+                           "Length of Type Unit Info");
+      dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+                             debug_skeleton_abbrev_section_label,
+                             debug_abbrev_section,
+                             "Offset Into Abbrev. Section");
+      dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+      output_signature (node->signature, "Type Signature");
+      dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "Offset to Type DIE");
+
+      output_die (get_skeleton_type_unit ());
+    }
 }
 
 /* Return the DWARF2/3 pubname associated with a decl.  */
@@ -8232,7 +8742,7 @@ 
      class_member, it will either be inside the class already, or will have just
      looked up the class to find the member.  Either way, searching the class is
      faster than searching the index.  */
-  if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent))
+  if ((TREE_PUBLIC (decl) && !class_scope_p (die->die_parent))
       || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
     {
       const char *name = dwarf2_name (decl, 1);
@@ -8340,9 +8850,14 @@ 
 			 "Length of Public Type Names Info");
   /* Version number for pubnames/pubtypes is still 2, even in DWARF3.  */
   dw2_asm_output_data (2, 2, "DWARF Version");
-  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
-			 debug_info_section,
-			 "Offset of Compilation Unit Info");
+  if (dwarf_split_debug_info)
+    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
+                           debug_skeleton_info_section,
+                           "Offset of Compilation Unit Info");
+  else
+    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+                           debug_info_section,
+                           "Offset of Compilation Unit Info");
   dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
 		       "Compilation Unit Length");
 
@@ -8403,9 +8918,14 @@ 
 		       "Length of Address Ranges Info");
   /* Version number for aranges is still 2, even in DWARF3.  */
   dw2_asm_output_data (2, 2, "DWARF Version");
-  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
-			 debug_info_section,
-			 "Offset of Compilation Unit Info");
+  if (dwarf_split_debug_info)
+    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
+                           debug_skeleton_info_section,
+                           "Offset of Compilation Unit Info");
+  else
+    dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+                           debug_info_section,
+                           "Offset of Compilation Unit Info");
   dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
   dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
 
@@ -8502,12 +9022,13 @@ 
   return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
 }
 
-/* Add a new entry to .debug_ranges corresponding to a pair of
-   labels.  */
+/* Add a new entry to .debug_ranges corresponding to a pair of labels.  The
+   parameter force_direct makes the attribute use DW_AT_addr, rather than
+   DW_AT_GNU_addr_index.  */
 
 static void
 add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
-		      bool *added)
+		      bool *added, bool force_direct)
 {
   unsigned int in_use = ranges_by_label_in_use;
   unsigned int offset;
@@ -8530,7 +9051,7 @@ 
   offset = add_ranges_num (-(int)in_use - 1);
   if (!*added)
     {
-      add_AT_range_list (die, DW_AT_ranges, offset);
+      add_AT_range_list (die, DW_AT_ranges, offset, force_direct);
       *added = true;
     }
 }
@@ -9067,7 +9588,7 @@ 
    information goes into the .debug_line section.  */
 
 static void
-output_line_info (void)
+output_line_info (bool prologue_only)
 {
   char l1[20], l2[20], p1[20], p2[20];
   int ver = dwarf_version;
@@ -9137,6 +9658,12 @@ 
   /* Write out the information about the files we use.  */
   output_file_names ();
   ASM_OUTPUT_LABEL (asm_out_file, p2);
+  if (prologue_only)
+    {
+      /* Output the marker for the end of the line number info.  */
+      ASM_OUTPUT_LABEL (asm_out_file, l2);
+      return;
+    }
 
   if (separate_line_info)
     {
@@ -11437,14 +11964,7 @@ 
 	  if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
 	    break;
 
-	  /* We used to emit DW_OP_addr here, but that's wrong, since
-	     DW_OP_addr should be relocated by the debug info consumer,
-	     while DW_OP_GNU_push_tls_address operand should not.  */
-	  temp = new_loc_descr (DWARF2_ADDR_SIZE == 4
-				? DW_OP_const4u : DW_OP_const8u, 0, 0);
-	  temp->dw_loc_oprnd1.val_class = dw_val_class_addr;
-	  temp->dw_loc_oprnd1.v.val_addr = rtl;
-	  temp->dtprel = true;
+          temp = new_addr_loc_descr (rtl, dtprel_true);
 
 	  mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
 	  add_loc_descr (&mem_loc_result, temp);
@@ -11456,9 +11976,7 @@ 
 	break;
 
     symref:
-      mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
-      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
-      mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+      mem_loc_result = new_addr_loc_descr (rtl, dtprel_false);
       VEC_safe_push (rtx, gc, used_rtx_array, rtl);
       break;
 
@@ -12360,9 +12878,7 @@ 
       if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE
 	  && (dwarf_version >= 4 || !dwarf_strict))
 	{
-	  loc_result = new_loc_descr (DW_OP_addr, 0, 0);
-	  loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
-	  loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+	  loc_result = new_addr_loc_descr (rtl, dtprel_false);
 	  add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
 	  VEC_safe_push (rtx, gc, used_rtx_array, rtl);
 	}
@@ -13062,9 +13578,8 @@ 
       if (DECL_THREAD_LOCAL_P (loc))
 	{
 	  rtx rtl;
-	  enum dwarf_location_atom first_op;
-	  enum dwarf_location_atom second_op;
-	  bool dtprel = false;
+	  enum dwarf_location_atom tls_op;
+	  enum dtprel_bool dtprel = dtprel_false;
 
 	  if (targetm.have_tls)
 	    {
@@ -13081,9 +13596,8 @@ 
 		  operand shouldn't be.  */
 	      if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
 		return 0;
-	      first_op = DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u;
-	      dtprel = true;
-	      second_op = DW_OP_GNU_push_tls_address;
+	      dtprel = dtprel_true;
+	      tls_op = DW_OP_GNU_push_tls_address;
 	    }
 	  else
 	    {
@@ -13095,8 +13609,7 @@ 
 		 no longer appear in gimple code.  We used the control
 		 variable in specific so that we could pick it up here.  */
 	      loc = DECL_VALUE_EXPR (loc);
-	      first_op = DW_OP_addr;
-	      second_op = DW_OP_form_tls_address;
+	      tls_op = DW_OP_form_tls_address;
 	    }
 
 	  rtl = rtl_for_decl_location (loc);
@@ -13109,12 +13622,8 @@ 
 	  if (! CONSTANT_P (rtl))
 	    return 0;
 
-	  ret = new_loc_descr (first_op, 0, 0);
-	  ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
-	  ret->dw_loc_oprnd1.v.val_addr = rtl;
-	  ret->dtprel = dtprel;
-
-	  ret1 = new_loc_descr (second_op, 0, 0);
+          ret = new_addr_loc_descr (rtl, dtprel);
+	  ret1 = new_loc_descr (tls_op, 0, 0);
 	  add_loc_descr (&ret, ret1);
 
 	  have_address = 1;
@@ -13159,11 +13668,7 @@ 
 	    return 0;
 	  }
 	else if (CONSTANT_P (rtl) && const_ok_for_output (rtl))
-	  {
-	    ret = new_loc_descr (DW_OP_addr, 0, 0);
-	    ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
-	    ret->dw_loc_oprnd1.v.val_addr = rtl;
-	  }
+          ret = new_addr_loc_descr (rtl, dtprel_false);
 	else
 	  {
 	    enum machine_mode mode, mem_mode;
@@ -14091,9 +14596,7 @@ 
 	  dw_loc_descr_ref loc_result;
 	  resolve_one_addr (&rtl, NULL);
 	rtl_addr:
-	  loc_result = new_loc_descr (DW_OP_addr, 0, 0);
-	  loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
-	  loc_result->dw_loc_oprnd1.v.val_addr = rtl;
+	  loc_result = new_addr_loc_descr (rtl, dtprel_false);
 	  add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0));
 	  add_AT_loc (die, DW_AT_location, loc_result);
 	  VEC_safe_push (rtx, gc, used_rtx_array, rtl);
@@ -15611,7 +16114,7 @@ 
   if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
     {
       add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address,
-		   XEXP (DECL_RTL (decl), 0));
+		   XEXP (DECL_RTL (decl), 0), false);
       VEC_safe_push (rtx, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0));
     }
 #endif /* VMS_DEBUGGING_INFO */
@@ -15632,7 +16135,7 @@ 
   add_name_attribute (die, VMS_DEBUG_MAIN_POINTER);
   ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
 			       current_function_funcdef_no);
-  add_AT_lbl_id (die, DW_AT_entry_pc, label);
+  add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
 
   /* Make it the first child of comp_unit_die ().  */
   die->die_parent = comp_unit_die ();
@@ -16223,7 +16726,7 @@ 
   if (DECL_ABSTRACT (decl))
     equate_decl_number_to_die (decl, decl_die);
   else
-    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
+    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl), false);
 }
 #endif
 
@@ -16873,7 +17376,7 @@ 
   if (stmt_die == NULL)
     stmt_die = subr_die;
   die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
-  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
+  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label, false);
   if (ca_loc->tail_call_p)
     add_AT_flag (die, DW_AT_GNU_tail_call, 1);
   if (ca_loc->symbol_ref)
@@ -16882,7 +17385,7 @@ 
       if (tdie)
 	add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
       else
-	add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref);
+	add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref, false);
     }
   return die;
 }
@@ -17073,7 +17576,8 @@ 
 	  if (fde->dw_fde_begin)
 	    {
 	      /* We have already generated the labels.  */
-	      add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end);
+	      add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
+				  fde->dw_fde_end, false);
 	    }
 	  else
 	    {
@@ -17084,7 +17588,8 @@ 
 					   current_function_funcdef_no);
 	      ASM_GENERATE_INTERNAL_LABEL (label_id_high, FUNC_END_LABEL,
 					   current_function_funcdef_no);
-	      add_AT_low_high_pc (subr_die, label_id_low, label_id_high);
+	      add_AT_low_high_pc (subr_die, label_id_low, label_id_high,
+				  false);
 	    }
 
 #if VMS_DEBUGGING_INFO
@@ -17127,10 +17632,11 @@ 
 		     alignment offset.  */
 		  bool range_list_added = false;
 		  add_ranges_by_labels (subr_die, fde->dw_fde_begin,
-					fde->dw_fde_end, &range_list_added);
+					fde->dw_fde_end, &range_list_added,
+					false);
 		  add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
 					fde->dw_fde_second_end,
-					&range_list_added);
+					&range_list_added, false);
 		  if (range_list_added)
 		    add_ranges (NULL);
 		}
@@ -17149,7 +17655,7 @@ 
 
 		  /* Do the 'primary' section.   */
 		  add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
-				      fde->dw_fde_end);
+				      fde->dw_fde_end, false);
 
 		  /* Build a minimal DIE for the secondary section.  */
 		  seg_die = new_die (DW_TAG_subprogram,
@@ -17174,14 +17680,15 @@ 
 
 		  name = concat ("__second_sect_of_", name, NULL); 
 		  add_AT_low_high_pc (seg_die, fde->dw_fde_second_begin,
-				      fde->dw_fde_second_end);
+				      fde->dw_fde_second_end, false);
 		  add_name_attribute (seg_die, name);
 		  if (want_pubnames ())
 		    add_pubname_string (name, seg_die);
 		}
 	    }
 	  else
-	    add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end);
+	    add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end,
+				false);
 	}
 
       cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
@@ -17622,7 +18129,7 @@ 
 	    {
 	      /* Optimize the common case.  */
 	      if (single_element_loc_list_p (loc)
-		  && loc->expr->dw_loc_opc == DW_OP_addr
+                  && loc->expr->dw_loc_opc == DW_OP_addr
 		  && loc->expr->dw_loc_next == NULL
 		  && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
 		{
@@ -17809,7 +18316,7 @@ 
 	  gcc_assert (!INSN_DELETED_P (insn));
 
 	  ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
-	  add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
+	  add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
 	}
       else if (insn
 	       && NOTE_P (insn)
@@ -17817,7 +18324,7 @@ 
 	       && CODE_LABEL_NUMBER (insn) != -1)
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn));
-	  add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
+	  add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false);
 	}
     }
 }
@@ -17858,7 +18365,7 @@ 
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
 				       BLOCK_NUMBER (stmt));
-	  add_AT_lbl_id (die, DW_AT_entry_pc, label);
+	  add_AT_lbl_id (die, DW_AT_entry_pc, label, false);
 	}
 
       /* Optimize duplicate .debug_ranges lists or even tails of
@@ -17906,12 +18413,13 @@ 
 	    ++thiscnt;
 	  gcc_assert (supercnt >= thiscnt);
 	  add_AT_range_list (die, DW_AT_ranges,
-			     (off + supercnt - thiscnt)
-			     * 2 * DWARF2_ADDR_SIZE);
+			     ((off + supercnt - thiscnt)
+			      * 2 * DWARF2_ADDR_SIZE),
+			     false);
 	  return;
 	}
 
-      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
+      add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt), false);
 
       chain = BLOCK_FRAGMENT_CHAIN (stmt);
       do
@@ -17929,7 +18437,7 @@ 
 				   BLOCK_NUMBER (stmt));
       ASM_GENERATE_INTERNAL_LABEL (label_high, BLOCK_END_LABEL,
 				   BLOCK_NUMBER (stmt));
-      add_AT_low_high_pc (die, label, label_high);
+      add_AT_low_high_pc (die, label, label_high, false);
     }
 }
 
@@ -20518,13 +21026,12 @@ 
     case DW_MACRO_GNU_define_indirect:
     case DW_MACRO_GNU_undef_indirect:
       node = find_AT_string (ref->info);
-      if (node->form != DW_FORM_strp)
+      if ((node->form != DW_FORM_string)
+          && (node->form != DW_FORM_GNU_str_index))
 	{
 	  char label[32];
 	  ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
-	  ++dw2_string_counter;
-	  node->label = xstrdup (label);
-	  node->form = DW_FORM_strp;
+          add_indirect_string (node, label);
 	}
       dw2_asm_output_data (1, ref->code,
 			   ref->code == DW_MACRO_GNU_define_indirect
@@ -20705,8 +21212,10 @@ 
 	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, debug_line_section_label,
-			     debug_line_section, NULL);
+      dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+                             (!dwarf_split_debug_info ? debug_line_section_label
+                              : debug_skeleton_line_section_label),
+                             debug_line_section, NULL);
     }
 
   /* In the first loop, it emits the primary .debug_macinfo section
@@ -20845,26 +21354,60 @@ 
 
   used_rtx_array = VEC_alloc (rtx, gc, 32);
 
-  debug_info_section = get_section (DEBUG_INFO_SECTION,
-				    SECTION_DEBUG, NULL);
-  debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
-				      SECTION_DEBUG, NULL);
+  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_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_aranges_section = get_section (DEBUG_ARANGES_SECTION,
 				       SECTION_DEBUG, NULL);
   debug_macinfo_section = get_section (dwarf_strict
 				       ? DEBUG_MACINFO_SECTION
 				       : DEBUG_MACRO_SECTION,
-				       SECTION_DEBUG, NULL);
+				       DEBUG_MACRO_SECTION_FLAGS, NULL);
   debug_line_section = get_section (DEBUG_LINE_SECTION,
 				    SECTION_DEBUG, NULL);
-  debug_loc_section = get_section (DEBUG_LOC_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_STR_SECTION_FLAGS, NULL);
   debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
 				      SECTION_DEBUG, NULL);
   debug_frame_section = get_section (DEBUG_FRAME_SECTION,
@@ -20884,10 +21427,13 @@ 
 			       DEBUG_LINE_SECTION_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
 			       DEBUG_RANGES_SECTION_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
+			       DEBUG_ADDR_SECTION_LABEL, 0);
   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);
 
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     macinfo_table = VEC_alloc (macinfo_entry, gc, 64);
@@ -20931,6 +21477,83 @@ 
   return 1;
 }
 
+/* Output the indexed string table.  */
+
+static void
+output_index_strings (void)
+{
+  unsigned int i;
+  unsigned int len = 0;
+  struct indirect_string_node *node;
+
+  gcc_assert (dwarf_split_debug_info);
+
+  if (VEC_empty (indirect_string_node, index_string_table))
+    return;
+
+  switch_to_section (debug_str_offsets_section);
+  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
+       i++)
+    {
+      gcc_assert (node->form == DW_FORM_GNU_str_index);
+      dw2_asm_output_data (DWARF_OFFSET_SIZE, len,
+                           "indexed string 0x%x: %s", i, node->str);
+      len += strlen (node->str) + 1;
+    }
+  switch_to_section (debug_str_section);
+  for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node);
+       i++)
+    {
+      ASM_OUTPUT_LABEL (asm_out_file, node->label);
+      assemble_string (node->str, strlen (node->str) + 1);
+    }
+}
+
+/* Write the index table.  */
+
+static void
+output_addr_table (void)
+{
+  unsigned int i;
+  dw_attr_node *node;
+
+  if (VEC_empty (dw_attr_node, addr_index_table))
+    return;
+
+  switch_to_section (debug_addr_section);
+  for (i = 0; VEC_iterate (dw_attr_node, addr_index_table, i, node); i++)
+    {
+      const char *name;
+
+      if (node->dw_attr == 0)
+	{
+	  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, "<Removed entry>");
+	  continue;
+	}
+
+      name = dwarf_attr_name (node->dw_attr);
+      switch (AT_class (node))
+        {
+          case dw_val_class_addr:
+            dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (node),
+                                     "%s", name);
+            break;
+          case dw_val_class_loc:
+            gcc_assert (targetm.asm_out.output_dwarf_dtprel);
+            targetm.asm_out.output_dwarf_dtprel (asm_out_file,
+                                                 DWARF2_ADDR_SIZE,
+                                                 node->dw_attr_val.v.val_addr);
+            fputc ('\n', asm_out_file);
+            break;
+          case dw_val_class_lbl_id:
+            dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (node), "%s", name);
+            break;
+          default:
+            gcc_unreachable ();
+        }
+    }
+}
+
 #if ENABLE_ASSERT_CHECKING
 /* Verify that all marks are clear.  */
 
@@ -21537,6 +22160,17 @@ 
 	if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
 	  return false;
 	break;
+      case DW_OP_GNU_addr_index:
+      case DW_OP_GNU_const_index:
+        {
+          unsigned int idx = loc->dw_loc_oprnd1.val_index;
+          dw_attr_node *node = &VEC_index (dw_attr_node, addr_index_table, idx);
+          if ((loc->dw_loc_opc == DW_OP_GNU_addr_index
+               || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel))
+              && resolve_one_addr (&node->dw_attr_val.v.val_addr, NULL))
+            return false;
+        }
+	break;
       case DW_OP_const4u:
       case DW_OP_const8u:
 	if (loc->dtprel
@@ -21671,11 +22305,15 @@ 
 		if (!resolve_addr_in_expr ((*curr)->expr))
 		  {
 		    dw_loc_list_ref next = (*curr)->dw_loc_next;
+		    dw_loc_descr_ref l = (*curr)->expr;
+
 		    if (next && (*curr)->ll_symbol)
 		      {
 			gcc_assert (!next->ll_symbol);
 			next->ll_symbol = (*curr)->ll_symbol;
 		      }
+		    if (dwarf_split_debug_info)
+		      remove_loc_list_addr_table_entries (l);
 		    *curr = next;
 		  }
 		else
@@ -21689,6 +22327,8 @@ 
 	    else
 	      {
 		loc->replaced = 1;
+                if (dwarf_split_debug_info)
+                  remove_loc_list_addr_table_entries (loc->expr);
 		loc->dw_loc_next = *start;
 	      }
 	  }
@@ -21713,6 +22353,8 @@ 
 	       || l->dw_loc_next != NULL)
 	      && !resolve_addr_in_expr (l))
 	    {
+	      if (dwarf_split_debug_info)
+		remove_loc_list_addr_table_entries (l);
 	      remove_AT (die, a->dw_attr);
 	      ix--;
 	    }
@@ -21724,6 +22366,8 @@ 
 	if (a->dw_attr == DW_AT_const_value
 	    && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL))
 	  {
+	    if (AT_index (a) != -1U)
+	      remove_addr_table_entry (AT_index (a));
 	    remove_AT (die, a->dw_attr);
 	    ix--;
 	  }
@@ -21747,6 +22391,8 @@ 
 	      }
 	    else
 	      {
+		if (AT_index (a) != -1U)
+		  remove_addr_table_entry (AT_index (a));
 		remove_AT (die, a->dw_attr);
 		ix--;
 	      }
@@ -21880,6 +22526,19 @@ 
 	}
       hash = iterative_hash_rtx (val1->v.val_addr, hash);
       break;
+    case DW_OP_GNU_addr_index:
+    case DW_OP_GNU_const_index:
+      {
+        dw_attr_ref attr = &VEC_index (dw_attr_node, addr_index_table,
+				       val1->val_index);
+        if (loc->dtprel)
+	  {
+            unsigned char dtprel = 0xd1;
+            hash = iterative_hash_object (dtprel, hash);
+          }
+        hash = iterative_hash_rtx (attr->dw_attr_val.v.val_addr, hash);
+      }
+      break;
     case DW_OP_GNU_implicit_pointer:
       hash = iterative_hash_object (val2->v.val_int, hash);
       break;
@@ -22061,9 +22720,12 @@ 
       return valx1->v.val_int == valy1->v.val_int;
     case DW_OP_skip:
     case DW_OP_bra:
+      /* If splitting debug info, the use of DW_OP_GNU_addr_index
+	 can cause irrelevant differences in dw_loc_addr.  */
       gcc_assert (valx1->val_class == dw_val_class_loc
 		  && valy1->val_class == dw_val_class_loc
-		  && x->dw_loc_addr == y->dw_loc_addr);
+		  && (dwarf_split_debug_info
+		      || x->dw_loc_addr == y->dw_loc_addr));
       return valx1->v.val_loc->dw_loc_addr == valy1->v.val_loc->dw_loc_addr;
     case DW_OP_implicit_value:
       if (valx1->v.val_unsigned != valy1->v.val_unsigned
@@ -22094,6 +22756,18 @@ 
     case DW_OP_addr:
     hash_addr:
       return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr);
+    case DW_OP_GNU_addr_index:
+    case DW_OP_GNU_const_index:
+      {
+        dw_attr_node *attrx1 = &VEC_index (dw_attr_node,
+                                           addr_index_table,
+                                           valx1->val_index);
+        dw_attr_node *attry1 = &VEC_index (dw_attr_node,
+                                           addr_index_table,
+                                           valy1->val_index);
+        return rtx_equal_p (attrx1->dw_attr_val.v.val_addr,
+                            attry1->dw_attr_val.v.val_addr);
+      }
     case DW_OP_GNU_implicit_pointer:
       return valx1->val_class == dw_val_class_die_ref
 	     && valx1->val_class == valy1->val_class
@@ -22207,7 +22881,7 @@ 
 	if (*slot == NULL)
 	  *slot = (void *) list;
 	else
-	  a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
+          a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot;
       }
 
   FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab));
@@ -22223,6 +22897,43 @@ 
   optimize_location_lists_1 (die, htab);
   htab_delete (htab);
 }
+
+
+/* Recursively assign each location list a unique index into the debug_addr
+   section.  */
+
+static void
+index_location_lists (dw_die_ref die)
+{
+  dw_die_ref c;
+  dw_attr_ref a;
+  unsigned ix;
+
+  FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a)
+    if (AT_class (a) == dw_val_class_loc_list)
+      {
+        dw_loc_list_ref list = AT_loc_list (a);
+        dw_loc_list_ref curr;
+        for (curr = list; curr != NULL; curr = curr->dw_loc_next)
+          {
+            dw_attr_node attr;
+
+            /* Don't index an entry that has already been indexed
+	       or won't be output.  */
+            if (curr->begin_index != -1U
+	        || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
+	      continue;
+
+            attr.dw_attr = DW_AT_location;
+            attr.dw_attr_val.val_class = dw_val_class_lbl_id;
+            attr.dw_attr_val.val_index = -1U;
+            attr.dw_attr_val.v.val_lbl_id = xstrdup (curr->begin);
+            curr->begin_index = add_addr_table_entry (&attr);
+          }
+      }
+
+  FOR_EACH_CHILD (die, c, index_location_lists (c));
+}
 
 /* Output stuff that dwarf requires at the end of every file,
    and generate the DWARF-2 debugging info.  */
@@ -22234,6 +22945,7 @@ 
   comdat_type_node *ctnode;
   htab_t comdat_type_table;
   unsigned int i;
+  dw_die_ref main_comp_unit_die;
 
   /* PCH might result in DW_AT_producer string being restored from the
      header compilation, fix it up if needed.  */
@@ -22386,6 +23098,14 @@ 
   for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
     add_sibling_attributes (ctnode->root_die);
 
+  /* When splitting DWARF info, we put some attributes in the
+     skeleton compile_unit DIE that remains in the .o, while
+     most attributes go in the DWO compile_unit_die.  */
+  if (dwarf_split_debug_info)
+    main_comp_unit_die = gen_compile_unit_die (NULL);
+  else
+    main_comp_unit_die = comp_unit_die ();
+
   /* Output a terminator label for the .text section.  */
   switch_to_section (text_section);
   targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
@@ -22402,8 +23122,8 @@ 
     {
       /* Don't add if the CU has no associated code.  */
       if (text_section_used)
-	add_AT_low_high_pc (comp_unit_die (), text_section_label,
-			    text_end_label);
+	add_AT_low_high_pc (main_comp_unit_die, text_section_label,
+			    text_end_label, true);
     }
   else
     {
@@ -22412,22 +23132,24 @@ 
       bool range_list_added = false;
 
       if (text_section_used)
-	add_ranges_by_labels (comp_unit_die (), text_section_label,
-			      text_end_label, &range_list_added);
+	add_ranges_by_labels (main_comp_unit_die, text_section_label,
+			      text_end_label, &range_list_added, true);
       if (cold_text_section_used)
-	add_ranges_by_labels (comp_unit_die (), cold_text_section_label,
-			      cold_end_label, &range_list_added);
+	add_ranges_by_labels (main_comp_unit_die, cold_text_section_label,
+			      cold_end_label, &range_list_added, true);
 
       FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde)
 	{
 	  if (DECL_IGNORED_P (fde->decl))
 	    continue;
 	  if (!fde->in_std_section)
-	    add_ranges_by_labels (comp_unit_die (), fde->dw_fde_begin,
-				  fde->dw_fde_end, &range_list_added);
+	    add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_begin,
+				  fde->dw_fde_end, &range_list_added,
+				  true);
 	  if (fde->dw_fde_second_begin && !fde->second_in_std_section)
-	    add_ranges_by_labels (comp_unit_die (), fde->dw_fde_second_begin,
-				  fde->dw_fde_second_end, &range_list_added);
+	    add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_second_begin,
+				  fde->dw_fde_second_end, &range_list_added,
+				  true);
 	}
 
       if (range_list_added)
@@ -22437,16 +23159,16 @@ 
 	     absolute.  Historically, we've emitted the unexpected
 	     DW_AT_entry_pc instead of DW_AT_low_pc for this purpose.
 	     Emit both to give time for other tools to adapt.  */
-	  add_AT_addr (comp_unit_die (), DW_AT_low_pc, const0_rtx);
+	  add_AT_addr (main_comp_unit_die, DW_AT_low_pc, const0_rtx, true);
 	  if (! dwarf_strict && dwarf_version < 4)
-	    add_AT_addr (comp_unit_die (), DW_AT_entry_pc, const0_rtx);
+	    add_AT_addr (main_comp_unit_die, DW_AT_entry_pc, const0_rtx, true);
 
 	  add_ranges (NULL);
 	}
     }
 
   if (debug_info_level >= DINFO_LEVEL_NORMAL)
-    add_AT_lineptr (comp_unit_die (), DW_AT_stmt_list,
+    add_AT_lineptr (main_comp_unit_die, DW_AT_stmt_list,
 		    debug_line_section_label);
 
   if (have_macinfo)
@@ -22455,7 +23177,11 @@ 
 		   macinfo_section_label);
 
   if (have_location_lists)
-    optimize_location_lists (comp_unit_die ());
+    {
+      optimize_location_lists (comp_unit_die ());
+      if (dwarf_split_debug_info)
+        index_location_lists (comp_unit_die ());
+    }
 
   /* Output all of the compilation units.  We put the main one last so that
      the offsets are available to output_pubnames.  */
@@ -22476,19 +23202,54 @@ 
          attributes.  */
       if (debug_info_level >= DINFO_LEVEL_NORMAL)
         add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
-		        debug_line_section_label);
+                        (!dwarf_split_debug_info
+                         ? debug_line_section_label
+                         : debug_skeleton_line_section_label));
 
       output_comdat_type_unit (ctnode);
       *slot = ctnode;
     }
   htab_delete (comdat_type_table);
 
-  add_AT_pubnames (comp_unit_die ());
+  /* 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 ());
 
+  if (dwarf_split_debug_info)
+    {
+      int mark;
+      unsigned char checksum[16];
+      struct md5_ctx ctx;
+
+      /* Compute a checksum of the comp_unit to use as the dwo_id.  */
+      md5_init_ctx (&ctx);
+      mark = 0;
+      die_checksum (comp_unit_die (), &ctx, &mark);
+      unmark_all_dies (comp_unit_die ());
+      md5_finish_ctx (&ctx, checksum);
+
+      /* Use the first 8 bytes of the checksum as the dwo_id,
+	 and add it to both comp-unit DIEs.  */
+      add_AT_data8 (main_comp_unit_die, DW_AT_GNU_dwo_id, checksum);
+      add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, checksum);
+
+      /* Add the base offset of the ranges table to the skeleton
+	 comp-unit DIE.  */
+      if (ranges_table_in_use)
+	add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base,
+			ranges_section_label);
+    }
+
   /* Output the main compilation unit if non-empty or if .debug_macinfo
      or .debug_macro will be emitted.  */
   output_comp_unit (comp_unit_die (), have_macinfo);
 
+  if (dwarf_split_debug_info && info_section_emitted)
+    output_skeleton_debug_sections (main_comp_unit_die);
+
   /* Output the abbreviation table.  */
   if (abbrev_die_table_in_use != 1)
     {
@@ -22502,8 +23263,6 @@ 
     {
       /* Output the location lists info.  */
       switch_to_section (debug_loc_section);
-      ASM_GENERATE_INTERNAL_LABEL (loc_section_label,
-				   DEBUG_LOC_SECTION_LABEL, 0);
       ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
       output_location_lists (comp_unit_die ());
     }
@@ -22554,10 +23313,22 @@ 
   switch_to_section (debug_line_section);
   ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
   if (! DWARF2_ASM_LINE_DEBUG_INFO)
-    output_line_info ();
+    output_line_info (false);
 
-  /* If we emitted any DW_FORM_strp form attribute, output the string
-     table too.  */
+  if (dwarf_split_debug_info && info_section_emitted)
+    {
+      switch_to_section (debug_skeleton_line_section);
+      ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label);
+      output_line_info (true);
+
+      output_index_strings ();
+
+      switch_to_section (debug_addr_section);
+      ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label);
+      output_addr_table ();
+    }
+
+  /* If we emitted any indirect strings, output the string table too.  */
   if (debug_str_hash)
     htab_traverse (debug_str_hash, output_indirect_string, NULL);
 }
Index: gcc/dwarf2out.h
===================================================================
--- gcc/dwarf2out.h	(revision 190603)
+++ gcc/dwarf2out.h	(working copy)
@@ -172,6 +172,7 @@ 
 
 typedef struct GTY(()) dw_val_struct {
   enum dw_val_class val_class;
+  unsigned int val_index;
   union dw_val_struct_union
     {
       rtx GTY ((tag ("dw_val_class_addr"))) val_addr;
Index: gcc/opts.c
===================================================================
--- gcc/opts.c	(revision 190603)
+++ gcc/opts.c	(working copy)
@@ -829,9 +829,14 @@ 
   if (opts->x_warn_unused_but_set_parameter == -1)
     opts->x_warn_unused_but_set_parameter = (opts->x_warn_unused
 					     && opts->x_extra_warnings);
+
   /* Wunused-local-typedefs is enabled by -Wunused or -Wall.  */
   if (opts->x_warn_unused_local_typedefs == -1)
     opts->x_warn_unused_local_typedefs = opts->x_warn_unused;
+
+  /* The -gsplit-dwarf option requires -gpubnames.  */
+  if (opts->x_dwarf_split_debug_info)
+    opts->x_debug_generate_pub_sections = 1;
 }
 
 #define LEFT_COLUMN	27
@@ -1692,6 +1697,13 @@ 
       set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc);
       break;
 
+    case OPT_gsplit_dwarf:
+      if (opts->x_dwarf_version < 4)
+        opts->x_dwarf_version = 4;
+      set_debug_level (DWARF2_DEBUG, DEFAULT_GDB_EXTENSIONS, "", opts, opts_set,
+		       loc);
+      break;
+
     case OPT_ggdb:
       set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc);
       break;
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 190603)
+++ gcc/common.opt	(working copy)
@@ -2282,6 +2282,20 @@ 
 Common RejectNegative Var(dwarf_record_gcc_switches,1)
 Record gcc command line switches in DWARF DW_AT_producer.
 
+gno-split-dwarf
+Common Driver RejectNegative Var(dwarf_split_debug_info,0) Init(0)
+Don't generate debug information in separate .dwo files
+
+gsplit-dwarf
+Common Driver RejectNegative Var(dwarf_split_debug_info,1)
+Generate debug information in separate .dwo files
+
 gstabs
 Common JoinedOrMissing Negative(gstabs+)
 Generate debug information in STABS format

--
This patch is available for review at http://codereview.appspot.com/6305113