From patchwork Wed Jul 25 00:08:44 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cary Coutant X-Patchwork-Id: 173083 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id EC4502C008D for ; Wed, 25 Jul 2012 10:09:37 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1343779779; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Received:Received:Received:To:Subject:Message-Id:Date: From:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=na3SJjA 4u3ACb0t3y6A5h8GQeFc=; b=elHiT9vBDfQl1+sEzSC8DaZAfaVxJhpa3qN3SrO NFGVxepCbpG3ygZ3JC8b9w72eSZ9gCZSlK0ovaB2QuZ703r84lklyLaOuXsTTReQ 96ebwPGqPe2F6gNQIy5Q2RL8eZ84blJ0ki0NT8r8Ygjusf/8g8pHNwIk/4+LU3IX sRKo= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:X-Google-DKIM-Signature:Received:Received:Received:Received:Received:To:Subject:Message-Id:Date:From:X-Gm-Message-State:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=I0cMMhvyVLomCLjG604MQ7rfcOHlxu/mS/jHgC0/Q8wCR46tps5+1knkWot7SV IXxncS6V63YqE+gwUODWj011ZS0achOXWWHoROs0TXfIyM4R8oew7IbeoWvAFLwy y6E0BREABhwKwhiUUrBUbvVRxvsITzF+LZLZva6xeJI7Q=; Received: (qmail 5363 invoked by alias); 25 Jul 2012 00:09:25 -0000 Received: (qmail 5310 invoked by uid 22791); 25 Jul 2012 00:09:12 -0000 X-SWARE-Spam-Status: No, hits=-4.0 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, KHOP_RCVD_TRUST, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE, TW_BJ, TW_CP, TW_JC, TW_TM, TW_XF, T_RP_MATCHES_RCVD, URIBL_DBL_REDIR X-Spam-Check-By: sourceware.org Received: from mail-wg0-f73.google.com (HELO mail-wg0-f73.google.com) (74.125.82.73) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 25 Jul 2012 00:08:48 +0000 Received: by wgbdt12 with SMTP id dt12so3720wgb.2 for ; Tue, 24 Jul 2012 17:08:46 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=to:subject:message-id:date:from:x-gm-message-state; bh=smfZ7BF2vnkfwlXKiEPvGPZf+TIThBfsWgu5iNOBI4Q=; b=lL541I/y5qsAOk6lv0IHtsQBZKg7IpuQdn5ZTFMge73XEPvw8TOlQbrsPYJtihfw5n SU7roEULJjtgtGNKTM87uJ083pmX+Ha51pK7aSsupx1GM7RNYIxIeyyWH6Rfe0Cu4rUd sYpp9XV/lNVUWGbu6hV7tm0EBFnkw6+HNLW0a6exVpQOXPDAzggog57xdAWs7LRpN5lu ajGnPOBRR0S6yr1epoDTwQoBgT3Ec4JlWqpJ9OTacLhqSUHgfnZqVCJCEzwhhotsRGHP tVrI1/7p87wExZZ7zvYdQueJuiH6/Et3q6XTUQR8zVNKKSedqGVQ+I5etyrvRFmeJrw4 mM5g== Received: by 10.180.14.169 with SMTP id q9mr1154177wic.0.1343174926065; Tue, 24 Jul 2012 17:08:46 -0700 (PDT) Received: by 10.180.14.169 with SMTP id q9mr1154173wic.0.1343174925960; Tue, 24 Jul 2012 17:08:45 -0700 (PDT) Received: from hpza9.eem.corp.google.com ([74.125.121.33]) by gmr-mx.google.com with ESMTPS id i1si110163eem.0.2012.07.24.17.08.45 (version=TLSv1/SSLv3 cipher=AES128-SHA); Tue, 24 Jul 2012 17:08:45 -0700 (PDT) Received: from ccoutant.mtv.corp.google.com (ccoutant.mtv.corp.google.com [172.18.110.42]) by hpza9.eem.corp.google.com (Postfix) with ESMTP id 29E245C0050; Tue, 24 Jul 2012 17:08:45 -0700 (PDT) Received: by ccoutant.mtv.corp.google.com (Postfix, from userid 62097) id 6CCD9E0F80; Tue, 24 Jul 2012 17:08:44 -0700 (PDT) To: reply@codereview.appspotmail.com, saugustine@google.com, gcc-patches@gcc.gnu.org Subject: [google/gcc-4_7] Backport pending Fission patch (issue6443043) Message-Id: <20120725000844.6CCD9E0F80@ccoutant.mtv.corp.google.com> Date: Tue, 24 Jul 2012 17:08:44 -0700 (PDT) From: ccoutant@google.com (Cary Coutant) X-Gm-Message-State: ALoCoQkn6e6PITkikJ2FAOP3QET1aD3U2MRu9nUq6wdmIB+WCwHZ1tNuZ0Bb1dROYR146UpZEdUUiuh653AZcYS1lZmVJjKiqt7N3/SmmMQhjv/2zTMHdCucUjHkh/MjmTEfDLk7QrzpURosmCfX+Qg/4WD8/z2kesFhIWC+KxO6g6I3bBycZ1IprGo+UG05fC5DdXVWkMoK X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch is for the google/gcc-4_7 branch. Backport Fission patches from trunk at r186934, r187061, and r188759. Backport pending Fission patch at http://codereview.appspot.com/6305113. Patches for include/dwarf2.def have been backported to include/dwarf2.h. Tested by bootstrap and regression testing. 2012-07-18 Sterling Augustine Cary Coutant include/ * dwarf2.h (dwarf_location_list_entry_type): New enum with enumerators DW_LLE_end_of_list_entry, DW_LLE_base_address_selection_entry, DW_LLE_start_end_entry, DW_LLE_start_length_entry. gcc/ * common.opt (gno-split-dwarf, gsplit-dwarf): New switches. * doc/invoke.texi (Debugging Options): Document them. * opts.c (finish_options): Make gsplit-dwarf imply -gpubnames. * dwarf2out.h (dw_val_struct): New field val_index. * dwarf2out.c (debug_skeleton_info_section, debug_skeleton_abbrev_section, debug_addr_section, debug_skeleton_line_section, debug_str_offsets_section): New sections. (indirect_string_node): Add index field. (dw_loc_list_node): Add begin_index field. (dw_addr_op, new_addr_loc_descr, AT_index, set_AT_index, add_addr_table_entry, remove_addr_table_entry, output_range_list_offset, output_loc_list_offset, output_attr_index_or_value, remove_loc_list_addr_table_entries, output_die_abbrevs, add_top_level_skeleton_die_attrs, get_skeleton_type_unit, output_skeleton_debug_sections, output_index_strings, output_addr_table, index_location_lists): New functions. (DEBUG_DWO_INFO_SECTION, DEBUG_DWO_ABBREV_SECTION, DEBUG_ADDR_SECTION, DEBUG_NORM_MACINFO_SECTION, DEBUG_DWO_MACINFO_SECTION, DEBUG_DWO_LINE_SECTION, DEBUG_DWO_LOC_SECTION, DEBUG_NORM_STR_OFFSETS_SECTION, DEBUG_DWO_STR_SECTION, DEBUG_MACRO_SECTION_FLAGS, DEBUG_SKELETON_LINE_SECTION_LABEL, DEBUG_SKELETON_INFO_SECTION_LABEL, DEBUG_SKELETON_ABBREV_SECTION_LABEL, DEBUG_ADDR_SECTIN_LABEL, SKELETON_COMP_DIE_ABBREV, SKELETON_TYPE_DIE_ABBREV): New defines. (DEBUG_MACINFO_SECTION, DEBUG_MACRO_SECTION, DEBUG_STR_SECTION DEBUG_STR_SECTION_FLAGS): Adjust definitions. (TEXT_SECTION_LABEL, COLD_TEXT_SECTION_LABEL, DEBUG_INFO_SECTION_LABEL, DEBUG_ABBREV_SECTION_LABEL, DEBUG_LOC_SECTION_LABEL, DEBUG_RANGES_SECTION_LABEL, DEBUG_MACINFO_SECTION_LABEL, DEBUG_MACRO_SECTION_LABEL): Adjust indentation. (debug_skeleton_info_section_label, debug_skeleton_abbrev_section_label, debug_addr_section_label, debug_skeleton_line_section_label, dw_id_placeholder): New global variables. (add_AT_lbl_id): Add force_direct parameter. Adjust calls throughout file. Handle dwarf_split_debug_info. (add_AT_addr). Likewise. Initialize val_index_field. (add_AT_range_list): Add force parameter. Adjust calls throughout file. Initialize val_index field. (add_ranges_by_labels): Add and handle force_direct parameter. Adjust calls throughout file. (size_of_die): New variable form. Handle dwarf_split_debug_info and call AT_index. (value_format): Use AT_class instead of calling val_class directly. Handle DW_FORM_addr and dw_val_class_lbl_id appropriately for dwarf_split_debug_info and AT_index. (output_abbrev_section): Move most code to new function output_die_abbrevs. (output_loc_list): Handle dwarf_split_debug_info by using DW_LLE_start_length_entry and DW_LLE_end_of_list_entry. (output_die): Call output_attr_index_or_value, output_range_list_offset, Fix format string. Check val_str->form directly to avoid side effect. (add_pubtype): Fix indention. (output_comdat_type_unit): Handle dwarf_split_debug_info. (output_pubnames): Likewise. (output_aranges): Likewise. (output_mac_info): Likewise. (output_line_info): New parameter prologue_only. Adjust calls throughout file. (mem_loc_descriptor): Call new_addr_loc_descr. (loc_descriptor): Likewise. (add_const_value_attribute): Likewise. (loc_list_from_tree): Replace first_op and second_op with tls_op. Update associated logic. Call new_addr_loc_descr. (dwarf2out_init): Handle dwarf_split_debug_info. Initialize debug_skeleton_info_section, debug_skeleton_abbrev_section, debug_addr_section, debug_skeleton_line_section, debug_str_offsets_section, debug_skeleton_info_section_label, debug_skeleton_abbrev_section_label, debug_addr_section_label and debug_skeleton_line_section_label. Use DEBUG_MACRO_SECTION_FLAGS. (new_loc_descr, build_cfa_loc, add_AT_flag, add_AT_int, add_AT_unsigned, add_AT_double, add_AT_vec, add_AT_data8, add_AT_string, add_AT_die_ref, add_AT_fde_ref, add_AT_loc, add_AT_loc_list, add_AT_file, add_AT_vms_delta, add_AT_lineptr, add_AT_macptr, add_AT_offset): Initialize val_index field. (size_of_loc_descr, output_loc_operands, output_loc_operands_raw, resolve_addr_in_expression, hash_loc_operands): Handle DW_OP_GNU_addr_index and DW_OP_GNU_const_index. (compare_loc_operands): Likewise. Adjust assertion. (AT_string_form): Handle dwarf_split_debug_info. (resolve_addr): New local variable l. Check val_index. Call remove_addr_table_entry and remove_loc_list_addr_table_entries. (dwarf2out_finish): Handle dwarf_split_debug_info. New variable main_comp_unit_die. Call index_location_lists, add_AT_data8, add_AT_lineptr, output_skeleton_debug_sections, output_addr_table. Move call to ASM_GENERATE_INTERNAL_LABEL to dwarf2out_init. Call ASM_OUTPUT_LABEL for debug_skeleton_line_section_label and debug_addr_section_label. Adjust comment. * gcc.c (replace_extension_spec_func): New function. (ASM_FINAL_SPEC): Adjust. Fix related comments. (check_live_switch): Likewise. 2012-06-18 Doug Evans * dwarf2.def (DW_OP): Add DW_OP_GNU_const_index. 2012-05-02 Cary Coutant * dwarf2.def: Remove DW_FORM_GNU_ref_index, replace DW_AT_GNU_ref_base with DW_AT_GNU_ranges_base. 2012-04-28 Doug Evans * dwarf2.def (DW_OP): Add DW_OP_GNU_addr_index. --- This patch is available for review at http://codereview.appspot.com/6443043 Index: include/dwarf2.h =================================================================== --- include/dwarf2.h (revision 189829) +++ include/dwarf2.h (working copy) @@ -190,7 +190,6 @@ enum dwarf_form DW_FORM_flag_present = 0x19, DW_FORM_ref_sig8 = 0x20, /* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ - DW_FORM_GNU_ref_index = 0x1f00, DW_FORM_GNU_addr_index = 0x1f01, DW_FORM_GNU_str_index = 0x1f02 }; @@ -375,7 +374,7 @@ enum dwarf_attribute /* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ DW_AT_GNU_dwo_name = 0x2130, DW_AT_GNU_dwo_id = 0x2131, - DW_AT_GNU_ref_base = 0x2132, + DW_AT_GNU_ranges_base = 0x2132, DW_AT_GNU_addr_base = 0x2133, DW_AT_GNU_pubnames = 0x2134, DW_AT_GNU_pubtypes = 0x2135, @@ -578,6 +577,9 @@ enum dwarf_location_atom DW_OP_GNU_reinterpret = 0xf9, /* The GNU parameter ref extension. */ DW_OP_GNU_parameter_ref = 0xfa, + /* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ + DW_OP_GNU_addr_index = 0xfb, + DW_OP_GNU_const_index = 0xfc, /* HP extensions. */ DW_OP_HP_unknown = 0xe0, /* Ouch, the same as GNU_push_tls_address. */ DW_OP_HP_is_value = 0xe1, @@ -829,6 +831,17 @@ enum dwarf_call_frame_info DW_CFA_GNU_negative_offset_extended = 0x2f }; +/* Type codes for location list entries. + Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ + +enum dwarf_location_list_entry_type + { + DW_LLE_end_of_list_entry = 0, + DW_LLE_base_address_selection_entry = 1, + DW_LLE_start_end_entry = 2, + DW_LLE_start_length_entry = 3 + }; + #define DW_CIE_ID 0xffffffff #define DW64_CIE_ID 0xffffffffffffffffULL #define DW_CIE_VERSION 1 Index: gcc/doc/invoke.texi =================================================================== --- gcc/doc/invoke.texi (revision 189829) +++ gcc/doc/invoke.texi (working copy) @@ -4952,6 +4952,14 @@ it reasonable to use the optimizer for p The following options are useful when GCC is generated with the capability for more than one debugging format. +@item -gsplit-dwarf +@opindex gsplit-dwarf +Separate as much dwarf debugging information as possible into a +separate output file with the extension .dwo. This option allows +the build system to avoid linking files with debug information. To +be useful, this option requires a debugger capable of reading .dwo +files. + @item -ggdb @opindex ggdb Produce debugging information for use by GDB@. This means to use the Index: gcc/gcc.c =================================================================== --- gcc/gcc.c (revision 189829) +++ gcc/gcc.c (working copy) @@ -267,6 +267,7 @@ static const char *compare_debug_dump_op static const char *compare_debug_self_opt_spec_function (int, const char **); static const char *compare_debug_auxbase_opt_spec_function (int, const char **); static const char *pass_through_libs_spec_func (int, const char **); +static const char *replace_extension_spec_func (int, const char **); /* The Specs Language @@ -446,7 +447,7 @@ ignored. White space may also appear an 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 @@ -479,7 +480,14 @@ proper position among the other output f /* config.h can define ASM_FINAL_SPEC to run a post processor after the assembler has run. */ #ifndef ASM_FINAL_SPEC -#define ASM_FINAL_SPEC "" +#define ASM_FINAL_SPEC \ + "%{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 @@ -1276,6 +1284,7 @@ static const struct spec_function static { "compare-debug-self-opt", compare_debug_self_opt_spec_function }, { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function }, { "pass-through-libs", pass_through_libs_spec_func }, + { "replace-extension", replace_extension_spec_func }, #ifdef EXTRA_SPEC_FUNCTIONS EXTRA_SPEC_FUNCTIONS #endif @@ -5783,7 +5792,7 @@ process_brace_body (const char *p, const 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. */ @@ -5820,7 +5829,7 @@ check_live_switch (int switchnum, int pr } 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. */ @@ -8394,3 +8403,27 @@ pass_through_libs_spec_func (int argc, c } return prepended; } + +/* %:replace-extension spec function. Replaces the extension of the + first argument with the second argument. */ + +const char * +replace_extension_spec_func (int argc, const char **argv) +{ + char *name; + char *p; + char *result; + + if (argc != 2) + fatal_error ("too few arguments to %%:replace-extension"); + + name = xstrdup (argv[0]); + p = strrchr (name, '.'); + if (p != NULL) + *p = '\0'; + + result = concat (name, argv[1], NULL); + + free (name); + return result; +} Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 189829) +++ gcc/dwarf2out.c (working copy) @@ -153,14 +153,19 @@ static GTY(()) VEC(tree,gc) *decl_scope_ /* Pointers to various DWARF2 sections. */ static GTY(()) section *debug_info_section; +static GTY(()) section *debug_skeleton_info_section; static GTY(()) section *debug_abbrev_section; +static GTY(()) section *debug_skeleton_abbrev_section; static GTY(()) section *debug_aranges_section; +static GTY(()) section *debug_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; @@ -203,6 +208,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; @@ -1214,7 +1220,8 @@ DEF_VEC_ALLOC_P(dw_die_ref,heap); their entire life. */ typedef struct GTY(()) dw_loc_list_struct { dw_loc_list_ref dw_loc_next; - const char *begin; /* Label for begin address of range */ + const char *begin; /* Label and index for begin address of range */ + unsigned int begin_index; const char *end; /* Label for end address of range */ char *ll_symbol; /* Label for beginning of location list. Only on head of list */ @@ -1591,8 +1598,10 @@ new_loc_descr (enum dwarf_location_atom descr->dw_loc_opc = op; descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const; + descr->dw_loc_oprnd1.val_index = -1U; descr->dw_loc_oprnd1.v.val_unsigned = oprnd1; descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const; + descr->dw_loc_oprnd2.val_index = -1U; descr->dw_loc_oprnd2.v.val_unsigned = oprnd2; return descr; @@ -1796,6 +1805,10 @@ size_of_loc_descr (dw_loc_descr_ref loc) case DW_OP_addr: size += DWARF2_ADDR_SIZE; break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + size += size_of_uleb128 (loc->dw_loc_oprnd1.val_index); + break; case DW_OP_const1u: case DW_OP_const1s: size += 1; @@ -2232,6 +2245,12 @@ output_loc_operands (dw_loc_descr_ref lo } break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + dw2_asm_output_data_uleb128 (loc->dw_loc_oprnd1.val_index, + "(index into .debug_addr)"); + break; + case DW_OP_GNU_implicit_pointer: { char label[MAX_ARTIFICIAL_LABEL_BYTES @@ -2407,6 +2426,8 @@ output_loc_operands_raw (dw_loc_descr_re 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 (); @@ -2590,6 +2611,7 @@ build_cfa_loc (dw_cfa_location *cfa, HOS { head = new_reg_loc_descr (cfa->reg, cfa->base_offset); head->dw_loc_oprnd1.val_class = dw_val_class_const; + head->dw_loc_oprnd1.val_index = -1U; tmp = new_loc_descr (DW_OP_deref, 0, 0); add_loc_descr (&head, tmp); if (offset != 0) @@ -3217,6 +3239,8 @@ static tree decl_ultimate_origin (const_ static tree decl_class_context (tree); static void add_dwarf_attr (dw_die_ref, dw_attr_ref); static inline enum dw_val_class AT_class (dw_attr_ref); +static inline unsigned int AT_index (dw_attr_ref); +static inline void set_AT_index (dw_attr_ref, unsigned int); static void add_AT_flag (dw_die_ref, enum dwarf_attribute, unsigned); static inline unsigned AT_flag (dw_attr_ref); static void add_AT_int (dw_die_ref, enum dwarf_attribute, HOST_WIDE_INT); @@ -3244,15 +3268,18 @@ static inline dw_loc_descr_ref AT_loc (d static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute, dw_loc_list_ref); static inline dw_loc_list_ref AT_loc_list (dw_attr_ref); -static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx); +static unsigned int add_addr_table_entry (dw_attr_node *); +static void remove_addr_table_entry (unsigned int); +static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool); static inline rtx AT_addr (dw_attr_ref); -static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *); +static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *, + bool); static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *); static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *); static void add_AT_offset (dw_die_ref, enum dwarf_attribute, unsigned HOST_WIDE_INT); static void add_AT_range_list (dw_die_ref, enum dwarf_attribute, - unsigned long); + unsigned long, bool); static inline const char *AT_lbl (dw_attr_ref); static dw_attr_ref get_AT (dw_die_ref, enum dwarf_attribute); static const char *get_AT_low_pc (dw_die_ref); @@ -3347,6 +3374,7 @@ static unsigned long size_of_aranges (vo static enum dwarf_form value_format (dw_attr_ref); static void output_value_format (dw_attr_ref); static void output_abbrev_section (void); +static void output_die_abbrevs (unsigned long, dw_die_ref); static void output_die_symbol (dw_die_ref); static void output_die (dw_die_ref); static void output_compilation_unit_header (void); @@ -3362,10 +3390,10 @@ static void output_aranges (unsigned lon 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); @@ -3504,36 +3532,124 @@ static bool generic_type_p (tree); static void schedule_generic_params_dies_gen (tree t); static void gen_scheduled_generic_parms_dies (void); +/* Return the operator to use for an address of a variable. + DTPREL is true for thread-local variables whose address + is really an offset relative to the TLS pointer, which + will need link-time relocation, but will not need relocation + by the DWARF consumer. For those, we use DW_OP_const*. + For regular variables, which need both link-time relocation + and consumer-level relocation (e.g., to account for + shared objects loaded at a random address), we use + DW_OP_addr*. */ + +static inline enum dwarf_location_atom dw_addr_op (bool dtprel) +{ + if (dtprel) + return (dwarf_split_debug_info ? DW_OP_GNU_const_index + : (DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u)); + else + return (dwarf_split_debug_info ? DW_OP_GNU_addr_index : DW_OP_addr); +} + +/* Return a pointer to a newly allocated address location description. If + dwarf_split_debug_info is true, then record the address with the appropriate + relocation. */ +static inline dw_loc_descr_ref +new_addr_loc_descr (rtx addr, int dtprel) +{ + dw_loc_descr_ref ref = new_loc_descr (dw_addr_op (dtprel), 0, 0); + + ref->dw_loc_oprnd1.val_class = dw_val_class_addr; + ref->dw_loc_oprnd1.val_index = -1U; + ref->dw_loc_oprnd1.v.val_addr = addr; + ref->dtprel = dtprel; + if (dwarf_split_debug_info) + { + dw_attr_node attr; + + attr.dw_attr = DW_AT_location; + attr.dw_attr_val.val_class = (dtprel + ? dw_val_class_loc : dw_val_class_addr); + attr.dw_attr_val.val_index = -1U; + attr.dw_attr_val.v.val_addr = addr; + + ref->dw_loc_oprnd1.val_index = add_addr_table_entry (&attr); + } + return ref; +} + /* Section names used to hold DWARF debugging information. */ + #ifndef DEBUG_INFO_SECTION #define DEBUG_INFO_SECTION ".debug_info" #endif +#ifndef DEBUG_DWO_INFO_SECTION +#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo" +#endif #ifndef DEBUG_ABBREV_SECTION #define DEBUG_ABBREV_SECTION ".debug_abbrev" #endif +#ifndef DEBUG_DWO_ABBREV_SECTION +#define DEBUG_DWO_ABBREV_SECTION ".debug_abbrev.dwo" +#endif #ifndef DEBUG_ARANGES_SECTION #define DEBUG_ARANGES_SECTION ".debug_aranges" #endif +#ifndef DEBUG_ADDR_SECTION +#define DEBUG_ADDR_SECTION ".debug_addr" +#endif +#ifndef DEBUG_NORM_MACINFO_SECTION +#define DEBUG_NORM_MACINFO_SECTION ".debug_macinfo" +#endif +#ifndef DEBUG_DWO_MACINFO_SECTION +#define DEBUG_DWO_MACINFO_SECTION ".debug_macinfo.dwo" +#endif #ifndef DEBUG_MACINFO_SECTION -#define DEBUG_MACINFO_SECTION ".debug_macinfo" +#define DEBUG_MACINFO_SECTION \ + (!dwarf_split_debug_info \ + ? (DEBUG_NORM_MACINFO_SECTION) : (DEBUG_DWO_MACINFO_SECTION)) +#endif +#ifndef DEBUG_NORM_MACRO_SECTION +#define DEBUG_NORM_MACRO_SECTION ".debug_macro" +#endif +#ifndef DEBUG_DWO_MACRO_SECTION +#define DEBUG_DWO_MACRO_SECTION ".debug_macro.dwo" #endif #ifndef DEBUG_MACRO_SECTION -#define DEBUG_MACRO_SECTION ".debug_macro" +#define DEBUG_MACRO_SECTION \ + (!dwarf_split_debug_info \ + ? (DEBUG_NORM_MACRO_SECTION) : (DEBUG_DWO_MACRO_SECTION)) #endif #ifndef DEBUG_LINE_SECTION #define DEBUG_LINE_SECTION ".debug_line" #endif +#ifndef DEBUG_DWO_LINE_SECTION +#define DEBUG_DWO_LINE_SECTION ".debug_line.dwo" +#endif #ifndef DEBUG_LOC_SECTION #define DEBUG_LOC_SECTION ".debug_loc" #endif +#ifndef DEBUG_DWO_LOC_SECTION +#define DEBUG_DWO_LOC_SECTION ".debug_loc.dwo" +#endif #ifndef DEBUG_PUBNAMES_SECTION #define DEBUG_PUBNAMES_SECTION ".debug_pubnames" #endif #ifndef DEBUG_PUBTYPES_SECTION #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes" #endif +#define DEBUG_NORM_STR_OFFSETS_SECTION ".debug_str_offsets" +#define DEBUG_DWO_STR_OFFSETS_SECTION ".debug_str_offsets.dwo" +#ifndef DEBUG_STR_OFFSETS_SECTION +#define DEBUG_STR_OFFSETS_SECTION \ + (!dwarf_split_debug_info \ + ? (DEBUG_NORM_STR_OFFSETS_SECTION) : (DEBUG_DWO_STR_OFFSETS_SECTION)) +#endif +#define DEBUG_DWO_STR_SECTION ".debug_str.dwo" +#define DEBUG_NORM_STR_SECTION ".debug_str" #ifndef DEBUG_STR_SECTION -#define DEBUG_STR_SECTION ".debug_str" +#define DEBUG_STR_SECTION \ + (!dwarf_split_debug_info ? (DEBUG_NORM_STR_SECTION) : (DEBUG_DWO_STR_SECTION)) #endif #ifndef DEBUG_RANGES_SECTION #define DEBUG_RANGES_SECTION ".debug_ranges" @@ -3544,11 +3660,17 @@ static void gen_scheduled_generic_parms_ #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. */ @@ -3568,12 +3690,24 @@ static void gen_scheduled_generic_parms_ #ifndef DEBUG_LINE_SECTION_LABEL #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" #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" #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" #endif @@ -3587,6 +3721,9 @@ static void gen_scheduled_generic_parms_ #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 @@ -3600,7 +3737,11 @@ static char cold_text_section_label[MAX_ static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; +static char debug_skeleton_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; +static char debug_skeleton_abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; +static char debug_addr_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; +static char debug_skeleton_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char debug_pubnames_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char debug_pubtypes_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; @@ -4271,6 +4412,31 @@ AT_class (dw_attr_ref a) return a->dw_attr_val.val_class; } +/* Return the index for any attribute that will be referenced with a + DW_FORM_GNU_addr_index. Strings have their indices handled differently to + account for reference counting pruning. */ + +static inline unsigned int +AT_index (dw_attr_ref a) +{ + if (AT_class (a) == dw_val_class_str) + return a->dw_attr_val.v.val_str->index; + else + return a->dw_attr_val.val_index; +} + +/* Set the index for any attribute that will be referenced with a + DW_FORM_GNU_addr_index. */ + +static inline void +set_AT_index (dw_attr_ref a, unsigned int index) +{ + if (AT_class (a) == dw_val_class_str) + a->dw_attr_val.v.val_str->index = index; + else + a->dw_attr_val.val_index = index; +} + /* Add a flag value attribute to a DIE. */ static inline void @@ -4280,6 +4446,7 @@ add_AT_flag (dw_die_ref die, enum dwarf_ attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_flag; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_flag = flag; add_dwarf_attr (die, &attr); } @@ -4300,6 +4467,7 @@ add_AT_int (dw_die_ref die, enum dwarf_a attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_const; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_int = int_val; add_dwarf_attr (die, &attr); } @@ -4321,6 +4489,7 @@ add_AT_unsigned (dw_die_ref die, enum dw attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_unsigned_const; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_unsigned = unsigned_val; add_dwarf_attr (die, &attr); } @@ -4342,6 +4511,7 @@ add_AT_double (dw_die_ref die, enum dwar attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_const_double; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_double.high = high; attr.dw_attr_val.v.val_double.low = low; add_dwarf_attr (die, &attr); @@ -4357,6 +4527,7 @@ add_AT_vec (dw_die_ref die, enum dwarf_a attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_vec; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_vec.length = length; attr.dw_attr_val.v.val_vec.elt_size = elt_size; attr.dw_attr_val.v.val_vec.array = array; @@ -4373,6 +4544,7 @@ add_AT_data8 (dw_die_ref die, enum dwarf attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_data8; + attr.dw_attr_val.val_index = -1U; memcpy (attr.dw_attr_val.v.val_data8, data8, 8); add_dwarf_attr (die, &attr); } @@ -4431,6 +4603,7 @@ add_AT_string (dw_die_ref die, enum dwar attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_str; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_str = node; add_dwarf_attr (die, &attr); } @@ -4442,12 +4615,20 @@ AT_string (dw_attr_ref a) return a->dw_attr_val.v.val_str->str; } +/* A vector for a table of strings in the form DW_FORM_GNU_index_str. */ + +typedef struct indirect_string_node indirect_string_node; +DEF_VEC_O(indirect_string_node); +DEF_VEC_ALLOC_O(indirect_string_node, gc); +static GTY (()) VEC (indirect_string_node, gc) *index_string_table; + /* Find out whether a string should be output inline in DIE or out-of-line in .debug_str section. */ static enum dwarf_form AT_string_form (dw_attr_ref a) { + static unsigned int index_string_count = 0; struct indirect_string_node *node; unsigned int len; char label[32]; @@ -4477,7 +4658,17 @@ AT_string_form (dw_attr_ref a) ++dw2_string_counter; node->label = xstrdup (label); - return node->form = DW_FORM_strp; + if (!dwarf_split_debug_info) + node->form = DW_FORM_strp; + else + { + node->form = DW_FORM_GNU_str_index; + set_AT_index (a, index_string_count); + index_string_count++; + VEC_safe_push (indirect_string_node, gc, index_string_table, node); + } + + return node->form; } /* Add a DIE reference attribute value to a DIE. */ @@ -4498,6 +4689,7 @@ add_AT_die_ref (dw_die_ref die, enum dwa attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_die_ref; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_die_ref.die = targ_die; attr.dw_attr_val.v.val_die_ref.external = 0; add_dwarf_attr (die, &attr); @@ -4546,6 +4738,7 @@ add_AT_fde_ref (dw_die_ref die, enum dwa attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_fde_ref; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_fde_index = targ_fde; add_dwarf_attr (die, &attr); } @@ -4559,6 +4752,7 @@ add_AT_loc (dw_die_ref die, enum dwarf_a attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_loc; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_loc = loc; add_dwarf_attr (die, &attr); } @@ -4577,6 +4771,7 @@ add_AT_loc_list (dw_die_ref die, enum dw attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_loc_list; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_loc_list = loc_list; add_dwarf_attr (die, &attr); have_location_lists = true; @@ -4596,17 +4791,64 @@ AT_loc_list_ptr (dw_attr_ref a) return &a->dw_attr_val.v.val_loc_list; } +/* A table of entries into the .debug_addr section. */ + +static GTY (()) VEC (dw_attr_node,gc) * addr_index_table; + +static unsigned int +add_addr_table_entry (dw_attr_node *attr) +{ + gcc_assert (dwarf_split_debug_info); + + VEC_safe_push (dw_attr_node, gc, addr_index_table, attr); + return VEC_length (dw_attr_node, addr_index_table) - 1; +} + +/* Remove an entry from the addr table. Since we have already numbered + all the entries, the best we can do here is null it out. */ + +static void +remove_addr_table_entry (unsigned int i) +{ + dw_attr_node *attr; + + gcc_assert (dwarf_split_debug_info); + gcc_assert (i < VEC_length (dw_attr_node, addr_index_table)); + + attr = VEC_index (dw_attr_node, addr_index_table, i); + attr->dw_attr = (enum dwarf_attribute) 0; +} + +/* Given a location list, remove all addresses it refers to from the + address_table. */ + +static void +remove_loc_list_addr_table_entries (dw_loc_list_ref loc) +{ + dw_loc_descr_ref descr; + + gcc_assert (loc->replaced); + + for (descr = loc->expr; descr; descr = descr->dw_loc_next) + if (descr->dw_loc_oprnd1.val_index != -1U) + remove_addr_table_entry (descr->dw_loc_oprnd1.val_index); +} + /* Add an address constant attribute value to a DIE. */ static inline void -add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr) +add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr, + bool force_direct) { dw_attr_node attr; attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_addr; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_addr = addr; add_dwarf_attr (die, &attr); + if (dwarf_split_debug_info && !force_direct) + set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr)); } /* Get the RTX from to an address DIE attribute. */ @@ -4628,6 +4870,7 @@ add_AT_file (dw_die_ref die, enum dwarf_ attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_file; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_file = fd; add_dwarf_attr (die, &attr); } @@ -4651,6 +4894,7 @@ add_AT_vms_delta (dw_die_ref die, enum d attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_vms_delta; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_vms_delta.lbl1 = xstrdup (lbl1); attr.dw_attr_val.v.val_vms_delta.lbl2 = xstrdup (lbl2); add_dwarf_attr (die, &attr); @@ -4659,14 +4903,18 @@ add_AT_vms_delta (dw_die_ref die, enum d /* Add a label identifier attribute value to a DIE. */ static inline void -add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id) +add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, + const char *lbl_id, bool force_direct) { dw_attr_node attr; attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_lbl_id; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id); add_dwarf_attr (die, &attr); + if (dwarf_split_debug_info && !force_direct) + set_AT_index (get_AT (die, attr_kind), add_addr_table_entry (&attr)); } /* Add a section offset attribute value to a DIE, an offset into the @@ -4680,6 +4928,7 @@ add_AT_lineptr (dw_die_ref die, enum dwa attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_lineptr; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_lbl_id = xstrdup (label); add_dwarf_attr (die, &attr); } @@ -4695,6 +4944,7 @@ add_AT_macptr (dw_die_ref die, enum dwar attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_macptr; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_lbl_id = xstrdup (label); add_dwarf_attr (die, &attr); } @@ -4709,20 +4959,25 @@ add_AT_offset (dw_die_ref die, enum dwar attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_offset; + attr.dw_attr_val.val_index = -1U; attr.dw_attr_val.v.val_offset = offset; add_dwarf_attr (die, &attr); } -/* Add an range_list attribute value to a DIE. */ +/* Add a range_list attribute value to a DIE. */ static void add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind, - long unsigned int offset) + long unsigned int offset, bool force_direct) { dw_attr_node attr; attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_range_list; + /* This is a bit of a misnomer--the offset isn't an index, but we need to + save force_direct for output. */ + attr.dw_attr_val.val_index + = (dwarf_split_debug_info && !force_direct) ? offset : -1U; attr.dw_attr_val.v.val_offset = offset; add_dwarf_attr (die, &attr); } @@ -7716,6 +7971,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) @@ -7723,7 +7979,10 @@ size_of_die (dw_die_ref die) switch (AT_class (a)) { case dw_val_class_addr: - size += DWARF2_ADDR_SIZE; + if (dwarf_split_debug_info && AT_index (a) != -1U) + size += size_of_uleb128 (AT_index (a)); + else + size += DWARF2_ADDR_SIZE; break; case dw_val_class_offset: size += DWARF_OFFSET_SIZE; @@ -7741,10 +8000,13 @@ size_of_die (dw_die_ref die) } break; case dw_val_class_loc_list: - size += DWARF_OFFSET_SIZE; + if (dwarf_split_debug_info && AT_index (a) != -1U) + size += size_of_uleb128 (AT_index (a)); + else + size += DWARF_OFFSET_SIZE; break; case dw_val_class_range_list: - size += DWARF_OFFSET_SIZE; + size += DWARF_OFFSET_SIZE; break; case dw_val_class_const: size += size_of_sleb128 (AT_int (a)); @@ -7804,15 +8066,21 @@ size_of_die (dw_die_ref die) size += DWARF_OFFSET_SIZE; break; case dw_val_class_lbl_id: - size += DWARF2_ADDR_SIZE; + if (dwarf_split_debug_info && AT_index (a) != -1U) + size += size_of_uleb128 (AT_index (a)); + else + size += DWARF2_ADDR_SIZE; break; case dw_val_class_lineptr: case dw_val_class_macptr: - size += DWARF_OFFSET_SIZE; + size += DWARF_OFFSET_SIZE; break; case dw_val_class_str: - if (AT_string_form (a) == DW_FORM_strp) + form = AT_string_form (a); + if (form == DW_FORM_strp) size += DWARF_OFFSET_SIZE; + else if (form == DW_FORM_GNU_str_index) + size += size_of_uleb128 (AT_index (a)); else size += strlen (a->dw_attr_val.v.val_str->str) + 1; break; @@ -7994,7 +8262,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. */ @@ -8004,7 +8272,8 @@ value_format (dw_attr_ref a) case DW_AT_high_pc: case DW_AT_entry_pc: case DW_AT_trampoline: - return DW_FORM_addr; + return (dwarf_split_debug_info && AT_index (a) != -1U + ? DW_FORM_GNU_addr_index : DW_FORM_addr); default: break; } @@ -8023,7 +8292,7 @@ value_format (dw_attr_ref a) } case dw_val_class_range_list: case dw_val_class_loc_list: - if (dwarf_version >= 4) + if (dwarf_version >= 4 || dwarf_split_debug_info) return DW_FORM_sec_offset; /* FALLTHRU */ case dw_val_class_vms_delta: @@ -8120,7 +8389,8 @@ value_format (dw_attr_ref a) case dw_val_class_fde_ref: return DW_FORM_data; case dw_val_class_lbl_id: - return DW_FORM_addr; + return (dwarf_split_debug_info && AT_index (a) != -1U + ? DW_FORM_GNU_addr_index : DW_FORM_addr); case dw_val_class_lineptr: case dw_val_class_macptr: return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data; @@ -8157,40 +8427,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 (1, 0, NULL); + dw2_asm_output_data (1, 0, NULL); +} - 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"); +/* Output the .debug_abbrev section which defines the DIE abbreviation + table. */ - 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); - } +static void +output_abbrev_section (void) +{ + unsigned long abbrev_id; - dw2_asm_output_data (1, 0, NULL); - dw2_asm_output_data (1, 0, NULL); - } + 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); @@ -8225,6 +8501,7 @@ new_loc_list (dw_loc_descr_ref expr, con dw_loc_list_ref retlist = ggc_alloc_cleared_dw_loc_list_node (); retlist->begin = begin; + retlist->begin_index = -1U; retlist->end = end; retlist->expr = expr; retlist->section = section; @@ -8269,7 +8546,22 @@ output_loc_list (dw_loc_list_ref list_he in a single range are unlikely very useful. */ if (size > 0xffff) continue; - if (!have_multiple_function_sections) + if (dwarf_split_debug_info) + { + dw2_asm_output_data (1, DW_LLE_start_length_entry, + "Location list start/length entry (%s)", + list_head->ll_symbol); + dw2_asm_output_data_uleb128 (curr->begin_index, + "Location list range start index (%s)", + curr->begin); + /* The length field is 4 bytes. If we ever need to support + an 8-byte length, we can add a new DW_LLE code or fall back + to DW_LLE_start_end_entry. */ + dw2_asm_output_delta (4, curr->end, curr->begin, + "Location list range length (%s)", + list_head->ll_symbol); + } + else if (!have_multiple_function_sections) { dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section, "Location list begin address (%s)", @@ -8295,12 +8587,83 @@ output_loc_list (dw_loc_list_ref list_he output_loc_sequence (curr->expr, -1); } - dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, - "Location list terminator begin (%s)", - list_head->ll_symbol); - dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, - "Location list terminator end (%s)", - list_head->ll_symbol); + if (dwarf_split_debug_info) + dw2_asm_output_data (1, DW_LLE_end_of_list_entry, + "Location list terminator (%s)", + list_head->ll_symbol); + else + { + dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, + "Location list terminator begin (%s)", + list_head->ll_symbol); + dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, + "Location list terminator end (%s)", + list_head->ll_symbol); + } +} + +/* Output the offset into the debug_range section. */ + +static void +output_range_list_offset (dw_attr_ref a) +{ + const char *name = dwarf_attr_name (a->dw_attr); + + if (!dwarf_split_debug_info || AT_index (a) == -1U) + { + char *p = strchr (ranges_section_label, '\0'); + sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label, + debug_ranges_section, "%s", name); + *p = '\0'; + } + else + dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset, + "%s (offset from %s)", name, ranges_section_label); +} + +/* Output the offset into the debug_loc section. */ + +static void +output_loc_list_offset (dw_attr_ref a) +{ + char *sym = AT_loc_list (a)->ll_symbol; + + gcc_assert (sym); + if (dwarf_split_debug_info) + dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label, + "%s", dwarf_attr_name (a->dw_attr)); + else + dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section, + "%s", dwarf_attr_name (a->dw_attr)); +} + +/* Output an attribute's index or value appropriately. */ + +static void +output_attr_index_or_value (dw_attr_ref a) +{ + const char *name = dwarf_attr_name (a->dw_attr); + + if (dwarf_split_debug_info && AT_index (a) != -1U) + { + dw2_asm_output_data_uleb128 (AT_index (a), "%s", name); + return; + } + switch (AT_class (a)) + { + case dw_val_class_addr: + dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name); + break; + case dw_val_class_lbl_id: + dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name); + break; + case dw_val_class_loc_list: + output_loc_list_offset (a); + break; + default: + gcc_unreachable (); + } } /* Output a type signature. */ @@ -8341,7 +8704,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: @@ -8350,15 +8713,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: @@ -8414,7 +8769,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); } @@ -8461,13 +8816,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: @@ -8524,7 +8873,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: @@ -8538,12 +8887,15 @@ output_die (dw_die_ref die) break; case dw_val_class_str: - if (AT_string_form (a) == DW_FORM_strp) + if (a->dw_attr_val.v.val_str->form == DW_FORM_strp) dw2_asm_output_offset (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_str->label, debug_str_section, "%s: \"%s\"", name, AT_string (a)); - else + else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index) + dw2_asm_output_data_uleb128 (AT_index (a), + "%s: \"%s\"", name, AT_string (a)); + else dw2_asm_output_nstring (AT_string (a), -1, "%s", name); break; @@ -8683,6 +9035,103 @@ add_AT_pubnames (dw_die_ref die) } } +/* Helper function to generate top-level dies for skeleton debug_info and + debug_types. */ + +static void +add_top_level_skeleton_die_attrs (dw_die_ref die) +{ + const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL); + dw_attr_ref attr; + + add_comp_dir_attribute (die); + add_AT_string (die, DW_AT_GNU_dwo_name, dwo_file_name); + /* The specification suggests that these attributes be inline to avoid + having a .debug_str section. We know that they exist in the die because + we just added them. */ + attr = get_AT (die, DW_AT_GNU_dwo_name); + attr->dw_attr_val.v.val_str->form = DW_FORM_string; + attr = get_AT (die, DW_AT_comp_dir); + attr->dw_attr_val.v.val_str->form = DW_FORM_string; + + add_AT_pubnames (die); + add_AT_lineptr (die, DW_AT_GNU_addr_base, debug_addr_section_label); +} + +/* Return the single type-unit die for skeleton type units. */ + +static dw_die_ref +get_skeleton_type_unit (void) +{ + /* For split_debug_sections with use_type info, all type units int the + skeleton sections have identical dies (but different headers). This single + die will be output many times. */ + + static dw_die_ref skeleton_type_unit = NULL; + + if (skeleton_type_unit == NULL) + { + skeleton_type_unit = new_die (DW_TAG_type_unit, NULL, NULL); + add_top_level_skeleton_die_attrs (skeleton_type_unit); + skeleton_type_unit->die_abbrev = SKELETON_TYPE_DIE_ABBREV; + } + return skeleton_type_unit; +} + +/* The splitter will fill in this value. */ + +unsigned char dwo_id_placeholder[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* Output skeleton debug sections that point to the dwo file. */ + +static void +output_skeleton_debug_sections (dw_die_ref comp_unit) +{ + /* These attributes will be found in the full debug_info section. */ + remove_AT (comp_unit, DW_AT_producer); + remove_AT (comp_unit, DW_AT_language); + + /* Add attributes common to skeleton compile_units and type_units. */ + add_top_level_skeleton_die_attrs (comp_unit); + + /* The dwo_id is only for compile_units. */ + add_AT_data8 (comp_unit, DW_AT_GNU_dwo_id, dwo_id_placeholder); + + switch_to_section (debug_skeleton_info_section); + ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_info_section_label); + + /* Produce the skeleton compilation-unit header. This one differs enough from + a normal CU header that it's better not to call output_compilation_unit + header. */ + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + dw2_asm_output_data (4, 0xffffffff, + "Initial length escape value indicating 64-bit DWARF extension"); + + dw2_asm_output_data (DWARF_OFFSET_SIZE, + DWARF_COMPILE_UNIT_HEADER_SIZE + - DWARF_INITIAL_LENGTH_SIZE + + size_of_die (comp_unit), + "Length of Compilation Unit Info"); + dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label, + debug_abbrev_section, + "Offset Into Abbrev. Section"); + dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); + + comp_unit->die_abbrev = 1; + output_die (comp_unit); + + /* Build the skeleton debug_abbrev section. */ + switch_to_section (debug_skeleton_abbrev_section); + ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_abbrev_section_label); + + output_die_abbrevs (SKELETON_COMP_DIE_ABBREV, comp_unit); + if (use_debug_types) + output_die_abbrevs (SKELETON_TYPE_DIE_ABBREV, get_skeleton_type_unit ()); + + dw2_asm_output_data (1, 0, "end of skeleton .debug_abbrev"); +} + /* Output a comdat type unit DIE and its children. */ static void @@ -8705,7 +9154,11 @@ output_comdat_type_unit (comdat_type_nod calc_die_sizes (node->root_die); #if defined (OBJECT_FORMAT_ELF) - secname = ".debug_types"; + if (!dwarf_split_debug_info) + secname = ".debug_types"; + else + secname = ".debug_types.dwo"; + tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2); sprintf (tmp, "wt."); for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++) @@ -8714,6 +9167,7 @@ output_comdat_type_unit (comdat_type_nod targetm.asm_out.named_section (secname, SECTION_DEBUG | SECTION_LINKONCE, comdat_key); + #else tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2); sprintf (tmp, ".gnu.linkonce.wt."); @@ -8731,6 +9185,37 @@ output_comdat_type_unit (comdat_type_nod output_die (node->root_die); unmark_dies (node->root_die); + + if (dwarf_split_debug_info) + { + /* Produce the skeleton type-unit header. */ + const char *secname = ".debug_types"; + + targetm.asm_out.named_section (secname, + SECTION_DEBUG | SECTION_LINKONCE, + comdat_key); + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + dw2_asm_output_data (4, 0xffffffff, + "Initial length escape value indicating 64-bit DWARF extension"); + + /* One for the terminating NULL byte. */ + dw2_asm_output_data (DWARF_OFFSET_SIZE, + DWARF_COMPILE_UNIT_HEADER_SIZE + - DWARF_INITIAL_LENGTH_SIZE + + size_of_die (get_skeleton_type_unit ()) + + DWARF_TYPE_SIGNATURE_SIZE + DWARF_OFFSET_SIZE, + "Length of Type Unit Info"); + dw2_asm_output_data (2, dwarf_version, "DWARF version number"); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, + debug_skeleton_abbrev_section_label, + debug_abbrev_section, + "Offset Into Abbrev. Section"); + dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); + output_signature (node->signature, "Type Signature"); + dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "Offset to Type DIE"); + + output_die (get_skeleton_type_unit ()); + } } /* Return the DWARF2/3 pubname associated with a decl. */ @@ -8880,9 +9365,14 @@ output_pubnames (VEC (pubname_entry, gc) "Length of Public Type Names Info"); /* Version number for pubnames/pubtypes is still 2, even in DWARF3. */ dw2_asm_output_data (2, 2, "DWARF Version"); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, - debug_info_section, - "Offset of Compilation Unit Info"); + if (dwarf_split_debug_info) + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label, + debug_skeleton_info_section, + "Offset of Compilation Unit Info"); + else + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, + debug_info_section, + "Offset of Compilation Unit Info"); dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset, "Compilation Unit Length"); @@ -8937,9 +9427,14 @@ output_aranges (unsigned long aranges_le "Length of Address Ranges Info"); /* Version number for aranges is still 2, even in DWARF3. */ dw2_asm_output_data (2, 2, "DWARF Version"); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, - debug_info_section, - "Offset of Compilation Unit Info"); + if (dwarf_split_debug_info) + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label, + debug_skeleton_info_section, + "Offset of Compilation Unit Info"); + else + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, + debug_info_section, + "Offset of Compilation Unit Info"); dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address"); dw2_asm_output_data (1, 0, "Size of Segment Descriptor"); @@ -9039,7 +9534,7 @@ add_ranges (const_tree block) static void add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end, - bool *added) + bool *added, bool force_direct) { unsigned int in_use = ranges_by_label_in_use; unsigned int offset; @@ -9062,7 +9557,7 @@ add_ranges_by_labels (dw_die_ref die, co 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; } } @@ -9599,7 +10094,7 @@ output_one_line_info_table (dw_line_info 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; @@ -9669,6 +10164,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) { @@ -11975,14 +12476,7 @@ mem_loc_descriptor (rtx rtl, enum machin if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel) break; - /* We used to emit DW_OP_addr here, but that's wrong, since - DW_OP_addr should be relocated by the debug info consumer, - while DW_OP_GNU_push_tls_address operand should not. */ - temp = new_loc_descr (DWARF2_ADDR_SIZE == 4 - ? DW_OP_const4u : DW_OP_const8u, 0, 0); - temp->dw_loc_oprnd1.val_class = dw_val_class_addr; - temp->dw_loc_oprnd1.v.val_addr = rtl; - temp->dtprel = true; + temp = new_addr_loc_descr (rtl, true); mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0); add_loc_descr (&mem_loc_result, temp); @@ -11994,9 +12488,7 @@ mem_loc_descriptor (rtx rtl, enum machin break; symref: - mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0); - mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; - mem_loc_result->dw_loc_oprnd1.v.val_addr = rtl; + mem_loc_result = new_addr_loc_descr (rtl, 0); VEC_safe_push (rtx, gc, used_rtx_array, rtl); break; @@ -12898,9 +13390,7 @@ loc_descriptor (rtx rtl, enum machine_mo if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE && (dwarf_version >= 4 || !dwarf_strict)) { - loc_result = new_loc_descr (DW_OP_addr, 0, 0); - loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; - loc_result->dw_loc_oprnd1.v.val_addr = rtl; + loc_result = new_addr_loc_descr (rtl, 0); add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0)); VEC_safe_push (rtx, gc, used_rtx_array, rtl); } @@ -13601,8 +14091,7 @@ loc_list_from_tree (tree loc, int want_a if (DECL_THREAD_LOCAL_P (loc)) { rtx rtl; - enum dwarf_location_atom first_op; - enum dwarf_location_atom second_op; + enum dwarf_location_atom tls_op; bool dtprel = false; if (targetm.have_tls) @@ -13620,9 +14109,8 @@ loc_list_from_tree (tree loc, int want_a operand shouldn't be. */ if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc)) return 0; - first_op = DWARF2_ADDR_SIZE == 4 ? DW_OP_const4u : DW_OP_const8u; dtprel = true; - second_op = DW_OP_GNU_push_tls_address; + tls_op = DW_OP_GNU_push_tls_address; } else { @@ -13634,8 +14122,7 @@ loc_list_from_tree (tree loc, int want_a 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); @@ -13648,12 +14135,8 @@ loc_list_from_tree (tree loc, int want_a 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; @@ -13698,11 +14181,7 @@ loc_list_from_tree (tree loc, int want_a return 0; } else if (CONSTANT_P (rtl) && const_ok_for_output (rtl)) - { - ret = new_loc_descr (DW_OP_addr, 0, 0); - ret->dw_loc_oprnd1.val_class = dw_val_class_addr; - ret->dw_loc_oprnd1.v.val_addr = rtl; - } + ret = new_addr_loc_descr (rtl, 0); else { enum machine_mode mode, mem_mode; @@ -14640,9 +15119,7 @@ add_const_value_attribute (dw_die_ref di dw_loc_descr_ref loc_result; resolve_one_addr (&rtl, NULL); rtl_addr: - loc_result = new_loc_descr (DW_OP_addr, 0, 0); - loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; - loc_result->dw_loc_oprnd1.v.val_addr = rtl; + loc_result = new_addr_loc_descr (rtl, 0); add_loc_descr (&loc_result, new_loc_descr (DW_OP_stack_value, 0, 0)); add_AT_loc (die, DW_AT_location, loc_result); VEC_safe_push (rtx, gc, used_rtx_array, rtl); @@ -16151,7 +16628,7 @@ add_name_and_src_coords_attributes (dw_d 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 */ @@ -16172,7 +16649,7 @@ dwarf2out_vms_debug_main_pointer (void) add_name_attribute (die, VMS_DEBUG_MAIN_POINTER); ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL, FUNC_LABEL_ID (cfun)); - add_AT_lbl_id (die, DW_AT_entry_pc, label); + add_AT_lbl_id (die, DW_AT_entry_pc, label, false); /* Make it the first child of comp_unit_die (). */ die->die_parent = comp_unit_die (); @@ -16759,7 +17236,7 @@ gen_entry_point_die (tree decl, dw_die_r if (DECL_ABSTRACT (decl)) equate_decl_number_to_die (decl, decl_die); else - add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl)); + add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl), false); } #endif @@ -17280,7 +17757,7 @@ gen_call_site_die (tree decl, dw_die_ref if (stmt_die == NULL) stmt_die = subr_die; die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE); - add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label); + add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label, false); if (ca_loc->tail_call_p) add_AT_flag (die, DW_AT_GNU_tail_call, 1); if (ca_loc->symbol_ref) @@ -17289,7 +17766,7 @@ gen_call_site_die (tree decl, dw_die_ref 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; } @@ -17480,8 +17957,8 @@ gen_subprogram_die (tree decl, dw_die_re if (fde->dw_fde_begin) { /* We have already generated the labels. */ - add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin); - add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end); + add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin, false); + add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end, false); } else { @@ -17489,10 +17966,10 @@ gen_subprogram_die (tree decl, dw_die_re char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL, FUNC_LABEL_ID (cfun)); - add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id); + add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id, false); ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, FUNC_LABEL_ID (cfun)); - add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id); + add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id, false); } #if VMS_DEBUGGING_INFO @@ -17535,10 +18012,11 @@ gen_subprogram_die (tree decl, dw_die_re 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); } @@ -17557,9 +18035,9 @@ gen_subprogram_die (tree decl, dw_die_re /* Do the 'primary' section. */ add_AT_lbl_id (subr_die, DW_AT_low_pc, - fde->dw_fde_begin); + fde->dw_fde_begin, false); add_AT_lbl_id (subr_die, DW_AT_high_pc, - fde->dw_fde_end); + fde->dw_fde_end, false); /* Build a minimal DIE for the secondary section. */ seg_die = new_die (DW_TAG_subprogram, @@ -17584,9 +18062,9 @@ gen_subprogram_die (tree decl, dw_die_re name = concat ("__second_sect_of_", name, NULL); add_AT_lbl_id (seg_die, DW_AT_low_pc, - fde->dw_fde_second_begin); + fde->dw_fde_second_begin, false); add_AT_lbl_id (seg_die, DW_AT_high_pc, - fde->dw_fde_second_end); + fde->dw_fde_second_end, false); add_name_attribute (seg_die, name); if (want_pubnames ()) add_pubname_string (name, seg_die); @@ -17594,8 +18072,8 @@ gen_subprogram_die (tree decl, dw_die_re } else { - add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin); - add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end); + add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin, false); + add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end, false); } } @@ -18039,7 +18517,7 @@ gen_variable_die (tree decl, tree origin { /* 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) loc->expr->dw_loc_oprnd1.v.val_addr @@ -18223,7 +18701,7 @@ gen_label_die (tree decl, dw_die_ref con gcc_assert (!INSN_DELETED_P (insn)); ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn)); - add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); + add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false); } else if (insn && NOTE_P (insn) @@ -18231,7 +18709,7 @@ gen_label_die (tree decl, dw_die_ref con && CODE_LABEL_NUMBER (insn) != -1) { ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER (insn)); - add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); + add_AT_lbl_id (lbl_die, DW_AT_low_pc, label, false); } } } @@ -18270,10 +18748,10 @@ add_high_low_attributes (tree stmt, dw_d { ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, BLOCK_NUMBER (stmt)); - add_AT_lbl_id (die, DW_AT_entry_pc, label); + add_AT_lbl_id (die, DW_AT_entry_pc, label, false); } - 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 @@ -18288,10 +18766,10 @@ add_high_low_attributes (tree stmt, dw_d { ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, BLOCK_NUMBER (stmt)); - add_AT_lbl_id (die, DW_AT_low_pc, label); + add_AT_lbl_id (die, DW_AT_low_pc, label, false); ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, BLOCK_NUMBER (stmt)); - add_AT_lbl_id (die, DW_AT_high_pc, label); + add_AT_lbl_id (die, DW_AT_high_pc, label, false); } } @@ -20943,6 +21421,7 @@ output_macinfo_op (macinfo_entry *ref) case DW_MACRO_GNU_define_indirect: case DW_MACRO_GNU_undef_indirect: node = find_AT_string (ref->info); + /* FIXME: needs to change for dwarf_split_debug_info. */ if (node->form != DW_FORM_strp) { char label[32]; @@ -21130,8 +21609,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 @@ -21270,26 +21751,60 @@ dwarf2out_init (const char *filename ATT used_rtx_array = VEC_alloc (rtx, gc, 32); - debug_info_section = get_section (DEBUG_INFO_SECTION, - SECTION_DEBUG, NULL); - debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION, - SECTION_DEBUG, NULL); + if (!dwarf_split_debug_info) + { + debug_info_section = get_section (DEBUG_INFO_SECTION, + SECTION_DEBUG, NULL); + debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION, + SECTION_DEBUG, NULL); + debug_loc_section = get_section (DEBUG_LOC_SECTION, + SECTION_DEBUG, NULL); + } + else + { + debug_info_section = get_section (DEBUG_DWO_INFO_SECTION, + SECTION_DEBUG | SECTION_EXCLUDE, NULL); + debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION, + SECTION_DEBUG | SECTION_EXCLUDE, + NULL); + debug_addr_section = get_section (DEBUG_ADDR_SECTION, + SECTION_DEBUG, NULL); + debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION, + SECTION_DEBUG, NULL); + debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION, + SECTION_DEBUG, NULL); + ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label, + DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0); + + /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in + the main .o, but the skeleton_line goes into the split off dwo. */ + debug_skeleton_line_section + = get_section (DEBUG_DWO_LINE_SECTION, + SECTION_DEBUG | SECTION_EXCLUDE, NULL); + ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label, + DEBUG_SKELETON_LINE_SECTION_LABEL, 0); + debug_str_offsets_section = get_section (DEBUG_STR_OFFSETS_SECTION, + SECTION_DEBUG | SECTION_EXCLUDE, + NULL); + ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label, + DEBUG_SKELETON_INFO_SECTION_LABEL, 0); + debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION, + SECTION_DEBUG | SECTION_EXCLUDE, NULL); + } debug_aranges_section = get_section (DEBUG_ARANGES_SECTION, SECTION_DEBUG, NULL); debug_macinfo_section = get_section (dwarf_strict ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION, - SECTION_DEBUG, NULL); + DEBUG_MACRO_SECTION_FLAGS, NULL); debug_line_section = get_section (DEBUG_LINE_SECTION, SECTION_DEBUG, NULL); - debug_loc_section = get_section (DEBUG_LOC_SECTION, - SECTION_DEBUG, NULL); debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION, SECTION_DEBUG, NULL); debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION, SECTION_DEBUG, NULL); debug_str_section = get_section (DEBUG_STR_SECTION, - DEBUG_STR_SECTION_FLAGS, NULL); + DEBUG_STR_SECTION_FLAGS, NULL); debug_ranges_section = get_section (DEBUG_RANGES_SECTION, SECTION_DEBUG, NULL); debug_frame_section = get_section (DEBUG_FRAME_SECTION, @@ -21313,10 +21828,13 @@ dwarf2out_init (const char *filename ATT DEBUG_LINE_SECTION_LABEL, 0); ASM_GENERATE_INTERNAL_LABEL (ranges_section_label, DEBUG_RANGES_SECTION_LABEL, 0); + ASM_GENERATE_INTERNAL_LABEL (debug_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); @@ -21360,6 +21878,79 @@ output_indirect_string (void **h, void * return 1; } +static void +output_index_strings (void) +{ + unsigned int i; + unsigned int len = 0; + struct indirect_string_node *node; + + if (VEC_empty (indirect_string_node, index_string_table)) + return; + + switch_to_section (debug_str_offsets_section); + for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node); + i++) + { + gcc_assert (node->form == DW_FORM_GNU_str_index); + dw2_asm_output_data (DWARF_OFFSET_SIZE, len, + "indexed string 0x%x: %s", i, node->str); + len += strlen (node->str) + 1; + } + switch_to_section (debug_str_section); + for (i = 0; VEC_iterate (indirect_string_node, index_string_table, i, node); + i++) + { + ASM_OUTPUT_LABEL (asm_out_file, node->label); + assemble_string (node->str, strlen (node->str) + 1); + } +} + +/* Write the index table. */ + +static void +output_addr_table (void) +{ + unsigned int i; + dw_attr_node *node; + + if (VEC_empty (dw_attr_node, addr_index_table)) + return; + + switch_to_section (debug_addr_section); + for (i = 0; VEC_iterate (dw_attr_node, addr_index_table, i, node); i++) + { + const char *name; + + if (node->dw_attr == 0) + { + dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, ""); + continue; + } + + name = dwarf_attr_name (node->dw_attr); + switch (AT_class (node)) + { + case dw_val_class_addr: + dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (node), + "%s", name); + break; + case dw_val_class_loc: + gcc_assert (targetm.asm_out.output_dwarf_dtprel); + targetm.asm_out.output_dwarf_dtprel (asm_out_file, + DWARF2_ADDR_SIZE, + node->dw_attr_val.v.val_addr); + fputc ('\n', asm_out_file); + break; + case dw_val_class_lbl_id: + dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (node), "%s", name); + break; + default: + gcc_unreachable (); + } + } +} + #if ENABLE_ASSERT_CHECKING /* Verify that all marks are clear. */ @@ -21964,6 +22555,17 @@ resolve_addr_in_expr (dw_loc_descr_ref l if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL)) return false; break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + { + unsigned int idx = loc->dw_loc_oprnd1.val_index; + dw_attr_node *node = VEC_index (dw_attr_node, addr_index_table, idx); + if ((loc->dw_loc_opc == DW_OP_GNU_addr_index + || (loc->dw_loc_opc == DW_OP_GNU_const_index && loc->dtprel)) + && resolve_one_addr (&node->dw_attr_val.v.val_addr, NULL)) + return false; + } + break; case DW_OP_const4u: case DW_OP_const8u: if (loc->dtprel @@ -22098,11 +22700,15 @@ resolve_addr (dw_die_ref die) if (!resolve_addr_in_expr ((*curr)->expr)) { dw_loc_list_ref next = (*curr)->dw_loc_next; + dw_loc_descr_ref l = (*curr)->expr; + if (next && (*curr)->ll_symbol) { gcc_assert (!next->ll_symbol); next->ll_symbol = (*curr)->ll_symbol; } + if (l->dw_loc_oprnd1.val_index != -1U) + remove_addr_table_entry (l->dw_loc_oprnd1.val_index); *curr = next; } else @@ -22116,6 +22722,8 @@ resolve_addr (dw_die_ref die) else { loc->replaced = 1; + if (dwarf_split_debug_info) + remove_loc_list_addr_table_entries (loc); loc->dw_loc_next = *start; } } @@ -22140,6 +22748,8 @@ resolve_addr (dw_die_ref die) || l->dw_loc_next != NULL) && !resolve_addr_in_expr (l)) { + if (l->dw_loc_oprnd1.val_index != -1U) + remove_addr_table_entry (l->dw_loc_oprnd1.val_index); remove_AT (die, a->dw_attr); ix--; } @@ -22151,6 +22761,8 @@ resolve_addr (dw_die_ref die) if (a->dw_attr == DW_AT_const_value && resolve_one_addr (&a->dw_attr_val.v.val_addr, NULL)) { + if (AT_index (a) != -1U) + remove_addr_table_entry (AT_index (a)); remove_AT (die, a->dw_attr); ix--; } @@ -22174,6 +22786,8 @@ resolve_addr (dw_die_ref die) } else { + if (AT_index (a) != -1U) + remove_addr_table_entry (AT_index (a)); remove_AT (die, a->dw_attr); ix--; } @@ -22307,6 +22921,19 @@ hash_loc_operands (dw_loc_descr_ref loc, } hash = iterative_hash_rtx (val1->v.val_addr, hash); break; + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + { + dw_attr_ref attr = VEC_index (dw_attr_node, addr_index_table, + val1->val_index); + if (loc->dtprel) + { + unsigned char dtprel = 0xd1; + hash = iterative_hash_object (dtprel, hash); + } + hash = iterative_hash_rtx (attr->dw_attr_val.v.val_addr, hash); + } + break; case DW_OP_GNU_implicit_pointer: hash = iterative_hash_object (val2->v.val_int, hash); break; @@ -22488,9 +23115,12 @@ compare_loc_operands (dw_loc_descr_ref x 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 @@ -22521,6 +23151,18 @@ compare_loc_operands (dw_loc_descr_ref x case DW_OP_addr: hash_addr: return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr); + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + { + dw_attr_node *attrx1 = VEC_index (dw_attr_node, + addr_index_table, + valx1->val_index); + dw_attr_node *attry1 = VEC_index (dw_attr_node, + addr_index_table, + valy1->val_index); + return rtx_equal_p (attrx1->dw_attr_val.v.val_addr, + attry1->dw_attr_val.v.val_addr); + } case DW_OP_GNU_implicit_pointer: return valx1->val_class == dw_val_class_die_ref && valx1->val_class == valy1->val_class @@ -22634,7 +23276,7 @@ optimize_location_lists_1 (dw_die_ref di 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)); @@ -22650,6 +23292,43 @@ optimize_location_lists (dw_die_ref die) optimize_location_lists_1 (die, htab); htab_delete (htab); } + + +/* Recursively assign each location list a unique index into the debug_addr + section. */ + +static void +index_location_lists (dw_die_ref die) +{ + dw_die_ref c; + dw_attr_ref a; + unsigned ix; + + FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a) + if (AT_class (a) == dw_val_class_loc_list) + { + dw_loc_list_ref list = AT_loc_list (a); + dw_loc_list_ref curr; + for (curr = list; curr != NULL; curr = curr->dw_loc_next) + { + dw_attr_node attr; + + /* Don't index an entry that has already been indexed + or won't be output. */ + if (curr->begin_index != -1U + || (strcmp (curr->begin, curr->end) == 0 && !curr->force)) + continue; + + attr.dw_attr = DW_AT_location; + attr.dw_attr_val.val_class = dw_val_class_lbl_id; + attr.dw_attr_val.val_index = -1U; + attr.dw_attr_val.v.val_lbl_id = xstrdup (curr->begin); + curr->begin_index = add_addr_table_entry (&attr); + } + } + + FOR_EACH_CHILD (die, c, index_location_lists (c)); +} /* Output stuff that dwarf requires at the end of every file, and generate the DWARF-2 debugging info. */ @@ -22661,6 +23340,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. */ @@ -22814,6 +23494,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); @@ -22831,8 +23519,10 @@ dwarf2out_finish (const char *filename) /* Don't add if the CU has no associated code. */ if (text_section_used) { - add_AT_lbl_id (comp_unit_die (), DW_AT_low_pc, text_section_label); - add_AT_lbl_id (comp_unit_die (), DW_AT_high_pc, text_end_label); + add_AT_lbl_id (main_comp_unit_die, DW_AT_low_pc, text_section_label, + true); + add_AT_lbl_id (main_comp_unit_die, DW_AT_high_pc, text_end_label, + true); } } else @@ -22842,20 +23532,22 @@ 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 (!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) @@ -22865,16 +23557,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 (generate_debug_line_table) - 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) @@ -22883,7 +23575,11 @@ dwarf2out_finish (const char *filename) macinfo_section_label); if (have_location_lists) - optimize_location_lists (comp_unit_die ()); + { + optimize_location_lists (comp_unit_die ()); + if (dwarf_split_debug_info) + index_location_lists (comp_unit_die ()); + } /* Output all of the compilation units. We put the main one last so that the offsets are available to output_pubnames. */ @@ -22904,19 +23600,34 @@ dwarf2out_finish (const char *filename) attributes. */ if (generate_debug_line_table) add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list, - debug_line_section_label); + (!dwarf_split_debug_info + ? debug_line_section_label + : debug_skeleton_line_section_label)); output_comdat_type_unit (ctnode); *slot = ctnode; } htab_delete (comdat_type_table); - add_AT_pubnames (comp_unit_die ()); + if (!dwarf_split_debug_info) + add_AT_pubnames (comp_unit_die ()); + + if (dwarf_split_debug_info) + { + /* Add a place-holder for the dwo_id to the comp-unit die. */ + add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, dwo_id_placeholder); + if (ranges_table_in_use) + add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base, + ranges_section_label); + } /* Output the main compilation unit if non-empty or if .debug_macinfo or .debug_macro will be emitted. */ output_comp_unit (comp_unit_die (), have_macinfo); + if (dwarf_split_debug_info && info_section_emitted) + output_skeleton_debug_sections (main_comp_unit_die); + /* Output the abbreviation table. */ if (abbrev_die_table_in_use != 1) { @@ -22930,8 +23641,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 ()); } @@ -22982,10 +23691,22 @@ dwarf2out_finish (const char *filename) switch_to_section (debug_line_section); ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label); if (! DWARF2_ASM_LINE_DEBUG_INFO) - output_line_info (); + output_line_info (false); + + if (dwarf_split_debug_info && info_section_emitted) + { + switch_to_section (debug_skeleton_line_section); + ASM_OUTPUT_LABEL (asm_out_file, debug_skeleton_line_section_label); + output_line_info (true); + + output_index_strings (); + + switch_to_section (debug_addr_section); + ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label); + output_addr_table (); + } - /* If we emitted any 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); } Index: gcc/dwarf2out.h =================================================================== --- gcc/dwarf2out.h (revision 189829) +++ gcc/dwarf2out.h (working copy) @@ -171,6 +171,7 @@ dw_vec_const; typedef struct GTY(()) dw_val_struct { enum dw_val_class val_class; + unsigned int val_index; union dw_val_struct_union { rtx GTY ((tag ("dw_val_class_addr"))) val_addr; Index: gcc/opts.c =================================================================== --- gcc/opts.c (revision 189829) +++ gcc/opts.c (working copy) @@ -865,6 +865,10 @@ finish_options (struct gcc_options *opts /* Turn on -ffunction-sections when -freorder-functions=* is used. */ if (opts->x_flag_reorder_functions > 1) opts->x_flag_function_sections = 1; + + /* The -gsplit-dwarf option requires -gpubnames. */ + if (opts->x_dwarf_split_debug_info) + opts->x_debug_generate_pub_sections = 1; } #define LEFT_COLUMN 27 @@ -1776,6 +1780,11 @@ common_handle_option (struct gcc_options set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc); break; + case OPT_gsplit_dwarf: + set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, "", opts, opts_set, + loc); + break; + case OPT_ggdb: set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc); break; Index: gcc/common.opt =================================================================== --- gcc/common.opt (revision 189829) +++ gcc/common.opt (working copy) @@ -2432,6 +2432,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