From 787749ead66eee8c20754c160bd79404b2109553 Mon Sep 17 00:00:00 2001 From: Pierre Langlois Date: Mon, 21 Sep 2015 15:01:04 +0100 Subject: [PATCH] Move instruction decoding into new arch/ directory This patch moves the following functions into the arch/ common directory, in new files arch/aarch64-insn.{h,c}. They are prefixed with 'aarch64_': - aarch64_decode_adrp - aarch64_decode_b - aarch64_decode_cb - aarch64_decode_tb We will need them to implement fast tracepoints in GDBserver. For consistency, this patch also adds the 'aarch64_' prefix to static decoding functions that do not need to be shared right now. V2: make sure the formatting issues propagated fix `gdbserver/configure.srv'. gdb/ChangeLog: * Makefile.in (ALL_64_TARGET_OBS): Add aarch64-insn.o. (HFILES_NO_SRCDIR): Add arch/aarch64-insn.h. (aarch64-insn.o): New rule. * configure.tgt (aarch64*-*-elf): Add aarch64-insn.o. (aarch64*-*-linux*): Likewise. * arch/aarch64-insn.c: New file. * arch/aarch64-insn.h: New file. * aarch64-tdep.c: Include arch/aarch64-insn.h. (aarch64_debug): Move to arch/aarch64-insn.c. Declare in arch/aarch64-insn.h. (decode_add_sub_imm): Rename to ... (aarch64_decode_add_sub_imm): ... this. (decode_adrp): Rename to ... (aarch64_decode_adrp): ... this. Move to arch/aarch64-insn.c. Declare in arch/aarch64-insn.h. (decode_b): Rename to ... (aarch64_decode_b): ... this. Move to arch/aarch64-insn.c. Declare in arch/aarch64-insn.h. (decode_bcond): Rename to ... (aarch64_decode_bcond): ... this. Move to arch/aarch64-insn.c. Declare in arch/aarch64-insn.h. (decode_br): Rename to ... (aarch64_decode_br): ... this. (decode_cb): Rename to ... (aarch64_decode_cb): ... this. Move to arch/aarch64-insn.c. Declare in arch/aarch64-insn.h. (decode_eret): Rename to ... (aarch64_decode_eret): ... this. (decode_movz): Rename to ... (aarch64_decode_movz): ... this. (decode_orr_shifted_register_x): Rename to ... (aarch64_decode_orr_shifted_register_x): ... this. (decode_ret): Rename to ... (aarch64_decode_ret): ... this. (decode_stp_offset): Rename to ... (aarch64_decode_stp_offset): ... this. (decode_stp_offset_wb): Rename to ... (aarch64_decode_stp_offset_wb): ... this. (decode_stur): Rename to ... (aarch64_decode_stur): ... this. (decode_tb): Rename to ... (aarch64_decode_tb): ... this. Move to arch/aarch64-insn.c. Declare in arch/aarch64-insn.h. (aarch64_analyze_prologue): Adjust calls to renamed functions. gdb/gdbserver/ChangeLog: * Makefile.in (aarch64-insn.o): New rule. * configure.srv (aarch64*-*-linux*): Add aarch64-insn.o. --- gdb/ChangeLog | 47 ++++++++ gdb/Makefile.in | 13 +- gdb/aarch64-tdep.c | 235 ++++++------------------------------ gdb/arch/aarch64-insn.c | 218 +++++++++++++++++++++++++++++++++ gdb/arch/aarch64-insn.h | 38 ++++++ gdb/configure.tgt | 4 +- gdb/gdbserver/ChangeLog | 5 + gdb/gdbserver/Makefile.in | 6 + gdb/gdbserver/configure.srv | 1 + 9 files changed, 366 insertions(+), 201 deletions(-) create mode 100644 gdb/arch/aarch64-insn.c create mode 100644 gdb/arch/aarch64-insn.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index fe56b753bbc..7d8feeb0ce5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,50 @@ +2015-09-21 Pierre Langlois + + * Makefile.in (ALL_64_TARGET_OBS): Add aarch64-insn.o. + (HFILES_NO_SRCDIR): Add arch/aarch64-insn.h. + (aarch64-insn.o): New rule. + * configure.tgt (aarch64*-*-elf): Add aarch64-insn.o. + (aarch64*-*-linux*): Likewise. + * arch/aarch64-insn.c: New file. + * arch/aarch64-insn.h: New file. + * aarch64-tdep.c: Include arch/aarch64-insn.h. + (aarch64_debug): Move to arch/aarch64-insn.c. Declare in + arch/aarch64-insn.h. + (decode_add_sub_imm): Rename to ... + (aarch64_decode_add_sub_imm): ... this. + (decode_adrp): Rename to ... + (aarch64_decode_adrp): ... this. Move to arch/aarch64-insn.c. + Declare in arch/aarch64-insn.h. + (decode_b): Rename to ... + (aarch64_decode_b): ... this. Move to arch/aarch64-insn.c. + Declare in arch/aarch64-insn.h. + (decode_bcond): Rename to ... + (aarch64_decode_bcond): ... this. Move to arch/aarch64-insn.c. + Declare in arch/aarch64-insn.h. + (decode_br): Rename to ... + (aarch64_decode_br): ... this. + (decode_cb): Rename to ... + (aarch64_decode_cb): ... this. Move to arch/aarch64-insn.c. + Declare in arch/aarch64-insn.h. + (decode_eret): Rename to ... + (aarch64_decode_eret): ... this. + (decode_movz): Rename to ... + (aarch64_decode_movz): ... this. + (decode_orr_shifted_register_x): Rename to ... + (aarch64_decode_orr_shifted_register_x): ... this. + (decode_ret): Rename to ... + (aarch64_decode_ret): ... this. + (decode_stp_offset): Rename to ... + (aarch64_decode_stp_offset): ... this. + (decode_stp_offset_wb): Rename to ... + (aarch64_decode_stp_offset_wb): ... this. + (decode_stur): Rename to ... + (aarch64_decode_stur): ... this. + (decode_tb): Rename to ... + (aarch64_decode_tb): ... this. Move to arch/aarch64-insn.c. + Declare in arch/aarch64-insn.h. + (aarch64_analyze_prologue): Adjust calls to renamed functions. + 2015-09-20 Doug Evans * dwarf2read.c (add_partial_symbol): Remove outdated comments. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 5659116191c..d5ca2ee770f 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -644,7 +644,7 @@ TARGET_OBS = @TARGET_OBS@ # All target-dependent objects files that require 64-bit CORE_ADDR # (used with --enable-targets=all --enable-64-bit-bfd). ALL_64_TARGET_OBS = \ - aarch64-tdep.o aarch64-linux-tdep.o aarch64-newlib-tdep.o \ + aarch64-tdep.o aarch64-linux-tdep.o aarch64-newlib-tdep.o aarch64-insn.o \ alphabsd-tdep.o alphafbsd-tdep.o alpha-linux-tdep.o alpha-mdebug-tdep.o \ alphanbsd-tdep.o alphaobsd-tdep.o alpha-tdep.o \ amd64fbsd-tdep.o amd64-darwin-tdep.o amd64-dicos-tdep.o \ @@ -986,7 +986,7 @@ common/common-debug.h common/cleanups.h common/gdb_setjmp.h \ common/common-exceptions.h target/target.h common/symbol.h \ common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \ common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h \ -nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h +nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h arch/aarch64-insn.h # Header files that already have srcdir in them, or which are in objdir. @@ -2336,6 +2336,15 @@ aarch64-linux.o: ${srcdir}/nat/aarch64-linux.c $(COMPILE) $(srcdir)/nat/aarch64-linux.c $(POSTCOMPILE) +# gdb/arch/ dependencies +# +# Need to explicitly specify the compile rule as make will do nothing +# or try to compile the object file into the sub-directory. + +aarch64-insn.o: ${srcdir}/arch/aarch64-insn.c + $(COMPILE) $(srcdir)/arch/aarch64-insn.c + $(POSTCOMPILE) + # # gdb/tui/ dependencies # diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 9a4eda2f451..92e24047bb4 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -57,6 +57,8 @@ #include "features/aarch64.c" +#include "arch/aarch64-insn.h" + /* Pseudo register base numbers. */ #define AARCH64_Q0_REGNUM 0 #define AARCH64_D0_REGNUM (AARCH64_Q0_REGNUM + 32) @@ -179,9 +181,6 @@ struct aarch64_prologue_cache struct trad_frame_saved_reg *saved_regs; }; -/* Toggle this file's internal debugging dump. */ -static int aarch64_debug; - static void show_aarch64_debug (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -231,8 +230,8 @@ decode_masked_match (uint32_t insn, uint32_t mask, uint32_t pattern) Return 1 if the opcodes matches and is decoded, otherwise 0. */ static int -decode_add_sub_imm (CORE_ADDR addr, uint32_t insn, unsigned *rd, unsigned *rn, - int32_t *imm) +aarch64_decode_add_sub_imm (CORE_ADDR addr, uint32_t insn, unsigned *rd, + unsigned *rn, int32_t *imm) { if ((insn & 0x9f000000) == 0x91000000) { @@ -271,94 +270,6 @@ decode_add_sub_imm (CORE_ADDR addr, uint32_t insn, unsigned *rd, unsigned *rn, return 0; } -/* Decode an opcode if it represents an ADRP instruction. - - ADDR specifies the address of the opcode. - INSN specifies the opcode to test. - RD receives the 'rd' field from the decoded instruction. - - Return 1 if the opcodes matches and is decoded, otherwise 0. */ - -static int -decode_adrp (CORE_ADDR addr, uint32_t insn, unsigned *rd) -{ - if (decode_masked_match (insn, 0x9f000000, 0x90000000)) - { - *rd = (insn >> 0) & 0x1f; - - if (aarch64_debug) - { - debug_printf ("decode: 0x%s 0x%x adrp x%u, #?\n", - core_addr_to_string_nz (addr), insn, *rd); - } - return 1; - } - return 0; -} - -/* Decode an opcode if it represents an branch immediate or branch - and link immediate instruction. - - ADDR specifies the address of the opcode. - INSN specifies the opcode to test. - IS_BL receives the 'op' bit from the decoded instruction. - OFFSET receives the immediate offset from the decoded instruction. - - Return 1 if the opcodes matches and is decoded, otherwise 0. */ - -static int -decode_b (CORE_ADDR addr, uint32_t insn, int *is_bl, int32_t *offset) -{ - /* b 0001 01ii iiii iiii iiii iiii iiii iiii */ - /* bl 1001 01ii iiii iiii iiii iiii iiii iiii */ - if (decode_masked_match (insn, 0x7c000000, 0x14000000)) - { - *is_bl = (insn >> 31) & 0x1; - *offset = extract_signed_bitfield (insn, 26, 0) << 2; - - if (aarch64_debug) - { - debug_printf ("decode: 0x%s 0x%x %s 0x%s\n", - core_addr_to_string_nz (addr), insn, - *is_bl ? "bl" : "b", - core_addr_to_string_nz (addr + *offset)); - } - - return 1; - } - return 0; -} - -/* Decode an opcode if it represents a conditional branch instruction. - - ADDR specifies the address of the opcode. - INSN specifies the opcode to test. - COND receives the branch condition field from the decoded - instruction. - OFFSET receives the immediate offset from the decoded instruction. - - Return 1 if the opcodes matches and is decoded, otherwise 0. */ - -static int -decode_bcond (CORE_ADDR addr, uint32_t insn, unsigned *cond, int32_t *offset) -{ - /* b.cond 0101 0100 iiii iiii iiii iiii iii0 cccc */ - if (decode_masked_match (insn, 0xff000010, 0x54000000)) - { - *cond = (insn >> 0) & 0xf; - *offset = extract_signed_bitfield (insn, 19, 5) << 2; - - if (aarch64_debug) - { - debug_printf ("decode: 0x%s 0x%x b<%u> 0x%s\n", - core_addr_to_string_nz (addr), insn, *cond, - core_addr_to_string_nz (addr + *offset)); - } - return 1; - } - return 0; -} - /* Decode an opcode if it represents a branch via register instruction. ADDR specifies the address of the opcode. @@ -369,7 +280,8 @@ decode_bcond (CORE_ADDR addr, uint32_t insn, unsigned *cond, int32_t *offset) Return 1 if the opcodes matches and is decoded, otherwise 0. */ static int -decode_br (CORE_ADDR addr, uint32_t insn, int *is_blr, unsigned *rn) +aarch64_decode_br (CORE_ADDR addr, uint32_t insn, int *is_blr, + unsigned *rn) { /* 8 4 0 6 2 8 4 0 */ /* blr 110101100011111100000000000rrrrr */ @@ -391,42 +303,6 @@ decode_br (CORE_ADDR addr, uint32_t insn, int *is_blr, unsigned *rn) return 0; } -/* Decode an opcode if it represents a CBZ or CBNZ instruction. - - ADDR specifies the address of the opcode. - INSN specifies the opcode to test. - IS64 receives the 'sf' field from the decoded instruction. - IS_CBNZ receives the 'op' field from the decoded instruction. - RN receives the 'rn' field from the decoded instruction. - OFFSET receives the 'imm19' field from the decoded instruction. - - Return 1 if the opcodes matches and is decoded, otherwise 0. */ - -static int -decode_cb (CORE_ADDR addr, uint32_t insn, int *is64, int *is_cbnz, - unsigned *rn, int32_t *offset) -{ - /* cbz T011 010o iiii iiii iiii iiii iiir rrrr */ - /* cbnz T011 010o iiii iiii iiii iiii iiir rrrr */ - if (decode_masked_match (insn, 0x7e000000, 0x34000000)) - { - *rn = (insn >> 0) & 0x1f; - *is64 = (insn >> 31) & 0x1; - *is_cbnz = (insn >> 24) & 0x1; - *offset = extract_signed_bitfield (insn, 19, 5) << 2; - - if (aarch64_debug) - { - debug_printf ("decode: 0x%s 0x%x %s 0x%s\n", - core_addr_to_string_nz (addr), insn, - *is_cbnz ? "cbnz" : "cbz", - core_addr_to_string_nz (addr + *offset)); - } - return 1; - } - return 0; -} - /* Decode an opcode if it represents a ERET instruction. ADDR specifies the address of the opcode. @@ -435,7 +311,7 @@ decode_cb (CORE_ADDR addr, uint32_t insn, int *is64, int *is_cbnz, Return 1 if the opcodes matches and is decoded, otherwise 0. */ static int -decode_eret (CORE_ADDR addr, uint32_t insn) +aarch64_decode_eret (CORE_ADDR addr, uint32_t insn) { /* eret 1101 0110 1001 1111 0000 0011 1110 0000 */ if (insn == 0xd69f03e0) @@ -459,7 +335,7 @@ decode_eret (CORE_ADDR addr, uint32_t insn) Return 1 if the opcodes matches and is decoded, otherwise 0. */ static int -decode_movz (CORE_ADDR addr, uint32_t insn, unsigned *rd) +aarch64_decode_movz (CORE_ADDR addr, uint32_t insn, unsigned *rd) { if (decode_masked_match (insn, 0xff800000, 0x52800000)) { @@ -488,9 +364,9 @@ decode_movz (CORE_ADDR addr, uint32_t insn, unsigned *rd) Return 1 if the opcodes matches and is decoded, otherwise 0. */ static int -decode_orr_shifted_register_x (CORE_ADDR addr, - uint32_t insn, unsigned *rd, unsigned *rn, - unsigned *rm, int32_t *imm) +aarch64_decode_orr_shifted_register_x (CORE_ADDR addr, uint32_t insn, + unsigned *rd, unsigned *rn, + unsigned *rm, int32_t *imm) { if (decode_masked_match (insn, 0xff200000, 0xaa000000)) { @@ -519,7 +395,7 @@ decode_orr_shifted_register_x (CORE_ADDR addr, Return 1 if the opcodes matches and is decoded, otherwise 0. */ static int -decode_ret (CORE_ADDR addr, uint32_t insn, unsigned *rn) +aarch64_decode_ret (CORE_ADDR addr, uint32_t insn, unsigned *rn) { if (decode_masked_match (insn, 0xfffffc1f, 0xd65f0000)) { @@ -547,9 +423,8 @@ decode_ret (CORE_ADDR addr, uint32_t insn, unsigned *rn) Return 1 if the opcodes matches and is decoded, otherwise 0. */ static int -decode_stp_offset (CORE_ADDR addr, - uint32_t insn, - unsigned *rt1, unsigned *rt2, unsigned *rn, int32_t *imm) +aarch64_decode_stp_offset (CORE_ADDR addr, uint32_t insn, unsigned *rt1, + unsigned *rt2, unsigned *rn, int32_t *imm) { if (decode_masked_match (insn, 0xffc00000, 0xa9000000)) { @@ -583,10 +458,8 @@ decode_stp_offset (CORE_ADDR addr, Return 1 if the opcodes matches and is decoded, otherwise 0. */ static int -decode_stp_offset_wb (CORE_ADDR addr, - uint32_t insn, - unsigned *rt1, unsigned *rt2, unsigned *rn, - int32_t *imm) +aarch64_decode_stp_offset_wb (CORE_ADDR addr, uint32_t insn, unsigned *rt1, + unsigned *rt2, unsigned *rn, int32_t *imm) { if (decode_masked_match (insn, 0xffc00000, 0xa9800000)) { @@ -620,8 +493,8 @@ decode_stp_offset_wb (CORE_ADDR addr, Return 1 if the opcodes matches and is decoded, otherwise 0. */ static int -decode_stur (CORE_ADDR addr, uint32_t insn, int *is64, unsigned *rt, - unsigned *rn, int32_t *imm) +aarch64_decode_stur (CORE_ADDR addr, uint32_t insn, int *is64, + unsigned *rt, unsigned *rn, int32_t *imm) { if (decode_masked_match (insn, 0xbfe00c00, 0xb8000000)) { @@ -641,42 +514,6 @@ decode_stur (CORE_ADDR addr, uint32_t insn, int *is64, unsigned *rt, return 0; } -/* Decode an opcode if it represents a TBZ or TBNZ instruction. - - ADDR specifies the address of the opcode. - INSN specifies the opcode to test. - IS_TBNZ receives the 'op' field from the decoded instruction. - BIT receives the bit position field from the decoded instruction. - RT receives 'rt' field from the decoded instruction. - IMM receives 'imm' field from the decoded instruction. - - Return 1 if the opcodes matches and is decoded, otherwise 0. */ - -static int -decode_tb (CORE_ADDR addr, uint32_t insn, int *is_tbnz, unsigned *bit, - unsigned *rt, int32_t *imm) -{ - /* tbz b011 0110 bbbb biii iiii iiii iiir rrrr */ - /* tbnz B011 0111 bbbb biii iiii iiii iiir rrrr */ - if (decode_masked_match (insn, 0x7e000000, 0x36000000)) - { - *rt = (insn >> 0) & 0x1f; - *is_tbnz = (insn >> 24) & 0x1; - *bit = ((insn >> (31 - 4)) & 0x20) | ((insn >> 19) & 0x1f); - *imm = extract_signed_bitfield (insn, 14, 5) << 2; - - if (aarch64_debug) - { - debug_printf ("decode: 0x%s 0x%x %s x%u, #%u, 0x%s\n", - core_addr_to_string_nz (addr), insn, - *is_tbnz ? "tbnz" : "tbz", *rt, *bit, - core_addr_to_string_nz (addr + *imm)); - } - return 1; - } - return 0; -} - /* 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. */ @@ -718,39 +555,40 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch, insn = read_memory_unsigned_integer (start, 4, byte_order_for_code); - if (decode_add_sub_imm (start, insn, &rd, &rn, &imm)) + if (aarch64_decode_add_sub_imm (start, insn, &rd, &rn, &imm)) regs[rd] = pv_add_constant (regs[rn], imm); - else if (decode_adrp (start, insn, &rd)) + else if (aarch64_decode_adrp (start, insn, &rd)) regs[rd] = pv_unknown (); - else if (decode_b (start, insn, &is_link, &offset)) + else if (aarch64_decode_b (start, insn, &is_link, &offset)) { /* Stop analysis on branch. */ break; } - else if (decode_bcond (start, insn, &cond, &offset)) + else if (aarch64_decode_bcond (start, insn, &cond, &offset)) { /* Stop analysis on branch. */ break; } - else if (decode_br (start, insn, &is_link, &rn)) + else if (aarch64_decode_br (start, insn, &is_link, &rn)) { /* Stop analysis on branch. */ break; } - else if (decode_cb (start, insn, &is64, &is_cbnz, &rn, &offset)) + else if (aarch64_decode_cb (start, insn, &is64, &is_cbnz, &rn, + &offset)) { /* Stop analysis on branch. */ break; } - else if (decode_eret (start, insn)) + else if (aarch64_decode_eret (start, insn)) { /* Stop analysis on branch. */ break; } - else if (decode_movz (start, insn, &rd)) + else if (aarch64_decode_movz (start, insn, &rd)) regs[rd] = pv_unknown (); - else - if (decode_orr_shifted_register_x (start, insn, &rd, &rn, &rm, &imm)) + else if (aarch64_decode_orr_shifted_register_x (start, insn, &rd, + &rn, &rm, &imm)) { if (imm == 0 && rn == 31) regs[rd] = regs[rm]; @@ -765,17 +603,18 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch, break; } } - else if (decode_ret (start, insn, &rn)) + else if (aarch64_decode_ret (start, insn, &rn)) { /* Stop analysis on branch. */ break; } - else if (decode_stur (start, insn, &is64, &rt, &rn, &offset)) + else if (aarch64_decode_stur (start, insn, &is64, &rt, &rn, &offset)) { pv_area_store (stack, pv_add_constant (regs[rn], offset), is64 ? 8 : 4, regs[rt]); } - else if (decode_stp_offset (start, insn, &rt1, &rt2, &rn, &imm)) + else if (aarch64_decode_stp_offset (start, insn, &rt1, &rt2, &rn, + &imm)) { /* If recording this store would invalidate the store area (perhaps because rn is not known) then we should abandon @@ -793,7 +632,8 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch, pv_area_store (stack, pv_add_constant (regs[rn], imm + 8), 8, regs[rt2]); } - else if (decode_stp_offset_wb (start, insn, &rt1, &rt2, &rn, &imm)) + else if (aarch64_decode_stp_offset_wb (start, insn, &rt1, &rt2, &rn, + &imm)) { /* If recording this store would invalidate the store area (perhaps because rn is not known) then we should abandon @@ -812,7 +652,8 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch, regs[rt2]); regs[rn] = pv_add_constant (regs[rn], imm); } - else if (decode_tb (start, insn, &is_tbnz, &bit, &rn, &offset)) + else if (aarch64_decode_tb (start, insn, &is_tbnz, &bit, &rn, + &offset)) { /* Stop analysis on branch. */ break; @@ -2663,7 +2504,7 @@ aarch64_software_single_step (struct frame_info *frame) byte_order_for_code); /* Check if the instruction is a conditional branch. */ - if (decode_bcond (loc, insn, &cond, &offset)) + if (aarch64_decode_bcond (loc, insn, &cond, &offset)) { if (bc_insn_count >= 1) return 0; diff --git a/gdb/arch/aarch64-insn.c b/gdb/arch/aarch64-insn.c new file mode 100644 index 00000000000..3a289a26da8 --- /dev/null +++ b/gdb/arch/aarch64-insn.c @@ -0,0 +1,218 @@ +/* Copyright (C) 2009-2015 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + 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 . */ + +#include "common-defs.h" +#include "aarch64-insn.h" + +/* Toggle this file's internal debugging dump. */ +int aarch64_debug = 0; + +/* Extract a signed value from a bit field within an instruction + encoding. + + INSN is the instruction opcode. + + WIDTH specifies the width of the bit field to extract (in bits). + + OFFSET specifies the least significant bit of the field where bits + are numbered zero counting from least to most significant. */ + +static int32_t +extract_signed_bitfield (uint32_t insn, unsigned width, unsigned offset) +{ + unsigned shift_l = sizeof (int32_t) * 8 - (offset + width); + unsigned shift_r = sizeof (int32_t) * 8 - width; + + return ((int32_t) insn << shift_l) >> shift_r; +} + +/* Determine if specified bits within an instruction opcode matches a + specific pattern. + + INSN is the instruction opcode. + + MASK specifies the bits within the opcode that are to be tested + agsinst for a match with PATTERN. */ + +static int +decode_masked_match (uint32_t insn, uint32_t mask, uint32_t pattern) +{ + return (insn & mask) == pattern; +} + +/* Decode an opcode if it represents an ADRP instruction. + + ADDR specifies the address of the opcode. + INSN specifies the opcode to test. + RD receives the 'rd' field from the decoded instruction. + + Return 1 if the opcodes matches and is decoded, otherwise 0. */ + +int +aarch64_decode_adrp (CORE_ADDR addr, uint32_t insn, unsigned *rd) +{ + if (decode_masked_match (insn, 0x9f000000, 0x90000000)) + { + *rd = (insn >> 0) & 0x1f; + + if (aarch64_debug) + { + debug_printf ("decode: 0x%s 0x%x adrp x%u, #?\n", + core_addr_to_string_nz (addr), insn, *rd); + } + return 1; + } + return 0; +} + +/* Decode an opcode if it represents an branch immediate or branch + and link immediate instruction. + + ADDR specifies the address of the opcode. + INSN specifies the opcode to test. + IS_BL receives the 'op' bit from the decoded instruction. + OFFSET receives the immediate offset from the decoded instruction. + + Return 1 if the opcodes matches and is decoded, otherwise 0. */ + +int +aarch64_decode_b (CORE_ADDR addr, uint32_t insn, int *is_bl, + int32_t *offset) +{ + /* b 0001 01ii iiii iiii iiii iiii iiii iiii */ + /* bl 1001 01ii iiii iiii iiii iiii iiii iiii */ + if (decode_masked_match (insn, 0x7c000000, 0x14000000)) + { + *is_bl = (insn >> 31) & 0x1; + *offset = extract_signed_bitfield (insn, 26, 0) << 2; + + if (aarch64_debug) + { + debug_printf ("decode: 0x%s 0x%x %s 0x%s\n", + core_addr_to_string_nz (addr), insn, + *is_bl ? "bl" : "b", + core_addr_to_string_nz (addr + *offset)); + } + + return 1; + } + return 0; +} + +/* Decode an opcode if it represents a conditional branch instruction. + + ADDR specifies the address of the opcode. + INSN specifies the opcode to test. + COND receives the branch condition field from the decoded + instruction. + OFFSET receives the immediate offset from the decoded instruction. + + Return 1 if the opcodes matches and is decoded, otherwise 0. */ + +int +aarch64_decode_bcond (CORE_ADDR addr, uint32_t insn, unsigned *cond, + int32_t *offset) +{ + /* b.cond 0101 0100 iiii iiii iiii iiii iii0 cccc */ + if (decode_masked_match (insn, 0xff000010, 0x54000000)) + { + *cond = (insn >> 0) & 0xf; + *offset = extract_signed_bitfield (insn, 19, 5) << 2; + + if (aarch64_debug) + { + debug_printf ("decode: 0x%s 0x%x b<%u> 0x%s\n", + core_addr_to_string_nz (addr), insn, *cond, + core_addr_to_string_nz (addr + *offset)); + } + return 1; + } + return 0; +} + +/* Decode an opcode if it represents a CBZ or CBNZ instruction. + + ADDR specifies the address of the opcode. + INSN specifies the opcode to test. + IS64 receives the 'sf' field from the decoded instruction. + IS_CBNZ receives the 'op' field from the decoded instruction. + RN receives the 'rn' field from the decoded instruction. + OFFSET receives the 'imm19' field from the decoded instruction. + + Return 1 if the opcodes matches and is decoded, otherwise 0. */ + +int +aarch64_decode_cb (CORE_ADDR addr, uint32_t insn, int *is64, int *is_cbnz, + unsigned *rn, int32_t *offset) +{ + /* cbz T011 010o iiii iiii iiii iiii iiir rrrr */ + /* cbnz T011 010o iiii iiii iiii iiii iiir rrrr */ + if (decode_masked_match (insn, 0x7e000000, 0x34000000)) + { + *rn = (insn >> 0) & 0x1f; + *is64 = (insn >> 31) & 0x1; + *is_cbnz = (insn >> 24) & 0x1; + *offset = extract_signed_bitfield (insn, 19, 5) << 2; + + if (aarch64_debug) + { + debug_printf ("decode: 0x%s 0x%x %s 0x%s\n", + core_addr_to_string_nz (addr), insn, + *is_cbnz ? "cbnz" : "cbz", + core_addr_to_string_nz (addr + *offset)); + } + return 1; + } + return 0; +} + +/* Decode an opcode if it represents a TBZ or TBNZ instruction. + + ADDR specifies the address of the opcode. + INSN specifies the opcode to test. + IS_TBNZ receives the 'op' field from the decoded instruction. + BIT receives the bit position field from the decoded instruction. + RT receives 'rt' field from the decoded instruction. + IMM receives 'imm' field from the decoded instruction. + + Return 1 if the opcodes matches and is decoded, otherwise 0. */ + +int +aarch64_decode_tb (CORE_ADDR addr, uint32_t insn, int *is_tbnz, + unsigned *bit, unsigned *rt, int32_t *imm) +{ + /* tbz b011 0110 bbbb biii iiii iiii iiir rrrr */ + /* tbnz B011 0111 bbbb biii iiii iiii iiir rrrr */ + if (decode_masked_match (insn, 0x7e000000, 0x36000000)) + { + *rt = (insn >> 0) & 0x1f; + *is_tbnz = (insn >> 24) & 0x1; + *bit = ((insn >> (31 - 4)) & 0x20) | ((insn >> 19) & 0x1f); + *imm = extract_signed_bitfield (insn, 14, 5) << 2; + + if (aarch64_debug) + { + debug_printf ("decode: 0x%s 0x%x %s x%u, #%u, 0x%s\n", + core_addr_to_string_nz (addr), insn, + *is_tbnz ? "tbnz" : "tbz", *rt, *bit, + core_addr_to_string_nz (addr + *imm)); + } + return 1; + } + return 0; +} diff --git a/gdb/arch/aarch64-insn.h b/gdb/arch/aarch64-insn.h new file mode 100644 index 00000000000..7775a34e829 --- /dev/null +++ b/gdb/arch/aarch64-insn.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2009-2015 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + 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 . */ + +#ifndef AARCH64_INSN_H +#define AARCH64_INSN_H 1 + +extern int aarch64_debug; + +int aarch64_decode_adrp (CORE_ADDR addr, uint32_t insn, unsigned *rd); + +int aarch64_decode_b (CORE_ADDR addr, uint32_t insn, int *is_bl, + int32_t *offset); + +int aarch64_decode_bcond (CORE_ADDR addr, uint32_t insn, unsigned *cond, + int32_t *offset); + +int aarch64_decode_cb (CORE_ADDR addr, uint32_t insn, int *is64, + int *is_cbnz, unsigned *rn, int32_t *offset); + +int aarch64_decode_tb (CORE_ADDR addr, uint32_t insn, int *is_tbnz, + unsigned *bit, unsigned *rt, int32_t *imm); + +#endif diff --git a/gdb/configure.tgt b/gdb/configure.tgt index c42b4dff103..33d4cfc15fb 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -38,12 +38,12 @@ esac case "${targ}" in aarch64*-*-elf) # Target: AArch64 embedded system - gdb_target_obs="aarch64-tdep.o aarch64-newlib-tdep.o" + gdb_target_obs="aarch64-tdep.o aarch64-newlib-tdep.o aarch64-insn.o" ;; aarch64*-*-linux*) # Target: AArch64 linux - gdb_target_obs="aarch64-tdep.o aarch64-linux-tdep.o \ + gdb_target_obs="aarch64-tdep.o aarch64-linux-tdep.o aarch64-insn.o \ arm-tdep.o arm-linux-tdep.o \ glibc-tdep.o linux-tdep.o solib-svr4.o \ symfile-mem.o linux-record.o" diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 16b02ca969f..83a7848f833 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,8 @@ +2015-09-21 Pierre Langlois + + * Makefile.in (aarch64-insn.o): New rule. + * configure.srv (aarch64*-*-linux*): Add aarch64-insn.o. + 2015-09-21 Yao Qi * ax.c [!IN_PROCESS_AGENT] (gdb_agent_op_sizes): Define it. diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index b715a3252f5..d096663645a 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -625,6 +625,12 @@ linux-namespaces.o: ../nat/linux-namespaces.c $(COMPILE) $< $(POSTCOMPILE) +# Architecture specific object files rules from ../arch + +aarch64-insn.o: ../arch/aarch64-insn.c + $(COMPILE) $< + $(POSTCOMPILE) + aarch64.c : $(srcdir)/../regformats/aarch64.dat $(regdat_sh) $(SHELL) $(regdat_sh) $(srcdir)/../regformats/aarch64.dat aarch64.c reg-arm.c : $(srcdir)/../regformats/reg-arm.dat $(regdat_sh) diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index aa232f8239e..a62df83d29a 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -53,6 +53,7 @@ case "${target}" in srv_tgtobj="linux-aarch64-low.o aarch64-linux-hw-point.o" srv_tgtobj="$srv_tgtobj linux-aarch32-low.o" srv_tgtobj="$srv_tgtobj aarch64-linux.o" + srv_tgtobj="$srv_tgtobj aarch64-insn.o" srv_tgtobj="${srv_tgtobj} $srv_linux_obj" srv_xmlfiles="aarch64.xml" srv_xmlfiles="${srv_xmlfiles} aarch64-core.xml" -- 2.30.2