]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[gdb/testsuite] Add selftest disassemble-s390x
authorTom de Vries <tdevries@suse.de>
Wed, 23 Apr 2025 09:02:53 +0000 (11:02 +0200)
committerTom de Vries <tdevries@suse.de>
Wed, 23 Apr 2025 09:02:53 +0000 (11:02 +0200)
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
gdb/disasm-selftests.h [new file with mode: 0644]
gdb/s390-tdep.c

index ffd25bdff93abdae5af938c50631003f09a36985..3ccc174798214c145f75c8503227f7d3ddeea22b 100644 (file)
@@ -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 (file)
index 0000000..29acf87
--- /dev/null
@@ -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 */
index d030a4d032316dd1679fceebfff951905791bb21..a3b7658ceed2fc189de05cd778c96dc32f8f30df 100644 (file)
@@ -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 */
 }