diff --git a/gdb/frame.c b/gdb/frame.c
index a74deef..afdc157 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1716,23 +1716,6 @@ select_frame (struct frame_info *fi)
     }
 }
 
-#if GDB_SELF_TEST
-struct frame_info *
-create_test_frame (struct regcache *regcache)
-{
-  struct frame_info *this_frame = XCNEW (struct frame_info);
-
-  sentinel_frame = create_sentinel_frame (NULL, regcache);
-  sentinel_frame->prev = this_frame;
-  sentinel_frame->prev_p = 1;;
-  this_frame->prev_arch.p = 1;
-  this_frame->prev_arch.arch = get_regcache_arch (regcache);
-  this_frame->next = sentinel_frame;
-
-  return this_frame;
-}
-#endif
-
 /* Create an arbitrary (i.e. address specified by user) or innermost frame.
    Always returns a non-NULL value.  */
 
diff --git a/gdb/frame.h b/gdb/frame.h
index 0249857..1b72610 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -833,14 +833,6 @@ extern struct frame_info *deprecated_safe_get_selected_frame (void);
 
 extern struct frame_info *create_new_frame (CORE_ADDR base, CORE_ADDR pc);
 
-#if GDB_SELF_TEST
-
-/* Create a frame for unit test.  Its next frame is sentinel frame,
-   created from REGCACHE.  */
-
-extern struct frame_info *create_test_frame (struct regcache *regcache);
-#endif
-
 /* Return true if the frame unwinder for frame FI is UNWINDER; false
    otherwise.  */
 
diff --git a/gdb/gdbarch-selftests.c b/gdb/gdbarch-selftests.c
index f0b8d5d..58ed112 100644
--- a/gdb/gdbarch-selftests.c
+++ b/gdb/gdbarch-selftests.c
@@ -22,25 +22,57 @@
 #include "selftest.h"
 #include "selftest-arch.h"
 #include "inferior.h"
+#include "gdbthread.h"
+#include "target.h"
 
 namespace selftests {
 
-/* A read-write regcache which doesn't write the target.  */
+/* A mock process_stratum target_ops that doesn't read/write registers
+   anywhere.  */
 
-class regcache_test : public regcache
+static int
+test_target_has_registers (target_ops *self)
 {
-public:
-  explicit regcache_test (struct gdbarch *gdbarch)
-    : regcache (gdbarch, NULL, false)
-  {
-    set_ptid (inferior_ptid);
+  return 1;
+}
 
-    current_regcache.push_front (this);
-  }
+static int
+test_target_has_stack (target_ops *self)
+{
+  return 1;
+}
+
+static int
+test_target_has_memory (target_ops *self)
+{
+  return 1;
+}
+
+static void
+test_target_prepare_to_store (target_ops *self, regcache *regs)
+{
+}
+
+static void
+test_target_store_registers (target_ops *self, regcache *regs, int regno)
+{
+}
 
-  void raw_write (int regnum, const gdb_byte *buf) override
+class test_target_ops : public target_ops
+{
+public:
+  test_target_ops ()
+    : target_ops {}
   {
-    raw_set_cached_value (regnum, buf);
+    to_magic = OPS_MAGIC;
+    to_stratum = process_stratum;
+    to_has_memory = test_target_has_memory;
+    to_has_stack = test_target_has_stack;
+    to_has_registers = test_target_has_registers;
+    to_prepare_to_store = test_target_prepare_to_store;
+    to_store_registers = test_target_store_registers;
+
+    complete_target_initialization (this);
   }
 };
 
@@ -84,15 +116,56 @@ register_to_value_test (struct gdbarch *gdbarch)
       builtin->builtin_char32,
     };
 
-  current_inferior()->gdbarch = gdbarch;
+  /* Error out if debugging something, because we're going to push the
+     test target, which would pop any existing target.  */
+  if (current_target.to_stratum >= process_stratum)
+    error (_("target already pushed"));
+
+  /* Create a mock environment.  An inferior with a thread, with a
+     process_stratum target pushed.  */
+
+  test_target_ops mock_target;
+  ptid_t mock_ptid (1, 1);
+  inferior mock_inferior (mock_ptid.pid ());
+  address_space mock_aspace {};
+  mock_inferior.gdbarch = gdbarch;
+  mock_inferior.aspace = &mock_aspace;
+  thread_info mock_thread (&mock_inferior, mock_ptid);
+
+  scoped_restore restore_thread_list
+    = make_scoped_restore (&thread_list, &mock_thread);
+
+  /* Add the mock inferior to the inferior list so that look ups by
+     target+ptid can find it.  */
+  scoped_restore restore_inferior_list
+    = make_scoped_restore (&inferior_list);
+  inferior_list = &mock_inferior;
+
+  /* Switch to the mock inferior.  */
+  scoped_restore_current_inferior restore_current_inferior;
+  set_current_inferior (&mock_inferior);
+
+  /* Push the process_stratum target so we can mock accessing
+     registers.  */
+  push_target (&mock_target);
+
+  /* Pop it again on exit (return/exception).  */
+  struct on_exit
+  {
+    ~on_exit ()
+    {
+      pop_all_targets_at_and_above (process_stratum);
+    }
+  } pop_targets;
+
+  /* Switch to the mock thread.  */
+  scoped_restore restore_inferior_ptid
+    = make_scoped_restore (&inferior_ptid, mock_ptid);
 
-  struct regcache *regcache = new regcache_test (gdbarch);
-  struct frame_info *frame = create_test_frame (regcache);
+  struct frame_info *frame = get_current_frame ();
   const int num_regs = (gdbarch_num_regs (gdbarch)
 			+ gdbarch_num_pseudo_regs (gdbarch));
 
-  SELF_CHECK (regcache == get_current_regcache ());
-
   /* Test gdbarch methods register_to_value and value_to_register with
      different combinations of register numbers and types.  */
   for (const auto &type : types)
diff --git a/gdb/progspace.c b/gdb/progspace.c
index 41e8cd0..ea328c8 100644
--- a/gdb/progspace.c
+++ b/gdb/progspace.c
@@ -44,18 +44,6 @@ static int highest_address_space_num;
 
 DEFINE_REGISTRY (program_space, REGISTRY_ACCESS_FIELD)
 
-/* An address space.  It is used for comparing if pspaces/inferior/threads
-   see the same address space and for associating caches to each address
-   space.  */
-
-struct address_space
-{
-  int num;
-
-  /* Per aspace data-pointers required by other GDB modules.  */
-  REGISTRY_FIELDS;
-};
-
 /* Keep a registry of per-address_space data-pointers required by other GDB
    modules.  */
 
diff --git a/gdb/progspace.h b/gdb/progspace.h
index f679fe3..85c99a62 100644
--- a/gdb/progspace.h
+++ b/gdb/progspace.h
@@ -210,6 +210,17 @@ struct program_space
     REGISTRY_FIELDS;
   };
 
+/* An address space.  It is used for comparing if
+   pspaces/inferior/threads see the same address space and for
+   associating caches to each address space.  */
+struct address_space
+{
+  int num;
+
+  /* Per aspace data-pointers required by other GDB modules.  */
+  REGISTRY_FIELDS;
+};
+
 /* The object file that the main symbol table was loaded from (e.g. the
    argument to the "symbol-file" or "file" command).  */
 
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 3ecdb3b..6f42fb93 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -252,11 +252,6 @@ public:
 
   DISABLE_COPY_AND_ASSIGN (regcache);
 
-  /* class regcache is only extended in unit test, so only mark it
-     virtual when selftest is enabled.  */
-#if GDB_SELF_TEST
-  virtual
-#endif
   ~regcache ()
   {
     xfree (m_registers);
@@ -277,11 +272,6 @@ public:
 
   enum register_status raw_read (int regnum, gdb_byte *buf);
 
-  /* class regcache is only extended in unit test, so only mark it
-     virtual when selftest is enabled.  */
-#if GDB_SELF_TEST
-  virtual
-#endif
   void raw_write (int regnum, const gdb_byte *buf);
 
   template<typename T, typename = RequireLongest<T>>
