diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 04979f3d12f..94dcf8ac314 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -869,6 +869,9 @@ struct dwp_file
   asection **elf_sections = nullptr;
 };
 
+struct abbrev_table;
+typedef std::unique_ptr<struct abbrev_table> abbrev_table_up;
+
 /* Struct used to pass misc. parameters to read_die_and_children, et
    al.  which are used for both .debug_info and .debug_types dies.
    All parameters here are unchanging for the life of the call.  This
@@ -902,12 +905,44 @@ struct die_reader_specs
   struct abbrev_table *abbrev_table;
 };
 
-/* Type of function passed to init_cutu_and_read_dies, et.al.  */
-typedef void (die_reader_func_ftype) (const struct die_reader_specs *reader,
-				      const gdb_byte *info_ptr,
-				      struct die_info *comp_unit_die,
-				      int has_children,
-				      void *data);
+/* A subclass of die_reader_specs that holds storage and has complex
+   constructor and destructor behavior.  */
+
+class cutu_reader : public die_reader_specs
+{
+public:
+
+  cutu_reader (struct dwarf2_per_cu_data *this_cu,
+	       struct abbrev_table *abbrev_table,
+	       int use_existing_cu, int keep,
+	       bool skip_partial);
+
+  explicit cutu_reader (struct dwarf2_per_cu_data *this_cu,
+			struct dwo_file *dwo_file = nullptr);
+
+  ~cutu_reader ();
+
+  DISABLE_COPY_AND_ASSIGN (cutu_reader);
+
+  const gdb_byte *info_ptr = nullptr;
+  struct die_info *comp_unit_die = nullptr;
+  int has_children = 0;
+  bool dummy_p = false;
+
+private:
+  void init_tu_and_read_dwo_dies (struct dwarf2_per_cu_data *this_cu,
+				  int use_existing_cu, int keep);
+
+  struct dwarf2_per_cu_data *m_this_cu;
+  int m_keep = 0;
+  std::unique_ptr<dwarf2_cu> m_new_cu;
+
+  /* The ordinary abbreviation table.  */
+  abbrev_table_up m_abbrev_table_holder;
+
+  /* The DWO abbreviation table.  */
+  abbrev_table_up m_dwo_abbrev_table;
+};
 
 /* dir_index is 1-based in DWARF 4 and before, and is 0-based in DWARF 5 and
    later.  */
@@ -1259,8 +1294,6 @@ private:
   struct abbrev_info **m_abbrevs;
 };
 
-typedef std::unique_ptr<struct abbrev_table> abbrev_table_up;
-
 /* Attributes have a name and a value.  */
 struct attribute
   {
@@ -1447,7 +1480,7 @@ static struct partial_symtab *create_partial_symtab
 static void build_type_psymtabs_reader (const struct die_reader_specs *reader,
 					const gdb_byte *info_ptr,
 					struct die_info *type_unit_die,
-					int has_children, void *data);
+					int has_children);
 
 static void dwarf2_build_psymtabs_hard
   (struct dwarf2_per_objfile *dwarf2_per_objfile);
@@ -1977,15 +2010,6 @@ static const gdb_byte *read_and_check_comp_unit_head
    struct dwarf2_section_info *abbrev_section, const gdb_byte *info_ptr,
    rcuh_kind section_kind);
 
-static void init_cutu_and_read_dies
-  (struct dwarf2_per_cu_data *this_cu, struct abbrev_table *abbrev_table,
-   int use_existing_cu, int keep, bool skip_partial,
-   die_reader_func_ftype *die_reader_func, void *data);
-
-static void init_cutu_and_read_dies_simple
-  (struct dwarf2_per_cu_data *this_cu,
-   die_reader_func_ftype *die_reader_func, void *data);
-
 static htab_t allocate_signatured_type_table (struct objfile *objfile);
 
 static htab_t allocate_dwo_unit_table (struct objfile *objfile);
@@ -3645,8 +3669,7 @@ static void
 dw2_get_file_names_reader (const struct die_reader_specs *reader,
 			   const gdb_byte *info_ptr,
 			   struct die_info *comp_unit_die,
-			   int has_children,
-			   void *data)
+			   int has_children)
 {
   struct dwarf2_cu *cu = reader->cu;
   struct dwarf2_per_cu_data *this_cu = cu->per_cu;
@@ -3742,7 +3765,10 @@ dw2_get_file_names (struct dwarf2_per_cu_data *this_cu)
   if (this_cu->v.quick->no_file_data)
     return NULL;
 
-  init_cutu_and_read_dies_simple (this_cu, dw2_get_file_names_reader, NULL);
+  cutu_reader reader  (this_cu);
+  if (!reader.dummy_p)
+    dw2_get_file_names_reader (&reader, reader.info_ptr, reader.comp_unit_die,
+			       reader.has_children);
 
   if (this_cu->v.quick->no_file_data)
     return NULL;
@@ -6777,9 +6803,8 @@ create_debug_type_hash_table (struct dwarf2_per_objfile *dwarf2_per_objfile,
      not present, in which case the bfd is unknown.  */
   abfd = get_section_bfd_owner (section);
 
-  /* We don't use init_cutu_and_read_dies_simple, or some such, here
-     because we don't need to read any dies: the signature is in the
-     header.  */
+  /* We don't use cutu_reader here because we don't need to read
+     any dies: the signature is in the header.  */
 
   end_ptr = info_ptr + section->size;
   while (info_ptr < end_ptr)
@@ -7194,9 +7219,9 @@ init_cu_die_reader (struct die_reader_specs *reader,
   reader->abbrev_table = abbrev_table;
 }
 
-/* Subroutine of init_cutu_and_read_dies to simplify it.
+/* Subroutine of cutu_reader to simplify it.
    Read in the rest of a CU/TU top level DIE from DWO_UNIT.
-   There's just a lot of work to do, and init_cutu_and_read_dies is big enough
+   There's just a lot of work to do, and cutu_reader is big enough
    already.
 
    STUB_COMP_UNIT_DIE is for the stub DIE, we copy over certain attributes
@@ -7412,17 +7437,18 @@ lookup_dwo_id (struct dwarf2_cu *cu, struct die_info* comp_unit_die)
   return DW_UNSND (attr);
 }
 
-/* Subroutine of init_cutu_and_read_dies to simplify it.
+/* Subroutine of cutu_reader to simplify it.
    Look up the DWO unit specified by COMP_UNIT_DIE of THIS_CU.
    Returns NULL if the specified DWO unit cannot be found.  */
 
 static struct dwo_unit *
 lookup_dwo_unit (struct dwarf2_per_cu_data *this_cu,
-		 struct die_info *comp_unit_die)
+		 struct die_info *comp_unit_die,
+		 const char *dwo_name)
 {
   struct dwarf2_cu *cu = this_cu->cu;
   struct dwo_unit *dwo_unit;
-  const char *comp_dir, *dwo_name;
+  const char *comp_dir;
 
   gdb_assert (cu != NULL);
 
@@ -7453,23 +7479,16 @@ lookup_dwo_unit (struct dwarf2_per_cu_data *this_cu,
   return dwo_unit;
 }
 
-/* Subroutine of init_cutu_and_read_dies to simplify it.
+/* Subroutine of cutu_reader to simplify it.
    See it for a description of the parameters.
    Read a TU directly from a DWO file, bypassing the stub.  */
 
-static void
-init_tu_and_read_dwo_dies (struct dwarf2_per_cu_data *this_cu,
-			   int use_existing_cu, int keep,
-			   die_reader_func_ftype *die_reader_func,
-			   void *data)
+void
+cutu_reader::init_tu_and_read_dwo_dies (struct dwarf2_per_cu_data *this_cu,
+					int use_existing_cu, int keep)
 {
-  std::unique_ptr<dwarf2_cu> new_cu;
   struct signatured_type *sig_type;
   struct die_reader_specs reader;
-  const gdb_byte *info_ptr;
-  struct die_info *comp_unit_die;
-  int has_children;
-  struct dwarf2_per_objfile *dwarf2_per_objfile = this_cu->dwarf2_per_objfile;
 
   /* Verify we can do the following downcast, and that we have the
      data we need.  */
@@ -7481,48 +7500,28 @@ init_tu_and_read_dwo_dies (struct dwarf2_per_cu_data *this_cu,
     {
       gdb_assert (this_cu->cu->dwo_unit == sig_type->dwo_unit);
       /* There's no need to do the rereading_dwo_cu handling that
-	 init_cutu_and_read_dies does since we don't read the stub.  */
+	 cutu_reader does since we don't read the stub.  */
     }
   else
     {
       /* If !use_existing_cu, this_cu->cu must be NULL.  */
       gdb_assert (this_cu->cu == NULL);
-      new_cu.reset (new dwarf2_cu (this_cu));
+      m_new_cu.reset (new dwarf2_cu (this_cu));
     }
 
   /* A future optimization, if needed, would be to use an existing
      abbrev table.  When reading DWOs with skeletonless TUs, all the TUs
      could share abbrev tables.  */
 
-  /* The abbreviation table used by READER, this must live at least as long as
-     READER.  */
-  abbrev_table_up dwo_abbrev_table;
-
   if (read_cutu_die_from_dwo (this_cu, sig_type->dwo_unit,
 			      NULL /* stub_comp_unit_die */,
 			      sig_type->dwo_unit->dwo_file->comp_dir,
 			      &reader, &info_ptr,
 			      &comp_unit_die, &has_children,
-			      &dwo_abbrev_table) == 0)
+			      &m_dwo_abbrev_table) == 0)
     {
       /* Dummy die.  */
-      return;
-    }
-
-  /* All the "real" work is done here.  */
-  die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data);
-
-  /* This duplicates the code in init_cutu_and_read_dies,
-     but the alternative is making the latter more complex.
-     This function is only for the special case of using DWO files directly:
-     no point in overly complicating the general case just to handle this.  */
-  if (new_cu != NULL && keep)
-    {
-      /* Link this CU into read_in_chain.  */
-      this_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain;
-      dwarf2_per_objfile->read_in_chain = this_cu;
-      /* The chain owns it now.  */
-      new_cu.release ();
+      dummy_p = true;
     }
 }
 
@@ -7537,28 +7536,23 @@ init_tu_and_read_dwo_dies (struct dwarf2_per_cu_data *this_cu,
    Otherwise, a new CU is allocated with xmalloc.
 
    If KEEP is non-zero, then if we allocated a dwarf2_cu we add it to
-   read_in_chain.  Otherwise the dwarf2_cu data is freed at the end.
-
-   WARNING: If THIS_CU is a "dummy CU" (used as filler by the incremental
-   linker) then DIE_READER_FUNC will not get called.  */
+   read_in_chain.  Otherwise the dwarf2_cu data is freed at the
+   end.  */
 
-static void
-init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
-			 struct abbrev_table *abbrev_table,
-			 int use_existing_cu, int keep,
-			 bool skip_partial,
-			 die_reader_func_ftype *die_reader_func,
-			 void *data)
+cutu_reader::cutu_reader (struct dwarf2_per_cu_data *this_cu,
+			  struct abbrev_table *abbrev_table,
+			  int use_existing_cu, int keep,
+			  bool skip_partial)
+  : die_reader_specs {},
+    m_this_cu (this_cu),
+    m_keep (keep)
 {
   struct dwarf2_per_objfile *dwarf2_per_objfile = this_cu->dwarf2_per_objfile;
   struct objfile *objfile = dwarf2_per_objfile->objfile;
   struct dwarf2_section_info *section = this_cu->section;
   bfd *abfd = get_section_bfd_owner (section);
   struct dwarf2_cu *cu;
-  const gdb_byte *begin_info_ptr, *info_ptr;
-  struct die_reader_specs reader;
-  struct die_info *comp_unit_die;
-  int has_children;
+  const gdb_byte *begin_info_ptr;
   struct signatured_type *sig_type = NULL;
   struct dwarf2_section_info *abbrev_section;
   /* Non-zero if CU currently points to a DWO file and we need to
@@ -7581,8 +7575,7 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
       /* Narrow down the scope of possibilities to have to understand.  */
       gdb_assert (this_cu->is_debug_types);
       gdb_assert (abbrev_table == NULL);
-      init_tu_and_read_dwo_dies (this_cu, use_existing_cu, keep,
-				 die_reader_func, data);
+      init_tu_and_read_dwo_dies (this_cu, use_existing_cu, keep);
       return;
     }
 
@@ -7593,7 +7586,6 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
 
   abbrev_section = get_abbrev_section_for_cu (this_cu);
 
-  std::unique_ptr<dwarf2_cu> new_cu;
   if (use_existing_cu && this_cu->cu != NULL)
     {
       cu = this_cu->cu;
@@ -7610,8 +7602,8 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
     {
       /* If !use_existing_cu, this_cu->cu must be NULL.  */
       gdb_assert (this_cu->cu == NULL);
-      new_cu.reset (new dwarf2_cu (this_cu));
-      cu = new_cu.get ();
+      m_new_cu.reset (new dwarf2_cu (this_cu));
+      cu = m_new_cu.get ();
     }
 
   /* Get the header.  */
@@ -7664,28 +7656,33 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
   /* Skip dummy compilation units.  */
   if (info_ptr >= begin_info_ptr + this_cu->length
       || peek_abbrev_code (abfd, info_ptr) == 0)
-    return;
+    {
+      dummy_p = true;
+      return;
+    }
 
   /* If we don't have them yet, read the abbrevs for this compilation unit.
      And if we need to read them now, make sure they're freed when we're
-     done (own the table through ABBREV_TABLE_HOLDER).  */
-  abbrev_table_up abbrev_table_holder;
+     done.  */
   if (abbrev_table != NULL)
     gdb_assert (cu->header.abbrev_sect_off == abbrev_table->sect_off);
   else
     {
-      abbrev_table_holder
+      m_abbrev_table_holder
 	= abbrev_table_read_table (dwarf2_per_objfile, abbrev_section,
 				   cu->header.abbrev_sect_off);
-      abbrev_table = abbrev_table_holder.get ();
+      abbrev_table = m_abbrev_table_holder.get ();
     }
 
   /* Read the top level CU/TU die.  */
-  init_cu_die_reader (&reader, cu, section, NULL, abbrev_table);
-  info_ptr = read_full_die (&reader, &comp_unit_die, info_ptr, &has_children);
+  init_cu_die_reader (this, cu, section, NULL, abbrev_table);
+  info_ptr = read_full_die (this, &comp_unit_die, info_ptr, &has_children);
 
   if (skip_partial && comp_unit_die->tag == DW_TAG_partial_unit)
-    return;
+    {
+      dummy_p = true;
+      return;
+    }
 
   /* If we are in a DWO stub, process it and then read in the "real" CU/TU
      from the DWO file.  read_cutu_die_from_dwo will allocate the abbreviation
@@ -7696,7 +7693,6 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
      Note that if USE_EXISTING_OK != 0, and THIS_CU->cu already contains a
      DWO CU, that this test will fail (the attribute will not be present).  */
   const char *dwo_name = dwarf2_dwo_name (comp_unit_die, cu);
-  abbrev_table_up dwo_abbrev_table;
   if (dwo_name != nullptr)
     {
       struct dwo_unit *dwo_unit;
@@ -7709,16 +7705,17 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
 		     sect_offset_str (this_cu->sect_off),
 		     bfd_get_filename (abfd));
 	}
-      dwo_unit = lookup_dwo_unit (this_cu, comp_unit_die);
+      dwo_unit = lookup_dwo_unit (this_cu, comp_unit_die, dwo_name);
       if (dwo_unit != NULL)
 	{
 	  if (read_cutu_die_from_dwo (this_cu, dwo_unit,
 				      comp_unit_die, NULL,
-				      &reader, &info_ptr,
+				      this, &info_ptr,
 				      &dwo_comp_unit_die, &has_children,
-				      &dwo_abbrev_table) == 0)
+				      &m_dwo_abbrev_table) == 0)
 	    {
 	      /* Dummy die.  */
+	      dummy_p = true;
 	      return;
 	    }
 	  comp_unit_die = dwo_comp_unit_die;
@@ -7732,18 +7729,20 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
 	     debug info.  */
 	}
     }
+}
 
-  /* All of the above is setup for this call.  Yikes.  */
-  die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data);
-
+cutu_reader::~cutu_reader ()
+{
   /* Done, clean up.  */
-  if (new_cu != NULL && keep)
+  if (m_new_cu != NULL && m_keep && !dummy_p)
     {
+      struct dwarf2_per_objfile *dwarf2_per_objfile
+	= m_this_cu->dwarf2_per_objfile;
       /* Link this CU into read_in_chain.  */
-      this_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain;
-      dwarf2_per_objfile->read_in_chain = this_cu;
+      m_this_cu->cu->read_in_chain = dwarf2_per_objfile->read_in_chain;
+      dwarf2_per_objfile->read_in_chain = m_this_cu;
       /* The chain owns it now.  */
-      new_cu.release ();
+      m_new_cu.release ();
     }
 }
 
@@ -7756,18 +7755,14 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
 
    We fill in THIS_CU->length.
 
-   WARNING: If THIS_CU is a "dummy CU" (used as filler by the incremental
-   linker) then DIE_READER_FUNC will not get called.
-
    THIS_CU->cu is always freed when done.
    This is done in order to not leave THIS_CU->cu in a state where we have
    to care whether it refers to the "main" CU or the DWO CU.  */
 
-static void
-init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
-				   struct dwo_file *dwo_file,
-				   die_reader_func_ftype *die_reader_func,
-				   void *data)
+cutu_reader::cutu_reader (struct dwarf2_per_cu_data *this_cu,
+			  struct dwo_file *dwo_file)
+  : die_reader_specs {},
+    m_this_cu (this_cu)
 {
   struct dwarf2_per_objfile *dwarf2_per_objfile = this_cu->dwarf2_per_objfile;
   struct objfile *objfile = dwarf2_per_objfile->objfile;
@@ -7775,8 +7770,6 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
   bfd *abfd = get_section_bfd_owner (section);
   struct dwarf2_section_info *abbrev_section;
   const gdb_byte *begin_info_ptr, *info_ptr;
-  struct die_reader_specs reader;
-  struct die_info *comp_unit_die;
   int has_children;
 
   if (dwarf_die_debug)
@@ -7793,49 +7786,35 @@ init_cutu_and_read_dies_no_follow (struct dwarf2_per_cu_data *this_cu,
   /* This is cheap if the section is already read in.  */
   dwarf2_read_section (objfile, section);
 
-  struct dwarf2_cu cu (this_cu);
+  m_new_cu.reset (new dwarf2_cu (this_cu));
 
   begin_info_ptr = info_ptr = section->buffer + to_underlying (this_cu->sect_off);
   info_ptr = read_and_check_comp_unit_head (dwarf2_per_objfile,
-					    &cu.header, section,
+					    &m_new_cu->header, section,
 					    abbrev_section, info_ptr,
 					    (this_cu->is_debug_types
 					     ? rcuh_kind::TYPE
 					     : rcuh_kind::COMPILE));
 
-  this_cu->length = get_cu_length (&cu.header);
+  this_cu->length = get_cu_length (&m_new_cu->header);
 
   /* Skip dummy compilation units.  */
   if (info_ptr >= begin_info_ptr + this_cu->length
       || peek_abbrev_code (abfd, info_ptr) == 0)
-    return;
+    {
+      dummy_p = true;
+      return;
+    }
 
-  abbrev_table_up abbrev_table
+  m_abbrev_table_holder
     = abbrev_table_read_table (dwarf2_per_objfile, abbrev_section,
-			       cu.header.abbrev_sect_off);
-
-  init_cu_die_reader (&reader, &cu, section, dwo_file, abbrev_table.get ());
-  info_ptr = read_full_die (&reader, &comp_unit_die, info_ptr, &has_children);
+			       m_new_cu->header.abbrev_sect_off);
 
-  die_reader_func (&reader, info_ptr, comp_unit_die, has_children, data);
+  init_cu_die_reader (this, m_new_cu.get (), section, dwo_file,
+		      m_abbrev_table_holder.get ());
+  info_ptr = read_full_die (this, &comp_unit_die, info_ptr, &has_children);
 }
 
-/* Read a CU/TU, except that this does not look for DW_AT_GNU_dwo_name and
-   does not lookup the specified DWO file.
-   This cannot be used to read DWO files.
-
-   THIS_CU->cu is always freed when done.
-   This is done in order to not leave THIS_CU->cu in a state where we have
-   to care whether it refers to the "main" CU or the DWO CU.
-   We can revisit this if the data shows there's a performance issue.  */
-
-static void
-init_cutu_and_read_dies_simple (struct dwarf2_per_cu_data *this_cu,
-				die_reader_func_ftype *die_reader_func,
-				void *data)
-{
-  init_cutu_and_read_dies_no_follow (this_cu, NULL, die_reader_func, data);
-}
 
 /* Type Unit Groups.
 
@@ -8013,29 +7992,15 @@ create_partial_symtab (struct dwarf2_per_cu_data *per_cu, const char *name)
   return pst;
 }
 
-/* The DATA object passed to process_psymtab_comp_unit_reader has this
-   type.  */
-
-struct process_psymtab_comp_unit_data
-{
-  /* True if we are reading a DW_TAG_partial_unit.  */
-
-  int want_partial_unit;
-
-  /* The "pretend" language that is used if the CU doesn't declare a
-     language.  */
-
-  enum language pretend_language;
-};
-
-/* die_reader_func for process_psymtab_comp_unit.  */
+/* DIE reader function for process_psymtab_comp_unit.  */
 
 static void
 process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
 				  const gdb_byte *info_ptr,
 				  struct die_info *comp_unit_die,
 				  int has_children,
-				  void *data)
+				  int want_partial_unit,
+				  enum language pretend_language)
 {
   struct dwarf2_cu *cu = reader->cu;
   struct objfile *objfile = cu->per_cu->dwarf2_per_objfile->objfile;
@@ -8046,15 +8011,13 @@ process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
   struct partial_symtab *pst;
   enum pc_bounds_kind cu_bounds_kind;
   const char *filename;
-  struct process_psymtab_comp_unit_data *info
-    = (struct process_psymtab_comp_unit_data *) data;
 
-  if (comp_unit_die->tag == DW_TAG_partial_unit && !info->want_partial_unit)
+  if (comp_unit_die->tag == DW_TAG_partial_unit && !want_partial_unit)
     return;
 
   gdb_assert (! per_cu->is_debug_types);
 
-  prepare_one_comp_unit (cu, comp_unit_die, info->pretend_language);
+  prepare_one_comp_unit (cu, comp_unit_die, pretend_language);
 
   /* Allocate a new partial symbol table structure.  */
   filename = dwarf2_string_attr (comp_unit_die, DW_AT_name, cu);
@@ -8176,17 +8139,21 @@ process_psymtab_comp_unit (struct dwarf2_per_cu_data *this_cu,
   if (this_cu->cu != NULL)
     free_one_cached_comp_unit (this_cu);
 
-  if (this_cu->is_debug_types)
-    init_cutu_and_read_dies (this_cu, NULL, 0, 0, false,
-			     build_type_psymtabs_reader, NULL);
-  else
+  cutu_reader reader (this_cu, NULL, 0, 0, false);
+
+  if (reader.dummy_p)
     {
-      process_psymtab_comp_unit_data info;
-      info.want_partial_unit = want_partial_unit;
-      info.pretend_language = pretend_language;
-      init_cutu_and_read_dies (this_cu, NULL, 0, 0, false,
-			       process_psymtab_comp_unit_reader, &info);
+      /* Nothing.  */
     }
+  else if (this_cu->is_debug_types)
+    build_type_psymtabs_reader (&reader, reader.info_ptr, reader.comp_unit_die,
+				reader.has_children);
+  else
+    process_psymtab_comp_unit_reader (&reader, reader.info_ptr,
+				      reader.comp_unit_die,
+				      reader.has_children,
+				      want_partial_unit,
+				      pretend_language);
 
   /* Age out any secondary CUs.  */
   age_cached_comp_units (this_cu->dwarf2_per_objfile);
@@ -8198,8 +8165,7 @@ static void
 build_type_psymtabs_reader (const struct die_reader_specs *reader,
 			    const gdb_byte *info_ptr,
 			    struct die_info *type_unit_die,
-			    int has_children,
-			    void *data)
+			    int has_children)
 {
   struct dwarf2_per_objfile *dwarf2_per_objfile
     = reader->cu->per_cu->dwarf2_per_objfile;
@@ -8213,7 +8179,6 @@ build_type_psymtabs_reader (const struct die_reader_specs *reader,
   CORE_ADDR lowpc, highpc;
   struct partial_symtab *pst;
 
-  gdb_assert (data == NULL);
   gdb_assert (per_cu->is_debug_types);
   sig_type = (struct signatured_type *) per_cu;
 
@@ -8344,8 +8309,12 @@ build_type_psymtabs_1 (struct dwarf2_per_objfile *dwarf2_per_objfile)
 	  ++tu_stats->nr_uniq_abbrev_tables;
 	}
 
-      init_cutu_and_read_dies (&tu.sig_type->per_cu, abbrev_table.get (),
-			       0, 0, false, build_type_psymtabs_reader, NULL);
+      cutu_reader reader (&tu.sig_type->per_cu, abbrev_table.get (),
+			  0, 0, false);
+      if (!reader.dummy_p)
+	build_type_psymtabs_reader (&reader, reader.info_ptr,
+				    reader.comp_unit_die,
+				    reader.has_children);
     }
 }
 
@@ -8450,8 +8419,10 @@ process_skeletonless_type_unit (void **slot, void *info)
   *slot = entry;
 
   /* This does the job that build_type_psymtabs_1 would have done.  */
-  init_cutu_and_read_dies (&entry->per_cu, NULL, 0, 0, false,
-			   build_type_psymtabs_reader, NULL);
+  cutu_reader reader (&entry->per_cu, NULL, 0, 0, false);
+  if (!reader.dummy_p)
+    build_type_psymtabs_reader (&reader, reader.info_ptr,
+				reader.comp_unit_die, reader.has_children);
 
   return 1;
 }
@@ -8573,34 +8544,25 @@ dwarf2_build_psymtabs_hard (struct dwarf2_per_objfile *dwarf2_per_objfile)
 			objfile_name (objfile));
 }
 
-/* die_reader_func for load_partial_comp_unit.  */
-
-static void
-load_partial_comp_unit_reader (const struct die_reader_specs *reader,
-			       const gdb_byte *info_ptr,
-			       struct die_info *comp_unit_die,
-			       int has_children,
-			       void *data)
-{
-  struct dwarf2_cu *cu = reader->cu;
-
-  prepare_one_comp_unit (cu, comp_unit_die, language_minimal);
-
-  /* Check if comp unit has_children.
-     If so, read the rest of the partial symbols from this comp unit.
-     If not, there's no more debug_info for this comp unit.  */
-  if (has_children)
-    load_partial_dies (reader, info_ptr, 0);
-}
-
 /* Load the partial DIEs for a secondary CU into memory.
    This is also used when rereading a primary CU with load_all_dies.  */
 
 static void
 load_partial_comp_unit (struct dwarf2_per_cu_data *this_cu)
 {
-  init_cutu_and_read_dies (this_cu, NULL, 1, 1, false,
-			   load_partial_comp_unit_reader, NULL);
+  cutu_reader reader (this_cu, NULL, 1, 1, false);
+
+  if (!reader.dummy_p)
+    {
+      prepare_one_comp_unit (reader.cu, reader.comp_unit_die,
+			     language_minimal);
+
+      /* Check if comp unit has_children.
+	 If so, read the rest of the partial symbols from this comp unit.
+	 If not, there's no more debug_info for this comp unit.  */
+      if (reader.has_children)
+	load_partial_dies (&reader, reader.info_ptr, 0);
+    }
 }
 
 static void
@@ -9738,19 +9700,21 @@ die_eq (const void *item_lhs, const void *item_rhs)
   return die_lhs->sect_off == die_rhs->sect_off;
 }
 
-/* die_reader_func for load_full_comp_unit.
-   This is identical to read_signatured_type_reader,
-   but is kept separate for now.  */
+/* Load the DIEs associated with PER_CU into memory.  */
 
 static void
-load_full_comp_unit_reader (const struct die_reader_specs *reader,
-			    const gdb_byte *info_ptr,
-			    struct die_info *comp_unit_die,
-			    int has_children,
-			    void *data)
+load_full_comp_unit (struct dwarf2_per_cu_data *this_cu,
+		     bool skip_partial,
+		     enum language pretend_language)
 {
-  struct dwarf2_cu *cu = reader->cu;
-  enum language *language_ptr = (enum language *) data;
+  gdb_assert (! this_cu->is_debug_types);
+
+  cutu_reader reader (this_cu, NULL, 1, 1, skip_partial);
+  if (reader.dummy_p)
+    return;
+
+  struct dwarf2_cu *cu = reader.cu;
+  const gdb_byte *info_ptr = reader.info_ptr;
 
   gdb_assert (cu->die_hash == NULL);
   cu->die_hash =
@@ -9762,10 +9726,11 @@ load_full_comp_unit_reader (const struct die_reader_specs *reader,
 			  hashtab_obstack_allocate,
 			  dummy_obstack_deallocate);
 
-  if (has_children)
-    comp_unit_die->child = read_die_and_siblings (reader, info_ptr,
-						  &info_ptr, comp_unit_die);
-  cu->dies = comp_unit_die;
+  if (reader.has_children)
+    reader.comp_unit_die->child
+      = read_die_and_siblings (&reader, reader.info_ptr,
+			       &info_ptr, reader.comp_unit_die);
+  cu->dies = reader.comp_unit_die;
   /* comp_unit_die is not stored in die_hash, no need.  */
 
   /* We try not to read any attributes in this function, because not
@@ -9774,20 +9739,7 @@ load_full_comp_unit_reader (const struct die_reader_specs *reader,
      or we won't be able to build types correctly.
      Similarly, if we do not read the producer, we can not apply
      producer-specific interpretation.  */
-  prepare_one_comp_unit (cu, cu->dies, *language_ptr);
-}
-
-/* Load the DIEs associated with PER_CU into memory.  */
-
-static void
-load_full_comp_unit (struct dwarf2_per_cu_data *this_cu,
-		     bool skip_partial,
-		     enum language pretend_language)
-{
-  gdb_assert (! this_cu->is_debug_types);
-
-  init_cutu_and_read_dies (this_cu, NULL, 1, 1, skip_partial,
-			   load_full_comp_unit_reader, &pretend_language);
+  prepare_one_comp_unit (cu, cu->dies, pretend_language);
 }
 
 /* Add a DIE to the delayed physname list.  */
@@ -11924,14 +11876,6 @@ allocate_dwo_unit_table (struct objfile *objfile)
 			       dummy_obstack_deallocate);
 }
 
-/* Structure used to pass data to create_dwo_debug_info_hash_table_reader.  */
-
-struct create_dwo_cu_data
-{
-  struct dwo_file *dwo_file;
-  struct dwo_unit dwo_unit;
-};
-
 /* die_reader_func for create_dwo_cu.  */
 
 static void
@@ -11939,14 +11883,12 @@ create_dwo_cu_reader (const struct die_reader_specs *reader,
 		      const gdb_byte *info_ptr,
 		      struct die_info *comp_unit_die,
 		      int has_children,
-		      void *datap)
+		      struct dwo_file *dwo_file,
+		      struct dwo_unit *dwo_unit)
 {
   struct dwarf2_cu *cu = reader->cu;
   sect_offset sect_off = cu->per_cu->sect_off;
   struct dwarf2_section_info *section = cu->per_cu->section;
-  struct create_dwo_cu_data *data = (struct create_dwo_cu_data *) datap;
-  struct dwo_file *dwo_file = data->dwo_file;
-  struct dwo_unit *dwo_unit = &data->dwo_unit;
 
   gdb::optional<ULONGEST> signature = lookup_dwo_id (cu, comp_unit_die);
   if (!signature.has_value ())
@@ -11997,33 +11939,32 @@ create_cus_hash_table (struct dwarf2_per_objfile *dwarf2_per_objfile,
   while (info_ptr < end_ptr)
     {
       struct dwarf2_per_cu_data per_cu;
-      struct create_dwo_cu_data create_dwo_cu_data;
+      struct dwo_unit read_unit {};
       struct dwo_unit *dwo_unit;
       void **slot;
       sect_offset sect_off = (sect_offset) (info_ptr - section.buffer);
 
-      memset (&create_dwo_cu_data.dwo_unit, 0,
-	      sizeof (create_dwo_cu_data.dwo_unit));
       memset (&per_cu, 0, sizeof (per_cu));
       per_cu.dwarf2_per_objfile = dwarf2_per_objfile;
       per_cu.is_debug_types = 0;
       per_cu.sect_off = sect_offset (info_ptr - section.buffer);
       per_cu.section = &section;
-      create_dwo_cu_data.dwo_file = &dwo_file;
 
-      init_cutu_and_read_dies_no_follow (
-	  &per_cu, &dwo_file, create_dwo_cu_reader, &create_dwo_cu_data);
+      cutu_reader reader (&per_cu, &dwo_file);
+      if (!reader.dummy_p)
+	create_dwo_cu_reader (&reader, reader.info_ptr, reader.comp_unit_die,
+			      reader.has_children, &dwo_file, &read_unit);
       info_ptr += per_cu.length;
 
       // If the unit could not be parsed, skip it.
-      if (create_dwo_cu_data.dwo_unit.dwo_file == NULL)
+      if (read_unit.dwo_file == NULL)
 	continue;
 
       if (cus_htab == NULL)
 	cus_htab = allocate_dwo_unit_table (objfile);
 
       dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
-      *dwo_unit = create_dwo_cu_data.dwo_unit;
+      *dwo_unit = read_unit;
       slot = htab_find_slot (cus_htab, dwo_unit, INSERT);
       gdb_assert (slot != NULL);
       if (*slot != NULL)
@@ -20161,32 +20102,6 @@ read_addr_index_from_leb128 (struct dwarf2_cu *cu, const gdb_byte *info_ptr,
   return read_addr_index (cu, addr_index);
 }
 
-/* Data structure to pass results from dwarf2_read_addr_index_reader
-   back to dwarf2_read_addr_index.  */
-
-struct dwarf2_read_addr_index_data
-{
-  ULONGEST addr_base;
-  int addr_size;
-};
-
-/* die_reader_func for dwarf2_read_addr_index.  */
-
-static void
-dwarf2_read_addr_index_reader (const struct die_reader_specs *reader,
-			       const gdb_byte *info_ptr,
-			       struct die_info *comp_unit_die,
-			       int has_children,
-			       void *data)
-{
-  struct dwarf2_cu *cu = reader->cu;
-  struct dwarf2_read_addr_index_data *aidata =
-    (struct dwarf2_read_addr_index_data *) data;
-
-  aidata->addr_base = cu->addr_base;
-  aidata->addr_size = cu->header.addr_size;
-}
-
 /* Given an index in .debug_addr, fetch the value.
    NOTE: This can be called during dwarf expression evaluation,
    long after the debug information has been read, and thus per_cu->cu
@@ -20224,14 +20139,9 @@ dwarf2_read_addr_index (struct dwarf2_per_cu_data *per_cu,
     }
   else
     {
-      struct dwarf2_read_addr_index_data aidata;
-
-      /* Note: We can't use init_cutu_and_read_dies_simple here,
-	 we need addr_base.  */
-      init_cutu_and_read_dies (per_cu, NULL, 0, 0, false,
-			       dwarf2_read_addr_index_reader, &aidata);
-      addr_base = aidata.addr_base;
-      addr_size = aidata.addr_size;
+      cutu_reader reader (per_cu, NULL, 0, 0, false);
+      addr_base = reader.cu->addr_base;
+      addr_size = reader.cu->header.addr_size;
     }
 
   return read_addr_index_1 (dwarf2_per_objfile, addr_index, addr_base,
@@ -24075,44 +23985,6 @@ load_full_type_unit (struct dwarf2_per_cu_data *per_cu)
   gdb_assert (per_cu->cu != NULL);
 }
 
-/* die_reader_func for read_signatured_type.
-   This is identical to load_full_comp_unit_reader,
-   but is kept separate for now.  */
-
-static void
-read_signatured_type_reader (const struct die_reader_specs *reader,
-			     const gdb_byte *info_ptr,
-			     struct die_info *comp_unit_die,
-			     int has_children,
-			     void *data)
-{
-  struct dwarf2_cu *cu = reader->cu;
-
-  gdb_assert (cu->die_hash == NULL);
-  cu->die_hash =
-    htab_create_alloc_ex (cu->header.length / 12,
-			  die_hash,
-			  die_eq,
-			  NULL,
-			  &cu->comp_unit_obstack,
-			  hashtab_obstack_allocate,
-			  dummy_obstack_deallocate);
-
-  if (has_children)
-    comp_unit_die->child = read_die_and_siblings (reader, info_ptr,
-						  &info_ptr, comp_unit_die);
-  cu->dies = comp_unit_die;
-  /* comp_unit_die is not stored in die_hash, no need.  */
-
-  /* We try not to read any attributes in this function, because not
-     all CUs needed for references have been loaded yet, and symbol
-     table processing isn't initialized.  But we have to set the CU language,
-     or we won't be able to build types correctly.
-     Similarly, if we do not read the producer, we can not apply
-     producer-specific interpretation.  */
-  prepare_one_comp_unit (cu, cu->dies, language_minimal);
-}
-
 /* Read in a signatured type and build its CU and DIEs.
    If the type is a stub for the real type in a DWO file,
    read in the real type from the DWO file as well.  */
@@ -24125,8 +23997,39 @@ read_signatured_type (struct signatured_type *sig_type)
   gdb_assert (per_cu->is_debug_types);
   gdb_assert (per_cu->cu == NULL);
 
-  init_cutu_and_read_dies (per_cu, NULL, 0, 1, false,
-			   read_signatured_type_reader, NULL);
+  cutu_reader reader (per_cu, NULL, 0, 1, false);
+
+  if (!reader.dummy_p)
+    {
+      struct dwarf2_cu *cu = reader.cu;
+      const gdb_byte *info_ptr = reader.info_ptr;
+
+      gdb_assert (cu->die_hash == NULL);
+      cu->die_hash =
+	htab_create_alloc_ex (cu->header.length / 12,
+			      die_hash,
+			      die_eq,
+			      NULL,
+			      &cu->comp_unit_obstack,
+			      hashtab_obstack_allocate,
+			      dummy_obstack_deallocate);
+
+      if (reader.has_children)
+	reader.comp_unit_die->child
+	  = read_die_and_siblings (&reader, info_ptr, &info_ptr,
+				   reader.comp_unit_die);
+      cu->dies = reader.comp_unit_die;
+      /* comp_unit_die is not stored in die_hash, no need.  */
+
+      /* We try not to read any attributes in this function, because
+	 not all CUs needed for references have been loaded yet, and
+	 symbol table processing isn't initialized.  But we have to
+	 set the CU language, or we won't be able to build types
+	 correctly.  Similarly, if we do not read the producer, we can
+	 not apply producer-specific interpretation.  */
+      prepare_one_comp_unit (cu, cu->dies, language_minimal);
+    }
+
   sig_type->per_cu.tu_read = 1;
 }
 
