[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
Comments
On 4/9/25 11:47, Tom de Vries wrote:
> 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
> ...
>
I've pushed this.
Thanks,
- Tom
> 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
>
> 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 */
> }
>
> 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 */
}