--- /dev/null
+/* DWARF DIEs
+
+   Copyright (C) 1994-2023 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "dwarf2/die.h"
+#include "dwarf2/stringify.h"
+
+/* See die.h.  */
+
+struct die_info *
+die_info::allocate (struct obstack *obstack, int num_attrs)
+{
+  size_t size = sizeof (struct die_info);
+
+  if (num_attrs > 1)
+    size += (num_attrs - 1) * sizeof (struct attribute);
+
+  struct die_info *die = (struct die_info *) obstack_alloc (obstack, size);
+  memset (die, 0, size);
+  return die;
+}
+
+/* See die.h.  */
+
+hashval_t
+die_info::hash (const void *item)
+{
+  const struct die_info *die = (const struct die_info *) item;
+
+  return to_underlying (die->sect_off);
+}
+
+/* See die.h.  */
+
+int
+die_info::eq (const void *item_lhs, const void *item_rhs)
+{
+  const struct die_info *die_lhs = (const struct die_info *) item_lhs;
+  const struct die_info *die_rhs = (const struct die_info *) item_rhs;
+
+  return die_lhs->sect_off == die_rhs->sect_off;
+}
+
+static void
+dump_die_shallow (struct ui_file *f, int indent, struct die_info *die)
+{
+  unsigned int i;
+
+  gdb_printf (f, "%*sDie: %s (abbrev %d, offset %s)\n",
+             indent, "",
+             dwarf_tag_name (die->tag), die->abbrev,
+             sect_offset_str (die->sect_off));
+
+  if (die->parent != NULL)
+    gdb_printf (f, "%*s  parent at offset: %s\n",
+               indent, "",
+               sect_offset_str (die->parent->sect_off));
+
+  gdb_printf (f, "%*s  has children: %s\n",
+             indent, "",
+             dwarf_bool_name (die->child != NULL));
+
+  gdb_printf (f, "%*s  attributes:\n", indent, "");
+
+  for (i = 0; i < die->num_attrs; ++i)
+    {
+      gdb_printf (f, "%*s    %s (%s) ",
+                 indent, "",
+                 dwarf_attr_name (die->attrs[i].name),
+                 dwarf_form_name (die->attrs[i].form));
+
+      switch (die->attrs[i].form)
+       {
+       case DW_FORM_addr:
+       case DW_FORM_addrx:
+       case DW_FORM_GNU_addr_index:
+         gdb_printf (f, "address: ");
+         gdb_puts (hex_string (die->attrs[i].as_address ()), f);
+         break;
+       case DW_FORM_block2:
+       case DW_FORM_block4:
+       case DW_FORM_block:
+       case DW_FORM_block1:
+         gdb_printf (f, "block: size %s",
+                     pulongest (die->attrs[i].as_block ()->size));
+         break;
+       case DW_FORM_exprloc:
+         gdb_printf (f, "expression: size %s",
+                     pulongest (die->attrs[i].as_block ()->size));
+         break;
+       case DW_FORM_data16:
+         gdb_printf (f, "constant of 16 bytes");
+         break;
+       case DW_FORM_ref_addr:
+         gdb_printf (f, "ref address: ");
+         gdb_puts (hex_string (die->attrs[i].as_unsigned ()), f);
+         break;
+       case DW_FORM_GNU_ref_alt:
+         gdb_printf (f, "alt ref address: ");
+         gdb_puts (hex_string (die->attrs[i].as_unsigned ()), f);
+         break;
+       case DW_FORM_ref1:
+       case DW_FORM_ref2:
+       case DW_FORM_ref4:
+       case DW_FORM_ref8:
+       case DW_FORM_ref_udata:
+         gdb_printf (f, "constant ref: 0x%lx (adjusted)",
+                     (long) (die->attrs[i].as_unsigned ()));
+         break;
+       case DW_FORM_data1:
+       case DW_FORM_data2:
+       case DW_FORM_data4:
+       case DW_FORM_data8:
+       case DW_FORM_udata:
+         gdb_printf (f, "constant: %s",
+                     pulongest (die->attrs[i].as_unsigned ()));
+         break;
+       case DW_FORM_sec_offset:
+         gdb_printf (f, "section offset: %s",
+                     pulongest (die->attrs[i].as_unsigned ()));
+         break;
+       case DW_FORM_ref_sig8:
+         gdb_printf (f, "signature: %s",
+                     hex_string (die->attrs[i].as_signature ()));
+         break;
+       case DW_FORM_string:
+       case DW_FORM_strp:
+       case DW_FORM_line_strp:
+       case DW_FORM_strx:
+       case DW_FORM_GNU_str_index:
+       case DW_FORM_GNU_strp_alt:
+         gdb_printf (f, "string: \"%s\" (%s canonicalized)",
+                     die->attrs[i].as_string ()
+                     ? die->attrs[i].as_string () : "",
+                     die->attrs[i].canonical_string_p () ? "is" : "not");
+         break;
+       case DW_FORM_flag:
+         if (die->attrs[i].as_boolean ())
+           gdb_printf (f, "flag: TRUE");
+         else
+           gdb_printf (f, "flag: FALSE");
+         break;
+       case DW_FORM_flag_present:
+         gdb_printf (f, "flag: TRUE");
+         break;
+       case DW_FORM_indirect:
+         /* The reader will have reduced the indirect form to
+            the "base form" so this form should not occur.  */
+         gdb_printf (f,
+                     "unexpected attribute form: DW_FORM_indirect");
+         break;
+       case DW_FORM_sdata:
+       case DW_FORM_implicit_const:
+         gdb_printf (f, "constant: %s",
+                     plongest (die->attrs[i].as_signed ()));
+         break;
+       default:
+         gdb_printf (f, "unsupported attribute form: %d.",
+                     die->attrs[i].form);
+         break;
+       }
+      gdb_printf (f, "\n");
+    }
+}
+
+static void
+dump_die_1 (struct ui_file *f, int level, int max_level, struct die_info *die)
+{
+  int indent = level * 4;
+
+  gdb_assert (die != NULL);
+
+  if (level >= max_level)
+    return;
+
+  dump_die_shallow (f, indent, die);
+
+  if (die->child != NULL)
+    {
+      gdb_printf (f, "%*s  Children:", indent, "");
+      if (level + 1 < max_level)
+       {
+         gdb_printf (f, "\n");
+         dump_die_1 (f, level + 1, max_level, die->child);
+       }
+      else
+       {
+         gdb_printf (f,
+                     " [not printed, max nesting level reached]\n");
+       }
+    }
+
+  if (die->sibling != NULL && level > 0)
+    {
+      dump_die_1 (f, level, max_level, die->sibling);
+    }
+}
+
+/* See die.h.  */
+
+void
+die_info::dump (int max_level)
+{
+  dump_die_1 (gdb_stdlog, 0, max_level, this);
+}
+
+/* See die.h.  */
+
+void
+die_info::error_dump ()
+{
+  dump_die_shallow (gdb_stderr, 0, this);
+}
 
 static struct die_info *dwarf2_extension (struct die_info *die,
                                          struct dwarf2_cu **);
 
-static void dump_die_shallow (struct ui_file *, int indent, struct die_info *);
-
-static void dump_die_for_error (struct die_info *);
-
-static void dump_die_1 (struct ui_file *, int level, int max_level,
-                       struct die_info *);
-
-/*static*/ void dump_die (struct die_info *, int max_level);
-
 static void store_in_ref_table (struct die_info *,
                                struct dwarf2_cu *);
 
 
 static struct dwarf_block *dwarf_alloc_block (struct dwarf2_cu *);
 
-static struct die_info *dwarf_alloc_die (struct dwarf2_cu *, int);
-
 static void dwarf_decode_macros (struct dwarf2_cu *, unsigned int, int);
 
 static void fill_in_loclist_baton (struct dwarf2_cu *cu,
                  section->get_name (),
                  (unsigned) (begin_info_ptr - section->buffer),
                  bfd_get_filename (abfd));
-      dump_die (comp_unit_die, dwarf_die_debug);
+      comp_unit_die->dump (dwarf_die_debug);
     }
 
   /* Skip dummy compilation units.  */
                           objfile_name (per_objfile->objfile));
 }
 
-/* Trivial hash function for die_info: the hash value of a DIE
-   is its offset in .debug_info for this objfile.  */
-
-static hashval_t
-die_hash (const void *item)
-{
-  const struct die_info *die = (const struct die_info *) item;
-
-  return to_underlying (die->sect_off);
-}
-
-/* Trivial comparison function for die_info structures: two DIEs
-   are equal if they have the same offset.  */
-
-static int
-die_eq (const void *item_lhs, const void *item_rhs)
-{
-  const struct die_info *die_lhs = (const struct die_info *) item_lhs;
-  const struct die_info *die_rhs = (const struct die_info *) item_rhs;
-
-  return die_lhs->sect_off == die_rhs->sect_off;
-}
-
 /* Load the DIEs associated with PER_CU into memory.
 
    In some cases, the caller, while reading partial symbols, will need to load
   gdb_assert (cu->die_hash == NULL);
   cu->die_hash =
     htab_create_alloc_ex (cu->header.get_length_without_initial () / 12,
-                         die_hash,
-                         die_eq,
+                         die_info::hash,
+                         die_info::eq,
                          NULL,
                          &cu->comp_unit_obstack,
                          hashtab_obstack_allocate,
                  reader->die_section->get_name (),
                  (unsigned) (info_ptr - reader->die_section->buffer),
                  bfd_get_filename (reader->abfd));
-      dump_die (die, dwarf_die_debug);
+      die->dump (dwarf_die_debug);
     }
 
   return die;
           abbrev_number,
           bfd_get_filename (abfd));
 
-  die = dwarf_alloc_die (cu, abbrev->num_attrs + num_extra_attrs);
+  die = die_info::allocate (&cu->comp_unit_obstack,
+                           abbrev->num_attrs + num_extra_attrs);
   die->sect_off = sect_off;
   die->tag = abbrev->tag;
   die->abbrev = abbrev_number;
                  reader->die_section->get_name (),
                  (unsigned) (info_ptr - reader->die_section->buffer),
                  bfd_get_filename (reader->abfd));
-      dump_die (*diep, dwarf_die_debug);
+      (*diep)->dump (dwarf_die_debug);
     }
 
   return result;
   return follow_die_ref (die, attr, ext_cu);
 }
 
-static void
-dump_die_shallow (struct ui_file *f, int indent, struct die_info *die)
-{
-  unsigned int i;
-
-  gdb_printf (f, "%*sDie: %s (abbrev %d, offset %s)\n",
-             indent, "",
-             dwarf_tag_name (die->tag), die->abbrev,
-             sect_offset_str (die->sect_off));
-
-  if (die->parent != NULL)
-    gdb_printf (f, "%*s  parent at offset: %s\n",
-               indent, "",
-               sect_offset_str (die->parent->sect_off));
-
-  gdb_printf (f, "%*s  has children: %s\n",
-             indent, "",
-             dwarf_bool_name (die->child != NULL));
-
-  gdb_printf (f, "%*s  attributes:\n", indent, "");
-
-  for (i = 0; i < die->num_attrs; ++i)
-    {
-      gdb_printf (f, "%*s    %s (%s) ",
-                 indent, "",
-                 dwarf_attr_name (die->attrs[i].name),
-                 dwarf_form_name (die->attrs[i].form));
-
-      switch (die->attrs[i].form)
-       {
-       case DW_FORM_addr:
-       case DW_FORM_addrx:
-       case DW_FORM_GNU_addr_index:
-         gdb_printf (f, "address: ");
-         gdb_puts (hex_string (die->attrs[i].as_address ()), f);
-         break;
-       case DW_FORM_block2:
-       case DW_FORM_block4:
-       case DW_FORM_block:
-       case DW_FORM_block1:
-         gdb_printf (f, "block: size %s",
-                     pulongest (die->attrs[i].as_block ()->size));
-         break;
-       case DW_FORM_exprloc:
-         gdb_printf (f, "expression: size %s",
-                     pulongest (die->attrs[i].as_block ()->size));
-         break;
-       case DW_FORM_data16:
-         gdb_printf (f, "constant of 16 bytes");
-         break;
-       case DW_FORM_ref_addr:
-         gdb_printf (f, "ref address: ");
-         gdb_puts (hex_string (die->attrs[i].as_unsigned ()), f);
-         break;
-       case DW_FORM_GNU_ref_alt:
-         gdb_printf (f, "alt ref address: ");
-         gdb_puts (hex_string (die->attrs[i].as_unsigned ()), f);
-         break;
-       case DW_FORM_ref1:
-       case DW_FORM_ref2:
-       case DW_FORM_ref4:
-       case DW_FORM_ref8:
-       case DW_FORM_ref_udata:
-         gdb_printf (f, "constant ref: 0x%lx (adjusted)",
-                     (long) (die->attrs[i].as_unsigned ()));
-         break;
-       case DW_FORM_data1:
-       case DW_FORM_data2:
-       case DW_FORM_data4:
-       case DW_FORM_data8:
-       case DW_FORM_udata:
-         gdb_printf (f, "constant: %s",
-                     pulongest (die->attrs[i].as_unsigned ()));
-         break;
-       case DW_FORM_sec_offset:
-         gdb_printf (f, "section offset: %s",
-                     pulongest (die->attrs[i].as_unsigned ()));
-         break;
-       case DW_FORM_ref_sig8:
-         gdb_printf (f, "signature: %s",
-                     hex_string (die->attrs[i].as_signature ()));
-         break;
-       case DW_FORM_string:
-       case DW_FORM_strp:
-       case DW_FORM_line_strp:
-       case DW_FORM_strx:
-       case DW_FORM_GNU_str_index:
-       case DW_FORM_GNU_strp_alt:
-         gdb_printf (f, "string: \"%s\" (%s canonicalized)",
-                     die->attrs[i].as_string ()
-                     ? die->attrs[i].as_string () : "",
-                     die->attrs[i].canonical_string_p () ? "is" : "not");
-         break;
-       case DW_FORM_flag:
-         if (die->attrs[i].as_boolean ())
-           gdb_printf (f, "flag: TRUE");
-         else
-           gdb_printf (f, "flag: FALSE");
-         break;
-       case DW_FORM_flag_present:
-         gdb_printf (f, "flag: TRUE");
-         break;
-       case DW_FORM_indirect:
-         /* The reader will have reduced the indirect form to
-            the "base form" so this form should not occur.  */
-         gdb_printf (f,
-                     "unexpected attribute form: DW_FORM_indirect");
-         break;
-       case DW_FORM_sdata:
-       case DW_FORM_implicit_const:
-         gdb_printf (f, "constant: %s",
-                     plongest (die->attrs[i].as_signed ()));
-         break;
-       default:
-         gdb_printf (f, "unsupported attribute form: %d.",
-                     die->attrs[i].form);
-         break;
-       }
-      gdb_printf (f, "\n");
-    }
-}
-
-static void
-dump_die_for_error (struct die_info *die)
-{
-  dump_die_shallow (gdb_stderr, 0, die);
-}
-
-static void
-dump_die_1 (struct ui_file *f, int level, int max_level, struct die_info *die)
-{
-  int indent = level * 4;
-
-  gdb_assert (die != NULL);
-
-  if (level >= max_level)
-    return;
-
-  dump_die_shallow (f, indent, die);
-
-  if (die->child != NULL)
-    {
-      gdb_printf (f, "%*s  Children:", indent, "");
-      if (level + 1 < max_level)
-       {
-         gdb_printf (f, "\n");
-         dump_die_1 (f, level + 1, max_level, die->child);
-       }
-      else
-       {
-         gdb_printf (f,
-                     " [not printed, max nesting level reached]\n");
-       }
-    }
-
-  if (die->sibling != NULL && level > 0)
-    {
-      dump_die_1 (f, level, max_level, die->sibling);
-    }
-}
-
-/* This is called from the pdie macro in gdbinit.in.
-   It's not static so gcc will keep a copy callable from gdb.  */
-
-void
-dump_die (struct die_info *die, int max_level)
-{
-  dump_die_1 (gdb_stdlog, 0, max_level, die);
-}
-
 static void
 store_in_ref_table (struct die_info *die, struct dwarf2_cu *cu)
 {
     die = follow_die_sig (src_die, attr, ref_cu);
   else
     {
-      dump_die_for_error (src_die);
+      src_die->error_dump ();
       error (_("Dwarf Error: Expected reference attribute [in module %s]"),
             objfile_name ((*ref_cu)->per_objfile->objfile));
     }
   die = follow_die_sig_1 (src_die, sig_type, ref_cu);
   if (die == NULL)
     {
-      dump_die_for_error (src_die);
+      src_die->error_dump ();
       error (_("Dwarf Error: Problem reading signatured DIE %s referenced"
               " from DIE at %s [in module %s]"),
             hex_string (signature), sect_offset_str (src_die->sect_off),
       gdb_assert (cu->die_hash == NULL);
       cu->die_hash =
        htab_create_alloc_ex (cu->header.get_length_without_initial () / 12,
-                             die_hash,
-                             die_eq,
+                             die_info::hash,
+                             die_info::eq,
                              NULL,
                              &cu->comp_unit_obstack,
                              hashtab_obstack_allocate,
   return XOBNEW (&cu->comp_unit_obstack, struct dwarf_block);
 }
 
-static struct die_info *
-dwarf_alloc_die (struct dwarf2_cu *cu, int num_attrs)
-{
-  struct die_info *die;
-  size_t size = sizeof (struct die_info);
-
-  if (num_attrs > 1)
-    size += (num_attrs - 1) * sizeof (struct attribute);
-
-  die = (struct die_info *) obstack_alloc (&cu->comp_unit_obstack, size);
-  memset (die, 0, sizeof (struct die_info));
-  return (die);
-}
-
 \f
 
 /* Macro support.  */