Message ID | 20120827180000.CC1ED160EFD@sterling.mtv.corp.google.com |
---|---|
State | New |
Headers | show |
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
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?
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
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
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