From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31114 invoked by alias); 27 Dec 2019 00:41:37 -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 31105 invoked by uid 89); 27 Dec 2019 00:41:37 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.9 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.1 spammy=Did, longest, wrapper, cached X-HELO: mail-pf1-f201.google.com Received: from mail-pf1-f201.google.com (HELO mail-pf1-f201.google.com) (209.85.210.201) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 27 Dec 2019 00:41:32 +0000 Received: by mail-pf1-f201.google.com with SMTP id d85so16767342pfd.4 for ; Thu, 26 Dec 2019 16:41:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=CTrGzyU0sCfaZIJ0tTV3eaUNDZvGGOxv+woyrJKEKvE=; b=hrAR8EXy8fBu7veGEuT9rsmSs7LPBSnZQXp9YRysAuZALCNn5Ix8g/hxNmEtFEPsIi sdRmaXIJMYnHReQnySjHKF2/UvXUcACfBIvTxXIeoFeLW++0zWzHTHpnqL4AvxtZNyr0 EBsTY5co4PI2F+mIc36Cf/J5Aw8NM/z8N8Q81YzTqgTLOCc6jEwKFFRwgiMJ0ja3Pm96 J2ugF7rcPSNXLYhlZC6/FmyzlH2AEQqS0pLEzzjLrWyCjHqe1TgVsBE7OGWGHVUQtUxZ mVxpKRpCtd1L5EO329Rf8X8n9B7uble3EVS9ecblSDyhNAARePkqWWfDECUewUzc2XRP 9JWg== Date: Fri, 27 Dec 2019 00:41:00 -0000 In-Reply-To: <867ce990-e0c7-c2cd-5b5b-126339a32a44@polymtl.ca> Message-Id: <20191227004127.167554-1-tamur@google.com> Mime-Version: 1.0 References: <867ce990-e0c7-c2cd-5b5b-126339a32a44@polymtl.ca> Subject: [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets. From: "Ali Tamur via gdb-patches" Reply-To: Ali Tamur To: gdb-patches@sourceware.org Cc: Simon Marchi , Ali Tamur Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes X-SW-Source: 2019-12/txt/msg01029.txt.bz2 Hi, Sorry for late response, (I got involved in some nasty unrelated bug),=20 please take another look. *** >> - ULONGEST ranges_base =3D 0; >> + gdb::optional ranges_base =3D 0; > *** I am probably missing something, but I don't really understand the l= ogic > of making this field optional and initializing it to 0 Done (Reverted back to ULONGEST). *** >Ok, so that reprocessing happens right after having read the attributes fr= om the DIE. > >Another approach that I would have expected would be to do it more lazily.= Only keep >the index in the attribute, and go read the actual string when we call dwa= rf2_string_attr >on it (and then maybe cache the value). Did you consider doing something = like that, and >perhaps it was a too involving change? I want the patch to be as little invasive as possible, so I prefer not chan= ging laziness, if that's ok with you. *** >> + else >> + { >> + if (attr->name !=3D DW_AT_comp_dir >> + && attr->name !=3D DW_AT_GNU_dwo_name >> + && attr->name !=3D 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) =3D str_index; >> + DW_STRING_IS_STR_INDEX (attr) =3D true; >> + } >I don't understand this part. When read_attribute_reprocess is called, >if there's a DW_AT_str_offsets_base, we will have read it at this point. >So when is the else clause actually useful? Hmm, ok, I deleted this part, tests pass and everything continues to work, thank you, done. --- * Process debug_str_offsets section. Handle DW_AT_str_offsets_base attribut= e and keep the value in dwarf2_cu. * Make addr_base field 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 poin= t 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 case= s. Tested with CC=3D/usr/bin/gcc (version 8.3.0) against master branch (also w= ith -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 DWAR= F 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/dwarf2read.c | 397 ++++++++++++++++++++++++++++++++++++----------- gdb/dwarf2read.h | 1 + gdb/symfile.h | 1 + gdb/xcoffread.c | 1 + 4 files changed, 307 insertions(+), 93 deletions(-) diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 685d996297..99a0440dc3 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -287,6 +287,7 @@ static const struct dwarf2_debug_sections dwarf2_elf_na= mes =3D { ".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,27 +501,25 @@ 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 poi= nt 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 t= his is non-NULL). */ struct dwo_unit *dwo_unit =3D nullptr; =20 - /* 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 =3D 0; + gdb::optional addr_base {}; =20 - /* 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 =3D 0; =20 @@ -532,6 +531,12 @@ public: all such types here and process them after expansion. */ std::vector rust_unions; =20 + /* 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, t= he + 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; =20 @@ -697,7 +702,7 @@ struct dwo_file dwo_file () =3D default; DISABLE_COPY_AND_ASSIGN (dwo_file); =20 - /* 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; =20 + /* 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_b= ase? + 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_inde= x 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 =20 #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, =20 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 *reade= r, + struct attribute *attr); + +static CORE_ADDR read_addr_index (struct dwarf2_cu *cu, unsigned int addr_= index); =20 static unsigned int read_1_byte (bfd *, const gdb_byte *); =20 @@ -1578,8 +1601,17 @@ static CORE_ADDR read_addr_index_from_leb128 (struct= dwarf2_cu *, const gdb_byte *, unsigned int *); =20 -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 *read= er, + 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); =20 static void set_cu_language (unsigned int, struct dwarf2_cu *); =20 @@ -2412,6 +2444,11 @@ dwarf2_per_objfile::locate_sections (bfd *abfd, asec= tion *sectp, this->str.s.section =3D sectp; this->str.size =3D bfd_section_size (sectp); } + else if (section_is_p (sectp->name, &names.str_offsets)) + { + this->str_offsets.s.section =3D sectp; + this->str_offsets.size =3D bfd_section_size (sectp); + } else if (section_is_p (sectp->name, &names.line_str)) { this->line_str.s.section =3D sectp; @@ -7182,7 +7219,47 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGE= ST sig) return entry; } } -=0C + +/* Return the address base of the compile unit, which, if exists, is stored + either at the attribute DW_AT_GNU_addr_base, or DW_AT_addr_base. Also = takes + as parameter whether it should follow DW_AT_specification. See the com= ments + on dwarf2_attr_no_follow and dwarf2_attr for the difference. */ +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 =3D dwarf2_attr (comp_unit_die, DW_AT_addr_base, cu); + if (attr =3D=3D nullptr) + attr =3D dwarf2_attr (comp_unit_die, DW_AT_GNU_addr_base, cu); + } + else + { + attr =3D dwarf2_attr_no_follow (comp_unit_die, DW_AT_addr_base); + if (attr =3D=3D nullptr) + attr =3D dwarf2_attr_no_follow (comp_unit_die, DW_AT_GNU_addr_base= ); + } + if (attr =3D=3D nullptr) + return gdb::optional (); + return DW_UNSND (attr); +} + +/* Return range lists base of the compile unit, which, if exists, is stored + either at the attribute DW_AT_rnglists_base or DW_AT_GNU_ranges_base. = */ +ULONGEST +lookup_ranges_base (struct dwarf2_cu *cu, struct die_info* comp_unit_die) +{ + struct attribute *attr; + attr =3D dwarf2_attr (comp_unit_die, DW_AT_rnglists_base, cu); + if (attr =3D=3D nullptr) + attr =3D dwarf2_attr (comp_unit_die, DW_AT_GNU_ranges_base, cu); + if (attr =3D=3D nullptr) + return 0; + return DW_UNSND (attr); +} + /* Low level DIE reading support. */ =20 /* Initialize a die_reader_specs struct from a dwarf2_cu struct. */ @@ -7243,7 +7320,6 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data *th= is_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; =20 /* At most one of these may be provided. */ @@ -7274,20 +7350,14 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data *= this_cu, ranges =3D dwarf2_attr (stub_comp_unit_die, DW_AT_ranges, cu); comp_dir =3D dwarf2_attr (stub_comp_unit_die, DW_AT_comp_dir, cu); =20 - /* 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 =3D 0; - attr =3D dwarf2_attr (stub_comp_unit_die, DW_AT_GNU_addr_base, cu); - if (attr !=3D nullptr) - cu->addr_base =3D DW_UNSND (attr); + auto maybe_addr_base =3D lookup_addr_base (cu, stub_comp_unit_die, t= rue); + if (maybe_addr_base.has_value ()) + cu->addr_base =3D *maybe_addr_base; =20 - /* 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 =3D 0; - attr =3D dwarf2_attr (stub_comp_unit_die, DW_AT_GNU_ranges_base, cu); - if (attr !=3D nullptr) - cu->ranges_base =3D DW_UNSND (attr); + /* There should be a DW_AT_rnglists_base (DW_AT_GNU_ranges_base) att= ribute + here (if needed). We need the value before we can process + DW_AT_ranges. */ + cu->ranges_base =3D lookup_ranges_base (cu, stub_comp_unit_die); } else if (stub_comp_dir !=3D NULL) { @@ -7296,6 +7366,7 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data *th= is_cu, comp_dir->name =3D DW_AT_comp_dir; comp_dir->form =3D DW_FORM_string; DW_STRING_IS_CANONICAL (comp_dir) =3D 0; + DW_STRING_IS_STR_INDEX (comp_dir) =3D false; DW_STRING (comp_dir) =3D stub_comp_dir; } =20 @@ -7396,8 +7467,7 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data *th= is_cu, TUs by skipping the stub and going directly to the entry in the DWO f= ile. However, skipping the stub means we won't get DW_AT_comp_dir, so we h= ave to get it via circuitous means. Blech. */ - if (comp_dir !=3D NULL) - result_reader->comp_dir =3D DW_STRING (comp_dir); + result_reader->comp_dir =3D get_comp_dir_attr (comp_unit_die, cu); =20 /* Skip dummy compilation units. */ if (info_ptr >=3D begin_info_ptr + dwo_unit->length @@ -7695,6 +7765,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 =3D read_full_die (&reader, &comp_unit_die, info_ptr, &has_chil= dren); =20 + /* 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 =3D dwarf2_attr (comp_unit_die, + DW_AT_str_offsets_base, cu); + if (attr !=3D nullptr) + cu->str_offsets_base =3D DW_UNSND (attr); + if (skip_partial && comp_unit_die->tag =3D=3D DW_TAG_partial_unit) return; =20 @@ -7758,9 +7835,9 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *t= his_cu, } } =20 -/* 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_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). =20 The caller is required to fill in THIS_CU->section, THIS_CU->offset, and THIS_CU->is_debug_types, but nothing else. @@ -7772,10 +7849,14 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data = *this_cu, =20 THIS_CU->cu is always freed when done. This is done in order to not leave THIS_CU->cu in a state where we have - to care whether it refers to the "main" CU or the DWO CU. */ + to care whether it refers to the "main" CU or the DWO CU. + + When parent_cu is passed, it is used to provide a default value for + str_offsets_base and addr_base from the parent. */ =20 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) @@ -7814,6 +7895,11 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per= _cu_data *this_cu, ? rcuh_kind::TYPE : rcuh_kind::COMPILE)); =20 + if (parent_cu !=3D nullptr) + { + cu.str_offsets_base =3D parent_cu->str_offsets_base; + cu.addr_base =3D parent_cu->addr_base; + } this_cu->length =3D get_cu_length (&cu.header); =20 /* Skip dummy compilation units. */ @@ -7831,8 +7917,8 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_= cu_data *this_cu, die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data); } =20 -/* 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. =20 THIS_CU->cu is always freed when done. @@ -7845,7 +7931,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); } =0C /* Type Unit Groups. @@ -9356,7 +9442,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 =3D=3D 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 =3D=3D DW_FORM_ref_addr) complaint (_("ignoring absolute DW_AT_sibling")); else @@ -9452,6 +9540,7 @@ skip_one_die (const struct die_reader_specs *reader, = const gdb_byte *info_ptr, case DW_FORM_ref_udata: case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: + case DW_FORM_rnglistx: info_ptr =3D safe_skip_leb128 (info_ptr, buffer_end); break; case DW_FORM_indirect: @@ -11996,8 +12085,8 @@ create_dwo_cu_reader (const struct die_reader_specs= *reader, =20 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 =3D dwarf2_per_objfile->objfile; const gdb_byte *info_ptr, *end_ptr; @@ -12034,7 +12123,7 @@ create_cus_hash_table (struct dwarf2_per_objfile *d= warf2_per_objfile, create_dwo_cu_data.dwo_file =3D &dwo_file; =20 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 +=3D per_cu.length; =20 // If the unit could not be parsed, skip it. @@ -13068,8 +13157,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); =20 - 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); =20 create_debug_types_hash_table (dwarf2_per_objfile, dwo_file.get (), dwo_file->sections.types, dwo_file->tus); @@ -14730,7 +14819,7 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_AD= DR *lowpc, attr =3D dwarf2_attr (die, DW_AT_ranges, cu); if (attr !=3D NULL) { - /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton. + /* DW_AT_rnglists_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 =3D die->tag !=3D DW_TAG_compile_unit; @@ -14901,7 +14990,7 @@ dwarf2_record_block_ranges (struct die_info *die, s= truct block *block, attr =3D dwarf2_attr (die, DW_AT_ranges, cu); if (attr !=3D nullptr) { - /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton. + /* DW_AT_rnglists_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 =3D die->tag !=3D DW_TAG_compile_unit; @@ -18481,10 +18570,26 @@ read_full_die_1 (const struct die_reader_specs *r= eader, attributes. */ die->num_attrs =3D abbrev->num_attrs; =20 + std::vector indexes_that_need_reprocess; for (i =3D 0; i < abbrev->num_attrs; ++i) - info_ptr =3D read_attribute (reader, &die->attrs[i], &abbrev->attrs[i], - info_ptr); + { + bool need_reprocess; + info_ptr =3D + 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 =3D dwarf2_attr_no_follow (die, DW_AT_str_offsets= _base); + if (attr) + cu->str_offsets_base =3D DW_UNSND (attr); =20 + auto maybe_addr_base =3D lookup_addr_base(cu, die, false); + if (maybe_addr_base.has_value()) + cu->addr_base =3D *maybe_addr_base; + for (int index : indexes_that_need_reprocess) + read_attribute_reprocess (reader, &die->attrs[index]); *diep =3D die; *has_children =3D abbrev->has_children; return info_ptr; @@ -18996,12 +19101,23 @@ partial_die_info::read (const struct die_reader_s= pecs *reader, int has_high_pc_attr =3D 0; int high_pc_relative =3D 0; =20 + std::vector attr_vec; + std::vector indexes_that_need_reprocess; + attr_vec.resize(abbrev.num_attrs); for (i =3D 0; i < abbrev.num_attrs; ++i) { - struct attribute attr; - - info_ptr =3D read_attribute (reader, &attr, &abbrev.attrs[i], info_p= tr); + bool need_reprocess; + info_ptr =3D 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]); =20 + for (i =3D 0; i < abbrev.num_attrs; ++i) + { + struct attribute &attr =3D attr_vec[i]; /* Store the data if it is of an attribute we want to keep in a partial symbol table. */ switch (attr.name) @@ -19443,12 +19559,49 @@ partial_die_info::fixup (struct dwarf2_cu *cu) fixup_called =3D 1; } =20 +/* Process the attributes that had to be skipped in the first round. These + attributes are the ones that need str_offsets_base or addr_base attribu= tes. + They could not have been processed in the first round, because at the t= ime + the values of str_offsets_base or addr_base may not have been known. */ +void read_attribute_reprocess (const struct die_reader_specs *reader, + struct attribute *attr) +{ + struct dwarf2_cu *cu =3D reader->cu; + switch (attr->form) + { + case DW_FORM_addrx: + case DW_FORM_GNU_addr_index: + DW_ADDR (attr) =3D 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 =3D DW_UNSND (attr); + if (reader->dwo_file !=3D NULL) + { + DW_STRING (attr) =3D read_dwo_str_index (reader, str_index); + DW_STRING_IS_CANONICAL (attr) =3D 0; + DW_STRING_IS_STR_INDEX (attr) =3D false; + } + else if (cu->str_offsets_base.has_value ()) + { + DW_STRING (attr) =3D read_stub_str_index (cu, str_index); + DW_STRING_IS_CANONICAL (attr) =3D 0; + DW_STRING_IS_STR_INDEX (attr) =3D false; + } + } +} + /* Read an attribute value described by an attribute form. */ =20 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 =3D reader->cu; struct dwarf2_per_objfile *dwarf2_per_objfile @@ -19459,6 +19612,7 @@ read_attribute_value (const struct die_reader_specs= *reader, struct comp_unit_head *cu_header =3D &cu->header; unsigned int bytes_read; struct dwarf_block *blk; + *need_reprocess =3D false; =20 attr->form =3D (enum dwarf_form) form; switch (form) @@ -19522,6 +19676,7 @@ read_attribute_value (const struct die_reader_specs= *reader, case DW_FORM_string: DW_STRING (attr) =3D read_direct_string (abfd, info_ptr, &bytes_read= ); DW_STRING_IS_CANONICAL (attr) =3D 0; + DW_STRING_IS_STR_INDEX (attr) =3D false; info_ptr +=3D bytes_read; break; case DW_FORM_strp: @@ -19531,6 +19686,7 @@ read_attribute_value (const struct die_reader_specs= *reader, abfd, info_ptr, cu_header, &bytes_read); DW_STRING_IS_CANONICAL (attr) =3D 0; + DW_STRING_IS_STR_INDEX (attr) =3D false; info_ptr +=3D bytes_read; break; } @@ -19555,6 +19711,7 @@ read_attribute_value (const struct die_reader_specs= *reader, DW_STRING (attr) =3D read_indirect_string_from_dwz (objfile, dwz, str_offset); DW_STRING_IS_CANONICAL (attr) =3D 0; + DW_STRING_IS_STR_INDEX (attr) =3D false; info_ptr +=3D bytes_read; } break; @@ -19591,6 +19748,7 @@ read_attribute_value (const struct die_reader_specs= *reader, info_ptr +=3D bytes_read; break; case DW_FORM_udata: + case DW_FORM_rnglistx: DW_UNSND (attr) =3D read_unsigned_leb128 (abfd, info_ptr, &bytes_rea= d); info_ptr +=3D bytes_read; break; @@ -19632,22 +19790,15 @@ read_attribute_value (const struct die_reader_spe= cs *reader, info_ptr +=3D bytes_read; } info_ptr =3D read_attribute_value (reader, attr, form, implicit_cons= t, - info_ptr); + info_ptr, need_reprocess); break; case DW_FORM_implicit_const: DW_SND (attr) =3D implicit_const; break; case DW_FORM_addrx: case DW_FORM_GNU_addr_index: - if (reader->dwo_file =3D=3D 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) =3D read_addr_index_from_leb128 (cu, info_ptr, &bytes= _read); + *need_reprocess =3D true; + DW_UNSND (attr) =3D read_unsigned_leb128 (abfd, info_ptr, &bytes_rea= d); info_ptr +=3D bytes_read; break; case DW_FORM_strx: @@ -19656,14 +19807,6 @@ read_attribute_value (const struct die_reader_spec= s *reader, case DW_FORM_strx3: case DW_FORM_strx4: case DW_FORM_GNU_str_index: - if (reader->dwo_file =3D=3D 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 =3D=3D DW_FORM_strx1) @@ -19691,9 +19834,9 @@ read_attribute_value (const struct die_reader_specs= *reader, str_index =3D read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr +=3D bytes_read; } - DW_STRING (attr) =3D read_str_index (reader, str_index); - DW_STRING_IS_CANONICAL (attr) =3D 0; - } + *need_reprocess =3D true; + DW_UNSND (attr) =3D str_index; + } break; default: error (_("Dwarf Error: Cannot handle %s in DWARF reader [in module %= s]"), @@ -19729,11 +19872,12 @@ read_attribute_value (const struct die_reader_spe= cs *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 =3D abbrev->name; return read_attribute_value (reader, attr, abbrev->form, - abbrev->implicit_const, info_ptr); + abbrev->implicit_const, info_ptr, + need_reprocess); } =20 /* Read dwarf information from a buffer. */ @@ -20160,27 +20304,30 @@ read_signed_leb128 (bfd *abfd, const gdb_byte *bu= f, } =20 /* 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 zer= o. ADDR_SIZE is the size of addresses from the CU header. */ =20 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 =3D dwarf2_per_objfile->objfile; bfd *abfd =3D objfile->obfd; const gdb_byte *info_ptr; + ULONGEST addr_base_or_zero =3D addr_base.has_value() ? *addr_base : 0; =20 dwarf2_read_section (objfile, &dwarf2_per_objfile->addr); if (dwarf2_per_objfile->addr.buffer =3D=3D NULL) error (_("DW_FORM_addr_index used without .debug_addr section [in modu= le %s]"), objfile_name (objfile)); - if (addr_base + addr_index * addr_size >=3D dwarf2_per_objfile->addr.siz= e) + if (addr_base_or_zero + addr_index * addr_size + >=3D dwarf2_per_objfile->addr.size) error (_("DW_FORM_addr_index pointing outside of " ".debug_addr section [in module %s]"), objfile_name (objfile)); info_ptr =3D (dwarf2_per_objfile->addr.buffer - + addr_base + addr_index * addr_size); + + addr_base_or_zero + addr_index * addr_size); if (addr_size =3D=3D 4) return bfd_get_32 (abfd, info_ptr); else @@ -20213,7 +20360,7 @@ read_addr_index_from_leb128 (struct dwarf2_cu *cu, = const gdb_byte *info_ptr, =20 struct dwarf2_read_addr_index_data { - ULONGEST addr_base; + gdb::optional addr_base; int addr_size; }; =20 @@ -20245,7 +20392,7 @@ dwarf2_read_addr_index (struct dwarf2_per_cu_data *= per_cu, { struct dwarf2_per_objfile *dwarf2_per_objfile =3D per_cu->dwarf2_per_obj= file; struct dwarf2_cu *cu =3D per_cu->cu; - ULONGEST addr_base; + gdb::optional addr_base; int addr_size; =20 /* We need addr_base and addr_size. @@ -20285,21 +20432,21 @@ dwarf2_read_addr_index (struct dwarf2_per_cu_data= *per_cu, addr_size); } =20 -/* 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. */ =20 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 =3D reader->cu; struct dwarf2_per_objfile *dwarf2_per_objfile =3D cu->per_cu->dwarf2_per_objfile; struct objfile *objfile =3D dwarf2_per_objfile->objfile; const char *objf_name =3D objfile_name (objfile); bfd *abfd =3D objfile->obfd; - struct dwarf2_section_info *str_section =3D &reader->dwo_file->sections.= str; - struct dwarf2_section_info *str_offsets_section =3D - &reader->dwo_file->sections.str_offsets; const gdb_byte *info_ptr; ULONGEST str_offset; static const char form_name[] =3D "DW_FORM_GNU_str_index or DW_FORM_strx= "; @@ -20307,18 +20454,17 @@ read_str_index (const struct die_reader_specs *re= ader, ULONGEST str_index) dwarf2_read_section (objfile, str_section); dwarf2_read_section (objfile, str_offsets_section); if (str_section->buffer =3D=3D 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 =3D=3D 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 >=3D 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 =3D (str_offsets_section->buffer + + str_offsets_base + str_index * cu->header.offset_size); if (cu->header.offset_size =3D=3D 4) str_offset =3D bfd_get_32 (abfd, info_ptr); @@ -20331,6 +20477,71 @@ read_str_index (const struct die_reader_specs *rea= der, ULONGEST str_index) return (const char *) (str_section->buffer + str_offset); } =20 +/* 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_in= dex) +{ + ULONGEST str_offsets_base =3D reader->cu->header.version >=3D 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 =3D cu->per_cu->dwarf2_per_objfile->objfile; + const char *objf_name =3D objfile_name (objfile); + static const char form_name[] =3D "DW_FORM_GNU_str_index"; + static const char str_offsets_attr_name[] =3D "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 lev= el + 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 =3D dwarf2_attr (die, DW_AT_comp_dir, cu); + if (attr =3D=3D NULL) + return NULL; + return get_stub_string_attr (cu, attr); +} + + /* Return the length of an LEB128 number in BUF. */ =20 static int diff --git a/gdb/dwarf2read.h b/gdb/dwarf2read.h index 140bbed08a..f392200049 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 eaa77fd491..b736306227 100644 --- a/gdb/xcoffread.c +++ b/gdb/xcoffread.c @@ -166,6 +166,7 @@ static const struct dwarf2_debug_sections dwarf2_xcoff_= names =3D { { NULL, NULL }, { ".dwmac", NULL }, { ".dwstr", NULL }, + { NULL, NULL }, /* debug_str_offsets */ { NULL, NULL }, /* debug_line_str */ { ".dwrnges", NULL }, { NULL, NULL }, /* debug_rnglists */ --=20 2.24.1.735.g03f4e72817-goog