diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 16 | ||||
-rw-r--r-- | gdb/aarch64-tdep.c | 121 | ||||
-rw-r--r-- | gdb/trad-frame.c | 21 | ||||
-rw-r--r-- | gdb/trad-frame.h | 1 |
4 files changed, 150 insertions, 9 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 620b582..b4dd117 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,19 @@ +2016-12-02 Yao Qi <yao.qi@linaro.org> + Pedro Alves <palves@redhat.com> + + * aarch64-tdep.c: Include "selftest.h". + (abstract_instruction_reader): New class. + (instruction_reader): New class. + (aarch64_analyze_prologue): Add new parameter reader. Call + reader.read instead of read_memory_unsigned_integer. + [GDB_SELF_TEST] (instruction_reader_test): New class. + (aarch64_analyze_prologue_test): New function. + (_initialize_aarch64_tdep) [GDB_SELF_TEST]: Register + selftests::aarch64_analyze_prologue_test. + * trad-frame.c (trad_frame_cache_zalloc): + (trad_frame_alloc_saved_regs): Add a new function. + * trad-frame.h (trad_frame_alloc_saved_regs): Declare. + 2016-12-01 Simon Marchi <simon.marchi@polymtl.ca> * ui-out.c (enum ui_out_table_state): Move to class diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 6b95d7c..576ee70 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -44,6 +44,7 @@ #include "infcall.h" #include "ax.h" #include "ax-gdb.h" +#include "selftest.h" #include "aarch64-tdep.h" @@ -195,6 +196,27 @@ show_aarch64_debug (struct ui_file *file, int from_tty, fprintf_filtered (file, _("AArch64 debugging is %s.\n"), value); } +/* Abstract instruction reader. */ + +class abstract_instruction_reader +{ +public: + /* Read in one instruction. */ + virtual ULONGEST read (CORE_ADDR memaddr, int len, + enum bfd_endian byte_order) = 0; +}; + +/* Instruction reader from real target. */ + +class instruction_reader : public abstract_instruction_reader +{ + public: + ULONGEST read (CORE_ADDR memaddr, int len, enum bfd_endian byte_order) + { + return read_memory_unsigned_integer (memaddr, len, byte_order); + } +}; + /* Analyze a prologue, looking for a recognizable stack frame and frame pointer. Scan until we encounter a store that could clobber the stack frame unexpectedly, or an unknown instruction. */ @@ -202,7 +224,8 @@ show_aarch64_debug (struct ui_file *file, int from_tty, static CORE_ADDR aarch64_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR start, CORE_ADDR limit, - struct aarch64_prologue_cache *cache) + struct aarch64_prologue_cache *cache, + abstract_instruction_reader& reader) { enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); int i; @@ -221,7 +244,7 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch, uint32_t insn; aarch64_inst inst; - insn = read_memory_unsigned_integer (start, 4, byte_order_for_code); + insn = reader.read (start, 4, byte_order_for_code); if (aarch64_decode_insn (insn, &inst, 1) != 0) break; @@ -436,6 +459,96 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch, return start; } +static CORE_ADDR +aarch64_analyze_prologue (struct gdbarch *gdbarch, + CORE_ADDR start, CORE_ADDR limit, + struct aarch64_prologue_cache *cache) +{ + instruction_reader reader; + + return aarch64_analyze_prologue (gdbarch, start, limit, cache, + reader); +} + +#if GDB_SELF_TEST + +namespace selftests { + +/* Instruction reader from manually cooked instruction sequences. */ + +class instruction_reader_test : public abstract_instruction_reader +{ +public: + template<size_t SIZE> + explicit instruction_reader_test (const uint32_t (&insns)[SIZE]) + : m_insns (insns), m_insns_size (SIZE) + {} + + ULONGEST read (CORE_ADDR memaddr, int len, enum bfd_endian byte_order) + { + SELF_CHECK (len == 4); + SELF_CHECK (memaddr % 4 == 0); + SELF_CHECK (memaddr / 4 < m_insns_size); + + return m_insns[memaddr / 4]; + } + +private: + const uint32_t *m_insns; + size_t m_insns_size; +}; + +static void +aarch64_analyze_prologue_test (void) +{ + struct gdbarch_info info; + + gdbarch_info_init (&info); + info.bfd_arch_info = bfd_scan_arch ("aarch64"); + + struct gdbarch *gdbarch = gdbarch_find_by_info (info); + SELF_CHECK (gdbarch != NULL); + + /* Test the simple prologue in which frame pointer is used. */ + { + struct aarch64_prologue_cache cache; + cache.saved_regs = trad_frame_alloc_saved_regs (gdbarch); + + static const uint32_t insns[] = { + 0xa9af7bfd, /* stp x29, x30, [sp,#-272]! */ + 0x910003fd, /* mov x29, sp */ + 0x97ffffe6, /* bl 0x400580 */ + }; + instruction_reader_test reader (insns); + + CORE_ADDR end = aarch64_analyze_prologue (gdbarch, 0, 128, &cache, reader); + SELF_CHECK (end == 4 * 2); + + SELF_CHECK (cache.framereg == AARCH64_FP_REGNUM); + SELF_CHECK (cache.framesize == 272); + + for (int i = 0; i < AARCH64_X_REGISTER_COUNT; i++) + { + if (i == AARCH64_FP_REGNUM) + SELF_CHECK (cache.saved_regs[i].addr == -272); + else if (i == AARCH64_LR_REGNUM) + SELF_CHECK (cache.saved_regs[i].addr == -264); + else + SELF_CHECK (cache.saved_regs[i].addr == -1); + } + + for (int i = 0; i < AARCH64_D_REGISTER_COUNT; i++) + { + int regnum = gdbarch_num_regs (gdbarch); + + SELF_CHECK (cache.saved_regs[i + regnum + AARCH64_D0_REGNUM].addr + == -1); + } + } +} +} // namespace selftests +#endif /* GDB_SELF_TEST */ + /* Implement the "skip_prologue" gdbarch method. */ static CORE_ADDR @@ -2864,6 +2977,10 @@ When on, AArch64 specific debugging is enabled."), NULL, show_aarch64_debug, &setdebuglist, &showdebuglist); + +#if GDB_SELF_TEST + register_self_test (selftests::aarch64_analyze_prologue_test); +#endif } /* AArch64 process record-replay related structures, defines etc. */ diff --git a/gdb/trad-frame.c b/gdb/trad-frame.c index ebf19df..4430dd5 100644 --- a/gdb/trad-frame.c +++ b/gdb/trad-frame.c @@ -43,16 +43,10 @@ trad_frame_cache_zalloc (struct frame_info *this_frame) return this_trad_cache; } -/* A traditional frame is unwound by analysing the function prologue - and using the information gathered to track registers. For - non-optimized frames, the technique is reliable (just need to check - for all potential instruction sequences). */ - struct trad_frame_saved_reg * -trad_frame_alloc_saved_regs (struct frame_info *this_frame) +trad_frame_alloc_saved_regs (struct gdbarch *gdbarch) { int regnum; - struct gdbarch *gdbarch = get_frame_arch (this_frame); int numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); struct trad_frame_saved_reg *this_saved_regs = FRAME_OBSTACK_CALLOC (numregs, struct trad_frame_saved_reg); @@ -65,6 +59,19 @@ trad_frame_alloc_saved_regs (struct frame_info *this_frame) return this_saved_regs; } +/* A traditional frame is unwound by analysing the function prologue + and using the information gathered to track registers. For + non-optimized frames, the technique is reliable (just need to check + for all potential instruction sequences). */ + +struct trad_frame_saved_reg * +trad_frame_alloc_saved_regs (struct frame_info *this_frame) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + + return trad_frame_alloc_saved_regs (gdbarch); +} + enum { TF_REG_VALUE = -1, TF_REG_UNKNOWN = -2 }; int diff --git a/gdb/trad-frame.h b/gdb/trad-frame.h index b8aed16..d1c24b0 100644 --- a/gdb/trad-frame.h +++ b/gdb/trad-frame.h @@ -104,6 +104,7 @@ int trad_frame_realreg_p (struct trad_frame_saved_reg this_saved_regs[], /* Return a freshly allocated (and initialized) trad_frame array. */ struct trad_frame_saved_reg *trad_frame_alloc_saved_regs (struct frame_info *); +struct trad_frame_saved_reg *trad_frame_alloc_saved_regs (struct gdbarch *); /* Given the trad_frame info, return the location of the specified register. */ |