From: Antoine Tremblay <antoine.tremblay@ericsson.com>
To: <gdb-patches@sourceware.org>
Cc: Simon Marchi <simon.marchi@ericsson.com>
Subject: [PATCH v3 18/18] arm fast tracepoints: Relocation of Thumb 32-bits instructions
Date: Tue, 05 Jul 2016 13:42:00 -0000 [thread overview]
Message-ID: <1467726030-13020-19-git-send-email-antoine.tremblay@ericsson.com> (raw)
In-Reply-To: <1467726030-13020-1-git-send-email-antoine.tremblay@ericsson.com>
From: Simon Marchi <simon.marchi@ericsson.com>
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
--
2.8.1
next prev parent reply other threads:[~2016-07-05 13:42 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
2016-07-05 13:41 ` [PATCH v3 06/18] arm-tdep.c: Use relocation visitor in Thumb 16-bits instruction decoding Antoine Tremblay
2016-07-05 13:41 ` [PATCH v3 08/18] Move Thumb 32 bits instruction decode functions to arch/arm-insn-reloc.c Antoine Tremblay
2016-07-05 13:41 ` [PATCH v3 02/18] arm-tdep.c: Refactor displaced stepping relocation functions Antoine Tremblay
2016-07-05 13:41 ` [PATCH v3 12/18] Add ARM/Thumb instruction assembler for fast tracepoints Antoine Tremblay
2016-07-05 13:41 ` [PATCH v3 03/18] arm-tdep.c: Move debug printout from decode to copy function Antoine Tremblay
2016-07-05 13:41 ` [PATCH v3 15/18] JIT conditions support for ARM tracepoints Antoine Tremblay
2016-07-05 13:41 ` [PATCH v3 11/18] Use software single step to step out of a fast tracepoint jump pad Antoine Tremblay
2016-07-05 13:41 ` [PATCH v3 16/18] arm: Move insn_references_pc to common code Antoine Tremblay
2016-07-05 13:41 ` [PATCH v3 13/18] Export tracing control breakpoints functions via global function pointers Antoine Tremblay
2016-07-05 13:42 ` [PATCH v3 01/18] arm-tdep.c: Replace arguments to decode function by a structure Antoine Tremblay
2016-07-05 13:42 ` [PATCH v3 10/18] gdbserver: pass pointer to struct tracepoint to install_fast_tracepoint_jump_pad Antoine Tremblay
2016-07-05 13:42 ` [PATCH v3 14/18] Fast tracepoint support for ARM on Linux Antoine Tremblay
2016-07-05 13:42 ` [PATCH v3 07/18] Move ARM instruction decode functions to arch/arm-insn-reloc.c Antoine Tremblay
2016-07-05 13:42 ` [PATCH v3 17/18] arm fast tracepoints: Relocation of ARM instructions Antoine Tremblay
2016-07-05 13:42 ` [PATCH v3 09/18] Move Thumb 16 bits instruction decode functions to arch/arm-insn-reloc.c Antoine Tremblay
2016-07-05 13:42 ` Antoine Tremblay [this message]
2016-07-05 13:56 ` [PATCH v3 05/18] arm-tdep.c: Use relocation visitor in Thumb 32-bits instruction decoding Antoine Tremblay
2016-07-05 13:56 ` [PATCH v3 04/18] arm-tdep.c: Use relocation visitor in ARM " Antoine Tremblay
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1467726030-13020-19-git-send-email-antoine.tremblay@ericsson.com \
--to=antoine.tremblay@ericsson.com \
--cc=gdb-patches@sourceware.org \
--cc=simon.marchi@ericsson.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).