Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 0/6] Rewrite registry.h
@ 2022-05-30 17:59 Tom Tromey
  2022-05-30 17:59 ` [PATCH 1/6] Change address_space to use new and delete Tom Tromey
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Tom Tromey @ 2022-05-30 17:59 UTC (permalink / raw)
  To: gdb-patches

This series rewrites registry.h, changing it from a lengthy macro to a
C++ template.

After this, registries are slightly less flexible, in that only the
type-safe form is supplied.  However, I consider that a plus and not a
minus.

Regression tested on x86-64 Fedora 34.

Tom



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

* [PATCH 1/6] Change address_space to use new and delete
  2022-05-30 17:59 [PATCH 0/6] Rewrite registry.h Tom Tromey
@ 2022-05-30 17:59 ` Tom Tromey
  2022-05-30 17:59 ` [PATCH 2/6] Change allocation of type-copying hash table Tom Tromey
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Tom Tromey @ 2022-05-30 17:59 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes address_space to use new and delete, and makes some other
small C++-ification changes as well, like changing address_space_num
to be a method.

This patch was needed for the subsequent patch to rewrite the registry
system.
---
 gdb/infrun.c              |  6 +++---
 gdb/progspace.c           | 38 ++++++++++++--------------------------
 gdb/progspace.h           | 22 ++++++++++++++--------
 gdb/scoped-mock-context.h |  2 +-
 gdb/target-debug.h        |  2 +-
 5 files changed, 31 insertions(+), 39 deletions(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index 02c98b50c8c..b1f98377cad 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -501,7 +501,7 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
 	    }
 	  else
 	    {
-	      child_inf->aspace = new_address_space ();
+	      child_inf->aspace = new address_space ();
 	      child_inf->pspace = new program_space (child_inf->aspace);
 	      child_inf->removable = 1;
 	      clone_program_space (child_inf->pspace, parent_inf->pspace);
@@ -573,7 +573,7 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
 
 	  child_inf->aspace = parent_inf->aspace;
 	  child_inf->pspace = parent_inf->pspace;
-	  parent_inf->aspace = new_address_space ();
+	  parent_inf->aspace = new address_space ();
 	  parent_inf->pspace = new program_space (parent_inf->aspace);
 	  clone_program_space (parent_inf->pspace, child_inf->pspace);
 
@@ -583,7 +583,7 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
 	}
       else
 	{
-	  child_inf->aspace = new_address_space ();
+	  child_inf->aspace = new address_space ();
 	  child_inf->pspace = new program_space (child_inf->aspace);
 	  child_inf->removable = 1;
 	  child_inf->symfile_flags = SYMFILE_NO_READ;
diff --git a/gdb/progspace.c b/gdb/progspace.c
index 1ee4fe3f940..3232ea9ab01 100644
--- a/gdb/progspace.c
+++ b/gdb/progspace.c
@@ -57,16 +57,10 @@ DEFINE_REGISTRY (address_space, REGISTRY_ACCESS_FIELD)
 
 /* Create a new address space object, and add it to the list.  */
 
-struct address_space *
-new_address_space (void)
+address_space::address_space ()
+  : m_num (++highest_address_space_num)
 {
-  struct address_space *aspace;
-
-  aspace = XCNEW (struct address_space);
-  aspace->num = ++highest_address_space_num;
-  address_space_alloc_data (aspace);
-
-  return aspace;
+  address_space_alloc_data (this);
 }
 
 /* Maybe create a new address space object, and add it to the list, or
@@ -84,20 +78,12 @@ maybe_new_address_space (void)
       return program_spaces[0]->aspace;
     }
 
-  return new_address_space ();
-}
-
-static void
-free_address_space (struct address_space *aspace)
-{
-  address_space_free_data (aspace);
-  xfree (aspace);
+  return new address_space ();
 }
 
-int
-address_space_num (struct address_space *aspace)
+address_space::~address_space ()
 {
-  return aspace->num;
+  address_space_free_data (this);
 }
 
 /* Start counting over from scratch.  */
@@ -153,7 +139,7 @@ program_space::~program_space ()
      locations for this pspace which we're tearing down.  */
   clear_symtab_users (SYMFILE_DEFER_BP_RESET);
   if (!gdbarch_has_shared_address_space (target_gdbarch ()))
-    free_address_space (this->aspace);
+    delete this->aspace;
     /* Discard any data modules have associated with the PSPACE.  */
   program_space_free_data (this);
 }
@@ -411,17 +397,17 @@ update_address_spaces (void)
 
   if (shared_aspace)
     {
-      struct address_space *aspace = new_address_space ();
+      struct address_space *aspace = new address_space ();
 
-      free_address_space (current_program_space->aspace);
+      delete current_program_space->aspace;
       for (struct program_space *pspace : program_spaces)
 	pspace->aspace = aspace;
     }
   else
     for (struct program_space *pspace : program_spaces)
       {
-	free_address_space (pspace->aspace);
-	pspace->aspace = new_address_space ();
+	delete pspace->aspace;
+	pspace->aspace = new address_space ();
       }
 
   for (inferior *inf : all_inferiors ())
@@ -459,5 +445,5 @@ initialize_progspace (void)
      modules have done that.  Do this before
      initialize_current_architecture, because that accesses the ebfd
      of current_program_space.  */
-  current_program_space = new program_space (new_address_space ());
+  current_program_space = new program_space (new address_space ());
 }
diff --git a/gdb/progspace.h b/gdb/progspace.h
index 73beb7a4710..eff157b0dd3 100644
--- a/gdb/progspace.h
+++ b/gdb/progspace.h
@@ -385,10 +385,22 @@ struct program_space
    associating caches to each address space.  */
 struct address_space
 {
-  int num;
+  /* Create a new address space object, and add it to the list.  */
+  address_space ();
+  ~address_space ();
+  DISABLE_COPY_AND_ASSIGN (address_space);
+
+  /* Returns the integer address space id of this address space.  */
+  int num () const
+  {
+    return m_num;
+  }
 
   /* Per aspace data-pointers required by other GDB modules.  */
-  REGISTRY_FIELDS;
+  REGISTRY_FIELDS {};
+
+private:
+  int m_num;
 };
 
 /* The list of all program spaces.  There's always at least one.  */
@@ -430,17 +442,11 @@ class scoped_restore_current_program_space
   program_space *m_saved_pspace;
 };
 
-/* Create a new address space object, and add it to the list.  */
-extern struct address_space *new_address_space (void);
-
 /* Maybe create a new address space object, and add it to the list, or
    return a pointer to an existing address space, in case inferiors
    share an address space.  */
 extern struct address_space *maybe_new_address_space (void);
 
-/* Returns the integer address space id of ASPACE.  */
-extern int address_space_num (struct address_space *aspace);
-
 /* Update all program spaces matching to address spaces.  The user may
    have created several program spaces, and loaded executables into
    them before connecting to the target interface that will create the
diff --git a/gdb/scoped-mock-context.h b/gdb/scoped-mock-context.h
index b91d43b1716..a9895303015 100644
--- a/gdb/scoped-mock-context.h
+++ b/gdb/scoped-mock-context.h
@@ -38,7 +38,7 @@ struct scoped_mock_context
 
   Target mock_target;
   ptid_t mock_ptid {1, 1};
-  program_space mock_pspace {new_address_space ()};
+  program_space mock_pspace {new address_space ()};
   inferior mock_inferior {mock_ptid.pid ()};
   thread_info mock_thread {&mock_inferior, mock_ptid};
 
diff --git a/gdb/target-debug.h b/gdb/target-debug.h
index c2b1db1ce8e..ab89c0a5185 100644
--- a/gdb/target-debug.h
+++ b/gdb/target-debug.h
@@ -89,7 +89,7 @@
 #define target_debug_print_LONGEST_p(X)		\
   target_debug_do_print (phex (*(X), 0))
 #define target_debug_print_struct_address_space_p(X)	\
-  target_debug_do_print (plongest (address_space_num (X)))
+  target_debug_do_print (plongest ((X)->num ()))
 #define target_debug_print_struct_bp_target_info_p(X)	\
   target_debug_do_print (core_addr_to_string ((X)->placed_address))
 #define target_debug_print_struct_expression_p(X)	\
-- 
2.34.1


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

* [PATCH 2/6] Change allocation of type-copying hash table
  2022-05-30 17:59 [PATCH 0/6] Rewrite registry.h Tom Tromey
  2022-05-30 17:59 ` [PATCH 1/6] Change address_space to use new and delete Tom Tromey
@ 2022-05-30 17:59 ` Tom Tromey
  2022-05-30 17:59 ` [PATCH 3/6] Remove some unused functions from guile code Tom Tromey
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Tom Tromey @ 2022-05-30 17:59 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

When an objfile is destroyed, types that are still in use and
allocated on that objfile are copied.  A temporary hash map is created
during this process, and it is allocated on the destroyed objfile's
obstack -- which normally is fine, as that is going to be destroyed
shortly anyway.

However, this approach requires that the objfile be passed to registry
destruction, and this won't be possible in the rewritten registry.
This patch changes the copied type hash table to simply use the heap
instead.  It also removes the 'objfile' parameter from
copy_type_recursive, to make this all more clear.

This patch also fixes an apparent bug in copy_type_recursive.
Previously it was copying the dynamic property list to the dying
objfile's obstack:

-      = copy_dynamic_prop_list (&objfile->objfile_obstack,

However I think this is incorrect -- that obstack is about to be
destroyed.
---
 gdb/compile/compile-object-run.c |  4 ++--
 gdb/gdbtypes.c                   | 40 +++++++++++---------------------
 gdb/gdbtypes.h                   |  5 ++--
 gdb/guile/scm-type.c             |  4 ++--
 gdb/python/py-type.c             |  5 ++--
 gdb/value.c                      |  9 ++++---
 6 files changed, 26 insertions(+), 41 deletions(-)

diff --git a/gdb/compile/compile-object-run.c b/gdb/compile/compile-object-run.c
index 331ae35c5e9..6fcd10b29a4 100644
--- a/gdb/compile/compile-object-run.c
+++ b/gdb/compile/compile-object-run.c
@@ -109,8 +109,8 @@ do_module_cleanup (void *arg, int registers_valid)
 static type *
 create_copied_type_recursive (objfile *objfile, type *func_type)
 {
-  htab_up copied_types = create_copied_types_hash (objfile);
-  func_type = copy_type_recursive (objfile, func_type, copied_types.get ());
+  htab_up copied_types = create_copied_types_hash ();
+  func_type = copy_type_recursive (func_type, copied_types.get ());
   return func_type;
 }
 
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 2a51372a037..9f49c15862f 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -5562,7 +5562,7 @@ recursive_dump_type (struct type *type, int spaces)
 /* Trivial helpers for the libiberty hash table, for mapping one
    type to another.  */
 
-struct type_pair : public allocate_on_obstack
+struct type_pair
 {
   type_pair (struct type *old_, struct type *newobj_)
     : old (old_), newobj (newobj_)
@@ -5589,22 +5589,20 @@ type_pair_eq (const void *item_lhs, const void *item_rhs)
 }
 
 /* Allocate the hash table used by copy_type_recursive to walk
-   types without duplicates.  We use OBJFILE's obstack, because
-   OBJFILE is about to be deleted.  */
+   types without duplicates.  */
 
 htab_up
-create_copied_types_hash (struct objfile *objfile)
+create_copied_types_hash ()
 {
-  return htab_up (htab_create_alloc_ex (1, type_pair_hash, type_pair_eq,
-					NULL, &objfile->objfile_obstack,
-					hashtab_obstack_allocate,
-					dummy_obstack_deallocate));
+  return htab_up (htab_create_alloc (1, type_pair_hash, type_pair_eq,
+				     htab_delete_entry<type_pair>,
+				     xcalloc, xfree));
 }
 
 /* Recursively copy (deep copy) a dynamic attribute list of a type.  */
 
 static struct dynamic_prop_list *
-copy_dynamic_prop_list (struct obstack *objfile_obstack,
+copy_dynamic_prop_list (struct obstack *storage,
 			struct dynamic_prop_list *list)
 {
   struct dynamic_prop_list *copy = list;
@@ -5615,7 +5613,7 @@ copy_dynamic_prop_list (struct obstack *objfile_obstack,
       struct dynamic_prop_list *node_copy;
 
       node_copy = ((struct dynamic_prop_list *)
-		   obstack_copy (objfile_obstack, *node_ptr,
+		   obstack_copy (storage, *node_ptr,
 				 sizeof (struct dynamic_prop_list)));
       node_copy->prop = (*node_ptr)->prop;
       *node_ptr = node_copy;
@@ -5632,9 +5630,7 @@ copy_dynamic_prop_list (struct obstack *objfile_obstack,
    it is not associated with OBJFILE.  */
 
 struct type *
-copy_type_recursive (struct objfile *objfile, 
-		     struct type *type,
-		     htab_t copied_types)
+copy_type_recursive (struct type *type, htab_t copied_types)
 {
   void **slot;
   struct type *new_type;
@@ -5642,10 +5638,6 @@ copy_type_recursive (struct objfile *objfile,
   if (!type->is_objfile_owned ())
     return type;
 
-  /* This type shouldn't be pointing to any types in other objfiles;
-     if it did, the type might disappear unexpectedly.  */
-  gdb_assert (type->objfile_owner () == objfile);
-
   struct type_pair pair (type, nullptr);
 
   slot = htab_find_slot (copied_types, &pair, INSERT);
@@ -5656,8 +5648,7 @@ copy_type_recursive (struct objfile *objfile,
 
   /* We must add the new type to the hash table immediately, in case
      we encounter this type again during a recursive call below.  */
-  struct type_pair *stored
-    = new (&objfile->objfile_obstack) struct type_pair (type, new_type);
+  struct type_pair *stored = new type_pair (type, new_type);
 
   *slot = stored;
 
@@ -5690,8 +5681,7 @@ copy_type_recursive (struct objfile *objfile,
 	  TYPE_FIELD_BITSIZE (new_type, i) = TYPE_FIELD_BITSIZE (type, i);
 	  if (type->field (i).type ())
 	    new_type->field (i).set_type
-	      (copy_type_recursive (objfile, type->field (i).type (),
-				    copied_types));
+	      (copy_type_recursive (type->field (i).type (), copied_types));
 	  if (type->field (i).name ())
 	    new_type->field (i).set_name (xstrdup (type->field (i).name ()));
 
@@ -5736,16 +5726,14 @@ copy_type_recursive (struct objfile *objfile,
 
   if (type->main_type->dyn_prop_list != NULL)
     new_type->main_type->dyn_prop_list
-      = copy_dynamic_prop_list (&objfile->objfile_obstack,
+      = copy_dynamic_prop_list (gdbarch_obstack (new_type->arch_owner ()),
 				type->main_type->dyn_prop_list);
 
 
   /* Copy pointers to other types.  */
   if (TYPE_TARGET_TYPE (type))
     TYPE_TARGET_TYPE (new_type) = 
-      copy_type_recursive (objfile, 
-			   TYPE_TARGET_TYPE (type),
-			   copied_types);
+      copy_type_recursive (TYPE_TARGET_TYPE (type), copied_types);
 
   /* Maybe copy the type_specific bits.
 
@@ -5774,7 +5762,7 @@ copy_type_recursive (struct objfile *objfile,
       break;
     case TYPE_SPECIFIC_SELF_TYPE:
       set_type_self_type (new_type,
-			  copy_type_recursive (objfile, TYPE_SELF_TYPE (type),
+			  copy_type_recursive (TYPE_SELF_TYPE (type),
 					       copied_types));
       break;
     case TYPE_SPECIFIC_FIXED_POINT:
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 7437e1db8ab..cb989228222 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -2875,10 +2875,9 @@ extern int class_or_union_p (const struct type *);
 
 extern void maintenance_print_type (const char *, int);
 
-extern htab_up create_copied_types_hash (struct objfile *objfile);
+extern htab_up create_copied_types_hash ();
 
-extern struct type *copy_type_recursive (struct objfile *objfile,
-					 struct type *type,
+extern struct type *copy_type_recursive (struct type *type,
 					 htab_t copied_types);
 
 extern struct type *copy_type (const struct type *type);
diff --git a/gdb/guile/scm-type.c b/gdb/guile/scm-type.c
index 27d00f12a95..dd7eace8d40 100644
--- a/gdb/guile/scm-type.c
+++ b/gdb/guile/scm-type.c
@@ -360,7 +360,7 @@ tyscm_copy_type_recursive (void **slot, void *info)
   gdb_assert (objfile != NULL);
 
   htab_empty (copied_types);
-  t_smob->type = copy_type_recursive (objfile, t_smob->type, copied_types);
+  t_smob->type = copy_type_recursive (t_smob->type, copied_types);
 
   /* The eq?-hashtab that the type lived in is going away.
      Add the type to its new eq?-hashtab: Otherwise if/when the type is later
@@ -391,7 +391,7 @@ save_objfile_types (struct objfile *objfile, void *datum)
   if (!gdb_scheme_initialized)
     return;
 
-  htab_up copied_types = create_copied_types_hash (objfile);
+  htab_up copied_types = create_copied_types_hash ();
 
   if (htab != NULL)
     {
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 5352ead84bd..6cbf5f2eb6a 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -1125,7 +1125,7 @@ save_objfile_types (struct objfile *objfile, void *datum)
      operating on.  */
   gdbpy_enter enter_py (objfile->arch ());
 
-  htab_up copied_types = create_copied_types_hash (objfile);
+  htab_up copied_types = create_copied_types_hash ();
 
   while (obj)
     {
@@ -1133,8 +1133,7 @@ save_objfile_types (struct objfile *objfile, void *datum)
 
       htab_empty (copied_types.get ());
 
-      obj->type = copy_type_recursive (objfile, obj->type,
-				       copied_types.get ());
+      obj->type = copy_type_recursive (obj->type, copied_types.get ());
 
       obj->next = NULL;
       obj->prev = NULL;
diff --git a/gdb/value.c b/gdb/value.c
index 022fca91a42..6fb84aee582 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2567,11 +2567,10 @@ preserve_one_value (struct value *value, struct objfile *objfile,
 		    htab_t copied_types)
 {
   if (value->type->objfile_owner () == objfile)
-    value->type = copy_type_recursive (objfile, value->type, copied_types);
+    value->type = copy_type_recursive (value->type, copied_types);
 
   if (value->enclosing_type->objfile_owner () == objfile)
-    value->enclosing_type = copy_type_recursive (objfile,
-						 value->enclosing_type,
+    value->enclosing_type = copy_type_recursive (value->enclosing_type,
 						 copied_types);
 }
 
@@ -2587,7 +2586,7 @@ preserve_one_internalvar (struct internalvar *var, struct objfile *objfile,
       if (var->u.integer.type
 	  && var->u.integer.type->objfile_owner () == objfile)
 	var->u.integer.type
-	  = copy_type_recursive (objfile, var->u.integer.type, copied_types);
+	  = copy_type_recursive (var->u.integer.type, copied_types);
       break;
 
     case INTERNALVAR_VALUE:
@@ -2609,7 +2608,7 @@ preserve_values (struct objfile *objfile)
 
   /* Create the hash table.  We allocate on the objfile's obstack, since
      it is soon to be deleted.  */
-  htab_up copied_types = create_copied_types_hash (objfile);
+  htab_up copied_types = create_copied_types_hash ();
 
   for (const value_ref_ptr &item : value_history)
     preserve_one_value (item.get (), objfile, copied_types.get ());
-- 
2.34.1


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

* [PATCH 3/6] Remove some unused functions from guile code
  2022-05-30 17:59 [PATCH 0/6] Rewrite registry.h Tom Tromey
  2022-05-30 17:59 ` [PATCH 1/6] Change address_space to use new and delete Tom Tromey
  2022-05-30 17:59 ` [PATCH 2/6] Change allocation of type-copying hash table Tom Tromey
@ 2022-05-30 17:59 ` Tom Tromey
  2022-05-30 17:59 ` [PATCH 4/6] Rewrite registry.h Tom Tromey
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Tom Tromey @ 2022-05-30 17:59 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

The guile code has a couple of unused functions that touch on the
registry API.  This patch removes them.
---
 gdb/guile/guile-internal.h |  8 --------
 gdb/guile/scm-gsmob.c      | 36 ------------------------------------
 2 files changed, 44 deletions(-)

diff --git a/gdb/guile/guile-internal.h b/gdb/guile/guile-internal.h
index 28e4889bfa9..4cdb7e355d7 100644
--- a/gdb/guile/guile-internal.h
+++ b/gdb/guile/guile-internal.h
@@ -287,14 +287,6 @@ extern void gdbscm_init_chained_gsmob (chained_gdb_smob *base);
 extern void gdbscm_init_eqable_gsmob (eqable_gdb_smob *base,
 				      SCM containing_scm);
 
-extern void gdbscm_add_objfile_ref (struct objfile *objfile,
-				    const struct objfile_data *data_key,
-				    chained_gdb_smob *g_smob);
-
-extern void gdbscm_remove_objfile_ref (struct objfile *objfile,
-				       const struct objfile_data *data_key,
-				       chained_gdb_smob *g_smob);
-
 extern htab_t gdbscm_create_eqable_gsmob_ptr_map (htab_hash hash_fn,
 						  htab_eq eq_fn);
 
diff --git a/gdb/guile/scm-gsmob.c b/gdb/guile/scm-gsmob.c
index 5096f1c475a..71fb263efdd 100644
--- a/gdb/guile/scm-gsmob.c
+++ b/gdb/guile/scm-gsmob.c
@@ -206,42 +206,6 @@ gdbscm_gsmob_kind (SCM self)
    smobs with references to them.  There are several smobs that reference
    objfile-based data, so we provide helpers to manage this.  */
 
-/* Add G_SMOB to the reference chain for OBJFILE specified by DATA_KEY.
-   OBJFILE may be NULL, in which case just set prev,next to NULL.  */
-
-void
-gdbscm_add_objfile_ref (struct objfile *objfile,
-			const struct objfile_data *data_key,
-			chained_gdb_smob *g_smob)
-{
-  g_smob->prev = NULL;
-  if (objfile != NULL)
-    {
-      g_smob->next = (chained_gdb_smob *) objfile_data (objfile, data_key);
-      if (g_smob->next)
-	g_smob->next->prev = g_smob;
-      set_objfile_data (objfile, data_key, g_smob);
-    }
-  else
-    g_smob->next = NULL;
-}
-
-/* Remove G_SMOB from the reference chain for OBJFILE specified
-   by DATA_KEY.  OBJFILE may be NULL.  */
-
-void
-gdbscm_remove_objfile_ref (struct objfile *objfile,
-			   const struct objfile_data *data_key,
-			   chained_gdb_smob *g_smob)
-{
-  if (g_smob->prev)
-    g_smob->prev->next = g_smob->next;
-  else if (objfile != NULL)
-    set_objfile_data (objfile, data_key, g_smob->next);
-  if (g_smob->next)
-    g_smob->next->prev = g_smob->prev;
-}
-
 /* Create a hash table for mapping a pointer to a gdb data structure to the
    gsmob that wraps it.  */
 
-- 
2.34.1


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

* [PATCH 4/6] Rewrite registry.h
  2022-05-30 17:59 [PATCH 0/6] Rewrite registry.h Tom Tromey
                   ` (2 preceding siblings ...)
  2022-05-30 17:59 ` [PATCH 3/6] Remove some unused functions from guile code Tom Tromey
@ 2022-05-30 17:59 ` Tom Tromey
  2022-06-07 10:55   ` Lancelot SIX via Gdb-patches
  2022-05-30 17:59 ` [PATCH 5/6] Change registry to use less memory Tom Tromey
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Tom Tromey @ 2022-05-30 17:59 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This rewrites registry.h, removing all the macros and replacing it
with relatively ordinary template classes.  The result is less code
than the previous setup.  It replaces large macros with a relatively
straightforward C++ class, and now manages its own cleanup.

The existing type-safe "key" class is replaced with the equivalent
template class.  This approach ended up requiring relatively few
changes to the users of the registry code in gdb -- code using the key
system just required a small change to the key's declaration.

All existing users of the old C-like API are now converted to use the
type-safe API.  This mostly involved changing explicit deletion
functions to be an operator() in a deleter class.

The old "save/free" two-phase process is removed, and replaced with a
single "free" phase.  No existing code used both phases.

The old "free" callbacks took a parameter for the enclosing container
object.  However, this wasn't truly needed and is removed here as
well.
---
 gdb/Makefile.in            |   1 -
 gdb/ada-lang.c             |   5 +-
 gdb/ada-tasks.c            |   4 +-
 gdb/arm-tdep.c             |   4 +-
 gdb/auto-load.c            |   4 +-
 gdb/auxv.c                 |   2 +-
 gdb/break-catch-syscall.c  |   2 +-
 gdb/breakpoint.c           |   2 +-
 gdb/coffread.c             |   2 +-
 gdb/ctfread.c              |   8 +-
 gdb/dbxread.c              |   2 +-
 gdb/dwarf2/frame.c         |   4 +-
 gdb/dwarf2/read.c          |   8 +-
 gdb/elfread.c              |   4 +-
 gdb/fbsd-tdep.c            |   2 +-
 gdb/gdb-stabs.h            |   2 +-
 gdb/gdb_bfd.c              |  14 +-
 gdb/gdb_bfd.h              |  10 +-
 gdb/gdbtypes.c             |   6 +-
 gdb/guile/guile-internal.h |   2 +-
 gdb/guile/scm-block.c      |  75 +++---
 gdb/guile/scm-frame.c      |  75 +++---
 gdb/guile/scm-objfile.c    |  46 ++--
 gdb/guile/scm-progspace.c  |  47 ++--
 gdb/guile/scm-symbol.c     |  70 +++---
 gdb/guile/scm-symtab.c     |  76 +++---
 gdb/guile/scm-type.c       |  63 +++--
 gdb/hppa-tdep.c            |   3 +-
 gdb/inferior.c             |  11 +-
 gdb/inferior.h             |   7 +-
 gdb/inflow.c               |   2 +-
 gdb/linux-tdep.c           |   2 +-
 gdb/mdebugread.c           |   4 +-
 gdb/minidebug.c            |   2 +-
 gdb/nto-tdep.c             |   2 +-
 gdb/objc-lang.c            |   2 +-
 gdb/objfiles.c             |  15 +-
 gdb/objfiles.h             |   6 +-
 gdb/progspace.c            |  22 --
 gdb/progspace.h            |  18 +-
 gdb/python/py-block.c      |  70 +++---
 gdb/python/py-inferior.c   |  68 +++---
 gdb/python/py-objfile.c    |  37 ++-
 gdb/python/py-progspace.c  |  59 ++---
 gdb/python/py-symbol.c     |  63 ++---
 gdb/python/py-symtab.c     | 142 +++++------
 gdb/python/py-type.c       |  59 ++---
 gdb/registry.c             | 112 ---------
 gdb/registry.h             | 469 ++++++++++++++++---------------------
 gdb/remote-sim.c           |   2 +-
 gdb/remote.c               |   2 +-
 gdb/rs6000-tdep.c          |   2 +-
 gdb/solib-aix.c            |   3 +-
 gdb/solib-darwin.c         |   3 +-
 gdb/solib-dsbt.c           |   2 +-
 gdb/solib-svr4.c           |   2 +-
 gdb/solib.c                |   3 +-
 gdb/source.c               |   3 +-
 gdb/stabsread.c            |   4 +-
 gdb/symfile-debug.c        |   2 +-
 gdb/symfile.c              |   4 +-
 gdb/symtab.c               |   4 +-
 gdb/target-dcache.c        |   2 +-
 gdb/xcoffread.c            |   2 +-
 64 files changed, 684 insertions(+), 1071 deletions(-)
 delete mode 100644 gdb/registry.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index d80087749de..94e8da1dbbd 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1149,7 +1149,6 @@ COMMON_SFILES = \
 	regcache.c \
 	regcache-dump.c \
 	reggroups.c \
-	registry.c \
 	remote.c \
 	remote-fileio.c \
 	remote-notif.c \
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 6ab01fd27d4..77616476617 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -334,7 +334,7 @@ struct ada_inferior_data
 };
 
 /* Our key to this module's inferior data.  */
-static const struct inferior_key<ada_inferior_data> ada_inferior_data;
+static const registry<inferior>::key<ada_inferior_data> ada_inferior_data;
 
 /* Return our inferior data for the given inferior (INF).
 
@@ -376,7 +376,8 @@ struct ada_pspace_data
 };
 
 /* Key to our per-program-space data.  */
-static const struct program_space_key<ada_pspace_data> ada_pspace_data_handle;
+static const registry<program_space>::key<ada_pspace_data>
+  ada_pspace_data_handle;
 
 /* Return this module's data for the given program space (PSPACE).
    If not is found, add a zero'ed one now.
diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c
index 0043f2999d9..fda49557a4f 100644
--- a/gdb/ada-tasks.c
+++ b/gdb/ada-tasks.c
@@ -166,7 +166,7 @@ struct ada_tasks_pspace_data
 };
 
 /* Key to our per-program-space data.  */
-static const struct program_space_key<ada_tasks_pspace_data>
+static const registry<program_space>::key<ada_tasks_pspace_data>
   ada_tasks_pspace_data_handle;
 
 /* The kind of data structure used by the runtime to store the list
@@ -242,7 +242,7 @@ struct ada_tasks_inferior_data
 };
 
 /* Key to our per-inferior data.  */
-static const struct inferior_key<ada_tasks_inferior_data>
+static const registry<inferior>::key<ada_tasks_inferior_data>
   ada_tasks_inferior_data_handle;
 
 /* Return a string with TASKNO followed by the task name if TASK_INFO
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 49664093f00..dbcf4d286ab 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -123,7 +123,7 @@ struct arm_per_bfd
 };
 
 /* Per-bfd data used for mapping symbols.  */
-static bfd_key<arm_per_bfd> arm_bfd_data_key;
+static const registry<bfd>::key<arm_per_bfd> arm_bfd_data_key;
 
 /* The list of available "set arm ..." and "show arm ..." commands.  */
 static struct cmd_list_element *setarmcmdlist = NULL;
@@ -2368,7 +2368,7 @@ struct arm_exidx_data
 };
 
 /* Per-BFD key to store exception handling information.  */
-static const struct bfd_key<arm_exidx_data> arm_exidx_data_key;
+static const registry<bfd>::key<arm_exidx_data> arm_exidx_data_key;
 
 static struct obj_section *
 arm_obj_section_from_vma (struct objfile *objfile, bfd_vma vma)
diff --git a/gdb/auto-load.c b/gdb/auto-load.c
index b6056f5d60a..54ed73d1bf3 100644
--- a/gdb/auto-load.c
+++ b/gdb/auto-load.c
@@ -536,8 +536,8 @@ struct loaded_script
 };
 
 /* Per-program-space data key.  */
-static const struct program_space_key<struct auto_load_pspace_info>
-  auto_load_pspace_data;
+static const registry<program_space>::key<auto_load_pspace_info>
+     auto_load_pspace_data;
 
 /* Get the current autoload data.  If none is found yet, add it now.  This
    function always returns a valid object.  */
diff --git a/gdb/auxv.c b/gdb/auxv.c
index 8e175138f5d..6154988f6dd 100644
--- a/gdb/auxv.c
+++ b/gdb/auxv.c
@@ -332,7 +332,7 @@ struct auxv_info
 };
 
 /* Per-inferior data key for auxv.  */
-static const struct inferior_key<auxv_info> auxv_inferior_data;
+static const registry<inferior>::key<auxv_info> auxv_inferior_data;
 
 /* Invalidate INF's auxv cache.  */
 
diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
index 06d48466de7..805bb86cee6 100644
--- a/gdb/break-catch-syscall.c
+++ b/gdb/break-catch-syscall.c
@@ -79,7 +79,7 @@ struct catch_syscall_inferior_data
   int total_syscalls_count;
 };
 
-static const struct inferior_key<struct catch_syscall_inferior_data>
+static const registry<inferior>::key<catch_syscall_inferior_data>
   catch_syscall_inferior_data;
 
 static struct catch_syscall_inferior_data *
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index ed932a19ed7..8bc7cef9f86 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3326,7 +3326,7 @@ struct breakpoint_objfile_data
   std::vector<probe *> exception_probes;
 };
 
-static const struct objfile_key<breakpoint_objfile_data>
+static const registry<objfile>::key<breakpoint_objfile_data>
   breakpoint_objfile_key;
 
 /* Minimal symbol not found sentinel.  */
diff --git a/gdb/coffread.c b/gdb/coffread.c
index 75cf646c980..47828ac6090 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -61,7 +61,7 @@ struct coff_symfile_info
 
 /* Key for COFF-associated data.  */
 
-static const struct objfile_key<coff_symfile_info> coff_objfile_data_key;
+static const registry<objfile>::key<coff_symfile_info> coff_objfile_data_key;
 
 /* Translate an external name string into a user-visible name.  */
 #define	EXTERNAL_NAME(string, abfd) \
diff --git a/gdb/ctfread.c b/gdb/ctfread.c
index 828f300d29d..0da4f0d0720 100644
--- a/gdb/ctfread.c
+++ b/gdb/ctfread.c
@@ -87,7 +87,7 @@
 #include "ctf.h"
 #include "ctf-api.h"
 
-static const struct objfile_key<htab, htab_deleter> ctf_tid_key;
+static const registry<objfile>::key<htab, htab_deleter> ctf_tid_key;
 
 struct ctf_fp_info
 {
@@ -107,7 +107,7 @@ ctf_fp_info::~ctf_fp_info ()
   ctf_close (arc);
 }
 
-static const objfile_key<ctf_fp_info> ctf_dict_key;
+static const registry<objfile>::key<ctf_fp_info> ctf_dict_key;
 
 /* A CTF context consists of a file pointer and an objfile pointer.  */
 
@@ -243,7 +243,7 @@ set_tid_type (struct objfile *of, ctf_id_t tid, struct type *typ)
 {
   htab_t htab;
 
-  htab = (htab_t) ctf_tid_key.get (of);
+  htab = ctf_tid_key.get (of);
   if (htab == NULL)
     {
       htab = htab_create_alloc (1, tid_and_type_hash,
@@ -271,7 +271,7 @@ get_tid_type (struct objfile *of, ctf_id_t tid)
   struct ctf_tid_and_type *slot, ids;
   htab_t htab;
 
-  htab = (htab_t) ctf_tid_key.get (of);
+  htab = ctf_tid_key.get (of);
   if (htab == NULL)
     return nullptr;
 
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index bcf519000bc..e1bf9a01e30 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -57,7 +57,7 @@
 
 /* Key for dbx-associated data.  */
 
-objfile_key<dbx_symfile_info> dbx_objfile_data_key;
+const registry<objfile>::key<dbx_symfile_info> dbx_objfile_data_key;
 
 /* We put a pointer to this structure in the read_symtab_private field
    of the psymtab.  */
diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
index 5878d72f922..d7a06395acb 100644
--- a/gdb/dwarf2/frame.c
+++ b/gdb/dwarf2/frame.c
@@ -1370,12 +1370,12 @@ dwarf2_frame_cfa (struct frame_info *this_frame)
 \f
 /* We store the frame data on the BFD.  This is only done if it is
    independent of the address space and so can be shared.  */
-static const struct bfd_key<comp_unit> dwarf2_frame_bfd_data;
+static const registry<bfd>::key<comp_unit> dwarf2_frame_bfd_data;
 
 /* If any BFD sections require relocations (note; really should be if
    any debug info requires relocations), then we store the frame data
    on the objfile instead, and do not share it.  */
-const struct objfile_key<comp_unit> dwarf2_frame_objfile_data;
+static const registry<objfile>::key<comp_unit> dwarf2_frame_objfile_data;
 \f
 
 /* Pointer encoding helper functions.  */
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index c4578c687d2..470e92a6c48 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -124,7 +124,8 @@ static bool check_physname = false;
 static bool use_deprecated_index_sections = false;
 
 /* This is used to store the data that is always per objfile.  */
-static const objfile_key<dwarf2_per_objfile> dwarf2_objfile_data_key;
+static const registry<objfile>::key<dwarf2_per_objfile>
+     dwarf2_objfile_data_key;
 
 /* These are used to store the dwarf2_per_bfd objects.
 
@@ -134,8 +135,9 @@ static const objfile_key<dwarf2_per_objfile> dwarf2_objfile_data_key;
    Other objfiles are not going to share a dwarf2_per_bfd with any other
    objfiles, so they'll have their own version kept in the _objfile_data_key
    version.  */
-static const struct bfd_key<dwarf2_per_bfd> dwarf2_per_bfd_bfd_data_key;
-static const struct objfile_key<dwarf2_per_bfd> dwarf2_per_bfd_objfile_data_key;
+static const registry<bfd>::key<dwarf2_per_bfd> dwarf2_per_bfd_bfd_data_key;
+static const registry<objfile>::key<dwarf2_per_bfd>
+  dwarf2_per_bfd_objfile_data_key;
 
 /* The "aclass" indices for various kinds of computed DWARF symbols.  */
 
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 32cb27c8967..ec0deb5fd93 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -69,7 +69,7 @@ typedef std::vector<std::unique_ptr<probe>> elfread_data;
 
 /* Per-BFD data for probe info.  */
 
-static const struct bfd_key<elfread_data> probe_key;
+static const registry<bfd>::key<elfread_data> probe_key;
 
 /* Minimal symbols located at the GOT entries for .plt - that is the real
    pointer where the given entry will jump to.  It gets updated by the real
@@ -646,7 +646,7 @@ elf_rel_plt_read (minimal_symbol_reader &reader,
 
 /* The data pointer is htab_t for gnu_ifunc_record_cache_unchecked.  */
 
-static const struct objfile_key<htab, htab_deleter>
+static const registry<objfile>::key<htab, htab_deleter>
   elf_objfile_gnu_ifunc_cache_data;
 
 /* Map function names to CORE_ADDR in elf_objfile_gnu_ifunc_cache_data.  */
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index b241e855bd6..f2f961b5486 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -520,7 +520,7 @@ struct fbsd_pspace_data
 };
 
 /* Per-program-space data for FreeBSD architectures.  */
-static const struct program_space_key<fbsd_pspace_data>
+static const registry<program_space>::key<fbsd_pspace_data>
   fbsd_pspace_data_handle;
 
 static struct fbsd_pspace_data *
diff --git a/gdb/gdb-stabs.h b/gdb/gdb-stabs.h
index fef988524f2..5c697906cab 100644
--- a/gdb/gdb-stabs.h
+++ b/gdb/gdb-stabs.h
@@ -60,7 +60,7 @@ struct dbx_symfile_info
 
 /* The tag used to find the DBX info attached to an objfile.  This is
    global because it is referenced by several modules.  */
-extern objfile_key<dbx_symfile_info> dbx_objfile_data_key;
+extern const registry<objfile>::key<dbx_symfile_info> dbx_objfile_data_key;
 
 #define DBX_SYMFILE_INFO(o)	(dbx_objfile_data_key.get (o))
 #define DBX_TEXT_ADDR(o)	(DBX_SYMFILE_INFO(o)->text_addr)
diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c
index 22828482d5b..6c03ae5ef05 100644
--- a/gdb/gdb_bfd.c
+++ b/gdb/gdb_bfd.c
@@ -112,13 +112,15 @@ struct gdb_bfd_data
   std::vector<gdb_bfd_ref_ptr> included_bfds;
 
   /* The registry.  */
-  REGISTRY_FIELDS = {};
+  registry<bfd> registry_fields;
 };
 
-#define GDB_BFD_DATA_ACCESSOR(ABFD) \
-  ((struct gdb_bfd_data *) bfd_usrdata (ABFD))
-
-DEFINE_REGISTRY (bfd, GDB_BFD_DATA_ACCESSOR)
+registry<bfd> *
+registry_accessor<bfd>::get (bfd *abfd)
+{
+  struct gdb_bfd_data *gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
+  return &gdata->registry_fields;
+}
 
 /* A hash table storing all the BFDs maintained in the cache.  */
 
@@ -498,7 +500,6 @@ gdb_bfd_init_data (struct bfd *abfd, struct stat *st)
 
   gdata = new gdb_bfd_data (abfd, st);
   bfd_set_usrdata (abfd, gdata);
-  bfd_alloc_data (abfd);
 
   /* This is the first we've seen it, so add it to the hash table.  */
   slot = htab_find_slot (all_bfds, abfd, INSERT);
@@ -725,7 +726,6 @@ gdb_bfd_unref (struct bfd *abfd)
 	htab_clear_slot (gdb_bfd_cache, slot);
     }
 
-  bfd_free_data (abfd);
   delete gdata;
   bfd_set_usrdata (abfd, NULL);  /* Paranoia.  */
 
diff --git a/gdb/gdb_bfd.h b/gdb/gdb_bfd.h
index 6845d6ccef5..edd38f5c34d 100644
--- a/gdb/gdb_bfd.h
+++ b/gdb/gdb_bfd.h
@@ -26,7 +26,15 @@
 #include "gdbsupport/iterator-range.h"
 #include "gdbsupport/next-iterator.h"
 
-DECLARE_REGISTRY (bfd);
+struct gdb_bfd_data;
+
+/* A registry adaptor for BFD.  This arranges to store the registry in
+   gdb's per-BFD data, which is stored as the bfd_usrdata.  */
+template<>
+struct registry_accessor<bfd>
+{
+  static registry<bfd> *get (bfd *abfd);
+};
 
 /* If supplied a path starting with this sequence, gdb_bfd_open will
    open BFDs using target fileio operations.  */
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 9f49c15862f..6a732fe3586 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -6081,7 +6081,7 @@ typedef std::vector<std::unique_ptr<fixed_point_type_info>>
     fixed_point_type_storage;
 
 /* Key used for managing the storage of fixed-point type info.  */
-static const struct objfile_key<fixed_point_type_storage>
+static const struct registry<objfile>::key<fixed_point_type_storage>
     fixed_point_objfile_key;
 
 /* See gdbtypes.h.  */
@@ -6308,8 +6308,8 @@ gdbtypes_post_init (struct gdbarch *gdbarch)
 /* This set of objfile-based types is intended to be used by symbol
    readers as basic types.  */
 
-static const struct objfile_key<struct objfile_type,
-				gdb::noop_deleter<struct objfile_type>>
+static const registry<objfile>::key<struct objfile_type,
+				    gdb::noop_deleter<struct objfile_type>>
   objfile_type_data;
 
 const struct objfile_type *
diff --git a/gdb/guile/guile-internal.h b/gdb/guile/guile-internal.h
index 4cdb7e355d7..30cc5c307ae 100644
--- a/gdb/guile/guile-internal.h
+++ b/gdb/guile/guile-internal.h
@@ -28,6 +28,7 @@
 #include "extension-priv.h"
 #include "symtab.h"
 #include "libguile.h"
+#include "objfiles.h"
 
 struct block;
 struct frame_info;
@@ -272,7 +273,6 @@ struct eqable_gdb_smob
 #undef GDB_SMOB_HEAD
 
 struct objfile;
-struct objfile_data;
 
 /* A predicate that returns non-zero if an object is a particular kind
    of gsmob.  */
diff --git a/gdb/guile/scm-block.c b/gdb/guile/scm-block.c
index 41954c70519..a29c2db58f1 100644
--- a/gdb/guile/scm-block.c
+++ b/gdb/guile/scm-block.c
@@ -76,7 +76,37 @@ static scm_t_bits block_syms_progress_smob_tag;
 /* The "next!" block syms iterator method.  */
 static SCM bkscm_next_symbol_x_proc;
 
-static const struct objfile_data *bkscm_objfile_data_key;
+/* This is called when an objfile is about to be freed.
+   Invalidate the block as further actions on the block would result
+   in bad data.  All access to b_smob->block should be gated by
+   checks to ensure the block is (still) valid.  */
+struct bkscm_deleter
+{
+  /* Helper function for bkscm_del_objfile_blocks to mark the block
+     as invalid.  */
+
+  static int
+  bkscm_mark_block_invalid (void **slot, void *info)
+  {
+    block_smob *b_smob = (block_smob *) *slot;
+
+    b_smob->block = NULL;
+    b_smob->objfile = NULL;
+    return 1;
+  }
+
+  void operator() (htab_t htab)
+  {
+    if (htab != NULL)
+      {
+	htab_traverse_noresize (htab, bkscm_mark_block_invalid, NULL);
+	htab_delete (htab);
+      }
+  }
+};
+
+static const registry<objfile>::key<htab, bkscm_deleter>
+     bkscm_objfile_data_key;
 \f
 /* Administrivia for block smobs.  */
 
@@ -108,13 +138,13 @@ bkscm_eq_block_smob (const void *ap, const void *bp)
 static htab_t
 bkscm_objfile_block_map (struct objfile *objfile)
 {
-  htab_t htab = (htab_t) objfile_data (objfile, bkscm_objfile_data_key);
+  htab_t htab = bkscm_objfile_data_key.get (objfile);
 
   if (htab == NULL)
     {
       htab = gdbscm_create_eqable_gsmob_ptr_map (bkscm_hash_block_smob,
 						 bkscm_eq_block_smob);
-      set_objfile_data (objfile, bkscm_objfile_data_key, htab);
+      bkscm_objfile_data_key.set (objfile, htab);
     }
 
   return htab;
@@ -326,35 +356,6 @@ bkscm_scm_to_block (SCM block_scm, int arg_pos, const char *func_name,
   return NULL;
 }
 
-/* Helper function for bkscm_del_objfile_blocks to mark the block
-   as invalid.  */
-
-static int
-bkscm_mark_block_invalid (void **slot, void *info)
-{
-  block_smob *b_smob = (block_smob *) *slot;
-
-  b_smob->block = NULL;
-  b_smob->objfile = NULL;
-  return 1;
-}
-
-/* This function is called when an objfile is about to be freed.
-   Invalidate the block as further actions on the block would result
-   in bad data.  All access to b_smob->block should be gated by
-   checks to ensure the block is (still) valid.  */
-
-static void
-bkscm_del_objfile_blocks (struct objfile *objfile, void *datum)
-{
-  htab_t htab = (htab_t) datum;
-
-  if (htab != NULL)
-    {
-      htab_traverse_noresize (htab, bkscm_mark_block_invalid, NULL);
-      htab_delete (htab);
-    }
-}
 \f
 /* Block methods.  */
 
@@ -800,13 +801,3 @@ gdbscm_initialize_blocks (void)
 				gdbscm_scm_from_c_string ("\
 Internal function to assist the block symbols iterator."));
 }
-
-void _initialize_scm_block ();
-void
-_initialize_scm_block ()
-{
-  /* Register an objfile "free" callback so we can properly
-     invalidate blocks when an object file is about to be deleted.  */
-  bkscm_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, bkscm_del_objfile_blocks);
-}
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 6bbb6f81d68..4132bb246d8 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -74,7 +74,37 @@ static scm_t_bits frame_smob_tag;
 /* Keywords used in argument passing.  */
 static SCM block_keyword;
 
-static const struct inferior_data *frscm_inferior_data_key;
+/* This is called when an inferior is about to be freed.
+   Invalidate the frame as further actions on the frame could result
+   in bad data.  All access to the frame should be gated by
+   frscm_get_frame_smob_arg_unsafe which will raise an exception on
+   invalid frames.  */
+struct frscm_deleter
+{
+  /* Helper function for frscm_del_inferior_frames to mark the frame
+     as invalid.  */
+
+  static int
+  frscm_mark_frame_invalid (void **slot, void *info)
+  {
+    frame_smob *f_smob = (frame_smob *) *slot;
+
+    f_smob->inferior = NULL;
+    return 1;
+  }
+
+  void operator() (htab_t htab)
+  {
+    if (htab != NULL)
+      {
+	htab_traverse_noresize (htab, frscm_mark_frame_invalid, NULL);
+	htab_delete (htab);
+      }
+  }
+};
+
+static const registry<inferior>::key<htab, frscm_deleter>
+    frscm_inferior_data_key;
 \f
 /* Administrivia for frame smobs.  */
 
@@ -117,13 +147,13 @@ frscm_eq_frame_smob (const void *ap, const void *bp)
 static htab_t
 frscm_inferior_frame_map (struct inferior *inferior)
 {
-  htab_t htab = (htab_t) inferior_data (inferior, frscm_inferior_data_key);
+  htab_t htab = frscm_inferior_data_key.get (inferior);
 
   if (htab == NULL)
     {
       htab = gdbscm_create_eqable_gsmob_ptr_map (frscm_hash_frame_smob,
 						 frscm_eq_frame_smob);
-      set_inferior_data (inferior, frscm_inferior_data_key, htab);
+      frscm_inferior_data_key.set (inferior, htab);
     }
 
   return htab;
@@ -346,35 +376,6 @@ frscm_frame_smob_to_frame (frame_smob *f_smob)
   return frame;
 }
 
-/* Helper function for frscm_del_inferior_frames to mark the frame
-   as invalid.  */
-
-static int
-frscm_mark_frame_invalid (void **slot, void *info)
-{
-  frame_smob *f_smob = (frame_smob *) *slot;
-
-  f_smob->inferior = NULL;
-  return 1;
-}
-
-/* This function is called when an inferior is about to be freed.
-   Invalidate the frame as further actions on the frame could result
-   in bad data.  All access to the frame should be gated by
-   frscm_get_frame_smob_arg_unsafe which will raise an exception on
-   invalid frames.  */
-
-static void
-frscm_del_inferior_frames (struct inferior *inferior, void *datum)
-{
-  htab_t htab = (htab_t) datum;
-
-  if (htab != NULL)
-    {
-      htab_traverse_noresize (htab, frscm_mark_frame_invalid, NULL);
-      htab_delete (htab);
-    }
-}
 \f
 /* Frame methods.  */
 
@@ -1170,13 +1171,3 @@ gdbscm_initialize_frames (void)
 
   block_keyword = scm_from_latin1_keyword ("block");
 }
-
-void _initialize_scm_frame ();
-void
-_initialize_scm_frame ()
-{
-  /* Register an inferior "free" callback so we can properly
-     invalidate frames when an inferior file is about to be deleted.  */
-  frscm_inferior_data_key
-    = register_inferior_data_with_cleanup (NULL, frscm_del_inferior_frames);
-}
diff --git a/gdb/guile/scm-objfile.c b/gdb/guile/scm-objfile.c
index 760d5aa1f4b..1a87dcf74fa 100644
--- a/gdb/guile/scm-objfile.c
+++ b/gdb/guile/scm-objfile.c
@@ -49,7 +49,18 @@ static const char objfile_smob_name[] = "gdb:objfile";
 /* The tag Guile knows the objfile smob by.  */
 static scm_t_bits objfile_smob_tag;
 
-static const struct objfile_data *ofscm_objfile_data_key;
+/* Objfile registry cleanup handler for when an objfile is deleted.  */
+struct ofscm_deleter
+{
+  void operator() (objfile_smob *o_smob)
+  {
+    o_smob->objfile = NULL;
+    scm_gc_unprotect_object (o_smob->containing_scm);
+  }
+};
+
+static const registry<objfile>::key<objfile_smob, ofscm_deleter>
+     ofscm_objfile_data_key;
 
 /* Return the list of pretty-printers registered with O_SMOB.  */
 
@@ -101,27 +112,6 @@ ofscm_make_objfile_smob (void)
   return o_scm;
 }
 
-/* Clear the OBJFILE pointer in O_SMOB and unprotect the object from GC.  */
-
-static void
-ofscm_release_objfile (objfile_smob *o_smob)
-{
-  o_smob->objfile = NULL;
-  scm_gc_unprotect_object (o_smob->containing_scm);
-}
-
-/* Objfile registry cleanup handler for when an objfile is deleted.  */
-
-static void
-ofscm_handle_objfile_deleted (struct objfile *objfile, void *datum)
-{
-  objfile_smob *o_smob = (objfile_smob *) datum;
-
-  gdb_assert (o_smob->objfile == objfile);
-
-  ofscm_release_objfile (o_smob);
-}
-
 /* Return non-zero if SCM is a <gdb:objfile> object.  */
 
 static int
@@ -147,7 +137,7 @@ ofscm_objfile_smob_from_objfile (struct objfile *objfile)
 {
   objfile_smob *o_smob;
 
-  o_smob = (objfile_smob *) objfile_data (objfile, ofscm_objfile_data_key);
+  o_smob = ofscm_objfile_data_key.get (objfile);
   if (o_smob == NULL)
     {
       SCM o_scm = ofscm_make_objfile_smob ();
@@ -155,7 +145,7 @@ ofscm_objfile_smob_from_objfile (struct objfile *objfile)
       o_smob = (objfile_smob *) SCM_SMOB_DATA (o_scm);
       o_smob->objfile = objfile;
 
-      set_objfile_data (objfile, ofscm_objfile_data_key, o_smob);
+      ofscm_objfile_data_key.set (objfile, o_smob);
       scm_gc_protect_object (o_smob->containing_scm);
     }
 
@@ -424,11 +414,3 @@ gdbscm_initialize_objfiles (void)
 
   gdbscm_define_functions (objfile_functions, 1);
 }
-
-void _initialize_scm_objfile ();
-void
-_initialize_scm_objfile ()
-{
-  ofscm_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, ofscm_handle_objfile_deleted);
-}
diff --git a/gdb/guile/scm-progspace.c b/gdb/guile/scm-progspace.c
index c48da761945..7a197d76543 100644
--- a/gdb/guile/scm-progspace.c
+++ b/gdb/guile/scm-progspace.c
@@ -52,7 +52,18 @@ static const char pspace_smob_name[] = "gdb:progspace";
 /* The tag Guile knows the pspace smob by.  */
 static scm_t_bits pspace_smob_tag;
 
-static const struct program_space_data *psscm_pspace_data_key;
+/* Progspace registry cleanup handler for when a progspace is deleted.  */
+struct psscm_deleter
+{
+  void operator() (pspace_smob *p_smob)
+  {
+    p_smob->pspace = NULL;
+    scm_gc_unprotect_object (p_smob->containing_scm);
+  }
+};
+
+static const registry<program_space>::key<pspace_smob, psscm_deleter>
+     psscm_pspace_data_key;
 
 /* Return the list of pretty-printers registered with P_SMOB.  */
 
@@ -111,27 +122,6 @@ psscm_make_pspace_smob (void)
   return p_scm;
 }
 
-/* Clear the progspace pointer in P_SMOB and unprotect the object from GC.  */
-
-static void
-psscm_release_pspace (pspace_smob *p_smob)
-{
-  p_smob->pspace = NULL;
-  scm_gc_unprotect_object (p_smob->containing_scm);
-}
-
-/* Progspace registry cleanup handler for when a progspace is deleted.  */
-
-static void
-psscm_handle_pspace_deleted (struct program_space *pspace, void *datum)
-{
-  pspace_smob *p_smob = (pspace_smob *) datum;
-
-  gdb_assert (p_smob->pspace == pspace);
-
-  psscm_release_pspace (p_smob);
-}
-
 /* Return non-zero if SCM is a <gdb:progspace> object.  */
 
 static int
@@ -157,7 +147,7 @@ psscm_pspace_smob_from_pspace (struct program_space *pspace)
 {
   pspace_smob *p_smob;
 
-  p_smob = (pspace_smob *) program_space_data (pspace, psscm_pspace_data_key);
+  p_smob = psscm_pspace_data_key.get (pspace);
   if (p_smob == NULL)
     {
       SCM p_scm = psscm_make_pspace_smob ();
@@ -165,7 +155,7 @@ psscm_pspace_smob_from_pspace (struct program_space *pspace)
       p_smob = (pspace_smob *) SCM_SMOB_DATA (p_scm);
       p_smob->pspace = pspace;
 
-      set_program_space_data (pspace, psscm_pspace_data_key, p_smob);
+      psscm_pspace_data_key.set (pspace, p_smob);
       scm_gc_protect_object (p_smob->containing_scm);
     }
 
@@ -418,12 +408,3 @@ gdbscm_initialize_pspaces (void)
 
   gdbscm_define_functions (pspace_functions, 1);
 }
-
-void _initialize_scm_progspace ();
-void
-_initialize_scm_progspace ()
-{
-  psscm_pspace_data_key
-    = register_program_space_data_with_cleanup (NULL,
-						psscm_handle_pspace_deleted);
-}
diff --git a/gdb/guile/scm-symbol.c b/gdb/guile/scm-symbol.c
index 55eac3cfff6..0b96e5a02c1 100644
--- a/gdb/guile/scm-symbol.c
+++ b/gdb/guile/scm-symbol.c
@@ -49,7 +49,37 @@ static SCM block_keyword;
 static SCM domain_keyword;
 static SCM frame_keyword;
 
-static const struct objfile_data *syscm_objfile_data_key;
+/* This is called when an objfile is about to be freed.
+   Invalidate the symbol as further actions on the symbol would result
+   in bad data.  All access to s_smob->symbol should be gated by
+   syscm_get_valid_symbol_smob_arg_unsafe which will raise an exception on
+   invalid symbols.  */
+struct syscm_deleter
+{
+  /* Helper function for syscm_del_objfile_symbols to mark the symbol
+     as invalid.  */
+
+  static int
+  syscm_mark_symbol_invalid (void **slot, void *info)
+  {
+    symbol_smob *s_smob = (symbol_smob *) *slot;
+
+    s_smob->symbol = NULL;
+    return 1;
+  }
+
+  void operator() (htab_t htab)
+  {
+    if (htab != NULL)
+      {
+	htab_traverse_noresize (htab, syscm_mark_symbol_invalid, NULL);
+	htab_delete (htab);
+      }
+  }
+};
+
+static const registry<objfile>::key<htab, syscm_deleter>
+     syscm_objfile_data_key;
 static struct gdbarch_data *syscm_gdbarch_data_key;
 
 struct syscm_gdbarch_data
@@ -105,12 +135,12 @@ syscm_get_symbol_map (struct symbol *symbol)
     {
       struct objfile *objfile = symbol->objfile ();
 
-      htab = (htab_t) objfile_data (objfile, syscm_objfile_data_key);
+      htab = syscm_objfile_data_key.get (objfile);
       if (htab == NULL)
 	{
 	  htab = gdbscm_create_eqable_gsmob_ptr_map (syscm_hash_symbol_smob,
 						     syscm_eq_symbol_smob);
-	  set_objfile_data (objfile, syscm_objfile_data_key, htab);
+	  syscm_objfile_data_key.set (objfile, htab);
 	}
     }
   else
@@ -291,35 +321,6 @@ syscm_get_valid_symbol_arg_unsafe (SCM self, int arg_pos,
   return s_smob->symbol;
 }
 
-/* Helper function for syscm_del_objfile_symbols to mark the symbol
-   as invalid.  */
-
-static int
-syscm_mark_symbol_invalid (void **slot, void *info)
-{
-  symbol_smob *s_smob = (symbol_smob *) *slot;
-
-  s_smob->symbol = NULL;
-  return 1;
-}
-
-/* This function is called when an objfile is about to be freed.
-   Invalidate the symbol as further actions on the symbol would result
-   in bad data.  All access to s_smob->symbol should be gated by
-   syscm_get_valid_symbol_smob_arg_unsafe which will raise an exception on
-   invalid symbols.  */
-
-static void
-syscm_del_objfile_symbols (struct objfile *objfile, void *datum)
-{
-  htab_t htab = (htab_t) datum;
-
-  if (htab != NULL)
-    {
-      htab_traverse_noresize (htab, syscm_mark_symbol_invalid, NULL);
-      htab_delete (htab);
-    }
-}
 \f
 /* Symbol methods.  */
 
@@ -823,11 +824,6 @@ void _initialize_scm_symbol ();
 void
 _initialize_scm_symbol ()
 {
-  /* Register an objfile "free" callback so we can properly
-     invalidate symbols when an object file is about to be deleted.  */
-  syscm_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, syscm_del_objfile_symbols);
-
   /* Arch-specific symbol data.  */
   syscm_gdbarch_data_key
     = gdbarch_data_register_post_init (syscm_init_arch_symbols);
diff --git a/gdb/guile/scm-symtab.c b/gdb/guile/scm-symtab.c
index 518ceeaa15d..940823147bf 100644
--- a/gdb/guile/scm-symtab.c
+++ b/gdb/guile/scm-symtab.c
@@ -77,7 +77,37 @@ static const char sal_smob_name[] = "gdb:sal";
 static scm_t_bits symtab_smob_tag;
 static scm_t_bits sal_smob_tag;
 
-static const struct objfile_data *stscm_objfile_data_key;
+/* This is called when an objfile is about to be freed.
+   Invalidate the symbol table as further actions on the symbol table
+   would result in bad data.  All access to st_smob->symtab should be
+   gated by stscm_get_valid_symtab_smob_arg_unsafe which will raise an
+   exception on invalid symbol tables.  */
+struct stscm_deleter
+{
+  /* Helper function for stscm_del_objfile_symtabs to mark the symtab
+     as invalid.  */
+
+  static int
+  stscm_mark_symtab_invalid (void **slot, void *info)
+  {
+    symtab_smob *st_smob = (symtab_smob *) *slot;
+
+    st_smob->symtab = NULL;
+    return 1;
+  }
+
+  void operator() (htab_t htab)
+  {
+    if (htab != NULL)
+      {
+	htab_traverse_noresize (htab, stscm_mark_symtab_invalid, NULL);
+	htab_delete (htab);
+      }
+  }
+};
+
+static const registry<objfile>::key<htab, stscm_deleter>
+     stscm_objfile_data_key;
 \f
 /* Administrivia for symtab smobs.  */
 
@@ -110,13 +140,13 @@ static htab_t
 stscm_objfile_symtab_map (struct symtab *symtab)
 {
   struct objfile *objfile = symtab->compunit ()->objfile ();
-  htab_t htab = (htab_t) objfile_data (objfile, stscm_objfile_data_key);
+  htab_t htab = stscm_objfile_data_key.get (objfile);
 
   if (htab == NULL)
     {
       htab = gdbscm_create_eqable_gsmob_ptr_map (stscm_hash_symtab_smob,
 						 stscm_eq_symtab_smob);
-      set_objfile_data (objfile, stscm_objfile_data_key, htab);
+      stscm_objfile_data_key.set (objfile, htab);
     }
 
   return htab;
@@ -271,35 +301,6 @@ stscm_get_valid_symtab_smob_arg_unsafe (SCM self, int arg_pos,
   return st_smob;
 }
 
-/* Helper function for stscm_del_objfile_symtabs to mark the symtab
-   as invalid.  */
-
-static int
-stscm_mark_symtab_invalid (void **slot, void *info)
-{
-  symtab_smob *st_smob = (symtab_smob *) *slot;
-
-  st_smob->symtab = NULL;
-  return 1;
-}
-
-/* This function is called when an objfile is about to be freed.
-   Invalidate the symbol table as further actions on the symbol table
-   would result in bad data.  All access to st_smob->symtab should be
-   gated by stscm_get_valid_symtab_smob_arg_unsafe which will raise an
-   exception on invalid symbol tables.  */
-
-static void
-stscm_del_objfile_symtabs (struct objfile *objfile, void *datum)
-{
-  htab_t htab = (htab_t) datum;
-
-  if (htab != NULL)
-    {
-      htab_traverse_noresize (htab, stscm_mark_symtab_invalid, NULL);
-      htab_delete (htab);
-    }
-}
 \f
 /* Symbol table methods.  */
 
@@ -687,14 +688,3 @@ gdbscm_initialize_symtabs (void)
 
   gdbscm_define_functions (symtab_functions, 1);
 }
-
-void _initialize_scm_symtab ();
-void
-_initialize_scm_symtab ()
-{
-  /* Register an objfile "free" callback so we can properly
-     invalidate symbol tables, and symbol table and line data
-     structures when an object file that is about to be deleted.  */
-  stscm_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, stscm_del_objfile_symtabs);
-}
diff --git a/gdb/guile/scm-type.c b/gdb/guile/scm-type.c
index dd7eace8d40..2dadbefb3a4 100644
--- a/gdb/guile/scm-type.c
+++ b/gdb/guile/scm-type.c
@@ -81,7 +81,30 @@ static SCM tyscm_next_field_x_proc;
 /* Keywords used in argument passing.  */
 static SCM block_keyword;
 
-static const struct objfile_data *tyscm_objfile_data_key;
+static int tyscm_copy_type_recursive (void **slot, void *info);
+
+/* Called when an objfile is about to be deleted.
+   Make a copy of all types associated with OBJFILE.  */
+
+struct tyscm_deleter
+{
+  void operator() (htab_t htab)
+  {
+    if (!gdb_scheme_initialized)
+      return;
+
+    htab_up copied_types = create_copied_types_hash ();
+
+    if (htab != NULL)
+      {
+	htab_traverse_noresize (htab, tyscm_copy_type_recursive, copied_types.get ());
+	htab_delete (htab);
+      }
+  }
+};
+
+static const registry<objfile>::key<htab, tyscm_deleter>
+     tyscm_objfile_data_key;
 
 /* Hash table to uniquify global (non-objfile-owned) types.  */
 static htab_t global_types_map;
@@ -158,12 +181,12 @@ tyscm_type_map (struct type *type)
   if (objfile == NULL)
     return global_types_map;
 
-  htab = (htab_t) objfile_data (objfile, tyscm_objfile_data_key);
+  htab = tyscm_objfile_data_key.get (objfile);
   if (htab == NULL)
     {
       htab = gdbscm_create_eqable_gsmob_ptr_map (tyscm_hash_type_smob,
 						 tyscm_eq_type_smob);
-      set_objfile_data (objfile, tyscm_objfile_data_key, htab);
+      tyscm_objfile_data_key.set (objfile, htab);
     }
 
   return htab;
@@ -345,20 +368,17 @@ tyscm_scm_to_type (SCM t_scm)
   return t_smob->type;
 }
 
-/* Helper function for save_objfile_types to make a deep copy of the type.  */
+/* Helper function to make a deep copy of the type.  */
 
 static int
 tyscm_copy_type_recursive (void **slot, void *info)
 {
   type_smob *t_smob = (type_smob *) *slot;
   htab_t copied_types = (htab_t) info;
-  struct objfile *objfile = t_smob->type->objfile_owner ();
   htab_t htab;
   eqable_gdb_smob **new_slot;
   type_smob t_smob_for_lookup;
 
-  gdb_assert (objfile != NULL);
-
   htab_empty (copied_types);
   t_smob->type = copy_type_recursive (t_smob->type, copied_types);
 
@@ -380,25 +400,6 @@ tyscm_copy_type_recursive (void **slot, void *info)
   return 1;
 }
 
-/* Called when OBJFILE is about to be deleted.
-   Make a copy of all types associated with OBJFILE.  */
-
-static void
-save_objfile_types (struct objfile *objfile, void *datum)
-{
-  htab_t htab = (htab_t) datum;
-
-  if (!gdb_scheme_initialized)
-    return;
-
-  htab_up copied_types = create_copied_types_hash ();
-
-  if (htab != NULL)
-    {
-      htab_traverse_noresize (htab, tyscm_copy_type_recursive, copied_types.get ());
-      htab_delete (htab);
-    }
-}
 \f
 /* Administrivia for field smobs.  */
 
@@ -1510,13 +1511,3 @@ Internal function to assist the type fields iterator."));
   global_types_map = gdbscm_create_eqable_gsmob_ptr_map (tyscm_hash_type_smob,
 							 tyscm_eq_type_smob);
 }
-
-void _initialize_scm_type ();
-void
-_initialize_scm_type ()
-{
-  /* Register an objfile "free" callback so we can properly copy types
-     associated with the objfile when it's about to be deleted.  */
-  tyscm_objfile_data_key
-    = register_objfile_data_with_cleanup (save_objfile_types, NULL);
-}
diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index f9ececbb04f..80a1c0bbd4d 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -84,7 +84,8 @@ struct hppa_objfile_private
    that separately and make this static. The solib data is probably hpux-
    specific, so we can create a separate extern objfile_data that is registered
    by hppa-hpux-tdep.c and shared with pa64solib.c and somsolib.c.  */
-static const struct objfile_key<hppa_objfile_private> hppa_objfile_priv_data;
+static const registry<objfile>::key<hppa_objfile_private>
+  hppa_objfile_priv_data;
 
 /* Get at various relevant fields of an instruction word.  */
 #define MASK_5 0x1f
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 606b4189181..7eb2bd97907 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -38,11 +38,6 @@
 #include "gdbsupport/buildargv.h"
 #include "cli/cli-style.h"
 
-/* Keep a registry of per-inferior data-pointers required by other GDB
-   modules.  */
-
-DEFINE_REGISTRY (inferior, REGISTRY_ACCESS_FIELD)
-
 intrusive_list<inferior> inferior_list;
 static int highest_inferior_num;
 
@@ -76,18 +71,14 @@ inferior::~inferior ()
   inferior *inf = this;
 
   m_continuations.clear ();
-  inferior_free_data (inf);
   target_desc_info_free (inf->tdesc_info);
 }
 
 inferior::inferior (int pid_)
   : num (++highest_inferior_num),
     pid (pid_),
-    environment (gdb_environ::from_host_environ ()),
-    registry_data ()
+    environment (gdb_environ::from_host_environ ())
 {
-  inferior_alloc_data (this);
-
   m_target_stack.push (get_dummy_target ());
 }
 
diff --git a/gdb/inferior.h b/gdb/inferior.h
index f6e26a32feb..f6a7e7fd239 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -588,7 +588,7 @@ class inferior : public refcounted_object,
   displaced_step_inferior_state displaced_step_state;
 
   /* Per inferior data-pointers required by other GDB modules.  */
-  REGISTRY_FIELDS;
+  registry<inferior> registry_fields;
 
 private:
   /* The inferior's target stack.  */
@@ -608,11 +608,6 @@ class inferior : public refcounted_object,
   std::string m_cwd;
 };
 
-/* Keep a registry of per-inferior data-pointers required by other GDB
-   modules.  */
-
-DECLARE_REGISTRY (inferior);
-
 /* Add an inferior to the inferior list, print a message that a new
    inferior is found, and return the pointer to the new inferior.
    Caller may use this pointer to initialize the private inferior
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 9c7e2907625..5477624bcd5 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -599,7 +599,7 @@ child_pass_ctrlc (struct target_ops *self)
 }
 
 /* Per-inferior data key.  */
-static const struct inferior_key<terminal_info> inflow_inferior_data;
+static const registry<inferior>::key<terminal_info> inflow_inferior_data;
 
 terminal_info::~terminal_info ()
 {
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 4e728a06e7e..714825d96c1 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -235,7 +235,7 @@ struct linux_info
 };
 
 /* Per-inferior data key.  */
-static const struct inferior_key<linux_info> linux_inferior_data;
+static const registry<inferior>::key<linux_info> linux_inferior_data;
 
 /* Frees whatever allocated space there is to be freed and sets INF's
    linux cache data pointer to NULL.  */
diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c
index ca7c15ee63f..bf90471da63 100644
--- a/gdb/mdebugread.c
+++ b/gdb/mdebugread.c
@@ -1354,8 +1354,8 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char *ext_sh, int bigend,
 
 /* Basic types.  */
 
-static const struct objfile_key<struct type *,
-				gdb::noop_deleter<struct type *>>
+static const registry<objfile>::key<struct type *,
+				    gdb::noop_deleter<struct type *>>
   basic_type_data;
 
 static struct type *
diff --git a/gdb/minidebug.c b/gdb/minidebug.c
index e94768ac69c..dbbdf85e08c 100644
--- a/gdb/minidebug.c
+++ b/gdb/minidebug.c
@@ -28,7 +28,7 @@
 
 /* We stash a reference to the .gnu_debugdata BFD on the enclosing
    BFD.  */
-static const bfd_key<gdb_bfd_ref_ptr> gnu_debug_key;
+static const registry<bfd>::key<gdb_bfd_ref_ptr> gnu_debug_key;
 
 #include <lzma.h>
 
diff --git a/gdb/nto-tdep.c b/gdb/nto-tdep.c
index 9b08adfa18c..301d403eb13 100644
--- a/gdb/nto-tdep.c
+++ b/gdb/nto-tdep.c
@@ -51,7 +51,7 @@ static char default_nto_target[] = "";
 
 struct nto_target_ops current_nto_target;
 
-static const struct inferior_key<struct nto_inferior_data>
+static const registry<inferior>::key<struct nto_inferior_data>
   nto_inferior_data_reg;
 
 static char *
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 37008da529a..4429d4a7d44 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -76,7 +76,7 @@ struct objc_method {
   CORE_ADDR imp;
 };
 
-static const struct objfile_key<unsigned int> objc_objfile_data;
+static const registry<objfile>::key<unsigned int> objc_objfile_data;
 
 /* Lookup a structure type named "struct NAME", visible in lexical
    block BLOCK.  If NOERR is nonzero, return zero if NAME is not
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 80f68fda1c1..b9a59b4d96c 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -57,11 +57,6 @@
 #include <algorithm>
 #include <vector>
 
-/* Keep a registry of per-objfile data-pointers required by other GDB
-   modules.  */
-
-DEFINE_REGISTRY (objfile, REGISTRY_ACCESS_FIELD)
-
 /* Externally visible variables that are owned by this module.
    See declarations in objfile.h for more info.  */
 
@@ -85,7 +80,7 @@ struct objfile_pspace_info
 };
 
 /* Per-program-space data key.  */
-static const struct program_space_key<objfile_pspace_info>
+static const registry<program_space>::key<objfile_pspace_info>
   objfiles_pspace_data;
 
 objfile_pspace_info::~objfile_pspace_info ()
@@ -112,7 +107,7 @@ get_objfile_pspace_data (struct program_space *pspace)
 
 /* Per-BFD data key.  */
 
-static const struct bfd_key<objfile_per_bfd_storage> objfiles_bfd_data;
+static const registry<bfd>::key<objfile_per_bfd_storage> objfiles_bfd_data;
 
 objfile_per_bfd_storage::~objfile_per_bfd_storage ()
 {
@@ -329,8 +324,6 @@ objfile::objfile (bfd *abfd, const char *name, objfile_flags flags_)
      gdb_obstack.h specifies the alloc/dealloc functions.  */
   obstack_init (&objfile_obstack);
 
-  objfile_alloc_data (this);
-
   std::string name_holder;
   if (name == NULL)
     {
@@ -565,10 +558,6 @@ objfile::~objfile ()
   if (sf != NULL)
     (*sf->sym_finish) (this);
 
-  /* Discard any data modules have associated with the objfile.  The function
-     still may reference obfd.  */
-  objfile_free_data (this);
-
   if (obfd)
     gdb_bfd_unref (obfd);
   else
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index 9da12ff12e0..aee9b324b17 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -682,7 +682,7 @@ struct objfile
 
   /* Per objfile data-pointers required by other GDB modules.  */
 
-  REGISTRY_FIELDS {};
+  registry<objfile> registry_fields;
 
   /* Set of relocation offsets to apply to each section.
      The table is indexed by the_bfd_section->index, thus it is generally
@@ -900,10 +900,6 @@ in_plt_section (CORE_ADDR pc)
 	  || pc_in_section (pc, ".plt.sec"));
 }
 
-/* Keep a registry of per-objfile data-pointers required by other GDB
-   modules.  */
-DECLARE_REGISTRY(objfile);
-
 /* In normal use, the section map will be rebuilt by find_pc_section
    if objfiles have been added, removed or relocated since it was last
    called.  Calling inhibit_section_map_updates will inhibit this
diff --git a/gdb/progspace.c b/gdb/progspace.c
index 3232ea9ab01..7c801d2d960 100644
--- a/gdb/progspace.c
+++ b/gdb/progspace.c
@@ -43,24 +43,11 @@ static int highest_address_space_num;
 
 \f
 
-/* Keep a registry of per-program_space data-pointers required by other GDB
-   modules.  */
-
-DEFINE_REGISTRY (program_space, REGISTRY_ACCESS_FIELD)
-
-/* Keep a registry of per-address_space data-pointers required by other GDB
-   modules.  */
-
-DEFINE_REGISTRY (address_space, REGISTRY_ACCESS_FIELD)
-
-\f
-
 /* Create a new address space object, and add it to the list.  */
 
 address_space::address_space ()
   : m_num (++highest_address_space_num)
 {
-  address_space_alloc_data (this);
 }
 
 /* Maybe create a new address space object, and add it to the list, or
@@ -81,11 +68,6 @@ maybe_new_address_space (void)
   return new address_space ();
 }
 
-address_space::~address_space ()
-{
-  address_space_free_data (this);
-}
-
 /* Start counting over from scratch.  */
 
 static void
@@ -115,8 +97,6 @@ program_space::program_space (address_space *aspace_)
   : num (++last_program_space_num),
     aspace (aspace_)
 {
-  program_space_alloc_data (this);
-
   program_spaces.push_back (this);
 }
 
@@ -140,8 +120,6 @@ program_space::~program_space ()
   clear_symtab_users (SYMFILE_DEFER_BP_RESET);
   if (!gdbarch_has_shared_address_space (target_gdbarch ()))
     delete this->aspace;
-    /* Discard any data modules have associated with the PSPACE.  */
-  program_space_free_data (this);
 }
 
 /* See progspace.h.  */
diff --git a/gdb/progspace.h b/gdb/progspace.h
index eff157b0dd3..44836ff37aa 100644
--- a/gdb/progspace.h
+++ b/gdb/progspace.h
@@ -37,8 +37,7 @@ struct objfile;
 struct inferior;
 struct exec;
 struct address_space;
-struct program_space_data;
-struct address_space_data;
+struct program_space;
 struct so_list;
 
 typedef std::list<std::shared_ptr<objfile>> objfile_list;
@@ -372,7 +371,7 @@ struct program_space
   std::vector<std::string> deleted_solibs;
 
   /* Per pspace data-pointers required by other GDB modules.  */
-  REGISTRY_FIELDS {};
+  registry<program_space> registry_fields;
 
 private:
   /* The set of target sections matching the sections mapped into
@@ -387,7 +386,6 @@ struct address_space
 {
   /* Create a new address space object, and add it to the list.  */
   address_space ();
-  ~address_space ();
   DISABLE_COPY_AND_ASSIGN (address_space);
 
   /* Returns the integer address space id of this address space.  */
@@ -397,7 +395,7 @@ struct address_space
   }
 
   /* Per aspace data-pointers required by other GDB modules.  */
-  REGISTRY_FIELDS {};
+  registry<address_space> registry_fields;
 
 private:
   int m_num;
@@ -457,14 +455,4 @@ extern struct address_space *maybe_new_address_space (void);
    mappings.  */
 extern void update_address_spaces (void);
 
-/* Keep a registry of per-pspace data-pointers required by other GDB
-   modules.  */
-
-DECLARE_REGISTRY (program_space);
-
-/* Keep a registry of per-aspace data-pointers required by other GDB
-   modules.  */
-
-DECLARE_REGISTRY (address_space);
-
 #endif
diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c
index 872fb89ba83..b9aea3aca69 100644
--- a/gdb/python/py-block.c
+++ b/gdb/python/py-block.c
@@ -77,9 +77,33 @@ struct block_syms_iterator_object {
       }									\
   } while (0)
 
+/* This is called when an objfile is about to be freed.
+   Invalidate the block as further actions on the block would result
+   in bad data.  All access to obj->symbol should be gated by
+   BLPY_REQUIRE_VALID which will raise an exception on invalid
+   blocks.  */
+struct blpy_deleter
+{
+  void operator() (block_object *obj)
+  {
+    while (obj)
+      {
+	block_object *next = obj->next;
+
+	obj->block = NULL;
+	obj->objfile = NULL;
+	obj->next = NULL;
+	obj->prev = NULL;
+
+	obj = next;
+      }
+  }
+};
+
 extern PyTypeObject block_syms_iterator_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("block_syms_iterator_object");
-static const struct objfile_data *blpy_objfile_data_key;
+static const registry<objfile>::key<block_object, blpy_deleter>
+     blpy_objfile_data_key;
 
 static PyObject *
 blpy_iter (PyObject *self)
@@ -269,10 +293,7 @@ blpy_dealloc (PyObject *obj)
   if (block->prev)
     block->prev->next = block->next;
   else if (block->objfile)
-    {
-      set_objfile_data (block->objfile, blpy_objfile_data_key,
-			block->next);
-    }
+    blpy_objfile_data_key.set (block->objfile, block->next);
   if (block->next)
     block->next->prev = block->prev;
   block->block = NULL;
@@ -293,11 +314,10 @@ set_block (block_object *obj, const struct block *block,
   if (objfile)
     {
       obj->objfile = objfile;
-      obj->next = ((block_object *)
-		   objfile_data (objfile, blpy_objfile_data_key));
+      obj->next = blpy_objfile_data_key.get (objfile);
       if (obj->next)
 	obj->next->prev = obj;
-      set_objfile_data (objfile, blpy_objfile_data_key, obj);
+      blpy_objfile_data_key.set (objfile, obj);
     }
   else
     obj->next = NULL;
@@ -404,40 +424,6 @@ blpy_iter_is_valid (PyObject *self, PyObject *args)
   Py_RETURN_TRUE;
 }
 
-/* This function is called when an objfile is about to be freed.
-   Invalidate the block as further actions on the block would result
-   in bad data.  All access to obj->symbol should be gated by
-   BLPY_REQUIRE_VALID which will raise an exception on invalid
-   blocks.  */
-static void
-del_objfile_blocks (struct objfile *objfile, void *datum)
-{
-  block_object *obj = (block_object *) datum;
-
-  while (obj)
-    {
-      block_object *next = obj->next;
-
-      obj->block = NULL;
-      obj->objfile = NULL;
-      obj->next = NULL;
-      obj->prev = NULL;
-
-      obj = next;
-    }
-}
-
-void _initialize_py_block ();
-void
-_initialize_py_block ()
-{
-  /* Register an objfile "free" callback so we can properly
-     invalidate blocks when an object file is about to be
-     deleted.  */
-  blpy_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, del_objfile_blocks);
-}
-
 int
 gdbpy_initialize_blocks (void)
 {
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index ebcd5b0a70f..ac94d1322cc 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -60,7 +60,35 @@ struct inferior_object
 extern PyTypeObject inferior_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("inferior_object");
 
-static const struct inferior_data *infpy_inf_data_key;
+/* Deleter to clean up when an inferior is removed.  */
+struct infpy_deleter
+{
+  void operator() (inferior_object *obj)
+  {
+    struct threadlist_entry *th_entry, *th_tmp;
+
+    if (!gdb_python_initialized)
+      return;
+
+    gdbpy_enter enter_py;
+    gdbpy_ref<inferior_object> inf_obj (obj);
+
+    inf_obj->inferior = NULL;
+
+    /* Deallocate threads list.  */
+    for (th_entry = inf_obj->threads; th_entry != NULL;)
+      {
+	th_tmp = th_entry;
+	th_entry = th_entry->next;
+	delete th_tmp;
+      }
+
+    inf_obj->nthreads = 0;
+  }
+};
+
+static const registry<inferior>::key<inferior_object, infpy_deleter>
+     infpy_inf_data_key;
 
 /* Require that INFERIOR be a valid inferior ID.  */
 #define INFPY_REQUIRE_VALID(Inferior)				\
@@ -207,7 +235,7 @@ inferior_to_inferior_object (struct inferior *inferior)
 {
   inferior_object *inf_obj;
 
-  inf_obj = (inferior_object *) inferior_data (inferior, infpy_inf_data_key);
+  inf_obj = infpy_inf_data_key.get (inferior);
   if (!inf_obj)
     {
       inf_obj = PyObject_New (inferior_object, &inferior_object_type);
@@ -220,7 +248,7 @@ inferior_to_inferior_object (struct inferior *inferior)
 
       /* PyObject_New initializes the new object with a refcount of 1.  This
 	 counts for the reference we are keeping in the inferior data.  */
-      set_inferior_data (inferior, infpy_inf_data_key, inf_obj);
+      infpy_inf_data_key.set (inferior, inf_obj);
     }
 
   /* We are returning a new reference.  */
@@ -781,32 +809,6 @@ infpy_dealloc (PyObject *obj)
   Py_TYPE (obj)->tp_free (obj);
 }
 
-/* Clear the INFERIOR pointer in an Inferior object and clear the
-   thread list.  */
-static void
-py_free_inferior (struct inferior *inf, void *datum)
-{
-  struct threadlist_entry *th_entry, *th_tmp;
-
-  if (!gdb_python_initialized)
-    return;
-
-  gdbpy_enter enter_py;
-  gdbpy_ref<inferior_object> inf_obj ((inferior_object *) datum);
-
-  inf_obj->inferior = NULL;
-
-  /* Deallocate threads list.  */
-  for (th_entry = inf_obj->threads; th_entry != NULL;)
-    {
-      th_tmp = th_entry;
-      th_entry = th_entry->next;
-      delete th_tmp;
-    }
-
-  inf_obj->nthreads = 0;
-}
-
 /* Implementation of gdb.selected_inferior() -> gdb.Inferior.
    Returns the current inferior object.  */
 
@@ -817,14 +819,6 @@ gdbpy_selected_inferior (PyObject *self, PyObject *args)
 	  inferior_to_inferior_object (current_inferior ()).release ());
 }
 
-void _initialize_py_inferior ();
-void
-_initialize_py_inferior ()
-{
-  infpy_inf_data_key =
-    register_inferior_data_with_cleanup (NULL, py_free_inferior);
-}
-
 int
 gdbpy_initialize_inferior (void)
 {
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index 3e3270e7cd3..8954c2e5abb 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -55,7 +55,20 @@ struct objfile_object
 extern PyTypeObject objfile_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("objfile_object");
 
-static const struct objfile_data *objfpy_objfile_data_key;
+/* Clear the OBJFILE pointer in an Objfile object and remove the
+   reference.  */
+struct objfpy_deleter
+{
+  void operator() (objfile_object *obj)
+  {
+    gdbpy_enter enter_py;
+    gdbpy_ref<objfile_object> object (obj);
+    object->objfile = nullptr;
+  }
+};
+
+static const registry<objfile>::key<objfile_object, objfpy_deleter>
+     objfpy_objfile_data_key;
 
 /* Require that OBJF be a valid objfile.  */
 #define OBJFPY_REQUIRE_VALID(obj)				\
@@ -656,16 +669,6 @@ gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw)
 
 \f
 
-/* Clear the OBJFILE pointer in an Objfile object and remove the
-   reference.  */
-static void
-py_free_objfile (struct objfile *objfile, void *datum)
-{
-  gdbpy_enter enter_py (objfile->arch ());
-  gdbpy_ref<objfile_object> object ((objfile_object *) datum);
-  object->objfile = NULL;
-}
-
 /* Return a new reference to the Python object of type Objfile
    representing OBJFILE.  If the object has already been created,
    return it.  Otherwise, create it.  Return NULL and set the Python
@@ -675,7 +678,7 @@ gdbpy_ref<>
 objfile_to_objfile_object (struct objfile *objfile)
 {
   PyObject *result
-    = ((PyObject *) objfile_data (objfile, objfpy_objfile_data_key));
+    = (PyObject *) objfpy_objfile_data_key.get (objfile);
   if (result == NULL)
     {
       gdbpy_ref<objfile_object> object
@@ -686,21 +689,13 @@ objfile_to_objfile_object (struct objfile *objfile)
 	return NULL;
 
       object->objfile = objfile;
-      set_objfile_data (objfile, objfpy_objfile_data_key, object.get ());
+      objfpy_objfile_data_key.set (objfile, object.get ());
       result = (PyObject *) object.release ();
     }
 
   return gdbpy_ref<>::new_reference (result);
 }
 
-void _initialize_py_objfile ();
-void
-_initialize_py_objfile ()
-{
-  objfpy_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, py_free_objfile);
-}
-
 int
 gdbpy_initialize_objfile (void)
 {
diff --git a/gdb/python/py-progspace.c b/gdb/python/py-progspace.c
index 5657ef7756c..64a172dcdd3 100644
--- a/gdb/python/py-progspace.c
+++ b/gdb/python/py-progspace.c
@@ -57,7 +57,30 @@ struct pspace_object
 extern PyTypeObject pspace_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("pspace_object");
 
-static const struct program_space_data *pspy_pspace_data_key;
+/* Clear the PSPACE pointer in a Pspace object and remove the reference.  */
+struct pspace_deleter
+{
+  void operator() (pspace_object *obj)
+  {
+    /* This is a fiction, but we're in a nasty spot: The pspace is in the
+       process of being deleted, we can't rely on anything in it.  Plus
+       this is one time when the current program space and current inferior
+       are not in sync: All inferiors that use PSPACE may no longer exist.
+       We don't need to do much here, and since "there is always an inferior"
+       using target_gdbarch suffices.
+       Note: We cannot call get_current_arch because it may try to access
+       the target, which may involve accessing data in the pspace currently
+       being deleted.  */
+    struct gdbarch *arch = target_gdbarch ();
+
+    gdbpy_enter enter_py (arch);
+    gdbpy_ref<pspace_object> object (obj);
+    object->pspace = NULL;
+  }
+};
+
+static const registry<program_space>::key<pspace_object, pspace_deleter>
+     pspy_pspace_data_key;
 
 /* Require that PSPACE_OBJ be a valid program space ID.  */
 #define PSPY_REQUIRE_VALID(pspace_obj)				\
@@ -456,27 +479,6 @@ pspy_is_valid (PyObject *o, PyObject *args)
 
 \f
 
-/* Clear the PSPACE pointer in a Pspace object and remove the reference.  */
-
-static void
-py_free_pspace (struct program_space *pspace, void *datum)
-{
-  /* This is a fiction, but we're in a nasty spot: The pspace is in the
-     process of being deleted, we can't rely on anything in it.  Plus
-     this is one time when the current program space and current inferior
-     are not in sync: All inferiors that use PSPACE may no longer exist.
-     We don't need to do much here, and since "there is always an inferior"
-     using target_gdbarch suffices.
-     Note: We cannot call get_current_arch because it may try to access
-     the target, which may involve accessing data in the pspace currently
-     being deleted.  */
-  struct gdbarch *arch = target_gdbarch ();
-
-  gdbpy_enter enter_py (arch);
-  gdbpy_ref<pspace_object> object ((pspace_object *) datum);
-  object->pspace = NULL;
-}
-
 /* Return a new reference to the Python object of type Pspace
    representing PSPACE.  If the object has already been created,
    return it.  Otherwise, create it.  Return NULL and set the Python
@@ -485,8 +487,7 @@ py_free_pspace (struct program_space *pspace, void *datum)
 gdbpy_ref<>
 pspace_to_pspace_object (struct program_space *pspace)
 {
-  PyObject *result
-    ((PyObject *) program_space_data (pspace, pspy_pspace_data_key));
+  PyObject *result = (PyObject *) pspy_pspace_data_key.get (pspace);
   if (result == NULL)
     {
       gdbpy_ref<pspace_object> object
@@ -497,7 +498,7 @@ pspace_to_pspace_object (struct program_space *pspace)
 	return NULL;
 
       object->pspace = pspace;
-      set_program_space_data (pspace, pspy_pspace_data_key, object.get ());
+      pspy_pspace_data_key.set (pspace, object.get ());
       result = (PyObject *) object.release ();
     }
 
@@ -521,14 +522,6 @@ gdbpy_is_progspace (PyObject *obj)
   return PyObject_TypeCheck (obj, &pspace_object_type);
 }
 
-void _initialize_py_progspace ();
-void
-_initialize_py_progspace ()
-{
-  pspy_pspace_data_key
-    = register_program_space_data_with_cleanup (NULL, py_free_pspace);
-}
-
 int
 gdbpy_initialize_pspace (void)
 {
diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
index 02c35acd1e9..b5b8056f321 100644
--- a/gdb/python/py-symbol.c
+++ b/gdb/python/py-symbol.c
@@ -50,7 +50,26 @@ struct symbol_object {
       }							\
   } while (0)
 
-static const struct objfile_data *sympy_objfile_data_key;
+/* A deleter that is used when an objfile is about to be freed.  */
+struct symbol_object_deleter
+{
+  void operator() (symbol_object *obj)
+  {
+    while (obj)
+      {
+	symbol_object *next = obj->next;
+
+	obj->symbol = NULL;
+	obj->next = NULL;
+	obj->prev = NULL;
+
+	obj = next;
+      }
+  }
+};
+
+static const registry<objfile>::key<symbol_object, symbol_object_deleter>
+     sympy_objfile_data_key;
 
 static PyObject *
 sympy_str (PyObject *self)
@@ -307,11 +326,10 @@ set_symbol (symbol_object *obj, struct symbol *symbol)
     {
       struct objfile *objfile = symbol->objfile ();
 
-      obj->next = ((symbol_object *)
-		   objfile_data (objfile, sympy_objfile_data_key));
+      obj->next = sympy_objfile_data_key.get (objfile);
       if (obj->next)
 	obj->next->prev = obj;
-      set_objfile_data (objfile, sympy_objfile_data_key, obj);
+      sympy_objfile_data_key.set (objfile, obj);
     }
   else
     obj->next = NULL;
@@ -350,10 +368,7 @@ sympy_dealloc (PyObject *obj)
   else if (sym_obj->symbol != NULL
 	   && sym_obj->symbol->is_objfile_owned ()
 	   && sym_obj->symbol->symtab () != NULL)
-    {
-      set_objfile_data (sym_obj->symbol->objfile (),
-			sympy_objfile_data_key, sym_obj->next);
-    }
+    sympy_objfile_data_key.set (sym_obj->symbol->objfile (), sym_obj->next);
   if (sym_obj->next)
     sym_obj->next->prev = sym_obj->prev;
   sym_obj->symbol = NULL;
@@ -597,38 +612,6 @@ gdbpy_lookup_static_symbols (PyObject *self, PyObject *args, PyObject *kw)
   return return_list.release ();
 }
 
-/* This function is called when an objfile is about to be freed.
-   Invalidate the symbol as further actions on the symbol would result
-   in bad data.  All access to obj->symbol should be gated by
-   SYMPY_REQUIRE_VALID which will raise an exception on invalid
-   symbols.  */
-static void
-del_objfile_symbols (struct objfile *objfile, void *datum)
-{
-  symbol_object *obj = (symbol_object *) datum;
-  while (obj)
-    {
-      symbol_object *next = obj->next;
-
-      obj->symbol = NULL;
-      obj->next = NULL;
-      obj->prev = NULL;
-
-      obj = next;
-    }
-}
-
-void _initialize_py_symbol ();
-void
-_initialize_py_symbol ()
-{
-  /* Register an objfile "free" callback so we can properly
-     invalidate symbol when an object file that is about to be
-     deleted.  */
-  sympy_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, del_objfile_symbols);
-}
-
 int
 gdbpy_initialize_symbols (void)
 {
diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
index 7ed62716b67..03c274dfff6 100644
--- a/gdb/python/py-symtab.c
+++ b/gdb/python/py-symtab.c
@@ -37,9 +37,31 @@ struct symtab_object {
   symtab_object *next;
 };
 
+/* This function is called when an objfile is about to be freed.
+   Invalidate the symbol table as further actions on the symbol table
+   would result in bad data.  All access to obj->symtab should be
+   gated by STPY_REQUIRE_VALID which will raise an exception on
+   invalid symbol tables.  */
+struct stpy_deleter
+{
+  void operator() (symtab_object *obj)
+  {
+    while (obj)
+      {
+	symtab_object *next = obj->next;
+
+	obj->symtab = NULL;
+	obj->next = NULL;
+	obj->prev = NULL;
+	obj = next;
+      }
+  }
+};
+
 extern PyTypeObject symtab_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("symtab_object");
-static const struct objfile_data *stpy_objfile_data_key;
+static const registry<objfile>::key<symtab_object, stpy_deleter>
+     stpy_objfile_data_key;
 
 /* Require a valid symbol table.  All access to symtab_object->symtab
    should be gated by this call.  */
@@ -68,9 +90,39 @@ struct sal_object {
   sal_object *next;
 };
 
+/* This is called when an objfile is about to be freed.  Invalidate
+   the sal object as further actions on the sal would result in bad
+   data.  All access to obj->sal should be gated by
+   SALPY_REQUIRE_VALID which will raise an exception on invalid symbol
+   table and line objects.  */
+struct salpy_deleter
+{
+  void operator() (sal_object *obj)
+  {
+    gdbpy_enter enter_py;
+
+    while (obj)
+      {
+	sal_object *next = obj->next;
+
+	gdbpy_ref<> tmp (obj->symtab);
+	obj->symtab = Py_None;
+	Py_INCREF (Py_None);
+
+	obj->next = NULL;
+	obj->prev = NULL;
+	xfree (obj->sal);
+	obj->sal = NULL;
+
+	obj = next;
+      }
+  }
+};
+
 extern PyTypeObject sal_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("sal_object");
-static const struct objfile_data *salpy_objfile_data_key;
+static const registry<objfile>::key<sal_object, salpy_deleter>
+     salpy_objfile_data_key;
 
 /* Require a valid symbol table and line object.  All access to
    sal_object->sal should be gated by this call.  */
@@ -246,10 +298,8 @@ stpy_dealloc (PyObject *obj)
   if (symtab->prev)
     symtab->prev->next = symtab->next;
   else if (symtab->symtab)
-    {
-      set_objfile_data (symtab->symtab->compunit ()->objfile (),
-			stpy_objfile_data_key, symtab->next);
-    }
+    stpy_objfile_data_key.set (symtab->symtab->compunit ()->objfile (),
+			       symtab->next);
   if (symtab->next)
     symtab->next->prev = symtab->prev;
   symtab->symtab = NULL;
@@ -329,9 +379,9 @@ salpy_dealloc (PyObject *self)
   if (self_sal->prev)
     self_sal->prev->next = self_sal->next;
   else if (self_sal->symtab != Py_None)
-    set_objfile_data
+    salpy_objfile_data_key.set
       (symtab_object_to_symtab (self_sal->symtab)->compunit ()->objfile (),
-       salpy_objfile_data_key, self_sal->next);
+       self_sal->next);
 
   if (self_sal->next)
     self_sal->next->prev = self_sal->prev;
@@ -378,13 +428,11 @@ set_sal (sal_object *sal_obj, struct symtab_and_line sal)
       symtab *symtab = symtab_object_to_symtab (sal_obj->symtab);
 
       sal_obj->next
-	= ((sal_object *) objfile_data (symtab->compunit ()->objfile (),
-					salpy_objfile_data_key));
+	= salpy_objfile_data_key.get (symtab->compunit ()->objfile ());
       if (sal_obj->next)
 	sal_obj->next->prev = sal_obj;
 
-      set_objfile_data (symtab->compunit ()->objfile (),
-			salpy_objfile_data_key, sal_obj);
+      salpy_objfile_data_key.set (symtab->compunit ()->objfile (), sal_obj);
     }
   else
     sal_obj->next = NULL;
@@ -404,14 +452,10 @@ set_symtab (symtab_object *obj, struct symtab *symtab)
   obj->prev = NULL;
   if (symtab)
     {
-      obj->next
-	= ((symtab_object *)
-	   objfile_data (symtab->compunit ()->objfile (),
-			 stpy_objfile_data_key));
+      obj->next = stpy_objfile_data_key.get (symtab->compunit ()->objfile ());
       if (obj->next)
 	obj->next->prev = obj;
-      set_objfile_data (symtab->compunit ()->objfile (),
-			stpy_objfile_data_key, obj);
+      stpy_objfile_data_key.set (symtab->compunit ()->objfile (), obj);
     }
   else
     obj->next = NULL;
@@ -465,68 +509,6 @@ symtab_object_to_symtab (PyObject *obj)
   return ((symtab_object *) obj)->symtab;
 }
 
-/* This function is called when an objfile is about to be freed.
-   Invalidate the symbol table as further actions on the symbol table
-   would result in bad data.  All access to obj->symtab should be
-   gated by STPY_REQUIRE_VALID which will raise an exception on
-   invalid symbol tables.  */
-static void
-del_objfile_symtab (struct objfile *objfile, void *datum)
-{
-  symtab_object *obj = (symtab_object *) datum;
-
-  while (obj)
-    {
-      symtab_object *next = obj->next;
-
-      obj->symtab = NULL;
-      obj->next = NULL;
-      obj->prev = NULL;
-      obj = next;
-    }
-}
-
-/* This function is called when an objfile is about to be freed.
-   Invalidate the sal object as further actions on the sal
-   would result in bad data.  All access to obj->sal should be
-   gated by SALPY_REQUIRE_VALID which will raise an exception on
-   invalid symbol table and line objects.  */
-static void
-del_objfile_sal (struct objfile *objfile, void *datum)
-{
-  sal_object *obj = (sal_object *) datum;
-
-  while (obj)
-    {
-      sal_object *next = obj->next;
-
-      gdbpy_ref<> tmp (obj->symtab);
-      obj->symtab = Py_None;
-      Py_INCREF (Py_None);
-
-      obj->next = NULL;
-      obj->prev = NULL;
-      xfree (obj->sal);
-      obj->sal = NULL;
-
-      obj = next;
-    }
-}
-
-void _initialize_py_symtab ();
-void
-_initialize_py_symtab ()
-{
-  /* Register an objfile "free" callback so we can properly
-     invalidate symbol tables, and symbol table and line data
-     structures when an object file that is about to be
-     deleted.  */
-  stpy_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, del_objfile_symtab);
-  salpy_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, del_objfile_sal);
-}
-
 int
 gdbpy_initialize_symtabs (void)
 {
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 6cbf5f2eb6a..068a212b77b 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -1111,36 +1111,38 @@ typy_richcompare (PyObject *self, PyObject *other, int op)
 
 \f
 
-static const struct objfile_data *typy_objfile_data_key;
-
-static void
-save_objfile_types (struct objfile *objfile, void *datum)
+/* Deleter that saves types when an objfile is being destroyed.  */
+struct typy_deleter
 {
-  type_object *obj = (type_object *) datum;
+  void operator() (type_object *obj)
+  {
+    if (!gdb_python_initialized)
+      return;
 
-  if (!gdb_python_initialized)
-    return;
+    /* This prevents another thread from freeing the objects we're
+       operating on.  */
+    gdbpy_enter enter_py;
 
-  /* This prevents another thread from freeing the objects we're
-     operating on.  */
-  gdbpy_enter enter_py (objfile->arch ());
+    htab_up copied_types = create_copied_types_hash ();
 
-  htab_up copied_types = create_copied_types_hash ();
+    while (obj)
+      {
+	type_object *next = obj->next;
 
-  while (obj)
-    {
-      type_object *next = obj->next;
+	htab_empty (copied_types.get ());
 
-      htab_empty (copied_types.get ());
+	obj->type = copy_type_recursive (obj->type, copied_types.get ());
 
-      obj->type = copy_type_recursive (obj->type, copied_types.get ());
+	obj->next = NULL;
+	obj->prev = NULL;
 
-      obj->next = NULL;
-      obj->prev = NULL;
+	obj = next;
+      }
+  }
+};
 
-      obj = next;
-    }
-}
+static const registry<objfile>::key<type_object, typy_deleter>
+     typy_objfile_data_key;
 
 static void
 set_type (type_object *obj, struct type *type)
@@ -1151,11 +1153,10 @@ set_type (type_object *obj, struct type *type)
     {
       struct objfile *objfile = type->objfile_owner ();
 
-      obj->next = ((type_object *)
-		   objfile_data (objfile, typy_objfile_data_key));
+      obj->next = typy_objfile_data_key.get (objfile);
       if (obj->next)
 	obj->next->prev = obj;
-      set_objfile_data (objfile, typy_objfile_data_key, obj);
+      typy_objfile_data_key.set (objfile, obj);
     }
   else
     obj->next = NULL;
@@ -1174,7 +1175,7 @@ typy_dealloc (PyObject *obj)
       struct objfile *objfile = type->type->objfile_owner ();
 
       if (objfile)
-	set_objfile_data (objfile, typy_objfile_data_key, type->next);
+	typy_objfile_data_key.set (objfile, type->next);
     }
   if (type->next)
     type->next->prev = type->prev;
@@ -1466,14 +1467,6 @@ gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw)
   return type_to_type_object (type);
 }
 
-void _initialize_py_type ();
-void
-_initialize_py_type ()
-{
-  typy_objfile_data_key
-    = register_objfile_data_with_cleanup (save_objfile_types, NULL);
-}
-
 int
 gdbpy_initialize_types (void)
 {
diff --git a/gdb/registry.c b/gdb/registry.c
deleted file mode 100644
index 2e977e2528f..00000000000
--- a/gdb/registry.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/* Support functions for general registry objects.
-
-   Copyright (C) 2011-2022 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 "registry.h"
-const struct registry_data *
-register_data_with_cleanup (struct registry_data_registry *registry,
-			    registry_data_callback save,
-			    registry_data_callback free)
-{
-  struct registry_data_registration **curr;
-
-  /* Append new registration.  */
-  for (curr = &registry->registrations;
-       *curr != NULL;
-       curr = &(*curr)->next)
-    ;
-
-  *curr = XNEW (struct registry_data_registration);
-  (*curr)->next = NULL;
-  (*curr)->data = XNEW (struct registry_data);
-  (*curr)->data->index = registry->num_registrations++;
-  (*curr)->data->save = save;
-  (*curr)->data->free = free;
-
-  return (*curr)->data;
-}
-
-void
-registry_alloc_data (struct registry_data_registry *registry,
-		       struct registry_fields *fields)
-{
-  gdb_assert (fields->data == NULL);
-  fields->num_data = registry->num_registrations;
-  fields->data = XCNEWVEC (void *, fields->num_data);
-}
-
-void
-registry_clear_data (struct registry_data_registry *data_registry,
-		     registry_callback_adaptor adaptor,
-		     struct registry_container *container,
-		     struct registry_fields *fields)
-{
-  struct registry_data_registration *registration;
-  int i;
-
-  gdb_assert (fields->data != NULL);
-
-  /* Process all the save handlers.  */
-
-  for (registration = data_registry->registrations, i = 0;
-       i < fields->num_data;
-       registration = registration->next, i++)
-    if (fields->data[i] != NULL && registration->data->save != NULL)
-      adaptor (registration->data->save, container, fields->data[i]);
-
-  /* Now process all the free handlers.  */
-
-  for (registration = data_registry->registrations, i = 0;
-       i < fields->num_data;
-       registration = registration->next, i++)
-    if (fields->data[i] != NULL && registration->data->free != NULL)
-      adaptor (registration->data->free, container, fields->data[i]);
-
-  memset (fields->data, 0, fields->num_data * sizeof (void *));
-}
-
-void
-registry_container_free_data (struct registry_data_registry *data_registry,
-			      registry_callback_adaptor adaptor,
-			      struct registry_container *container,
-			      struct registry_fields *fields)
-{
-  void ***rdata = &fields->data;
-  gdb_assert (*rdata != NULL);
-  registry_clear_data (data_registry, adaptor, container, fields);
-  xfree (*rdata);
-  *rdata = NULL;
-}
-
-void
-registry_set_data (struct registry_fields *fields,
-		   const struct registry_data *data,
-		   void *value)
-{
-  gdb_assert (data->index < fields->num_data);
-  fields->data[data->index] = value;
-}
-
-void *
-registry_data (struct registry_fields *fields,
-	       const struct registry_data *data)
-{
-  gdb_assert (data->index < fields->num_data);
-  return fields->data[data->index];
-}
diff --git a/gdb/registry.h b/gdb/registry.h
index 1475fd2ec26..27592ff6e2a 100644
--- a/gdb/registry.h
+++ b/gdb/registry.h
@@ -22,288 +22,213 @@
 
 #include <type_traits>
 
-/* The macros here implement a template type and functions for
-   associating some user data with a container object.
-
-   A registry is associated with a struct tag name.  To attach a
-   registry to a structure, use DEFINE_REGISTRY.  This takes the
-   structure tag and an access method as arguments.  In the usual
-   case, where the registry fields appear directly in the struct, you
-   can use the 'REGISTRY_FIELDS' macro to declare the fields in the
-   struct definition, and you can pass 'REGISTRY_ACCESS_FIELD' as the
-   access argument to DEFINE_REGISTRY.  In other cases, use
-   REGISTRY_FIELDS to define the fields in the appropriate spot, and
-   then define your own accessor to find the registry field structure
-   given an instance of your type.
-
-   The API user requests a key from a registry during gdb
-   initialization.  Later this key can be used to associate some
-   module-specific data with a specific container object.
-
-   The exported API is best used via the wrapper macros:
-   
-   - register_TAG_data(TAG)
-   Get a new key for the container type TAG.
-   
-   - register_TAG_data_with_cleanup(TAG, SAVE, FREE)
-   Get a new key for the container type TAG.
-   SAVE and FREE are defined as void (*) (struct TAG *object, void *data)
-   When the container object OBJECT is destroyed, first all registered SAVE
-   functions are called.
-   Then all FREE functions are called.
-   Either or both may be NULL.  DATA is the data associated with the
-   container object OBJECT.
-   
-   - clear_TAG_data(TAG, OBJECT)
-   Clear all the data associated with OBJECT.  Should be called by the
-   container implementation when a container object is destroyed.
-   
-   - set_TAG_data(TAG, OBJECT, KEY, DATA)
-   Set the data on an object.
-   
-   - TAG_data(TAG, OBJECT, KEY)
-   Fetch the data for an object; returns NULL if it has not been set.
-*/
-
-/* This structure is used in a container to hold the data that the
-   registry uses.  */
-
-struct registry_fields
-{
-  void **data;
-  unsigned num_data;
-};
+template<typename T> class registry;
 
-/* This macro is used in a container struct definition to define the
-   fields used by the registry code.  */
+/* An accessor class that is used by registry_key.
 
-#define REGISTRY_FIELDS				\
-  struct registry_fields registry_data
+   Normally, a container class derives from registry<>.  In this case,
+   the default accessor is used, as it simply returns the object.
 
-/* A convenience macro for the typical case where the registry data is
-   kept as fields of the object.  This can be passed as the ACCESS
-   method to DEFINE_REGISTRY.  */
+   However, a container may sometimes need to store the registry
+   elsewhere.  In this case, registry_accessor can be specialized to
+   perform the needed indirection.  */
 
-#define REGISTRY_ACCESS_FIELD(CONTAINER) \
-  (CONTAINER)
+template<typename T>
+struct registry_accessor
+{
+  /* Given a container of type T, return its registry.  */
+  static registry<T> *get (T *obj)
+  {
+    return &obj->registry_fields;
+  }
+};
 
-/* Opaque type representing a container type with a registry.  This
-   type is never defined.  This is used to factor out common
-   functionality of all struct tag names into common code.  IOW,
-   "struct tag name" pointers are cast to and from "struct
-   registry_container" pointers when calling the common registry
-   "backend" functions.  */
-struct registry_container;
+/* In gdb, sometimes there is a need for one module (e.g., the Python
+   Type code) to attach some data to another object (e.g., an
+   objfile); but it's also desirable that this be done such that the
+   base object (the objfile in this example) not need to know anything
+   about the attaching module (the Python code).
 
-/* Registry callbacks have this type.  */
-typedef void (*registry_data_callback) (struct registry_container *, void *);
+   This is handled using the registry system.
 
-struct registry_data
-{
-  unsigned index;
-  registry_data_callback save;
-  registry_data_callback free;
-};
+   A class needing to allow this sort registration can add a registry
+   field.  For example, you would write:
 
-struct registry_data_registration
-{
-  struct registry_data *data;
-  struct registry_data_registration *next;
-};
+   class some_container { registry<some_container> registry_fields; };
 
-struct registry_data_registry
-{
-  struct registry_data_registration *registrations;
-  unsigned num_registrations;
-};
+   The name of the field matters by default, see registry_accessor.
+
+   A module wanting to attach data to instances of some_container uses
+   the "key" class to register a key.  This key can then be passed to
+   the "get" and "set" methods to handle this module's data.  */
 
-/* Registry backend functions.  Client code uses the frontend
-   functions defined by DEFINE_REGISTRY below instead.  */
-
-const struct registry_data *register_data_with_cleanup
-  (struct registry_data_registry *registry,
-   registry_data_callback save,
-   registry_data_callback free);
-
-void registry_alloc_data (struct registry_data_registry *registry,
-			  struct registry_fields *registry_fields);
-
-/* Cast FUNC and CONTAINER to the real types, and call FUNC, also
-   passing DATA.  */
-typedef void (*registry_callback_adaptor) (registry_data_callback func,
-					   struct registry_container *container,
-					   void *data);
-
-void registry_clear_data (struct registry_data_registry *data_registry,
-			  registry_callback_adaptor adaptor,
-			  struct registry_container *container,
-			  struct registry_fields *fields);
-
-void registry_container_free_data (struct registry_data_registry *data_registry,
-				   registry_callback_adaptor adaptor,
-				   struct registry_container *container,
-				   struct registry_fields *fields);
-
-void registry_set_data (struct registry_fields *fields,
-			const struct registry_data *data,
-			void *value);
-
-void *registry_data (struct registry_fields *fields,
-		     const struct registry_data *data);
-
-/* Define a new registry implementation.  */
-
-#define DEFINE_REGISTRY(TAG, ACCESS)					\
-static struct registry_data_registry TAG ## _data_registry = { NULL, 0 }; \
-									\
-const struct TAG ## _data *						\
-register_ ## TAG ## _data_with_cleanup (void (*save) (struct TAG *, void *), \
-					void (*free) (struct TAG *, void *)) \
-{									\
-  return (struct TAG ## _data *)					\
-    register_data_with_cleanup (&TAG ## _data_registry,			\
-				(registry_data_callback) save,		\
-				(registry_data_callback) free);		\
-}									\
-									\
-const struct TAG ## _data *						\
-register_ ## TAG ## _data (void)					\
-{									\
-  return register_ ## TAG ## _data_with_cleanup (NULL, NULL);		\
-}									\
-									\
-static void								\
-TAG ## _alloc_data (struct TAG *container)				\
-{									\
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-									\
-  registry_alloc_data (&TAG ## _data_registry, rdata);			\
-}									\
-									\
-static void								\
-TAG ## registry_callback_adaptor (registry_data_callback func,		\
-				  struct registry_container *container, \
-				  void *data)				\
-{									\
-  struct TAG *tagged_container = (struct TAG *) container;		\
-									\
-  registry_ ## TAG ## _callback tagged_func				\
-    = (registry_ ## TAG ## _callback) func;				\
-									\
-  tagged_func (tagged_container, data);					\
-}									\
-									\
-void									\
-clear_ ## TAG ## _data (struct TAG *container)				\
-{									\
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-									\
-  registry_clear_data (&TAG ## _data_registry,				\
-		       TAG ## registry_callback_adaptor,		\
-		       (struct registry_container *) container,		\
-		       rdata);						\
-}									\
-									\
-static void								\
-TAG ## _free_data (struct TAG *container)				\
-{									\
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-									\
-  registry_container_free_data (&TAG ## _data_registry,			\
-				TAG ## registry_callback_adaptor,	\
-				(struct registry_container *) container, \
-				rdata);					\
-}									\
-									\
-void									\
-set_ ## TAG ## _data (struct TAG *container,				\
-		      const struct TAG ## _data *data,			\
-		      void *value)					\
-{									\
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-									\
-  registry_set_data (rdata,						\
-		     (struct registry_data *) data,			\
-		     value);						\
-}									\
-									\
-void *									\
-TAG ## _data (struct TAG *container, const struct TAG ## _data *data)	\
-{									\
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-									\
-  return registry_data (rdata,						\
-			(struct registry_data *) data);			\
-}
-
-
-/* External declarations for the registry functions.  */
-
-#define DECLARE_REGISTRY(TAG)						\
-struct TAG ## _data;							\
-typedef void (*registry_ ## TAG ## _callback) (struct TAG *, void *);	\
-extern const struct TAG ## _data *register_ ## TAG ## _data (void);	\
-extern const struct TAG ## _data *register_ ## TAG ## _data_with_cleanup \
- (registry_ ## TAG ## _callback save, registry_ ## TAG ## _callback free); \
-extern void clear_ ## TAG ## _data (struct TAG *);			\
-extern void set_ ## TAG ## _data (struct TAG *,				\
-				  const struct TAG ## _data *data,	\
-				  void *value);				\
-extern void *TAG ## _data (struct TAG *,				\
-			   const struct TAG ## _data *data);		\
-									\
-template<typename DATA, typename Deleter = std::default_delete<DATA>>	\
-class TAG ## _key							\
-{									\
-public:									\
-									\
-  TAG ## _key ()							\
-    : m_key (register_ ## TAG ## _data_with_cleanup (nullptr,		\
-						     cleanup))		\
-  {									\
-  }									\
-									\
-  DATA *get (struct TAG *obj) const					\
-  {									\
-    return (DATA *) TAG ## _data (obj, m_key);				\
-  }									\
-									\
-  void set (struct TAG *obj, DATA *data) const				\
-  {									\
-    set_ ## TAG ## _data (obj, m_key, data);				\
-  }									\
-									\
-  template<typename Dummy = DATA *, typename... Args>			\
-  typename std::enable_if<std::is_same<Deleter,				\
-				       std::default_delete<DATA>>::value, \
-			  Dummy>::type					\
-  emplace (struct TAG *obj, Args &&...args) const			\
-  {									\
-    DATA *result = new DATA (std::forward<Args> (args)...);		\
-    set (obj, result);							\
-    return result;							\
-  }									\
-									\
-  void clear (struct TAG *obj) const					\
-  {									\
-    DATA *datum = get (obj);						\
-    if (datum != nullptr)						\
-      {									\
-	cleanup (obj, datum);						\
-	set (obj, nullptr);						\
-      }									\
-  }									\
-									\
-private:								\
-									\
-  static void cleanup (struct TAG *obj, void *arg)			\
-  {									\
-    DATA *datum = (DATA *) arg;						\
-    Deleter d;								\
-    d (datum);								\
-  }									\
-									\
-  const struct TAG ## _data *m_key;					\
+template<typename T>
+class registry
+{
+public:
+
+  registry ()
+    : m_fields (get_registrations ().size ())
+  {
+  }
+
+  ~registry ()
+  {
+    clear_registry ();
+  }
+
+  DISABLE_COPY_AND_ASSIGN (registry);
+
+  /* A type-safe registry key.
+
+     The registry itself holds just a "void *".  This is not always
+     convenient to manage, so this template class can be used instead,
+     to provide a type-safe interface, that also helps manage the
+     lifetime of the stored objects.
+
+     When the container is destroyed, this key arranges to destroy the
+     underlying data using Deleter.  This defaults to
+     std::default_delete.  */
+
+  template<typename DATA, typename Deleter = std::default_delete<DATA>>
+  class key
+  {
+  public:
+
+    key ()
+      : m_key (registry<T>::new_key (cleanup))
+    {
+    }
+
+    DISABLE_COPY_AND_ASSIGN (key);
+
+    /* Fetch the data attached to OBJ that is associated with this key.
+       If no such data has been attached, nullptr is returned.  */
+    DATA *get (T *obj) const
+    {
+      registry<T> *reg_obj = registry_accessor<T>::get (obj);
+      return (DATA *) reg_obj->get (m_key);
+    }
+
+    /* Attach DATA to OBJ, associated with this key.  Note that any
+       previous data is simply dropped -- if destruction is needed,
+       'clear' should be called.  */
+    void set (T *obj, DATA *data) const
+    {
+      registry<T> *reg_obj = registry_accessor<T>::get (obj);
+      reg_obj->set (m_key, data);
+    }
+
+    /* If this key uses the default deleter, then this method is
+       available.  It emplaces a new instance of the associated data
+       type and attaches it to OBJ using this key.  The arguments, if
+       any, are forwarded to the constructor.  */
+    template<typename Dummy = DATA *, typename... Args>
+    typename std::enable_if<std::is_same<Deleter,
+					 std::default_delete<DATA>>::value,
+			    Dummy>::type
+    emplace (T *obj, Args &&...args) const
+    {
+      DATA *result = new DATA (std::forward<Args> (args)...);
+      set (obj, result);
+      return result;
+    }
+
+    /* Clear the data attached to OBJ that is associated with this KEY.
+       Any existing data is destroyed using the deleter, and the data is
+       reset to nullptr.  */
+    void clear (T *obj) const
+    {
+      DATA *datum = get (obj);
+      if (datum != nullptr)
+	{
+	  cleanup (datum);
+	  set (obj, nullptr);
+	}
+    }
+
+  private:
+
+    /* A helper function that is called by the registry to delete the
+       contained object.  */
+    static void cleanup (void *arg)
+    {
+      DATA *datum = (DATA *) arg;
+      Deleter d;
+      d (datum);
+    }
+
+    /* The underlying key.  */
+    const typename registry<T>::registry_data *m_key;
+  };
+
+  /* Clear all the data associated with this container.  This is
+     dangerous and should not normally be done.  */
+  void clear_registry ()
+  {
+    /* Call all the free functions.  */
+    for (const auto &datum : get_registrations ())
+      {
+	void *elt = m_fields[datum->index];
+	if (elt != nullptr)
+	  {
+	    datum->free (elt);
+	    m_fields[datum->index] = nullptr;
+	  }
+      }
+  }
+
+private:
+
+  /* Registry callbacks have this type.  */
+  typedef void (*registry_data_callback) (void *);
+
+  /* The type of a key.  */
+  struct registry_data
+  {
+    unsigned index;
+    registry_data_callback free;
+  };
+
+  /* Get a new key for this particular registry.  FREE is a callback.
+     When the container object is destroyed, all FREE functions are
+     called.  The data associated with the container object is passed
+     to the callback.  */
+  static const registry_data *new_key (registry_data_callback free)
+  {
+    std::unique_ptr<registry_data> result (new registry_data);
+    std::vector<std::unique_ptr<registry_data>> &registrations
+      = get_registrations ();
+    result->index = registrations.size ();
+    result->free = free;
+    registrations.emplace_back (std::move (result));
+    return registrations.back ().get ();
+  }
+
+  /* Set the datum associated with KEY in this container.  */
+  void set (const registry_data *key, void *datum)
+  {
+    m_fields[key->index] = datum;
+  }
+
+  /* Fetch the datum associated with KEY in this container.  If 'set'
+     has not been called for this key, nullptr is returned.  */
+  void *get (const registry_data *key)
+  {
+    return m_fields[key->index];
+  }
+
+  /* The data stored in this instance.  */
+  std::vector<void *> m_fields;
+
+  /* Return a reference to the vector of all the registrations that
+     have been made.  We do separate allocations here so that the
+     addresses are stable and can be used as keys.  */
+  static std::vector<std::unique_ptr<registry_data>> &get_registrations ()
+  {
+    static std::vector<std::unique_ptr<registry_data>> registrations;
+    return registrations;
+  }
 };
 
 #endif /* REGISTRY_H */
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index 4b8afd27688..01f88fc9da2 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -178,7 +178,7 @@ struct gdbsim_target final
 
 static struct gdbsim_target gdbsim_ops;
 
-static inferior_key<sim_inferior_data> sim_inferior_data_key;
+static const registry<inferior>::key<sim_inferior_data> sim_inferior_data_key;
 
 /* Flag indicating the "open" status of this module.  It's set to 1
    in gdbsim_open() and 0 in gdbsim_close().  */
diff --git a/gdb/remote.c b/gdb/remote.c
index f41e6ce82c2..b57c55e8580 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1033,7 +1033,7 @@ is_remote_target (process_stratum_target *target)
 }
 
 /* Per-program-space data key.  */
-static const struct program_space_key<char, gdb::xfree_deleter<char>>
+static const registry<program_space>::key<char, gdb::xfree_deleter<char>>
   remote_pspace_data;
 
 /* The variable registered as the control variable used by the
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 6815dfaa820..0386bfb6223 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -155,7 +155,7 @@ static const char *powerpc_vector_abi_string = "auto";
 
 /* PowerPC-related per-inferior data.  */
 
-static inferior_key<ppc_inferior_data> ppc_inferior_data_key;
+static registry<inferior>::key<ppc_inferior_data> ppc_inferior_data_key;
 
 /* Get the per-inferior PowerPC data for INF.  */
 
diff --git a/gdb/solib-aix.c b/gdb/solib-aix.c
index 3a8debf2c5a..33b15a9d8ad 100644
--- a/gdb/solib-aix.c
+++ b/gdb/solib-aix.c
@@ -80,7 +80,8 @@ struct solib_aix_inferior_data
 };
 
 /* Key to our per-inferior data.  */
-static inferior_key<solib_aix_inferior_data> solib_aix_inferior_data_handle;
+static const registry<inferior>::key<solib_aix_inferior_data>
+  solib_aix_inferior_data_handle;
 
 /* Return this module's data for the given inferior.
    If none is found, add a zero'ed one now.  */
diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
index d7789f68dfe..e61ec0d4bf3 100644
--- a/gdb/solib-darwin.c
+++ b/gdb/solib-darwin.c
@@ -80,7 +80,8 @@ struct darwin_info
 };
 
 /* Per-program-space data key.  */
-static program_space_key<darwin_info> solib_darwin_pspace_data;
+static const registry<program_space>::key<darwin_info>
+  solib_darwin_pspace_data;
 
 /* Get the current darwin data.  If none is found yet, add it now.  This
    function always returns a valid object.  */
diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c
index 0b03f944608..fe6b6e122d9 100644
--- a/gdb/solib-dsbt.c
+++ b/gdb/solib-dsbt.c
@@ -164,7 +164,7 @@ struct dsbt_info
 };
 
 /* Per-program-space data key.  */
-static program_space_key<dsbt_info> solib_dsbt_pspace_data;
+static const registry<program_space>::key<dsbt_info> solib_dsbt_pspace_data;
 
 /* Get the current dsbt data.  If none is found yet, add it now.  This
    function always returns a valid object.  */
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 5c046d3fab5..f9a43e23969 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -365,7 +365,7 @@ struct svr4_info
 };
 
 /* Per-program-space data key.  */
-static const struct program_space_key<svr4_info> solib_svr4_pspace_data;
+static const registry<program_space>::key<svr4_info> solib_svr4_pspace_data;
 
 /* Free the probes table.  */
 
diff --git a/gdb/solib.c b/gdb/solib.c
index 0fbf5bc988d..d4a7c092da8 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -529,7 +529,8 @@ typedef std::unordered_map<std::string, std::string> soname_build_id_map;
 
 /* Key used to associate a soname_build_id_map to a core file bfd.  */
 
-static const struct bfd_key<soname_build_id_map> cbfd_soname_build_id_data_key;
+static const struct registry<bfd>::key<soname_build_id_map>
+     cbfd_soname_build_id_data_key;
 
 /* See solib.h.  */
 
diff --git a/gdb/source.c b/gdb/source.c
index 8691113c729..425b02fc3a0 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -115,7 +115,8 @@ struct current_source_location
   int m_line = 0;
 };
 
-static program_space_key<current_source_location> current_source_key;
+static const registry<program_space>::key<current_source_location>
+     current_source_key;
 
 /* Default number of lines to print with commands like "list".
    This is based on guessing how many long (i.e. more than chars_per_line
diff --git a/gdb/stabsread.c b/gdb/stabsread.c
index 4fe2110a47f..aedbca2d0eb 100644
--- a/gdb/stabsread.c
+++ b/gdb/stabsread.c
@@ -2016,8 +2016,8 @@ read_type (const char **pp, struct objfile *objfile)
 /* RS/6000 xlc/dbx combination uses a set of builtin types, starting from -1.
    Return the proper type node for a given builtin type number.  */
 
-static const struct objfile_key<struct type *,
-				gdb::noop_deleter<struct type *>>
+static const registry<objfile>::key<struct type *,
+				    gdb::noop_deleter<struct type *>>
   rs6000_builtin_type_data;
 
 static struct type *
diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
index 2af04433444..59726290011 100644
--- a/gdb/symfile-debug.c
+++ b/gdb/symfile-debug.c
@@ -47,7 +47,7 @@ struct debug_sym_fns_data
 
 /* We need to record a pointer to the real set of functions for each
    objfile.  */
-static const struct objfile_key<debug_sym_fns_data>
+static const registry<objfile>::key<debug_sym_fns_data>
   symfile_debug_objfile_data_key;
 
 /* If true all calls to the symfile functions are logged.  */
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 6f546f5b059..ec3244269b1 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -2500,7 +2500,7 @@ reread_symbols (int from_tty)
 	      (*objfile->sf->sym_finish) (objfile);
 	    }
 
-	  clear_objfile_data (objfile);
+	  objfile->registry_fields.clear_registry ();
 
 	  /* Clean up any state BFD has sitting around.  */
 	  {
@@ -2638,7 +2638,7 @@ reread_symbols (int from_tty)
     {
       clear_symtab_users (0);
 
-      /* clear_objfile_data for each objfile was called before freeing it and
+      /* The registry for each objfile was cleared and
 	 gdb::observers::new_objfile.notify (NULL) has been called by
 	 clear_symtab_users above.  Notify the new files now.  */
       for (auto iter : new_objfiles)
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 8564986f66d..8d3be357ded 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -121,7 +121,7 @@ struct main_info
 
 /* Program space key for finding name and language of "main".  */
 
-static const program_space_key<main_info> main_progspace_key;
+static const registry<program_space>::key<main_info> main_progspace_key;
 
 /* The default symbol cache size.
    There is no extra cpu cost for large N (except when flushing the cache,
@@ -251,7 +251,7 @@ struct symbol_cache
 
 /* Program space key for finding its symbol cache.  */
 
-static const program_space_key<symbol_cache> symbol_cache_key;
+static const registry<program_space>::key<symbol_cache> symbol_cache_key;
 
 /* When non-zero, print debugging messages related to symtab creation.  */
 unsigned int symtab_create_debug = 0;
diff --git a/gdb/target-dcache.c b/gdb/target-dcache.c
index 0aa53302cea..3e3c0c6ee4d 100644
--- a/gdb/target-dcache.c
+++ b/gdb/target-dcache.c
@@ -24,7 +24,7 @@
 /* The target dcache is kept per-address-space.  This key lets us
    associate the cache with the address space.  */
 
-static const struct address_space_key<DCACHE, dcache_deleter>
+static const registry<address_space>::key<DCACHE, dcache_deleter>
   target_dcache_aspace_key;
 
 /* Target dcache is initialized or not.  */
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index d8735d29ede..0be7991d5c2 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -147,7 +147,7 @@ struct xcoff_symfile_info
 
 /* Key for XCOFF-associated data.  */
 
-static const struct objfile_key<xcoff_symfile_info> xcoff_objfile_data_key;
+static const registry<objfile>::key<xcoff_symfile_info> xcoff_objfile_data_key;
 
 /* Convenience macro to access the per-objfile XCOFF data.  */
 
-- 
2.34.1


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

* [PATCH 5/6] Change registry to use less memory
  2022-05-30 17:59 [PATCH 0/6] Rewrite registry.h Tom Tromey
                   ` (3 preceding siblings ...)
  2022-05-30 17:59 ` [PATCH 4/6] Rewrite registry.h Tom Tromey
@ 2022-05-30 17:59 ` Tom Tromey
  2022-05-30 17:59 ` [PATCH 6/6] Remove some unneeded checks in Guile code Tom Tromey
  2022-07-28 20:13 ` [PATCH 0/6] Rewrite registry.h Tom Tromey
  6 siblings, 0 replies; 13+ messages in thread
From: Tom Tromey @ 2022-05-30 17:59 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

The registry code creates "registry_data" objects that hold the free
function and the index; then the registry keys refer to this object.
However, only the index is really useful, and now that registries have
a private implementation, just the index can be stored and we can
reduce the memory use of registries a little bit.  This also
simplifies the code somewhat.
---
 gdb/registry.h | 47 ++++++++++++++++++++---------------------------
 1 file changed, 20 insertions(+), 27 deletions(-)

diff --git a/gdb/registry.h b/gdb/registry.h
index 27592ff6e2a..f2d952ac847 100644
--- a/gdb/registry.h
+++ b/gdb/registry.h
@@ -159,7 +159,7 @@ class registry
     }
 
     /* The underlying key.  */
-    const typename registry<T>::registry_data *m_key;
+    const unsigned m_key;
   };
 
   /* Clear all the data associated with this container.  This is
@@ -167,13 +167,16 @@ class registry
   void clear_registry ()
   {
     /* Call all the free functions.  */
-    for (const auto &datum : get_registrations ())
+    std::vector<registry_data_callback> &registrations
+      = get_registrations ();
+    unsigned last = registrations.size ();
+    for (unsigned i = 0; i < last; ++i)
       {
-	void *elt = m_fields[datum->index];
+	void *elt = m_fields[i];
 	if (elt != nullptr)
 	  {
-	    datum->free (elt);
-	    m_fields[datum->index] = nullptr;
+	    registrations[i] (elt);
+	    m_fields[i] = nullptr;
 	  }
       }
   }
@@ -183,50 +186,40 @@ class registry
   /* Registry callbacks have this type.  */
   typedef void (*registry_data_callback) (void *);
 
-  /* The type of a key.  */
-  struct registry_data
-  {
-    unsigned index;
-    registry_data_callback free;
-  };
-
   /* Get a new key for this particular registry.  FREE is a callback.
      When the container object is destroyed, all FREE functions are
      called.  The data associated with the container object is passed
      to the callback.  */
-  static const registry_data *new_key (registry_data_callback free)
+  static unsigned new_key (registry_data_callback free)
   {
-    std::unique_ptr<registry_data> result (new registry_data);
-    std::vector<std::unique_ptr<registry_data>> &registrations
+    std::vector<registry_data_callback> &registrations
       = get_registrations ();
-    result->index = registrations.size ();
-    result->free = free;
-    registrations.emplace_back (std::move (result));
-    return registrations.back ().get ();
+    unsigned result = registrations.size ();
+    registrations.push_back (free);
+    return result;
   }
 
   /* Set the datum associated with KEY in this container.  */
-  void set (const registry_data *key, void *datum)
+  void set (unsigned key, void *datum)
   {
-    m_fields[key->index] = datum;
+    m_fields[key] = datum;
   }
 
   /* Fetch the datum associated with KEY in this container.  If 'set'
      has not been called for this key, nullptr is returned.  */
-  void *get (const registry_data *key)
+  void *get (unsigned key)
   {
-    return m_fields[key->index];
+    return m_fields[key];
   }
 
   /* The data stored in this instance.  */
   std::vector<void *> m_fields;
 
   /* Return a reference to the vector of all the registrations that
-     have been made.  We do separate allocations here so that the
-     addresses are stable and can be used as keys.  */
-  static std::vector<std::unique_ptr<registry_data>> &get_registrations ()
+     have been made.  */
+  static std::vector<registry_data_callback> &get_registrations ()
   {
-    static std::vector<std::unique_ptr<registry_data>> registrations;
+    static std::vector<registry_data_callback> registrations;
     return registrations;
   }
 };
-- 
2.34.1


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

* [PATCH 6/6] Remove some unneeded checks in Guile code
  2022-05-30 17:59 [PATCH 0/6] Rewrite registry.h Tom Tromey
                   ` (4 preceding siblings ...)
  2022-05-30 17:59 ` [PATCH 5/6] Change registry to use less memory Tom Tromey
@ 2022-05-30 17:59 ` Tom Tromey
  2022-07-28 20:13 ` [PATCH 0/6] Rewrite registry.h Tom Tromey
  6 siblings, 0 replies; 13+ messages in thread
From: Tom Tromey @ 2022-05-30 17:59 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

The Guile code generally checks to see if an htab is non-null before
destroying it.  However, the registry code already ensures this, so we
can change these checks to asserts and simplify the code a little.
---
 gdb/guile/scm-block.c  | 8 +++-----
 gdb/guile/scm-frame.c  | 8 +++-----
 gdb/guile/scm-symbol.c | 8 +++-----
 gdb/guile/scm-symtab.c | 8 +++-----
 gdb/guile/scm-type.c   | 9 +++------
 5 files changed, 15 insertions(+), 26 deletions(-)

diff --git a/gdb/guile/scm-block.c b/gdb/guile/scm-block.c
index a29c2db58f1..07c6a2bd5e5 100644
--- a/gdb/guile/scm-block.c
+++ b/gdb/guile/scm-block.c
@@ -97,11 +97,9 @@ struct bkscm_deleter
 
   void operator() (htab_t htab)
   {
-    if (htab != NULL)
-      {
-	htab_traverse_noresize (htab, bkscm_mark_block_invalid, NULL);
-	htab_delete (htab);
-      }
+    gdb_assert (htab != nullptr);
+    htab_traverse_noresize (htab, bkscm_mark_block_invalid, NULL);
+    htab_delete (htab);
   }
 };
 
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 4132bb246d8..159603b8008 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -95,11 +95,9 @@ struct frscm_deleter
 
   void operator() (htab_t htab)
   {
-    if (htab != NULL)
-      {
-	htab_traverse_noresize (htab, frscm_mark_frame_invalid, NULL);
-	htab_delete (htab);
-      }
+    gdb_assert (htab != nullptr);
+    htab_traverse_noresize (htab, frscm_mark_frame_invalid, NULL);
+    htab_delete (htab);
   }
 };
 
diff --git a/gdb/guile/scm-symbol.c b/gdb/guile/scm-symbol.c
index 0b96e5a02c1..78917bdbed0 100644
--- a/gdb/guile/scm-symbol.c
+++ b/gdb/guile/scm-symbol.c
@@ -70,11 +70,9 @@ struct syscm_deleter
 
   void operator() (htab_t htab)
   {
-    if (htab != NULL)
-      {
-	htab_traverse_noresize (htab, syscm_mark_symbol_invalid, NULL);
-	htab_delete (htab);
-      }
+    gdb_assert (htab != nullptr);
+    htab_traverse_noresize (htab, syscm_mark_symbol_invalid, NULL);
+    htab_delete (htab);
   }
 };
 
diff --git a/gdb/guile/scm-symtab.c b/gdb/guile/scm-symtab.c
index 940823147bf..2ff66c49d51 100644
--- a/gdb/guile/scm-symtab.c
+++ b/gdb/guile/scm-symtab.c
@@ -98,11 +98,9 @@ struct stscm_deleter
 
   void operator() (htab_t htab)
   {
-    if (htab != NULL)
-      {
-	htab_traverse_noresize (htab, stscm_mark_symtab_invalid, NULL);
-	htab_delete (htab);
-      }
+    gdb_assert (htab != nullptr);
+    htab_traverse_noresize (htab, stscm_mark_symtab_invalid, NULL);
+    htab_delete (htab);
   }
 };
 
diff --git a/gdb/guile/scm-type.c b/gdb/guile/scm-type.c
index 2dadbefb3a4..5cb1cabe14d 100644
--- a/gdb/guile/scm-type.c
+++ b/gdb/guile/scm-type.c
@@ -93,13 +93,10 @@ struct tyscm_deleter
     if (!gdb_scheme_initialized)
       return;
 
+    gdb_assert (htab != nullptr);
     htab_up copied_types = create_copied_types_hash ();
-
-    if (htab != NULL)
-      {
-	htab_traverse_noresize (htab, tyscm_copy_type_recursive, copied_types.get ());
-	htab_delete (htab);
-      }
+    htab_traverse_noresize (htab, tyscm_copy_type_recursive, copied_types.get ());
+    htab_delete (htab);
   }
 };
 
-- 
2.34.1


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

* Re: [PATCH 4/6] Rewrite registry.h
  2022-05-30 17:59 ` [PATCH 4/6] Rewrite registry.h Tom Tromey
@ 2022-06-07 10:55   ` Lancelot SIX via Gdb-patches
  2022-06-08  1:33     ` Tom Tromey
  0 siblings, 1 reply; 13+ messages in thread
From: Lancelot SIX via Gdb-patches @ 2022-06-07 10:55 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Hi Tom,

After this patch, if I build GDB with address sanitizer, I end up having
many regressions related to heap-use-after-free in the testsuite.

You can see this by using the gdb.base/cached-source-file.exp for
example.

    ==901008==ERROR: AddressSanitizer: heap-use-after-free on address 0x61a000080f88 at pc 0x56310c94a9b1 bp 0x7ffc6ec5de70 sp 0x7ffc6ec5de60
    READ of size 1 at 0x61a000080f88 thread T0
        #0 0x56310c94a9b0 in gdb::optional<std::queue<dwarf2_queue_item, std::__debug::deque<dwarf2_queue_item, std::allocator<dwarf2_queue_item> > > >::has_value() const ../../gdb/../gdbsupport/gdb_optional.h:183
        #1 0x56310c88b638 in dwarf2_per_objfile::remove_all_cus() ../../gdb/dwarf2/read.c:1479
        #2 0x56310c91db2f in dwarf2_per_objfile::~dwarf2_per_objfile() ../../gdb/dwarf2/read.c:23606
        #3 0x56310c989241 in std::default_delete<dwarf2_per_objfile>::operator()(dwarf2_per_objfile*) const /usr/include/c++/9/bits/unique_ptr.h:81
        #4 0x56310c962fc2 in registry<objfile>::key<dwarf2_per_objfile, std::default_delete<dwarf2_per_objfile> >::cleanup(void*) ../../gdb/registry.h:158
        #5 0x56310cf60fa3 in registry<objfile>::clear_registry() ../../gdb/registry.h:175
        #6 0x56310cf5f833 in registry<objfile>::~registry() ../../gdb/registry.h:77
        #7 0x56310cf56499 in objfile::~objfile() ../../gdb/objfiles.c:501
        #8 0x56310cf6ae22 in std::_Sp_counted_ptr<objfile*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/include/c++/9/bits/shared_ptr_base.h:377
        #9 0x56310c3c17cc in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/9/bits/shared_ptr_base.h:155
        #10 0x56310c3b3f5b in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/9/bits/shared_ptr_base.h:730
        #11 0x56310cf5ed9f in std::__shared_ptr<objfile, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/9/bits/shared_ptr_base.h:1169
        #12 0x56310cf5edbf in std::shared_ptr<objfile>::~shared_ptr() /usr/include/c++/9/bits/shared_ptr.h:103
        #13 0x56310d00c0c9 in void __gnu_cxx::new_allocator<std::__cxx1998::_List_node<std::shared_ptr<objfile> > >::destroy<std::shared_ptr<objfile> >(std::shared_ptr<objfile>*) /usr/include/c++/9/ext/new_allocator.h:152
        #14 0x56310d0084ee in void std::allocator_traits<std::allocator<std::__cxx1998::_List_node<std::shared_ptr<objfile> > > >::destroy<std::shared_ptr<objfile> >(std::allocator<std::__cxx1998::_List_node<std::shared_ptr<objfile> > >&, std::shared_ptr<objfile>*) /usr/include/c++/9/bits/alloc_traits.h:496
        #15 0x56310d00e85d in std::__cxx1998::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::_M_erase(std::__cxx1998::_List_iterator<std::shared_ptr<objfile> >) /usr/include/c++/9/bits/stl_list.h:1921
        #16 0x56310d00a468 in std::__cxx1998::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::erase(std::__cxx1998::_List_const_iterator<std::shared_ptr<objfile> >) /usr/include/c++/9/bits/list.tcc:158
        #17 0x56310d005ad7 in std::__debug::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::_M_erase(std::__cxx1998::_List_const_iterator<std::shared_ptr<objfile> >) /usr/include/c++/9/debug/list:499
        #18 0x56310d001dda in std::__debug::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::erase(__gnu_debug::_Safe_iterator<std::__cxx1998::_List_const_iterator<std::shared_ptr<objfile> >, std::__debug::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >, std::bidirectional_iterator_tag>) /usr/include/c++/9/debug/list:511
        #19 0x56310cffb808 in program_space::remove_objfile(objfile*) ../../gdb/progspace.c:175
        #20 0x56310cf55cd3 in objfile::unlink() ../../gdb/objfiles.c:480
        [...]

    0x61a000080f88 is located 1288 bytes inside of 1304-byte region [0x61a000080a80,0x61a000080f98)
    freed by thread T0 here:
        #0 0x7f937d886c65 in operator delete(void*, unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cc:177
        #1 0x56310c98928a in std::default_delete<dwarf2_per_bfd>::operator()(dwarf2_per_bfd*) const /usr/include/c++/9/bits/unique_ptr.h:81
        #2 0x56310c9630cb in registry<bfd>::key<dwarf2_per_bfd, std::default_delete<dwarf2_per_bfd> >::cleanup(void*) ../../gdb/registry.h:158
        #3 0x56310cafb85f in registry<bfd>::clear_registry() (/home/lancesix/src/worktrees/gdb/upstream-master/_build/gdb/gdb+0x1c2985f)
        #4 0x56310cafb175 in registry<bfd>::~registry() (/home/lancesix/src/worktrees/gdb/upstream-master/_build/gdb/gdb+0x1c29175)
        #5 0x56310cafadc1 in gdb_bfd_data::~gdb_bfd_data() ../../gdb/gdb_bfd.c:76
        #6 0x56310caf80ff in gdb_bfd_unref(bfd*) ../../gdb/gdb_bfd.c:729
        #7 0x56310cf5615d in objfile::~objfile() ../../gdb/objfiles.c:562
        #8 0x56310cf6ae22 in std::_Sp_counted_ptr<objfile*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/include/c++/9/bits/shared_ptr_base.h:377
        #9 0x56310c3c17cc in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/9/bits/shared_ptr_base.h:155
        #10 0x56310c3b3f5b in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/9/bits/shared_ptr_base.h:730
        #11 0x56310cf5ed9f in std::__shared_ptr<objfile, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/9/bits/shared_ptr_base.h:1169
        #12 0x56310cf5edbf in std::shared_ptr<objfile>::~shared_ptr() /usr/include/c++/9/bits/shared_ptr.h:103
        #13 0x56310d00c0c9 in void __gnu_cxx::new_allocator<std::__cxx1998::_List_node<std::shared_ptr<objfile> > >::destroy<std::shared_ptr<objfile> >(std::shared_ptr<objfile>*) /usr/include/c++/9/ext/new_allocator.h:152
        #14 0x56310d0084ee in void std::allocator_traits<std::allocator<std::__cxx1998::_List_node<std::shared_ptr<objfile> > > >::destroy<std::shared_ptr<objfile> >(std::allocator<std::__cxx1998::_List_node<std::shared_ptr<objfile> > >&, std::shared_ptr<objfile>*) /usr/include/c++/9/bits/alloc_traits.h:496
        #15 0x56310d00e85d in std::__cxx1998::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::_M_erase(std::__cxx1998::_List_iterator<std::shared_ptr<objfile> >) /usr/include/c++/9/bits/stl_list.h:1921
        #16 0x56310d00a468 in std::__cxx1998::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::erase(std::__cxx1998::_List_const_iterator<std::shared_ptr<objfile> >) /usr/include/c++/9/bits/list.tcc:158
        #17 0x56310d005ad7 in std::__debug::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::_M_erase(std::__cxx1998::_List_const_iterator<std::shared_ptr<objfile> >) /usr/include/c++/9/debug/list:499
        #18 0x56310d001dda in std::__debug::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::erase(__gnu_debug::_Safe_iterator<std::__cxx1998::_List_const_iterator<std::shared_ptr<objfile> >, std::__debug::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >, std::bidirectional_iterator_tag>) /usr/include/c++/9/debug/list:511
        #19 0x56310cffb808 in program_space::remove_objfile(objfile*) ../../gdb/progspace.c:175
        #20 0x56310cf55cd3 in objfile::unlink() ../../gdb/objfiles.c:480
        [...]
    
    previously allocated by thread T0 here:
        #0 0x7f937d885587 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cc:104
        #1 0x56310c88bfff in dwarf2_has_info(objfile*, dwarf2_debug_sections const*, bool) ../../gdb/dwarf2/read.c:1579
        #2 0x56310ca3ab84 in elf_symfile_read ../../gdb/elfread.c:1255
        #3 0x56310d38538d in read_symbols ../../gdb/symfile.c:772
        [...]

I have not really looked into things much, but looks like the order in
which things are destructed/deallocated changed slightly, leading to
this issue.

Best,
Lancelot

On Mon, May 30, 2022 at 11:59:32AM -0600, Tom Tromey wrote:
> This rewrites registry.h, removing all the macros and replacing it
> with relatively ordinary template classes.  The result is less code
> than the previous setup.  It replaces large macros with a relatively
> straightforward C++ class, and now manages its own cleanup.
> 
> The existing type-safe "key" class is replaced with the equivalent
> template class.  This approach ended up requiring relatively few
> changes to the users of the registry code in gdb -- code using the key
> system just required a small change to the key's declaration.
> 
> All existing users of the old C-like API are now converted to use the
> type-safe API.  This mostly involved changing explicit deletion
> functions to be an operator() in a deleter class.
> 
> The old "save/free" two-phase process is removed, and replaced with a
> single "free" phase.  No existing code used both phases.
> 
> The old "free" callbacks took a parameter for the enclosing container
> object.  However, this wasn't truly needed and is removed here as
> well.
> ---
>  gdb/Makefile.in            |   1 -
>  gdb/ada-lang.c             |   5 +-
>  gdb/ada-tasks.c            |   4 +-
>  gdb/arm-tdep.c             |   4 +-
>  gdb/auto-load.c            |   4 +-
>  gdb/auxv.c                 |   2 +-
>  gdb/break-catch-syscall.c  |   2 +-
>  gdb/breakpoint.c           |   2 +-
>  gdb/coffread.c             |   2 +-
>  gdb/ctfread.c              |   8 +-
>  gdb/dbxread.c              |   2 +-
>  gdb/dwarf2/frame.c         |   4 +-
>  gdb/dwarf2/read.c          |   8 +-
>  gdb/elfread.c              |   4 +-
>  gdb/fbsd-tdep.c            |   2 +-
>  gdb/gdb-stabs.h            |   2 +-
>  gdb/gdb_bfd.c              |  14 +-
>  gdb/gdb_bfd.h              |  10 +-
>  gdb/gdbtypes.c             |   6 +-
>  gdb/guile/guile-internal.h |   2 +-
>  gdb/guile/scm-block.c      |  75 +++---
>  gdb/guile/scm-frame.c      |  75 +++---
>  gdb/guile/scm-objfile.c    |  46 ++--
>  gdb/guile/scm-progspace.c  |  47 ++--
>  gdb/guile/scm-symbol.c     |  70 +++---
>  gdb/guile/scm-symtab.c     |  76 +++---
>  gdb/guile/scm-type.c       |  63 +++--
>  gdb/hppa-tdep.c            |   3 +-
>  gdb/inferior.c             |  11 +-
>  gdb/inferior.h             |   7 +-
>  gdb/inflow.c               |   2 +-
>  gdb/linux-tdep.c           |   2 +-
>  gdb/mdebugread.c           |   4 +-
>  gdb/minidebug.c            |   2 +-
>  gdb/nto-tdep.c             |   2 +-
>  gdb/objc-lang.c            |   2 +-
>  gdb/objfiles.c             |  15 +-
>  gdb/objfiles.h             |   6 +-
>  gdb/progspace.c            |  22 --
>  gdb/progspace.h            |  18 +-
>  gdb/python/py-block.c      |  70 +++---
>  gdb/python/py-inferior.c   |  68 +++---
>  gdb/python/py-objfile.c    |  37 ++-
>  gdb/python/py-progspace.c  |  59 ++---
>  gdb/python/py-symbol.c     |  63 ++---
>  gdb/python/py-symtab.c     | 142 +++++------
>  gdb/python/py-type.c       |  59 ++---
>  gdb/registry.c             | 112 ---------
>  gdb/registry.h             | 469 ++++++++++++++++---------------------
>  gdb/remote-sim.c           |   2 +-
>  gdb/remote.c               |   2 +-
>  gdb/rs6000-tdep.c          |   2 +-
>  gdb/solib-aix.c            |   3 +-
>  gdb/solib-darwin.c         |   3 +-
>  gdb/solib-dsbt.c           |   2 +-
>  gdb/solib-svr4.c           |   2 +-
>  gdb/solib.c                |   3 +-
>  gdb/source.c               |   3 +-
>  gdb/stabsread.c            |   4 +-
>  gdb/symfile-debug.c        |   2 +-
>  gdb/symfile.c              |   4 +-
>  gdb/symtab.c               |   4 +-
>  gdb/target-dcache.c        |   2 +-
>  gdb/xcoffread.c            |   2 +-
>  64 files changed, 684 insertions(+), 1071 deletions(-)
>  delete mode 100644 gdb/registry.c
> 
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index d80087749de..94e8da1dbbd 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1149,7 +1149,6 @@ COMMON_SFILES = \
>  	regcache.c \
>  	regcache-dump.c \
>  	reggroups.c \
> -	registry.c \
>  	remote.c \
>  	remote-fileio.c \
>  	remote-notif.c \
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 6ab01fd27d4..77616476617 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -334,7 +334,7 @@ struct ada_inferior_data
>  };
>  
>  /* Our key to this module's inferior data.  */
> -static const struct inferior_key<ada_inferior_data> ada_inferior_data;
> +static const registry<inferior>::key<ada_inferior_data> ada_inferior_data;
>  
>  /* Return our inferior data for the given inferior (INF).
>  
> @@ -376,7 +376,8 @@ struct ada_pspace_data
>  };
>  
>  /* Key to our per-program-space data.  */
> -static const struct program_space_key<ada_pspace_data> ada_pspace_data_handle;
> +static const registry<program_space>::key<ada_pspace_data>
> +  ada_pspace_data_handle;
>  
>  /* Return this module's data for the given program space (PSPACE).
>     If not is found, add a zero'ed one now.
> diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c
> index 0043f2999d9..fda49557a4f 100644
> --- a/gdb/ada-tasks.c
> +++ b/gdb/ada-tasks.c
> @@ -166,7 +166,7 @@ struct ada_tasks_pspace_data
>  };
>  
>  /* Key to our per-program-space data.  */
> -static const struct program_space_key<ada_tasks_pspace_data>
> +static const registry<program_space>::key<ada_tasks_pspace_data>
>    ada_tasks_pspace_data_handle;
>  
>  /* The kind of data structure used by the runtime to store the list
> @@ -242,7 +242,7 @@ struct ada_tasks_inferior_data
>  };
>  
>  /* Key to our per-inferior data.  */
> -static const struct inferior_key<ada_tasks_inferior_data>
> +static const registry<inferior>::key<ada_tasks_inferior_data>
>    ada_tasks_inferior_data_handle;
>  
>  /* Return a string with TASKNO followed by the task name if TASK_INFO
> diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
> index 49664093f00..dbcf4d286ab 100644
> --- a/gdb/arm-tdep.c
> +++ b/gdb/arm-tdep.c
> @@ -123,7 +123,7 @@ struct arm_per_bfd
>  };
>  
>  /* Per-bfd data used for mapping symbols.  */
> -static bfd_key<arm_per_bfd> arm_bfd_data_key;
> +static const registry<bfd>::key<arm_per_bfd> arm_bfd_data_key;
>  
>  /* The list of available "set arm ..." and "show arm ..." commands.  */
>  static struct cmd_list_element *setarmcmdlist = NULL;
> @@ -2368,7 +2368,7 @@ struct arm_exidx_data
>  };
>  
>  /* Per-BFD key to store exception handling information.  */
> -static const struct bfd_key<arm_exidx_data> arm_exidx_data_key;
> +static const registry<bfd>::key<arm_exidx_data> arm_exidx_data_key;
>  
>  static struct obj_section *
>  arm_obj_section_from_vma (struct objfile *objfile, bfd_vma vma)
> diff --git a/gdb/auto-load.c b/gdb/auto-load.c
> index b6056f5d60a..54ed73d1bf3 100644
> --- a/gdb/auto-load.c
> +++ b/gdb/auto-load.c
> @@ -536,8 +536,8 @@ struct loaded_script
>  };
>  
>  /* Per-program-space data key.  */
> -static const struct program_space_key<struct auto_load_pspace_info>
> -  auto_load_pspace_data;
> +static const registry<program_space>::key<auto_load_pspace_info>
> +     auto_load_pspace_data;
>  
>  /* Get the current autoload data.  If none is found yet, add it now.  This
>     function always returns a valid object.  */
> diff --git a/gdb/auxv.c b/gdb/auxv.c
> index 8e175138f5d..6154988f6dd 100644
> --- a/gdb/auxv.c
> +++ b/gdb/auxv.c
> @@ -332,7 +332,7 @@ struct auxv_info
>  };
>  
>  /* Per-inferior data key for auxv.  */
> -static const struct inferior_key<auxv_info> auxv_inferior_data;
> +static const registry<inferior>::key<auxv_info> auxv_inferior_data;
>  
>  /* Invalidate INF's auxv cache.  */
>  
> diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
> index 06d48466de7..805bb86cee6 100644
> --- a/gdb/break-catch-syscall.c
> +++ b/gdb/break-catch-syscall.c
> @@ -79,7 +79,7 @@ struct catch_syscall_inferior_data
>    int total_syscalls_count;
>  };
>  
> -static const struct inferior_key<struct catch_syscall_inferior_data>
> +static const registry<inferior>::key<catch_syscall_inferior_data>
>    catch_syscall_inferior_data;
>  
>  static struct catch_syscall_inferior_data *
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index ed932a19ed7..8bc7cef9f86 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -3326,7 +3326,7 @@ struct breakpoint_objfile_data
>    std::vector<probe *> exception_probes;
>  };
>  
> -static const struct objfile_key<breakpoint_objfile_data>
> +static const registry<objfile>::key<breakpoint_objfile_data>
>    breakpoint_objfile_key;
>  
>  /* Minimal symbol not found sentinel.  */
> diff --git a/gdb/coffread.c b/gdb/coffread.c
> index 75cf646c980..47828ac6090 100644
> --- a/gdb/coffread.c
> +++ b/gdb/coffread.c
> @@ -61,7 +61,7 @@ struct coff_symfile_info
>  
>  /* Key for COFF-associated data.  */
>  
> -static const struct objfile_key<coff_symfile_info> coff_objfile_data_key;
> +static const registry<objfile>::key<coff_symfile_info> coff_objfile_data_key;
>  
>  /* Translate an external name string into a user-visible name.  */
>  #define	EXTERNAL_NAME(string, abfd) \
> diff --git a/gdb/ctfread.c b/gdb/ctfread.c
> index 828f300d29d..0da4f0d0720 100644
> --- a/gdb/ctfread.c
> +++ b/gdb/ctfread.c
> @@ -87,7 +87,7 @@
>  #include "ctf.h"
>  #include "ctf-api.h"
>  
> -static const struct objfile_key<htab, htab_deleter> ctf_tid_key;
> +static const registry<objfile>::key<htab, htab_deleter> ctf_tid_key;
>  
>  struct ctf_fp_info
>  {
> @@ -107,7 +107,7 @@ ctf_fp_info::~ctf_fp_info ()
>    ctf_close (arc);
>  }
>  
> -static const objfile_key<ctf_fp_info> ctf_dict_key;
> +static const registry<objfile>::key<ctf_fp_info> ctf_dict_key;
>  
>  /* A CTF context consists of a file pointer and an objfile pointer.  */
>  
> @@ -243,7 +243,7 @@ set_tid_type (struct objfile *of, ctf_id_t tid, struct type *typ)
>  {
>    htab_t htab;
>  
> -  htab = (htab_t) ctf_tid_key.get (of);
> +  htab = ctf_tid_key.get (of);
>    if (htab == NULL)
>      {
>        htab = htab_create_alloc (1, tid_and_type_hash,
> @@ -271,7 +271,7 @@ get_tid_type (struct objfile *of, ctf_id_t tid)
>    struct ctf_tid_and_type *slot, ids;
>    htab_t htab;
>  
> -  htab = (htab_t) ctf_tid_key.get (of);
> +  htab = ctf_tid_key.get (of);
>    if (htab == NULL)
>      return nullptr;
>  
> diff --git a/gdb/dbxread.c b/gdb/dbxread.c
> index bcf519000bc..e1bf9a01e30 100644
> --- a/gdb/dbxread.c
> +++ b/gdb/dbxread.c
> @@ -57,7 +57,7 @@
>  
>  /* Key for dbx-associated data.  */
>  
> -objfile_key<dbx_symfile_info> dbx_objfile_data_key;
> +const registry<objfile>::key<dbx_symfile_info> dbx_objfile_data_key;
>  
>  /* We put a pointer to this structure in the read_symtab_private field
>     of the psymtab.  */
> diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
> index 5878d72f922..d7a06395acb 100644
> --- a/gdb/dwarf2/frame.c
> +++ b/gdb/dwarf2/frame.c
> @@ -1370,12 +1370,12 @@ dwarf2_frame_cfa (struct frame_info *this_frame)
>  \f
>  /* We store the frame data on the BFD.  This is only done if it is
>     independent of the address space and so can be shared.  */
> -static const struct bfd_key<comp_unit> dwarf2_frame_bfd_data;
> +static const registry<bfd>::key<comp_unit> dwarf2_frame_bfd_data;
>  
>  /* If any BFD sections require relocations (note; really should be if
>     any debug info requires relocations), then we store the frame data
>     on the objfile instead, and do not share it.  */
> -const struct objfile_key<comp_unit> dwarf2_frame_objfile_data;
> +static const registry<objfile>::key<comp_unit> dwarf2_frame_objfile_data;
>  \f
>  
>  /* Pointer encoding helper functions.  */
> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> index c4578c687d2..470e92a6c48 100644
> --- a/gdb/dwarf2/read.c
> +++ b/gdb/dwarf2/read.c
> @@ -124,7 +124,8 @@ static bool check_physname = false;
>  static bool use_deprecated_index_sections = false;
>  
>  /* This is used to store the data that is always per objfile.  */
> -static const objfile_key<dwarf2_per_objfile> dwarf2_objfile_data_key;
> +static const registry<objfile>::key<dwarf2_per_objfile>
> +     dwarf2_objfile_data_key;
>  
>  /* These are used to store the dwarf2_per_bfd objects.
>  
> @@ -134,8 +135,9 @@ static const objfile_key<dwarf2_per_objfile> dwarf2_objfile_data_key;
>     Other objfiles are not going to share a dwarf2_per_bfd with any other
>     objfiles, so they'll have their own version kept in the _objfile_data_key
>     version.  */
> -static const struct bfd_key<dwarf2_per_bfd> dwarf2_per_bfd_bfd_data_key;
> -static const struct objfile_key<dwarf2_per_bfd> dwarf2_per_bfd_objfile_data_key;
> +static const registry<bfd>::key<dwarf2_per_bfd> dwarf2_per_bfd_bfd_data_key;
> +static const registry<objfile>::key<dwarf2_per_bfd>
> +  dwarf2_per_bfd_objfile_data_key;
>  
>  /* The "aclass" indices for various kinds of computed DWARF symbols.  */
>  
> diff --git a/gdb/elfread.c b/gdb/elfread.c
> index 32cb27c8967..ec0deb5fd93 100644
> --- a/gdb/elfread.c
> +++ b/gdb/elfread.c
> @@ -69,7 +69,7 @@ typedef std::vector<std::unique_ptr<probe>> elfread_data;
>  
>  /* Per-BFD data for probe info.  */
>  
> -static const struct bfd_key<elfread_data> probe_key;
> +static const registry<bfd>::key<elfread_data> probe_key;
>  
>  /* Minimal symbols located at the GOT entries for .plt - that is the real
>     pointer where the given entry will jump to.  It gets updated by the real
> @@ -646,7 +646,7 @@ elf_rel_plt_read (minimal_symbol_reader &reader,
>  
>  /* The data pointer is htab_t for gnu_ifunc_record_cache_unchecked.  */
>  
> -static const struct objfile_key<htab, htab_deleter>
> +static const registry<objfile>::key<htab, htab_deleter>
>    elf_objfile_gnu_ifunc_cache_data;
>  
>  /* Map function names to CORE_ADDR in elf_objfile_gnu_ifunc_cache_data.  */
> diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
> index b241e855bd6..f2f961b5486 100644
> --- a/gdb/fbsd-tdep.c
> +++ b/gdb/fbsd-tdep.c
> @@ -520,7 +520,7 @@ struct fbsd_pspace_data
>  };
>  
>  /* Per-program-space data for FreeBSD architectures.  */
> -static const struct program_space_key<fbsd_pspace_data>
> +static const registry<program_space>::key<fbsd_pspace_data>
>    fbsd_pspace_data_handle;
>  
>  static struct fbsd_pspace_data *
> diff --git a/gdb/gdb-stabs.h b/gdb/gdb-stabs.h
> index fef988524f2..5c697906cab 100644
> --- a/gdb/gdb-stabs.h
> +++ b/gdb/gdb-stabs.h
> @@ -60,7 +60,7 @@ struct dbx_symfile_info
>  
>  /* The tag used to find the DBX info attached to an objfile.  This is
>     global because it is referenced by several modules.  */
> -extern objfile_key<dbx_symfile_info> dbx_objfile_data_key;
> +extern const registry<objfile>::key<dbx_symfile_info> dbx_objfile_data_key;
>  
>  #define DBX_SYMFILE_INFO(o)	(dbx_objfile_data_key.get (o))
>  #define DBX_TEXT_ADDR(o)	(DBX_SYMFILE_INFO(o)->text_addr)
> diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c
> index 22828482d5b..6c03ae5ef05 100644
> --- a/gdb/gdb_bfd.c
> +++ b/gdb/gdb_bfd.c
> @@ -112,13 +112,15 @@ struct gdb_bfd_data
>    std::vector<gdb_bfd_ref_ptr> included_bfds;
>  
>    /* The registry.  */
> -  REGISTRY_FIELDS = {};
> +  registry<bfd> registry_fields;
>  };
>  
> -#define GDB_BFD_DATA_ACCESSOR(ABFD) \
> -  ((struct gdb_bfd_data *) bfd_usrdata (ABFD))
> -
> -DEFINE_REGISTRY (bfd, GDB_BFD_DATA_ACCESSOR)
> +registry<bfd> *
> +registry_accessor<bfd>::get (bfd *abfd)
> +{
> +  struct gdb_bfd_data *gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
> +  return &gdata->registry_fields;
> +}
>  
>  /* A hash table storing all the BFDs maintained in the cache.  */
>  
> @@ -498,7 +500,6 @@ gdb_bfd_init_data (struct bfd *abfd, struct stat *st)
>  
>    gdata = new gdb_bfd_data (abfd, st);
>    bfd_set_usrdata (abfd, gdata);
> -  bfd_alloc_data (abfd);
>  
>    /* This is the first we've seen it, so add it to the hash table.  */
>    slot = htab_find_slot (all_bfds, abfd, INSERT);
> @@ -725,7 +726,6 @@ gdb_bfd_unref (struct bfd *abfd)
>  	htab_clear_slot (gdb_bfd_cache, slot);
>      }
>  
> -  bfd_free_data (abfd);
>    delete gdata;
>    bfd_set_usrdata (abfd, NULL);  /* Paranoia.  */
>  
> diff --git a/gdb/gdb_bfd.h b/gdb/gdb_bfd.h
> index 6845d6ccef5..edd38f5c34d 100644
> --- a/gdb/gdb_bfd.h
> +++ b/gdb/gdb_bfd.h
> @@ -26,7 +26,15 @@
>  #include "gdbsupport/iterator-range.h"
>  #include "gdbsupport/next-iterator.h"
>  
> -DECLARE_REGISTRY (bfd);
> +struct gdb_bfd_data;
> +
> +/* A registry adaptor for BFD.  This arranges to store the registry in
> +   gdb's per-BFD data, which is stored as the bfd_usrdata.  */
> +template<>
> +struct registry_accessor<bfd>
> +{
> +  static registry<bfd> *get (bfd *abfd);
> +};
>  
>  /* If supplied a path starting with this sequence, gdb_bfd_open will
>     open BFDs using target fileio operations.  */
> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
> index 9f49c15862f..6a732fe3586 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -6081,7 +6081,7 @@ typedef std::vector<std::unique_ptr<fixed_point_type_info>>
>      fixed_point_type_storage;
>  
>  /* Key used for managing the storage of fixed-point type info.  */
> -static const struct objfile_key<fixed_point_type_storage>
> +static const struct registry<objfile>::key<fixed_point_type_storage>
>      fixed_point_objfile_key;
>  
>  /* See gdbtypes.h.  */
> @@ -6308,8 +6308,8 @@ gdbtypes_post_init (struct gdbarch *gdbarch)
>  /* This set of objfile-based types is intended to be used by symbol
>     readers as basic types.  */
>  
> -static const struct objfile_key<struct objfile_type,
> -				gdb::noop_deleter<struct objfile_type>>
> +static const registry<objfile>::key<struct objfile_type,
> +				    gdb::noop_deleter<struct objfile_type>>
>    objfile_type_data;
>  
>  const struct objfile_type *
> diff --git a/gdb/guile/guile-internal.h b/gdb/guile/guile-internal.h
> index 4cdb7e355d7..30cc5c307ae 100644
> --- a/gdb/guile/guile-internal.h
> +++ b/gdb/guile/guile-internal.h
> @@ -28,6 +28,7 @@
>  #include "extension-priv.h"
>  #include "symtab.h"
>  #include "libguile.h"
> +#include "objfiles.h"
>  
>  struct block;
>  struct frame_info;
> @@ -272,7 +273,6 @@ struct eqable_gdb_smob
>  #undef GDB_SMOB_HEAD
>  
>  struct objfile;
> -struct objfile_data;
>  
>  /* A predicate that returns non-zero if an object is a particular kind
>     of gsmob.  */
> diff --git a/gdb/guile/scm-block.c b/gdb/guile/scm-block.c
> index 41954c70519..a29c2db58f1 100644
> --- a/gdb/guile/scm-block.c
> +++ b/gdb/guile/scm-block.c
> @@ -76,7 +76,37 @@ static scm_t_bits block_syms_progress_smob_tag;
>  /* The "next!" block syms iterator method.  */
>  static SCM bkscm_next_symbol_x_proc;
>  
> -static const struct objfile_data *bkscm_objfile_data_key;
> +/* This is called when an objfile is about to be freed.
> +   Invalidate the block as further actions on the block would result
> +   in bad data.  All access to b_smob->block should be gated by
> +   checks to ensure the block is (still) valid.  */
> +struct bkscm_deleter
> +{
> +  /* Helper function for bkscm_del_objfile_blocks to mark the block
> +     as invalid.  */
> +
> +  static int
> +  bkscm_mark_block_invalid (void **slot, void *info)
> +  {
> +    block_smob *b_smob = (block_smob *) *slot;
> +
> +    b_smob->block = NULL;
> +    b_smob->objfile = NULL;
> +    return 1;
> +  }
> +
> +  void operator() (htab_t htab)
> +  {
> +    if (htab != NULL)
> +      {
> +	htab_traverse_noresize (htab, bkscm_mark_block_invalid, NULL);
> +	htab_delete (htab);
> +      }
> +  }
> +};
> +
> +static const registry<objfile>::key<htab, bkscm_deleter>
> +     bkscm_objfile_data_key;
>  \f
>  /* Administrivia for block smobs.  */
>  
> @@ -108,13 +138,13 @@ bkscm_eq_block_smob (const void *ap, const void *bp)
>  static htab_t
>  bkscm_objfile_block_map (struct objfile *objfile)
>  {
> -  htab_t htab = (htab_t) objfile_data (objfile, bkscm_objfile_data_key);
> +  htab_t htab = bkscm_objfile_data_key.get (objfile);
>  
>    if (htab == NULL)
>      {
>        htab = gdbscm_create_eqable_gsmob_ptr_map (bkscm_hash_block_smob,
>  						 bkscm_eq_block_smob);
> -      set_objfile_data (objfile, bkscm_objfile_data_key, htab);
> +      bkscm_objfile_data_key.set (objfile, htab);
>      }
>  
>    return htab;
> @@ -326,35 +356,6 @@ bkscm_scm_to_block (SCM block_scm, int arg_pos, const char *func_name,
>    return NULL;
>  }
>  
> -/* Helper function for bkscm_del_objfile_blocks to mark the block
> -   as invalid.  */
> -
> -static int
> -bkscm_mark_block_invalid (void **slot, void *info)
> -{
> -  block_smob *b_smob = (block_smob *) *slot;
> -
> -  b_smob->block = NULL;
> -  b_smob->objfile = NULL;
> -  return 1;
> -}
> -
> -/* This function is called when an objfile is about to be freed.
> -   Invalidate the block as further actions on the block would result
> -   in bad data.  All access to b_smob->block should be gated by
> -   checks to ensure the block is (still) valid.  */
> -
> -static void
> -bkscm_del_objfile_blocks (struct objfile *objfile, void *datum)
> -{
> -  htab_t htab = (htab_t) datum;
> -
> -  if (htab != NULL)
> -    {
> -      htab_traverse_noresize (htab, bkscm_mark_block_invalid, NULL);
> -      htab_delete (htab);
> -    }
> -}
>  \f
>  /* Block methods.  */
>  
> @@ -800,13 +801,3 @@ gdbscm_initialize_blocks (void)
>  				gdbscm_scm_from_c_string ("\
>  Internal function to assist the block symbols iterator."));
>  }
> -
> -void _initialize_scm_block ();
> -void
> -_initialize_scm_block ()
> -{
> -  /* Register an objfile "free" callback so we can properly
> -     invalidate blocks when an object file is about to be deleted.  */
> -  bkscm_objfile_data_key
> -    = register_objfile_data_with_cleanup (NULL, bkscm_del_objfile_blocks);
> -}
> diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
> index 6bbb6f81d68..4132bb246d8 100644
> --- a/gdb/guile/scm-frame.c
> +++ b/gdb/guile/scm-frame.c
> @@ -74,7 +74,37 @@ static scm_t_bits frame_smob_tag;
>  /* Keywords used in argument passing.  */
>  static SCM block_keyword;
>  
> -static const struct inferior_data *frscm_inferior_data_key;
> +/* This is called when an inferior is about to be freed.
> +   Invalidate the frame as further actions on the frame could result
> +   in bad data.  All access to the frame should be gated by
> +   frscm_get_frame_smob_arg_unsafe which will raise an exception on
> +   invalid frames.  */
> +struct frscm_deleter
> +{
> +  /* Helper function for frscm_del_inferior_frames to mark the frame
> +     as invalid.  */
> +
> +  static int
> +  frscm_mark_frame_invalid (void **slot, void *info)
> +  {
> +    frame_smob *f_smob = (frame_smob *) *slot;
> +
> +    f_smob->inferior = NULL;
> +    return 1;
> +  }
> +
> +  void operator() (htab_t htab)
> +  {
> +    if (htab != NULL)
> +      {
> +	htab_traverse_noresize (htab, frscm_mark_frame_invalid, NULL);
> +	htab_delete (htab);
> +      }
> +  }
> +};
> +
> +static const registry<inferior>::key<htab, frscm_deleter>
> +    frscm_inferior_data_key;
>  \f
>  /* Administrivia for frame smobs.  */
>  
> @@ -117,13 +147,13 @@ frscm_eq_frame_smob (const void *ap, const void *bp)
>  static htab_t
>  frscm_inferior_frame_map (struct inferior *inferior)
>  {
> -  htab_t htab = (htab_t) inferior_data (inferior, frscm_inferior_data_key);
> +  htab_t htab = frscm_inferior_data_key.get (inferior);
>  
>    if (htab == NULL)
>      {
>        htab = gdbscm_create_eqable_gsmob_ptr_map (frscm_hash_frame_smob,
>  						 frscm_eq_frame_smob);
> -      set_inferior_data (inferior, frscm_inferior_data_key, htab);
> +      frscm_inferior_data_key.set (inferior, htab);
>      }
>  
>    return htab;
> @@ -346,35 +376,6 @@ frscm_frame_smob_to_frame (frame_smob *f_smob)
>    return frame;
>  }
>  
> -/* Helper function for frscm_del_inferior_frames to mark the frame
> -   as invalid.  */
> -
> -static int
> -frscm_mark_frame_invalid (void **slot, void *info)
> -{
> -  frame_smob *f_smob = (frame_smob *) *slot;
> -
> -  f_smob->inferior = NULL;
> -  return 1;
> -}
> -
> -/* This function is called when an inferior is about to be freed.
> -   Invalidate the frame as further actions on the frame could result
> -   in bad data.  All access to the frame should be gated by
> -   frscm_get_frame_smob_arg_unsafe which will raise an exception on
> -   invalid frames.  */
> -
> -static void
> -frscm_del_inferior_frames (struct inferior *inferior, void *datum)
> -{
> -  htab_t htab = (htab_t) datum;
> -
> -  if (htab != NULL)
> -    {
> -      htab_traverse_noresize (htab, frscm_mark_frame_invalid, NULL);
> -      htab_delete (htab);
> -    }
> -}
>  \f
>  /* Frame methods.  */
>  
> @@ -1170,13 +1171,3 @@ gdbscm_initialize_frames (void)
>  
>    block_keyword = scm_from_latin1_keyword ("block");
>  }
> -
> -void _initialize_scm_frame ();
> -void
> -_initialize_scm_frame ()
> -{
> -  /* Register an inferior "free" callback so we can properly
> -     invalidate frames when an inferior file is about to be deleted.  */
> -  frscm_inferior_data_key
> -    = register_inferior_data_with_cleanup (NULL, frscm_del_inferior_frames);
> -}
> diff --git a/gdb/guile/scm-objfile.c b/gdb/guile/scm-objfile.c
> index 760d5aa1f4b..1a87dcf74fa 100644
> --- a/gdb/guile/scm-objfile.c
> +++ b/gdb/guile/scm-objfile.c
> @@ -49,7 +49,18 @@ static const char objfile_smob_name[] = "gdb:objfile";
>  /* The tag Guile knows the objfile smob by.  */
>  static scm_t_bits objfile_smob_tag;
>  
> -static const struct objfile_data *ofscm_objfile_data_key;
> +/* Objfile registry cleanup handler for when an objfile is deleted.  */
> +struct ofscm_deleter
> +{
> +  void operator() (objfile_smob *o_smob)
> +  {
> +    o_smob->objfile = NULL;
> +    scm_gc_unprotect_object (o_smob->containing_scm);
> +  }
> +};
> +
> +static const registry<objfile>::key<objfile_smob, ofscm_deleter>
> +     ofscm_objfile_data_key;
>  
>  /* Return the list of pretty-printers registered with O_SMOB.  */
>  
> @@ -101,27 +112,6 @@ ofscm_make_objfile_smob (void)
>    return o_scm;
>  }
>  
> -/* Clear the OBJFILE pointer in O_SMOB and unprotect the object from GC.  */
> -
> -static void
> -ofscm_release_objfile (objfile_smob *o_smob)
> -{
> -  o_smob->objfile = NULL;
> -  scm_gc_unprotect_object (o_smob->containing_scm);
> -}
> -
> -/* Objfile registry cleanup handler for when an objfile is deleted.  */
> -
> -static void
> -ofscm_handle_objfile_deleted (struct objfile *objfile, void *datum)
> -{
> -  objfile_smob *o_smob = (objfile_smob *) datum;
> -
> -  gdb_assert (o_smob->objfile == objfile);
> -
> -  ofscm_release_objfile (o_smob);
> -}
> -
>  /* Return non-zero if SCM is a <gdb:objfile> object.  */
>  
>  static int
> @@ -147,7 +137,7 @@ ofscm_objfile_smob_from_objfile (struct objfile *objfile)
>  {
>    objfile_smob *o_smob;
>  
> -  o_smob = (objfile_smob *) objfile_data (objfile, ofscm_objfile_data_key);
> +  o_smob = ofscm_objfile_data_key.get (objfile);
>    if (o_smob == NULL)
>      {
>        SCM o_scm = ofscm_make_objfile_smob ();
> @@ -155,7 +145,7 @@ ofscm_objfile_smob_from_objfile (struct objfile *objfile)
>        o_smob = (objfile_smob *) SCM_SMOB_DATA (o_scm);
>        o_smob->objfile = objfile;
>  
> -      set_objfile_data (objfile, ofscm_objfile_data_key, o_smob);
> +      ofscm_objfile_data_key.set (objfile, o_smob);
>        scm_gc_protect_object (o_smob->containing_scm);
>      }
>  
> @@ -424,11 +414,3 @@ gdbscm_initialize_objfiles (void)
>  
>    gdbscm_define_functions (objfile_functions, 1);
>  }
> -
> -void _initialize_scm_objfile ();
> -void
> -_initialize_scm_objfile ()
> -{
> -  ofscm_objfile_data_key
> -    = register_objfile_data_with_cleanup (NULL, ofscm_handle_objfile_deleted);
> -}
> diff --git a/gdb/guile/scm-progspace.c b/gdb/guile/scm-progspace.c
> index c48da761945..7a197d76543 100644
> --- a/gdb/guile/scm-progspace.c
> +++ b/gdb/guile/scm-progspace.c
> @@ -52,7 +52,18 @@ static const char pspace_smob_name[] = "gdb:progspace";
>  /* The tag Guile knows the pspace smob by.  */
>  static scm_t_bits pspace_smob_tag;
>  
> -static const struct program_space_data *psscm_pspace_data_key;
> +/* Progspace registry cleanup handler for when a progspace is deleted.  */
> +struct psscm_deleter
> +{
> +  void operator() (pspace_smob *p_smob)
> +  {
> +    p_smob->pspace = NULL;
> +    scm_gc_unprotect_object (p_smob->containing_scm);
> +  }
> +};
> +
> +static const registry<program_space>::key<pspace_smob, psscm_deleter>
> +     psscm_pspace_data_key;
>  
>  /* Return the list of pretty-printers registered with P_SMOB.  */
>  
> @@ -111,27 +122,6 @@ psscm_make_pspace_smob (void)
>    return p_scm;
>  }
>  
> -/* Clear the progspace pointer in P_SMOB and unprotect the object from GC.  */
> -
> -static void
> -psscm_release_pspace (pspace_smob *p_smob)
> -{
> -  p_smob->pspace = NULL;
> -  scm_gc_unprotect_object (p_smob->containing_scm);
> -}
> -
> -/* Progspace registry cleanup handler for when a progspace is deleted.  */
> -
> -static void
> -psscm_handle_pspace_deleted (struct program_space *pspace, void *datum)
> -{
> -  pspace_smob *p_smob = (pspace_smob *) datum;
> -
> -  gdb_assert (p_smob->pspace == pspace);
> -
> -  psscm_release_pspace (p_smob);
> -}
> -
>  /* Return non-zero if SCM is a <gdb:progspace> object.  */
>  
>  static int
> @@ -157,7 +147,7 @@ psscm_pspace_smob_from_pspace (struct program_space *pspace)
>  {
>    pspace_smob *p_smob;
>  
> -  p_smob = (pspace_smob *) program_space_data (pspace, psscm_pspace_data_key);
> +  p_smob = psscm_pspace_data_key.get (pspace);
>    if (p_smob == NULL)
>      {
>        SCM p_scm = psscm_make_pspace_smob ();
> @@ -165,7 +155,7 @@ psscm_pspace_smob_from_pspace (struct program_space *pspace)
>        p_smob = (pspace_smob *) SCM_SMOB_DATA (p_scm);
>        p_smob->pspace = pspace;
>  
> -      set_program_space_data (pspace, psscm_pspace_data_key, p_smob);
> +      psscm_pspace_data_key.set (pspace, p_smob);
>        scm_gc_protect_object (p_smob->containing_scm);
>      }
>  
> @@ -418,12 +408,3 @@ gdbscm_initialize_pspaces (void)
>  
>    gdbscm_define_functions (pspace_functions, 1);
>  }
> -
> -void _initialize_scm_progspace ();
> -void
> -_initialize_scm_progspace ()
> -{
> -  psscm_pspace_data_key
> -    = register_program_space_data_with_cleanup (NULL,
> -						psscm_handle_pspace_deleted);
> -}
> diff --git a/gdb/guile/scm-symbol.c b/gdb/guile/scm-symbol.c
> index 55eac3cfff6..0b96e5a02c1 100644
> --- a/gdb/guile/scm-symbol.c
> +++ b/gdb/guile/scm-symbol.c
> @@ -49,7 +49,37 @@ static SCM block_keyword;
>  static SCM domain_keyword;
>  static SCM frame_keyword;
>  
> -static const struct objfile_data *syscm_objfile_data_key;
> +/* This is called when an objfile is about to be freed.
> +   Invalidate the symbol as further actions on the symbol would result
> +   in bad data.  All access to s_smob->symbol should be gated by
> +   syscm_get_valid_symbol_smob_arg_unsafe which will raise an exception on
> +   invalid symbols.  */
> +struct syscm_deleter
> +{
> +  /* Helper function for syscm_del_objfile_symbols to mark the symbol
> +     as invalid.  */
> +
> +  static int
> +  syscm_mark_symbol_invalid (void **slot, void *info)
> +  {
> +    symbol_smob *s_smob = (symbol_smob *) *slot;
> +
> +    s_smob->symbol = NULL;
> +    return 1;
> +  }
> +
> +  void operator() (htab_t htab)
> +  {
> +    if (htab != NULL)
> +      {
> +	htab_traverse_noresize (htab, syscm_mark_symbol_invalid, NULL);
> +	htab_delete (htab);
> +      }
> +  }
> +};
> +
> +static const registry<objfile>::key<htab, syscm_deleter>
> +     syscm_objfile_data_key;
>  static struct gdbarch_data *syscm_gdbarch_data_key;
>  
>  struct syscm_gdbarch_data
> @@ -105,12 +135,12 @@ syscm_get_symbol_map (struct symbol *symbol)
>      {
>        struct objfile *objfile = symbol->objfile ();
>  
> -      htab = (htab_t) objfile_data (objfile, syscm_objfile_data_key);
> +      htab = syscm_objfile_data_key.get (objfile);
>        if (htab == NULL)
>  	{
>  	  htab = gdbscm_create_eqable_gsmob_ptr_map (syscm_hash_symbol_smob,
>  						     syscm_eq_symbol_smob);
> -	  set_objfile_data (objfile, syscm_objfile_data_key, htab);
> +	  syscm_objfile_data_key.set (objfile, htab);
>  	}
>      }
>    else
> @@ -291,35 +321,6 @@ syscm_get_valid_symbol_arg_unsafe (SCM self, int arg_pos,
>    return s_smob->symbol;
>  }
>  
> -/* Helper function for syscm_del_objfile_symbols to mark the symbol
> -   as invalid.  */
> -
> -static int
> -syscm_mark_symbol_invalid (void **slot, void *info)
> -{
> -  symbol_smob *s_smob = (symbol_smob *) *slot;
> -
> -  s_smob->symbol = NULL;
> -  return 1;
> -}
> -
> -/* This function is called when an objfile is about to be freed.
> -   Invalidate the symbol as further actions on the symbol would result
> -   in bad data.  All access to s_smob->symbol should be gated by
> -   syscm_get_valid_symbol_smob_arg_unsafe which will raise an exception on
> -   invalid symbols.  */
> -
> -static void
> -syscm_del_objfile_symbols (struct objfile *objfile, void *datum)
> -{
> -  htab_t htab = (htab_t) datum;
> -
> -  if (htab != NULL)
> -    {
> -      htab_traverse_noresize (htab, syscm_mark_symbol_invalid, NULL);
> -      htab_delete (htab);
> -    }
> -}
>  \f
>  /* Symbol methods.  */
>  
> @@ -823,11 +824,6 @@ void _initialize_scm_symbol ();
>  void
>  _initialize_scm_symbol ()
>  {
> -  /* Register an objfile "free" callback so we can properly
> -     invalidate symbols when an object file is about to be deleted.  */
> -  syscm_objfile_data_key
> -    = register_objfile_data_with_cleanup (NULL, syscm_del_objfile_symbols);
> -
>    /* Arch-specific symbol data.  */
>    syscm_gdbarch_data_key
>      = gdbarch_data_register_post_init (syscm_init_arch_symbols);
> diff --git a/gdb/guile/scm-symtab.c b/gdb/guile/scm-symtab.c
> index 518ceeaa15d..940823147bf 100644
> --- a/gdb/guile/scm-symtab.c
> +++ b/gdb/guile/scm-symtab.c
> @@ -77,7 +77,37 @@ static const char sal_smob_name[] = "gdb:sal";
>  static scm_t_bits symtab_smob_tag;
>  static scm_t_bits sal_smob_tag;
>  
> -static const struct objfile_data *stscm_objfile_data_key;
> +/* This is called when an objfile is about to be freed.
> +   Invalidate the symbol table as further actions on the symbol table
> +   would result in bad data.  All access to st_smob->symtab should be
> +   gated by stscm_get_valid_symtab_smob_arg_unsafe which will raise an
> +   exception on invalid symbol tables.  */
> +struct stscm_deleter
> +{
> +  /* Helper function for stscm_del_objfile_symtabs to mark the symtab
> +     as invalid.  */
> +
> +  static int
> +  stscm_mark_symtab_invalid (void **slot, void *info)
> +  {
> +    symtab_smob *st_smob = (symtab_smob *) *slot;
> +
> +    st_smob->symtab = NULL;
> +    return 1;
> +  }
> +
> +  void operator() (htab_t htab)
> +  {
> +    if (htab != NULL)
> +      {
> +	htab_traverse_noresize (htab, stscm_mark_symtab_invalid, NULL);
> +	htab_delete (htab);
> +      }
> +  }
> +};
> +
> +static const registry<objfile>::key<htab, stscm_deleter>
> +     stscm_objfile_data_key;
>  \f
>  /* Administrivia for symtab smobs.  */
>  
> @@ -110,13 +140,13 @@ static htab_t
>  stscm_objfile_symtab_map (struct symtab *symtab)
>  {
>    struct objfile *objfile = symtab->compunit ()->objfile ();
> -  htab_t htab = (htab_t) objfile_data (objfile, stscm_objfile_data_key);
> +  htab_t htab = stscm_objfile_data_key.get (objfile);
>  
>    if (htab == NULL)
>      {
>        htab = gdbscm_create_eqable_gsmob_ptr_map (stscm_hash_symtab_smob,
>  						 stscm_eq_symtab_smob);
> -      set_objfile_data (objfile, stscm_objfile_data_key, htab);
> +      stscm_objfile_data_key.set (objfile, htab);
>      }
>  
>    return htab;
> @@ -271,35 +301,6 @@ stscm_get_valid_symtab_smob_arg_unsafe (SCM self, int arg_pos,
>    return st_smob;
>  }
>  
> -/* Helper function for stscm_del_objfile_symtabs to mark the symtab
> -   as invalid.  */
> -
> -static int
> -stscm_mark_symtab_invalid (void **slot, void *info)
> -{
> -  symtab_smob *st_smob = (symtab_smob *) *slot;
> -
> -  st_smob->symtab = NULL;
> -  return 1;
> -}
> -
> -/* This function is called when an objfile is about to be freed.
> -   Invalidate the symbol table as further actions on the symbol table
> -   would result in bad data.  All access to st_smob->symtab should be
> -   gated by stscm_get_valid_symtab_smob_arg_unsafe which will raise an
> -   exception on invalid symbol tables.  */
> -
> -static void
> -stscm_del_objfile_symtabs (struct objfile *objfile, void *datum)
> -{
> -  htab_t htab = (htab_t) datum;
> -
> -  if (htab != NULL)
> -    {
> -      htab_traverse_noresize (htab, stscm_mark_symtab_invalid, NULL);
> -      htab_delete (htab);
> -    }
> -}
>  \f
>  /* Symbol table methods.  */
>  
> @@ -687,14 +688,3 @@ gdbscm_initialize_symtabs (void)
>  
>    gdbscm_define_functions (symtab_functions, 1);
>  }
> -
> -void _initialize_scm_symtab ();
> -void
> -_initialize_scm_symtab ()
> -{
> -  /* Register an objfile "free" callback so we can properly
> -     invalidate symbol tables, and symbol table and line data
> -     structures when an object file that is about to be deleted.  */
> -  stscm_objfile_data_key
> -    = register_objfile_data_with_cleanup (NULL, stscm_del_objfile_symtabs);
> -}
> diff --git a/gdb/guile/scm-type.c b/gdb/guile/scm-type.c
> index dd7eace8d40..2dadbefb3a4 100644
> --- a/gdb/guile/scm-type.c
> +++ b/gdb/guile/scm-type.c
> @@ -81,7 +81,30 @@ static SCM tyscm_next_field_x_proc;
>  /* Keywords used in argument passing.  */
>  static SCM block_keyword;
>  
> -static const struct objfile_data *tyscm_objfile_data_key;
> +static int tyscm_copy_type_recursive (void **slot, void *info);
> +
> +/* Called when an objfile is about to be deleted.
> +   Make a copy of all types associated with OBJFILE.  */
> +
> +struct tyscm_deleter
> +{
> +  void operator() (htab_t htab)
> +  {
> +    if (!gdb_scheme_initialized)
> +      return;
> +
> +    htab_up copied_types = create_copied_types_hash ();
> +
> +    if (htab != NULL)
> +      {
> +	htab_traverse_noresize (htab, tyscm_copy_type_recursive, copied_types.get ());
> +	htab_delete (htab);
> +      }
> +  }
> +};
> +
> +static const registry<objfile>::key<htab, tyscm_deleter>
> +     tyscm_objfile_data_key;
>  
>  /* Hash table to uniquify global (non-objfile-owned) types.  */
>  static htab_t global_types_map;
> @@ -158,12 +181,12 @@ tyscm_type_map (struct type *type)
>    if (objfile == NULL)
>      return global_types_map;
>  
> -  htab = (htab_t) objfile_data (objfile, tyscm_objfile_data_key);
> +  htab = tyscm_objfile_data_key.get (objfile);
>    if (htab == NULL)
>      {
>        htab = gdbscm_create_eqable_gsmob_ptr_map (tyscm_hash_type_smob,
>  						 tyscm_eq_type_smob);
> -      set_objfile_data (objfile, tyscm_objfile_data_key, htab);
> +      tyscm_objfile_data_key.set (objfile, htab);
>      }
>  
>    return htab;
> @@ -345,20 +368,17 @@ tyscm_scm_to_type (SCM t_scm)
>    return t_smob->type;
>  }
>  
> -/* Helper function for save_objfile_types to make a deep copy of the type.  */
> +/* Helper function to make a deep copy of the type.  */
>  
>  static int
>  tyscm_copy_type_recursive (void **slot, void *info)
>  {
>    type_smob *t_smob = (type_smob *) *slot;
>    htab_t copied_types = (htab_t) info;
> -  struct objfile *objfile = t_smob->type->objfile_owner ();
>    htab_t htab;
>    eqable_gdb_smob **new_slot;
>    type_smob t_smob_for_lookup;
>  
> -  gdb_assert (objfile != NULL);
> -
>    htab_empty (copied_types);
>    t_smob->type = copy_type_recursive (t_smob->type, copied_types);
>  
> @@ -380,25 +400,6 @@ tyscm_copy_type_recursive (void **slot, void *info)
>    return 1;
>  }
>  
> -/* Called when OBJFILE is about to be deleted.
> -   Make a copy of all types associated with OBJFILE.  */
> -
> -static void
> -save_objfile_types (struct objfile *objfile, void *datum)
> -{
> -  htab_t htab = (htab_t) datum;
> -
> -  if (!gdb_scheme_initialized)
> -    return;
> -
> -  htab_up copied_types = create_copied_types_hash ();
> -
> -  if (htab != NULL)
> -    {
> -      htab_traverse_noresize (htab, tyscm_copy_type_recursive, copied_types.get ());
> -      htab_delete (htab);
> -    }
> -}
>  \f
>  /* Administrivia for field smobs.  */
>  
> @@ -1510,13 +1511,3 @@ Internal function to assist the type fields iterator."));
>    global_types_map = gdbscm_create_eqable_gsmob_ptr_map (tyscm_hash_type_smob,
>  							 tyscm_eq_type_smob);
>  }
> -
> -void _initialize_scm_type ();
> -void
> -_initialize_scm_type ()
> -{
> -  /* Register an objfile "free" callback so we can properly copy types
> -     associated with the objfile when it's about to be deleted.  */
> -  tyscm_objfile_data_key
> -    = register_objfile_data_with_cleanup (save_objfile_types, NULL);
> -}
> diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
> index f9ececbb04f..80a1c0bbd4d 100644
> --- a/gdb/hppa-tdep.c
> +++ b/gdb/hppa-tdep.c
> @@ -84,7 +84,8 @@ struct hppa_objfile_private
>     that separately and make this static. The solib data is probably hpux-
>     specific, so we can create a separate extern objfile_data that is registered
>     by hppa-hpux-tdep.c and shared with pa64solib.c and somsolib.c.  */
> -static const struct objfile_key<hppa_objfile_private> hppa_objfile_priv_data;
> +static const registry<objfile>::key<hppa_objfile_private>
> +  hppa_objfile_priv_data;
>  
>  /* Get at various relevant fields of an instruction word.  */
>  #define MASK_5 0x1f
> diff --git a/gdb/inferior.c b/gdb/inferior.c
> index 606b4189181..7eb2bd97907 100644
> --- a/gdb/inferior.c
> +++ b/gdb/inferior.c
> @@ -38,11 +38,6 @@
>  #include "gdbsupport/buildargv.h"
>  #include "cli/cli-style.h"
>  
> -/* Keep a registry of per-inferior data-pointers required by other GDB
> -   modules.  */
> -
> -DEFINE_REGISTRY (inferior, REGISTRY_ACCESS_FIELD)
> -
>  intrusive_list<inferior> inferior_list;
>  static int highest_inferior_num;
>  
> @@ -76,18 +71,14 @@ inferior::~inferior ()
>    inferior *inf = this;
>  
>    m_continuations.clear ();
> -  inferior_free_data (inf);
>    target_desc_info_free (inf->tdesc_info);
>  }
>  
>  inferior::inferior (int pid_)
>    : num (++highest_inferior_num),
>      pid (pid_),
> -    environment (gdb_environ::from_host_environ ()),
> -    registry_data ()
> +    environment (gdb_environ::from_host_environ ())
>  {
> -  inferior_alloc_data (this);
> -
>    m_target_stack.push (get_dummy_target ());
>  }
>  
> diff --git a/gdb/inferior.h b/gdb/inferior.h
> index f6e26a32feb..f6a7e7fd239 100644
> --- a/gdb/inferior.h
> +++ b/gdb/inferior.h
> @@ -588,7 +588,7 @@ class inferior : public refcounted_object,
>    displaced_step_inferior_state displaced_step_state;
>  
>    /* Per inferior data-pointers required by other GDB modules.  */
> -  REGISTRY_FIELDS;
> +  registry<inferior> registry_fields;
>  
>  private:
>    /* The inferior's target stack.  */
> @@ -608,11 +608,6 @@ class inferior : public refcounted_object,
>    std::string m_cwd;
>  };
>  
> -/* Keep a registry of per-inferior data-pointers required by other GDB
> -   modules.  */
> -
> -DECLARE_REGISTRY (inferior);
> -
>  /* Add an inferior to the inferior list, print a message that a new
>     inferior is found, and return the pointer to the new inferior.
>     Caller may use this pointer to initialize the private inferior
> diff --git a/gdb/inflow.c b/gdb/inflow.c
> index 9c7e2907625..5477624bcd5 100644
> --- a/gdb/inflow.c
> +++ b/gdb/inflow.c
> @@ -599,7 +599,7 @@ child_pass_ctrlc (struct target_ops *self)
>  }
>  
>  /* Per-inferior data key.  */
> -static const struct inferior_key<terminal_info> inflow_inferior_data;
> +static const registry<inferior>::key<terminal_info> inflow_inferior_data;
>  
>  terminal_info::~terminal_info ()
>  {
> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
> index 4e728a06e7e..714825d96c1 100644
> --- a/gdb/linux-tdep.c
> +++ b/gdb/linux-tdep.c
> @@ -235,7 +235,7 @@ struct linux_info
>  };
>  
>  /* Per-inferior data key.  */
> -static const struct inferior_key<linux_info> linux_inferior_data;
> +static const registry<inferior>::key<linux_info> linux_inferior_data;
>  
>  /* Frees whatever allocated space there is to be freed and sets INF's
>     linux cache data pointer to NULL.  */
> diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c
> index ca7c15ee63f..bf90471da63 100644
> --- a/gdb/mdebugread.c
> +++ b/gdb/mdebugread.c
> @@ -1354,8 +1354,8 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char *ext_sh, int bigend,
>  
>  /* Basic types.  */
>  
> -static const struct objfile_key<struct type *,
> -				gdb::noop_deleter<struct type *>>
> +static const registry<objfile>::key<struct type *,
> +				    gdb::noop_deleter<struct type *>>
>    basic_type_data;
>  
>  static struct type *
> diff --git a/gdb/minidebug.c b/gdb/minidebug.c
> index e94768ac69c..dbbdf85e08c 100644
> --- a/gdb/minidebug.c
> +++ b/gdb/minidebug.c
> @@ -28,7 +28,7 @@
>  
>  /* We stash a reference to the .gnu_debugdata BFD on the enclosing
>     BFD.  */
> -static const bfd_key<gdb_bfd_ref_ptr> gnu_debug_key;
> +static const registry<bfd>::key<gdb_bfd_ref_ptr> gnu_debug_key;
>  
>  #include <lzma.h>
>  
> diff --git a/gdb/nto-tdep.c b/gdb/nto-tdep.c
> index 9b08adfa18c..301d403eb13 100644
> --- a/gdb/nto-tdep.c
> +++ b/gdb/nto-tdep.c
> @@ -51,7 +51,7 @@ static char default_nto_target[] = "";
>  
>  struct nto_target_ops current_nto_target;
>  
> -static const struct inferior_key<struct nto_inferior_data>
> +static const registry<inferior>::key<struct nto_inferior_data>
>    nto_inferior_data_reg;
>  
>  static char *
> diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
> index 37008da529a..4429d4a7d44 100644
> --- a/gdb/objc-lang.c
> +++ b/gdb/objc-lang.c
> @@ -76,7 +76,7 @@ struct objc_method {
>    CORE_ADDR imp;
>  };
>  
> -static const struct objfile_key<unsigned int> objc_objfile_data;
> +static const registry<objfile>::key<unsigned int> objc_objfile_data;
>  
>  /* Lookup a structure type named "struct NAME", visible in lexical
>     block BLOCK.  If NOERR is nonzero, return zero if NAME is not
> diff --git a/gdb/objfiles.c b/gdb/objfiles.c
> index 80f68fda1c1..b9a59b4d96c 100644
> --- a/gdb/objfiles.c
> +++ b/gdb/objfiles.c
> @@ -57,11 +57,6 @@
>  #include <algorithm>
>  #include <vector>
>  
> -/* Keep a registry of per-objfile data-pointers required by other GDB
> -   modules.  */
> -
> -DEFINE_REGISTRY (objfile, REGISTRY_ACCESS_FIELD)
> -
>  /* Externally visible variables that are owned by this module.
>     See declarations in objfile.h for more info.  */
>  
> @@ -85,7 +80,7 @@ struct objfile_pspace_info
>  };
>  
>  /* Per-program-space data key.  */
> -static const struct program_space_key<objfile_pspace_info>
> +static const registry<program_space>::key<objfile_pspace_info>
>    objfiles_pspace_data;
>  
>  objfile_pspace_info::~objfile_pspace_info ()
> @@ -112,7 +107,7 @@ get_objfile_pspace_data (struct program_space *pspace)
>  
>  /* Per-BFD data key.  */
>  
> -static const struct bfd_key<objfile_per_bfd_storage> objfiles_bfd_data;
> +static const registry<bfd>::key<objfile_per_bfd_storage> objfiles_bfd_data;
>  
>  objfile_per_bfd_storage::~objfile_per_bfd_storage ()
>  {
> @@ -329,8 +324,6 @@ objfile::objfile (bfd *abfd, const char *name, objfile_flags flags_)
>       gdb_obstack.h specifies the alloc/dealloc functions.  */
>    obstack_init (&objfile_obstack);
>  
> -  objfile_alloc_data (this);
> -
>    std::string name_holder;
>    if (name == NULL)
>      {
> @@ -565,10 +558,6 @@ objfile::~objfile ()
>    if (sf != NULL)
>      (*sf->sym_finish) (this);
>  
> -  /* Discard any data modules have associated with the objfile.  The function
> -     still may reference obfd.  */
> -  objfile_free_data (this);
> -
>    if (obfd)
>      gdb_bfd_unref (obfd);
>    else
> diff --git a/gdb/objfiles.h b/gdb/objfiles.h
> index 9da12ff12e0..aee9b324b17 100644
> --- a/gdb/objfiles.h
> +++ b/gdb/objfiles.h
> @@ -682,7 +682,7 @@ struct objfile
>  
>    /* Per objfile data-pointers required by other GDB modules.  */
>  
> -  REGISTRY_FIELDS {};
> +  registry<objfile> registry_fields;
>  
>    /* Set of relocation offsets to apply to each section.
>       The table is indexed by the_bfd_section->index, thus it is generally
> @@ -900,10 +900,6 @@ in_plt_section (CORE_ADDR pc)
>  	  || pc_in_section (pc, ".plt.sec"));
>  }
>  
> -/* Keep a registry of per-objfile data-pointers required by other GDB
> -   modules.  */
> -DECLARE_REGISTRY(objfile);
> -
>  /* In normal use, the section map will be rebuilt by find_pc_section
>     if objfiles have been added, removed or relocated since it was last
>     called.  Calling inhibit_section_map_updates will inhibit this
> diff --git a/gdb/progspace.c b/gdb/progspace.c
> index 3232ea9ab01..7c801d2d960 100644
> --- a/gdb/progspace.c
> +++ b/gdb/progspace.c
> @@ -43,24 +43,11 @@ static int highest_address_space_num;
>  
>  \f
>  
> -/* Keep a registry of per-program_space data-pointers required by other GDB
> -   modules.  */
> -
> -DEFINE_REGISTRY (program_space, REGISTRY_ACCESS_FIELD)
> -
> -/* Keep a registry of per-address_space data-pointers required by other GDB
> -   modules.  */
> -
> -DEFINE_REGISTRY (address_space, REGISTRY_ACCESS_FIELD)
> -
> -\f
> -
>  /* Create a new address space object, and add it to the list.  */
>  
>  address_space::address_space ()
>    : m_num (++highest_address_space_num)
>  {
> -  address_space_alloc_data (this);
>  }
>  
>  /* Maybe create a new address space object, and add it to the list, or
> @@ -81,11 +68,6 @@ maybe_new_address_space (void)
>    return new address_space ();
>  }
>  
> -address_space::~address_space ()
> -{
> -  address_space_free_data (this);
> -}
> -
>  /* Start counting over from scratch.  */
>  
>  static void
> @@ -115,8 +97,6 @@ program_space::program_space (address_space *aspace_)
>    : num (++last_program_space_num),
>      aspace (aspace_)
>  {
> -  program_space_alloc_data (this);
> -
>    program_spaces.push_back (this);
>  }
>  
> @@ -140,8 +120,6 @@ program_space::~program_space ()
>    clear_symtab_users (SYMFILE_DEFER_BP_RESET);
>    if (!gdbarch_has_shared_address_space (target_gdbarch ()))
>      delete this->aspace;
> -    /* Discard any data modules have associated with the PSPACE.  */
> -  program_space_free_data (this);
>  }
>  
>  /* See progspace.h.  */
> diff --git a/gdb/progspace.h b/gdb/progspace.h
> index eff157b0dd3..44836ff37aa 100644
> --- a/gdb/progspace.h
> +++ b/gdb/progspace.h
> @@ -37,8 +37,7 @@ struct objfile;
>  struct inferior;
>  struct exec;
>  struct address_space;
> -struct program_space_data;
> -struct address_space_data;
> +struct program_space;
>  struct so_list;
>  
>  typedef std::list<std::shared_ptr<objfile>> objfile_list;
> @@ -372,7 +371,7 @@ struct program_space
>    std::vector<std::string> deleted_solibs;
>  
>    /* Per pspace data-pointers required by other GDB modules.  */
> -  REGISTRY_FIELDS {};
> +  registry<program_space> registry_fields;
>  
>  private:
>    /* The set of target sections matching the sections mapped into
> @@ -387,7 +386,6 @@ struct address_space
>  {
>    /* Create a new address space object, and add it to the list.  */
>    address_space ();
> -  ~address_space ();
>    DISABLE_COPY_AND_ASSIGN (address_space);
>  
>    /* Returns the integer address space id of this address space.  */
> @@ -397,7 +395,7 @@ struct address_space
>    }
>  
>    /* Per aspace data-pointers required by other GDB modules.  */
> -  REGISTRY_FIELDS {};
> +  registry<address_space> registry_fields;
>  
>  private:
>    int m_num;
> @@ -457,14 +455,4 @@ extern struct address_space *maybe_new_address_space (void);
>     mappings.  */
>  extern void update_address_spaces (void);
>  
> -/* Keep a registry of per-pspace data-pointers required by other GDB
> -   modules.  */
> -
> -DECLARE_REGISTRY (program_space);
> -
> -/* Keep a registry of per-aspace data-pointers required by other GDB
> -   modules.  */
> -
> -DECLARE_REGISTRY (address_space);
> -
>  #endif
> diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c
> index 872fb89ba83..b9aea3aca69 100644
> --- a/gdb/python/py-block.c
> +++ b/gdb/python/py-block.c
> @@ -77,9 +77,33 @@ struct block_syms_iterator_object {
>        }									\
>    } while (0)
>  
> +/* This is called when an objfile is about to be freed.
> +   Invalidate the block as further actions on the block would result
> +   in bad data.  All access to obj->symbol should be gated by
> +   BLPY_REQUIRE_VALID which will raise an exception on invalid
> +   blocks.  */
> +struct blpy_deleter
> +{
> +  void operator() (block_object *obj)
> +  {
> +    while (obj)
> +      {
> +	block_object *next = obj->next;
> +
> +	obj->block = NULL;
> +	obj->objfile = NULL;
> +	obj->next = NULL;
> +	obj->prev = NULL;
> +
> +	obj = next;
> +      }
> +  }
> +};
> +
>  extern PyTypeObject block_syms_iterator_object_type
>      CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("block_syms_iterator_object");
> -static const struct objfile_data *blpy_objfile_data_key;
> +static const registry<objfile>::key<block_object, blpy_deleter>
> +     blpy_objfile_data_key;
>  
>  static PyObject *
>  blpy_iter (PyObject *self)
> @@ -269,10 +293,7 @@ blpy_dealloc (PyObject *obj)
>    if (block->prev)
>      block->prev->next = block->next;
>    else if (block->objfile)
> -    {
> -      set_objfile_data (block->objfile, blpy_objfile_data_key,
> -			block->next);
> -    }
> +    blpy_objfile_data_key.set (block->objfile, block->next);
>    if (block->next)
>      block->next->prev = block->prev;
>    block->block = NULL;
> @@ -293,11 +314,10 @@ set_block (block_object *obj, const struct block *block,
>    if (objfile)
>      {
>        obj->objfile = objfile;
> -      obj->next = ((block_object *)
> -		   objfile_data (objfile, blpy_objfile_data_key));
> +      obj->next = blpy_objfile_data_key.get (objfile);
>        if (obj->next)
>  	obj->next->prev = obj;
> -      set_objfile_data (objfile, blpy_objfile_data_key, obj);
> +      blpy_objfile_data_key.set (objfile, obj);
>      }
>    else
>      obj->next = NULL;
> @@ -404,40 +424,6 @@ blpy_iter_is_valid (PyObject *self, PyObject *args)
>    Py_RETURN_TRUE;
>  }
>  
> -/* This function is called when an objfile is about to be freed.
> -   Invalidate the block as further actions on the block would result
> -   in bad data.  All access to obj->symbol should be gated by
> -   BLPY_REQUIRE_VALID which will raise an exception on invalid
> -   blocks.  */
> -static void
> -del_objfile_blocks (struct objfile *objfile, void *datum)
> -{
> -  block_object *obj = (block_object *) datum;
> -
> -  while (obj)
> -    {
> -      block_object *next = obj->next;
> -
> -      obj->block = NULL;
> -      obj->objfile = NULL;
> -      obj->next = NULL;
> -      obj->prev = NULL;
> -
> -      obj = next;
> -    }
> -}
> -
> -void _initialize_py_block ();
> -void
> -_initialize_py_block ()
> -{
> -  /* Register an objfile "free" callback so we can properly
> -     invalidate blocks when an object file is about to be
> -     deleted.  */
> -  blpy_objfile_data_key
> -    = register_objfile_data_with_cleanup (NULL, del_objfile_blocks);
> -}
> -
>  int
>  gdbpy_initialize_blocks (void)
>  {
> diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
> index ebcd5b0a70f..ac94d1322cc 100644
> --- a/gdb/python/py-inferior.c
> +++ b/gdb/python/py-inferior.c
> @@ -60,7 +60,35 @@ struct inferior_object
>  extern PyTypeObject inferior_object_type
>      CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("inferior_object");
>  
> -static const struct inferior_data *infpy_inf_data_key;
> +/* Deleter to clean up when an inferior is removed.  */
> +struct infpy_deleter
> +{
> +  void operator() (inferior_object *obj)
> +  {
> +    struct threadlist_entry *th_entry, *th_tmp;
> +
> +    if (!gdb_python_initialized)
> +      return;
> +
> +    gdbpy_enter enter_py;
> +    gdbpy_ref<inferior_object> inf_obj (obj);
> +
> +    inf_obj->inferior = NULL;
> +
> +    /* Deallocate threads list.  */
> +    for (th_entry = inf_obj->threads; th_entry != NULL;)
> +      {
> +	th_tmp = th_entry;
> +	th_entry = th_entry->next;
> +	delete th_tmp;
> +      }
> +
> +    inf_obj->nthreads = 0;
> +  }
> +};
> +
> +static const registry<inferior>::key<inferior_object, infpy_deleter>
> +     infpy_inf_data_key;
>  
>  /* Require that INFERIOR be a valid inferior ID.  */
>  #define INFPY_REQUIRE_VALID(Inferior)				\
> @@ -207,7 +235,7 @@ inferior_to_inferior_object (struct inferior *inferior)
>  {
>    inferior_object *inf_obj;
>  
> -  inf_obj = (inferior_object *) inferior_data (inferior, infpy_inf_data_key);
> +  inf_obj = infpy_inf_data_key.get (inferior);
>    if (!inf_obj)
>      {
>        inf_obj = PyObject_New (inferior_object, &inferior_object_type);
> @@ -220,7 +248,7 @@ inferior_to_inferior_object (struct inferior *inferior)
>  
>        /* PyObject_New initializes the new object with a refcount of 1.  This
>  	 counts for the reference we are keeping in the inferior data.  */
> -      set_inferior_data (inferior, infpy_inf_data_key, inf_obj);
> +      infpy_inf_data_key.set (inferior, inf_obj);
>      }
>  
>    /* We are returning a new reference.  */
> @@ -781,32 +809,6 @@ infpy_dealloc (PyObject *obj)
>    Py_TYPE (obj)->tp_free (obj);
>  }
>  
> -/* Clear the INFERIOR pointer in an Inferior object and clear the
> -   thread list.  */
> -static void
> -py_free_inferior (struct inferior *inf, void *datum)
> -{
> -  struct threadlist_entry *th_entry, *th_tmp;
> -
> -  if (!gdb_python_initialized)
> -    return;
> -
> -  gdbpy_enter enter_py;
> -  gdbpy_ref<inferior_object> inf_obj ((inferior_object *) datum);
> -
> -  inf_obj->inferior = NULL;
> -
> -  /* Deallocate threads list.  */
> -  for (th_entry = inf_obj->threads; th_entry != NULL;)
> -    {
> -      th_tmp = th_entry;
> -      th_entry = th_entry->next;
> -      delete th_tmp;
> -    }
> -
> -  inf_obj->nthreads = 0;
> -}
> -
>  /* Implementation of gdb.selected_inferior() -> gdb.Inferior.
>     Returns the current inferior object.  */
>  
> @@ -817,14 +819,6 @@ gdbpy_selected_inferior (PyObject *self, PyObject *args)
>  	  inferior_to_inferior_object (current_inferior ()).release ());
>  }
>  
> -void _initialize_py_inferior ();
> -void
> -_initialize_py_inferior ()
> -{
> -  infpy_inf_data_key =
> -    register_inferior_data_with_cleanup (NULL, py_free_inferior);
> -}
> -
>  int
>  gdbpy_initialize_inferior (void)
>  {
> diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
> index 3e3270e7cd3..8954c2e5abb 100644
> --- a/gdb/python/py-objfile.c
> +++ b/gdb/python/py-objfile.c
> @@ -55,7 +55,20 @@ struct objfile_object
>  extern PyTypeObject objfile_object_type
>      CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("objfile_object");
>  
> -static const struct objfile_data *objfpy_objfile_data_key;
> +/* Clear the OBJFILE pointer in an Objfile object and remove the
> +   reference.  */
> +struct objfpy_deleter
> +{
> +  void operator() (objfile_object *obj)
> +  {
> +    gdbpy_enter enter_py;
> +    gdbpy_ref<objfile_object> object (obj);
> +    object->objfile = nullptr;
> +  }
> +};
> +
> +static const registry<objfile>::key<objfile_object, objfpy_deleter>
> +     objfpy_objfile_data_key;
>  
>  /* Require that OBJF be a valid objfile.  */
>  #define OBJFPY_REQUIRE_VALID(obj)				\
> @@ -656,16 +669,6 @@ gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw)
>  
>  \f
>  
> -/* Clear the OBJFILE pointer in an Objfile object and remove the
> -   reference.  */
> -static void
> -py_free_objfile (struct objfile *objfile, void *datum)
> -{
> -  gdbpy_enter enter_py (objfile->arch ());
> -  gdbpy_ref<objfile_object> object ((objfile_object *) datum);
> -  object->objfile = NULL;
> -}
> -
>  /* Return a new reference to the Python object of type Objfile
>     representing OBJFILE.  If the object has already been created,
>     return it.  Otherwise, create it.  Return NULL and set the Python
> @@ -675,7 +678,7 @@ gdbpy_ref<>
>  objfile_to_objfile_object (struct objfile *objfile)
>  {
>    PyObject *result
> -    = ((PyObject *) objfile_data (objfile, objfpy_objfile_data_key));
> +    = (PyObject *) objfpy_objfile_data_key.get (objfile);
>    if (result == NULL)
>      {
>        gdbpy_ref<objfile_object> object
> @@ -686,21 +689,13 @@ objfile_to_objfile_object (struct objfile *objfile)
>  	return NULL;
>  
>        object->objfile = objfile;
> -      set_objfile_data (objfile, objfpy_objfile_data_key, object.get ());
> +      objfpy_objfile_data_key.set (objfile, object.get ());
>        result = (PyObject *) object.release ();
>      }
>  
>    return gdbpy_ref<>::new_reference (result);
>  }
>  
> -void _initialize_py_objfile ();
> -void
> -_initialize_py_objfile ()
> -{
> -  objfpy_objfile_data_key
> -    = register_objfile_data_with_cleanup (NULL, py_free_objfile);
> -}
> -
>  int
>  gdbpy_initialize_objfile (void)
>  {
> diff --git a/gdb/python/py-progspace.c b/gdb/python/py-progspace.c
> index 5657ef7756c..64a172dcdd3 100644
> --- a/gdb/python/py-progspace.c
> +++ b/gdb/python/py-progspace.c
> @@ -57,7 +57,30 @@ struct pspace_object
>  extern PyTypeObject pspace_object_type
>      CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("pspace_object");
>  
> -static const struct program_space_data *pspy_pspace_data_key;
> +/* Clear the PSPACE pointer in a Pspace object and remove the reference.  */
> +struct pspace_deleter
> +{
> +  void operator() (pspace_object *obj)
> +  {
> +    /* This is a fiction, but we're in a nasty spot: The pspace is in the
> +       process of being deleted, we can't rely on anything in it.  Plus
> +       this is one time when the current program space and current inferior
> +       are not in sync: All inferiors that use PSPACE may no longer exist.
> +       We don't need to do much here, and since "there is always an inferior"
> +       using target_gdbarch suffices.
> +       Note: We cannot call get_current_arch because it may try to access
> +       the target, which may involve accessing data in the pspace currently
> +       being deleted.  */
> +    struct gdbarch *arch = target_gdbarch ();
> +
> +    gdbpy_enter enter_py (arch);
> +    gdbpy_ref<pspace_object> object (obj);
> +    object->pspace = NULL;
> +  }
> +};
> +
> +static const registry<program_space>::key<pspace_object, pspace_deleter>
> +     pspy_pspace_data_key;
>  
>  /* Require that PSPACE_OBJ be a valid program space ID.  */
>  #define PSPY_REQUIRE_VALID(pspace_obj)				\
> @@ -456,27 +479,6 @@ pspy_is_valid (PyObject *o, PyObject *args)
>  
>  \f
>  
> -/* Clear the PSPACE pointer in a Pspace object and remove the reference.  */
> -
> -static void
> -py_free_pspace (struct program_space *pspace, void *datum)
> -{
> -  /* This is a fiction, but we're in a nasty spot: The pspace is in the
> -     process of being deleted, we can't rely on anything in it.  Plus
> -     this is one time when the current program space and current inferior
> -     are not in sync: All inferiors that use PSPACE may no longer exist.
> -     We don't need to do much here, and since "there is always an inferior"
> -     using target_gdbarch suffices.
> -     Note: We cannot call get_current_arch because it may try to access
> -     the target, which may involve accessing data in the pspace currently
> -     being deleted.  */
> -  struct gdbarch *arch = target_gdbarch ();
> -
> -  gdbpy_enter enter_py (arch);
> -  gdbpy_ref<pspace_object> object ((pspace_object *) datum);
> -  object->pspace = NULL;
> -}
> -
>  /* Return a new reference to the Python object of type Pspace
>     representing PSPACE.  If the object has already been created,
>     return it.  Otherwise, create it.  Return NULL and set the Python
> @@ -485,8 +487,7 @@ py_free_pspace (struct program_space *pspace, void *datum)
>  gdbpy_ref<>
>  pspace_to_pspace_object (struct program_space *pspace)
>  {
> -  PyObject *result
> -    ((PyObject *) program_space_data (pspace, pspy_pspace_data_key));
> +  PyObject *result = (PyObject *) pspy_pspace_data_key.get (pspace);
>    if (result == NULL)
>      {
>        gdbpy_ref<pspace_object> object
> @@ -497,7 +498,7 @@ pspace_to_pspace_object (struct program_space *pspace)
>  	return NULL;
>  
>        object->pspace = pspace;
> -      set_program_space_data (pspace, pspy_pspace_data_key, object.get ());
> +      pspy_pspace_data_key.set (pspace, object.get ());
>        result = (PyObject *) object.release ();
>      }
>  
> @@ -521,14 +522,6 @@ gdbpy_is_progspace (PyObject *obj)
>    return PyObject_TypeCheck (obj, &pspace_object_type);
>  }
>  
> -void _initialize_py_progspace ();
> -void
> -_initialize_py_progspace ()
> -{
> -  pspy_pspace_data_key
> -    = register_program_space_data_with_cleanup (NULL, py_free_pspace);
> -}
> -
>  int
>  gdbpy_initialize_pspace (void)
>  {
> diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
> index 02c35acd1e9..b5b8056f321 100644
> --- a/gdb/python/py-symbol.c
> +++ b/gdb/python/py-symbol.c
> @@ -50,7 +50,26 @@ struct symbol_object {
>        }							\
>    } while (0)
>  
> -static const struct objfile_data *sympy_objfile_data_key;
> +/* A deleter that is used when an objfile is about to be freed.  */
> +struct symbol_object_deleter
> +{
> +  void operator() (symbol_object *obj)
> +  {
> +    while (obj)
> +      {
> +	symbol_object *next = obj->next;
> +
> +	obj->symbol = NULL;
> +	obj->next = NULL;
> +	obj->prev = NULL;
> +
> +	obj = next;
> +      }
> +  }
> +};
> +
> +static const registry<objfile>::key<symbol_object, symbol_object_deleter>
> +     sympy_objfile_data_key;
>  
>  static PyObject *
>  sympy_str (PyObject *self)
> @@ -307,11 +326,10 @@ set_symbol (symbol_object *obj, struct symbol *symbol)
>      {
>        struct objfile *objfile = symbol->objfile ();
>  
> -      obj->next = ((symbol_object *)
> -		   objfile_data (objfile, sympy_objfile_data_key));
> +      obj->next = sympy_objfile_data_key.get (objfile);
>        if (obj->next)
>  	obj->next->prev = obj;
> -      set_objfile_data (objfile, sympy_objfile_data_key, obj);
> +      sympy_objfile_data_key.set (objfile, obj);
>      }
>    else
>      obj->next = NULL;
> @@ -350,10 +368,7 @@ sympy_dealloc (PyObject *obj)
>    else if (sym_obj->symbol != NULL
>  	   && sym_obj->symbol->is_objfile_owned ()
>  	   && sym_obj->symbol->symtab () != NULL)
> -    {
> -      set_objfile_data (sym_obj->symbol->objfile (),
> -			sympy_objfile_data_key, sym_obj->next);
> -    }
> +    sympy_objfile_data_key.set (sym_obj->symbol->objfile (), sym_obj->next);
>    if (sym_obj->next)
>      sym_obj->next->prev = sym_obj->prev;
>    sym_obj->symbol = NULL;
> @@ -597,38 +612,6 @@ gdbpy_lookup_static_symbols (PyObject *self, PyObject *args, PyObject *kw)
>    return return_list.release ();
>  }
>  
> -/* This function is called when an objfile is about to be freed.
> -   Invalidate the symbol as further actions on the symbol would result
> -   in bad data.  All access to obj->symbol should be gated by
> -   SYMPY_REQUIRE_VALID which will raise an exception on invalid
> -   symbols.  */
> -static void
> -del_objfile_symbols (struct objfile *objfile, void *datum)
> -{
> -  symbol_object *obj = (symbol_object *) datum;
> -  while (obj)
> -    {
> -      symbol_object *next = obj->next;
> -
> -      obj->symbol = NULL;
> -      obj->next = NULL;
> -      obj->prev = NULL;
> -
> -      obj = next;
> -    }
> -}
> -
> -void _initialize_py_symbol ();
> -void
> -_initialize_py_symbol ()
> -{
> -  /* Register an objfile "free" callback so we can properly
> -     invalidate symbol when an object file that is about to be
> -     deleted.  */
> -  sympy_objfile_data_key
> -    = register_objfile_data_with_cleanup (NULL, del_objfile_symbols);
> -}
> -
>  int
>  gdbpy_initialize_symbols (void)
>  {
> diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
> index 7ed62716b67..03c274dfff6 100644
> --- a/gdb/python/py-symtab.c
> +++ b/gdb/python/py-symtab.c
> @@ -37,9 +37,31 @@ struct symtab_object {
>    symtab_object *next;
>  };
>  
> +/* This function is called when an objfile is about to be freed.
> +   Invalidate the symbol table as further actions on the symbol table
> +   would result in bad data.  All access to obj->symtab should be
> +   gated by STPY_REQUIRE_VALID which will raise an exception on
> +   invalid symbol tables.  */
> +struct stpy_deleter
> +{
> +  void operator() (symtab_object *obj)
> +  {
> +    while (obj)
> +      {
> +	symtab_object *next = obj->next;
> +
> +	obj->symtab = NULL;
> +	obj->next = NULL;
> +	obj->prev = NULL;
> +	obj = next;
> +      }
> +  }
> +};
> +
>  extern PyTypeObject symtab_object_type
>      CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("symtab_object");
> -static const struct objfile_data *stpy_objfile_data_key;
> +static const registry<objfile>::key<symtab_object, stpy_deleter>
> +     stpy_objfile_data_key;
>  
>  /* Require a valid symbol table.  All access to symtab_object->symtab
>     should be gated by this call.  */
> @@ -68,9 +90,39 @@ struct sal_object {
>    sal_object *next;
>  };
>  
> +/* This is called when an objfile is about to be freed.  Invalidate
> +   the sal object as further actions on the sal would result in bad
> +   data.  All access to obj->sal should be gated by
> +   SALPY_REQUIRE_VALID which will raise an exception on invalid symbol
> +   table and line objects.  */
> +struct salpy_deleter
> +{
> +  void operator() (sal_object *obj)
> +  {
> +    gdbpy_enter enter_py;
> +
> +    while (obj)
> +      {
> +	sal_object *next = obj->next;
> +
> +	gdbpy_ref<> tmp (obj->symtab);
> +	obj->symtab = Py_None;
> +	Py_INCREF (Py_None);
> +
> +	obj->next = NULL;
> +	obj->prev = NULL;
> +	xfree (obj->sal);
> +	obj->sal = NULL;
> +
> +	obj = next;
> +      }
> +  }
> +};
> +
>  extern PyTypeObject sal_object_type
>      CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("sal_object");
> -static const struct objfile_data *salpy_objfile_data_key;
> +static const registry<objfile>::key<sal_object, salpy_deleter>
> +     salpy_objfile_data_key;
>  
>  /* Require a valid symbol table and line object.  All access to
>     sal_object->sal should be gated by this call.  */
> @@ -246,10 +298,8 @@ stpy_dealloc (PyObject *obj)
>    if (symtab->prev)
>      symtab->prev->next = symtab->next;
>    else if (symtab->symtab)
> -    {
> -      set_objfile_data (symtab->symtab->compunit ()->objfile (),
> -			stpy_objfile_data_key, symtab->next);
> -    }
> +    stpy_objfile_data_key.set (symtab->symtab->compunit ()->objfile (),
> +			       symtab->next);
>    if (symtab->next)
>      symtab->next->prev = symtab->prev;
>    symtab->symtab = NULL;
> @@ -329,9 +379,9 @@ salpy_dealloc (PyObject *self)
>    if (self_sal->prev)
>      self_sal->prev->next = self_sal->next;
>    else if (self_sal->symtab != Py_None)
> -    set_objfile_data
> +    salpy_objfile_data_key.set
>        (symtab_object_to_symtab (self_sal->symtab)->compunit ()->objfile (),
> -       salpy_objfile_data_key, self_sal->next);
> +       self_sal->next);
>  
>    if (self_sal->next)
>      self_sal->next->prev = self_sal->prev;
> @@ -378,13 +428,11 @@ set_sal (sal_object *sal_obj, struct symtab_and_line sal)
>        symtab *symtab = symtab_object_to_symtab (sal_obj->symtab);
>  
>        sal_obj->next
> -	= ((sal_object *) objfile_data (symtab->compunit ()->objfile (),
> -					salpy_objfile_data_key));
> +	= salpy_objfile_data_key.get (symtab->compunit ()->objfile ());
>        if (sal_obj->next)
>  	sal_obj->next->prev = sal_obj;
>  
> -      set_objfile_data (symtab->compunit ()->objfile (),
> -			salpy_objfile_data_key, sal_obj);
> +      salpy_objfile_data_key.set (symtab->compunit ()->objfile (), sal_obj);
>      }
>    else
>      sal_obj->next = NULL;
> @@ -404,14 +452,10 @@ set_symtab (symtab_object *obj, struct symtab *symtab)
>    obj->prev = NULL;
>    if (symtab)
>      {
> -      obj->next
> -	= ((symtab_object *)
> -	   objfile_data (symtab->compunit ()->objfile (),
> -			 stpy_objfile_data_key));
> +      obj->next = stpy_objfile_data_key.get (symtab->compunit ()->objfile ());
>        if (obj->next)
>  	obj->next->prev = obj;
> -      set_objfile_data (symtab->compunit ()->objfile (),
> -			stpy_objfile_data_key, obj);
> +      stpy_objfile_data_key.set (symtab->compunit ()->objfile (), obj);
>      }
>    else
>      obj->next = NULL;
> @@ -465,68 +509,6 @@ symtab_object_to_symtab (PyObject *obj)
>    return ((symtab_object *) obj)->symtab;
>  }
>  
> -/* This function is called when an objfile is about to be freed.
> -   Invalidate the symbol table as further actions on the symbol table
> -   would result in bad data.  All access to obj->symtab should be
> -   gated by STPY_REQUIRE_VALID which will raise an exception on
> -   invalid symbol tables.  */
> -static void
> -del_objfile_symtab (struct objfile *objfile, void *datum)
> -{
> -  symtab_object *obj = (symtab_object *) datum;
> -
> -  while (obj)
> -    {
> -      symtab_object *next = obj->next;
> -
> -      obj->symtab = NULL;
> -      obj->next = NULL;
> -      obj->prev = NULL;
> -      obj = next;
> -    }
> -}
> -
> -/* This function is called when an objfile is about to be freed.
> -   Invalidate the sal object as further actions on the sal
> -   would result in bad data.  All access to obj->sal should be
> -   gated by SALPY_REQUIRE_VALID which will raise an exception on
> -   invalid symbol table and line objects.  */
> -static void
> -del_objfile_sal (struct objfile *objfile, void *datum)
> -{
> -  sal_object *obj = (sal_object *) datum;
> -
> -  while (obj)
> -    {
> -      sal_object *next = obj->next;
> -
> -      gdbpy_ref<> tmp (obj->symtab);
> -      obj->symtab = Py_None;
> -      Py_INCREF (Py_None);
> -
> -      obj->next = NULL;
> -      obj->prev = NULL;
> -      xfree (obj->sal);
> -      obj->sal = NULL;
> -
> -      obj = next;
> -    }
> -}
> -
> -void _initialize_py_symtab ();
> -void
> -_initialize_py_symtab ()
> -{
> -  /* Register an objfile "free" callback so we can properly
> -     invalidate symbol tables, and symbol table and line data
> -     structures when an object file that is about to be
> -     deleted.  */
> -  stpy_objfile_data_key
> -    = register_objfile_data_with_cleanup (NULL, del_objfile_symtab);
> -  salpy_objfile_data_key
> -    = register_objfile_data_with_cleanup (NULL, del_objfile_sal);
> -}
> -
>  int
>  gdbpy_initialize_symtabs (void)
>  {
> diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
> index 6cbf5f2eb6a..068a212b77b 100644
> --- a/gdb/python/py-type.c
> +++ b/gdb/python/py-type.c
> @@ -1111,36 +1111,38 @@ typy_richcompare (PyObject *self, PyObject *other, int op)
>  
>  \f
>  
> -static const struct objfile_data *typy_objfile_data_key;
> -
> -static void
> -save_objfile_types (struct objfile *objfile, void *datum)
> +/* Deleter that saves types when an objfile is being destroyed.  */
> +struct typy_deleter
>  {
> -  type_object *obj = (type_object *) datum;
> +  void operator() (type_object *obj)
> +  {
> +    if (!gdb_python_initialized)
> +      return;
>  
> -  if (!gdb_python_initialized)
> -    return;
> +    /* This prevents another thread from freeing the objects we're
> +       operating on.  */
> +    gdbpy_enter enter_py;
>  
> -  /* This prevents another thread from freeing the objects we're
> -     operating on.  */
> -  gdbpy_enter enter_py (objfile->arch ());
> +    htab_up copied_types = create_copied_types_hash ();
>  
> -  htab_up copied_types = create_copied_types_hash ();
> +    while (obj)
> +      {
> +	type_object *next = obj->next;
>  
> -  while (obj)
> -    {
> -      type_object *next = obj->next;
> +	htab_empty (copied_types.get ());
>  
> -      htab_empty (copied_types.get ());
> +	obj->type = copy_type_recursive (obj->type, copied_types.get ());
>  
> -      obj->type = copy_type_recursive (obj->type, copied_types.get ());
> +	obj->next = NULL;
> +	obj->prev = NULL;
>  
> -      obj->next = NULL;
> -      obj->prev = NULL;
> +	obj = next;
> +      }
> +  }
> +};
>  
> -      obj = next;
> -    }
> -}
> +static const registry<objfile>::key<type_object, typy_deleter>
> +     typy_objfile_data_key;
>  
>  static void
>  set_type (type_object *obj, struct type *type)
> @@ -1151,11 +1153,10 @@ set_type (type_object *obj, struct type *type)
>      {
>        struct objfile *objfile = type->objfile_owner ();
>  
> -      obj->next = ((type_object *)
> -		   objfile_data (objfile, typy_objfile_data_key));
> +      obj->next = typy_objfile_data_key.get (objfile);
>        if (obj->next)
>  	obj->next->prev = obj;
> -      set_objfile_data (objfile, typy_objfile_data_key, obj);
> +      typy_objfile_data_key.set (objfile, obj);
>      }
>    else
>      obj->next = NULL;
> @@ -1174,7 +1175,7 @@ typy_dealloc (PyObject *obj)
>        struct objfile *objfile = type->type->objfile_owner ();
>  
>        if (objfile)
> -	set_objfile_data (objfile, typy_objfile_data_key, type->next);
> +	typy_objfile_data_key.set (objfile, type->next);
>      }
>    if (type->next)
>      type->next->prev = type->prev;
> @@ -1466,14 +1467,6 @@ gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw)
>    return type_to_type_object (type);
>  }
>  
> -void _initialize_py_type ();
> -void
> -_initialize_py_type ()
> -{
> -  typy_objfile_data_key
> -    = register_objfile_data_with_cleanup (save_objfile_types, NULL);
> -}
> -
>  int
>  gdbpy_initialize_types (void)
>  {
> diff --git a/gdb/registry.c b/gdb/registry.c
> deleted file mode 100644
> index 2e977e2528f..00000000000
> --- a/gdb/registry.c
> +++ /dev/null
> @@ -1,112 +0,0 @@
> -/* Support functions for general registry objects.
> -
> -   Copyright (C) 2011-2022 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 "registry.h"
> -const struct registry_data *
> -register_data_with_cleanup (struct registry_data_registry *registry,
> -			    registry_data_callback save,
> -			    registry_data_callback free)
> -{
> -  struct registry_data_registration **curr;
> -
> -  /* Append new registration.  */
> -  for (curr = &registry->registrations;
> -       *curr != NULL;
> -       curr = &(*curr)->next)
> -    ;
> -
> -  *curr = XNEW (struct registry_data_registration);
> -  (*curr)->next = NULL;
> -  (*curr)->data = XNEW (struct registry_data);
> -  (*curr)->data->index = registry->num_registrations++;
> -  (*curr)->data->save = save;
> -  (*curr)->data->free = free;
> -
> -  return (*curr)->data;
> -}
> -
> -void
> -registry_alloc_data (struct registry_data_registry *registry,
> -		       struct registry_fields *fields)
> -{
> -  gdb_assert (fields->data == NULL);
> -  fields->num_data = registry->num_registrations;
> -  fields->data = XCNEWVEC (void *, fields->num_data);
> -}
> -
> -void
> -registry_clear_data (struct registry_data_registry *data_registry,
> -		     registry_callback_adaptor adaptor,
> -		     struct registry_container *container,
> -		     struct registry_fields *fields)
> -{
> -  struct registry_data_registration *registration;
> -  int i;
> -
> -  gdb_assert (fields->data != NULL);
> -
> -  /* Process all the save handlers.  */
> -
> -  for (registration = data_registry->registrations, i = 0;
> -       i < fields->num_data;
> -       registration = registration->next, i++)
> -    if (fields->data[i] != NULL && registration->data->save != NULL)
> -      adaptor (registration->data->save, container, fields->data[i]);
> -
> -  /* Now process all the free handlers.  */
> -
> -  for (registration = data_registry->registrations, i = 0;
> -       i < fields->num_data;
> -       registration = registration->next, i++)
> -    if (fields->data[i] != NULL && registration->data->free != NULL)
> -      adaptor (registration->data->free, container, fields->data[i]);
> -
> -  memset (fields->data, 0, fields->num_data * sizeof (void *));
> -}
> -
> -void
> -registry_container_free_data (struct registry_data_registry *data_registry,
> -			      registry_callback_adaptor adaptor,
> -			      struct registry_container *container,
> -			      struct registry_fields *fields)
> -{
> -  void ***rdata = &fields->data;
> -  gdb_assert (*rdata != NULL);
> -  registry_clear_data (data_registry, adaptor, container, fields);
> -  xfree (*rdata);
> -  *rdata = NULL;
> -}
> -
> -void
> -registry_set_data (struct registry_fields *fields,
> -		   const struct registry_data *data,
> -		   void *value)
> -{
> -  gdb_assert (data->index < fields->num_data);
> -  fields->data[data->index] = value;
> -}
> -
> -void *
> -registry_data (struct registry_fields *fields,
> -	       const struct registry_data *data)
> -{
> -  gdb_assert (data->index < fields->num_data);
> -  return fields->data[data->index];
> -}
> diff --git a/gdb/registry.h b/gdb/registry.h
> index 1475fd2ec26..27592ff6e2a 100644
> --- a/gdb/registry.h
> +++ b/gdb/registry.h
> @@ -22,288 +22,213 @@
>  
>  #include <type_traits>
>  
> -/* The macros here implement a template type and functions for
> -   associating some user data with a container object.
> -
> -   A registry is associated with a struct tag name.  To attach a
> -   registry to a structure, use DEFINE_REGISTRY.  This takes the
> -   structure tag and an access method as arguments.  In the usual
> -   case, where the registry fields appear directly in the struct, you
> -   can use the 'REGISTRY_FIELDS' macro to declare the fields in the
> -   struct definition, and you can pass 'REGISTRY_ACCESS_FIELD' as the
> -   access argument to DEFINE_REGISTRY.  In other cases, use
> -   REGISTRY_FIELDS to define the fields in the appropriate spot, and
> -   then define your own accessor to find the registry field structure
> -   given an instance of your type.
> -
> -   The API user requests a key from a registry during gdb
> -   initialization.  Later this key can be used to associate some
> -   module-specific data with a specific container object.
> -
> -   The exported API is best used via the wrapper macros:
> -   
> -   - register_TAG_data(TAG)
> -   Get a new key for the container type TAG.
> -   
> -   - register_TAG_data_with_cleanup(TAG, SAVE, FREE)
> -   Get a new key for the container type TAG.
> -   SAVE and FREE are defined as void (*) (struct TAG *object, void *data)
> -   When the container object OBJECT is destroyed, first all registered SAVE
> -   functions are called.
> -   Then all FREE functions are called.
> -   Either or both may be NULL.  DATA is the data associated with the
> -   container object OBJECT.
> -   
> -   - clear_TAG_data(TAG, OBJECT)
> -   Clear all the data associated with OBJECT.  Should be called by the
> -   container implementation when a container object is destroyed.
> -   
> -   - set_TAG_data(TAG, OBJECT, KEY, DATA)
> -   Set the data on an object.
> -   
> -   - TAG_data(TAG, OBJECT, KEY)
> -   Fetch the data for an object; returns NULL if it has not been set.
> -*/
> -
> -/* This structure is used in a container to hold the data that the
> -   registry uses.  */
> -
> -struct registry_fields
> -{
> -  void **data;
> -  unsigned num_data;
> -};
> +template<typename T> class registry;
>  
> -/* This macro is used in a container struct definition to define the
> -   fields used by the registry code.  */
> +/* An accessor class that is used by registry_key.
>  
> -#define REGISTRY_FIELDS				\
> -  struct registry_fields registry_data
> +   Normally, a container class derives from registry<>.  In this case,
> +   the default accessor is used, as it simply returns the object.
>  
> -/* A convenience macro for the typical case where the registry data is
> -   kept as fields of the object.  This can be passed as the ACCESS
> -   method to DEFINE_REGISTRY.  */
> +   However, a container may sometimes need to store the registry
> +   elsewhere.  In this case, registry_accessor can be specialized to
> +   perform the needed indirection.  */
>  
> -#define REGISTRY_ACCESS_FIELD(CONTAINER) \
> -  (CONTAINER)
> +template<typename T>
> +struct registry_accessor
> +{
> +  /* Given a container of type T, return its registry.  */
> +  static registry<T> *get (T *obj)
> +  {
> +    return &obj->registry_fields;
> +  }
> +};
>  
> -/* Opaque type representing a container type with a registry.  This
> -   type is never defined.  This is used to factor out common
> -   functionality of all struct tag names into common code.  IOW,
> -   "struct tag name" pointers are cast to and from "struct
> -   registry_container" pointers when calling the common registry
> -   "backend" functions.  */
> -struct registry_container;
> +/* In gdb, sometimes there is a need for one module (e.g., the Python
> +   Type code) to attach some data to another object (e.g., an
> +   objfile); but it's also desirable that this be done such that the
> +   base object (the objfile in this example) not need to know anything
> +   about the attaching module (the Python code).
>  
> -/* Registry callbacks have this type.  */
> -typedef void (*registry_data_callback) (struct registry_container *, void *);
> +   This is handled using the registry system.
>  
> -struct registry_data
> -{
> -  unsigned index;
> -  registry_data_callback save;
> -  registry_data_callback free;
> -};
> +   A class needing to allow this sort registration can add a registry
> +   field.  For example, you would write:
>  
> -struct registry_data_registration
> -{
> -  struct registry_data *data;
> -  struct registry_data_registration *next;
> -};
> +   class some_container { registry<some_container> registry_fields; };
>  
> -struct registry_data_registry
> -{
> -  struct registry_data_registration *registrations;
> -  unsigned num_registrations;
> -};
> +   The name of the field matters by default, see registry_accessor.
> +
> +   A module wanting to attach data to instances of some_container uses
> +   the "key" class to register a key.  This key can then be passed to
> +   the "get" and "set" methods to handle this module's data.  */
>  
> -/* Registry backend functions.  Client code uses the frontend
> -   functions defined by DEFINE_REGISTRY below instead.  */
> -
> -const struct registry_data *register_data_with_cleanup
> -  (struct registry_data_registry *registry,
> -   registry_data_callback save,
> -   registry_data_callback free);
> -
> -void registry_alloc_data (struct registry_data_registry *registry,
> -			  struct registry_fields *registry_fields);
> -
> -/* Cast FUNC and CONTAINER to the real types, and call FUNC, also
> -   passing DATA.  */
> -typedef void (*registry_callback_adaptor) (registry_data_callback func,
> -					   struct registry_container *container,
> -					   void *data);
> -
> -void registry_clear_data (struct registry_data_registry *data_registry,
> -			  registry_callback_adaptor adaptor,
> -			  struct registry_container *container,
> -			  struct registry_fields *fields);
> -
> -void registry_container_free_data (struct registry_data_registry *data_registry,
> -				   registry_callback_adaptor adaptor,
> -				   struct registry_container *container,
> -				   struct registry_fields *fields);
> -
> -void registry_set_data (struct registry_fields *fields,
> -			const struct registry_data *data,
> -			void *value);
> -
> -void *registry_data (struct registry_fields *fields,
> -		     const struct registry_data *data);
> -
> -/* Define a new registry implementation.  */
> -
> -#define DEFINE_REGISTRY(TAG, ACCESS)					\
> -static struct registry_data_registry TAG ## _data_registry = { NULL, 0 }; \
> -									\
> -const struct TAG ## _data *						\
> -register_ ## TAG ## _data_with_cleanup (void (*save) (struct TAG *, void *), \
> -					void (*free) (struct TAG *, void *)) \
> -{									\
> -  return (struct TAG ## _data *)					\
> -    register_data_with_cleanup (&TAG ## _data_registry,			\
> -				(registry_data_callback) save,		\
> -				(registry_data_callback) free);		\
> -}									\
> -									\
> -const struct TAG ## _data *						\
> -register_ ## TAG ## _data (void)					\
> -{									\
> -  return register_ ## TAG ## _data_with_cleanup (NULL, NULL);		\
> -}									\
> -									\
> -static void								\
> -TAG ## _alloc_data (struct TAG *container)				\
> -{									\
> -  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
> -									\
> -  registry_alloc_data (&TAG ## _data_registry, rdata);			\
> -}									\
> -									\
> -static void								\
> -TAG ## registry_callback_adaptor (registry_data_callback func,		\
> -				  struct registry_container *container, \
> -				  void *data)				\
> -{									\
> -  struct TAG *tagged_container = (struct TAG *) container;		\
> -									\
> -  registry_ ## TAG ## _callback tagged_func				\
> -    = (registry_ ## TAG ## _callback) func;				\
> -									\
> -  tagged_func (tagged_container, data);					\
> -}									\
> -									\
> -void									\
> -clear_ ## TAG ## _data (struct TAG *container)				\
> -{									\
> -  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
> -									\
> -  registry_clear_data (&TAG ## _data_registry,				\
> -		       TAG ## registry_callback_adaptor,		\
> -		       (struct registry_container *) container,		\
> -		       rdata);						\
> -}									\
> -									\
> -static void								\
> -TAG ## _free_data (struct TAG *container)				\
> -{									\
> -  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
> -									\
> -  registry_container_free_data (&TAG ## _data_registry,			\
> -				TAG ## registry_callback_adaptor,	\
> -				(struct registry_container *) container, \
> -				rdata);					\
> -}									\
> -									\
> -void									\
> -set_ ## TAG ## _data (struct TAG *container,				\
> -		      const struct TAG ## _data *data,			\
> -		      void *value)					\
> -{									\
> -  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
> -									\
> -  registry_set_data (rdata,						\
> -		     (struct registry_data *) data,			\
> -		     value);						\
> -}									\
> -									\
> -void *									\
> -TAG ## _data (struct TAG *container, const struct TAG ## _data *data)	\
> -{									\
> -  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
> -									\
> -  return registry_data (rdata,						\
> -			(struct registry_data *) data);			\
> -}
> -
> -
> -/* External declarations for the registry functions.  */
> -
> -#define DECLARE_REGISTRY(TAG)						\
> -struct TAG ## _data;							\
> -typedef void (*registry_ ## TAG ## _callback) (struct TAG *, void *);	\
> -extern const struct TAG ## _data *register_ ## TAG ## _data (void);	\
> -extern const struct TAG ## _data *register_ ## TAG ## _data_with_cleanup \
> - (registry_ ## TAG ## _callback save, registry_ ## TAG ## _callback free); \
> -extern void clear_ ## TAG ## _data (struct TAG *);			\
> -extern void set_ ## TAG ## _data (struct TAG *,				\
> -				  const struct TAG ## _data *data,	\
> -				  void *value);				\
> -extern void *TAG ## _data (struct TAG *,				\
> -			   const struct TAG ## _data *data);		\
> -									\
> -template<typename DATA, typename Deleter = std::default_delete<DATA>>	\
> -class TAG ## _key							\
> -{									\
> -public:									\
> -									\
> -  TAG ## _key ()							\
> -    : m_key (register_ ## TAG ## _data_with_cleanup (nullptr,		\
> -						     cleanup))		\
> -  {									\
> -  }									\
> -									\
> -  DATA *get (struct TAG *obj) const					\
> -  {									\
> -    return (DATA *) TAG ## _data (obj, m_key);				\
> -  }									\
> -									\
> -  void set (struct TAG *obj, DATA *data) const				\
> -  {									\
> -    set_ ## TAG ## _data (obj, m_key, data);				\
> -  }									\
> -									\
> -  template<typename Dummy = DATA *, typename... Args>			\
> -  typename std::enable_if<std::is_same<Deleter,				\
> -				       std::default_delete<DATA>>::value, \
> -			  Dummy>::type					\
> -  emplace (struct TAG *obj, Args &&...args) const			\
> -  {									\
> -    DATA *result = new DATA (std::forward<Args> (args)...);		\
> -    set (obj, result);							\
> -    return result;							\
> -  }									\
> -									\
> -  void clear (struct TAG *obj) const					\
> -  {									\
> -    DATA *datum = get (obj);						\
> -    if (datum != nullptr)						\
> -      {									\
> -	cleanup (obj, datum);						\
> -	set (obj, nullptr);						\
> -      }									\
> -  }									\
> -									\
> -private:								\
> -									\
> -  static void cleanup (struct TAG *obj, void *arg)			\
> -  {									\
> -    DATA *datum = (DATA *) arg;						\
> -    Deleter d;								\
> -    d (datum);								\
> -  }									\
> -									\
> -  const struct TAG ## _data *m_key;					\
> +template<typename T>
> +class registry
> +{
> +public:
> +
> +  registry ()
> +    : m_fields (get_registrations ().size ())
> +  {
> +  }
> +
> +  ~registry ()
> +  {
> +    clear_registry ();
> +  }
> +
> +  DISABLE_COPY_AND_ASSIGN (registry);
> +
> +  /* A type-safe registry key.
> +
> +     The registry itself holds just a "void *".  This is not always
> +     convenient to manage, so this template class can be used instead,
> +     to provide a type-safe interface, that also helps manage the
> +     lifetime of the stored objects.
> +
> +     When the container is destroyed, this key arranges to destroy the
> +     underlying data using Deleter.  This defaults to
> +     std::default_delete.  */
> +
> +  template<typename DATA, typename Deleter = std::default_delete<DATA>>
> +  class key
> +  {
> +  public:
> +
> +    key ()
> +      : m_key (registry<T>::new_key (cleanup))
> +    {
> +    }
> +
> +    DISABLE_COPY_AND_ASSIGN (key);
> +
> +    /* Fetch the data attached to OBJ that is associated with this key.
> +       If no such data has been attached, nullptr is returned.  */
> +    DATA *get (T *obj) const
> +    {
> +      registry<T> *reg_obj = registry_accessor<T>::get (obj);
> +      return (DATA *) reg_obj->get (m_key);
> +    }
> +
> +    /* Attach DATA to OBJ, associated with this key.  Note that any
> +       previous data is simply dropped -- if destruction is needed,
> +       'clear' should be called.  */
> +    void set (T *obj, DATA *data) const
> +    {
> +      registry<T> *reg_obj = registry_accessor<T>::get (obj);
> +      reg_obj->set (m_key, data);
> +    }
> +
> +    /* If this key uses the default deleter, then this method is
> +       available.  It emplaces a new instance of the associated data
> +       type and attaches it to OBJ using this key.  The arguments, if
> +       any, are forwarded to the constructor.  */
> +    template<typename Dummy = DATA *, typename... Args>
> +    typename std::enable_if<std::is_same<Deleter,
> +					 std::default_delete<DATA>>::value,
> +			    Dummy>::type
> +    emplace (T *obj, Args &&...args) const
> +    {
> +      DATA *result = new DATA (std::forward<Args> (args)...);
> +      set (obj, result);
> +      return result;
> +    }
> +
> +    /* Clear the data attached to OBJ that is associated with this KEY.
> +       Any existing data is destroyed using the deleter, and the data is
> +       reset to nullptr.  */
> +    void clear (T *obj) const
> +    {
> +      DATA *datum = get (obj);
> +      if (datum != nullptr)
> +	{
> +	  cleanup (datum);
> +	  set (obj, nullptr);
> +	}
> +    }
> +
> +  private:
> +
> +    /* A helper function that is called by the registry to delete the
> +       contained object.  */
> +    static void cleanup (void *arg)
> +    {
> +      DATA *datum = (DATA *) arg;
> +      Deleter d;
> +      d (datum);
> +    }
> +
> +    /* The underlying key.  */
> +    const typename registry<T>::registry_data *m_key;
> +  };
> +
> +  /* Clear all the data associated with this container.  This is
> +     dangerous and should not normally be done.  */
> +  void clear_registry ()
> +  {
> +    /* Call all the free functions.  */
> +    for (const auto &datum : get_registrations ())
> +      {
> +	void *elt = m_fields[datum->index];
> +	if (elt != nullptr)
> +	  {
> +	    datum->free (elt);
> +	    m_fields[datum->index] = nullptr;
> +	  }
> +      }
> +  }
> +
> +private:
> +
> +  /* Registry callbacks have this type.  */
> +  typedef void (*registry_data_callback) (void *);
> +
> +  /* The type of a key.  */
> +  struct registry_data
> +  {
> +    unsigned index;
> +    registry_data_callback free;
> +  };
> +
> +  /* Get a new key for this particular registry.  FREE is a callback.
> +     When the container object is destroyed, all FREE functions are
> +     called.  The data associated with the container object is passed
> +     to the callback.  */
> +  static const registry_data *new_key (registry_data_callback free)
> +  {
> +    std::unique_ptr<registry_data> result (new registry_data);
> +    std::vector<std::unique_ptr<registry_data>> &registrations
> +      = get_registrations ();
> +    result->index = registrations.size ();
> +    result->free = free;
> +    registrations.emplace_back (std::move (result));
> +    return registrations.back ().get ();
> +  }
> +
> +  /* Set the datum associated with KEY in this container.  */
> +  void set (const registry_data *key, void *datum)
> +  {
> +    m_fields[key->index] = datum;
> +  }
> +
> +  /* Fetch the datum associated with KEY in this container.  If 'set'
> +     has not been called for this key, nullptr is returned.  */
> +  void *get (const registry_data *key)
> +  {
> +    return m_fields[key->index];
> +  }
> +
> +  /* The data stored in this instance.  */
> +  std::vector<void *> m_fields;
> +
> +  /* Return a reference to the vector of all the registrations that
> +     have been made.  We do separate allocations here so that the
> +     addresses are stable and can be used as keys.  */
> +  static std::vector<std::unique_ptr<registry_data>> &get_registrations ()
> +  {
> +    static std::vector<std::unique_ptr<registry_data>> registrations;
> +    return registrations;
> +  }
>  };
>  
>  #endif /* REGISTRY_H */
> diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
> index 4b8afd27688..01f88fc9da2 100644
> --- a/gdb/remote-sim.c
> +++ b/gdb/remote-sim.c
> @@ -178,7 +178,7 @@ struct gdbsim_target final
>  
>  static struct gdbsim_target gdbsim_ops;
>  
> -static inferior_key<sim_inferior_data> sim_inferior_data_key;
> +static const registry<inferior>::key<sim_inferior_data> sim_inferior_data_key;
>  
>  /* Flag indicating the "open" status of this module.  It's set to 1
>     in gdbsim_open() and 0 in gdbsim_close().  */
> diff --git a/gdb/remote.c b/gdb/remote.c
> index f41e6ce82c2..b57c55e8580 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -1033,7 +1033,7 @@ is_remote_target (process_stratum_target *target)
>  }
>  
>  /* Per-program-space data key.  */
> -static const struct program_space_key<char, gdb::xfree_deleter<char>>
> +static const registry<program_space>::key<char, gdb::xfree_deleter<char>>
>    remote_pspace_data;
>  
>  /* The variable registered as the control variable used by the
> diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
> index 6815dfaa820..0386bfb6223 100644
> --- a/gdb/rs6000-tdep.c
> +++ b/gdb/rs6000-tdep.c
> @@ -155,7 +155,7 @@ static const char *powerpc_vector_abi_string = "auto";
>  
>  /* PowerPC-related per-inferior data.  */
>  
> -static inferior_key<ppc_inferior_data> ppc_inferior_data_key;
> +static registry<inferior>::key<ppc_inferior_data> ppc_inferior_data_key;
>  
>  /* Get the per-inferior PowerPC data for INF.  */
>  
> diff --git a/gdb/solib-aix.c b/gdb/solib-aix.c
> index 3a8debf2c5a..33b15a9d8ad 100644
> --- a/gdb/solib-aix.c
> +++ b/gdb/solib-aix.c
> @@ -80,7 +80,8 @@ struct solib_aix_inferior_data
>  };
>  
>  /* Key to our per-inferior data.  */
> -static inferior_key<solib_aix_inferior_data> solib_aix_inferior_data_handle;
> +static const registry<inferior>::key<solib_aix_inferior_data>
> +  solib_aix_inferior_data_handle;
>  
>  /* Return this module's data for the given inferior.
>     If none is found, add a zero'ed one now.  */
> diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
> index d7789f68dfe..e61ec0d4bf3 100644
> --- a/gdb/solib-darwin.c
> +++ b/gdb/solib-darwin.c
> @@ -80,7 +80,8 @@ struct darwin_info
>  };
>  
>  /* Per-program-space data key.  */
> -static program_space_key<darwin_info> solib_darwin_pspace_data;
> +static const registry<program_space>::key<darwin_info>
> +  solib_darwin_pspace_data;
>  
>  /* Get the current darwin data.  If none is found yet, add it now.  This
>     function always returns a valid object.  */
> diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c
> index 0b03f944608..fe6b6e122d9 100644
> --- a/gdb/solib-dsbt.c
> +++ b/gdb/solib-dsbt.c
> @@ -164,7 +164,7 @@ struct dsbt_info
>  };
>  
>  /* Per-program-space data key.  */
> -static program_space_key<dsbt_info> solib_dsbt_pspace_data;
> +static const registry<program_space>::key<dsbt_info> solib_dsbt_pspace_data;
>  
>  /* Get the current dsbt data.  If none is found yet, add it now.  This
>     function always returns a valid object.  */
> diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
> index 5c046d3fab5..f9a43e23969 100644
> --- a/gdb/solib-svr4.c
> +++ b/gdb/solib-svr4.c
> @@ -365,7 +365,7 @@ struct svr4_info
>  };
>  
>  /* Per-program-space data key.  */
> -static const struct program_space_key<svr4_info> solib_svr4_pspace_data;
> +static const registry<program_space>::key<svr4_info> solib_svr4_pspace_data;
>  
>  /* Free the probes table.  */
>  
> diff --git a/gdb/solib.c b/gdb/solib.c
> index 0fbf5bc988d..d4a7c092da8 100644
> --- a/gdb/solib.c
> +++ b/gdb/solib.c
> @@ -529,7 +529,8 @@ typedef std::unordered_map<std::string, std::string> soname_build_id_map;
>  
>  /* Key used to associate a soname_build_id_map to a core file bfd.  */
>  
> -static const struct bfd_key<soname_build_id_map> cbfd_soname_build_id_data_key;
> +static const struct registry<bfd>::key<soname_build_id_map>
> +     cbfd_soname_build_id_data_key;
>  
>  /* See solib.h.  */
>  
> diff --git a/gdb/source.c b/gdb/source.c
> index 8691113c729..425b02fc3a0 100644
> --- a/gdb/source.c
> +++ b/gdb/source.c
> @@ -115,7 +115,8 @@ struct current_source_location
>    int m_line = 0;
>  };
>  
> -static program_space_key<current_source_location> current_source_key;
> +static const registry<program_space>::key<current_source_location>
> +     current_source_key;
>  
>  /* Default number of lines to print with commands like "list".
>     This is based on guessing how many long (i.e. more than chars_per_line
> diff --git a/gdb/stabsread.c b/gdb/stabsread.c
> index 4fe2110a47f..aedbca2d0eb 100644
> --- a/gdb/stabsread.c
> +++ b/gdb/stabsread.c
> @@ -2016,8 +2016,8 @@ read_type (const char **pp, struct objfile *objfile)
>  /* RS/6000 xlc/dbx combination uses a set of builtin types, starting from -1.
>     Return the proper type node for a given builtin type number.  */
>  
> -static const struct objfile_key<struct type *,
> -				gdb::noop_deleter<struct type *>>
> +static const registry<objfile>::key<struct type *,
> +				    gdb::noop_deleter<struct type *>>
>    rs6000_builtin_type_data;
>  
>  static struct type *
> diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
> index 2af04433444..59726290011 100644
> --- a/gdb/symfile-debug.c
> +++ b/gdb/symfile-debug.c
> @@ -47,7 +47,7 @@ struct debug_sym_fns_data
>  
>  /* We need to record a pointer to the real set of functions for each
>     objfile.  */
> -static const struct objfile_key<debug_sym_fns_data>
> +static const registry<objfile>::key<debug_sym_fns_data>
>    symfile_debug_objfile_data_key;
>  
>  /* If true all calls to the symfile functions are logged.  */
> diff --git a/gdb/symfile.c b/gdb/symfile.c
> index 6f546f5b059..ec3244269b1 100644
> --- a/gdb/symfile.c
> +++ b/gdb/symfile.c
> @@ -2500,7 +2500,7 @@ reread_symbols (int from_tty)
>  	      (*objfile->sf->sym_finish) (objfile);
>  	    }
>  
> -	  clear_objfile_data (objfile);
> +	  objfile->registry_fields.clear_registry ();
>  
>  	  /* Clean up any state BFD has sitting around.  */
>  	  {
> @@ -2638,7 +2638,7 @@ reread_symbols (int from_tty)
>      {
>        clear_symtab_users (0);
>  
> -      /* clear_objfile_data for each objfile was called before freeing it and
> +      /* The registry for each objfile was cleared and
>  	 gdb::observers::new_objfile.notify (NULL) has been called by
>  	 clear_symtab_users above.  Notify the new files now.  */
>        for (auto iter : new_objfiles)
> diff --git a/gdb/symtab.c b/gdb/symtab.c
> index 8564986f66d..8d3be357ded 100644
> --- a/gdb/symtab.c
> +++ b/gdb/symtab.c
> @@ -121,7 +121,7 @@ struct main_info
>  
>  /* Program space key for finding name and language of "main".  */
>  
> -static const program_space_key<main_info> main_progspace_key;
> +static const registry<program_space>::key<main_info> main_progspace_key;
>  
>  /* The default symbol cache size.
>     There is no extra cpu cost for large N (except when flushing the cache,
> @@ -251,7 +251,7 @@ struct symbol_cache
>  
>  /* Program space key for finding its symbol cache.  */
>  
> -static const program_space_key<symbol_cache> symbol_cache_key;
> +static const registry<program_space>::key<symbol_cache> symbol_cache_key;
>  
>  /* When non-zero, print debugging messages related to symtab creation.  */
>  unsigned int symtab_create_debug = 0;
> diff --git a/gdb/target-dcache.c b/gdb/target-dcache.c
> index 0aa53302cea..3e3c0c6ee4d 100644
> --- a/gdb/target-dcache.c
> +++ b/gdb/target-dcache.c
> @@ -24,7 +24,7 @@
>  /* The target dcache is kept per-address-space.  This key lets us
>     associate the cache with the address space.  */
>  
> -static const struct address_space_key<DCACHE, dcache_deleter>
> +static const registry<address_space>::key<DCACHE, dcache_deleter>
>    target_dcache_aspace_key;
>  
>  /* Target dcache is initialized or not.  */
> diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
> index d8735d29ede..0be7991d5c2 100644
> --- a/gdb/xcoffread.c
> +++ b/gdb/xcoffread.c
> @@ -147,7 +147,7 @@ struct xcoff_symfile_info
>  
>  /* Key for XCOFF-associated data.  */
>  
> -static const struct objfile_key<xcoff_symfile_info> xcoff_objfile_data_key;
> +static const registry<objfile>::key<xcoff_symfile_info> xcoff_objfile_data_key;
>  
>  /* Convenience macro to access the per-objfile XCOFF data.  */
>  
> -- 
> 2.34.1
> 

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

* Re: [PATCH 4/6] Rewrite registry.h
  2022-06-07 10:55   ` Lancelot SIX via Gdb-patches
@ 2022-06-08  1:33     ` Tom Tromey
  2022-06-08 18:51       ` Tom Tromey
  0 siblings, 1 reply; 13+ messages in thread
From: Tom Tromey @ 2022-06-08  1:33 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: Tom Tromey, gdb-patches

>>>>> Lancelot SIX <lsix@lancelotsix.com> writes:

> Hi Tom,
> After this patch, if I build GDB with address sanitizer, I end up having
> many regressions related to heap-use-after-free in the testsuite.

> You can see this by using the gdb.base/cached-source-file.exp for
> example.

Thanks.  I should have thought to do this testing myself.

This particular failure comes because the order of destruction of the
per-bfd and per-objfile objects changed.  I think it's better to avoid
this problem entirely.  I've got a patch to do this that I will send
soon.

After that's in, I'll rebase the registry series and test it with ASAN.

Tom

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

* Re: [PATCH 4/6] Rewrite registry.h
  2022-06-08  1:33     ` Tom Tromey
@ 2022-06-08 18:51       ` Tom Tromey
  0 siblings, 0 replies; 13+ messages in thread
From: Tom Tromey @ 2022-06-08 18:51 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Lancelot SIX, gdb-patches

Tom> This particular failure comes because the order of destruction of the
Tom> per-bfd and per-objfile objects changed.  I think it's better to avoid
Tom> this problem entirely.  I've got a patch to do this that I will send
Tom> soon.

Tom> After that's in, I'll rebase the registry series and test it with ASAN.

This series helped but there are still a couple of issues.

One I haven't investigated and I suspect it's pre-existing.  I'll look
soon.

The other I think will benefit from:

    https://sourceware.org/pipermail/gdb-patches/2022-June/189818.html

So I will at least wait for that to go in.

Tom

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

* Re: [PATCH 0/6] Rewrite registry.h
  2022-05-30 17:59 [PATCH 0/6] Rewrite registry.h Tom Tromey
                   ` (5 preceding siblings ...)
  2022-05-30 17:59 ` [PATCH 6/6] Remove some unneeded checks in Guile code Tom Tromey
@ 2022-07-28 20:13 ` Tom Tromey
  2022-07-29  2:33   ` Simon Marchi via Gdb-patches
  6 siblings, 1 reply; 13+ messages in thread
From: Tom Tromey @ 2022-07-28 20:13 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:

Tom> This series rewrites registry.h, changing it from a lengthy macro to a
Tom> C++ template.

Tom> After this, registries are slightly less flexible, in that only the
Tom> type-safe form is supplied.  However, I consider that a plus and not a
Tom> minus.

Tom> Regression tested on x86-64 Fedora 34.

I've rebased this and retested it.
I'm going to check it in.

Tom

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

* Re: [PATCH 0/6] Rewrite registry.h
  2022-07-28 20:13 ` [PATCH 0/6] Rewrite registry.h Tom Tromey
@ 2022-07-29  2:33   ` Simon Marchi via Gdb-patches
  2022-08-02  2:46     ` Tom Tromey
  0 siblings, 1 reply; 13+ messages in thread
From: Simon Marchi via Gdb-patches @ 2022-07-29  2:33 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 812 bytes --]



On 2022-07-28 16:13, Tom Tromey wrote:
>>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:
> 
> Tom> This series rewrites registry.h, changing it from a lengthy macro to a
> Tom> C++ template.
> 
> Tom> After this, registries are slightly less flexible, in that only the
> Tom> type-safe form is supplied.  However, I consider that a plus and not a
> Tom> minus.
> 
> Tom> Regression tested on x86-64 Fedora 34.
> 
> I've rebased this and retested it.
> I'm going to check it in.
> 
> Tom

Hi Tom,

I see these failures following this series:

UNRESOLVED: gdb.guile/scm-value.exp: discard the symbols
UNRESOLVED: gdb.python/py-template.exp: gdb_breakpoint: set breakpoint at main (eof)
UNRESOLVED: gdb.python/py-value.exp: discard the symbols

I attached gdb.log for these three tests, in case it helps.

Simon

[-- Attachment #2: gdb.log --]
[-- Type: text/x-log, Size: 113938 bytes --]

Test run by simark on Thu Jul 28 22:30:24 2022
Native configuration is x86_64-pc-linux-gnu

		=== gdb tests ===

Schedule of variations:
    unix

Running target unix
Using /usr/share/dejagnu/baseboards/unix.exp as board description file for target.
Using /usr/share/dejagnu/config/unix.exp as generic interface file for target.
Using /home/simark/src/binutils-gdb/gdb/testsuite/config/unix.exp as tool-and-target-specific interface file.
Running /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.exp ...
Executing on host: gcc    -fdiagnostics-color=never -c -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/ccopts2942025.o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/ccopts2942025.c    (timeout = 300)
builtin_spawn -ignore SIGHUP gcc -fdiagnostics-color=never -c -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/ccopts2942025.o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/ccopts2942025.c
get_compiler_info: gcc-12-1-0
Executing on host: gcc  -fno-stack-protector /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/has_argv0-2942025.c   -fdiagnostics-color=never -w -g  -lm  -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/has_argv0-2942025.x    (timeout = 300)
builtin_spawn -ignore SIGHUP gcc -fno-stack-protector /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/has_argv0-2942025.c -fdiagnostics-color=never -w -g -lm -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/has_argv0-2942025.x
builtin_spawn /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../../gdb/gdb -nw -nx -iex set height 0 -iex set width 0 -data-directory /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../data-directory
warning: Found custom handler for signal 7 (Bus error) preinstalled.
warning: Found custom handler for signal 8 (Floating point exception) preinstalled.
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 13.0.50.20220728-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) set height 0
(gdb) set width 0
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
(gdb) dir /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile
Source directories searched: /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile:$cdir:$cwd
(gdb) kill
The program is not being run.
(gdb) file /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/has_argv0-2942025.x
Reading symbols from /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/has_argv0-2942025.x...
(gdb) break -q main
Breakpoint 1 at 0x1124: file /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/has_argv0-2942025.c, line 3.
(gdb) run 
Starting program: /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/has_argv0-2942025.x 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/../lib/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffd278) at /home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/has_argv0-2942025.c:3
3	/home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/has_argv0-2942025.c: No such file or directory.
(gdb) show print elements
Limit on string chars or array elements to print is 200.
(gdb) show print repeats
Threshold for repeated print elements is 10.
(gdb) set print elements unlimited
(gdb) gdb_do_cache_wrap ignoring pass: set print elements unlimited
set print repeats unlimited
(gdb) gdb_do_cache_wrap ignoring pass: set print repeats unlimited
p argc
$1 = 1
(gdb) p argv[0]
$2 = 0x7fffffffd734 "/home/simark/build/binutils-gdb-one-target/gdb/testsuite/temp/2942025/has_argv0-2942025.x"
(gdb) set print elements 200
(gdb) gdb_do_cache_wrap ignoring pass: set print elements 200
set print repeats 10
(gdb) gdb_do_cache_wrap ignoring pass: set print repeats 10
Executing on host: gcc  -fno-stack-protector   -fdiagnostics-color=never -c -g -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value.o /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c    (timeout = 300)
builtin_spawn -ignore SIGHUP gcc -fno-stack-protector -fdiagnostics-color=never -c -g -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value.o /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c
Executing on host: gcc  -fno-stack-protector /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value.o   -fdiagnostics-color=never -g  -lm  -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value    (timeout = 300)
builtin_spawn -ignore SIGHUP gcc -fno-stack-protector /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value.o -fdiagnostics-color=never -g -lm -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value
builtin_spawn /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../../gdb/gdb -nw -nx -iex set height 0 -iex set width 0 -data-directory /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../data-directory
warning: Found custom handler for signal 7 (Bus error) preinstalled.
warning: Found custom handler for signal 8 (Floating point exception) preinstalled.
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 13.0.50.20220728-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) set height 0
(gdb) set width 0
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
(gdb) dir /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile
Source directories searched: /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile:$cdir:$cwd
(gdb) kill
The program is not being run.
(gdb) file /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value
Reading symbols from /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value...
(gdb) guile (display "test\n")
test
(gdb) guile (define (print x) (format #t "= ~A" x) (newline))
(gdb) guile (define (raw-print x) (format #t "= ~S" x) (newline))
(gdb) guile (use-modules (gdb))
(gdb) gu (print (parse-and-eval "23"))
= 23
(gdb) PASS: gdb.guile/scm-value.exp: parse-and-eval constant test
gu (print (parse-and-eval "5 + 7"))
= 12
(gdb) PASS: gdb.guile/scm-value.exp: parse-and-eval simple expression test
gu (raw-print (parse-and-eval "5 + 7"))
= #<gdb:value 12>
(gdb) PASS: gdb.guile/scm-value.exp: parse-and-eval type test
guile
>PASS: gdb.guile/scm-value.exp: Simple Guile value dictionary: input 1: guile
(define one (make-value 1))
>PASS: gdb.guile/scm-value.exp: Simple Guile value dictionary: input 2: (define one (make-value 1))
(define two (make-value 2))
>PASS: gdb.guile/scm-value.exp: Simple Guile value dictionary: input 3: (define two (make-value 2))
(define three (make-value 3))
>PASS: gdb.guile/scm-value.exp: Simple Guile value dictionary: input 4: (define three (make-value 3))
(define vdict (make-hash-table 5))
>PASS: gdb.guile/scm-value.exp: Simple Guile value dictionary: input 5: (define vdict (make-hash-table 5))
(hash-set! vdict one "one str")
>PASS: gdb.guile/scm-value.exp: Simple Guile value dictionary: input 6: (hash-set! vdict one "one str")
(hash-set! vdict two "two str")
>PASS: gdb.guile/scm-value.exp: Simple Guile value dictionary: input 7: (hash-set! vdict two "two str")
(hash-set! vdict three "three str")
>PASS: gdb.guile/scm-value.exp: Simple Guile value dictionary: input 8: (hash-set! vdict three "three str")
end
(gdb) PASS: gdb.guile/scm-value.exp: Simple Guile value dictionary: input 9: end
gu (print (hash-ref vdict one))
= one str
(gdb) PASS: gdb.guile/scm-value.exp: Test dictionary hash 1
gu (print (hash-ref vdict two))
= two str
(gdb) PASS: gdb.guile/scm-value.exp: Test dictionary hash 2
gu (print (hash-ref vdict three))
= three str
(gdb) PASS: gdb.guile/scm-value.exp: Test dictionary hash 3
delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break -qualified main
Breakpoint 1 at 0x117b: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c, line 76.
(gdb) run 
Starting program: /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/../lib/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffd268) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c:76
76	  char *cp = argv[0]; /* Prevent gcc from optimizing argv[] out.  */
(gdb) guile (define (print x) (format #t "= ~A" x) (newline))
(gdb) guile (define (raw-print x) (format #t "= ~S" x) (newline))
(gdb) guile (use-modules (gdb))
(gdb) break 99
Breakpoint 2 at 0x55555555525b: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c, line 99.
(gdb) continue
Continuing.
void function called

Breakpoint 2, main (argc=1, argv=0x7fffffffd268) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c:99
99	  save_argv = argv;      /* break to inspect struct and union */
(gdb) PASS: gdb.guile/scm-value.exp: continue to breakpoint: break to inspect struct and union
print s
$1 = {a = 3, b = 5}
(gdb) PASS: gdb.guile/scm-value.exp: print s
gu (define s (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: set s
gu (print (value-field s "a"))
= 3
(gdb) PASS: gdb.guile/scm-value.exp: access element inside struct using string name
gu (define i (history-append! (make-value 42)))
(gdb) PASS: gdb.guile/scm-value.exp: append 42
gu i
2
(gdb) PASS: gdb.guile/scm-value.exp: gu i
gu (history-ref i)
#<gdb:value 42>
(gdb) PASS: gdb.guile/scm-value.exp: gu (history-ref i)
p $
$3 = 42
(gdb) PASS: gdb.guile/scm-value.exp: p $
guile (gc)
(gdb) PASS: gdb.guile/scm-value.exp: guile (gc)
p $$
$4 = 42
(gdb) PASS: gdb.guile/scm-value.exp: p $$
gu (history-append! 123)
ERROR: In procedure history-append!:
ERROR: In procedure gdbscm_history_append_x: Wrong type argument in position 1 (expecting gdb:value): 123
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: history-append! type error
print argv
$5 = (char **) 0x7fffffffd268
(gdb) PASS: gdb.guile/scm-value.exp: print argv
gu (define argv (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: set argv
gu (define arg0 (value-dereference argv))
(gdb) PASS: gdb.guile/scm-value.exp: set arg0
set print elements unlimited
(gdb) PASS: gdb.guile/scm-value.exp: set print elements unlimited
set print repeats unlimited
(gdb) PASS: gdb.guile/scm-value.exp: set print repeats unlimited
gu (print arg0)
= 0x7fffffffd725 "/home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value"
(gdb) PASS: gdb.guile/scm-value.exp: verify dereferenced value
gu (print (value-optimized-out? arg0))
= #f
(gdb) PASS: gdb.guile/scm-value.exp: Test value-optimized-out?
gu (print (value-address arg0))
= 0x7fffffffd268
(gdb) PASS: gdb.guile/scm-value.exp: Test address attribute
gu (print (value-address (make-value 42)))
= #f
(gdb) PASS: gdb.guile/scm-value.exp: Test address attribute in non-addressable value
x 0
0x0:	Cannot access memory at address 0x0
(gdb) gu (print (parse-and-eval "*(int*)0"))
= ERROR: Cannot access memory at address 0x0
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: parse_and_eval with memory error
gu (define inval (parse-and-eval "*(int*)0"))
(gdb) PASS: gdb.guile/scm-value.exp: gu (define inval (parse-and-eval "*(int*)0"))
gu (print (value-lazy? inval))
= #t
(gdb) PASS: gdb.guile/scm-value.exp: gu (print (value-lazy? inval))
gu (define inval2 (value-add inval 1))
ERROR: Cannot access memory at address 0x0
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: memory error and lazy values, using value in value-add
gu (value-fetch-lazy! inval))
ERROR: Cannot access memory at address 0x0
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: memory error and lazy values, using value in value-fetch-lazy!
gu (define argc-lazy (parse-and-eval "argc"))
(gdb) PASS: gdb.guile/scm-value.exp: gu (define argc-lazy (parse-and-eval "argc"))
gu (define argc-notlazy (parse-and-eval "argc"))
(gdb) PASS: gdb.guile/scm-value.exp: gu (define argc-notlazy (parse-and-eval "argc"))
gu (value-fetch-lazy! argc-notlazy)
(gdb) PASS: gdb.guile/scm-value.exp: gu (value-fetch-lazy! argc-notlazy)
gu (print (value-lazy? argc-lazy))
= #t
(gdb) PASS: gdb.guile/scm-value.exp: argc-lazy is initially lazy
gu (print (value-lazy? argc-notlazy))
= #f
(gdb) PASS: gdb.guile/scm-value.exp: gu (print (value-lazy? argc-notlazy))
print argc
$6 = 1
(gdb) PASS: gdb.guile/scm-value.exp: sanity check argc
gu (print (value-lazy? argc-lazy))
= #t
(gdb) PASS: gdb.guile/scm-value.exp: argc-lazy is still lazy after argc is printed
set argc=2
(gdb) PASS: gdb.guile/scm-value.exp: set argc=2
gu (print argc-notlazy)
= 1
(gdb) PASS: gdb.guile/scm-value.exp: gu (print argc-notlazy)
gu (print argc-lazy)
= 2
(gdb) PASS: gdb.guile/scm-value.exp: gu (print argc-lazy)
gu (print (value-lazy? argc-lazy))
= #f
(gdb) PASS: gdb.guile/scm-value.exp: argc-lazy is no longer lazy
print st
$7 = "divide et impera"
(gdb) PASS: gdb.guile/scm-value.exp: print st
gu (define st (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: inf: get st value from history
gu (print (value->string st))
= divide et impera
(gdb) PASS: gdb.guile/scm-value.exp: Test string with no length
gu (print (value->string st #:length -1))
= divide et impera
(gdb) PASS: gdb.guile/scm-value.exp: Test string (length = -1) is all of the string
gu (print (value->string st #:length 6))
= divide
(gdb) PASS: gdb.guile/scm-value.exp: gu (print (value->string st #:length 6))
gu (print (string-append "---" (value->string st #:length 0) "---"))
= ------
(gdb) PASS: gdb.guile/scm-value.exp: Test string (length = 0) is empty
gu (print (string-length (value->string st #:length 0)))
= 0
(gdb) PASS: gdb.guile/scm-value.exp: Test length is 0
print nullst
$8 = "divide\000et\000impera"
(gdb) PASS: gdb.guile/scm-value.exp: print nullst
gu (define nullst (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: inf: get nullst value from history
gu (print (value->string nullst))
= divide
(gdb) PASS: gdb.guile/scm-value.exp: Test string to first null
gu (set! nullst (value->string nullst #:length 9))
(gdb) PASS: gdb.guile/scm-value.exp: get string beyond null
gu (print nullst)
= divide\000et
(gdb) PASS: gdb.guile/scm-value.exp: gu (print nullst)
gu (define argv-ref (value-reference-value argv))
(gdb) PASS: gdb.guile/scm-value.exp: test value-reference-value
gu (equal? argv (value-referenced-value argv-ref))
#t
(gdb) PASS: gdb.guile/scm-value.exp: gu (equal? argv (value-referenced-value argv-ref))
gu (eqv? (type-code (value-type argv-ref)) TYPE_CODE_REF)
#t
(gdb) PASS: gdb.guile/scm-value.exp: gu (eqv? (type-code (value-type argv-ref)) TYPE_CODE_REF)
gu (define argv-rref (value-rvalue-reference-value argv))
(gdb) PASS: gdb.guile/scm-value.exp: test value-rvalue-reference-value
gu (equal? argv (value-referenced-value argv-rref))
#t
(gdb) PASS: gdb.guile/scm-value.exp: gu (equal? argv (value-referenced-value argv-rref))
gu (eqv? (type-code (value-type argv-rref)) TYPE_CODE_RVALUE_REF)
#t
(gdb) PASS: gdb.guile/scm-value.exp: gu (eqv? (type-code (value-type argv-rref)) TYPE_CODE_RVALUE_REF)
gu (equal? (value-type (value-const-value argv)) (type-const (value-type argv)))
#t
(gdb) PASS: gdb.guile/scm-value.exp: gu (equal? (value-type (value-const-value argv)) (type-const (value-type argv)))
p/x fp1
$9 = 0x555555555139
(gdb) PASS: gdb.guile/scm-value.exp: p/x fp1
gu (define fp1 (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: get fp1 value from history
gu (set! fp1 (value-dereference fp1))
(gdb) PASS: gdb.guile/scm-value.exp: dereference fp1
gu (print (value-call fp1 '()))
void function called
= void
(gdb) PASS: gdb.guile/scm-value.exp: gu (print (value-call fp1 '()))
p/x fp2
$10 = 0x55555555514f
(gdb) PASS: gdb.guile/scm-value.exp: place fp2 into value history, the first time
gu (define fp2 (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: get fp2 value from history
gu (set! fp2 (value-dereference fp2))
(gdb) PASS: gdb.guile/scm-value.exp: dereference fp2
gu (print (value-call fp2 (list 10 20)))
= 30
(gdb) PASS: gdb.guile/scm-value.exp: gu (print (value-call fp2 (list 10 20)))
p i
$11 = 2
(gdb) PASS: gdb.guile/scm-value.exp: p i
gu (define i (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: inf call: get i value from history
gu (print (value-call i '()))
ERROR: In procedure value-call:
ERROR: In procedure gdbscm_value_call: Wrong type argument in position 1 (expecting function (value of TYPE_CODE_FUNC)): #<gdb:value 2>
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: gu (print (value-call i '()))
p/x fp2
$12 = 0x55555555514f
(gdb) PASS: gdb.guile/scm-value.exp: place fp2 into value history, the second time
gu (define fp3 (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: get fp3 value from history
gu (set! fp3 (value-dereference fp3))
(gdb) PASS: gdb.guile/scm-value.exp: dereference fp3
gu (print (value-call fp3 (list 10)))
ERROR: Too few arguments in function call.
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: gu (print (value-call fp3 (list 10)))
gu (make-value "test")
#<gdb:value "test">
(gdb) PASS: gdb.guile/scm-value.exp: make string
show target-charset
The target character set is "auto; currently ANSI_X3.4-1968".
(gdb) set target-charset UTF-8
(gdb) PASS: gdb.guile/scm-value.exp: set target-charset UTF-8
gu (set-port-conversion-strategy! #f 'error)
(gdb) PASS: gdb.guile/scm-value.exp: gu (set-port-conversion-strategy! #f 'error)
gu (print (value->string (make-value (string #\x1234)) #:encoding "ASCII"))
ERROR: In procedure value->string:
ERROR: Throw to key `decoding-error' with args `("scm_from_stringn" "input locale conversion error" 84 #vu8(225 136 180))'.
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: value->string with default #:errors = 'error
gu (set-port-conversion-strategy! #f 'escape)
(gdb) PASS: gdb.guile/scm-value.exp: gu (set-port-conversion-strategy! #f 'escape)
gu (print (value->string (make-value (string #\x1234)) #:encoding "ASCII" #:errors #f))
= ???
(gdb) PASS: gdb.guile/scm-value.exp: value->string with default #:errors = 'escape
gu (set-port-conversion-strategy! #f 'substitute)
(gdb) PASS: gdb.guile/scm-value.exp: gu (set-port-conversion-strategy! #f 'substitute)
gu (print (value->string (make-value (string #\x1234)) #:encoding "ASCII"))
= ???
(gdb) PASS: gdb.guile/scm-value.exp: value->string with default #:errors = 'substitute
gu (print (value->string (make-value (string #\x1234)) #:encoding "ASCII" #:errors 'error))
ERROR: In procedure value->string:
ERROR: Throw to key `decoding-error' with args `("scm_from_stringn" "input locale conversion error" 84 #vu8(225 136 180))'.
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: value->string #:errors 'error
gu (print (value->string (make-value (string #\x1234)) #:encoding "ASCII" #:errors 'substitute))
= ???
(gdb) PASS: gdb.guile/scm-value.exp: value->string #:errors 'substitute
gu (print (value->string (make-value "abc") #:errors "foo"))
ERROR: In procedure value->string:
ERROR: In procedure gdbscm_value_to_string: Out of range: invalid error kind in position 3: "foo"
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: bad value for #:errors
set target-charset ANSI_X3.4-1968
(gdb) PASS: gdb.guile/scm-value.exp: restore target-charset
gu (define ptrtype (lookup-type "PTR"))
(gdb) PASS: gdb.guile/scm-value.exp: create PTR type
kill
Kill the program being debugged? (y or n) y
[Inferior 1 (process 2942164) killed]
(gdb) PASS: gdb.guile/scm-value.exp: kill the inferior
file
No executable file now.
Discard symbol table from `/home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value'? (y or n) y


Fatal signal: Aborted
----- Backtrace -----
0x56313bf2b26a gdb_internal_backtrace_1
	/home/simark/src/binutils-gdb/gdb/bt-utils.c:122
0x56313bf2b761 _Z22gdb_internal_backtracev
	/home/simark/src/binutils-gdb/gdb/bt-utils.c:168
0x56313cb3bfe6 handle_fatal_signal
	/home/simark/src/binutils-gdb/gdb/event-top.c:946
0x7f04cf03e8df ???
0x7f04cf08e36c ???
0x7f04cf03e837 ???
0x7f04cf028534 ???
0x7f04d08dfce3 _ZN11__sanitizer5AbortEv
	/usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:143
0x7f04d08ed1c1 _ZN11__sanitizer3DieEv
	/usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_termination.cpp:58
0x7f04d08c9c1f _ZN6__asan19ScopedInErrorReportD2Ev
	/usr/src/debug/gcc/libsanitizer/asan/asan_report.cpp:190
0x7f04d08c910b _ZN6__asan18ReportGenericErrorEmmmmbmjb
	/usr/src/debug/gcc/libsanitizer/asan/asan_report.cpp:479
0x7f04d08ca4ab __asan_report_load8
	/usr/src/debug/gcc/libsanitizer/asan/asan_rtl.cpp:123
0x56313b8a1a0c _ZNK4type16is_objfile_ownedEv
	/home/simark/src/binutils-gdb/gdb/gdbtypes.h:1380
0x56313ccb7849 _Z19copy_type_recursiveP4typeP4htab
	/home/simark/src/binutils-gdb/gdb/gdbtypes.c:5638
0x56313cda6dc4 tyscm_copy_type_recursive
	/home/simark/src/binutils-gdb/gdb/guile/scm-type.c:383
0x56313ea22b35 htab_traverse_noresize
	/home/simark/src/binutils-gdb/libiberty/hashtab.c:775
0x56313cdae16d _ZN13tyscm_deleterclEP4htab
	/home/simark/src/binutils-gdb/gdb/guile/scm-type.c:100
0x56313cdae471 _ZN8registryI7objfileE3keyI4htab13tyscm_deleterE7cleanupEPv
	/home/simark/src/binutils-gdb/gdb/registry.h:159
0x56313d568978 _ZN8registryI7objfileE14clear_registryEv
	/home/simark/src/binutils-gdb/gdb/registry.h:176
0x56313d564adb _ZN8registryI7objfileED2Ev
	/home/simark/src/binutils-gdb/gdb/registry.h:78
0x56313d5556b5 _ZN7objfileD2Ev
	/home/simark/src/binutils-gdb/gdb/objfiles.c:590
0x56313d568dc8 _ZNKSt14default_deleteI7objfileEclEPS0_
	/usr/include/c++/12.1.0/bits/unique_ptr.h:95
0x56313d564e98 _ZNSt10unique_ptrI7objfileSt14default_deleteIS0_EED2Ev
	/usr/include/c++/12.1.0/bits/unique_ptr.h:396
0x56313d6aa172 _ZNSt15__new_allocatorINSt9__cxx199810_List_nodeISt10unique_ptrI7objfileSt14default_deleteIS3_EEEEE7destroyIS6_EEvPT_
	/usr/include/c++/12.1.0/bits/new_allocator.h:181
0x56313d69f2f2 _ZNSt16allocator_traitsISaINSt9__cxx199810_List_nodeISt10unique_ptrI7objfileSt14default_deleteIS3_EEEEEE7destroyIS6_EEvRS8_PT_
	/usr/include/c++/12.1.0/bits/alloc_traits.h:535
0x56313d6af5a6 _ZNSt9__cxx19987__cxx114listISt10unique_ptrI7objfileSt14default_deleteIS3_EESaIS6_EE8_M_eraseENS_14_List_iteratorIS6_EE
	/usr/include/c++/12.1.0/bits/stl_list.h:2019
0x56313d6a4b7d _ZNSt9__cxx19987__cxx114listISt10unique_ptrI7objfileSt14default_deleteIS3_EESaIS6_EE5eraseENS_20_List_const_iteratorIS6_EE
	/usr/include/c++/12.1.0/bits/list.tcc:158
0x56313d6994b1 _ZNSt7__debug4listISt10unique_ptrI7objfileSt14default_deleteIS2_EESaIS5_EE8_M_eraseENSt9__cxx199820_List_const_iteratorIS5_EE
	/usr/include/c++/12.1.0/debug/list:521
0x56313d692f44 _ZNSt7__debug4listISt10unique_ptrI7objfileSt14default_deleteIS2_EESaIS5_EE5eraseEN11__gnu_debug14_Safe_iteratorINSt9__cxx199820_List_const_iteratorIS5_EES7_St26bidirectional_iterator_tagEE
	/usr/include/c++/12.1.0/debug/list:533
0x56313d6884dd _ZN13program_space14remove_objfileEP7objfile
	/home/simark/src/binutils-gdb/gdb/progspace.c:175
0x56313d5542be _ZN7objfile6unlinkEv
	/home/simark/src/binutils-gdb/gdb/objfiles.c:478
0x56313d687228 _ZN13program_space17free_all_objfilesEv
	/home/simark/src/binutils-gdb/gdb/progspace.c:135
0x56313dd64a39 _Z17symbol_file_cleari
	/home/simark/src/binutils-gdb/gdb/symfile.c:1232
0x56313dd6754d _Z19symbol_file_commandPKci
	/home/simark/src/binutils-gdb/gdb/symfile.c:1598
0x56313cb4a532 file_command
	/home/simark/src/binutils-gdb/gdb/exec.c:555
0x56313c173dd0 do_simple_func
	/home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:95
0x56313c18977b _Z8cmd_funcP16cmd_list_elementPKci
	/home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:2516
0x56313e0db5ca _Z15execute_commandPKci
	/home/simark/src/binutils-gdb/gdb/top.c:699
0x56313cb3a5a9 _Z15command_handlerPKc
	/home/simark/src/binutils-gdb/gdb/event-top.c:598
0x56313cb3b3b1 _Z20command_line_handlerOSt10unique_ptrIcN3gdb13xfree_deleterIcEEE
	/home/simark/src/binutils-gdb/gdb/event-top.c:842
0x56313e2272e6 tui_command_line_handler
	/home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:104
0x56313cb3859e gdb_rl_callback_handler
	/home/simark/src/binutils-gdb/gdb/event-top.c:230
0x7f04d10429df ???
0x56313cb37fa9 gdb_rl_callback_read_char_wrapper_noexcept
	/home/simark/src/binutils-gdb/gdb/event-top.c:188
0x56313cb381ec gdb_rl_callback_read_char_wrapper
	/home/simark/src/binutils-gdb/gdb/event-top.c:205
0x56313cb39b77 _Z19stdin_event_handleriPv
	/home/simark/src/binutils-gdb/gdb/event-top.c:525
0x56313e998e3b handle_file_event
	/home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:549
0x56313e999777 gdb_wait_for_event
	/home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:670
0x56313e997531 _Z16gdb_do_one_eventv
	/home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:235
0x56313d25e714 start_event_loop
	/home/simark/src/binutils-gdb/gdb/main.c:411
0x56313d25eb6e captured_command_loop
	/home/simark/src/binutils-gdb/gdb/main.c:471
0x56313d264000 captured_main
	/home/simark/src/binutils-gdb/gdb/main.c:1329
0x56313d2640dd _Z8gdb_mainP18captured_main_args
	/home/simark/src/binutils-gdb/gdb/main.c:1344
0x56313b877c9d main
	/home/simark/src/binutils-gdb/gdb/gdb.c:32
---------------------
A fatal error internal to GDB has been detected, further
debugging is not possible.  GDB will now terminate.

This is a bug, please report it.  For instructions, see:
<https://www.gnu.org/software/gdb/bugs/>.

ERROR: GDB process no longer exists
GDB process exited with wait status 2942127 exp9 0 0 CHILDKILLED SIGABRT SIGABRT
UNRESOLVED: gdb.guile/scm-value.exp: discard the symbols
ERROR: Couldn't send gu (gc) to GDB.
ERROR: can not find channel named "exp9"
    while executing
"expect {
-i exp9 -timeout 10 
	-re ".*A problem internal to GDB has been detected" {
	    fail "$message (GDB internal error)"
	    gdb_internal_error..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" TCL LOOKUP CHANNEL exp9 can not find channel named "exp9"
ERROR: Couldn't send gu (define castval (value-cast arg0 (type-pointer ptrtype))) to GDB.
ERROR: can not find channel named "exp9"
    while executing
"expect {
-i exp9 -timeout 10 
	-re ".*A problem internal to GDB has been detected" {
	    fail "$message (GDB internal error)"
	    gdb_internal_error..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" TCL LOOKUP CHANNEL exp9 can not find channel named "exp9"
ERROR: Couldn't send gu (set! ptrtype #f) to GDB.
ERROR: can not find channel named "exp9"
    while executing
"expect {
-i exp9 -timeout 10 
	-re ".*A problem internal to GDB has been detected" {
	    fail "$message (GDB internal error)"
	    gdb_internal_error..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" TCL LOOKUP CHANNEL exp9 can not find channel named "exp9"
ERROR: Couldn't send gu (print (value-type castval)) to GDB.
ERROR: can not find channel named "exp9"
    while executing
"expect {
-i exp9 -timeout 10 
	-re ".*A problem internal to GDB has been detected" {
	    fail "$message (GDB internal error)"
	    gdb_internal_error..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" TCL LOOKUP CHANNEL exp9 can not find channel named "exp9"
builtin_spawn /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../../gdb/gdb -nw -nx -iex set height 0 -iex set width 0 -data-directory /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../data-directory
warning: Found custom handler for signal 7 (Bus error) preinstalled.
warning: Found custom handler for signal 8 (Floating point exception) preinstalled.
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 13.0.50.20220728-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) set height 0
(gdb) set width 0
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
(gdb) dir /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile
Source directories searched: /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile:$cdir:$cwd
(gdb) kill
The program is not being run.
(gdb) file /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value
Reading symbols from /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value...
(gdb) delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break -qualified main
Breakpoint 1 at 0x117b: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c, line 76.
(gdb) run 
Starting program: /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/../lib/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffd268) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c:76
76	  char *cp = argv[0]; /* Prevent gcc from optimizing argv[] out.  */
(gdb) guile (define (print x) (format #t "= ~A" x) (newline))
(gdb) guile (define (raw-print x) (format #t "= ~S" x) (newline))
(gdb) guile (use-modules (gdb))
(gdb) break 99
Breakpoint 2 at 0x55555555525b: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c, line 99.
(gdb) continue
Continuing.
void function called

Breakpoint 2, main (argc=1, argv=0x7fffffffd268) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c:99
99	  save_argv = argv;      /* break to inspect struct and union */
(gdb) PASS: gdb.guile/scm-value.exp: continue to breakpoint: break to inspect struct and union in c
gu (define intv (make-value 1))
(gdb) PASS: gdb.guile/scm-value.exp: Create int value for subscript test
gu (define stringv (make-value "foo"))
(gdb) PASS: gdb.guile/scm-value.exp: Create string value for subscript test
gu (print intv)
= 1
(gdb) PASS: gdb.guile/scm-value.exp: Baseline print of an int Guile value
gu (print (value-subscript intv 0))
ERROR: Cannot subscript requested type
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: Attempt to access an integer with a subscript
gu (print stringv)
= "foo"
(gdb) PASS: gdb.guile/scm-value.exp: Baseline print of a string Guile value
gu (print (value-subscript stringv 0))
= 102 'f'
(gdb) PASS: gdb.guile/scm-value.exp: Attempt to access a string with a subscript
print p
$1 = (int *) 0x7fffffffd0c4
(gdb) PASS: gdb.guile/scm-value.exp: Build pointer to array
gu (define pointer (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: set pointer
gu (print (value-subscript pointer 0))
= 1
(gdb) PASS: gdb.guile/scm-value.exp: Access array via pointer with int subscript
gu (print (value-subscript pointer intv))
= 2
(gdb) PASS: gdb.guile/scm-value.exp: Access array via pointer with value subscript
gu (print (value-subscript (value-subscript pointer intv) 0))
ERROR: Cannot subscript requested type
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: Attempt to access an integer with a subscript 2
print {"fu ","foo","bar"}
$2 = {"fu ", "foo", "bar"}
(gdb) PASS: gdb.guile/scm-value.exp: Build array
gu (define marray (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp:
gu (print (value-subscript (value-subscript marray 1) 2))
= 111 'o'
(gdb) PASS: gdb.guile/scm-value.exp: Test multiple subscript
Executing on host: g++  -fno-stack-protector   -fdiagnostics-color=never  -c -g -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value-cxx.o /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c    (timeout = 300)
builtin_spawn -ignore SIGHUP g++ -fno-stack-protector -fdiagnostics-color=never -c -g -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value-cxx.o /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c
Executing on host: g++  -fno-stack-protector /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value-cxx.o   -fdiagnostics-color=never   -L/home/simark/build/binutils-gdb-one-target/libiberty  -g  -lm  -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value-cxx    (timeout = 300)
builtin_spawn -ignore SIGHUP g++ -fno-stack-protector /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value-cxx.o -fdiagnostics-color=never -L/home/simark/build/binutils-gdb-one-target/libiberty -g -lm -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value-cxx
builtin_spawn /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../../gdb/gdb -nw -nx -iex set height 0 -iex set width 0 -data-directory /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../data-directory
warning: Found custom handler for signal 7 (Bus error) preinstalled.
warning: Found custom handler for signal 8 (Floating point exception) preinstalled.
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 13.0.50.20220728-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) set height 0
(gdb) set width 0
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
(gdb) dir /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile
Source directories searched: /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile:$cdir:$cwd
(gdb) kill
The program is not being run.
(gdb) file /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value-cxx
Reading symbols from /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value-cxx...
(gdb) delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break -qualified main
Breakpoint 1 at 0x1196: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c, line 76.
(gdb) run 
Starting program: /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.guile/scm-value/scm-value-cxx 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/../lib/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffd258) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c:76
76	  char *cp = argv[0]; /* Prevent gcc from optimizing argv[] out.  */
(gdb) guile (define (print x) (format #t "= ~A" x) (newline))
(gdb) guile (define (raw-print x) (format #t "= ~S" x) (newline))
(gdb) guile (use-modules (gdb))
(gdb) break 57
Breakpoint 2 at 0x555555555151: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c, line 57.
(gdb) continue
Continuing.
void function called

Breakpoint 2, ptr_ref (rptr_int=@0x7fffffffd0b8: 0x7fffffffd0c0) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c:57
57	  return; /* break to inspect pointer by reference. */
(gdb) PASS: gdb.guile/scm-value.exp: c++: continue to breakpoint: break to inspect pointer by reference
print rptr_int
$1 = (int *&) @0x7fffffffd0b8: 0x7fffffffd0c0
(gdb) PASS: gdb.guile/scm-value.exp: c++: Obtain address
gu (define rptr (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: c++: set rptr
gu (print (value-subscript rptr 0))
= 2
(gdb) PASS: gdb.guile/scm-value.exp: c++: Check pointer passed as reference
gu (print (value->bool (value-dynamic-cast (parse-and-eval "base") (type-pointer (lookup-type "Derived")))))
= #t
(gdb) PASS: gdb.guile/scm-value.exp: c++: gu (print (value->bool (value-dynamic-cast (parse-and-eval "base") (type-pointer (lookup-type "Derived")))))
gu (print (value-dynamic-type (parse-and-eval "base")))
= Derived *
(gdb) PASS: gdb.guile/scm-value.exp: c++: gu (print (value-dynamic-type (parse-and-eval "base")))
gu (print (value-dynamic-type (parse-and-eval "base_ref")))
= Derived &
(gdb) PASS: gdb.guile/scm-value.exp: c++: gu (print (value-dynamic-type (parse-and-eval "base_ref")))
gu (print (value-dynamic-type (parse-and-eval "5")))
= int
(gdb) PASS: gdb.guile/scm-value.exp: c++: gu (print (value-dynamic-type (parse-and-eval "5")))
break 99
Breakpoint 3 at 0x555555555276: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c, line 99.
(gdb) continue
Continuing.

Breakpoint 3, main (argc=1, argv=0x7fffffffd258) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.c:99
99	  save_argv = argv;      /* break to inspect struct and union */
(gdb) PASS: gdb.guile/scm-value.exp: c++: continue to breakpoint: break to inspect struct and union in c++
gu (define intv (make-value 1))
(gdb) PASS: gdb.guile/scm-value.exp: c++: Create int value for subscript test
gu (define stringv (make-value "foo"))
(gdb) PASS: gdb.guile/scm-value.exp: c++: Create string value for subscript test
gu (print intv)
= 1
(gdb) PASS: gdb.guile/scm-value.exp: c++: Baseline print of an int Guile value
gu (print (value-subscript intv 0))
ERROR: Cannot subscript requested type
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: c++: Attempt to access an integer with a subscript
gu (print stringv)
= "foo"
(gdb) PASS: gdb.guile/scm-value.exp: c++: Baseline print of a string Guile value
gu (print (value-subscript stringv 0))
= 102 'f'
(gdb) PASS: gdb.guile/scm-value.exp: c++: Attempt to access a string with a subscript
print p
$2 = (int *) 0x7fffffffd0c4
(gdb) PASS: gdb.guile/scm-value.exp: c++: Build pointer to array
gu (define pointer (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: c++: set pointer
gu (print (value-subscript pointer 0))
= 1
(gdb) PASS: gdb.guile/scm-value.exp: c++: Access array via pointer with int subscript
gu (print (value-subscript pointer intv))
= 2
(gdb) PASS: gdb.guile/scm-value.exp: c++: Access array via pointer with value subscript
gu (print (value-subscript (value-subscript pointer intv) 0))
ERROR: Cannot subscript requested type
Error while executing Scheme code.
(gdb) PASS: gdb.guile/scm-value.exp: c++: Attempt to access an integer with a subscript 2
print {"fu ","foo","bar"}
$3 = {"fu ", "foo", "bar"}
(gdb) PASS: gdb.guile/scm-value.exp: c++: Build array
gu (define marray (history-ref 0))
(gdb) PASS: gdb.guile/scm-value.exp: c++:
gu (print (value-subscript (value-subscript marray 1) 2))
= 111 'o'
(gdb) PASS: gdb.guile/scm-value.exp: c++: Test multiple subscript
testcase /home/simark/src/binutils-gdb/gdb/testsuite/gdb.guile/scm-value.exp completed in 4 seconds
Running /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp ...
Executing on host: g++  -fno-stack-protector /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.cc   -fdiagnostics-color=never   -L/home/simark/build/binutils-gdb-one-target/libiberty  -g  -lm  -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template    (timeout = 300)
builtin_spawn -ignore SIGHUP g++ -fno-stack-protector /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.cc -fdiagnostics-color=never -L/home/simark/build/binutils-gdb-one-target/libiberty -g -lm -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template
builtin_spawn /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../../gdb/gdb -nw -nx -iex set height 0 -iex set width 0 -data-directory /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../data-directory
warning: Found custom handler for signal 7 (Bus error) preinstalled.
warning: Found custom handler for signal 8 (Floating point exception) preinstalled.
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 13.0.50.20220728-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) set height 0
(gdb) set width 0
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
(gdb) dir /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python
Source directories searched: /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python:$cdir:$cwd
(gdb) python print ('test')
test
(gdb) Executing on host: g++  -fno-stack-protector /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.cc   -fdiagnostics-color=never  "-DTYPE=const int"  -L/home/simark/build/binutils-gdb-one-target/libiberty  -g  -lm  -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-ci    (timeout = 300)
builtin_spawn -ignore SIGHUP g++ -fno-stack-protector /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.cc -fdiagnostics-color=never -DTYPE=const int -L/home/simark/build/binutils-gdb-one-target/libiberty -g -lm -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-ci
kill
The program is not being run.
(gdb) file /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-ci
Reading symbols from /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-ci...
(gdb) delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break -qualified main
Breakpoint 1 at 0x111d: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.cc, line 29.
(gdb) run 
Starting program: /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-ci 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/../lib/libthread_db.so.1".

Breakpoint 1, main () at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.cc:29
29	  return 0; // break here
(gdb) print (foo)
$1 = {<No data fields>}
(gdb) PASS: gdb.python/py-template.exp: print (foo) in template test of const int
python foo = gdb.history(0)
(gdb) PASS: gdb.python/py-template.exp: fetch foo from gdb.history(0) in template test of const int
python print (foo.type.template_argument(0))
const int
(gdb) PASS: gdb.python/py-template.exp: const int
python print(foo.type.template_argument(-1))
Traceback (most recent call last):
  File "<string>", line 1, in <module>
RuntimeError: Template argument number must be non-negative
Error while executing Python code.
(gdb) PASS: gdb.python/py-template.exp: negative template argument number in template test of const int
Executing on host: g++  -fno-stack-protector /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.cc   -fdiagnostics-color=never  "-DTYPE=volatile int"  -L/home/simark/build/binutils-gdb-one-target/libiberty  -g  -lm  -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-vi    (timeout = 300)
builtin_spawn -ignore SIGHUP g++ -fno-stack-protector /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.cc -fdiagnostics-color=never -DTYPE=volatile int -L/home/simark/build/binutils-gdb-one-target/libiberty -g -lm -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-vi
kill
Kill the program being debugged? (y or n) y
[Inferior 1 (process 2942339) killed]
(gdb) file /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-vi
Load new symbol table from "/home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-vi"? (y or n) y
Reading symbols from /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-vi...


Fatal signal: Aborted
----- Backtrace -----
0x55ba2245e26a gdb_internal_backtrace_1
	/home/simark/src/binutils-gdb/gdb/bt-utils.c:122
0x55ba2245e761 _Z22gdb_internal_backtracev
	/home/simark/src/binutils-gdb/gdb/bt-utils.c:168
0x55ba2306efe6 handle_fatal_signal
	/home/simark/src/binutils-gdb/gdb/event-top.c:946
0x7f2d30a3e8df ???
0x7f2d30a8e36c ???
0x7f2d30a3e837 ???
0x7f2d30a28534 ???
0x7f2d322dfce3 _ZN11__sanitizer5AbortEv
	/usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:143
0x7f2d322ed1c1 _ZN11__sanitizer3DieEv
	/usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_termination.cpp:58
0x7f2d322c9c1f _ZN6__asan19ScopedInErrorReportD2Ev
	/usr/src/debug/gcc/libsanitizer/asan/asan_report.cpp:190
0x7f2d322c910b _ZN6__asan18ReportGenericErrorEmmmmbmjb
	/usr/src/debug/gcc/libsanitizer/asan/asan_report.cpp:479
0x7f2d322ca4ab __asan_report_load8
	/usr/src/debug/gcc/libsanitizer/asan/asan_rtl.cpp:123
0x55ba21dd4a0c _ZNK4type16is_objfile_ownedEv
	/home/simark/src/binutils-gdb/gdb/gdbtypes.h:1380
0x55ba231ea849 _Z19copy_type_recursiveP4typeP4htab
	/home/simark/src/binutils-gdb/gdb/gdbtypes.c:5638
0x55ba23d8355c _ZN12typy_deleterclEP11type_object
	/home/simark/src/binutils-gdb/gdb/python/py-type.c:1132
0x55ba23d83d1c _ZN8registryI7objfileE3keyI11type_object12typy_deleterE7cleanupEPv
	/home/simark/src/binutils-gdb/gdb/registry.h:159
0x55ba23a9b978 _ZN8registryI7objfileE14clear_registryEv
	/home/simark/src/binutils-gdb/gdb/registry.h:176
0x55ba23a97adb _ZN8registryI7objfileED2Ev
	/home/simark/src/binutils-gdb/gdb/registry.h:78
0x55ba23a886b5 _ZN7objfileD2Ev
	/home/simark/src/binutils-gdb/gdb/objfiles.c:590
0x55ba23a9bdc8 _ZNKSt14default_deleteI7objfileEclEPS0_
	/usr/include/c++/12.1.0/bits/unique_ptr.h:95
0x55ba23a97e98 _ZNSt10unique_ptrI7objfileSt14default_deleteIS0_EED2Ev
	/usr/include/c++/12.1.0/bits/unique_ptr.h:396
0x55ba23bdd172 _ZNSt15__new_allocatorINSt9__cxx199810_List_nodeISt10unique_ptrI7objfileSt14default_deleteIS3_EEEEE7destroyIS6_EEvPT_
	/usr/include/c++/12.1.0/bits/new_allocator.h:181
0x55ba23bd22f2 _ZNSt16allocator_traitsISaINSt9__cxx199810_List_nodeISt10unique_ptrI7objfileSt14default_deleteIS3_EEEEEE7destroyIS6_EEvRS8_PT_
	/usr/include/c++/12.1.0/bits/alloc_traits.h:535
0x55ba23be25a6 _ZNSt9__cxx19987__cxx114listISt10unique_ptrI7objfileSt14default_deleteIS3_EESaIS6_EE8_M_eraseENS_14_List_iteratorIS6_EE
	/usr/include/c++/12.1.0/bits/stl_list.h:2019
0x55ba23bd7b7d _ZNSt9__cxx19987__cxx114listISt10unique_ptrI7objfileSt14default_deleteIS3_EESaIS6_EE5eraseENS_20_List_const_iteratorIS6_EE
	/usr/include/c++/12.1.0/bits/list.tcc:158
0x55ba23bcc4b1 _ZNSt7__debug4listISt10unique_ptrI7objfileSt14default_deleteIS2_EESaIS5_EE8_M_eraseENSt9__cxx199820_List_const_iteratorIS5_EE
	/usr/include/c++/12.1.0/debug/list:521
0x55ba23bc5f44 _ZNSt7__debug4listISt10unique_ptrI7objfileSt14default_deleteIS2_EESaIS5_EE5eraseEN11__gnu_debug14_Safe_iteratorINSt9__cxx199820_List_const_iteratorIS5_EES7_St26bidirectional_iterator_tagEE
	/usr/include/c++/12.1.0/debug/list:533
0x55ba23bbb4dd _ZN13program_space14remove_objfileEP7objfile
	/home/simark/src/binutils-gdb/gdb/progspace.c:175
0x55ba23a872be _ZN7objfile6unlinkEv
	/home/simark/src/binutils-gdb/gdb/objfiles.c:478
0x55ba24294a30 syms_from_objfile_1
	/home/simark/src/binutils-gdb/gdb/symfile.c:938
0x55ba24295204 syms_from_objfile
	/home/simark/src/binutils-gdb/gdb/symfile.c:985
0x55ba24296255 symbol_file_add_with_addrs
	/home/simark/src/binutils-gdb/gdb/symfile.c:1088
0x55ba24297175 _Z24symbol_file_add_from_bfdP3bfdPKc10enum_flagsI16symfile_add_flagEPNSt7__debug6vectorI14other_sectionsSaIS8_EEES3_I12objfile_flagEP7objfile
	/home/simark/src/binutils-gdb/gdb/symfile.c:1168
0x55ba24297321 _Z15symbol_file_addPKc10enum_flagsI16symfile_add_flagEPNSt7__debug6vectorI14other_sectionsSaIS6_EEES1_I12objfile_flagE
	/home/simark/src/binutils-gdb/gdb/symfile.c:1181
0x55ba242976c9 symbol_file_add_main_1
	/home/simark/src/binutils-gdb/gdb/symfile.c:1205
0x55ba2429abca _Z19symbol_file_commandPKci
	/home/simark/src/binutils-gdb/gdb/symfile.c:1653
0x55ba2307d532 file_command
	/home/simark/src/binutils-gdb/gdb/exec.c:555
0x55ba226a6dd0 do_simple_func
	/home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:95
0x55ba226bc77b _Z8cmd_funcP16cmd_list_elementPKci
	/home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:2516
0x55ba2460e5ca _Z15execute_commandPKci
	/home/simark/src/binutils-gdb/gdb/top.c:699
0x55ba2306d5a9 _Z15command_handlerPKc
	/home/simark/src/binutils-gdb/gdb/event-top.c:598
0x55ba2306e3b1 _Z20command_line_handlerOSt10unique_ptrIcN3gdb13xfree_deleterIcEEE
	/home/simark/src/binutils-gdb/gdb/event-top.c:842
0x55ba2475a2e6 tui_command_line_handler
	/home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:104
0x55ba2306b59e gdb_rl_callback_handler
	/home/simark/src/binutils-gdb/gdb/event-top.c:230
0x7f2d32a629df ???
0x55ba2306afa9 gdb_rl_callback_read_char_wrapper_noexcept
	/home/simark/src/binutils-gdb/gdb/event-top.c:188
0x55ba2306b1ec gdb_rl_callback_read_char_wrapper
	/home/simark/src/binutils-gdb/gdb/event-top.c:205
0x55ba2306cb77 _Z19stdin_event_handleriPv
	/home/simark/src/binutils-gdb/gdb/event-top.c:525
0x55ba24ecbe3b handle_file_event
	/home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:549
0x55ba24ecc777 gdb_wait_for_event
	/home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:670
0x55ba24eca531 _Z16gdb_do_one_eventv
	/home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:235
0x55ba23791714 start_event_loop
	/home/simark/src/binutils-gdb/gdb/main.c:411
0x55ba23791b6e captured_command_loop
	/home/simark/src/binutils-gdb/gdb/main.c:471
0x55ba23797000 captured_main
	/home/simark/src/binutils-gdb/gdb/main.c:1329
0x55ba237970dd _Z8gdb_mainP18captured_main_args
	/home/simark/src/binutils-gdb/gdb/main.c:1344
0x55ba21daac9d main
	/home/simark/src/binutils-gdb/gdb/gdb.c:32
---------------------
A fatal error internal to GDB has been detected, further
debugging is not possible.  GDB will now terminate.

This is a bug, please report it.  For instructions, see:
<https://www.gnu.org/software/gdb/bugs/>.

ERROR: Couldn't load py-template-vi -- with new symbol table into GDB (eof).
ERROR: Couldn't send delete breakpoints to GDB.
ERROR: : spawn id exp9 not open
    while executing
"expect {
-i exp9 -timeout 100 
	-re ".*A problem internal to GDB has been detected" {
	    fail "$message (GDB internal error)"
	    gdb_internal_erro..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" NONE : spawn id exp9 not open
ERROR: breakpoints not deleted
ERROR: : spawn id exp9 not open
    while executing
"expect {
-i exp9 -timeout 30 
	-re "$break_message \[0-9\]* at .*: file .*, line $decimal.\r\n$gdb_prompt $" {}
	-re "$break_message \[0-9\]*: file .*..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" NONE : spawn id exp9 not open
ERROR: GDB process no longer exists
GDB process exited with wait status 2942293 exp9 0 0 CHILDKILLED SIGABRT SIGABRT
UNRESOLVED: gdb.python/py-template.exp: gdb_breakpoint: set breakpoint at main (eof)
ERROR: couldn't run to breakpoint
Executing on host: g++  -fno-stack-protector /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.cc   -fdiagnostics-color=never  "-DTYPE=const int &"  -L/home/simark/build/binutils-gdb-one-target/libiberty  -g  -lm  -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-cir    (timeout = 300)
builtin_spawn -ignore SIGHUP g++ -fno-stack-protector /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.cc -fdiagnostics-color=never -DTYPE=const int & -L/home/simark/build/binutils-gdb-one-target/libiberty -g -lm -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-template/py-template-cir
ERROR: can not find channel named "exp9"
    while executing
"expect {
-i exp9 -timeout 120 
	-re "Kill the program being debugged. .y or n. $" {
	    send_gdb "y\n" answer
	    verbose "\t\tKilling previous prog..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" TCL LOOKUP CHANNEL exp9 can not find channel named "exp9"
WARNING: remote_expect statement without a default case
ERROR: can not find channel named "exp9"
    while executing
"expect {
-i exp9 -timeout 120 
	-re "(Reading symbols from.*LZMA support was disabled.*$gdb_prompt $)" {
	    verbose "\t\tLoaded $arg into $GDB; .gnu..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" TCL LOOKUP CHANNEL exp9 can not find channel named "exp9"
ERROR: Couldn't load py-template-cir into GDB (eof).
ERROR: Couldn't send delete breakpoints to GDB.
ERROR: can not find channel named "exp9"
    while executing
"expect {
-i exp9 -timeout 100 
	-re ".*A problem internal to GDB has been detected" {
	    fail "$message (GDB internal error)"
	    gdb_internal_erro..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" TCL LOOKUP CHANNEL exp9 can not find channel named "exp9"
ERROR: breakpoints not deleted
ERROR: can not find channel named "exp9"
    while executing
"expect {
-i exp9 -timeout 30 
	-re "$break_message \[0-9\]* at .*: file .*, line $decimal.\r\n$gdb_prompt $" {}
	-re "$break_message \[0-9\]*: file .*..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" TCL LOOKUP CHANNEL exp9 can not find channel named "exp9"
ERROR: GDB process no longer exists
ERROR: tcl error sourcing /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp.
ERROR: tcl error code TCL LOOKUP CHANNEL exp9
ERROR: can not find channel named "exp9"
    while executing
"wait -i $gdb_spawn_id"
    ("uplevel" body line 4)
    invoked from within
"uplevel $error_sect"
    invoked from within
"remote_expect host 30 {
	-re "$break_message \[0-9\]* at .*: file .*, line $decimal.\r\n$gdb_prompt $" {}
	-re "$break_message \[0-9\]*: file .*, line..."
    ("uplevel" body line 1)
    invoked from within
"uplevel remote_expect host $tmt $expcode"
    invoked from within
"gdb_expect 30 {
	-re "$break_message \[0-9\]* at .*: file .*, line $decimal.\r\n$gdb_prompt $" {}
	-re "$break_message \[0-9\]*: file .*, line $decima..."
    (procedure "gdb_breakpoint" line 36)
    invoked from within
"gdb_breakpoint $linespec qualified"
    ("eval" body line 1)
    invoked from within
"eval gdb_breakpoint {$linespec} $args"
    (procedure "runto" line 25)
    invoked from within
"runto main qualified"
    (procedure "runto_main" line 2)
    invoked from within
"runto_main "
    (procedure "test_template_arg" line 8)
    invoked from within
"test_template_arg "${binfile}-cir" "const int &""
    (file "/home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp" line 67)
    invoked from within
"source /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp"
    ("uplevel" body line 1)
    invoked from within
"uplevel #0 source /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp"
    invoked from within
"catch "uplevel #0 source $test_file_name" msg"
UNRESOLVED: gdb.python/py-template.exp: testcase '/home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp' aborted due to Tcl error
PATH: gdb.python/py-template.exp: testcase '/home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp' aborted due to Tcl error
testcase /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp completed in 2 seconds
Running /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.exp ...
Executing on host: gcc  -fno-stack-protector   -fdiagnostics-color=never -c -g -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value.o /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c    (timeout = 300)
builtin_spawn -ignore SIGHUP gcc -fno-stack-protector -fdiagnostics-color=never -c -g -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value.o /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c
Executing on host: gcc  -fno-stack-protector /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value.o   -fdiagnostics-color=never -g  -lm  -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value    (timeout = 300)
builtin_spawn -ignore SIGHUP gcc -fno-stack-protector /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value.o -fdiagnostics-color=never -g -lm -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value
builtin_spawn /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../../gdb/gdb -nw -nx -iex set height 0 -iex set width 0 -data-directory /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../data-directory
warning: Found custom handler for signal 7 (Bus error) preinstalled.
warning: Found custom handler for signal 8 (Floating point exception) preinstalled.
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 13.0.50.20220728-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) set height 0
(gdb) set width 0
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
(gdb) dir /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python
Source directories searched: /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python:$cdir:$cwd
(gdb) kill
The program is not being run.
(gdb) file /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value
Reading symbols from /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value...
(gdb) python print ('test')
test
(gdb) python print('history count is %d' % gdb.history_count())
history count is 0
(gdb) PASS: gdb.python/py-value.exp: history count is 0
print 0
$1 = 0
(gdb) PASS: gdb.python/py-value.exp: print 0
python print('history count is %d' % gdb.history_count())
history count is 1
(gdb) PASS: gdb.python/py-value.exp: history count is 1
print 1
$2 = 1
(gdb) PASS: gdb.python/py-value.exp: print 1
python print('history count is %d' % gdb.history_count())
history count is 2
(gdb) PASS: gdb.python/py-value.exp: history count is 2
print 2
$3 = 2
(gdb) PASS: gdb.python/py-value.exp: print 2
python print('history count is %d' % gdb.history_count())
history count is 3
(gdb) PASS: gdb.python/py-value.exp: history count is 3
print 3
$4 = 3
(gdb) PASS: gdb.python/py-value.exp: print 3
python print('history count is %d' % gdb.history_count())
history count is 4
(gdb) PASS: gdb.python/py-value.exp: history count is 4
print 4
$5 = 4
(gdb) PASS: gdb.python/py-value.exp: print 4
python i = gdb.Value (True)
(gdb) PASS: gdb.python/py-value.exp: create boolean value
python i = gdb.Value (5)
(gdb) PASS: gdb.python/py-value.exp: create integer value
python i = gdb.Value (3,None)
(gdb) PASS: gdb.python/py-value.exp: create integer value, with None type
python l = gdb.Value(0xffffffff12345678)
(gdb) PASS: gdb.python/py-value.exp: create large unsigned 64-bit value
python print (int(l))
18446744069720004216
(gdb) PASS: gdb.python/py-value.exp: large unsigned 64-bit int conversion to python
python f = gdb.Value (1.25)
(gdb) PASS: gdb.python/py-value.exp: create double value
python a = gdb.Value ('string test')
(gdb) PASS: gdb.python/py-value.exp: create 8-bit string value
python print (a)
"string test"
(gdb) PASS: gdb.python/py-value.exp: print 8-bit string
python print (a.__class__)
<class 'gdb.Value'>
(gdb) PASS: gdb.python/py-value.exp: verify type of 8-bit string
python print ('result = %s' % i.address)
result = None
(gdb) PASS: gdb.python/py-value.exp: test address attribute in non-addressable value
python print(gdb.Value(gdb.Value(5).type.optimized_out()))
<optimized out>
(gdb) PASS: gdb.python/py-value.exp: python print(gdb.Value(gdb.Value(5).type.optimized_out()))
python v = gdb.Value (3)
(gdb) PASS: gdb.python/py-value.exp: create initial integer value
python print(v)
3
(gdb) PASS: gdb.python/py-value.exp: check initial value contents
python v.__init__(5)
(gdb) PASS: gdb.python/py-value.exp: call gdb.Value.__init__ manually
python print(v)
5
(gdb) PASS: gdb.python/py-value.exp: check new value contents
python i = gdb.Value (5)
(gdb) python j = gdb.Value (2)
(gdb) python f = gdb.Value (1.25)
(gdb) python g = gdb.Value (2.5)
(gdb) python print ('result = ' + str(i+j))
result = 7
(gdb) PASS: gdb.python/py-value.exp: add two integer values
python print ((i+j).__class__)
<class 'gdb.Value'>
(gdb) PASS: gdb.python/py-value.exp: verify type of integer add result
python print ('result = ' + str(f+g))
result = 3.75
(gdb) PASS: gdb.python/py-value.exp: add two double values
python print ('result = ' + str(i-j))
result = 3
(gdb) PASS: gdb.python/py-value.exp: subtract two integer values
python print ('result = ' + str(f-g))
result = -1.25
(gdb) PASS: gdb.python/py-value.exp: subtract two double values
python print ('result = ' + str(i*j))
result = 10
(gdb) PASS: gdb.python/py-value.exp: multiply two integer values
python print ('result = ' + str(f*g))
result = 3.125
(gdb) PASS: gdb.python/py-value.exp: multiply two double values
python print ('result = ' + str(i/j))
result = 2
(gdb) PASS: gdb.python/py-value.exp: divide two integer values
python print ('result = ' + str(f/g))
result = 0.5
(gdb) PASS: gdb.python/py-value.exp: divide two double values
python print ('result = ' + str(i%j))
result = 1
(gdb) PASS: gdb.python/py-value.exp: take remainder of two integer values
python print ('result = ' + str(i**j))
result = 25
(gdb) PASS: gdb.python/py-value.exp: integer value raised to the power of another integer value
python print ('result = ' + str(g**j))
result = 6.25
(gdb) PASS: gdb.python/py-value.exp: double value raised to the power of integer value
python print ('result = ' + str(-i))
result = -5
(gdb) PASS: gdb.python/py-value.exp: negated integer value
python print ('result = ' + str(+i))
result = 5
(gdb) PASS: gdb.python/py-value.exp: positive integer value
python print ('result = ' + str(-f))
result = -1.25
(gdb) PASS: gdb.python/py-value.exp: negated double value
python print ('result = ' + str(+f))
result = 1.25
(gdb) PASS: gdb.python/py-value.exp: positive double value
python print ('result = ' + str(abs(j-i)))
result = 3
(gdb) PASS: gdb.python/py-value.exp: absolute of integer value
python print ('result = ' + str(abs(f-g)))
result = 1.25
(gdb) PASS: gdb.python/py-value.exp: absolute of double value
python print ('result = ' + str(i-1))
result = 4
(gdb) PASS: gdb.python/py-value.exp: subtract integer value from python integer
python print ((i-1).__class__)
<class 'gdb.Value'>
(gdb) PASS: gdb.python/py-value.exp: verify type of mixed integer subtraction result
python print ('result = ' + str(f+1.5))
result = 2.75
(gdb) PASS: gdb.python/py-value.exp: add double value with python float
python print ('result = ' + str(1-i))
result = -4
(gdb) PASS: gdb.python/py-value.exp: subtract python integer from integer value
python print ('result = ' + str(1.5+f))
result = 2.75
(gdb) PASS: gdb.python/py-value.exp: add python float with double value
print evalue
$6 = TWO
(gdb) PASS: gdb.python/py-value.exp: print evalue
python evalue = gdb.history (0)
(gdb) PASS: gdb.python/py-value.exp: python evalue = gdb.history (0)
python print (int (evalue))
2
(gdb) PASS: gdb.python/py-value.exp: python print (int (evalue))
print (void *) 2
$7 = (void *) 0x2
(gdb) PASS: gdb.python/py-value.exp: print (void *) 2
python a = gdb.history (0)
(gdb) PASS: gdb.python/py-value.exp: python a = gdb.history (0)
print (void *) 5
$8 = (void *) 0x5
(gdb) PASS: gdb.python/py-value.exp: print (void *) 5
python b = gdb.history (0)
(gdb) PASS: gdb.python/py-value.exp: python b = gdb.history (0)
python print(int(b))
5
(gdb) PASS: gdb.python/py-value.exp: convert pointer to int
python print ('result = ' + str(a+5))
result = 0x7
(gdb) PASS: gdb.python/py-value.exp: add pointer value with python integer
python print ('result = ' + str(b-2))
result = 0x3
(gdb) PASS: gdb.python/py-value.exp: subtract python integer from pointer value
python print ('result = ' + str(b-a))
result = 3
(gdb) PASS: gdb.python/py-value.exp: subtract two pointer values
python print ('result = ' + 'result'[gdb.Value(0)])
result = r
(gdb) PASS: gdb.python/py-value.exp: use value as string index
python print ('result = ' + str((1,2,3)[gdb.Value(0)]))
result = 1
(gdb) PASS: gdb.python/py-value.exp: use value as tuple index
python print ('result = ' + str([1,2,3][gdb.Value(0)]))
result = 1
(gdb) PASS: gdb.python/py-value.exp: use value as array index
python print('%x' % int(gdb.parse_and_eval('-1ull')))
ffffffffffffffff
(gdb) PASS: gdb.python/py-value.exp: int conversion respect type sign
python print ('result = ' + str(i+'foo'))
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.error: Argument to arithmetic operation not a number or boolean.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: catch error in python type conversion
python print ('result = ' + str(i+gdb.Value('foo')))
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.error: Argument to arithmetic operation not a number or boolean.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: catch throw of GDB error
python
>PASS: gdb.python/py-value.exp: define function to test booleans: input 1: python
def test_bool (val):
>PASS: gdb.python/py-value.exp: define function to test booleans: input 2: def test_bool (val):
  if val:
>PASS: gdb.python/py-value.exp: define function to test booleans: input 3:   if val:
    print ('yay')
>PASS: gdb.python/py-value.exp: define function to test booleans: input 4:     print ('yay')
  else:
>PASS: gdb.python/py-value.exp: define function to test booleans: input 5:   else:
    print ('nay')
>PASS: gdb.python/py-value.exp: define function to test booleans: input 6:     print ('nay')
end
(gdb) PASS: gdb.python/py-value.exp: define function to test booleans: input 7: end
py test_bool (gdb.Value (True))
yay
(gdb) PASS: gdb.python/py-value.exp: check evaluation of true boolean value in expression
py test_bool (gdb.Value (False))
nay
(gdb) PASS: gdb.python/py-value.exp: check evaluation of false boolean value in expression
py test_bool (gdb.Value (5))
yay
(gdb) PASS: gdb.python/py-value.exp: check evaluation of true integer value in expression
py test_bool (gdb.Value (0))
nay
(gdb) PASS: gdb.python/py-value.exp: check evaluation of false integer value in expression
py test_bool (gdb.Value (5.2))
yay
(gdb) PASS: gdb.python/py-value.exp: check evaluation of true float value in expression
py test_bool (gdb.Value (0.0))
nay
(gdb) PASS: gdb.python/py-value.exp: check evaluation of false float value in expression
py print (gdb.Value (1) < gdb.Value (1))
False
(gdb) PASS: gdb.python/py-value.exp: less than, equal
py print (gdb.Value (1) < gdb.Value (2))
True
(gdb) PASS: gdb.python/py-value.exp: less than, less
py print (gdb.Value (2) < gdb.Value (1))
False
(gdb) PASS: gdb.python/py-value.exp: less than, greater
py print (gdb.Value (2) < None)
False
(gdb) PASS: gdb.python/py-value.exp: less than, None
py print (gdb.Value (1) <= gdb.Value (1))
True
(gdb) PASS: gdb.python/py-value.exp: less or equal, equal
py print (gdb.Value (1) <= gdb.Value (2))
True
(gdb) PASS: gdb.python/py-value.exp: less or equal, less
py print (gdb.Value (2) <= gdb.Value (1))
False
(gdb) PASS: gdb.python/py-value.exp: less or equal, greater
py print (gdb.Value (2) <= None)
False
(gdb) PASS: gdb.python/py-value.exp: less or equal, None
py print (gdb.Value (1) == gdb.Value (1))
True
(gdb) PASS: gdb.python/py-value.exp: equality of gdb.Values
py print (gdb.Value (1) == gdb.Value (2))
False
(gdb) PASS: gdb.python/py-value.exp: inequality of gdb.Values
py print (gdb.Value (1) == 1.0)
True
(gdb) PASS: gdb.python/py-value.exp: equality of gdb.Value with Python value
py print (gdb.Value (1) == 2)
False
(gdb) PASS: gdb.python/py-value.exp: inequality of gdb.Value with Python value
py print (gdb.Value (1) == None)
False
(gdb) PASS: gdb.python/py-value.exp: inequality of gdb.Value with None
py print (gdb.Value (1) != gdb.Value (1))
False
(gdb) PASS: gdb.python/py-value.exp: inequality, false
py print (gdb.Value (1) != gdb.Value (2))
True
(gdb) PASS: gdb.python/py-value.exp: inequality, true
py print (gdb.Value (1) != None)
True
(gdb) PASS: gdb.python/py-value.exp: inequality, None
py print (gdb.Value (1) > gdb.Value (1))
False
(gdb) PASS: gdb.python/py-value.exp: greater than, equal
py print (gdb.Value (1) > gdb.Value (2))
False
(gdb) PASS: gdb.python/py-value.exp: greater than, less
py print (gdb.Value (2) > gdb.Value (1))
True
(gdb) PASS: gdb.python/py-value.exp: greater than, greater
py print (gdb.Value (2) > None)
True
(gdb) PASS: gdb.python/py-value.exp: greater than, None
py print (gdb.Value (1) >= gdb.Value (1))
True
(gdb) PASS: gdb.python/py-value.exp: greater or equal, equal
py print (gdb.Value (1) >= gdb.Value (2))
False
(gdb) PASS: gdb.python/py-value.exp: greater or equal, less
py print (gdb.Value (2) >= gdb.Value (1))
True
(gdb) PASS: gdb.python/py-value.exp: greater or equal, greater
py print (gdb.Value (2) >= None)
True
(gdb) PASS: gdb.python/py-value.exp: greater or equal, None
python
>ok=False
>for file in gdb.objfiles():
>  if 'py-value' in file.filename:
>    ok=True
>print (ok)
>end
True
(gdb) PASS: gdb.python/py-value.exp: py-value in file.filename
python print (gdb.objfiles()[0].pretty_printers)
[]
(gdb) PASS: gdb.python/py-value.exp: python print (gdb.objfiles()[0].pretty_printers)
python gdb.objfiles()[0].pretty_printers = 0
Traceback (most recent call last):
  File "<string>", line 1, in <module>
TypeError: The pretty_printers attribute must be a list.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: python gdb.objfiles()[0].pretty_printers = 0
python print (gdb.parse_and_eval ('23'))
23
(gdb) PASS: gdb.python/py-value.exp: parse_and_eval constant test
python print (gdb.parse_and_eval ('5 + 7'))
12
(gdb) PASS: gdb.python/py-value.exp: parse_and_eval simple expression test
python print (type(gdb.parse_and_eval ('5 + 7')))
<class 'gdb.Value'>
(gdb) PASS: gdb.python/py-value.exp: parse_and_eval type test
python
>PASS: gdb.python/py-value.exp: Simple Python value dictionary: input 1: python
one = gdb.Value(1)
>PASS: gdb.python/py-value.exp: Simple Python value dictionary: input 2: one = gdb.Value(1)
two = gdb.Value(2)
>PASS: gdb.python/py-value.exp: Simple Python value dictionary: input 3: two = gdb.Value(2)
three = gdb.Value(3)
>PASS: gdb.python/py-value.exp: Simple Python value dictionary: input 4: three = gdb.Value(3)
vdict = {one:"one str",two:"two str",three:"three str"}
>PASS: gdb.python/py-value.exp: Simple Python value dictionary: input 5: vdict = {one:"one str",two:"two str",three:"three str"}
end
(gdb) PASS: gdb.python/py-value.exp: Simple Python value dictionary: input 6: end
python print (vdict[one])
one str
(gdb) PASS: gdb.python/py-value.exp: test dictionary hash for one
python print (vdict[two])
two str
(gdb) PASS: gdb.python/py-value.exp: test dictionary hash for two
python print (vdict[three])
three str
(gdb) PASS: gdb.python/py-value.exp: test dictionary hash for three
python print (one.__hash__() == hash(one))
True
(gdb) PASS: gdb.python/py-value.exp: test inbuilt hash
python print(int(gdb.Value(0)))
0
(gdb) PASS: gdb.python/py-value.exp: python print(int(gdb.Value(0)))
python print(int(gdb.Value(2.5)))
2
(gdb) PASS: gdb.python/py-value.exp: python print(int(gdb.Value(2.5)))
python print(float(gdb.Value(2.5)))
2.5
(gdb) PASS: gdb.python/py-value.exp: python print(float(gdb.Value(2.5)))
python print(float(gdb.Value(0)))
0.0
(gdb) PASS: gdb.python/py-value.exp: python print(float(gdb.Value(0)))
python idx = gdb.add_history(gdb.Value(42))
(gdb) PASS: gdb.python/py-value.exp: add value 42 to the history list
python print ("$%d = %s" % (idx, gdb.history (idx)))
$9 = 42
(gdb) PASS: gdb.python/py-value.exp: print value 42 from the history list
python print ("valueof: %s" % (idx))
valueof: 9
(gdb) PASS: gdb.python/py-value.exp: get idx for value 42
print $9
$10 = 42
(gdb) PASS: gdb.python/py-value.exp: print $9
python idx = gdb.add_history(84)
(gdb) PASS: gdb.python/py-value.exp: add value to 84 to the history list
python print ("$%d = %s" % (idx, gdb.history (idx)))
$11 = 84
(gdb) PASS: gdb.python/py-value.exp: print value 84 from the history list
python print ("valueof: %s" % (idx))
valueof: 11
(gdb) PASS: gdb.python/py-value.exp: get idx for value 84
print $11
$12 = 84
(gdb) PASS: gdb.python/py-value.exp: print $11
python idx = gdb.add_history(gdb.GdbError("an error"))
Traceback (most recent call last):
  File "<string>", line 1, in <module>
TypeError: Could not convert Python object: an error.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: python idx = gdb.add_history(gdb.GdbError("an error"))
delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break -qualified main
Breakpoint 1 at 0x119b: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c, line 88.
(gdb) run 
Starting program: /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/../lib/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffd268) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c:88
88	  PTR x = &s;
(gdb) break 124
Breakpoint 2 at 0x5555555552b7: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c, line 124.
(gdb) continue
Continuing.
void function called

Breakpoint 2, main (argc=1, argv=0x7fffffffd268) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c:124
124	  save_argv = argv;      /* break to inspect struct and union */
(gdb) PASS: gdb.python/py-value.exp: continue to breakpoint: break to inspect struct and union
print s
$13 = {a = 3, b = 5}
(gdb) PASS: gdb.python/py-value.exp: print s
python s = gdb.history (0)
(gdb) PASS: gdb.python/py-value.exp: get value s from history
python print ('result = ' + str(s['a']))
result = 3
(gdb) PASS: gdb.python/py-value.exp: access element inside struct using 8-bit string name
print argv
$14 = (char **) 0x7fffffffd268
(gdb) PASS: gdb.python/py-value.exp: print argv
python argv = gdb.history (0)
(gdb) python arg0 = argv.dereference ()
(gdb) PASS: gdb.python/py-value.exp: dereference value
set print elements unlimited
(gdb) PASS: gdb.python/py-value.exp: set print elements unlimited
set print repeats unlimited
(gdb) PASS: gdb.python/py-value.exp: set print repeats unlimited
python print (arg0)
0x7fffffffd728 "/home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value"
(gdb) PASS: gdb.python/py-value.exp: verify dereferenced value
python print ('result = %s' % arg0.is_optimized_out)
result = False
(gdb) PASS: gdb.python/py-value.exp: test is_optimized_out attribute
python print ('result = %s' % arg0.address)
result = 0x7fffffffd268
(gdb) PASS: gdb.python/py-value.exp: test address attribute
python print (gdb.parse_and_eval('*(int*)0'))
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.MemoryError: Cannot access memory at address 0x0
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: parse_and_eval with memory error
python inval = gdb.parse_and_eval('*(int*)0')
(gdb) PASS: gdb.python/py-value.exp: python inval = gdb.parse_and_eval('*(int*)0')
python print (inval.is_lazy)
True
(gdb) PASS: gdb.python/py-value.exp: python print (inval.is_lazy)
python inval2 = inval+1
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.MemoryError: Cannot access memory at address 0x0
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: memory error and lazy values, first test
python inval.fetch_lazy ()
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.MemoryError: Cannot access memory at address 0x0
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: memory error and lazy values, second test
print /d argc
$15 = 1
(gdb) PASS: gdb.python/py-value.exp: get integer valueof "argc"
python argc_lazy = gdb.parse_and_eval('argc')
(gdb) PASS: gdb.python/py-value.exp: python argc_lazy = gdb.parse_and_eval('argc')
python argc_notlazy = gdb.parse_and_eval('argc')
(gdb) PASS: gdb.python/py-value.exp: python argc_notlazy = gdb.parse_and_eval('argc')
python argc_notlazy.fetch_lazy()
(gdb) PASS: gdb.python/py-value.exp: python argc_notlazy.fetch_lazy()
python print (argc_lazy.is_lazy)
True
(gdb) PASS: gdb.python/py-value.exp: python print (argc_lazy.is_lazy) the first time
python print (argc_notlazy.is_lazy)
False
(gdb) PASS: gdb.python/py-value.exp: python print (argc_notlazy.is_lazy)
print argc
$16 = 1
(gdb) PASS: gdb.python/py-value.exp: sanity check argc
python print (argc_lazy.is_lazy)
True
(gdb) PASS: gdb.python/py-value.exp: python print (argc_lazy.is_lazy) the second time
set argc=2
(gdb) PASS: gdb.python/py-value.exp: change argc
python print (argc_notlazy)
1
(gdb) PASS: gdb.python/py-value.exp: python print (argc_notlazy)
python print (argc_lazy)
2
(gdb) PASS: gdb.python/py-value.exp: python print (argc_lazy)
python print (argc_lazy.is_lazy)
False
(gdb) PASS: gdb.python/py-value.exp: python print (argc_lazy.is_lazy)
print st
$17 = "divide et impera"
(gdb) PASS: gdb.python/py-value.exp: print st
python st = gdb.history (0)
(gdb) PASS: gdb.python/py-value.exp: get value st from history
python print (st.string ())
divide et impera
(gdb) PASS: gdb.python/py-value.exp: Test string with no length
python print (st.string (length = -1))
divide et impera
(gdb) PASS: gdb.python/py-value.exp: test string (length = -1) is all of the string
python print (st.string (length = 6))
divide
(gdb) PASS: gdb.python/py-value.exp: python print (st.string (length = 6))
python print ("---"+st.string (length = 0)+"---")
------
(gdb) PASS: gdb.python/py-value.exp: test string (length = 0) is empty
python print (len(st.string (length = 0)))
0
(gdb) PASS: gdb.python/py-value.exp: test length is 0
set lang ada
Warning: the current language does not match this frame.
(gdb) PASS: gdb.python/py-value.exp: set lang ada
python print (st.string ())
divide et impera
(gdb) PASS: gdb.python/py-value.exp: Test string with no length in ada
set lang auto
(gdb) PASS: gdb.python/py-value.exp: set lang auto
print nullst
$18 = "divide\000et\000impera"
(gdb) PASS: gdb.python/py-value.exp: print nullst
python nullst = gdb.history (0)
(gdb) PASS: gdb.python/py-value.exp: get value nullst from history
python print (nullst.string ())
divide
(gdb) PASS: gdb.python/py-value.exp: test string to first null
python nullst = nullst.string (length = 9)
(gdb) PASS: gdb.python/py-value.exp: get string beyond null
python print (repr(nullst))
'divide\x00et'
(gdb) PASS: gdb.python/py-value.exp: python print (repr(nullst))
python xstr = gdb.parse_and_eval('xstr')
(gdb) PASS: gdb.python/py-value.exp: get xstr
python print(xstr['text'].string (length = xstr['length']))
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
(gdb) PASS: gdb.python/py-value.exp: read string beyond declared size
python str = '"str"'
(gdb) PASS: gdb.python/py-value.exp: set up str variable
python print (gdb.parse_and_eval (str).string (length = 10))
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.error: Attempt to take address of value not located in memory.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: python print (gdb.parse_and_eval (str).string (length = 10))
python tp=gdb.lookup_type('int')
(gdb) python size_a=gdb.parse_and_eval('sizeof(a)')
(gdb) python size_a0=gdb.parse_and_eval('sizeof(a[0])')
(gdb) python addr=gdb.parse_and_eval('&a')
(gdb) python b=gdb.selected_inferior().read_memory(addr,size_a)
(gdb) python v=gdb.Value(b,tp); print(v)
1
(gdb) PASS: gdb.python/py-value.exp: construct value from buffer
python v=gdb.Value(b[size_a0:],tp); print(v)
2
(gdb) PASS: gdb.python/py-value.exp: convert 2nd elem of buffer to value
python v=gdb.Value(b[2*size_a0:],tp); print(v)
3
(gdb) PASS: gdb.python/py-value.exp: convert 3rd elem of buffer to value
python v=gdb.Value(b[2*size_a0+1:],tp); print(v)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ValueError: Size of type is larger than that of buffer object.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: attempt to convert smaller buffer than size of type
python atp=tp.array(2) ; print(atp)
int [3]
(gdb) python va=gdb.Value(b,atp)
(gdb) python print(va)
{1, 2, 3}
(gdb) PASS: gdb.python/py-value.exp: print array value
python print(va[0])
1
(gdb) PASS: gdb.python/py-value.exp: print first array element
python print(va[1])
2
(gdb) PASS: gdb.python/py-value.exp: print second array element
python print(va[2])
3
(gdb) PASS: gdb.python/py-value.exp: print third array element
python print(va[3])
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.error: no such vector element
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: print out of bounds array element
python atpbig=tp.array(3)
(gdb) python vabig=gdb.Value(b,atpbig)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ValueError: Size of type is larger than that of buffer object.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: attempt to construct large value with small buffer
python v=gdb.Value(2048,tp)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
TypeError: Object must support the python buffer protocol.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: attempt to construct value from buffer with non-buffer object
python v=gdb.Value(b,'int'); print(v)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
TypeError: type argument must be a gdb.Type.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: attempt to construct value with string as type
python tp=gdb.lookup_type('int')
(gdb) python size_a=gdb.parse_and_eval('sizeof(a)')
(gdb) python size_a0=gdb.parse_and_eval('sizeof(a[0])')
(gdb) python addr=gdb.parse_and_eval('&a')
(gdb) python b=gdb.selected_inferior().read_memory(addr,size_a)
(gdb) python
>PASS: gdb.python/py-value.exp: Create sub-class of gdb.Value: input 1: python
class MyValue(gdb.Value):
>PASS: gdb.python/py-value.exp: Create sub-class of gdb.Value: input 2: class MyValue(gdb.Value):
  def __init__(self,val,type=None):
>PASS: gdb.python/py-value.exp: Create sub-class of gdb.Value: input 3:   def __init__(self,val,type=None):
    gdb.Value.__init__(self,val,type)
>PASS: gdb.python/py-value.exp: Create sub-class of gdb.Value: input 4:     gdb.Value.__init__(self,val,type)
    print("In MyValue.__init__")
>PASS: gdb.python/py-value.exp: Create sub-class of gdb.Value: input 5:     print("In MyValue.__init__")
end
(gdb) PASS: gdb.python/py-value.exp: Create sub-class of gdb.Value: input 6: end
python obj = MyValue (123)
In MyValue.__init__
(gdb) PASS: gdb.python/py-value.exp: create instance of MyValue
python print(obj)
123
(gdb) PASS: gdb.python/py-value.exp: check printing of MyValue
python obj = MyValue(b[size_a0:],tp)
In MyValue.__init__
(gdb) PASS: gdb.python/py-value.exp: convert 2nd elem of buffer to a MyValue
python print(obj)
2
(gdb) PASS: gdb.python/py-value.exp: check printing of MyValue when initiaized with a type
p/x fp1
$19 = 0x555555555159
(gdb) PASS: gdb.python/py-value.exp: p/x fp1
python fp1 = gdb.history (0)
(gdb) PASS: gdb.python/py-value.exp: get value fp1 from history
python fp1 = fp1.dereference()
(gdb) PASS: gdb.python/py-value.exp: python fp1 = fp1.dereference()
python result = fp1()
void function called
(gdb) PASS: gdb.python/py-value.exp: python result = fp1()
python print (result)
void
(gdb) PASS: gdb.python/py-value.exp: python print (result)
p/x fp2
$20 = 0x55555555516f
(gdb) PASS: gdb.python/py-value.exp: print fp2 to place it into history
python fp2 = gdb.history (0)
(gdb) PASS: gdb.python/py-value.exp: get value fp2 from history
python fp2 = fp2.dereference()
(gdb) PASS: gdb.python/py-value.exp: python fp2 = fp2.dereference()
python result2 = fp2(10,20)
(gdb) PASS: gdb.python/py-value.exp: python result2 = fp2(10,20)
python print (result2)
30
(gdb) PASS: gdb.python/py-value.exp: python print (result2)
p i
$21 = 2
(gdb) PASS: gdb.python/py-value.exp: p i
python i = gdb.history (0)
(gdb) PASS: gdb.python/py-value.exp: get value i from history
python result3 = i()
Traceback (most recent call last):
  File "<string>", line 1, in <module>
RuntimeError: Value is not callable (not TYPE_CODE_FUNC).
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: python result3 = i()
p/x fp2
$22 = 0x55555555516f
(gdb) PASS: gdb.python/py-value.exp: print fp2 again to place it into history
python fp3 = gdb.history (0)
(gdb) PASS: gdb.python/py-value.exp: get value fp3 from history
python fp3 = fp3.dereference()
(gdb) PASS: gdb.python/py-value.exp: python fp3 = fp3.dereference()
python result2 = fp3(10)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.error: Too few arguments in function call.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: python result2 = fp3(10)
python ptrtype = gdb.lookup_type('PTR')
(gdb) PASS: gdb.python/py-value.exp: create PTR type
kill
Kill the program being debugged? (y or n) y
[Inferior 1 (process 2942418) killed]
(gdb) PASS: gdb.python/py-value.exp: kill the inferior
file
No executable file now.
Discard symbol table from `/home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value'? (y or n) y


Fatal signal: Aborted
----- Backtrace -----
0x5642e034726a gdb_internal_backtrace_1
	/home/simark/src/binutils-gdb/gdb/bt-utils.c:122
0x5642e0347761 _Z22gdb_internal_backtracev
	/home/simark/src/binutils-gdb/gdb/bt-utils.c:168
0x5642e0f57fe6 handle_fatal_signal
	/home/simark/src/binutils-gdb/gdb/event-top.c:946
0x7f7b9903e8df ???
0x7f7b9908e36c ???
0x7f7b9903e837 ???
0x7f7b99028534 ???
0x7f7b9a8dfce3 _ZN11__sanitizer5AbortEv
	/usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:143
0x7f7b9a8ed1c1 _ZN11__sanitizer3DieEv
	/usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_termination.cpp:58
0x7f7b9a8c9c1f _ZN6__asan19ScopedInErrorReportD2Ev
	/usr/src/debug/gcc/libsanitizer/asan/asan_report.cpp:190
0x7f7b9a8c910b _ZN6__asan18ReportGenericErrorEmmmmbmjb
	/usr/src/debug/gcc/libsanitizer/asan/asan_report.cpp:479
0x7f7b9a8ca4ab __asan_report_load8
	/usr/src/debug/gcc/libsanitizer/asan/asan_rtl.cpp:123
0x5642dfcbda0c _ZNK4type16is_objfile_ownedEv
	/home/simark/src/binutils-gdb/gdb/gdbtypes.h:1380
0x5642e10d3849 _Z19copy_type_recursiveP4typeP4htab
	/home/simark/src/binutils-gdb/gdb/gdbtypes.c:5638
0x5642e1c6c55c _ZN12typy_deleterclEP11type_object
	/home/simark/src/binutils-gdb/gdb/python/py-type.c:1132
0x5642e1c6cd1c _ZN8registryI7objfileE3keyI11type_object12typy_deleterE7cleanupEPv
	/home/simark/src/binutils-gdb/gdb/registry.h:159
0x5642e1984978 _ZN8registryI7objfileE14clear_registryEv
	/home/simark/src/binutils-gdb/gdb/registry.h:176
0x5642e1980adb _ZN8registryI7objfileED2Ev
	/home/simark/src/binutils-gdb/gdb/registry.h:78
0x5642e19716b5 _ZN7objfileD2Ev
	/home/simark/src/binutils-gdb/gdb/objfiles.c:590
0x5642e1984dc8 _ZNKSt14default_deleteI7objfileEclEPS0_
	/usr/include/c++/12.1.0/bits/unique_ptr.h:95
0x5642e1980e98 _ZNSt10unique_ptrI7objfileSt14default_deleteIS0_EED2Ev
	/usr/include/c++/12.1.0/bits/unique_ptr.h:396
0x5642e1ac6172 _ZNSt15__new_allocatorINSt9__cxx199810_List_nodeISt10unique_ptrI7objfileSt14default_deleteIS3_EEEEE7destroyIS6_EEvPT_
	/usr/include/c++/12.1.0/bits/new_allocator.h:181
0x5642e1abb2f2 _ZNSt16allocator_traitsISaINSt9__cxx199810_List_nodeISt10unique_ptrI7objfileSt14default_deleteIS3_EEEEEE7destroyIS6_EEvRS8_PT_
	/usr/include/c++/12.1.0/bits/alloc_traits.h:535
0x5642e1acb5a6 _ZNSt9__cxx19987__cxx114listISt10unique_ptrI7objfileSt14default_deleteIS3_EESaIS6_EE8_M_eraseENS_14_List_iteratorIS6_EE
	/usr/include/c++/12.1.0/bits/stl_list.h:2019
0x5642e1ac0b7d _ZNSt9__cxx19987__cxx114listISt10unique_ptrI7objfileSt14default_deleteIS3_EESaIS6_EE5eraseENS_20_List_const_iteratorIS6_EE
	/usr/include/c++/12.1.0/bits/list.tcc:158
0x5642e1ab54b1 _ZNSt7__debug4listISt10unique_ptrI7objfileSt14default_deleteIS2_EESaIS5_EE8_M_eraseENSt9__cxx199820_List_const_iteratorIS5_EE
	/usr/include/c++/12.1.0/debug/list:521
0x5642e1aaef44 _ZNSt7__debug4listISt10unique_ptrI7objfileSt14default_deleteIS2_EESaIS5_EE5eraseEN11__gnu_debug14_Safe_iteratorINSt9__cxx199820_List_const_iteratorIS5_EES7_St26bidirectional_iterator_tagEE
	/usr/include/c++/12.1.0/debug/list:533
0x5642e1aa44dd _ZN13program_space14remove_objfileEP7objfile
	/home/simark/src/binutils-gdb/gdb/progspace.c:175
0x5642e19702be _ZN7objfile6unlinkEv
	/home/simark/src/binutils-gdb/gdb/objfiles.c:478
0x5642e1aa3228 _ZN13program_space17free_all_objfilesEv
	/home/simark/src/binutils-gdb/gdb/progspace.c:135
0x5642e2180a39 _Z17symbol_file_cleari
	/home/simark/src/binutils-gdb/gdb/symfile.c:1232
0x5642e218354d _Z19symbol_file_commandPKci
	/home/simark/src/binutils-gdb/gdb/symfile.c:1598
0x5642e0f66532 file_command
	/home/simark/src/binutils-gdb/gdb/exec.c:555
0x5642e058fdd0 do_simple_func
	/home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:95
0x5642e05a577b _Z8cmd_funcP16cmd_list_elementPKci
	/home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:2516
0x5642e24f75ca _Z15execute_commandPKci
	/home/simark/src/binutils-gdb/gdb/top.c:699
0x5642e0f565a9 _Z15command_handlerPKc
	/home/simark/src/binutils-gdb/gdb/event-top.c:598
0x5642e0f573b1 _Z20command_line_handlerOSt10unique_ptrIcN3gdb13xfree_deleterIcEEE
	/home/simark/src/binutils-gdb/gdb/event-top.c:842
0x5642e26432e6 tui_command_line_handler
	/home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:104
0x5642e0f5459e gdb_rl_callback_handler
	/home/simark/src/binutils-gdb/gdb/event-top.c:230
0x7f7b9b00a9df ???
0x5642e0f53fa9 gdb_rl_callback_read_char_wrapper_noexcept
	/home/simark/src/binutils-gdb/gdb/event-top.c:188
0x5642e0f541ec gdb_rl_callback_read_char_wrapper
	/home/simark/src/binutils-gdb/gdb/event-top.c:205
0x5642e0f55b77 _Z19stdin_event_handleriPv
	/home/simark/src/binutils-gdb/gdb/event-top.c:525
0x5642e2db4e3b handle_file_event
	/home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:549
0x5642e2db5777 gdb_wait_for_event
	/home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:670
0x5642e2db3531 _Z16gdb_do_one_eventv
	/home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:235
0x5642e167a714 start_event_loop
	/home/simark/src/binutils-gdb/gdb/main.c:411
0x5642e167ab6e captured_command_loop
	/home/simark/src/binutils-gdb/gdb/main.c:471
0x5642e1680000 captured_main
	/home/simark/src/binutils-gdb/gdb/main.c:1329
0x5642e16800dd _Z8gdb_mainP18captured_main_args
	/home/simark/src/binutils-gdb/gdb/main.c:1344
0x5642dfc93c9d main
	/home/simark/src/binutils-gdb/gdb/gdb.c:32
---------------------
A fatal error internal to GDB has been detected, further
debugging is not possible.  GDB will now terminate.

This is a bug, please report it.  For instructions, see:
<https://www.gnu.org/software/gdb/bugs/>.

ERROR: GDB process no longer exists
GDB process exited with wait status 2942381 exp9 0 0 CHILDKILLED SIGABRT SIGABRT
UNRESOLVED: gdb.python/py-value.exp: discard the symbols
ERROR: Couldn't send python castval = arg0.cast(ptrtype.pointer()) to GDB.
ERROR: can not find channel named "exp9"
    while executing
"expect {
-i exp9 -timeout 10 
	-re ".*A problem internal to GDB has been detected" {
	    fail "$message (GDB internal error)"
	    gdb_internal_error..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" TCL LOOKUP CHANNEL exp9 can not find channel named "exp9"
ERROR: Couldn't send python ptrtype = None to GDB.
ERROR: can not find channel named "exp9"
    while executing
"expect {
-i exp9 -timeout 10 
	-re ".*A problem internal to GDB has been detected" {
	    fail "$message (GDB internal error)"
	    gdb_internal_error..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" TCL LOOKUP CHANNEL exp9 can not find channel named "exp9"
ERROR: Couldn't send python print (castval.type) to GDB.
ERROR: can not find channel named "exp9"
    while executing
"expect {
-i exp9 -timeout 10 
	-re ".*A problem internal to GDB has been detected" {
	    fail "$message (GDB internal error)"
	    gdb_internal_error..."
    ("uplevel" body line 1)
    invoked from within
"uplevel $body" TCL LOOKUP CHANNEL exp9 can not find channel named "exp9"
builtin_spawn /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../../gdb/gdb -nw -nx -iex set height 0 -iex set width 0 -data-directory /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../data-directory
warning: Found custom handler for signal 7 (Bus error) preinstalled.
warning: Found custom handler for signal 8 (Floating point exception) preinstalled.
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 13.0.50.20220728-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) set height 0
(gdb) set width 0
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
(gdb) dir /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python
Source directories searched: /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python:$cdir:$cwd
(gdb) kill
The program is not being run.
(gdb) file /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value
Reading symbols from /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value...
(gdb) delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break -qualified main
Breakpoint 1 at 0x119b: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c, line 88.
(gdb) run 
Starting program: /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/../lib/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffd268) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c:88
88	  PTR x = &s;
(gdb) break 124
Breakpoint 2 at 0x5555555552b7: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c, line 124.
(gdb) continue
Continuing.
void function called

Breakpoint 2, main (argc=1, argv=0x7fffffffd268) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c:124
124	  save_argv = argv;      /* break to inspect struct and union */
(gdb) PASS: gdb.python/py-value.exp: continue to breakpoint: break to inspect struct and union for subscript regression test
python intv = gdb.Value(1)
(gdb) PASS: gdb.python/py-value.exp: Create value intv for subscript test
python stringv = gdb.Value("foo")
(gdb) PASS: gdb.python/py-value.exp: Create value stringv for subscript test
python print (intv)
1
(gdb) PASS: gdb.python/py-value.exp: baseline print of an int Python value
python print (intv[0])
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.error: Cannot subscript requested type.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: Attempt to access an integer with a subscript
python print (stringv)
"foo"
(gdb) PASS: gdb.python/py-value.exp: baseline print of a string Python value
python print (stringv[0])
102 'f'
(gdb) PASS: gdb.python/py-value.exp: attempt to access a string with a subscript
print p
$1 = (int *) 0x7fffffffd0c4
(gdb) PASS: gdb.python/py-value.exp: Build pointer to array
python pointer = gdb.history(0)
(gdb) python print (pointer[0])
1
(gdb) PASS: gdb.python/py-value.exp: access array via pointer with int subscript
python print (pointer[intv])
2
(gdb) PASS: gdb.python/py-value.exp: access array via pointer with value subscript
python print (pointer[intv][0])
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.error: Cannot subscript requested type.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: Attempt to access a single dimension array with a two subscripts
print {"fu ","foo","bar"}
$2 = {"fu ", "foo", "bar"}
(gdb) PASS: gdb.python/py-value.exp: Build array
python marray = gdb.history(0)
(gdb) python print (marray[1][2])
111 'o'
(gdb) PASS: gdb.python/py-value.exp: test multiple subscript
Executing on host: g++  -fno-stack-protector   -fdiagnostics-color=never  -c -g -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value-cxx.o /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c    (timeout = 300)
builtin_spawn -ignore SIGHUP g++ -fno-stack-protector -fdiagnostics-color=never -c -g -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value-cxx.o /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c
Executing on host: g++  -fno-stack-protector /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value-cxx.o   -fdiagnostics-color=never   -L/home/simark/build/binutils-gdb-one-target/libiberty  -g  -lm  -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value-cxx    (timeout = 300)
builtin_spawn -ignore SIGHUP g++ -fno-stack-protector /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value-cxx.o -fdiagnostics-color=never -L/home/simark/build/binutils-gdb-one-target/libiberty -g -lm -o /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value-cxx
builtin_spawn /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../../gdb/gdb -nw -nx -iex set height 0 -iex set width 0 -data-directory /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../data-directory
warning: Found custom handler for signal 7 (Bus error) preinstalled.
warning: Found custom handler for signal 8 (Floating point exception) preinstalled.
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 13.0.50.20220728-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) set height 0
(gdb) set width 0
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
(gdb) dir /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python
Source directories searched: /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python:$cdir:$cwd
(gdb) kill
The program is not being run.
(gdb) file /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value-cxx
Reading symbols from /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value-cxx...
(gdb) delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break -qualified main
Breakpoint 1 at 0x11b6: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c, line 88.
(gdb) run 
Starting program: /home/simark/build/binutils-gdb-one-target/gdb/testsuite/outputs/gdb.python/py-value/py-value-cxx 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/../lib/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffd258) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c:88
88	  PTR x = &s;
(gdb) break 66
Breakpoint 2 at 0x555555555171: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c, line 66.
(gdb) continue
Continuing.
void function called

Breakpoint 2, ptr_ref (rptr_int=@0x7fffffffd0a8: 0x7fffffffd0b0) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c:66
66	  return; /* break to inspect pointer by reference. */
(gdb) PASS: gdb.python/py-value.exp: c++: continue to breakpoint: break to inspect pointer by reference
print rptr_int
$1 = (int *&) @0x7fffffffd0a8: 0x7fffffffd0b0
(gdb) PASS: gdb.python/py-value.exp: c++: Obtain address
python rptr = gdb.history(0)
(gdb) PASS: gdb.python/py-value.exp: c++: Obtains value from GDB
python print (rptr[0])
2
(gdb) PASS: gdb.python/py-value.exp: c++: check pointer passed as reference
python print (bool(gdb.parse_and_eval('base').dynamic_cast(gdb.lookup_type('Derived').pointer())))
True
(gdb) PASS: gdb.python/py-value.exp: c++: python print (bool(gdb.parse_and_eval('base').dynamic_cast(gdb.lookup_type('Derived').pointer())))
python print (gdb.parse_and_eval('base').dynamic_type)
Derived *
(gdb) PASS: gdb.python/py-value.exp: c++: python print (gdb.parse_and_eval('base').dynamic_type)
python print (gdb.parse_and_eval('base_ref').dynamic_type)
Derived &
(gdb) PASS: gdb.python/py-value.exp: c++: python print (gdb.parse_and_eval('base_ref').dynamic_type)
python print (gdb.parse_and_eval('5').dynamic_type)
int
(gdb) PASS: gdb.python/py-value.exp: c++: python print (gdb.parse_and_eval('5').dynamic_type)
break 124
Breakpoint 3 at 0x5555555552e4: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c, line 124.
(gdb) continue
Continuing.

Breakpoint 3, main (argc=1, argv=0x7fffffffd258) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.c:124
124	  save_argv = argv;      /* break to inspect struct and union */
(gdb) PASS: gdb.python/py-value.exp: c++: continue to breakpoint: break to inspect struct and union for subscript regression test
python intv = gdb.Value(1)
(gdb) PASS: gdb.python/py-value.exp: c++: Create value intv for subscript test
python stringv = gdb.Value("foo")
(gdb) PASS: gdb.python/py-value.exp: c++: Create value stringv for subscript test
python print (intv)
1
(gdb) PASS: gdb.python/py-value.exp: c++: baseline print of an int Python value
python print (intv[0])
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.error: Cannot subscript requested type.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: c++: Attempt to access an integer with a subscript
python print (stringv)
"foo"
(gdb) PASS: gdb.python/py-value.exp: c++: baseline print of a string Python value
python print (stringv[0])
102 'f'
(gdb) PASS: gdb.python/py-value.exp: c++: attempt to access a string with a subscript
print p
$2 = (int *) 0x7fffffffd0b4
(gdb) PASS: gdb.python/py-value.exp: c++: Build pointer to array
python pointer = gdb.history(0)
(gdb) python print (pointer[0])
1
(gdb) PASS: gdb.python/py-value.exp: c++: access array via pointer with int subscript
python print (pointer[intv])
2
(gdb) PASS: gdb.python/py-value.exp: c++: access array via pointer with value subscript
python print (pointer[intv][0])
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.error: Cannot subscript requested type.
Error while executing Python code.
(gdb) PASS: gdb.python/py-value.exp: c++: Attempt to access a single dimension array with a two subscripts
print {"fu ","foo","bar"}
$3 = {"fu ", "foo", "bar"}
(gdb) PASS: gdb.python/py-value.exp: c++: Build array
python marray = gdb.history(0)
(gdb) python print (marray[1][2])
111 'o'
(gdb) PASS: gdb.python/py-value.exp: c++: test multiple subscript
testcase /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-value.exp completed in 4 seconds

		=== gdb Summary ===

# of expected passes		394
# of unresolved testcases	4
# of paths in test names	1
Executing on host: /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../../gdb/gdb -nw -nx -iex "set height 0" -iex "set width 0" -data-directory /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../data-directory --version    (timeout = 300)
builtin_spawn -ignore SIGHUP /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../../gdb/gdb -nw -nx -iex set height 0 -iex set width 0 -data-directory /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../data-directory --version
warning: Found custom handler for signal 7 (Bus error) preinstalled.
warning: Found custom handler for signal 8 (Floating point exception) preinstalled.
warning: Found custom handler for signal 11 (Segmentation fault) preinstalled.
Some signal dispositions inherited from the environment (SIG_DFL/SIG_IGN)
won't be propagated to spawned programs.
GNU gdb (GDB) 13.0.50.20220728-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
/home/simark/build/binutils-gdb-one-target/gdb/gdb version  11 -nw -nx -iex "set height 0" -iex "set width 0" -data-directory /home/simark/build/binutils-gdb-one-target/gdb/testsuite/../data-directory 

ERROR: -------------------------------------------
ERROR: in testcase /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp
ERROR:  can not find channel named "exp9"
ERROR:  tcl error code TCL LOOKUP CHANNEL exp9
ERROR:  tcl error info:
can not find channel named "exp9"
    while executing
"wait -i $gdb_spawn_id"
    ("uplevel" body line 4)
    invoked from within
"uplevel $error_sect"
    invoked from within
"remote_expect host 30 {
	-re "$break_message \[0-9\]* at .*: file .*, line $decimal.\r\n$gdb_prompt $" {}
	-re "$break_message \[0-9\]*: file .*, line..."
    ("uplevel" body line 1)
    invoked from within
"uplevel remote_expect host $tmt $expcode"
    invoked from within
"gdb_expect 30 {
	-re "$break_message \[0-9\]* at .*: file .*, line $decimal.\r\n$gdb_prompt $" {}
	-re "$break_message \[0-9\]*: file .*, line $decima..."
    (procedure "gdb_breakpoint" line 36)
    invoked from within
"gdb_breakpoint $linespec qualified"
    ("eval" body line 1)
    invoked from within
"eval gdb_breakpoint {$linespec} $args"
    (procedure "runto" line 25)
    invoked from within
"runto main qualified"
    (procedure "runto_main" line 2)
    invoked from within
"runto_main "
    (procedure "test_template_arg" line 8)
    invoked from within
"test_template_arg "${binfile}-cir" "const int &""
    (file "/home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp" line 67)
    invoked from within
"source /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp"
    ("uplevel" body line 1)
    invoked from within
"uplevel #0 source /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-template.exp"
    invoked from within
"catch "uplevel #0 source $test_file_name" msg"
--------------------------------------------------
runtest completed at Thu Jul 28 22:30:34 2022

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

* Re: [PATCH 0/6] Rewrite registry.h
  2022-07-29  2:33   ` Simon Marchi via Gdb-patches
@ 2022-08-02  2:46     ` Tom Tromey
  0 siblings, 0 replies; 13+ messages in thread
From: Tom Tromey @ 2022-08-02  2:46 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tom Tromey, gdb-patches

Simon> I see these failures following this series:
Simon> UNRESOLVED: gdb.guile/scm-value.exp: discard the symbols
Simon> UNRESOLVED: gdb.python/py-template.exp: gdb_breakpoint: set breakpoint at main (eof)
Simon> UNRESOLVED: gdb.python/py-value.exp: discard the symbols

Sorry about this.  I reproduced this today & will come up with a fix soon.

Tom

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

end of thread, other threads:[~2022-08-02  2:46 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-30 17:59 [PATCH 0/6] Rewrite registry.h Tom Tromey
2022-05-30 17:59 ` [PATCH 1/6] Change address_space to use new and delete Tom Tromey
2022-05-30 17:59 ` [PATCH 2/6] Change allocation of type-copying hash table Tom Tromey
2022-05-30 17:59 ` [PATCH 3/6] Remove some unused functions from guile code Tom Tromey
2022-05-30 17:59 ` [PATCH 4/6] Rewrite registry.h Tom Tromey
2022-06-07 10:55   ` Lancelot SIX via Gdb-patches
2022-06-08  1:33     ` Tom Tromey
2022-06-08 18:51       ` Tom Tromey
2022-05-30 17:59 ` [PATCH 5/6] Change registry to use less memory Tom Tromey
2022-05-30 17:59 ` [PATCH 6/6] Remove some unneeded checks in Guile code Tom Tromey
2022-07-28 20:13 ` [PATCH 0/6] Rewrite registry.h Tom Tromey
2022-07-29  2:33   ` Simon Marchi via Gdb-patches
2022-08-02  2:46     ` Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox