From patchwork Wed Oct 14 11:14:31 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: 9114 Received: (qmail 116268 invoked by alias); 14 Oct 2015 15:15:05 -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 116191 invoked by uid 89); 14 Oct 2015 15:15:05 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-0.3 required=5.0 tests=AWL, BAYES_00, 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:14:56 +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 t9EBEZ44010725 for ; Wed, 14 Oct 2015 04:14:35 -0700 (PDT) Received: by arn-build2.wrs.com (Postfix, from userid 18580) id 01B91220D5E; Wed, 14 Oct 2015 13:14:34 +0200 (CEST) From: henrik.wallin@windriver.com To: gdb-patches@sourceware.org Subject: [RFC][PATCH 13/15] gdbserver: Add arm_install_fast_tracepoint_jump_pad Date: Wed, 14 Oct 2015 13:14:31 +0200 Message-Id: <3365a9fee5668182c0906efdb316113998683bbd.1444820235.git.henrik.wallin@windriver.com> In-Reply-To: References: In-Reply-To: References: From: Henrik Wallin This adds the function. No users yet. Installs the jump pad. It handles arm and thumb mode. It will fail if it turns out that the distance to jump is too far away, or if the relocation done by the gdb side returns "not possible". gdb/gdbserver/ChangeLog: * linux-arm-low.c (append_insns) : New function. (copy_instruction) : New function. (arm_install_fast_tracepoint_jump_pad): New function. Signed-off-by: Henrik Wallin --- gdb/gdbserver/linux-arm-low.c | 229 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c index 1853e79bc140..6bb069fe71bb 100644 --- a/gdb/gdbserver/linux-arm-low.c +++ b/gdb/gdbserver/linux-arm-low.c @@ -926,6 +926,21 @@ is_target_arm (CORE_ADDR to, CORE_ADDR from) return (to == ptr) ? 0 : 1; } +static void +append_insns (CORE_ADDR *to, size_t len, const unsigned char *buf) +{ + write_inferior_memory (*to, buf, len); + *to += len; +} + +static int +copy_instruction (CORE_ADDR *to, CORE_ADDR from, size_t len) +{ + CORE_ADDR before = *to; + relocate_instruction (to, from); + return (before == *to) ? -1 : 1; +} + static uint32_t mk_t_b_rel (CORE_ADDR from, CORE_ADDR to) { @@ -1060,6 +1075,220 @@ mk_a_load_instr (uint32_t *mem, int reg, uint32_t val) return mem; } +static int +arm_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, + CORE_ADDR tpaddr, + CORE_ADDR collector, + CORE_ADDR lockaddr, + ULONGEST orig_size, + CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, + unsigned char *jjump_pad_insn, + ULONGEST *jjump_pad_insn_size, + CORE_ADDR *adjusted_insn_addr, + CORE_ADDR *adjusted_insn_addr_end, + char *err) +{ + unsigned char buf[0x100]; + CORE_ADDR buildaddr = *jump_entry; + + /* Register usage: + r0 - arg1:tpoint / tmp + r1 - arg2:sp + r2 - collector + r3 - tmp + r4 - lockaddr + r5 - saved sp / collector_t */ + + if (is_target_arm(buildaddr, tpaddr)) /* arm mode */ + { + uint32_t *ptr = (uint32_t *) buf; + + *ptr++ = 0xe92d5fff; /* push { r0-r12,lr } */ + *ptr++ = 0xe10f0000; /* mrs r0,cpsr */ + *ptr++ = 0xe52d0004; /* push r0 */ + + ptr = mk_a_load_instr (ptr, 0, (uint32_t) tpaddr); + *ptr++ = 0xe52d0004; /* push r0 (orig pc) */ + *ptr++ = 0xe1a0100d; /* mov r1, sp (regs:arg2) */ + + ptr = mk_a_load_instr (ptr, 0, 0xffff0fe0); + ptr = mk_a_blx_instr (ptr, 0); + *ptr++ = 0xe52d0004; /* push r0 (tls) */ + + ptr = mk_a_load_instr (ptr, 0, (uint32_t) tpoint); + *ptr++ = 0xe52d0004; /* push r0 (tpoint:arg1) */ + ptr = mk_a_load_instr (ptr, 2, (uint32_t) collector); + ptr = mk_a_load_instr (ptr, 4, (uint32_t) lockaddr); + + *ptr++ = 0xe1a0500d; /* mov r5, sp */ + *ptr++ = 0xf57ff05f; /* 1: dmb sy */ + *ptr++ = 0xe1943f9f; /* 2: ldrex r3, [r4] */ + *ptr++ = 0xe3530000; /* cmp r3, #0 */ + *ptr++ = 0x1a000002; /* bne 3 */ + *ptr++ = 0xe184ef95; /* strex r14, r5, [r4] */ + *ptr++ = 0xe35e0000; /* cmp r14, #0 */ + *ptr++ = 0x1afffff9; /* bne 2 */ + *ptr++ = 0xf57ff05f; /* 3: dmb sy */ + *ptr++ = 0x1afffff6; /* bne 1 */ + + *ptr++ = 0xe3c53007; /* bic r3, r5, 7 */ + *ptr++ = 0xe1a0d003; /* mov sp, r3 */ + ptr = mk_a_blx_instr (ptr, 2); + *ptr++ = 0xe1a0d005; /* mov sp, r5 */ + + *ptr++ = 0xe3a03000; /* mov r3, #0 */ + *ptr++ = 0xe5843000; /* str r3, [r4] */ + + *ptr++ = 0xe28dd00c; /* add sp, sp, #12 */ + *ptr++ = 0xe49d0004; /* pop r0 */ + *ptr++ = 0xe12cf000; /* msr cpsr,r0 */ + *ptr++ = 0xe8bd5fff; /* pop { r0-r12,lr } */ + + append_insns (&buildaddr, (uint32_t) ptr - (uint32_t) buf, buf); + + *adjusted_insn_addr = buildaddr; + if (copy_instruction (&buildaddr, tpaddr, 4) < 0) + { + strcpy (err, "E.Cannot move instruction to jump_pad. " + "Not possible to relocate."); + return 1; + } + *adjusted_insn_addr_end = buildaddr; + + /* Possible improvements: + This branch can be made non-relative: + B : + push {r0,r1} + movw r0, # + movt r0, # + str r0, [sp, #4] + pop {r0,pc} */ + if (!mk_a_b_isreachable (buildaddr, tpaddr + 4)) + { + strcpy (err, "E.Cannot construct valid branch " + "instruction for fast tracepoint." + " Too long relative branch."); + return 1; + } + /* b */ + (void) mk_a_b_instr ((uint32_t *) buf, buildaddr, tpaddr + 4); + append_insns (&buildaddr, 4, buf); + + /* write tp instr. */ + if (!mk_a_b_isreachable (tpaddr, *jump_entry)) + { + strcpy (err, "E.Cannot construct valid branch " + "instruction for fast tracepoint." + " Too long relative branch."); + return 1; + } + (void) mk_a_b_instr ((uint32_t *) jjump_pad_insn, tpaddr, *jump_entry); + *jjump_pad_insn_size = 4; + *jump_entry = buildaddr; + } + else /* thumb mode */ + { + uint16_t *ptr = (uint16_t *) buf; + + *ptr++ = 0xe92d; /* push { r0-r12,lr } */ + *ptr++ = 0x5fff; + *ptr++ = 0xf3ef; /* mrs r0,cpsr */ + *ptr++ = 0x8000; + *ptr++ = 0xb401; /* push r0 */ + + ptr = mk_t_load_instr (ptr, 0, (uint32_t) tpaddr); + *ptr++ = 0xb401; /* push r0 (orig pc) */ + *ptr++ = 0x4669; /* mov r1, sp (regs:arg2) */ + + ptr = mk_t_load_instr (ptr, 0, 0xffff0fe0); + ptr = mk_t_blx_instr (ptr, 0); + *ptr++ = 0xb401; /* push r0 (tls) */ + + ptr = mk_t_load_instr (ptr, 0, (uint32_t) tpoint); + *ptr++ = 0xb401; /* push r0 (tpoint:arg1) */ + ptr = mk_t_load_instr (ptr, 2, (uint32_t) collector); + ptr = mk_t_load_instr (ptr, 4, (uint32_t) lockaddr); + + *ptr++ = 0x466d; /* mov r5, sp */ + *ptr++ = 0xf3bf; /* 1: dmb sy */ + *ptr++ = 0x8f5f; + *ptr++ = 0xe854; /* 2: ldrex r3, [r4] */ + *ptr++ = 0x3f00; + *ptr++ = 0x2b00; /* cmp r3, #0 */ + *ptr++ = 0xd104; /* bne.n 3 */ + *ptr++ = 0xe844; /* strex r14, r5, [r4] */ + *ptr++ = 0x5e00; + *ptr++ = 0xf1be; /* cmp.w r14, #0 */ + *ptr++ = 0x0f00; + *ptr++ = 0xd1f6; /* bne.n 2 */ + *ptr++ = 0xf3bf; /* 3. dmb sy */ + *ptr++ = 0x8f5f; + *ptr++ = 0xd1f1; /* bne.n 1 */ + + *ptr++ = 0xf025; /* bic r3, r5, 7 */ + *ptr++ = 0x0307; + *ptr++ = 0x469d; /* mov sp, r3 */ + ptr = mk_t_blx_instr (ptr, 2); + *ptr++ = 0x46ad; /* mov sp, r5 */ + + *ptr++ = 0xf04f; /* mov r3, #0 */ + *ptr++ = 0x0300; + *ptr++ = 0x6023; /* str r3, [r4] */ + + *ptr++ = 0xb003; /* add sp, #12 */ + *ptr++ = 0xbc01; /* pop r0 */ + *ptr++ = 0xf380; /* msr cpsr,r0 */ + *ptr++ = 0x8c00; + *ptr++ = 0xe8bd; /* pop { r0-r12,lr } */ + *ptr++ = 0x5fff; + + append_insns (&buildaddr, (uint32_t) ptr - (uint32_t) buf, buf); + + *adjusted_insn_addr = buildaddr; + if (copy_instruction (&buildaddr, tpaddr, 4) < 0) + { + strcpy (err, "E.Cannot move instruction to jump_pad." + " Not possible to relocate."); + return 1; + } + *adjusted_insn_addr_end = buildaddr; + + /* Possible improvements: + This branch can be made non-relative: + B : + push {r0,r1} + movw r0, # + movt r0, # + str r0, [sp, #4] + pop {r0,pc} */ + if (!mk_t_b_isreachable (buildaddr, tpaddr + 4)) + { + strcpy (err, "E.Cannot construct valid branch " + "instruction for fast tracepoint." + "Too long relative branch."); + return 1; + } + (void) mk_t_b_instr ((uint16_t *) buf, buildaddr, tpaddr + 4); + append_insns (&buildaddr, 4, buf); + + /* write tp instr. */ + if (!mk_t_b_isreachable (tpaddr, *jump_entry)) + { + strcpy (err, "E.Cannot construct valid branch " + "instruction for fast tracepoint." + "Too long relative branch."); + return 1; + } + (void) mk_t_b_instr ((uint16_t *) jjump_pad_insn, tpaddr, *jump_entry); + *jjump_pad_insn_size = 4; + *jump_entry = buildaddr; + } + + return 0; +} + struct linux_target_ops the_low_target = { arm_arch_setup, arm_regs_info,