public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
@ 2019-11-01 23:44 Ali Tamur via gdb-patches
  2019-11-12 20:25 ` Ali Tamur via gdb-patches
  2019-11-15  3:05 ` Simon Marchi
  0 siblings, 2 replies; 15+ messages in thread
From: Ali Tamur via gdb-patches @ 2019-11-01 23:44 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Ali Tamur

* 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;
     }
 }
-\f
+
+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);
 }
 \f
 /* 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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2019-11-01 23:44 [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets Ali Tamur via gdb-patches
@ 2019-11-12 20:25 ` Ali Tamur via gdb-patches
  2019-11-15  3:05 ` Simon Marchi
  1 sibling, 0 replies; 15+ messages in thread
From: Ali Tamur via gdb-patches @ 2019-11-12 20:25 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2019-11-01 23:44 [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets Ali Tamur via gdb-patches
  2019-11-12 20:25 ` Ali Tamur via gdb-patches
@ 2019-11-15  3:05 ` Simon Marchi
  2019-11-19  4:46   ` Ali Tamur via gdb-patches
  1 sibling, 1 reply; 15+ messages in thread
From: Simon Marchi @ 2019-11-15  3:05 UTC (permalink / raw)
  To: Ali Tamur, gdb-patches

On 2019-11-01 7:43 p.m., Ali Tamur via gdb-patches 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.

Hi Ali,

I did a first pass, I have to admit I don't understand everything.  I have noted
some random comments and questions, hopefully it will become a bit clearer on the
second read.

> -  /* 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;

I am probably missing something, but I don't really understand the logic of making
this field optional and initializing it to 0, or the need to make it optional at all.

The only way the "optional" is used is in cases like these:

	    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
					     : 0));

In which case, the old code:

	    int need_ranges_base = tag != DW_TAG_compile_unit;
	    unsigned int ranges_offset = (DW_UNSND (&attr)
					  + (need_ranges_base
					     ? cu->ranges_base
					     : 0));

If the CU does not have a DW_AT_rnglists_base attribute, doesn't it implicitly
mean that this CU's ranges offset is 0?  So it would seem fine to just leave it
at 0 and keep the arithmetic as before.

That question might apply to the other similar fields too.

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

Two spaces after period.

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

I don't really mind if you want to keep the consistency, but for new stuff
I would favor either reading the attribute directly, or using getters/setters.
I don't really see the advantage of those macros.

> +static gdb::optional<ULONGEST>
> +lookup_addr_base (struct dwarf2_cu *cu, struct die_info* comp_unit_die,
> +		  bool will_follow)

Please provide a comment for this function.

> +{> +  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);
> +  }

The curly braces scopes above are missing an indentation level.

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

Please provide a comment for this function too.

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

Use:

  if (attr != nullptr)

There are a few instances throughout the patch.

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

You listed DW_AT_GNU_dwo_name twice, I don't think that was the intent.

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

Please document this new parameter.

>  				   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;
> +    }

Since "parent" is passed only to get the base offsets, I think it would be clearer to pass
the offsets directly.  If I look at the signature of the function and see "dwarf2_cu *parent_cu",
I can't really tell what it's for (though a comment might help).  But if I see
"ULONGEST str_offsets_base" and "ULONGEST addr_base", it's more self-explanatory.


>    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);
> +	}

Remove the curly braces.

> +    }
> +
>    die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data);
>  }

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

Improvements like this one look good, but if they are not directly related to the patch,
please submit them in their own patch, it's easier to review and justify that way.

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

Please document this function.


> +{
> +  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;
> +	  }

I'm a bit confused with those different cases, could you please add a bit
of comments to explain the logic for each case?  Why is it not possible to
obtain the string value at this point?  If cu->str_offsets_base has no value,
doesn't it mean that the offset is 0?

Maybe it would be more obvious if I saw the actual DWARF being parsed.  Could
you suggest some gcc or clang commands to obtain some DWARF where we have a
DW_AT_dwo_name that is an indirect string?

Thanks,

Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2019-11-15  3:05 ` Simon Marchi
@ 2019-11-19  4:46   ` Ali Tamur via gdb-patches
  2019-11-19  5:27     ` Simon Marchi
  2019-11-20  4:29     ` Simon Marchi
  0 siblings, 2 replies; 15+ messages in thread
From: Ali Tamur via gdb-patches @ 2019-11-19  4:46 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Ali Tamur

Hi Simon,
Thanks for the review. Please see my replies below.

> -  ULONGEST ranges_base = 0;
> +  gdb::optional<ULONGEST> ranges_base = 0;
***  I am probably missing something, but I don't really understand the logic
of making this field optional and initializing it to 0, or the need to make it
optional at all. If the CU does not have a DW_AT_rnglists_base attribute,
doesn't it implicitly mean that this CU's ranges offset is 0?  So it would seem
fine to just leave it at 0 and keep the arithmetic as before.

Ok, I changed the initial value to 'no value' and thank you, it's better. It
seems a good idea to differentiate between an unexisting value and an existing
value of 0 even if the math stays the same. For example, for str_offsets_base,
there are different code paths depending on whether there is a value (not
depending whether the value is 0). It seems to me all of [addr_base,
ranges_base, str_offsets_base] should have similar semantics. But I agree that
currently there is no behavioral difference in ranges_base case, do you prefer
it ULONGEST?


***  Two spaces after period.
Done.


> +#define DW_STRING_IS_STR_INDEX(attr) ((attr)->string_is_str_index)
***  I don't really see the advantage of those macros.

I agree and I don't like these macros at all. But I wanted to be
consistent. (Maybe I should clear all of them as a separate refactoring cl
sometime)


> +static gdb::optional<ULONGEST>
> +lookup_addr_base (struct dwarf2_cu *cu, struct die_info* comp_unit_die,
> +               bool will_follow)
***  Please provide a comment for this function.
Done.


***   The curly braces scopes above are missing an indentation level.
Done.


> +static gdb::optional<ULONGEST>
> +lookup_ranges_base (struct dwarf2_cu *cu, struct die_info* comp_unit_die)
***  Please provide a comment for this function too.
Done.


> +  struct attribute *attr = dwarf2_attr (comp_unit_die,
> +                                     DW_AT_str_offsets_base, cu);
> +  if (attr)
*** Use: if (attr != nullptr)

Done and sent another patch to replace all "if (attr)" with 
"if (attr != nullptr)" in this file (there were 48 occurences).


> +/* Read CU/TU THIS_CU but do not follow DW_AT_GNU_dwo_name (DW_AT_GNU_dwo_name)
***  You listed DW_AT_GNU_dwo_name twice, I don't think that was the intent.
Done.


>  static void
>  init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
> +                                struct dwarf2_cu *parent_cu,
***  Please document this new parameter. Since "parent" is passed only to get
the base offsets, I think it would be clearer to pass the offsets directly. 
If I look at the signature of the function and see "dwarf2_cu *parent_cu", I
can't really tell what it's for (though a comment might help).  But if I see
"ULONGEST str_offsets_base" and "ULONGEST addr_base", it's more self-explanatory.

I wrote a comment, I hope it's good. I prefer not changing the parameters to
ULONGEST str_offsets_base and ULONGEST addr_base, because I am confused a little
too: there is a case where there is no parent_cu and in that case I believe any
existing value should not be overridden and it is difficult to do that on the
caller site.


*** Remove the curly braces.
DONE


> -           if (sibling_ptr < info_ptr)
> -             complaint (_("DW_AT_sibling points backwards"));
> -           else if (sibling_ptr > reader->buffer_end)
> +           if (sibling_ptr > reader->buffer_end)
*** Improvements like this one look good, but if they are not directly related
to the patch, please submit them in their own patch, it's easier to review and
justify that way.

OK. I need to dig up the exact case how the code failed and I made this change,
until then I am reverting this part.


***  I'm a bit confused with those different cases, could you please add a bit
of comments to explain the logic for each case?  Why is it not possible to
obtain the string value at this point?  If cu->str_offsets_base has no value,
doesn't it mean that the offset is 0?

Maybe it would be more obvious if I saw the actual DWARF being parsed.  Could
you suggest some gcc or clang commands to obtain some DWARF where we have a
DW_AT_dwo_name that is an indirect string?

Reply:
Sure, here's an example.
$  cd /tmp/dw5 && echo "int calculate() { return 4; } int main(int argc, char** argv) { return calculate(); }" >>main.cc
$  clang -gdwarf-5 -gsplit-dwarf main.cc
$  ls
a.out main.cc main.dwo 

$  llvm-dwarfdump --all a.out
a.out:	file format ELF64-x86-64

.debug_abbrev contents:
Abbrev table for offset: 0x00000000
[1] DW_TAG_compile_unit	DW_CHILDREN_no
	DW_AT_stmt_list	DW_FORM_sec_offset
	DW_AT_str_offsets_base	DW_FORM_sec_offset
	DW_AT_comp_dir	DW_FORM_strx1
	DW_AT_GNU_pubnames	DW_FORM_flag_present
	DW_AT_GNU_dwo_name	DW_FORM_strx1
	DW_AT_low_pc	DW_FORM_addrx
	DW_AT_high_pc	DW_FORM_data4
	DW_AT_addr_base	DW_FORM_sec_offset

.debug_info contents:
0x00000000: Compile Unit: length = 0x00000024 version = 0x0005 unit_type = DW_UT_skeleton abbr_offset = 0x0000 addr_size = 0x08 DWO_id = 0xee1d4b42a2f0ca0b (next unit at 0x00000028)

0x00000014: DW_TAG_compile_unit
              DW_AT_stmt_list	(0x00000000)
              DW_AT_str_offsets_base	(0x00000008)
              DW_AT_comp_dir	("/tmp/dw5")
              DW_AT_GNU_pubnames	(true)
              DW_AT_GNU_dwo_name	("main.dwo")
              DW_AT_low_pc	(0x0000000000401110)
              DW_AT_high_pc	(0x0000000000401141)
              DW_AT_addr_base	(0x00000008)
....
.debug_str contents:
0x00000000: "/tmp/dw5"
0x00000009: "main.dwo"
....
.debug_str_offsets contents:
0x00000000: Contribution size = 12, Format = DWARF32, Version = 5
0x00000008: 00000000 "/tmp/dw5"
0x0000000c: 00000009 "main.dwo"

Here is what happens. gdb starts to parse DW_TAG_compile_unit DIE. It comes
to DW_AT_GNU_dwo_name. It is of form DW_FORM_strx1 and it has a value of 1.
The actual value is somewhere in .debug_str section. To find it we need to
process .debug_str_offsets (refer to 1st index somewhere within) and also know
the value of DW_AT_str_offsets_base. However, we are in the middle of parsing
the die and there is no guarantee that we have yet processed
DW_AT_str_offsets_base, it may be parsed later. 

My solution is to temporarily write "1" as the value of the attribute
DW_AT_GNU_dwo_name, and mark it as 'needs reprocessing'. After all the
attributes of the die have been processed, DW_AT_str_offsets_base will hold the
correct value if it exists. Then, we revisit the marked attributes. During
reprocess, we don't need to read the binary file again, because we had already
written the value we need (1) in the first pass. We calculate the correct
address using that value, the contents of .debug_str* sections and
DW_AT_str_offsets_base value.

I am not claiming this is the only or the best solution, but I think it is
intuitive and changes relatively few lines of code.

---

* 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. Support DW_FORM_rnglistx.
	(create_cus_hash_table): Reflect API changes.
	(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. 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 | 428 ++++++++++++++++++++++++++++++++++++-----------
 gdb/dwarf2read.h |   1 +
 gdb/symfile.h    |   1 +
 gdb/xcoffread.c  |   1 +
 4 files changed, 330 insertions(+), 101 deletions(-)

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 4372a47c6d..6d6c76b748 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 {};
 
   /* 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,47 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
       return entry;
     }
 }
-\f
+
+/* Return the address base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_GNU_addr_base, or DW_AT_addr_base.  Also takes
+   as parameter whether it should follow DW_AT_specification.  See the comments
+   on dwarf2_attr_no_follow and dwarf2_attr for the difference.  */
+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);
+}
+
+/* Return range lists base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_rnglists_base or DW_AT_GNU_ranges_base.  */
+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 +7292,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 +7322,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 +7338,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 +7439,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 +7737,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 != nullptr)
+    cu->str_offsets_base = DW_UNSND (attr);
+
   if (skip_partial && comp_unit_die->tag == DW_TAG_partial_unit)
     return;
 
@@ -7730,9 +7807,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_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.
@@ -7744,10 +7821,14 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
 
    THIS_CU->cu is always freed when done.
    This is done in order to not leave THIS_CU->cu in a state where we have
-   to care whether it refers to the "main" CU or the DWO CU.  */
+   to care whether it refers to the "main" CU or the DWO CU.
+
+   When parent_cu is passed, it is used to provide a default value for
+   str_offsets_base and addr_base from the parent.  */
 
 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 +7867,11 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
 					     ? rcuh_kind::TYPE
 					     : rcuh_kind::COMPILE));
 
+  if (parent_cu != nullptr)
+    {
+      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.  */
@@ -7803,8 +7889,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.
@@ -7817,7 +7903,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);
 }
 \f
 /* Type Unit Groups.
@@ -9327,7 +9413,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
@@ -9423,6 +9511,7 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
 	case DW_FORM_ref_udata:
 	case DW_FORM_GNU_addr_index:
 	case DW_FORM_GNU_str_index:
+	case DW_FORM_rnglistx:
 	  info_ptr = safe_skip_leb128 (info_ptr, buffer_end);
 	  break;
 	case DW_FORM_indirect:
@@ -11968,8 +12057,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 +12095,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 +13129,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);
@@ -14700,13 +14789,14 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
       attr = dwarf2_attr (die, DW_AT_ranges, cu);
       if (attr != NULL)
 	{
-	  /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+	  /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	     We take advantage of the fact that DW_AT_ranges does not appear
 	     in DW_TAG_compile_unit of DWO files.  */
-	  int need_ranges_base = 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
@@ -14871,15 +14961,15 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block,
   attr = dwarf2_attr (die, DW_AT_ranges, cu);
   if (attr)
     {
-      /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+      /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	 We take advantage of the fact that DW_AT_ranges does not appear
 	 in DW_TAG_compile_unit of DWO files.  */
-      int need_ranges_base = 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 +18304,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 +18835,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)
@@ -18882,10 +18999,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 +19294,62 @@ partial_die_info::fixup (struct dwarf2_cu *cu)
   fixup_called = 1;
 }
 
+/* Process the attributes that had to be skipped in the first round. These
+   attributes are the ones that need str_offsets_base or addr_base attributes.
+   They could not have been processed in the first round, because at the time
+   the values of str_offsets_base or addr_base may not have been known.  */
+void read_attribute_reprocess (const struct die_reader_specs *reader,
+			       struct attribute *attr)
+{
+  struct dwarf2_cu *cu = 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 +19360,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 +19424,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 +19434,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 +19459,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;
@@ -19324,6 +19496,7 @@ read_attribute_value (const struct die_reader_specs *reader,
       info_ptr += bytes_read;
       break;
     case DW_FORM_udata:
+    case DW_FORM_rnglistx:
       DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
       break;
@@ -19365,22 +19538,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 +19555,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 +19582,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 +19620,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 +20052,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 +20108,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 +20140,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 +20180,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 +20202,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 +20225,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.432.g9d3f5f5b63-goog

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2019-11-19  4:46   ` Ali Tamur via gdb-patches
@ 2019-11-19  5:27     ` Simon Marchi
  2019-11-20  4:29     ` Simon Marchi
  1 sibling, 0 replies; 15+ messages in thread
From: Simon Marchi @ 2019-11-19  5:27 UTC (permalink / raw)
  To: Ali Tamur, gdb-patches

On 2019-11-18 11:46 p.m., Ali Tamur wrote:
> Hi Simon,
> Thanks for the review. Please see my replies below.
> 
>> -  ULONGEST ranges_base = 0;
>> +  gdb::optional<ULONGEST> ranges_base = 0;
> ***  I am probably missing something, but I don't really understand the logic
> of making this field optional and initializing it to 0, or the need to make it
> optional at all. If the CU does not have a DW_AT_rnglists_base attribute,
> doesn't it implicitly mean that this CU's ranges offset is 0?  So it would seem
> fine to just leave it at 0 and keep the arithmetic as before.
> 
> Ok, I changed the initial value to 'no value' and thank you, it's better. It
> seems a good idea to differentiate between an unexisting value and an existing
> value of 0 even if the math stays the same. For example, for str_offsets_base,
> there are different code paths depending on whether there is a value (not
> depending whether the value is 0). It seems to me all of [addr_base,
> ranges_base, str_offsets_base] should have similar semantics. But I agree that
> currently there is no behavioral difference in ranges_base case, do you prefer
> it ULONGEST?

I don't know enough about the situation to be able to tell.  But in my mind the choice
would be: if a missing information is semantically equivalent to it being zero, then we
don't need the optional.  The value 0 is just a no-op.  But if a missing information has
a different meaning than an information present with a value 0, then the optional is
probably necessary because we'll need to do some branching based on whether the value is
present or not.

>> +#define DW_STRING_IS_STR_INDEX(attr) ((attr)->string_is_str_index)
> ***  I don't really see the advantage of those macros.
> 
> I agree and I don't like these macros at all. But I wanted to be
> consistent. (Maybe I should clear all of them as a separate refactoring cl
> sometime)

Being consistent with the code around is a good justification, so if you want to keep it
like that I am fine with that.

>> +  struct attribute *attr = dwarf2_attr (comp_unit_die,
>> +                                     DW_AT_str_offsets_base, cu);
>> +  if (attr)
> *** Use: if (attr != nullptr)
> 
> Done and sent another patch to replace all "if (attr)" with 

Thanks, very appreciated.

>>  static void
>>  init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
>> +                                struct dwarf2_cu *parent_cu,
> ***  Please document this new parameter. Since "parent" is passed only to get
> the base offsets, I think it would be clearer to pass the offsets directly. 
> If I look at the signature of the function and see "dwarf2_cu *parent_cu", I
> can't really tell what it's for (though a comment might help).  But if I see
> "ULONGEST str_offsets_base" and "ULONGEST addr_base", it's more self-explanatory.
> 
> I wrote a comment, I hope it's good. I prefer not changing the parameters to
> ULONGEST str_offsets_base and ULONGEST addr_base, because I am confused a little
> too: there is a case where there is no parent_cu and in that case I believe any
> existing value should not be overridden and it is difficult to do that on the
> caller site.

Ok, I had not noticed that.

> ***  I'm a bit confused with those different cases, could you please add a bit
> of comments to explain the logic for each case?  Why is it not possible to
> obtain the string value at this point?  If cu->str_offsets_base has no value,
> doesn't it mean that the offset is 0?
> 
> Maybe it would be more obvious if I saw the actual DWARF being parsed.  Could
> you suggest some gcc or clang commands to obtain some DWARF where we have a
> DW_AT_dwo_name that is an indirect string?
> 
> Reply:
> Sure, here's an example.
> $  cd /tmp/dw5 && echo "int calculate() { return 4; } int main(int argc, char** argv) { return calculate(); }" >>main.cc
> $  clang -gdwarf-5 -gsplit-dwarf main.cc
> $  ls
> a.out main.cc main.dwo 
> 
> $  llvm-dwarfdump --all a.out
> a.out:	file format ELF64-x86-64
> 
> .debug_abbrev contents:
> Abbrev table for offset: 0x00000000
> [1] DW_TAG_compile_unit	DW_CHILDREN_no
> 	DW_AT_stmt_list	DW_FORM_sec_offset
> 	DW_AT_str_offsets_base	DW_FORM_sec_offset
> 	DW_AT_comp_dir	DW_FORM_strx1
> 	DW_AT_GNU_pubnames	DW_FORM_flag_present
> 	DW_AT_GNU_dwo_name	DW_FORM_strx1
> 	DW_AT_low_pc	DW_FORM_addrx
> 	DW_AT_high_pc	DW_FORM_data4
> 	DW_AT_addr_base	DW_FORM_sec_offset
> 
> .debug_info contents:
> 0x00000000: Compile Unit: length = 0x00000024 version = 0x0005 unit_type = DW_UT_skeleton abbr_offset = 0x0000 addr_size = 0x08 DWO_id = 0xee1d4b42a2f0ca0b (next unit at 0x00000028)
> 
> 0x00000014: DW_TAG_compile_unit
>               DW_AT_stmt_list	(0x00000000)
>               DW_AT_str_offsets_base	(0x00000008)
>               DW_AT_comp_dir	("/tmp/dw5")
>               DW_AT_GNU_pubnames	(true)
>               DW_AT_GNU_dwo_name	("main.dwo")
>               DW_AT_low_pc	(0x0000000000401110)
>               DW_AT_high_pc	(0x0000000000401141)
>               DW_AT_addr_base	(0x00000008)
> ....
> .debug_str contents:
> 0x00000000: "/tmp/dw5"
> 0x00000009: "main.dwo"
> ....
> .debug_str_offsets contents:
> 0x00000000: Contribution size = 12, Format = DWARF32, Version = 5
> 0x00000008: 00000000 "/tmp/dw5"
> 0x0000000c: 00000009 "main.dwo"
> 
> Here is what happens. gdb starts to parse DW_TAG_compile_unit DIE. It comes
> to DW_AT_GNU_dwo_name. It is of form DW_FORM_strx1 and it has a value of 1.
> The actual value is somewhere in .debug_str section. To find it we need to
> process .debug_str_offsets (refer to 1st index somewhere within) and also know
> the value of DW_AT_str_offsets_base. However, we are in the middle of parsing
> the die and there is no guarantee that we have yet processed
> DW_AT_str_offsets_base, it may be parsed later. 
> 
> My solution is to temporarily write "1" as the value of the attribute
> DW_AT_GNU_dwo_name, and mark it as 'needs reprocessing'. After all the
> attributes of the die have been processed, DW_AT_str_offsets_base will hold the
> correct value if it exists. Then, we revisit the marked attributes. During
> reprocess, we don't need to read the binary file again, because we had already
> written the value we need (1) in the first pass. We calculate the correct
> address using that value, the contents of .debug_str* sections and
> DW_AT_str_offsets_base value.
> 
> I am not claiming this is the only or the best solution, but I think it is
> intuitive and changes relatively few lines of code.

Thanks for the details above.  It is a bit late here for me to process all of this, but I'll try
to give it a look (and at the revised patch) in the following days.

Thanks,

Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2019-11-19  4:46   ` Ali Tamur via gdb-patches
  2019-11-19  5:27     ` Simon Marchi
@ 2019-11-20  4:29     ` Simon Marchi
  2019-12-27  0:41       ` Ali Tamur via gdb-patches
  1 sibling, 1 reply; 15+ messages in thread
From: Simon Marchi @ 2019-11-20  4:29 UTC (permalink / raw)
  To: Ali Tamur, gdb-patches

On 2019-11-18 11:46 p.m., Ali Tamur via gdb-patches wrote:
> Reply:
> Sure, here's an example.
> $  cd /tmp/dw5 && echo "int calculate() { return 4; } int main(int argc, char** argv) { return calculate(); }" >>main.cc
> $  clang -gdwarf-5 -gsplit-dwarf main.cc
> $  ls
> a.out main.cc main.dwo 
> 
> $  llvm-dwarfdump --all a.out
> a.out:	file format ELF64-x86-64
> 
> .debug_abbrev contents:
> Abbrev table for offset: 0x00000000
> [1] DW_TAG_compile_unit	DW_CHILDREN_no
> 	DW_AT_stmt_list	DW_FORM_sec_offset
> 	DW_AT_str_offsets_base	DW_FORM_sec_offset
> 	DW_AT_comp_dir	DW_FORM_strx1
> 	DW_AT_GNU_pubnames	DW_FORM_flag_present
> 	DW_AT_GNU_dwo_name	DW_FORM_strx1
> 	DW_AT_low_pc	DW_FORM_addrx
> 	DW_AT_high_pc	DW_FORM_data4
> 	DW_AT_addr_base	DW_FORM_sec_offset
> 
> .debug_info contents:
> 0x00000000: Compile Unit: length = 0x00000024 version = 0x0005 unit_type = DW_UT_skeleton abbr_offset = 0x0000 addr_size = 0x08 DWO_id = 0xee1d4b42a2f0ca0b (next unit at 0x00000028)
> 
> 0x00000014: DW_TAG_compile_unit
>               DW_AT_stmt_list	(0x00000000)
>               DW_AT_str_offsets_base	(0x00000008)
>               DW_AT_comp_dir	("/tmp/dw5")
>               DW_AT_GNU_pubnames	(true)
>               DW_AT_GNU_dwo_name	("main.dwo")
>               DW_AT_low_pc	(0x0000000000401110)
>               DW_AT_high_pc	(0x0000000000401141)
>               DW_AT_addr_base	(0x00000008)
> ....
> .debug_str contents:
> 0x00000000: "/tmp/dw5"
> 0x00000009: "main.dwo"
> ....
> .debug_str_offsets contents:
> 0x00000000: Contribution size = 12, Format = DWARF32, Version = 5
> 0x00000008: 00000000 "/tmp/dw5"
> 0x0000000c: 00000009 "main.dwo"
> 
> Here is what happens. gdb starts to parse DW_TAG_compile_unit DIE. It comes
> to DW_AT_GNU_dwo_name. It is of form DW_FORM_strx1 and it has a value of 1.
> The actual value is somewhere in .debug_str section. To find it we need to
> process .debug_str_offsets (refer to 1st index somewhere within) and also know
> the value of DW_AT_str_offsets_base. However, we are in the middle of parsing
> the die and there is no guarantee that we have yet processed
> DW_AT_str_offsets_base, it may be parsed later. 
> 
> My solution is to temporarily write "1" as the value of the attribute
> DW_AT_GNU_dwo_name, and mark it as 'needs reprocessing'. After all the
> attributes of the die have been processed, DW_AT_str_offsets_base will hold the
> correct value if it exists. Then, we revisit the marked attributes. During
> reprocess, we don't need to read the binary file again, because we had already
> written the value we need (1) in the first pass. We calculate the correct
> address using that value, the contents of .debug_str* sections and
> DW_AT_str_offsets_base value.

Ok, so that reprocessing happens right after having read the attributes from the DIE.

Another approach that I would have expected would be to do it more lazily.  Only keep
the index in the attribute, and go read the actual string when we call dwarf2_string_attr
on it (and then maybe cache the value).  Did you consider doing something like that, and
perhaps it was a too involving change?

I see that this is kind of done in get_stub_string_attr, for attributes marked with
DW_STRING_IS_STR_INDEX, so I was wondering why not do it for all strx forms and avoid
the reprocessing.

> +/* Process the attributes that had to be skipped in the first round. These
> +   attributes are the ones that need str_offsets_base or addr_base attributes.
> +   They could not have been processed in the first round, because at the time
> +   the values of str_offsets_base or addr_base may not have been known.  */
> +void read_attribute_reprocess (const struct die_reader_specs *reader,
> +			       struct attribute *attr)
> +{
> +  struct dwarf2_cu *cu = 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;
> +	  }

I don't understand this part.  When read_attribute_reprocess is called,
if there's a DW_AT_str_offsets_base, we will have read it at this point.
So when is the else clause actually useful?  Can you give a practical
example of how to exercise this code?

Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2019-11-20  4:29     ` Simon Marchi
@ 2019-12-27  0:41       ` Ali Tamur via gdb-patches
  2019-12-27 23:20         ` Simon Marchi
  0 siblings, 1 reply; 15+ messages in thread
From: Ali Tamur via gdb-patches @ 2019-12-27  0:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Ali Tamur

Hi,

Sorry for late response, (I got involved in some nasty unrelated bug), 
please take another look.

***
>> -  ULONGEST ranges_base = 0;
>> +  gdb::optional<ULONGEST> ranges_base = 0;
> ***  I am probably missing something, but I don't really understand the logic
> of making this field optional and initializing it to 0

Done (Reverted back to ULONGEST).


***
>Ok, so that reprocessing happens right after having read the attributes from the DIE.
>
>Another approach that I would have expected would be to do it more lazily.  Only keep
>the index in the attribute, and go read the actual string when we call dwarf2_string_attr
>on it (and then maybe cache the value).  Did you consider doing something like that, and
>perhaps it was a too involving change?

I want the patch to be as little invasive as possible, so I prefer not changing laziness,
if that's ok with you.


***
>> +     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;
>> +       }

>I don't understand this part.  When read_attribute_reprocess is called,
>if there's a DW_AT_str_offsets_base, we will have read it at this point.
>So when is the else clause actually useful?

Hmm, ok, I deleted this part, tests pass and everything continues to work,
thank you, done.

---
* Process debug_str_offsets section. Handle DW_AT_str_offsets_base attribute and
keep the value in dwarf2_cu.

* Make addr_base field in dwarf2_cu optional to disambiguate 0 value
(absent or present and 0).

* During parsing, there is no guarantee that DW_AT_str_offsets_base and
DW_AT_rnglists_base fields will be processed before the attributes that need
those values for correct computation. So make two passes, on the first one mark
the attributes that depend on *_base attributes and process only the others.
On the second pass, only process the attributes that are marked on the first
pass.

* For string attributes, differentiate between addresses that directly 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/dwarf2read.c | 397 ++++++++++++++++++++++++++++++++++++-----------
 gdb/dwarf2read.h |   1 +
 gdb/symfile.h    |   1 +
 gdb/xcoffread.c  |   1 +
 4 files changed, 307 insertions(+), 93 deletions(-)

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 685d996297..99a0440dc3 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -287,6 +287,7 @@ static const struct dwarf2_debug_sections dwarf2_elf_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,27 +501,25 @@ public:
      There is an invariant here that is important to remember:
      Except for attributes copied from the top level DIE in the "main"
      (or "stub") file in preparation for reading the DWO file
-     (e.g., DW_AT_GNU_addr_base), we KISS: there is only *one* CU.
+     (e.g., DW_AT_addr_base), we KISS: there is only *one* CU.
      Either there isn't a DWO file (in which case this is NULL and the 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;
 
@@ -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 *);
 
@@ -2412,6 +2444,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;
@@ -7182,7 +7219,47 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
       return entry;
     }
 }
-\f
+
+/* Return the address base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_GNU_addr_base, or DW_AT_addr_base.  Also takes
+   as parameter whether it should follow DW_AT_specification.  See the comments
+   on dwarf2_attr_no_follow and dwarf2_attr for the difference.  */
+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);
+}
+
+/* Return range lists base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_rnglists_base or DW_AT_GNU_ranges_base.  */
+ULONGEST
+lookup_ranges_base (struct dwarf2_cu *cu, struct die_info* comp_unit_die)
+{
+  struct attribute *attr;
+  attr = 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 0;
+  return DW_UNSND (attr);
+}
+
 /* Low level DIE reading support.  */
 
 /* Initialize a die_reader_specs struct from a dwarf2_cu struct.  */
@@ -7243,7 +7320,6 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data *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.  */
@@ -7274,20 +7350,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 != nullptr)
-	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 != nullptr)
-	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)
     {
@@ -7296,6 +7366,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;
     }
 
@@ -7396,8 +7467,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
@@ -7695,6 +7765,13 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
   init_cu_die_reader (&reader, cu, section, NULL, abbrev_table);
   info_ptr = 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 != nullptr)
+    cu->str_offsets_base = DW_UNSND (attr);
+
   if (skip_partial && comp_unit_die->tag == DW_TAG_partial_unit)
     return;
 
@@ -7758,9 +7835,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_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.
@@ -7772,10 +7849,14 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
 
    THIS_CU->cu is always freed when done.
    This is done in order to not leave THIS_CU->cu in a state where we have
-   to care whether it refers to the "main" CU or the DWO CU.  */
+   to care whether it refers to the "main" CU or the DWO CU.
+
+   When parent_cu is passed, it is used to provide a default value for
+   str_offsets_base and addr_base from the parent.  */
 
 static void
 init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
+				   struct dwarf2_cu *parent_cu,
 				   struct dwo_file *dwo_file,
 				   die_reader_func_ftype *die_reader_func,
 				   void *data)
@@ -7814,6 +7895,11 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
 					     ? rcuh_kind::TYPE
 					     : rcuh_kind::COMPILE));
 
+  if (parent_cu != nullptr)
+    {
+      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.  */
@@ -7831,8 +7917,8 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
   die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data);
 }
 
-/* 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.
@@ -7845,7 +7931,7 @@ init_cutu_and_read_dies_simple (struct dwarf2_per_cu_data *this_cu,
 				die_reader_func_ftype *die_reader_func,
 				void *data)
 {
-  init_cutu_and_read_dies_no_follow (this_cu, NULL, die_reader_func, data);
+  init_cutu_and_read_dies_no_follow (this_cu, NULL, NULL, die_reader_func, data);
 }
 \f
 /* Type Unit Groups.
@@ -9356,7 +9442,9 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
       /* The only abbrev we care about is DW_AT_sibling.  */
       if (abbrev->attrs[i].name == 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
@@ -9452,6 +9540,7 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
 	case DW_FORM_ref_udata:
 	case DW_FORM_GNU_addr_index:
 	case DW_FORM_GNU_str_index:
+	case DW_FORM_rnglistx:
 	  info_ptr = safe_skip_leb128 (info_ptr, buffer_end);
 	  break;
 	case DW_FORM_indirect:
@@ -11996,8 +12085,8 @@ create_dwo_cu_reader (const struct die_reader_specs *reader,
 
 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;
@@ -12034,7 +12123,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.
@@ -13068,8 +13157,8 @@ open_and_init_dwo_file (struct dwarf2_per_cu_data *per_cu,
   bfd_map_over_sections (dwo_file->dbfd.get (), dwarf2_locate_dwo_sections,
 			 &dwo_file->sections);
 
-  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);
@@ -14730,7 +14819,7 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
       attr = dwarf2_attr (die, DW_AT_ranges, cu);
       if (attr != NULL)
 	{
-	  /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+	  /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	     We take advantage of the fact that DW_AT_ranges does not appear
 	     in DW_TAG_compile_unit of DWO files.  */
 	  int need_ranges_base = die->tag != DW_TAG_compile_unit;
@@ -14901,7 +14990,7 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block,
   attr = dwarf2_attr (die, DW_AT_ranges, cu);
   if (attr != nullptr)
     {
-      /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+      /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	 We take advantage of the fact that DW_AT_ranges does not appear
 	 in DW_TAG_compile_unit of DWO files.  */
       int need_ranges_base = die->tag != DW_TAG_compile_unit;
@@ -18481,10 +18570,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;
@@ -18996,12 +19101,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)
@@ -19443,12 +19559,49 @@ partial_die_info::fixup (struct dwarf2_cu *cu)
   fixup_called = 1;
 }
 
+/* Process the attributes that had to be skipped in the first round. These
+   attributes are the ones that need str_offsets_base or addr_base attributes.
+   They could not have been processed in the first round, because at the time
+   the values of str_offsets_base or addr_base may not have been known.  */
+void read_attribute_reprocess (const struct die_reader_specs *reader,
+			       struct attribute *attr)
+{
+  struct dwarf2_cu *cu = 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;
+	  }
+    }
+}
+
 /* 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
@@ -19459,6 +19612,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)
@@ -19522,6 +19676,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:
@@ -19531,6 +19686,7 @@ read_attribute_value (const struct die_reader_specs *reader,
 						   abfd, info_ptr, cu_header,
 						   &bytes_read);
 	  DW_STRING_IS_CANONICAL (attr) = 0;
+	  DW_STRING_IS_STR_INDEX (attr) = false;
 	  info_ptr += bytes_read;
 	  break;
 	}
@@ -19555,6 +19711,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;
@@ -19591,6 +19748,7 @@ read_attribute_value (const struct die_reader_specs *reader,
       info_ptr += bytes_read;
       break;
     case DW_FORM_udata:
+    case DW_FORM_rnglistx:
       DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
       break;
@@ -19632,22 +19790,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:
@@ -19656,14 +19807,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)
@@ -19691,9 +19834,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]"),
@@ -19729,11 +19872,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.  */
@@ -20160,27 +20304,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
@@ -20213,7 +20360,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;
 };
 
@@ -20245,7 +20392,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.
@@ -20285,21 +20432,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";
@@ -20307,18 +20454,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);
@@ -20331,6 +20477,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 140bbed08a..f392200049 100644
--- a/gdb/dwarf2read.h
+++ b/gdb/dwarf2read.h
@@ -156,6 +156,7 @@ public:
   dwarf2_section_info macinfo {};
   dwarf2_section_info macro {};
   dwarf2_section_info str {};
+  dwarf2_section_info str_offsets {};
   dwarf2_section_info line_str {};
   dwarf2_section_info ranges {};
   dwarf2_section_info rnglists {};
diff --git a/gdb/symfile.h b/gdb/symfile.h
index cb5bed9d85..fc0fa77183 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -569,6 +569,7 @@ struct dwarf2_debug_sections {
   struct dwarf2_section_names macinfo;
   struct dwarf2_section_names macro;
   struct dwarf2_section_names str;
+  struct dwarf2_section_names str_offsets;
   struct dwarf2_section_names line_str;
   struct dwarf2_section_names ranges;
   struct dwarf2_section_names rnglists;
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index eaa77fd491..b736306227 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -166,6 +166,7 @@ static const struct dwarf2_debug_sections dwarf2_xcoff_names = {
   { NULL, NULL },
   { ".dwmac", NULL },
   { ".dwstr", NULL },
+  { NULL, NULL }, /* debug_str_offsets */
   { NULL, NULL }, /* debug_line_str */
   { ".dwrnges", NULL },
   { NULL, NULL }, /* debug_rnglists */
-- 
2.24.1.735.g03f4e72817-goog

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2019-12-27  0:41       ` Ali Tamur via gdb-patches
@ 2019-12-27 23:20         ` Simon Marchi
  2020-01-08  5:19           ` Ali Tamur via gdb-patches
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Marchi @ 2019-12-27 23:20 UTC (permalink / raw)
  To: Ali Tamur, gdb-patches

On 2019-12-26 7:41 p.m., Ali Tamur wrote:
>> Ok, so that reprocessing happens right after having read the attributes from the DIE.
>>
>> Another approach that I would have expected would be to do it more lazily.  Only keep
>> the index in the attribute, and go read the actual string when we call dwarf2_string_attr
>> on it (and then maybe cache the value).  Did you consider doing something like that, and
>> perhaps it was a too involving change?
> 
> I want the patch to be as little invasive as possible, so I prefer not changing laziness,
> if that's ok with you.

Yeah, that's fine, it is simple like that.

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

Two spaces after the period.

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

Two spaces after the period.

> +       need to reprocess these attributes later.  */
> +    bool string_is_str_index;

Thanks for this comment.  If it avoids increasing the structure size, we could eat
another bit from the `form` field.

> @@ -7182,7 +7219,47 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
>        return entry;
>      }
>  }
> -\f
> +
> +/* Return the address base of the compile unit, which, if exists, is stored
> +   either at the attribute DW_AT_GNU_addr_base, or DW_AT_addr_base.  Also takes
> +   as parameter whether it should follow DW_AT_specification.  See the comments
> +   on dwarf2_attr_no_follow and dwarf2_attr for the difference.  */
> +static gdb::optional<ULONGEST>
> +lookup_addr_base (struct dwarf2_cu *cu, struct die_info* comp_unit_die,

Space before the asterisk:

  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);
> +}
> +
> +/* Return range lists base of the compile unit, which, if exists, is stored
> +   either at the attribute DW_AT_rnglists_base or DW_AT_GNU_ranges_base.  */
> +ULONGEST
> +lookup_ranges_base (struct dwarf2_cu *cu, struct die_info* comp_unit_die)

Space before the asterisk.

> @@ -7274,20 +7350,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 != nullptr)
> -	cu->addr_base = DW_UNSND (attr);
> +      auto maybe_addr_base = lookup_addr_base (cu, stub_comp_unit_die, true);

Can you explain why we need to use the "follow" version here (passing true as the third
argument)?

I'm generating executables with split DWARF using both clang 9.0.0 and gcc 9.2.0,
using both -gdwarf-4 and -gdwarf-5 and in all cases it's not needed: the DW_AT_addr_base
or DW_AT_GNU_addr_base attribute is directly in the stub comp unit die, which we
are passing here.  So if it's really not needed here, then I wonder when this third
parameter is useful.

> @@ -7396,8 +7467,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);

If you do get rid of str_is_string_index, I think this change won't be necessary anymore,
since it will essentially just end up using DW_STRING.

>  
>    /* Skip dummy compilation units.  */
>    if (info_ptr >= begin_info_ptr + dwo_unit->length
> @@ -7695,6 +7765,13 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
>    init_cu_die_reader (&reader, cu, section, NULL, abbrev_table);
>    info_ptr = 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 != nullptr)
> +    cu->str_offsets_base = DW_UNSND (attr);

From what I understand, cu->str_offsets_base will have already been set by
read_full_die so it would be unnecessary to do so here.

> @@ -18481,10 +18570,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)

attr != nullptr

> +    cu->str_offsets_base = DW_UNSND (attr);
>  
> +  auto maybe_addr_base = lookup_addr_base(cu, die, false);
> +  if (maybe_addr_base.has_value())

Space before parentheses on the two lines above.

It would also be good to add a comment above this block of code, that explains
what we are doing (reading the attribute values that require the string and address
offset tables, after having read the base for both tables for this CU).

> +    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;
> @@ -18996,12 +19101,23 @@ partial_die_info::read (const struct die_reader_specs *reader,
>    int has_high_pc_attr = 0;
>    int high_pc_relative = 0;

Could the changes in this function be simpler, do we really need to do
two passes on the attributes?  I think that at this point, the string
offset/addr bases will be known and set in the CU, they will have been
set by read_full_die that was called on the top-level CU die.  So we
could just reprocess the attributes as we read them in the existing loop,
like this:

      bool needs_reprocess;

      info_ptr = read_attribute (reader, &attr, &abbrev.attrs[i], info_ptr,
                 &needs_reprocess);
      if (needs_reprocess)
        read_attribute_reprocess (reader, &attr);

> +  std::vector<struct attribute> attr_vec;
> +  std::vector<int> indexes_that_need_reprocess;
> +  attr_vec.resize(abbrev.num_attrs);

You could use the std::vector constructor that creates the vector with
the right size from the start:

  std::vector<struct attribute> attr_vec (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)

Since we now iterate on the vector, this loop can be

  for (const attribute &attr : attr_vec)

> +    {
> +      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)
> @@ -19443,12 +19559,49 @@ partial_die_info::fixup (struct dwarf2_cu *cu)
>    fixup_called = 1;
>  }
>  
> +/* Process the attributes that had to be skipped in the first round. These
> +   attributes are the ones that need str_offsets_base or addr_base attributes.
> +   They could not have been processed in the first round, because at the time
> +   the values of str_offsets_base or addr_base may not have been known.  */
> +void read_attribute_reprocess (const struct die_reader_specs *reader,
> +			       struct attribute *attr)
> +{
> +  struct dwarf2_cu *cu = 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;
> +	  }

Since this function is only supposed to be called on forms that need reprocessing,
I'd suggest adding a default case with:

  gdb_assert_not_reached (_("Unexpected DWARF form.");

> @@ -20331,6 +20477,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())

Space before parentheses.

> +    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);
> +}

I was wondering about this: in which situation would the string not be read
already?  In other words, when would the "if" above be true?  It appears that
with this patch, str_is_string_index is never set to true.  Instead, everything
happens under read_full_die_1.  When read_full_die_1, all the strings that
needed reprocessing have been read in.  So it seems like you could actually
remove str_is_string_index and all that is related.

I think that's a good way to do it, actually, because all the complexity related
to this corner case is encapsulated in read_full_die_1 and a few related functions.
For all other functions, strings using the string offset table just work like
other strings.

Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2019-12-27 23:20         ` Simon Marchi
@ 2020-01-08  5:19           ` Ali Tamur via gdb-patches
  2020-01-08 15:51             ` Simon Marchi
  0 siblings, 1 reply; 15+ messages in thread
From: Ali Tamur via gdb-patches @ 2020-01-08  5:19 UTC (permalink / raw)
  To: gdb-patches, simon.marchi; +Cc: Ali Tamur

Hi,
Thank you for the review, all your suggestions are spot on and the patch is
much more cleaner now.

> Can you explain why we need to use the "follow" version here (passing true as the third
argument)?
It turned out to be unnecessary, removed.

> If you do get rid of str_is_string_index, I think this change won't be necessary anymore,
since it will essentially just end up using DW_STRING.
Yes, I deleted str_is_string_index.

> From what I understand, cu->str_offsets_base will have already been set by
read_full_die so it would be unnecessary to do so here.
Removed.

> Could the changes in this function be simpler, do we really need to do
two passes on the attributes?
Done.

> You could use the std::vector constructor that creates the vector with
the right size from the start
Done.

> Since we now iterate on the vector, this loop can be
>
>  for (const attribute &attr : attr_vec)
Done.

> I'd suggest adding a default case with:
>
>  gdb_assert_not_reached (_("Unexpected DWARF form.");
Done.

> It appears that with this patch, str_is_string_index is never set to true. 
Removed.

---
* Process debug_str_offsets section. Handle DW_AT_str_offsets_base attribute and
keep the value in dwarf2_cu.

* Make addr_base field in dwarf2_cu optional to disambiguate 0 value
(absent or present and 0).

* During parsing, there is no guarantee that DW_AT_str_offsets_base and
DW_AT_rnglists_base fields will be processed before the attributes that need
those values for correct computation. So make two passes, on the first one mark
the attributes that depend on *_base attributes and process only the others.
On the second pass, only process the attributes that are marked on the first
pass.

* For string attributes, differentiate between addresses that directly 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/dwarf2read.c | 348 ++++++++++++++++++++++++++++++++++-------------
 gdb/dwarf2read.h |   1 +
 gdb/symfile.h    |   1 +
 gdb/xcoffread.c  |   1 +
 4 files changed, 257 insertions(+), 94 deletions(-)

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 685d996297..05a476054e 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,27 +501,25 @@ public:
      There is an invariant here that is important to remember:
      Except for attributes copied from the top level DIE in the "main"
      (or "stub") file in preparation for reading the DWO file
-     (e.g., DW_AT_GNU_addr_base), we KISS: there is only *one* CU.
+     (e.g., DW_AT_addr_base), we KISS: there is only *one* CU.
      Either there isn't a DWO file (in which case this is NULL and the 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;
 
@@ -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.  */
@@ -1519,7 +1524,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 +1588,14 @@ 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 void set_cu_language (unsigned int, struct dwarf2_cu *);
 
@@ -2412,6 +2428,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;
@@ -7182,7 +7203,35 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
       return entry;
     }
 }
-\f
+
+/* Return the address base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_GNU_addr_base, or DW_AT_addr_base.  */
+static gdb::optional<ULONGEST>
+lookup_addr_base (struct dwarf2_cu *cu, struct die_info *comp_unit_die)
+{
+  struct attribute *attr;
+  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);
+}
+
+/* Return range lists base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_rnglists_base or DW_AT_GNU_ranges_base.  */
+ULONGEST
+lookup_ranges_base (struct dwarf2_cu *cu, struct die_info *comp_unit_die)
+{
+  struct attribute *attr;
+  attr = 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 0;
+  return DW_UNSND (attr);
+}
+
 /* Low level DIE reading support.  */
 
 /* Initialize a die_reader_specs struct from a dwarf2_cu struct.  */
@@ -7243,7 +7292,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.  */
@@ -7274,20 +7322,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 != nullptr)
-	cu->addr_base = DW_UNSND (attr);
+      auto maybe_addr_base = lookup_addr_base (cu, stub_comp_unit_die);
+      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 != nullptr)
-	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)
     {
@@ -7396,8 +7438,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
@@ -7758,9 +7799,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_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.
@@ -7772,10 +7813,14 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
 
    THIS_CU->cu is always freed when done.
    This is done in order to not leave THIS_CU->cu in a state where we have
-   to care whether it refers to the "main" CU or the DWO CU.  */
+   to care whether it refers to the "main" CU or the DWO CU.
+
+   When parent_cu is passed, it is used to provide a default value for
+   str_offsets_base and addr_base from the parent.  */
 
 static void
 init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
+				   struct dwarf2_cu *parent_cu,
 				   struct dwo_file *dwo_file,
 				   die_reader_func_ftype *die_reader_func,
 				   void *data)
@@ -7814,6 +7859,11 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
 					     ? rcuh_kind::TYPE
 					     : rcuh_kind::COMPILE));
 
+  if (parent_cu != nullptr)
+    {
+      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.  */
@@ -7831,8 +7881,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.
@@ -7845,7 +7895,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);
 }
 \f
 /* Type Unit Groups.
@@ -9356,7 +9406,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
@@ -9452,6 +9504,7 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
 	case DW_FORM_ref_udata:
 	case DW_FORM_GNU_addr_index:
 	case DW_FORM_GNU_str_index:
+	case DW_FORM_rnglistx:
 	  info_ptr = safe_skip_leb128 (info_ptr, buffer_end);
 	  break;
 	case DW_FORM_indirect:
@@ -11996,8 +12049,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;
@@ -12034,7 +12087,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.
@@ -13068,8 +13121,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);
@@ -14730,7 +14783,7 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
       attr = dwarf2_attr (die, DW_AT_ranges, cu);
       if (attr != NULL)
 	{
-	  /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+	  /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	     We take advantage of the fact that DW_AT_ranges does not appear
 	     in DW_TAG_compile_unit of DWO files.  */
 	  int need_ranges_base = die->tag != DW_TAG_compile_unit;
@@ -14901,7 +14954,7 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block,
   attr = dwarf2_attr (die, DW_AT_ranges, cu);
   if (attr != nullptr)
     {
-      /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+      /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	 We take advantage of the fact that DW_AT_ranges does not appear
 	 in DW_TAG_compile_unit of DWO files.  */
       int need_ranges_base = die->tag != DW_TAG_compile_unit;
@@ -17840,7 +17893,7 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
   enum bfd_endian byte_order = gdbarch_byte_order (arch);
 
   attr = dwarf2_attr (die, DW_AT_endianity, cu);
-  if (attr)
+  if (attr != nullptr)
     {
       int endianity = DW_UNSND (attr);
 
@@ -18481,10 +18534,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 != nullptr)
+    cu->str_offsets_base = DW_UNSND (attr);
+
+  auto maybe_addr_base = lookup_addr_base(cu, die);
+  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;
@@ -18996,12 +19065,19 @@ 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 (abbrev.num_attrs);
+  std::vector<int> indexes_that_need_reprocess;
   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)
+        read_attribute_reprocess (reader, &attr_vec[i]);
+    }
 
+  for (attribute &attr : attr_vec)
+    {
       /* Store the data if it is of an attribute we want to keep in a
          partial symbol table.  */
       switch (attr.name)
@@ -19443,12 +19519,52 @@ partial_die_info::fixup (struct dwarf2_cu *cu)
   fixup_called = 1;
 }
 
+/* Process the attributes that had to be skipped in the first round. These
+   attributes are the ones that need str_offsets_base or addr_base attributes.
+   They could not have been processed in the first round, because at the time
+   the values of str_offsets_base or addr_base may not have been known.  */
+void read_attribute_reprocess (const struct die_reader_specs *reader,
+			       struct attribute *attr)
+{
+  struct dwarf2_cu *cu = 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;
+	    }
+	  else if (cu->str_offsets_base.has_value ())
+	    {
+	      DW_STRING (attr) = read_stub_str_index (cu, str_index);
+	      DW_STRING_IS_CANONICAL (attr) = 0;
+	    }
+	  break;
+	}
+      default:
+	gdb_assert_not_reached (_("Unexpected DWARF form."));
+    }
+}
+
 /* 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
@@ -19459,6 +19575,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)
@@ -19591,6 +19708,7 @@ read_attribute_value (const struct die_reader_specs *reader,
       info_ptr += bytes_read;
       break;
     case DW_FORM_udata:
+    case DW_FORM_rnglistx:
       DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
       break;
@@ -19632,22 +19750,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:
@@ -19656,14 +19767,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)
@@ -19691,9 +19794,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]"),
@@ -19729,11 +19832,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.  */
@@ -20160,27 +20264,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
@@ -20213,7 +20320,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;
 };
 
@@ -20245,7 +20352,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.
@@ -20285,21 +20392,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";
@@ -20307,18 +20414,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);
@@ -20331,6 +20437,60 @@ 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);
+}
+
+/* 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 DW_STRING (attr);
+}
+
+
 /* Return the length of an LEB128 number in BUF.  */
 
 static int
diff --git a/gdb/dwarf2read.h b/gdb/dwarf2read.h
index 140bbed08a..f392200049 100644
--- a/gdb/dwarf2read.h
+++ b/gdb/dwarf2read.h
@@ -156,6 +156,7 @@ public:
   dwarf2_section_info macinfo {};
   dwarf2_section_info macro {};
   dwarf2_section_info str {};
+  dwarf2_section_info str_offsets {};
   dwarf2_section_info line_str {};
   dwarf2_section_info ranges {};
   dwarf2_section_info rnglists {};
diff --git a/gdb/symfile.h b/gdb/symfile.h
index cb5bed9d85..fc0fa77183 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -569,6 +569,7 @@ struct dwarf2_debug_sections {
   struct dwarf2_section_names macinfo;
   struct dwarf2_section_names macro;
   struct dwarf2_section_names str;
+  struct dwarf2_section_names str_offsets;
   struct dwarf2_section_names line_str;
   struct dwarf2_section_names ranges;
   struct dwarf2_section_names rnglists;
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index eaa77fd491..b736306227 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -166,6 +166,7 @@ static const struct dwarf2_debug_sections dwarf2_xcoff_names = {
   { NULL, NULL },
   { ".dwmac", NULL },
   { ".dwstr", NULL },
+  { NULL, NULL }, /* debug_str_offsets */
   { NULL, NULL }, /* debug_line_str */
   { ".dwrnges", NULL },
   { NULL, NULL }, /* debug_rnglists */
-- 
2.24.1.735.g03f4e72817-goog

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2020-01-08  5:19           ` Ali Tamur via gdb-patches
@ 2020-01-08 15:51             ` Simon Marchi
  2020-01-09  0:57               ` Ali Tamur via gdb-patches
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Marchi @ 2020-01-08 15:51 UTC (permalink / raw)
  To: Ali Tamur, gdb-patches

On 2020-01-08 12:19 a.m., Ali Tamur wrote:
> Hi,
> Thank you for the review, all your suggestions are spot on and the patch is
> much more cleaner now.
> 
>> Can you explain why we need to use the "follow" version here (passing true as the third
> argument)?
> It turned out to be unnecessary, removed.
> 
>> If you do get rid of str_is_string_index, I think this change won't be necessary anymore,
> since it will essentially just end up using DW_STRING.
> Yes, I deleted str_is_string_index.
> 
>> From what I understand, cu->str_offsets_base will have already been set by
> read_full_die so it would be unnecessary to do so here.
> Removed.
> 
>> Could the changes in this function be simpler, do we really need to do
> two passes on the attributes?
> Done.
> 
>> You could use the std::vector constructor that creates the vector with
> the right size from the start
> Done.
> 
>> Since we now iterate on the vector, this loop can be
>>
>>  for (const attribute &attr : attr_vec)
> Done.
> 
>> I'd suggest adding a default case with:
>>
>>  gdb_assert_not_reached (_("Unexpected DWARF form.");
> Done.
> 
>> It appears that with this patch, str_is_string_index is never set to true. 
> Removed.

Hi Ali,

Thanks, here are a few more comments.  I'm probably being a little bit picky,
but I really want to avoid adding any unnecessary complexity in this code that
is already very complex.

> @@ -500,27 +501,25 @@ public:
>       There is an invariant here that is important to remember:
>       Except for attributes copied from the top level DIE in the "main"
>       (or "stub") file in preparation for reading the DWO file
> -     (e.g., DW_AT_GNU_addr_base), we KISS: there is only *one* CU.
> +     (e.g., DW_AT_addr_base), we KISS: there is only *one* CU.
>       Either there isn't a DWO file (in which case this is NULL and the 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 {};

You don't need the {}, as the optional will be default-constructed empty in any case.

>  
> -  /* 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;
>  
> @@ -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 {};

Same here.

> @@ -7182,7 +7203,35 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
>        return entry;
>      }
>  }
> -\f
> +
> +/* Return the address base of the compile unit, which, if exists, is stored
> +   either at the attribute DW_AT_GNU_addr_base, or DW_AT_addr_base.  */
> +static gdb::optional<ULONGEST>
> +lookup_addr_base (struct dwarf2_cu *cu, struct die_info *comp_unit_die)

The "cu" parameter is no longer needed.

> +{
> +  struct attribute *attr;
> +  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);
> +}
> +
> +/* Return range lists base of the compile unit, which, if exists, is stored
> +   either at the attribute DW_AT_rnglists_base or DW_AT_GNU_ranges_base.  */
> +ULONGEST
> +lookup_ranges_base (struct dwarf2_cu *cu, struct die_info *comp_unit_die)
> +{
> +  struct attribute *attr;
> +  attr = 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 0;
> +  return DW_UNSND (attr);
> +}

I think lookup_ranges_base could use dwarf2_attr_no_follow too, and thus you could get
rid of the "cu" parameter.  The reasonning is that we know comp_unit_die is either
a DW_TAG_compile_unit or a DW_TAG_partial_unit (I wouldn't mind if you added a gdb_assert
to check that in these functions), and those DIEs can't have DW_AT_specification or
DW_AT_abstract_origin, which is what dwarf2_attr checks for.

> +
>  /* Low level DIE reading support.  */
>  
>  /* Initialize a die_reader_specs struct from a dwarf2_cu struct.  */
> @@ -7243,7 +7292,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.  */
> @@ -7274,20 +7322,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 != nullptr)
> -	cu->addr_base = DW_UNSND (attr);
> +      auto maybe_addr_base = lookup_addr_base (cu, stub_comp_unit_die);
> +      if (maybe_addr_base.has_value ())
> +	cu->addr_base = *maybe_addr_base;

If I'm not mistaken, this could just be

    cu->addr_base = lookup_addr_base (cu, stub_comp_unit_die);

right? If lookup_addr_base returns an empty optional, then cu->addr_base will remain
an empty optional, which is what we want.

>  
> -      /* 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 != nullptr)
> -	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)
>      {
> @@ -7396,8 +7438,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);

Can you explain why this change is necessary (or at least desirable)?  I think it doesn't change
anything, because `comp_dir` will have been assigned to `comp_unit_die`, so in the end we should
read the same thing.

get_comp_dir_attr now is pretty much equivalent to dwarf2_string_attr.  dwarf2_string_attr does
some validation on the attribute form, which could be desirable, so we could use that instead
of DW_STRING directly, but I don't think using get_comp_dir_attr is useful.

> @@ -17840,7 +17893,7 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
>    enum bfd_endian byte_order = gdbarch_byte_order (arch);
>  
>    attr = dwarf2_attr (die, DW_AT_endianity, cu);
> -  if (attr)
> +  if (attr != nullptr)

That change is not wrong, but it's unrelated to this patch.  I don't mind doing these
improvements when touching the code around, but that's not the case here.  However,
feel free to push it separately, as an obvious patch.

> @@ -18996,12 +19065,19 @@ 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 (abbrev.num_attrs);
> +  std::vector<int> indexes_that_need_reprocess;
>    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)
> +        read_attribute_reprocess (reader, &attr_vec[i]);
> +    }

I think this would deserve a comment.  Readers could be surprised that we reprocess
attributes directly.  In essence, the comment should say that we never deal with a
CU DIE here, only its descendants, so the string/address offsets necessary to do
the reprocessing will have already been read from the CU DIE earlier, and therefore
it's safe to reprocess immediatly.


> @@ -20160,27 +20264,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;

Space before parenthesis.

> +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 DW_STRING (attr);
> +}

As mentioned earlier, I think this can be removed, as it's doing essentially the same thing
as dwarf2_string_attr.

Thanks,

Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2020-01-08 15:51             ` Simon Marchi
@ 2020-01-09  0:57               ` Ali Tamur via gdb-patches
  2020-01-10  3:46                 ` Simon Marchi
  0 siblings, 1 reply; 15+ messages in thread
From: Ali Tamur via gdb-patches @ 2020-01-09  0:57 UTC (permalink / raw)
  To: gdb-patches, simon.marchi; +Cc: Ali Tamur

Hi.

> +  gdb::optional<ULONGEST> addr_base {};
> You don't need the {}, as the optional will be default-constructed empty in any case.
Done.

> +  gdb::optional<ULONGEST> str_offsets_base {};
> Same here.
Done.

> +lookup_addr_base (struct dwarf2_cu *cu, struct die_info *comp_unit_die)
> The "cu" parameter is no longer needed.
Done.

> I think lookup_ranges_base could use dwarf2_attr_no_follow too, and thus you could get
> rid of the "cu" parameter.
Done.

> If I'm not mistaken, this could just be
>   cu->addr_base = lookup_addr_base (cu, stub_comp_unit_die);
> right?
Done.

> +  result_reader->comp_dir = get_comp_dir_attr (comp_unit_die, cu);
> Can you explain why this change is necessary (or at least desirable)?
Reverted.

> +  if (attr != nullptr)
> That change is not wrong, but it's unrelated to this patch.
Reverted.

> +      if (need_reprocess)
> +        read_attribute_reprocess (reader, &attr_vec[i]);
> +    }
> I think this would deserve a comment.
Done.

> +  ULONGEST addr_base_or_zero = addr_base.has_value() ? *addr_base : 0;
> Space before parenthesis.
Done.

> +get_comp_dir_attr (struct die_info *die, struct dwarf2_cu *cu)
> As mentioned earlier, I think this can be removed, as it's doing essentially the same thing
> as dwarf2_string_attr
Done.
---
* Process debug_str_offsets section. Handle DW_AT_str_offsets_base attribute and
keep the value in dwarf2_cu.

* Make addr_base field in dwarf2_cu optional to disambiguate 0 value
(absent or present and 0).

* During parsing, there is no guarantee that DW_AT_str_offsets_base and
DW_AT_rnglists_base fields will be processed before the attributes that need
those values for correct computation. So make two passes, on the first one mark
the attributes that depend on *_base attributes and process only the others.
On the second pass, only process the attributes that are marked on the first
pass.

* For string attributes, differentiate between addresses that directly 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/dwarf2read.c | 322 +++++++++++++++++++++++++++++++++--------------
 gdb/dwarf2read.h |   1 +
 gdb/symfile.h    |   1 +
 gdb/xcoffread.c  |   1 +
 4 files changed, 234 insertions(+), 91 deletions(-)

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 685d996297..ff9fa75def 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,27 +501,25 @@ public:
      There is an invariant here that is important to remember:
      Except for attributes copied from the top level DIE in the "main"
      (or "stub") file in preparation for reading the DWO file
-     (e.g., DW_AT_GNU_addr_base), we KISS: there is only *one* CU.
+     (e.g., DW_AT_addr_base), we KISS: there is only *one* CU.
      Either there isn't a DWO file (in which case this is NULL and the 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;
 
@@ -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.  */
@@ -1519,7 +1524,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 +1588,11 @@ 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 void set_cu_language (unsigned int, struct dwarf2_cu *);
 
@@ -2412,6 +2425,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;
@@ -7182,7 +7200,35 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
       return entry;
     }
 }
-\f
+
+/* Return the address base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_GNU_addr_base, or DW_AT_addr_base.  */
+static gdb::optional<ULONGEST>
+lookup_addr_base (struct die_info *comp_unit_die)
+{
+  struct attribute *attr;
+  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);
+}
+
+/* Return range lists base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_rnglists_base or DW_AT_GNU_ranges_base.  */
+ULONGEST
+lookup_ranges_base (struct dwarf2_cu *cu, struct die_info *comp_unit_die)
+{
+  struct attribute *attr;
+  attr = dwarf2_attr_no_follow (comp_unit_die, DW_AT_rnglists_base);
+  if (attr == nullptr)
+    attr = dwarf2_attr_no_follow (comp_unit_die, DW_AT_GNU_ranges_base);
+  if (attr == nullptr)
+    return 0;
+  return DW_UNSND (attr);
+}
+
 /* Low level DIE reading support.  */
 
 /* Initialize a die_reader_specs struct from a dwarf2_cu struct.  */
@@ -7243,7 +7289,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.  */
@@ -7274,20 +7319,12 @@ 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 != nullptr)
-	cu->addr_base = DW_UNSND (attr);
+      cu->addr_base = lookup_addr_base (stub_comp_unit_die);
 
-      /* 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 != nullptr)
-	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)
     {
@@ -7758,9 +7795,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_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.
@@ -7772,10 +7809,14 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
 
    THIS_CU->cu is always freed when done.
    This is done in order to not leave THIS_CU->cu in a state where we have
-   to care whether it refers to the "main" CU or the DWO CU.  */
+   to care whether it refers to the "main" CU or the DWO CU.
+
+   When parent_cu is passed, it is used to provide a default value for
+   str_offsets_base and addr_base from the parent.  */
 
 static void
 init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
+				   struct dwarf2_cu *parent_cu,
 				   struct dwo_file *dwo_file,
 				   die_reader_func_ftype *die_reader_func,
 				   void *data)
@@ -7814,6 +7855,11 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
 					     ? rcuh_kind::TYPE
 					     : rcuh_kind::COMPILE));
 
+  if (parent_cu != nullptr)
+    {
+      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.  */
@@ -7831,8 +7877,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.
@@ -7845,7 +7891,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);
 }
 \f
 /* Type Unit Groups.
@@ -9356,7 +9402,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
@@ -9452,6 +9500,7 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
 	case DW_FORM_ref_udata:
 	case DW_FORM_GNU_addr_index:
 	case DW_FORM_GNU_str_index:
+	case DW_FORM_rnglistx:
 	  info_ptr = safe_skip_leb128 (info_ptr, buffer_end);
 	  break;
 	case DW_FORM_indirect:
@@ -11996,8 +12045,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;
@@ -12034,7 +12083,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.
@@ -13068,8 +13117,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);
@@ -14730,7 +14779,7 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
       attr = dwarf2_attr (die, DW_AT_ranges, cu);
       if (attr != NULL)
 	{
-	  /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+	  /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	     We take advantage of the fact that DW_AT_ranges does not appear
 	     in DW_TAG_compile_unit of DWO files.  */
 	  int need_ranges_base = die->tag != DW_TAG_compile_unit;
@@ -14901,7 +14950,7 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block,
   attr = dwarf2_attr (die, DW_AT_ranges, cu);
   if (attr != nullptr)
     {
-      /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+      /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	 We take advantage of the fact that DW_AT_ranges does not appear
 	 in DW_TAG_compile_unit of DWO files.  */
       int need_ranges_base = die->tag != DW_TAG_compile_unit;
@@ -18481,10 +18530,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 != nullptr)
+    cu->str_offsets_base = DW_UNSND (attr);
 
+  auto maybe_addr_base = lookup_addr_base(die);
+  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;
@@ -18996,12 +19061,22 @@ 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 (abbrev.num_attrs);
+  std::vector<int> indexes_that_need_reprocess;
   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);
+      /* String and address offsets that need to do the reprocessing have
+         already been read at this point, so there is no need to wait until
+	 the loop terminates to do the reprocessing.  */
+      if (need_reprocess)
+        read_attribute_reprocess (reader, &attr_vec[i]);
+    }
 
+  for (attribute &attr : attr_vec)
+    {
       /* Store the data if it is of an attribute we want to keep in a
          partial symbol table.  */
       switch (attr.name)
@@ -19443,12 +19518,52 @@ partial_die_info::fixup (struct dwarf2_cu *cu)
   fixup_called = 1;
 }
 
+/* Process the attributes that had to be skipped in the first round. These
+   attributes are the ones that need str_offsets_base or addr_base attributes.
+   They could not have been processed in the first round, because at the time
+   the values of str_offsets_base or addr_base may not have been known.  */
+void read_attribute_reprocess (const struct die_reader_specs *reader,
+			       struct attribute *attr)
+{
+  struct dwarf2_cu *cu = 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;
+	    }
+	  else if (cu->str_offsets_base.has_value ())
+	    {
+	      DW_STRING (attr) = read_stub_str_index (cu, str_index);
+	      DW_STRING_IS_CANONICAL (attr) = 0;
+	    }
+	  break;
+	}
+      default:
+	gdb_assert_not_reached (_("Unexpected DWARF form."));
+    }
+}
+
 /* 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
@@ -19459,6 +19574,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)
@@ -19591,6 +19707,7 @@ read_attribute_value (const struct die_reader_specs *reader,
       info_ptr += bytes_read;
       break;
     case DW_FORM_udata:
+    case DW_FORM_rnglistx:
       DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
       break;
@@ -19632,22 +19749,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:
@@ -19656,14 +19766,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)
@@ -19691,9 +19793,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]"),
@@ -19729,11 +19831,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.  */
@@ -20160,27 +20263,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
@@ -20213,7 +20319,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;
 };
 
@@ -20245,7 +20351,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.
@@ -20285,21 +20391,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";
@@ -20307,18 +20413,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);
@@ -20331,6 +20436,41 @@ 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);
+}
+
 /* Return the length of an LEB128 number in BUF.  */
 
 static int
diff --git a/gdb/dwarf2read.h b/gdb/dwarf2read.h
index 140bbed08a..f392200049 100644
--- a/gdb/dwarf2read.h
+++ b/gdb/dwarf2read.h
@@ -156,6 +156,7 @@ public:
   dwarf2_section_info macinfo {};
   dwarf2_section_info macro {};
   dwarf2_section_info str {};
+  dwarf2_section_info str_offsets {};
   dwarf2_section_info line_str {};
   dwarf2_section_info ranges {};
   dwarf2_section_info rnglists {};
diff --git a/gdb/symfile.h b/gdb/symfile.h
index cb5bed9d85..fc0fa77183 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -569,6 +569,7 @@ struct dwarf2_debug_sections {
   struct dwarf2_section_names macinfo;
   struct dwarf2_section_names macro;
   struct dwarf2_section_names str;
+  struct dwarf2_section_names str_offsets;
   struct dwarf2_section_names line_str;
   struct dwarf2_section_names ranges;
   struct dwarf2_section_names rnglists;
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index eaa77fd491..b736306227 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -166,6 +166,7 @@ static const struct dwarf2_debug_sections dwarf2_xcoff_names = {
   { NULL, NULL },
   { ".dwmac", NULL },
   { ".dwstr", NULL },
+  { NULL, NULL }, /* debug_str_offsets */
   { NULL, NULL }, /* debug_line_str */
   { ".dwrnges", NULL },
   { NULL, NULL }, /* debug_rnglists */
-- 
2.25.0.rc1.283.g88dfdc4193-goog

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2020-01-09  0:57               ` Ali Tamur via gdb-patches
@ 2020-01-10  3:46                 ` Simon Marchi
  2020-01-11  3:45                   ` Ali Tamur via gdb-patches
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Marchi @ 2020-01-10  3:46 UTC (permalink / raw)
  To: Ali Tamur, gdb-patches

Hi Ali,

Just a few more comments.  We should be close nowthanks a lot for enduring my nitpicks :).
> @@ -7182,7 +7200,35 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
>        return entry;
>      }
>  }
> -\f
> +
> +/* Return the address base of the compile unit, which, if exists, is stored
> +   either at the attribute DW_AT_GNU_addr_base, or DW_AT_addr_base.  */
> +static gdb::optional<ULONGEST>
> +lookup_addr_base (struct die_info *comp_unit_die)
> +{
> +  struct attribute *attr;
> +  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);
> +}
> +
> +/* Return range lists base of the compile unit, which, if exists, is stored
> +   either at the attribute DW_AT_rnglists_base or DW_AT_GNU_ranges_base.  */
> +ULONGEST
> +lookup_ranges_base (struct dwarf2_cu *cu, struct die_info *comp_unit_die)

Remove the `cu` parameter.

> @@ -18481,10 +18530,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 != nullptr)
> +    cu->str_offsets_base = DW_UNSND (attr);
>  
> +  auto maybe_addr_base = lookup_addr_base(die);
> +  if (maybe_addr_base.has_value ())
> +    cu->addr_base = *maybe_addr_base;

Could this be

  cu->addr_base = lookup_addr_base (die);

?

> @@ -18996,12 +19061,22 @@ 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 (abbrev.num_attrs);
> +  std::vector<int> indexes_that_need_reprocess;
>    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);
> +      /* String and address offsets that need to do the reprocessing have
> +         already been read at this point, so there is no need to wait until
> +	 the loop terminates to do the reprocessing.  */
> +      if (need_reprocess)
> +        read_attribute_reprocess (reader, &attr_vec[i]);
> +    }
>  
> +  for (attribute &attr : attr_vec)
> +    {
>        /* Store the data if it is of an attribute we want to keep in a
>           partial symbol table.  */
>        switch (attr.name)

I might just have a brain fart at the moment but... what is the reason we
need to have two separate loops here again?  What's the reason you can't just
add the read_attribute_reprocess call in the existing loop?

> @@ -19443,12 +19518,52 @@ partial_die_info::fixup (struct dwarf2_cu *cu)
>    fixup_called = 1;
>  }
>  
> +/* Process the attributes that had to be skipped in the first round. These
> +   attributes are the ones that need str_offsets_base or addr_base attributes.
> +   They could not have been processed in the first round, because at the time
> +   the values of str_offsets_base or addr_base may not have been known.  */
> +void read_attribute_reprocess (const struct die_reader_specs *reader,
> +			       struct attribute *attr)
> +{
> +  struct dwarf2_cu *cu = 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;
> +	    }
> +	  else if (cu->str_offsets_base.has_value ())
> +	    {
> +	      DW_STRING (attr) = read_stub_str_index (cu, str_index);
> +	      DW_STRING_IS_CANONICAL (attr) = 0;
> +	    }

What happens if we encounter one these indirect string forms (strx and company) here, but
we don't enter any of the two "if" clauses above?  If that happens, it means we'll leave
a string-type attribute with its `DW_STRING` unset, and it will just break later.

Is it:

- a GDB bug, in which case we should add a gdb_assert_not_reached?
- Wrong DWARF, in which case we should add a complain?
- something else?

Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2020-01-10  3:46                 ` Simon Marchi
@ 2020-01-11  3:45                   ` Ali Tamur via gdb-patches
  2020-01-11 13:35                     ` Simon Marchi
  0 siblings, 1 reply; 15+ messages in thread
From: Ali Tamur via gdb-patches @ 2020-01-11  3:45 UTC (permalink / raw)
  To: gdb-patches, simon.marchi; +Cc: Ali Tamur

Hi Simon,

> Remove the `cu` parameter.
Done.

> Could this be
> cu->addr_base = lookup_addr_base (die);
gdb.dwarf2/fission-base.exp consistently failed when I tried your suggestion,
and now I am scared whether it is a safe change. (I don't understand the
control flow well, but if cu->addr_base was assigned previously and
lookup_addr_base fails, it would unassign the previous value.

> what is the reason we need to have two separate loops here again?
Converted to a single loop.

> What happens if we encounter one these indirect string forms (strx and
> company) here, but we don't enter any of the two "if" clauses above?
I think that means an incorrect DWARF; I removed the if condition, so the
complaint in read_stub_str_index will trigger.

Thanks,
---
* Process debug_str_offsets section. Handle DW_AT_str_offsets_base attribute and
keep the value in dwarf2_cu.

* Make addr_base field in dwarf2_cu optional to disambiguate 0 value
(absent or present and 0).

* During parsing, there is no guarantee that DW_AT_str_offsets_base and
DW_AT_rnglists_base fields will be processed before the attributes that need
those values for correct computation. So make two passes, on the first one mark
the attributes that depend on *_base attributes and process only the others.
On the second pass, only process the attributes that are marked on the first
pass.

* For string attributes, differentiate between addresses that directly 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/dwarf2read.c | 320 +++++++++++++++++++++++++++++++++--------------
 gdb/dwarf2read.h |   1 +
 gdb/symfile.h    |   1 +
 gdb/xcoffread.c  |   1 +
 4 files changed, 231 insertions(+), 92 deletions(-)

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 685d996297..ccc52f835e 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,27 +501,25 @@ public:
      There is an invariant here that is important to remember:
      Except for attributes copied from the top level DIE in the "main"
      (or "stub") file in preparation for reading the DWO file
-     (e.g., DW_AT_GNU_addr_base), we KISS: there is only *one* CU.
+     (e.g., DW_AT_addr_base), we KISS: there is only *one* CU.
      Either there isn't a DWO file (in which case this is NULL and the 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;
 
@@ -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.  */
@@ -1519,7 +1524,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 +1588,11 @@ 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 void set_cu_language (unsigned int, struct dwarf2_cu *);
 
@@ -2412,6 +2425,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;
@@ -7182,7 +7200,35 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
       return entry;
     }
 }
-\f
+
+/* Return the address base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_GNU_addr_base, or DW_AT_addr_base.  */
+static gdb::optional<ULONGEST>
+lookup_addr_base (struct die_info *comp_unit_die)
+{
+  struct attribute *attr;
+  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);
+}
+
+/* Return range lists base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_rnglists_base or DW_AT_GNU_ranges_base.  */
+ULONGEST
+lookup_ranges_base (struct die_info *comp_unit_die)
+{
+  struct attribute *attr;
+  attr = dwarf2_attr_no_follow (comp_unit_die, DW_AT_rnglists_base);
+  if (attr == nullptr)
+    attr = dwarf2_attr_no_follow (comp_unit_die, DW_AT_GNU_ranges_base);
+  if (attr == nullptr)
+    return 0;
+  return DW_UNSND (attr);
+}
+
 /* Low level DIE reading support.  */
 
 /* Initialize a die_reader_specs struct from a dwarf2_cu struct.  */
@@ -7243,7 +7289,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.  */
@@ -7274,20 +7319,12 @@ 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 != nullptr)
-	cu->addr_base = DW_UNSND (attr);
+      cu->addr_base = lookup_addr_base (stub_comp_unit_die);
 
-      /* 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 != nullptr)
-	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 (stub_comp_unit_die);
     }
   else if (stub_comp_dir != NULL)
     {
@@ -7758,9 +7795,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_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.
@@ -7772,10 +7809,14 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
 
    THIS_CU->cu is always freed when done.
    This is done in order to not leave THIS_CU->cu in a state where we have
-   to care whether it refers to the "main" CU or the DWO CU.  */
+   to care whether it refers to the "main" CU or the DWO CU.
+
+   When parent_cu is passed, it is used to provide a default value for
+   str_offsets_base and addr_base from the parent.  */
 
 static void
 init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
+				   struct dwarf2_cu *parent_cu,
 				   struct dwo_file *dwo_file,
 				   die_reader_func_ftype *die_reader_func,
 				   void *data)
@@ -7814,6 +7855,11 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
 					     ? rcuh_kind::TYPE
 					     : rcuh_kind::COMPILE));
 
+  if (parent_cu != nullptr)
+    {
+      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.  */
@@ -7831,8 +7877,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.
@@ -7845,7 +7891,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);
 }
 \f
 /* Type Unit Groups.
@@ -9356,7 +9402,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
@@ -9452,6 +9500,7 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
 	case DW_FORM_ref_udata:
 	case DW_FORM_GNU_addr_index:
 	case DW_FORM_GNU_str_index:
+	case DW_FORM_rnglistx:
 	  info_ptr = safe_skip_leb128 (info_ptr, buffer_end);
 	  break;
 	case DW_FORM_indirect:
@@ -11996,8 +12045,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;
@@ -12034,7 +12083,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.
@@ -13068,8 +13117,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);
@@ -14730,7 +14779,7 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
       attr = dwarf2_attr (die, DW_AT_ranges, cu);
       if (attr != NULL)
 	{
-	  /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+	  /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	     We take advantage of the fact that DW_AT_ranges does not appear
 	     in DW_TAG_compile_unit of DWO files.  */
 	  int need_ranges_base = die->tag != DW_TAG_compile_unit;
@@ -14901,7 +14950,7 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block,
   attr = dwarf2_attr (die, DW_AT_ranges, cu);
   if (attr != nullptr)
     {
-      /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+      /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	 We take advantage of the fact that DW_AT_ranges does not appear
 	 in DW_TAG_compile_unit of DWO files.  */
       int need_ranges_base = die->tag != DW_TAG_compile_unit;
@@ -18481,10 +18530,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 != nullptr)
+    cu->str_offsets_base = DW_UNSND (attr);
 
+  auto maybe_addr_base = lookup_addr_base(die);
+  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;
@@ -18996,12 +19061,18 @@ 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 (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);
+      /* String and address offsets that need to do the reprocessing have
+         already been read at this point, so there is no need to wait until
+	 the loop terminates to do the reprocessing.  */
+      if (need_reprocess)
+	read_attribute_reprocess (reader, &attr_vec[i]);
+      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)
@@ -19443,12 +19514,52 @@ partial_die_info::fixup (struct dwarf2_cu *cu)
   fixup_called = 1;
 }
 
+/* Process the attributes that had to be skipped in the first round. These
+   attributes are the ones that need str_offsets_base or addr_base attributes.
+   They could not have been processed in the first round, because at the time
+   the values of str_offsets_base or addr_base may not have been known.  */
+void read_attribute_reprocess (const struct die_reader_specs *reader,
+			       struct attribute *attr)
+{
+  struct dwarf2_cu *cu = 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;
+	    }
+	  else
+	    {
+	      DW_STRING (attr) = read_stub_str_index (cu, str_index);
+	      DW_STRING_IS_CANONICAL (attr) = 0;
+	    }
+	  break;
+	}
+      default:
+	gdb_assert_not_reached (_("Unexpected DWARF form."));
+    }
+}
+
 /* 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
@@ -19459,6 +19570,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)
@@ -19591,6 +19703,7 @@ read_attribute_value (const struct die_reader_specs *reader,
       info_ptr += bytes_read;
       break;
     case DW_FORM_udata:
+    case DW_FORM_rnglistx:
       DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
       break;
@@ -19632,22 +19745,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:
@@ -19656,14 +19762,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)
@@ -19691,9 +19789,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]"),
@@ -19729,11 +19827,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.  */
@@ -20160,27 +20259,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
@@ -20213,7 +20315,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;
 };
 
@@ -20245,7 +20347,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.
@@ -20285,21 +20387,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";
@@ -20307,18 +20409,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);
@@ -20331,6 +20432,41 @@ 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);
+}
+
 /* Return the length of an LEB128 number in BUF.  */
 
 static int
diff --git a/gdb/dwarf2read.h b/gdb/dwarf2read.h
index 140bbed08a..f392200049 100644
--- a/gdb/dwarf2read.h
+++ b/gdb/dwarf2read.h
@@ -156,6 +156,7 @@ public:
   dwarf2_section_info macinfo {};
   dwarf2_section_info macro {};
   dwarf2_section_info str {};
+  dwarf2_section_info str_offsets {};
   dwarf2_section_info line_str {};
   dwarf2_section_info ranges {};
   dwarf2_section_info rnglists {};
diff --git a/gdb/symfile.h b/gdb/symfile.h
index cb5bed9d85..fc0fa77183 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -569,6 +569,7 @@ struct dwarf2_debug_sections {
   struct dwarf2_section_names macinfo;
   struct dwarf2_section_names macro;
   struct dwarf2_section_names str;
+  struct dwarf2_section_names str_offsets;
   struct dwarf2_section_names line_str;
   struct dwarf2_section_names ranges;
   struct dwarf2_section_names rnglists;
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index eaa77fd491..b736306227 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -166,6 +166,7 @@ static const struct dwarf2_debug_sections dwarf2_xcoff_names = {
   { NULL, NULL },
   { ".dwmac", NULL },
   { ".dwstr", NULL },
+  { NULL, NULL }, /* debug_str_offsets */
   { NULL, NULL }, /* debug_line_str */
   { ".dwrnges", NULL },
   { NULL, NULL }, /* debug_rnglists */
-- 
2.25.0.rc1.283.g88dfdc4193-goog

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2020-01-11  3:45                   ` Ali Tamur via gdb-patches
@ 2020-01-11 13:35                     ` Simon Marchi
  2020-01-14  3:46                       ` Ali Tamur via gdb-patches
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Marchi @ 2020-01-11 13:35 UTC (permalink / raw)
  To: Ali Tamur, gdb-patches

On 2020-01-10 10:45 p.m., Ali Tamur via gdb-patches wrote:
>> Could this be
>> cu->addr_base = lookup_addr_base (die);
> gdb.dwarf2/fission-base.exp consistently failed when I tried your suggestion,
> and now I am scared whether it is a safe change. (I don't understand the
> control flow well, but if cu->addr_base was assigned previously and
> lookup_addr_base fails, it would unassign the previous value.

Yeah, I'm not sure either.  I'm fairly confident that if, for some reason,
the field is already set, then it would set it to the same value.  After all,
stub_comp_unit_die is the stub DIE that corresponds to the DWO file we
are reading.  If for some reason, there  is already a value in cu->addr_base,
then it must come from this DIE.

If your tests pass, I think we can leave it like this, but of course that can
be changed if that proves to be wrong.

>> what is the reason we need to have two separate loops here again?
> Converted to a single loop.
> 
>> What happens if we encounter one these indirect string forms (strx and
>> company) here, but we don't enter any of the two "if" clauses above?
> I think that means an incorrect DWARF; I removed the if condition, so the
> complaint in read_stub_str_index will trigger.

Ok, that's fine with me, it will error out immediatly in that case.

The patch LGTM, but I think we are just missing a ChangeLog entry?

Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets.
  2020-01-11 13:35                     ` Simon Marchi
@ 2020-01-14  3:46                       ` Ali Tamur via gdb-patches
  0 siblings, 0 replies; 15+ messages in thread
From: Ali Tamur via gdb-patches @ 2020-01-14  3:46 UTC (permalink / raw)
  To: gdb-patches, simon.marchi; +Cc: Ali Tamur

Thanks for the review, I am submitting this shortly.

---
* Process debug_str_offsets section. Handle DW_AT_str_offsets_base attribute and
keep the value in dwarf2_cu.

* Make addr_base field in dwarf2_cu optional to disambiguate 0 value
(absent or present and 0).

* During parsing, there is no guarantee that DW_AT_str_offsets_base and
DW_AT_rnglists_base fields will be processed before the attributes that need
those values for correct computation. So make two passes, on the first one mark
the attributes that depend on *_base attributes and process only the others.
On the second pass, only process the attributes that are marked on the first
pass.

* For string attributes, differentiate between addresses that directly 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

2020-01-13  Ali Tamur <tamur@google.com>

	* dwarf2read.c (dwarf2_debug_sections): Add debug_str_offsets sections.
	(dwarf2_cu): Add str_offsets_base field.  Change the type of addr_base
        to gdb::optional.  Update comments.
	(dwo_file): Update comments.
	(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_attribute_reprocess): New function declaration.
	(read_addr_index): Likewise.
	(read_dwo_str_index): Likewise.
	(read_stub_str_index): Likewise.
	(dwarf2_per_objfile::locate_sections): Handle debug_str_offsets section.
	(lookup_addr_base): New function definition.
	(lookup_ranges_base): Likewise.
	(read_cutu_die_from_dwo): Use the new functions: lookup_addr_base,
	lookup_ranges_base.
	(init_cutu_and_read_dies): Update comments.
	(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): Reflect API changes.  Handle DW_FORM_rnglistx.
	(create_cus_hash_table): Change API to take parent compile unit.  
	Reflect API changes.
	(open_and_init_dwo_file): Reflect API changes.
	(dwarf2_get_pc_bounds): Update comments.
	(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): Likewise.
	(read_attribute_reprocess): New function definition.
	(read_attribute_value): Change API to take an additional out parameter,
        need_reprocess.  Handle DW_FORM_rnglistx.  No longer trigger 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.
	(dwarf2_read_addr_index): Likewise.
	(read_str_index): Change API and implementation.  This becomes a helper
        to be used by the new string index related methods.  Update error
	message and comments.
	(read_dwo_str_index): New function definition.
	(read_stub_str_index): Likewise.
	* dwarf2read.h (dwarf2_per_objfile): Add str_offsets field.
	* symfile.h (dwarf2_debug_sections): Likewise.
	* xcoffread.c (dwarf2_debug_sections): Likewise.
---
 gdb/dwarf2read.c | 320 +++++++++++++++++++++++++++++++++--------------
 gdb/dwarf2read.h |   1 +
 gdb/symfile.h    |   1 +
 gdb/xcoffread.c  |   1 +
 4 files changed, 231 insertions(+), 92 deletions(-)

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 216601a61a..d1b65b7bc3 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,27 +501,25 @@ public:
      There is an invariant here that is important to remember:
      Except for attributes copied from the top level DIE in the "main"
      (or "stub") file in preparation for reading the DWO file
-     (e.g., DW_AT_GNU_addr_base), we KISS: there is only *one* CU.
+     (e.g., DW_AT_addr_base), we KISS: there is only *one* CU.
      Either there isn't a DWO file (in which case this is NULL and the 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;
 
@@ -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.  */
@@ -1510,7 +1515,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 *);
 
@@ -1569,8 +1579,11 @@ 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 void set_cu_language (unsigned int, struct dwarf2_cu *);
 
@@ -2403,6 +2416,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;
@@ -7171,7 +7189,35 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
       return entry;
     }
 }
-\f
+
+/* Return the address base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_GNU_addr_base, or DW_AT_addr_base.  */
+static gdb::optional<ULONGEST>
+lookup_addr_base (struct die_info *comp_unit_die)
+{
+  struct attribute *attr;
+  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);
+}
+
+/* Return range lists base of the compile unit, which, if exists, is stored
+   either at the attribute DW_AT_rnglists_base or DW_AT_GNU_ranges_base.  */
+static ULONGEST
+lookup_ranges_base (struct die_info *comp_unit_die)
+{
+  struct attribute *attr;
+  attr = dwarf2_attr_no_follow (comp_unit_die, DW_AT_rnglists_base);
+  if (attr == nullptr)
+    attr = dwarf2_attr_no_follow (comp_unit_die, DW_AT_GNU_ranges_base);
+  if (attr == nullptr)
+    return 0;
+  return DW_UNSND (attr);
+}
+
 /* Low level DIE reading support.  */
 
 /* Initialize a die_reader_specs struct from a dwarf2_cu struct.  */
@@ -7232,7 +7278,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.  */
@@ -7263,20 +7308,12 @@ 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 != nullptr)
-	cu->addr_base = DW_UNSND (attr);
+      cu->addr_base = lookup_addr_base (stub_comp_unit_die);
 
-      /* 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 != nullptr)
-	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 (stub_comp_unit_die);
     }
   else if (stub_comp_dir != NULL)
     {
@@ -7747,9 +7784,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_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.
@@ -7761,10 +7798,14 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
 
    THIS_CU->cu is always freed when done.
    This is done in order to not leave THIS_CU->cu in a state where we have
-   to care whether it refers to the "main" CU or the DWO CU.  */
+   to care whether it refers to the "main" CU or the DWO CU.
+
+   When parent_cu is passed, it is used to provide a default value for
+   str_offsets_base and addr_base from the parent.  */
 
 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)
@@ -7803,6 +7844,11 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
 					     ? rcuh_kind::TYPE
 					     : rcuh_kind::COMPILE));
 
+  if (parent_cu != nullptr)
+    {
+      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.  */
@@ -7820,8 +7866,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.
@@ -7834,7 +7880,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);
 }
 \f
 /* Type Unit Groups.
@@ -9337,7 +9383,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
@@ -9433,6 +9481,7 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
 	case DW_FORM_ref_udata:
 	case DW_FORM_GNU_addr_index:
 	case DW_FORM_GNU_str_index:
+	case DW_FORM_rnglistx:
 	  info_ptr = safe_skip_leb128 (info_ptr, buffer_end);
 	  break;
 	case DW_FORM_indirect:
@@ -11974,8 +12023,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;
@@ -12012,7 +12061,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.
@@ -13045,8 +13094,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);
@@ -14706,7 +14755,7 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
       attr = dwarf2_attr (die, DW_AT_ranges, cu);
       if (attr != NULL)
 	{
-	  /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+	  /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	     We take advantage of the fact that DW_AT_ranges does not appear
 	     in DW_TAG_compile_unit of DWO files.  */
 	  int need_ranges_base = die->tag != DW_TAG_compile_unit;
@@ -14877,7 +14926,7 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block,
   attr = dwarf2_attr (die, DW_AT_ranges, cu);
   if (attr != nullptr)
     {
-      /* DW_AT_ranges_base does not apply to DIEs from the DWO skeleton.
+      /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
 	 We take advantage of the fact that DW_AT_ranges does not appear
 	 in DW_TAG_compile_unit of DWO files.  */
       int need_ranges_base = die->tag != DW_TAG_compile_unit;
@@ -18448,10 +18497,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 != nullptr)
+    cu->str_offsets_base = DW_UNSND (attr);
 
+  auto maybe_addr_base = lookup_addr_base(die);
+  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;
@@ -18952,12 +19017,18 @@ 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 (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);
+      /* String and address offsets that need to do the reprocessing have
+         already been read at this point, so there is no need to wait until
+	 the loop terminates to do the reprocessing.  */
+      if (need_reprocess)
+	read_attribute_reprocess (reader, &attr_vec[i]);
+      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)
@@ -19396,12 +19467,52 @@ partial_die_info::fixup (struct dwarf2_cu *cu)
   fixup_called = 1;
 }
 
+/* Process the attributes that had to be skipped in the first round. These
+   attributes are the ones that need str_offsets_base or addr_base attributes.
+   They could not have been processed in the first round, because at the time
+   the values of str_offsets_base or addr_base may not have been known.  */
+void read_attribute_reprocess (const struct die_reader_specs *reader,
+			       struct attribute *attr)
+{
+  struct dwarf2_cu *cu = 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;
+	    }
+	  else
+	    {
+	      DW_STRING (attr) = read_stub_str_index (cu, str_index);
+	      DW_STRING_IS_CANONICAL (attr) = 0;
+	    }
+	  break;
+	}
+      default:
+	gdb_assert_not_reached (_("Unexpected DWARF form."));
+    }
+}
+
 /* 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
@@ -19412,6 +19523,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)
@@ -19544,6 +19656,7 @@ read_attribute_value (const struct die_reader_specs *reader,
       info_ptr += bytes_read;
       break;
     case DW_FORM_udata:
+    case DW_FORM_rnglistx:
       DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
       break;
@@ -19585,22 +19698,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:
@@ -19609,14 +19715,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)
@@ -19644,9 +19742,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]"),
@@ -19682,11 +19780,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.  */
@@ -20113,27 +20212,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
@@ -20166,7 +20268,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;
 };
 
@@ -20198,7 +20300,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.
@@ -20238,21 +20340,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";
@@ -20260,18 +20362,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);
@@ -20284,6 +20385,41 @@ 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);
+}
+
 /* Return the length of an LEB128 number in BUF.  */
 
 static int
diff --git a/gdb/dwarf2read.h b/gdb/dwarf2read.h
index ae1f74ab67..bc8087ba40 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 5b349752d5..85f8e7c155 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -568,6 +568,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 5c6061077f..aae2e37c90 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.25.0.rc1.283.g88dfdc4193-goog

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2020-01-13 23:21 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-01 23:44 [PATCH] Dwarf 5: Handle debug_str_offsets and indexed attributes that have base offsets Ali Tamur via gdb-patches
2019-11-12 20:25 ` Ali Tamur via gdb-patches
2019-11-15  3:05 ` Simon Marchi
2019-11-19  4:46   ` Ali Tamur via gdb-patches
2019-11-19  5:27     ` Simon Marchi
2019-11-20  4:29     ` Simon Marchi
2019-12-27  0:41       ` Ali Tamur via gdb-patches
2019-12-27 23:20         ` Simon Marchi
2020-01-08  5:19           ` Ali Tamur via gdb-patches
2020-01-08 15:51             ` Simon Marchi
2020-01-09  0:57               ` Ali Tamur via gdb-patches
2020-01-10  3:46                 ` Simon Marchi
2020-01-11  3:45                   ` Ali Tamur via gdb-patches
2020-01-11 13:35                     ` Simon Marchi
2020-01-14  3:46                       ` Ali Tamur via gdb-patches

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).