From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 102098 invoked by alias); 16 Dec 2016 13:59:04 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 101937 invoked by uid 89); 16 Dec 2016 13:59:03 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.4 required=5.0 tests=AWL,BAYES_00,KAM_LAZY_DOMAIN_SECURITY,RCVD_IN_DNSWL_LOW,RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=gdbarch, 23687, 2368,7, gdb_byte X-HELO: mga07.intel.com Received: from mga07.intel.com (HELO mga07.intel.com) (134.134.136.100) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 16 Dec 2016 13:58:53 +0000 Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga105.jf.intel.com with ESMTP; 16 Dec 2016 05:58:52 -0800 X-ExtLoop1: 1 Received: from irvmail001.ir.intel.com ([163.33.26.43]) by fmsmga005.fm.intel.com with ESMTP; 16 Dec 2016 05:58:51 -0800 Received: from ulvlx001.iul.intel.com (ulvlx001.iul.intel.com [172.28.207.17]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id uBGDwoZf000975; Fri, 16 Dec 2016 13:58:50 GMT Received: from ulvlx001.iul.intel.com (localhost [127.0.0.1]) by ulvlx001.iul.intel.com with ESMTP id uBGDwnT1001517; Fri, 16 Dec 2016 14:58:49 +0100 Received: (from heckel@localhost) by ulvlx001.iul.intel.com with œ id uBGDwnLU001514; Fri, 16 Dec 2016 14:58:49 +0100 From: Bernhard Heckel To: qiyaoltc@gmail.com Cc: gdb-patches@sourceware.org, Bernhard Heckel Subject: [PATCH V2 2/2] Prologue: Add selftests to x64/x32 architecture. Date: Fri, 16 Dec 2016 13:59:00 -0000 Message-Id: <1481896716-1233-3-git-send-email-bernhard.heckel@intel.com> In-Reply-To: <1481896716-1233-1-git-send-email-bernhard.heckel@intel.com> References: <1481896716-1233-1-git-send-email-bernhard.heckel@intel.com> X-IsSubscribed: yes X-SW-Source: 2016-12/txt/msg00324.txt.bz2 2016-12-16 Bernhard Heckel 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 memory; + +public: + explicit code_reader_test (const std::vector &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 memory; +}; + +/* Returns x64 test pattern and expected results. */ + +static std::vector get_prologue_tests_x64 (void) +{ + std::vector 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 get_prologue_tests_x32 (void) +{ + std::vector 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 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 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