diff options
-rw-r--r-- | gcc/ChangeLog | 113 | ||||
-rw-r--r-- | gcc/common.opt | 8 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 8 | ||||
-rw-r--r-- | gcc/dwarf2out.c | 1453 | ||||
-rw-r--r-- | gcc/dwarf2out.h | 3 | ||||
-rw-r--r-- | gcc/gcc.c | 47 | ||||
-rw-r--r-- | gcc/opts.c | 8 | ||||
-rw-r--r-- | include/ChangeLog | 8 | ||||
-rw-r--r-- | include/dwarf2.h | 11 |
9 files changed, 1437 insertions, 222 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3c38d3f6ae8..b4dd302fe60 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,116 @@ +2012-11-06 Sterling Augustine <saugustine@google.com> + Cary Coutant <ccoutant@google.com> + + * common.opt (gno-split-dwarf, gsplit-dwarf): New switches. + * doc/invoke.texi (Debugging Options): Document them. + * gcc.c (replace_extension_spec_func): New function. + (ASM_FINAL_SPEC): Adjust. + (static_spec_functions): Add new field for replace-extension. + (check_live_switch): Adjust comment. Add case for 'g'. + * opts.c (finish_options): Set x_debug_generate_pub_sections based on + x_dwarf_split_debug_info. + (common_handle_option): Add case for OPT_gsplit_dwarf. + * dwarf2out.h (addr_table_entry_struct): Add forward declaration. + (dw_val_struct): Add val_entry pointer. + * dwarf2out.c: (debug_skeleton_info_section, + debug_skeleton_abbrev_section, debug_addr_section, + debug_skeleton_line_section, debug_str_offsets_section): New globals. + (NOT_INDEXED, NO_INDEX_ASSIGNED): New defines. + (indirect_string_node): New field index. + (ate_kind): New enum with fields ate_kind_rtc, ate_kind_rtx_dtprel, + ate_kind_label. + (addr_table_entry): New structure and type. + (dw_loc_list_struct): Add field begin_entry. + (new_loc_desc): Initialize val_entry. + (size_of_loc_descr, output_loc_operands, output_loc_operands_raw): + Add cases for DW_OP_GNU_addr_index and DW_OP_const_index. + (build_cfa_loc): Initialize val_entry. + (AT_index, add_addr_table_entry, remove_addr_table_entry, + add_AT_lbl_id): New functions. + (add_AT_addr, add_AT_range_list): New parameter force_direct. + (output_die_abbrevs): New function. + (add_ranges_by_labels): New parameter force_direct. + (output_line_info): New parameter prologue_only. + (dtprel_bool): New enum with dtprel_false and dtprel_true. + (dw_addr_op, new_addr_loc_descr): New functions. + (DEBUG_DWO_INFO_SECTION, DEBUG_DWO_ABBREV_SECTION, + DEBUG_ADDR_SECTION, DEBUG_NORM_MACINFO_SECTION, + DEBUG_DWO_MACINFO_SECTION, DEBUG_MACINFO_SECTION, + DEBUG_NORM_MACRO_SECTION, DEBUG_DWO_MACRO_SECTION, + DEBUG_MACRO_SECTION, DEBUG_DWO_LINE_SECTION, + DEBUG_DWO_LOC_SECTION, DEBUG_NORM_STR_OFFSETS_SECTION, + DEBUG_DWO_STR_OFFSETS_SECTION, DEBUG_STR_OFFSETS_SECTION, + DEBUG_DWO_STR_SECTION, DEBUG_NORM_STR_SECTION, DEBUG_STR_SECTION, + DEBUG_MACRO_SECTION_FLAGS, DEBUG_SKELETON_LINE_SECTION_LABEL, + DEBUG_SKELETON_INFO_SECTION_LABEL, DEBUG_ADDR_SECTION_LABEL + DEBUG_SKELETON_ABBREV_SECTION_LABEL): New macros. + (DEBUG_STR_SECTION_FLAGS): Adjust. + (TEXT_SECTION_LABEL, COLD_TEXT_SECTION_LABEL, + DEBUG_LINE_SECTION_LABEL, DEBUG_INFO_SECTION_LABEL, + DEBUG_ABBREV_SECTION_LABEL, DEBUG_ADDR_SECTION_LABEL, + DEBUG_LOC_SECTION_LABEL, DEBUG_RANGES_SECTION_LABEL, + DEBUG_MACINFO_SECTION_LABEL, DEBUG_MACRO_SECTION_LABEL): Adjust + indentation. + (debug_skeleton_abbrev_section_label, debug_addr_section_label, + debug_skeleton_line_section_label, debug_skeleton_info_section_label): + New global variables. + (add_AT_flag, add_AT_int, add_AT_unsigned, add_AT_double, add_AT_vec, + add_AT_data8): Initialize val_entry. + (add_AT_low_high_pc): New parameter force_direct. Handle + dwarf_split_debug_info. + (set_indirect_string, find_AT_string_form): New functions. + (AT_string_form): Adjust to call find_AT_string_from. + (add_AT_die_ref, add_AT_fde_ref, add_AT_loc, add_AT_list): + Initialize val_entry. + (addr_index_table): New global variable. + (addr_table_entry_do_hash, addr_table_entry_eq, add_addr_table_entry, + init_addr_table_entry, remove_addr_table_entry, index_addr_table_entry, + remove_loc_list_addr_table_entries): New functions. + (add_AT_addr, add_AT_lbl_id, add_AT_range_list): New parameter + force_direct. Handle dwarf_split_debug_info. + (add_AT_file, add_AT_vms_delta, add_AT_lineptr, add_AT_macptr, + add_AT_offset): Initialize val_entry. + (UNRELOCATED_OFFSET, RELOCATED_OFFSET): New defines. + (size_of_die): Handle dwarf_split_debug_info. + (size_of_aranges, value_format): Call AT_class. Check AT_index. + (output_die_abbrevs): New function. + (output_abbrev_section): Call output_die_abbrevs. + (new_loc_list): Initialize begin_entry. + (output_loc_list): Handle dwarf_split_debug_info. + (output_range_list_offset, output_loc_list_offset, + output_attr_index_or_value, ): New functions. + (output_die): Fix call to dw2_asm_output_data. Call + output_attr_index_or_value and output_range_list_offset. + Adjust logic around dw_val_class_str. + (add_top_lebel_skeleton_die_attrs, get_skeleton_type_unit, + output_skeleton_debug_sections): New functions. + (output_comdat_type_unit, output_pubname, output_aranges): Handle + dwarf_split_debug_info. + (add_ranges_by_labels): New parameter force_direct. + (mem_loc_descriptor, loc_descr): Call new_addr_loc_descr. + (loc_list_from_tree, add_const_value_attribtue): Use dtprel_bools in + place of generic integer. + (dwarf2out_vms_debug_main_pointer, gen_entry_point_die, gen_label_die, + gen_call_site_die, gen_subprogram_die, gen_variable_die, + add_high_low_attributes): Adjust calls to add_AT_lbl_id. + (output_macinfo_op): Adjust indirect_string_logic. + (save_macinfo_strings): New function. + (output_macinfo): Adjust. + (dwarf2out_init): Handle dwarf_split_debug_info. + (index_string, output_index_string_offset, output_index_string): New + functions. + (output_indirect_string): Adjust. + (output_indirect_strings, output_addr_table_entry, output_addr_table): + New functions. + (resolve_addr_in_expr, hash_loc_operands): Handle DW_OP_GNU_addr_index + and DW_OP_GNU_const_index. Handle dwarf_split_debug_info. Call + remove_loc_list_addr_table_entries and remove_addr_table_entry. + (index_location_lists): New function. + (dwarf2out_finish): Handle dwarf_split_debug_info. New variable + main_comp_unit_die. Adjust calls to add_AT_low_high_pc, + add_ranges_by_labels, add_AT_addr, and add_AT_lineptr. Call + save_macinfo_strings and output_indirect_strings. + 2012-11-06 Gerald Pfeifer <gerald@pfeifer.com> * config/i386/i386.c (make_dispatcher_decl): Guard with diff --git a/gcc/common.opt b/gcc/common.opt index 5b69aff2feb..6b95c0558b7 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2314,6 +2314,14 @@ grecord-gcc-switches Common RejectNegative Var(dwarf_record_gcc_switches,1) Record gcc command line switches in DWARF DW_AT_producer. +gno-split-dwarf +Common Driver RejectNegative Var(dwarf_split_debug_info,0) Init(0) +Don't generate debug information in separate .dwo files + +gsplit-dwarf +Common Driver RejectNegative Var(dwarf_split_debug_info,1) +Generate debug information in separate .dwo files + gstabs Common JoinedOrMissing Negative(gstabs+) Generate debug information in STABS format diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 73363a1a5a6..55f72297ea0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -4846,6 +4846,14 @@ it reasonable to use the optimizer for programs that might have bugs. The following options are useful when GCC is generated with the capability for more than one debugging format. +@item -gsplit-dwarf +@opindex gsplit-dwarf +Separate as much dwarf debugging information as possible into a +separate output file with the extension .dwo. This option allows +the build system to avoid linking files with debug information. To +be useful, this option requires a debugger capable of reading .dwo +files. + @item -ggdb @opindex ggdb Produce debugging information for use by GDB@. This means to use the diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 9405c34d1e6..310f2dd5373 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -147,14 +147,19 @@ static GTY(()) VEC(tree,gc) *decl_scope_table; /* Pointers to various DWARF2 sections. */ static GTY(()) section *debug_info_section; +static GTY(()) section *debug_skeleton_info_section; static GTY(()) section *debug_abbrev_section; +static GTY(()) section *debug_skeleton_abbrev_section; static GTY(()) section *debug_aranges_section; +static GTY(()) section *debug_addr_section; static GTY(()) section *debug_macinfo_section; static GTY(()) section *debug_line_section; +static GTY(()) section *debug_skeleton_line_section; static GTY(()) section *debug_loc_section; static GTY(()) section *debug_pubnames_section; static GTY(()) section *debug_pubtypes_section; static GTY(()) section *debug_str_section; +static GTY(()) section *debug_str_offsets_section; static GTY(()) section *debug_ranges_section; static GTY(()) section *debug_frame_section; @@ -190,6 +195,9 @@ DEF_VEC_ALLOC_P (dw_fde_ref, gc); /* A vector for a table that contains frame description information for each routine. */ +#define NOT_INDEXED (-1U) +#define NO_INDEX_ASSIGNED (-2U) + static GTY(()) VEC(dw_fde_ref, gc) *fde_vec; struct GTY(()) indirect_string_node { @@ -197,6 +205,7 @@ struct GTY(()) indirect_string_node { unsigned int refcount; enum dwarf_form form; char *label; + unsigned int index; }; static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash; @@ -1198,13 +1207,35 @@ static GTY(()) VEC(deferred_locations, gc) *deferred_locations_list; DEF_VEC_P(dw_die_ref); DEF_VEC_ALLOC_P(dw_die_ref,heap); +/* Describe an entry into the .debug_addr section. */ + +enum ate_kind { + ate_kind_rtx, + ate_kind_rtx_dtprel, + ate_kind_label +}; + +typedef struct GTY(()) addr_table_entry_struct { + enum ate_kind kind; + unsigned int refcount; + unsigned int index; + union addr_table_entry_struct_union + { + rtx GTY ((tag ("0"))) rtl; + char * GTY ((tag ("1"))) label; + } + GTY ((desc ("%1.kind"))) addr; +} +addr_table_entry; + /* Location lists are ranges + location descriptions for that range, so you can track variables that are in different places over their entire life. */ typedef struct GTY(()) dw_loc_list_struct { dw_loc_list_ref dw_loc_next; - const char *begin; /* Label for begin address of range */ - const char *end; /* Label for end address of range */ + const char *begin; /* Label and addr_entry for start of range */ + addr_table_entry *begin_entry; + const char *end; /* Label for end of range */ char *ll_symbol; /* Label for beginning of location list. Only on head of list */ const char *section; /* Section this loclist is relative to */ @@ -1248,8 +1279,10 @@ new_loc_descr (enum dwarf_location_atom op, unsigned HOST_WIDE_INT oprnd1, descr->dw_loc_opc = op; descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const; + descr->dw_loc_oprnd1.val_entry = NULL; descr->dw_loc_oprnd1.v.val_unsigned = oprnd1; descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const; + descr->dw_loc_oprnd2.val_entry = NULL; descr->dw_loc_oprnd2.v.val_unsigned = oprnd2; return descr; @@ -1454,6 +1487,11 @@ size_of_loc_descr (dw_loc_descr_ref loc) case DW_OP_addr: size += DWARF2_ADDR_SIZE; break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED); + size += size_of_uleb128 (loc->dw_loc_oprnd1.val_entry->index); + break; case DW_OP_const1u: case DW_OP_const1s: size += 1; @@ -1890,6 +1928,13 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip) } break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + gcc_assert (loc->dw_loc_oprnd1.val_entry->index != NO_INDEX_ASSIGNED); + dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_entry->index, + "(index into .debug_addr)"); + break; + case DW_OP_GNU_implicit_pointer: { char label[MAX_ARTIFICIAL_LABEL_BYTES @@ -2065,6 +2110,8 @@ output_loc_operands_raw (dw_loc_descr_ref loc) switch (loc->dw_loc_opc) { case DW_OP_addr: + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: case DW_OP_implicit_value: /* We cannot output addresses in .cfi_escape, only bytes. */ gcc_unreachable (); @@ -2248,6 +2295,7 @@ build_cfa_loc (dw_cfa_location *cfa, HOST_WIDE_INT offset) { head = new_reg_loc_descr (cfa->reg, cfa->base_offset); head->dw_loc_oprnd1.val_class = dw_val_class_const; + head->dw_loc_oprnd1.val_entry = NULL; tmp = new_loc_descr (DW_OP_deref, 0, 0); add_loc_descr (&head, tmp); if (offset != 0) @@ -2877,6 +2925,7 @@ static tree decl_ultimate_origin (const_tree); static tree decl_class_context (tree); static void add_dwarf_attr (dw_die_ref, dw_attr_ref); static inline enum dw_val_class AT_class (dw_attr_ref); +static inline unsigned int AT_index (dw_attr_ref); static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned); static inline unsigned AT_flag (dw_attr_ref); static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT); @@ -2904,7 +2953,9 @@ static inline dw_loc_descr_ref AT_loc (dw_attr_ref); static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute, dw_loc_list_ref); static inline dw_loc_list_ref AT_loc_list (dw_attr_ref); -static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx); +static addr_table_entry *add_addr_table_entry (void *, enum ate_kind); +static void remove_addr_table_entry (addr_table_entry *); +static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool); static inline rtx AT_addr (dw_attr_ref); static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *); static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *); @@ -2912,7 +2963,7 @@ static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *); static void add_AT_offset (dw_die_ref, enum dwarf_attribute, unsigned HOST_WIDE_INT); static void add_AT_range_list (dw_die_ref, enum dwarf_attribute, - unsigned long); + unsigned long, bool); static inline const char *AT_lbl (dw_attr_ref); static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute); static const char *get_AT_low_pc (dw_die_ref); @@ -3007,6 +3058,7 @@ static unsigned long size_of_aranges (void); static enum dwarf_form value_format (dw_attr_ref); static void output_value_format (dw_attr_ref); static void output_abbrev_section (void); +static void output_die_abbrevs (unsigned long, dw_die_ref); static void output_die_symbol (dw_die_ref); static void output_die (dw_die_ref); static void output_compilation_unit_header (void); @@ -3022,10 +3074,10 @@ static void output_aranges (unsigned long); static unsigned int add_ranges_num (int); static unsigned int add_ranges (const_tree); static void add_ranges_by_labels (dw_die_ref, const char *, const char *, - bool *); + bool *, bool); static void output_ranges (void); static dw_line_info_table *new_line_info_table (void); -static void output_line_info (void); +static void output_line_info (bool); static void output_file_names (void); static dw_die_ref base_type_die (tree); static int is_base_type (tree); @@ -3164,36 +3216,124 @@ static bool generic_type_p (tree); static void schedule_generic_params_dies_gen (tree t); static void gen_scheduled_generic_parms_dies (void); +/* enum for tracking thread-local variables whose address is really an offset + relative to the TLS pointer, which will need link-time relocation, but will + not need relocation by the DWARF consumer. */ + +enum dtprel_bool +{ + dtprel_false = 0, + dtprel_true = 1 +}; + +/* Return the operator to use for an address of a variable. For dtprel_true, we + use DW_OP_const*. For regular variables, which need both link-time + relocation and consumer-level relocation (e.g., to account for shared objects + loaded at a random address), we use DW_OP_addr*. */ + +static inline enum dwarf_location_atom +dw_addr_op (enum dtprel_bool dtprel) +{ + if (dtprel == dtprel_true) + return (dwarf_split_debug_info ? DW_OP_GNU_const_index + : (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u)); + else + return dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr; +} + +/* Return a pointer to a newly allocated address location description. If + dwarf_split_debug_info is true, then record the address with the appropriate + relocation. */ +static inline dw_loc_descr_ref +new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel) +{ + dw_loc_descr_ref ref = new_loc_descr (dw_addr_op (dtprel), 0, 0); + + ref->dw_loc_oprnd1.val_class = dw_val_class_addr; + ref->dw_loc_oprnd1.v.val_addr = addr; + ref->dtprel = dtprel; + if (dwarf_split_debug_info) + ref->dw_loc_oprnd1.val_entry + = add_addr_table_entry (addr, + dtprel ? ate_kind_rtx_dtprel : ate_kind_rtx); + else + ref->dw_loc_oprnd1.val_entry = NULL; + + return ref; +} + /* Section names used to hold DWARF debugging information. */ + #ifndef DEBUG_INFO_SECTION #define DEBUG_INFO_SECTION ".debug_info" #endif +#ifndef DEBUG_DWO_INFO_SECTION +#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo" +#endif #ifndef DEBUG_ABBREV_SECTION #define DEBUG_ABBREV_SECTION ".debug_abbrev" #endif +#ifndef DEBUG_DWO_ABBREV_SECTION +#define DEBUG_DWO_ABBREV_SECTION ".debug_abbrev.dwo" +#endif #ifndef DEBUG_ARANGES_SECTION #define DEBUG_ARANGES_SECTION ".debug_aranges" #endif +#ifndef DEBUG_ADDR_SECTION +#define DEBUG_ADDR_SECTION ".debug_addr" +#endif +#ifndef DEBUG_NORM_MACINFO_SECTION +#define DEBUG_NORM_MACINFO_SECTION ".debug_macinfo" +#endif +#ifndef DEBUG_DWO_MACINFO_SECTION +#define DEBUG_DWO_MACINFO_SECTION ".debug_macinfo.dwo" +#endif #ifndef DEBUG_MACINFO_SECTION -#define DEBUG_MACINFO_SECTION ".debug_macinfo" +#define DEBUG_MACINFO_SECTION \ + (!dwarf_split_debug_info \ + ? (DEBUG_NORM_MACINFO_SECTION) : (DEBUG_DWO_MACINFO_SECTION)) +#endif +#ifndef DEBUG_NORM_MACRO_SECTION +#define DEBUG_NORM_MACRO_SECTION ".debug_macro" +#endif +#ifndef DEBUG_DWO_MACRO_SECTION +#define DEBUG_DWO_MACRO_SECTION ".debug_macro.dwo" #endif #ifndef DEBUG_MACRO_SECTION -#define DEBUG_MACRO_SECTION ".debug_macro" +#define DEBUG_MACRO_SECTION \ + (!dwarf_split_debug_info \ + ? (DEBUG_NORM_MACRO_SECTION) : (DEBUG_DWO_MACRO_SECTION)) #endif #ifndef DEBUG_LINE_SECTION #define DEBUG_LINE_SECTION ".debug_line" #endif +#ifndef DEBUG_DWO_LINE_SECTION +#define DEBUG_DWO_LINE_SECTION ".debug_line.dwo" +#endif #ifndef DEBUG_LOC_SECTION #define DEBUG_LOC_SECTION ".debug_loc" #endif +#ifndef DEBUG_DWO_LOC_SECTION +#define DEBUG_DWO_LOC_SECTION ".debug_loc.dwo" +#endif #ifndef DEBUG_PUBNAMES_SECTION #define DEBUG_PUBNAMES_SECTION ".debug_pubnames" #endif #ifndef DEBUG_PUBTYPES_SECTION #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes" #endif +#define DEBUG_NORM_STR_OFFSETS_SECTION ".debug_str_offsets" +#define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo" +#ifndef DEBUG_STR_OFFSETS_SECTION +#define DEBUG_STR_OFFSETS_SECTION \ + (!dwarf_split_debug_info \ + ? (DEBUG_NORM_STR_OFFSETS_SECTION) : (DEBUG_DWO_STR_OFFSETS_SECTION)) +#endif +#define DEBUG_DWO_STR_SECTION ".debug_str.dwo" +#define DEBUG_NORM_STR_SECTION ".debug_str" #ifndef DEBUG_STR_SECTION -#define DEBUG_STR_SECTION ".debug_str" +#define DEBUG_STR_SECTION \ + (!dwarf_split_debug_info ? (DEBUG_NORM_STR_SECTION) : (DEBUG_DWO_STR_SECTION)) #endif #ifndef DEBUG_RANGES_SECTION #define DEBUG_RANGES_SECTION ".debug_ranges" @@ -3204,43 +3344,62 @@ static void gen_scheduled_generic_parms_dies (void); #define TEXT_SECTION_NAME ".text" #endif +/* Section flags for .debug_macinfo/.debug_macro section. */ +#define DEBUG_MACRO_SECTION_FLAGS \ + (dwarf_split_debug_info ? SECTION_DEBUG | SECTION_EXCLUDE : SECTION_DEBUG) + /* Section flags for .debug_str section. */ #define DEBUG_STR_SECTION_FLAGS \ - (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings \ - ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1 \ - : SECTION_DEBUG) + (dwarf_split_debug_info \ + ? SECTION_DEBUG | SECTION_EXCLUDE \ + : (HAVE_GAS_SHF_MERGE && flag_merge_debug_strings \ + ? SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1 \ + : SECTION_DEBUG)) /* Labels we insert at beginning sections we can reference instead of the section names themselves. */ #ifndef TEXT_SECTION_LABEL -#define TEXT_SECTION_LABEL "Ltext" +#define TEXT_SECTION_LABEL "Ltext" #endif #ifndef COLD_TEXT_SECTION_LABEL -#define COLD_TEXT_SECTION_LABEL "Ltext_cold" +#define COLD_TEXT_SECTION_LABEL "Ltext_cold" #endif #ifndef DEBUG_LINE_SECTION_LABEL -#define DEBUG_LINE_SECTION_LABEL "Ldebug_line" +#define DEBUG_LINE_SECTION_LABEL "Ldebug_line" +#endif +#ifndef DEBUG_SKELETON_LINE_SECTION_LABEL +#define DEBUG_SKELETON_LINE_SECTION_LABEL "Lskeleton_debug_line" #endif #ifndef DEBUG_INFO_SECTION_LABEL -#define DEBUG_INFO_SECTION_LABEL "Ldebug_info" +#define DEBUG_INFO_SECTION_LABEL "Ldebug_info" +#endif +#ifndef DEBUG_SKELETON_INFO_SECTION_LABEL +#define DEBUG_SKELETON_INFO_SECTION_LABEL "Lskeleton_debug_info" #endif #ifndef DEBUG_ABBREV_SECTION_LABEL -#define DEBUG_ABBREV_SECTION_LABEL "Ldebug_abbrev" +#define DEBUG_ABBREV_SECTION_LABEL "Ldebug_abbrev" +#endif +#ifndef DEBUG_SKELETON_ABBREV_SECTION_LABEL +#define DEBUG_SKELETON_ABBREV_SECTION_LABEL "Lskeleton_debug_abbrev" +#endif +#ifndef DEBUG_ADDR_SECTION_LABEL +#define DEBUG_ADDR_SECTION_LABEL "Ldebug_addr" #endif #ifndef DEBUG_LOC_SECTION_LABEL -#define DEBUG_LOC_SECTION_LABEL "Ldebug_loc" +#define DEBUG_LOC_SECTION_LABEL "Ldebug_loc" #endif #ifndef DEBUG_RANGES_SECTION_LABEL -#define DEBUG_RANGES_SECTION_LABEL "Ldebug_ranges" +#define DEBUG_RANGES_SECTION_LABEL "Ldebug_ranges" #endif #ifndef DEBUG_MACINFO_SECTION_LABEL -#define DEBUG_MACINFO_SECTION_LABEL "Ldebug_macinfo" +#define DEBUG_MACINFO_SECTION_LABEL "Ldebug_macinfo" #endif #ifndef DEBUG_MACRO_SECTION_LABEL -#define DEBUG_MACRO_SECTION_LABEL "Ldebug_macro" +#define DEBUG_MACRO_SECTION_LABEL "Ldebug_macro" #endif - +#define SKELETON_COMP_DIE_ABBREV 1 +#define SKELETON_TYPE_DIE_ABBREV 2 /* Definitions of defaults for formats and names of various special (artificial) labels which may be generated within this file (when the -g @@ -3254,7 +3413,11 @@ static char cold_text_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; +static char debug_skeleton_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; +static char debug_skeleton_abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; +static char debug_addr_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; +static char debug_skeleton_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES]; @@ -3495,6 +3658,21 @@ AT_class (dw_attr_ref a) return a->dw_attr_val.val_class; } +/* Return the index for any attribute that will be referenced with a + DW_FORM_GNU_addr_index or DW_FORM_GNU_str_index. String indices + are stored in dw_attr_val.v.val_str for reference counting + pruning. */ + +static inline unsigned int +AT_index (dw_attr_ref a) +{ + if (AT_class (a) == dw_val_class_str) + return a->dw_attr_val.v.val_str->index; + else if (a->dw_attr_val.val_entry != NULL) + return a->dw_attr_val.val_entry->index; + return NOT_INDEXED; +} + /* Add a flag value attribute to a DIE. */ static inline void @@ -3504,6 +3682,7 @@ add_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int flag) attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_flag; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_flag = flag; add_dwarf_attr (die, &attr); } @@ -3524,6 +3703,7 @@ add_AT_int (dw_die_ref die, enum dwarf_attribute attr_kind, HOST_WIDE_INT int_va attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_const; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_int = int_val; add_dwarf_attr (die, &attr); } @@ -3545,6 +3725,7 @@ add_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind, attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_unsigned_const; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_unsigned = unsigned_val; add_dwarf_attr (die, &attr); } @@ -3566,6 +3747,7 @@ add_AT_double (dw_die_ref die, enum dwarf_attribute attr_kind, attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_const_double; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_double.high = high; attr.dw_attr_val.v.val_double.low = low; add_dwarf_attr (die, &attr); @@ -3581,6 +3763,7 @@ add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind, attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_vec; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_vec.length = length; attr.dw_attr_val.v.val_vec.elt_size = elt_size; attr.dw_attr_val.v.val_vec.array = array; @@ -3597,19 +3780,32 @@ add_AT_data8 (dw_die_ref die, enum dwarf_attribute attr_kind, attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_data8; + attr.dw_attr_val.val_entry = NULL; memcpy (attr.dw_attr_val.v.val_data8, data8, 8); add_dwarf_attr (die, &attr); } -/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE. */ +/* Add DW_AT_low_pc and DW_AT_high_pc to a DIE. When using + dwarf_split_debug_info, address attributes in dies destined for the + final executable have force_direct set to avoid using indexed + references. */ + static inline void -add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high) +add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high, + bool force_direct) { dw_attr_node attr; + char * lbl_id; + lbl_id = xstrdup (lbl_low); attr.dw_attr = DW_AT_low_pc; attr.dw_attr_val.val_class = dw_val_class_lbl_id; - attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_low); + attr.dw_attr_val.v.val_lbl_id = lbl_id; + if (dwarf_split_debug_info && !force_direct) + attr.dw_attr_val.val_entry + = add_addr_table_entry (lbl_id, ate_kind_label); + else + attr.dw_attr_val.val_entry = NULL; add_dwarf_attr (die, &attr); attr.dw_attr = DW_AT_high_pc; @@ -3617,7 +3813,14 @@ add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high) attr.dw_attr_val.val_class = dw_val_class_lbl_id; else attr.dw_attr_val.val_class = dw_val_class_high_pc; - attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_high); + lbl_id = xstrdup (lbl_high); + attr.dw_attr_val.v.val_lbl_id = lbl_id; + if (attr.dw_attr_val.val_class == dw_val_class_lbl_id + && dwarf_split_debug_info && !force_direct) + attr.dw_attr_val.val_entry + = add_addr_table_entry (lbl_id, ate_kind_label); + else + attr.dw_attr_val.val_entry = NULL; add_dwarf_attr (die, &attr); } @@ -3675,6 +3878,7 @@ add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str) attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_str; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_str = node; add_dwarf_attr (die, &attr); } @@ -3686,19 +3890,43 @@ AT_string (dw_attr_ref a) return a->dw_attr_val.v.val_str->str; } +/* Call this function directly to bypass AT_string_form's logic to put + the string inline in the die. */ + +static void +set_indirect_string (struct indirect_string_node *node) +{ + char label[32]; + /* Already indirect is a no op. */ + if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index) + { + gcc_assert (node->label); + return; + } + ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter); + ++dw2_string_counter; + node->label = xstrdup (label); + + if (!dwarf_split_debug_info) + { + node->form = DW_FORM_strp; + node->index = NOT_INDEXED; + } + else + { + node->form = DW_FORM_GNU_str_index; + node->index = NO_INDEX_ASSIGNED; + } +} + /* Find out whether a string should be output inline in DIE or out-of-line in .debug_str section. */ static enum dwarf_form -AT_string_form (dw_attr_ref a) +find_string_form (struct indirect_string_node *node) { - struct indirect_string_node *node; unsigned int len; - char label[32]; - gcc_assert (a && AT_class (a) == dw_val_class_str); - - node = a->dw_attr_val.v.val_str; if (node->form) return node->form; @@ -3717,11 +3945,19 @@ AT_string_form (dw_attr_ref a) && (len - DWARF_OFFSET_SIZE) * node->refcount <= len)) return node->form = DW_FORM_string; - ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter); - ++dw2_string_counter; - node->label = xstrdup (label); + set_indirect_string (node); + + return node->form; +} - return node->form = DW_FORM_strp; +/* Find out whether the string referenced from the attribute should be + output inline in DIE or out-of-line in .debug_str section. */ + +static enum dwarf_form +AT_string_form (dw_attr_ref a) +{ + gcc_assert (a && AT_class (a) == dw_val_class_str); + return find_string_form (a->dw_attr_val.v.val_str); } /* Add a DIE reference attribute value to a DIE. */ @@ -3742,6 +3978,7 @@ add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_ attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_die_ref; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_die_ref.die = targ_die; attr.dw_attr_val.v.val_die_ref.external = 0; add_dwarf_attr (die, &attr); @@ -3800,6 +4037,7 @@ add_AT_fde_ref (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int tar attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_fde_ref; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_fde_index = targ_fde; add_dwarf_attr (die, &attr); } @@ -3813,6 +4051,7 @@ add_AT_loc (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_descr_ref loc attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_loc; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_loc = loc; add_dwarf_attr (die, &attr); } @@ -3831,6 +4070,7 @@ add_AT_loc_list (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_list_ref attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_loc_list; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_loc_list = loc_list; add_dwarf_attr (die, &attr); have_location_lists = true; @@ -3850,16 +4090,169 @@ AT_loc_list_ptr (dw_attr_ref a) return &a->dw_attr_val.v.val_loc_list; } -/* Add an address constant attribute value to a DIE. */ +/* Table of entries into the .debug_addr section. */ + +static GTY ((param_is (addr_table_entry))) htab_t addr_index_table; + +/* Hash an address_table_entry. */ + +static hashval_t +addr_table_entry_do_hash (const void *x) +{ + const addr_table_entry *a = (const addr_table_entry *) x; + switch (a->kind) + { + case ate_kind_rtx: + return iterative_hash_rtx (a->addr.rtl, 0); + case ate_kind_rtx_dtprel: + return iterative_hash_rtx (a->addr.rtl, 1); + case ate_kind_label: + return htab_hash_string (a->addr.label); + default: + gcc_unreachable (); + } +} + +/* Determine equality for two address_table_entries. */ + +static int +addr_table_entry_eq (const void *x1, const void *x2) +{ + const addr_table_entry *a1 = (const addr_table_entry *) x1; + const addr_table_entry *a2 = (const addr_table_entry *) x2; + + if (a1->kind != a2->kind) + return 0; + switch (a1->kind) + { + case ate_kind_rtx: + case ate_kind_rtx_dtprel: + return rtx_equal_p (a1->addr.rtl, a2->addr.rtl); + case ate_kind_label: + return strcmp (a1->addr.label, a2->addr.label) == 0; + default: + gcc_unreachable (); + } +} + +/* Initialize an addr_table_entry. */ + +void +init_addr_table_entry (addr_table_entry *e, enum ate_kind kind, void *addr) +{ + e->kind = kind; + switch (kind) + { + case ate_kind_rtx: + case ate_kind_rtx_dtprel: + e->addr.rtl = (rtx) addr; + break; + case ate_kind_label: + e->addr.label = (char *) addr; + break; + } + e->refcount = 0; + e->index = NO_INDEX_ASSIGNED; +} + +/* Add attr to the address table entry to the table. Defer setting an + index until output time. */ + +static addr_table_entry * +add_addr_table_entry (void *addr, enum ate_kind kind) +{ + addr_table_entry *node; + addr_table_entry finder; + void **slot; + + gcc_assert (dwarf_split_debug_info); + if (! addr_index_table) + addr_index_table = htab_create_ggc (10, addr_table_entry_do_hash, + addr_table_entry_eq, NULL); + init_addr_table_entry (&finder, kind, addr); + slot = htab_find_slot (addr_index_table, &finder, INSERT); + + if (*slot == HTAB_EMPTY_ENTRY) + { + node = ggc_alloc_cleared_addr_table_entry (); + init_addr_table_entry (node, kind, addr); + *slot = node; + } + else + node = (addr_table_entry *) *slot; + + node->refcount++; + return node; +} + +/* Remove an entry from the addr table by decrementing its refcount. + Strictly, decrementing the refcount would be enough, but the + assertion that the entry is actually in the table has found + bugs. */ + +static void +remove_addr_table_entry (addr_table_entry *entry) +{ + addr_table_entry *node; + + gcc_assert (dwarf_split_debug_info && addr_index_table); + node = (addr_table_entry *) htab_find (addr_index_table, entry); + /* After an index is assigned, the table is frozen. */ + gcc_assert (node->refcount > 0 && node->index == NO_INDEX_ASSIGNED); + node->refcount--; +} + +/* Given a location list, remove all addresses it refers to from the + address_table. */ + +static void +remove_loc_list_addr_table_entries (dw_loc_descr_ref descr) +{ + for (; descr; descr = descr->dw_loc_next) + if (descr->dw_loc_oprnd1.val_entry != NULL) + { + gcc_assert (descr->dw_loc_oprnd1.val_entry->index == NO_INDEX_ASSIGNED); + remove_addr_table_entry (descr->dw_loc_oprnd1.val_entry); + } +} + +/* A helper function for dwarf2out_finish called through + htab_traverse. Assign an addr_table_entry its index. All entries + must be collected into the table when this function is called, + because the indexing code relies on htab_traverse to traverse nodes + in the same order for each run. */ + +static int +index_addr_table_entry (void **h, void *v) +{ + addr_table_entry *node = (addr_table_entry *) *h; + unsigned int *index = (unsigned int *) v; + + gcc_assert(node->index == NO_INDEX_ASSIGNED); + node->index = *index; + *index += 1; + + return 1; +} + +/* Add an address constant attribute value to a DIE. When using + dwarf_split_debug_info, address attributes in dies destined for the + final executable should be direct references--setting the parameter + force_direct ensures this behavior. */ static inline void -add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr) +add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr, + bool force_direct) { dw_attr_node attr; attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_addr; attr.dw_attr_val.v.val_addr = addr; + if (dwarf_split_debug_info && !force_direct) + attr.dw_attr_val.val_entry = add_addr_table_entry (addr, ate_kind_rtx); + else + attr.dw_attr_val.val_entry = NULL; add_dwarf_attr (die, &attr); } @@ -3882,6 +4275,7 @@ add_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind, attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_file; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_file = fd; add_dwarf_attr (die, &attr); } @@ -3905,6 +4299,7 @@ add_AT_vms_delta (dw_die_ref die, enum dwarf_attribute attr_kind, attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_vms_delta; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1); attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2); add_dwarf_attr (die, &attr); @@ -3913,13 +4308,19 @@ add_AT_vms_delta (dw_die_ref die, enum dwarf_attribute attr_kind, /* Add a label identifier attribute value to a DIE. */ static inline void -add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id) +add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, + const char *lbl_id) { dw_attr_node attr; attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_lbl_id; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id); + if (dwarf_split_debug_info) + attr.dw_attr_val.val_entry + = add_addr_table_entry (attr.dw_attr_val.v.val_lbl_id, + ate_kind_label); add_dwarf_attr (die, &attr); } @@ -3934,6 +4335,7 @@ add_AT_lineptr (dw_die_ref die, enum dwarf_attribute attr_kind, attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_lineptr; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_lbl_id = xstrdup (label); add_dwarf_attr (die, &attr); } @@ -3949,6 +4351,7 @@ add_AT_macptr (dw_die_ref die, enum dwarf_attribute attr_kind, attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_macptr; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_lbl_id = xstrdup (label); add_dwarf_attr (die, &attr); } @@ -3963,20 +4366,34 @@ add_AT_offset (dw_die_ref die, enum dwarf_attribute attr_kind, attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_offset; + attr.dw_attr_val.val_entry = NULL; attr.dw_attr_val.v.val_offset = offset; add_dwarf_attr (die, &attr); } -/* Add an range_list attribute value to a DIE. */ +/* Add a range_list attribute value to a DIE. When using + dwarf_split_debug_info, address attributes in dies destined for the + final executable should be direct references--setting the parameter + force_direct ensures this behavior. */ + +#define UNRELOCATED_OFFSET ((addr_table_entry *) 1) +#define RELOCATED_OFFSET (NULL) static void add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind, - long unsigned int offset) + long unsigned int offset, bool force_direct) { dw_attr_node attr; attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_range_list; + /* For the range_list attribute, use val_entry to store whether the + offset should follow split-debug-info or normal semantics. This + value is read in output_range_list_offset. */ + if (dwarf_split_debug_info && !force_direct) + attr.dw_attr_val.val_entry = UNRELOCATED_OFFSET; + else + attr.dw_attr_val.val_entry = RELOCATED_OFFSET; attr.dw_attr_val.v.val_offset = offset; add_dwarf_attr (die, &attr); } @@ -7163,6 +7580,7 @@ size_of_die (dw_die_ref die) unsigned long size = 0; dw_attr_ref a; unsigned ix; + enum dwarf_form form; size += size_of_uleb128 (die->die_abbrev); FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a) @@ -7170,7 +7588,13 @@ size_of_die (dw_die_ref die) switch (AT_class (a)) { case dw_val_class_addr: - size += DWARF2_ADDR_SIZE; + if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED) + { + gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED); + size += size_of_uleb128 (AT_index (a)); + } + else + size += DWARF2_ADDR_SIZE; break; case dw_val_class_offset: size += DWARF_OFFSET_SIZE; @@ -7188,10 +7612,16 @@ size_of_die (dw_die_ref die) } break; case dw_val_class_loc_list: - size += DWARF_OFFSET_SIZE; + if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED) + { + gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED); + size += size_of_uleb128 (AT_index (a)); + } + else + size += DWARF_OFFSET_SIZE; break; case dw_val_class_range_list: - size += DWARF_OFFSET_SIZE; + size += DWARF_OFFSET_SIZE; break; case dw_val_class_const: size += size_of_sleb128 (AT_int (a)); @@ -7251,15 +7681,24 @@ size_of_die (dw_die_ref die) size += DWARF_OFFSET_SIZE; break; case dw_val_class_lbl_id: - size += DWARF2_ADDR_SIZE; + if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED) + { + gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED); + size += size_of_uleb128 (AT_index (a)); + } + else + size += DWARF2_ADDR_SIZE; break; case dw_val_class_lineptr: case dw_val_class_macptr: - size += DWARF_OFFSET_SIZE; + size += DWARF_OFFSET_SIZE; break; case dw_val_class_str: - if (AT_string_form (a) == DW_FORM_strp) + form = AT_string_form (a); + if (form == DW_FORM_strp) size += DWARF_OFFSET_SIZE; + else if (form == DW_FORM_GNU_str_index) + size += size_of_uleb128 (AT_index (a)); else size += strlen (a->dw_attr_val.v.val_str->str) + 1; break; @@ -7444,7 +7883,7 @@ size_of_aranges (void) static enum dwarf_form value_format (dw_attr_ref a) { - switch (a->dw_attr_val.val_class) + switch (AT_class (a)) { case dw_val_class_addr: /* Only very few attributes allow DW_FORM_addr. */ @@ -7454,7 +7893,8 @@ value_format (dw_attr_ref a) case DW_AT_high_pc: case DW_AT_entry_pc: case DW_AT_trampoline: - return DW_FORM_addr; + return (AT_index (a) == NOT_INDEXED + ? DW_FORM_addr : DW_FORM_GNU_addr_index); default: break; } @@ -7572,7 +8012,8 @@ value_format (dw_attr_ref a) case dw_val_class_fde_ref: return DW_FORM_data; case dw_val_class_lbl_id: - return DW_FORM_addr; + return (AT_index (a) == NOT_INDEXED + ? DW_FORM_addr : DW_FORM_GNU_addr_index); case dw_val_class_lineptr: case dw_val_class_macptr: return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data; @@ -7624,40 +8065,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); @@ -7694,6 +8141,7 @@ new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end, dw_loc_list_ref retlist = ggc_alloc_cleared_dw_loc_list_node (); retlist->begin = begin; + retlist->begin_entry = NULL; retlist->end = end; retlist->expr = expr; retlist->section = section; @@ -7738,7 +8186,22 @@ output_loc_list (dw_loc_list_ref list_head) in a single range are unlikely very useful. */ if (size > 0xffff) continue; - if (!have_multiple_function_sections) + if (dwarf_split_debug_info) + { + dw2_asm_output_data (1, DW_LLE_GNU_start_length_entry, + "Location list start/length entry (%s)", + list_head->ll_symbol); + dw2_asm_output_data_uleb128 (curr->begin_entry->index, + "Location list range start index (%s)", + curr->begin); + /* The length field is 4 bytes. If we ever need to support + an 8-byte length, we can add a new DW_LLE code or fall back + to DW_LLE_GNU_start_end_entry. */ + dw2_asm_output_delta (4, curr->end, curr->begin, + "Location list range length (%s)", + list_head->ll_symbol); + } + else if (!have_multiple_function_sections) { dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section, "Location list begin address (%s)", @@ -7764,12 +8227,86 @@ output_loc_list (dw_loc_list_ref list_head) output_loc_sequence (curr->expr, -1); } - dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, - "Location list terminator begin (%s)", - list_head->ll_symbol); - dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, - "Location list terminator end (%s)", - list_head->ll_symbol); + if (dwarf_split_debug_info) + dw2_asm_output_data (1, DW_LLE_GNU_end_of_list_entry, + "Location list terminator (%s)", + list_head->ll_symbol); + else + { + dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, + "Location list terminator begin (%s)", + list_head->ll_symbol); + dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, + "Location list terminator end (%s)", + list_head->ll_symbol); + } +} + +/* Output a range_list offset into the debug_range section. Emit a + relocated reference if val_entry is NULL, otherwise, emit an + indirect reference. */ + +static void +output_range_list_offset (dw_attr_ref a) +{ + const char *name = dwarf_attr_name (a->dw_attr); + + if (a->dw_attr_val.val_entry == RELOCATED_OFFSET) + { + char *p = strchr (ranges_section_label, '\0'); + sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label, + debug_ranges_section, "%s", name); + *p = '\0'; + } + else + dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset, + "%s (offset from %s)", name, ranges_section_label); +} + +/* Output the offset into the debug_loc section. */ + +static void +output_loc_list_offset (dw_attr_ref a) +{ + char *sym = AT_loc_list (a)->ll_symbol; + + gcc_assert (sym); + if (dwarf_split_debug_info) + dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label, + "%s", dwarf_attr_name (a->dw_attr)); + else + dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section, + "%s", dwarf_attr_name (a->dw_attr)); +} + +/* Output an attribute's index or value appropriately. */ + +static void +output_attr_index_or_value (dw_attr_ref a) +{ + const char *name = dwarf_attr_name (a->dw_attr); + + if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED) + { + dw2_asm_output_data_uleb128 (AT_index (a), "%s", name); + return; + } + switch (AT_class (a)) + { + case dw_val_class_addr: + dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name); + break; + case dw_val_class_high_pc: + case dw_val_class_lbl_id: + dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name); + break; + case dw_val_class_loc_list: + output_loc_list_offset (a); + break; + default: + gcc_unreachable (); + } } /* Output a type signature. */ @@ -7810,7 +8347,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: @@ -7819,15 +8356,7 @@ output_die (dw_die_ref die) break; case dw_val_class_range_list: - { - char *p = strchr (ranges_section_label, '\0'); - - sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, - a->dw_attr_val.v.val_offset); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label, - debug_ranges_section, "%s", name); - *p = '\0'; - } + output_range_list_offset (a); break; case dw_val_class_loc: @@ -7883,7 +8412,7 @@ output_die (dw_die_ref die) } dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR, - first, name); + first, "%s", name); dw2_asm_output_data (HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR, second, NULL); } @@ -7930,13 +8459,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: @@ -7993,7 +8516,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: @@ -8007,12 +8530,15 @@ output_die (dw_die_ref die) break; case dw_val_class_str: - if (AT_string_form (a) == DW_FORM_strp) - dw2_asm_output_offset (DWARF_OFFSET_SIZE, - a->dw_attr_val.v.val_str->label, - debug_str_section, - "%s: \"%s\"", name, AT_string (a)); - else + if (a->dw_attr_val.v.val_str->form == DW_FORM_strp) + dw2_asm_output_offset (DWARF_OFFSET_SIZE, + a->dw_attr_val.v.val_str->label, + debug_str_section, + "%s: \"%s\"", name, AT_string (a)); + else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index) + dw2_asm_output_data_uleb128 (AT_index (a), + "%s: \"%s\"", name, AT_string (a)); + else dw2_asm_output_nstring (AT_string (a), -1, "%s", name); break; @@ -8155,6 +8681,96 @@ add_AT_pubnames (dw_die_ref die) add_AT_flag (die, DW_AT_GNU_pubnames, 1); } +/* Helper function to generate top-level dies for skeleton debug_info and + debug_types. */ + +static void +add_top_level_skeleton_die_attrs (dw_die_ref die) +{ + const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL); + dw_attr_ref attr; + + add_comp_dir_attribute (die); + add_AT_string (die, DW_AT_GNU_dwo_name, dwo_file_name); + /* The specification suggests that these attributes be inline to avoid + having a .debug_str section. We know that they exist in the die because + we just added them. */ + attr = get_AT (die, DW_AT_GNU_dwo_name); + attr->dw_attr_val.v.val_str->form = DW_FORM_string; + attr = get_AT (die, DW_AT_comp_dir); + attr->dw_attr_val.v.val_str->form = DW_FORM_string; + + add_AT_pubnames (die); + add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label); +} + +/* Return the single type-unit die for skeleton type units. */ + +static dw_die_ref +get_skeleton_type_unit (void) +{ + /* For dwarf_split_debug_sections with use_type info, all type units in the + skeleton sections have identical dies (but different headers). This + single die will be output many times. */ + + static dw_die_ref skeleton_type_unit = NULL; + + if (skeleton_type_unit == NULL) + { + skeleton_type_unit = new_die (DW_TAG_type_unit, NULL, NULL); + add_top_level_skeleton_die_attrs (skeleton_type_unit); + skeleton_type_unit->die_abbrev = SKELETON_TYPE_DIE_ABBREV; + } + return skeleton_type_unit; +} + +/* Output skeleton debug sections that point to the dwo file. */ + +static void +output_skeleton_debug_sections (dw_die_ref comp_unit) +{ + /* These attributes will be found in the full debug_info section. */ + remove_AT (comp_unit, DW_AT_producer); + remove_AT (comp_unit, DW_AT_language); + + /* Add attributes common to skeleton compile_units and type_units. */ + add_top_level_skeleton_die_attrs (comp_unit); + + switch_to_section (debug_skeleton_info_section); + ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_info_section_label); + + /* Produce the skeleton compilation-unit header. This one differs enough from + a normal CU header that it's better not to call output_compilation_unit + header. */ + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + dw2_asm_output_data (4, 0xffffffff, + "Initial length escape value indicating 64-bit DWARF extension"); + + dw2_asm_output_data (DWARF_OFFSET_SIZE, + DWARF_COMPILE_UNIT_HEADER_SIZE + - DWARF_INITIAL_LENGTH_SIZE + + size_of_die (comp_unit), + "Length of Compilation Unit Info"); + dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label, + debug_abbrev_section, + "Offset Into Abbrev. Section"); + dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); + + comp_unit->die_abbrev = SKELETON_COMP_DIE_ABBREV; + output_die (comp_unit); + + /* Build the skeleton debug_abbrev section. */ + switch_to_section (debug_skeleton_abbrev_section); + ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_abbrev_section_label); + + output_die_abbrevs (SKELETON_COMP_DIE_ABBREV, comp_unit); + if (use_debug_types) + output_die_abbrevs (SKELETON_TYPE_DIE_ABBREV, get_skeleton_type_unit ()); + + dw2_asm_output_data (1, 0, "end of skeleton .debug_abbrev"); +} + /* Output a comdat type unit DIE and its children. */ static void @@ -8182,7 +8798,11 @@ output_comdat_type_unit (comdat_type_node *node) calc_die_sizes (node->root_die); #if defined (OBJECT_FORMAT_ELF) - secname = ".debug_types"; + if (!dwarf_split_debug_info) + secname = ".debug_types"; + else + secname = ".debug_types.dwo"; + tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2); sprintf (tmp, "wt."); for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++) @@ -8208,6 +8828,36 @@ output_comdat_type_unit (comdat_type_node *node) output_die (node->root_die); unmark_dies (node->root_die); + + if (dwarf_split_debug_info) + { + /* Produce the skeleton type-unit header. */ + const char *secname = ".debug_types"; + + targetm.asm_out.named_section (secname, + SECTION_DEBUG | SECTION_LINKONCE, + comdat_key); + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + dw2_asm_output_data (4, 0xffffffff, + "Initial length escape value indicating 64-bit DWARF extension"); + + dw2_asm_output_data (DWARF_OFFSET_SIZE, + DWARF_COMPILE_UNIT_HEADER_SIZE + - DWARF_INITIAL_LENGTH_SIZE + + size_of_die (get_skeleton_type_unit ()) + + DWARF_TYPE_SIGNATURE_SIZE + DWARF_OFFSET_SIZE, + "Length of Type Unit Info"); + dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, + debug_skeleton_abbrev_section_label, + debug_abbrev_section, + "Offset Into Abbrev. Section"); + dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); + output_signature (node->signature, "Type Signature"); + dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "Offset to Type DIE"); + + output_die (get_skeleton_type_unit ()); + } } /* Return the DWARF2/3 pubname associated with a decl. */ @@ -8243,7 +8893,7 @@ add_pubname (tree decl, dw_die_ref die) class_member, it will either be inside the class already, or will have just looked up the class to find the member. Either way, searching the class is faster than searching the index. */ - if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent)) + if ((TREE_PUBLIC (decl) && !class_scope_p (die->die_parent)) || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent)) { const char *name = dwarf2_name (decl, 1); @@ -8351,9 +9001,14 @@ output_pubnames (VEC (pubname_entry, gc) * names) "Length of Public Type Names Info"); /* Version number for pubnames/pubtypes is still 2, even in DWARF3. */ dw2_asm_output_data (2, 2, "DWARF Version"); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, - debug_info_section, - "Offset of Compilation Unit Info"); + if (dwarf_split_debug_info) + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label, + debug_skeleton_info_section, + "Offset of Compilation Unit Info"); + else + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, + debug_info_section, + "Offset of Compilation Unit Info"); dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset, "Compilation Unit Length"); @@ -8414,9 +9069,14 @@ output_aranges (unsigned long aranges_length) "Length of Address Ranges Info"); /* Version number for aranges is still 2, even in DWARF3. */ dw2_asm_output_data (2, 2, "DWARF Version"); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, - debug_info_section, - "Offset of Compilation Unit Info"); + if (dwarf_split_debug_info) + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label, + debug_skeleton_info_section, + "Offset of Compilation Unit Info"); + else + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, + debug_info_section, + "Offset of Compilation Unit Info"); dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address"); dw2_asm_output_data (1, 0, "Size of Segment Descriptor"); @@ -8513,12 +9173,14 @@ add_ranges (const_tree block) return add_ranges_num (block ? BLOCK_NUMBER (block) : 0); } -/* Add a new entry to .debug_ranges corresponding to a pair of - labels. */ +/* Add a new entry to .debug_ranges corresponding to a pair of labels. + When using dwarf_split_debug_info, address attributes in dies destined + for the final executable should be direct references--setting the + parameter force_direct ensures this behavior. */ static void add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end, - bool *added) + bool *added, bool force_direct) { unsigned int in_use = ranges_by_label_in_use; unsigned int offset; @@ -8541,7 +9203,7 @@ add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end, offset = add_ranges_num (-(int)in_use - 1); if (!*added) { - add_AT_range_list (die, DW_AT_ranges, offset); + add_AT_range_list (die, DW_AT_ranges, offset, force_direct); *added = true; } } @@ -9078,7 +9740,7 @@ output_one_line_info_table (dw_line_info_table *table) information goes into the .debug_line section. */ static void -output_line_info (void) +output_line_info (bool prologue_only) { char l1[20], l2[20], p1[20], p2[20]; int ver = dwarf_version; @@ -9148,6 +9810,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; + } if (separate_line_info) { @@ -11452,14 +12120,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel) break; - /* We used to emit DW_OP_addr here, but that's wrong, since - DW_OP_addr should be relocated by the debug info consumer, - while DW_OP_GNU_push_tls_address operand should not. */ - temp = new_loc_descr (DWARF2_ADDR_SIZE == 4 - ? DW_OP_const4u : DW_OP_const8u, 0, 0); - temp->dw_loc_oprnd1.val_class = dw_val_class_addr; - temp->dw_loc_oprnd1.v.val_addr = rtl; - temp->dtprel = true; + temp = new_addr_loc_descr (rtl, dtprel_true); mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0); add_loc_descr (&mem_loc_result, temp); @@ -11471,9 +12132,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, break; symref: - mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0); - mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; - mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl; + mem_loc_result = new_addr_loc_descr (rtl, dtprel_false); VEC_safe_push (rtx, gc, used_rtx_array, rtl); break; @@ -12377,9 +13036,7 @@ loc_descriptor (rtx rtl, enum machine_mode mode, if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE && (dwarf_version >= 4 || !dwarf_strict)) { - loc_result = new_loc_descr (DW_OP_addr, 0, 0); - loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; - loc_result->dw_loc_oprnd1.v.val_addr = rtl; + loc_result = new_addr_loc_descr (rtl, dtprel_false); add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0)); VEC_safe_push (rtx, gc, used_rtx_array, rtl); } @@ -13079,9 +13736,8 @@ loc_list_from_tree (tree loc, int want_address) if (DECL_THREAD_LOCAL_P (loc)) { rtx rtl; - enum dwarf_location_atom first_op; - enum dwarf_location_atom second_op; - bool dtprel = false; + enum dwarf_location_atom tls_op; + enum dtprel_bool dtprel = dtprel_false; if (targetm.have_tls) { @@ -13098,9 +13754,8 @@ loc_list_from_tree (tree loc, int want_address) operand shouldn't be. */ if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc)) return 0; - first_op = DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u; - dtprel = true; - second_op = DW_OP_GNU_push_tls_address; + dtprel = dtprel_true; + tls_op = DW_OP_GNU_push_tls_address; } else { @@ -13112,8 +13767,7 @@ loc_list_from_tree (tree loc, int want_address) no longer appear in gimple code. We used the control variable in specific so that we could pick it up here. */ loc = DECL_VALUE_EXPR (loc); - first_op = DW_OP_addr; - second_op = DW_OP_form_tls_address; + tls_op = DW_OP_form_tls_address; } rtl = rtl_for_decl_location (loc); @@ -13126,12 +13780,8 @@ loc_list_from_tree (tree loc, int want_address) if (! CONSTANT_P (rtl)) return 0; - ret = new_loc_descr (first_op, 0, 0); - ret->dw_loc_oprnd1.val_class = dw_val_class_addr; - ret->dw_loc_oprnd1.v.val_addr = rtl; - ret->dtprel = dtprel; - - ret1 = new_loc_descr (second_op, 0, 0); + ret = new_addr_loc_descr (rtl, dtprel); + ret1 = new_loc_descr (tls_op, 0, 0); add_loc_descr (&ret, ret1); have_address = 1; @@ -13176,11 +13826,7 @@ loc_list_from_tree (tree loc, int want_address) return 0; } else if (CONSTANT_P (rtl) && const_ok_for_output (rtl)) - { - ret = new_loc_descr (DW_OP_addr, 0, 0); - ret->dw_loc_oprnd1.val_class = dw_val_class_addr; - ret->dw_loc_oprnd1.v.val_addr = rtl; - } + ret = new_addr_loc_descr (rtl, dtprel_false); else { enum machine_mode mode, mem_mode; @@ -14105,9 +14751,7 @@ add_const_value_attribute (dw_die_ref die, rtx rtl) dw_loc_descr_ref loc_result; resolve_one_addr (&rtl, NULL); rtl_addr: - loc_result = new_loc_descr (DW_OP_addr, 0, 0); - loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; - loc_result->dw_loc_oprnd1.v.val_addr = rtl; + loc_result = new_addr_loc_descr (rtl, dtprel_false); add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0)); add_AT_loc (die, DW_AT_location, loc_result); VEC_safe_push (rtx, gc, used_rtx_array, rtl); @@ -15627,7 +16271,7 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl) if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl)) { add_AT_addr (die, DW_AT_VMS_rtnbeg_pd_address, - XEXP (DECL_RTL (decl), 0)); + XEXP (DECL_RTL (decl), 0), false); VEC_safe_push (rtx, gc, used_rtx_array, XEXP (DECL_RTL (decl), 0)); } #endif /* VMS_DEBUGGING_INFO */ @@ -16896,7 +17540,7 @@ gen_call_site_die (tree decl, dw_die_ref subr_die, if (tdie) add_AT_die_ref (die, DW_AT_abstract_origin, tdie); else - add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref); + add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref, false); } return die; } @@ -17089,7 +17733,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (fde->dw_fde_begin) { /* We have already generated the labels. */ - add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end); + add_AT_low_high_pc (subr_die, fde->dw_fde_begin, + fde->dw_fde_end, false); } else { @@ -17100,7 +17745,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) current_function_funcdef_no); ASM_GENERATE_INTERNAL_LABEL (label_id_high, FUNC_END_LABEL, current_function_funcdef_no); - add_AT_low_high_pc (subr_die, label_id_low, label_id_high); + add_AT_low_high_pc (subr_die, label_id_low, label_id_high, + false); } #if VMS_DEBUGGING_INFO @@ -17143,10 +17789,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) alignment offset. */ bool range_list_added = false; add_ranges_by_labels (subr_die, fde->dw_fde_begin, - fde->dw_fde_end, &range_list_added); + fde->dw_fde_end, &range_list_added, + false); add_ranges_by_labels (subr_die, fde->dw_fde_second_begin, fde->dw_fde_second_end, - &range_list_added); + &range_list_added, false); if (range_list_added) add_ranges (NULL); } @@ -17165,7 +17812,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) /* Do the 'primary' section. */ add_AT_low_high_pc (subr_die, fde->dw_fde_begin, - fde->dw_fde_end); + fde->dw_fde_end, false); /* Build a minimal DIE for the secondary section. */ seg_die = new_die (DW_TAG_subprogram, @@ -17190,14 +17837,15 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) name = concat ("__second_sect_of_", name, NULL); add_AT_low_high_pc (seg_die, fde->dw_fde_second_begin, - fde->dw_fde_second_end); + fde->dw_fde_second_end, false); add_name_attribute (seg_die, name); if (want_pubnames ()) add_pubname_string (name, seg_die); } } else - add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end); + add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end, + false); } cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl); @@ -17638,7 +18286,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) { /* Optimize the common case. */ if (single_element_loc_list_p (loc) - && loc->expr->dw_loc_opc == DW_OP_addr + && loc->expr->dw_loc_opc == DW_OP_addr && loc->expr->dw_loc_next == NULL && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF) { @@ -17825,7 +18473,7 @@ gen_label_die (tree decl, dw_die_ref context_die) gcc_assert (!INSN_DELETED_P (insn)); ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn)); - add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); + add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); } else if (insn && NOTE_P (insn) @@ -17833,7 +18481,7 @@ gen_label_die (tree decl, dw_die_ref context_die) && CODE_LABEL_NUMBER (insn) != -1) { ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn)); - add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); + add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); } } } @@ -17874,7 +18522,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die) { ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, BLOCK_NUMBER (stmt)); - add_AT_lbl_id (die, DW_AT_entry_pc, label); + add_AT_lbl_id (die, DW_AT_entry_pc, label); } /* Optimize duplicate .debug_ranges lists or even tails of @@ -17922,12 +18570,13 @@ add_high_low_attributes (tree stmt, dw_die_ref die) ++thiscnt; gcc_assert (supercnt >= thiscnt); add_AT_range_list (die, DW_AT_ranges, - (off + supercnt - thiscnt) - * 2 * DWARF2_ADDR_SIZE); + ((off + supercnt - thiscnt) + * 2 * DWARF2_ADDR_SIZE), + false); return; } - add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt)); + add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt), false); chain = BLOCK_FRAGMENT_CHAIN (stmt); do @@ -17945,7 +18594,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die) BLOCK_NUMBER (stmt)); ASM_GENERATE_INTERNAL_LABEL (label_high, BLOCK_END_LABEL, BLOCK_NUMBER (stmt)); - add_AT_low_high_pc (die, label, label_high); + add_AT_low_high_pc (die, label, label_high, false); } } @@ -20539,23 +21188,22 @@ output_macinfo_op (macinfo_entry *ref) case DW_MACRO_GNU_define_indirect: case DW_MACRO_GNU_undef_indirect: node = find_AT_string (ref->info); - if (node->form != DW_FORM_strp) - { - char label[32]; - ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter); - ++dw2_string_counter; - node->label = xstrdup (label); - node->form = DW_FORM_strp; - } + gcc_assert (node + && ((node->form == DW_FORM_strp) + || (node->form == DW_FORM_GNU_str_index))); dw2_asm_output_data (1, ref->code, ref->code == DW_MACRO_GNU_define_indirect ? "Define macro indirect" : "Undefine macro indirect"); dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu", (unsigned long) ref->lineno); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, - debug_str_section, "The macro: \"%s\"", - ref->info); + if (node->form == DW_FORM_strp) + dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label, + debug_str_section, "The macro: \"%s\"", + ref->info); + else + dw2_asm_output_data_uleb128 (node->index, "The macro: \"%s\"", + ref->info); break; case DW_MACRO_GNU_transparent_include: dw2_asm_output_data (1, ref->code, "Transparent include"); @@ -20698,6 +21346,42 @@ optimize_macinfo_range (unsigned int idx, VEC (macinfo_entry, gc) *files, return count; } +/* Save any strings needed by the macinfo table in the debug str + table. All strings must be collected into the table by the time + index_string is called. */ + +static void +save_macinfo_strings (void) +{ + unsigned len; + unsigned i; + macinfo_entry *ref; + + for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++) + { + switch (ref->code) + { + /* Match the logic in output_macinfo_op to decide on + indirect strings. */ + case DW_MACINFO_define: + case DW_MACINFO_undef: + len = strlen (ref->info) + 1; + if (!dwarf_strict + && len > DWARF_OFFSET_SIZE + && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET + && (debug_str_section->common.flags & SECTION_MERGE) != 0) + set_indirect_string (find_AT_string (ref->info)); + break; + case DW_MACRO_GNU_define_indirect: + case DW_MACRO_GNU_undef_indirect: + set_indirect_string (find_AT_string (ref->info)); + break; + default: + break; + } + } +} + /* Output macinfo section(s). */ static void @@ -20726,8 +21410,10 @@ output_macinfo (void) dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present"); else dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present"); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_section_label, - debug_line_section, NULL); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, + (!dwarf_split_debug_info ? debug_line_section_label + : debug_skeleton_line_section_label), + debug_line_section, NULL); } /* In the first loop, it emits the primary .debug_macinfo section @@ -20866,20 +21552,54 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) used_rtx_array = VEC_alloc (rtx, gc, 32); - debug_info_section = get_section (DEBUG_INFO_SECTION, - SECTION_DEBUG, NULL); - debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION, - SECTION_DEBUG, NULL); + if (!dwarf_split_debug_info) + { + debug_info_section = get_section (DEBUG_INFO_SECTION, + SECTION_DEBUG, NULL); + debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION, + SECTION_DEBUG, NULL); + debug_loc_section = get_section (DEBUG_LOC_SECTION, + SECTION_DEBUG, NULL); + } + else + { + debug_info_section = get_section (DEBUG_DWO_INFO_SECTION, + SECTION_DEBUG | SECTION_EXCLUDE, NULL); + debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION, + SECTION_DEBUG | SECTION_EXCLUDE, + NULL); + debug_addr_section = get_section (DEBUG_ADDR_SECTION, + SECTION_DEBUG, NULL); + debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION, + SECTION_DEBUG, NULL); + debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION, + SECTION_DEBUG, NULL); + ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label, + DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0); + + /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in + the main .o, but the skeleton_line goes into the split off dwo. */ + debug_skeleton_line_section + = get_section (DEBUG_DWO_LINE_SECTION, + SECTION_DEBUG | SECTION_EXCLUDE, NULL); + ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label, + DEBUG_SKELETON_LINE_SECTION_LABEL, 0); + debug_str_offsets_section = get_section (DEBUG_STR_OFFSETS_SECTION, + SECTION_DEBUG | SECTION_EXCLUDE, + NULL); + ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label, + DEBUG_SKELETON_INFO_SECTION_LABEL, 0); + debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION, + SECTION_DEBUG | SECTION_EXCLUDE, NULL); + } debug_aranges_section = get_section (DEBUG_ARANGES_SECTION, SECTION_DEBUG, NULL); debug_macinfo_section = get_section (dwarf_strict ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION, - SECTION_DEBUG, NULL); + DEBUG_MACRO_SECTION_FLAGS, NULL); debug_line_section = get_section (DEBUG_LINE_SECTION, SECTION_DEBUG, NULL); - debug_loc_section = get_section (DEBUG_LOC_SECTION, - SECTION_DEBUG, NULL); debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION, SECTION_DEBUG, NULL); debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION, @@ -20905,10 +21625,13 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) DEBUG_LINE_SECTION_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (ranges_section_label, DEBUG_RANGES_SECTION_LABEL, 0); + ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label, + DEBUG_ADDR_SECTION_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label, dwarf_strict ? DEBUG_MACINFO_SECTION_LABEL : DEBUG_MACRO_SECTION_LABEL, 0); + ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0); if (debug_info_level >= DINFO_LEVEL_VERBOSE) macinfo_table = VEC_alloc (macinfo_entry, gc, 64); @@ -20935,6 +21658,71 @@ dwarf2out_assembly_start (void) } /* A helper function for dwarf2out_finish called through + htab_traverse. Assign a string its index. All strings must be + collected into the table by the time index_string is called, + because the indexing code relies on htab_traverse to traverse nodes + in the same order for each run. */ + +static int +index_string (void **h, void *v) +{ + struct indirect_string_node *node = (struct indirect_string_node *) *h; + unsigned int *index = (unsigned int *) v; + + find_string_form (node); + if (node->form == DW_FORM_GNU_str_index && node->refcount > 0) + { + gcc_assert(node->index == NO_INDEX_ASSIGNED); + node->index = *index; + *index += 1; + } + return 1; +} + +/* A helper function for output_indirect_strings called through + htab_traverse. Output the offset to a string and update the + current offset. */ + +static int +output_index_string_offset (void **h, void *v) +{ + struct indirect_string_node *node = (struct indirect_string_node *) *h; + unsigned int *offset = (unsigned int *) v; + + if (node->form == DW_FORM_GNU_str_index && node->refcount > 0) + { + /* Assert that this node has been assigned an index. */ + gcc_assert (node->index != NO_INDEX_ASSIGNED + && node->index != NOT_INDEXED); + dw2_asm_output_data (DWARF_OFFSET_SIZE, *offset, + "indexed string 0x%x: %s", node->index, node->str); + *offset += strlen (node->str) + 1; + } + return 1; +} + +/* A helper function for dwarf2out_finish called through + htab_traverse. Output the indexed string. */ + +static int +output_index_string (void **h, void *v) +{ + struct indirect_string_node *node = (struct indirect_string_node *) *h; + unsigned int *cur_idx = (unsigned int *) v; + + if (node->form == DW_FORM_GNU_str_index && node->refcount > 0) + { + /* Assert that the strings are output in the same order as their + indexes were assigned. */ + gcc_assert (*cur_idx == node->index); + ASM_OUTPUT_LABEL (asm_out_file, node->label); + assemble_string (node->str, strlen (node->str) + 1); + *cur_idx += 1; + } + return 1; +} + +/* A helper function for dwarf2out_finish called through htab_traverse. Emit one queued .debug_str string. */ static int @@ -20942,9 +21730,8 @@ output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED) { struct indirect_string_node *node = (struct indirect_string_node *) *h; - if (node->form == DW_FORM_strp) + if (node->form == DW_FORM_strp && node->refcount > 0) { - switch_to_section (debug_str_section); ASM_OUTPUT_LABEL (asm_out_file, node->label); assemble_string (node->str, strlen (node->str) + 1); } @@ -20952,6 +21739,87 @@ output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED) return 1; } +/* Output the indexed string table. */ + +static void +output_indirect_strings (void) +{ + if (!dwarf_split_debug_info) + { + switch_to_section (debug_str_section); + htab_traverse (debug_str_hash, output_indirect_string, NULL); + } + else + { + unsigned int offset = 0; + unsigned int cur_idx = 0; + + switch_to_section (debug_str_offsets_section); + htab_traverse_noresize (debug_str_hash, + output_index_string_offset, + &offset); + switch_to_section (debug_str_section); + htab_traverse_noresize (debug_str_hash, + output_index_string, + &cur_idx); + } +} + +/* Callback for htab_traverse to assign an index to an entry in the + table, and to write that entry to the .debug_addr section. */ + +static int +output_addr_table_entry (void **slot, void *data) +{ + addr_table_entry *entry = (addr_table_entry *) *slot; + unsigned int *cur_index = (unsigned int *)data; + + if (entry->refcount == 0) + { + gcc_assert (entry->index == NO_INDEX_ASSIGNED + || entry->index == NOT_INDEXED); + return 1; + } + + gcc_assert (entry->index == *cur_index); + (*cur_index)++; + + switch (entry->kind) + { + case ate_kind_rtx: + dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, entry->addr.rtl, + "0x%x", entry->index); + break; + case ate_kind_rtx_dtprel: + gcc_assert (targetm.asm_out.output_dwarf_dtprel); + targetm.asm_out.output_dwarf_dtprel (asm_out_file, + DWARF2_ADDR_SIZE, + entry->addr.rtl); + fputc ('\n', asm_out_file); + break; + case ate_kind_label: + dw2_asm_output_addr (DWARF2_ADDR_SIZE, entry->addr.label, + "0x%x", entry->index); + break; + default: + gcc_unreachable (); + } + return 1; +} + +/* Produce the .debug_addr section. */ + +static void +output_addr_table (void) +{ + unsigned int index = 0; + if (addr_index_table == NULL || htab_size (addr_index_table) == 0) + return; + + switch_to_section (debug_addr_section); + htab_traverse_noresize (addr_index_table, output_addr_table_entry, &index); +} + #if ENABLE_ASSERT_CHECKING /* Verify that all marks are clear. */ @@ -21571,6 +22439,16 @@ resolve_addr_in_expr (dw_loc_descr_ref loc) if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL)) return false; break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + { + if ((loc->dw_loc_opc == DW_OP_GNU_addr_index + || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel)) + && resolve_one_addr (&loc->dw_loc_oprnd1.val_entry->addr.rtl, + NULL)) + return false; + } + break; case DW_OP_const4u: case DW_OP_const8u: if (loc->dtprel @@ -21705,11 +22583,15 @@ resolve_addr (dw_die_ref die) if (!resolve_addr_in_expr ((*curr)->expr)) { dw_loc_list_ref next = (*curr)->dw_loc_next; + dw_loc_descr_ref l = (*curr)->expr; + if (next && (*curr)->ll_symbol) { gcc_assert (!next->ll_symbol); next->ll_symbol = (*curr)->ll_symbol; } + if (dwarf_split_debug_info) + remove_loc_list_addr_table_entries (l); *curr = next; } else @@ -21723,6 +22605,8 @@ resolve_addr (dw_die_ref die) else { loc->replaced = 1; + if (dwarf_split_debug_info) + remove_loc_list_addr_table_entries (loc->expr); loc->dw_loc_next = *start; } } @@ -21747,6 +22631,8 @@ resolve_addr (dw_die_ref die) || l->dw_loc_next != NULL) && !resolve_addr_in_expr (l)) { + if (dwarf_split_debug_info) + remove_loc_list_addr_table_entries (l); remove_AT (die, a->dw_attr); ix--; } @@ -21758,6 +22644,8 @@ resolve_addr (dw_die_ref die) if (a->dw_attr == DW_AT_const_value && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL)) { + if (AT_index (a) != NOT_INDEXED) + remove_addr_table_entry (a->dw_attr_val.val_entry); remove_AT (die, a->dw_attr); ix--; } @@ -21781,6 +22669,8 @@ resolve_addr (dw_die_ref die) } else { + if (AT_index (a) != NOT_INDEXED) + remove_addr_table_entry (a->dw_attr_val.val_entry); remove_AT (die, a->dw_attr); ix--; } @@ -21914,6 +22804,17 @@ hash_loc_operands (dw_loc_descr_ref loc, hashval_t hash) } hash = iterative_hash_rtx (val1->v.val_addr, hash); break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + { + if (loc->dtprel) + { + unsigned char dtprel = 0xd1; + hash = iterative_hash_object (dtprel, hash); + } + hash = iterative_hash_rtx (val1->val_entry->addr.rtl, hash); + } + break; case DW_OP_GNU_implicit_pointer: hash = iterative_hash_object (val2->v.val_int, hash); break; @@ -22095,9 +22996,12 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y) return valx1->v.val_int == valy1->v.val_int; case DW_OP_skip: case DW_OP_bra: + /* If splitting debug info, the use of DW_OP_GNU_addr_index + can cause irrelevant differences in dw_loc_addr. */ gcc_assert (valx1->val_class == dw_val_class_loc && valy1->val_class == dw_val_class_loc - && x->dw_loc_addr == y->dw_loc_addr); + && (dwarf_split_debug_info + || x->dw_loc_addr == y->dw_loc_addr)); return valx1->v.val_loc->dw_loc_addr == valy1->v.val_loc->dw_loc_addr; case DW_OP_implicit_value: if (valx1->v.val_unsigned != valy1->v.val_unsigned @@ -22128,6 +23032,13 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y) case DW_OP_addr: hash_addr: return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr); + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + { + rtx ax1 = valx1->val_entry->addr.rtl; + rtx ay1 = valy1->val_entry->addr.rtl; + return rtx_equal_p (ax1, ay1); + } case DW_OP_GNU_implicit_pointer: return valx1->val_class == dw_val_class_die_ref && valx1->val_class == valy1->val_class @@ -22241,12 +23152,45 @@ optimize_location_lists_1 (dw_die_ref die, htab_t htab) if (*slot == NULL) *slot = (void *) list; else - a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot; + a->dw_attr_val.v.val_loc_list = (dw_loc_list_ref) *slot; } FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab)); } + +/* Recursively assign each location list a unique index into the debug_addr + section. */ + +static void +index_location_lists (dw_die_ref die) +{ + dw_die_ref c; + dw_attr_ref a; + unsigned ix; + + FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a) + if (AT_class (a) == dw_val_class_loc_list) + { + dw_loc_list_ref list = AT_loc_list (a); + dw_loc_list_ref curr; + for (curr = list; curr != NULL; curr = curr->dw_loc_next) + { + /* Don't index an entry that has already been indexed + or won't be output. */ + if (curr->begin_entry != NULL + || (strcmp (curr->begin, curr->end) == 0 && !curr->force)) + continue; + + curr->begin_entry + = add_addr_table_entry (xstrdup (curr->begin), + ate_kind_label); + } + } + + FOR_EACH_CHILD (die, c, index_location_lists (c)); +} + /* Optimize location lists referenced from DIE children and share them whenever possible. */ @@ -22268,6 +23212,7 @@ dwarf2out_finish (const char *filename) comdat_type_node *ctnode; htab_t comdat_type_table; unsigned int i; + dw_die_ref main_comp_unit_die; /* PCH might result in DW_AT_producer string being restored from the header compilation, fix it up if needed. */ @@ -22420,6 +23365,14 @@ dwarf2out_finish (const char *filename) for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next) add_sibling_attributes (ctnode->root_die); + /* When splitting DWARF info, we put some attributes in the + skeleton compile_unit DIE that remains in the .o, while + most attributes go in the DWO compile_unit_die. */ + if (dwarf_split_debug_info) + main_comp_unit_die = gen_compile_unit_die (NULL); + else + main_comp_unit_die = comp_unit_die (); + /* Output a terminator label for the .text section. */ switch_to_section (text_section); targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0); @@ -22436,8 +23389,8 @@ dwarf2out_finish (const char *filename) { /* Don't add if the CU has no associated code. */ if (text_section_used) - add_AT_low_high_pc (comp_unit_die (), text_section_label, - text_end_label); + add_AT_low_high_pc (main_comp_unit_die, text_section_label, + text_end_label, true); } else { @@ -22446,22 +23399,24 @@ dwarf2out_finish (const char *filename) bool range_list_added = false; if (text_section_used) - add_ranges_by_labels (comp_unit_die (), text_section_label, - text_end_label, &range_list_added); + add_ranges_by_labels (main_comp_unit_die, text_section_label, + text_end_label, &range_list_added, true); if (cold_text_section_used) - add_ranges_by_labels (comp_unit_die (), cold_text_section_label, - cold_end_label, &range_list_added); + add_ranges_by_labels (main_comp_unit_die, cold_text_section_label, + cold_end_label, &range_list_added, true); FOR_EACH_VEC_ELT (dw_fde_ref, fde_vec, fde_idx, fde) { if (DECL_IGNORED_P (fde->decl)) continue; if (!fde->in_std_section) - add_ranges_by_labels (comp_unit_die (), fde->dw_fde_begin, - fde->dw_fde_end, &range_list_added); + add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_begin, + fde->dw_fde_end, &range_list_added, + true); if (fde->dw_fde_second_begin && !fde->second_in_std_section) - add_ranges_by_labels (comp_unit_die (), fde->dw_fde_second_begin, - fde->dw_fde_second_end, &range_list_added); + add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_second_begin, + fde->dw_fde_second_end, &range_list_added, + true); } if (range_list_added) @@ -22471,16 +23426,16 @@ dwarf2out_finish (const char *filename) absolute. Historically, we've emitted the unexpected DW_AT_entry_pc instead of DW_AT_low_pc for this purpose. Emit both to give time for other tools to adapt. */ - add_AT_addr (comp_unit_die (), DW_AT_low_pc, const0_rtx); + add_AT_addr (main_comp_unit_die, DW_AT_low_pc, const0_rtx, true); if (! dwarf_strict && dwarf_version < 4) - add_AT_addr (comp_unit_die (), DW_AT_entry_pc, const0_rtx); + add_AT_addr (main_comp_unit_die, DW_AT_entry_pc, const0_rtx, true); add_ranges (NULL); } } if (debug_info_level >= DINFO_LEVEL_NORMAL) - add_AT_lineptr (comp_unit_die (), DW_AT_stmt_list, + add_AT_lineptr (main_comp_unit_die, DW_AT_stmt_list, debug_line_section_label); if (have_macinfo) @@ -22488,9 +23443,28 @@ dwarf2out_finish (const char *filename) dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros, macinfo_section_label); + if (dwarf_split_debug_info && addr_index_table != NULL) + { + /* optimize_location_lists calculates the size of the lists, + so index them first, and assign indices to the entries. + Although optimize_location_lists will remove entries from + the table, it only does so for duplicates, and therefore + only reduces ref_counts to 1. */ + unsigned int index = 0; + index_location_lists (comp_unit_die ()); + htab_traverse_noresize (addr_index_table, + index_addr_table_entry, &index); + } if (have_location_lists) optimize_location_lists (comp_unit_die ()); + save_macinfo_strings (); + if (dwarf_split_debug_info) + { + unsigned int index = 0; + htab_traverse_noresize (debug_str_hash, index_string, &index); + } + /* Output all of the compilation units. We put the main one last so that the offsets are available to output_pubnames. */ for (node = limbo_die_list; node; node = node->next) @@ -22510,19 +23484,58 @@ dwarf2out_finish (const char *filename) attributes. */ if (debug_info_level >= DINFO_LEVEL_NORMAL) add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list, - debug_line_section_label); + (!dwarf_split_debug_info + ? debug_line_section_label + : debug_skeleton_line_section_label)); output_comdat_type_unit (ctnode); *slot = ctnode; } htab_delete (comdat_type_table); - add_AT_pubnames (comp_unit_die ()); + /* The AT_pubnames attribute needs to go in all skeleton dies, including + both the main_cu and all skeleton TUs. Making this call unconditional + would end up either adding a second copy of the AT_pubnames attribute, or + requiring a special case in add_top_level_skeleton_die_attrs. */ + if (!dwarf_split_debug_info) + add_AT_pubnames (comp_unit_die ()); + + if (dwarf_split_debug_info) + { + int mark; + unsigned char checksum[16]; + struct md5_ctx ctx; + + /* Compute a checksum of the comp_unit to use as the dwo_id. */ + md5_init_ctx (&ctx); + mark = 0; + die_checksum (comp_unit_die (), &ctx, &mark); + unmark_all_dies (comp_unit_die ()); + md5_finish_ctx (&ctx, checksum); + + /* Use the first 8 bytes of the checksum as the dwo_id, + and add it to both comp-unit DIEs. */ + add_AT_data8 (main_comp_unit_die, DW_AT_GNU_dwo_id, checksum); + add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, checksum); + + /* Add the base offset of the ranges table to the skeleton + comp-unit DIE. */ + if (ranges_table_in_use) + add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base, + ranges_section_label); + + switch_to_section (debug_addr_section); + ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label); + output_addr_table (); + } /* Output the main compilation unit if non-empty or if .debug_macinfo or .debug_macro will be emitted. */ output_comp_unit (comp_unit_die (), have_macinfo); + if (dwarf_split_debug_info && info_section_emitted) + output_skeleton_debug_sections (main_comp_unit_die); + /* Output the abbreviation table. */ if (abbrev_die_table_in_use != 1) { @@ -22536,8 +23549,6 @@ dwarf2out_finish (const char *filename) { /* Output the location lists info. */ switch_to_section (debug_loc_section); - ASM_GENERATE_INTERNAL_LABEL (loc_section_label, - DEBUG_LOC_SECTION_LABEL, 0); ASM_OUTPUT_LABEL (asm_out_file, loc_section_label); output_location_lists (comp_unit_die ()); } @@ -22588,12 +23599,18 @@ dwarf2out_finish (const char *filename) switch_to_section (debug_line_section); ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label); if (! DWARF2_ASM_LINE_DEBUG_INFO) - output_line_info (); + output_line_info (false); + + if (dwarf_split_debug_info && info_section_emitted) + { + switch_to_section (debug_skeleton_line_section); + ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label); + output_line_info (true); + } - /* If we emitted any DW_FORM_strp form attribute, output the string - table too. */ + /* If we emitted any indirect strings, output the string table too. */ if (debug_str_hash) - htab_traverse (debug_str_hash, output_indirect_string, NULL); + output_indirect_strings (); } #include "gt-dwarf2out.h" diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h index 853dce40ded..7fa62581177 100644 --- a/gcc/dwarf2out.h +++ b/gcc/dwarf2out.h @@ -167,11 +167,14 @@ typedef struct GTY(()) dw_vec_struct { } dw_vec_const; +struct addr_table_entry_struct; + /* The dw_val_node describes an attribute's value, as it is represented internally. */ typedef struct GTY(()) dw_val_struct { enum dw_val_class val_class; + struct addr_table_entry_struct * GTY(()) val_entry; union dw_val_struct_union { rtx GTY ((tag ("dw_val_class_addr"))) val_addr; diff --git a/gcc/gcc.c b/gcc/gcc.c index bbca6d84e33..a795981f002 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -267,6 +267,7 @@ static const char *compare_debug_dump_opt_spec_function (int, const char **); static const char *compare_debug_self_opt_spec_function (int, const char **); static const char *compare_debug_auxbase_opt_spec_function (int, const char **); static const char *pass_through_libs_spec_func (int, const char **); +static const char *replace_extension_spec_func (int, const char **); /* The Specs Language @@ -447,7 +448,7 @@ ignored. White space may also appear anywhere on the left side of the colon in these constructs, except between . or * and the corresponding word. -The -O, -f, -m, and -W switches are handled specifically in these +The -O, -f, -g, -m, and -W switches are handled specifically in these constructs. If another value of -O or the negated form of a -f, -m, or -W switch is found later in the command line, the earlier switch value is ignored, except with {S*} where S is just one letter; this @@ -480,7 +481,14 @@ proper position among the other output files. */ /* config.h can define ASM_FINAL_SPEC to run a post processor after the assembler has run. */ #ifndef ASM_FINAL_SPEC -#define ASM_FINAL_SPEC "" +#define ASM_FINAL_SPEC \ + "%{gsplit-dwarf: \n\ + objcopy --extract-dwo \ + %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \ + %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\ + objcopy --strip-dwo \ + %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \ + }" #endif /* config.h can define CPP_SPEC to provide extra args to the C preprocessor @@ -1262,6 +1270,7 @@ static const struct spec_function static_spec_functions[] = { "compare-debug-self-opt", compare_debug_self_opt_spec_function }, { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function }, { "pass-through-libs", pass_through_libs_spec_func }, + { "replace-extension", replace_extension_spec_func }, #ifdef EXTRA_SPEC_FUNCTIONS EXTRA_SPEC_FUNCTIONS #endif @@ -5814,7 +5823,7 @@ process_brace_body (const char *p, const char *atom, const char *end_atom, on the command line. PREFIX_LENGTH is the length of XXX in an {XXX*} spec, or -1 if either exact match or %* is used. - A -O switch is obsoleted by a later -O switch. A -f, -m, or -W switch + A -O switch is obsoleted by a later -O switch. A -f, -g, -m, or -W switch whose value does not begin with "no-" is obsoleted by the same value with the "no-", similarly for a switch with the "no-" prefix. */ @@ -5851,7 +5860,7 @@ check_live_switch (int switchnum, int prefix_length) } break; - case 'W': case 'f': case 'm': + case 'W': case 'f': case 'm': case 'g': if (! strncmp (name + 1, "no-", 3)) { /* We have Xno-YYY, search for XYYY. */ @@ -8380,3 +8389,33 @@ pass_through_libs_spec_func (int argc, const char **argv) } return prepended; } + +/* %:replace-extension spec function. Replaces the extension of the + first argument with the second argument. */ + +const char * +replace_extension_spec_func (int argc, const char **argv) +{ + char *name; + char *p; + char *result; + int i; + + if (argc != 2) + fatal_error ("too few arguments to %%:replace-extension"); + + name = xstrdup (argv[0]); + + for (i = strlen(name) - 1; i >= 0; i--) + if (IS_DIR_SEPARATOR (name[i])) + break; + + p = strrchr (name + i + 1, '.'); + if (p != NULL) + *p = '\0'; + + result = concat (name, argv[1], NULL); + + free (name); + return result; +} diff --git a/gcc/opts.c b/gcc/opts.c index 3160b8cc521..34c5698ba30 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -829,6 +829,9 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, maybe_set_param_value (PARAM_MAX_STORES_TO_SINK, 0, opts->x_param_values, opts_set->x_param_values); + /* The -gsplit-dwarf option requires -gpubnames. */ + if (opts->x_dwarf_split_debug_info) + opts->x_debug_generate_pub_sections = 1; } #define LEFT_COLUMN 27 @@ -1705,6 +1708,11 @@ common_handle_option (struct gcc_options *opts, set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc); break; + case OPT_gsplit_dwarf: + set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, "", opts, opts_set, + loc); + break; + case OPT_ggdb: set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc); break; diff --git a/include/ChangeLog b/include/ChangeLog index e5d3e87b920..afac33a7aef 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,11 @@ +2012-10-29 Sterling Augustine <saugustine@google.com> + Cary Coutant <ccoutant@google.com> + + * dwarf2.h (dwarf_location_list_entry_type): New enum with fields + DW_LLE_GNU_end_of_list_entry, DW_LLE_GNU_base_address_selection_entry, + DW_LLE_GNU_start_end_entry and DW_LLE_GNU_start_length_entry. + + 2012-10-08 Jason Merrill <jason@redhat.com> * demangle.h (enum demangle_component_type): Add diff --git a/include/dwarf2.h b/include/dwarf2.h index 2c1aeb6b912..e98505ac2f9 100644 --- a/include/dwarf2.h +++ b/include/dwarf2.h @@ -259,6 +259,17 @@ enum dwarf_line_number_hp_sfc_ops DW_LNE_HP_SFC_associate = 3 }; +/* Type codes for location list entries. + Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ + +enum dwarf_location_list_entry_type + { + DW_LLE_GNU_end_of_list_entry = 0, + DW_LLE_GNU_base_address_selection_entry = 1, + DW_LLE_GNU_start_end_entry = 2, + DW_LLE_GNU_start_length_entry = 3 + }; + #define DW_CIE_ID 0xffffffff #define DW64_CIE_ID 0xffffffffffffffffULL #define DW_CIE_VERSION 1 |