|
|
Created:
13 years, 1 month ago by Cary Modified:
13 years, 1 month ago CC:
gcc-patches_gcc.gnu.org Base URL:
svn+ssh://gcc.gnu.org/svn/gcc/branches/google/gcc-4_6/gcc/ Visibility:
Public. |
Patch Set 1 #Patch Set 2 : [google] Add -gfission support to GCC #
MessagesTotal messages: 10
Add GCC support for -gfission option. Debug info is partitioned into skeleton sections that will remain in the .o file, and "dwo" sections that will be moved to a .dwo file. After compilation, the gcc driver calls objcopy twice: once to extract the "dwo" sections into the .dwo file, and a second time to remove the sections from the .o file. For google/gcc-4_6 branch. (To be submitted for trunk soon.) Tested: bootstrap,core,mantle,crust 2012-03-09 Sterling Augustine <saugustine@google.com> Cary Coutant <ccoutant@google.com> * gcc.c (ASM_FINAL_SPEC): For -gfission, call objcopy. (static_spec_functions): Add replace-extension. (replace_extension_spec_func): New function. * dwarf2out.c (debug_skeleton_info_section) (debug_skeleton_abbrev_section, debug_ref_section, debug_addr_section) (debug_skeleton_line_section, debug_str_offsets_section): New variables. (struct indirect_string_node): Add index field. (DEBUG_DWO_INFO_SECTION, DEBUG_DWO_ABBREV_SECTION, DEBUG_REF_SECTION) (DEBUG_ADDR_SECTION, DEBUG_DWO_LINE_SECTION) (DEBUG_NORM_STR_OFFSETS_SECTION, DEBUG_DWO_STR_OFFSETS_SECTION) (DEBUG_STR_OFFSETS_SECTION, DEBUG_DWO_STR_SECTION) (DEBUG_NORM_STR_SECTION): New debug section macros. (DEBUG_STR_SECTION): Change definition for -gfission. (DEBUG_STR_SECTION_FLAGS): Don't set SECTION_MERGE for -gfission. (DEBUG_SKELETON_LINE_SECTION_LABEL, DEBUG_SKELETON_INFO_SECTION_LABEL) (DEBUG_SKELETON_ABBREV_SECTION_LABEL, DEBUG_REF_SECTION_LABEL) (DEBUG_ADDR_SECTION_LABEL): New section label macros. (SKELETON_COMP_DIE_ABBREV, SKELETON_TYPE_DIE_ABBREV): New macros. (debug_skeleton_info_section_label, debug_skeleton_abbrev_section_label) (debug_ref_section_label, debug_addr_section_label) (debug_skeleton_line_section_label): New section label variables. (dwarf_attr_name): Add new attribute names. (dwarf_form_name): Add new form names. (AT_index): New function. (set_AT_index): New function. (index_string_table): New variable. (AT_string_form): Use DW_FORM_GNU_str_index for -gfission. (add_addr_table_entry): New function. (add_AT_addr): Record index for indirect references with -gfission. (add_AT_lbl_id): Likewise. (add_ref_table_entry): New function. (add_AT_range_list): Use indirect reference for -gfission. (break_out_comdat_types): Don't add DW_AT_GNU_pubnames/pubtypes attributes here. (size_of_die): Account for indirect forms with -gfission. (value_format): Use indirect forms for -gfission. (output_die_abbrevs): New function. (output_abbrev_section): Refactor code into output_die_abbrevs. (output_range_list_offset): New function. (output_loc_list_offset): New function. (output_attr_index_or_value): New function. (output_die): Call output_attr_index_or_value to output possibly indirect forms. Output indirect strings for -gfission. (add_AT_pubnames): New function. (add_top_level_skeleton_die_attrs): New function. (skeleton_type_unit): New variable. (output_skeleton_debug_sections): New function. (output_comdat_type_unit): Write to .debug_types.dwo for -gfission. (output_pubnames): Add assembly label to beginning of section; use label for skeleton info section with -gfission. (output_aranges): Use label for skeleton info section with -gfission. (output_line_info ): Add prologue_only parameter. (dwarf2out_init): Create new sections for -gfission. (output_index_strings): New function. (output_ref_table): New function. (output_addr_table): New function. (index_location_lists): New function. (dwarf2out_finish): For -gfission, write skeleton debug sections, write pubnames tables unconditionally, and write indirect sections. * opts.c (common_handle_option): Add OPT_gfission. * common.opt: Add -gfission option. Index: gcc.c =================================================================== --- gcc.c (revision 185159) +++ gcc.c (working copy) @@ -265,6 +265,7 @@ static const char *compare_debug_dump_op 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 @@ -478,7 +479,14 @@ proper position among the other output f /* 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 \ + "%{gfission: \n\ + objcopy --extract-dwo \ + %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%g%O} \ + %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\ + objcopy --strip-dwo \ + %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%g%O} \ + }" #endif /* config.h can define CPP_SPEC to provide extra args to the C preprocessor @@ -1245,6 +1253,7 @@ static const struct spec_function static { "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 @@ -8279,3 +8288,27 @@ pass_through_libs_spec_func (int argc, c } 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: dwarf2out.c =================================================================== --- dwarf2out.c (revision 185159) +++ dwarf2out.c (working copy) @@ -225,16 +225,22 @@ static GTY(()) VEC(tree,gc) *decl_scope_ /* 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_ref_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_dcall_section; static GTY(()) section *debug_vcall_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; @@ -430,6 +436,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; @@ -4377,6 +4384,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; @@ -6277,6 +6285,8 @@ static tree decl_ultimate_origin (const_ 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); @@ -6406,6 +6416,7 @@ static unsigned long size_of_aranges (vo 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); @@ -6423,7 +6434,7 @@ static unsigned int add_ranges (const_tr static void add_ranges_by_labels (dw_die_ref, const char *, const char *, bool *); static void output_ranges (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); @@ -6561,21 +6572,37 @@ static void schedule_generic_params_dies static void gen_scheduled_generic_parms_dies (void); /* 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_REF_SECTION +#define DEBUG_REF_SECTION ".debug_ref" +#endif +#ifndef DEBUG_ADDR_SECTION +#define DEBUG_ADDR_SECTION ".debug_addr" +#endif #ifndef DEBUG_MACINFO_SECTION #define DEBUG_MACINFO_SECTION ".debug_macinfo" #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 @@ -6591,8 +6618,18 @@ static void gen_scheduled_generic_parms_ #ifndef DEBUG_VCALL_SECTION #define DEBUG_VCALL_SECTION ".debug_vcall" #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" @@ -6605,44 +6642,60 @@ static void gen_scheduled_generic_parms_ /* 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 \ + (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings && !dwarf_split_debug_info \ + ? 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_PUBNAMES_SECTION_LABEL -#define DEBUG_PUBNAMES_SECTION_LABEL "Ldebug_pubnames" +#define DEBUG_PUBNAMES_SECTION_LABEL "Ldebug_pubnames" #endif #ifndef DEBUG_PUBTYPES_SECTION_LABEL -#define DEBUG_PUBTYPES_SECTION_LABEL "Ldebug_pubtypes" +#define DEBUG_PUBTYPES_SECTION_LABEL "Ldebug_pubtypes" #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_REF_SECTION_LABEL +#define DEBUG_REF_SECTION_LABEL "Ldebug_ref" +#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 - +#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 @@ -6656,7 +6709,12 @@ static char cold_text_section_label[MAX_ 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_ref_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 debug_pubnames_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char debug_pubtypes_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; @@ -7144,6 +7202,19 @@ dwarf_attr_name (unsigned int attr) case DW_AT_GNU_template_name: return "DW_AT_GNU_template_name"; + case DW_AT_GNU_dwo_name: + return "DW_AT_GNU_dwo_name"; + case DW_AT_GNU_dwo_id: + return "DW_AT_GNU_dwo_id"; + case DW_AT_GNU_ref_base: + return "DW_AT_GNU_ref_base"; + case DW_AT_GNU_addr_base: + return "DW_AT_GNU_addr_base"; + case DW_AT_GNU_pubnames: + return "DW_AT_GNU_pubnames"; + case DW_AT_GNU_pubtypes: + return "DW_AT_GNU_pubtypes"; + case DW_AT_VMS_rtnbeg_pd_address: return "DW_AT_VMS_rtnbeg_pd_address"; @@ -7185,6 +7256,8 @@ dwarf_form_name (unsigned int form) return "DW_FORM_sdata"; case DW_FORM_strp: return "DW_FORM_strp"; + case DW_FORM_GNU_str_index: + return "DW_FORM_GNU_str_index"; case DW_FORM_udata: return "DW_FORM_udata"; case DW_FORM_ref_addr: @@ -7203,6 +7276,10 @@ dwarf_form_name (unsigned int form) return "DW_FORM_indirect"; case DW_FORM_sec_offset: return "DW_FORM_sec_offset"; + case DW_FORM_GNU_ref_index: + return "DW_FORM_GNU_ref_index"; + case DW_FORM_GNU_addr_index: + return "DW_FORM_GNU_addr_index"; case DW_FORM_exprloc: return "DW_FORM_exprloc"; case DW_FORM_flag_present: @@ -7280,6 +7357,32 @@ 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_ref_index of 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_ref_index of 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 @@ -7482,12 +7585,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; @@ -7514,7 +7625,17 @@ AT_string_form (dw_attr_ref a) gen_label_for_indirect_string (node); - 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. */ @@ -7633,6 +7754,21 @@ AT_loc_list_ptr (dw_attr_ref a) return &a->dw_attr_val.v.val_loc_list; } +/* A table of entries into the .debug_ref section. */ + +static GTY (()) VEC (dw_attr_node,gc) * addr_index_table; + +static unsigned int +add_addr_table_entry (dw_attr_node *attr) +{ + if (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; + } + return 0; +} + /* Add an address constant attribute value to a DIE. */ static inline void @@ -7644,6 +7780,8 @@ add_AT_addr (dw_die_ref die, enum dwarf_ attr.dw_attr_val.val_class = dw_val_class_addr; attr.dw_attr_val.v.val_addr = addr; add_dwarf_attr (die, &attr); + if (dwarf_split_debug_info) + set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr)); } /* Get the RTX from to an address DIE attribute. */ @@ -7704,6 +7842,8 @@ add_AT_lbl_id (dw_die_ref die, enum dwar attr.dw_attr_val.val_class = dw_val_class_lbl_id; attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id); add_dwarf_attr (die, &attr); + if (dwarf_split_debug_info) + 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 @@ -7750,6 +7890,21 @@ add_AT_offset (dw_die_ref die, enum dwar add_dwarf_attr (die, &attr); } +/* A table of entries into the .debug_ref section. */ + +static GTY (()) VEC (dw_attr_node,gc) * ref_index_table; + +static unsigned int +add_ref_table_entry (dw_attr_node *attr) +{ + if (dwarf_split_debug_info) + { + VEC_safe_push (dw_attr_node, gc, ref_index_table, attr); + return VEC_length (dw_attr_node, ref_index_table) - 1; + } + return 0; +} + /* Add an range_list attribute value to a DIE. */ static void @@ -7762,6 +7917,14 @@ add_AT_range_list (dw_die_ref die, enum attr.dw_attr_val.val_class = dw_val_class_range_list; attr.dw_attr_val.v.val_offset = offset; add_dwarf_attr (die, &attr); + if (dwarf_split_debug_info) + { + /* There will be two copies of the attr, one in the die, and one in the + ref table. Substitute the index for the actual offset in the die, and + save the actual offset in the ref table. */ + get_AT (die, DW_AT_ranges)->dw_attr_val.v.val_offset + = add_ref_table_entry (&attr); + } } /* Return the start label of a delta attribute. */ @@ -10318,15 +10481,6 @@ break_out_comdat_types (dw_die_ref die) type_node->root_die = unit; type_node->next = comdat_type_list; comdat_type_list = type_node; - if (targetm.want_debug_pub_sections) - { - /* FIXME: Should use add_AT_pubnamesptr. This works because most - targets don't care what the base section is. */ - add_AT_lineptr (unit, DW_AT_GNU_pubnames, - debug_pubnames_section_label); - add_AT_lineptr (unit, DW_AT_GNU_pubtypes, - debug_pubtypes_section_label); - } /* Generate the type signature. */ generate_type_signature (c, type_node); @@ -10718,6 +10872,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) @@ -10725,7 +10880,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) + size += size_of_uleb128 (AT_index (a)); + else + size += DWARF2_ADDR_SIZE; break; case dw_val_class_offset: size += DWARF_OFFSET_SIZE; @@ -10743,10 +10901,16 @@ size_of_die (dw_die_ref die) } break; case dw_val_class_loc_list: - size += DWARF_OFFSET_SIZE; + if (dwarf_split_debug_info) + size += size_of_uleb128 (AT_index (a)); + else + size += DWARF_OFFSET_SIZE; break; case dw_val_class_range_list: - size += DWARF_OFFSET_SIZE; + if (dwarf_split_debug_info) + size += size_of_uleb128 (a->dw_attr_val.v.val_offset); + else + size += DWARF_OFFSET_SIZE; break; case dw_val_class_const: size += size_of_sleb128 (AT_int (a)); @@ -10806,15 +10970,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) + 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; @@ -10965,7 +11135,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. */ @@ -10975,7 +11145,7 @@ 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 ? DW_FORM_GNU_addr_index : DW_FORM_addr; default: break; } @@ -10994,6 +11164,8 @@ value_format (dw_attr_ref a) } case dw_val_class_range_list: case dw_val_class_loc_list: + if (dwarf_split_debug_info) + return DW_FORM_GNU_ref_index; if (dwarf_version >= 4) return DW_FORM_sec_offset; /* FALLTHRU */ @@ -11091,7 +11263,7 @@ 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 ? 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; @@ -11128,40 +11300,46 @@ output_value_format (dw_attr_ref a) dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form)); } -/* Output the .debug_abbrev section which defines the DIE abbreviation - table. */ +/* Given a die and id, produce the appropriate abbreviations. */ static void -output_abbrev_section (void) +output_die_abbrevs (unsigned long abbrev_id, dw_die_ref abbrev) { - unsigned long abbrev_id; + unsigned ix; + dw_attr_ref a_attr; - for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++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++) { - dw_die_ref abbrev = abbrev_die_table[abbrev_id]; - unsigned ix; - dw_attr_ref a_attr; + 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_uleb128 (abbrev_id, "(abbrev code)"); - dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)", - dwarf_tag_name (abbrev->die_tag)); + dw2_asm_output_data (1, 0, NULL); + dw2_asm_output_data (1, 0, NULL); +} - 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); - } +/* Output the .debug_abbrev section which defines the DIE abbreviation + table. */ - dw2_asm_output_data (1, 0, NULL); - dw2_asm_output_data (1, 0, NULL); - } +static void +output_abbrev_section (void) +{ + unsigned long abbrev_id; + + for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) + output_die_abbrevs (abbrev_id, abbrev_die_table[abbrev_id]); /* Terminate the table. */ dw2_asm_output_data (1, 0, NULL); @@ -11274,6 +11452,63 @@ output_loc_list (dw_loc_list_ref list_he list_head->ll_symbol); } +/* Output the offset into the debug_range section. */ + +static void +output_range_list_offset (dw_attr_ref a) +{ + char *p = strchr (ranges_section_label, '\0'); + const char *name = dwarf_attr_name (a->dw_attr); + + 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 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); + 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) + { + 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; + case dw_val_class_range_list: + output_range_list_offset (a); + break; + default: + gcc_unreachable (); + } +} + /* Output a type signature. */ static inline void @@ -11312,7 +11547,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: @@ -11321,15 +11556,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_attr_index_or_value (a); break; case dw_val_class_loc: @@ -11432,13 +11659,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: @@ -11495,7 +11716,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: @@ -11509,12 +11730,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; @@ -11626,6 +11850,118 @@ output_comp_unit (dw_die_ref die, int ou } } +/* Add the DW_AT_GNU_pubnames and DW_AT_GNU_pubtypes attributes. */ + +static void +add_AT_pubnames (dw_die_ref die) +{ + /* FIXME: Should use add_AT_pubnamesptr. This works because most targets + don't care what the base section is. */ + add_AT_lineptr (die, DW_AT_GNU_pubnames, debug_pubnames_section_label); + add_AT_lineptr (die, DW_AT_GNU_pubtypes, debug_pubtypes_section_label); +} + +/* 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) +{ + /* The splitter will fill in the file name. It would be good to allocate + a fairly large string here to make it easy for the splitter though. */ + const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL); + dw_attr_ref attr; + + add_AT_lineptr (die, DW_AT_stmt_list, debug_line_section_label); + 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; + /* The post compile splitter will fill in this value. */ + add_AT_pubnames (die); + add_AT_lineptr (die, DW_AT_GNU_ref_base, debug_ref_section_label); + add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label); +} + +/* 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; + +/* 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 (void) +{ + dw_die_ref comp_unit = gen_compile_unit_die (NULL); + + /* 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_top_level_skeleton_die_attrs (comp_unit); + /* Only the compilation unit gets the dwo_id. */ + add_AT_data8 (comp_unit, DW_AT_GNU_dwo_id, dwo_id_placeholder); + + switch_to_section (debug_skeleton_info_section); + ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label, + DEBUG_SKELETON_INFO_SECTION_LABEL, 0); + 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"); + + /* 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 (comp_unit) + 1, + "Length of Compilation Unit Info"); + dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label, + DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0); + 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); + + dw2_asm_output_data (1, 0, "end of skeleton .debug_info"); + + /* 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 (dwarf_version >= 4) + { + /* Because all skeleton type_units have identical dies, just generate + one, and output it repeatedly. */ + 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; + output_die_abbrevs (SKELETON_TYPE_DIE_ABBREV, 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 @@ -11648,7 +11984,11 @@ output_comdat_type_unit (comdat_type_nod 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++) @@ -11657,6 +11997,7 @@ output_comdat_type_unit (comdat_type_nod 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."); @@ -11674,6 +12015,39 @@ output_comdat_type_unit (comdat_type_nod 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"; + gcc_assert (skeleton_type_unit); + + 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 (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 (skeleton_type_unit); + /* dw2_asm_output_data (1, 0, "end of skeleton .debug_types"); */ + } } /* Return the DWARF2/3 pubname associated with a decl. */ @@ -11710,6 +12084,7 @@ add_pubname (tree decl, dw_die_ref die) || 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); } @@ -11822,9 +12197,14 @@ output_pubnames (VEC (pubname_entry, gc) "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"); @@ -11864,9 +12244,14 @@ output_aranges (unsigned long aranges_le "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"); @@ -12416,7 +12801,7 @@ output_file_names (void) 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]; char line_label[MAX_ARTIFICIAL_LABEL_BYTES]; @@ -12493,6 +12878,12 @@ output_line_info (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; + } /* We used to set the address register to the first location in the text section here, but that didn't accomplish anything since we already @@ -22544,10 +22935,37 @@ dwarf2out_init (const char *filename ATT 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); + } + else + { + debug_info_section = get_section (DEBUG_DWO_INFO_SECTION, + SECTION_DEBUG, NULL); + debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION, + SECTION_DEBUG, NULL); + debug_ref_section = get_section (DEBUG_REF_SECTION, + SECTION_DEBUG, 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); + + /* 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, 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, NULL); + } debug_aranges_section = get_section (DEBUG_ARANGES_SECTION, SECTION_DEBUG, NULL); debug_macinfo_section = get_section (DEBUG_MACINFO_SECTION, @@ -22565,7 +22983,7 @@ dwarf2out_init (const char *filename ATT debug_vcall_section = get_section (DEBUG_VCALL_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, @@ -22589,6 +23007,10 @@ dwarf2out_init (const char *filename ATT DEBUG_LINE_SECTION_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (ranges_section_label, DEBUG_RANGES_SECTION_LABEL, 0); + ASM_GENERATE_INTERNAL_LABEL (debug_ref_section_label, + DEBUG_REF_SECTION_LABEL, 0); + ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label, + DEBUG_ADDR_SECTION_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label, DEBUG_MACINFO_SECTION_LABEL, 0); @@ -22630,6 +23052,87 @@ output_indirect_string (void **h, void * 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 refs table. */ + +static void +output_ref_table (void) +{ + unsigned int i; + dw_attr_node *node; + + if (VEC_empty (dw_attr_node, ref_index_table)) + return; + + switch_to_section (debug_ref_section); + for (i = 0; VEC_iterate (dw_attr_node, ref_index_table, i, node); i++) + { + if (AT_class (node) == dw_val_class_range_list) + output_range_list_offset (node); + else if (AT_class (node) == dw_val_class_loc_list) + output_loc_list_offset (node); + else + gcc_unreachable (); + } +} + +/* 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 = 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_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. */ @@ -23600,6 +24103,24 @@ 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_ref + 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) + set_AT_index (a, add_ref_table_entry (a)); + + FOR_EACH_CHILD (die, c, index_location_lists (c)); +} /* Output stuff that dwarf requires at the end of every file, @@ -23814,7 +24335,19 @@ dwarf2out_finish (const char *filename) add_AT_macptr (comp_unit_die (), DW_AT_macro_info, macinfo_section_label); if (have_location_lists) - optimize_location_lists (comp_unit_die ()); + { + optimize_location_lists (comp_unit_die ()); + index_location_lists (comp_unit_die ()); + } + + if (dwarf_split_debug_info) + { + /* Add a place-holder for the dwo_id to the comp-unit die. Similarly, the + skeleton die gets a placeholder inside + output_skeleton_debug_sections. */ + add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, dwo_id_placeholder); + output_skeleton_debug_sections (); + } /* Output all of the compilation units. We put the main one last so that the offsets are available to output_pubnames. */ @@ -23835,23 +24368,17 @@ dwarf2out_finish (const char *filename) attributes. */ if (generate_debug_line_table) 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 the DW_AT_GNU_pubnames and DW_AT_GNU_pubtypes attributes. */ - if (targetm.want_debug_pub_sections) - { - /* FIXME: Should use add_AT_pubnamesptr. This works because most targets - don't care what the base section is. */ - add_AT_lineptr (comp_unit_die (), DW_AT_GNU_pubnames, - debug_pubnames_section_label); - add_AT_lineptr (comp_unit_die (), DW_AT_GNU_pubtypes, - debug_pubtypes_section_label); - } + if (!dwarf_split_debug_info) + add_AT_pubnames (comp_unit_die ()); /* Output the main compilation unit if non-empty or if .debug_macinfo will be emitted. */ @@ -23926,7 +24453,7 @@ 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); /* Have to end the macro section. */ if (debug_info_level >= DINFO_LEVEL_VERBOSE) @@ -23938,8 +24465,24 @@ dwarf2out_finish (const char *filename) dw2_asm_output_data (1, 0, "End compilation unit"); } - /* If we emitted any DW_FORM_strp form attribute, output the string - table too. */ + if (dwarf_split_debug_info) + { + 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_ref_section); + ASM_OUTPUT_LABEL (asm_out_file, debug_ref_section_label); + output_ref_table (); + + 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: opts.c =================================================================== --- opts.c (revision 185159) +++ opts.c (working copy) @@ -1707,6 +1707,11 @@ common_handle_option (struct gcc_options set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc); break; + case OPT_gfission: + set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, arg, opts, opts_set, + loc); + break; + case OPT_ggdb: set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc); break; Index: common.opt =================================================================== --- common.opt (revision 185159) +++ common.opt (working copy) @@ -2333,6 +2333,10 @@ gdwarf- Common Joined UInteger Var(dwarf_version) Init(2) Negative(gstabs) Generate debug information in DWARF v2 (or later) format +gfission +Common Driver JoinedOrMissing Var(dwarf_split_debug_info,1) +Generate debug information in separate .dwo files + ggdb Common JoinedOrMissing Generate debug information in default extended format -- This patch is available for review at http://codereview.appspot.com/5754090
Sign in to reply to this message.
[Revised patch to fix problem with ASM_FINAL_SPEC in the case where neither -c nor -o are specified.] Add GCC support for -gfission option. Debug info is partitioned into skeleton sections that will remain in the .o file, and "dwo" sections that will be moved to a .dwo file. After compilation, the gcc driver calls objcopy twice: once to extract the "dwo" sections into the .dwo file, and a second time to remove the sections from the .o file. For google/gcc-4_6 branch. (To be submitted for trunk soon.) Tested: bootstrap,core,mantle,crust 2012-03-09 Sterling Augustine <saugustine@google.com> Cary Coutant <ccoutant@google.com> * gcc.c (ASM_FINAL_SPEC): For -gfission, call objcopy. (static_spec_functions): Add replace-extension. (replace_extension_spec_func): New function. * dwarf2out.c (debug_skeleton_info_section) (debug_skeleton_abbrev_section, debug_ref_section, debug_addr_section) (debug_skeleton_line_section, debug_str_offsets_section): New variables. (struct indirect_string_node): Add index field. (DEBUG_DWO_INFO_SECTION, DEBUG_DWO_ABBREV_SECTION, DEBUG_REF_SECTION) (DEBUG_ADDR_SECTION, DEBUG_DWO_LINE_SECTION) (DEBUG_NORM_STR_OFFSETS_SECTION, DEBUG_DWO_STR_OFFSETS_SECTION) (DEBUG_STR_OFFSETS_SECTION, DEBUG_DWO_STR_SECTION) (DEBUG_NORM_STR_SECTION): New debug section macros. (DEBUG_STR_SECTION): Change definition for -gfission. (DEBUG_STR_SECTION_FLAGS): Don't set SECTION_MERGE for -gfission. (DEBUG_SKELETON_LINE_SECTION_LABEL, DEBUG_SKELETON_INFO_SECTION_LABEL) (DEBUG_SKELETON_ABBREV_SECTION_LABEL, DEBUG_REF_SECTION_LABEL) (DEBUG_ADDR_SECTION_LABEL): New section label macros. (SKELETON_COMP_DIE_ABBREV, SKELETON_TYPE_DIE_ABBREV): New macros. (debug_skeleton_info_section_label, debug_skeleton_abbrev_section_label) (debug_ref_section_label, debug_addr_section_label) (debug_skeleton_line_section_label): New section label variables. (dwarf_attr_name): Add new attribute names. (dwarf_form_name): Add new form names. (AT_index): New function. (set_AT_index): New function. (index_string_table): New variable. (AT_string_form): Use DW_FORM_GNU_str_index for -gfission. (add_addr_table_entry): New function. (add_AT_addr): Record index for indirect references with -gfission. (add_AT_lbl_id): Likewise. (add_ref_table_entry): New function. (add_AT_range_list): Use indirect reference for -gfission. (break_out_comdat_types): Don't add DW_AT_GNU_pubnames/pubtypes attributes here. (size_of_die): Account for indirect forms with -gfission. (value_format): Use indirect forms for -gfission. (output_die_abbrevs): New function. (output_abbrev_section): Refactor code into output_die_abbrevs. (output_range_list_offset): New function. (output_loc_list_offset): New function. (output_attr_index_or_value): New function. (output_die): Call output_attr_index_or_value to output possibly indirect forms. Output indirect strings for -gfission. (add_AT_pubnames): New function. (add_top_level_skeleton_die_attrs): New function. (skeleton_type_unit): New variable. (output_skeleton_debug_sections): New function. (output_comdat_type_unit): Write to .debug_types.dwo for -gfission. (output_pubnames): Add assembly label to beginning of section; use label for skeleton info section with -gfission. (output_aranges): Use label for skeleton info section with -gfission. (output_line_info ): Add prologue_only parameter. (dwarf2out_init): Create new sections for -gfission. (output_index_strings): New function. (output_ref_table): New function. (output_addr_table): New function. (index_location_lists): New function. (dwarf2out_finish): For -gfission, write skeleton debug sections, write pubnames tables unconditionally, and write indirect sections. * opts.c (common_handle_option): Add OPT_gfission. * common.opt: Add -gfission option. Index: gcc.c =================================================================== --- gcc.c (revision 185159) +++ gcc.c (working copy) @@ -265,6 +265,7 @@ static const char *compare_debug_dump_op 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 @@ -478,7 +479,14 @@ proper position among the other output f /* 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 \ + "%{gfission: \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 @@ -1245,6 +1253,7 @@ static const struct spec_function static { "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 @@ -8279,3 +8288,27 @@ pass_through_libs_spec_func (int argc, c } 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: dwarf2out.c =================================================================== --- dwarf2out.c (revision 185159) +++ dwarf2out.c (working copy) @@ -225,16 +225,22 @@ static GTY(()) VEC(tree,gc) *decl_scope_ /* 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_ref_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_dcall_section; static GTY(()) section *debug_vcall_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; @@ -430,6 +436,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; @@ -4377,6 +4384,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; @@ -6277,6 +6285,8 @@ static tree decl_ultimate_origin (const_ 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); @@ -6406,6 +6416,7 @@ static unsigned long size_of_aranges (vo 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); @@ -6423,7 +6434,7 @@ static unsigned int add_ranges (const_tr static void add_ranges_by_labels (dw_die_ref, const char *, const char *, bool *); static void output_ranges (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); @@ -6561,21 +6572,37 @@ static void schedule_generic_params_dies static void gen_scheduled_generic_parms_dies (void); /* 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_REF_SECTION +#define DEBUG_REF_SECTION ".debug_ref" +#endif +#ifndef DEBUG_ADDR_SECTION +#define DEBUG_ADDR_SECTION ".debug_addr" +#endif #ifndef DEBUG_MACINFO_SECTION #define DEBUG_MACINFO_SECTION ".debug_macinfo" #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 @@ -6591,8 +6618,18 @@ static void gen_scheduled_generic_parms_ #ifndef DEBUG_VCALL_SECTION #define DEBUG_VCALL_SECTION ".debug_vcall" #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" @@ -6605,44 +6642,60 @@ static void gen_scheduled_generic_parms_ /* 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 \ + (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings && !dwarf_split_debug_info \ + ? 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_PUBNAMES_SECTION_LABEL -#define DEBUG_PUBNAMES_SECTION_LABEL "Ldebug_pubnames" +#define DEBUG_PUBNAMES_SECTION_LABEL "Ldebug_pubnames" #endif #ifndef DEBUG_PUBTYPES_SECTION_LABEL -#define DEBUG_PUBTYPES_SECTION_LABEL "Ldebug_pubtypes" +#define DEBUG_PUBTYPES_SECTION_LABEL "Ldebug_pubtypes" #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_REF_SECTION_LABEL +#define DEBUG_REF_SECTION_LABEL "Ldebug_ref" +#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 - +#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 @@ -6656,7 +6709,12 @@ static char cold_text_section_label[MAX_ 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_ref_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 debug_pubnames_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char debug_pubtypes_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; @@ -7144,6 +7202,19 @@ dwarf_attr_name (unsigned int attr) case DW_AT_GNU_template_name: return "DW_AT_GNU_template_name"; + case DW_AT_GNU_dwo_name: + return "DW_AT_GNU_dwo_name"; + case DW_AT_GNU_dwo_id: + return "DW_AT_GNU_dwo_id"; + case DW_AT_GNU_ref_base: + return "DW_AT_GNU_ref_base"; + case DW_AT_GNU_addr_base: + return "DW_AT_GNU_addr_base"; + case DW_AT_GNU_pubnames: + return "DW_AT_GNU_pubnames"; + case DW_AT_GNU_pubtypes: + return "DW_AT_GNU_pubtypes"; + case DW_AT_VMS_rtnbeg_pd_address: return "DW_AT_VMS_rtnbeg_pd_address"; @@ -7185,6 +7256,8 @@ dwarf_form_name (unsigned int form) return "DW_FORM_sdata"; case DW_FORM_strp: return "DW_FORM_strp"; + case DW_FORM_GNU_str_index: + return "DW_FORM_GNU_str_index"; case DW_FORM_udata: return "DW_FORM_udata"; case DW_FORM_ref_addr: @@ -7203,6 +7276,10 @@ dwarf_form_name (unsigned int form) return "DW_FORM_indirect"; case DW_FORM_sec_offset: return "DW_FORM_sec_offset"; + case DW_FORM_GNU_ref_index: + return "DW_FORM_GNU_ref_index"; + case DW_FORM_GNU_addr_index: + return "DW_FORM_GNU_addr_index"; case DW_FORM_exprloc: return "DW_FORM_exprloc"; case DW_FORM_flag_present: @@ -7280,6 +7357,32 @@ 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_ref_index of 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_ref_index of 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 @@ -7482,12 +7585,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; @@ -7514,7 +7625,17 @@ AT_string_form (dw_attr_ref a) gen_label_for_indirect_string (node); - 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. */ @@ -7633,6 +7754,21 @@ AT_loc_list_ptr (dw_attr_ref a) return &a->dw_attr_val.v.val_loc_list; } +/* A table of entries into the .debug_ref section. */ + +static GTY (()) VEC (dw_attr_node,gc) * addr_index_table; + +static unsigned int +add_addr_table_entry (dw_attr_node *attr) +{ + if (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; + } + return 0; +} + /* Add an address constant attribute value to a DIE. */ static inline void @@ -7644,6 +7780,8 @@ add_AT_addr (dw_die_ref die, enum dwarf_ attr.dw_attr_val.val_class = dw_val_class_addr; attr.dw_attr_val.v.val_addr = addr; add_dwarf_attr (die, &attr); + if (dwarf_split_debug_info) + set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr)); } /* Get the RTX from to an address DIE attribute. */ @@ -7704,6 +7842,8 @@ add_AT_lbl_id (dw_die_ref die, enum dwar attr.dw_attr_val.val_class = dw_val_class_lbl_id; attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id); add_dwarf_attr (die, &attr); + if (dwarf_split_debug_info) + 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 @@ -7750,6 +7890,21 @@ add_AT_offset (dw_die_ref die, enum dwar add_dwarf_attr (die, &attr); } +/* A table of entries into the .debug_ref section. */ + +static GTY (()) VEC (dw_attr_node,gc) * ref_index_table; + +static unsigned int +add_ref_table_entry (dw_attr_node *attr) +{ + if (dwarf_split_debug_info) + { + VEC_safe_push (dw_attr_node, gc, ref_index_table, attr); + return VEC_length (dw_attr_node, ref_index_table) - 1; + } + return 0; +} + /* Add an range_list attribute value to a DIE. */ static void @@ -7762,6 +7917,14 @@ add_AT_range_list (dw_die_ref die, enum attr.dw_attr_val.val_class = dw_val_class_range_list; attr.dw_attr_val.v.val_offset = offset; add_dwarf_attr (die, &attr); + if (dwarf_split_debug_info) + { + /* There will be two copies of the attr, one in the die, and one in the + ref table. Substitute the index for the actual offset in the die, and + save the actual offset in the ref table. */ + get_AT (die, DW_AT_ranges)->dw_attr_val.v.val_offset + = add_ref_table_entry (&attr); + } } /* Return the start label of a delta attribute. */ @@ -10318,15 +10481,6 @@ break_out_comdat_types (dw_die_ref die) type_node->root_die = unit; type_node->next = comdat_type_list; comdat_type_list = type_node; - if (targetm.want_debug_pub_sections) - { - /* FIXME: Should use add_AT_pubnamesptr. This works because most - targets don't care what the base section is. */ - add_AT_lineptr (unit, DW_AT_GNU_pubnames, - debug_pubnames_section_label); - add_AT_lineptr (unit, DW_AT_GNU_pubtypes, - debug_pubtypes_section_label); - } /* Generate the type signature. */ generate_type_signature (c, type_node); @@ -10718,6 +10872,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) @@ -10725,7 +10880,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) + size += size_of_uleb128 (AT_index (a)); + else + size += DWARF2_ADDR_SIZE; break; case dw_val_class_offset: size += DWARF_OFFSET_SIZE; @@ -10743,10 +10901,16 @@ size_of_die (dw_die_ref die) } break; case dw_val_class_loc_list: - size += DWARF_OFFSET_SIZE; + if (dwarf_split_debug_info) + size += size_of_uleb128 (AT_index (a)); + else + size += DWARF_OFFSET_SIZE; break; case dw_val_class_range_list: - size += DWARF_OFFSET_SIZE; + if (dwarf_split_debug_info) + size += size_of_uleb128 (a->dw_attr_val.v.val_offset); + else + size += DWARF_OFFSET_SIZE; break; case dw_val_class_const: size += size_of_sleb128 (AT_int (a)); @@ -10806,15 +10970,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) + 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; @@ -10965,7 +11135,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. */ @@ -10975,7 +11145,7 @@ 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 ? DW_FORM_GNU_addr_index : DW_FORM_addr; default: break; } @@ -10994,6 +11164,8 @@ value_format (dw_attr_ref a) } case dw_val_class_range_list: case dw_val_class_loc_list: + if (dwarf_split_debug_info) + return DW_FORM_GNU_ref_index; if (dwarf_version >= 4) return DW_FORM_sec_offset; /* FALLTHRU */ @@ -11091,7 +11263,7 @@ 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 ? 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; @@ -11128,40 +11300,46 @@ output_value_format (dw_attr_ref a) dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form)); } -/* Output the .debug_abbrev section which defines the DIE abbreviation - table. */ +/* Given a die and id, produce the appropriate abbreviations. */ static void -output_abbrev_section (void) +output_die_abbrevs (unsigned long abbrev_id, dw_die_ref abbrev) { - unsigned long abbrev_id; + unsigned ix; + dw_attr_ref a_attr; - for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++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++) { - dw_die_ref abbrev = abbrev_die_table[abbrev_id]; - unsigned ix; - dw_attr_ref a_attr; + 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_uleb128 (abbrev_id, "(abbrev code)"); - dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)", - dwarf_tag_name (abbrev->die_tag)); + dw2_asm_output_data (1, 0, NULL); + dw2_asm_output_data (1, 0, NULL); +} - 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); - } +/* Output the .debug_abbrev section which defines the DIE abbreviation + table. */ - dw2_asm_output_data (1, 0, NULL); - dw2_asm_output_data (1, 0, NULL); - } +static void +output_abbrev_section (void) +{ + unsigned long abbrev_id; + + for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) + output_die_abbrevs (abbrev_id, abbrev_die_table[abbrev_id]); /* Terminate the table. */ dw2_asm_output_data (1, 0, NULL); @@ -11274,6 +11452,63 @@ output_loc_list (dw_loc_list_ref list_he list_head->ll_symbol); } +/* Output the offset into the debug_range section. */ + +static void +output_range_list_offset (dw_attr_ref a) +{ + char *p = strchr (ranges_section_label, '\0'); + const char *name = dwarf_attr_name (a->dw_attr); + + 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 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); + 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) + { + 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; + case dw_val_class_range_list: + output_range_list_offset (a); + break; + default: + gcc_unreachable (); + } +} + /* Output a type signature. */ static inline void @@ -11312,7 +11547,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: @@ -11321,15 +11556,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_attr_index_or_value (a); break; case dw_val_class_loc: @@ -11432,13 +11659,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: @@ -11495,7 +11716,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: @@ -11509,12 +11730,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; @@ -11626,6 +11850,118 @@ output_comp_unit (dw_die_ref die, int ou } } +/* Add the DW_AT_GNU_pubnames and DW_AT_GNU_pubtypes attributes. */ + +static void +add_AT_pubnames (dw_die_ref die) +{ + /* FIXME: Should use add_AT_pubnamesptr. This works because most targets + don't care what the base section is. */ + add_AT_lineptr (die, DW_AT_GNU_pubnames, debug_pubnames_section_label); + add_AT_lineptr (die, DW_AT_GNU_pubtypes, debug_pubtypes_section_label); +} + +/* 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) +{ + /* The splitter will fill in the file name. It would be good to allocate + a fairly large string here to make it easy for the splitter though. */ + const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL); + dw_attr_ref attr; + + add_AT_lineptr (die, DW_AT_stmt_list, debug_line_section_label); + 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; + /* The post compile splitter will fill in this value. */ + add_AT_pubnames (die); + add_AT_lineptr (die, DW_AT_GNU_ref_base, debug_ref_section_label); + add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label); +} + +/* 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; + +/* 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 (void) +{ + dw_die_ref comp_unit = gen_compile_unit_die (NULL); + + /* 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_top_level_skeleton_die_attrs (comp_unit); + /* Only the compilation unit gets the dwo_id. */ + add_AT_data8 (comp_unit, DW_AT_GNU_dwo_id, dwo_id_placeholder); + + switch_to_section (debug_skeleton_info_section); + ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label, + DEBUG_SKELETON_INFO_SECTION_LABEL, 0); + 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"); + + /* 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 (comp_unit) + 1, + "Length of Compilation Unit Info"); + dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label, + DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0); + 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); + + dw2_asm_output_data (1, 0, "end of skeleton .debug_info"); + + /* 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 (dwarf_version >= 4) + { + /* Because all skeleton type_units have identical dies, just generate + one, and output it repeatedly. */ + 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; + output_die_abbrevs (SKELETON_TYPE_DIE_ABBREV, 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 @@ -11648,7 +11984,11 @@ output_comdat_type_unit (comdat_type_nod 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++) @@ -11657,6 +11997,7 @@ output_comdat_type_unit (comdat_type_nod 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."); @@ -11674,6 +12015,39 @@ output_comdat_type_unit (comdat_type_nod 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"; + gcc_assert (skeleton_type_unit); + + 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 (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 (skeleton_type_unit); + /* dw2_asm_output_data (1, 0, "end of skeleton .debug_types"); */ + } } /* Return the DWARF2/3 pubname associated with a decl. */ @@ -11710,6 +12084,7 @@ add_pubname (tree decl, dw_die_ref die) || 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); } @@ -11822,9 +12197,14 @@ output_pubnames (VEC (pubname_entry, gc) "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"); @@ -11864,9 +12244,14 @@ output_aranges (unsigned long aranges_le "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"); @@ -12416,7 +12801,7 @@ output_file_names (void) 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]; char line_label[MAX_ARTIFICIAL_LABEL_BYTES]; @@ -12493,6 +12878,12 @@ output_line_info (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; + } /* We used to set the address register to the first location in the text section here, but that didn't accomplish anything since we already @@ -22544,10 +22935,37 @@ dwarf2out_init (const char *filename ATT 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); + } + else + { + debug_info_section = get_section (DEBUG_DWO_INFO_SECTION, + SECTION_DEBUG, NULL); + debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION, + SECTION_DEBUG, NULL); + debug_ref_section = get_section (DEBUG_REF_SECTION, + SECTION_DEBUG, 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); + + /* 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, 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, NULL); + } debug_aranges_section = get_section (DEBUG_ARANGES_SECTION, SECTION_DEBUG, NULL); debug_macinfo_section = get_section (DEBUG_MACINFO_SECTION, @@ -22565,7 +22983,7 @@ dwarf2out_init (const char *filename ATT debug_vcall_section = get_section (DEBUG_VCALL_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, @@ -22589,6 +23007,10 @@ dwarf2out_init (const char *filename ATT DEBUG_LINE_SECTION_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (ranges_section_label, DEBUG_RANGES_SECTION_LABEL, 0); + ASM_GENERATE_INTERNAL_LABEL (debug_ref_section_label, + DEBUG_REF_SECTION_LABEL, 0); + ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label, + DEBUG_ADDR_SECTION_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label, DEBUG_MACINFO_SECTION_LABEL, 0); @@ -22630,6 +23052,87 @@ output_indirect_string (void **h, void * 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 refs table. */ + +static void +output_ref_table (void) +{ + unsigned int i; + dw_attr_node *node; + + if (VEC_empty (dw_attr_node, ref_index_table)) + return; + + switch_to_section (debug_ref_section); + for (i = 0; VEC_iterate (dw_attr_node, ref_index_table, i, node); i++) + { + if (AT_class (node) == dw_val_class_range_list) + output_range_list_offset (node); + else if (AT_class (node) == dw_val_class_loc_list) + output_loc_list_offset (node); + else + gcc_unreachable (); + } +} + +/* 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 = 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_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. */ @@ -23600,6 +24103,24 @@ 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_ref + 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) + set_AT_index (a, add_ref_table_entry (a)); + + FOR_EACH_CHILD (die, c, index_location_lists (c)); +} /* Output stuff that dwarf requires at the end of every file, @@ -23814,7 +24335,19 @@ dwarf2out_finish (const char *filename) add_AT_macptr (comp_unit_die (), DW_AT_macro_info, macinfo_section_label); if (have_location_lists) - optimize_location_lists (comp_unit_die ()); + { + optimize_location_lists (comp_unit_die ()); + index_location_lists (comp_unit_die ()); + } + + if (dwarf_split_debug_info) + { + /* Add a place-holder for the dwo_id to the comp-unit die. Similarly, the + skeleton die gets a placeholder inside + output_skeleton_debug_sections. */ + add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, dwo_id_placeholder); + output_skeleton_debug_sections (); + } /* Output all of the compilation units. We put the main one last so that the offsets are available to output_pubnames. */ @@ -23835,23 +24368,17 @@ dwarf2out_finish (const char *filename) attributes. */ if (generate_debug_line_table) 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 the DW_AT_GNU_pubnames and DW_AT_GNU_pubtypes attributes. */ - if (targetm.want_debug_pub_sections) - { - /* FIXME: Should use add_AT_pubnamesptr. This works because most targets - don't care what the base section is. */ - add_AT_lineptr (comp_unit_die (), DW_AT_GNU_pubnames, - debug_pubnames_section_label); - add_AT_lineptr (comp_unit_die (), DW_AT_GNU_pubtypes, - debug_pubtypes_section_label); - } + if (!dwarf_split_debug_info) + add_AT_pubnames (comp_unit_die ()); /* Output the main compilation unit if non-empty or if .debug_macinfo will be emitted. */ @@ -23926,7 +24453,7 @@ 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); /* Have to end the macro section. */ if (debug_info_level >= DINFO_LEVEL_VERBOSE) @@ -23938,8 +24465,24 @@ dwarf2out_finish (const char *filename) dw2_asm_output_data (1, 0, "End compilation unit"); } - /* If we emitted any DW_FORM_strp form attribute, output the string - table too. */ + if (dwarf_split_debug_info) + { + 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_ref_section); + ASM_OUTPUT_LABEL (asm_out_file, debug_ref_section_label); + output_ref_table (); + + 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: opts.c =================================================================== --- opts.c (revision 185159) +++ opts.c (working copy) @@ -1707,6 +1707,11 @@ common_handle_option (struct gcc_options set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc); break; + case OPT_gfission: + set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, arg, opts, opts_set, + loc); + break; + case OPT_ggdb: set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc); break; Index: common.opt =================================================================== --- common.opt (revision 185159) +++ common.opt (working copy) @@ -2333,6 +2333,10 @@ gdwarf- Common Joined UInteger Var(dwarf_version) Init(2) Negative(gstabs) Generate debug information in DWARF v2 (or later) format +gfission +Common Driver JoinedOrMissing Var(dwarf_split_debug_info,1) +Generate debug information in separate .dwo files + ggdb Common JoinedOrMissing Generate debug information in default extended format -- This patch is available for review at http://codereview.appspot.com/5754090
Sign in to reply to this message.
On 2012/03/12 21:32:46, Cary wrote: > [Revised patch to fix problem with ASM_FINAL_SPEC in the case where > neither -c nor -o are specified.] > > Add GCC support for -gfission option. Debug info is partitioned > into skeleton sections that will remain in the .o file, and "dwo" > sections that will be moved to a .dwo file. After compilation, > the gcc driver calls objcopy twice: once to extract the "dwo" > sections into the .dwo file, and a second time to remove the > sections from the .o file. > > For google/gcc-4_6 branch. (To be submitted for trunk soon.) I approve for google/gcc-4_6. Sterling
Sign in to reply to this message.
> For google/gcc-4_6 branch. (To be submitted for trunk soon.) The option name sounds like the brainchild of the marketing department. :-) Can we avoid going nuclear in the compiler and use something more mundane? -- Eric Botcazou
Sign in to reply to this message.
On 13/03/12 04:14 , Eric Botcazou wrote: >> For google/gcc-4_6 branch. (To be submitted for trunk soon.) > > The option name sounds like the brainchild of the marketing department. :-) > Can we avoid going nuclear in the compiler and use something more mundane? I, for one, welcome our new nuclear overlords.
Sign in to reply to this message.
> I, for one, welcome our new nuclear overlords. AFAICS the internal switch is called dwarf_split_debug_info so a short moniker based on it would be more understandable (and avoid a useless pomposity). -- Eric Botcazou
Sign in to reply to this message.
>> I, for one, welcome our new nuclear overlords. > > AFAICS the internal switch is called dwarf_split_debug_info so a short moniker > based on it would be more understandable (and avoid a useless pomposity). I wasn't trying to be pompous! It's just our project name, but I thought "fission" to be quite appropriate for what it does. How does "-gsplit" or "-gsplit-dwarf" work for you? -cary
Sign in to reply to this message.
On Tue, Mar 13, 2012 at 11:56 AM, Cary Coutant <ccoutant@google.com> wrote: >>> I, for one, welcome our new nuclear overlords. >> >> AFAICS the internal switch is called dwarf_split_debug_info so a short moniker >> based on it would be more understandable (and avoid a useless pomposity). > > I wasn't trying to be pompous! It's just our project name, but I > thought "fission" to be quite appropriate for what it does. How does > "-gsplit" or "-gsplit-dwarf" work for you? Or -gsplit-debug? David > > -cary
Sign in to reply to this message.
On 13/03/12 15:43 , Xinliang David Li wrote: > On Tue, Mar 13, 2012 at 11:56 AM, Cary Coutant<ccoutant@google.com> wrote: >>>> I, for one, welcome our new nuclear overlords. >>> >>> AFAICS the internal switch is called dwarf_split_debug_info so a short moniker >>> based on it would be more understandable (and avoid a useless pomposity). >> >> I wasn't trying to be pompous! It's just our project name, but I >> thought "fission" to be quite appropriate for what it does. How does >> "-gsplit" or "-gsplit-dwarf" work for you? > > Or -gsplit-debug? > > David You guys are boring ;)
Sign in to reply to this message.
> > I wasn't trying to be pompous! It's just our project name, but I > > thought "fission" to be quite appropriate for what it does. How does > > "-gsplit" or "-gsplit-dwarf" work for you? > > Or -gsplit-debug? -g is already supposed to convey the "debug", so I think that -gsplit-dwarf is the best proposal (and we already have -gstrict-dwarf for example). Thanks. -- Eric Botcazou
Sign in to reply to this message.
|