[v3,gdb/testsuite] Add selftest disassemble-s390x

Message ID 20250409094718.27893-1-tdevries@suse.de
State New
Headers
Series [v3,gdb/testsuite] Add selftest disassemble-s390x |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed

Commit Message

Tom de Vries April 9, 2025, 9:47 a.m. UTC
  In commit a98a6fa2d8e ("s390: Add arch15 instructions"), support for
new instructions was added to libopcodes, but the added tests only exercise
this for gas.

Add a unit test disassemble-s390x that checks gdb's ability to
disassemble one of these instructions:
...
$ gdb -q -batch -ex "maint selftest -v disassemble-s390x"
Running selftest disassemble-s390x.
0xb9 0x68 0x00 0x03 -> clzg	%r0,%r3
Ran 1 unit tests, 0 failed
...

Tested on x86_64-linux and s390x-linux.
---
 gdb/disasm-selftests.c | 87 ++++++++++++++++++++++++++++++++++++++++++
 gdb/disasm-selftests.h | 32 ++++++++++++++++
 gdb/s390-tdep.c        | 52 +++++++++++++++++++++++++
 3 files changed, 171 insertions(+)
 create mode 100644 gdb/disasm-selftests.h


base-commit: 981fe5fd80faf511aa265e841a380c9b46be30e6
  

Patch

diff --git a/gdb/disasm-selftests.c b/gdb/disasm-selftests.c
index ffd25bdff93..3ccc1747982 100644
--- a/gdb/disasm-selftests.c
+++ b/gdb/disasm-selftests.c
@@ -21,6 +21,7 @@ 
 #include "gdbsupport/selftest.h"
 #include "selftest-arch.h"
 #include "gdbarch.h"
+#include "disasm-selftests.h"
 
 namespace selftests {
 
@@ -329,6 +330,92 @@  memory_error_test (struct gdbarch *gdbarch)
   SELF_CHECK (saw_memory_error);
 }
 
+/* Disassemble INSN (a GDBARCH insn), and return the result.  */
+
+static std::string
+disassemble_one_insn_to_string (struct gdbarch *gdbarch,
+				gdb::array_view<const gdb_byte> insn)
+{
+  string_file buffer;
+
+  class gdb_disassembler_test : public gdb_disassembler
+  {
+  public:
+
+    explicit gdb_disassembler_test (struct gdbarch *gdbarch,
+				    gdb::array_view<const gdb_byte> insn,
+				    string_file &buffer)
+      : gdb_disassembler (gdbarch,
+			  &buffer,
+			  gdb_disassembler_test::read_memory),
+	m_insn (insn)
+    {
+    }
+
+    int
+    print_insn (CORE_ADDR memaddr)
+    {
+      try
+	{
+	  return gdb_disassembler::print_insn (memaddr);
+	}
+      catch (const gdb_exception_error &)
+	{
+	  return -1;
+	}
+    }
+
+  private:
+    gdb::array_view<const gdb_byte> m_insn;
+
+    static int read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+			    unsigned int len,
+			    struct disassemble_info *info) noexcept
+    {
+      gdb_disassembler_test *self
+	= static_cast<gdb_disassembler_test *>(info->application_data);
+
+      if (len > self->m_insn.size ())
+	return -1;
+
+      for (size_t i = 0; i < len; i++)
+	myaddr[i] = self->m_insn[i];
+
+      return 0;
+    }
+  };
+
+  gdb_disassembler_test di (gdbarch, insn, buffer);
+  if (di.print_insn (0) != insn.size ())
+    return "";
+
+  return buffer.string ();
+}
+
+/* See disasm-selftests.h.  */
+
+void
+disassemble_insn (gdbarch *gdbarch, gdb::byte_vector &insn,
+		  const std::string &expected)
+{
+  std::string buffer
+    = disassemble_one_insn_to_string (gdbarch, insn);
+
+  bool check_ok = buffer == expected;
+
+  if (run_verbose () || !check_ok)
+    {
+      for (gdb_byte b : insn)
+	debug_printf ("0x%02x ", b);
+      debug_printf ("-> %s\n", buffer.c_str ());
+    }
+
+  if (!check_ok)
+    debug_printf ("expected: %s\n", expected.c_str ());
+
+  SELF_CHECK (check_ok);
+}
+
 } /* namespace selftests */
 
 void _initialize_disasm_selftests ();
diff --git a/gdb/disasm-selftests.h b/gdb/disasm-selftests.h
new file mode 100644
index 00000000000..29acf876cce
--- /dev/null
+++ b/gdb/disasm-selftests.h
@@ -0,0 +1,32 @@ 
+/* Copyright (C) 2025 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/>.  */
+
+#ifndef GDB_DISASM_SELFTESTS_H
+#define GDB_DISASM_SELFTESTS_H
+
+namespace selftests
+{
+
+/* Check that disassembly of INSN (a GDBARCH insn) matches EXPECTED.  */
+
+void
+disassemble_insn (gdbarch *gdbarch, gdb::byte_vector &insn,
+		  const std::string &expected);
+
+}
+
+#endif /* GDB_DISASM_SELFTESTS_H */
diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
index d030a4d0323..a3b7658ceed 100644
--- a/gdb/s390-tdep.c
+++ b/gdb/s390-tdep.c
@@ -41,6 +41,8 @@ 
 #include "value.h"
 #include "inferior.h"
 #include "dwarf2/loc.h"
+#include "gdbsupport/selftest.h"
+#include "gdb/disasm-selftests.h"
 
 #include "features/s390-linux32.c"
 #include "features/s390x-linux64.c"
@@ -7468,6 +7470,51 @@  s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   return gdbarch;
 }
 
+#if GDB_SELF_TEST
+namespace selftests {
+
+/* Return bfd_arch_info representing s390x.  */
+
+static const bfd_arch_info *
+bfd_arch_info_s390x ()
+{
+  return bfd_lookup_arch (bfd_arch_s390, bfd_mach_s390_64);
+}
+
+/* Return gdbarch representing s390x.  */
+
+static gdbarch *
+gdbarch_s390x ()
+{
+  struct gdbarch_info info;
+  info.bfd_arch_info = bfd_arch_info_s390x ();
+  if (info.bfd_arch_info == nullptr)
+    return nullptr;
+
+  info.osabi = GDB_OSABI_NONE;
+  return gdbarch_find_by_info (info);
+}
+
+/* Check disassembly of s390x instructions.  */
+
+static void
+disassemble_s390x ()
+{
+  gdbarch *gdbarch = gdbarch_s390x ();
+  if (gdbarch == nullptr)
+    return;
+
+  scoped_restore disassembler_options_restore
+    = make_scoped_restore (&s390_disassembler_options, "zarch");
+
+  gdb::byte_vector insn = { 0xb9, 0x68, 0x00, 0x03 };
+  disassemble_insn (gdbarch, insn, "clzg\t%r0,%r3");
+}
+
+} /* namespace selftests */
+
+#endif /* GDB_SELF_TEST */
+
 void _initialize_s390_tdep ();
 void
 _initialize_s390_tdep ()
@@ -7477,4 +7524,9 @@  _initialize_s390_tdep ()
 
   initialize_tdesc_s390_linux32 ();
   initialize_tdesc_s390x_linux64 ();
+
+#if GDB_SELF_TEST
+  selftests::register_test ("disassemble-s390x",
+			    selftests::disassemble_s390x);
+#endif /* GDB_SELF_TEST */
 }