Re: [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.

Ali Tamur via gdb-patches
2019-11-12T20:25:09Z

Friendly ping?

On Fri, Nov 1, 2019 at 4:43 PM Ali Tamur <tamur@google.com> wrote:

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