This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH V2 2/2] Prologue: Add selftests to x64/x32 architecture.
- From: Bernhard Heckel <bernhard dot heckel at intel dot com>
- To: qiyaoltc at gmail dot com
- Cc: gdb-patches at sourceware dot org, Bernhard Heckel <bernhard dot heckel at intel dot com>
- Date: Fri, 16 Dec 2016 14:58:36 +0100
- Subject: [PATCH V2 2/2] Prologue: Add selftests to x64/x32 architecture.
- Authentication-results: sourceware.org; auth=none
- References: <1481896716-1233-1-git-send-email-bernhard.heckel@intel.com>
2016-12-16 Bernhard Heckel <bernhard.heckel@intel.com>
gdb/Changelog:
* amd64-tdep.c: Include "selftest.h".
(abstract_code_reader): New class.
(code_reader): New class.
(amd64_analyze_prologue): Add new parameter reader. Call
reader.read instead of read_code.
[GDB_SELF_TEST] (code_reader_test): New class.
(get_prologue_tests_x64): New function.
(get_prologue_tests_x32): New function.
(get_prologue_tests): New function.
(amd64_analyze_prologue_test): New function.
(_initialize_amd64_tdep) [GDB_SELF_TEST]: Register
selftests::amd64_analyze_prologue_test.
---
gdb/amd64-tdep.c | 286 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 276 insertions(+), 10 deletions(-)
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index cbcddcb..67ecdaeb6 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -54,6 +54,7 @@
#include "ax.h"
#include "ax-gdb.h"
+#include "selftest.h"
/* Note that the AMD64 architecture was previously known as x86-64.
The latter is (forever) engraved into the canonical system name as
@@ -2253,6 +2254,35 @@ amd64_x32_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc,
return std::min (pc + offset + 2, current_pc);
}
+/* Abstract code reader. */
+
+class abstract_code_reader
+{
+protected:
+ bool target_memory = 0;
+public:
+ /* Read in one byte. */
+ virtual void read (CORE_ADDR memaddr, gdb_byte *buffer, ssize_t len) = 0;
+
+ bool is_target_memory (void) { return target_memory;};
+};
+
+/* Code reader from real target. */
+
+class code_reader : public abstract_code_reader
+{
+public:
+ code_reader (void)
+ {
+ target_memory = 1;
+ }
+
+ void read (CORE_ADDR memaddr, gdb_byte *buffer, ssize_t len)
+ {
+ read_code (memaddr, buffer, len);
+ }
+};
+
/* Do a limited analysis of the prologue at PC and update CACHE
accordingly. Bail out early if CURRENT_PC is reached. Return the
address where the analysis stopped.
@@ -2282,7 +2312,8 @@ amd64_x32_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc,
static CORE_ADDR
amd64_analyze_prologue (struct gdbarch *gdbarch,
CORE_ADDR pc, CORE_ADDR current_pc,
- struct amd64_frame_cache *cache)
+ struct amd64_frame_cache *cache,
+ abstract_code_reader& reader)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
/* There are two variations of movq %rsp, %rbp. */
@@ -2304,12 +2335,15 @@ amd64_analyze_prologue (struct gdbarch *gdbarch,
if (current_pc <= pc)
return current_pc;
- if (gdbarch_ptr_bit (gdbarch) == 32)
- pc = amd64_x32_analyze_stack_align (pc, current_pc, cache);
- else
- pc = amd64_analyze_stack_align (pc, current_pc, cache);
-
- op = read_code_unsigned_integer (pc, 1, byte_order);
+ /* For selftests, we don't analyze stack alignment. */
+ if (reader.is_target_memory ())
+ {
+ if (gdbarch_ptr_bit (gdbarch) == 32)
+ pc = amd64_x32_analyze_stack_align (pc, current_pc, cache);
+ else
+ pc = amd64_analyze_stack_align (pc, current_pc, cache);
+ }
+ reader.read (pc, &op, 1);
if (op == 0x55) /* pushq %rbp */
{
@@ -2322,7 +2356,7 @@ amd64_analyze_prologue (struct gdbarch *gdbarch,
if (current_pc <= pc + 1)
return current_pc;
- read_code (pc + 1, buf, 3);
+ reader.read (pc + 1, buf, 3);
/* Check for `movq %rsp, %rbp'. */
if (memcmp (buf, mov_rsp_rbp_1, 3) == 0
@@ -2334,7 +2368,7 @@ amd64_analyze_prologue (struct gdbarch *gdbarch,
/* GCC, ICC and Clang do subtraction on the stack pointer
to reserve memory for local variables.
Two common variants exist to do so. */
- read_code (pc + 4, buf, 3);
+ reader.read (pc + 4, buf, 3);
if (memcmp (buf, sub_rsp_imm8, 3) == 0)
/* Operand is 1 byte. */
return pc + 8;
@@ -2357,7 +2391,7 @@ amd64_analyze_prologue (struct gdbarch *gdbarch,
/* GCC, ICC and Clang do subtraction on the stack pointer
to reserve memory for local variables.
Two common variants exist to do so. */
- read_code (pc + 3, buf, 2);
+ reader.read (pc + 3, buf, 2);
if (memcmp (buf, sub_esp_imm8, 2) == 0)
/* Operand is 1 byte. */
return pc + 6;
@@ -2375,6 +2409,234 @@ amd64_analyze_prologue (struct gdbarch *gdbarch,
return pc;
}
+static CORE_ADDR
+amd64_analyze_prologue (struct gdbarch *gdbarch,
+ CORE_ADDR pc, CORE_ADDR current_pc,
+ struct amd64_frame_cache *cache)
+{
+ code_reader reader;
+
+ return amd64_analyze_prologue (gdbarch, pc, current_pc, cache, reader);
+}
+
+#if GDB_SELF_TEST
+
+namespace selftests {
+
+/* Code reader from manually created instruction sequences. */
+
+class code_reader_test : public abstract_code_reader
+{
+private:
+ const std::vector<gdb_byte> memory;
+
+public:
+ explicit code_reader_test (const std::vector<gdb_byte> &memory)
+ : memory (memory)
+ {
+ /* Nothing to do. */
+ }
+
+ void read (CORE_ADDR memaddr, gdb_byte *buffer, ssize_t len)
+ {
+ SELF_CHECK ((memaddr + len) <= memory.size ());
+ memcpy (buffer, memory.data () + memaddr, len);
+ }
+};
+
+struct prologue_test_t {
+ amd64_frame_cache exp_cache;
+ CORE_ADDR exp_pc;
+ std::vector<gdb_byte> memory;
+};
+
+/* Returns x64 test pattern and expected results. */
+
+static std::vector<struct prologue_test_t> get_prologue_tests_x64 (void)
+{
+ std::vector<struct prologue_test_t> prologue_tests;
+ struct prologue_test_t prologue_test;
+
+ /* Negative test. */
+ prologue_test.exp_pc = 0;
+ prologue_test.memory = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 1;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 4;
+ prologue_test.memory = {0x55, /* push %rbp */
+ 0x48, 0x89, 0xe5, /* mov %rsp, %rbp */
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 4;
+ prologue_test.memory = {0x55, /* push %rbp */
+ 0x48, 0x8b, 0xec, /* mov %rsp, %rbp */
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 8;
+ prologue_test.memory = {0x55, /* push %rbp */
+ 0x48, 0x89, 0xe5, /* mov %rsp, %rbp */
+ 0x48, 0x83, 0xec, 0x10, /* sub imm8, %rsp */
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 11;
+ prologue_test.memory = {0x55, /* push %rbp */
+ 0x48, 0x89, 0xe5, /* mov %rsp, %rbp */
+ 0x48, 0x81, 0xec, 0x10, 0x00, 0x00, 0x00, /* sub imm32, %rsp */
+ 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 8;
+ prologue_test.memory = {0x55, /* push %rbp */
+ 0x48, 0x8b, 0xec, /* mov %rsp, %rbp */
+ 0x48, 0x83, 0xec, 0x10, /* sub imm8, %rsp */
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 11;
+ prologue_test.memory = {0x55, /* push %rbp */
+ 0x48, 0x8b, 0xec, /* mov %rsp, %rbp */
+ 0x48, 0x81, 0xec, 0x10, 0x00, 0x00, 0x00, /* sub imm32, %rsp */
+ 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ return prologue_tests;
+}
+
+/* Returns x32 test pattern and expected results. */
+
+static std::vector<struct prologue_test_t> get_prologue_tests_x32 (void)
+{
+ std::vector<struct prologue_test_t> prologue_tests;
+ struct prologue_test_t prologue_test;
+
+ /* Negative test. */
+ prologue_test.exp_pc = 0;
+ prologue_test.memory = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 1;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 3;
+ prologue_test.memory = {0x55, /* push %ebp */
+ 0x89, 0xe5, /* mov %esp, %ebp */
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 3;
+ prologue_test.memory = {0x55, /* push %ebp */
+ 0x8b, 0xec, /* mov %esp, %ebp */
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 6;
+ prologue_test.memory = {0x55, /* push %ebp */
+ 0x89, 0xe5, /* mov %esp, %ebp */
+ 0x83, 0xec, 0x10, /* sub imm8, %esp */
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 9;
+ prologue_test.memory = {0x55, /* push %ebp */
+ 0x89, 0xe5, /* mov %esp, %ebp */
+ 0x81, 0xec, 0x10, 0x00, 0x00, 0x00, /* sub imm32, %esp */
+ 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 6;
+ prologue_test.memory = {0x55, /* push %ebp */
+ 0x8b, 0xec, /* mov %esp, %ebp */
+ 0x83, 0xec, 0x10, /* sub imm8, %esp */
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ prologue_test.exp_pc = 9;
+ prologue_test.memory = {0x55, /* push %ebp */
+ 0x8b, 0xec, /* mov %esp, %ebp */
+ 0x81, 0xec, 0x10, 0x00, 0x00, 0x00, /* sub imm32, %esp */
+ 0x90, 0x90, 0x90}; /* nop */
+ amd64_init_frame_cache (&prologue_test.exp_cache);
+ prologue_test.exp_cache.frameless_p = 0;
+ prologue_tests.push_back (prologue_test);
+
+ return prologue_tests;
+}
+
+/* Returns test pattern and expected results. */
+
+static std::vector<struct prologue_test_t> get_prologue_tests (const std::string arch)
+{
+ SELF_CHECK (arch == "i386:x86-64"
+ || arch == "i386:x64-32");
+
+ if (arch == "i386:x86-64")
+ return get_prologue_tests_x64 ();
+ else
+ return get_prologue_tests_x32 ();
+}
+
+static void
+amd64_analyze_prologue_test (void)
+{
+ const std::string arch_string[] = {"i386:x86-64", "i386:x64-32"};
+
+ for (const auto& current_arch : arch_string)
+ {
+ struct gdbarch_info info;
+ gdbarch_info_init (&info);
+ info.bfd_arch_info = bfd_scan_arch (current_arch.c_str ());
+ struct gdbarch *gdbarch = gdbarch_find_by_info (info);
+ SELF_CHECK (gdbarch != NULL);
+
+ const std::vector<struct prologue_test_t> prologue_tests =
+ get_prologue_tests (current_arch);
+
+ for (auto& prologue_test : prologue_tests)
+ {
+ code_reader_test reader (prologue_test.memory);
+ struct amd64_frame_cache cache;
+ amd64_init_frame_cache (&cache);
+
+ CORE_ADDR pc = amd64_analyze_prologue (gdbarch, 0, 128, &cache,
+ reader);
+
+ SELF_CHECK (pc == prologue_test.exp_pc);
+ SELF_CHECK (cache.frameless_p == prologue_test.exp_cache.frameless_p);
+ }
+ }
+}
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
+
/* Work around false termination of prologue - GCC PR debug/48827.
START_PC is the first instruction of a function, PC is its minimal already
@@ -3256,6 +3518,10 @@ _initialize_amd64_tdep (void)
initialize_tdesc_x32 ();
initialize_tdesc_x32_avx ();
initialize_tdesc_x32_avx512 ();
+
+#if GDB_SELF_TEST
+ register_self_test (selftests::amd64_analyze_prologue_test);
+#endif
}
--
2.7.1.339.g0233b80