gdb: remove the silent parameter from exit_inferior_1 and cleanup
[binutils-gdb.git] / gdb / gdbarch-selftests.c
index 73a31244b452275b781ba63c139c55161cb7396e..cc9604b9bf7e1b0b39c4753e11c999945163967a 100644 (file)
@@ -1,6 +1,6 @@
 /* Self tests for gdbarch for GDB, the GNU debugger.
 
-   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+   Copyright (C) 2017-2023 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-#if GDB_SELF_TEST
-#include "selftest.h"
+#include "gdbsupport/selftest.h"
 #include "selftest-arch.h"
-#include "inferior.h"
-#include "gdbthread.h"
 #include "target.h"
+#include "test-target.h"
 #include "target-float.h"
-#include "common/def-vector.h"
+#include "gdbsupport/def-vector.h"
+#include "gdbarch.h"
+#include "scoped-mock-context.h"
+
+#include <map>
 
 namespace selftests {
 
@@ -69,55 +71,10 @@ register_to_value_test (struct gdbarch *gdbarch)
       builtin->builtin_char32,
     };
 
-  /* Error out if debugging something, because we're going to push the
-     test target, which would pop any existing target.  */
-  if (current_top_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);
+  scoped_mock_context<test_target_ops> mockctx (gdbarch);
 
-  struct frame_info *frame = get_current_frame ();
-  const int num_regs = (gdbarch_num_regs (gdbarch)
-                       + gdbarch_num_pseudo_regs (gdbarch));
+  frame_info_ptr frame = get_current_frame ();
+  const int num_regs = gdbarch_num_cooked_regs (gdbarch);
 
   /* Test gdbarch methods register_to_value and value_to_register with
      different combinations of register numbers and types.  */
@@ -127,9 +84,9 @@ register_to_value_test (struct gdbarch *gdbarch)
        {
          if (gdbarch_convert_register_p (gdbarch, regnum, type))
            {
-             std::vector<gdb_byte> expected (TYPE_LENGTH (type), 0);
+             std::vector<gdb_byte> expected (type->length (), 0);
 
-             if (TYPE_CODE (type) == TYPE_CODE_FLT)
+             if (type->code () == TYPE_CODE_FLT)
                {
                  /* Generate valid float format.  */
                  target_float_from_string (expected.data (), type, "1.25");
@@ -144,12 +101,12 @@ register_to_value_test (struct gdbarch *gdbarch)
                                         expected.data ());
 
              /* Allocate two bytes more for overflow check.  */
-             std::vector<gdb_byte> buf (TYPE_LENGTH (type) + 2, 0);
+             std::vector<gdb_byte> buf (type->length () + 2, 0);
              int optim, unavail, ok;
 
              /* Set the fingerprint in the last two bytes.  */
-             buf [TYPE_LENGTH (type)]= 'w';
-             buf [TYPE_LENGTH (type) + 1]= 'l';
+             buf [type->length ()]= 'w';
+             buf [type->length () + 1]= 'l';
              ok = gdbarch_register_to_value (gdbarch, frame, regnum, type,
                                              buf.data (), &optim, &unavail);
 
@@ -157,24 +114,66 @@ register_to_value_test (struct gdbarch *gdbarch)
              SELF_CHECK (!optim);
              SELF_CHECK (!unavail);
 
-             SELF_CHECK (buf[TYPE_LENGTH (type)] == 'w');
-             SELF_CHECK (buf[TYPE_LENGTH (type) + 1] == 'l');
+             SELF_CHECK (buf[type->length ()] == 'w');
+             SELF_CHECK (buf[type->length () + 1] == 'l');
 
-             for (auto k = 0; k < TYPE_LENGTH(type); k++)
+             for (auto k = 0; k < type->length (); k++)
                SELF_CHECK (buf[k] == expected[k]);
            }
        }
     }
 }
 
+/* Test function gdbarch_register_name.  */
+
+static void
+register_name_test (struct gdbarch *gdbarch)
+{
+  scoped_mock_context<test_target_ops> mockctx (gdbarch);
+
+  /* Track the number of times each register name appears.  */
+  std::map<const std::string, int> name_counts;
+
+  const int num_regs = gdbarch_num_cooked_regs (gdbarch);
+  for (auto regnum = 0; regnum < num_regs; regnum++)
+    {
+      /* If a register is to be hidden from the user then we should get
+        back an empty string, not nullptr.  Every other register should
+        return a non-empty string.  */
+      const char *name = gdbarch_register_name (gdbarch, regnum);
+
+      if (run_verbose() && name == nullptr)
+       debug_printf ("arch: %s, register: %d returned nullptr\n",
+                     gdbarch_bfd_arch_info (gdbarch)->printable_name,
+                     regnum);
+      SELF_CHECK (name != nullptr);
+
+      /* Every register name, that is not the empty string, should be
+        unique.  If this is not the case then the user will see duplicate
+        copies of the register in e.g. 'info registers' output, but will
+        only be able to interact with one of the copies.  */
+      if (*name != '\0')
+       {
+         std::string s (name);
+         name_counts[s]++;
+         if (run_verbose() && name_counts[s] > 1)
+           debug_printf ("arch: %s, register: %d (%s) is a duplicate\n",
+                         gdbarch_bfd_arch_info (gdbarch)->printable_name,
+                         regnum, name);
+         SELF_CHECK (name_counts[s] == 1);
+       }
+    }
+}
+
 } // namespace selftests
-#endif /* GDB_SELF_TEST */
 
+void _initialize_gdbarch_selftests ();
 void
-_initialize_gdbarch_selftests (void)
+_initialize_gdbarch_selftests ()
 {
-#if GDB_SELF_TEST
   selftests::register_test_foreach_arch ("register_to_value",
                                         selftests::register_to_value_test);
-#endif
+
+  selftests::register_test_foreach_arch ("register_name",
+                                        selftests::register_name_test);
 }