From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2232 invoked by alias); 12 Nov 2019 20:25:09 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 2223 invoked by uid 89); 12 Nov 2019 20:25:08 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-32.5 required=5.0 tests=AWL,BAYES_00,ENV_AND_HDR_SPF_MATCH,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,HTML_MESSAGE,KAM_INFOUSMEBIZ,RCVD_IN_DNSWL_NONE,SPF_PASS,USER_IN_DEF_SPF_WL autolearn=ham version=3.3.1 spammy=tus, comply, Low, Ali X-HELO: mail-wr1-f66.google.com Received: from mail-wr1-f66.google.com (HELO mail-wr1-f66.google.com) (209.85.221.66) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 12 Nov 2019 20:24:59 +0000 Received: by mail-wr1-f66.google.com with SMTP id a15so19980669wrf.9 for ; Tue, 12 Nov 2019 12:24:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=udhHrGAjBCJWQEi78CZUvxZa/avRDm9ofn2arxMMjXg=; b=JRy3MQcQA2395tTYmK8l0ErUkk8LQg7B6Asw+BpAExxUxnMmzpzVBujPEupvdsgJ2J pZIayoyCGQxWEAmeli5JV1n4lW58gQDqBC1nW2h34t+dZd+HhbKWD1iF/vsWsiF/1+h1 G/CZDeFyXuGw2hpLzsvf2ttnus4y//dy6tfSu8eG5ImEAgga1ur0gFqxOpWySKzkWGJE 0n/J++QBjbU163ImKZc1CO755poq/fOHZqueHfrFtC02EdDwT3CHlTnzcItU7gq/thgs MapaaDZNq5RQZv2eJnga7d3JJIkfXQUqiTLoYf85O0K2CeniKwktjTaH1+vwni0r8c8p 9eKw== MIME-Version: 1.0 References: <20191101234344.122009-1-tamur@google.com> In-Reply-To: <20191101234344.122009-1-tamur@google.com> From: "Ali Tamur via gdb-patches" Reply-To: Ali Tamur Date: Tue, 12 Nov 2019 20:25:00 -0000 Message-ID: Subject: Re: [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets. To: gdb-patches@sourceware.org Cc: Simon Marchi Content-Type: text/plain; charset="UTF-8" X-IsSubscribed: yes X-SW-Source: 2019-11/txt/msg00342.txt.bz2 Friendly ping? On Fri, Nov 1, 2019 at 4:43 PM Ali Tamur wrote: > * Process debug_str_offsets section. Handle DW_AT_str_offsets_base > attribute and > keep the value in dwarf2_cu. > > * Make addr_base and ranges_base fields in dwarf2_cu optional to > disambiguate 0 > value (absent or present and 0). > > * During parsing, there is no guarantee that DW_AT_str_offsets_base and > DW_AT_rnglists_base fields will be processed before the attributes that > need > those values for correct computation. So make two passes, on the first one > mark > the attributes that depend on *_base attributes and process only the > others. > On the second pass, only process the attributes that are marked on the > first > pass. > > * For string attributes, differentiate between addresses that directly > point to > a string and those that point to an offset in debug_str_offsets section. > > * There are now two attributes, DW_AT_addr_base and DW_AT_GNU_addr_base to > read > address offset base. Likewise, there are two attributes, > DW_AT_rnglists_base > and DW_AT_GNU_ranges_base to read ranges base. Since there is no guarantee > which > ones the compiler will generate, create helper functions to handle all > cases. > > Tested with CC=/usr/bin/gcc (version 8.3.0) against master branch (also > with > -gsplit-dwarf and -gdwarf-4 flags) and there was no increase in the set of > tests that fails. (gdb still cannot debug a 'hello world' program with > DWARF 5, > so for the time being, this is all we care about). > > This is part of an effort to support DWARF-5 in gdb. > > > gdb/ChangeLog > > * dwarf2read.c (dwarf2_debug_sections): Add debug_str_offsets > sections > (dwarf2_cu): Add str_offsets_base field. Change the type of > addr_base > and ranges_base to gdb::optional. Update comments. > (dwo_file): Update comments. > (attribute): Add string_is_str_index field. > (DW_STRING_IS_STR_INDEX): New macro (to comply with local > standard). > (read_attribute): Update API to take an additional out parameter, > need_reprocess. This is used to mark attributes that need other > attributes (e.g. str_offsets_base) for correct computation which > may not > have been read yet. > (read_addr_index): New function. > (read_dwo_str_index): Likewise. > (read_stub_str_index): Likewise. > (get_comp_dir_attr): Likewise. > (get_stub_string_attr): Likewise. > (dwarf2_per_objfile::locate_sections): Handle debug_str_offsets > section. > (lookup_addr_base): New function. > (lookup_ranges_base): Likewise. > (read_cutu_die_from_dwo): Use the new functions: lookup_addr_base, > lookup_ranges_base, DW_STRING_IS_STR_INDEX, get_comp_dir_attr. > (init_cutu_and_read_dies): Initialize str_offsets_base fields. > (init_cutu_and_read_dies_no_follow): Change API to take parent > compile > unit. This is used to inherit parent's str_offsets_base and > addr_base. > Update comments. > (init_cutu_and_read_dies_simple): Reflect API changes. > (skip_one_die): Likewise. > (create_cus_hash_table): Likewise. > (open_and_init_dwo_file): Likewise. > (dwarf2_get_pc_bounds): Likewise. > (dwarf2_record_block_ranges): Likewise. > (read_full_die_1): Change implementation to reprocess attributes > that > need str_offsets_base and addr_base. > (partial_die_info::read): Change implementation to reprocess > attributes > that need str_offsets_base and addr_base. Don't complain if > DW_AT_sibling points to an attribute before this one. Update Api > change > of addr_base field. > (read_attribute_reprocess): New method. > (read_attribute_value): Change API to take an additional out > parameter, > need_reprocess. Initialize string_is_str_index field. No longer > mark an > error when a non-dwo compile unit has index based attributes. > (read_attribute): Reflect API changes. > (read_addr_index_1): Reflect API changes. Update comments. > (dwarf2_read_addr_index_data): Reflect API changes. > (read_str_index): Change API and implementation. This becomes a > helper > to be used by the new string index related methods. > * dwarf2read.h (dwarf2_per_objfile): Add str_offsets field. > * symfile.h (dwarf2_debug_sections): Likewise. > * xcoffread.c (dwarf2_xcoff_names): Likewise. > --- > gdb/dwarf2read.c | 431 ++++++++++++++++++++++++++++++++++++----------- > gdb/dwarf2read.h | 1 + > gdb/symfile.h | 1 + > gdb/xcoffread.c | 1 + > 4 files changed, 333 insertions(+), 101 deletions(-) > > diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c > index 4372a47c6d..8d201c125e 100644 > --- a/gdb/dwarf2read.c > +++ b/gdb/dwarf2read.c > @@ -287,6 +287,7 @@ static const struct dwarf2_debug_sections > dwarf2_elf_names = > { ".debug_macinfo", ".zdebug_macinfo" }, > { ".debug_macro", ".zdebug_macro" }, > { ".debug_str", ".zdebug_str" }, > + { ".debug_str_offsets", ".zdebug_str_offsets" }, > { ".debug_line_str", ".zdebug_line_str" }, > { ".debug_ranges", ".zdebug_ranges" }, > { ".debug_rnglists", ".zdebug_rnglists" }, > @@ -500,29 +501,27 @@ public: > There is an invariant here that is important to remember: > Except for attributes copied from the top level DIE in the "main" > (or "stub") file in preparation for reading the DWO file > - (e.g., DW_AT_GNU_addr_base), we KISS: there is only *one* CU. > + (e.g., DW_AT_addr_base), we KISS: there is only *one* CU. > Either there isn't a DWO file (in which case this is NULL and the > point > is moot), or there is and either we're not going to read it (in which > case this is NULL) or there is and we are reading it (in which case > this > is non-NULL). */ > struct dwo_unit *dwo_unit = nullptr; > > - /* The DW_AT_addr_base attribute if present, zero otherwise > - (zero is a valid value though). > + /* The DW_AT_addr_base (DW_AT_GNU_addr_base) attribute if present. > Note this value comes from the Fission stub CU/TU's DIE. */ > - ULONGEST addr_base = 0; > + gdb::optional addr_base {}; > > - /* The DW_AT_ranges_base attribute if present, zero otherwise > - (zero is a valid value though). > + /* The DW_AT_rnglists_base attribute if present. > Note this value comes from the Fission stub CU/TU's DIE. > Also note that the value is zero in the non-DWO case so this value > can > be used without needing to know whether DWO files are in use or not. > N.B. This does not apply to DW_AT_ranges appearing in > DW_TAG_compile_unit dies. This is a bit of a wart, consider if ever > DW_AT_ranges appeared in the DW_TAG_compile_unit of DWO DIEs: then > - DW_AT_ranges_base *would* have to be applied, and we'd have to care > + DW_AT_rnglists_base *would* have to be applied, and we'd have to care > whether the DW_AT_ranges attribute came from the skeleton or DWO. */ > - ULONGEST ranges_base = 0; > + gdb::optional ranges_base = 0; > > /* When reading debug info generated by older versions of rustc, we > have to rewrite some union types to be struct types with a > @@ -532,6 +531,12 @@ public: > all such types here and process them after expansion. */ > std::vector rust_unions; > > + /* The DW_AT_str_offsets_base attribute if present. For DWARF 4 version > DWO > + files, the value is implicitly zero. For DWARF 5 version DWO files, > the > + value is often implicit and is the size of the header of > + .debug_str_offsets section (8 or 4, depending on the address size). > */ > + gdb::optional str_offsets_base {}; > + > /* Mark used when releasing cached dies. */ > bool mark : 1; > > @@ -697,7 +702,7 @@ struct dwo_file > dwo_file () = default; > DISABLE_COPY_AND_ASSIGN (dwo_file); > > - /* The DW_AT_GNU_dwo_name attribute. > + /* The DW_AT_GNU_dwo_name or DW_AT_dwo_name attribute. > For virtual DWO files the name is constructed from the section > offsets > of abbrev,line,loc,str_offsets so that we combine virtual DWO files > from related CU+TUs. */ > @@ -1272,6 +1277,18 @@ struct attribute > here for better struct attribute alignment. */ > unsigned int string_is_canonical : 1; > > + /* For strings in non-DWO files, was a string recorded with > + DW_AT_GNU_str_index before we knew the value of > DW_AT_str_offsets_base? > + If non-zero, then the "value" of the string is in u.unsnd, and > + read_dwo_str_index must be called to obtain the actual string. > + This is necessary for DW_AT_comp_dir and DW_AT_GNU_dwo_name (or > + DW_AT_dwo_name) attributes: To save a relocation > DW_AT_GNU_str_index is > + used, but because all .o file .debug_str_offsets sections are > + concatenated together in the executable each .o has its own offset > into > + this section. So if DW_AT_str_offsets_base comes later in the DIE, > we > + need to reprocess these attributes later. */ > + bool string_is_str_index; > + > union > { > const char *str; > @@ -1324,6 +1341,7 @@ struct die_info > > #define DW_STRING(attr) ((attr)->u.str) > #define DW_STRING_IS_CANONICAL(attr) ((attr)->string_is_canonical) > +#define DW_STRING_IS_STR_INDEX(attr) ((attr)->string_is_str_index) > #define DW_UNSND(attr) ((attr)->u.unsnd) > #define DW_BLOCK(attr) ((attr)->u.blk) > #define DW_SND(attr) ((attr)->u.snd) > @@ -1519,7 +1537,12 @@ static const struct cu_partial_die_info > find_partial_die (sect_offset, int, > > static const gdb_byte *read_attribute (const struct die_reader_specs *, > struct attribute *, struct > attr_abbrev *, > - const gdb_byte *); > + const gdb_byte *, bool > *need_reprocess); > + > +static void read_attribute_reprocess (const struct die_reader_specs > *reader, > + struct attribute *attr); > + > +static CORE_ADDR read_addr_index (struct dwarf2_cu *cu, unsigned int > addr_index); > > static unsigned int read_1_byte (bfd *, const gdb_byte *); > > @@ -1578,8 +1601,17 @@ static CORE_ADDR read_addr_index_from_leb128 > (struct dwarf2_cu *, > const gdb_byte *, > unsigned int *); > > -static const char *read_str_index (const struct die_reader_specs *reader, > - ULONGEST str_index); > +static const char *read_dwo_str_index (const struct die_reader_specs > *reader, > + ULONGEST str_index); > + > +static const char *read_stub_str_index (struct dwarf2_cu *cu, > + ULONGEST str_index); > + > +static const char *get_comp_dir_attr (struct die_info *die, > + struct dwarf2_cu *cu); > + > +static const char *get_stub_string_attr (struct dwarf2_cu *cu, > + const struct attribute *attr); > > static void set_cu_language (unsigned int, struct dwarf2_cu *); > > @@ -2409,6 +2441,11 @@ dwarf2_per_objfile::locate_sections (bfd *abfd, > asection *sectp, > this->str.s.section = sectp; > this->str.size = bfd_section_size (sectp); > } > + else if (section_is_p (sectp->name, &names.str_offsets)) > + { > + this->str_offsets.s.section = sectp; > + this->str_offsets.size = bfd_section_size (sectp); > + } > else if (section_is_p (sectp->name, &names.line_str)) > { > this->line_str.s.section = sectp; > @@ -7154,7 +7191,41 @@ lookup_signatured_type (struct dwarf2_cu *cu, > ULONGEST sig) > return entry; > } > } > - > + > +static gdb::optional > +lookup_addr_base (struct dwarf2_cu *cu, struct die_info* comp_unit_die, > + bool will_follow) > +{ > + struct attribute *attr; > + if (will_follow) > + { > + attr = dwarf2_attr (comp_unit_die, DW_AT_addr_base, cu); > + if (attr == nullptr) > + attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_addr_base, cu); > + } > + else > + { > + attr = dwarf2_attr_no_follow (comp_unit_die, DW_AT_addr_base); > + if (attr == nullptr) > + attr = dwarf2_attr_no_follow (comp_unit_die, DW_AT_GNU_addr_base); > + } > + if (attr == nullptr) > + return gdb::optional (); > + return DW_UNSND (attr); > +} > + > +static gdb::optional > +lookup_ranges_base (struct dwarf2_cu *cu, struct die_info* comp_unit_die) > +{ > + struct attribute *attr; > + attr = dwarf2_attr (comp_unit_die, DW_AT_rnglists_base, cu); > + if (attr == nullptr) > + attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_ranges_base, cu); > + if (attr == nullptr) > + return gdb::optional (); > + return DW_UNSND (attr); > +} > + > /* Low level DIE reading support. */ > > /* Initialize a die_reader_specs struct from a dwarf2_cu struct. */ > @@ -7215,7 +7286,6 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data > *this_cu, > struct attribute *comp_dir, *stmt_list, *low_pc, *high_pc, *ranges; > int i,num_extra_attrs; > struct dwarf2_section_info *dwo_abbrev_section; > - struct attribute *attr; > struct die_info *comp_unit_die; > > /* At most one of these may be provided. */ > @@ -7246,20 +7316,14 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data > *this_cu, > ranges = dwarf2_attr (stub_comp_unit_die, DW_AT_ranges, cu); > comp_dir = dwarf2_attr (stub_comp_unit_die, DW_AT_comp_dir, cu); > > - /* There should be a DW_AT_addr_base attribute here (if needed). > - We need the value before we can process DW_FORM_GNU_addr_index > - or DW_FORM_addrx. */ > - cu->addr_base = 0; > - attr = dwarf2_attr (stub_comp_unit_die, DW_AT_GNU_addr_base, cu); > - if (attr) > - cu->addr_base = DW_UNSND (attr); > + auto maybe_addr_base = lookup_addr_base (cu, stub_comp_unit_die, > true); > + if (maybe_addr_base.has_value ()) > + cu->addr_base = *maybe_addr_base; > > - /* There should be a DW_AT_ranges_base attribute here (if needed). > - We need the value before we can process DW_AT_ranges. */ > - cu->ranges_base = 0; > - attr = dwarf2_attr (stub_comp_unit_die, DW_AT_GNU_ranges_base, cu); > - if (attr) > - cu->ranges_base = DW_UNSND (attr); > + /* There should be a DW_AT_rnglists_base (DW_AT_GNU_ranges_base) > attribute > + here (if needed). We need the value before we can process > + DW_AT_ranges. */ > + cu->ranges_base = lookup_ranges_base (cu, stub_comp_unit_die); > } > else if (stub_comp_dir != NULL) > { > @@ -7268,6 +7332,7 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data > *this_cu, > comp_dir->name = DW_AT_comp_dir; > comp_dir->form = DW_FORM_string; > DW_STRING_IS_CANONICAL (comp_dir) = 0; > + DW_STRING_IS_STR_INDEX (comp_dir) = false; > DW_STRING (comp_dir) = stub_comp_dir; > } > > @@ -7368,8 +7433,7 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data > *this_cu, > TUs by skipping the stub and going directly to the entry in the DWO > file. > However, skipping the stub means we won't get DW_AT_comp_dir, so we > have > to get it via circuitous means. Blech. */ > - if (comp_dir != NULL) > - result_reader->comp_dir = DW_STRING (comp_dir); > + result_reader->comp_dir = get_comp_dir_attr (comp_unit_die, cu); > > /* Skip dummy compilation units. */ > if (info_ptr >= begin_info_ptr + dwo_unit->length > @@ -7667,6 +7731,13 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data > *this_cu, > init_cu_die_reader (&reader, cu, section, NULL, abbrev_table); > info_ptr = read_full_die (&reader, &comp_unit_die, info_ptr, > &has_children); > > + /* DWO_AT_GNU_dwo_name and DW_AT_comp_dir in the stub may be using > + DW_FORM_GNU_str_index which needs DW_AT_str_offsets_base. */ > + struct attribute *attr = dwarf2_attr (comp_unit_die, > + DW_AT_str_offsets_base, cu); > + if (attr) > + cu->str_offsets_base = DW_UNSND (attr); > + > if (skip_partial && comp_unit_die->tag == DW_TAG_partial_unit) > return; > > @@ -7730,9 +7801,9 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data > *this_cu, > } > } > > -/* Read CU/TU THIS_CU but do not follow DW_AT_GNU_dwo_name if present. > - DWO_FILE, if non-NULL, is the DWO file to read (the caller is assumed > - to have already done the lookup to find the DWO file). > +/* Read CU/TU THIS_CU but do not follow DW_AT_GNU_dwo_name > (DW_AT_GNU_dwo_name) > + if present. DWO_FILE, if non-NULL, is the DWO file to read (the caller > is > + assumed to have already done the lookup to find the DWO file). > > The caller is required to fill in THIS_CU->section, THIS_CU->offset, > and > THIS_CU->is_debug_types, but nothing else. > @@ -7748,6 +7819,7 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data > *this_cu, > > static void > init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu, > + struct dwarf2_cu *parent_cu, > struct dwo_file *dwo_file, > die_reader_func_ftype *die_reader_func, > void *data) > @@ -7786,6 +7858,11 @@ init_cutu_and_read_dies_no_follow (struct > dwarf2_per_cu_data *this_cu, > ? rcuh_kind::TYPE > : rcuh_kind::COMPILE)); > > + if (parent_cu) > + { > + cu.str_offsets_base = parent_cu->str_offsets_base; > + cu.addr_base = parent_cu->addr_base; > + } > this_cu->length = get_cu_length (&cu.header); > > /* Skip dummy compilation units. */ > @@ -7800,11 +7877,31 @@ init_cutu_and_read_dies_no_follow (struct > dwarf2_per_cu_data *this_cu, > init_cu_die_reader (&reader, &cu, section, dwo_file, abbrev_table.get > ()); > info_ptr = read_full_die (&reader, &comp_unit_die, info_ptr, > &has_children); > > + /* DWO_AT_GNU_dwo_name and DW_AT_comp_dir in the stub may be using > + DW_FORM_GNU_str_index, so we need to fetch DW_AT_str_offsets_base > + ASAP. */ > + struct attribute *attr = dwarf2_attr (comp_unit_die, > + DW_AT_str_offsets_base, &cu); > + if (attr) > + { > + /* DW_AT_str_offsets_base shouldn't appear in DWOs. */ > + if (dwo_file != NULL) > + { > + complaint (_("DW_AT_str_offsets_base present in DWO file %s," > + " ignored"), > + dwo_file->dwo_name); > + } > + else > + { > + cu.str_offsets_base = DW_UNSND (attr); > + } > + } > + > die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data); > } > > -/* Read a CU/TU, except that this does not look for DW_AT_GNU_dwo_name and > - does not lookup the specified DWO file. > +/* Read a CU/TU, except that this does not look for DW_AT_GNU_dwo_name > + (DW_AT_dwo_name) and does not lookup the specified DWO file. > This cannot be used to read DWO files. > > THIS_CU->cu is always freed when done. > @@ -7817,7 +7914,7 @@ init_cutu_and_read_dies_simple (struct > dwarf2_per_cu_data *this_cu, > die_reader_func_ftype *die_reader_func, > void *data) > { > - init_cutu_and_read_dies_no_follow (this_cu, NULL, die_reader_func, > data); > + init_cutu_and_read_dies_no_follow (this_cu, NULL, NULL, > die_reader_func, data); > } > > /* Type Unit Groups. > @@ -9327,7 +9424,9 @@ skip_one_die (const struct die_reader_specs *reader, > const gdb_byte *info_ptr, > /* The only abbrev we care about is DW_AT_sibling. */ > if (abbrev->attrs[i].name == DW_AT_sibling) > { > - read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr); > + bool ignored; > + read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr, > + &ignored); > if (attr.form == DW_FORM_ref_addr) > complaint (_("ignoring absolute DW_AT_sibling")); > else > @@ -11968,8 +12067,8 @@ create_dwo_cu_reader (const struct > die_reader_specs *reader, > > static void > create_cus_hash_table (struct dwarf2_per_objfile *dwarf2_per_objfile, > - struct dwo_file &dwo_file, dwarf2_section_info > §ion, > - htab_t &cus_htab) > + dwarf2_cu *cu, struct dwo_file &dwo_file, > + dwarf2_section_info §ion, htab_t &cus_htab) > { > struct objfile *objfile = dwarf2_per_objfile->objfile; > const gdb_byte *info_ptr, *end_ptr; > @@ -12006,7 +12105,7 @@ create_cus_hash_table (struct dwarf2_per_objfile > *dwarf2_per_objfile, > create_dwo_cu_data.dwo_file = &dwo_file; > > init_cutu_and_read_dies_no_follow ( > - &per_cu, &dwo_file, create_dwo_cu_reader, &create_dwo_cu_data); > + &per_cu, cu, &dwo_file, create_dwo_cu_reader, > &create_dwo_cu_data); > info_ptr += per_cu.length; > > // If the unit could not be parsed, skip it. > @@ -13040,8 +13139,8 @@ open_and_init_dwo_file (struct dwarf2_per_cu_data > *per_cu, > bfd_map_over_sections (dwo_file->dbfd.get (), > dwarf2_locate_dwo_sections, > &dwo_file->sections); > > - create_cus_hash_table (dwarf2_per_objfile, *dwo_file, dwo_file-> > sections.info, > - dwo_file->cus); > + create_cus_hash_table (dwarf2_per_objfile, per_cu->cu, *dwo_file, > + dwo_file->sections.info, dwo_file->cus); > > create_debug_types_hash_table (dwarf2_per_objfile, dwo_file.get (), > dwo_file->sections.types, dwo_file->tus); > @@ -14703,10 +14802,11 @@ dwarf2_get_pc_bounds (struct die_info *die, > CORE_ADDR *lowpc, > /* DW_AT_ranges_base does not apply to DIEs from the DWO > skeleton. > We take advantage of the fact that DW_AT_ranges does not > appear > in DW_TAG_compile_unit of DWO files. */ > - int need_ranges_base = die->tag != DW_TAG_compile_unit; > + int need_ranges_base = die->tag != DW_TAG_compile_unit > + && cu->ranges_base.has_value(); > unsigned int ranges_offset = (DW_UNSND (attr) > + (need_ranges_base > - ? cu->ranges_base > + ? *cu->ranges_base > : 0)); > > /* Value of the DW_AT_ranges attribute is the offset in the > @@ -14874,12 +14974,12 @@ dwarf2_record_block_ranges (struct die_info > *die, struct block *block, > /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton. > We take advantage of the fact that DW_AT_ranges does not appear > in DW_TAG_compile_unit of DWO files. */ > - int need_ranges_base = die->tag != DW_TAG_compile_unit; > - > + int need_ranges_base = die->tag != DW_TAG_compile_unit > + && cu->ranges_base.has_value(); > /* The value of the DW_AT_ranges attribute is the offset of the > address range list in the .debug_ranges section. */ > unsigned long offset = (DW_UNSND (attr) > - + (need_ranges_base ? cu->ranges_base : 0)); > + + (need_ranges_base ? *cu->ranges_base : 0)); > > std::vector blockvec; > dwarf2_ranges_process (offset, cu, > @@ -18214,10 +18314,26 @@ read_full_die_1 (const struct die_reader_specs > *reader, > attributes. */ > die->num_attrs = abbrev->num_attrs; > > + std::vector indexes_that_need_reprocess; > for (i = 0; i < abbrev->num_attrs; ++i) > - info_ptr = read_attribute (reader, &die->attrs[i], &abbrev->attrs[i], > - info_ptr); > + { > + bool need_reprocess; > + info_ptr = > + read_attribute (reader, &die->attrs[i], &abbrev->attrs[i], > + info_ptr, &need_reprocess); > + if (need_reprocess) > + indexes_that_need_reprocess.push_back (i); > + } > > + struct attribute *attr = dwarf2_attr_no_follow (die, > DW_AT_str_offsets_base); > + if (attr) > + cu->str_offsets_base = DW_UNSND (attr); > + > + auto maybe_addr_base = lookup_addr_base(cu, die, false); > + if (maybe_addr_base.has_value()) > + cu->addr_base = *maybe_addr_base; > + for (int index : indexes_that_need_reprocess) > + read_attribute_reprocess (reader, &die->attrs[index]); > *diep = die; > *has_children = abbrev->has_children; > return info_ptr; > @@ -18729,12 +18845,23 @@ partial_die_info::read (const struct > die_reader_specs *reader, > int has_high_pc_attr = 0; > int high_pc_relative = 0; > > + std::vector attr_vec; > + std::vector indexes_that_need_reprocess; > + attr_vec.resize(abbrev.num_attrs); > for (i = 0; i < abbrev.num_attrs; ++i) > { > - struct attribute attr; > - > - info_ptr = read_attribute (reader, &attr, &abbrev.attrs[i], > info_ptr); > + bool need_reprocess; > + info_ptr = read_attribute (reader, &attr_vec[i], &abbrev.attrs[i], > + info_ptr, &need_reprocess); > + if (need_reprocess) > + indexes_that_need_reprocess.push_back (i); > + } > + for (int index : indexes_that_need_reprocess) > + read_attribute_reprocess (reader, &attr_vec[index]); > > + for (i = 0; i < abbrev.num_attrs; ++i) > + { > + struct attribute &attr = attr_vec[i]; > /* Store the data if it is of an attribute we want to keep in a > partial symbol table. */ > switch (attr.name) > @@ -18825,9 +18952,7 @@ partial_die_info::read (const struct > die_reader_specs *reader, > sect_offset off = dwarf2_get_ref_die_offset (&attr); > const gdb_byte *sibling_ptr = buffer + to_underlying (off); > > - if (sibling_ptr < info_ptr) > - complaint (_("DW_AT_sibling points backwards")); > - else if (sibling_ptr > reader->buffer_end) > + if (sibling_ptr > reader->buffer_end) > dwarf2_section_buffer_overflow_complaint > (reader->die_section); > else > sibling = sibling_ptr; > @@ -18882,10 +19007,11 @@ partial_die_info::read (const struct > die_reader_specs *reader, > /* It would be nice to reuse dwarf2_get_pc_bounds here, > but that requires a full DIE, so instead we just > reimplement it. */ > - int need_ranges_base = tag != DW_TAG_compile_unit; > + int need_ranges_base = tag != DW_TAG_compile_unit > + && cu->ranges_base.has_value(); > unsigned int ranges_offset = (DW_UNSND (&attr) > + (need_ranges_base > - ? cu->ranges_base > + ? *cu->ranges_base > : 0)); > > /* Value of the DW_AT_ranges attribute is the offset in the > @@ -19176,12 +19302,58 @@ partial_die_info::fixup (struct dwarf2_cu *cu) > fixup_called = 1; > } > > +void read_attribute_reprocess (const struct die_reader_specs *reader, > + struct attribute *attr) > +{ > + struct dwarf2_cu *cu = reader->cu; > + switch (attr->form) > + { > + case DW_FORM_addrx: > + case DW_FORM_GNU_addr_index: > + DW_ADDR (attr) = read_addr_index (cu, DW_UNSND (attr)); > + break; > + case DW_FORM_strx: > + case DW_FORM_strx1: > + case DW_FORM_strx2: > + case DW_FORM_strx3: > + case DW_FORM_strx4: > + case DW_FORM_GNU_str_index: > + unsigned int str_index = DW_UNSND (attr); > + if (reader->dwo_file != NULL) > + { > + DW_STRING (attr) = read_dwo_str_index (reader, str_index); > + DW_STRING_IS_CANONICAL (attr) = 0; > + DW_STRING_IS_STR_INDEX (attr) = false; > + } > + else if (cu->str_offsets_base.has_value ()) > + { > + DW_STRING (attr) = read_stub_str_index (cu, str_index); > + DW_STRING_IS_CANONICAL (attr) = 0; > + DW_STRING_IS_STR_INDEX (attr) = false; > + } > + else > + { > + if (attr->name != DW_AT_comp_dir > + && attr->name != DW_AT_GNU_dwo_name > + && attr->name != DW_AT_dwo_name) > + { > + error (_("Dwarf Error: %s/%s found in non-DWO CU"), > + dwarf_form_name (attr->form), > + dwarf_attr_name (attr->name)); > + } > + DW_UNSND (attr) = str_index; > + DW_STRING_IS_STR_INDEX (attr) = true; > + } > + } > +} > + > /* Read an attribute value described by an attribute form. */ > > static const gdb_byte * > read_attribute_value (const struct die_reader_specs *reader, > struct attribute *attr, unsigned form, > - LONGEST implicit_const, const gdb_byte *info_ptr) > + LONGEST implicit_const, const gdb_byte *info_ptr, > + bool *need_reprocess) > { > struct dwarf2_cu *cu = reader->cu; > struct dwarf2_per_objfile *dwarf2_per_objfile > @@ -19192,6 +19364,7 @@ read_attribute_value (const struct > die_reader_specs *reader, > struct comp_unit_head *cu_header = &cu->header; > unsigned int bytes_read; > struct dwarf_block *blk; > + *need_reprocess = false; > > attr->form = (enum dwarf_form) form; > switch (form) > @@ -19255,6 +19428,7 @@ read_attribute_value (const struct > die_reader_specs *reader, > case DW_FORM_string: > DW_STRING (attr) = read_direct_string (abfd, info_ptr, &bytes_read); > DW_STRING_IS_CANONICAL (attr) = 0; > + DW_STRING_IS_STR_INDEX (attr) = false; > info_ptr += bytes_read; > break; > case DW_FORM_strp: > @@ -19264,6 +19438,7 @@ read_attribute_value (const struct > die_reader_specs *reader, > abfd, info_ptr, > cu_header, > &bytes_read); > DW_STRING_IS_CANONICAL (attr) = 0; > + DW_STRING_IS_STR_INDEX (attr) = false; > info_ptr += bytes_read; > break; > } > @@ -19288,6 +19463,7 @@ read_attribute_value (const struct > die_reader_specs *reader, > DW_STRING (attr) = read_indirect_string_from_dwz (objfile, > dwz, str_offset); > DW_STRING_IS_CANONICAL (attr) = 0; > + DW_STRING_IS_STR_INDEX (attr) = false; > info_ptr += bytes_read; > } > break; > @@ -19365,22 +19541,15 @@ read_attribute_value (const struct > die_reader_specs *reader, > info_ptr += bytes_read; > } > info_ptr = read_attribute_value (reader, attr, form, implicit_const, > - info_ptr); > + info_ptr, need_reprocess); > break; > case DW_FORM_implicit_const: > DW_SND (attr) = implicit_const; > break; > case DW_FORM_addrx: > case DW_FORM_GNU_addr_index: > - if (reader->dwo_file == NULL) > - { > - /* For now flag a hard error. > - Later we can turn this into a complaint. */ > - error (_("Dwarf Error: %s found in non-DWO CU [in module %s]"), > - dwarf_form_name (form), > - bfd_get_filename (abfd)); > - } > - DW_ADDR (attr) = read_addr_index_from_leb128 (cu, info_ptr, > &bytes_read); > + *need_reprocess = true; > + DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, > &bytes_read); > info_ptr += bytes_read; > break; > case DW_FORM_strx: > @@ -19389,14 +19558,6 @@ read_attribute_value (const struct > die_reader_specs *reader, > case DW_FORM_strx3: > case DW_FORM_strx4: > case DW_FORM_GNU_str_index: > - if (reader->dwo_file == NULL) > - { > - /* For now flag a hard error. > - Later we can turn this into a complaint if warranted. */ > - error (_("Dwarf Error: %s found in non-DWO CU [in module %s]"), > - dwarf_form_name (form), > - bfd_get_filename (abfd)); > - } > { > ULONGEST str_index; > if (form == DW_FORM_strx1) > @@ -19424,9 +19585,9 @@ read_attribute_value (const struct > die_reader_specs *reader, > str_index = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); > info_ptr += bytes_read; > } > - DW_STRING (attr) = read_str_index (reader, str_index); > - DW_STRING_IS_CANONICAL (attr) = 0; > - } > + *need_reprocess = true; > + DW_UNSND (attr) = str_index; > + } > break; > default: > error (_("Dwarf Error: Cannot handle %s in DWARF reader [in module > %s]"), > @@ -19462,11 +19623,12 @@ read_attribute_value (const struct > die_reader_specs *reader, > static const gdb_byte * > read_attribute (const struct die_reader_specs *reader, > struct attribute *attr, struct attr_abbrev *abbrev, > - const gdb_byte *info_ptr) > + const gdb_byte *info_ptr, bool *need_reprocess) > { > attr->name = abbrev->name; > return read_attribute_value (reader, attr, abbrev->form, > - abbrev->implicit_const, info_ptr); > + abbrev->implicit_const, info_ptr, > + need_reprocess); > } > > /* Read dwarf information from a buffer. */ > @@ -19893,27 +20055,30 @@ read_signed_leb128 (bfd *abfd, const gdb_byte > *buf, > } > > /* Given index ADDR_INDEX in .debug_addr, fetch the value. > - ADDR_BASE is the DW_AT_GNU_addr_base attribute or zero. > + ADDR_BASE is the DW_AT_addr_base (DW_AT_GNU_addr_base) attribute or > zero. > ADDR_SIZE is the size of addresses from the CU header. */ > > static CORE_ADDR > read_addr_index_1 (struct dwarf2_per_objfile *dwarf2_per_objfile, > - unsigned int addr_index, ULONGEST addr_base, int > addr_size) > + unsigned int addr_index, gdb::optional > addr_base, > + int addr_size) > { > struct objfile *objfile = dwarf2_per_objfile->objfile; > bfd *abfd = objfile->obfd; > const gdb_byte *info_ptr; > + ULONGEST addr_base_or_zero = addr_base.has_value() ? *addr_base : 0; > > dwarf2_read_section (objfile, &dwarf2_per_objfile->addr); > if (dwarf2_per_objfile->addr.buffer == NULL) > error (_("DW_FORM_addr_index used without .debug_addr section [in > module %s]"), > objfile_name (objfile)); > - if (addr_base + addr_index * addr_size >= dwarf2_per_objfile->addr.size) > + if (addr_base_or_zero + addr_index * addr_size > + >= dwarf2_per_objfile->addr.size) > error (_("DW_FORM_addr_index pointing outside of " > ".debug_addr section [in module %s]"), > objfile_name (objfile)); > info_ptr = (dwarf2_per_objfile->addr.buffer > - + addr_base + addr_index * addr_size); > + + addr_base_or_zero + addr_index * addr_size); > if (addr_size == 4) > return bfd_get_32 (abfd, info_ptr); > else > @@ -19946,7 +20111,7 @@ read_addr_index_from_leb128 (struct dwarf2_cu *cu, > const gdb_byte *info_ptr, > > struct dwarf2_read_addr_index_data > { > - ULONGEST addr_base; > + gdb::optional addr_base; > int addr_size; > }; > > @@ -19978,7 +20143,7 @@ dwarf2_read_addr_index (struct dwarf2_per_cu_data > *per_cu, > { > struct dwarf2_per_objfile *dwarf2_per_objfile = > per_cu->dwarf2_per_objfile; > struct dwarf2_cu *cu = per_cu->cu; > - ULONGEST addr_base; > + gdb::optional addr_base; > int addr_size; > > /* We need addr_base and addr_size. > @@ -20018,21 +20183,21 @@ dwarf2_read_addr_index (struct > dwarf2_per_cu_data *per_cu, > addr_size); > } > > -/* Given a DW_FORM_GNU_str_index or DW_FORM_strx, fetch the string. > - This is only used by the Fission support. */ > +/* Given a DW_FORM_GNU_str_index value STR_INDEX, fetch the string. > + STR_SECTION, STR_OFFSETS_SECTION can be from a Fission stub or a > + DWO file. */ > > static const char * > -read_str_index (const struct die_reader_specs *reader, ULONGEST str_index) > +read_str_index (struct dwarf2_cu *cu, > + struct dwarf2_section_info *str_section, > + struct dwarf2_section_info *str_offsets_section, > + ULONGEST str_offsets_base, ULONGEST str_index) > { > - struct dwarf2_cu *cu = reader->cu; > struct dwarf2_per_objfile *dwarf2_per_objfile > = cu->per_cu->dwarf2_per_objfile; > struct objfile *objfile = dwarf2_per_objfile->objfile; > const char *objf_name = objfile_name (objfile); > bfd *abfd = objfile->obfd; > - struct dwarf2_section_info *str_section = > &reader->dwo_file->sections.str; > - struct dwarf2_section_info *str_offsets_section = > - &reader->dwo_file->sections.str_offsets; > const gdb_byte *info_ptr; > ULONGEST str_offset; > static const char form_name[] = "DW_FORM_GNU_str_index or DW_FORM_strx"; > @@ -20040,18 +20205,17 @@ read_str_index (const struct die_reader_specs > *reader, ULONGEST str_index) > dwarf2_read_section (objfile, str_section); > dwarf2_read_section (objfile, str_offsets_section); > if (str_section->buffer == NULL) > - error (_("%s used without .debug_str.dwo section" > + error (_("%s used without %s section" > " in CU at offset %s [in module %s]"), > - form_name, sect_offset_str (cu->header.sect_off), objf_name); > + form_name, get_section_name (str_section), > + sect_offset_str (cu->header.sect_off), objf_name); > if (str_offsets_section->buffer == NULL) > - error (_("%s used without .debug_str_offsets.dwo section" > + error (_("%s used without %s section" > " in CU at offset %s [in module %s]"), > - form_name, sect_offset_str (cu->header.sect_off), objf_name); > - if (str_index * cu->header.offset_size >= str_offsets_section->size) > - error (_("%s pointing outside of .debug_str_offsets.dwo" > - " section in CU at offset %s [in module %s]"), > - form_name, sect_offset_str (cu->header.sect_off), objf_name); > + form_name, get_section_name (str_section), > + sect_offset_str (cu->header.sect_off), objf_name); > info_ptr = (str_offsets_section->buffer > + + str_offsets_base > + str_index * cu->header.offset_size); > if (cu->header.offset_size == 4) > str_offset = bfd_get_32 (abfd, info_ptr); > @@ -20064,6 +20228,71 @@ read_str_index (const struct die_reader_specs > *reader, ULONGEST str_index) > return (const char *) (str_section->buffer + str_offset); > } > > +/* Given a DW_FORM_GNU_str_index from a DWO file, fetch the string. */ > + > +static const char * > +read_dwo_str_index (const struct die_reader_specs *reader, ULONGEST > str_index) > +{ > + ULONGEST str_offsets_base = reader->cu->header.version >= 5 > + ? reader->cu->header.addr_size : 0; > + return read_str_index (reader->cu, > + &reader->dwo_file->sections.str, > + &reader->dwo_file->sections.str_offsets, > + str_offsets_base, str_index); > +} > + > +/* Given a DW_FORM_GNU_str_index from a Fission stub, fetch the string. > */ > + > +static const char * > +read_stub_str_index (struct dwarf2_cu *cu, ULONGEST str_index) > +{ > + struct objfile *objfile = cu->per_cu->dwarf2_per_objfile->objfile; > + const char *objf_name = objfile_name (objfile); > + static const char form_name[] = "DW_FORM_GNU_str_index"; > + static const char str_offsets_attr_name[] = "DW_AT_str_offsets"; > + > + if (!cu->str_offsets_base.has_value()) > + error (_("%s used in Fission stub without %s" > + " in CU at offset 0x%lx [in module %s]"), > + form_name, str_offsets_attr_name, > + (long) cu->header.offset_size, objf_name); > + > + return read_str_index (cu, > + &cu->per_cu->dwarf2_per_objfile->str, > + &cu->per_cu->dwarf2_per_objfile->str_offsets, > + *cu->str_offsets_base, str_index); > +} > + > +/* Wrapper around read_stub_str_index for attributes that *may* be using > + DW_AT_GNU_str_index from a non-DWO file. */ > + > +static const char * > +get_stub_string_attr (struct dwarf2_cu *cu, const struct attribute *attr) > +{ > + if (DW_STRING_IS_STR_INDEX (attr)) > + return read_stub_str_index (cu, DW_UNSND (attr)); > + return DW_STRING (attr); > +} > + > +/* Fetch the value of the DW_AT_comp_dir attribute. > + The result is NULL if the attribute isn't present or if the value is > + empty string. If the caller needs to do something different depending > on > + whether the attribute is present, the caller must check. This function > + should always be used to fetch this attribute as it handles > + DW_AT_GNU_str_index from Fission stubs. This is important as the low > + level DIE reader combines the contents of the stub with the DWO top > level > + DIE so that the rest of the code only ever sees one DIE. */ > + > +static const char * > +get_comp_dir_attr (struct die_info *die, struct dwarf2_cu *cu) > +{ > + const struct attribute *attr = dwarf2_attr (die, DW_AT_comp_dir, cu); > + if (attr == NULL) > + return NULL; > + return get_stub_string_attr (cu, attr); > +} > + > + > /* Return the length of an LEB128 number in BUF. */ > > static int > diff --git a/gdb/dwarf2read.h b/gdb/dwarf2read.h > index 53fc7f4d9b..d2b06c9a4a 100644 > --- a/gdb/dwarf2read.h > +++ b/gdb/dwarf2read.h > @@ -156,6 +156,7 @@ public: > dwarf2_section_info macinfo {}; > dwarf2_section_info macro {}; > dwarf2_section_info str {}; > + dwarf2_section_info str_offsets {}; > dwarf2_section_info line_str {}; > dwarf2_section_info ranges {}; > dwarf2_section_info rnglists {}; > diff --git a/gdb/symfile.h b/gdb/symfile.h > index cb5bed9d85..fc0fa77183 100644 > --- a/gdb/symfile.h > +++ b/gdb/symfile.h > @@ -569,6 +569,7 @@ struct dwarf2_debug_sections { > struct dwarf2_section_names macinfo; > struct dwarf2_section_names macro; > struct dwarf2_section_names str; > + struct dwarf2_section_names str_offsets; > struct dwarf2_section_names line_str; > struct dwarf2_section_names ranges; > struct dwarf2_section_names rnglists; > diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c > index bc4877389b..341afd4001 100644 > --- a/gdb/xcoffread.c > +++ b/gdb/xcoffread.c > @@ -166,6 +166,7 @@ static const struct dwarf2_debug_sections > dwarf2_xcoff_names = { > { NULL, NULL }, > { ".dwmac", NULL }, > { ".dwstr", NULL }, > + { NULL, NULL }, /* debug_str_offsets */ > { NULL, NULL }, /* debug_line_str */ > { ".dwrnges", NULL }, > { NULL, NULL }, /* debug_rnglists */ > -- > 2.24.0.rc1.363.gb1bccd3e3d-goog > >