From patchwork Tue Aug 27 23:42:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Terekhov, Mikhail via Gdb-patches" X-Patchwork-Id: 34291 Received: (qmail 72935 invoked by alias); 27 Aug 2019 23:42:12 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 72860 invoked by uid 89); 27 Aug 2019 23:42:12 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.2 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=releasing 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; Tue, 27 Aug 2019 23:42:07 +0000 Received: by mail-vk1-f202.google.com with SMTP id f188so430408vkh.6 for ; Tue, 27 Aug 2019 16:42:07 -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=265zPEwH1zA2ALhdIPw540SkaSqKk74p9Uyuk3QOXHY=; b=KqbuH2z8yT9Pr+BWeemkbxZaOPVhYSczzEuQJ1A8eXvenKTsb5K2yhJnxhDd5NPFX8 qMYmYexP56dIsYwVCCBq5fon0YgxfjbA3NBbzlfStPeKhK+raSJR9lCNCebFhuv7b9ct YSMhXQU0MfflZrNMS7STIXQ+ehu/F0M984NzM2tSpe+Yst+1ftC9JvOFllHC/ukCcwwn e0T8i5QnoAwe4jCiEMmLm1s9px74vloRK9i66Wgk6wdgOMMa11UHnzYEw39J8Cp2ygSK uCLcLKbdbmANN6mjteSLupqt8p5rgt45z6axLofKrZ+hMmvc/EZj4GaBDrnd44605H/3 /Gvg== Date: Tue, 27 Aug 2019 16:42:02 -0700 Message-Id: <20190827234202.246144-1-tamur@google.com> Mime-Version: 1.0 Subject: [PATCH 4/4] Increasing support for dwarf 5. X-Patchwork-Original-From: "Ali Tamur via gdb-patches" From: "Terekhov, Mikhail via Gdb-patches" Reply-To: Ali Tamur To: gdb-patches@sourceware.org Cc: Ali Tamur X-IsSubscribed: yes * Add support for .debug_str_offsets section and str_offsets_base attribute. * string and address indexes that point to an entry in .debug_str_offsets and .addr_offsets need special handling because they need .str_offsets_base and addr_base attrobutes be known at the time, however, those attributes may occur later in the DIE. So, such attributes need to be reprocessed after other parts of the DIE are parsed. * DW_FORM_GNU_str_index, DW_FORM_strx and other similar forms can also occur in .dwo files. Likewise for DW_FORM_GNU_addr_index and DW_FORM_addrx. * DW_AT_dwo_name is a new name for DW_AT_GNU_dwo_name. After these changes, gdb is able to process a 'hello world' program compiled with -gdwarf-5 flag. It is also able to support an additional -gsplit-dwarf flag. As future work, it does not yet support address and range lists, also type units may be lacking some support. The patch contains local previous work done by Doug Evans. gdb/ChangeLog: 2019-08-26 Ali Tamur * gdb/dwarf2read.c (dwarf2_elf_names): Add .(z)debug_str_offsets items. (dwarf2_cu): Add str_offsets_base field. (dwo_file): Update comment. (attribute): Add string_is_str_index field. (DW_STRING_IS_STR_INDEX): New macro. (read_attribute): New parameter. (read_attribute_reprocess): New function declaration. (read_addr_index): New declaration for existing function. (read_dwo_str_index): New function declaration. (read_stub_str_index): New function declaration. (get_comp_dir_attr): New function declaration. (get_stub_string_attr): New function declaration. (dwarf2_per_objfile::locate_sections): Add support for .str_offsets. (read_cutu_die_from_dwo): Don't touch addr_base field. Change how compilation dir is calculated. (init_cutu_and_read_dies_no_follow): Update comment. Add parent_cu parameter to inherit str_offset_base and addr_base. (init_cutu_and_read_dies_simple): Reflect API change. (skip_one_die): Reflect API change. (create_cus_hash_table): Get dwarf2_cu as parameter to reflect API change. (open_and_init_dwo_file): Reflect API change. (read_full_die_1): Make a 2nd pass for attributes that need reprocessing. (partial_die_info::read): Likewise. Remove obsolete complaint. (read_attribute_reprocess): Process attributes that need str_offsets_base or addr_base in the die. This is needed because there is no guarantee that those values were available at the first pass. Must be called after all attributes are processed. (read_attribute_value): Add output parameter, whether the attribute needs a second pass, handle string & address indexes, remove obsolete error. (read_attribute): Add output parameter, whether the attribute needs a second pass. Attributes that need str_offsets_base and addr_base need to be processed after all attributes are read, because str_offsets_base or addr_base may not be available at the time. (read_str_index): Update comment. API change and fix the computation of the string address in dwo files. (read_dwo_str_index): Return the string at the given index in dwo files. (read_stub_str_index): Return the string at the given index in a non-dwo file. (get_stub_string_attr): Wrapper around read_stub_str_index. (get_comp_dir_attr): Fetch the value of the DW_AT_comp_dir attribute. * gdb/dwarf2read.h (struct dwarf2_per_objfile): Add field. * gdb/symfile.h (struct dwarf2_debug_sections): Add field. --- gdb/dwarf2read.c | 315 ++++++++++++++++++++++++++++++++++++----------- gdb/dwarf2read.h | 1 + gdb/symfile.h | 1 + 3 files changed, 248 insertions(+), 69 deletions(-) diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 73ec371af1..73a83ae4cb 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -299,6 +299,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" }, @@ -542,6 +543,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 dw4 version DWO files, + the value is implicitly zero. For dw5 version DWO files, the value is often + implicit and is the size of the header of .debug_str_offsets section (i.e. + 8 or 4, depending on the address size). */ + gdb::optional str_offsets_base {}; + /* Mark used when releasing cached dies. */ bool mark : 1; @@ -707,7 +714,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. */ @@ -1276,6 +1283,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. */ + unsigned int string_is_str_index : 1; + union { const char *str; @@ -1328,6 +1347,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) @@ -1523,7 +1543,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 *); @@ -1582,8 +1607,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 *); @@ -2396,6 +2430,11 @@ dwarf2_per_objfile::locate_sections (bfd *abfd, asection *sectp, this->str.s.section = sectp; this->str.size = bfd_get_section_size (sectp); } + else if (section_is_p (sectp->name, &names.str_offsets)) + { + this->str_offsets.s.section = sectp; + this->str_offsets.size = bfd_get_section_size (sectp); + } else if (section_is_p (sectp->name, &names.line_str)) { this->line_str.s.section = sectp; @@ -7188,10 +7227,6 @@ 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); @@ -7210,6 +7245,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) = 0; DW_STRING (comp_dir) = stub_comp_dir; } @@ -7309,9 +7345,8 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data *this_cu, /* Save the comp_dir attribute. If there is no DWP file then we'll read 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); + to get it via circuitous means. */ + 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 @@ -7675,9 +7710,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. @@ -7693,6 +7728,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) @@ -7731,6 +7767,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. */ @@ -7748,8 +7789,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); } -/* 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. @@ -7762,7 +7803,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. @@ -9265,7 +9306,8 @@ 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 @@ -11908,8 +11950,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; @@ -11946,7 +11988,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. @@ -12980,7 +13022,7 @@ 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, + 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 (), @@ -18149,10 +18191,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); + attr = dwarf2_attr_no_follow (die, DW_AT_addr_base); + if (attr) + cu->addr_base = DW_UNSND (attr); + for (int index : indexes_that_need_reprocess) + read_attribute_reprocess(reader, &die->attrs[index]); *diep = die; *has_children = abbrev->has_children; return info_ptr; @@ -18663,12 +18721,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) @@ -18759,9 +18828,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; @@ -19110,12 +19177,66 @@ 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 the DIE is from a Fission stub and we don't have + DW_AT_str_offsets yet then we cannot fetch the string. + All we can do is record the index and leave it to the caller + to deal with. */ + 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) = 0; + } + 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) = 0; + } + else + { + /* Until it's clear handling the general case is worth it, + flag any other uses of this situation as errors to avoid + latent bugs. What should happen is we should make DW_STRING + check DW_STRING_IS_STR_INDEX, but ugh. */ + 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) = 1; + } + } +} + /* 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 @@ -19126,6 +19247,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) @@ -19189,6 +19311,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) = 0; info_ptr += bytes_read; break; case DW_FORM_strp: @@ -19198,6 +19321,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) = 0; info_ptr += bytes_read; break; } @@ -19222,6 +19346,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) = 0; info_ptr += bytes_read; } break; @@ -19299,22 +19424,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: @@ -19323,14 +19441,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) @@ -19358,9 +19468,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]"), @@ -19396,11 +19506,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. */ @@ -19952,21 +20063,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"; @@ -19974,18 +20085,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); @@ -19998,6 +20108,73 @@ 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 of + the attribute is "". 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 8939f97af5..3f6d52d9a3 100644 --- a/gdb/dwarf2read.h +++ b/gdb/dwarf2read.h @@ -154,6 +154,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 741b085e0c..a227022be4 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;