[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
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
@@ -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 ();
new file mode 100644
@@ -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 */
@@ -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 */
}