From 246994ce350923199a4c952b38dcee5bcbe8c554 Mon Sep 17 00:00:00 2001 From: Yao Qi Date: Mon, 12 Oct 2015 11:28:38 +0100 Subject: [PATCH] Move aarch64_relocate_instruction to arch/aarch64-insn.c This patch moves aarch64_relocate_instruction and visitor class to arch/aarch64-insn.c, so that both GDB and GDBserver can use it. gdb: 2015-10-12 Yao Qi * arch/aarch64-insn.c (aarch64_decode_ldr_literal): Moved from gdbserver/linux-aarch64-low.c. (aarch64_relocate_instruction): Likewise. * arch/aarch64-insn.h (aarch64_decode_ldr_literal): Declare. (struct aarch64_insn_data): Moved from gdbserver/linux-aarch64-low.c. (struct aarch64_insn_visitor): Likewise. (aarch64_relocate_instruction): Declare. gdb/gdbserver: 2015-10-12 Yao Qi * linux-aarch64-low.c (extract_signed_bitfield): Remove. (aarch64_decode_ldr_literal): Move to gdb/arch/aarch64-insn.c. (aarch64_relocate_instruction): Likewise. (struct aarch64_insn_data): Move to gdb/arch/aarch64-insn.h. (struct aarch64_insn_visitor): Likewise. --- gdb/ChangeLog | 11 +++ gdb/arch/aarch64-insn.c | 93 ++++++++++++++++++ gdb/arch/aarch64-insn.h | 50 ++++++++++ gdb/gdbserver/ChangeLog | 8 ++ gdb/gdbserver/linux-aarch64-low.c | 155 ------------------------------ 5 files changed, 162 insertions(+), 155 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index e760bd00620..f79c93df0fb 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,14 @@ +2015-10-12 Yao Qi + + * arch/aarch64-insn.c (aarch64_decode_ldr_literal): Moved from + gdbserver/linux-aarch64-low.c. + (aarch64_relocate_instruction): Likewise. + * arch/aarch64-insn.h (aarch64_decode_ldr_literal): Declare. + (struct aarch64_insn_data): Moved from + gdbserver/linux-aarch64-low.c. + (struct aarch64_insn_visitor): Likewise. + (aarch64_relocate_instruction): Declare. + 2015-10-12 Pierre-Marie de Rodat * eval.c (evaluate_subexp_standard) : If diff --git a/gdb/arch/aarch64-insn.c b/gdb/arch/aarch64-insn.c index 13d0013d6e9..d0e88fa88d1 100644 --- a/gdb/arch/aarch64-insn.c +++ b/gdb/arch/aarch64-insn.c @@ -235,3 +235,96 @@ aarch64_decode_tb (CORE_ADDR addr, uint32_t insn, int *is_tbnz, } return 0; } + +/* Decode an opcode if it represents an LDR or LDRSW instruction taking a + literal offset from the current PC. + + ADDR specifies the address of the opcode. + INSN specifies the opcode to test. + IS_W is set if the instruction is LDRSW. + IS64 receives size field from the decoded instruction. + RT receives the 'rt' field from the decoded instruction. + OFFSET receives the 'imm' field from the decoded instruction. + + Return 1 if the opcodes matches and is decoded, otherwise 0. */ + +int +aarch64_decode_ldr_literal (CORE_ADDR addr, uint32_t insn, int *is_w, + int *is64, unsigned *rt, int32_t *offset) +{ + /* LDR 0T01 1000 iiii iiii iiii iiii iiir rrrr */ + /* LDRSW 1001 1000 iiii iiii iiii iiii iiir rrrr */ + if ((insn & 0x3f000000) == 0x18000000) + { + *is_w = (insn >> 31) & 0x1; + + if (*is_w) + { + /* LDRSW always takes a 64-bit destination registers. */ + *is64 = 1; + } + else + *is64 = (insn >> 30) & 0x1; + + *rt = (insn >> 0) & 0x1f; + *offset = extract_signed_bitfield (insn, 19, 5) << 2; + + if (aarch64_debug) + debug_printf ("decode: %s 0x%x %s %s%u, #?\n", + core_addr_to_string_nz (addr), insn, + *is_w ? "ldrsw" : "ldr", + *is64 ? "x" : "w", *rt); + + return 1; + } + + return 0; +} + +/* Visit an instruction INSN by VISITOR with all needed information in DATA. + + PC relative instructions need to be handled specifically: + + - B/BL + - B.COND + - CBZ/CBNZ + - TBZ/TBNZ + - ADR/ADRP + - LDR/LDRSW (literal) */ + +void +aarch64_relocate_instruction (uint32_t insn, + const struct aarch64_insn_visitor *visitor, + struct aarch64_insn_data *data) +{ + int is_bl; + int is64; + int is_sw; + int is_cbnz; + int is_tbnz; + int is_adrp; + unsigned rn; + unsigned rt; + unsigned rd; + unsigned cond; + unsigned bit; + int32_t offset; + + if (aarch64_decode_b (data->insn_addr, insn, &is_bl, &offset)) + visitor->b (is_bl, offset, data); + else if (aarch64_decode_bcond (data->insn_addr, insn, &cond, &offset)) + visitor->b_cond (cond, offset, data); + else if (aarch64_decode_cb (data->insn_addr, insn, &is64, &is_cbnz, &rn, + &offset)) + visitor->cb (offset, is_cbnz, rn, is64, data); + else if (aarch64_decode_tb (data->insn_addr, insn, &is_tbnz, &bit, &rt, + &offset)) + visitor->tb (offset, is_tbnz, rt, bit, data); + else if (aarch64_decode_adr (data->insn_addr, insn, &is_adrp, &rd, &offset)) + visitor->adr (offset, rd, is_adrp, data); + else if (aarch64_decode_ldr_literal (data->insn_addr, insn, &is_sw, &is64, + &rt, &offset)) + visitor->ldr_literal (offset, is_sw, rt, is64, data); + else + visitor->others (insn, data); +} diff --git a/gdb/arch/aarch64-insn.h b/gdb/arch/aarch64-insn.h index 2facb44aea8..47f671565bd 100644 --- a/gdb/arch/aarch64-insn.h +++ b/gdb/arch/aarch64-insn.h @@ -36,4 +36,54 @@ int aarch64_decode_cb (CORE_ADDR addr, uint32_t insn, int *is64, int aarch64_decode_tb (CORE_ADDR addr, uint32_t insn, int *is_tbnz, unsigned *bit, unsigned *rt, int32_t *imm); +int aarch64_decode_ldr_literal (CORE_ADDR addr, uint32_t insn, int *is_w, + int *is64, unsigned *rt, int32_t *offset); + +/* Data passed to each method of aarch64_insn_visitor. */ + +struct aarch64_insn_data +{ + /* The instruction address. */ + CORE_ADDR insn_addr; +}; + +/* Visit different instructions by different methods. */ + +struct aarch64_insn_visitor +{ + /* Visit instruction B/BL OFFSET. */ + void (*b) (const int is_bl, const int32_t offset, + struct aarch64_insn_data *data); + + /* Visit instruction B.COND OFFSET. */ + void (*b_cond) (const unsigned cond, const int32_t offset, + struct aarch64_insn_data *data); + + /* Visit instruction CBZ/CBNZ Rn, OFFSET. */ + void (*cb) (const int32_t offset, const int is_cbnz, + const unsigned rn, int is64, + struct aarch64_insn_data *data); + + /* Visit instruction TBZ/TBNZ Rt, #BIT, OFFSET. */ + void (*tb) (const int32_t offset, int is_tbnz, + const unsigned rt, unsigned bit, + struct aarch64_insn_data *data); + + /* Visit instruction ADR/ADRP Rd, OFFSET. */ + void (*adr) (const int32_t offset, const unsigned rd, + const int is_adrp, struct aarch64_insn_data *data); + + /* Visit instruction LDR/LDRSW Rt, OFFSET. */ + void (*ldr_literal) (const int32_t offset, const int is_sw, + const unsigned rt, const int is64, + struct aarch64_insn_data *data); + + /* Visit instruction INSN of other kinds. */ + void (*others) (const uint32_t insn, struct aarch64_insn_data *data); +}; + +void aarch64_relocate_instruction (uint32_t insn, + const struct aarch64_insn_visitor *visitor, + struct aarch64_insn_data *data); + #endif diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index f72a0e249e2..6d3d66de280 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,11 @@ +2015-10-12 Yao Qi + + * linux-aarch64-low.c (extract_signed_bitfield): Remove. + (aarch64_decode_ldr_literal): Move to gdb/arch/aarch64-insn.c. + (aarch64_relocate_instruction): Likewise. + (struct aarch64_insn_data): Move to gdb/arch/aarch64-insn.h. + (struct aarch64_insn_visitor): Likewise. + 2015-10-12 Yao Qi * linux-aarch64-low.c (struct aarch64_insn_data): New. diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c index b4181ed53f7..1241434f080 100644 --- a/gdb/gdbserver/linux-aarch64-low.c +++ b/gdb/gdbserver/linux-aarch64-low.c @@ -584,70 +584,6 @@ aarch64_get_thread_area (int lwpid, CORE_ADDR *addrp) return 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; -} - -/* Decode an opcode if it represents an LDR or LDRSW instruction taking a - literal offset from the current PC. - - ADDR specifies the address of the opcode. - INSN specifies the opcode to test. - IS_W is set if the instruction is LDRSW. - IS64 receives size field from the decoded instruction. - RT receives the 'rt' field from the decoded instruction. - OFFSET receives the 'imm' field from the decoded instruction. - - Return 1 if the opcodes matches and is decoded, otherwise 0. */ - -int -aarch64_decode_ldr_literal (CORE_ADDR addr, uint32_t insn, int *is_w, - int *is64, unsigned *rt, int32_t *offset) -{ - /* LDR 0T01 1000 iiii iiii iiii iiii iiir rrrr */ - /* LDRSW 1001 1000 iiii iiii iiii iiii iiir rrrr */ - if ((insn & 0x3f000000) == 0x18000000) - { - *is_w = (insn >> 31) & 0x1; - - if (*is_w) - { - /* LDRSW always takes a 64-bit destination registers. */ - *is64 = 1; - } - else - *is64 = (insn >> 30) & 0x1; - - *rt = (insn >> 0) & 0x1f; - *offset = extract_signed_bitfield (insn, 19, 5) << 2; - - if (aarch64_debug) - debug_printf ("decode: %s 0x%x %s %s%u, #?\n", - core_addr_to_string_nz (addr), insn, - *is_w ? "ldrsw" : "ldr", - *is64 ? "x" : "w", *rt); - - return 1; - } - - return 0; -} - /* List of opcodes that we need for building the jump pad and relocating an instruction. */ @@ -1924,49 +1860,6 @@ can_encode_int32 (int32_t val, unsigned bits) return rest == 0 || rest == -1; } -/* Data passed to each method of aarch64_insn_visitor. */ - -struct aarch64_insn_data -{ - /* The instruction address. */ - CORE_ADDR insn_addr; -}; - -/* Visit different instructions by different methods. */ - -struct aarch64_insn_visitor -{ - /* Visit instruction B/BL OFFSET. */ - void (*b) (const int is_bl, const int32_t offset, - struct aarch64_insn_data *data); - - /* Visit instruction B.COND OFFSET. */ - void (*b_cond) (const unsigned cond, const int32_t offset, - struct aarch64_insn_data *data); - - /* Visit instruction CBZ/CBNZ Rn, OFFSET. */ - void (*cb) (const int32_t offset, const int is_cbnz, - const unsigned rn, int is64, - struct aarch64_insn_data *data); - - /* Visit instruction TBZ/TBNZ Rt, #BIT, OFFSET. */ - void (*tb) (const int32_t offset, int is_tbnz, - const unsigned rt, unsigned bit, - struct aarch64_insn_data *data); - - /* Visit instruction ADR/ADRP Rd, OFFSET. */ - void (*adr) (const int32_t offset, const unsigned rd, - const int is_adrp, struct aarch64_insn_data *data); - - /* Visit instruction LDR/LDRSW Rt, OFFSET. */ - void (*ldr_literal) (const int32_t offset, const int is_sw, - const unsigned rt, const int is64, - struct aarch64_insn_data *data); - - /* Visit instruction INSN of other kinds. */ - void (*others) (const uint32_t insn, struct aarch64_insn_data *data); -}; - /* Sub-class of struct aarch64_insn_data, store information of instruction relocation for fast tracepoint. Visitor can relocate an instruction from BASE.INSN_ADDR to NEW_ADDR and save @@ -2195,54 +2088,6 @@ static const struct aarch64_insn_visitor visitor = aarch64_ftrace_insn_reloc_others, }; -/* Visit an instruction INSN by VISITOR with all needed information in DATA. - - PC relative instructions need to be handled specifically: - - - B/BL - - B.COND - - CBZ/CBNZ - - TBZ/TBNZ - - ADR/ADRP - - LDR/LDRSW (literal) */ - -static void -aarch64_relocate_instruction (uint32_t insn, - const struct aarch64_insn_visitor *visitor, - struct aarch64_insn_data *data) -{ - int is_bl; - int is64; - int is_sw; - int is_cbnz; - int is_tbnz; - int is_adrp; - unsigned rn; - unsigned rt; - unsigned rd; - unsigned cond; - unsigned bit; - int32_t offset; - - if (aarch64_decode_b (data->insn_addr, insn, &is_bl, &offset)) - visitor->b (is_bl, offset, data); - else if (aarch64_decode_bcond (data->insn_addr, insn, &cond, &offset)) - visitor->b_cond (cond, offset, data); - else if (aarch64_decode_cb (data->insn_addr, insn, &is64, &is_cbnz, &rn, - &offset)) - visitor->cb (offset, is_cbnz, rn, is64, data); - else if (aarch64_decode_tb (data->insn_addr, insn, &is_tbnz, &bit, &rt, - &offset)) - visitor->tb (offset, is_tbnz, rt, bit, data); - else if (aarch64_decode_adr (data->insn_addr, insn, &is_adrp, &rd, &offset)) - visitor->adr (offset, rd, is_adrp, data); - else if (aarch64_decode_ldr_literal (data->insn_addr, insn, &is_sw, &is64, - &rt, &offset)) - visitor->ldr_literal (offset, is_sw, rt, is64, data); - else - visitor->others (insn, data); -} - /* Implementation of linux_target_ops method "install_fast_tracepoint_jump_pad". */ -- 2.30.2