From patchwork Wed Oct 14 11:14:27 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: henrik.wallin@windriver.com X-Patchwork-Id: 9115 Received: (qmail 15748 invoked by alias); 14 Oct 2015 15:21:42 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 15732 invoked by uid 89); 14 Oct 2015 15:21:42 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=1.0 required=5.0 tests=AWL, BAYES_50, KAM_LAZY_DOMAIN_SECURITY, T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mail.windriver.com Received: from mail.windriver.com (HELO mail.windriver.com) (147.11.1.11) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Wed, 14 Oct 2015 15:21:39 +0000 Received: from arn-build2.wrs.com (arn-build2.wrs.com [128.224.95.15]) by mail.windriver.com (8.15.2/8.15.1) with ESMTP id t9EBEZCU010721 for ; Wed, 14 Oct 2015 04:14:35 -0700 (PDT) Received: by arn-build2.wrs.com (Postfix, from userid 18580) id E8376220B36; Wed, 14 Oct 2015 13:14:33 +0200 (CEST) From: henrik.wallin@windriver.com To: gdb-patches@sourceware.org Subject: [RFC][PATCH 09/15] gdb: Add relocate instruction helpers Date: Wed, 14 Oct 2015 13:14:27 +0200 Message-Id: In-Reply-To: References: In-Reply-To: References: From: Henrik Wallin This adds the functions. No users yet. The functions are used both when validating an instruction when the users sets a fast tracepoint and when relocating an instruction when gdbserver/ipa installs the jump pad. Currently all PC relative instructions are considered not relocatable. Futher improvements can be made by rewriting some of those instructions with alternative instructions. gdb/ChangeLog: * arm-tdep.c : Add relocate functionality to be used by fast tracepoint support. Signed-off-by: Henrik Wallin --- gdb/arm-tdep.c | 599 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 599 insertions(+) diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 4c99ddfe89cb..b277c3ef405c 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -9907,6 +9907,605 @@ arm_register_g_packet_guesses (struct gdbarch *gdbarch) /* Otherwise we don't have a useful guess. */ } +/* Local structure to pass information in and out of the relocate + helper functions */ +struct relocate_insn +{ + struct gdbarch *gdbarch; + CORE_ADDR *to; + CORE_ADDR oldloc; + enum bfd_endian byte_order_for_code; + int result; /* 0: copy unmodif, >0: handled, <0: not possible */ +}; + +static void +append_insns (CORE_ADDR *to, ULONGEST len, uint32_t insn, + enum bfd_endian byte_order) +{ + write_memory_unsigned_integer (*to, len, byte_order, insn); + *to += len; +} + +static void +arm_relocate_insn_arm (struct relocate_insn *rel, uint32_t insn) +{ + unsigned int cond = bits (insn, 28, 31); + unsigned int op = (bits (insn, 25, 27) << 1) | bit (insn, 4); + + /* 1111 ---- ---- ---- ---- ---- ---- ---- : + unconditional instructions */ + if (cond == 15) + { + /* 1111 0--- ---- ---- ---- ---- ---- ---- : + Memory hints, Advanced SIMD instructions, and + miscellaneous instructions */ + if (bit (insn, 27) == 0) + { + unsigned int op1 = bits (insn, 20, 26); + unsigned int op2 = bits (insn, 4, 7); + unsigned int rn = bits (insn, 16, 19); + + /* All variants we are interested in have rn == 15 - check first */ + if (rn == 15) + { + /* 1111 0100 x101 1111 ---- ---- ---- ---- : + PLI (literal) */ + if ((op1 & 0x77) == 0x45) + rel->result = -1; + /* 1111 0101 x101 1111 ---- ---- ---- ---- : + PLD (literal) */ + else if ((op1 & 0x77) == 0x55) + rel->result = -1; + /* 1111 0110 x101 1111 ---- ---- ---0 ---- : + PLI (register) */ + else if ((op1 & 0x77) == 0x65 && (op2 & 0x1) == 0x0) + rel->result = -1; + /* 1111 0111 xx01 1111 ---- ---- ---0 ---- : + PLD, PLDW (register) */ + else if ((op1 & 0x73) == 0x71 && (op2 & 0x1) == 0x0) + rel->result = -1; + } + } + /* 1111 101- ---- ---- ---- ---- ---- ---- : + BL, BLX (immediate) */ + else if (bits (insn, 25, 27) == 5) + rel->result = -1; + /* 1111 110x xxxx ---- ---- ---- ---- ---- : + STC/STC2, LDC/LDC2 ( x != 00x0x) */ + else if (bits (insn, 25, 27) == 6 && + (bits (insn, 20, 24) & 0x1A) != 0x0) + { + unsigned int rn = bits (insn, 16, 19); + if (rn == 15) + rel->result = -1; + } + } + + /* ---- 00x- ---- ---- ---- ---- ---x ---- : + Data-processing and miscellaneous instructions */ + else if (op <= 3) + { + unsigned int op1 = bits (insn, 20, 24); + unsigned int op2 = bits (insn, 4, 7); + + if (bit (insn, 25) == 0) + { + /* ---- 000x xxxx ---- ---- ---- xxx0 ---- : + Data-processing (register) ( x != 10xx0 ) */ + if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0) { + unsigned int rm = bits (insn, 0, 3); + unsigned int rn = bits (insn, 16, 19); + + /* ---- 000x xxxx nnnn ---- ---- xxx0 mmmm : + AND,EOR,SUB,RSB,ADD,ADC,SBC,RSC,TST,TEQ, + CMP,CMN,ORR,MOV,LSL,LSR,ASR,RRX,ROR,BIC,MVN */ + if (rn == 15 || rm == 15) + rel->result = -1; + } + /* ---- 000x xxxx ---- ---- ---- xxx1 ---- : + Data-processing (register-shifted register) */ + else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1) + { + ; + } + + /* ---- 0001 0xx0 ---- ---- ---- 0xxx ---- : + Miscellaneous instructions */ + else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0) + { + /* ---- 0001 0010 ---- ---- ---- 0011 ---- : + BLX (register) */ + if (bits (insn, 4, 6) == 3 && bits (insn, 21, 22) == 1) /* BLX */ + rel->result = -1; + } + /* ---- 0001 0xx0 ---- ---- ---- 1xx0 ---- : + Halfword multiply and multiply accumulate */ + else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8) + { + ; + } + /* ---- 0000 xxxx ---- ---- ---- 1001 ---- : + Multiply and multiply accumulate */ + else if ((op1 & 0x10) == 0x00 && op2 == 0x9) + { + ; + } + /* ---- 0001 xxxx ---- ---- ---- 1001 ---- : + Synchronization primitives */ + else if ((op1 & 0x10) == 0x10 && op2 == 0x9) + { + ; + } + /* ---- 000x xxxx ---- ---- ---- 1xx1 ---- : + Extra load/store instructions */ + else if (op2 == 0xB || (op2 & 0xd) == 0xd) + { + unsigned int rn = bits (insn, 16, 19); + /* ---- 000x xxxx 1111 ---- ---- 1xx1 ---- : + STRH, LDRH, LDRD, LDRSB */ + if (rn == 15) + rel->result = -1; + } + } + else + { + /* ---- 001x xxxx ---- ---- ---- ---- ---- : + Data-processing (immediate) */ + if ((op1 & 0x19) != 0x10) + { + unsigned int op = bits (insn, 21, 24); + unsigned int op2 = bits (insn, 20, 24); + unsigned int rn = bits (insn, 16, 19); + + if (rn == 15) /* Only check those with n == 15 */ + { + /* ---- 0010 xxxx 1111 ---- ---- ---- ---- : + AND, EOR, ADR, RSB, ADR, ADC, SBC, RSC */ + if (op <= 7) + rel->result = -1; + /* ---- 0011 0xx1 1111 ---- ---- ---- ---- : + TST, TEQ, CMP, CMN */ + else if ((op2 & 0x19) == 0x11) + rel->result = -1; + /* ---- 0011 1x0x 1111 ---- ---- ---- ---- : + ORR, BIC */ + else if (op == 0xC || op == 0xE) + rel->result = -1; + /* ---- 0011 1x1x 1111 ---- ---- ---- ---- : + MOV, MVN */ + else if (op == 0xD || op == 0xF) + { + ; + } + } + } + } + } + + /* ---- 01A- ---- ---- ---- ---- ---B ---- : + Load/store word and unsigned byte */ + else if (op <= 6) + { + unsigned int a = bit (insn, 25); + unsigned int rt = bits (insn, 12, 15); + unsigned int rn = bits (insn, 16, 19); + unsigned int op1 = bits (insn, 20, 24); + unsigned int op1_m1 = (op1 & 0x17); + unsigned int op1_m2 = (op1 & 0x5); + + /* a and b can not both be 1 - no need to test for b */ + + /* ---- 01Ax xxxx nnnn ---- ---- ---B ---- : + STR (immediate), STR (register) */ + if (op1_m2 == 0x00 && op1_m1 != 0x02) + { + if (rt == 15 || rn == 15) + rel->result = -1; + } + /* ---- 01Ax xxxx nnnn ---- ---- ---B ---- : + STRT */ + else if (op1_m1 == 0x02) + { + if (rt == 15) + rel->result = -1; + } + /* ---- 01Ax xxxx nnnn ---- ---- ---B ---- : + LDR (literal) */ + else if (op1_m2 == 0x01 && op1_m1 != 0x03) + { + if (rn == 15) + rel->result = -1; + } + /* ---- 01Ax xxxx nnnn ---- ---- ---B ---- : + LDRT */ + else if (op1_m1 == 0x03) + { + ; + } + /* ---- 01Ax xxxx nnnn ---- ---- ---B ---- : + STRB (immediate), STRB (register) */ + else if (op1_m2 == 0x04 && op1_m1 != 0x06) + { + if (rn == 15) + rel->result = -1; + } + /* ---- 01Ax xxxx nnnn ---- ---- ---B ---- : + STRBT */ + else if (op1_m1 == 0x06) + { + ; + } + /* ---- 01Ax xxxx nnnn ---- ---- ---B ---- : + LDRB (immediate), LDRB (register) */ + else if (op1_m2 == 0x05 && op1_m1 != 0x07) + { + if (rn == 15) + rel->result = -1; + } + /* ---- 01Ax xxxx nnnn ---- ---- ---B ---- : + LDRBT */ + else if (op1_m1 == 0x07) + { + ; + } + } + + /* ---- 011- ---- ---- ---- ---- ---1 ---- : + Media instructions */ + else if (op <= 7) + { + ; + } + + /* ---- 10x- ---- ---- ---- ---- ---x ---- : + Branch, branch with link, and block data transfer */ + else if (op <= 11) + { + unsigned int op1 = bits (insn, 20, 24); + unsigned int r = bit (insn, 15); + unsigned int rn = bits (insn, 16, 19); + + /* ---- 101x xxxx nnnn r--- ---- ---- ---- : + B, BL, BLX */ + if (bit (insn, 25)) + rel->result = -1; + /* ---- 100x xxx0 nnnn r--- ---- ---- ---- : + STMDA, STM, STMDB, STMIB */ + else if (bit (insn, 20) == 0) + { + if (rn == 15 || r == 1) + rel->result = -1; + } + /* ---- 100x xxx1 nnnn r--- ---- ---- ---- : + LDMDA, LDM/LDMIALDMFD, LDMDB/LDMEA, LSMIB/LDMED */ + else + { + ; + } + } + + /* ---- 11x- ---- ---- ---- ---- ---x ---- : + Coprocessor instructions, and Supervisor Call */ + else + { + unsigned int op1 = bits (insn, 20, 25); + unsigned int rn = bits (insn, 16, 19); + unsigned int coproc = bits (insn, 8, 11); + unsigned int op = bit (insn, 4); + + /* ---- 1100 000x nnnn ---- xxxx ---x ---- : + undefined */ + /* ---- 1111 xxxx nnnn ---- xxxx ---x ---- : + SVC */ + if ((op1 & 0x3E) == 0 || (op1 & 0x30) == 0x30) + { + ; + } + else if ((coproc & 0xE) != 0xA) + { + /* ---- 1100 010x nnnn ---- xxxx ---x ---- : + MCRR/MCRR2, MRRC/MRRC2 */ + if (op1 == 4 || op1 == 5) + { + ; + } + /* ---- 110x xxxx nnnn ---- xxxx ---x ---- : + STC/STC2, LDC/LDC2 */ + else if ((op1 & 0x20) == 0) + { + if (rn == 15) + rel->result = -1; + } + /* ---- 1110 xxxx nnnn ---- xxxx ---x ---- : + CDP/CDP2, MCR/MCR2, MRC/MRC2 */ + else if ((op1 & 0x30) == 0x20) + { + ; + } + } + else + { + /* ---- 110x xxxx nnnn ---- 101x ---x ---- : + Extension register load/store instructions */ + if ((op1 & 0x20) == 0 && (op1 & 0x3A) != 0) + { + /* ---- 110x xxxx 1111 ---- 101- ---- ---- : + VSTM, VSTR, VLDM, VLDR */ + if (rn == 15) + rel->result = -1; + } + } + } + + if (rel->to && rel->result == 0) + { + append_insns (rel->to, 4, insn, rel->byte_order_for_code); + } +} + +static void +arm_relocate_insn_thumb16 (struct relocate_insn *rel, uint16_t insn) +{ + unsigned short op = bits (insn, 10, 15); + + /* 0100 01-- ---- ---- : + Special data instructions and branch and exchange. */ + if (op == 0x11) + { + /* 0100 0111 1x-- ---- : + BLX (register) */ + if (bits (insn, 7, 9) == 7) + rel->result = -1; + /* 0100 01xx xx-- ---- : + ADD/MOV/CMP high registers. */ + else if (bits (insn, 6, 7) != 0) + { + if (bits (insn, 3, 6) == 15 || + ((bit (insn, 7) << 3) | bits (insn, 0, 2)) == 15) + rel->result = -1; + } + } + /* 0100 1x-- ---- ---- : + LDR (literal) */ + else if ((op & 0x3E) == 0x12) + rel->result = -1; + /* 1010 0x-- ---- ---- : + Generate PC-relative address (ADR) */ + else if ((op & 0x3E) == 0x28) + rel->result = -1; + /* 1011 xx-- ---- ---- : + Misc 16-bit instructions */ + else if ((op & 0x3C) == 0x2C) + { + unsigned short op2 = bits (insn, 8, 11); + /* 1011 x0x1 ---- ---- : + CBNZ, CBZ */ + if ((op2 & 0x5) == 0x1) + rel->result = -1; + /* 1011 1111 ---- xxxx : + IT */ + else if (op2 == 0xF && bits (insn, 0, 3) != 0) + rel->result = -1; + } + /* 1101 xx-- ---- ---- : + Conditional branch and supervisor calls */ + else if ((op & 0x3C) == 0x34) /* */ + { + /* 1101 xxxx ---- ---- : + B (conditional) */ + if (bits (insn, 9, 11) != 7) + rel->result = -1; + } + /* 1110 0x-- ---- ---- : + B (unconditional) */ + else if ((op & 0x3E) == 0x38) + rel->result = -1; + + if (rel->to && rel->result == 0) + append_insns (rel->to, 2, insn, rel->byte_order_for_code); +} + +static void +arm_relocate_insn_thumb32 (struct relocate_insn *rel, + uint16_t insn1, uint16_t insn2) +{ + unsigned int op1 = bits (insn1, 11, 12); + unsigned int op2 = bits (insn1, 4, 10); + unsigned short op = bit (insn2, 15); + + if (op1 == 1) + { + /* 1110 100x x1xx ---- x--- ---- ---- ---- : + Load/store dual, load/store excl, table branch */ + if ((op2 & 0x64) == 0x04) /* */ + { + unsigned int op1 = bits (insn1, 7, 8); + unsigned int op2 = bits (insn1, 4, 5); + /* 1110 1000 1101 ---- ---- ---- 000- ---- : + TBB, TBH */ + if (op1 == 1 && op2 == 1 && bits (insn2, 5, 7) == 0) + rel->result = -1; + /* 1110 1000 x111 1111 ---- ---- ---- ---- : + LDRD (literal) */ + /* 1110 1001 x1x1 1111 ---- ---- ---- ---- : + LDRD (literal) */ + else if (bits (insn1, 0, 3) == 15) + { + if (((op1 & 0x2) == 0 && op2 == 3) || + ((op1 & 0x2) == 2 && (op2 & 1) == 1)) + rel->result = -1; + } + } + /* 1110 11xx xxxx ---- x--- ---- ---- ---- : + Coprocessor, Advanced SIMD, and Floating-point instructions */ + else if ((op2 & 0x40) == 0x40) + { + unsigned int op3 = bits (insn1, 4, 9); + unsigned int coproc = bits (insn2, 9, 11); + /* 1110 1101 xx01 nnnn ---- 101x ---x ---- : + Extension register load/store instructions / VLDR */ + if (coproc == 5 && (op3 & 0x33) == 0x11) + rel->result = -1; + /* 1110 110x xxx1 nnnn ---- xxxx ---x ---- : + LDC/LDC2 (literal) */ + else if (coproc != 5 && (op3 & 0x21) == 1 && + (op3 & 0x3A) != 0 && bits (insn1, 0, 3) == 0xF) + rel->result = -1; + } + } + + else if (op1 == 2) + { + /* 1111 0xxx xxxx ---- 1--- ---- ---- ---- : + Branches and miscellaneous control */ + if (op) + { + /* 1111 0xxx xxxx ---- 11xx xxxx ---- ---- : + BL/BLX */ + if (bit (insn2, 14)) + rel->result = -1; + /* 1111 0xxx xxxx ---- 10x1 xxxx ---- ---- : + B (unconditional) */ + else if (bit (insn2, 12)) + rel->result = -1; + /* 1111 0xxx xxxx ---- 10x0 xxxx ---- ---- : + B (conditional) */ + else if (bits (insn1, 7, 9) != 0x7) + rel->result = -1; + } + /* 1111 0x1x xxxx ---- 0--- ---- ---- ---- : + Data processing (plain binary immediate) */ + else if (bit (insn1, 9)) + { + int op = bits (insn1, 4, 8); + int rn = bits (insn1, 0, 3); + /* 1111 0x1x x0x0 1111 0--- ---- ---- ---- : + ADR */ + if ((op == 0 || op == 0xa) && rn == 0xf) + rel->result = -1; + } + } + + else + { + /* 1111 100x x001 ---- x--- ---- ---- ---- : + Load byte, memory hints */ + if ((op2 & 0x67) == 0x1) + { + /* 1111 100x x001 nnnn tttt xxxx xx-- ---- : + LDRB (literal), PLD (literal), + LDRSB (literal), PLI (immediate, literal) */ + if (bits (insn1, 0, 3) == 15) + rel->result = -1; + } + /* 1111 100x x011 ---- x--- ---- ---- ---- : + Load halfword, memory hints */ + else if ((op2 & 0x67) == 0x3) + { + /* 1111 100x x011 nnnn tttt xxxx xx-- ---- : + LDRH (literal), LDRSH (literal) */ + if (bits (insn1, 0, 3) == 15 && bits (insn2, 12, 15) != 15) + rel->result = -1; + } + /* 1111 100x x101 ---- x--- ---- ---- ---- : + Load word */ + else if ((op2 & 0x67) == 0x5) + { + int rt = bits (insn2, 12, 15); + int rn = bits (insn1, 0, 3); + /* 1111 100x x101 1111 ---- xxxx xx-- ---- : + LDR (literal) */ + if (rn == 15) + rel->result = -1; + } + /* 1111 11xx xxxx ---- x--- ---- ---- ---- : + Coprocessor, Advanced SIMD, and Floating-point instructions */ + else if ((op2 & 0x40) == 0x40) + { + unsigned int op1_ = bits (insn1, 4, 9); + + /* 1111 110x xxx1 1111 ---- xxxx ---x ---- : + LDC, LDC2 (literal) */ + if ((bits (insn2, 8, 11) & 0xE) != 0xA && + (op1_ & 0x21) == 0x01 && (op1_ & 0x3A) != 0 && + bits (insn1, 0, 3) == 15) + rel->result = -1; + } + } + + if (rel->to && rel->result == 0) + { + append_insns (rel->to, 2, insn1, rel->byte_order_for_code); + append_insns (rel->to, 2, insn2, rel->byte_order_for_code); + } +} + +static void +arm_relocate_instruction_func (struct relocate_insn *rel) +{ + rel->byte_order_for_code = gdbarch_byte_order_for_code (rel->gdbarch); + rel->result = 0; + + if (arm_pc_is_thumb (rel->gdbarch, rel->oldloc)) + { + uint16_t insn1; + uint16_t insn2; + + insn1 = read_memory_unsigned_integer (rel->oldloc, 2, + rel->byte_order_for_code); + if (thumb_insn_size (insn1) == 2) + arm_relocate_insn_thumb16 (rel, insn1); + else + { + insn2 = read_memory_unsigned_integer (rel->oldloc + 2, 2, + rel->byte_order_for_code); + arm_relocate_insn_thumb32 (rel, insn1, insn2); + } + } + else + { + uint32_t insn; + + insn = read_memory_unsigned_integer (rel->oldloc, 4, + rel->byte_order_for_code); + arm_relocate_insn_arm (rel, insn); + } +} + +static int +arm_check_relocate_instruction (struct gdbarch *gdbarch, + CORE_ADDR oldloc, char **msg) +{ + struct relocate_insn rel; + + rel.gdbarch = gdbarch; + rel.to = NULL; + rel.oldloc = oldloc; + + arm_relocate_instruction_func (&rel); + + if (rel.result == -1) + { + if (msg) + *msg = xstrprintf (_("; instruction cannot be relocated")); + } + + return rel.result; +} + +static void +arm_relocate_instruction (struct gdbarch *gdbarch, + CORE_ADDR *to, CORE_ADDR oldloc) +{ + struct relocate_insn rel; + + rel.gdbarch = gdbarch; + rel.to = to; + rel.oldloc = oldloc; + + arm_relocate_instruction_func (&rel); +} + /* Initialize the current architecture based on INFO. If possible, re-use an architecture from ARCHES, which is a list of