aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom de Vries <tdevries@suse.de>2025-03-07 09:25:33 +0100
committerTom de Vries <tdevries@suse.de>2025-03-07 09:25:33 +0100
commitbbb04932e6cab8aac83b3ab8d0d4aa5fae3356f9 (patch)
tree95bd901050a498ff1d88a58ae08704633b9a51b7
parent0c1eecdfc6348ec9213ebbb42ddce78fc197a428 (diff)
downloadbinutils-bbb04932e6cab8aac83b3ab8d0d4aa5fae3356f9.zip
binutils-bbb04932e6cab8aac83b3ab8d0d4aa5fae3356f9.tar.gz
binutils-bbb04932e6cab8aac83b3ab8d0d4aa5fae3356f9.tar.bz2
[gdb/tdep] Add amd64-insn-decode selftest
Add a selftest that checks the results of amd64_get_insn_details and related functions for two basic instructions. Add a parameter assumptions to amd64_get_used_input_int_regs, to make sure that this selftest: ... /* INSN: add %eax,(%rcx). */ ... SELF_CHECK (amd64_get_used_input_int_regs (&details, false) == ((1 << EAX_REG_NUM) | (1 << ECX_REG_NUM))); ... passes because it found the "%eax" in the insn, rather than passing because of this assumption: ... /* Assume RAX is used. If not, we'd have to detect opcodes that implicitly use RAX. */ used_regs_mask |= 1 << EAX_REG_NUM; ... Tested on x86_64-linux.
-rw-r--r--gdb/amd64-tdep.c71
1 files changed, 63 insertions, 8 deletions
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index dd0fa06..8471ca6 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -50,6 +50,7 @@
#include "osabi.h"
#include "x86-tdep.h"
#include "amd64-ravenscar-thread.h"
+#include "gdbsupport/selftest.h"
/* Note that the AMD64 architecture was previously known as x86-64.
The latter is (forever) engraved into the canonical system name as
@@ -1207,20 +1208,25 @@ amd64_skip_prefixes (gdb_byte *insn)
}
/* Return a register mask for the integer registers that are used as an input
- operand in INSN. */
+ operand in INSN. If !ASSUMPTIONS, only return the registers we actually
+ found, for the benefit of self tests. */
static uint32_t
-amd64_get_used_input_int_regs (const struct amd64_insn *details)
+amd64_get_used_input_int_regs (const struct amd64_insn *details,
+ bool assumptions = true)
{
/* 1 bit for each reg */
uint32_t used_regs_mask = 0;
- /* Assume RAX is used. If not, we'd have to detect opcodes that implicitly
- use RAX. */
- used_regs_mask |= 1 << EAX_REG_NUM;
- /* Assume RDX is used. If not, we'd have to detect opcodes that implicitly
- use RDX, like divides. */
- used_regs_mask |= 1 << EDX_REG_NUM;
+ if (assumptions)
+ {
+ /* Assume RAX is used. If not, we'd have to detect opcodes that implicitly
+ use RAX. */
+ used_regs_mask |= 1 << EAX_REG_NUM;
+ /* Assume RDX is used. If not, we'd have to detect opcodes that implicitly
+ use RDX, like divides. */
+ used_regs_mask |= 1 << EDX_REG_NUM;
+ }
/* If the opcode is one byte long and there's no ModRM byte,
assume the opcode specifies a register. */
@@ -3395,6 +3401,51 @@ amd64_target_description (uint64_t xcr0, bool segments)
return *tdesc;
}
+#if GDB_SELF_TEST
+
+namespace selftests {
+
+/* Test amd64_get_insn_details. */
+
+static void
+test_amd64_get_insn_details (void)
+{
+ struct amd64_insn details;
+ gdb::byte_vector insn;
+
+ /* INSN: add %eax,(%rcx). */
+ insn = { 0x01, 0x01 };
+ amd64_get_insn_details (insn.data (), &details);
+ SELF_CHECK (details.opcode_len == 1);
+ SELF_CHECK (details.enc_prefix_offset == -1);
+ SELF_CHECK (details.opcode_offset == 0);
+ SELF_CHECK (details.modrm_offset == 1);
+ SELF_CHECK (amd64_get_used_input_int_regs (&details, false)
+ == ((1 << EAX_REG_NUM) | (1 << ECX_REG_NUM)));
+ SELF_CHECK (rip_relative_offset (&details) == 0);
+
+ /* INSN: push %rax. This exercises the "opcode specifies register" case in
+ amd64_get_used_input_int_regs. */
+ insn = { 0x50 };
+ amd64_get_insn_details (insn.data (), &details);
+ SELF_CHECK (details.opcode_len == 1);
+ SELF_CHECK (details.enc_prefix_offset == -1);
+ SELF_CHECK (details.opcode_offset == 0);
+ SELF_CHECK (details.modrm_offset == -1);
+ SELF_CHECK (amd64_get_used_input_int_regs (&details, false)
+ == ((1 << EAX_REG_NUM)));
+ SELF_CHECK (rip_relative_offset (&details) == 0);
+}
+
+static void
+amd64_insn_decode (void)
+{
+ test_amd64_get_insn_details ();
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
void _initialize_amd64_tdep ();
void
_initialize_amd64_tdep ()
@@ -3403,6 +3454,10 @@ _initialize_amd64_tdep ()
amd64_none_init_abi);
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x64_32, GDB_OSABI_NONE,
amd64_x32_none_init_abi);
+#if GDB_SELF_TEST
+ selftests::register_test ("amd64-insn-decode",
+ selftests::amd64_insn_decode);
+#endif
}