gdb: Fix testsuite issue in gdb.arch/amd64-disp-step-avx.exp
[external/binutils.git] / gdb / dwarf2read.c
index 53c57ef..6100438 100644 (file)
@@ -86,9 +86,8 @@
 #include <cmath>
 #include <set>
 #include <forward_list>
-
-typedef struct symbol *symbolp;
-DEF_VEC_P (symbolp);
+#include "rust-lang.h"
+#include "common/pathstuff.h"
 
 /* When == 1, print basic high level tracing messages.
    When > 1, be more verbose.
@@ -383,7 +382,7 @@ struct tu_stats
 /* Collection of data recorded per objfile.
    This hangs off of dwarf2_objfile_data_key.  */
 
-struct dwarf2_per_objfile
+struct dwarf2_per_objfile : public allocate_on_obstack
 {
   /* Construct a dwarf2_per_objfile for OBJFILE.  NAMES points to the
      dwarf2 section names, or is NULL if the standard ELF names are
@@ -765,6 +764,14 @@ struct dwarf2_cu
      whether the DW_AT_ranges attribute came from the skeleton or DWO.  */
   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
+     variant part.  This rewriting must be done after the CU is fully
+     read in, because otherwise at the point of rewriting some struct
+     type might not have been fully processed.  So, we keep a list of
+     all such types here and process them after expansion.  */
+  std::vector<struct type *> rust_unions;
+
   /* Mark used when releasing cached dies.  */
   unsigned int mark : 1;
 
@@ -788,6 +795,8 @@ struct dwarf2_cu
      this information, but later versions do.  */
 
   unsigned int processing_has_namespace_info : 1;
+
+  struct partial_die_info *find_partial_die (sect_offset sect_off);
 };
 
 /* Persistent data held for a compilation unit, even when not
@@ -1403,16 +1412,34 @@ file_entry::include_dir (const line_header *lh) const
 
 /* When we construct a partial symbol table entry we only
    need this much information.  */
-struct partial_die_info
+struct partial_die_info : public allocate_on_obstack
   {
+    partial_die_info (sect_offset sect_off, struct abbrev_info *abbrev);
+
+    /* Disable assign but still keep copy ctor, which is needed
+       load_partial_dies.   */
+    partial_die_info& operator=(const partial_die_info& rhs) = delete;
+
+    /* Adjust the partial die before generating a symbol for it.  This
+       function may set the is_external flag or change the DIE's
+       name.  */
+    void fixup (struct dwarf2_cu *cu);
+
+    /* Read a minimal amount of information into the minimal die
+       structure.  */
+    const gdb_byte *read (const struct die_reader_specs *reader,
+                         const struct abbrev_info &abbrev,
+                         const gdb_byte *info_ptr);
+
     /* Offset of this DIE.  */
-    sect_offset sect_off;
+    const sect_offset sect_off;
 
     /* DWARF-2 tag for this DIE.  */
-    ENUM_BITFIELD(dwarf_tag) tag : 16;
+    const ENUM_BITFIELD(dwarf_tag) tag : 16;
 
     /* Assorted flags describing the data found in this DIE.  */
-    unsigned int has_children : 1;
+    const unsigned int has_children : 1;
+
     unsigned int is_external : 1;
     unsigned int is_declaration : 1;
     unsigned int has_type : 1;
@@ -1436,7 +1463,7 @@ struct partial_die_info
     /* Flag set if any of the DIE's children are template arguments.  */
     unsigned int has_template_arguments : 1;
 
-    /* Flag set if fixup_partial_die has been called on this die.  */
+    /* Flag set if fixup has been called on this die.  */
     unsigned int fixup_called : 1;
 
     /* Flag set if DW_TAG_imported_unit uses DW_FORM_GNU_ref_alt.  */
@@ -1447,15 +1474,15 @@ struct partial_die_info
 
     /* The name of this DIE.  Normally the value of DW_AT_name, but
        sometimes a default name for unnamed DIEs.  */
-    const char *name;
+    const char *name = nullptr;
 
     /* The linkage name, if present.  */
-    const char *linkage_name;
+    const char *linkage_name = nullptr;
 
     /* The scope to prepend to our children.  This is generally
        allocated on the comp_unit_obstack, so will disappear
        when this compilation unit leaves the cache.  */
-    const char *scope;
+    const char *scope = nullptr;
 
     /* Some data associated with the partial DIE.  The tag determines
        which field is live.  */
@@ -1465,26 +1492,58 @@ struct partial_die_info
       struct dwarf_block *locdesc;
       /* The offset of an import, for DW_TAG_imported_unit.  */
       sect_offset sect_off;
-    } d;
+    } d {};
 
     /* If HAS_PC_INFO, the PC range associated with this DIE.  */
-    CORE_ADDR lowpc;
-    CORE_ADDR highpc;
+    CORE_ADDR lowpc = 0;
+    CORE_ADDR highpc = 0;
 
     /* Pointer into the info_buffer (or types_buffer) pointing at the target of
        DW_AT_sibling, if any.  */
-    /* NOTE: This member isn't strictly necessary, read_partial_die could
-       return DW_AT_sibling values to its caller load_partial_dies.  */
-    const gdb_byte *sibling;
+    /* NOTE: This member isn't strictly necessary, partial_die_info::read
+       could return DW_AT_sibling values to its caller load_partial_dies.  */
+    const gdb_byte *sibling = nullptr;
 
     /* If HAS_SPECIFICATION, the offset of the DIE referred to by
        DW_AT_specification (or DW_AT_abstract_origin or
        DW_AT_extension).  */
-    sect_offset spec_offset;
+    sect_offset spec_offset {};
 
     /* Pointers to this DIE's parent, first child, and next sibling,
        if any.  */
-    struct partial_die_info *die_parent, *die_child, *die_sibling;
+    struct partial_die_info *die_parent = nullptr;
+    struct partial_die_info *die_child = nullptr;
+    struct partial_die_info *die_sibling = nullptr;
+
+    friend struct partial_die_info *
+    dwarf2_cu::find_partial_die (sect_offset sect_off);
+
+  private:
+    /* Only need to do look up in dwarf2_cu::find_partial_die.  */
+    partial_die_info (sect_offset sect_off)
+      : partial_die_info (sect_off, DW_TAG_padding, 0)
+    {
+    }
+
+    partial_die_info (sect_offset sect_off_, enum dwarf_tag tag_,
+                     int has_children_)
+      : sect_off (sect_off_), tag (tag_), has_children (has_children_)
+    {
+      is_external = 0;
+      is_declaration = 0;
+      has_type = 0;
+      has_specification = 0;
+      has_pc_info = 0;
+      may_be_inlined = 0;
+      main_subprogram = 0;
+      scope_set = 0;
+      has_byte_size = 0;
+      has_const_value = 0;
+      has_template_arguments = 0;
+      fixup_called = 0;
+      is_dwz = 0;
+      spec_is_dwz = 0;
+    }
   };
 
 /* This data structure holds the information of an abbrev.  */
@@ -1517,9 +1576,9 @@ struct abbrev_table
   explicit abbrev_table (sect_offset off)
     : sect_off (off)
   {
-    abbrevs =
+    m_abbrevs =
       XOBNEWVEC (&abbrev_obstack, struct abbrev_info *, ABBREV_HASH_SIZE);
-    memset (abbrevs, 0, ABBREV_HASH_SIZE * sizeof (struct abbrev_info *));
+    memset (m_abbrevs, 0, ABBREV_HASH_SIZE * sizeof (struct abbrev_info *));
   }
 
   DISABLE_COPY_AND_ASSIGN (abbrev_table);
@@ -1544,11 +1603,13 @@ struct abbrev_table
   /* Storage for the abbrev table.  */
   auto_obstack abbrev_obstack;
 
+private:
+
   /* Hash table of abbrevs.
      This is an array of size ABBREV_HASH_SIZE allocated in abbrev_obstack.
      It could be statically allocated, but the previous code didn't so we
      don't either.  */
-  struct abbrev_info **abbrevs;
+  struct abbrev_info **m_abbrevs;
 };
 
 typedef std::unique_ptr<struct abbrev_table> abbrev_table_up;
@@ -1645,31 +1706,36 @@ struct dwarf_block
    and friends.  */
 static int bits_per_byte = 8;
 
-struct nextfield
-{
-  struct nextfield *next;
-  int accessibility;
-  int virtuality;
-  struct field field;
-};
+/* When reading a variant or variant part, we track a bit more
+   information about the field, and store it in an object of this
+   type.  */
 
-struct nextfnfield
+struct variant_field
 {
-  struct nextfnfield *next;
-  struct fn_field fnfield;
+  /* If we see a DW_TAG_variant, then this will be the discriminant
+     value.  */
+  ULONGEST discriminant_value;
+  /* If we see a DW_TAG_variant, then this will be set if this is the
+     default branch.  */
+  bool default_branch;
+  /* While reading a DW_TAG_variant_part, this will be set if this
+     field is the discriminant.  */
+  bool is_discriminant;
 };
 
-struct fnfieldlist
+struct nextfield
 {
-  const char *name;
-  int length;
-  struct nextfnfield *head;
+  int accessibility = 0;
+  int virtuality = 0;
+  /* Extra information to describe a variant or variant part.  */
+  struct variant_field variant {};
+  struct field field {};
 };
 
-struct decl_field_list
+struct fnfieldlist
 {
-  struct decl_field field;
-  struct decl_field_list *next;
+  const char *name = nullptr;
+  std::vector<struct fn_field> fnfields;
 };
 
 /* The routines that read and process dies for a C struct or C++ class
@@ -1678,34 +1744,27 @@ struct decl_field_list
 struct field_info
   {
     /* List of data member and baseclasses fields.  */
-    struct nextfield *fields, *baseclasses;
+    std::vector<struct nextfield> fields;
+    std::vector<struct nextfield> baseclasses;
 
     /* Number of fields (including baseclasses).  */
-    int nfields;
-
-    /* Number of baseclasses.  */
-    int nbaseclasses;
+    int nfields = 0;
 
     /* Set if the accesibility of one of the fields is not public.  */
-    int non_public_fields;
+    int non_public_fields = 0;
 
     /* Member function fieldlist array, contains name of possibly overloaded
        member function, number of overloaded member functions and a pointer
        to the head of the member function field chain.  */
-    struct fnfieldlist *fnfieldlists;
-
-    /* Number of entries in the fnfieldlists array.  */
-    int nfnfields;
+    std::vector<struct fnfieldlist> fnfieldlists;
 
     /* typedefs defined inside this class.  TYPEDEF_FIELD_LIST contains head of
        a NULL terminated list of TYPEDEF_FIELD_LIST_COUNT elements.  */
-    struct decl_field_list *typedef_field_list;
-    unsigned typedef_field_list_count;
+    std::vector<struct decl_field> typedef_field_list;
 
     /* Nested types defined by this class and the number of elements in this
        list.  */
-    struct decl_field_list *nested_types_list;
-    unsigned nested_types_list_count;
+    std::vector<struct decl_field> nested_types_list;
   };
 
 /* One item on the queue of compilation units to read in full symbols
@@ -1791,18 +1850,9 @@ static unsigned int peek_abbrev_code (bfd *, const gdb_byte *);
 static struct partial_die_info *load_partial_dies
   (const struct die_reader_specs *, const gdb_byte *, int);
 
-static const gdb_byte *read_partial_die (const struct die_reader_specs *,
-                                        struct partial_die_info *,
-                                        struct abbrev_info *,
-                                        unsigned int,
-                                        const gdb_byte *);
-
 static struct partial_die_info *find_partial_die (sect_offset, int,
                                                  struct dwarf2_cu *);
 
-static void fixup_partial_die (struct partial_die_info *,
-                              struct dwarf2_cu *);
-
 static const gdb_byte *read_attribute (const struct die_reader_specs *,
                                       struct attribute *, struct attr_abbrev *,
                                       const gdb_byte *);
@@ -2186,13 +2236,48 @@ static struct type *get_die_type_at_offset (sect_offset,
 
 static struct type *get_die_type (struct die_info *die, struct dwarf2_cu *cu);
 
-static void dwarf2_release_queue (void *dummy);
-
 static void queue_comp_unit (struct dwarf2_per_cu_data *per_cu,
                             enum language pretend_language);
 
 static void process_queue (struct dwarf2_per_objfile *dwarf2_per_objfile);
 
+/* Class, the destructor of which frees all allocated queue entries.  This
+   will only have work to do if an error was thrown while processing the
+   dwarf.  If no error was thrown then the queue entries should have all
+   been processed, and freed, as we went along.  */
+
+class dwarf2_queue_guard
+{
+public:
+  dwarf2_queue_guard () = default;
+
+  /* Free any entries remaining on the queue.  There should only be
+     entries left if we hit an error while processing the dwarf.  */
+  ~dwarf2_queue_guard ()
+  {
+    struct dwarf2_queue_item *item, *last;
+
+    item = dwarf2_queue;
+    while (item)
+      {
+       /* Anything still marked queued is likely to be in an
+          inconsistent state, so discard it.  */
+       if (item->per_cu->queued)
+         {
+           if (item->per_cu->cu != NULL)
+             free_one_cached_comp_unit (item->per_cu);
+           item->per_cu->queued = 0;
+         }
+
+       last = item;
+       item = item->next;
+       xfree (last);
+      }
+
+    dwarf2_queue = dwarf2_queue_tail = NULL;
+  }
+};
+
 /* The return type of find_file_and_directory.  Note, the enclosed
    string pointers are only valid while this object is valid.  */
 
@@ -2419,6 +2504,8 @@ dwarf2_per_objfile::dwarf2_per_objfile (struct objfile *objfile_,
     locate_sections (obfd, sec, *names);
 }
 
+static void free_dwo_files (htab_t dwo_files, struct objfile *objfile);
+
 dwarf2_per_objfile::~dwarf2_per_objfile ()
 {
   /* Cached DIE trees use xmalloc and the comp_unit_obstack.  */
@@ -2430,6 +2517,27 @@ dwarf2_per_objfile::~dwarf2_per_objfile ()
   if (line_header_hash)
     htab_delete (line_header_hash);
 
+  for (int ix = 0; ix < n_comp_units; ++ix)
+   VEC_free (dwarf2_per_cu_ptr, all_comp_units[ix]->imported_symtabs);
+
+  for (int ix = 0; ix < n_type_units; ++ix)
+    VEC_free (dwarf2_per_cu_ptr,
+             all_type_units[ix]->per_cu.imported_symtabs);
+  xfree (all_type_units);
+
+  VEC_free (dwarf2_section_info_def, types);
+
+  if (dwo_files != NULL)
+    free_dwo_files (dwo_files, objfile);
+  if (dwp_file != NULL)
+    gdb_bfd_unref (dwp_file->dbfd);
+
+  if (dwz_file != NULL && dwz_file->dwz_bfd)
+    gdb_bfd_unref (dwz_file->dwz_bfd);
+
+  if (index_table != NULL)
+    index_table->~mapped_index ();
+
   /* Everything else should be on the objfile obstack.  */
 }
 
@@ -2468,10 +2576,9 @@ dwarf2_has_info (struct objfile *objfile,
   if (dwarf2_per_objfile == NULL)
     {
       /* Initialize per-objfile state.  */
-      struct dwarf2_per_objfile *data
-       = XOBNEW (&objfile->objfile_obstack, struct dwarf2_per_objfile);
-
-      dwarf2_per_objfile = new (data) struct dwarf2_per_objfile (objfile, names);
+      dwarf2_per_objfile
+       = new (&objfile->objfile_obstack) struct dwarf2_per_objfile (objfile,
+                                                                    names);
       set_dwarf2_per_objfile (objfile, dwarf2_per_objfile);
     }
   return (!dwarf2_per_objfile->info.is_virtual
@@ -3108,7 +3215,6 @@ load_cu (struct dwarf2_per_cu_data *per_cu)
 static void
 dw2_do_instantiate_symtab (struct dwarf2_per_cu_data *per_cu)
 {
-  struct cleanup *back_to;
   struct dwarf2_per_objfile *dwarf2_per_objfile = per_cu->dwarf2_per_objfile;
 
   /* Skip type_unit_groups, reading the type units they contain
@@ -3116,7 +3222,10 @@ dw2_do_instantiate_symtab (struct dwarf2_per_cu_data *per_cu)
   if (IS_TYPE_UNIT_GROUP (per_cu))
     return;
 
-  back_to = make_cleanup (dwarf2_release_queue, NULL);
+  /* The destructor of dwarf2_queue_guard frees any entries left on
+     the queue.  After this point we're guaranteed to leave this function
+     with the dwarf queue empty.  */
+  dwarf2_queue_guard q_guard;
 
   if (dwarf2_per_objfile->using_index
       ? per_cu->v.quick->compunit_symtab == NULL
@@ -3143,8 +3252,6 @@ dw2_do_instantiate_symtab (struct dwarf2_per_cu_data *per_cu)
   /* Age the cache, releasing compilation units that have not
      been used recently.  */
   age_cached_comp_units (dwarf2_per_objfile);
-
-  do_cleanups (back_to);
 }
 
 /* Ensure that the symbols for PER_CU have been read in.  OBJFILE is
@@ -3496,8 +3603,8 @@ create_addrmap_from_aranges (struct dwarf2_per_objfile *dwarf2_per_objfile,
       if (!insertpair.second)
        {
          warning (_("Section .debug_aranges in %s has duplicate "
-                    "debug_info_offset %u, ignoring .debug_aranges."),
-                  objfile_name (objfile), to_underlying (per_cu->sect_off));
+                    "debug_info_offset %s, ignoring .debug_aranges."),
+                  objfile_name (objfile), sect_offset_str (per_cu->sect_off));
          return;
        }
     }
@@ -6785,10 +6892,10 @@ error_check_comp_unit_head (struct dwarf2_per_objfile *dwarf2_per_objfile,
 
   if (to_underlying (header->abbrev_sect_off)
       >= dwarf2_section_size (dwarf2_per_objfile->objfile, abbrev_section))
-    error (_("Dwarf Error: bad offset (0x%x) in compilation unit header "
-          "(offset 0x%x + 6) [in module %s]"),
-          to_underlying (header->abbrev_sect_off),
-          to_underlying (header->sect_off),
+    error (_("Dwarf Error: bad offset (%s) in compilation unit header "
+          "(offset %s + 6) [in module %s]"),
+          sect_offset_str (header->abbrev_sect_off),
+          sect_offset_str (header->sect_off),
           filename);
 
   /* Cast to ULONGEST to use 64-bit arithmetic when possible to
@@ -6796,8 +6903,8 @@ error_check_comp_unit_head (struct dwarf2_per_objfile *dwarf2_per_objfile,
   if (((ULONGEST) header->sect_off + get_cu_length (header))
       > section->size)
     error (_("Dwarf Error: bad length (0x%x) in compilation unit header "
-          "(offset 0x%x + 0) [in module %s]"),
-          header->length, to_underlying (header->sect_off),
+          "(offset %s + 0) [in module %s]"),
+          header->length, sect_offset_str (header->sect_off),
           filename);
 }
 
@@ -7093,16 +7200,16 @@ create_debug_type_hash_table (struct dwarf2_per_objfile *dwarf2_per_objfile,
            }
 
          complaint (&symfile_complaints,
-                    _("debug type entry at offset 0x%x is duplicate to"
-                      " the entry at offset 0x%x, signature %s"),
-                    to_underlying (sect_off), to_underlying (dup_sect_off),
+                    _("debug type entry at offset %s is duplicate to"
+                      " the entry at offset %s, signature %s"),
+                    sect_offset_str (sect_off), sect_offset_str (dup_sect_off),
                     hex_string (header.signature));
        }
       *slot = dwo_file ? (void *) dwo_tu : (void *) sig_type;
 
       if (dwarf_read_debug > 1)
-       fprintf_unfiltered (gdb_stdlog, "  offset 0x%x, signature %s\n",
-                           to_underlying (sect_off),
+       fprintf_unfiltered (gdb_stdlog, "  offset %s, signature %s\n",
+                           sect_offset_str (sect_off),
                            hex_string (header.signature));
 
       info_ptr += length;
@@ -7553,10 +7660,10 @@ read_cutu_die_from_dwo (struct dwarf2_per_cu_data *this_cu,
       if (sig_type->signature != cu->header.signature)
        {
          error (_("Dwarf Error: signature mismatch %s vs %s while reading"
-                  " TU at offset 0x%x [in module %s]"),
+                  " TU at offset %s [in module %s]"),
                 hex_string (sig_type->signature),
                 hex_string (cu->header.signature),
-                to_underlying (dwo_unit->sect_off),
+                sect_offset_str (dwo_unit->sect_off),
                 bfd_get_filename (abfd));
        }
       gdb_assert (dwo_unit->sect_off == cu->header.sect_off);
@@ -7801,9 +7908,9 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
   int rereading_dwo_cu = 0;
 
   if (dwarf_die_debug)
-    fprintf_unfiltered (gdb_stdlog, "Reading %s unit at offset 0x%x\n",
+    fprintf_unfiltered (gdb_stdlog, "Reading %s unit at offset %s\n",
                        this_cu->is_debug_types ? "type" : "comp",
-                       to_underlying (this_cu->sect_off));
+                       sect_offset_str (this_cu->sect_off));
 
   if (use_existing_cu)
     gdb_assert (keep);
@@ -7937,8 +8044,9 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
        {
          complaint (&symfile_complaints,
                     _("compilation unit with DW_AT_GNU_dwo_name"
-                      " has children (offset 0x%x) [in module %s]"),
-                    to_underlying (this_cu->sect_off), bfd_get_filename (abfd));
+                      " has children (offset %s) [in module %s]"),
+                    sect_offset_str (this_cu->sect_off),
+                    bfd_get_filename (abfd));
        }
       dwo_unit = lookup_dwo_unit (this_cu, comp_unit_die);
       if (dwo_unit != NULL)
@@ -8011,9 +8119,9 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
   int has_children;
 
   if (dwarf_die_debug)
-    fprintf_unfiltered (gdb_stdlog, "Reading %s unit at offset 0x%x\n",
+    fprintf_unfiltered (gdb_stdlog, "Reading %s unit at offset %s\n",
                        this_cu->is_debug_types ? "type" : "comp",
-                       to_underlying (this_cu->sect_off));
+                       sect_offset_str (this_cu->sect_off));
 
   gdb_assert (this_cu->cu == NULL);
 
@@ -8384,10 +8492,10 @@ process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
       struct gdbarch *gdbarch = get_objfile_arch (objfile);
 
       fprintf_unfiltered (gdb_stdlog,
-                         "Psymtab for %s unit @0x%x: %s - %s"
+                         "Psymtab for %s unit @%s: %s - %s"
                          ", %d global, %d static syms\n",
                          per_cu->is_debug_types ? "type" : "comp",
-                         to_underlying (per_cu->sect_off),
+                         sect_offset_str (per_cu->sect_off),
                          paddress (gdbarch, pst->textlow),
                          paddress (gdbarch, pst->texthigh),
                          pst->n_global_syms, pst->n_static_syms);
@@ -8481,19 +8589,13 @@ struct tu_abbrev_offset
   sect_offset abbrev_offset;
 };
 
-/* Helper routine for build_type_psymtabs_1, passed to qsort.  */
+/* Helper routine for build_type_psymtabs_1, passed to std::sort.  */
 
-static int
-sort_tu_by_abbrev_offset (const void *ap, const void *bp)
+static bool
+sort_tu_by_abbrev_offset (const struct tu_abbrev_offset &a,
+                         const struct tu_abbrev_offset &b)
 {
-  const struct tu_abbrev_offset * const *a
-    = (const struct tu_abbrev_offset * const*) ap;
-  const struct tu_abbrev_offset * const *b
-    = (const struct tu_abbrev_offset * const*) bp;
-  sect_offset aoff = (*a)->abbrev_offset;
-  sect_offset boff = (*b)->abbrev_offset;
-
-  return (aoff > boff) - (aoff < boff);
+  return a.abbrev_offset < b.abbrev_offset;
 }
 
 /* Efficiently read all the type units.
@@ -8518,10 +8620,8 @@ static void
 build_type_psymtabs_1 (struct dwarf2_per_objfile *dwarf2_per_objfile)
 {
   struct tu_stats *tu_stats = &dwarf2_per_objfile->tu_stats;
-  struct cleanup *cleanups;
   abbrev_table_up abbrev_table;
   sect_offset abbrev_offset;
-  struct tu_abbrev_offset *sorted_by_abbrev;
   int i;
 
   /* It's up to the caller to not call us multiple times.  */
@@ -8554,8 +8654,8 @@ build_type_psymtabs_1 (struct dwarf2_per_objfile *dwarf2_per_objfile)
 
   /* Sort in a separate table to maintain the order of all_type_units
      for .gdb_index: TU indices directly index all_type_units.  */
-  sorted_by_abbrev = XNEWVEC (struct tu_abbrev_offset,
-                             dwarf2_per_objfile->n_type_units);
+  std::vector<struct tu_abbrev_offset> sorted_by_abbrev
+    (dwarf2_per_objfile->n_type_units);
   for (i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
     {
       struct signatured_type *sig_type = dwarf2_per_objfile->all_type_units[i];
@@ -8566,9 +8666,8 @@ build_type_psymtabs_1 (struct dwarf2_per_objfile *dwarf2_per_objfile)
                            sig_type->per_cu.section,
                            sig_type->per_cu.sect_off);
     }
-  cleanups = make_cleanup (xfree, sorted_by_abbrev);
-  qsort (sorted_by_abbrev, dwarf2_per_objfile->n_type_units,
-        sizeof (struct tu_abbrev_offset), sort_tu_by_abbrev_offset);
+  std::sort (sorted_by_abbrev.begin (), sorted_by_abbrev.end (),
+            sort_tu_by_abbrev_offset);
 
   abbrev_offset = (sect_offset) ~(unsigned) 0;
 
@@ -8591,8 +8690,6 @@ build_type_psymtabs_1 (struct dwarf2_per_objfile *dwarf2_per_objfile)
       init_cutu_and_read_dies (&tu->sig_type->per_cu, abbrev_table.get (),
                               0, 0, build_type_psymtabs_reader, NULL);
     }
-
-  do_cleanups (cleanups);
 }
 
 /* Print collected type unit statistics.  */
@@ -8986,7 +9083,7 @@ scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc,
 
   while (pdi != NULL)
     {
-      fixup_partial_die (pdi, cu);
+      pdi->fixup (cu);
 
       /* Anonymous namespaces or modules have no name but have interesting
         children, so we need to look at them.  Ditto for anonymous
@@ -9122,7 +9219,7 @@ partial_die_parent_scope (struct partial_die_info *pdi,
   if (parent->scope_set)
     return parent->scope;
 
-  fixup_partial_die (parent, cu);
+  parent->fixup (cu);
 
   grandparent_scope = partial_die_parent_scope (parent, cu);
 
@@ -9163,8 +9260,8 @@ partial_die_parent_scope (struct partial_die_info *pdi,
         function-local names?  For partial symbols, we should probably be
         ignoring them.  */
       complaint (&symfile_complaints,
-                _("unhandled containing DIE tag %d for DIE at %d"),
-                parent->tag, to_underlying (pdi->sect_off));
+                _("unhandled containing DIE tag %d for DIE at %s"),
+                parent->tag, sect_offset_str (pdi->sect_off));
       parent->scope = grandparent_scope;
     }
 
@@ -9187,7 +9284,7 @@ partial_die_full_name (struct partial_die_info *pdi,
      types here will be reused if full symbols are loaded later.  */
   if (pdi->has_template_arguments)
     {
-      fixup_partial_die (pdi, cu);
+      pdi->fixup (cu);
 
       if (pdi->name != NULL && strchr (pdi->name, '<') == NULL)
        {
@@ -9496,7 +9593,7 @@ add_partial_subprogram (struct partial_die_info *pdi,
       pdi = pdi->die_child;
       while (pdi != NULL)
        {
-         fixup_partial_die (pdi, cu);
+         pdi->fixup (cu);
          if (pdi->tag == DW_TAG_subprogram
              || pdi->tag == DW_TAG_inlined_subroutine
              || pdi->tag == DW_TAG_lexical_block)
@@ -9561,9 +9658,9 @@ peek_die_abbrev (const die_reader_specs &reader,
   if (!abbrev)
     {
       error (_("Dwarf Error: Could not find abbrev number %d in %s"
-              " at offset 0x%x [in module %s]"),
+              " at offset %s [in module %s]"),
             abbrev_number, cu->per_cu->is_debug_types ? "TU" : "CU",
-            to_underlying (cu->header.sect_off), bfd_get_filename (abfd));
+            sect_offset_str (cu->header.sect_off), bfd_get_filename (abfd));
     }
 
   return abbrev;
@@ -9900,17 +9997,17 @@ process_queue (struct dwarf2_per_objfile *dwarf2_per_objfile)
              struct signatured_type *sig_type =
                (struct signatured_type *) per_cu;
 
-             sprintf (buf, "TU %s at offset 0x%x",
+             sprintf (buf, "TU %s at offset %s",
                       hex_string (sig_type->signature),
-                      to_underlying (per_cu->sect_off));
+                      sect_offset_str (per_cu->sect_off));
              /* There can be 100s of TUs.
                 Only print them in verbose mode.  */
              debug_print_threshold = 2;
            }
          else
            {
-             sprintf (buf, "CU at offset 0x%x",
-                      to_underlying (per_cu->sect_off));
+             sprintf (buf, "CU at offset %s",
+                      sect_offset_str (per_cu->sect_off));
              debug_print_threshold = 1;
            }
 
@@ -9940,35 +10037,6 @@ process_queue (struct dwarf2_per_objfile *dwarf2_per_objfile)
     }
 }
 
-/* Free all allocated queue entries.  This function only releases anything if
-   an error was thrown; if the queue was processed then it would have been
-   freed as we went along.  */
-
-static void
-dwarf2_release_queue (void *dummy)
-{
-  struct dwarf2_queue_item *item, *last;
-
-  item = dwarf2_queue;
-  while (item)
-    {
-      /* Anything still marked queued is likely to be in an
-        inconsistent state, so discard it.  */
-      if (item->per_cu->queued)
-       {
-         if (item->per_cu->cu != NULL)
-           free_one_cached_comp_unit (item->per_cu);
-         item->per_cu->queued = 0;
-       }
-
-      last = item;
-      item = item->next;
-      xfree (last);
-    }
-
-  dwarf2_queue = dwarf2_queue_tail = NULL;
-}
-
 /* Read in full symbols for PST, and anything it depends on.  */
 
 static void
@@ -10247,6 +10315,305 @@ fixup_go_packaging (struct dwarf2_cu *cu)
     }
 }
 
+/* Allocate a fully-qualified name consisting of the two parts on the
+   obstack.  */
+
+static const char *
+rust_fully_qualify (struct obstack *obstack, const char *p1, const char *p2)
+{
+  return obconcat (obstack, p1, "::", p2, (char *) NULL);
+}
+
+/* A helper that allocates a struct discriminant_info to attach to a
+   union type.  */
+
+static struct discriminant_info *
+alloc_discriminant_info (struct type *type, int discriminant_index,
+                        int default_index)
+{
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+  gdb_assert (discriminant_index == -1
+             || (discriminant_index >= 0
+                 && discriminant_index < TYPE_NFIELDS (type)));
+  gdb_assert (default_index == -1
+             || (default_index >= 0 && default_index < TYPE_NFIELDS (type)));
+
+  TYPE_FLAG_DISCRIMINATED_UNION (type) = 1;
+
+  struct discriminant_info *disc
+    = ((struct discriminant_info *)
+       TYPE_ZALLOC (type,
+                   offsetof (struct discriminant_info, discriminants)
+                   + TYPE_NFIELDS (type) * sizeof (disc->discriminants[0])));
+  disc->default_index = default_index;
+  disc->discriminant_index = discriminant_index;
+
+  struct dynamic_prop prop;
+  prop.kind = PROP_UNDEFINED;
+  prop.data.baton = disc;
+
+  add_dyn_prop (DYN_PROP_DISCRIMINATED, prop, type);
+
+  return disc;
+}
+
+/* Some versions of rustc emitted enums in an unusual way.
+
+   Ordinary enums were emitted as unions.  The first element of each
+   structure in the union was named "RUST$ENUM$DISR".  This element
+   held the discriminant.
+
+   These versions of Rust also implemented the "non-zero"
+   optimization.  When the enum had two values, and one is empty and
+   the other holds a pointer that cannot be zero, the pointer is used
+   as the discriminant, with a zero value meaning the empty variant.
+   Here, the union's first member is of the form
+   RUST$ENCODED$ENUM$<fieldno>$<fieldno>$...$<variantname>
+   where the fieldnos are the indices of the fields that should be
+   traversed in order to find the field (which may be several fields deep)
+   and the variantname is the name of the variant of the case when the
+   field is zero.
+
+   This function recognizes whether TYPE is of one of these forms,
+   and, if so, smashes it to be a variant type.  */
+
+static void
+quirk_rust_enum (struct type *type, struct objfile *objfile)
+{
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
+
+  /* We don't need to deal with empty enums.  */
+  if (TYPE_NFIELDS (type) == 0)
+    return;
+
+#define RUST_ENUM_PREFIX "RUST$ENCODED$ENUM$"
+  if (TYPE_NFIELDS (type) == 1
+      && startswith (TYPE_FIELD_NAME (type, 0), RUST_ENUM_PREFIX))
+    {
+      const char *name = TYPE_FIELD_NAME (type, 0) + strlen (RUST_ENUM_PREFIX);
+
+      /* Decode the field name to find the offset of the
+        discriminant.  */
+      ULONGEST bit_offset = 0;
+      struct type *field_type = TYPE_FIELD_TYPE (type, 0);
+      while (name[0] >= '0' && name[0] <= '9')
+       {
+         char *tail;
+         unsigned long index = strtoul (name, &tail, 10);
+         name = tail;
+         if (*name != '$'
+             || index >= TYPE_NFIELDS (field_type)
+             || (TYPE_FIELD_LOC_KIND (field_type, index)
+                 != FIELD_LOC_KIND_BITPOS))
+           {
+             complaint (&symfile_complaints,
+                        _("Could not parse Rust enum encoding string \"%s\""
+                          "[in module %s]"),
+                        TYPE_FIELD_NAME (type, 0),
+                        objfile_name (objfile));
+             return;
+           }
+         ++name;
+
+         bit_offset += TYPE_FIELD_BITPOS (field_type, index);
+         field_type = TYPE_FIELD_TYPE (field_type, index);
+       }
+
+      /* Make a union to hold the variants.  */
+      struct type *union_type = alloc_type (objfile);
+      TYPE_CODE (union_type) = TYPE_CODE_UNION;
+      TYPE_NFIELDS (union_type) = 3;
+      TYPE_FIELDS (union_type)
+       = (struct field *) TYPE_ZALLOC (type, 3 * sizeof (struct field));
+      TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
+
+      /* Put the discriminant must at index 0.  */
+      TYPE_FIELD_TYPE (union_type, 0) = field_type;
+      TYPE_FIELD_ARTIFICIAL (union_type, 0) = 1;
+      TYPE_FIELD_NAME (union_type, 0) = "<<discriminant>>";
+      SET_FIELD_BITPOS (TYPE_FIELD (union_type, 0), bit_offset);
+
+      /* The order of fields doesn't really matter, so put the real
+        field at index 1 and the data-less field at index 2.  */
+      struct discriminant_info *disc
+       = alloc_discriminant_info (union_type, 0, 1);
+      TYPE_FIELD (union_type, 1) = TYPE_FIELD (type, 0);
+      TYPE_FIELD_NAME (union_type, 1)
+       = rust_last_path_segment (TYPE_NAME (TYPE_FIELD_TYPE (union_type, 1)));
+      TYPE_NAME (TYPE_FIELD_TYPE (union_type, 1))
+       = rust_fully_qualify (&objfile->objfile_obstack, TYPE_NAME (type),
+                             TYPE_FIELD_NAME (union_type, 1));
+
+      const char *dataless_name
+       = rust_fully_qualify (&objfile->objfile_obstack, TYPE_NAME (type),
+                             name);
+      struct type *dataless_type = init_type (objfile, TYPE_CODE_VOID, 0,
+                                             dataless_name);
+      TYPE_FIELD_TYPE (union_type, 2) = dataless_type;
+      /* NAME points into the original discriminant name, which
+        already has the correct lifetime.  */
+      TYPE_FIELD_NAME (union_type, 2) = name;
+      SET_FIELD_BITPOS (TYPE_FIELD (union_type, 2), 0);
+      disc->discriminants[2] = 0;
+
+      /* Smash this type to be a structure type.  We have to do this
+        because the type has already been recorded.  */
+      TYPE_CODE (type) = TYPE_CODE_STRUCT;
+      TYPE_NFIELDS (type) = 1;
+      TYPE_FIELDS (type)
+       = (struct field *) TYPE_ZALLOC (type, sizeof (struct field));
+
+      /* Install the variant part.  */
+      TYPE_FIELD_TYPE (type, 0) = union_type;
+      SET_FIELD_BITPOS (TYPE_FIELD (type, 0), 0);
+      TYPE_FIELD_NAME (type, 0) = "<<variants>>";
+    }
+  else if (TYPE_NFIELDS (type) == 1)
+    {
+      /* We assume that a union with a single field is a univariant
+        enum.  */
+      /* Smash this type to be a structure type.  We have to do this
+        because the type has already been recorded.  */
+      TYPE_CODE (type) = TYPE_CODE_STRUCT;
+
+      /* Make a union to hold the variants.  */
+      struct type *union_type = alloc_type (objfile);
+      TYPE_CODE (union_type) = TYPE_CODE_UNION;
+      TYPE_NFIELDS (union_type) = TYPE_NFIELDS (type);
+      TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
+      TYPE_FIELDS (union_type) = TYPE_FIELDS (type);
+
+      struct type *field_type = TYPE_FIELD_TYPE (union_type, 0);
+      const char *variant_name
+       = rust_last_path_segment (TYPE_NAME (field_type));
+      TYPE_FIELD_NAME (union_type, 0) = variant_name;
+      TYPE_NAME (field_type)
+       = rust_fully_qualify (&objfile->objfile_obstack,
+                             TYPE_NAME (type), variant_name);
+
+      /* Install the union in the outer struct type.  */
+      TYPE_NFIELDS (type) = 1;
+      TYPE_FIELDS (type)
+       = (struct field *) TYPE_ZALLOC (union_type, sizeof (struct field));
+      TYPE_FIELD_TYPE (type, 0) = union_type;
+      TYPE_FIELD_NAME (type, 0) = "<<variants>>";
+      SET_FIELD_BITPOS (TYPE_FIELD (type, 0), 0);
+
+      alloc_discriminant_info (union_type, -1, 0);
+    }
+  else
+    {
+      struct type *disr_type = nullptr;
+      for (int i = 0; i < TYPE_NFIELDS (type); ++i)
+       {
+         disr_type = TYPE_FIELD_TYPE (type, i);
+
+         if (TYPE_NFIELDS (disr_type) == 0)
+           {
+             /* Could be data-less variant, so keep going.  */
+           }
+         else if (strcmp (TYPE_FIELD_NAME (disr_type, 0),
+                          "RUST$ENUM$DISR") != 0)
+           {
+             /* Not a Rust enum.  */
+             return;
+           }
+         else
+           {
+             /* Found one.  */
+             break;
+           }
+       }
+
+      /* If we got here without a discriminant, then it's probably
+        just a union.  */
+      if (disr_type == nullptr)
+       return;
+
+      /* Smash this type to be a structure type.  We have to do this
+        because the type has already been recorded.  */
+      TYPE_CODE (type) = TYPE_CODE_STRUCT;
+
+      /* Make a union to hold the variants.  */
+      struct field *disr_field = &TYPE_FIELD (disr_type, 0);
+      struct type *union_type = alloc_type (objfile);
+      TYPE_CODE (union_type) = TYPE_CODE_UNION;
+      TYPE_NFIELDS (union_type) = 1 + TYPE_NFIELDS (type);
+      TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
+      TYPE_FIELDS (union_type)
+       = (struct field *) TYPE_ZALLOC (union_type,
+                                       (TYPE_NFIELDS (union_type)
+                                        * sizeof (struct field)));
+
+      memcpy (TYPE_FIELDS (union_type) + 1, TYPE_FIELDS (type),
+             TYPE_NFIELDS (type) * sizeof (struct field));
+
+      /* Install the discriminant at index 0 in the union.  */
+      TYPE_FIELD (union_type, 0) = *disr_field;
+      TYPE_FIELD_ARTIFICIAL (union_type, 0) = 1;
+      TYPE_FIELD_NAME (union_type, 0) = "<<discriminant>>";
+
+      /* Install the union in the outer struct type.  */
+      TYPE_FIELD_TYPE (type, 0) = union_type;
+      TYPE_FIELD_NAME (type, 0) = "<<variants>>";
+      TYPE_NFIELDS (type) = 1;
+
+      /* Set the size and offset of the union type.  */
+      SET_FIELD_BITPOS (TYPE_FIELD (type, 0), 0);
+
+      /* We need a way to find the correct discriminant given a
+        variant name.  For convenience we build a map here.  */
+      struct type *enum_type = FIELD_TYPE (*disr_field);
+      std::unordered_map<std::string, ULONGEST> discriminant_map;
+      for (int i = 0; i < TYPE_NFIELDS (enum_type); ++i)
+       {
+         if (TYPE_FIELD_LOC_KIND (enum_type, i) == FIELD_LOC_KIND_ENUMVAL)
+           {
+             const char *name
+               = rust_last_path_segment (TYPE_FIELD_NAME (enum_type, i));
+             discriminant_map[name] = TYPE_FIELD_ENUMVAL (enum_type, i);
+           }
+       }
+
+      int n_fields = TYPE_NFIELDS (union_type);
+      struct discriminant_info *disc
+       = alloc_discriminant_info (union_type, 0, -1);
+      /* Skip the discriminant here.  */
+      for (int i = 1; i < n_fields; ++i)
+       {
+         /* Find the final word in the name of this variant's type.
+            That name can be used to look up the correct
+            discriminant.  */
+         const char *variant_name
+           = rust_last_path_segment (TYPE_NAME (TYPE_FIELD_TYPE (union_type,
+                                                                 i)));
+
+         auto iter = discriminant_map.find (variant_name);
+         if (iter != discriminant_map.end ())
+           disc->discriminants[i] = iter->second;
+
+         /* Remove the discriminant field.  */
+         struct type *sub_type = TYPE_FIELD_TYPE (union_type, i);
+         --TYPE_NFIELDS (sub_type);
+         ++TYPE_FIELDS (sub_type);
+         TYPE_FIELD_NAME (union_type, i) = variant_name;
+         TYPE_NAME (sub_type)
+           = rust_fully_qualify (&objfile->objfile_obstack,
+                                 TYPE_NAME (type), variant_name);
+       }
+    }
+}
+
+/* Rewrite some Rust unions to be structures with variants parts.  */
+
+static void
+rust_union_quirks (struct dwarf2_cu *cu)
+{
+  gdb_assert (cu->language == language_rust);
+  for (struct type *type : cu->rust_unions)
+    quirk_rust_enum (type, cu->per_cu->dwarf2_per_objfile->objfile);
+}
+
 /* Return the symtab for PER_CU.  This works properly regardless of
    whether we're using the index or psymtabs.  */
 
@@ -10431,6 +10798,9 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu,
      physnames.  */
   compute_delayed_physnames (cu);
 
+  if (cu->language == language_rust)
+    rust_union_quirks (cu);
+
   /* Some compilers don't define a DW_AT_high_pc attribute for the
      compilation unit.  If the DW_AT_high_pc is missing, synthesize
      it, by scanning the DIE's below the compilation unit.  */
@@ -10533,6 +10903,9 @@ process_full_type_unit (struct dwarf2_per_cu_data *per_cu,
      physnames.  */
   compute_delayed_physnames (cu);
 
+  if (cu->language == language_rust)
+    rust_union_quirks (cu);
+
   /* TUs share symbol tables.
      If this is the first TU to use this symtab, complete the construction
      of it with end_expandable_symtab.  Otherwise, complete the addition of
@@ -11119,14 +11492,6 @@ dwarf2_physname (const char *name, struct die_info *die, struct dwarf2_cu *cu)
   gdb::unique_xmalloc_ptr<char> demangled;
   if (mangled != NULL)
     {
-      /* Use DMGL_RET_DROP for C++ template functions to suppress their return
-        type.  It is easier for GDB users to search for such functions as
-        `name(params)' than `long name(params)'.  In such case the minimal
-        symbol names do not match the full symbol names but for template
-        functions there is never a need to look up their definition from their
-        declaration so the only disadvantage remains the minimal symbol
-        variant `long name(params)' does not have the proper inferior type.
-        */
 
       if (cu->language == language_go)
        {
@@ -11136,6 +11501,14 @@ dwarf2_physname (const char *name, struct die_info *die, struct dwarf2_cu *cu)
        }
       else
        {
+         /* Use DMGL_RET_DROP for C++ template functions to suppress
+            their return type.  It is easier for GDB users to search
+            for such functions as `name(params)' than `long name(params)'.
+            In such case the minimal symbol names do not match the full
+            symbol names but for template functions there is never a need
+            to look up their definition from their declaration so
+            the only disadvantage remains the minimal symbol variant
+            `long name(params)' does not have the proper inferior type.  */
          demangled.reset (gdb_demangle (mangled,
                                         (DMGL_PARAMS | DMGL_ANSI
                                          | DMGL_RET_DROP)));
@@ -11161,8 +11534,8 @@ dwarf2_physname (const char *name, struct die_info *die, struct dwarf2_cu *cu)
 
          complaint (&symfile_complaints,
                     _("Computed physname <%s> does not match demangled <%s> "
-                      "(from linkage <%s>) - DIE at 0x%x [in module %s]"),
-                    physname, canon, mangled, to_underlying (die->sect_off),
+                      "(from linkage <%s>) - DIE at %s [in module %s]"),
+                    physname, canon, mangled, sect_offset_str (die->sect_off),
                     objfile_name (objfile));
 
          /* Prefer DW_AT_linkage_name (in the CANON form) - when it
@@ -11224,8 +11597,8 @@ read_namespace_alias (struct die_info *die, struct dwarf2_cu *cu)
       if (num == MAX_NESTED_IMPORTED_DECLARATIONS)
        {
          complaint (&symfile_complaints,
-                    _("DIE at 0x%x has too many recursively imported "
-                      "declarations"), to_underlying (d->sect_off));
+                    _("DIE at %s has too many recursively imported "
+                      "declarations"), sect_offset_str (d->sect_off));
          return 0;
        }
 
@@ -11368,8 +11741,9 @@ read_import_statement (struct die_info *die, struct dwarf2_cu *cu)
          {
            complaint (&symfile_complaints,
                       _("child DW_TAG_imported_declaration expected "
-                        "- DIE at 0x%x [in module %s]"),
-                      to_underlying (child_die->sect_off), objfile_name (objfile));
+                        "- DIE at %s [in module %s]"),
+                      sect_offset_str (child_die->sect_off),
+                      objfile_name (objfile));
            continue;
          }
 
@@ -11389,8 +11763,9 @@ read_import_statement (struct die_info *die, struct dwarf2_cu *cu)
          {
            complaint (&symfile_complaints,
                       _("child DW_TAG_imported_declaration has unknown "
-                        "imported name - DIE at 0x%x [in module %s]"),
-                      to_underlying (child_die->sect_off), objfile_name (objfile));
+                        "imported name - DIE at %s [in module %s]"),
+                      sect_offset_str (child_die->sect_off),
+                      objfile_name (objfile));
            continue;
          }
 
@@ -11932,9 +12307,9 @@ create_dwo_cu_reader (const struct die_reader_specs *reader,
   if (attr == NULL)
     {
       complaint (&symfile_complaints,
-                _("Dwarf Error: debug entry at offset 0x%x is missing"
+                _("Dwarf Error: debug entry at offset %s is missing"
                   " its dwo_id [in module %s]"),
-                to_underlying (sect_off), dwo_file->dwo_name);
+                sect_offset_str (sect_off), dwo_file->dwo_name);
       return;
     }
 
@@ -11945,8 +12320,8 @@ create_dwo_cu_reader (const struct die_reader_specs *reader,
   dwo_unit->length = cu->per_cu->length;
 
   if (dwarf_read_debug)
-    fprintf_unfiltered (gdb_stdlog, "  offset 0x%x, dwo_id %s\n",
-                       to_underlying (sect_off),
+    fprintf_unfiltered (gdb_stdlog, "  offset %s, dwo_id %s\n",
+                       sect_offset_str (sect_off),
                        hex_string (dwo_unit->signature));
 }
 
@@ -12013,9 +12388,9 @@ create_cus_hash_table (struct dwarf2_per_objfile *dwarf2_per_objfile,
          sect_offset dup_sect_off = dup_cu->sect_off;
 
          complaint (&symfile_complaints,
-                    _("debug cu entry at offset 0x%x is duplicate to"
-                      " the entry at offset 0x%x, signature %s"),
-                    to_underlying (sect_off), to_underlying (dup_sect_off),
+                    _("debug cu entry at offset %s is duplicate to"
+                      " the entry at offset %s, signature %s"),
+                    sect_offset_str (sect_off), sect_offset_str (dup_sect_off),
                     hex_string (dwo_unit->signature));
        }
       *slot = (void *)dwo_unit;
@@ -12852,36 +13227,41 @@ static gdb_bfd_ref_ptr
 try_open_dwop_file (struct dwarf2_per_objfile *dwarf2_per_objfile,
                    const char *file_name, int is_dwp, int search_cwd)
 {
-  int desc, flags;
-  char *absolute_name;
+  int desc;
   /* Blech.  OPF_TRY_CWD_FIRST also disables searching the path list if
      FILE_NAME contains a '/'.  So we can't use it.  Instead prepend "."
      to debug_file_directory.  */
-  char *search_path;
+  const char *search_path;
   static const char dirname_separator_string[] = { DIRNAME_SEPARATOR, '\0' };
 
+  gdb::unique_xmalloc_ptr<char> search_path_holder;
   if (search_cwd)
     {
       if (*debug_file_directory != '\0')
-       search_path = concat (".", dirname_separator_string,
-                             debug_file_directory, (char *) NULL);
+       {
+         search_path_holder.reset (concat (".", dirname_separator_string,
+                                           debug_file_directory,
+                                           (char *) NULL));
+         search_path = search_path_holder.get ();
+       }
       else
-       search_path = xstrdup (".");
+       search_path = ".";
     }
   else
-    search_path = xstrdup (debug_file_directory);
+    search_path = debug_file_directory;
 
-  flags = OPF_RETURN_REALPATH;
+  openp_flags flags = OPF_RETURN_REALPATH;
   if (is_dwp)
     flags |= OPF_SEARCH_IN_PATH;
+
+  gdb::unique_xmalloc_ptr<char> absolute_name;
   desc = openp (search_path, flags, file_name,
                O_RDONLY | O_BINARY, &absolute_name);
-  xfree (search_path);
   if (desc < 0)
     return NULL;
 
-  gdb_bfd_ref_ptr sym_bfd (gdb_bfd_open (absolute_name, gnutarget, desc));
-  xfree (absolute_name);
+  gdb_bfd_ref_ptr sym_bfd (gdb_bfd_open (absolute_name.get (),
+                                        gnutarget, desc));
   if (sym_bfd == NULL)
     return NULL;
   bfd_set_cacheable (sym_bfd.get (), 1);
@@ -13461,12 +13841,12 @@ lookup_dwo_cutu (struct dwarf2_per_cu_data *this_unit,
       dwp_text = string_printf (" [in DWP file %s]",
                                lbasename (dwp_file->name));
 
-    warning (_("Could not find DWO %s %s(%s)%s referenced by %s at offset 0x%x"
+    warning (_("Could not find DWO %s %s(%s)%s referenced by %s at offset %s"
               " [in module %s]"),
             kind, dwo_name, hex_string (signature),
             dwp_text.c_str (),
             this_unit->is_debug_types ? "TU" : "CU",
-            to_underlying (this_unit->sect_off), objfile_name (objfile));
+            sect_offset_str (this_unit->sect_off), objfile_name (objfile));
   }
   return NULL;
 }
@@ -13629,9 +14009,9 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
       && !(die->tag == DW_TAG_inlined_subroutine
           && origin_die->tag == DW_TAG_subprogram))
     complaint (&symfile_complaints,
-              _("DIE 0x%x and its abstract origin 0x%x have different tags"),
-              to_underlying (die->sect_off),
-              to_underlying (origin_die->sect_off));
+              _("DIE %s and its abstract origin %s have different tags"),
+              sect_offset_str (die->sect_off),
+              sect_offset_str (origin_die->sect_off));
 
   std::vector<sect_offset> offsets;
 
@@ -13676,16 +14056,16 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
              && !(child_die->tag == DW_TAG_inlined_subroutine
                   && child_origin_die->tag == DW_TAG_subprogram))
            complaint (&symfile_complaints,
-                      _("Child DIE 0x%x and its abstract origin 0x%x have "
+                      _("Child DIE %s and its abstract origin %s have "
                         "different tags"),
-                      to_underlying (child_die->sect_off),
-                      to_underlying (child_origin_die->sect_off));
+                      sect_offset_str (child_die->sect_off),
+                      sect_offset_str (child_origin_die->sect_off));
          if (child_origin_die->parent != origin_die)
            complaint (&symfile_complaints,
-                      _("Child DIE 0x%x and its abstract origin 0x%x have "
+                      _("Child DIE %s and its abstract origin %s have "
                         "different parents"),
-                      to_underlying (child_die->sect_off),
-                      to_underlying (child_origin_die->sect_off));
+                      sect_offset_str (child_die->sect_off),
+                      sect_offset_str (child_origin_die->sect_off));
          else
            offsets.push_back (child_origin_die->sect_off);
        }
@@ -13695,9 +14075,9 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
   for (offsetp = offsets.data () + 1; offsetp < offsets_end; offsetp++)
     if (offsetp[-1] == *offsetp)
       complaint (&symfile_complaints,
-                _("Multiple children of DIE 0x%x refer "
-                  "to DIE 0x%x as their abstract origin"),
-                to_underlying (die->sect_off), to_underlying (*offsetp));
+                _("Multiple children of DIE %s refer "
+                  "to DIE %s as their abstract origin"),
+                sect_offset_str (die->sect_off), sect_offset_str (*offsetp));
 
   offsetp = offsets.data ();
   origin_child_die = origin_die->child;
@@ -13762,8 +14142,8 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
   if (name == NULL)
     {
       complaint (&symfile_complaints,
-                _("missing name for subprogram DIE at %d"),
-                to_underlying (die->sect_off));
+                _("missing name for subprogram DIE at %s"),
+                sect_offset_str (die->sect_off));
       return;
     }
 
@@ -13775,8 +14155,8 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
       if (!attr || !DW_UNSND (attr))
        complaint (&symfile_complaints,
                   _("cannot get low and high bounds "
-                    "for subprogram DIE at %d"),
-                  to_underlying (die->sect_off));
+                    "for subprogram DIE at %s"),
+                  sect_offset_str (die->sect_off));
       return;
     }
 
@@ -14009,8 +14389,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
     {
       complaint (&symfile_complaints,
                 _("missing DW_AT_call_return_pc for DW_TAG_call_site "
-                  "DIE 0x%x [in module %s]"),
-                to_underlying (die->sect_off), objfile_name (objfile));
+                  "DIE %s [in module %s]"),
+                sect_offset_str (die->sect_off), objfile_name (objfile));
       return;
     }
   pc = attr_value_as_address (attr) + baseaddr;
@@ -14026,8 +14406,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
     {
       complaint (&symfile_complaints,
                 _("Duplicate PC %s for DW_TAG_call_site "
-                  "DIE 0x%x [in module %s]"),
-                paddress (gdbarch, pc), to_underlying (die->sect_off),
+                  "DIE %s [in module %s]"),
+                paddress (gdbarch, pc), sect_offset_str (die->sect_off),
                 objfile_name (objfile));
       return;
     }
@@ -14043,8 +14423,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
        {
          complaint (&symfile_complaints,
                     _("Tag %d is not DW_TAG_call_site_parameter in "
-                      "DW_TAG_call_site child DIE 0x%x [in module %s]"),
-                    child_die->tag, to_underlying (child_die->sect_off),
+                      "DW_TAG_call_site child DIE %s [in module %s]"),
+                    child_die->tag, sect_offset_str (child_die->sect_off),
                     objfile_name (objfile));
          continue;
        }
@@ -14106,8 +14486,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
          else
            complaint (&symfile_complaints,
                       _("Cannot find function owning DW_TAG_call_site "
-                        "DIE 0x%x [in module %s]"),
-                      to_underlying (die->sect_off), objfile_name (objfile));
+                        "DIE %s [in module %s]"),
+                      sect_offset_str (die->sect_off), objfile_name (objfile));
        }
     }
 
@@ -14153,8 +14533,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
          if (target_physname == NULL)
            complaint (&symfile_complaints,
                       _("DW_AT_call_target target DIE has invalid "
-                        "physname, for referencing DIE 0x%x [in module %s]"),
-                      to_underlying (die->sect_off), objfile_name (objfile));
+                        "physname, for referencing DIE %s [in module %s]"),
+                      sect_offset_str (die->sect_off), objfile_name (objfile));
          else
            SET_FIELD_PHYSNAME (call_site->target, target_physname);
        }
@@ -14167,8 +14547,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
              <= PC_BOUNDS_INVALID)
            complaint (&symfile_complaints,
                       _("DW_AT_call_target target DIE has invalid "
-                        "low pc, for referencing DIE 0x%x [in module %s]"),
-                      to_underlying (die->sect_off), objfile_name (objfile));
+                        "low pc, for referencing DIE %s [in module %s]"),
+                      sect_offset_str (die->sect_off), objfile_name (objfile));
          else
            {
              lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr);
@@ -14179,8 +14559,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
   else
     complaint (&symfile_complaints,
               _("DW_TAG_call_site DW_AT_call_target is neither "
-                "block nor reference, for DIE 0x%x [in module %s]"),
-              to_underlying (die->sect_off), objfile_name (objfile));
+                "block nor reference, for DIE %s [in module %s]"),
+              sect_offset_str (die->sect_off), objfile_name (objfile));
 
   call_site->per_cu = cu->per_cu;
 
@@ -14226,8 +14606,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
                 therefore cannot be even moved to DW_TAG_partial_unit.  */
              complaint (&symfile_complaints,
                         _("DW_AT_call_parameter offset is not in CU for "
-                          "DW_TAG_call_site child DIE 0x%x [in module %s]"),
-                        to_underlying (child_die->sect_off),
+                          "DW_TAG_call_site child DIE %s [in module %s]"),
+                        sect_offset_str (child_die->sect_off),
                         objfile_name (objfile));
              continue;
            }
@@ -14238,8 +14618,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
        {
          complaint (&symfile_complaints,
                     _("No DW_FORM_block* DW_AT_location for "
-                      "DW_TAG_call_site child DIE 0x%x [in module %s]"),
-                    to_underlying (child_die->sect_off), objfile_name (objfile));
+                      "DW_TAG_call_site child DIE %s [in module %s]"),
+                    sect_offset_str (child_die->sect_off), objfile_name (objfile));
          continue;
        }
       else
@@ -14257,9 +14637,9 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
              complaint (&symfile_complaints,
                         _("Only single DW_OP_reg or DW_OP_fbreg is supported "
                           "for DW_FORM_block* DW_AT_location is supported for "
-                          "DW_TAG_call_site child DIE 0x%x "
+                          "DW_TAG_call_site child DIE %s "
                           "[in module %s]"),
-                        to_underlying (child_die->sect_off),
+                        sect_offset_str (child_die->sect_off),
                         objfile_name (objfile));
              continue;
            }
@@ -14272,8 +14652,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
        {
          complaint (&symfile_complaints,
                     _("No DW_FORM_block* DW_AT_call_value for "
-                      "DW_TAG_call_site child DIE 0x%x [in module %s]"),
-                    to_underlying (child_die->sect_off),
+                      "DW_TAG_call_site child DIE %s [in module %s]"),
+                    sect_offset_str (child_die->sect_off),
                     objfile_name (objfile));
          continue;
        }
@@ -14293,8 +14673,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
          if (!attr_form_is_block (attr))
            complaint (&symfile_complaints,
                       _("No DW_FORM_block* DW_AT_call_data_value for "
-                        "DW_TAG_call_site child DIE 0x%x [in module %s]"),
-                      to_underlying (child_die->sect_off),
+                        "DW_TAG_call_site child DIE %s [in module %s]"),
+                      sect_offset_str (child_die->sect_off),
                       objfile_name (objfile));
          else
            {
@@ -14763,7 +15143,7 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
        return PC_BOUNDS_NOT_PRESENT;
     }
 
-  /* read_partial_die has also the strict LOW < HIGH requirement.  */
+  /* partial_die_info::read has also the strict LOW < HIGH requirement.  */
   if (high <= low)
     return PC_BOUNDS_INVALID;
 
@@ -15079,21 +15459,17 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
   struct field *fp;
   const char *fieldname = "";
 
-  /* Allocate a new field list entry and link it in.  */
-  new_field = XNEW (struct nextfield);
-  make_cleanup (xfree, new_field);
-  memset (new_field, 0, sizeof (struct nextfield));
-
   if (die->tag == DW_TAG_inheritance)
     {
-      new_field->next = fip->baseclasses;
-      fip->baseclasses = new_field;
+      fip->baseclasses.emplace_back ();
+      new_field = &fip->baseclasses.back ();
     }
   else
     {
-      new_field->next = fip->fields;
-      fip->fields = new_field;
+      fip->fields.emplace_back ();
+      new_field = &fip->fields.back ();
     }
+
   fip->nfields++;
 
   attr = dwarf2_attr (die, DW_AT_accessibility, cu);
@@ -15253,8 +15629,21 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
       FIELD_BITSIZE (*fp) = 0;
       FIELD_TYPE (*fp) = die_type (die, cu);
       FIELD_NAME (*fp) = type_name_no_tag (fp->type);
-      fip->nbaseclasses++;
     }
+  else if (die->tag == DW_TAG_variant_part)
+    {
+      /* process_structure_scope will treat this DIE as a union.  */
+      process_structure_scope (die, cu);
+
+      /* The variant part is relative to the start of the enclosing
+        structure.  */
+      SET_FIELD_BITPOS (*fp, 0);
+      fp->type = get_die_type (die, cu);
+      fp->artificial = 1;
+      fp->name = "<<variant>>";
+    }
+  else
+    gdb_assert_not_reached ("missing case in dwarf2_add_field");
 }
 
 /* Can the type given by DIE define another type?  */
@@ -15282,20 +15671,14 @@ static void
 dwarf2_add_type_defn (struct field_info *fip, struct die_info *die,
                      struct dwarf2_cu *cu)
 {
-  struct decl_field_list *new_field;
-  struct decl_field *fp;
-
-  /* Allocate a new field list entry and link it in.  */
-  new_field = XCNEW (struct decl_field_list);
-  make_cleanup (xfree, new_field);
+  struct decl_field fp;
+  memset (&fp, 0, sizeof (fp));
 
   gdb_assert (type_can_define_types (die));
 
-  fp = &new_field->field;
-
   /* Get name of field.  NULL is okay here, meaning an anonymous type.  */
-  fp->name = dwarf2_name (die, cu);
-  fp->type = read_type_die (die, cu);
+  fp.name = dwarf2_name (die, cu);
+  fp.type = read_type_die (die, cu);
 
   /* Save accessibility.  */
   enum dwarf_access_attribute accessibility;
@@ -15310,10 +15693,10 @@ dwarf2_add_type_defn (struct field_info *fip, struct die_info *die,
       /* The assumed value if neither private nor protected.  */
       break;
     case DW_ACCESS_private:
-      fp->is_private = 1;
+      fp.is_private = 1;
       break;
     case DW_ACCESS_protected:
-      fp->is_protected = 1;
+      fp.is_protected = 1;
       break;
     default:
       complaint (&symfile_complaints,
@@ -15321,17 +15704,9 @@ dwarf2_add_type_defn (struct field_info *fip, struct die_info *die,
     }
 
   if (die->tag == DW_TAG_typedef)
-    {
-      new_field->next = fip->typedef_field_list;
-      fip->typedef_field_list = new_field;
-      fip->typedef_field_list_count++;
-    }
+    fip->typedef_field_list.push_back (fp);
   else
-    {
-      new_field->next = fip->nested_types_list;
-      fip->nested_types_list = new_field;
-      fip->nested_types_list_count++;
-    }
+    fip->nested_types_list.push_back (fp);
 }
 
 /* Create the vector of fields, and attach it to the type.  */
@@ -15346,8 +15721,7 @@ dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type,
      and create blank accessibility bitfields if necessary.  */
   TYPE_NFIELDS (type) = nfields;
   TYPE_FIELDS (type) = (struct field *)
-    TYPE_ALLOC (type, sizeof (struct field) * nfields);
-  memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields);
+    TYPE_ZALLOC (type, sizeof (struct field) * nfields);
 
   if (fip->non_public_fields && cu->language != language_ada)
     {
@@ -15368,47 +15742,53 @@ dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type,
 
   /* If the type has baseclasses, allocate and clear a bit vector for
      TYPE_FIELD_VIRTUAL_BITS.  */
-  if (fip->nbaseclasses && cu->language != language_ada)
+  if (!fip->baseclasses.empty () && cu->language != language_ada)
     {
-      int num_bytes = B_BYTES (fip->nbaseclasses);
+      int num_bytes = B_BYTES (fip->baseclasses.size ());
       unsigned char *pointer;
 
       ALLOCATE_CPLUS_STRUCT_TYPE (type);
       pointer = (unsigned char *) TYPE_ALLOC (type, num_bytes);
       TYPE_FIELD_VIRTUAL_BITS (type) = pointer;
-      B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), fip->nbaseclasses);
-      TYPE_N_BASECLASSES (type) = fip->nbaseclasses;
+      B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), fip->baseclasses.size ());
+      TYPE_N_BASECLASSES (type) = fip->baseclasses.size ();
     }
 
-  /* Copy the saved-up fields into the field vector.  Start from the head of
-     the list, adding to the tail of the field array, so that they end up in
-     the same order in the array in which they were added to the list.  */
-  while (nfields-- > 0)
+  if (TYPE_FLAG_DISCRIMINATED_UNION (type))
     {
-      struct nextfield *fieldp;
+      struct discriminant_info *di = alloc_discriminant_info (type, -1, -1);
 
-      if (fip->fields)
-       {
-         fieldp = fip->fields;
-         fip->fields = fieldp->next;
-       }
-      else
+      for (int index = 0; index < nfields; ++index)
        {
-         fieldp = fip->baseclasses;
-         fip->baseclasses = fieldp->next;
+         struct nextfield &field = fip->fields[index];
+
+         if (field.variant.is_discriminant)
+           di->discriminant_index = index;
+         else if (field.variant.default_branch)
+           di->default_index = index;
+         else
+           di->discriminants[index] = field.variant.discriminant_value;
        }
+    }
 
-      TYPE_FIELD (type, nfields) = fieldp->field;
-      switch (fieldp->accessibility)
+  /* Copy the saved-up fields into the field vector.  */
+  for (int i = 0; i < nfields; ++i)
+    {
+      struct nextfield &field
+       = ((i < fip->baseclasses.size ()) ? fip->baseclasses[i]
+          : fip->fields[i - fip->baseclasses.size ()]);
+
+      TYPE_FIELD (type, i) = field.field;
+      switch (field.accessibility)
        {
        case DW_ACCESS_private:
          if (cu->language != language_ada)
-           SET_TYPE_FIELD_PRIVATE (type, nfields);
+           SET_TYPE_FIELD_PRIVATE (type, i);
          break;
 
        case DW_ACCESS_protected:
          if (cu->language != language_ada)
-           SET_TYPE_FIELD_PROTECTED (type, nfields);
+           SET_TYPE_FIELD_PROTECTED (type, i);
          break;
 
        case DW_ACCESS_public:
@@ -15418,19 +15798,19 @@ dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type,
          /* Unknown accessibility.  Complain and treat it as public.  */
          {
            complaint (&symfile_complaints, _("unsupported accessibility %d"),
-                      fieldp->accessibility);
+                      field.accessibility);
          }
          break;
        }
-      if (nfields < fip->nbaseclasses)
+      if (i < fip->baseclasses.size ())
        {
-         switch (fieldp->virtuality)
+         switch (field.virtuality)
            {
            case DW_VIRTUALITY_virtual:
            case DW_VIRTUALITY_pure_virtual:
              if (cu->language == language_ada)
                error (_("unexpected virtuality in component of Ada type"));
-             SET_TYPE_FIELD_VIRTUAL (type, nfields);
+             SET_TYPE_FIELD_VIRTUAL (type, i);
              break;
            }
        }
@@ -15473,11 +15853,10 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
 {
   struct objfile *objfile = cu->per_cu->dwarf2_per_objfile->objfile;
   struct attribute *attr;
-  struct fnfieldlist *flp;
   int i;
+  struct fnfieldlist *flp = nullptr;
   struct fn_field *fnp;
   const char *fieldname;
-  struct nextfnfield *new_fnfield;
   struct type *this_type;
   enum dwarf_access_attribute accessibility;
 
@@ -15490,51 +15869,33 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
     return;
 
   /* Look up member function name in fieldlist.  */
-  for (i = 0; i < fip->nfnfields; i++)
+  for (i = 0; i < fip->fnfieldlists.size (); i++)
     {
       if (strcmp (fip->fnfieldlists[i].name, fieldname) == 0)
-       break;
+       {
+         flp = &fip->fnfieldlists[i];
+         break;
+       }
     }
 
-  /* Create new list element if necessary.  */
-  if (i < fip->nfnfields)
-    flp = &fip->fnfieldlists[i];
-  else
+  /* Create a new fnfieldlist if necessary.  */
+  if (flp == nullptr)
     {
-      if ((fip->nfnfields % DW_FIELD_ALLOC_CHUNK) == 0)
-       {
-         fip->fnfieldlists = (struct fnfieldlist *)
-           xrealloc (fip->fnfieldlists,
-                     (fip->nfnfields + DW_FIELD_ALLOC_CHUNK)
-                     * sizeof (struct fnfieldlist));
-         if (fip->nfnfields == 0)
-           make_cleanup (free_current_contents, &fip->fnfieldlists);
-       }
-      flp = &fip->fnfieldlists[fip->nfnfields];
+      fip->fnfieldlists.emplace_back ();
+      flp = &fip->fnfieldlists.back ();
       flp->name = fieldname;
-      flp->length = 0;
-      flp->head = NULL;
-      i = fip->nfnfields++;
+      i = fip->fnfieldlists.size () - 1;
     }
 
-  /* Create a new member function field and chain it to the field list
-     entry.  */
-  new_fnfield = XNEW (struct nextfnfield);
-  make_cleanup (xfree, new_fnfield);
-  memset (new_fnfield, 0, sizeof (struct nextfnfield));
-  new_fnfield->next = flp->head;
-  flp->head = new_fnfield;
-  flp->length++;
-
-  /* Fill in the member function field info.  */
-  fnp = &new_fnfield->fnfield;
+  /* Create a new member function field and add it to the vector of
+     fnfieldlists.  */
+  flp->fnfields.emplace_back ();
+  fnp = &flp->fnfields.back ();
 
   /* Delay processing of the physname until later.  */
   if (cu->language == language_cplus)
-    {
-      add_to_method_list (type, i, flp->length - 1, fieldname,
-                         die, cu);
-    }
+    add_to_method_list (type, i, flp->fnfields.size () - 1, fieldname,
+                       die, cu);
   else
     {
       const char *physname = dwarf2_physname (fieldname, die, cu);
@@ -15639,8 +16000,8 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
                {
                  complaint (&symfile_complaints,
                             _("cannot determine context for virtual member "
-                              "function \"%s\" (offset %d)"),
-                            fieldname, to_underlying (die->sect_off));
+                              "function \"%s\" (offset %s)"),
+                            fieldname, sect_offset_str (die->sect_off));
                }
              else
                {
@@ -15666,9 +16027,9 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
        {
          /* GCC does this, as of 2008-08-25; PR debug/37237.  */
          complaint (&symfile_complaints,
-                    _("Member function \"%s\" (offset %d) is virtual "
+                    _("Member function \"%s\" (offset %s) is virtual "
                       "but the vtable offset is not specified"),
-                    fieldname, to_underlying (die->sect_off));
+                    fieldname, sect_offset_str (die->sect_off));
          ALLOCATE_CPLUS_STRUCT_TYPE (type);
          TYPE_CPLUS_DYNAMIC (type) = 1;
        }
@@ -15681,31 +16042,29 @@ static void
 dwarf2_attach_fn_fields_to_type (struct field_info *fip, struct type *type,
                                 struct dwarf2_cu *cu)
 {
-  struct fnfieldlist *flp;
-  int i;
-
   if (cu->language == language_ada)
     error (_("unexpected member functions in Ada type"));
 
   ALLOCATE_CPLUS_STRUCT_TYPE (type);
   TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
-    TYPE_ALLOC (type, sizeof (struct fn_fieldlist) * fip->nfnfields);
+    TYPE_ALLOC (type,
+               sizeof (struct fn_fieldlist) * fip->fnfieldlists.size ());
 
-  for (i = 0, flp = fip->fnfieldlists; i < fip->nfnfields; i++, flp++)
+  for (int i = 0; i < fip->fnfieldlists.size (); i++)
     {
-      struct nextfnfield *nfp = flp->head;
+      struct fnfieldlist &nf = fip->fnfieldlists[i];
       struct fn_fieldlist *fn_flp = &TYPE_FN_FIELDLIST (type, i);
-      int k;
 
-      TYPE_FN_FIELDLIST_NAME (type, i) = flp->name;
-      TYPE_FN_FIELDLIST_LENGTH (type, i) = flp->length;
+      TYPE_FN_FIELDLIST_NAME (type, i) = nf.name;
+      TYPE_FN_FIELDLIST_LENGTH (type, i) = nf.fnfields.size ();
       fn_flp->fn_fields = (struct fn_field *)
-       TYPE_ALLOC (type, sizeof (struct fn_field) * flp->length);
-      for (k = flp->length; (k--, nfp); nfp = nfp->next)
-       fn_flp->fn_fields[k] = nfp->fnfield;
+       TYPE_ALLOC (type, sizeof (struct fn_field) * nf.fnfields.size ());
+
+      for (int k = 0; k < nf.fnfields.size (); ++k)
+       fn_flp->fn_fields[k] = nf.fnfields[k];
     }
 
-  TYPE_NFN_FIELDS (type) = fip->nfnfields;
+  TYPE_NFN_FIELDS (type) = fip->fnfieldlists.size ();
 }
 
 /* Returns non-zero if NAME is the name of a vtable member in CU's
@@ -15841,6 +16200,11 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu)
     {
       TYPE_CODE (type) = TYPE_CODE_UNION;
     }
+  else if (die->tag == DW_TAG_variant_part)
+    {
+      TYPE_CODE (type) = TYPE_CODE_UNION;
+      TYPE_FLAG_DISCRIMINATED_UNION (type) = 1;
+    }
   else
     {
       TYPE_CODE (type) = TYPE_CODE_STRUCT;
@@ -15900,6 +16264,92 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu)
   return type;
 }
 
+/* A helper for process_structure_scope that handles a single member
+   DIE.  */
+
+static void
+handle_struct_member_die (struct die_info *child_die, struct type *type,
+                         struct field_info *fi,
+                         std::vector<struct symbol *> *template_args,
+                         struct dwarf2_cu *cu)
+{
+  if (child_die->tag == DW_TAG_member
+      || child_die->tag == DW_TAG_variable
+      || child_die->tag == DW_TAG_variant_part)
+    {
+      /* NOTE: carlton/2002-11-05: A C++ static data member
+        should be a DW_TAG_member that is a declaration, but
+        all versions of G++ as of this writing (so through at
+        least 3.2.1) incorrectly generate DW_TAG_variable
+        tags for them instead.  */
+      dwarf2_add_field (fi, child_die, cu);
+    }
+  else if (child_die->tag == DW_TAG_subprogram)
+    {
+      /* Rust doesn't have member functions in the C++ sense.
+        However, it does emit ordinary functions as children
+        of a struct DIE.  */
+      if (cu->language == language_rust)
+       read_func_scope (child_die, cu);
+      else
+       {
+         /* C++ member function.  */
+         dwarf2_add_member_fn (fi, child_die, type, cu);
+       }
+    }
+  else if (child_die->tag == DW_TAG_inheritance)
+    {
+      /* C++ base class field.  */
+      dwarf2_add_field (fi, child_die, cu);
+    }
+  else if (type_can_define_types (child_die))
+    dwarf2_add_type_defn (fi, child_die, cu);
+  else if (child_die->tag == DW_TAG_template_type_param
+          || child_die->tag == DW_TAG_template_value_param)
+    {
+      struct symbol *arg = new_symbol (child_die, NULL, cu);
+
+      if (arg != NULL)
+       template_args->push_back (arg);
+    }
+  else if (child_die->tag == DW_TAG_variant)
+    {
+      /* In a variant we want to get the discriminant and also add a
+        field for our sole member child.  */
+      struct attribute *discr = dwarf2_attr (child_die, DW_AT_discr_value, cu);
+
+      for (struct die_info *variant_child = child_die->child;
+          variant_child != NULL;
+          variant_child = sibling_die (variant_child))
+       {
+         if (variant_child->tag == DW_TAG_member)
+           {
+             handle_struct_member_die (variant_child, type, fi,
+                                       template_args, cu);
+             /* Only handle the one.  */
+             break;
+           }
+       }
+
+      /* We don't handle this but we might as well report it if we see
+        it.  */
+      if (dwarf2_attr (child_die, DW_AT_discr_list, cu) != nullptr)
+         complaint (&symfile_complaints,
+                    _("DW_AT_discr_list is not supported yet"
+                      " - DIE at %s [in module %s]"),
+                    sect_offset_str (child_die->sect_off),
+                    objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
+
+      /* The first field was just added, so we can stash the
+        discriminant there.  */
+      gdb_assert (!fi->fields.empty ());
+      if (discr == NULL)
+       fi->fields.back ().variant.default_branch = true;
+      else
+       fi->fields.back ().variant.discriminant_value = DW_UNSND (discr);
+    }
+}
+
 /* Finish creating a structure or union type, including filling in
    its members and creating a symbol for it.  */
 
@@ -15914,56 +16364,52 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
   if (type == NULL)
     type = read_structure_type (die, cu);
 
+  /* When reading a DW_TAG_variant_part, we need to notice when we
+     read the discriminant member, so we can record it later in the
+     discriminant_info.  */
+  bool is_variant_part = TYPE_FLAG_DISCRIMINATED_UNION (type);
+  sect_offset discr_offset;
+
+  if (is_variant_part)
+    {
+      struct attribute *discr = dwarf2_attr (die, DW_AT_discr, cu);
+      if (discr == NULL)
+       {
+         /* Maybe it's a univariant form, an extension we support.
+            In this case arrange not to check the offset.  */
+         is_variant_part = false;
+       }
+      else if (attr_form_is_ref (discr))
+       {
+         struct dwarf2_cu *target_cu = cu;
+         struct die_info *target_die = follow_die_ref (die, discr, &target_cu);
+
+         discr_offset = target_die->sect_off;
+       }
+      else
+       {
+         complaint (&symfile_complaints,
+                    _("DW_AT_discr does not have DIE reference form"
+                      " - DIE at %s [in module %s]"),
+                    sect_offset_str (die->sect_off),
+                    objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
+         is_variant_part = false;
+       }
+    }
+
   if (die->child != NULL && ! die_is_declaration (die, cu))
     {
       struct field_info fi;
       std::vector<struct symbol *> template_args;
-      struct cleanup *back_to = make_cleanup (null_cleanup, 0);
-
-      memset (&fi, 0, sizeof (struct field_info));
 
       child_die = die->child;
 
       while (child_die && child_die->tag)
        {
-         if (child_die->tag == DW_TAG_member
-             || child_die->tag == DW_TAG_variable)
-           {
-             /* NOTE: carlton/2002-11-05: A C++ static data member
-                should be a DW_TAG_member that is a declaration, but
-                all versions of G++ as of this writing (so through at
-                least 3.2.1) incorrectly generate DW_TAG_variable
-                tags for them instead.  */
-             dwarf2_add_field (&fi, child_die, cu);
-           }
-         else if (child_die->tag == DW_TAG_subprogram)
-           {
-             /* Rust doesn't have member functions in the C++ sense.
-                However, it does emit ordinary functions as children
-                of a struct DIE.  */
-             if (cu->language == language_rust)
-               read_func_scope (child_die, cu);
-             else
-               {
-                 /* C++ member function.  */
-                 dwarf2_add_member_fn (&fi, child_die, type, cu);
-               }
-           }
-         else if (child_die->tag == DW_TAG_inheritance)
-           {
-             /* C++ base class field.  */
-             dwarf2_add_field (&fi, child_die, cu);
-           }
-         else if (type_can_define_types (child_die))
-           dwarf2_add_type_defn (&fi, child_die, cu);
-         else if (child_die->tag == DW_TAG_template_type_param
-                  || child_die->tag == DW_TAG_template_value_param)
-           {
-             struct symbol *arg = new_symbol (child_die, NULL, cu);
+         handle_struct_member_die (child_die, type, &fi, &template_args, cu);
 
-             if (arg != NULL)
-               template_args.push_back (arg);
-           }
+         if (is_variant_part && discr_offset == child_die->sect_off)
+           fi.fields.back ().variant.is_discriminant = true;
 
          child_die = sibling_die (child_die);
        }
@@ -15986,7 +16432,7 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
       /* Attach fields and member functions to the type.  */
       if (fi.nfields)
        dwarf2_attach_fields_to_type (&fi, type, cu);
-      if (fi.nfnfields)
+      if (!fi.fnfieldlists.empty ())
        {
          dwarf2_attach_fn_fields_to_type (&fi, type, cu);
 
@@ -16056,56 +16502,41 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
 
       /* Copy fi.typedef_field_list linked list elements content into the
         allocated array TYPE_TYPEDEF_FIELD_ARRAY (type).  */
-      if (fi.typedef_field_list)
+      if (!fi.typedef_field_list.empty ())
        {
-         int i = fi.typedef_field_list_count;
+         int count = fi.typedef_field_list.size ();
 
          ALLOCATE_CPLUS_STRUCT_TYPE (type);
          TYPE_TYPEDEF_FIELD_ARRAY (type)
            = ((struct decl_field *)
-              TYPE_ALLOC (type, sizeof (TYPE_TYPEDEF_FIELD (type, 0)) * i));
-         TYPE_TYPEDEF_FIELD_COUNT (type) = i;
+              TYPE_ALLOC (type,
+                          sizeof (TYPE_TYPEDEF_FIELD (type, 0)) * count));
+         TYPE_TYPEDEF_FIELD_COUNT (type) = count;
 
-         /* Reverse the list order to keep the debug info elements order.  */
-         while (--i >= 0)
-           {
-             struct decl_field *dest, *src;
-
-             dest = &TYPE_TYPEDEF_FIELD (type, i);
-             src = &fi.typedef_field_list->field;
-             fi.typedef_field_list = fi.typedef_field_list->next;
-             *dest = *src;
-           }
+         for (int i = 0; i < fi.typedef_field_list.size (); ++i)
+           TYPE_TYPEDEF_FIELD (type, i) = fi.typedef_field_list[i];
        }
 
       /* Copy fi.nested_types_list linked list elements content into the
         allocated array TYPE_NESTED_TYPES_ARRAY (type).  */
-      if (fi.nested_types_list != NULL && cu->language != language_ada)
+      if (!fi.nested_types_list.empty () && cu->language != language_ada)
        {
-         int i = fi.nested_types_list_count;
+         int count = fi.nested_types_list.size ();
 
          ALLOCATE_CPLUS_STRUCT_TYPE (type);
          TYPE_NESTED_TYPES_ARRAY (type)
            = ((struct decl_field *)
-              TYPE_ALLOC (type, sizeof (struct decl_field) * i));
-         TYPE_NESTED_TYPES_COUNT (type) = i;
-
-         /* Reverse the list order to keep the debug info elements order.  */
-         while (--i >= 0)
-           {
-             struct decl_field *dest, *src;
+              TYPE_ALLOC (type, sizeof (struct decl_field) * count));
+         TYPE_NESTED_TYPES_COUNT (type) = count;
 
-             dest = &TYPE_NESTED_TYPES_FIELD (type, i);
-             src = &fi.nested_types_list->field;
-             fi.nested_types_list = fi.nested_types_list->next;
-             *dest = *src;
-           }
+         for (int i = 0; i < fi.nested_types_list.size (); ++i)
+           TYPE_NESTED_TYPES_FIELD (type, i) = fi.nested_types_list[i];
        }
-
-      do_cleanups (back_to);
     }
 
   quirk_gcc_member_function_pointer (type, objfile);
+  if (cu->language == language_rust && die->tag == DW_TAG_union_type)
+    cu->rust_unions.push_back (type);
 
   /* NOTE: carlton/2004-03-16: GCC 3.4 (or at least one of its
      snapshots) has been known to create a die giving a declaration
@@ -16406,8 +16837,8 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
        {
          complaint (&symfile_complaints,
                     _("unable to read array DW_AT_byte_stride "
-                      " - DIE at 0x%x [in module %s]"),
-                    to_underlying (die->sect_off),
+                      " - DIE at %s [in module %s]"),
+                    sect_offset_str (die->sect_off),
                     objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
          /* Ignore this attribute.  We will likely not be able to print
             arrays of this type correctly, but there is little we can do
@@ -16715,8 +17146,8 @@ read_common_block (struct die_info *die, struct dwarf2_cu *cu)
                  complaint (&symfile_complaints,
                             _("Variable in common block has "
                               "DW_AT_data_member_location "
-                              "- DIE at 0x%x [in module %s]"),
-                            to_underlying (child_die->sect_off),
+                              "- DIE at %s [in module %s]"),
+                              sect_offset_str (child_die->sect_off),
                             objfile_name (objfile));
 
                  if (attr_form_is_section_offset (member_loc))
@@ -16836,8 +17267,8 @@ read_module_type (struct die_info *die, struct dwarf2_cu *cu)
   module_name = dwarf2_name (die, cu);
   if (!module_name)
     complaint (&symfile_complaints,
-              _("DW_TAG_module has no name, offset 0x%x"),
-               to_underlying (die->sect_off));
+              _("DW_TAG_module has no name, offset %s"),
+               sect_offset_str (die->sect_off));
   type = init_type (objfile, TYPE_CODE_MODULE, 0, module_name);
 
   /* determine_prefix uses TYPE_TAG_NAME.  */
@@ -17381,8 +17812,8 @@ read_typedef (struct die_info *die, struct dwarf2_cu *cu)
         spec and cause infinite loops in GDB.  */
       complaint (&symfile_complaints,
                 _("Self-referential DW_TAG_typedef "
-                  "- DIE at 0x%x [in module %s]"),
-                to_underlying (die->sect_off), objfile_name (objfile));
+                  "- DIE at %s [in module %s]"),
+                sect_offset_str (die->sect_off), objfile_name (objfile));
       TYPE_TARGET_TYPE (this_type) = NULL;
     }
   return this_type;
@@ -17688,8 +18119,8 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
     attr_to_dynamic_prop (attr, die, cu, &low);
   else if (!low_default_is_valid)
     complaint (&symfile_complaints, _("Missing DW_AT_lower_bound "
-                                     "- DIE at 0x%x [in module %s]"),
-              to_underlying (die->sect_off),
+                                     "- DIE at %s [in module %s]"),
+              sect_offset_str (die->sect_off),
               objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
 
   attr = dwarf2_attr (die, DW_AT_upper_bound, cu);
@@ -18014,8 +18445,8 @@ abbrev_table::add_abbrev (unsigned int abbrev_number,
   unsigned int hash_number;
 
   hash_number = abbrev_number % ABBREV_HASH_SIZE;
-  abbrev->next = abbrevs[hash_number];
-  abbrevs[hash_number] = abbrev;
+  abbrev->next = m_abbrevs[hash_number];
+  m_abbrevs[hash_number] = abbrev;
 }
 
 /* Look up an abbrev in the table.
@@ -18028,7 +18459,7 @@ abbrev_table::lookup_abbrev (unsigned int abbrev_number)
   struct abbrev_info *abbrev;
 
   hash_number = abbrev_number % ABBREV_HASH_SIZE;
-  abbrev = abbrevs[hash_number];
+  abbrev = m_abbrevs[hash_number];
 
   while (abbrev)
     {
@@ -18184,7 +18615,6 @@ load_partial_dies (const struct die_reader_specs *reader,
 {
   struct dwarf2_cu *cu = reader->cu;
   struct objfile *objfile = cu->per_cu->dwarf2_per_objfile->objfile;
-  struct partial_die_info *part_die;
   struct partial_die_info *parent_die, *last_die, *first_die = NULL;
   unsigned int bytes_read;
   unsigned int load_all = 0;
@@ -18206,8 +18636,6 @@ load_partial_dies (const struct die_reader_specs *reader,
                            hashtab_obstack_allocate,
                            dummy_obstack_deallocate);
 
-  part_die = XOBNEW (&cu->comp_unit_obstack, struct partial_die_info);
-
   while (1)
     {
       abbrev_info *abbrev = peek_die_abbrev (*reader, info_ptr, &bytes_read);
@@ -18216,15 +18644,8 @@ load_partial_dies (const struct die_reader_specs *reader,
       if (abbrev == NULL)
        {
          if (--nesting_level == 0)
-           {
-             /* PART_DIE was probably the last thing allocated on the
-                comp_unit_obstack, so we could call obstack_free
-                here.  We don't do that because the waste is small,
-                and will be cleaned up when we're done with this
-                compilation unit.  This way, we're also more robust
-                against other users of the comp_unit_obstack.  */
-             return first_die;
-           }
+           return first_die;
+
          info_ptr += bytes_read;
          last_die = parent_die;
          parent_die = parent_die->die_parent;
@@ -18282,8 +18703,10 @@ load_partial_dies (const struct die_reader_specs *reader,
          continue;
        }
 
-      info_ptr = read_partial_die (reader, part_die, abbrev, bytes_read,
-                                  info_ptr);
+      struct partial_die_info pdi ((sect_offset) (info_ptr - reader->buffer),
+                                  abbrev);
+
+      info_ptr = pdi.read (reader, *abbrev, info_ptr + bytes_read);
 
       /* This two-pass algorithm for processing partial symbols has a
         high cost in cache pressure.  Thus, handle some simple cases
@@ -18302,18 +18725,18 @@ load_partial_dies (const struct die_reader_specs *reader,
         of them, for a language without namespaces), can be processed
         directly.  */
       if (parent_die == NULL
-         && part_die->has_specification == 0
-         && part_die->is_declaration == 0
-         && ((part_die->tag == DW_TAG_typedef && !part_die->has_children)
-             || part_die->tag == DW_TAG_base_type
-             || part_die->tag == DW_TAG_subrange_type))
-       {
-         if (building_psymtab && part_die->name != NULL)
-           add_psymbol_to_list (part_die->name, strlen (part_die->name), 0,
+         && pdi.has_specification == 0
+         && pdi.is_declaration == 0
+         && ((pdi.tag == DW_TAG_typedef && !pdi.has_children)
+             || pdi.tag == DW_TAG_base_type
+             || pdi.tag == DW_TAG_subrange_type))
+       {
+         if (building_psymtab && pdi.name != NULL)
+           add_psymbol_to_list (pdi.name, strlen (pdi.name), 0,
                                 VAR_DOMAIN, LOC_TYPEDEF,
                                 &objfile->static_psymbols,
                                 0, cu->language, objfile);
-         info_ptr = locate_pdi_sibling (reader, part_die, info_ptr);
+         info_ptr = locate_pdi_sibling (reader, &pdi, info_ptr);
          continue;
        }
 
@@ -18325,37 +18748,40 @@ load_partial_dies (const struct die_reader_specs *reader,
         it could not find the child DIEs referenced later, this is checked
         above.  In correct DWARF DW_TAG_typedef should have no children.  */
 
-      if (part_die->tag == DW_TAG_typedef && part_die->has_children)
+      if (pdi.tag == DW_TAG_typedef && pdi.has_children)
        complaint (&symfile_complaints,
                   _("DW_TAG_typedef has childen - GCC PR debug/47510 bug "
-                    "- DIE at 0x%x [in module %s]"),
-                  to_underlying (part_die->sect_off), objfile_name (objfile));
+                    "- DIE at %s [in module %s]"),
+                  sect_offset_str (pdi.sect_off), objfile_name (objfile));
 
       /* If we're at the second level, and we're an enumerator, and
         our parent has no specification (meaning possibly lives in a
         namespace elsewhere), then we can add the partial symbol now
         instead of queueing it.  */
-      if (part_die->tag == DW_TAG_enumerator
+      if (pdi.tag == DW_TAG_enumerator
          && parent_die != NULL
          && parent_die->die_parent == NULL
          && parent_die->tag == DW_TAG_enumeration_type
          && parent_die->has_specification == 0)
        {
-         if (part_die->name == NULL)
+         if (pdi.name == NULL)
            complaint (&symfile_complaints,
                       _("malformed enumerator DIE ignored"));
          else if (building_psymtab)
-           add_psymbol_to_list (part_die->name, strlen (part_die->name), 0,
+           add_psymbol_to_list (pdi.name, strlen (pdi.name), 0,
                                 VAR_DOMAIN, LOC_CONST,
                                 cu->language == language_cplus
                                 ? &objfile->global_psymbols
                                 : &objfile->static_psymbols,
                                 0, cu->language, objfile);
 
-         info_ptr = locate_pdi_sibling (reader, part_die, info_ptr);
+         info_ptr = locate_pdi_sibling (reader, &pdi, info_ptr);
          continue;
        }
 
+      struct partial_die_info *part_die
+       = new (&cu->comp_unit_obstack) partial_die_info (pdi);
+
       /* We'll save this DIE so link it in.  */
       part_die->die_parent = parent_die;
       part_die->die_sibling = NULL;
@@ -18407,8 +18833,6 @@ load_partial_dies (const struct die_reader_specs *reader,
          *slot = part_die;
        }
 
-      part_die = XOBNEW (&cu->comp_unit_obstack, struct partial_die_info);
-
       /* For some DIEs we want to follow their children (if any).  For C
         we have no reason to follow the children of structures; for other
         languages we have to, so that we can get at method physnames
@@ -18451,47 +18875,39 @@ load_partial_dies (const struct die_reader_specs *reader,
     }
 }
 
-/* Read a minimal amount of information into the minimal die structure.  */
+partial_die_info::partial_die_info (sect_offset sect_off_,
+                                   struct abbrev_info *abbrev)
+  : partial_die_info (sect_off_, abbrev->tag, abbrev->has_children)
+{
+}
 
-static const gdb_byte *
-read_partial_die (const struct die_reader_specs *reader,
-                 struct partial_die_info *part_die,
-                 struct abbrev_info *abbrev, unsigned int abbrev_len,
-                 const gdb_byte *info_ptr)
+/* Read a minimal amount of information into the minimal die structure.
+   INFO_PTR should point just after the initial uleb128 of a DIE.  */
+
+const gdb_byte *
+partial_die_info::read (const struct die_reader_specs *reader,
+                       const struct abbrev_info &abbrev, const gdb_byte *info_ptr)
 {
   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 gdb_byte *buffer = reader->buffer;
   unsigned int i;
-  struct attribute attr;
   int has_low_pc_attr = 0;
   int has_high_pc_attr = 0;
   int high_pc_relative = 0;
 
-  memset (part_die, 0, sizeof (struct partial_die_info));
-
-  part_die->sect_off = (sect_offset) (info_ptr - buffer);
-
-  info_ptr += abbrev_len;
-
-  if (abbrev == NULL)
-    return info_ptr;
-
-  part_die->tag = abbrev->tag;
-  part_die->has_children = abbrev->has_children;
-
-  for (i = 0; i < abbrev->num_attrs; ++i)
+  for (i = 0; i < abbrev.num_attrs; ++i)
     {
-      info_ptr = read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr);
+      struct attribute attr;
+
+      info_ptr = read_attribute (reader, &attr, &abbrev.attrs[i], info_ptr);
 
       /* Store the data if it is of an attribute we want to keep in a
          partial symbol table.  */
       switch (attr.name)
        {
        case DW_AT_name:
-         switch (part_die->tag)
+         switch (tag)
            {
            case DW_TAG_compile_unit:
            case DW_TAG_partial_unit:
@@ -18502,12 +18918,16 @@ read_partial_die (const struct die_reader_specs *reader,
            case DW_TAG_enumerator:
              /* These tags always have simple identifiers already; no need
                 to canonicalize them.  */
-             part_die->name = DW_STRING (&attr);
+             name = DW_STRING (&attr);
              break;
            default:
-             part_die->name
-               = dwarf2_canonicalize_name (DW_STRING (&attr), cu,
-                                           &objfile->per_bfd->storage_obstack);
+             {
+               struct objfile *objfile = dwarf2_per_objfile->objfile;
+
+               name
+                 = dwarf2_canonicalize_name (DW_STRING (&attr), cu,
+                                             &objfile->per_bfd->storage_obstack);
+             }
              break;
            }
          break;
@@ -18517,16 +18937,16 @@ read_partial_die (const struct die_reader_specs *reader,
             assume they will be the same, and we only store the last
             one we see.  */
          if (cu->language == language_ada)
-           part_die->name = DW_STRING (&attr);
-         part_die->linkage_name = DW_STRING (&attr);
+           name = DW_STRING (&attr);
+         linkage_name = DW_STRING (&attr);
          break;
        case DW_AT_low_pc:
          has_low_pc_attr = 1;
-         part_die->lowpc = attr_value_as_address (&attr);
+         lowpc = attr_value_as_address (&attr);
          break;
        case DW_AT_high_pc:
          has_high_pc_attr = 1;
-         part_die->highpc = attr_value_as_address (&attr);
+         highpc = attr_value_as_address (&attr);
          if (cu->header.version >= 4 && attr_form_is_constant (&attr))
                high_pc_relative = 1;
          break;
@@ -18534,7 +18954,7 @@ read_partial_die (const struct die_reader_specs *reader,
           /* Support the .debug_loc offsets.  */
           if (attr_form_is_block (&attr))
             {
-              part_die->d.locdesc = DW_BLOCK (&attr);
+              d.locdesc = DW_BLOCK (&attr);
             }
           else if (attr_form_is_section_offset (&attr))
             {
@@ -18547,20 +18967,20 @@ read_partial_die (const struct die_reader_specs *reader,
             }
          break;
        case DW_AT_external:
-         part_die->is_external = DW_UNSND (&attr);
+         is_external = DW_UNSND (&attr);
          break;
        case DW_AT_declaration:
-         part_die->is_declaration = DW_UNSND (&attr);
+         is_declaration = DW_UNSND (&attr);
          break;
        case DW_AT_type:
-         part_die->has_type = 1;
+         has_type = 1;
          break;
        case DW_AT_abstract_origin:
        case DW_AT_specification:
        case DW_AT_extension:
-         part_die->has_specification = 1;
-         part_die->spec_offset = dwarf2_get_ref_die_offset (&attr);
-         part_die->spec_is_dwz = (attr.form == DW_FORM_GNU_ref_alt
+         has_specification = 1;
+         spec_offset = dwarf2_get_ref_die_offset (&attr);
+         spec_is_dwz = (attr.form == DW_FORM_GNU_ref_alt
                                   || cu->per_cu->is_dwz);
          break;
        case DW_AT_sibling:
@@ -18571,6 +18991,7 @@ read_partial_die (const struct die_reader_specs *reader,
                       _("ignoring absolute DW_AT_sibling"));
          else
            {
+             const gdb_byte *buffer = reader->buffer;
              sect_offset off = dwarf2_get_ref_die_offset (&attr);
              const gdb_byte *sibling_ptr = buffer + to_underlying (off);
 
@@ -18580,14 +19001,14 @@ read_partial_die (const struct die_reader_specs *reader,
              else if (sibling_ptr > reader->buffer_end)
                dwarf2_section_buffer_overflow_complaint (reader->die_section);
              else
-               part_die->sibling = sibling_ptr;
+               sibling = sibling_ptr;
            }
          break;
         case DW_AT_byte_size:
-          part_die->has_byte_size = 1;
+          has_byte_size = 1;
           break;
         case DW_AT_const_value:
-          part_die->has_const_value = 1;
+          has_const_value = 1;
           break;
        case DW_AT_calling_convention:
          /* DWARF doesn't provide a way to identify a program's source-level
@@ -18606,25 +19027,25 @@ read_partial_die (const struct die_reader_specs *reader,
             compatibility.  */
          if (DW_UNSND (&attr) == DW_CC_program
              && cu->language == language_fortran)
-           part_die->main_subprogram = 1;
+           main_subprogram = 1;
          break;
        case DW_AT_inline:
          if (DW_UNSND (&attr) == DW_INL_inlined
              || DW_UNSND (&attr) == DW_INL_declared_inlined)
-           part_die->may_be_inlined = 1;
+           may_be_inlined = 1;
          break;
 
        case DW_AT_import:
-         if (part_die->tag == DW_TAG_imported_unit)
+         if (tag == DW_TAG_imported_unit)
            {
-             part_die->d.sect_off = dwarf2_get_ref_die_offset (&attr);
-             part_die->is_dwz = (attr.form == DW_FORM_GNU_ref_alt
+             d.sect_off = dwarf2_get_ref_die_offset (&attr);
+             is_dwz = (attr.form == DW_FORM_GNU_ref_alt
                                  || cu->per_cu->is_dwz);
            }
          break;
 
        case DW_AT_main_subprogram:
-         part_die->main_subprogram = DW_UNSND (&attr);
+         main_subprogram = DW_UNSND (&attr);
          break;
 
        default:
@@ -18633,7 +19054,7 @@ read_partial_die (const struct die_reader_specs *reader,
     }
 
   if (high_pc_relative)
-    part_die->highpc += part_die->lowpc;
+    highpc += lowpc;
 
   if (has_low_pc_attr && has_high_pc_attr)
     {
@@ -18645,31 +19066,34 @@ read_partial_die (const struct die_reader_specs *reader,
         labels are not in the output, so the relocs get a value of 0.
         If this is a discarded function, mark the pc bounds as invalid,
         so that GDB will ignore it.  */
-      if (part_die->lowpc == 0 && !dwarf2_per_objfile->has_section_at_zero)
+      if (lowpc == 0 && !dwarf2_per_objfile->has_section_at_zero)
        {
+         struct objfile *objfile = dwarf2_per_objfile->objfile;
          struct gdbarch *gdbarch = get_objfile_arch (objfile);
 
          complaint (&symfile_complaints,
                     _("DW_AT_low_pc %s is zero "
-                      "for DIE at 0x%x [in module %s]"),
-                    paddress (gdbarch, part_die->lowpc),
-                    to_underlying (part_die->sect_off), objfile_name (objfile));
+                      "for DIE at %s [in module %s]"),
+                    paddress (gdbarch, lowpc),
+                    sect_offset_str (sect_off),
+                    objfile_name (objfile));
        }
       /* dwarf2_get_pc_bounds has also the strict low < high requirement.  */
-      else if (part_die->lowpc >= part_die->highpc)
+      else if (lowpc >= highpc)
        {
+         struct objfile *objfile = dwarf2_per_objfile->objfile;
          struct gdbarch *gdbarch = get_objfile_arch (objfile);
 
          complaint (&symfile_complaints,
                     _("DW_AT_low_pc %s is not < DW_AT_high_pc %s "
-                      "for DIE at 0x%x [in module %s]"),
-                    paddress (gdbarch, part_die->lowpc),
-                    paddress (gdbarch, part_die->highpc),
-                    to_underlying (part_die->sect_off),
+                      "for DIE at %s [in module %s]"),
+                    paddress (gdbarch, lowpc),
+                    paddress (gdbarch, highpc),
+                    sect_offset_str (sect_off),
                     objfile_name (objfile));
        }
       else
-       part_die->has_pc_info = 1;
+       has_pc_info = 1;
     }
 
   return info_ptr;
@@ -18677,15 +19101,14 @@ read_partial_die (const struct die_reader_specs *reader,
 
 /* Find a cached partial DIE at OFFSET in CU.  */
 
-static struct partial_die_info *
-find_partial_die_in_comp_unit (sect_offset sect_off, struct dwarf2_cu *cu)
+struct partial_die_info *
+dwarf2_cu::find_partial_die (sect_offset sect_off)
 {
   struct partial_die_info *lookup_die = NULL;
-  struct partial_die_info part_die;
+  struct partial_die_info part_die (sect_off);
 
-  part_die.sect_off = sect_off;
   lookup_die = ((struct partial_die_info *)
-               htab_find_with_hash (cu->partial_dies, &part_die,
+               htab_find_with_hash (partial_dies, &part_die,
                                     to_underlying (sect_off)));
 
   return lookup_die;
@@ -18708,7 +19131,7 @@ find_partial_die (sect_offset sect_off, int offset_in_dwz, struct dwarf2_cu *cu)
   if (offset_in_dwz == cu->per_cu->is_dwz
       && offset_in_cu_p (&cu->header, sect_off))
     {
-      pd = find_partial_die_in_comp_unit (sect_off, cu);
+      pd = cu->find_partial_die (sect_off);
       if (pd != NULL)
        return pd;
       /* We missed recording what we needed.
@@ -18720,9 +19143,9 @@ find_partial_die (sect_offset sect_off, int offset_in_dwz, struct dwarf2_cu *cu)
       /* TUs don't reference other CUs/TUs (except via type signatures).  */
       if (cu->per_cu->is_debug_types)
        {
-         error (_("Dwarf Error: Type Unit at offset 0x%x contains"
-                  " external reference to offset 0x%x [in module %s].\n"),
-                to_underlying (cu->header.sect_off), to_underlying (sect_off),
+         error (_("Dwarf Error: Type Unit at offset %s contains"
+                  " external reference to offset %s [in module %s].\n"),
+                sect_offset_str (cu->header.sect_off), sect_offset_str (sect_off),
                 bfd_get_filename (objfile->obfd));
        }
       per_cu = dwarf2_find_containing_comp_unit (sect_off, offset_in_dwz,
@@ -18732,7 +19155,7 @@ find_partial_die (sect_offset sect_off, int offset_in_dwz, struct dwarf2_cu *cu)
        load_partial_comp_unit (per_cu);
 
       per_cu->cu->last_used = 0;
-      pd = find_partial_die_in_comp_unit (sect_off, per_cu->cu);
+      pd = per_cu->cu->find_partial_die (sect_off);
     }
 
   /* If we didn't find it, and not all dies have been loaded,
@@ -18750,14 +19173,14 @@ find_partial_die (sect_offset sect_off, int offset_in_dwz, struct dwarf2_cu *cu)
         set.  */
       load_partial_comp_unit (per_cu);
 
-      pd = find_partial_die_in_comp_unit (sect_off, per_cu->cu);
+      pd = per_cu->cu->find_partial_die (sect_off);
     }
 
   if (pd == NULL)
     internal_error (__FILE__, __LINE__,
-                   _("could not find partial DIE 0x%x "
+                   _("could not find partial DIE %s "
                      "in cache [from module %s]\n"),
-                   to_underlying (sect_off), bfd_get_filename (objfile->obfd));
+                   sect_offset_str (sect_off), bfd_get_filename (objfile->obfd));
   return pd;
 }
 
@@ -18815,45 +19238,40 @@ guess_partial_die_structure_name (struct partial_die_info *struct_pdi,
     }
 }
 
-/* Adjust PART_DIE before generating a symbol for it.  This function
-   may set the is_external flag or change the DIE's name.  */
-
-static void
-fixup_partial_die (struct partial_die_info *part_die,
-                  struct dwarf2_cu *cu)
+void
+partial_die_info::fixup (struct dwarf2_cu *cu)
 {
   /* Once we've fixed up a die, there's no point in doing so again.
      This also avoids a memory leak if we were to call
      guess_partial_die_structure_name multiple times.  */
-  if (part_die->fixup_called)
+  if (fixup_called)
     return;
 
   /* If we found a reference attribute and the DIE has no name, try
      to find a name in the referred to DIE.  */
 
-  if (part_die->name == NULL && part_die->has_specification)
+  if (name == NULL && has_specification)
     {
       struct partial_die_info *spec_die;
 
-      spec_die = find_partial_die (part_die->spec_offset,
-                                  part_die->spec_is_dwz, cu);
+      spec_die = find_partial_die (spec_offset, spec_is_dwz, cu);
 
-      fixup_partial_die (spec_die, cu);
+      spec_die->fixup (cu);
 
       if (spec_die->name)
        {
-         part_die->name = spec_die->name;
+         name = spec_die->name;
 
          /* Copy DW_AT_external attribute if it is set.  */
          if (spec_die->is_external)
-           part_die->is_external = spec_die->is_external;
+           is_external = spec_die->is_external;
        }
     }
 
   /* Set default names for some unnamed DIEs.  */
 
-  if (part_die->name == NULL && part_die->tag == DW_TAG_namespace)
-    part_die->name = CP_ANONYMOUS_NAMESPACE_STR;
+  if (name == NULL && tag == DW_TAG_namespace)
+    name = CP_ANONYMOUS_NAMESPACE_STR;
 
   /* If there is no parent die to provide a namespace, and there are
      children, see if we can determine the namespace from their linkage
@@ -18861,25 +19279,25 @@ fixup_partial_die (struct partial_die_info *part_die,
   if (cu->language == language_cplus
       && !VEC_empty (dwarf2_section_info_def,
                     cu->per_cu->dwarf2_per_objfile->types)
-      && part_die->die_parent == NULL
-      && part_die->has_children
-      && (part_die->tag == DW_TAG_class_type
-         || part_die->tag == DW_TAG_structure_type
-         || part_die->tag == DW_TAG_union_type))
-    guess_partial_die_structure_name (part_die, cu);
+      && die_parent == NULL
+      && has_children
+      && (tag == DW_TAG_class_type
+         || tag == DW_TAG_structure_type
+         || tag == DW_TAG_union_type))
+    guess_partial_die_structure_name (this, cu);
 
   /* GCC might emit a nameless struct or union that has a linkage
      name.  See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47510.  */
-  if (part_die->name == NULL
-      && (part_die->tag == DW_TAG_class_type
-         || part_die->tag == DW_TAG_interface_type
-         || part_die->tag == DW_TAG_structure_type
-         || part_die->tag == DW_TAG_union_type)
-      && part_die->linkage_name != NULL)
+  if (name == NULL
+      && (tag == DW_TAG_class_type
+         || tag == DW_TAG_interface_type
+         || tag == DW_TAG_structure_type
+         || tag == DW_TAG_union_type)
+      && linkage_name != NULL)
     {
       char *demangled;
 
-      demangled = gdb_demangle (part_die->linkage_name, DMGL_TYPES);
+      demangled = gdb_demangle (linkage_name, DMGL_TYPES);
       if (demangled)
        {
          const char *base;
@@ -18893,7 +19311,7 @@ fixup_partial_die (struct partial_die_info *part_die,
            base = demangled;
 
          struct objfile *objfile = cu->per_cu->dwarf2_per_objfile->objfile;
-         part_die->name
+         name
            = ((const char *)
               obstack_copy0 (&objfile->per_bfd->storage_obstack,
                              base, strlen (base)));
@@ -18901,7 +19319,7 @@ fixup_partial_die (struct partial_die_info *part_die,
        }
     }
 
-  part_die->fixup_called = 1;
+  fixup_called = 1;
 }
 
 /* Read an attribute value described by an attribute form.  */
@@ -19731,16 +20149,16 @@ read_str_index (const struct die_reader_specs *reader, ULONGEST str_index)
   dwarf2_read_section (objfile, str_offsets_section);
   if (str_section->buffer == NULL)
     error (_("%s used without .debug_str.dwo section"
-            " in CU at offset 0x%x [in module %s]"),
-          form_name, to_underlying (cu->header.sect_off), objf_name);
+            " in CU at offset %s [in module %s]"),
+          form_name, sect_offset_str (cu->header.sect_off), objf_name);
   if (str_offsets_section->buffer == NULL)
     error (_("%s used without .debug_str_offsets.dwo section"
-            " in CU at offset 0x%x [in module %s]"),
-          form_name, to_underlying (cu->header.sect_off), objf_name);
+            " 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 0x%x [in module %s]"),
-          form_name, to_underlying (cu->header.sect_off), objf_name);
+            " section in CU at offset %s [in module %s]"),
+          form_name, sect_offset_str (cu->header.sect_off), objf_name);
   info_ptr = (str_offsets_section->buffer
              + str_index * cu->header.offset_size);
   if (cu->header.offset_size == 4)
@@ -19749,8 +20167,8 @@ read_str_index (const struct die_reader_specs *reader, ULONGEST str_index)
     str_offset = bfd_get_64 (abfd, info_ptr);
   if (str_offset >= str_section->size)
     error (_("Offset from %s pointing outside of"
-            " .debug_str.dwo section in CU at offset 0x%x [in module %s]"),
-          form_name, to_underlying (cu->header.sect_off), objf_name);
+            " .debug_str.dwo section in CU at offset %s [in module %s]"),
+          form_name, sect_offset_str (cu->header.sect_off), objf_name);
   return (const char *) (str_section->buffer + str_offset);
 }
 
@@ -19897,8 +20315,8 @@ dwarf2_string_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *c
       else
         complaint (&symfile_complaints,
                   _("string type expected for attribute %s for "
-                    "DIE at 0x%x in module %s"),
-                  dwarf_attr_name (name), to_underlying (die->sect_off),
+                    "DIE at %s in module %s"),
+                  dwarf_attr_name (name), sect_offset_str (die->sect_off),
                   objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
     }
 
@@ -21817,15 +22235,9 @@ die_type (struct die_info *die, struct dwarf2_cu *cu)
 static int
 need_gnat_info (struct dwarf2_cu *cu)
 {
-  /* FIXME: brobecker/2010-10-12: As of now, only the AdaCore version
-     of GNAT produces this auxiliary information, without any indication
-     that it is produced.  Part of enhancing the FSF version of GNAT
-     to produce that information will be to put in place an indicator
-     that we can use in order to determine whether the descriptive type
-     info is available or not.  One suggestion that has been made is
-     to use a new attribute, attached to the CU die.  For now, assume
-     that the descriptive type info is not available.  */
-  return 0;
+  /* Assume that the Ada compiler was GNAT, which always produces
+     the auxiliary information.  */
+  return (cu->language == language_ada);
 }
 
 /* Return the auxiliary type of the die in question using its
@@ -21887,10 +22299,10 @@ build_error_marker_type (struct dwarf2_cu *cu, struct die_info *die)
   struct objfile *objfile = dwarf2_per_objfile->objfile;
   char *message, *saved;
 
-  message = xstrprintf (_("<unknown type in %s, CU 0x%x, DIE 0x%x>"),
+  message = xstrprintf (_("<unknown type in %s, CU %s, DIE %s>"),
                        objfile_name (objfile),
-                       to_underlying (cu->header.sect_off),
-                       to_underlying (die->sect_off));
+                       sect_offset_str (cu->header.sect_off),
+                       sect_offset_str (die->sect_off));
   saved = (char *) obstack_copy0 (&objfile->objfile_obstack,
                                  message, strlen (message));
   xfree (message);
@@ -21943,8 +22355,8 @@ lookup_die_type (struct die_info *die, const struct attribute *attr,
     {
       complaint (&symfile_complaints,
                 _("Dwarf Error: Bad type attribute %s in DIE"
-                  " at 0x%x [in module %s]"),
-                dwarf_attr_name (attr->name), to_underlying (die->sect_off),
+                  " at %s [in module %s]"),
+                dwarf_attr_name (attr->name), sect_offset_str (die->sect_off),
                 objfile_name (objfile));
       return build_error_marker_type (cu, die);
     }
@@ -22634,15 +23046,15 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die)
   unsigned int i;
 
   print_spaces (indent, f);
-  fprintf_unfiltered (f, "Die: %s (abbrev %d, offset 0x%x)\n",
+  fprintf_unfiltered (f, "Die: %s (abbrev %d, offset %s)\n",
                      dwarf_tag_name (die->tag), die->abbrev,
-                     to_underlying (die->sect_off));
+                     sect_offset_str (die->sect_off));
 
   if (die->parent != NULL)
     {
       print_spaces (indent, f);
-      fprintf_unfiltered (f, "  parent at offset: 0x%x\n",
-                         to_underlying (die->parent->sect_off));
+      fprintf_unfiltered (f, "  parent at offset: %s\n",
+                         sect_offset_str (die->parent->sect_off));
     }
 
   print_spaces (indent, f);
@@ -22947,9 +23359,9 @@ follow_die_ref (struct die_info *src_die, const struct attribute *attr,
                            || cu->per_cu->is_dwz),
                           ref_cu);
   if (!die)
-    error (_("Dwarf Error: Cannot find DIE at 0x%x referenced from DIE "
-          "at 0x%x [in module %s]"),
-          to_underlying (sect_off), to_underlying (src_die->sect_off),
+    error (_("Dwarf Error: Cannot find DIE at %s referenced from DIE "
+          "at %s [in module %s]"),
+          sect_offset_str (sect_off), sect_offset_str (src_die->sect_off),
           objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
 
   return die;
@@ -22981,14 +23393,14 @@ dwarf2_fetch_die_loc_sect_off (sect_offset sect_off,
     {
       /* We shouldn't get here for a dummy CU, but don't crash on the user.
         Instead just throw an error, not much else we can do.  */
-      error (_("Dwarf Error: Dummy CU at 0x%x referenced in module %s"),
-            to_underlying (sect_off), objfile_name (objfile));
+      error (_("Dwarf Error: Dummy CU at %s referenced in module %s"),
+            sect_offset_str (sect_off), objfile_name (objfile));
     }
 
   die = follow_die_offset (sect_off, per_cu->is_dwz, &cu);
   if (!die)
-    error (_("Dwarf Error: Cannot find DIE at 0x%x referenced in module %s"),
-          to_underlying (sect_off), objfile_name (objfile));
+    error (_("Dwarf Error: Cannot find DIE at %s referenced in module %s"),
+          sect_offset_str (sect_off), objfile_name (objfile));
 
   attr = dwarf2_attr (die, DW_AT_location, cu);
   if (!attr)
@@ -23014,9 +23426,9 @@ dwarf2_fetch_die_loc_sect_off (sect_offset sect_off,
   else
     {
       if (!attr_form_is_block (attr))
-       error (_("Dwarf Error: DIE at 0x%x referenced in module %s "
+       error (_("Dwarf Error: DIE at %s referenced in module %s "
                 "is neither DW_FORM_block* nor DW_FORM_exprloc"),
-              to_underlying (sect_off), objfile_name (objfile));
+              sect_offset_str (sect_off), objfile_name (objfile));
 
       retval.data = DW_BLOCK (attr)->data;
       retval.size = DW_BLOCK (attr)->size;
@@ -23088,15 +23500,14 @@ dwarf2_fetch_constant_bytes (sect_offset sect_off,
     {
       /* We shouldn't get here for a dummy CU, but don't crash on the user.
         Instead just throw an error, not much else we can do.  */
-      error (_("Dwarf Error: Dummy CU at 0x%x referenced in module %s"),
-            to_underlying (sect_off), objfile_name (objfile));
+      error (_("Dwarf Error: Dummy CU at %s referenced in module %s"),
+            sect_offset_str (sect_off), objfile_name (objfile));
     }
 
   die = follow_die_offset (sect_off, per_cu->is_dwz, &cu);
   if (!die)
-    error (_("Dwarf Error: Cannot find DIE at 0x%x referenced in module %s"),
-          to_underlying (sect_off), objfile_name (objfile));
-
+    error (_("Dwarf Error: Cannot find DIE at %s referenced in module %s"),
+          sect_offset_str (sect_off), objfile_name (objfile));
 
   attr = dwarf2_attr (die, DW_AT_const_value, cu);
   if (attr == NULL)
@@ -23300,8 +23711,8 @@ follow_die_sig (struct die_info *src_die, const struct attribute *attr,
   if (sig_type == NULL)
     {
       error (_("Dwarf Error: Cannot find signatured DIE %s referenced"
-               " from DIE at 0x%x [in module %s]"),
-             hex_string (signature), to_underlying (src_die->sect_off),
+               " from DIE at %s [in module %s]"),
+             hex_string (signature), sect_offset_str (src_die->sect_off),
             objfile_name ((*ref_cu)->per_cu->dwarf2_per_objfile->objfile));
     }
 
@@ -23310,8 +23721,8 @@ follow_die_sig (struct die_info *src_die, const struct attribute *attr,
     {
       dump_die_for_error (src_die);
       error (_("Dwarf Error: Problem reading signatured DIE %s referenced"
-              " from DIE at 0x%x [in module %s]"),
-            hex_string (signature), to_underlying (src_die->sect_off),
+              " from DIE at %s [in module %s]"),
+            hex_string (signature), sect_offset_str (src_die->sect_off),
             objfile_name ((*ref_cu)->per_cu->dwarf2_per_objfile->objfile));
     }
 
@@ -23339,8 +23750,8 @@ get_signatured_type (struct die_info *die, ULONGEST signature,
     {
       complaint (&symfile_complaints,
                 _("Dwarf Error: Cannot find signatured DIE %s referenced"
-                  " from DIE at 0x%x [in module %s]"),
-                hex_string (signature), to_underlying (die->sect_off),
+                  " from DIE at %s [in module %s]"),
+                hex_string (signature), sect_offset_str (die->sect_off),
                 objfile_name (dwarf2_per_objfile->objfile));
       return build_error_marker_type (cu, die);
     }
@@ -23361,8 +23772,8 @@ get_signatured_type (struct die_info *die, ULONGEST signature,
        {
          complaint (&symfile_complaints,
                     _("Dwarf Error: Cannot build signatured type %s"
-                      " referenced from DIE at 0x%x [in module %s]"),
-                    hex_string (signature), to_underlying (die->sect_off),
+                      " referenced from DIE at %s [in module %s]"),
+                    hex_string (signature), sect_offset_str (die->sect_off),
                     objfile_name (dwarf2_per_objfile->objfile));
          type = build_error_marker_type (cu, die);
        }
@@ -23371,8 +23782,8 @@ get_signatured_type (struct die_info *die, ULONGEST signature,
     {
       complaint (&symfile_complaints,
                 _("Dwarf Error: Problem reading signatured DIE %s referenced"
-                  " from DIE at 0x%x [in module %s]"),
-                hex_string (signature), to_underlying (die->sect_off),
+                  " from DIE at %s [in module %s]"),
+                hex_string (signature), sect_offset_str (die->sect_off),
                 objfile_name (dwarf2_per_objfile->objfile));
       type = build_error_marker_type (cu, die);
     }
@@ -23407,8 +23818,8 @@ get_DW_AT_signature_type (struct die_info *die, const struct attribute *attr,
 
       complaint (&symfile_complaints,
                 _("Dwarf Error: DW_AT_signature has bad form %s in DIE"
-                  " at 0x%x [in module %s]"),
-                dwarf_form_name (attr->form), to_underlying (die->sect_off),
+                  " at %s [in module %s]"),
+                dwarf_form_name (attr->form), sect_offset_str (die->sect_off),
                 objfile_name (dwarf2_per_objfile->objfile));
       return build_error_marker_type (cu, die);
     }
@@ -25025,8 +25436,8 @@ dwarf2_find_containing_comp_unit (sect_offset sect_off,
     {
       if (low == 0 || this_cu->is_dwz != offset_in_dwz)
        error (_("Dwarf Error: could not find partial DIE containing "
-              "offset 0x%x [in module %s]"),
-              to_underlying (sect_off),
+              "offset %s [in module %s]"),
+              sect_offset_str (sect_off),
               bfd_get_filename (dwarf2_per_objfile->objfile->obfd));
 
       gdb_assert (dwarf2_per_objfile->all_comp_units[low-1]->sect_off
@@ -25038,7 +25449,7 @@ dwarf2_find_containing_comp_unit (sect_offset sect_off,
       this_cu = dwarf2_per_objfile->all_comp_units[low];
       if (low == dwarf2_per_objfile->n_comp_units - 1
          && sect_off >= this_cu->sect_off + this_cu->length)
-       error (_("invalid dwarf2 offset %u"), to_underlying (sect_off));
+       error (_("invalid dwarf2 offset %s"), sect_offset_str (sect_off));
       gdb_assert (sect_off < this_cu->sect_off + this_cu->length);
       return this_cu;
     }
@@ -25175,10 +25586,7 @@ dwarf2_free_objfile (struct objfile *objfile)
   struct dwarf2_per_objfile *dwarf2_per_objfile
     = get_dwarf2_per_objfile (objfile);
 
-  if (dwarf2_per_objfile == NULL)
-    return;
-
-  dwarf2_per_objfile->~dwarf2_per_objfile ();
+  delete dwarf2_per_objfile;
 }
 
 /* A set of CU "per_cu" pointer, DIE offset, and GDB type pointer.
@@ -25281,9 +25689,9 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
   else if (attr != NULL)
     {
       complaint (&symfile_complaints,
-                _("DW_AT_allocated has the wrong form (%s) at DIE 0x%x"),
+                _("DW_AT_allocated has the wrong form (%s) at DIE %s"),
                 (attr != NULL ? dwarf_form_name (attr->form) : "n/a"),
-                to_underlying (die->sect_off));
+                sect_offset_str (die->sect_off));
     }
 
   /* Read DW_AT_associated and set in type.  */
@@ -25296,9 +25704,9 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
   else if (attr != NULL)
     {
       complaint (&symfile_complaints,
-                _("DW_AT_associated has the wrong form (%s) at DIE 0x%x"),
+                _("DW_AT_associated has the wrong form (%s) at DIE %s"),
                 (attr != NULL ? dwarf_form_name (attr->form) : "n/a"),
-                to_underlying (die->sect_off));
+                sect_offset_str (die->sect_off));
     }
 
   /* Read DW_AT_data_location and set in type.  */
@@ -25325,8 +25733,8 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
     htab_find_slot (dwarf2_per_objfile->die_type_hash, &ofs, INSERT);
   if (*slot)
     complaint (&symfile_complaints,
-              _("A problem internal to GDB: DIE 0x%x has type already set"),
-              to_underlying (die->sect_off));
+              _("A problem internal to GDB: DIE %s has type already set"),
+              sect_offset_str (die->sect_off));
   *slot = XOBNEW (&objfile->objfile_obstack,
                  struct dwarf2_per_cu_offset_and_type);
   **slot = ofs;
@@ -25477,37 +25885,6 @@ show_dwarf_cmd (const char *args, int from_tty)
   cmd_show_list (show_dwarf_cmdlist, from_tty, "");
 }
 
-/* Free data associated with OBJFILE, if necessary.  */
-
-static void
-dwarf2_per_objfile_free (struct objfile *objfile, void *d)
-{
-  struct dwarf2_per_objfile *data = (struct dwarf2_per_objfile *) d;
-  int ix;
-
-  for (ix = 0; ix < data->n_comp_units; ++ix)
-   VEC_free (dwarf2_per_cu_ptr, data->all_comp_units[ix]->imported_symtabs);
-
-  for (ix = 0; ix < data->n_type_units; ++ix)
-    VEC_free (dwarf2_per_cu_ptr,
-             data->all_type_units[ix]->per_cu.imported_symtabs);
-  xfree (data->all_type_units);
-
-  VEC_free (dwarf2_section_info_def, data->types);
-
-  if (data->dwo_files)
-    free_dwo_files (data->dwo_files, objfile);
-  if (data->dwp_file)
-    gdb_bfd_unref (data->dwp_file->dbfd);
-
-  if (data->dwz_file && data->dwz_file->dwz_bfd)
-    gdb_bfd_unref (data->dwz_file->dwz_bfd);
-
-  if (data->index_table != NULL)
-    data->index_table->~mapped_index ();
-}
-
-\f
 /* The "save gdb-index" command.  */
 
 /* Write SIZE bytes from the buffer pointed to by DATA to FILE, with
@@ -27139,8 +27516,7 @@ _initialize_dwarf2_read (void)
 {
   struct cmd_list_element *c;
 
-  dwarf2_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, dwarf2_per_objfile_free);
+  dwarf2_objfile_data_key = register_objfile_data ();
 
   add_prefix_cmd ("dwarf", class_maintenance, set_dwarf_cmd, _("\
 Set DWARF specific variables.\n\