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

Ali Tamur via gdb-patches gdb-patches@sourceware.org
Tue Nov 12 20:25:00 GMT 2019


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
>
>



More information about the Gdb-patches mailing list