From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 34088 invoked by alias); 1 Nov 2019 23:44:04 -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 34080 invoked by uid 89); 1 Nov 2019 23:44:03 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.8 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=comply, sk:DW_AT_s, sk:dw_at_s, sk:init_cu X-HELO: mail-vk1-f202.google.com Received: from mail-vk1-f202.google.com (HELO mail-vk1-f202.google.com) (209.85.221.202) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 01 Nov 2019 23:43:58 +0000 Received: by mail-vk1-f202.google.com with SMTP id r16so4572913vkd.1 for ; Fri, 01 Nov 2019 16:43:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:message-id:mime-version:subject:from:to:cc :content-transfer-encoding; bh=teyCPvvGX4ybuGaszqmHqOxl1a6k4Wkg71RDAyfASGU=; b=CuFpju6yqupviW/ILB+YTs9CJtBy0A4s7IDBGKEzrIn1H9LLby7HZpKx+IP7vTc+Mv dSYPfm/viZ4+I9QrS7Ap3xphsPmeprppFaWYujEqCBHwSTXWZEnC8WAhnc+WqWEjsLq3 Mlq5e+ll5pUWZYEyd4SOvBG2Mda1F2pCaTPooD0UdoeO7G+aKbR3cY8PJXvoxiw0JAoW AaihhArrcPre+apExjqzgdl+lIjpb4LmCKW2eGbTnjJcL7bsKEaDer/qkH9om5eskJ99 3KOCtqYSEHx//Mw9qU7G6jLZWZZwfwTNkCFAKL3u+E13eDD+n/N31cjZlxhSXqu8vGy3 HU4g== Date: Fri, 01 Nov 2019 23:44:00 -0000 Message-Id: <20191101234344.122009-1-tamur@google.com> Mime-Version: 1.0 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-11/txt/msg00045.txt.bz2 * Process debug_str_offsets section. Handle DW_AT_str_offsets_base attribut= e and keep the value in dwarf2_cu. * Make addr_base and ranges_base fields in dwarf2_cu optional to disambigua= te 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/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_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,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 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; + gdb::optional ranges_base =3D 0; =20 /* 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; =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 @@ -2409,6 +2441,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; @@ -7154,7 +7191,41 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGE= ST sig) return entry; } } -=0C + +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); +} + +static gdb::optional +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 gdb::optional (); + return DW_UNSND (attr); +} + /* Low level DIE reading support. */ =20 /* 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 *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. */ @@ -7246,20 +7316,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) - 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) - 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) { @@ -7268,6 +7332,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 @@ -7368,8 +7433,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 @@ -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 =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) + cu->str_offsets_base =3D DW_UNSND (attr); + if (skip_partial && comp_unit_die->tag =3D=3D DW_TAG_partial_unit) return; =20 @@ -7730,9 +7801,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_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). =20 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 *t= his_cu, =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) @@ -7786,6 +7858,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) + { + 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. */ @@ -7800,11 +7877,31 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_pe= r_cu_data *this_cu, init_cu_die_reader (&reader, &cu, section, dwo_file, abbrev_table.get ()= ); 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, so we need to fetch DW_AT_str_offsets_base + ASAP. */ + struct attribute *attr =3D 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 !=3D NULL) + { + complaint (_("DW_AT_str_offsets_base present in DWO file %s," + " ignored"), + dwo_file->dwo_name); + } + else + { + cu.str_offsets_base =3D DW_UNSND (attr); + } + } + 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. @@ -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); } =0C /* 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 =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 @@ -11968,8 +12067,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; @@ -12006,7 +12105,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. @@ -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); =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); @@ -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 =3D die->tag !=3D DW_TAG_compile_unit; + int need_ranges_base =3D die->tag !=3D DW_TAG_compile_unit + && cu->ranges_base.has_value(); unsigned int ranges_offset =3D (DW_UNSND (attr) + (need_ranges_base - ? cu->ranges_base + ? *cu->ranges_base : 0)); =20 /* 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 =3D die->tag !=3D DW_TAG_compile_unit; - + int need_ranges_base =3D die->tag !=3D 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 =3D (DW_UNSND (attr) - + (need_ranges_base ? cu->ranges_base : 0)); + + (need_ranges_base ? *cu->ranges_base : 0)); =20 std::vector blockvec; dwarf2_ranges_process (offset, cu, @@ -18214,10 +18314,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); + } =20 + struct attribute *attr =3D dwarf2_attr_no_follow (die, DW_AT_str_offsets= _base); + if (attr) + cu->str_offsets_base =3D DW_UNSND (attr); + + 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; @@ -18729,12 +18845,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) @@ -18825,9 +18952,7 @@ partial_die_info::read (const struct die_reader_spe= cs *reader, sect_offset off =3D dwarf2_get_ref_die_offset (&attr); const gdb_byte *sibling_ptr =3D buffer + to_underlying (off); =20 - 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 =3D sibling_ptr; @@ -18882,10 +19007,11 @@ partial_die_info::read (const struct die_reader_s= pecs *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 =3D tag !=3D DW_TAG_compile_unit; + int need_ranges_base =3D tag !=3D DW_TAG_compile_unit + && cu->ranges_base.has_value(); unsigned int ranges_offset =3D (DW_UNSND (&attr) + (need_ranges_base - ? cu->ranges_base + ? *cu->ranges_base : 0)); =20 /* 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 =3D 1; } =20 +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; + } + 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; + } + } +} + /* 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 @@ -19192,6 +19364,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) @@ -19255,6 +19428,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: @@ -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) =3D 0; + DW_STRING_IS_STR_INDEX (attr) =3D false; info_ptr +=3D bytes_read; break; } @@ -19288,6 +19463,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; @@ -19365,22 +19541,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: @@ -19389,14 +19558,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) @@ -19424,9 +19585,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]"), @@ -19462,11 +19623,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. */ @@ -19893,27 +20055,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 @@ -19946,7 +20111,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 @@ -19978,7 +20143,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. @@ -20018,21 +20183,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= "; @@ -20040,18 +20205,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); @@ -20064,6 +20228,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 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 =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.0.rc1.363.gb1bccd3e3d-goog