|
|
Created:
12 years, 10 months ago by saugustine Modified:
12 years, 5 months ago Reviewers:
Cary, jason CC:
gcc-patches_gcc.gnu.org Base URL:
svn+ssh://gcc.gnu.org/svn/gcc/trunk/ Visibility:
Public. |
Patch Set 1 #Patch Set 2 : [Dwarf Fission] Implement Fission Proposal #
Total comments: 2
Patch Set 3 : [Dwarf Patch] Implement split debug info proposal--Updated #Patch Set 4 : [Dwarf Fission] Implement Fission Proposal #Patch Set 5 : [Dwarf Fission] Implement Fission Proposal #
MessagesTotal messages: 20
The enclosed patch implements the proposed dwarf extension to split debug information from the .o file into a .dwo file. For more information about the design and plan, see: http://gcc.gnu.org/wiki/DebugFission The proposal has been discussed at in the Dwarf Standardization meetings and seems fairly stable at this point. It allows users to avoid linking quite a bit of debug information, which dramatically reduces linker time and memory requirements. Using it requires upgrading both binutils and gdb. Furthermore, there are additional optimization opportunities such as ensuring that entries in .debug_addr are unique. Although logically independent, split debug info is vastly more useful with pubnames and pubtypes; therefore this patch follows on Cary and my earlier pubnames patches. Although the patch is quite large, significant parts are boiler-plate. For example, adding a new dwarf section requires perhaps 50 lines of patch spread among several locations. There are similar issues with adding various fields with dwarf structures. This has been tested with a full bootstrap and running split-debug-aware GDB testsuite against the patched GCC. OK for mainline? Sterling saugustine@google.com gcc/ChangeLog 2012-06-19 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): 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 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_line_info): New parameter prologue_only. Adjust calls throughout file. (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): Handle dwarf_split_debug_info. (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. (common_handle_option): Add case for OPT_gsplit_dwarf. include/ChangeLog 2012-06-19 Sterling Augustine <saugustine@google.com> Cary Coutant <ccoutant@google.com> * dwarf2.h (enum dwarf_location_list_entry_type): New enum with fields DW_LLE_end_of_list_entry, DW_LLE_base_address_selection_entry, DW_LLE_start_end_entry and DW_LLE_start_length_entry. Index: include/dwarf2.h =================================================================== --- include/dwarf2.h (revision 188792) +++ include/dwarf2.h (working copy) @@ -259,6 +259,17 @@ enum dwarf_line_number_hp_sfc_ops 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_end_of_list_entry = 0, + DW_LLE_base_address_selection_entry = 1, + DW_LLE_start_end_entry = 2, + DW_LLE_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 188792) +++ gcc/doc/invoke.texi (working copy) @@ -4788,6 +4788,14 @@ it reasonable to use the optimizer for programs th 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 @@ -4795,6 +4803,10 @@ most expressive format available (DWARF 2, stabs, if neither of those are supported), including GDB extensions if at all possible. +@item -gpubnames +@opindex gpubnames +Generate dwarf .debug_pubnames and .debug_pubtypes sections. + @item -gstabs @opindex gstabs Produce debugging information in stabs format (if that is supported), Index: gcc/gcc.c =================================================================== --- gcc/gcc.c (revision 188792) +++ gcc/gcc.c (working copy) @@ -267,6 +267,7 @@ static const char *compare_debug_dump_opt_spec_fun 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 @@ ignored. White space may also appear anywhere on 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 @@ proper position among the other output files. */ /* 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 @@ static const struct spec_function static_spec_func { "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 @@ process_brace_body (const char *p, const char *ato 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 @@ check_live_switch (int switchnum, int prefix_lengt } 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. */ @@ -8362,3 +8371,27 @@ pass_through_libs_spec_func (int argc, const char } 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; + + if (argc != 2) + fatal_error ("too few arguments to %%:replace-extension"); + + name = xstrdup (argv[0]); + p = strrchr (name, '.'); + if (p != NULL) + *p = '\0'; + + result = concat (name, argv[1], NULL); + + free (name); + return result; +} Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 188792) +++ gcc/dwarf2out.c (working copy) @@ -147,14 +147,19 @@ static GTY(()) VEC(tree,gc) *decl_scope_table; /* 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; @@ -197,6 +202,7 @@ struct GTY(()) indirect_string_node { 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; @@ -1203,7 +1209,8 @@ DEF_VEC_ALLOC_P(dw_die_ref,heap); 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 */ @@ -1248,8 +1255,10 @@ new_loc_descr (enum dwarf_location_atom op, unsign 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; @@ -1453,6 +1462,10 @@ size_of_loc_descr (dw_loc_descr_ref loc) 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; @@ -1889,6 +1902,12 @@ output_loc_operands (dw_loc_descr_ref loc, int for } 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 @@ -2064,6 +2083,8 @@ output_loc_operands_raw (dw_loc_descr_ref loc) 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 (); @@ -2247,6 +2268,7 @@ build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT { 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) @@ -2538,6 +2560,7 @@ typedef struct GTY(()) comdat_type_struct { dw_die_ref root_die; dw_die_ref type_die; + dw_die_ref skeleton_die; char signature[DWARF_TYPE_SIGNATURE_SIZE]; struct comdat_type_struct *next; } @@ -2875,6 +2898,8 @@ static tree decl_ultimate_origin (const_tree); 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 +2927,18 @@ static inline dw_loc_descr_ref AT_loc (dw_attr_ref 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 +3033,7 @@ static unsigned long size_of_aranges (void); 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); @@ -3012,6 +3041,7 @@ static void output_comp_unit (dw_die_ref, int); static void output_comdat_type_unit (comdat_type_node *); static const char *dwarf2_name (tree, int); static void add_pubname (tree, dw_die_ref); +static void add_enumerator_pubname (const char *, dw_die_ref); static void add_pubname_string (const char *, dw_die_ref); static void add_pubtype (tree, dw_die_ref); static void output_pubnames (VEC (pubname_entry,gc) *); @@ -3019,10 +3049,10 @@ static void output_aranges (unsigned long); 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); @@ -3141,6 +3171,7 @@ static dw_loc_list_ref new_loc_list (dw_loc_descr_ const char *, const char *); static void output_loc_list (dw_loc_list_ref); static char *gen_internal_sym (const char *); +static bool want_pubnames (void); static void prune_unmark_dies (dw_die_ref); static void prune_unused_types_mark_generic_parms_dies (dw_die_ref); @@ -3160,36 +3191,124 @@ static bool generic_type_p (tree); static void schedule_generic_params_dies_gen (tree t); static void gen_scheduled_generic_parms_dies (void); +/* Return the operator to use for an address of a variable. + DTPREL is true for 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. For those, 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 (bool dtprel) +{ + if (dtprel) + 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, int 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 + ? 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" @@ -3200,44 +3319,63 @@ static void gen_scheduled_generic_parms_dies (void #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. @@ -3250,7 +3388,11 @@ static char cold_text_section_label[MAX_ARTIFICIAL 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]; @@ -3491,6 +3633,31 @@ AT_class (dw_attr_ref a) 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 @@ -3500,6 +3667,7 @@ add_AT_flag (dw_die_ref die, enum dwarf_attribute 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); } @@ -3520,6 +3688,7 @@ add_AT_int (dw_die_ref die, enum dwarf_attribute a 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); } @@ -3541,6 +3710,7 @@ add_AT_unsigned (dw_die_ref die, enum dwarf_attrib 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); } @@ -3562,6 +3732,7 @@ add_AT_double (dw_die_ref die, enum dwarf_attribut 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); @@ -3577,6 +3748,7 @@ add_AT_vec (dw_die_ref die, enum dwarf_attribute a 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; @@ -3593,6 +3765,7 @@ add_AT_data8 (dw_die_ref die, enum dwarf_attribute 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); } @@ -3651,6 +3824,7 @@ add_AT_string (dw_die_ref die, enum dwarf_attribut 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); } @@ -3662,12 +3836,20 @@ AT_string (dw_attr_ref a) 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; + /* Find out whether a string should be output inline in DIE or out-of-line in .debug_str section. */ static enum dwarf_form AT_string_form (dw_attr_ref a) { + static unsigned int index_string_count = 0; struct indirect_string_node *node; unsigned int len; char label[32]; @@ -3697,7 +3879,17 @@ AT_string_form (dw_attr_ref a) ++dw2_string_counter; node->label = xstrdup (label); - return node->form = DW_FORM_strp; + if (!dwarf_split_debug_info) + node->form = DW_FORM_strp; + else + { + node->form = DW_FORM_GNU_str_index; + set_AT_index (a, index_string_count); + index_string_count++; + VEC_safe_push (indirect_string_node, gc, index_string_table, node); + } + + return node->form; } /* Add a DIE reference attribute value to a DIE. */ @@ -3718,6 +3910,7 @@ add_AT_die_ref (dw_die_ref die, enum dwarf_attribu 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); @@ -3776,6 +3969,7 @@ add_AT_fde_ref (dw_die_ref die, enum dwarf_attribu 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); } @@ -3789,6 +3983,7 @@ add_AT_loc (dw_die_ref die, enum dwarf_attribute a 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); } @@ -3807,6 +4002,7 @@ add_AT_loc_list (dw_die_ref die, enum dwarf_attrib 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; @@ -3826,17 +4022,64 @@ AT_loc_list_ptr (dw_attr_ref a) return &a->dw_attr_val.v.val_loc_list; } +/* 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_list_ref loc) +{ + dw_loc_descr_ref descr; + + gcc_assert (loc->replaced); + + for (descr = loc->expr; 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. */ 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. */ @@ -3858,6 +4101,7 @@ add_AT_file (dw_die_ref die, enum dwarf_attribute 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); } @@ -3881,6 +4125,7 @@ add_AT_vms_delta (dw_die_ref die, enum dwarf_attri 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); @@ -3889,14 +4134,18 @@ add_AT_vms_delta (dw_die_ref die, enum dwarf_attri /* Add a label identifier attribute value to a DIE. */ 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 @@ -3910,6 +4159,7 @@ add_AT_lineptr (dw_die_ref die, enum dwarf_attribu 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); } @@ -3925,6 +4175,7 @@ add_AT_macptr (dw_die_ref die, enum dwarf_attribut 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); } @@ -3939,20 +4190,25 @@ add_AT_offset (dw_die_ref die, enum dwarf_attribut 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. */ 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; + /* This is a bit of a misnomer--the offset isn't an index, but we need to + save force_direct for output. */ + 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); } @@ -5971,6 +6227,23 @@ is_cu_die (dw_die_ref c) return c && c->die_tag == DW_TAG_compile_unit; } +/* Returns true iff C is a namespace DIE. */ + +static inline bool +is_namespace_die (dw_die_ref c) +{ + return c && c->die_tag == DW_TAG_namespace; +} + +/* Returns true iff C is a class or structure DIE. */ + +static inline bool +is_class_die (dw_die_ref c) +{ + return c && (c->die_tag == DW_TAG_class_type + || c->die_tag == DW_TAG_structure_type); +} + /* Returns true iff C is a unit DIE of some sort. */ static inline bool @@ -6567,6 +6840,7 @@ break_out_comdat_types (dw_die_ref die) declaration into the new type unit DIE, then remove this DIE from the main CU (or replace it with a skeleton if necessary). */ replacement = remove_child_or_replace_with_skeleton (unit, c, prev); + type_node->skeleton_die = replacement; /* Break out nested types into their own type units. */ break_out_comdat_types (c); @@ -7094,6 +7368,7 @@ size_of_die (dw_die_ref die) 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) @@ -7101,7 +7376,10 @@ size_of_die (dw_die_ref die) 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; @@ -7119,10 +7397,13 @@ size_of_die (dw_die_ref die) } 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)); @@ -7182,15 +7463,21 @@ size_of_die (dw_die_ref die) 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; @@ -7372,7 +7659,7 @@ size_of_aranges (void) 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. */ @@ -7382,7 +7669,8 @@ value_format (dw_attr_ref a) 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; } @@ -7401,7 +7689,7 @@ value_format (dw_attr_ref a) } case dw_val_class_range_list: case dw_val_class_loc_list: - if (dwarf_version >= 4) + if (dwarf_version >= 4 || dwarf_split_debug_info) return DW_FORM_sec_offset; /* FALLTHRU */ case dw_val_class_vms_delta: @@ -7498,7 +7786,8 @@ value_format (dw_attr_ref a) 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; @@ -7535,6 +7824,36 @@ output_value_format (dw_attr_ref a) 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. */ @@ -7544,32 +7863,8 @@ output_abbrev_section (void) 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); } @@ -7605,6 +7900,7 @@ new_loc_list (dw_loc_descr_ref expr, const char *b 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; @@ -7649,7 +7945,22 @@ output_loc_list (dw_loc_list_ref list_head) 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_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_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)", @@ -7675,14 +7986,85 @@ output_loc_list (dw_loc_list_ref list_head) 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_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 @@ -7721,7 +8103,7 @@ output_die (dw_die_ref die) 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: @@ -7730,15 +8112,7 @@ output_die (dw_die_ref die) 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: @@ -7794,7 +8168,7 @@ output_die (dw_die_ref die) } 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); } @@ -7841,13 +8215,7 @@ output_die (dw_die_ref die) 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: @@ -7904,7 +8272,7 @@ output_die (dw_die_ref die) 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: @@ -7918,12 +8286,15 @@ output_die (dw_die_ref die) 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; @@ -8040,6 +8411,124 @@ output_comp_unit (dw_die_ref die, int output_if_em } } +/* Whether to generate the DWARF accelerator tables in .debug_pubnames + and .debug_pubtypes. This is configured per-target, but can be + overridden by the -gpubnames or -gno-pubnames options. */ + +static inline bool +want_pubnames (void) +{ + return (debug_generate_pub_sections != -1 + ? debug_generate_pub_sections + : targetm.want_debug_pub_sections); +} + +/* Add the DW_AT_GNU_pubnames and DW_AT_GNU_pubtypes attributes. */ + +static void +add_AT_pubnames (dw_die_ref die) +{ + if (want_pubnames ()) + 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 split_debug_sections with use_type info, all type units int 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; +} + +/* The splitter will fill in this value. */ + +unsigned char dwo_id_placeholder[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* 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); + + /* The dwo_id is only for compile_units. */ + add_AT_data8 (comp_unit, DW_AT_GNU_dwo_id, dwo_id_placeholder); + + 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 = 1; + 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 @@ -8067,7 +8556,11 @@ output_comdat_type_unit (comdat_type_node *node) 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++) @@ -8076,6 +8569,7 @@ output_comdat_type_unit (comdat_type_node *node) 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."); @@ -8093,6 +8587,37 @@ output_comdat_type_unit (comdat_type_node *node) 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"); + + /* One for the terminating NULL byte. */ + 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. */ @@ -8110,7 +8635,7 @@ dwarf2_name (tree decl, int scope) static void add_pubname_string (const char *str, dw_die_ref die) { - if (targetm.want_debug_pub_sections) + if (want_pubnames ()) { pubname_entry e; @@ -8123,14 +8648,37 @@ add_pubname_string (const char *str, dw_die_ref di static void add_pubname (tree decl, dw_die_ref die) { - if (targetm.want_debug_pub_sections && TREE_PUBLIC (decl)) + if (!want_pubnames ()) + return; + + /* Don't add items to the table when we expect that the consumer will have + just read the enclosing die. For example, if the consumer is looking at a + 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)) + || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent)) { const char *name = dwarf2_name (decl, 1); + if (name) add_pubname_string (name, die); } } +/* Add an enumerator to the pubnames section. */ + +static void +add_enumerator_pubname (const char *scope_name, dw_die_ref die) +{ + pubname_entry e; + + gcc_assert (scope_name); + e.name = concat (scope_name, get_AT_string (die, DW_AT_name), NULL); + e.die = die; + VEC_safe_push (pubname_entry, gc, pubname_table, &e); +} + /* Add a new entry to .debug_pubtypes if appropriate. */ static void @@ -8138,39 +8686,54 @@ add_pubtype (tree decl, dw_die_ref die) { pubname_entry e; - if (!targetm.want_debug_pub_sections) + if (!want_pubnames ()) return; - e.name = NULL; if ((TREE_PUBLIC (decl) - || is_cu_die (die->die_parent)) + || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent)) && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl))) { - e.die = die; + tree scope = NULL; + const char *scope_name = ""; + const char *sep = is_cxx () ? "::" : "."; + const char *name; + + scope = TYPE_P (decl) ? TYPE_CONTEXT (decl) : NULL; + if (scope && TREE_CODE (scope) == NAMESPACE_DECL) + { + scope_name = lang_hooks.dwarf_name (scope, 1); + if (scope_name != NULL && scope_name[0] != '\0') + scope_name = concat (scope_name, sep, NULL); + else + scope_name = ""; + } + if (TYPE_P (decl)) - { - if (TYPE_NAME (decl)) - { - if (TREE_CODE (TYPE_NAME (decl)) == IDENTIFIER_NODE) - e.name = IDENTIFIER_POINTER (TYPE_NAME (decl)); - else if (TREE_CODE (TYPE_NAME (decl)) == TYPE_DECL - && DECL_NAME (TYPE_NAME (decl))) - e.name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl))); - else - e.name = xstrdup ((const char *) get_AT_string (die, DW_AT_name)); - } - } + name = type_tag (decl); else - { - e.name = dwarf2_name (decl, 1); - if (e.name) - e.name = xstrdup (e.name); - } + name = lang_hooks.dwarf_name (decl, 1); /* If we don't have a name for the type, there's no point in adding it to the table. */ - if (e.name && e.name[0] != '\0') - VEC_safe_push (pubname_entry, gc, pubtype_table, &e); + if (name != NULL && name[0] != '\0') + { + e.die = die; + e.name = concat (scope_name, name, NULL); + VEC_safe_push (pubname_entry, gc, pubtype_table, &e); + } + + /* Although it might be more consistent to add the pubinfo for the + enumerators as their dies are created, they should only be added if the + enum type meets the criteria above. So rather than re-check the parent + enum type whenever an enumerator die is created, just output them all + here. This isn't protected by the name conditional because anonymous + enums don't have names. */ + if (die->die_tag == DW_TAG_enumeration_type) + { + dw_die_ref c; + + FOR_EACH_CHILD (die, c, add_enumerator_pubname (scope_name, c)); + } } } @@ -8184,6 +8747,12 @@ output_pubnames (VEC (pubname_entry, gc) * names) unsigned long pubnames_length = size_of_pubnames (names); pubname_ref pub; + if (!want_pubnames () || !info_section_emitted) + return; + if (names == pubname_table) + switch_to_section (debug_pubnames_section); + else + switch_to_section (debug_pubtypes_section); if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) dw2_asm_output_data (4, 0xffffffff, "Initial length escape value indicating 64-bit DWARF extension"); @@ -8195,9 +8764,14 @@ output_pubnames (VEC (pubname_entry, gc) * names) "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"); @@ -8211,9 +8785,22 @@ output_pubnames (VEC (pubname_entry, gc) * names) || pub->die->die_offset != 0 || !flag_eliminate_unused_debug_types) { - dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset, - "DIE offset"); + dw_offset die_offset = pub->die->die_offset; + /* If we're putting types in their own .debug_types sections, + the .debug_pubtypes table will still point to the compile + unit (not the type unit), so we want to use the offset of + the skeleton DIE (if there is one). */ + if (pub->die->comdat_type_p && names == pubtype_table) + { + comdat_type_node_ref type_node = pub->die->die_id.die_type_node; + + if (type_node != NULL && type_node->skeleton_die != NULL) + die_offset = type_node->skeleton_die->die_offset; + } + + dw2_asm_output_data (DWARF_OFFSET_SIZE, die_offset, "DIE offset"); + dw2_asm_output_nstring (pub->name, -1, "external name"); } } @@ -8237,9 +8824,14 @@ output_aranges (unsigned long aranges_length) "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"); @@ -8341,7 +8933,7 @@ add_ranges (const_tree block) 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; @@ -8364,7 +8956,7 @@ add_ranges_by_labels (dw_die_ref die, const char * 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; } } @@ -8901,7 +9493,7 @@ output_one_line_info_table (dw_line_info_table *ta 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; @@ -8971,6 +9563,12 @@ static void /* 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) { @@ -9097,6 +9695,7 @@ base_type_die (tree type) add_AT_unsigned (base_type_result, DW_AT_byte_size, int_size_in_bytes (type)); add_AT_unsigned (base_type_result, DW_AT_encoding, encoding); + add_pubtype (type, base_type_result); return base_type_result; } @@ -11270,14 +11869,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mod 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, true); mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0); add_loc_descr (&mem_loc_result, temp); @@ -11289,9 +11881,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mod 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, 0); VEC_safe_push (rtx, gc, used_rtx_array, rtl); break; @@ -12193,9 +12783,7 @@ loc_descriptor (rtx rtl, enum machine_mode mode, 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, 0); add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0)); VEC_safe_push (rtx, gc, used_rtx_array, rtl); } @@ -12895,8 +13483,7 @@ loc_list_from_tree (tree loc, int want_address) if (DECL_THREAD_LOCAL_P (loc)) { rtx rtl; - enum dwarf_location_atom first_op; - enum dwarf_location_atom second_op; + enum dwarf_location_atom tls_op; bool dtprel = false; if (targetm.have_tls) @@ -12914,9 +13501,8 @@ loc_list_from_tree (tree loc, int want_address) 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; + tls_op = DW_OP_GNU_push_tls_address; } else { @@ -12928,8 +13514,7 @@ loc_list_from_tree (tree loc, int want_address) 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); @@ -12942,12 +13527,8 @@ loc_list_from_tree (tree loc, int want_address) 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; @@ -12992,11 +13573,7 @@ loc_list_from_tree (tree loc, int want_address) 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, 0); else { enum machine_mode mode, mem_mode; @@ -13924,9 +14501,7 @@ add_const_value_attribute (dw_die_ref die, rtx rtl 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, 0); 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); @@ -15444,7 +16019,7 @@ add_name_and_src_coords_attributes (dw_die_ref die 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 */ @@ -15465,7 +16040,7 @@ dwarf2out_vms_debug_main_pointer (void) 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 (); @@ -16056,7 +16631,7 @@ gen_entry_point_die (tree decl, dw_die_ref context 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 @@ -16179,8 +16754,7 @@ gen_enumeration_type_die (tree type, dw_die_ref co else add_AT_flag (type_die, DW_AT_declaration, 1); - if (get_AT (type_die, DW_AT_name)) - add_pubtype (type, type_die); + add_pubtype (type, type_die); return type_die; } @@ -16707,7 +17281,7 @@ gen_call_site_die (tree decl, dw_die_ref subr_die, 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) @@ -16716,7 +17290,7 @@ gen_call_site_die (tree decl, dw_die_ref subr_die, 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; } @@ -16843,6 +17417,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_ { subr_die = new_die (DW_TAG_subprogram, context_die, decl); add_AT_specification (subr_die, old_die); + add_pubname (decl, subr_die); if (get_AT_file (old_die, DW_AT_decl_file) != file_index) add_AT_file (subr_die, DW_AT_decl_file, file_index); if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line) @@ -16857,6 +17432,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_ add_AT_flag (subr_die, DW_AT_external, 1); add_name_and_src_coords_attributes (subr_die, decl); + add_pubname (decl, subr_die); if (debug_info_level > DINFO_LEVEL_TERSE) { add_prototyped_attribute (subr_die, TREE_TYPE (decl)); @@ -16929,8 +17505,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_ if (fde->dw_fde_begin) { /* We have already generated the labels. */ - add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin); - add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end); + add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin, false); + add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end, false); } else { @@ -16938,10 +17514,10 @@ gen_subprogram_die (tree decl, dw_die_ref context_ char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL, current_function_funcdef_no); - add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id); + add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id, false); ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, current_function_funcdef_no); - add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id); + add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id, false); } #if VMS_DEBUGGING_INFO @@ -16968,7 +17544,6 @@ gen_subprogram_die (tree decl, dw_die_ref context_ } #endif - add_pubname (decl, subr_die); } else { @@ -16985,11 +17560,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_ 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); - add_pubname (decl, subr_die); + &range_list_added, false); if (range_list_added) add_ranges (NULL); } @@ -17008,11 +17583,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_ /* Do the 'primary' section. */ add_AT_lbl_id (subr_die, DW_AT_low_pc, - fde->dw_fde_begin); + fde->dw_fde_begin, false); add_AT_lbl_id (subr_die, DW_AT_high_pc, - fde->dw_fde_end); - /* Add it. */ - add_pubname (decl, subr_die); + fde->dw_fde_end, false); /* Build a minimal DIE for the secondary section. */ seg_die = new_die (DW_TAG_subprogram, @@ -17037,18 +17610,17 @@ gen_subprogram_die (tree decl, dw_die_ref context_ name = concat ("__second_sect_of_", name, NULL); add_AT_lbl_id (seg_die, DW_AT_low_pc, - fde->dw_fde_second_begin); + fde->dw_fde_second_begin, false); add_AT_lbl_id (seg_die, DW_AT_high_pc, - fde->dw_fde_second_end); + fde->dw_fde_second_end, false); add_name_attribute (seg_die, name); add_pubname_string (name, seg_die); } } else { - add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin); - add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end); - add_pubname (decl, subr_die); + add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin, false); + add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end, false); } } @@ -17489,7 +18061,7 @@ gen_variable_die (tree decl, tree origin, dw_die_r { /* 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) { @@ -17676,7 +18248,7 @@ gen_label_die (tree decl, dw_die_ref context_die) 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) @@ -17684,7 +18256,7 @@ gen_label_die (tree decl, dw_die_ref context_die) && 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); } } } @@ -17725,7 +18297,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die { 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 @@ -17773,12 +18345,13 @@ add_high_low_attributes (tree stmt, dw_die_ref die ++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 @@ -17793,10 +18366,10 @@ add_high_low_attributes (tree stmt, dw_die_ref die { ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, BLOCK_NUMBER (stmt)); - add_AT_lbl_id (die, DW_AT_low_pc, label); + add_AT_lbl_id (die, DW_AT_low_pc, label, false); ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, BLOCK_NUMBER (stmt)); - add_AT_lbl_id (die, DW_AT_high_pc, label); + add_AT_lbl_id (die, DW_AT_high_pc, label, false); } } @@ -19089,6 +19662,8 @@ gen_namespace_die (tree decl, dw_die_ref context_d add_AT_die_ref (namespace_die, DW_AT_import, origin_die); equate_decl_number_to_die (decl, namespace_die); } + /* Bypass dwarf2_name's check for DECL_NAMELESS. */ + add_pubname_string (lang_hooks.dwarf_name (decl, 1), namespace_die); } /* Generate Dwarf debug information for a decl described by DECL. @@ -20389,6 +20964,7 @@ output_macinfo_op (macinfo_entry *ref) case DW_MACRO_GNU_define_indirect: case DW_MACRO_GNU_undef_indirect: node = find_AT_string (ref->info); + /* FIXME: needs to change for dwarf_split_debug_info. */ if (node->form != DW_FORM_strp) { char label[32]; @@ -20576,8 +21152,10 @@ output_macinfo (void) dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present"); else dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present"); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, 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 @@ -20716,26 +21294,60 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNU 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, @@ -20755,10 +21367,13 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNU 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); @@ -20802,6 +21417,79 @@ output_indirect_string (void **h, void *v ATTRIBUT return 1; } +static void +output_index_strings (void) +{ + unsigned int i; + unsigned int len = 0; + struct indirect_string_node *node; + + 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. */ @@ -21405,6 +22093,17 @@ resolve_addr_in_expr (dw_loc_descr_ref loc) 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 @@ -21539,11 +22238,15 @@ resolve_addr (dw_die_ref die) 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 (l->dw_loc_oprnd1.val_index != -1U) + remove_addr_table_entry (l->dw_loc_oprnd1.val_index); *curr = next; } else @@ -21557,6 +22260,8 @@ resolve_addr (dw_die_ref die) else { loc->replaced = 1; + if (dwarf_split_debug_info) + remove_loc_list_addr_table_entries (loc); loc->dw_loc_next = *start; } } @@ -21581,6 +22286,8 @@ resolve_addr (dw_die_ref die) || l->dw_loc_next != NULL) && !resolve_addr_in_expr (l)) { + if (l->dw_loc_oprnd1.val_index != -1U) + remove_addr_table_entry (l->dw_loc_oprnd1.val_index); remove_AT (die, a->dw_attr); ix--; } @@ -21592,6 +22299,8 @@ resolve_addr (dw_die_ref die) 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--; } @@ -21615,6 +22324,8 @@ resolve_addr (dw_die_ref die) } else { + if (AT_index (a) != -1U) + remove_addr_table_entry (AT_index (a)); remove_AT (die, a->dw_attr); ix--; } @@ -21748,6 +22459,19 @@ hash_loc_operands (dw_loc_descr_ref loc, hashval_t } 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; @@ -21929,9 +22653,12 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_d 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 @@ -21962,6 +22689,18 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_d 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 @@ -22075,7 +22814,7 @@ optimize_location_lists_1 (dw_die_ref die, htab_t 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)); @@ -22091,6 +22830,43 @@ optimize_location_lists (dw_die_ref die) 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. */ @@ -22102,6 +22878,7 @@ dwarf2out_finish (const char *filename) 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. */ @@ -22265,6 +23042,14 @@ dwarf2out_finish (const char *filename) 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); @@ -22282,8 +23067,10 @@ dwarf2out_finish (const char *filename) /* Don't add if the CU has no associated code. */ if (text_section_used) { - add_AT_lbl_id (comp_unit_die (), DW_AT_low_pc, text_section_label); - add_AT_lbl_id (comp_unit_die (), DW_AT_high_pc, text_end_label); + add_AT_lbl_id (main_comp_unit_die, DW_AT_low_pc, text_section_label, + true); + add_AT_lbl_id (main_comp_unit_die, DW_AT_high_pc, text_end_label, + true); } } else @@ -22293,22 +23080,24 @@ dwarf2out_finish (const char *filename) 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) @@ -22318,16 +23107,16 @@ dwarf2out_finish (const char *filename) 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) @@ -22336,7 +23125,11 @@ dwarf2out_finish (const char *filename) 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. */ @@ -22357,17 +23150,34 @@ dwarf2out_finish (const char *filename) 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); + if (!dwarf_split_debug_info) + add_AT_pubnames (comp_unit_die ()); + + if (dwarf_split_debug_info) + { + /* Add a place-holder for the dwo_id to the comp-unit die. */ + add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, dwo_id_placeholder); + add_AT_lineptr (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) { @@ -22381,48 +23191,16 @@ dwarf2out_finish (const char *filename) { /* 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 ()); } - /* Output public names table if necessary. */ - if (!VEC_empty (pubname_entry, pubname_table)) - { - gcc_assert (info_section_emitted); - switch_to_section (debug_pubnames_section); - output_pubnames (pubname_table); - } - - /* Output public types table if necessary. */ + /* Output public names and types tables if necessary. */ + output_pubnames (pubname_table); /* ??? Only defined by DWARF3, but emitted by Darwin for DWARF2. It shouldn't hurt to emit it always, since pure DWARF2 consumers simply won't look for the section. */ - if (!VEC_empty (pubname_entry, pubtype_table)) - { - bool empty = false; - - if (flag_eliminate_unused_debug_types) - { - /* The pubtypes table might be emptied by pruning unused items. */ - unsigned i; - pubname_ref p; - empty = true; - FOR_EACH_VEC_ELT (pubname_entry, pubtype_table, i, p) - if (p->die->die_offset != 0) - { - empty = false; - break; - } - } - if (!empty) - { - gcc_assert (info_section_emitted); - switch_to_section (debug_pubtypes_section); - output_pubnames (pubtype_table); - } - } + output_pubnames (pubtype_table); /* Output the address range information if a CU (.debug_info section) was emitted. We output an empty table even if we had no functions @@ -22463,10 +23241,22 @@ dwarf2out_finish (const char *filename) 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 188792) +++ gcc/dwarf2out.h (working copy) @@ -171,6 +171,7 @@ dw_vec_const; 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 188792) +++ gcc/opts.c (working copy) @@ -827,9 +827,14 @@ finish_options (struct gcc_options *opts, struct g 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,11 @@ common_handle_option (struct gcc_options *opts, set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc); break; + case OPT_gsplit_dwarf: + set_debug_level (NO_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 188792) +++ gcc/common.opt (working copy) @@ -2243,6 +2243,14 @@ ggdb Common JoinedOrMissing Generate debug information in default extended format +gno-pubnames +Common RejectNegative Var(debug_generate_pub_sections, 0) Init(-1) +Don't generate DWARF pubnames and pubtypes sections. + +gpubnames +Common RejectNegative Var(debug_generate_pub_sections, 1) +Generate DWARF pubnames and pubtypes sections. + gno-record-gcc-switches Common RejectNegative Var(dwarf_record_gcc_switches,0) Init(1) Don't record gcc command line switches in DWARF DW_AT_producer. @@ -2251,6 +2259,14 @@ grecord-gcc-switches 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
Sign in to reply to this message.
Enclosed is a revised dwarf-fission patch. Fundamentally, it is no different than the earlier edition. However, this version fixes several bugs we have discovered in our testing. This patch implements the split debug proposal discussed in the gcc wiki here: http://gcc.gnu.org/wiki/DebugFission Are there any comments whatever for mainline? Sterling saugustine@google.com include/ChangeLog 2012-07-18 Sterling Augustine <saugustine@google.com> Cary Coutant <ccoutant@google.com> * dwarf2.h (dwarf_location_list_entry_type): New enum with enumerators DW_LLE_end_of_list_entry, DW_LLE_base_address_selection_entry, DW_LLE_start_end_entry, DW_LLE_start_length_entry. gcc/ChangeLog 2012-07-18 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. * opts.c (finish_options): Make gsplit-dwarf imply -gpubnames. * 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): 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 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_line_info): New parameter prologue_only. Adjust calls throughout file. (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): Handle dwarf_split_debug_info. (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. Fix related comments. (check_live_switch): Likewise. Index: include/dwarf2.h =================================================================== --- include/dwarf2.h (revision 189624) +++ 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_end_of_list_entry = 0, + DW_LLE_base_address_selection_entry = 1, + DW_LLE_start_end_entry = 2, + DW_LLE_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 189624) +++ gcc/doc/invoke.texi (working copy) @@ -4792,6 +4792,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 189624) +++ 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. */ @@ -8362,3 +8371,27 @@ } 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; + + if (argc != 2) + fatal_error ("too few arguments to %%:replace-extension"); + + name = xstrdup (argv[0]); + p = strrchr (name, '.'); + if (p != NULL) + *p = '\0'; + + result = concat (name, argv[1], NULL); + + free (name); + return result; +} Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 189624) +++ gcc/dwarf2out.c (working copy) @@ -146,14 +146,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; @@ -196,6 +201,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; @@ -1202,7 +1208,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 */ @@ -1247,8 +1254,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,124 @@ static void schedule_generic_params_dies_gen (tree t); static void gen_scheduled_generic_parms_dies (void); +/* Return the operator to use for an address of a variable. + DTPREL is true for 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. For those, 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 (bool dtprel) +{ + if (dtprel) + 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, int 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 + ? 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 +3318,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 +3387,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 +3632,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 +3666,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 +3687,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 +3709,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 +3731,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 +3747,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,6 +3764,7 @@ 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); } @@ -3653,6 +3823,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); } @@ -3664,12 +3835,20 @@ 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; + /* Find out whether a string should be output inline in DIE or out-of-line in .debug_str section. */ static enum dwarf_form AT_string_form (dw_attr_ref a) { + static unsigned int index_string_count = 0; struct indirect_string_node *node; unsigned int len; char label[32]; @@ -3699,7 +3878,17 @@ ++dw2_string_counter; node->label = xstrdup (label); - return node->form = DW_FORM_strp; + if (!dwarf_split_debug_info) + node->form = DW_FORM_strp; + else + { + node->form = DW_FORM_GNU_str_index; + set_AT_index (a, index_string_count); + index_string_count++; + VEC_safe_push (indirect_string_node, gc, index_string_table, node); + } + + return node->form; } /* Add a DIE reference attribute value to a DIE. */ @@ -3720,6 +3909,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); @@ -3778,6 +3968,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); } @@ -3791,6 +3982,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); } @@ -3809,6 +4001,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; @@ -3828,17 +4021,64 @@ return &a->dw_attr_val.v.val_loc_list; } +/* 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_list_ref loc) +{ + dw_loc_descr_ref descr; + + gcc_assert (loc->replaced); + + for (descr = loc->expr; 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. */ 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. */ @@ -3860,6 +4100,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); } @@ -3883,6 +4124,7 @@ 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); @@ -3891,14 +4133,18 @@ /* Add a label identifier attribute value to a DIE. */ 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 @@ -3912,6 +4158,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); } @@ -3927,6 +4174,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); } @@ -3941,20 +4189,25 @@ 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. */ 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; + /* This is a bit of a misnomer--the offset isn't an index, but we need to + save force_direct for output. */ + 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); } @@ -5973,16 +6226,6 @@ return c && c->die_tag == DW_TAG_compile_unit; } -/* Returns true iff C is a unit DIE of some sort. */ - -static inline bool -is_unit_die (dw_die_ref c) -{ - return c && (c->die_tag == DW_TAG_compile_unit - || c->die_tag == DW_TAG_partial_unit - || c->die_tag == DW_TAG_type_unit); -} - /* Returns true iff C is a namespace DIE. */ static inline bool @@ -6000,6 +6243,16 @@ || c->die_tag == DW_TAG_structure_type); } +/* Returns true iff C is a unit DIE of some sort. */ + +static inline bool +is_unit_die (dw_die_ref c) +{ + return c && (c->die_tag == DW_TAG_compile_unit + || c->die_tag == DW_TAG_partial_unit + || c->die_tag == DW_TAG_type_unit); +} + static char * gen_internal_sym (const char *prefix) { @@ -7114,6 +7367,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) @@ -7121,7 +7375,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; @@ -7139,10 +7396,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)); @@ -7202,15 +7462,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; @@ -7392,7 +7658,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. */ @@ -7402,7 +7668,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; } @@ -7421,7 +7688,7 @@ } case dw_val_class_range_list: case dw_val_class_loc_list: - if (dwarf_version >= 4) + if (dwarf_version >= 4 || dwarf_split_debug_info) return DW_FORM_sec_offset; /* FALLTHRU */ case dw_val_class_vms_delta: @@ -7518,7 +7785,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; @@ -7555,6 +7823,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. */ @@ -7564,32 +7862,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); } @@ -7625,6 +7899,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; @@ -7669,7 +7944,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_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_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)", @@ -7695,14 +7985,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_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 @@ -7741,7 +8102,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: @@ -7750,15 +8111,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: @@ -7814,7 +8167,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); } @@ -7861,13 +8214,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: @@ -7924,7 +8271,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: @@ -7938,12 +8285,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; @@ -8081,6 +8431,103 @@ 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 split_debug_sections with use_type info, all type units int 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; +} + +/* The splitter will fill in this value. */ + +unsigned char dwo_id_placeholder[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* 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); + + /* The dwo_id is only for compile_units. */ + add_AT_data8 (comp_unit, DW_AT_GNU_dwo_id, dwo_id_placeholder); + + 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 = 1; + 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 @@ -8108,7 +8555,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++) @@ -8117,6 +8568,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."); @@ -8134,6 +8586,37 @@ 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"); + + /* One for the terminating NULL byte. */ + 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. */ @@ -8277,9 +8760,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"); @@ -8340,9 +8828,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"); @@ -8444,7 +8937,7 @@ 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; @@ -8467,7 +8960,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; } } @@ -9004,7 +9497,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; @@ -9074,6 +9567,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) { @@ -11374,14 +11873,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, true); mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0); add_loc_descr (&mem_loc_result, temp); @@ -11393,9 +11885,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, 0); VEC_safe_push (rtx, gc, used_rtx_array, rtl); break; @@ -12297,9 +12787,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, 0); add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0)); VEC_safe_push (rtx, gc, used_rtx_array, rtl); } @@ -12999,8 +13487,7 @@ if (DECL_THREAD_LOCAL_P (loc)) { rtx rtl; - enum dwarf_location_atom first_op; - enum dwarf_location_atom second_op; + enum dwarf_location_atom tls_op; bool dtprel = false; if (targetm.have_tls) @@ -13018,9 +13505,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; + tls_op = DW_OP_GNU_push_tls_address; } else { @@ -13032,8 +13518,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); @@ -13046,12 +13531,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; @@ -13096,11 +13577,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, 0); else { enum machine_mode mode, mem_mode; @@ -14028,9 +14505,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, 0); 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); @@ -15548,7 +16023,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 */ @@ -15569,7 +16044,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 (); @@ -16160,7 +16635,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 @@ -16810,7 +17285,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) @@ -16819,7 +17294,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; } @@ -17010,8 +17485,8 @@ if (fde->dw_fde_begin) { /* We have already generated the labels. */ - add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin); - add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end); + add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin, false); + add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end, false); } else { @@ -17019,10 +17494,10 @@ char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL, current_function_funcdef_no); - add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id); + add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id, false); ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, current_function_funcdef_no); - add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id); + add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id, false); } #if VMS_DEBUGGING_INFO @@ -17065,10 +17540,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); } @@ -17087,9 +17563,9 @@ /* Do the 'primary' section. */ add_AT_lbl_id (subr_die, DW_AT_low_pc, - fde->dw_fde_begin); + fde->dw_fde_begin, false); add_AT_lbl_id (subr_die, DW_AT_high_pc, - fde->dw_fde_end); + fde->dw_fde_end, false); /* Build a minimal DIE for the secondary section. */ seg_die = new_die (DW_TAG_subprogram, @@ -17114,9 +17590,9 @@ name = concat ("__second_sect_of_", name, NULL); add_AT_lbl_id (seg_die, DW_AT_low_pc, - fde->dw_fde_second_begin); + fde->dw_fde_second_begin, false); add_AT_lbl_id (seg_die, DW_AT_high_pc, - 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); @@ -17124,8 +17600,8 @@ } else { - add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin); - add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end); + add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin, false); + add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end, false); } } @@ -17567,7 +18043,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) { @@ -17754,7 +18230,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) @@ -17762,7 +18238,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); } } } @@ -17803,7 +18279,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 @@ -17851,12 +18327,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 @@ -17871,10 +18348,10 @@ { ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, BLOCK_NUMBER (stmt)); - add_AT_lbl_id (die, DW_AT_low_pc, label); + add_AT_lbl_id (die, DW_AT_low_pc, label, false); ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, BLOCK_NUMBER (stmt)); - add_AT_lbl_id (die, DW_AT_high_pc, label); + add_AT_lbl_id (die, DW_AT_high_pc, label, false); } } @@ -20463,6 +20940,7 @@ case DW_MACRO_GNU_define_indirect: case DW_MACRO_GNU_undef_indirect: node = find_AT_string (ref->info); + /* FIXME: needs to change for dwarf_split_debug_info. */ if (node->form != DW_FORM_strp) { char label[32]; @@ -20650,8 +21128,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 @@ -20790,26 +21270,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, @@ -20829,10 +21343,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); @@ -20876,6 +21393,79 @@ return 1; } +static void +output_index_strings (void) +{ + unsigned int i; + unsigned int len = 0; + struct indirect_string_node *node; + + 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. */ @@ -21482,6 +22072,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 @@ -21616,11 +22217,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 (l->dw_loc_oprnd1.val_index != -1U) + remove_addr_table_entry (l->dw_loc_oprnd1.val_index); *curr = next; } else @@ -21634,6 +22239,8 @@ else { loc->replaced = 1; + if (dwarf_split_debug_info) + remove_loc_list_addr_table_entries (loc); loc->dw_loc_next = *start; } } @@ -21658,6 +22265,8 @@ || l->dw_loc_next != NULL) && !resolve_addr_in_expr (l)) { + if (l->dw_loc_oprnd1.val_index != -1U) + remove_addr_table_entry (l->dw_loc_oprnd1.val_index); remove_AT (die, a->dw_attr); ix--; } @@ -21669,6 +22278,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--; } @@ -21692,6 +22303,8 @@ } else { + if (AT_index (a) != -1U) + remove_addr_table_entry (AT_index (a)); remove_AT (die, a->dw_attr); ix--; } @@ -21825,6 +22438,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; @@ -22006,9 +22632,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 @@ -22039,6 +22668,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 @@ -22152,7 +22793,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)); @@ -22168,6 +22809,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. */ @@ -22179,6 +22857,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. */ @@ -22331,6 +23010,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); @@ -22348,8 +23035,10 @@ /* Don't add if the CU has no associated code. */ if (text_section_used) { - add_AT_lbl_id (comp_unit_die (), DW_AT_low_pc, text_section_label); - add_AT_lbl_id (comp_unit_die (), DW_AT_high_pc, text_end_label); + add_AT_lbl_id (main_comp_unit_die, DW_AT_low_pc, text_section_label, + true); + add_AT_lbl_id (main_comp_unit_die, DW_AT_high_pc, text_end_label, + true); } } else @@ -22359,22 +23048,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) @@ -22384,16 +23075,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) @@ -22402,7 +23093,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. */ @@ -22423,19 +23118,34 @@ 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 ()); + if (!dwarf_split_debug_info) + add_AT_pubnames (comp_unit_die ()); + if (dwarf_split_debug_info) + { + /* Add a place-holder for the dwo_id to the comp-unit die. */ + add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, dwo_id_placeholder); + 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) { @@ -22449,8 +23159,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 ()); } @@ -22501,10 +23209,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 189624) +++ gcc/dwarf2out.h (working copy) @@ -171,6 +171,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 189624) +++ 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 @@ -1694,6 +1699,11 @@ set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc); break; + case OPT_gsplit_dwarf: + set_debug_level (NO_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 189624) +++ gcc/common.opt (working copy) @@ -2283,6 +2283,14 @@ 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
Sign in to reply to this message.
http://codereview.appspot.com/6305113/diff/3001/gcc/dwarf2out.c File gcc/dwarf2out.c (right): http://codereview.appspot.com/6305113/diff/3001/gcc/dwarf2out.c#newcode8517 gcc/dwarf2out.c:8517: Should use SKELETON_COMP_DIE_ABBREV here instead of 1. http://codereview.appspot.com/6305113/diff/3001/gcc/dwarf2out.c#newcode8602 gcc/dwarf2out.c:8602: const unsigned char *cp2; I don't think this comment applies here.
Sign in to reply to this message.
On 2012/07/20 00:37:15, Cary wrote: > http://codereview.appspot.com/6305113/diff/3001/gcc/dwarf2out.c > File gcc/dwarf2out.c (right): > > http://codereview.appspot.com/6305113/diff/3001/gcc/dwarf2out.c#newcode8517 > gcc/dwarf2out.c:8517: > Should use SKELETON_COMP_DIE_ABBREV here instead of 1. > > http://codereview.appspot.com/6305113/diff/3001/gcc/dwarf2out.c#newcode8602 > gcc/dwarf2out.c:8602: const unsigned char *cp2; > I don't think this comment applies here. I have fixed both of these issues in my local copy, and will post a revision after I received feedback from Jason. Sterling
Sign in to reply to this message.
On 07/18/2012 05:44 PM, Sterling Augustine wrote: > +/* 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. */ This sounds like a design flaw. Since we have everything in memory, there's no reason we shouldn't be able to pack the table appropriately. Why can't we wait to number the entries until after we know which entries we need? Perhaps instead of having a val_index field in each attribute you should have the attribute point to something like an indirect_string_node for addresses as well. > + 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); > + } And we shouldn't have multiple entries for the same address. Using a hash table would help with this as well. Deferring the choice of representation of the address until output time should also avoid the need for the "force_direct" parameter on various functions. > +static inline enum dwarf_location_atom dw_addr_op (bool dtprel) Function name should be on a new line. > + bool *added, bool force_direct) force_direct needs to be documented. > + /* This is a bit of a misnomer--the offset isn't an index, but we need to > + save force_direct for output. */ > + attr.dw_attr_val.val_index > + = (dwarf_split_debug_info && !force_direct) ? offset : -1U; How is this used for output? > -is_unit_die (dw_die_ref c) ... > +is_unit_die (dw_die_ref c) Why move is_unit_die? > + if (dwarf_version >= 4 || dwarf_split_debug_info) Shouldn't -gsplit-debug require -gdwarf-4+ anyway? > +enum dwarf_location_list_entry_type > + { > + DW_LLE_end_of_list_entry = 0, > + DW_LLE_base_address_selection_entry = 1, > + DW_LLE_start_end_entry = 2, > + DW_LLE_start_length_entry = 3 > + }; These should probably have GNU in the names so that it's clear at use sites that they're extensions. > + /* For split_debug_sections with use_type info, all type units int the > + skeleton sections have identical dies (but different headers). This single > + die will be output many times. */ s/int/in/ The second line goes past 80 chars. > + /* Produce the skeleton compilation-unit header. This one differs enough from > + (!dwarf_split_debug_info ? debug_line_section_label These lines are too long as well. > + temp = new_addr_loc_descr (rtl, true); > + mem_loc_result = new_addr_loc_descr (rtl, 0); Let's use true/false consistently when passing a boolean value, or better yet an enum. > + /* FIXME: needs to change for dwarf_split_debug_info. */ Please elaborate. > +static void > +output_index_strings (void) Needs a comment. > - add_AT_pubnames (comp_unit_die ()); > + if (!dwarf_split_debug_info) > + add_AT_pubnames (comp_unit_die ()); Why not emit AT_pubnames with DWO? > + /* The dwo_id is only for compile_units. */ > + add_AT_data8 (comp_unit, DW_AT_GNU_dwo_id, dwo_id_placeholder); >... > + /* Add a place-holder for the dwo_id to the comp-unit die. */ > + add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, dwo_id_placeholder); These are in the skeleton CU and the DWO CU, right? Let's add them to both at the same time. Jason
Sign in to reply to this message.
>> +/* 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. */ > > This sounds like a design flaw. Since we have everything in memory, there's > no reason we shouldn't be able to pack the table appropriately. Why can't > we wait to number the entries until after we know which entries we need? > > Perhaps instead of having a val_index field in each attribute you should > have the attribute point to something like an indirect_string_node for > addresses as well. The potential savings here didn't seem worth the effort of adding a pass over another table to assign slots in .debug_addr. In practice, we're seeing very few slots zeroed out here. >> + 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); >> + } > > And we shouldn't have multiple entries for the same address. Using a hash > table would help with this as well. I've got a patch in the works to coalesce multiple references to .LVL labels, which will take care of nearly all the duplicate entries we're seeing in practice. Sterling has started working on a hash table to solve the problem in general, but we were planning to wait to see how much would be gained from that. Would it be OK with you if we defer this to a follow-up patch or two? > Deferring the choice of representation of the address until output time > should also avoid the need for the "force_direct" parameter on various > functions. I'm not sure about that. Even if we build a hash table for slots in .debug_addr, we'll still need to know when we call add_AT_addr or add_AT_lbl_id whether or not we want to use an indirect reference. In the cases where force_direct is true, we won't want to add the label to the hash table. >> + /* This is a bit of a misnomer--the offset isn't an index, but we need >> to >> + save force_direct for output. */ >> + attr.dw_attr_val.val_index >> + = (dwarf_split_debug_info && !force_direct) ? offset : -1U; > > How is this used for output? I think that comment needs to be rewritten. Sterling can probably describe it better, but I think what's happening here is that 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. >> -is_unit_die (dw_die_ref c) > ... >> +is_unit_die (dw_die_ref c) > > Why move is_unit_die? I don't think that was intentional -- probably the result of merges from trunk (is_unit_die was added to trunk while we were developing on the branch). >> + if (dwarf_version >= 4 || dwarf_split_debug_info) > > Shouldn't -gsplit-debug require -gdwarf-4+ anyway? Seems better to check explicitly than to rely on an implied relationship. >> +enum dwarf_location_list_entry_type >> + { >> + DW_LLE_end_of_list_entry = 0, >> + DW_LLE_base_address_selection_entry = 1, >> + DW_LLE_start_end_entry = 2, >> + DW_LLE_start_length_entry = 3 >> + }; > > These should probably have GNU in the names so that it's clear at use sites > that they're extensions. OK with me. (I was guilty of anticipating eventual adoption into DWARF, and since this was a new namespace, I didn't feel it was necessary to qualify them.) >> + /* FIXME: needs to change for dwarf_split_debug_info. */ > > Please elaborate. I think we'll want to use DW_FORM_GNU_str_index there, but we didn't look at it closely. >> - add_AT_pubnames (comp_unit_die ()); >> + if (!dwarf_split_debug_info) >> + add_AT_pubnames (comp_unit_die ()); > > Why not emit AT_pubnames with DWO? In the dwarf_split_debug_info case, the attribute gets added by add_top_level_skeleton_die_attrs. Looks like both cases should be handled in the same place -- Sterling, can you remove the call in add_top_level_skeleton_die_attrs and make the one in dwarf2out_finish unconditional (using main_comp_unit_die)? >> + /* The dwo_id is only for compile_units. */ >> + add_AT_data8 (comp_unit, DW_AT_GNU_dwo_id, dwo_id_placeholder); > >>... > >> + /* Add a place-holder for the dwo_id to the comp-unit die. */ >> + add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, >> dwo_id_placeholder); > > These are in the skeleton CU and the DWO CU, right? Let's add them to both > at the same time. I have a separate patch underway that will do exactly that, and to compute a real dwo_id. In the meantime, let's just drop these from this patch. -cary
Sign in to reply to this message.
On Wed, Jul 25, 2012 at 4:00 PM, Cary Coutant <ccoutant@google.com> wrote: >>> +/* 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. */ >> >> This sounds like a design flaw. Since we have everything in memory, there's >> no reason we shouldn't be able to pack the table appropriately. Why can't >> we wait to number the entries until after we know which entries we need? >> >> Perhaps instead of having a val_index field in each attribute you should >> have the attribute point to something like an indirect_string_node for >> addresses as well. > > The potential savings here didn't seem worth the effort of adding a > pass over another table to assign slots in .debug_addr. In practice, > we're seeing very few slots zeroed out here. It also requires a carefully watching when die sizes are measured--if a leb128 fit inside a byte and then grows to need two bytes, all the size and die_offset calculations will need to be redone. Right now there is no attempt at deferring size calculations or ordering them. It's a pretty big change for only marginal benefit. >> Deferring the choice of representation of the address until output time >> should also avoid the need for the "force_direct" parameter on various >> functions. > > I'm not sure about that. Even if we build a hash table for slots in > .debug_addr, we'll still need to know when we call add_AT_addr or > add_AT_lbl_id whether or not we want to use an indirect reference. In > the cases where force_direct is true, we won't want to add the label > to the hash table. Right. We would have to track it even with a hash table. >>> + /* This is a bit of a misnomer--the offset isn't an index, but we need >>> to >>> + save force_direct for output. */ >>> + attr.dw_attr_val.val_index >>> + = (dwarf_split_debug_info && !force_direct) ? offset : -1U; >> >> How is this used for output? > > I think that comment needs to be rewritten. Sterling can probably > describe it better, but I think what's happening here is that > 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. Exactly. I'll fix up the comment. > >>> -is_unit_die (dw_die_ref c) >> ... >>> +is_unit_die (dw_die_ref c) >> >> Why move is_unit_die? > > I don't think that was intentional -- probably the result of merges > from trunk (is_unit_die was added to trunk while we were developing on > the branch). True, and I'll fix that. >>> + if (dwarf_version >= 4 || dwarf_split_debug_info) >> >> Shouldn't -gsplit-debug require -gdwarf-4+ anyway? > > Seems better to check explicitly than to rely on an implied relationship. I think Jason is right here. Although they are theoretically separate, there has been no testing of -gsplit-dwarf without dwarf4, and I don't think we plan to test it that way. I think the best thing to do is make -gspit-debug-info imply dwarf4. I'll fix it up. >>> + /* FIXME: needs to change for dwarf_split_debug_info. */ >> >> Please elaborate. > > I think we'll want to use DW_FORM_GNU_str_index there, but we didn't > look at it closely. Yes. I have a local fix for this--so there won't be any fixme at all-- I'll roll into the updated version. > >>> - add_AT_pubnames (comp_unit_die ()); >>> + if (!dwarf_split_debug_info) >>> + add_AT_pubnames (comp_unit_die ()); >> >> Why not emit AT_pubnames with DWO? > > In the dwarf_split_debug_info case, the attribute gets added by > add_top_level_skeleton_die_attrs. Looks like both cases should be > handled in the same place -- Sterling, can you remove the call in > add_top_level_skeleton_die_attrs and make the one in dwarf2out_finish > unconditional (using main_comp_unit_die)? AT_pubnames needs to go in all the skeleton dies, including the TUs, so moving the call from add_top_level_skeleton_die_attrs would cause a problem. Adding it here also would make me need to special case the comp_unit_die there. So that's pretty confusing. Still, you are absolutely right that it is confusing here. I'll add a comment to sort it all out. >>> + /* The dwo_id is only for compile_units. */ >>> + add_AT_data8 (comp_unit, DW_AT_GNU_dwo_id, dwo_id_placeholder); >> >>>... >> >>> + /* Add a place-holder for the dwo_id to the comp-unit die. */ >>> + add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, >>> dwo_id_placeholder); >> >> These are in the skeleton CU and the DWO CU, right? Let's add them to both >> at the same time. > > I have a separate patch underway that will do exactly that, and to > compute a real dwo_id. In the meantime, let's just drop these from > this patch. > > -cary
Sign in to reply to this message.
>>>> + if (dwarf_version >= 4 || dwarf_split_debug_info) >>> >>> Shouldn't -gsplit-debug require -gdwarf-4+ anyway? >> >> Seems better to check explicitly than to rely on an implied relationship. > > I think Jason is right here. Although they are theoretically separate, > there has been no testing of -gsplit-dwarf without dwarf4, and I don't > think we plan to test it that way. > > I think the best thing to do is make -gspit-debug-info imply dwarf4. > I'll fix it up. OK, sounds good to me. >>>> - add_AT_pubnames (comp_unit_die ()); >>>> + if (!dwarf_split_debug_info) >>>> + add_AT_pubnames (comp_unit_die ()); >>> >>> Why not emit AT_pubnames with DWO? >> >> In the dwarf_split_debug_info case, the attribute gets added by >> add_top_level_skeleton_die_attrs. Looks like both cases should be >> handled in the same place -- Sterling, can you remove the call in >> add_top_level_skeleton_die_attrs and make the one in dwarf2out_finish >> unconditional (using main_comp_unit_die)? > > AT_pubnames needs to go in all the skeleton dies, including the TUs, > so moving the call from add_top_level_skeleton_die_attrs would cause a > problem. Adding it here also would make me need to special case the > comp_unit_die there. So that's pretty confusing. > > Still, you are absolutely right that it is confusing here. I'll add a > comment to sort it all out. Right, I should have remembered about the TUs. -cary
Sign in to reply to this message.
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
Sign in to reply to this message.
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
Sign in to reply to this message.
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?
Sign in to reply to this message.
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
Sign in to reply to this message.
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
Sign in to reply to this message.
On 07/25/2012 07:54 PM, Sterling Augustine wrote: > On Wed, Jul 25, 2012 at 4:00 PM, Cary Coutant <ccoutant@google.com> wrote: >>> Perhaps instead of having a val_index field in each attribute you should >>> have the attribute point to something like an indirect_string_node for >>> addresses as well. >> >> The potential savings here didn't seem worth the effort of adding a >> pass over another table to assign slots in .debug_addr. In practice, >> we're seeing very few slots zeroed out here. And how many duplicate entries? What strategy does Cary's patch use to avoid those? > It also requires a carefully watching when die sizes are measured--if > a leb128 fit inside a byte and then grows to need two bytes, all the > size and die_offset calculations will need to be redone. I would expect it to be straightforward to assign the indices before calculating die sizes. >>> Deferring the choice of representation of the address until output time >>> should also avoid the need for the "force_direct" parameter on various >>> functions. >> >> I'm not sure about that. Even if we build a hash table for slots in >> .debug_addr, we'll still need to know when we call add_AT_addr or >> add_AT_lbl_id whether or not we want to use an indirect reference. In >> the cases where force_direct is true, we won't want to add the label >> to the hash table. > > Right. We would have to track it even with a hash table. I was thinking that the context of the reference would determine whether you want a direct or indirect reference, in a way that would be clear when we go to write out the reference. But if that isn't convenient, I don't mind determining it when we build the reference. The added documentation for force_direct tells me what it means, but not when you would want to pass true or false. What is the pattern here? Jason
Sign in to reply to this message.
>>> The potential savings here didn't seem worth the effort of adding a >>> pass over another table to assign slots in .debug_addr. In practice, >>> we're seeing very few slots zeroed out here. > > And how many duplicate entries? What strategy does Cary's patch use to > avoid those? I picked a compilation unit from one of our internal applications with one of the largest .debug_addr sections, and counted up the .debug_addr entries: Total count: 320,083 Unique entries: 8022 Unused entries (i.e., removed by resolve_addr): 13 Total refs to ".LVL" symbols: 313,554 Unique ".LVL" symbols: 3288 Entries after removing just duplicate ".LVL" refs: 9817 After the ".LVL" symbols, the most repeated entries were these: 298 .quad _ZdlPv 13 .quad _Znwm 12 .quad memmove Nearly all the remaining repeated entries were ".LC" (constant def) symbols (at most 6 of each). We have a lot of entries for ".LFB" (function begin) and ".LBB" (block begin) symbols, but no duplicates for any of these. I'm working on a follow-up patch to eliminate the duplicate references to ".LVL" symbols by keeping a direct-lookup table in dwarf2out_var_location. That will eliminate 310,266 of the 312,061 duplicates (99.4%) without using a hash table. With that patch, we'll have only a 22% overhead due to duplicate entries. (For this source file, at least -- I've seen similar numbers for a few other randomly-chosen sources, but I haven't done the same detailed analysis for them.) I'm also planning to do another later patch to generate location lists using the new DW_LLE_offset_pair_entry type for the .debug_locs.dwo section. This entry format uses offsets relative to the function's low_pc (or a base address selection entry), which (I think) will eliminate .debug_addr entries for ".LVL" symbols entirely. I think it should also get rid of most of the ".LFB" references as well. GDB isn't ready for that yet, so that one will come later. I'm trying to eliminate all .debug_addr entries that could be replaced by an offset relative to either another .debug_addr entry or an address in a range list. > I was thinking that the context of the reference would determine whether you > want a direct or indirect reference, in a way that would be clear when we go > to write out the reference. But if that isn't convenient, I don't mind > determining it when we build the reference. > > The added documentation for force_direct tells me what it means, but not > when you would want to pass true or false. What is the pattern here? We use force_direct when we're adding an attribute to a DIE in a skeleton compile unit or type unit (which will be in the .o file). It's false everywhere else (i.e., when the DIE is going into the .dwo file). -cary
Sign in to reply to this message.
On 10/10/2012 08:41 PM, Cary Coutant wrote: > I'm working on a follow-up patch to eliminate the duplicate references > to ".LVL" symbols by keeping a direct-lookup table in > dwarf2out_var_location. That will eliminate 310,266 of the 312,061 > duplicates (99.4%) without using a hash table. With that patch, we'll > have only a 22% overhead due to duplicate entries. That's certainly a big improvement, but 22% still seems worth addressing. > I'm trying to eliminate all .debug_addr entries that could be replaced > by an offset relative to either another .debug_addr entry or an > address in a range list. Sounds good. > We use force_direct when we're adding an attribute to a DIE in a > skeleton compile unit or type unit (which will be in the .o file). > It's false everywhere else (i.e., when the DIE is going into the .dwo > file). Right, so I was thinking that you could distinguish at output time between output going to .o vs .dwo and choose the appropriate addressing form then. Jason
Sign in to reply to this message.
Jason and other GCC Dwarf maintainers, Enclosed is what I hope is the final pass of the fission patch, which I hope to get into the main line before stage 1 closes. It was reviewed in an earlier thread here: http://gcc.gnu.org/ml/gcc-patches/2012-06/msg01284.html Most of the logic has stayed the same, however, I significantly reworked the .debug_address table building and handling in order to avoid duplicate entries, as requested. It also defers assigning indices to anything until as late as possible, which avoids the need for any empty entries in either the address table or the string table, at a cost of complexity in logic (and a raft of assertions). I did try to figure out a way to avoid the force_direct logic, but things end up even more complicated than this patch, and I think it is the most understandable method. Tested with a complete bootstrap and not observing any (new) failures with -dwarf-split-debug-info both off and on. The GDB testsuite also passes with -dwarf-split-debug-info both off and on, modulus some unrelated GDB test-suite bugs related to build ordering. OK for main line? Sterling Augustine saugustine@google.com gcc/ChangeLog 2012-10-29 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. * 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. (common_handle_option): Add case for OPT_gsplit_dwarf. * dwarf2out.h (addr_table_entry_struct): Add forward declaration. (dw_val_struct): Add val_entry pointer. * dwarf2out.c: (debug_skeleton_info_section, debug_skeleton_abbrev_section, debug_addr_section, debug_skeleton_line_section, debug_str_offsets_section): New globals. (NOT_INDEXED, NO_INDEX_ASSIGNED): New defines. (indirect_string_node): New field index. (ate_kind): New enum with fields ate_kind_rtc, ate_kind_rtx_dtprel, ate_kind_label. (addr_table_entry): New structure and type. (dw_loc_list_struct): Add field begin_entry. (new_loc_desc): Initialize val_entry. (size_of_loc_descr, output_loc_operands, output_loc_operands_raw): Add cases for DW_OP_GNU_addr_index and DW_OP_const_index. (build_cfa_loc): Initialize val_entry. (AT_index, add_addr_table_entry, remove_addr_table_entry, add_AT_lbl_id): New functions. (add_AT_addr, add_AT_range_list): New parameter force_direct. (output_die_abbrevs): New function. (add_ranges_by_labels): New parameter force_direct. (output_line_info): New parameter prologue_only. (dtprel_bool): New enum with dtprel_false and dtprel_true. (dw_addr_op, new_addr_loc_descr): New functions. (DEBUG_DWO_INFO_SECTION, DEBUG_DWO_ABBREV_SECTION, DEBUG_ADDR_SECTION, DEBUG_NORM_MACINFO_SECTION, DEBUG_DWO_MACINFO_SECTION, DEBUG_MACINFO_SECTION, DEBUG_NORM_MACRO_SECTION, DEBUG_DWO_MACRO_SECTION, DEBUG_MACRO_SECTION, DEBUG_DWO_LINE_SECTION, DEBUG_DWO_LOC_SECTION, DEBUG_NORM_STR_OFFSETS_SECTION, DEBUG_DWO_STR_OFFSETS_SECTION, DEBUG_STR_OFFSETS_SECTION, DEBUG_DWO_STR_SECTION, DEBUG_NORM_STR_SECTION, DEBUG_STR_SECTION, DEBUG_MACRO_SECTION_FLAGS, DEBUG_SKELETON_LINE_SECTION_LABEL, DEBUG_SKELETON_INFO_SECTION_LABEL, DEBUG_ADDR_SECTION_LABEL DEBUG_SKELETON_ABBREV_SECTION_LABEL): New macros. (DEBUG_STR_SECTION_FLAGS): Adjust. (TEXT_SECTION_LABEL, COLD_TEXT_SECTION_LABEL, DEBUG_LINE_SECTION_LABEL, DEBUG_INFO_SECTION_LABEL, DEBUG_ABBREV_SECTION_LABEL, DEBUG_ADDR_SECTION_LABEL, DEBUG_LOC_SECTION_LABEL, DEBUG_RANGES_SECTION_LABEL, DEBUG_MACINFO_SECTION_LABEL, DEBUG_MACRO_SECTION_LABEL): Adjust indentation. (debug_skeleton_abbrev_section_label, debug_addr_section_label, debug_skeleton_line_section_label, debug_skeleton_info_section_label): New global variables. (add_AT_flag, add_AT_int, add_AT_unsigned, add_AT_double, add_AT_vec, add_AT_data8): Initialize val_entry. (add_AT_low_high_pc): New parameter force_direct. Handle dwarf_split_debug_info. (set_indirect_string, find_AT_string_form): New functions. (AT_string_form): Adjust to call find_AT_string_from. (add_AT_die_ref, add_AT_fde_ref, add_AT_loc, add_AT_list): Initialize val_entry. (addr_index_table): New global variable. (addr_table_entry_do_hash, addr_table_entry_eq, add_addr_table_entry, init_addr_table_entry, remove_addr_table_entry, index_addr_table_entry, remove_loc_list_addr_table_entries): New functions. (add_AT_addr, add_AT_lbl_id, add_AT_range_list): New parameter force_direct. Handle dwarf_split_debug_info. (add_AT_file, add_AT_vms_delta, add_AT_lineptr, add_AT_macptr, add_AT_offset): Initialize val_entry. (UNRELOCATED_OFFSET, RELOCATED_OFFSET): New defines. (size_of_die): Handle dwarf_split_debug_info. (size_of_aranges, value_format): Call AT_class. Check AT_index. (output_die_abbrevs): New function. (output_abbrev_section): Call output_die_abbrevs. (new_loc_list): Initialize begin_entry. (output_loc_list): Handle dwarf_split_debug_info. (output_range_list_offset, output_loc_list_offset, output_attr_index_or_value, ): New functions. (output_die): Fix call to dw2_asm_output_data. Call output_attr_index_or_value and output_range_list_offset. Adjust logic around dw_val_class_str. (add_top_lebel_skeleton_die_attrs, get_skeleton_type_unit, output_skeleton_debug_sections): New functions. (output_comdat_type_unit, output_pubname, output_aranges): Handle dwarf_split_debug_info. (add_ranges_by_labels): New parameter force_direct. (mem_loc_descriptor, loc_descr): Call new_addr_loc_descr. (loc_list_from_tree, add_const_value_attribtue): Use dtprel_bools in place of generic integer. (dwarf2out_vms_debug_main_pointer, gen_entry_point_die, gen_label_die, gen_call_site_die, gen_subprogram_die, gen_variable_die, add_high_low_attributes): Adjust calls to add_AT_lbl_id. (output_macinfo_op): Adjust indirect_string_logic. (save_macinfo_strings): New function. (output_macinfo): Adjust. (dwarf2out_init): Handle dwarf_split_debug_info. (index_string, output_index_string_offset, output_index_string): New functions. (output_indirect_string): Ajust. (output_indirect_strings, output_addr_table_entry, output_addr_table): New functions. (resolve_addr_in_expr, hash_loc_operands): Handle DW_OP_GNU_addr_index and DW_OP_GNU_const_index. Handle dwarf_split_debug_info. Call remove_loc_list_addr_table_entries and remove_addr_table_entry. (index_location_lists): New function. (dwarf2out_finish): Handle dwarf_split_debug_info. New variable main_comp_unit_die. Adjust calls to add_AT_low_high_pc, add_ranges_by_labels, add_AT_addr, and add_AT_lineptr. Call save_macinfo_strings and output_indirect_strings. include/ChangeLog 2012-10-29 Sterling Augustine <saugustine@google.com> Cary Coutant <ccoutant@google.com> * dwarf2.h (dwarf_location_list_entry_type): New enum with fields DW_LLE_GNU_end_of_list_entry, DW_LLE_GNU_base_address_selection_entry, DW_LLE_GNU_start_end_entry and DW_LLE_GNU_start_length_entry. Index: include/dwarf2.h =================================================================== --- include/dwarf2.h (revision 192966) +++ include/dwarf2.h (working copy) @@ -259,6 +259,17 @@ enum dwarf_line_number_hp_sfc_ops 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 192966) +++ gcc/doc/invoke.texi (working copy) @@ -4840,6 +4840,14 @@ it reasonable to use the optimizer for programs th 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 192966) +++ gcc/gcc.c (working copy) @@ -267,6 +267,7 @@ static const char *compare_debug_dump_opt_spec_fun 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 @@ ignored. White space may also appear anywhere on 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 @@ proper position among the other output files. */ /* 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 @@ static const struct spec_function static_spec_func { "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 @@ -5814,7 +5823,7 @@ process_brace_body (const char *p, const char *ato 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. */ @@ -5851,7 +5860,7 @@ check_live_switch (int switchnum, int prefix_lengt } 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. */ @@ -8380,3 +8389,27 @@ pass_through_libs_spec_func (int argc, const char } 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; + + if (argc != 2) + fatal_error ("too few arguments to %%:replace-extension"); + + name = xstrdup (argv[0]); + p = strrchr (name, '.'); + if (p != NULL) + *p = '\0'; + + result = concat (name, argv[1], NULL); + + free (name); + return result; +} Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 192966) +++ gcc/dwarf2out.c (working copy) @@ -147,14 +147,19 @@ static GTY(()) VEC(tree,gc) *decl_scope_table; /* 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; @@ -190,6 +195,9 @@ DEF_VEC_ALLOC_P (dw_fde_ref, gc); /* A vector for a table that contains frame description information for each routine. */ +#define NOT_INDEXED (-1U) +#define NO_INDEX_ASSIGNED (-2U) + static GTY(()) VEC(dw_fde_ref, gc) *fde_vec; struct GTY(()) indirect_string_node { @@ -197,6 +205,7 @@ struct GTY(()) indirect_string_node { 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; @@ -1198,13 +1207,35 @@ static GTY(()) VEC(deferred_locations, gc) *deferr DEF_VEC_P(dw_die_ref); DEF_VEC_ALLOC_P(dw_die_ref,heap); +/* Describe an entry into the .debug_addr section. */ + +enum ate_kind { + ate_kind_rtx, + ate_kind_rtx_dtprel, + ate_kind_label +}; + +typedef struct GTY(()) addr_table_entry_struct { + enum ate_kind kind; + unsigned int refcount; + unsigned int index; + union addr_table_entry_struct_union + { + rtx GTY ((tag ("ate_kind_rtx"))) rtl; + char * GTY ((tag ("ate_kind_label"))) label; + } + GTY ((desc ("%1.kind"))) addr; +} +addr_table_entry; + /* Location lists are ranges + location descriptions for that range, so you can track variables that are in different places over 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 *end; /* Label for end address of range */ + const char *begin; /* Label and addr_entry for start of range */ + addr_table_entry *begin_entry; + const char *end; /* Label for end of range */ char *ll_symbol; /* Label for beginning of location list. Only on head of list */ const char *section; /* Section this loclist is relative to */ @@ -1248,8 +1279,10 @@ new_loc_descr (enum dwarf_location_atom op, unsign descr->dw_loc_opc = op; descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const; + descr->dw_loc_oprnd1.val_entry = NULL; descr->dw_loc_oprnd1.v.val_unsigned = oprnd1; descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const; + descr->dw_loc_oprnd2.val_entry = NULL; descr->dw_loc_oprnd2.v.val_unsigned = oprnd2; return descr; @@ -1454,6 +1487,11 @@ size_of_loc_descr (dw_loc_descr_ref loc) case DW_OP_addr: size += DWARF2_ADDR_SIZE; break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED); + size += size_of_uleb128 (loc->dw_loc_oprnd1.val_entry->index); + break; case DW_OP_const1u: case DW_OP_const1s: size += 1; @@ -1890,6 +1928,13 @@ output_loc_operands (dw_loc_descr_ref loc, int for } break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED); + dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_entry->index, + "(index into .debug_addr)"); + break; + case DW_OP_GNU_implicit_pointer: { char label[MAX_ARTIFICIAL_LABEL_BYTES @@ -2065,6 +2110,8 @@ output_loc_operands_raw (dw_loc_descr_ref loc) 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 (); @@ -2248,6 +2295,7 @@ build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT { 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_entry = NULL; tmp = new_loc_descr (DW_OP_deref, 0, 0); add_loc_descr (&head, tmp); if (offset != 0) @@ -2877,6 +2925,7 @@ static tree decl_ultimate_origin (const_tree); 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 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); @@ -2904,15 +2953,18 @@ static inline dw_loc_descr_ref AT_loc (dw_attr_ref 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 addr_table_entry *add_addr_table_entry (void *, enum ate_kind); +static void remove_addr_table_entry (addr_table_entry *); +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); @@ -3007,6 +3059,7 @@ static unsigned long size_of_aranges (void); 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); @@ -3022,10 +3075,10 @@ static void output_aranges (unsigned long); 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); @@ -3164,36 +3217,124 @@ static bool generic_type_p (tree); 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.v.val_addr = addr; + ref->dtprel = dtprel; + if (dwarf_split_debug_info) + ref->dw_loc_oprnd1.val_entry + = add_addr_table_entry (addr, + dtprel ? ate_kind_rtx_dtprel : ate_kind_rtx); + else + ref->dw_loc_oprnd1.val_entry = NULL; + + 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" @@ -3204,44 +3345,63 @@ static void gen_scheduled_generic_parms_dies (void #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. @@ -3254,7 +3414,11 @@ static char cold_text_section_label[MAX_ARTIFICIAL 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]; @@ -3495,6 +3659,20 @@ AT_class (dw_attr_ref a) 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 if (a->dw_attr_val.val_entry != NULL) + return a->dw_attr_val.val_entry->index; + return NOT_INDEXED; +} + /* Add a flag value attribute to a DIE. */ static inline void @@ -3504,6 +3682,7 @@ add_AT_flag (dw_die_ref die, enum dwarf_attribute attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_flag; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_flag = flag; add_dwarf_attr (die, &attr); } @@ -3524,6 +3703,7 @@ add_AT_int (dw_die_ref die, enum dwarf_attribute a attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_const; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_int = int_val; add_dwarf_attr (die, &attr); } @@ -3545,6 +3725,7 @@ add_AT_unsigned (dw_die_ref die, enum dwarf_attrib attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_unsigned_const; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_unsigned = unsigned_val; add_dwarf_attr (die, &attr); } @@ -3566,6 +3747,7 @@ add_AT_double (dw_die_ref die, enum dwarf_attribut attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_const_double; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_double.high = high; attr.dw_attr_val.v.val_double.low = low; add_dwarf_attr (die, &attr); @@ -3581,6 +3763,7 @@ add_AT_vec (dw_die_ref die, enum dwarf_attribute a attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_vec; + attr.dw_attr_val.val_entry = NULL; 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; @@ -3597,19 +3780,32 @@ add_AT_data8 (dw_die_ref die, enum dwarf_attribute attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_data8; + attr.dw_attr_val.val_entry = NULL; 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. When using + dwarf_split_debug_info, address attributes in dies destined for the + final executable have force_direct set to avoid using indexed + references. */ + 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; + char * lbl_id; + lbl_id = xstrdup (lbl_low); attr.dw_attr = DW_AT_low_pc; attr.dw_attr_val.val_class = dw_val_class_lbl_id; - attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_low); + attr.dw_attr_val.v.val_lbl_id = lbl_id; + if (dwarf_split_debug_info && !force_direct) + attr.dw_attr_val.val_entry + = add_addr_table_entry (lbl_id, ate_kind_label); + else + attr.dw_attr_val.val_entry = NULL; add_dwarf_attr (die, &attr); attr.dw_attr = DW_AT_high_pc; @@ -3617,7 +3813,14 @@ static inline void 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.v.val_lbl_id = xstrdup (lbl_high); + lbl_id = xstrdup (lbl_high); + attr.dw_attr_val.v.val_lbl_id = lbl_id; + if (attr.dw_attr_val.val_class == dw_val_class_lbl_id + && dwarf_split_debug_info && !force_direct) + attr.dw_attr_val.val_entry + = add_addr_table_entry (lbl_id, ate_kind_label); + else + attr.dw_attr_val.val_entry = NULL; add_dwarf_attr (die, &attr); } @@ -3675,6 +3878,7 @@ add_AT_string (dw_die_ref die, enum dwarf_attribut attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_str; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_str = node; add_dwarf_attr (die, &attr); } @@ -3686,19 +3890,43 @@ AT_string (dw_attr_ref a) return a->dw_attr_val.v.val_str->str; } +/* Call this function directly to bypass AT_string_form's logic to put + the string inline in the die. */ + +static void +set_indirect_string (struct indirect_string_node *node) +{ + char label[32]; + /* Already indirect is a no op. */ + if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index) + { + gcc_assert (node->label); + return; + } + ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter); + ++dw2_string_counter; + node->label = xstrdup (label); + + if (!dwarf_split_debug_info) + { + node->form = DW_FORM_strp; + node->index = NOT_INDEXED; + } + else + { + node->form = DW_FORM_GNU_str_index; + node->index = NO_INDEX_ASSIGNED; + } +} + /* Find out whether a string should be output inline in DIE or out-of-line in .debug_str section. */ static enum dwarf_form -AT_string_form (dw_attr_ref a) +find_string_form (struct indirect_string_node *node) { - struct indirect_string_node *node; unsigned int len; - char label[32]; - gcc_assert (a && AT_class (a) == dw_val_class_str); - - node = a->dw_attr_val.v.val_str; if (node->form) return node->form; @@ -3717,13 +3945,21 @@ static enum dwarf_form && (len - DWARF_OFFSET_SIZE) * node->refcount <= len)) return node->form = DW_FORM_string; - ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter); - ++dw2_string_counter; - node->label = xstrdup (label); + set_indirect_string (node); - return node->form = DW_FORM_strp; + return node->form; } +/* Find out whether the string referenced from the attribute should be + output inline in DIE or out-of-line in .debug_str section. */ + +static enum dwarf_form +AT_string_form (dw_attr_ref a) +{ + gcc_assert (a && AT_class (a) == dw_val_class_str); + return find_string_form (a->dw_attr_val.v.val_str); +} + /* Add a DIE reference attribute value to a DIE. */ static inline void @@ -3742,6 +3978,7 @@ add_AT_die_ref (dw_die_ref die, enum dwarf_attribu attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_die_ref; + attr.dw_attr_val.val_entry = NULL; 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); @@ -3800,6 +4037,7 @@ add_AT_fde_ref (dw_die_ref die, enum dwarf_attribu attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_fde_ref; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_fde_index = targ_fde; add_dwarf_attr (die, &attr); } @@ -3813,6 +4051,7 @@ add_AT_loc (dw_die_ref die, enum dwarf_attribute a attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_loc; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_loc = loc; add_dwarf_attr (die, &attr); } @@ -3831,6 +4070,7 @@ add_AT_loc_list (dw_die_ref die, enum dwarf_attrib attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_loc_list; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_loc_list = loc_list; add_dwarf_attr (die, &attr); have_location_lists = true; @@ -3850,16 +4090,169 @@ AT_loc_list_ptr (dw_attr_ref a) return &a->dw_attr_val.v.val_loc_list; } -/* Add an address constant attribute value to a DIE. */ +/* Table of entries into the .debug_addr section. */ +static GTY ((param_is (addr_table_entry))) htab_t addr_index_table; + +/* Hash an address_table_entry. */ + +static hashval_t +addr_table_entry_do_hash (const void *x) +{ + const addr_table_entry *a = (const addr_table_entry *) x; + switch (a->kind) + { + case ate_kind_rtx: + return iterative_hash_rtx (a->addr.rtl, 0); + case ate_kind_rtx_dtprel: + return iterative_hash_rtx (a->addr.rtl, 1); + case ate_kind_label: + return htab_hash_string (a->addr.label); + default: + gcc_unreachable (); + } +} + +/* Determine equality for two address_table_entries. */ + +static int +addr_table_entry_eq (const void *x1, const void *x2) +{ + const addr_table_entry *a1 = (const addr_table_entry *) x1; + const addr_table_entry *a2 = (const addr_table_entry *) x2; + + if (a1->kind != a2->kind) + return 0; + switch (a1->kind) + { + case ate_kind_rtx: + case ate_kind_rtx_dtprel: + return rtx_equal_p (a1->addr.rtl, a2->addr.rtl); + case ate_kind_label: + return strcmp (a1->addr.label, a2->addr.label) == 0; + default: + gcc_unreachable (); + } +} + +/* Initialize an addr_table_entry. */ + +void +init_addr_table_entry (addr_table_entry *e, enum ate_kind kind, void *addr) +{ + e->kind = kind; + switch (kind) + { + case ate_kind_rtx: + case ate_kind_rtx_dtprel: + e->addr.rtl = (rtx) addr; + break; + case ate_kind_label: + e->addr.label = (char *) addr; + break; + } + e->refcount = 0; + e->index = NO_INDEX_ASSIGNED; +} + +/* Add attr to the address table entry to the table. Defer setting an + index until output time. */ + +static addr_table_entry * +add_addr_table_entry (void *addr, enum ate_kind kind) +{ + addr_table_entry *node; + addr_table_entry finder; + void **slot; + + gcc_assert (dwarf_split_debug_info); + if (! addr_index_table) + addr_index_table = htab_create_ggc (10, addr_table_entry_do_hash, + addr_table_entry_eq, NULL); + init_addr_table_entry (&finder, kind, addr); + slot = htab_find_slot (addr_index_table, &finder, INSERT); + + if (*slot == HTAB_EMPTY_ENTRY) + { + node = ggc_alloc_cleared_addr_table_entry (); + init_addr_table_entry (node, kind, addr); + *slot = node; + } + else + node = (addr_table_entry *) *slot; + + node->refcount++; + return node; +} + +/* Remove an entry from the addr table by decrementing its refcount. + Strictly, decrementing the refcount would be enough, but the + assertion that the entry is actually in the table has found + bugs. */ + +static void +remove_addr_table_entry (addr_table_entry *entry) +{ + addr_table_entry *node; + + gcc_assert (dwarf_split_debug_info && addr_index_table); + node = (addr_table_entry *) htab_find (addr_index_table, entry); + node->refcount--; + /* After an index is assigned, the table is frozen. */ + gcc_assert (node->refcount > 0 || node->index == NO_INDEX_ASSIGNED); +} + +/* 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_entry != NULL) + { + gcc_assert (descr->dw_loc_oprnd1.val_entry->index == NO_INDEX_ASSIGNED); + remove_addr_table_entry (descr->dw_loc_oprnd1.val_entry); + } +} + +/* A helper function for dwarf2out_finish called through + htab_traverse. Assign an addr_table_entry its index. All entries + must be collected into the table when this function is called, + because the indexing code relies on htab_traverse to traverse nodes + in the same order for each run. */ + +static int +index_addr_table_entry (void **h, void *v) +{ + addr_table_entry *node = (addr_table_entry *) *h; + unsigned int *index = (unsigned int *) v; + + gcc_assert(node->index == NO_INDEX_ASSIGNED); + node->index = *index; + *index += 1; + + return 1; +} + +/* Add an address constant attribute value to a DIE. When using + dwarf_split_debug_info, address attributes in dies destined for the + final executable should be direct references--setting the parameter + force_direct ensures this behavior. */ + 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.v.val_addr = addr; + if (dwarf_split_debug_info && !force_direct) + attr.dw_attr_val.val_entry = add_addr_table_entry (addr, ate_kind_rtx); + else + attr.dw_attr_val.val_entry = NULL; add_dwarf_attr (die, &attr); } @@ -3882,6 +4275,7 @@ add_AT_file (dw_die_ref die, enum dwarf_attribute attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_file; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_file = fd; add_dwarf_attr (die, &attr); } @@ -3905,21 +4299,31 @@ add_AT_vms_delta (dw_die_ref die, enum dwarf_attri attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_vms_delta; + attr.dw_attr_val.val_entry = NULL; 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. When using + dwarf_split_debug_info, address attributes in dies destined for the + final executable should be direct references--setting the parameter + force_direct ensures this behavior. */ 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_entry = NULL; attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id); + if (dwarf_split_debug_info && !force_direct) + attr.dw_attr_val.val_entry + = add_addr_table_entry (attr.dw_attr_val.v.val_lbl_id, + ate_kind_label); add_dwarf_attr (die, &attr); } @@ -3934,6 +4338,7 @@ add_AT_lineptr (dw_die_ref die, enum dwarf_attribu attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_lineptr; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_lbl_id = xstrdup (label); add_dwarf_attr (die, &attr); } @@ -3949,6 +4354,7 @@ add_AT_macptr (dw_die_ref die, enum dwarf_attribut attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_macptr; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_lbl_id = xstrdup (label); add_dwarf_attr (die, &attr); } @@ -3963,20 +4369,34 @@ add_AT_offset (dw_die_ref die, enum dwarf_attribut attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_offset; + attr.dw_attr_val.val_entry = NULL; 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. When using + dwarf_split_debug_info, address attributes in dies destined for the + final executable should be direct references--setting the parameter + force_direct ensures this behavior. */ +#define UNRELOCATED_OFFSET ((addr_table_entry *) 1) +#define RELOCATED_OFFSET (NULL) + 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, use val_entry to store whether the + offset should follow split-debug-info or normal semantics. This + value is read in output_range_list_offset. */ + if (dwarf_split_debug_info && !force_direct) + attr.dw_attr_val.val_entry = UNRELOCATED_OFFSET; + else + attr.dw_attr_val.val_entry = RELOCATED_OFFSET; attr.dw_attr_val.v.val_offset = offset; add_dwarf_attr (die, &attr); } @@ -7163,6 +7583,7 @@ size_of_die (dw_die_ref die) 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) @@ -7170,7 +7591,13 @@ size_of_die (dw_die_ref die) switch (AT_class (a)) { case dw_val_class_addr: - size += DWARF2_ADDR_SIZE; + if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED) + { + gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED); + size += size_of_uleb128 (AT_index (a)); + } + else + size += DWARF2_ADDR_SIZE; break; case dw_val_class_offset: size += DWARF_OFFSET_SIZE; @@ -7188,10 +7615,16 @@ size_of_die (dw_die_ref die) } break; case dw_val_class_loc_list: - size += DWARF_OFFSET_SIZE; + if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED) + { + gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED); + 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)); @@ -7251,15 +7684,24 @@ size_of_die (dw_die_ref die) size += DWARF_OFFSET_SIZE; break; case dw_val_class_lbl_id: - size += DWARF2_ADDR_SIZE; + if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED) + { + gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED); + 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; @@ -7444,7 +7886,7 @@ size_of_aranges (void) 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. */ @@ -7454,7 +7896,8 @@ value_format (dw_attr_ref a) case DW_AT_high_pc: case DW_AT_entry_pc: case DW_AT_trampoline: - return DW_FORM_addr; + return (AT_index (a) == NOT_INDEXED + ? DW_FORM_addr : DW_FORM_GNU_addr_index); default: break; } @@ -7572,7 +8015,8 @@ value_format (dw_attr_ref a) case dw_val_class_fde_ref: return DW_FORM_data; case dw_val_class_lbl_id: - return DW_FORM_addr; + return (AT_index (a) == NOT_INDEXED + ? DW_FORM_addr : DW_FORM_GNU_addr_index); case dw_val_class_lineptr: case dw_val_class_macptr: return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data; @@ -7620,6 +8064,36 @@ output_value_format (dw_attr_ref a) 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. */ @@ -7629,32 +8103,8 @@ output_abbrev_section (void) 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); } @@ -7690,6 +8140,7 @@ new_loc_list (dw_loc_descr_ref expr, const char *b dw_loc_list_ref retlist = ggc_alloc_cleared_dw_loc_list_node (); retlist->begin = begin; + retlist->begin_entry = NULL; retlist->end = end; retlist->expr = expr; retlist->section = section; @@ -7734,7 +8185,22 @@ output_loc_list (dw_loc_list_ref list_head) 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_entry->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)", @@ -7760,14 +8226,88 @@ output_loc_list (dw_loc_list_ref list_head) 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 a range_list offset into the debug_range section. Emit a + relocated reference if val_entry is NULL, otherwise, emit an + indirect reference. */ + +static void +output_range_list_offset (dw_attr_ref a) +{ + const char *name = dwarf_attr_name (a->dw_attr); + + if (a->dw_attr_val.val_entry == RELOCATED_OFFSET) + { + 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) != NOT_INDEXED) + { + 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_high_pc: + 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 @@ -7806,7 +8346,7 @@ output_die (dw_die_ref die) 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: @@ -7815,15 +8355,7 @@ output_die (dw_die_ref die) 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: @@ -7879,7 +8411,7 @@ output_die (dw_die_ref die) } 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); } @@ -7926,13 +8458,7 @@ output_die (dw_die_ref die) 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: @@ -7989,7 +8515,7 @@ output_die (dw_die_ref die) 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: @@ -8003,12 +8529,15 @@ output_die (dw_die_ref die) break; case dw_val_class_str: - if (AT_string_form (a) == 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 + 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 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; @@ -8151,6 +8680,96 @@ add_AT_pubnames (dw_die_ref die) 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 @@ -8178,7 +8797,11 @@ output_comdat_type_unit (comdat_type_node *node) 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++) @@ -8204,6 +8827,36 @@ output_comdat_type_unit (comdat_type_node *node) 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. */ @@ -8239,7 +8892,7 @@ add_pubname (tree decl, dw_die_ref die) 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); @@ -8347,9 +9000,14 @@ output_pubnames (VEC (pubname_entry, gc) * names) "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"); @@ -8410,9 +9068,14 @@ output_aranges (unsigned long aranges_length) "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"); @@ -8509,12 +9172,14 @@ add_ranges (const_tree block) 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. + When using dwarf_split_debug_info, address attributes in dies destined + for the final executable should be direct references--setting the + parameter force_direct ensures this behavior. */ 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; @@ -8537,7 +9202,7 @@ add_ranges_by_labels (dw_die_ref die, const char * 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; } } @@ -9074,7 +9739,7 @@ output_one_line_info_table (dw_line_info_table *ta 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; @@ -9144,6 +9809,12 @@ static void /* 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) { @@ -11448,14 +12119,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mod 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); @@ -11467,9 +12131,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mod 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; @@ -12373,9 +13035,7 @@ loc_descriptor (rtx rtl, enum machine_mode mode, 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); } @@ -13075,9 +13735,8 @@ loc_list_from_tree (tree loc, int want_address) 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) { @@ -13094,9 +13753,8 @@ loc_list_from_tree (tree loc, int want_address) 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 { @@ -13108,8 +13766,7 @@ loc_list_from_tree (tree loc, int want_address) 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); @@ -13122,12 +13779,8 @@ loc_list_from_tree (tree loc, int want_address) 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; @@ -13172,11 +13825,7 @@ loc_list_from_tree (tree loc, int want_address) 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; @@ -14101,9 +14750,7 @@ add_const_value_attribute (dw_die_ref die, rtx rtl 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); @@ -15623,7 +16270,7 @@ add_name_and_src_coords_attributes (dw_die_ref die 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 */ @@ -15644,7 +16291,7 @@ dwarf2out_vms_debug_main_pointer (void) 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 (); @@ -16235,7 +16882,7 @@ gen_entry_point_die (tree decl, dw_die_ref context 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 @@ -16883,7 +17530,7 @@ gen_call_site_die (tree decl, dw_die_ref subr_die, 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) @@ -16892,7 +17539,7 @@ gen_call_site_die (tree decl, dw_die_ref subr_die, 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; } @@ -17085,7 +17732,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_ 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 { @@ -17096,7 +17744,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_ 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 @@ -17139,10 +17788,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_ 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); } @@ -17161,7 +17811,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_ /* 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, @@ -17186,14 +17836,15 @@ gen_subprogram_die (tree decl, dw_die_ref context_ 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); @@ -17634,7 +18285,7 @@ gen_variable_die (tree decl, tree origin, dw_die_r { /* 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) { @@ -17821,7 +18472,7 @@ gen_label_die (tree decl, dw_die_ref context_die) 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) @@ -17829,7 +18480,7 @@ gen_label_die (tree decl, dw_die_ref context_die) && 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); } } } @@ -17870,7 +18521,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die { 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 @@ -17918,12 +18569,13 @@ add_high_low_attributes (tree stmt, dw_die_ref die ++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 @@ -17941,7 +18593,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die 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); } } @@ -20535,23 +21187,22 @@ output_macinfo_op (macinfo_entry *ref) case DW_MACRO_GNU_define_indirect: case DW_MACRO_GNU_undef_indirect: node = find_AT_string (ref->info); - if (node->form != DW_FORM_strp) - { - char label[32]; - ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter); - ++dw2_string_counter; - node->label = xstrdup (label); - node->form = DW_FORM_strp; - } + gcc_assert (node + && ((node->form == DW_FORM_strp) + || (node->form == DW_FORM_GNU_str_index))); dw2_asm_output_data (1, ref->code, ref->code == DW_MACRO_GNU_define_indirect ? "Define macro indirect" : "Undefine macro indirect"); dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu", (unsigned long) ref->lineno); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, - debug_str_section, "The macro: \"%s\"", - ref->info); + if (node->form == DW_FORM_strp) + dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, + debug_str_section, "The macro: \"%s\"", + ref->info); + else + dw2_asm_output_data_uleb128 (node->index, "The macro: \"%s\"", + ref->info); break; case DW_MACRO_GNU_transparent_include: dw2_asm_output_data (1, ref->code, "Transparent include"); @@ -20694,6 +21345,42 @@ optimize_macinfo_range (unsigned int idx, VEC (mac return count; } +/* Save any strings needed by the macinfo table in the debug str + table. All strings must be collected into the table by the time + index_string is called. */ + +static void +save_macinfo_strings (void) +{ + unsigned len; + unsigned i; + macinfo_entry *ref; + + for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++) + { + switch (ref->code) + { + /* Match the logic in output_macinfo_op to decide on + indirect strings. */ + case DW_MACINFO_define: + case DW_MACINFO_undef: + len = strlen (ref->info) + 1; + if (!dwarf_strict + && len > DWARF_OFFSET_SIZE + && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET + && (debug_str_section->common.flags & SECTION_MERGE) != 0) + set_indirect_string (find_AT_string (ref->info)); + break; + case DW_MACRO_GNU_define_indirect: + case DW_MACRO_GNU_undef_indirect: + set_indirect_string (find_AT_string (ref->info)); + break; + default: + break; + } + } +} + /* Output macinfo section(s). */ static void @@ -20722,8 +21409,10 @@ output_macinfo (void) dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present"); else dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present"); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, 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 @@ -20862,20 +21551,54 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNU 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, @@ -20901,10 +21624,13 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNU 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 +21657,71 @@ dwarf2out_assembly_start (void) } /* A helper function for dwarf2out_finish called through + htab_traverse. Assign a string its index. All strings must be + collected into the table by the time index_string is called, + because the indexing code relies on htab_traverse to traverse nodes + in the same order for each run. */ + +static int +index_string (void **h, void *v) +{ + struct indirect_string_node *node = (struct indirect_string_node *) *h; + unsigned int *index = (unsigned int *) v; + + find_string_form (node); + if (node->form == DW_FORM_GNU_str_index && node->refcount > 0) + { + gcc_assert(node->index == NO_INDEX_ASSIGNED); + node->index = *index; + *index += 1; + } + return 1; +} + +/* A helper function for output_indirect_strings called through + htab_traverse. Output the offset to a string and update the + current offset. */ + +static int +output_index_string_offset (void **h, void *v) +{ + struct indirect_string_node *node = (struct indirect_string_node *) *h; + unsigned int *offset = (unsigned int *) v; + + if (node->form == DW_FORM_GNU_str_index && node->refcount > 0) + { + /* Assert that this node has been assigned an index. */ + gcc_assert (node->index != NO_INDEX_ASSIGNED + && node->index != NOT_INDEXED); + dw2_asm_output_data (DWARF_OFFSET_SIZE, *offset, + "indexed string 0x%x: %s", node->index, node->str); + *offset += strlen (node->str) + 1; + } + return 1; +} + +/* A helper function for dwarf2out_finish called through + htab_traverse. Output the indexed string. */ + +static int +output_index_string (void **h, void *v) +{ + struct indirect_string_node *node = (struct indirect_string_node *) *h; + unsigned int *cur_idx = (unsigned int *) v; + + if (node->form == DW_FORM_GNU_str_index && node->refcount > 0) + { + /* Assert that the strings are output in the same order as their + indexes were assigned. */ + gcc_assert (*cur_idx == node->index); + ASM_OUTPUT_LABEL (asm_out_file, node->label); + assemble_string (node->str, strlen (node->str) + 1); + *cur_idx += 1; + } + return 1; +} + +/* A helper function for dwarf2out_finish called through htab_traverse. Emit one queued .debug_str string. */ static int @@ -20938,9 +21729,8 @@ output_indirect_string (void **h, void *v ATTRIBUT { struct indirect_string_node *node = (struct indirect_string_node *) *h; - if (node->form == DW_FORM_strp) + if (node->form == DW_FORM_strp && node->refcount > 0) { - switch_to_section (debug_str_section); ASM_OUTPUT_LABEL (asm_out_file, node->label); assemble_string (node->str, strlen (node->str) + 1); } @@ -20948,6 +21738,87 @@ output_indirect_string (void **h, void *v ATTRIBUT return 1; } +/* Output the indexed string table. */ + +static void +output_indirect_strings (void) +{ + if (!dwarf_split_debug_info) + { + switch_to_section (debug_str_section); + htab_traverse (debug_str_hash, output_indirect_string, NULL); + } + else + { + unsigned int offset = 0; + unsigned int cur_idx = 0; + + switch_to_section (debug_str_offsets_section); + htab_traverse_noresize (debug_str_hash, + output_index_string_offset, + &offset); + switch_to_section (debug_str_section); + htab_traverse_noresize (debug_str_hash, + output_index_string, + &cur_idx); + } +} + +/* Callback for htab_traverse to assign an index to an entry in the + table, and to write that entry to the .debug_addr section. */ + +static int +output_addr_table_entry (void **slot, void *data) +{ + addr_table_entry *entry = (addr_table_entry *) *slot; + unsigned int *cur_index = (unsigned int *)data; + + if (entry->refcount == 0) + { + gcc_assert (entry->index == NO_INDEX_ASSIGNED + || entry->index == NOT_INDEXED); + return 1; + } + + gcc_assert (entry->index == *cur_index); + (*cur_index)++; + + switch (entry->kind) + { + case ate_kind_rtx: + dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, entry->addr.rtl, + "0x%x", entry->index); + break; + case ate_kind_rtx_dtprel: + gcc_assert (targetm.asm_out.output_dwarf_dtprel); + targetm.asm_out.output_dwarf_dtprel (asm_out_file, + DWARF2_ADDR_SIZE, + entry->addr.rtl); + fputc ('\n', asm_out_file); + break; + case ate_kind_label: + dw2_asm_output_addr (DWARF2_ADDR_SIZE, entry->addr.label, + "0x%x", entry->index); + break; + default: + gcc_unreachable (); + } + return 1; +} + +/* Produce the .debug_addr section. */ + +static void +output_addr_table (void) +{ + unsigned int index = 0; + if (addr_index_table == NULL || htab_size (addr_index_table) == 0) + return; + + switch_to_section (debug_addr_section); + htab_traverse_noresize (addr_index_table, output_addr_table_entry, &index); +} + #if ENABLE_ASSERT_CHECKING /* Verify that all marks are clear. */ @@ -21215,7 +22086,7 @@ prune_unused_types_update_strings (dw_die_ref die) *slot = s; } } -} + } /* Remove from the tree DIE any dies that aren't marked. */ @@ -21567,6 +22438,16 @@ resolve_addr_in_expr (dw_loc_descr_ref loc) 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: + { + if ((loc->dw_loc_opc == DW_OP_GNU_addr_index + || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel)) + && resolve_one_addr (&loc->dw_loc_oprnd1.val_entry->addr.rtl, + NULL)) + return false; + } + break; case DW_OP_const4u: case DW_OP_const8u: if (loc->dtprel @@ -21701,11 +22582,15 @@ resolve_addr (dw_die_ref die) 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 @@ -21719,6 +22604,8 @@ resolve_addr (dw_die_ref die) else { loc->replaced = 1; + if (dwarf_split_debug_info) + remove_loc_list_addr_table_entries (loc->expr); loc->dw_loc_next = *start; } } @@ -21743,6 +22630,8 @@ resolve_addr (dw_die_ref die) || 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--; } @@ -21754,6 +22643,8 @@ resolve_addr (dw_die_ref die) if (a->dw_attr == DW_AT_const_value && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL)) { + if (AT_index (a) != NOT_INDEXED) + remove_addr_table_entry (a->dw_attr_val.val_entry); remove_AT (die, a->dw_attr); ix--; } @@ -21777,6 +22668,8 @@ resolve_addr (dw_die_ref die) } else { + if (AT_index (a) != NOT_INDEXED) + remove_addr_table_entry (a->dw_attr_val.val_entry); remove_AT (die, a->dw_attr); ix--; } @@ -21910,6 +22803,17 @@ hash_loc_operands (dw_loc_descr_ref loc, hashval_t } hash = iterative_hash_rtx (val1->v.val_addr, hash); break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + { + if (loc->dtprel) + { + unsigned char dtprel = 0xd1; + hash = iterative_hash_object (dtprel, hash); + } + hash = iterative_hash_rtx (val1->val_entry->addr.rtl, hash); + } + break; case DW_OP_GNU_implicit_pointer: hash = iterative_hash_object (val2->v.val_int, hash); break; @@ -22091,9 +22995,12 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_d 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 @@ -22124,6 +23031,13 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_d 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: + { + rtx ax1 = valx1->val_entry->addr.rtl; + rtx ay1 = valy1->val_entry->addr.rtl; + return rtx_equal_p (ax1, ay1); + } case DW_OP_GNU_implicit_pointer: return valx1->val_class == dw_val_class_die_ref && valx1->val_class == valy1->val_class @@ -22237,12 +23151,45 @@ optimize_location_lists_1 (dw_die_ref die, htab_t 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)); } + +/* 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) + { + /* Don't index an entry that has already been indexed + or won't be output. */ + if (curr->begin_entry != NULL + || (strcmp (curr->begin, curr->end) == 0 && !curr->force)) + continue; + + curr->begin_entry + = add_addr_table_entry (xstrdup (curr->begin), + ate_kind_label); + } + } + + FOR_EACH_CHILD (die, c, index_location_lists (c)); +} + /* Optimize location lists referenced from DIE children and share them whenever possible. */ @@ -22264,6 +23211,7 @@ dwarf2out_finish (const char *filename) 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. */ @@ -22416,6 +23364,14 @@ dwarf2out_finish (const char *filename) 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); @@ -22432,8 +23388,8 @@ dwarf2out_finish (const char *filename) { /* 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 { @@ -22442,22 +23398,24 @@ dwarf2out_finish (const char *filename) 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) @@ -22467,16 +23425,16 @@ dwarf2out_finish (const char *filename) 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) @@ -22484,9 +23442,28 @@ dwarf2out_finish (const char *filename) dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros, macinfo_section_label); + if (dwarf_split_debug_info && addr_index_table != NULL) + { + /* optimize_location_lists calculates the size of the lists, + so index them first, and assign indices to the entries. + Although optimize_location_lists will remove entries from + the table, it only does so for duplicates, and therefore + only reduces ref_counts to 1. */ + unsigned int index = 0; + index_location_lists (comp_unit_die ()); + htab_traverse_noresize (addr_index_table, + index_addr_table_entry, &index); + } if (have_location_lists) optimize_location_lists (comp_unit_die ()); + save_macinfo_strings (); + if (dwarf_split_debug_info) + { + unsigned int index = 0; + htab_traverse_noresize (debug_str_hash, index_string, &index); + } + /* Output all of the compilation units. We put the main one last so that the offsets are available to output_pubnames. */ for (node = limbo_die_list; node; node = node->next) @@ -22506,19 +23483,58 @@ dwarf2out_finish (const char *filename) 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); + + switch_to_section (debug_addr_section); + ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label); + output_addr_table (); + } + /* 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) { @@ -22532,8 +23548,6 @@ dwarf2out_finish (const char *filename) { /* 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 ()); } @@ -22584,12 +23598,18 @@ dwarf2out_finish (const char *filename) 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); + } + + /* If we emitted any indirect strings, output the string table too. */ if (debug_str_hash) - htab_traverse (debug_str_hash, output_indirect_string, NULL); + output_indirect_strings (); } #include "gt-dwarf2out.h" Index: gcc/dwarf2out.h =================================================================== --- gcc/dwarf2out.h (revision 192966) +++ gcc/dwarf2out.h (working copy) @@ -167,11 +167,14 @@ typedef struct GTY(()) dw_vec_struct { } dw_vec_const; +struct addr_table_entry_struct; + /* The dw_val_node describes an attribute's value, as it is represented internally. */ typedef struct GTY(()) dw_val_struct { enum dw_val_class val_class; + struct addr_table_entry_struct * GTY(()) val_entry; union dw_val_struct_union { rtx GTY ((tag ("dw_val_class_addr"))) val_addr; Index: gcc/opts.c =================================================================== --- gcc/opts.c (revision 192966) +++ gcc/opts.c (working copy) @@ -829,6 +829,9 @@ finish_options (struct gcc_options *opts, struct g maybe_set_param_value (PARAM_MAX_STORES_TO_SINK, 0, opts->x_param_values, opts_set->x_param_values); + /* The -gsplit-dwarf option requires -gpubnames. */ + if (opts->x_dwarf_split_debug_info) + opts->x_debug_generate_pub_sections = 1; } #define LEFT_COLUMN 27 @@ -1699,6 +1702,11 @@ common_handle_option (struct gcc_options *opts, set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc); break; + case OPT_gsplit_dwarf: + set_debug_level (NO_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 192966) +++ gcc/common.opt (working copy) @@ -2314,6 +2314,14 @@ grecord-gcc-switches 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
Sign in to reply to this message.
> +/* %: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; > + > + if (argc != 2) > + fatal_error ("too few arguments to %%:replace-extension"); > + > + name = xstrdup (argv[0]); > + p = strrchr (name, '.'); > + if (p != NULL) > + *p = '\0'; > + > + result = concat (name, argv[1], NULL); > + > + free (name); > + return result; > +} This doesn't do the right thing when there is no '.' in the last component of the path. It should look for the last DIR_SEPARATOR, then search for the last '.' after that. > +/* Describe an entry into the .debug_addr section. */ > + > +enum ate_kind { > + ate_kind_rtx, > + ate_kind_rtx_dtprel, > + ate_kind_label > +}; > + > +typedef struct GTY(()) addr_table_entry_struct { > + enum ate_kind kind; > + unsigned int refcount; > + unsigned int index; > + union addr_table_entry_struct_union > + { > + rtx GTY ((tag ("ate_kind_rtx"))) rtl; > + char * GTY ((tag ("ate_kind_label"))) label; > + } > + GTY ((desc ("%1.kind"))) addr; When kind == ate_kind_rtx_dtprel, we use the rtl field. I think this needs to be covered for GC to work. As far as I know, gengtype doesn't support multiple tags for one union member, so I think it needs to be something like this: union addr_table_entry_struct_union { rtx GTY ((tag ("0"))) rtl; char * GTY ((tag ("1"))) label; } GTY ((desc ("(%1.kind == ate_kind_label)"))) addr; > +static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *, > + bool); It turns out we never call add_AT_lbl_id with force_direct == true. I don't think it's necessary to add this parameter here. > +/* 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 > + }; Extra indentation here. > +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); Unnecessary parentheses here. > +/* 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 if (a->dw_attr_val.val_entry != NULL) > + return a->dw_attr_val.val_entry->index; > + return NOT_INDEXED; > +} The comment seems out of date. DW_FORM_GNU_str_index should also be mentioned, and it doesn't look like strings have their indices handled differently (at least not here). > +static void > +remove_addr_table_entry (addr_table_entry *entry) > +{ > + addr_table_entry *node; > + > + gcc_assert (dwarf_split_debug_info && addr_index_table); > + node = (addr_table_entry *) htab_find (addr_index_table, entry); > + node->refcount--; > + /* After an index is assigned, the table is frozen. */ > + gcc_assert (node->refcount > 0 || node->index == NO_INDEX_ASSIGNED); This shouldn't ever be called after we've assigned any indexes at all, so I think it's always safe to asser that node->index == NO_INDEX_ASSIGNED. We can also assert that the ref count should never go negative, so I think you can rewrite this assert as: gcc_assert (node->refcount >= 0 && node->index == NO_INDEX_ASSIGNED); > @@ -21215,7 +22086,7 @@ prune_unused_types_update_strings (dw_die_ref die) > *slot = s; > } > } > -} > + } Accidental extra space? > +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) > + { > + /* Don't index an entry that has already been indexed > + or won't be output. */ > + if (curr->begin_entry != NULL > + || (strcmp (curr->begin, curr->end) == 0 && !curr->force)) > + continue; Check the indentation here -- looks like these last two lines are missing a space. OK for trunk with these changes. Thanks! -cary
Sign in to reply to this message.
On Mon, Nov 5, 2012 at 3:18 PM, Cary Coutant <ccoutant@google.com> wrote: >> +/* %: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; >> + >> + if (argc != 2) >> + fatal_error ("too few arguments to %%:replace-extension"); >> + >> + name = xstrdup (argv[0]); >> + p = strrchr (name, '.'); >> + if (p != NULL) >> + *p = '\0'; >> + >> + result = concat (name, argv[1], NULL); >> + >> + free (name); >> + return result; >> +} > > This doesn't do the right thing when there is no '.' in the last > component of the path. It should look for the last DIR_SEPARATOR, > then search for the last '.' after that. Good catch. Fixed. >> +/* Describe an entry into the .debug_addr section. */ >> + >> +enum ate_kind { >> + ate_kind_rtx, >> + ate_kind_rtx_dtprel, >> + ate_kind_label >> +}; >> + >> +typedef struct GTY(()) addr_table_entry_struct { >> + enum ate_kind kind; >> + unsigned int refcount; >> + unsigned int index; >> + union addr_table_entry_struct_union >> + { >> + rtx GTY ((tag ("ate_kind_rtx"))) rtl; >> + char * GTY ((tag ("ate_kind_label"))) label; >> + } >> + GTY ((desc ("%1.kind"))) addr; > > When kind == ate_kind_rtx_dtprel, we use the rtl field. I think this needs > to be covered for GC to work. As far as I know, gengtype doesn't support > multiple tags for one union member, so I think it needs to be something > like this: > > union addr_table_entry_struct_union > { > rtx GTY ((tag ("0"))) rtl; > char * GTY ((tag ("1"))) label; > } > GTY ((desc ("(%1.kind == ate_kind_label)"))) addr; > Done. >> +static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *, >> + bool); > > It turns out we never call add_AT_lbl_id with force_direct == true. > I don't think it's necessary to add this parameter here. Done--this actually cleans up the patch quite a bit. >> +/* 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 >> + }; > > Extra indentation here. Fixed. >> +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); > > Unnecessary parentheses here. Removed. >> +/* 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 if (a->dw_attr_val.val_entry != NULL) >> + return a->dw_attr_val.val_entry->index; >> + return NOT_INDEXED; >> +} > > The comment seems out of date. DW_FORM_GNU_str_index should also be > mentioned, and it doesn't look like strings have their indices handled > differently (at least not here). Updated. >> +static void >> +remove_addr_table_entry (addr_table_entry *entry) >> +{ >> + addr_table_entry *node; >> + >> + gcc_assert (dwarf_split_debug_info && addr_index_table); >> + node = (addr_table_entry *) htab_find (addr_index_table, entry); >> + node->refcount--; >> + /* After an index is assigned, the table is frozen. */ >> + gcc_assert (node->refcount > 0 || node->index == NO_INDEX_ASSIGNED); > > This shouldn't ever be called after we've assigned any indexes at all, > so I think it's always safe to asser that node->index == NO_INDEX_ASSIGNED. > We can also assert that the ref count should never go negative, so I think > you can rewrite this assert as: > > gcc_assert (node->refcount >= 0 && node->index == NO_INDEX_ASSIGNED); > Done. >> @@ -21215,7 +22086,7 @@ prune_unused_types_update_strings (dw_die_ref die) >> *slot = s; >> } >> } >> -} >> + } > > Accidental extra space? Yes. Fixed. >> +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) >> + { >> + /* Don't index an entry that has already been indexed >> + or won't be output. */ >> + if (curr->begin_entry != NULL >> + || (strcmp (curr->begin, curr->end) == 0 && !curr->force)) >> + continue; > > Check the indentation here -- looks like these last two lines are missing > a space. > Fixed. > > OK for trunk with these changes. Thanks! > > -cary And with that, unless anyone else (Jason?) has any more comments, I will check this in later today. Sterling
Sign in to reply to this message.
On Tue, Nov 6, 2012 at 11:21 AM, Sterling Augustine <saugustine@google.com> wrote: > On Mon, Nov 5, 2012 at 3:18 PM, Cary Coutant <ccoutant@google.com> wrote: >>> +/* %: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; >>> + >>> + if (argc != 2) >>> + fatal_error ("too few arguments to %%:replace-extension"); >>> + >>> + name = xstrdup (argv[0]); >>> + p = strrchr (name, '.'); >>> + if (p != NULL) >>> + *p = '\0'; >>> + >>> + result = concat (name, argv[1], NULL); >>> + >>> + free (name); >>> + return result; >>> +} >> >> This doesn't do the right thing when there is no '.' in the last >> component of the path. It should look for the last DIR_SEPARATOR, >> then search for the last '.' after that. > > Good catch. Fixed. > >>> +/* Describe an entry into the .debug_addr section. */ >>> + >>> +enum ate_kind { >>> + ate_kind_rtx, >>> + ate_kind_rtx_dtprel, >>> + ate_kind_label >>> +}; >>> + >>> +typedef struct GTY(()) addr_table_entry_struct { >>> + enum ate_kind kind; >>> + unsigned int refcount; >>> + unsigned int index; >>> + union addr_table_entry_struct_union >>> + { >>> + rtx GTY ((tag ("ate_kind_rtx"))) rtl; >>> + char * GTY ((tag ("ate_kind_label"))) label; >>> + } >>> + GTY ((desc ("%1.kind"))) addr; >> >> When kind == ate_kind_rtx_dtprel, we use the rtl field. I think this needs >> to be covered for GC to work. As far as I know, gengtype doesn't support >> multiple tags for one union member, so I think it needs to be something >> like this: >> >> union addr_table_entry_struct_union >> { >> rtx GTY ((tag ("0"))) rtl; >> char * GTY ((tag ("1"))) label; >> } >> GTY ((desc ("(%1.kind == ate_kind_label)"))) addr; >> > > Done. > >>> +static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *, >>> + bool); >> >> It turns out we never call add_AT_lbl_id with force_direct == true. >> I don't think it's necessary to add this parameter here. > > Done--this actually cleans up the patch quite a bit. > >>> +/* 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 >>> + }; >> >> Extra indentation here. > > Fixed. > >>> +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); >> >> Unnecessary parentheses here. > > Removed. > >>> +/* 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 if (a->dw_attr_val.val_entry != NULL) >>> + return a->dw_attr_val.val_entry->index; >>> + return NOT_INDEXED; >>> +} >> >> The comment seems out of date. DW_FORM_GNU_str_index should also be >> mentioned, and it doesn't look like strings have their indices handled >> differently (at least not here). > > Updated. > >>> +static void >>> +remove_addr_table_entry (addr_table_entry *entry) >>> +{ >>> + addr_table_entry *node; >>> + >>> + gcc_assert (dwarf_split_debug_info && addr_index_table); >>> + node = (addr_table_entry *) htab_find (addr_index_table, entry); >>> + node->refcount--; >>> + /* After an index is assigned, the table is frozen. */ >>> + gcc_assert (node->refcount > 0 || node->index == NO_INDEX_ASSIGNED); >> >> This shouldn't ever be called after we've assigned any indexes at all, >> so I think it's always safe to asser that node->index == NO_INDEX_ASSIGNED. >> We can also assert that the ref count should never go negative, so I think >> you can rewrite this assert as: >> >> gcc_assert (node->refcount >= 0 && node->index == NO_INDEX_ASSIGNED); >> > > Done. > >>> @@ -21215,7 +22086,7 @@ prune_unused_types_update_strings (dw_die_ref die) >>> *slot = s; >>> } >>> } >>> -} >>> + } >> >> Accidental extra space? > > Yes. Fixed. > >>> +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) >>> + { >>> + /* Don't index an entry that has already been indexed >>> + or won't be output. */ >>> + if (curr->begin_entry != NULL >>> + || (strcmp (curr->begin, curr->end) == 0 && !curr->force)) >>> + continue; >> >> Check the indentation here -- looks like these last two lines are missing >> a space. >> > > Fixed. >> >> OK for trunk with these changes. Thanks! >> >> -cary > > > And with that, unless anyone else (Jason?) has any more comments, I > will check this in later today. > > Sterling Committed as attached. Thanks everyone. Sterling
Sign in to reply to this message.
|