From patchwork Tue Jul 5 13:40:30 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antoine Tremblay X-Patchwork-Id: 13654 Received: (qmail 67486 invoked by alias); 5 Jul 2016 13:42:02 -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 67436 invoked by uid 89); 5 Jul 2016 13:42:02 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.9 required=5.0 tests=BAYES_00, KAM_LAZY_DOMAIN_SECURITY autolearn=no version=3.3.2 spammy=sp, Assign, relocate, Relocation X-HELO: usplmg21.ericsson.net Received: from usplmg21.ericsson.net (HELO usplmg21.ericsson.net) (198.24.6.65) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Tue, 05 Jul 2016 13:41:51 +0000 Received: from EUSAAHC008.ericsson.se (Unknown_Domain [147.117.188.96]) by usplmg21.ericsson.net (Symantec Mail Security) with SMTP id CB.66.03614.3B8BB775; Tue, 5 Jul 2016 15:40:03 +0200 (CEST) Received: from elxa4wqvvz1.dyn.mo.ca.am.ericsson.se (147.117.188.8) by smtps-am.internal.ericsson.com (147.117.188.96) with Microsoft SMTP Server (TLS) id 14.3.294.0; Tue, 5 Jul 2016 09:40:56 -0400 From: Antoine Tremblay To: CC: Simon Marchi Subject: [PATCH v3 18/18] arm fast tracepoints: Relocation of Thumb 32-bits instructions Date: Tue, 5 Jul 2016 09:40:30 -0400 Message-ID: <1467726030-13020-19-git-send-email-antoine.tremblay@ericsson.com> In-Reply-To: <1467726030-13020-1-git-send-email-antoine.tremblay@ericsson.com> References: <1467726030-13020-1-git-send-email-antoine.tremblay@ericsson.com> MIME-Version: 1.0 X-IsSubscribed: yes From: Simon Marchi This patch adds the possibility to relocate some common 32-bits Thumb-mode instructions that may depend on the current value of the PC. As with the ARM-mode instructions, branches are very frequent and pc-relative. Therefore, we support relocating all kinds of branches. Other instructions are rejected if they reference the PC. gdb/gdbserver/ChangeLog: * linux-arm-low.c (thumb32_reloc_alu_imm): Implement. (thumb32_reloc_b_bl_blx): Likewise. (thumb32_reloc_block_xfer): Likewise. (thumb32_reloc_copro_load_store): Likewise. (thumb32_reloc_load_literal): Likewise. (thumb32_reloc_load_reg_imm): Likewise. (thumb32_reloc_pc_relative_32bit): Likewise. (thumb32_reloc_preload): Likewise. (thumb32_reloc_undef): Likewise. (thumb32_reloc_table_branch): Likewise. (copy_instruction_thumb32): Assign orig_loc and new_loc.. gdb/testsuite/ChangeLog: * gdb.trace/ftrace-arm-insn.S (func_thumb_b_imm): New function. (func_thumb_b_imm_cond): Likewise. (func_thumb_bl_imm): Likewise. (func_thumb_blx_imm): Likewise. (func_thumb_ldm): Likewise. (func_thumb_ldm_pc): Likewise. (func_thumb_stm): Likewise. * gdb.trace/ftrace-arm-insn.c (thumb_b_imm): New function. (thumb_b_imm_cond): Likewise. (thumb_bl_imm): Likewise. (thumb_blx_imm): Likewise. (thumb_ldm): Likewise. (thumb_ldm_pc): Likewise. (thumb_stm): Likewise. (main): Call the new functions. * gdb.trace/ftrace-arm-insn.exp: Test Thumb instructions relocation. --- gdb/NEWS | 4 + gdb/gdbserver/linux-arm-low.c | 175 ++++++++++++++++++++++++++-- gdb/testsuite/gdb.trace/ftrace-arm-insn.S | 157 +++++++++++++++++++++++++ gdb/testsuite/gdb.trace/ftrace-arm-insn.c | 16 +++ gdb/testsuite/gdb.trace/ftrace-arm-insn.exp | 8 ++ 5 files changed, 350 insertions(+), 10 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index e4d9efb..5f78226 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,10 @@ *** Changes since GDB 7.11 +* Support for fast tracepoints on arm-linux was added in GDBserver, + including JIT compiling fast tracepoint's conditional expression + bytecode into native code. + * Support for tracepoints on arm-linux was added in GDBServer. * Fortran: Support structures with fields of dynamic types and diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c index ea3fee8..595f8fc 100644 --- a/gdb/gdbserver/linux-arm-low.c +++ b/gdb/gdbserver/linux-arm-low.c @@ -1344,35 +1344,167 @@ static int thumb32_reloc_alu_imm (uint16_t insn1, uint16_t insn2, struct arm_insn_reloc_data *data) { - return 1; + uint16_t rm = bits (insn2, 0, 3); + uint16_t rd = bits (insn2, 8, 11); + + /* This is essentially about the MOV (register, Thumb) instruction. Allow + relocation if it doesn't reference the PC. */ + if (rm == ARM_PC_REGNUM || rd == ARM_PC_REGNUM) + return arm_reloc_refs_pc_error (data); + + return thumb32_reloc_others (insn1, insn2, "ALU imm", data); } static int thumb32_reloc_b_bl_blx (uint16_t insn1, uint16_t insn2, struct arm_insn_reloc_data *data) { - return 1; + int ret = 1; + long offset; + CORE_ADDR absolute_dest; + uint16_t link = bit (insn2, 14); + + int j1 = bit (insn2, 13); + int j2 = bit (insn2, 11); + int i1 = !(j1 ^ bit (insn1, 10)); + int i2 = !(j2 ^ bit (insn1, 10)); + int s = sbits (insn1, 10, 10); + + if (!link) + { + /* It's a b. */ + int imm11 = bits (insn2, 0, 10); + + if (!bit (insn2, 12)) + { + /* Encoding T3, with a condition and smaller immediate. */ + + int imm6 = bits (insn1, 0, 5); + int cond = bits (insn1, 6, 9); + + offset = ((imm11 << 1) | + (imm6 << 12) | + (j1 << 18) | + (j2 << 19) | + (s << 20)) + 4; + + absolute_dest = data->orig_loc + offset; + + arm_emit_thumb_bw_cond (data->insns.thumb32, cond, + arm_thumb_branch_relative_distance + (data->new_loc, absolute_dest)); + } + else + { + /* Encoding T4, with no condition but a larger immediate */ + int imm10 = bits (insn1, 0, 9); + + offset = ((imm11 << 1) | + (imm10 << 12) | + (i2 << 22) | + (i1 << 23) | + (s << 24)) + 4; + + absolute_dest = data->orig_loc + offset; + + arm_emit_thumb_bw + (data->insns.thumb32, arm_thumb_branch_relative_distance + (data->new_loc, absolute_dest)); + } + + ret = 0; + } + else + { + int exchange = !bit (insn2, 12); + + if (!exchange) + { + /* It's a bl. */ + int imm11 = bits (insn2, 0, 10); + int imm10 = bits (insn1, 0, 9); + + offset = ((imm11 << 1) + | (imm10 << 12) + | (i2 << 22) + | (i1 << 23) + | (s << 24)) + 4; + + absolute_dest = data->orig_loc + offset; + + arm_emit_thumb_bl (data->insns.thumb32, + arm_thumb_branch_relative_distance + (data->new_loc, absolute_dest)); + ret = 0; + } + else + { + /* It's a blx. */ + int imm10l = bits (insn2, 1, 10); + int imm10h = bits (insn1, 0, 9); + + offset = ((imm10l << 2) + | (imm10h << 12) + | (i2 << 22) + | (i1 << 23) + | (s << 24)) + 4; + + absolute_dest = data->orig_loc + offset; + + arm_emit_thumb_blx (data->insns.thumb32, + immediate_operand + (arm_thumb_to_arm_branch_relative_distance + (data->new_loc, absolute_dest))); + ret = 0; + } + } + + return ret; } static int thumb32_reloc_block_xfer (uint16_t insn1, uint16_t insn2, struct arm_insn_reloc_data *data) { - return 1; + uint16_t rn = bits (insn1, 0, 3); + uint16_t load = bit (insn1, 4); + + /* For LDM/POP instructions, there is not problem executing out of line even + if PC is part of the register list. It will simply result in an absolute + jump to the address popped. + + For STM/PUSH instructions in Thumb mode, PC can't be in the register list, + unlike in ARM mode. So we don't need to check if it's present. + */ + + return thumb32_reloc_others (insn1, insn2, "ldm/stm", data); } static int thumb32_reloc_copro_load_store (uint16_t insn1, uint16_t insn2, struct arm_insn_reloc_data *data) { - return 1; + uint16_t rn = bits (insn1, 0, 3); + + if (rn == ARM_PC_REGNUM) + return arm_reloc_refs_pc_error (data); + + return thumb32_reloc_others (insn1, insn2, "copro load/store", data); } static int thumb32_reloc_load_literal (uint16_t insn1, uint16_t insn2, struct arm_insn_reloc_data *data, int size) { - return 1; + /* It should be possible to relocate this. The difficulty is that the + 12 offset bits are likely not to be enough to encode the offset at the new + location. We might be able to replace it by multiple instructions, loading + the absolute offset in a register, and using LDR (immediate, Thumb). We + would need to take care of which register we use and save the relevant + registers value. + */ + + return arm_reloc_refs_pc_error (data); } static int @@ -1380,27 +1512,45 @@ thumb32_reloc_load_reg_imm (uint16_t insn1, uint16_t insn2, struct arm_insn_reloc_data *data, int writeback, int immed) { - return 1; + uint16_t rn = bits (insn1, 0, 3); + + /* If rn is the PC, we should end up in load_literal, and that means the + instruction decoder has a bug. */ + gdb_assert (rn != ARM_PC_REGNUM); + + /* The instruction is safe even if the destination register (rt) is the PC, + as it will simply result in a branch. */ + return thumb32_reloc_others (insn1, insn2, "load reg", data); } static int thumb32_reloc_pc_relative_32bit (uint16_t insn1, uint16_t insn2, struct arm_insn_reloc_data *data) { - return 1; + /* Form PC-relative Address. We could re-encode this instruction with the + new PC of the instruction, if we determine that this instruction is common + enough for it to be worth it. */ + + return arm_reloc_refs_pc_error (data); } static int thumb32_reloc_preload (uint16_t insn1, uint16_t insn2, struct arm_insn_reloc_data *data) { - return 1; + unsigned int rn = bits (insn1, 0, 3); + + if (rn != ARM_PC_REGNUM) + return arm_reloc_refs_pc_error (data); + + return thumb32_reloc_others (insn1, insn2, "preload", data); } static int thumb32_reloc_undef (uint16_t insn1, uint16_t insn2, struct arm_insn_reloc_data *data) { + data->err = "The instruction is undefined, couldn't relocate."; return 1; } @@ -1408,9 +1558,12 @@ static int thumb32_reloc_table_branch (uint16_t insn1, uint16_t insn2, struct arm_insn_reloc_data *data) { - return 1; -} + /* The values in the table are relative offsets to PC. We could generate a + sequence of instructions to reproduce the same behavior. but these + instructions are probably not common enough for it to be worth it. */ + return arm_reloc_refs_pc_error (data); +} struct thumb_32bit_insn_reloc_visitor thumb_32bit_insns_reloc_visitor = { thumb32_reloc_alu_imm, @@ -1450,6 +1603,8 @@ copy_instruction_thumb32 (CORE_ADDR *to, CORE_ADDR from, const char **err) /* Set a default generic error message, which can be overridden by the relocation functions. */ data.err = "Error relocating instruction."; + data.orig_loc = from; + data.new_loc = *to; ret = thumb_32bit_relocate_insn (insn1, insn2, &thumb_32bit_insns_reloc_visitor, &data); diff --git a/gdb/testsuite/gdb.trace/ftrace-arm-insn.S b/gdb/testsuite/gdb.trace/ftrace-arm-insn.S index c123727..1460fa8 100644 --- a/gdb/testsuite/gdb.trace/ftrace-arm-insn.S +++ b/gdb/testsuite/gdb.trace/ftrace-arm-insn.S @@ -219,3 +219,160 @@ insn_arm_stm: epilogue + +/* thumb b imm (should test the encoding T4) */ +.thumb +.type func_thumb_b_imm, STT_FUNC +.global func_thumb_b_imm +func_thumb_b_imm: + prologue + +insn_thumb_b_imm: + b.w thumb_b_imm_jump + +thumb_b_imm_jump_back: + epilogue + +thumb_b_imm_jump: + ldr r0, =global_variable + ldr r1, =magic_number + ldr r1, [r1] + str r1, [r0] + + # return to the function + b thumb_b_imm_jump_back + + +/* thumb b imm cond (should test the encoding T3) */ +.thumb +.type func_thumb_b_imm_cond, STT_FUNC +.global func_thumb_b_imm_cond +func_thumb_b_imm_cond: + prologue + + /* Make a comparison that evaluates to true */ + cmp r0, r0 + +insn_thumb_b_imm_cond: + bne.w thumb_b_imm_cond_jump + + ldr r0, =global_variable + ldr r1, =magic_number + ldr r1, [r1] + str r1, [r0] + +thumb_b_imm_cond_jump: + epilogue + +/* thumb bl imm */ +.thumb +.type func_thumb_bl_imm, STT_FUNC +.global func_thumb_bl_imm +func_thumb_bl_imm: + prologue + +insn_thumb_bl_imm: + bl.w thumb_bl_imm_jump + + epilogue + +thumb_bl_imm_jump: + ldr r0, =global_variable + ldr r1, =magic_number + ldr r1, [r1] + str r1, [r0] + + # return to the function + bx lr + + +/* thumb blx imm */ +.thumb +.type func_thumb_blx_imm, STT_FUNC +.global func_thumb_blx_imm +func_thumb_blx_imm: + prologue + +insn_thumb_blx_imm: + blx.w thumb_blx_imm_jump + + epilogue + +.arm +thumb_blx_imm_jump: + ldr r0, =global_variable + ldr r1, =magic_number + ldr r1, [r1] + str r1, [r0] + + # return to the function + bx lr + + +/* thumb ldm */ +.thumb +.type func_thumb_ldm, STT_FUNC +.global func_thumb_ldm +func_thumb_ldm: + prologue + + /* Store magic number in r0. */ + ldr r0, =magic_number + ldr r0, [r0] + + /* Push the magic number on the stack. We need to use at least two + registers for the stm/ldm, otherwise the ldm will be encoded as an + ldr. */ + stmfd sp!, {r0, r1} + mov r0, 0 + +insn_thumb_ldm: + ldmfd.w sp!, {r0, r1} + ldr r1, =global_variable + str r0, [r1] + + epilogue + + +/* thumb ldm pc */ +.thumb +.type func_thumb_ldm_pc, STT_FUNC +.global func_thumb_ldm_pc +func_thumb_ldm_pc: + prologue + + bl thumb_ldm_pc_jump + + ldr r0, =global_variable + ldr r1, =magic_number + ldr r1, [r1] + str r1, [r0] + + epilogue + +thumb_ldm_pc_jump: + /* We need to specify at least two registers, otherwise the ldm instruction + will get encoded as an ldr. */ + stmfd sp!, {r0, lr} +insn_thumb_ldm_pc: + ldmfd.w sp!, {r0, pc} + + +/* thumb stm */ +.thumb +.type func_thumb_stm, STT_FUNC +.global func_thumb_stm +func_thumb_stm: + prologue + + ldr r0, =magic_number + ldr r0, [r0] + +insn_thumb_stm: + stmfd.w sp!, {r0} + + ldmfd sp!, {r1} + ldr r0, =global_variable + str r1, [r0] + + epilogue diff --git a/gdb/testsuite/gdb.trace/ftrace-arm-insn.c b/gdb/testsuite/gdb.trace/ftrace-arm-insn.c index ec08298..cbceddf 100644 --- a/gdb/testsuite/gdb.trace/ftrace-arm-insn.c +++ b/gdb/testsuite/gdb.trace/ftrace-arm-insn.c @@ -61,6 +61,14 @@ DEF_TEST_FN (arm_ldm) DEF_TEST_FN (arm_ldm_pc) DEF_TEST_FN (arm_stm) +DEF_TEST_FN (thumb_b_imm) +DEF_TEST_FN (thumb_b_imm_cond) +DEF_TEST_FN (thumb_bl_imm) +DEF_TEST_FN (thumb_blx_imm) +DEF_TEST_FN (thumb_ldm) +DEF_TEST_FN (thumb_ldm_pc) +DEF_TEST_FN (thumb_stm) + int main (void) { @@ -74,5 +82,13 @@ main (void) test_arm_ldm_pc (); test_arm_stm (); + test_thumb_b_imm (); + test_thumb_b_imm_cond (); + test_thumb_bl_imm (); + test_thumb_blx_imm (); + test_thumb_ldm (); + test_thumb_ldm_pc (); + test_thumb_stm (); + return 0; } diff --git a/gdb/testsuite/gdb.trace/ftrace-arm-insn.exp b/gdb/testsuite/gdb.trace/ftrace-arm-insn.exp index e78d484..35cb59d 100644 --- a/gdb/testsuite/gdb.trace/ftrace-arm-insn.exp +++ b/gdb/testsuite/gdb.trace/ftrace-arm-insn.exp @@ -101,3 +101,11 @@ do_test arm_blx_reg do_test arm_ldm do_test arm_ldm_pc do_test arm_stm + +do_test thumb_b_imm +do_test thumb_b_imm_cond +do_test thumb_bl_imm +do_test thumb_blx_imm +do_test thumb_ldm +do_test thumb_ldm_pc +do_test thumb_stm