public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3 03/18] arm-tdep.c: Move debug printout from decode to copy function
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (3 preceding siblings ...)
  2016-07-05 13:41 ` [PATCH v3 12/18] Add ARM/Thumb instruction assembler for fast tracepoints Antoine Tremblay
@ 2016-07-05 13:41 ` Antoine Tremblay
  2016-07-05 13:41 ` [PATCH v3 02/18] arm-tdep.c: Refactor displaced stepping relocation functions Antoine Tremblay
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

To be consistent with the rest of the code, the debug printout should be
in thumb_copy_pc_relative_16bit.  Also, thumb_decode_pc_relative_16bit
will be move out of arm-tdep.c to common code, so it can't contain
anything gdb-specific.

	* arm-tdep.c (thumb_decode_pc_relative_16bit): Move debug print
	from here...
	(thumb_copy_pc_relative_16bit): ... to here.
---
 gdb/arm-tdep.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 5a0e247..0c05aae 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -6972,9 +6972,13 @@ install_pc_relative (struct arm_insn_reloc_data *data, int rd)
 }
 
 static int
-thumb_copy_pc_relative_16bit (struct arm_insn_reloc_data *data, int rd,
-			      unsigned int imm)
+thumb_copy_pc_relative_16bit (uint16_t insn, struct arm_insn_reloc_data *data,
+			      int rd, unsigned int imm)
 {
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog,
+			"displaced: copying thumb adr r%d, #%d insn %.4x\n",
+			rd, imm, insn);
 
   /* Encoding T2: ADDS Rd, #imm */
   data->dsc->modinsn[0] = (0x3000 | (rd << 8) | imm);
@@ -6990,12 +6994,7 @@ thumb_decode_pc_relative_16bit (uint16_t insn, struct arm_insn_reloc_data *data)
   unsigned int rd = bits (insn, 8, 10);
   unsigned int imm8 = bits (insn, 0, 7);
 
-  if (debug_displaced)
-    fprintf_unfiltered (gdb_stdlog,
-			"displaced: copying thumb adr r%d, #%d insn %.4x\n",
-			rd, imm8, insn);
-
-  return thumb_copy_pc_relative_16bit (data, rd, imm8);
+  return thumb_copy_pc_relative_16bit (insn, data, rd, imm8);
 }
 
 static int
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 06/18] arm-tdep.c: Use relocation visitor in Thumb 16-bits instruction decoding
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (5 preceding siblings ...)
  2016-07-05 13:41 ` [PATCH v3 02/18] arm-tdep.c: Refactor displaced stepping relocation functions Antoine Tremblay
@ 2016-07-05 13:41 ` 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
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

This is the same as the previous patch, but for the 16-bits Thumb
instructions.

gdb/ChangeLog:

	* arm-tdep.c (thumb_16bit_insn_reloc_visitor): New.
	(thumb_decode_pc_relative_16bit): Add visitor parameter and use
	it.
	(thumb_16bit_relocate_insn): Add and use visitor parameter.
	(thumb_16bit_insn_reloc_visitor): New.
	(arm_process_displaced_insn): Pass
	thumb_16it_insn_reloc_visitor to thumb_16bit_relocate_insn.
---
 gdb/arm-tdep.c | 81 +++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 57 insertions(+), 24 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 6a9d110..0f35eb3 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -4529,6 +4529,21 @@ struct thumb_32bit_insn_reloc_visitor
 		       struct arm_insn_reloc_data *data);
 };
 
+struct thumb_16bit_insn_reloc_visitor
+{
+  int (*alu_reg) (uint16_t insn, struct arm_insn_reloc_data *data);
+  int (*b) (uint16_t insn, struct arm_insn_reloc_data *data);
+  int (*bx_blx_reg) (uint16_t insn, struct arm_insn_reloc_data *data);
+  int (*cbnz_cbz) (uint16_t insn1, struct arm_insn_reloc_data *data);
+  int (*load_literal) (uint16_t insn1, struct arm_insn_reloc_data *data);
+  int (*others) (uint16_t insn, const char *iname,
+		 struct arm_insn_reloc_data *data);
+  int (*pc_relative_16bit) (uint16_t insn, struct arm_insn_reloc_data *data,
+			    int rd, unsigned int imm);
+  int (*pop_pc_16bit) (uint16_t insn, struct arm_insn_reloc_data *data);
+  int (*svc) (uint16_t insn, struct arm_insn_reloc_data *data);
+};
+
 /* Helper for register reads for displaced stepping.  In particular, this
    returns the PC as it would be seen by the instruction at its original
    location.  */
@@ -7050,12 +7065,14 @@ thumb_copy_pc_relative_16bit (uint16_t insn, struct arm_insn_reloc_data *data,
 }
 
 static int
-thumb_decode_pc_relative_16bit (uint16_t insn, struct arm_insn_reloc_data *data)
+thumb_decode_pc_relative_16bit (uint16_t insn,
+				struct thumb_16bit_insn_reloc_visitor *visitor,
+				struct arm_insn_reloc_data *data)
 {
   unsigned int rd = bits (insn, 8, 10);
   unsigned int imm8 = bits (insn, 0, 7);
 
-  return thumb_copy_pc_relative_16bit (insn, data, rd, imm8);
+  return visitor->pc_relative_16bit (insn, data, rd, imm8);
 }
 
 static int
@@ -7320,7 +7337,9 @@ thumb_copy_pop_pc_16bit (uint16_t insn1, struct arm_insn_reloc_data *data)
 }
 
 static int
-thumb_16bit_relocate_insn (uint16_t insn1, struct arm_insn_reloc_data *data)
+thumb_16bit_relocate_insn (uint16_t insn1,
+			   struct thumb_16bit_insn_reloc_visitor *visitor,
+			   struct arm_insn_reloc_data *data)
 {
   unsigned short op_bit_12_15 = bits (insn1, 12, 15);
   unsigned short op_bit_10_11 = bits (insn1, 10, 11);
@@ -7331,79 +7350,79 @@ thumb_16bit_relocate_insn (uint16_t insn1, struct arm_insn_reloc_data *data)
     {
       /* Shift (imme), add, subtract, move and compare.  */
     case 0: case 1: case 2: case 3:
-      err = thumb_copy_unmodified_16bit (insn1, "shift/add/sub/mov/cmp", data);
+      err = visitor->others (insn1, "shift/add/sub/mov/cmp", data);
       break;
     case 4:
       switch (op_bit_10_11)
 	{
 	case 0: /* Data-processing */
-	  err = thumb_copy_unmodified_16bit (insn1, "data-processing", data);
+	  err = visitor->others (insn1, "data-processing", data);
 	  break;
 	case 1: /* Special data instructions and branch and exchange.  */
 	  {
 	    unsigned short op = bits (insn1, 7, 9);
 	    if (op == 6 || op == 7) /* BX or BLX */
-	      err = thumb_copy_bx_blx_reg (insn1, data);
+	      err = visitor->bx_blx_reg (insn1, data);
 	    else if (bits (insn1, 6, 7) != 0) /* ADD/MOV/CMP high registers.  */
-	      err = thumb_copy_alu_reg (insn1, data);
+	      err = visitor->alu_reg (insn1, data);
 	    else
-	      err = thumb_copy_unmodified_16bit (insn1, "special data", data);
+	      err = visitor->others (insn1, "special data", data);
 	  }
 	  break;
 	default: /* LDR (literal) */
-	  err = thumb_copy_16bit_ldr_literal (insn1, data);
+	  err = visitor->load_literal (insn1, data);
 	}
       break;
     case 5: case 6: case 7: case 8: case 9: /* Load/Store single data item */
-      err = thumb_copy_unmodified_16bit (insn1, "ldr/str", data);
+      err = visitor->others (insn1, "ldr/str", data);
       break;
     case 10:
       if (op_bit_10_11 < 2) /* Generate PC-relative address */
-	err = thumb_decode_pc_relative_16bit (insn1, data);
+	err = thumb_decode_pc_relative_16bit (insn1, visitor, data);
       else /* Generate SP-relative address */
-	err = thumb_copy_unmodified_16bit (insn1, "sp-relative", data);
+	err = visitor->others (insn1, "sp-relative", data);
       break;
     case 11: /* Misc 16-bit instructions */
       {
 	switch (bits (insn1, 8, 11))
 	  {
 	  case 1: case 3:  case 9: case 11: /* CBNZ, CBZ */
-	    err = thumb_copy_cbnz_cbz (insn1, data);
+	    err = visitor->cbnz_cbz (insn1, data);
 	    break;
 	  case 12: case 13: /* POP */
 	    if (bit (insn1, 8)) /* PC is in register list.  */
-	      err = thumb_copy_pop_pc_16bit (insn1, data);
+	      err = visitor->pop_pc_16bit (insn1, data);
 	    else
-	      err = thumb_copy_unmodified_16bit (insn1, "pop", data);
+	      err = visitor->others (insn1, "pop", data);
 	    break;
 	  case 15: /* If-Then, and hints */
 	    if (bits (insn1, 0, 3))
 	      /* If-Then makes up to four following instructions conditional.
 		 IT instruction itself is not conditional, so handle it as a
 		 common unmodified instruction.  */
-	      err = thumb_copy_unmodified_16bit (insn1, "If-Then", data);
+	      err = visitor->others (insn1, "If-Then", data);
 	    else
-	      err = thumb_copy_unmodified_16bit (insn1, "hints", data);
+	      err = visitor->others (insn1, "hints", data);
 	    break;
 	  default:
-	    err = thumb_copy_unmodified_16bit (insn1, "misc", data);
+	    err = visitor->others (insn1, "misc", data);
 	  }
       }
       break;
     case 12:
       if (op_bit_10_11 < 2) /* Store multiple registers */
-	err = thumb_copy_unmodified_16bit (insn1, "stm", data);
+	err = visitor->others (insn1, "stm", data);
       else /* Load multiple registers */
-	err = thumb_copy_unmodified_16bit (insn1, "ldm", data);
+	err = visitor->others (insn1, "ldm", data);
       break;
     case 13: /* Conditional branch and supervisor call */
       if (bits (insn1, 9, 11) != 7) /* conditional branch */
-	err = thumb_copy_b (insn1, data);
+	err = visitor->b (insn1, data);
       else
-	err = thumb_copy_svc (insn1, data);
+	err = visitor->svc (insn1, data);
       break;
     case 14: /* Unconditional branch */
-      err = thumb_copy_b (insn1, data);
+      err = visitor->b (insn1, data);
       break;
     default:
       err = 1;
@@ -7663,6 +7682,19 @@ static struct thumb_32bit_insn_reloc_visitor thumb_32bit_insn_reloc_visitor =
   thumb_32bit_copy_undef,
 };
 
+static struct thumb_16bit_insn_reloc_visitor thumb_16bit_insn_reloc_visitor =
+{
+  thumb_copy_alu_reg,
+  thumb_copy_b,
+  thumb_copy_bx_blx_reg,
+  thumb_copy_cbnz_cbz,
+  thumb_copy_16bit_ldr_literal,
+  thumb_copy_unmodified_16bit,
+  thumb_copy_pc_relative_16bit,
+  thumb_copy_pop_pc_16bit,
+  thumb_copy_svc,
+};
+
 void
 arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
 			    CORE_ADDR to, struct regcache *regs,
@@ -7722,7 +7754,8 @@ arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
 					   &reloc_data);
 	}
       else
-        err = thumb_16bit_relocate_insn (insn1, &reloc_data);
+	err = thumb_16bit_relocate_insn (insn1, &thumb_16bit_insn_reloc_visitor,
+					 &reloc_data);
     }
 
   if (err)
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 00/18] Fast tracepoint support for ARMv7
@ 2016-07-05 13:41 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
                   ` (17 more replies)
  0 siblings, 18 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

Hi,

In this v3:

I realized then testing something else that a fast tracepoint in an
infinite loop would crash the inferiror.

So I added patch: "Export tracing control breakpoints functions via global
function pointers"

That fixes this issue.

The intro is also updated, removing the possible single step issue.

--

Here's a link to the original V1
https://sourceware.org/ml/gdb-patches/2015-10/msg00195.html

This series needs to be applied on top of tracepoints support for ARM see:
https://sourceware.org/ml/gdb-patches/2016-01/msg00111.html

This patch enables fast tracepoints for ARM on Linux.

It has been reworked by Simon Marchi and Antoine Tremblay and the
following features have been added:

  * Relocation of many PC relative instructions.

  * JIT compilation of the condition expression.

There are some limitations:

     * The tracepoint insertion will fail if the distance from the
       instruction to the jump pad is big.

     * It is only possible to place fast tracepoints on 4-byte
       instructions, which also limits the valid locations in Thumb mode.

Patches:

Patches 1-9: Share instruction decoding code between GDB and GDBServer so
that it can be used for instruction relocation in GDBServer.

Patch 10: Refactors install_fast_tracepoint_jump_pad to pass a pointer to
the tracepoint, instead of separate arguments.

Patch 11: Enables software single stepping out of the jump pad.

Patch 12: Adds all the functions needed to assemble ARM instructions
needed in the jump pad and in the JIT condition evaluation.

Patch 13: Exports the tracing breakpoint control functions.

Patch 14: Adds fast tracepoint support, without JIT condition evaluation
and PC-relative instructions support.

Patch 15: Adds JIT condition evaluation support.

Patch 16-18: Adds PC-relative instruction relocation support.

Tested on ARMv7 linux {unix, native-gdbserver, native-extended-gdbserver}
no regression observed.


Antoine Tremblay (5):
  Use software single step to step out of a fast tracepoint jump pad
  Add ARM/Thumb instruction assembler for fast tracepoints
  Export tracing control breakpoints functions via global function
    pointers
  Fast tracepoint support for ARM on Linux
  JIT conditions support for ARM tracepoints.

Simon Marchi (13):
  arm-tdep.c: Replace arguments to decode function by a structure
  arm-tdep.c: Refactor displaced stepping relocation functions
  arm-tdep.c: Move debug printout from decode to copy function
  arm-tdep.c: Use relocation visitor in ARM instruction decoding
  arm-tdep.c: Use relocation visitor in Thumb 32-bits instruction
    decoding
  arm-tdep.c: Use relocation visitor in Thumb 16-bits instruction
    decoding
  Move ARM instruction decode functions to arch/arm-insn-reloc.c
  Move Thumb 32 bits instruction decode functions to
    arch/arm-insn-reloc.c
  Move Thumb 16 bits instruction decode functions to
    arch/arm-insn-reloc.c
  gdbserver: pass pointer to struct tracepoint to
    install_fast_tracepoint_jump_pad
  arm: Move insn_references_pc to common code
  arm fast tracepoints: Relocation of ARM instructions
  arm fast tracepoints: Relocation of Thumb 32-bits instructions

 gdb/Makefile.in                                 |   29 +-
 gdb/NEWS                                        |    4 +
 gdb/aarch64-tdep.c                              |    3 +-
 gdb/arch/aarch64-insn.c                         |    3 +-
 gdb/arch/aarch64-insn.h                         |   32 +-
 gdb/arch/arm-insn-emit.c                        | 1550 ++++++++++++++++++
 gdb/arch/arm-insn-emit.h                        | 1087 +++++++++++++
 gdb/arch/arm-insn-reloc.c                       |  881 ++++++++++
 gdb/arch/arm-insn-reloc.h                       |  109 ++
 gdb/arch/arm-insn-utils.c                       |   44 +
 gdb/arch/arm-insn-utils.h                       |   80 +
 gdb/arch/arm.h                                  |    2 +
 gdb/arm-tdep.c                                  | 1464 ++++-------------
 gdb/configure.tgt                               |    7 +-
 gdb/gdbserver/Makefile.in                       |   29 +-
 gdb/gdbserver/configure.srv                     |    8 +
 gdb/gdbserver/linux-aarch32-low.c               |    8 -
 gdb/gdbserver/linux-aarch32-low.h               |    8 +
 gdb/gdbserver/linux-aarch64-low.c               |   80 +-
 gdb/gdbserver/linux-arm-ipa.c                   |  228 +++
 gdb/gdbserver/linux-arm-low.c                   | 1957 ++++++++++++++++++++++-
 gdb/gdbserver/linux-low.c                       |   21 +-
 gdb/gdbserver/linux-low.h                       |    5 +-
 gdb/gdbserver/linux-ppc-low.c                   |   21 +-
 gdb/gdbserver/linux-s390-low.c                  |   13 +-
 gdb/gdbserver/linux-x86-low.c                   |   63 +-
 gdb/gdbserver/target.h                          |   26 +-
 gdb/gdbserver/tracepoint.c                      |  232 +--
 gdb/gdbserver/tracepoint.h                      |  126 ++
 gdb/testsuite/gdb.trace/ftrace-arm-insn.S       |  378 +++++
 gdb/testsuite/gdb.trace/ftrace-arm-insn.c       |   94 ++
 gdb/testsuite/gdb.trace/ftrace-arm-insn.exp     |  111 ++
 gdb/testsuite/gdb.trace/ftrace-flush-buffer.c   |   42 +
 gdb/testsuite/gdb.trace/ftrace-flush-buffer.exp |   98 ++
 gdb/testsuite/lib/trace-support.exp             |    3 +-
 35 files changed, 7357 insertions(+), 1489 deletions(-)
 create mode 100644 gdb/arch/arm-insn-emit.c
 create mode 100644 gdb/arch/arm-insn-emit.h
 create mode 100644 gdb/arch/arm-insn-reloc.c
 create mode 100644 gdb/arch/arm-insn-reloc.h
 create mode 100644 gdb/arch/arm-insn-utils.c
 create mode 100644 gdb/arch/arm-insn-utils.h
 create mode 100644 gdb/gdbserver/linux-arm-ipa.c
 create mode 100644 gdb/testsuite/gdb.trace/ftrace-arm-insn.S
 create mode 100644 gdb/testsuite/gdb.trace/ftrace-arm-insn.c
 create mode 100644 gdb/testsuite/gdb.trace/ftrace-arm-insn.exp
 create mode 100644 gdb/testsuite/gdb.trace/ftrace-flush-buffer.c
 create mode 100644 gdb/testsuite/gdb.trace/ftrace-flush-buffer.exp

-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 08/18] Move Thumb 32 bits instruction decode functions to arch/arm-insn-reloc.c
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (6 preceding siblings ...)
  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 ` Antoine Tremblay
  2016-07-05 13:41 ` [PATCH v3 15/18] JIT conditions support for ARM tracepoints Antoine Tremblay
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

This patch does the same as the previous one, but for 32-bits Thumb
instructions-related functions.

gdb/ChangeLog:

	* arch/arm-insn-reloc.h (struct thumb_32bit_insn_reloc_visitor):
	Move from arm-tdep.c.
	(thumb_32bit_relocate_insn): New declaration.
	* arch/arm-insn-reloc.c (thumb2_decode_dp_shift_reg): Move from
	arm-tdep.c.
	(thumb2_decode_ext_reg_ld_st): Likewise.
	(thumb2_decode_svc_copro): Likewise.
	(decode_thumb_32bit_ld_mem_hints): Likewise.
	(thumb_32bit_relocate_insn): Likewise.
	* arm-tdep.c (struct thumb_32bit_insn_reloc_visitor): Move to
	arch/arm-insn-reloc.h.
	(thumb2_decode_dp_shift_reg): Move to arch/arm-insn-reloc.c.
	(thumb2_decode_ext_reg_ld_st): Likewise.
	(thumb2_decode_svc_copro): Likewise.
	(decode_thumb_32bit_ld_mem_hints): Likewise.
	(thumb_32bit_relocate_insn): Likewise.
---
 gdb/arch/arm-insn-reloc.c | 274 +++++++++++++++++++++++++++++++++++++++++
 gdb/arch/arm-insn-reloc.h |  32 +++++
 gdb/arm-tdep.c            | 301 ----------------------------------------------
 3 files changed, 306 insertions(+), 301 deletions(-)

diff --git a/gdb/arch/arm-insn-reloc.c b/gdb/arch/arm-insn-reloc.c
index adf6243..f598c64 100644
--- a/gdb/arch/arm-insn-reloc.c
+++ b/gdb/arch/arm-insn-reloc.c
@@ -470,3 +470,277 @@ arm_relocate_insn (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
 
   return err;
 }
+
+/* Decode shifted register instructions.  */
+
+static int
+thumb2_decode_dp_shift_reg (uint16_t insn1, uint16_t insn2,
+			    struct thumb_32bit_insn_reloc_visitor *visitor,
+			    struct arm_insn_reloc_data *data)
+{
+  /* PC is only allowed to be used in instruction MOV.  */
+
+  unsigned int op = bits (insn1, 5, 8);
+  unsigned int rn = bits (insn1, 0, 3);
+
+  if (op == 0x2 && rn == 0xf) /* MOV */
+    return visitor->alu_imm (insn1, insn2, data);
+  else
+    return visitor->others (insn1, insn2, "dp (shift reg)", data);
+}
+
+
+/* Decode extension register load/store.  Exactly the same as
+   arm_decode_ext_reg_ld_st.  */
+
+static int
+thumb2_decode_ext_reg_ld_st (uint16_t insn1, uint16_t insn2,
+			     struct thumb_32bit_insn_reloc_visitor *visitor,
+			     struct arm_insn_reloc_data *data)
+{
+  unsigned int opcode = bits (insn1, 4, 8);
+
+  switch (opcode)
+    {
+    case 0x04: case 0x05:
+      return visitor->others (insn1, insn2, "vfp/neon vmov", data);
+
+    case 0x08: case 0x0c: /* 01x00 */
+    case 0x0a: case 0x0e: /* 01x10 */
+    case 0x12: case 0x16: /* 10x10 */
+      return visitor->others (insn1, insn2, "vfp/neon vstm/vpush", data);
+
+    case 0x09: case 0x0d: /* 01x01 */
+    case 0x0b: case 0x0f: /* 01x11 */
+    case 0x13: case 0x17: /* 10x11 */
+      return visitor->others (insn1, insn2, "vfp/neon vldm/vpop", data);
+
+    case 0x10: case 0x14: case 0x18: case 0x1c:  /* vstr.  */
+      return visitor->others (insn1, insn2, "vstr", data);
+    case 0x11: case 0x15: case 0x19: case 0x1d:  /* vldr.  */
+      return visitor->copro_load_store (insn1, insn2, data);
+    }
+
+  /* Should be unreachable.  */
+  return 1;
+}
+
+
+static int
+decode_thumb_32bit_ld_mem_hints (uint16_t insn1, uint16_t insn2,
+				 struct thumb_32bit_insn_reloc_visitor *visitor,
+				 struct arm_insn_reloc_data *data)
+{
+  int rt = bits (insn2, 12, 15);
+  int rn = bits (insn1, 0, 3);
+  int op1 = bits (insn1, 7, 8);
+
+  switch (bits (insn1, 5, 6))
+    {
+    case 0: /* Load byte and memory hints */
+      if (rt == 0xf) /* PLD/PLI */
+	{
+	  if (rn == 0xf)
+	    /* PLD literal or Encoding T3 of PLI(immediate, literal).  */
+	    return visitor->preload (insn1, insn2, data);
+	  else
+	    return visitor->others (insn1, insn2, "pli/pld", data);
+	}
+      else
+	{
+	  if (rn == 0xf) /* LDRB/LDRSB (literal) */
+	    return visitor->load_literal (insn1, insn2, data, 1);
+	  else
+	    return visitor->others (insn1, insn2, "ldrb{reg, immediate}/ldrbt",
+				    data);
+	}
+
+      break;
+    case 1: /* Load halfword and memory hints.  */
+      if (rt == 0xf) /* PLD{W} and Unalloc memory hint.  */
+	return visitor->others (insn1, insn2, "pld/unalloc memhint", data);
+      else
+	{
+	  if (rn == 0xf)
+	    return visitor->load_literal (insn1, insn2, data, 2);
+	  else
+	    return visitor->others (insn1, insn2, "ldrh/ldrht", data);
+	}
+      break;
+    case 2: /* Load word */
+      {
+	int insn2_bit_8_11 = bits (insn2, 8, 11);
+
+	if (rn == 0xf)
+	  return visitor->load_literal (insn1, insn2, data, 4);
+	else if (op1 == 0x1) /* Encoding T3 */
+	  return visitor->load_reg_imm (insn1, insn2, data, 0, 1);
+	else /* op1 == 0x0 */
+	  {
+	    if (insn2_bit_8_11 == 0xc || (insn2_bit_8_11 & 0x9) == 0x9)
+	      /* LDR (immediate) */
+	      return visitor->load_reg_imm (insn1, insn2, data,
+					       bit (insn2, 8), 1);
+	    else if (insn2_bit_8_11 == 0xe) /* LDRT */
+	      return visitor->others (insn1, insn2, "ldrt", data);
+	    else
+	      /* LDR (register) */
+	      return visitor->load_reg_imm (insn1, insn2, data, 0, 0);
+	  }
+	break;
+      }
+    default:
+      return visitor->undef (insn1, insn2, data);
+    }
+  return 0;
+}
+
+static int
+thumb2_decode_svc_copro (uint16_t insn1, uint16_t insn2,
+			 struct thumb_32bit_insn_reloc_visitor *visitor,
+			 struct arm_insn_reloc_data *data)
+{
+  unsigned int coproc = bits (insn2, 8, 11);
+  unsigned int bit_5_8 = bits (insn1, 5, 8);
+  unsigned int bit_9 = bit (insn1, 9);
+  unsigned int bit_4 = bit (insn1, 4);
+
+  if (bit_9 == 0)
+    {
+      if (bit_5_8 == 2)
+	return visitor->others (insn1, insn2,
+				"neon 64bit xfer/mrrc/mrrc2/mcrr/mcrr2", data);
+      else if (bit_5_8 == 0) /* UNDEFINED.  */
+	return visitor->undef (insn1, insn2, data);
+      else
+	{
+	   /*coproc is 101x.  SIMD/VFP, ext registers load/store.  */
+	  if ((coproc & 0xe) == 0xa)
+	    return thumb2_decode_ext_reg_ld_st (insn1, insn2, visitor, data);
+	  else /* coproc is not 101x.  */
+	    {
+	      if (bit_4 == 0) /* STC/STC2.  */
+		return visitor->others (insn1, insn2, "stc/stc2", data);
+	      else /* LDC/LDC2 {literal, immeidate}.  */
+		return visitor->copro_load_store (insn1, insn2, data);
+	    }
+	}
+    }
+  else
+    return visitor->others (insn1, insn2, "coproc", data);
+
+  return 0;
+}
+
+int
+thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
+			   struct thumb_32bit_insn_reloc_visitor *visitor,
+			   struct arm_insn_reloc_data *data)
+{
+  int err = 0;
+  unsigned short op = bit (insn2, 15);
+  unsigned int op1 = bits (insn1, 11, 12);
+
+  switch (op1)
+    {
+    case 1:
+      {
+	switch (bits (insn1, 9, 10))
+	  {
+	  case 0:
+	    if (bit (insn1, 6))
+	      {
+		/* Load/store {dual, execlusive}, table branch.  */
+		if (bits (insn1, 7, 8) == 1 && bits (insn1, 4, 5) == 1
+		    && bits (insn2, 5, 7) == 0)
+		  err = visitor->table_branch (insn1, insn2, data);
+		else
+		  /* PC is not allowed to use in load/store {dual, exclusive}
+		     instructions.  */
+		  err = visitor->others (insn1, insn2, "load/store dual/ex",
+					 data);
+	      }
+	    else /* load/store multiple */
+	      {
+		switch (bits (insn1, 7, 8))
+		  {
+		  case 0: case 3: /* SRS, RFE */
+		    err = visitor->others (insn1, insn2, "srs/rfe", data);
+		    break;
+		  case 1: case 2: /* LDM/STM/PUSH/POP */
+		    err = visitor->block_xfer (insn1, insn2, data);
+		    break;
+		  }
+	      }
+	    break;
+
+	  case 1:
+	    /* Data-processing (shift register).  */
+	    err = thumb2_decode_dp_shift_reg (insn1, insn2, visitor, data);
+	    break;
+	  default: /* Coprocessor instructions.  */
+	    err = thumb2_decode_svc_copro (insn1, insn2, visitor, data);
+	    break;
+	  }
+      break;
+      }
+    case 2: /* op1 = 2 */
+      if (op) /* Branch and misc control.  */
+	{
+	  if (bit (insn2, 14)  /* BLX/BL */
+	      || bit (insn2, 12) /* Unconditional branch */
+	      || (bits (insn1, 7, 9) != 0x7)) /* Conditional branch */
+	    err = visitor->b_bl_blx (insn1, insn2, data);
+	  else
+	    err = visitor->others (insn1, insn2, "misc ctrl", data);
+	}
+      else
+	{
+	  if (bit (insn1, 9)) /* Data processing (plain binary imm).  */
+	    {
+	      int op = bits (insn1, 4, 8);
+	      int rn = bits (insn1, 0, 3);
+	      if ((op == 0 || op == 0xa) && rn == 0xf)
+		err = visitor->pc_relative_32bit (insn1, insn2, data);
+	      else
+		err = visitor->others (insn1, insn2, "dp/pb", data);
+	    }
+	  else /* Data processing (modified immeidate) */
+	    err = visitor->others (insn1, insn2, "dp/mi", data);
+	}
+      break;
+    case 3: /* op1 = 3 */
+      switch (bits (insn1, 9, 10))
+	{
+	case 0:
+	  if (bit (insn1, 4))
+	    err = decode_thumb_32bit_ld_mem_hints (insn1, insn2, visitor, data);
+	  else /* NEON Load/Store and Store single data item */
+	    err = visitor->others (insn1, insn2, "neon elt/struct load/store",
+				   data);
+	  break;
+	case 1: /* op1 = 3, bits (9, 10) == 1 */
+	  switch (bits (insn1, 7, 8))
+	    {
+	    case 0: case 1: /* Data processing (register) */
+	      err = visitor->others (insn1, insn2, "dp(reg)", data);
+	      break;
+	    case 2: /* Multiply and absolute difference */
+	      err = visitor->others (insn1, insn2, "mul/mua/diff", data);
+	      break;
+	    case 3: /* Long multiply and divide */
+	      err = visitor->others (insn1, insn2, "lmul/lmua", data);
+	      break;
+	    }
+	  break;
+	default: /* Coprocessor instructions */
+	  err = thumb2_decode_svc_copro (insn1, insn2, visitor, data);
+	  break;
+	}
+      break;
+    default:
+      err = 1;
+    }
+
+  return err;
+}
diff --git a/gdb/arch/arm-insn-reloc.h b/gdb/arch/arm-insn-reloc.h
index 18d3916..ebfc89a 100644
--- a/gdb/arch/arm-insn-reloc.h
+++ b/gdb/arch/arm-insn-reloc.h
@@ -42,8 +42,40 @@ struct arm_insn_reloc_visitor
   int (*unpred) (uint32_t insn, struct arm_insn_reloc_data *data);
 };
 
+struct thumb_32bit_insn_reloc_visitor
+{
+  int (*alu_imm) (uint16_t insn1, uint16_t insn2,
+		  struct arm_insn_reloc_data *data);
+  int (*b_bl_blx) (uint16_t insn1, uint16_t insn2,
+		   struct arm_insn_reloc_data *data);
+  int (*block_xfer) (uint16_t insn1, uint16_t insn2,
+		     struct arm_insn_reloc_data *data);
+  int (*copro_load_store) (uint16_t insn1, uint16_t insn2,
+			   struct arm_insn_reloc_data *data);
+  int (*load_literal) (uint16_t insn1, uint16_t insn2,
+		       struct arm_insn_reloc_data *data, int size);
+  int (*load_reg_imm) (uint16_t insn1, uint16_t insn2,
+		       struct arm_insn_reloc_data *data, int writeback,
+		       int immed);
+  int (*others) (uint16_t insn1, uint16_t insn2, const char *iname,
+		 struct arm_insn_reloc_data *data);
+  int (*pc_relative_32bit) (uint16_t insn1, uint16_t insn2,
+			    struct arm_insn_reloc_data *data);
+  int (*preload) (uint16_t insn1, uint16_t insn2,
+		  struct arm_insn_reloc_data *data);
+  int (*undef) (uint16_t insn1, uint16_t insn2,
+		struct arm_insn_reloc_data *data);
+  int (*table_branch) (uint16_t insn1, uint16_t insn2,
+		       struct arm_insn_reloc_data *data);
+};
+
 extern int arm_relocate_insn (uint32_t insn,
 			      struct arm_insn_reloc_visitor *visitor,
 			      struct arm_insn_reloc_data *data);
 
+extern int thumb_32bit_relocate_insn (
+  uint16_t insn1, uint16_t insn2,
+  struct thumb_32bit_insn_reloc_visitor *visitor,
+  struct arm_insn_reloc_data *data);
+
 #endif /* ARM_INSN_RELOC_H */
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 1af4d36..4f4b6b2 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -4481,33 +4481,6 @@ struct arm_insn_reloc_data
   struct regcache *regs;
 };
 
-struct thumb_32bit_insn_reloc_visitor
-{
-  int (*alu_imm) (uint16_t insn1, uint16_t insn2,
-		  struct arm_insn_reloc_data *data);
-  int (*b_bl_blx) (uint16_t insn1, uint16_t insn2,
-		   struct arm_insn_reloc_data *data);
-  int (*block_xfer) (uint16_t insn1, uint16_t insn2,
-		     struct arm_insn_reloc_data *data);
-  int (*copro_load_store) (uint16_t insn1, uint16_t insn2,
-			   struct arm_insn_reloc_data *data);
-  int (*load_literal) (uint16_t insn1, uint16_t insn2,
-		       struct arm_insn_reloc_data *data, int size);
-  int (*load_reg_imm) (uint16_t insn1, uint16_t insn2,
-		       struct arm_insn_reloc_data *data, int writeback,
-		       int immed);
-  int (*others) (uint16_t insn1, uint16_t insn2, const char *iname,
-		 struct arm_insn_reloc_data *data);
-  int (*pc_relative_32bit) (uint16_t insn1, uint16_t insn2,
-			    struct arm_insn_reloc_data *data);
-  int (*preload) (uint16_t insn1, uint16_t insn2,
-		  struct arm_insn_reloc_data *data);
-  int (*undef) (uint16_t insn1, uint16_t insn2,
-		struct arm_insn_reloc_data *data);
-  int (*table_branch) (uint16_t insn1, uint16_t insn2,
-		       struct arm_insn_reloc_data *data);
-};
-
 struct thumb_16bit_insn_reloc_visitor
 {
   int (*alu_reg) (uint16_t insn, struct arm_insn_reloc_data *data);
@@ -6504,97 +6477,6 @@ arm_copy_unpred (uint32_t insn, struct arm_insn_reloc_data *data)
 /* The decode_* functions are instruction decoding helpers.  They mostly follow
    the presentation in the ARM ARM.  */
 
-/* Decode shifted register instructions.  */
-
-static int
-thumb2_decode_dp_shift_reg (uint16_t insn1, uint16_t insn2,
-			    struct thumb_32bit_insn_reloc_visitor *visitor,
-			    struct arm_insn_reloc_data *data)
-{
-  /* PC is only allowed to be used in instruction MOV.  */
-
-  unsigned int op = bits (insn1, 5, 8);
-  unsigned int rn = bits (insn1, 0, 3);
-
-  if (op == 0x2 && rn == 0xf) /* MOV */
-    return visitor->alu_imm (insn1, insn2, data);
-  else
-    return visitor->others (insn1, insn2, "dp (shift reg)", data);
-}
-
-
-/* Decode extension register load/store.  Exactly the same as
-   arm_decode_ext_reg_ld_st.  */
-
-static int
-thumb2_decode_ext_reg_ld_st (uint16_t insn1, uint16_t insn2,
-			     struct thumb_32bit_insn_reloc_visitor *visitor,
-			     struct arm_insn_reloc_data *data)
-{
-  unsigned int opcode = bits (insn1, 4, 8);
-
-  switch (opcode)
-    {
-    case 0x04: case 0x05:
-      return visitor->others (insn1, insn2, "vfp/neon vmov", data);
-
-    case 0x08: case 0x0c: /* 01x00 */
-    case 0x0a: case 0x0e: /* 01x10 */
-    case 0x12: case 0x16: /* 10x10 */
-      return visitor->others (insn1, insn2, "vfp/neon vstm/vpush", data);
-
-    case 0x09: case 0x0d: /* 01x01 */
-    case 0x0b: case 0x0f: /* 01x11 */
-    case 0x13: case 0x17: /* 10x11 */
-      return visitor->others (insn1, insn2, "vfp/neon vldm/vpop", data);
-
-    case 0x10: case 0x14: case 0x18: case 0x1c:  /* vstr.  */
-      return visitor->others (insn1, insn2, "vstr", data);
-    case 0x11: case 0x15: case 0x19: case 0x1d:  /* vldr.  */
-      return visitor->copro_load_store (insn1, insn2, data);
-    }
-
-  /* Should be unreachable.  */
-  return 1;
-}
-
-static int
-thumb2_decode_svc_copro (uint16_t insn1, uint16_t insn2,
-			 struct thumb_32bit_insn_reloc_visitor *visitor,
-			 struct arm_insn_reloc_data *data)
-{
-  unsigned int coproc = bits (insn2, 8, 11);
-  unsigned int bit_5_8 = bits (insn1, 5, 8);
-  unsigned int bit_9 = bit (insn1, 9);
-  unsigned int bit_4 = bit (insn1, 4);
-
-  if (bit_9 == 0)
-    {
-      if (bit_5_8 == 2)
-	return visitor->others (insn1, insn2,
-				"neon 64bit xfer/mrrc/mrrc2/mcrr/mcrr2", data);
-      else if (bit_5_8 == 0) /* UNDEFINED.  */
-	return visitor->undef (insn1, insn2, data);
-      else
-	{
-	   /*coproc is 101x.  SIMD/VFP, ext registers load/store.  */
-	  if ((coproc & 0xe) == 0xa)
-	    return thumb2_decode_ext_reg_ld_st (insn1, insn2, visitor, data);
-	  else /* coproc is not 101x.  */
-	    {
-	      if (bit_4 == 0) /* STC/STC2.  */
-		return visitor->others (insn1, insn2, "stc/stc2", data);
-	      else /* LDC/LDC2 {literal, immeidate}.  */
-		return visitor->copro_load_store (insn1, insn2, data);
-	    }
-	}
-    }
-  else
-    return visitor->others (insn1, insn2, "coproc", data);
-
-  return 0;
-}
-
 static void
 install_pc_relative (struct arm_insn_reloc_data *data, int rd)
 {
@@ -6996,189 +6878,6 @@ thumb_16bit_relocate_insn (uint16_t insn1,
   return err;
 }
 
-static int
-decode_thumb_32bit_ld_mem_hints (uint16_t insn1, uint16_t insn2,
-				 struct thumb_32bit_insn_reloc_visitor *visitor,
-				 struct arm_insn_reloc_data *data)
-{
-  int rt = bits (insn2, 12, 15);
-  int rn = bits (insn1, 0, 3);
-  int op1 = bits (insn1, 7, 8);
-
-  switch (bits (insn1, 5, 6))
-    {
-    case 0: /* Load byte and memory hints */
-      if (rt == 0xf) /* PLD/PLI */
-	{
-	  if (rn == 0xf)
-	    /* PLD literal or Encoding T3 of PLI(immediate, literal).  */
-	    return visitor->preload (insn1, insn2, data);
-	  else
-	    return visitor->others (insn1, insn2, "pli/pld", data);
-	}
-      else
-	{
-	  if (rn == 0xf) /* LDRB/LDRSB (literal) */
-	    return visitor->load_literal (insn1, insn2, data, 1);
-	  else
-	    return visitor->others (insn1, insn2, "ldrb{reg, immediate}/ldrbt",
-				    data);
-	}
-
-      break;
-    case 1: /* Load halfword and memory hints.  */
-      if (rt == 0xf) /* PLD{W} and Unalloc memory hint.  */
-	return visitor->others (insn1, insn2, "pld/unalloc memhint", data);
-      else
-	{
-	  if (rn == 0xf)
-	    return visitor->load_literal (insn1, insn2, data, 2);
-	  else
-	    return visitor->others (insn1, insn2, "ldrh/ldrht", data);
-	}
-      break;
-    case 2: /* Load word */
-      {
-	int insn2_bit_8_11 = bits (insn2, 8, 11);
-
-	if (rn == 0xf)
-	  return visitor->load_literal (insn1, insn2, data, 4);
-	else if (op1 == 0x1) /* Encoding T3 */
-	  return visitor->load_reg_imm (insn1, insn2, data, 0, 1);
-	else /* op1 == 0x0 */
-	  {
-	    if (insn2_bit_8_11 == 0xc || (insn2_bit_8_11 & 0x9) == 0x9)
-	      /* LDR (immediate) */
-	      return visitor->load_reg_imm (insn1, insn2, data,
-					       bit (insn2, 8), 1);
-	    else if (insn2_bit_8_11 == 0xe) /* LDRT */
-	      return visitor->others (insn1, insn2, "ldrt", data);
-	    else
-	      /* LDR (register) */
-	      return visitor->load_reg_imm (insn1, insn2, data, 0, 0);
-	  }
-	break;
-      }
-    default:
-      return visitor->undef (insn1, insn2, data);
-    }
-  return 0;
-}
-
-static int
-thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
-			   struct thumb_32bit_insn_reloc_visitor *visitor,
-			   struct arm_insn_reloc_data *data)
-{
-  int err = 0;
-  unsigned short op = bit (insn2, 15);
-  unsigned int op1 = bits (insn1, 11, 12);
-
-  switch (op1)
-    {
-    case 1:
-      {
-	switch (bits (insn1, 9, 10))
-	  {
-	  case 0:
-	    if (bit (insn1, 6))
-	      {
-		/* Load/store {dual, execlusive}, table branch.  */
-		if (bits (insn1, 7, 8) == 1 && bits (insn1, 4, 5) == 1
-		    && bits (insn2, 5, 7) == 0)
-		  err = visitor->table_branch (insn1, insn2, data);
-		else
-		  /* PC is not allowed to use in load/store {dual, exclusive}
-		     instructions.  */
-		  err = visitor->others (insn1, insn2, "load/store dual/ex",
-					 data);
-	      }
-	    else /* load/store multiple */
-	      {
-		switch (bits (insn1, 7, 8))
-		  {
-		  case 0: case 3: /* SRS, RFE */
-		    err = visitor->others (insn1, insn2, "srs/rfe", data);
-		    break;
-		  case 1: case 2: /* LDM/STM/PUSH/POP */
-		    err = visitor->block_xfer (insn1, insn2, data);
-		    break;
-		  }
-	      }
-	    break;
-
-	  case 1:
-	    /* Data-processing (shift register).  */
-	    err = thumb2_decode_dp_shift_reg (insn1, insn2, visitor, data);
-	    break;
-	  default: /* Coprocessor instructions.  */
-	    err = thumb2_decode_svc_copro (insn1, insn2, visitor, data);
-	    break;
-	  }
-      break;
-      }
-    case 2: /* op1 = 2 */
-      if (op) /* Branch and misc control.  */
-	{
-	  if (bit (insn2, 14)  /* BLX/BL */
-	      || bit (insn2, 12) /* Unconditional branch */
-	      || (bits (insn1, 7, 9) != 0x7)) /* Conditional branch */
-	    err = visitor->b_bl_blx (insn1, insn2, data);
-	  else
-	    err = visitor->others (insn1, insn2, "misc ctrl", data);
-	}
-      else
-	{
-	  if (bit (insn1, 9)) /* Data processing (plain binary imm).  */
-	    {
-	      int op = bits (insn1, 4, 8);
-	      int rn = bits (insn1, 0, 3);
-	      if ((op == 0 || op == 0xa) && rn == 0xf)
-		err = visitor->pc_relative_32bit (insn1, insn2, data);
-	      else
-		err = visitor->others (insn1, insn2, "dp/pb", data);
-	    }
-	  else /* Data processing (modified immeidate) */
-	    err = visitor->others (insn1, insn2, "dp/mi", data);
-	}
-      break;
-    case 3: /* op1 = 3 */
-      switch (bits (insn1, 9, 10))
-	{
-	case 0:
-	  if (bit (insn1, 4))
-	    err = decode_thumb_32bit_ld_mem_hints (insn1, insn2, visitor, data);
-	  else /* NEON Load/Store and Store single data item */
-	    err = visitor->others (insn1, insn2, "neon elt/struct load/store",
-				   data);
-	  break;
-	case 1: /* op1 = 3, bits (9, 10) == 1 */
-	  switch (bits (insn1, 7, 8))
-	    {
-	    case 0: case 1: /* Data processing (register) */
-	      err = visitor->others (insn1, insn2, "dp(reg)", data);
-	      break;
-	    case 2: /* Multiply and absolute difference */
-	      err = visitor->others (insn1, insn2, "mul/mua/diff", data);
-	      break;
-	    case 3: /* Long multiply and divide */
-	      err = visitor->others (insn1, insn2, "lmul/lmua", data);
-	      break;
-	    }
-	  break;
-	default: /* Coprocessor instructions */
-	  err = thumb2_decode_svc_copro (insn1, insn2, visitor, data);
-	  break;
-	}
-      break;
-    default:
-      err = 1;
-    }
-
-  return err;
-
-}
-
 static struct arm_insn_reloc_visitor arm_insn_reloc_visitor =
 {
   arm_copy_alu_imm,
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 12/18] Add ARM/Thumb instruction assembler for fast tracepoints
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (2 preceding siblings ...)
  2016-07-05 13:41 ` [PATCH v3 13/18] Export tracing control breakpoints functions via global function pointers Antoine Tremblay
@ 2016-07-05 13:41 ` Antoine Tremblay
  2016-07-05 13:41 ` [PATCH v3 03/18] arm-tdep.c: Move debug printout from decode to copy function Antoine Tremblay
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

This patch adds the required helper functions to emit native ARM and Thumb
instructions for use in the fast tracepoints jump pad and in the fast
tracepoints JIT condition implementation.

gdb/ChangeLog:

	* Makefile.in (ALL_64_TARGET_OBS): Add arm-insn-utils.o
	(ALL_TARGET_OBS): Add arm-insn-emit.o.
	(HFILES_NO_SRCDIR): Add arch/arm-insn-emit.h, arch/arm-insn-utils.h.
	(arm-linux.o:): Add rule.
	(arm-insn-emit.o): Likewise.
	(arm-insn-utils.o): Likewise.
	* aarch64-tdep.c: Include arch/arm-insn-utils.h
	(aarch64_displaced_step_ldr_literal): Adapt to sue arm_memory_operand.
	* arch/aarch64-insn.c: Include arch/arm-insn-utils.h
	(aarch64_emit_load_store): Adapt to use arm_memory_operand.
	* arch/aarch64-insn.h (struct aarch64_register): Likewise.
	(enum aarch64_memory_operand_type): Remove.
	(struct aarch64_memory_operand): Remove.
	(ENCODE): Move to arm-insn-utils.h.
	(aarch64_emit_load_store): Adapt to use arm_memory_operand.
	* arch/arm-insn-emit.c: New file.
	* arch/arm-insn-emit.h: New file.
	* configure.tgt (aarch64*-*-elf | aarch64*-*-rtems*): Add
	arm-insn-utils.o
	(aarch64*-*-linux*): Likewise.

gdb/gdbserver/ChangeLog:

	* Makefile.in (SFILES): Add arch/arm-insn-emit.c.
	(arm-insn-emit.o): New rule.
	(arm-insn-utils.o): New rule.
	* configure.srv (aarch64*-*-linux*): Add arm-insn-utils.o.
	(arm*-*-linux*): Likewise.
	* linux-aarch64-low.c: Include arch/arm-insn-utils.h.
	(enum aarch64_operand_type): Remove.
	(struct aarch64_operand): Adapt for arm_operand_type.
	(offset_memory_operand): Move to arm-insn-utils.c.
	(preindex_memory_operand): Likewise.
	(postindex_memory_operand): Likewise.
	(emit_load_store_pair): Adapt for arm_memory_operand.
	(emit_load_store_pair): Likewise.
	(emit_ldp): Likewise.
	(emit_ldrh): Likewise.
	(emit_ldrb): Likewise.
	(emit_str): Likewise.
---
 gdb/Makefile.in                   |   18 +-
 gdb/aarch64-tdep.c                |    3 +-
 gdb/arch/aarch64-insn.c           |    3 +-
 gdb/arch/aarch64-insn.h           |   32 +-
 gdb/arch/arm-insn-emit.c          | 1550 +++++++++++++++++++++++++++++++++++++
 gdb/arch/arm-insn-emit.h          | 1087 ++++++++++++++++++++++++++
 gdb/arch/arm-insn-utils.c         |   44 ++
 gdb/arch/arm-insn-utils.h         |   80 ++
 gdb/configure.tgt                 |    5 +-
 gdb/gdbserver/Makefile.in         |   10 +-
 gdb/gdbserver/configure.srv       |    3 +
 gdb/gdbserver/linux-aarch64-low.c |   54 +-
 12 files changed, 2804 insertions(+), 85 deletions(-)
 create mode 100644 gdb/arch/arm-insn-emit.c
 create mode 100644 gdb/arch/arm-insn-emit.h
 create mode 100644 gdb/arch/arm-insn-utils.c
 create mode 100644 gdb/arch/arm-insn-utils.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index a83b456..fe5b6f8 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -644,7 +644,9 @@ TARGET_OBS = @TARGET_OBS@
 # All target-dependent objects files that require 64-bit CORE_ADDR
 # (used with --enable-targets=all --enable-64-bit-bfd).
 ALL_64_TARGET_OBS = \
-	aarch64-tdep.o aarch64-linux-tdep.o aarch64-newlib-tdep.o aarch64-insn.o \
+	aarch64-tdep.o aarch64-linux-tdep.o aarch64-newlib-tdep.o \
+	aarch64-insn.o \
+	arm-insn-utils.o \
 	alphabsd-tdep.o alphafbsd-tdep.o alpha-linux-tdep.o alpha-mdebug-tdep.o \
 	alphanbsd-tdep.o alphaobsd-tdep.o alpha-tdep.o \
 	amd64fbsd-tdep.o amd64-darwin-tdep.o amd64-dicos-tdep.o \
@@ -662,8 +664,9 @@ ALL_TARGET_OBS = \
 	arm-linux.o \
 	arm-linux-tdep.o \
 	arm-get-next-pcs.o \
-	arm-symbian-tdep.o \
+	arm-insn-emit.o \
 	arm-insn-reloc.o \
+	arm-symbian-tdep.o \
 	armnbsd-tdep.o armobsd-tdep.o \
 	arm-tdep.o arm-wince-tdep.o \
 	avr-tdep.o \
@@ -994,7 +997,8 @@ common/common-exceptions.h target/target.h common/symbol.h \
 common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \
 common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h nat/amd64-linux-siginfo.h\
 nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h arch/aarch64-insn.h \
-tid-parse.h ser-event.h arch/arm-insn-reloc.h
+tid-parse.h ser-event.h arch/arm-insn-emit.h arch/arm-insn-reloc.h \
+arch/arm-insn-utils.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -2315,6 +2319,10 @@ arm-linux.o: ${srcdir}/arch/arm-linux.c
 	$(COMPILE) $(srcdir)/arch/arm-linux.c
 	$(POSTCOMPILE)
 
+arm-insn-emit.o: ${srcdir}/arch/arm-insn-emit.c
+	$(COMPILE) $(srcdir)/arch/arm-insn-emit.c
+	$(POSTCOMPILE)
+
 arm-insn-reloc.o: ${srcdir}/arch/arm-insn-reloc.c
 	$(COMPILE) $(srcdir)/arch/arm-insn-reloc.c
 	$(POSTCOMPILE)
@@ -2397,6 +2405,10 @@ aarch64-insn.o: ${srcdir}/arch/aarch64-insn.c
 	$(COMPILE) $(srcdir)/arch/aarch64-insn.c
 	$(POSTCOMPILE)
 
+arm-insn-utils.o: ${srcdir}/arch/arm-insn-utils.c
+	$(COMPILE) $(srcdir)/arch/arm-insn-utils.c
+	$(POSTCOMPILE)
+
 #
 # gdb/tui/ dependencies
 #
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index e5ce13e..67c10f2 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -57,6 +57,7 @@
 
 #include "features/aarch64.c"
 
+#include "arch/arm-insn-utils.h"
 #include "arch/aarch64-insn.h"
 
 #include "opcode/aarch64.h"
@@ -2471,7 +2472,7 @@ aarch64_displaced_step_ldr_literal (const int32_t offset, const int is_sw,
   struct aarch64_displaced_step_data *dsd
     = (struct aarch64_displaced_step_data *) data;
   CORE_ADDR address = data->insn_addr + offset;
-  struct aarch64_memory_operand zero = { MEMORY_OPERAND_OFFSET, 0 };
+  struct arm_memory_operand zero = { MEMORY_OPERAND_OFFSET, 0 };
 
   regcache_cooked_write_unsigned (dsd->regs, AARCH64_X0_REGNUM + rt,
 				  address);
diff --git a/gdb/arch/aarch64-insn.c b/gdb/arch/aarch64-insn.c
index 772512b..88fbffe 100644
--- a/gdb/arch/aarch64-insn.c
+++ b/gdb/arch/aarch64-insn.c
@@ -17,6 +17,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "common-defs.h"
+#include "arm-insn-utils.h"
 #include "aarch64-insn.h"
 
 /* Toggle this file's internal debugging dump.  */
@@ -346,7 +347,7 @@ aarch64_emit_load_store (uint32_t *buf, uint32_t size,
 			 enum aarch64_opcodes opcode,
 			 struct aarch64_register rt,
 			 struct aarch64_register rn,
-			 struct aarch64_memory_operand operand)
+			 struct arm_memory_operand operand)
 {
   uint32_t op;
 
diff --git a/gdb/arch/aarch64-insn.h b/gdb/arch/aarch64-insn.h
index a799515..511a80c 100644
--- a/gdb/arch/aarch64-insn.h
+++ b/gdb/arch/aarch64-insn.h
@@ -117,36 +117,6 @@ struct aarch64_register
   int is64;
 };
 
-enum aarch64_memory_operand_type
-{
-  MEMORY_OPERAND_OFFSET,
-  MEMORY_OPERAND_PREINDEX,
-  MEMORY_OPERAND_POSTINDEX,
-};
-
-/* Representation of a memory operand, used for load and store
-   instructions.
-
-   The types correspond to the following variants:
-
-   MEMORY_OPERAND_OFFSET:    LDR rt, [rn, #offset]
-   MEMORY_OPERAND_PREINDEX:  LDR rt, [rn, #index]!
-   MEMORY_OPERAND_POSTINDEX: LDR rt, [rn], #index  */
-
-struct aarch64_memory_operand
-{
-  /* Type of the operand.  */
-  enum aarch64_memory_operand_type type;
-
-  /* Index from the base register.  */
-  int32_t index;
-};
-
-/* Helper macro to mask and shift a value into a bitfield.  */
-
-#define ENCODE(val, size, offset) \
-  ((uint32_t) ((val & ((1ULL << size) - 1)) << offset))
-
 int aarch64_decode_adr (CORE_ADDR addr, uint32_t insn, int *is_adrp,
 			unsigned *rd, int32_t *offset);
 
@@ -319,6 +289,6 @@ int aarch64_emit_load_store (uint32_t *buf, uint32_t size,
 			     enum aarch64_opcodes opcode,
 			     struct aarch64_register rt,
 			     struct aarch64_register rn,
-			     struct aarch64_memory_operand operand);
+			     struct arm_memory_operand operand);
 
 #endif
diff --git a/gdb/arch/arm-insn-emit.c b/gdb/arch/arm-insn-emit.c
new file mode 100644
index 0000000..810172d
--- /dev/null
+++ b/gdb/arch/arm-insn-emit.c
@@ -0,0 +1,1550 @@
+/* Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "arm.h"
+#include "arm-insn-utils.h"
+#include "arm-insn-emit.h"
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+/* Encode a bitfield with a repetition of BIT starting at from FROM for
+   LENGHT.  Max 16 bits.  */
+
+static uint16_t
+repeat_bit (uint8_t bit, uint8_t from, uint8_t length)
+{
+  uint16_t value = 0;
+  int i;
+
+  for (i = from; i - from < length; i++)
+    {
+      value |= ENCODE (bit & 1, 1, i);
+    }
+
+  return value;
+}
+
+/* See arm-insn-emit.h.  */
+
+uint16_t
+encode_register_list (uint8_t from, uint8_t length, uint16_t initial)
+{
+  return repeat_bit (1, from, length) | initial;
+}
+
+/* See arm-insn-emit.h.  */
+
+struct arm_operand
+immediate_operand (uint32_t imm)
+{
+  struct arm_operand operand;
+
+  operand.type = OPERAND_IMMEDIATE;
+  operand.imm = imm;
+
+  return operand;
+}
+
+/* Helper function to create a register operand, for instructions with
+   different types of operands.
+
+   For example:
+   p += emit_mov (p, x0, register_operand (x1));  */
+
+/* See arm-insn-emit.h.  */
+
+struct arm_operand
+register_operand (uint8_t reg)
+{
+  struct arm_operand operand;
+
+  operand.type = OPERAND_REGISTER;
+  operand.reg = reg;
+
+  return operand;
+}
+
+/* See arm-insn-emit.h.  */
+
+struct arm_operand
+memory_operand (struct arm_memory_operand mem)
+{
+  struct arm_operand operand;
+
+  operand.type = OPERAND_MEMORY;
+  operand.mem = mem;
+
+  return operand;
+}
+
+/* Write a 32-bit unsigned integer INSN info *BUF.  Return the number of
+   instructions written (aka. 1).  */
+
+static int
+arm_emit_arm_insn (uint32_t *buf, uint32_t insn)
+{
+  *buf = insn;
+  return 1;
+}
+
+/* Write a 16-bit unsigned integer INSN info *BUF.  Return the number of
+   instructions written (aka. 1).  */
+
+static int
+arm_emit_thumb_insn (uint16_t *buf, uint16_t insn)
+{
+  *buf = insn;
+  return 1;
+}
+
+/* Write a 32-bit unsigned integer INSN representing a Thumb-2 wide
+   instruction info *BUF.  Return the number of instructions written
+   (aka. 2).  */
+
+static int
+arm_emit_thumb_w_insn (uint16_t *buf, uint32_t insn)
+{
+  int res = arm_emit_thumb_insn (buf, bits (insn, 16, 31));
+  res += arm_emit_thumb_insn (buf + res, bits (insn, 0, 15));
+  return res;
+}
+
+/* See arm-insn-emit.h.  */
+
+uint32_t
+arm_arm_branch_relative_distance (CORE_ADDR from, CORE_ADDR to)
+{
+  return arm_arm_branch_adjusted_offset ((uint32_t) to - (uint32_t) from);
+}
+
+/* See arm-insn-emit.h.  */
+
+uint32_t
+arm_thumb_branch_relative_distance (CORE_ADDR from, CORE_ADDR to)
+{
+  uint32_t from_ = ((uint32_t) from) & ~1;
+  uint32_t to_ = ((uint32_t) to) & ~1;
+  return arm_thumb_branch_adjusted_offset (to_ - from_);
+}
+
+/* See arm-insn-emit.h.  */
+
+uint32_t
+arm_thumb_to_arm_branch_relative_distance (CORE_ADDR from, CORE_ADDR to)
+{
+  uint32_t from_ = ((uint32_t) from) & ~3;
+  uint32_t to_ = ((uint32_t) to) & ~3;
+  return arm_thumb_branch_adjusted_offset (to_ - from_);
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_arm_is_reachable (CORE_ADDR from, CORE_ADDR to)
+{
+  int32_t rel = arm_arm_branch_relative_distance (from, to);
+  rel >>= 25;
+  return !rel || !(rel + 1);
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_thumb_is_reachable (CORE_ADDR from, CORE_ADDR to)
+{
+  int32_t rel = arm_thumb_branch_relative_distance (from, to);
+  rel >>= 24;
+  return !rel || !(rel + 1);
+}
+
+/* See arm-insn-emit.h.  */
+
+uint32_t
+arm_arm_branch_adjusted_offset (uint32_t offset)
+{
+  return offset - 8;
+}
+
+/* See arm-insn-emit.h.  */
+
+uint32_t
+arm_thumb_branch_adjusted_offset (uint32_t offset)
+{
+  return offset - 4;
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_mov_32 (uint16_t *mem, int reg, uint32_t val)
+{
+  uint16_t val_low = bits (val, 0, 15);
+  uint16_t val_high = bits (val, 16, 31);
+  int res = 0;
+
+  res += arm_emit_thumb_movw (mem, reg, immediate_operand (val_low));
+  res += arm_emit_thumb_movt (mem + res, reg, immediate_operand (val_high));
+
+  return res;
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_mov_32 (uint32_t *mem, int reg, uint32_t val)
+{
+  uint16_t val_low = bits (val, 0, 15);
+  uint16_t val_high = bits (val, 16, 31);
+  int res = 0;
+
+  res += arm_emit_arm_movw (mem, INST_AL, reg, immediate_operand (val_low));
+  res += arm_emit_arm_movt (mem + res, INST_AL, reg,
+			    immediate_operand (val_high));
+
+  return res;
+}
+
+/* Write ARM branch instructions into *BUF.
+
+   This is a base function to write
+   B, BL and BLX instructions with immediate or register operands.
+
+   Proper encodings documentation is provided in the
+   arm_emit_arm_{b_,bl_,blx} helper functions.
+
+   L if set a bl instruction will be written.
+   X if set a blx instruction will be written.  */
+
+static int
+arm_emit_arm_branch (uint32_t *buf, uint8_t cond,
+		     struct arm_operand operand,
+		     uint8_t l, uint8_t x)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      /* BLX  */
+      if (l == 1 && x == 1)
+	{
+	  cond = 0xF;
+	  l = bit (operand.imm, 1);
+	}
+      /* Encode B, BL or BLX.  */
+      return arm_emit_arm_insn (buf, (ARM_B
+				      | ENCODE (l, 1, 24)
+				      | ENCODE (cond, 4, 28)
+				      | ENCODE (operand.imm >> 2, 24, 0)));
+    }
+  else if (operand.type == OPERAND_REGISTER)
+    {
+      if (l == 1 && x == 1)
+	{
+	  return arm_emit_arm_insn (buf, (ARM_BLX
+					  | ENCODE (cond, 4, 28)
+					  | ENCODE (operand.reg, 4, 0)));
+	}
+      else
+	{
+	  /* error. Only BLX has a register operand.  */
+	  throw_error (NOT_SUPPORTED_ERROR,
+		       _("Unimplemented instruction encoding."));
+	}
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* Write Thumb branch instructions into *BUF.
+
+   This is a base function to write
+   BW, BL and BLX instructions with immediate or register operand.
+
+   Proper encodings documentation is provided in the
+   arm_emit_thumb_{bw_,bl_,blx} helper functions.
+
+   REL is the relative offset of the label.
+   L if set a bl instruction will be written.
+   X if set a blx instruction will be written.  */
+
+int
+arm_emit_thumb_branch (uint16_t *buf, struct arm_operand operand,
+		       uint8_t l, uint8_t x)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      uint32_t imm10, imm11;
+      uint32_t s, j1, j2;
+
+      if (x == 0)
+	imm11 = bits (operand.imm, 1, 11);
+      else
+	/* IMM10L:H.  */
+	imm11 = bits (operand.imm, 2, 11) << 1;
+
+      imm10 = bits (operand.imm, 12, 21);
+      s = bit (operand.imm, 24);
+      j1 = s ^ !(bit (operand.imm, 23));
+      j2 = s ^ !(bit (operand.imm, 22));
+
+      return arm_emit_thumb_w_insn (buf, (THUMB_BW
+					  | ENCODE (s, 1, 26)
+					  | ENCODE (imm10, 10, 16)
+					  | ENCODE (l, 1, 14)
+					  | ENCODE (j1, 1, 13)
+					  | ENCODE (x == 0 ? 1 : 0, 1, 12)
+					  | ENCODE (j2, 1, 11)
+					  | ENCODE (imm11, 11, 0)));
+    }
+  else if (operand.type == OPERAND_REGISTER)
+    {
+      if (l == 1 && x == 1)
+        return arm_emit_thumb_insn (buf, (THUMB_BLX
+					  | ENCODE (operand.reg, 4, 3)));
+      else
+	{
+	  throw_error (NOT_SUPPORTED_ERROR,
+		       _("Unimplemented instruction encoding."));
+	}
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_b (uint32_t *buf, uint8_t cond, uint32_t rel)
+{
+  return arm_emit_arm_branch (buf, cond, immediate_operand (rel), 0, 0);
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_bl (uint32_t *buf, uint8_t cond, uint32_t rel)
+{
+  return arm_emit_arm_branch (buf, cond, immediate_operand (rel), 1, 0);
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_bl (uint16_t *buf, uint32_t rel)
+{
+  return arm_emit_thumb_branch (buf, immediate_operand (rel), 1, 0);
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_b (uint16_t *buf, uint8_t cond, uint32_t rel)
+{
+  return arm_emit_thumb_insn (buf, (THUMB_B
+				    | ENCODE (cond, 4, 8)
+				    | ENCODE (rel >> 1, 8, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_bw (uint16_t *buf, uint32_t rel)
+{
+  return arm_emit_thumb_branch (buf, immediate_operand (rel), 0, 0);
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_bw_cond (uint16_t *buf, uint8_t cond, uint32_t rel)
+{
+  uint32_t imm6, imm11;
+  uint32_t s, j1, j2;
+
+  imm11 = bits (rel, 1, 11);
+  imm6 = bits (rel, 12, 17);
+  s = bit (rel, 24);
+  j1 = s ^ !(bit (rel, 23));
+  j2 = s ^ !(bit (rel, 22));
+
+  return arm_emit_thumb_w_insn (buf, (THUMB_BW
+				      | ENCODE (s, 1, 26)
+				      | ENCODE (imm6, 6, 16)
+				      | ENCODE (cond, 4, 22)
+				      | ENCODE (j1, 1, 13)
+				      | ENCODE (j2, 1, 11)
+				      | ENCODE (imm11, 11, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_blx (uint16_t *buf, struct arm_operand operand)
+{
+  return arm_emit_thumb_branch (buf, operand, 1, 1);
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_blx (uint32_t *buf, uint8_t cond, struct arm_operand operand)
+{
+  return arm_emit_arm_branch (buf, cond, operand, 1, 1);
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_movw (uint32_t *buf, uint8_t cond, uint8_t rd,
+		   struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_arm_insn (buf,
+				(ARM_MOVW
+				 | ENCODE (cond, 4, 28)
+				 | ENCODE (bits (operand.imm, 12, 15), 4, 16)
+				 | ENCODE (rd, 4, 12)
+				 | ENCODE (bits (operand.imm, 0, 11), 12, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_mov (uint32_t *buf, uint8_t cond, uint8_t rd,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_arm_insn (buf,
+				(ARM_MOV
+				 | ENCODE (cond, 4, 28)
+				 /* Immediate value opcode.  */
+				 | ENCODE (1, 1, 25)
+				 | ENCODE (rd, 4, 12)
+				 | ENCODE (bits (operand.imm, 0, 11), 12, 0)));
+    }
+  else if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_insn (buf, (ARM_MOV
+				      | ENCODE (cond, 4, 28)
+				      | ENCODE (rd, 4, 12)
+				      | ENCODE (operand.reg, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_movw (uint16_t *buf, uint8_t rd, struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_thumb_w_insn (buf,
+				    (THUMB_MOVW
+				     | ENCODE (bit (operand.imm, 11), 1, 26)
+				     | ENCODE (bits (operand.imm, 12, 15),
+					       4, 16)
+				     | ENCODE (bits (operand.imm, 8, 10), 3, 12)
+				     | ENCODE (rd, 4, 8)
+				     | ENCODE (bits (operand.imm, 0, 7),
+					       8, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_movt (uint32_t *buf, uint8_t cond, uint8_t rd,
+		   struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_arm_insn (buf,
+				(ARM_MOVT
+				 | ENCODE (cond, 4, 28)
+				 | ENCODE (bits (operand.imm, 12, 15), 4, 16)
+				 | ENCODE (rd, 4, 12)
+				 | ENCODE (bits (operand.imm, 0, 11), 12, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_movt (uint16_t *buf, uint8_t rd, struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_thumb_w_insn (buf,
+				    (THUMB_MOVT
+				     | ENCODE (bit (operand.imm, 11), 1, 26)
+				     | ENCODE (bits (operand.imm, 12, 15),
+					       4, 16)
+				     | ENCODE (bits (operand.imm, 8, 10), 3, 12)
+				     | ENCODE (rd, 4, 8)
+				     | ENCODE (bits (operand.imm, 0, 7),8, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_vpush (uint32_t *buf, uint8_t cond, uint8_t rs, uint8_t len)
+{
+  return arm_emit_arm_insn (buf, (ARM_VPUSH
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (bit (rs, 4), 1, 22)
+				  | ENCODE (bits (rs, 0, 3), 4, 12)
+				  | ENCODE (2 * len, 8, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_vpush (uint16_t *buf, uint8_t rs, uint8_t len)
+{
+  return arm_emit_thumb_w_insn (buf, (THUMB_VPUSH
+				      | ENCODE (bit (rs, 4), 1, 22)
+				      | ENCODE (bits (rs, 0, 3), 4, 12)
+				      | ENCODE (2 * len, 8, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_push_list (uint32_t *buf, uint8_t cond, uint16_t register_list)
+{
+  return arm_emit_arm_insn (buf, (ARM_PUSH_A1
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (register_list, 16, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_push_one (uint32_t *buf, uint8_t cond, uint8_t rt)
+{
+  return arm_emit_arm_insn (buf, (ARM_PUSH_A2
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (rt, 4, 12)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_push_one (uint16_t *buf, uint8_t register_list, uint8_t lr)
+{
+  return arm_emit_thumb_insn (buf, (THUMB_PUSH_T1
+				    | ENCODE (register_list, 8, 0)
+				    | ENCODE (lr, 1, 8)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_push_list (uint16_t *buf,
+			  uint16_t register_list,
+			  uint8_t lr)
+{
+  return arm_emit_thumb_w_insn (buf, (THUMB_PUSH_T2
+				      | ENCODE (bit (lr, 0), 1, 14)
+				      | ENCODE (register_list, 13, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_mrs (uint32_t *buf,
+		  uint8_t cond,
+		  uint8_t rd)
+{
+  return arm_emit_arm_insn (buf, (ARM_MRS
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (rd, 4, 12)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_mrs (uint16_t *buf, uint8_t rd)
+{
+  return arm_emit_thumb_w_insn (buf, THUMB_MRS | ENCODE (rd, 4, 12));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_mov (uint16_t *buf, uint8_t rd, struct arm_operand operand)
+{
+   if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_thumb_insn (buf, (THUMB_MOV
+					| ENCODE (bit (rd, 3), 1, 7)
+					| ENCODE (bits (rd, 0, 2), 3, 0)
+					| ENCODE (operand.reg, 4, 3)));
+    }
+   else
+     {
+       throw_error (NOT_SUPPORTED_ERROR,
+		    _("Unimplemented instruction encoding."));
+     }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_dmb (uint32_t *buf)
+{
+  return arm_emit_arm_insn (buf, ARM_DMB | ENCODE (0xF, 4, 0));
+
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_dmb (uint16_t *buf)
+{
+  return arm_emit_thumb_w_insn (buf, THUMB_DMB | ENCODE (0xF, 4, 0));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_ldrex (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn)
+{
+  return arm_emit_arm_insn (buf, (ARM_LDREX
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (rn, 4, 16)
+				  | ENCODE (rt, 4, 12)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_ldrex (uint16_t *buf, int8_t rt, uint8_t rn,
+			  struct arm_operand operand)
+{
+
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_thumb_w_insn (buf,
+				    (THUMB_LDREX
+				     | ENCODE (rn, 4, 16)
+				     | ENCODE (rt, 4, 12)
+				     | ENCODE (bits (operand.imm, 0, 7),
+					       8, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_cmp (uint32_t *buf, uint8_t cond, uint8_t rn,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_arm_insn (buf,
+				(ARM_CMP
+				 | ENCODE (cond, 4, 28)
+				 /* Immediate.  */
+				 | ENCODE (1, 1, 25)
+				 | ENCODE (rn, 4, 16)
+				 | ENCODE (bits (operand.imm, 0, 11), 12, 0)));
+    }
+  else if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_insn (buf, (ARM_CMP
+				      | ENCODE (cond, 4, 28)
+				      | ENCODE (rn, 4, 16)
+				      | ENCODE (operand.reg, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_cmp (uint16_t *buf, uint8_t rn, struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_thumb_insn (buf,
+				  (THUMB_CMP
+				   | ENCODE (rn, 3, 8)
+				   | ENCODE (bits (operand.imm, 0, 7), 8, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_cmpw (uint16_t *buf, uint8_t rn, struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_thumb_w_insn (buf,
+				    (THUMB_CMPW
+				     | ENCODE (rn, 4, 16)
+				     | ENCODE (bit (operand.imm, 11), 1, 26)
+				     | ENCODE (bits (operand.imm, 8, 10), 3, 12)
+				     | ENCODE (bits (operand.imm, 0, 7),
+					       8, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_bic (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_arm_insn (buf,
+				(ARM_BIC
+				 | ENCODE (cond, 4, 28)
+				 | ENCODE (rn, 4, 16)
+				 | ENCODE (rd, 4, 12)
+				 | ENCODE (bits (operand.imm, 0, 11), 12, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_bic (uint16_t *buf, uint8_t rd, uint8_t rn,
+		    struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_thumb_w_insn (buf,
+				    (THUMB_BIC
+				     | ENCODE (bit (operand.imm, 11), 1, 26)
+				     | ENCODE (rn, 4, 16)
+				     | ENCODE (rd, 4, 8)
+				     | ENCODE (bits (operand.imm, 8, 10), 3, 12)
+				     | ENCODE (bits (operand.imm, 0, 7),
+					       8, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_strex (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rt,
+		    uint8_t rn)
+{
+  return arm_emit_arm_insn (buf, (ARM_STREX
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (rn, 4, 16)
+				  | ENCODE (rd, 4, 12)
+				  | ENCODE (rt, 4, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_strex (uint16_t *buf, uint8_t rd, uint8_t rt, uint8_t rn,
+		      struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_thumb_w_insn (buf, (THUMB_STREX
+					  | ENCODE (rn, 4, 16)
+					  | ENCODE (rt, 4, 12)
+					  | ENCODE (rd, 4, 8)
+					  | ENCODE (operand.imm, 8, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_str (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_MEMORY)
+    {
+      switch (operand.mem.type)
+	{
+	case MEMORY_OPERAND_OFFSET:
+	  {
+	    return arm_emit_arm_insn (buf,
+				      (ARM_STR
+				       | ENCODE (cond, 4, 28)
+				       /* P.  */
+				       | ENCODE (1, 1, 24)
+				       /* U.  */
+				       | ENCODE (operand.mem.index < 0 ? 0 : 1,
+						 1, 23)
+				       | ENCODE (rn, 4, 16)
+				       | ENCODE (rt, 4, 12)
+				       | ENCODE (bits (ABS (operand.mem.index),
+						       0, 11), 12, 0)));
+
+	  }
+	default:
+	  {
+	    throw_error (NOT_SUPPORTED_ERROR,
+			 _("Unimplemented instruction encoding."));
+	  }
+	}
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_str (uint16_t *buf, uint8_t rt, uint8_t rn,
+		    struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_thumb_insn (buf, (THUMB_STR
+					| ENCODE (operand.imm, 5, 6)
+					| ENCODE (rn, 3, 3)
+					| ENCODE (rt, 3, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+
+}
+
+/* Helper function to emit data processing register instructions.  */
+
+static int
+arm_emit_arm_data_processing_reg (uint32_t *buf, uint32_t opcode,
+				  uint8_t cond, uint8_t flags,
+				  uint32_t operands)
+{
+  return arm_emit_arm_insn (buf, (opcode
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (flags, 1, 20)
+				  /* No shift.  */
+				  | ENCODE (0, 5, 7)
+				  | ENCODE (0, 2, 5)
+				  | operands));
+}
+
+/* Helper function to emit data processing immediate instructions.  */
+
+static int
+arm_emit_arm_data_processing_imm (uint32_t *buf, uint32_t opcode, uint8_t cond,
+				  uint8_t rn, uint32_t operands)
+{
+  return arm_emit_arm_insn (buf, (opcode
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (rn, 4, 16)
+				  | operands));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_add (uint32_t *buf, uint8_t cond, uint8_t flags, uint8_t rd,
+		  uint8_t rn, struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_arm_insn (buf, (ARM_ADD
+				      /* Immediate operand */
+				      | ENCODE (1, 1, 25)
+				      | ENCODE (cond, 4, 28)
+				      | ENCODE (flags, 1, 20)
+				      | ENCODE (rn, 4, 16)
+				      | ENCODE (rd, 4, 12)
+				      | ENCODE (operand.imm, 8, 0)));
+    }
+  else if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_data_processing_reg (buf, ARM_ADD, cond, flags,
+					       (ENCODE (rn, 4, 16)
+						| ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_adc (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+  else if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_data_processing_reg (buf, ARM_ADC, cond, 0,
+					       (ENCODE (rn, 4, 16)
+						| ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_add_sp (uint16_t *buf, struct arm_operand operand)
+{
+  if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_thumb_insn (buf, (THUMB_ADD_SP
+					| ENCODE (operand.imm >> 2, 7, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_pop_one (uint32_t *buf, uint8_t cond, uint8_t rt)
+{
+  return arm_emit_arm_insn (buf, (ARM_POP_A2
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (rt, 4, 12)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_pop_list (uint32_t *buf, uint8_t cond, uint16_t register_list)
+{
+  return arm_emit_arm_insn (buf, (ARM_POP_A1
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (register_list, 16, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_pop (uint16_t *buf, uint8_t register_list, uint8_t pc)
+{
+  return arm_emit_thumb_insn (buf, (THUMB_POP
+				    | ENCODE (pc, 1, 8)
+				    | ENCODE (register_list, 8, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_popw_list (uint16_t *buf, uint16_t register_list, uint8_t pc,
+			  uint8_t lr)
+{
+  return arm_emit_thumb_w_insn (buf, (THUMB_POPW
+				      | ENCODE (pc, 1, 15)
+				      | ENCODE (lr, 1, 14)
+				      | ENCODE (register_list, 13, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_msr (uint32_t *buf, uint8_t cond, uint8_t rn)
+{
+  return arm_emit_arm_insn (buf, (ARM_MSR
+				  | ENCODE (cond, 4, 28)
+				  /* Mask 0b11  */
+				  | ENCODE (3, 2, 18)
+				  | ENCODE (rn, 4, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_msr (uint16_t *buf, uint8_t rn)
+{
+  return arm_emit_thumb_w_insn (buf, (THUMB_MSR
+				      | ENCODE (rn, 4, 16)
+				      /* Mask 0b11  */
+				      | ENCODE (3, 2, 10)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_vpop (uint32_t *buf, uint8_t cond, uint8_t rs, uint8_t len)
+{
+  return arm_emit_arm_insn (buf, (ARM_VPOP
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (bit (rs, 4), 1, 22)
+				  | ENCODE (bits (rs, 0, 3), 4, 12)
+				  | ENCODE (2 * len, 8, 0)));
+
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_thumb_vpop (uint16_t *buf, uint8_t rs, uint8_t len)
+{
+  return arm_emit_thumb_w_insn (buf, (THUMB_VPOP
+				      | ENCODE (bit (rs, 4), 1, 22)
+				      | ENCODE (bits (rs, 0, 3), 4, 12)
+				      | ENCODE (2 * len, 8, 0)));
+}
+
+/* Helper function for LDR and LDRB instructions.  */
+
+static int
+arm_emit_arm_ldr_ldrb (uint32_t *buf, uint32_t opcode, uint8_t cond, uint8_t rt,
+		       uint8_t rn, struct arm_memory_operand operand)
+{
+  switch (operand.type)
+    {
+    case MEMORY_OPERAND_OFFSET:
+      {
+	/* Offset P 1 , W 0 */
+	/* Pre indexed P 1 W 1 */
+	/* Post indexed P 0 W1 */
+	/* U 1 if offset add */
+	/* U 0 if offset sub */
+
+	/* Offset P1 , W0.  */
+	uint32_t offset_op = ENCODE (1, 1, 24) | ENCODE (0, 1, 21);
+
+	/* U1 if offset added or omitted, U0 if subtracted.  */
+	if (operand.index >= 0)
+	  offset_op |= ENCODE (1, 1, 23);
+
+	return arm_emit_arm_insn (buf, (opcode
+					| ENCODE (cond, 4, 28)
+					| offset_op
+					| ENCODE (rn, 4, 16)
+					| ENCODE (rt, 4, 12)
+					| ENCODE (ABS (operand.index), 12, 0)));
+      }
+    default:
+      {
+	throw_error (NOT_SUPPORTED_ERROR,
+		     _("Unimplemented instruction encoding."));
+      }
+    }
+}
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_ldr (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn,
+		  struct arm_memory_operand operand)
+{
+  return arm_emit_arm_ldr_ldrb (buf, ARM_LDR, cond, rt, rn, operand);
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_ldrb (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn,
+		   struct arm_memory_operand operand)
+{
+  return arm_emit_arm_ldr_ldrb (buf, ARM_LDRB, cond, rt, rn, operand);
+}
+
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_ldrh (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn,
+		   struct arm_memory_operand operand)
+{
+  switch (operand.type)
+    {
+    case MEMORY_OPERAND_OFFSET:
+      {
+	/* Offset P 1 , W 0 */
+	/* Pre indexed P 1 W 1 */
+	/* Post indexed P 0 W1 */
+	/* U 1 if offset add */
+	/* U 0 if offset sub */
+
+	/* Offset P1 , W0.  */
+	uint32_t offset_op = ENCODE (1, 1, 24) | ENCODE (0, 1, 21);
+
+	/* U1 if offset added or omitted, U0 if subtracted.  */
+	if (operand.index >= 0)
+	  offset_op |= ENCODE (1, 1, 23);
+
+	return arm_emit_arm_insn (buf,
+				  (ARM_LDRH
+				   | ENCODE (cond, 4, 28)
+				   | offset_op
+				   | ENCODE (rn, 4, 16)
+				   | ENCODE (rt, 4, 12)
+				   | ENCODE (bits(ABS (operand.index), 4, 7),
+					     4, 8)
+				   | ENCODE (bits(ABS (operand.index), 0, 3),
+					     4, 0)));
+      }
+    default:
+      {
+	throw_error (NOT_SUPPORTED_ERROR,
+		     _("Unimplemented instruction encoding."));
+      }
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_ldrd (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn,
+		   struct arm_memory_operand operand)
+{
+  switch (operand.type)
+    {
+    case MEMORY_OPERAND_OFFSET:
+      {
+	/* Offset P 1 , W 0 */
+	/* Pre indexed P 1 W 1 */
+	/* Post indexed P 0 W1 */
+	/* U 1 if offset add */
+	/* U 0 if offset sub */
+
+	/* Offset P1 , W0.  */
+	uint32_t offset_op = ENCODE (1, 1, 24) | ENCODE (0, 1, 21);
+
+	/* U1 if offset added or omitted, U0 if subtracted.  */
+	if (operand.index >= 0)
+	  offset_op |= ENCODE (1, 1, 23);
+
+	return arm_emit_arm_insn (buf,
+				  (ARM_LDRD
+				   | ENCODE (cond, 4, 28)
+				   | offset_op
+				   | ENCODE (rn, 4, 16)
+				   | ENCODE (rt, 4, 12)
+				   | ENCODE (bits(ABS (operand.index), 4, 7),
+					     4, 8)
+				   | ENCODE (bits(ABS (operand.index), 0, 3),
+					     4, 0)));
+      }
+    default:
+      {
+	throw_error (NOT_SUPPORTED_ERROR,
+		     _("Unimplemented instruction encoding."));
+      }
+    }
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_sbfx (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		   uint32_t lsb, uint32_t width)
+{
+  return arm_emit_arm_insn (buf, (ARM_SBFX
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE ((width - 1), 5, 16)
+				  | ENCODE (rd, 4, 12)
+				  | ENCODE (lsb, 5, 7)
+				  | ENCODE (rn, 4, 0)));
+}
+
+/* See arm-insn-emit.h.  */
+
+int
+arm_emit_arm_nop (uint32_t *buf, uint8_t cond)
+{
+  return arm_emit_arm_insn (buf, ARM_NOP | ENCODE (cond, 4, 28));
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_ubfx (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		   uint8_t lsb, uint8_t width)
+{
+  return arm_emit_arm_insn (buf, (ARM_UBFX
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE ((lsb + width - 1), 5, 16)
+				  | ENCODE (rd, 4, 12)
+				  | ENCODE (lsb, 5, 7)
+				  | ENCODE (rn, 4, 0)));
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_sub (uint32_t *buf, uint8_t cond, uint8_t flags,
+		  uint8_t rd, uint8_t rn, struct arm_operand operand)
+{
+  if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_data_processing_reg (buf, ARM_SUB, cond, flags,
+					       (ENCODE (rn, 4, 16)
+						| ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 0)));
+    }
+  else if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_arm_data_processing_imm (buf,
+					       (ARM_SUB
+						/* Immediate.  */
+						| ENCODE (1, 1, 25)
+						| ENCODE (flags, 1, 20)),
+					       cond, rn,
+					       (ENCODE (rd, 4, 12)
+						| ENCODE (operand.imm, 12, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_rsb (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_data_processing_reg (buf, ARM_RSB, cond, 0,
+					       (ENCODE (rn, 4, 16)
+						| ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 0)));
+    }
+  else if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_arm_data_processing_imm (buf,
+					       (ARM_RSB
+						/* Immediate.  */
+						| ENCODE (1, 1, 25)
+						| ENCODE (0, 1, 20)),
+					       cond, rn,
+					       (ENCODE (rd, 4, 12)
+						| ENCODE (operand.imm, 12, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_sbc (uint32_t *buf, uint8_t cond, uint8_t flags, uint8_t rd,
+		  uint8_t rn, struct arm_operand operand)
+{
+  if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_data_processing_reg (buf, ARM_SBC, cond, flags,
+					       (ENCODE (rn, 4, 16)
+						| ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h  */
+
+int arm_emit_arm_mul (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		      struct arm_operand operand)
+{
+  if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_data_processing_reg (buf, ARM_MUL, cond, 0,
+					       (ENCODE (rd, 4, 16)
+						| ENCODE (operand.reg, 4, 8)
+						| ENCODE (rn, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_umull (uint32_t *buf, uint8_t cond, uint8_t rdlo, uint8_t rdhi,
+		    uint8_t rn, uint8_t rm)
+{
+  return arm_emit_arm_data_processing_reg (buf, ARM_UMULL, cond, 0,
+					   (ENCODE (rdhi, 4, 16)
+					    | ENCODE (rdlo, 4, 12)
+					    | ENCODE (rm, 4, 8)
+					    | ENCODE (rn, 4, 0)));
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_lsl (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_REGISTER)
+    {
+
+      return arm_emit_arm_data_processing_reg (buf, ARM_LSL, cond, 0,
+					       (ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 8)
+						| ENCODE (rn, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_lsr (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_REGISTER)
+    {
+
+      return arm_emit_arm_data_processing_reg (buf, ARM_LSR, cond, 0,
+					       (ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 8)
+						| ENCODE (rn, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_asr (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_data_processing_reg (buf, ARM_ASR, cond, 0,
+					       (ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 8)
+						/* Register op.  */
+						| ENCODE (1, 1, 4)
+						| ENCODE (rn, 4, 0)));
+    }
+  else if (operand.type == OPERAND_IMMEDIATE)
+    {
+      return arm_emit_arm_data_processing_imm (buf,
+					       (ARM_ASR
+						| ENCODE (0, 1, 20)
+						| ENCODE (rd, 4, 12)),
+					       cond, 0,
+					       (ENCODE (operand.imm, 5, 7)
+						| ENCODE (rn, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_and (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_data_processing_reg (buf, ARM_AND, cond, 0,
+					       (ENCODE (rn, 4, 16)
+						| ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_orr (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_data_processing_reg (buf, ARM_ORR, cond, 0,
+					       (ENCODE (rn, 4, 16)
+						| ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h  */
+int arm_emit_arm_orr_reg_shifted (uint32_t *buf, uint8_t cond, uint8_t rd,
+				  uint8_t rn, uint8_t rm, uint8_t shift,
+				  uint8_t rs)
+{
+  return arm_emit_arm_insn (buf, (ARM_ORR
+				  | ENCODE (cond, 4, 28)
+				  | ENCODE (0, 1, 20)
+				  | ENCODE (rn, 4, 16)
+				  | ENCODE (rd, 4, 12)
+				  | ENCODE (rs, 4, 8)
+				  | ENCODE (shift, 2, 5)
+				  | ENCODE (1, 1, 4)
+				  | ENCODE (rm, 4, 0)));
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_eor (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_data_processing_reg (buf, ARM_EOR, cond, 0,
+					       (ENCODE (rn, 4, 16)
+						| ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
+
+/* See arm-insn-emit.h  */
+
+int
+arm_emit_arm_mvn (uint32_t *buf, uint8_t cond, uint8_t rd,
+		  struct arm_operand operand)
+{
+  if (operand.type == OPERAND_REGISTER)
+    {
+      return arm_emit_arm_data_processing_reg (buf, ARM_MVN, cond, 0,
+					       (ENCODE (rd, 4, 12)
+						| ENCODE (operand.reg, 4, 0)));
+    }
+  else
+    {
+      throw_error (NOT_SUPPORTED_ERROR,
+		   _("Unimplemented instruction encoding."));
+    }
+}
diff --git a/gdb/arch/arm-insn-emit.h b/gdb/arch/arm-insn-emit.h
new file mode 100644
index 0000000..bcb216d
--- /dev/null
+++ b/gdb/arch/arm-insn-emit.h
@@ -0,0 +1,1087 @@
+/* Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef ARM_INSN_H
+#define ARM_INSN_H 1
+
+/* List of the ARM opcodes we need.  */
+
+enum arm_opcodes
+  {
+    ARM_ADC     = 0x00A00000,
+    ARM_ADD     = 0x00800000,
+    ARM_AND     = 0x00000000,
+    ARM_ASR     = 0x01A00040,
+    ARM_B       = 0x0A000000,
+    ARM_BIC     = 0x03C00000,
+    ARM_BLX     = 0x012FFF30,
+    ARM_CMP     = 0x01500000,
+    ARM_DMB     = 0xF57FF050,
+    ARM_EOR     = 0x00200000,
+    ARM_LDR     = 0x04100000,
+    ARM_LDRB    = 0x04500000,
+    ARM_LDRH    = 0x005000B0,
+    ARM_LDRD    = 0x004000D0,
+    ARM_LDREX   = 0x01900F9F,
+    ARM_LSL     = 0x01A00010,
+    ARM_LSR     = 0x01A00030,
+    ARM_MOV     = 0x01A00000,
+    ARM_MOVT    = 0x03400000,
+    ARM_MOVW    = 0x03000000,
+    ARM_MRS     = 0x010F0000,
+    ARM_MSR     = 0x0120F000,
+    ARM_MUL     = 0x00000090,
+    ARM_MVN     = 0x01E00000,
+    ARM_NOP     = 0x0320F000,
+    ARM_ORR     = 0x01800000,
+    ARM_POP_A1  = 0x08BD0000,
+    ARM_POP_A2  = 0x049D0004,
+    ARM_PUSH_A1 = 0x092D0000,
+    ARM_PUSH_A2 = 0x052D0004,
+    ARM_RSB     = 0x00600000,
+    ARM_SBC     = 0x00C00000,
+    ARM_SBFX    = 0x07A00050,
+    ARM_STR     = 0x04000000,
+    ARM_STREX   = 0x01800F90,
+    ARM_SUB     = 0x00400000,
+    ARM_UBFX    = 0x07E00050,
+    ARM_UMULL   = 0x00800090,
+    ARM_VPOP    = 0x0CBD0B00,
+    ARM_VPUSH   = 0x0D2D0B00,
+  };
+
+/* List of the Thumb opcodes we need.  */
+
+enum thumb_opcodes
+  {
+    THUMB_ADD_SP  = 0xB000,
+    THUMB_BLX     = 0x4780,
+    THUMB_B       = 0xD000,
+    THUMB_BIC     = 0xF0200000,
+    THUMB_BW      = 0xF0008000,
+    THUMB_CMP     = 0x2800,
+    THUMB_CMPW    = 0xF1B00F00,
+    THUMB_DMB     = 0xF3BF8F50,
+    THUMB_LDR     = 0xF1A00000,
+    THUMB_LDREX   = 0xE8500F00,
+    THUMB_MOVT    = 0xF2C00000,
+    THUMB_MOVW    = 0xF2400000,
+    THUMB_MOV     = 0x4600,
+    THUMB_MRS     = 0xF3EF8000,
+    THUMB_MSR     = 0xF3808000,
+    THUMB_POP     = 0xBC00,
+    THUMB_POPW    = 0xE8BD0000,
+    THUMB_PUSH_T1 = 0xB400,
+    THUMB_PUSH_T2 = 0xE92D0000,
+    THUMB_SBFX    = 0XF3400000,
+    THUMB_STR     = 0x6000,
+    THUMB_STREX   = 0xE8400000,
+    THUMB_VPOP    = 0xECBD0B00,
+    THUMB_VPUSH   = 0xED2D0B00,
+  };
+
+struct arm_operand
+{
+  /* Type of the operand.  */
+  enum arm_operand_type type;
+
+  /* Value of the operand according to the type.  */
+  union
+  {
+    uint32_t imm;
+    uint8_t reg;
+    struct arm_memory_operand mem;
+  };
+};
+
+enum arm_shifts
+  {
+    LSL = 0x0, /* Logical shift left.  */
+    LSR = 0x1, /* Logical shift right.  */
+    ASR = 0x2, /* Arithmetic shift right.  */
+  };
+
+/* Helper function to create an immediate operand
+
+   Example:
+
+     p += emit_mov (p, r0, immediate_operand (12));  */
+
+struct arm_operand immediate_operand (uint32_t imm);
+
+/* Helper function to create a register operand.
+
+   Example:
+
+     p += emit_mov (p, r0, register_operand (r1));  */
+
+struct arm_operand register_operand (uint8_t reg);
+
+/* Helper function to create an memory operand.
+
+   Example:
+
+     p += emit_mov (p, r0, immediate_operand (12));  */
+
+struct arm_operand memory_operand (struct arm_memory_operand mem);
+
+/* Encode a register list bitfield, using a consecutive list of bits from
+   FROM with length LENGTH and using an inital value of INITIAL. Max 16
+   bits.  */
+
+uint16_t encode_register_list (uint8_t from, uint8_t length, uint16_t initial);
+
+/* Return the distance in bytes from FROM to TO and adjusted for prefetch.  */
+
+uint32_t arm_arm_branch_relative_distance (CORE_ADDR from, CORE_ADDR to);
+
+/* Return the distance in bytes from FROM to TO and adjusted for prefetch.  */
+
+uint32_t arm_thumb_branch_relative_distance (CORE_ADDR from, CORE_ADDR to);
+
+/* Return the distance in bytes from FROM to TO , adjusted for prefetch
+   and for alignement when switching from ARM mode to Thumb mode.  */
+
+uint32_t arm_thumb_to_arm_branch_relative_distance (CORE_ADDR from,
+						    CORE_ADDR to);
+
+/* Return the offset is bytes adjusted for prefetch.  */
+
+uint32_t arm_arm_branch_adjusted_offset (uint32_t offset);
+
+/* Return the offset in bytes adjusted for prefetch.  */
+
+uint32_t arm_thumb_branch_adjusted_offset (uint32_t offset);
+
+/* Return whether it's possible to jump from FROM to TO using a relative
+   branch in arm mode.  */
+
+int arm_arm_is_reachable (CORE_ADDR from, CORE_ADDR to);
+
+/* Return whether it's possible to jump from FROM to TO using a relative
+   branch in thumb mode.  */
+
+int arm_thumb_is_reachable (CORE_ADDR from, CORE_ADDR to);
+
+/* Write arm instructions to move the 32bit value VAL into register REG.  */
+
+int arm_emit_arm_mov_32 (uint32_t *mem, int reg, uint32_t val);
+
+/* Write thumb instructions to move the 32bit value VAL into register REG.  */
+
+int arm_emit_thumb_mov_32 (uint16_t *mem, int reg, uint32_t val);
+
+/* Write an ARM B instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   B<c> <label>
+
+   COND is the conditionial instruction flag.
+   REL is the relative offset of the label.  */
+
+int arm_emit_arm_b (uint32_t *buf, uint8_t cond, uint32_t rel);
+
+/* Write an ARM BL instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   BL<c> <label>
+
+   REL is the relative offset of the label.  */
+
+int arm_emit_arm_bl (uint32_t *buf, uint8_t cond, uint32_t rel);
+
+/* Write a Thumb BL instruction into *BUF.
+
+   Encoding T1
+   BL<c> <label>
+   ARMv4T, ARMv5T*, ARMv6*, ARMv7 if J1 == J2 == 1
+   ARMv6T2, ARMv7 otherwise
+   Outside or last in IT block
+
+   REL is the relative offset of the label.  */
+
+int arm_emit_thumb_bl (uint16_t *buf, uint32_t rel);
+
+/* Write a Thumb B instruction into *BUF.
+
+   Encoding T1
+   ARMv4T, ARMv5T*, ARMv6*, ARMv7
+   B<c> <label>
+   Not permitted in IT block.
+
+   REL is the relative offset of the label.  */
+
+int arm_emit_thumb_b (uint16_t *buf, uint8_t cond, uint32_t rel);
+
+/* Write a Thumb BW instruction into *BUF.
+
+   Encoding T4
+   ARMv6T2, ARMv7
+   B<c>.W <label>
+   Outside or last in IT block
+
+   REL is the relative offset of the label.  */
+
+int arm_emit_thumb_bw (uint16_t *buf, uint32_t rel);
+
+/* Write a Thumb BW instruction into *BUF.
+
+   Encoding T3
+   ARMv6T2, ARMv7
+   B<c>.W <label>
+   Not permitted in IT block.
+
+   REL is the relative offset of the label.  */
+
+int arm_emit_thumb_bw_cond (uint16_t *buf, uint8_t cond, uint32_t rel);
+
+/* Write an ARM BLX instruction into *BUF.
+
+   Register:
+   Encoding A1
+   ARMv5T*, ARMv6*, ARMv7
+   BLX<c> <Rm>
+
+   OPERAND is the register or the immediate value that contains the branch
+   target address and instruction set selection bit.  */
+
+int arm_emit_arm_blx (uint32_t * buf, uint8_t cond, struct arm_operand operand);
+
+/* Write a Thumb BLX instruction into *BUF.
+
+   Register:
+   Encoding T1
+   ARMv5T*, ARMv6*, ARMv7
+   BLX<c> <Rm>
+   Outside or last in IT block
+
+   Immediate:
+   Encoding T2
+   BLX<c> <label>
+   ARMv5T*, ARMv6*, ARMv7 if J1 == J2 == 1
+   ARMv6T2, ARMv7 otherwise
+   Outside or last in IT block
+
+   OPERAND is the register or the immediate value that contains the branch
+   target address and instruction set selection bit.  */
+
+int arm_emit_thumb_blx (uint16_t *buf, struct arm_operand operand);
+
+/* Write an ARM MOVW (Immediate) instruction into *BUF.
+
+   Encoding A2
+   ARMv6T2, ARMv7
+   MOVW<c> <Rd>, #<imm16>
+
+   RD is the destination register.
+   OPERAND is the immediate value to be placed in RD.
+*/
+
+int arm_emit_arm_movw (uint32_t *buf, uint8_t cond, uint8_t rd,
+		       struct arm_operand operand);
+
+/* Write a Thumb MOVW (Immediate) instruction into *BUF.
+
+   Encoding T3
+   ARMv6T2, ARMv7
+   MOVW<c> <Rd>, #<imm16>
+
+   RD is the destination register.
+   OPERAND is the immediate value to be placed in RD.  */
+
+int arm_emit_thumb_movw (uint16_t *buf, uint8_t rd, struct arm_operand operand);
+
+/* Write an ARM MOV instruction into *BUF.
+
+   Encoding A1
+
+   Immediate:
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   MOV{S}<c> <Rd>, #<const>
+
+   Register:
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   MOV{S}<c> <Rd>, <Rm>
+
+   RD is the destination register.
+   OPERAND is the immediate value or source register.  */
+
+int arm_emit_arm_mov (uint32_t *buf, uint8_t cond, uint8_t rd,
+		      struct arm_operand operand);
+
+/* Write an ARM MOVT instruction into *BUF.
+
+   Encoding A1
+   ARMv6T2, ARMv7
+   MOVT<c> <Rd>, #<imm16>
+
+   RD is the destination register.
+   OPERAND is the immediate value to be placed in RD.  */
+
+int arm_emit_arm_movt (uint32_t *buf, uint8_t cond, uint8_t rd,
+		       struct arm_operand operand);
+
+/* Write a Thumb MOVT instruction into *BUF.
+
+   Encoding T1
+   ARMv6T2, ARMv7
+   MOVT<c> <Rd>, #<imm16>
+
+   RD is the destination register.
+   OPERAND is the immediate value to be placed in RD.  */
+
+int arm_emit_thumb_movt (uint16_t *buf, uint8_t rd,
+			 struct arm_operand operand);
+
+/* Write an ARM VPUSH instruction into *BUF.
+
+   Encoding A1
+   VFPv2, VFPv3, VFPv4, Advanced SIMD
+   VPUSH<c> <list>
+   <list> is consecutive 64-bit registers.
+
+   COND is the conditionial instruction flag.
+   RS is the starting register.
+   LEN is the length of the register list.  */
+
+int arm_emit_arm_vpush (uint32_t *buf, uint8_t cond, uint8_t rs, uint8_t len);
+
+/* Write a Thumb VPUSH instruction into *BUF.
+
+   Encoding T1
+   VFPv2, VFPv3, VFPv4, Advanced SIMD
+   VPUSH<c> <list>
+   <list> is consecutive 64-bit registers.
+
+   COND is the conditionial instruction flag.
+   RS is the starting register.
+   LEN is the length of the register list.  */
+
+int arm_emit_thumb_vpush (uint16_t *buf, uint8_t rs, uint8_t len);
+
+/* Write an ARM PUSH instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   PUSH<c> <registers>
+   <registers> contains more than one register
+
+   COND is the conditionial instruction flag.
+   REGISTER_LIST is the register list bitfield.  */
+
+int arm_emit_arm_push_list (uint32_t *buf, uint8_t cond,
+			    uint16_t register_list);
+
+/* Write a Thumb PUSH instruction into *BUF.
+
+   Encoding T2
+   ARMv6T2, ARMv7
+   PUSH<c>.W <registers>
+   <registers> contains more than one register
+
+   REGISTER_LIST is the register_list bitfield.
+   LR denotes the presence of LR in the list.  */
+
+int arm_emit_thumb_push_list (uint16_t *buf, uint16_t register_list,
+			      uint8_t lr);
+
+/* Write an ARM PUSH instruction into *BUF.
+
+   Encoding A2
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   PUSH<c> <registers>
+   <registers> contains one register, <Rt>
+
+   RT is the register to push.
+   COND is the conditionial instruction flag.  */
+
+int arm_emit_arm_push_one (uint32_t *buf, uint8_t cond, uint8_t rt);
+
+/* Write a Thumb PUSH instruction into *BUF.
+
+   Encoding T1
+   ARMv4T, ARMv5T*, ARMv6*, ARMv7
+   PUSH<c> <registers>
+
+   REGISTER_LIST is the registers list to push.
+   LR denotes the presence of LR in the list.  */
+
+int arm_emit_thumb_push_one (uint16_t *buf, uint8_t register_list, uint8_t lr);
+
+/* Write an ARM MRS instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   MRS<c> <Rd>, <spec_reg>
+
+   RD is the destination register.  */
+
+int arm_emit_arm_mrs (uint32_t *buf, uint8_t cond, uint8_t rd);
+
+/* Write a Thumb MRS instruction into *BUF.
+
+   Encoding T1
+   ARMv6T2, ARMv7
+   MRS<c> <Rd>, <spec_reg>
+
+   RD is the destination register.  */
+
+int arm_emit_thumb_mrs (uint16_t *buf, uint8_t rd);
+
+/* Write a Thumb MOV Register instruction into *BUF.
+
+   Encoding T1
+   MOV<c> <Rd>, <Rm>
+   ARMv6*, ARMv7 if <Rd> and <Rm> both from R0-R7
+   ARMv4T, ARMv5T*, ARMv6*, ARMv7 otherwise
+   If <Rd> is the PC, must be outside or last in IT block.
+
+   RD is the destination register.
+   OPERAND is the source register.  */
+
+int arm_emit_thumb_mov (uint16_t *buf, uint8_t rd, struct arm_operand operand);
+
+/* Write an ARM DMB instruction into *BUF.
+
+   Encoding A1
+   ARMv7
+   DMB <option>
+
+   option is ommited to mean SY.  */
+
+int arm_emit_arm_dmb (uint32_t *buf);
+
+/* Write a Thumb DMB instruction into *BUF.
+
+   Encoding T1
+   ARMv7
+   DMB <option>
+
+   option is ommited to mean SY.  */
+
+int arm_emit_thumb_dmb (uint16_t *buf);
+
+/* Write an ARM LDREX instruction into *BUF.
+   Encoding A1
+   ARMv6*, ARMv7
+   LDREX<c> <Rt>, [<Rn>]
+
+   COND is the conditionial instruction flag.
+   RT is the destination register.
+   RN is the base register.  */
+
+int arm_emit_arm_ldrex (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn);
+
+/* Write a Thumb LDREX instruction into *BUF.
+
+   Encoding T1
+   ARMv6T2, ARMv7
+   LDREX<c> <Rt>, [<Rn>{, #<imm>}]
+
+   RT is the destination register.
+   RN is the base register.
+
+   OPERAND is the immediate offset added to the value of RN to form the
+   address.  */
+
+int arm_emit_thumb_ldrex (uint16_t *buf, int8_t rt, uint8_t rn,
+			  struct arm_operand operand);
+
+/* Write an ARM CMP instruction into *BUF.
+
+   Immediate:
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   CMP<c> <Rn>, #<const>
+
+   Register:
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   CMP<c> <Rn>, <Rm>{, <shift>}
+
+   COND is the conditionial instruction flag.
+   RN is the base register.
+   OPERAND is the immediate value to be compared with the value obtained
+   from RN.  */
+
+int arm_emit_arm_cmp (uint32_t *buf, uint8_t cond, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write a Thumb CMP (immediate) instruction into *BUF.
+
+   Encoding T1
+   ARMv4T, ARMv5T*, ARMv6*, ARMv7
+   CMP<c> <Rn>, #<imm8>
+
+   RN is the base register.
+   OPERAND is the immediate value to be compared with the value obtained
+   from RN.  */
+
+int arm_emit_thumb_cmp (uint16_t *buf, uint8_t rn, struct arm_operand operand);
+
+/* Write a Thumb CMP.w (immediate) instruction into *BUF.
+
+   Encoding T2
+   ARMv6T2, ARMv7
+   CMP<c>.W <Rn>, #<const>
+
+   RN is the base register.
+   OPERAND is the immediate value to be compared with the value obtained
+   from RN.  */
+
+int arm_emit_thumb_cmpw (uint16_t *buf, uint8_t rn, struct arm_operand operand);
+
+/* Write an ARM BIC (immediate) instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   BIC{S}<c> <Rd>, <Rn>, #<const>
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the base register.
+   OPERAND is the immediate value to be bitwise inverted and ANDed with
+   the value obtained from RN.  */
+
+int arm_emit_arm_bic (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write a Thumb BIC (immediate) instruction into *BUF.
+
+   Encoding T1
+   ARMv6T2, ARMv7
+   BIC{S}<c> <Rd>, <Rn>, #<const>
+
+   RD is the destination register.
+   RN is the base register.
+   OPERAND is the immediate value to be bitwise inverted and ANDed with
+   the value obtained from RN.  */
+
+int arm_emit_thumb_bic (uint16_t *buf, uint8_t rd, uint8_t rn,
+			struct arm_operand operand);
+
+/* Write an ARM STREX instruction into *BUF.
+
+   Encoding A1
+   ARMv6*, ARMv7
+   STREX<c> <Rd>, <Rt>, [<Rn>]
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RT is the source register.
+   RN is the base register.  */
+
+int arm_emit_arm_strex (uint32_t *buf, uint8_t cond, uint8_t rd,
+			uint8_t rt, uint8_t rn);
+
+/* Write a Thumb STREX (immediate) instruction into *BUF.
+
+   Encoding T1
+   ARMv6T2, ARMv7
+   STREX<c> <Rd>, <Rt>, [<Rn>{, #<imm>}]
+
+   RD is the destination register.
+   RT is the source register.
+   RN is the base register.
+   OPERAND is the immediate offset added to the value of RN to form the
+   address.  */
+
+int arm_emit_thumb_strex (uint16_t *buf, uint8_t rd, uint8_t rt, uint8_t rn,
+			  struct arm_operand operand);
+
+/* Write an ARM STR (immediate) instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   STR<c> <Rt>, [<Rn>{, #+/-<imm12>}]
+   STR<c> <Rt>, [<Rn>], #+/-<imm12>
+   STR<c> <Rt>, [<Rn>, #+/-<imm12>]!
+
+   COND is the conditionial instruction flag.
+   RT is the source register.
+   RN is the base register.
+   OPERAND is the immediate offset used for forming the address.  */
+
+int arm_emit_arm_str (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write a Thumb STR (immediate) instruction into *BUF.
+
+   Encoding T1
+   ARMv4T, ARMv5T*, ARMv6*, ARMv7
+   STR<c> <Rt>, [<Rn>{, #<imm>}]
+
+   RT is the source register.
+   RN is the base register.
+   OPERAND is the immediate offset used for forming the address.  */
+
+int arm_emit_thumb_str (uint16_t *buf, uint8_t rt, uint8_t rn,
+			struct arm_operand operand);
+
+/* Write an ARM ADD instruction into *BUF.
+
+   Immediate:
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   ADD{S}<c> <Rd>, <Rn>, #<const>
+
+   Register:
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   ADD{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
+
+   COND is the conditionial instruction flag.
+   FLAGS update the flags if set to 1.
+   RD is the destination register.
+   RN is the base register.
+   OPERAND is the operand to be added to the value obtained from RN.  */
+
+int arm_emit_arm_add (uint32_t *buf, uint8_t cond, uint8_t flags, uint8_t rd,
+		      uint8_t rn, struct arm_operand operand);
+
+/* Write an ARM ADC instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   ADC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the base register.
+   OPERAND is the operand to be added to the value obtained from RN.  */
+
+int arm_emit_arm_adc (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write a Thumb ADD (SP plus immediate) instruction into *BUF.
+
+   Encoding T2
+   ARMv4T, ARMv5T*, ARMv6*, ARMv7
+   ADD<c> SP, SP, #<imm>
+
+   OPERAND is the immediate value to be added to the value obtained from SP.  */
+
+int arm_emit_thumb_add_sp (uint16_t *buf, struct arm_operand operand);
+
+/* Write an ARM POP instruction into *BUF.
+
+   Encoding A2
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   POP<c> <registers>
+   <registers> contains one register, <Rt>
+
+   RT is the register to be loaded.  */
+
+int arm_emit_arm_pop_one (uint32_t *buf, uint8_t cond, uint8_t rt);
+
+/* Write an ARM POP instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   POP<c> <registers>
+   <registers> contains more than one register
+
+   RT is the register to be loaded.  */
+
+int arm_emit_arm_pop_list (uint32_t *buf, uint8_t cond, uint16_t register_list);
+
+/* Write a Thumb POP instruction into *BUF.
+
+   Encoding T1
+   ARMv4T, ARMv5T*, ARMv6*, ARMv7
+   POP<c> <registers>
+
+   REGISTER_LIST is a list of one or more registers to be loaded.
+   PC is a flag that triggers the addition of the PC register to the list.  */
+
+int arm_emit_thumb_pop (uint16_t *buf, uint8_t register_list, uint8_t pc);
+
+/* Write a Thumb POPW instruction into *BUF.
+
+   Encoding T2
+   ARMv6T2, ARMv7
+   POP<c>.W <registers>
+   <registers> contains more than one register
+
+   REGISTER_LIST is a list of one or more registers to be loaded.
+   PC is a flag that triggers the addition of the PC register to the list.
+   LR is a flag that triggers the addition of the LR register to the list.  */
+
+int arm_emit_thumb_popw_list (uint16_t *buf, uint16_t register_list, uint8_t pc,
+			      uint8_t lr);
+
+/* Write an ARM MSR instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   MRS<c> <Rd>, <spec_reg>
+
+   RN is the ARM core register to be transferred to <spec_reg>.  */
+
+int arm_emit_arm_msr (uint32_t *buf, uint8_t cond, uint8_t rn);
+
+/* Write a Thumb MRS instruction into *BUF.
+
+   Encoding T1
+   ARMv6T2, ARMv7
+   MRS<c> <Rd>, <spec_reg>
+
+   RN is the ARM core register to be transferred to <spec_reg>.  */
+
+int arm_emit_thumb_msr (uint16_t *buf, uint8_t rn);
+
+/* Write an ARM VPOP instruction into *BUF.
+
+   Encoding A1
+   VFPv2, VFPv3, VFPv4, Advanced SIMD
+   VPOP <list>
+
+   <list> is consecutive 64-bit registers
+
+   COND is the conditionial instruction flag.
+   RS is the starting register.
+   LEN is the length of the register list.  */
+
+int arm_emit_arm_vpop (uint32_t *buf, uint8_t cond, uint8_t rs, uint8_t len);
+
+/* Write a Thumb VPOP instruction into *BUF.
+
+   Encoding T1
+   VFPv2, VFPv3, VFPv4, Advanced SIMD
+   VPOP <list>
+
+   COND is the conditionial instruction flag.
+   RS is the starting register.
+   LEN is the length of the register list.  */
+
+int arm_emit_thumb_vpop (uint16_t *buf, uint8_t rs, uint8_t len);
+
+/* Write an ARM LDR instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   LDR<c> <Rt>, [<Rn>{, #+/-<imm12>}]
+   LDR<c> <Rt>, [<Rn>], #+/-<imm12>
+   LDR<c> <Rt>, [<Rn>, #+/-<imm12>]!
+
+   COND is the conditionial instruction flag.
+   RT is the destination register.
+   RN is the base register.
+   OPERAND is the offset used for forming the address.  */
+
+int arm_emit_arm_ldr (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn,
+		      struct arm_memory_operand operand);
+
+/* Write an ARM LDRB instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   LDRB<c> <Rt>, [<Rn>{, #+/-<imm12>}]
+   LDRB<c> <Rt>, [<Rn>], #+/-<imm12>
+   LDRB<c> <Rt>, [<Rn>, #+/-<imm12>]!
+
+   COND is the conditionial instruction flag.
+   RT is the destination register.
+   RN is the base register.
+   OPERAND is the offset used for forming the address.  */
+
+int arm_emit_arm_ldrb (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn,
+		       struct arm_memory_operand operand);
+
+/* Write an ARM LDRH instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   LDRH<c> <Rt>, [<Rn>{, #+/-<imm8>}]
+   LDRH<c> <Rt>, [<Rn>], #+/-<imm8>
+   LDRH<c> <Rt>, [<Rn>, #+/-<imm8>]!
+
+   COND is the conditionial instruction flag.
+   RT is the destination register.
+   RN is the base register.
+   OPERAND is the offset used for forming the address.  */
+
+int arm_emit_arm_ldrh (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn,
+		       struct arm_memory_operand operand);
+
+/* Write an ARM LDRD instruction into *BUF.
+
+   Encoding A1
+   ARMv5TE*, ARMv6*, ARMv7
+   LDRD<c> <Rt>, <Rt2>, [<Rn>{, #+/-<imm8>}]
+   LDRD<c> <Rt>, <Rt2>, [<Rn>], #+/-<imm8>
+   LDRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]!
+
+   COND is the conditionial instruction flag.
+   RT is the frist destination register, second will automatically be RT+1.
+   RN is the base register.
+   OPERAND is the offset used for forming the address.  */
+
+int arm_emit_arm_ldrd (uint32_t *buf, uint8_t cond, uint8_t rt, uint8_t rn,
+		       struct arm_memory_operand operand);
+
+/* Write an ARM SBFX instruction into *BUF.
+
+   Encoding A1
+   ARMv6T2, ARMv7
+   SBFX<c> <Rd>, <Rn>, #<lsb>, #<width>
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN the first operand register.
+   LSB is the bit number of the least significant bit in the field, in the
+   range 0-31.
+   WIDTH is the width of the field, in the range 1 to 32- <LSB>.
+   OPERAND is the offset used for forming the address.  */
+
+int arm_emit_arm_sbfx (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		       uint32_t lsb, uint32_t width);
+
+/* Write an ARM NOP instruction into *BUF.
+
+   Encoding A1
+   ARMv6K, ARMv6T2, ARMv7
+   NOP<c>
+
+   COND is the conditionial instruction flag.  */
+
+int arm_emit_arm_nop (uint32_t *buf, uint8_t cond);
+
+/* Write an ARM UBFX instruction into *BUF.
+
+   Encoding A1
+   ARMv6T2, ARMv7
+   UBFX<c> <Rd>, <Rn>, #<lsb>, #<width>
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the first operand register.
+   LSB is the bit number of the least significant bit in the field, in the
+   range 0-31. This determines the required value of lsbit .
+   WIDTH is the width of the field, in the range 1 to 32- LSB.  */
+
+int arm_emit_arm_ubfx (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		       uint8_t lsb, uint8_t width);
+
+/* Write an ARM SUB instruction into *BUF.
+
+   Register:
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
+
+   Immediate:
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   SUB{S}<c> <Rd>, <Rn>, #<const>
+
+   COND is the conditionial instruction flag.
+   FLAGS update the flags if set to 1.
+   RD is the destination register.
+   RN is the first operand register.
+   OPERAND is used as the second operand.  */
+
+int arm_emit_arm_sub (uint32_t *buf, uint8_t cond, uint8_t flags, uint8_t rd,
+		      uint8_t rn, struct arm_operand operand);
+
+/* Write an ARM RSB instruction into *BUF.
+
+   Register:
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   RSB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
+
+   Immediate:
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   RSB{S}<c> <Rd>, <Rn>, #<const>
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the first operand register.
+   OPERAND is used as the second operand.  */
+
+int arm_emit_arm_rsb (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write an ARM SBC instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   SBC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
+
+   COND is the conditionial instruction flag.
+   FLAGS update the flags if set to 1.
+   RD is the destination register.
+   RN is the first operand register.
+   OPERAND is used as the second operand.  */
+
+int arm_emit_arm_sbc (uint32_t *buf, uint8_t cond, uint8_t flags, uint8_t rd,
+		      uint8_t rn, struct arm_operand operand);
+
+/* Write an ARM MUL instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   MUL{S}<c> <Rd>, <Rn>, <Rm>
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the first operand register.
+   OPERAND is used as the second operand.  */
+
+int arm_emit_arm_mul (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write an ARM UMULL instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   UMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
+
+   COND is the conditionial instruction flag.
+   RDLO is the lower 32 bits of the result.
+   RDHI is the upper 32 bits of the result.
+   RN is the first operand register.
+   RM is the second operand register.  */
+
+int arm_emit_arm_umull (uint32_t *buf, uint8_t cond, uint8_t rdlo,
+			uint8_t rdhi, uint8_t rn, uint8_t rm);
+
+/* Write an ARM LSL instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   LSL{S}<c> <Rd>, <Rn>, <Rm>
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the first operand register.
+   OPERAND is used as the second operand.  */
+
+int arm_emit_arm_lsl (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write an ARM LSR instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   LSR{S}<c> <Rd>, <Rn>, <Rm>
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the first operand register.
+   OPERAND is used as the second operand.  */
+
+int arm_emit_arm_lsr (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write an ARM ASR instruction into *BUF.
+
+   Register:
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   ASR{S}<c> <Rd>, <Rn>, <Rm>
+
+   Immediate:
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   ASR{S}<c> <Rd>, <Rm>, #<imm>
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the first operand register.
+   OPERAND is used as the second operand.  */
+
+int arm_emit_arm_asr (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write an ARM AND instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   AND{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the first operand register.
+   OPERAND is used as the second operand.  */
+
+int arm_emit_arm_and (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write an ARM ORR instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   ORR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the first operand register.
+   OPERAND is used as the second operand.  */
+
+int arm_emit_arm_orr (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write an ARM ORR (register-shifted register) instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   ORR{S}<c> <Rd>, <Rn>, <Rm>, <type> <Rs>
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the first operand register.
+   RM is the register that is shifted and used as the second operand.
+   SHIFT is the type of shift to apply to the value read from <Rm>.
+   RS is the register whose bottom byte contains the amount to shift by.  */
+
+int arm_emit_arm_orr_reg_shifted (uint32_t *buf, uint8_t cond, uint8_t rd,
+				  uint8_t rn, uint8_t rm, uint8_t shift,
+				  uint8_t rs);
+
+/* Write an ARM EOR instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   EOR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   RN is the first operand register.
+   OPERAND is used as the second operand.  */
+
+int arm_emit_arm_eor (uint32_t *buf, uint8_t cond, uint8_t rd, uint8_t rn,
+		      struct arm_operand operand);
+
+/* Write an ARM MVN instruction into *BUF.
+
+   Encoding A1
+   ARMv4*, ARMv5T*, ARMv6*, ARMv7
+   MVN{S}<c> <Rd>, <Rm>{, <shift>}
+
+   COND is the conditionial instruction flag.
+   RD is the destination register.
+   OPERAND is used as the operand.  */
+
+int arm_emit_arm_mvn (uint32_t *buf, uint8_t cond, uint8_t rd,
+		      struct arm_operand operand);
+
+#endif /* ARM_INSN_H */
diff --git a/gdb/arch/arm-insn-utils.c b/gdb/arch/arm-insn-utils.c
new file mode 100644
index 0000000..801bee1
--- /dev/null
+++ b/gdb/arch/arm-insn-utils.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "arm-insn-utils.h"
+
+/* See arm-insn-utils.h.  */
+
+struct arm_memory_operand
+offset_memory_operand (int32_t offset)
+{
+  return (struct arm_memory_operand) { MEMORY_OPERAND_OFFSET, offset };
+}
+
+/* See arm-insn-utils.h.  */
+
+struct arm_memory_operand
+preindex_memory_operand (int32_t index)
+{
+  return (struct arm_memory_operand) { MEMORY_OPERAND_PREINDEX, index };
+}
+
+/* See arm-insn-utils.h.  */
+
+struct arm_memory_operand
+postindex_memory_operand (int32_t index)
+{
+  return (struct arm_memory_operand) { MEMORY_OPERAND_POSTINDEX, index };
+}
diff --git a/gdb/arch/arm-insn-utils.h b/gdb/arch/arm-insn-utils.h
new file mode 100644
index 0000000..6b47438
--- /dev/null
+++ b/gdb/arch/arm-insn-utils.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 2009-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Helper macro to mask and shift a value into a bitfield.  */
+
+#ifndef ARM_INSN_UTILS_H
+#define ARM_INSN_UTILS_H 1
+
+#define ENCODE(val, size, offset) \
+  ((uint32_t) ((val & ((1ULL << size) - 1)) << offset))
+
+enum arm_memory_operand_type
+{
+  MEMORY_OPERAND_OFFSET,
+  MEMORY_OPERAND_PREINDEX,
+  MEMORY_OPERAND_POSTINDEX,
+};
+
+/* Representation of a memory operand, used for load and store
+   instructions.
+
+   The types correspond to the following variants:
+
+   MEMORY_OPERAND_OFFSET:    LDR rt, [rn, #offset]
+   MEMORY_OPERAND_PREINDEX:  LDR rt, [rn, #index]!
+   MEMORY_OPERAND_POSTINDEX: LDR rt, [rn], #index  */
+
+struct arm_memory_operand
+{
+  /* Type of the operand.  */
+  enum arm_memory_operand_type type;
+
+  /* Index from the base register.  */
+  int32_t index;
+};
+
+enum arm_operand_type
+{
+  OPERAND_IMMEDIATE,
+  OPERAND_REGISTER,
+  OPERAND_MEMORY,
+};
+
+/* Helper function to create an offset memory operand.
+
+   For example:
+   p += emit_ldr (p, x0, sp, offset_memory_operand (16));  */
+
+struct arm_memory_operand offset_memory_operand (int32_t offset);
+
+/* Helper function to create a pre-index memory operand.
+
+   For example:
+   p += emit_ldr (p, x0, sp, preindex_memory_operand (16));  */
+
+struct arm_memory_operand preindex_memory_operand (int32_t index);
+
+/* Helper function to create a post-index memory operand.
+
+   For example:
+   p += emit_ldr (p, x0, sp, postindex_memory_operand (16));  */
+
+struct arm_memory_operand postindex_memory_operand (int32_t index);
+
+#endif
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index e447356..902d043 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -38,7 +38,8 @@ esac
 case "${targ}" in
 aarch64*-*-elf | aarch64*-*-rtems*)
 	# Target: AArch64 embedded system
-	gdb_target_obs="aarch64-tdep.o aarch64-newlib-tdep.o aarch64-insn.o"
+	gdb_target_obs="aarch64-tdep.o aarch64-newlib-tdep.o aarch64-insn.o \
+			arm-insn-utils.o"
 	;;
 
 aarch64*-*-linux*)
@@ -47,7 +48,7 @@ aarch64*-*-linux*)
 			arm.o arm-linux.o arm-get-next-pcs.o arm-tdep.o \
 			arm-linux-tdep.o \
 			glibc-tdep.o linux-tdep.o solib-svr4.o \
-			symfile-mem.o linux-record.o"
+			symfile-mem.o linux-record.o arm-insn-utils.o"
 	build_gdbserver=yes
 	;;
 
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 2be61ef..271f804 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -185,7 +185,8 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/btrace-common.c \
 	$(srcdir)/common/fileio.c $(srcdir)/nat/linux-namespaces.c \
 	$(srcdir)/arch/arm.c $(srcdir)/common/common-regcache.c \
-	$(srcdir)/arch/arm-linux.c $(srcdir)/arch/arm-get-next-pcs.c
+	$(srcdir)/arch/arm-linux.c $(srcdir)/arch/arm-get-next-pcs.c \
+	$(srcdir)/arch/arm-insn-emit.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -727,6 +728,9 @@ arm-linux.o: ../arch/arm-linux.c
 arm-get-next-pcs.o: ../arch/arm-get-next-pcs.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+arm-insn-emit.o: ../arch/arm-insn-emit.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 
 # Native object files rules from ../nat
 
@@ -785,6 +789,10 @@ aarch64-insn.o: ../arch/aarch64-insn.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
 
+arm-insn-utils.o: ../arch/arm-insn-utils.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
+
 aarch64.c : $(srcdir)/../regformats/aarch64.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/aarch64.dat aarch64.c
 reg-arm.c : $(srcdir)/../regformats/reg-arm.dat $(regdat_sh)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index fe53e03..34d4be8 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -56,6 +56,7 @@ case "${target}" in
 			srv_tgtobj="${srv_tgtobj} arm.o"
 			srv_tgtobj="$srv_tgtobj aarch64-linux.o"
 			srv_tgtobj="$srv_tgtobj aarch64-insn.o"
+			srv_tgtobj="$srv_tgtobj arm-insn-utils.o"
 			srv_tgtobj="${srv_tgtobj} $srv_linux_obj"
 			srv_xmlfiles="aarch64.xml"
 			srv_xmlfiles="${srv_xmlfiles} aarch64-core.xml"
@@ -75,6 +76,8 @@ case "${target}" in
 			srv_tgtobj="${srv_tgtobj} arm.o"
 			srv_tgtobj="${srv_tgtobj} arm-linux.o"
 			srv_tgtobj="${srv_tgtobj} arm-get-next-pcs.o"
+			srv_tgtobj="${srv_tgtobj} arm-insn-emit.o"
+			srv_tgtobj="${srv_tgtobj} arm-insn-utils.o"
 			srv_xmlfiles="arm-with-iwmmxt.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv3.xml"
diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c
index da8c0cc..8aefe6b 100644
--- a/gdb/gdbserver/linux-aarch64-low.c
+++ b/gdb/gdbserver/linux-aarch64-low.c
@@ -23,6 +23,7 @@
 #include "linux-low.h"
 #include "nat/aarch64-linux.h"
 #include "nat/aarch64-linux-hw-point.h"
+#include "arch/arm-insn-utils.h"
 #include "arch/aarch64-insn.h"
 #include "linux-aarch32-low.h"
 #include "elf/common.h"
@@ -601,19 +602,13 @@ enum aarch64_condition_codes
   LE = 0xd,
 };
 
-enum aarch64_operand_type
-{
-  OPERAND_IMMEDIATE,
-  OPERAND_REGISTER,
-};
-
 /* Representation of an operand.  At this time, it only supports register
    and immediate types.  */
 
 struct aarch64_operand
 {
   /* Type of the operand.  */
-  enum aarch64_operand_type type;
+  enum arm_operand_type type;
 
   /* Value of the operand according to the type.  */
   union
@@ -690,39 +685,6 @@ immediate_operand (uint32_t imm)
   return operand;
 }
 
-/* Helper function to create an offset memory operand.
-
-   For example:
-   p += emit_ldr (p, x0, sp, offset_memory_operand (16));  */
-
-static struct aarch64_memory_operand
-offset_memory_operand (int32_t offset)
-{
-  return (struct aarch64_memory_operand) { MEMORY_OPERAND_OFFSET, offset };
-}
-
-/* Helper function to create a pre-index memory operand.
-
-   For example:
-   p += emit_ldr (p, x0, sp, preindex_memory_operand (16));  */
-
-static struct aarch64_memory_operand
-preindex_memory_operand (int32_t index)
-{
-  return (struct aarch64_memory_operand) { MEMORY_OPERAND_PREINDEX, index };
-}
-
-/* Helper function to create a post-index memory operand.
-
-   For example:
-   p += emit_ldr (p, x0, sp, postindex_memory_operand (16));  */
-
-static struct aarch64_memory_operand
-postindex_memory_operand (int32_t index)
-{
-  return (struct aarch64_memory_operand) { MEMORY_OPERAND_POSTINDEX, index };
-}
-
 /* System control registers.  These special registers can be written and
    read with the MRS and MSR instructions.
 
@@ -770,7 +732,7 @@ emit_load_store_pair (uint32_t *buf, enum aarch64_opcodes opcode,
 		      struct aarch64_register rt,
 		      struct aarch64_register rt2,
 		      struct aarch64_register rn,
-		      struct aarch64_memory_operand operand)
+		      struct arm_memory_operand operand)
 {
   uint32_t opc;
   uint32_t pre_index;
@@ -825,7 +787,7 @@ emit_load_store_pair (uint32_t *buf, enum aarch64_opcodes opcode,
 static int
 emit_stp (uint32_t *buf, struct aarch64_register rt,
 	  struct aarch64_register rt2, struct aarch64_register rn,
-	  struct aarch64_memory_operand operand)
+	  struct arm_memory_operand operand)
 {
   return emit_load_store_pair (buf, STP, rt, rt2, rn, operand);
 }
@@ -844,7 +806,7 @@ emit_stp (uint32_t *buf, struct aarch64_register rt,
 static int
 emit_ldp (uint32_t *buf, struct aarch64_register rt,
 	  struct aarch64_register rt2, struct aarch64_register rn,
-	  struct aarch64_memory_operand operand)
+	  struct arm_memory_operand operand)
 {
   return emit_load_store_pair (buf, LDP, rt, rt2, rn, operand);
 }
@@ -907,7 +869,7 @@ emit_stp_q_offset (uint32_t *buf, unsigned rt, unsigned rt2,
 static int
 emit_ldrh (uint32_t *buf, struct aarch64_register rt,
 	   struct aarch64_register rn,
-	   struct aarch64_memory_operand operand)
+	   struct arm_memory_operand operand)
 {
   return aarch64_emit_load_store (buf, 1, LDR, rt, rn, operand);
 }
@@ -926,7 +888,7 @@ emit_ldrh (uint32_t *buf, struct aarch64_register rt,
 static int
 emit_ldrb (uint32_t *buf, struct aarch64_register rt,
 	   struct aarch64_register rn,
-	   struct aarch64_memory_operand operand)
+	   struct arm_memory_operand operand)
 {
   return aarch64_emit_load_store (buf, 0, LDR, rt, rn, operand);
 }
@@ -947,7 +909,7 @@ emit_ldrb (uint32_t *buf, struct aarch64_register rt,
 static int
 emit_str (uint32_t *buf, struct aarch64_register rt,
 	  struct aarch64_register rn,
-	  struct aarch64_memory_operand operand)
+	  struct arm_memory_operand operand)
 {
   return aarch64_emit_load_store (buf, rt.is64 ? 3 : 2, STR, rt, rn, operand);
 }
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 16/18] arm: Move insn_references_pc to common code
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 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 ` Antoine Tremblay
  2016-07-05 13:41 ` [PATCH v3 13/18] Export tracing control breakpoints functions via global function pointers Antoine Tremblay
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

This patch moves insn_references_pc to common code in arch/, so that it
can be used in gdbserver.  It adds the arm_ prefix, since the function
is now exported.

gdb/ChangeLog:

	* arm-tdep.c (arm_copy_preload): Adjust to renaming.
	(arm_copy_preload_reg): Likewise.
	(arm_copy_copro_load_store): Likewise.
	(arm_copy_alu_imm): Likewise.
	(arm_copy_alu_reg): Likewise.
	(arm_copy_alu_shifted_reg): Likewise.
	(arm_copy_extra_ld_st): Likewise.
	(arm_copy_ldr_str_ldrb_strb): Likewise.
	(insn_references_pc): Move to...
	* arch/arm-insn-reloc.c (arm_insn_references_pc): ... here.
	* arch/arm-insn-reloc.h (arm_insn_references_pc): New declaraction.
---
 gdb/arch/arm-insn-reloc.c | 29 ++++++++++++++++++++++++++++
 gdb/arch/arm-insn-reloc.h |  8 ++++++++
 gdb/arm-tdep.c            | 49 ++++++++---------------------------------------
 3 files changed, 45 insertions(+), 41 deletions(-)

diff --git a/gdb/arch/arm-insn-reloc.c b/gdb/arch/arm-insn-reloc.c
index b6ede60..7ebb507 100644
--- a/gdb/arch/arm-insn-reloc.c
+++ b/gdb/arch/arm-insn-reloc.c
@@ -20,6 +20,35 @@
 #include "arm.h"
 #include "arm-insn-reloc.h"
 
+
+/* See arch/arm-insn-reloc.h.  */
+
+int
+arm_insn_references_pc (uint32_t insn, uint32_t bitmask)
+{
+  uint32_t lowbit = 1;
+
+  while (bitmask != 0)
+    {
+      uint32_t mask;
+
+      for (; lowbit && (bitmask & lowbit) == 0; lowbit <<= 1)
+	;
+
+      if (!lowbit)
+	break;
+
+      mask = lowbit * 0xf;
+
+      if ((insn & mask) == mask)
+	return 1;
+
+      bitmask &= ~mask;
+    }
+
+  return 0;
+}
+
 static int
 arm_decode_misc_memhint_neon (uint32_t insn,
 			      struct arm_insn_reloc_visitor *visitor,
diff --git a/gdb/arch/arm-insn-reloc.h b/gdb/arch/arm-insn-reloc.h
index 6e83ad4..8f93214 100644
--- a/gdb/arch/arm-insn-reloc.h
+++ b/gdb/arch/arm-insn-reloc.h
@@ -84,6 +84,14 @@ struct thumb_16bit_insn_reloc_visitor
   int (*svc) (uint16_t insn, struct arm_insn_reloc_data *data);
 };
 
+/* This function is used to concisely determine if an instruction INSN
+   references PC.  Register fields of interest in INSN should have the
+   corresponding fields of BITMASK set to 0b1111.  The function
+   returns return 1 if any of these fields in INSN reference the PC
+   (also 0b1111, r15), else it returns 0.  */
+
+extern int arm_insn_references_pc (uint32_t insn, uint32_t bitmask);
+
 extern int arm_relocate_insn (uint32_t insn,
 			      struct arm_insn_reloc_visitor *visitor,
 			      struct arm_insn_reloc_data *data);
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 2a83b82..32c81c2 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -4653,38 +4653,6 @@ displaced_write_reg (struct regcache *regs, struct displaced_step_closure *dsc,
     }
 }
 
-/* This function is used to concisely determine if an instruction INSN
-   references PC.  Register fields of interest in INSN should have the
-   corresponding fields of BITMASK set to 0b1111.  The function
-   returns return 1 if any of these fields in INSN reference the PC
-   (also 0b1111, r15), else it returns 0.  */
-
-static int
-insn_references_pc (uint32_t insn, uint32_t bitmask)
-{
-  uint32_t lowbit = 1;
-
-  while (bitmask != 0)
-    {
-      uint32_t mask;
-
-      for (; lowbit && (bitmask & lowbit) == 0; lowbit <<= 1)
-	;
-
-      if (!lowbit)
-	break;
-
-      mask = lowbit * 0xf;
-
-      if ((insn & mask) == mask)
-	return 1;
-
-      bitmask &= ~mask;
-    }
-
-  return 0;
-}
-
 /* The simplest copy function.  Many instructions have the same effect no
    matter what address they are executed at: in those cases, use this.  */
 
@@ -4773,7 +4741,7 @@ arm_copy_preload (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int rn = bits (insn, 16, 19);
 
-  if (!insn_references_pc (insn, 0x000f0000ul))
+  if (!arm_insn_references_pc (insn, 0x000f0000ul))
     return arm_copy_unmodified (insn, "preload", data);
 
   if (debug_displaced)
@@ -4870,8 +4838,7 @@ arm_copy_preload_reg (uint32_t insn, struct arm_insn_reloc_data *data)
   unsigned int rn = bits (insn, 16, 19);
   unsigned int rm = bits (insn, 0, 3);
 
-
-  if (!insn_references_pc (insn, 0x000f000ful))
+  if (!arm_insn_references_pc (insn, 0x000f000ful))
     return arm_copy_unmodified (insn, "preload reg", data);
 
   if (debug_displaced)
@@ -4932,7 +4899,7 @@ arm_copy_copro_load_store (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int rn = bits (insn, 16, 19);
 
-  if (!insn_references_pc (insn, 0x000f0000ul))
+  if (!arm_insn_references_pc (insn, 0x000f0000ul))
     return arm_copy_unmodified (insn, "copro load/store", data);
 
   if (debug_displaced)
@@ -5238,7 +5205,7 @@ arm_copy_alu_imm (uint32_t insn, struct arm_insn_reloc_data *data)
   int is_mov = (op == 0xd);
   ULONGEST rd_val, rn_val;
 
-  if (!insn_references_pc (insn, 0x000ff000ul))
+  if (!arm_insn_references_pc (insn, 0x000ff000ul))
     return arm_copy_unmodified (insn, "ALU immediate", data);
 
   if (debug_displaced)
@@ -5386,7 +5353,7 @@ arm_copy_alu_reg (uint32_t insn, struct arm_insn_reloc_data *data)
   unsigned int op = bits (insn, 21, 24);
   int is_mov = (op == 0xd);
 
-  if (!insn_references_pc (insn, 0x000ff00ful))
+  if (!arm_insn_references_pc (insn, 0x000ff00ful))
     return arm_copy_unmodified (insn, "ALU reg", data);
 
   if (debug_displaced)
@@ -5487,7 +5454,7 @@ arm_copy_alu_shifted_reg (uint32_t insn, struct arm_insn_reloc_data *data)
   int is_mov = (op == 0xd);
   unsigned int rd, rn, rm, rs;
 
-  if (!insn_references_pc (insn, 0x000fff0ful))
+  if (!arm_insn_references_pc (insn, 0x000fff0ful))
     return arm_copy_unmodified (insn, "ALU shifted reg", data);
 
   if (debug_displaced)
@@ -5581,7 +5548,7 @@ arm_copy_extra_ld_st (uint32_t insn, struct arm_insn_reloc_data *data,
   struct displaced_step_closure *dsc = data->dsc;
   struct regcache *regs = data->regs;
 
-  if (!insn_references_pc (insn, 0x000ff00ful))
+  if (!arm_insn_references_pc (insn, 0x000ff00ful))
     return arm_copy_unmodified (insn, "extra load/store", data);
 
   if (debug_displaced)
@@ -5812,7 +5779,7 @@ arm_copy_ldr_str_ldrb_strb (uint32_t insn, struct arm_insn_reloc_data *data,
   unsigned int rm = bits (insn, 0, 3);  /* Only valid if !immed.  */
   struct displaced_step_closure *dsc = data->dsc;
 
-  if (!insn_references_pc (insn, 0x000ff00ful))
+  if (!arm_insn_references_pc (insn, 0x000ff00ful))
     return arm_copy_unmodified (insn, "load/store", data);
 
   if (debug_displaced)
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 11/18] Use software single step to step out of a fast tracepoint jump pad
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
@ 2016-07-05 13:41 ` Antoine Tremblay
  2016-07-05 13:41 ` [PATCH v3 16/18] arm: Move insn_references_pc to common code Antoine Tremblay
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

This patch enables software single step to be used to single step a thread
out of the fast tracepoint jump pad.

gdb/gdbserver/ChangeLog:

	* linux-low.c (linux_resume_one_lwp_throw): Use software single
	step if available to step out of the fast tracepoint jump pad.
---
 gdb/gdbserver/linux-low.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 14e15df..023d51f 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -4308,14 +4308,7 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp,
 		      " single-stepping\n",
 		      lwpid_of (thread));
 
-      if (can_hardware_single_step ())
-	step = 1;
-      else
-	{
-	  internal_error (__FILE__, __LINE__,
-			  "moving out of jump pad single-stepping"
-			  " not implemented on this target");
-	}
+      step = single_step (lwp);
     }
 
   /* If we have while-stepping actions in this thread set it stepping.
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 13/18] Export tracing control breakpoints functions via global function pointers
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 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 ` Antoine Tremblay
  2016-07-05 13:41 ` [PATCH v3 12/18] Add ARM/Thumb instruction assembler for fast tracepoints Antoine Tremblay
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

Since ARM has 2 instructions sets ARM, and Thumb and thus 2 breakpoint
instructions. GDBServer needs to know what kind of breakpoint to set in
the IPA for it's tracing controls breakpoints (stop_tracing, flush_trace_buffer,
about_to_request_buffer_space).

Since qSymbol does not carry the Thumb bit on the symbol address, this
patch exports a function pointer with the address of the function to be
read by GDBServer.

This way the Thumb bit is carried in that value and GDBServer sets the
proper breakpoint.

This patch adds a test that collects 10MB of data, so that a flush is
triggered after the IPA reaches its 5MB limit.

gdb/gdbserver/ChangeLog:
	* tracepoint.c (stop_tracing, flush_trace_buffer,
	about_to_request_buffer_space): Rename with _ptr suffix.
	(struct ipa_sym_addresses)<stop_tracing, flush_trace_buffer,
	about_to_request_buffer_space>: Likewise.
	(symbol_list): Likewise.
	(stop_tracing): Remove function export.
	(flush_trace_buffer): Likewise.
	(about_to_request_buffer_space): Likewise.
	(cmd_qtstart): Read breakpoint addresses from the inferior.
	(handle_tracepoint_bkpts): Likewise.
	(stop_tracing_ptr, flush_trace_buffer_ptr,
	(tracepoint_bkpt_ptr_type): New typedef.
	about_to_request_buffer_space_ptr): New globals.
	(upload_fast_traceframes): Read breakpoint address from the inferior.

gdb/testsuite/ChangeLog:

	* ftrace-flush-buffer.exp: New file.
	* ftrace-flush-buffer.c: Likewise.
---
 gdb/gdbserver/tracepoint.c                      | 94 ++++++++++++++++++------
 gdb/testsuite/gdb.trace/ftrace-flush-buffer.c   | 42 +++++++++++
 gdb/testsuite/gdb.trace/ftrace-flush-buffer.exp | 98 +++++++++++++++++++++++++
 3 files changed, 213 insertions(+), 21 deletions(-)
 create mode 100644 gdb/testsuite/gdb.trace/ftrace-flush-buffer.c
 create mode 100644 gdb/testsuite/gdb.trace/ftrace-flush-buffer.exp

diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index a139f67..87211e9 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -109,9 +109,9 @@ trace_vdebug (const char *fmt, ...)
 # define gdb_trampoline_buffer_error IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_error)
 # define collecting IPA_SYM_EXPORTED_NAME (collecting)
 # define gdb_collect_ptr IPA_SYM_EXPORTED_NAME (gdb_collect_ptr)
-# define stop_tracing IPA_SYM_EXPORTED_NAME (stop_tracing)
-# define flush_trace_buffer IPA_SYM_EXPORTED_NAME (flush_trace_buffer)
-# define about_to_request_buffer_space IPA_SYM_EXPORTED_NAME (about_to_request_buffer_space)
+# define stop_tracing_ptr IPA_SYM_EXPORTED_NAME (stop_tracing_ptr)
+# define flush_trace_buffer_ptr IPA_SYM_EXPORTED_NAME (flush_trace_buffer_ptr)
+# define about_to_request_buffer_space_ptr IPA_SYM_EXPORTED_NAME (about_to_request_buffer_space_ptr)
 # define trace_buffer_is_full IPA_SYM_EXPORTED_NAME (trace_buffer_is_full)
 # define stopping_tracepoint IPA_SYM_EXPORTED_NAME (stopping_tracepoint)
 # define expr_eval_result IPA_SYM_EXPORTED_NAME (expr_eval_result)
@@ -151,9 +151,9 @@ struct ipa_sym_addresses
   CORE_ADDR addr_gdb_trampoline_buffer_error;
   CORE_ADDR addr_collecting;
   CORE_ADDR addr_gdb_collect_ptr;
-  CORE_ADDR addr_stop_tracing;
-  CORE_ADDR addr_flush_trace_buffer;
-  CORE_ADDR addr_about_to_request_buffer_space;
+  CORE_ADDR addr_stop_tracing_ptr;
+  CORE_ADDR addr_flush_trace_buffer_ptr;
+  CORE_ADDR addr_about_to_request_buffer_space_ptr;
   CORE_ADDR addr_trace_buffer_is_full;
   CORE_ADDR addr_stopping_tracepoint;
   CORE_ADDR addr_expr_eval_result;
@@ -188,9 +188,9 @@ static struct
   IPA_SYM(gdb_trampoline_buffer_error),
   IPA_SYM(collecting),
   IPA_SYM(gdb_collect_ptr),
-  IPA_SYM(stop_tracing),
-  IPA_SYM(flush_trace_buffer),
-  IPA_SYM(about_to_request_buffer_space),
+  IPA_SYM(stop_tracing_ptr),
+  IPA_SYM(flush_trace_buffer_ptr),
+  IPA_SYM(about_to_request_buffer_space_ptr),
   IPA_SYM(trace_buffer_is_full),
   IPA_SYM(stopping_tracepoint),
   IPA_SYM(expr_eval_result),
@@ -368,14 +368,14 @@ read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
 #  define UNKNOWN_SIDE_EFFECTS() do {} while (0)
 #endif
 
-IP_AGENT_EXPORT_FUNC void
+void
 stop_tracing (void)
 {
   /* GDBserver places breakpoint here.  */
   UNKNOWN_SIDE_EFFECTS();
 }
 
-IP_AGENT_EXPORT_FUNC void
+void
 flush_trace_buffer (void)
 {
   /* GDBserver places breakpoint here.  */
@@ -1379,7 +1379,7 @@ init_trace_buffer (LONGEST bufsize)
 
 #ifdef IN_PROCESS_AGENT
 
-IP_AGENT_EXPORT_FUNC void
+void
 about_to_request_buffer_space (void)
 {
   /* GDBserver places breakpoint here while it goes about to flush
@@ -3095,6 +3095,7 @@ cmd_qtstart (char *packet)
 {
   struct tracepoint *tpoint, *prev_ftpoint, *prev_stpoint;
   CORE_ADDR tpptr = 0, prev_tpptr = 0;
+  CORE_ADDR addr_flush_trace_buffer, addr_stop_tracing;
 
   trace_debug ("Starting the trace");
 
@@ -3291,14 +3292,29 @@ cmd_qtstart (char *packet)
 			  " in lib");
 	}
 
-      stop_tracing_bkpt = set_breakpoint_at (ipa_sym_addrs.addr_stop_tracing,
+      if (read_inferior_data_pointer (ipa_sym_addrs.addr_stop_tracing_ptr,
+				      &addr_stop_tracing))
+	{
+	  internal_error (__FILE__, __LINE__,
+			  "Error reading addr_stop_tracing_ptr variable"
+			  " in lib");
+	}
+
+      stop_tracing_bkpt = set_breakpoint_at (addr_stop_tracing,
 					     stop_tracing_handler);
       if (stop_tracing_bkpt == NULL)
 	error ("Error setting stop_tracing breakpoint");
 
-      flush_trace_buffer_bkpt
-	= set_breakpoint_at (ipa_sym_addrs.addr_flush_trace_buffer,
-			     flush_trace_buffer_handler);
+      if (read_inferior_data_pointer (ipa_sym_addrs.addr_flush_trace_buffer_ptr,
+				      &addr_flush_trace_buffer))
+	{
+	  internal_error (__FILE__, __LINE__,
+			  "Error reading addr_flsh_trace_ptr variable"
+			  " in lib");
+	}
+
+      flush_trace_buffer_bkpt = set_breakpoint_at (addr_flush_trace_buffer,
+						   flush_trace_buffer_handler);
       if (flush_trace_buffer_bkpt == NULL)
 	error ("Error setting flush_trace_buffer breakpoint");
     }
@@ -4385,6 +4401,8 @@ tracepoint_finished_step (struct thread_info *tinfo, CORE_ADDR stop_pc)
 int
 handle_tracepoint_bkpts (struct thread_info *tinfo, CORE_ADDR stop_pc)
 {
+  CORE_ADDR addr_stop_tracing, addr_flush_trace_buffer;
+
   /* Pull in fast tracepoint trace frames from the inferior in-process
      agent's buffer into our buffer.  */
 
@@ -4393,9 +4411,25 @@ handle_tracepoint_bkpts (struct thread_info *tinfo, CORE_ADDR stop_pc)
 
   upload_fast_traceframes ();
 
+  if (read_inferior_data_pointer (ipa_sym_addrs.addr_stop_tracing_ptr,
+				  &addr_stop_tracing))
+    {
+      internal_error (__FILE__, __LINE__,
+		      "Error reading addr_stop_tracing_ptr variable"
+		      " in lib");
+    }
+
+  if (read_inferior_data_pointer (ipa_sym_addrs.addr_flush_trace_buffer_ptr,
+				  &addr_flush_trace_buffer))
+    {
+      internal_error (__FILE__, __LINE__,
+		      "Error reading addr_flsh_trace_ptr variable"
+		      " in lib");
+    }
+
   /* Check if the in-process agent had decided we should stop
      tracing.  */
-  if (stop_pc == ipa_sym_addrs.addr_stop_tracing)
+  if (stop_pc == addr_stop_tracing)
     {
       int ipa_trace_buffer_is_full;
       CORE_ADDR ipa_stopping_tracepoint;
@@ -4452,7 +4486,7 @@ handle_tracepoint_bkpts (struct thread_info *tinfo, CORE_ADDR stop_pc)
       stop_tracing ();
       return 1;
     }
-  else if (stop_pc == ipa_sym_addrs.addr_flush_trace_buffer)
+  else if (stop_pc == addr_flush_trace_buffer)
     {
       trace_debug ("lib stopped at flush_trace_buffer");
       return 1;
@@ -5774,12 +5808,16 @@ gdb_collect (struct tracepoint *tpoint, unsigned char *regs)
 /* These global variables points to the corresponding functions.  This is
    necessary on powerpc64, where asking for function symbol address from gdb
    results in returning the actual code pointer, instead of the descriptor
-   pointer.  */
+   pointer.
+   These variables are also needed for ARM so that the address contains the
+   Thumb bit if the address is in thumb mode.
+ */
 
 typedef void (*gdb_collect_ptr_type) (struct tracepoint *, unsigned char *);
 typedef ULONGEST (*get_raw_reg_ptr_type) (const unsigned char *, int);
 typedef LONGEST (*get_trace_state_variable_value_ptr_type) (int);
 typedef void (*set_trace_state_variable_value_ptr_type) (int, LONGEST);
+typedef void (*tracepoint_bkpt_ptr_type) (void);
 
 EXTERN_C_PUSH
 IP_AGENT_EXPORT_VAR gdb_collect_ptr_type gdb_collect_ptr = gdb_collect;
@@ -5788,6 +5826,11 @@ IP_AGENT_EXPORT_VAR get_trace_state_variable_value_ptr_type
   get_trace_state_variable_value_ptr = get_trace_state_variable_value;
 IP_AGENT_EXPORT_VAR set_trace_state_variable_value_ptr_type
   set_trace_state_variable_value_ptr = set_trace_state_variable_value;
+IP_AGENT_EXPORT_VAR tracepoint_bkpt_ptr_type stop_tracing_ptr = stop_tracing;
+IP_AGENT_EXPORT_VAR tracepoint_bkpt_ptr_type
+  flush_trace_buffer_ptr = flush_trace_buffer;
+IP_AGENT_EXPORT_VAR tracepoint_bkpt_ptr_type
+  about_to_request_buffer_space_ptr = about_to_request_buffer_space;
 EXTERN_C_POP
 
 #endif
@@ -6238,6 +6281,7 @@ upload_fast_traceframes (void)
   struct breakpoint *about_to_request_buffer_space_bkpt;
   CORE_ADDR ipa_trace_buffer_lo;
   CORE_ADDR ipa_trace_buffer_hi;
+  CORE_ADDR addr_about_to_request_buffer_space;
 
   if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count,
 			      &ipa_traceframe_read_count_racy))
@@ -6260,9 +6304,17 @@ upload_fast_traceframes (void)
   if (ipa_traceframe_write_count_racy == ipa_traceframe_read_count_racy)
     return;
 
+  if (read_inferior_data_pointer
+      (ipa_sym_addrs.addr_about_to_request_buffer_space_ptr,
+       &addr_about_to_request_buffer_space))
+    {
+      internal_error (__FILE__, __LINE__,
+		      "Error reading  variable"
+		      "addr_about_to_request_buffer_space_ptr inn lib");
+    }
+
   about_to_request_buffer_space_bkpt
-    = set_breakpoint_at (ipa_sym_addrs.addr_about_to_request_buffer_space,
-			 NULL);
+    = set_breakpoint_at (addr_about_to_request_buffer_space, NULL);
 
   if (read_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr,
 			      &ipa_trace_buffer_ctrl_curr))
diff --git a/gdb/testsuite/gdb.trace/ftrace-flush-buffer.c b/gdb/testsuite/gdb.trace/ftrace-flush-buffer.c
new file mode 100644
index 0000000..c115f00
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/ftrace-flush-buffer.c
@@ -0,0 +1,42 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011-2016 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "trace-common.h"
+
+static void
+begin (void)
+{}
+
+static void
+end (void)
+{}
+
+int
+main ()
+{
+  int i = 0;
+  int table[1048576];
+
+  begin ();
+  for (i; i < 10; i++)
+    {
+      FAST_TRACEPOINT_LABEL(set_point);
+    }
+
+  end ();
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.trace/ftrace-flush-buffer.exp b/gdb/testsuite/gdb.trace/ftrace-flush-buffer.exp
new file mode 100644
index 0000000..08fa26a
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/ftrace-flush-buffer.exp
@@ -0,0 +1,98 @@
+# Copyright 2011-2016 Free Software Foundation, Inc.
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# The IPA flushes its internal buffer to GDBServer as it reaches 5MB
+# (hardcoded).  This test checks that this does not crash the inferiror by
+# collecting 10MB of data.
+
+load_lib "trace-support.exp"
+
+standard_testfile
+set executable $testfile
+set expfile $testfile.exp
+
+# Some targets have leading underscores on assembly symbols.
+set additional_flags [gdb_target_symbol_prefix_flags]
+
+if [prepare_for_testing $expfile $executable $srcfile \
+	[list debug $additional_flags]] {
+    untested "failed to prepare for trace tests"
+    return -1
+}
+
+if ![runto_main] {
+    fail "Can't run to main to check for trace support"
+    return -1
+}
+
+if ![gdb_target_supports_trace] {
+    unsupported "target does not support trace"
+    return -1
+}
+
+if {![gdb_target_supports_fast_trace]} {
+    unsupported "Target does not support fast tracepoints."
+    return -1
+}
+
+set libipa [get_in_proc_agent]
+set remote_libipa [gdb_load_shlib $libipa]
+
+# Can't use prepare_for_testing, because that splits compiling into
+# building objects and then linking, and we'd fail with "linker input
+# file unused because linking not done" when building the object.
+
+if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \
+	  executable [list debug $additional_flags shlib=$libipa] ] != "" } {
+    untested "failed to compile ftrace tests"
+    return -1
+}
+clean_restart ${executable}
+
+if ![runto_main] {
+    fail "Can't run to main for ftrace tests"
+    return 0
+}
+
+gdb_reinitialize_dir $srcdir/$subdir
+
+if { [gdb_test "info sharedlibrary" ".*${remote_libipa}.*" "IPA loaded"] != 0 } {
+    untested "Could not find IPA lib loaded"
+    return 1
+}
+
+gdb_test "break begin" ".*" ""
+
+gdb_test "break end" ".*" ""
+
+gdb_test "ftrace set_point" "Fast tracepoint .*" \
+    "fast tracepoint at set_point"
+
+gdb_trace_setactions "collect at set_point: define actions" \
+    "" \
+    "collect table" "^$"
+
+gdb_test "continue" \
+    ".*Breakpoint \[0-9\]+, begin .*" \
+    "advance to trace begin"
+
+gdb_test_no_output "tstart" "start trace experiment"
+
+gdb_test "continue" \
+    ".*Breakpoint \[0-9\]+, end .*" \
+    "advance through tracing"
+
+gdb_test "tstatus" ".*Trace .*" "check on trace status"
+
+gdb_test "tstop" "" ""
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 15/18] JIT conditions support for ARM tracepoints.
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (7 preceding siblings ...)
  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 ` Antoine Tremblay
  2016-07-05 13:42 ` [PATCH v3 18/18] arm fast tracepoints: Relocation of Thumb 32-bits instructions Antoine Tremblay
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

This patch adds JIT conditions support for ARM tracepoints.

gdb/ChangeLog:

	* arch/arm.h (submask_64): New macro.
	(bits_64): New macro.

gdb/gdbserver/ChangeLog:

	* linux-arm-ipa.c (get_raw_reg): Fetch registers for JIT.
	* linux-arm-low.c  (append_insns): New function.
	(add_insns_32): Likewise.
	(arm_ax_emit_arm_prologue): Likewise.
	(arm_ax_emit_arm_epilogue): Likewise.
	(arm_ax_emit_arm_add): Likewise.
	(arm_ax_emit_arm_sub): Likewise.
	(arm_ax_emit_arm_mul): Likewise.
	(arm_ax_emit_arm_lsh): Likewise.
	(arm_ax_emit_arm_rsh_signed): Likwise.
	(arm_ax_emit_arm_rsh_unsigned): Likewise.
	(arm_ax_emit_arm_ext): Likewise.
	(arm_ax_emit_arm_log_not): Likewise.
	(arm_ax_emit_arm_bit_and): Likewise.
	(arm_ax_emit_arm_bit_or): Likewise.
	(arm_ax_emit_arm_bit_xor): Likewise.
	(arm_ax_emit_arm_bit_not): Likewise.
	(arm_ax_emit_arm_equal): Likewise.
	(arm_ax_emit_arm_less_signed): Likewise.
	(arm_ax_emit_arm_less_unsigned): Likewise.
	(arm_ax_emit_arm_ref): Likewise.
	(arm_ax_emit_arm_if_goto): Likewise.
	(arm_ax_emit_arm_goto): Likewise.
	(arm_ax_arm_write_goto_address): Likewise.
	(arm_ax_emit_arm_const): Likewise.
	(arm_ax_emit_arm_call): Likewise.
	(arm_ax_emit_arm_reg): Likewise.
	(arm_ax_emit_arm_pop): Likewise.
	(arm_ax_emit_arm_stack_flush): Likewise.
	(arm_ax_emit_arm_zero_ext): Likewise.
	(arm_ax_emit_arm_swap): Likewise.
	(arm_ax_emit_arm_stack_adjust): Likewise.
	(arm_ax_emit_arm_int_call_1): Likewise.
	(arm_ax_emit_arm_void_call_2): Likewise.
	(arm_ax_emit_arm_cmp_eq_goto): Likewise.
	(arm_ax_emit_arm_cmp_lgte_goto): Likewise.
	(arm_ax_emit_arm_eq_goto): Likewise.
	(arm_ax_emit_arm_ne_goto): Likewise.
	(arm_ax_emit_arm_lt_goto): Likewise.
	(arm_ax_emit_arm_le_goto): Likewise.
	(arm_ax_emit_arm_gt_goto): Likewise.
	(arm_ax_emit_arm_ge_goto): Likewise.
	(struct emit_ops arm_ax_emit_arm_ops_impl): New struct.
	(arm_ax_emit_arm_ops): New function.
	(struct linux_target_ops) <emit_ops>: Initialize.
---
 gdb/arch/arm.h                |   2 +
 gdb/gdbserver/linux-arm-ipa.c |  13 +-
 gdb/gdbserver/linux-arm-low.c | 788 +++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 801 insertions(+), 2 deletions(-)

diff --git a/gdb/arch/arm.h b/gdb/arch/arm.h
index fcde3d0..e7bba24 100644
--- a/gdb/arch/arm.h
+++ b/gdb/arch/arm.h
@@ -96,7 +96,9 @@ enum gdb_regnum {
 
 /* Support routines for instruction parsing.  */
 #define submask(x) ((1L << ((x) + 1)) - 1)
+#define submask_64(x) ((1LL << ((x) + 1)) - 1)
 #define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
+#define bits_64(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
 #define bit(obj,st) (((obj) >> (st)) & 1)
 #define sbits(obj,st,fn) \
   ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
diff --git a/gdb/gdbserver/linux-arm-ipa.c b/gdb/gdbserver/linux-arm-ipa.c
index d684b78..ba2488e 100644
--- a/gdb/gdbserver/linux-arm-ipa.c
+++ b/gdb/gdbserver/linux-arm-ipa.c
@@ -159,7 +159,18 @@ supply_fast_tracepoint_registers (struct regcache *regcache,
 ULONGEST
 get_raw_reg (const unsigned char *raw_regs, int regnum)
 {
-  /* Used for JIT conditions.  */
+  if (regnum < ARM_CORE_NUM_FT_COLLECT_REGS)
+      return *(int *) (raw_regs + arm_core_ft_collect_regmap[regnum]);
+
+  if ((get_ipa_tdesc (get_ipa_tdesc_idx ()) == tdesc_arm_with_neon
+       || get_ipa_tdesc (get_ipa_tdesc_idx ()) == tdesc_arm_with_vfpv3)
+      && regnum  < ARM_VFPV3_NUM_FT_COLLECT_REGS)
+    return *(ULONGEST *) (raw_regs + arm_vfpv3_ft_collect_regmap[regnum]);
+
+  if (get_ipa_tdesc (get_ipa_tdesc_idx ()) == tdesc_arm_with_vfpv2
+      && regnum < ARM_VFPV2_NUM_FT_COLLECT_REGS)
+    return *(ULONGEST *) (raw_regs + arm_vfpv2_ft_collect_regmap[regnum]);
+
   return 0;
 }
 
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 5294f00..53c4151 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -1393,8 +1393,10 @@ static const int r2 = 2;
 static const int r3 = 3;
 static const int r4 = 4;
 static const int r5 = 5;
+static const int r12 = 12;
 static const int sp = 13;
 static const int lr = 14;
+static const int pc = 15;
 
 static int
 arm_install_fast_tracepoint_jump_pad_arm (struct tracepoint *tp,
@@ -1950,6 +1952,790 @@ arm_get_ipa_tdesc_idx (void)
   return 0;
 }
 
+/* Append variable length instructions to the inferior memory.  */
+
+static int
+append_insns (CORE_ADDR *to, size_t len, const unsigned char *buf)
+{
+  if (write_inferior_memory (*to, buf, len) != 0)
+    return 1;
+
+  *to += len;
+
+  return 0;
+}
+
+/* Append 32 bit instructions to the inferior memory.  */
+
+static void
+add_insns_32 (uint32_t *start, int len)
+{
+  CORE_ADDR buildaddr = current_insn_ptr;
+
+  if (debug_threads)
+    debug_printf ("Adding %d bytes of insn at %s\n",
+		  len * 4, paddress (buildaddr));
+
+  append_insns (&buildaddr, len * 4, (gdb_byte *) start);
+  current_insn_ptr = buildaddr;
+}
+
+/* The "emit_prologue" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_prologue (void)
+{
+  /* This function emit a prologue for the following function prototype:
+
+     enum eval_result_type f (unsigned char *regs,
+			      ULONGEST *value);
+
+     The first argument is a buffer of raw registers.  The second argument
+     is the result of evaluating the expression, which will be set to
+     whatever is on top of the stack at the end.
+
+     The stack set up by the prologue is as such:
+
+     High *------------------------------------------------------*
+	  | lr                                                   |
+	  | r4                                                   |
+	  | r0  (ULONGEST *value)                                |
+	  | r1  (unsigned char *regs)                            | <-r4
+     Low  *------------------------------------------------------*
+
+     As we are implementing a stack machine, each opcode can expand the
+     stack so we never know how far we are from the data saved by this
+     prologue.  In order to be able refer to value and regs later, we save
+     the current base of the stack in the r4 register.  This way, it is not
+     clobbered when calling C functions.
+
+     Finally, throughtout every operation, we are using register r0 and r1
+     as the top of the stack, and r2, r3, r12 as a scratch register.  */
+
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  /* push {r0, r1, r4, lr}  */
+  p += arm_emit_arm_push_list (p, INST_AL,
+			       encode_register_list (0, 2, ENCODE (1, 1, 4)
+						     | ENCODE (1, 1, 14)));
+  p += arm_emit_arm_mov (p, INST_AL, r4, register_operand (sp));
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_epilogue" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_epilogue (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_add (p, INST_AL, 0, sp, r4, immediate_operand (4));
+  p += arm_emit_arm_pop_list (p, INST_AL, ENCODE (1, 1, 1)
+			      | ENCODE (1, 1, 4)
+			      | ENCODE (1, 1, 14));
+  p += arm_emit_arm_str (p, INST_AL, r0, r1,
+			 memory_operand (offset_memory_operand (0)));
+  p += arm_emit_arm_mov (p, INST_AL, r0, immediate_operand (0));
+  p += arm_emit_arm_mov (p, INST_AL, pc, register_operand (lr));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_add" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_add (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  /* pop {r2,r3}  */
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_add (p, INST_AL, 1, r0, r2, register_operand (r0));
+  p += arm_emit_arm_adc (p, INST_AL, r1, r3, register_operand (r1));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_sub" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_sub (void)
+{
+  const struct target_desc *tdesc = current_process ()->tdesc;
+  const int r0 = find_regno (tdesc, "r0");
+  const int r1 = find_regno (tdesc, "r1");
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  /* pop {r2,r3}  */
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_sub (p, INST_AL, 1, r0, r2, register_operand (r0));
+  p += arm_emit_arm_sbc (p, INST_AL, 0, r1, r3, register_operand (r1));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_mul" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_mul (void)
+{
+  const struct target_desc *tdesc = current_process ()->tdesc;
+  const int r0 = find_regno (tdesc, "r0");
+  const int r1 = find_regno (tdesc, "r1");
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  /* pop {r2,r3}  */
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+
+  /* Multiply 64-64 int as : ((ah * bl) + (bh * al)) + (al * bl).
+     ah = operand a, high bits.
+     al = operand a, low bits.
+     same for operand b.  */
+
+  p += arm_emit_arm_mul (p, INST_AL, r1, r1, register_operand (r2));
+  p += arm_emit_arm_mul (p, INST_AL, r3, r0, register_operand (r3));
+  p += arm_emit_arm_add (p, INST_AL, 0, r1, r1, register_operand (r3));
+  p += arm_emit_arm_umull (p, INST_AL, r2, r3, r0, r2);
+  p += arm_emit_arm_add (p, INST_AL, 0, r1, r1, register_operand (r3));
+  p += arm_emit_arm_mov (p, INST_AL, r0, register_operand (r2));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_lsh" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_lsh (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_sub (p, INST_AL, 0, r12, r0, immediate_operand (32));
+  p += arm_emit_arm_rsb (p, INST_AL, r1, r0, immediate_operand (32));
+  p += arm_emit_arm_lsl (p, INST_AL, r3, r3, register_operand (r0));
+  p += arm_emit_arm_orr_reg_shifted (p, INST_AL, r3, r3, r2, LSL, r12);
+  p += arm_emit_arm_orr_reg_shifted (p, INST_AL, r3, r3, r2, LSR, r1);
+  p += arm_emit_arm_lsl (p, INST_AL, r0, r2, register_operand (r0));
+  p += arm_emit_arm_mov (p, INST_AL, r1, register_operand (r3));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_rsh_signed" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_rsh_signed (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_rsb (p, INST_AL, r1, r0, immediate_operand (32));
+  p += arm_emit_arm_sub (p, INST_AL, 1, r12, r0, immediate_operand (32));
+  p += arm_emit_arm_lsr (p, INST_AL, r2, r2, register_operand (r0));
+  p += arm_emit_arm_orr_reg_shifted (p, INST_AL, r2, r2, r3, LSL, r1);
+  p += arm_emit_arm_orr_reg_shifted (p, INST_PL, r2, r2, r3, ASR, r12);
+  p += arm_emit_arm_asr (p, INST_AL, r1, r3, register_operand (r0));
+  p += arm_emit_arm_mov (p, INST_AL, r0, register_operand (r2));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_rsh_unsigned" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_rsh_unsigned (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_rsb (p, INST_AL, r1, r0, immediate_operand (32));
+  p += arm_emit_arm_sub (p, INST_AL, 1, r12, r0, immediate_operand (32));
+  p += arm_emit_arm_lsr (p, INST_AL, r2, r2, register_operand (r0));
+  p += arm_emit_arm_orr_reg_shifted (p, INST_AL, r2, r2, r3, LSL, r1);
+  p += arm_emit_arm_orr_reg_shifted (p, INST_PL, r2, r2, r3, LSR, r12);
+  p += arm_emit_arm_lsr (p, INST_AL, r1, r3, register_operand (r0));
+  p += arm_emit_arm_mov (p, INST_AL, r0, register_operand (r2));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_ext" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_ext (int arg)
+{
+  const struct target_desc *tdesc = current_process ()->tdesc;
+  const int r0 = find_regno (tdesc, "r0");
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  if (arg <= 32)
+    {
+      p += arm_emit_arm_sbfx (p, INST_AL, r0, r0, 0, arg);
+      p += arm_emit_arm_mov (p, INST_AL, r1, register_operand (r0));
+      p += arm_emit_arm_asr (p, INST_AL, r1, r1, immediate_operand (31));
+    }
+  else
+    p += arm_emit_arm_sbfx (p, INST_AL, r1, r1, 0, 32 - arg);
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_log_not" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_log_not (void)
+{
+  const struct target_desc *tdesc = current_process ()->tdesc;
+  const int r0 = find_regno (tdesc, "r0");
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  /* Check if the top of the stack is 0 */
+  p += arm_emit_arm_cmp (p, INST_AL, r1, immediate_operand (0));
+  p += arm_emit_arm_cmp (p, INST_EQ, r0, immediate_operand (0));
+
+  /* Move 1 to the top of stack if it's 0 */
+  p += arm_emit_arm_mov (p, INST_EQ, r0, immediate_operand (1));
+  p += arm_emit_arm_mov (p, INST_EQ, r1, immediate_operand (0));
+
+  /* Move 0 to the top of stack if it's not 0 */
+  p += arm_emit_arm_mov (p, INST_NE, r0, immediate_operand (0));
+  p += arm_emit_arm_mov (p, INST_NE, r1, immediate_operand (0));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_bit_and" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_bit_and (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_and (p, INST_AL, r0, r0, register_operand (r2));
+  p += arm_emit_arm_and (p, INST_AL, r1, r1, register_operand (r3));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_bit_or" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_bit_or (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_orr (p, INST_AL, r0, r0, register_operand (r2));
+  p += arm_emit_arm_orr (p, INST_AL, r1, r1, register_operand (r3));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_bit_xor" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_bit_xor (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_eor (p, INST_AL, r0, r0, register_operand (r2));
+  p += arm_emit_arm_eor (p, INST_AL, r1, r1, register_operand (r3));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_bit_not" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_bit_not (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_mvn (p, INST_AL, r0, register_operand (r0));
+  p += arm_emit_arm_mvn (p, INST_AL, r1, register_operand (r1));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_equal" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_equal (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  /* pop {r2,r3}  */
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_cmp (p, INST_AL, r0, register_operand (r2));
+  p += arm_emit_arm_cmp (p, INST_EQ, r1, register_operand (r3));
+  p += arm_emit_arm_mov (p, INST_EQ, r0, immediate_operand (1));
+  p += arm_emit_arm_mov (p, INST_NE, r0, immediate_operand (0));
+  p += arm_emit_arm_mov (p, INST_AL, r1, immediate_operand (0));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_less_signed" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_less_signed (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_cmp (p, INST_AL, r2, register_operand (r0));
+  p += arm_emit_arm_sbc (p, INST_AL, 1, r1, r3, register_operand (r1));
+  p += arm_emit_arm_mov (p, INST_LT, r0, immediate_operand (1));
+  p += arm_emit_arm_mov (p, INST_GE, r0, immediate_operand (0));
+  p += arm_emit_arm_mov (p, INST_AL, r1, immediate_operand (0));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_less_unsigned" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_less_unsigned (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_cmp (p, INST_AL, r3, register_operand (r1));
+  p += arm_emit_arm_cmp (p, INST_EQ, r2, register_operand (r0));
+  p += arm_emit_arm_mov (p, INST_CC, r0, immediate_operand (1));
+  p += arm_emit_arm_mov (p, INST_CS, r0, immediate_operand (0));
+  p += arm_emit_arm_mov (p, INST_AL, r1, immediate_operand (0));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_ref" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_ref (int size)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  switch (size)
+    {
+    case 1:
+      p += arm_emit_arm_ldrb (p, INST_AL, r0, r0, offset_memory_operand (0));
+      p += arm_emit_arm_mov (p, INST_AL, r1, immediate_operand (0));
+      break;
+    case 2:
+      p += arm_emit_arm_ldrh (p, INST_AL, r0, r0, offset_memory_operand (0));
+      p += arm_emit_arm_mov (p, INST_AL, r1, immediate_operand (0));
+      break;
+    case 4:
+      p += arm_emit_arm_ldr (p, INST_AL, r0, r0, offset_memory_operand (0));
+      p += arm_emit_arm_mov (p, INST_AL, r1, immediate_operand (0));
+      break;
+    case 8:
+      p += arm_emit_arm_ldrd (p, INST_AL, r0, r0, offset_memory_operand (0));
+      break;
+    default:
+      emit_error = 1;
+    }
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_if_goto" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_if_goto (int *offset_p, int *size_p)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_cmp (p, INST_AL, r1, immediate_operand (0));
+  p += arm_emit_arm_cmp (p, INST_EQ, r0, immediate_operand (0));
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_bl (p, INST_EQ, arm_arm_branch_adjusted_offset (8));
+
+  /* The NOP instruction will be patched with an unconditional branch.  */
+  if (offset_p)
+    *offset_p = (p - buf) * 4;
+  if (size_p)
+    *size_p = 4;
+
+  p += arm_emit_arm_nop (p, INST_AL);
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_goto" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_goto (int *offset_p, int *size_p)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  /* The NOP instruction will be patched with an unconditional branch.  */
+  if (offset_p)
+    *offset_p = 0;
+  if (size_p)
+    *size_p = 4;
+
+  p += arm_emit_arm_nop (p, INST_AL);
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_write_goto_address" emit_ops method for ARM.  */
+
+static void
+arm_ax_arm_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size)
+{
+  uint32_t insn;
+  arm_emit_arm_b (&insn, INST_AL, arm_arm_branch_relative_distance (from, to));
+  append_insns (&from, 4, (const unsigned char *)&insn);
+}
+
+/* The "emit_const" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_const (LONGEST num)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_movw (p, INST_AL, r0,
+			  immediate_operand (bits_64 (num, 0, 15)));
+  p += arm_emit_arm_movt (p, INST_AL, r0,
+			  immediate_operand (bits_64 (num, 16, 31)));
+  p += arm_emit_arm_movw (p, INST_AL, r1,
+			  immediate_operand (bits_64 (num, 32, 47)));
+  p += arm_emit_arm_movt (p, INST_AL, r1,
+			  immediate_operand (bits_64 (num, 48, 63)));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_call" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_call (CORE_ADDR fn)
+{
+  const struct target_desc *tdesc = current_process ()->tdesc;
+  const int r12 = find_regno (tdesc, "r12");
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_mov_32 (p, r12, fn);
+  p += arm_emit_arm_blx (p, INST_AL, register_operand (r12));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_reg" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_reg (int reg)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  /* Set r0 to unsigned char *regs.  */
+  p += arm_emit_arm_mov (p, INST_AL, r0, register_operand (r4));
+  p += arm_emit_arm_ldr (p, INST_AL, r0, r0, offset_memory_operand (0));
+  p += arm_emit_arm_mov (p, INST_AL, r1, immediate_operand (reg));
+
+  add_insns_32 (buf, p - buf);
+
+  arm_ax_emit_arm_call (get_raw_reg_func_addr ());
+}
+
+/* The "emit_pop" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_pop (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (0, 2, 0));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_stack_flush" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_stack_flush (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  /* push {r0,r1}  */
+  p += arm_emit_arm_push_list (p, INST_AL, encode_register_list (0, 2, 0));
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_zero_ext" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_zero_ext (int arg)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  if (arg > 32)
+    {
+      p += arm_emit_arm_ubfx (p, INST_AL, r1, r1, 0, arg - 32);
+    }
+  else
+    {
+      p += arm_emit_arm_ubfx (p, INST_AL, r0, r0, 0, arg);
+      p += arm_emit_arm_mov (p, INST_AL, r1, immediate_operand (0));
+    }
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_swap" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_swap (void)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_push_list (p, INST_AL, encode_register_list (0, 2, 0));
+  p += arm_emit_arm_mov (p, INST_AL, r0, register_operand (r2));
+  p += arm_emit_arm_mov (p, INST_AL, r1, register_operand (r3));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_stack_adjust" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_stack_adjust (int n)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_add (p, INST_AL, 0, sp, sp, immediate_operand (n * 8));
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_int_call_1" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_int_call_1 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_mov_32 (p, r0, arg1);
+
+  add_insns_32 (buf, p - buf);
+  arm_ax_emit_arm_call (fn);
+}
+
+/* The "emit_void_call_2" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_void_call_2 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  arm_ax_emit_arm_stack_flush ();
+
+  /* Setup arguments for the function call:
+     r0: arg1
+     r2-r3 : arg2
+  */
+
+  p += arm_emit_arm_mov (p, INST_AL, r2, register_operand (r0));
+  p += arm_emit_arm_mov (p, INST_AL, r3, register_operand (r1));
+  p += arm_emit_arm_mov_32 (p, r0, arg1);
+
+  add_insns_32 (buf, p - buf);
+  arm_ax_emit_arm_call (fn);
+
+  /* Restore r0,r1.  */
+  arm_ax_emit_arm_pop ();
+}
+
+/* Helper function for arm_{EQ|NE}_goto.  */
+
+static void
+arm_ax_emit_arm_cmp_eq_goto (uint8_t cond, int *offset_p, int *size_p)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_cmp (p, INST_AL, r0, register_operand (r2));
+  p += arm_emit_arm_cmp (p, INST_EQ, r1, register_operand (r3));
+
+  /* Branch over the next instruction.  */
+  p += arm_emit_arm_bl (p, cond, arm_arm_branch_adjusted_offset (8));
+  /* The NOP instruction will be patched with an unconditional branch.  */
+  if (offset_p)
+    *offset_p = (p - buf) * 4;
+  if (size_p)
+    *size_p = 4;
+  p += arm_emit_arm_nop (p, INST_AL);
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* Helper function for arm_{LE|LT|GE|GT}_goto.  */
+
+static void
+arm_ax_emit_arm_cmp_lgte_goto (uint8_t cond, int *offset_p, int *size_p,
+			       int swap)
+{
+  uint32_t buf[16];
+  uint32_t *p = buf;
+
+  if (swap)
+    {
+      p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+      p += arm_emit_arm_push_list (p, INST_AL,encode_register_list (0, 2, 0));
+      p += arm_emit_arm_mov (p, INST_AL, r0, register_operand (r2));
+      p += arm_emit_arm_mov (p, INST_AL, r1, register_operand (r3));
+    }
+
+  p += arm_emit_arm_pop_list (p, INST_AL, encode_register_list (2, 2, 0));
+  p += arm_emit_arm_cmp (p, INST_AL, r2, register_operand (r0));
+  p += arm_emit_arm_sbc (p, INST_AL, 1, r2, r3, register_operand (r1));
+
+  /* Branch over the next instruction.  */
+  p += arm_emit_arm_bl (p, cond, arm_arm_branch_adjusted_offset (8));
+  /* The NOP instruction will be patched with an unconditional branch.  */
+  if (offset_p)
+    *offset_p = (p - buf) * 4;
+  if (size_p)
+    *size_p = 4;
+  p += arm_emit_arm_nop (p, INST_AL);
+
+  add_insns_32 (buf, p - buf);
+}
+
+/* The "emit_eq_goto" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_eq_goto (int *offset_p, int *size_p)
+{
+  arm_ax_emit_arm_cmp_eq_goto (INST_NE, offset_p, size_p);
+}
+
+/* The "emit_ne_goto" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_ne_goto (int *offset_p, int *size_p)
+{
+  arm_ax_emit_arm_cmp_eq_goto (INST_EQ, offset_p, size_p);
+}
+
+/* The "emit_lt_goto" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_lt_goto (int *offset_p, int *size_p)
+{
+  arm_ax_emit_arm_cmp_lgte_goto (INST_GE, offset_p, size_p, 0);
+}
+
+/* The "emit_le_goto" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_le_goto (int *offset_p, int *size_p)
+{
+  arm_ax_emit_arm_cmp_lgte_goto (INST_LT, offset_p, size_p, 1);
+}
+
+/* The "emit_gt_goto" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_gt_goto (int *offset_p, int *size_p)
+{
+  arm_ax_emit_arm_cmp_lgte_goto (INST_LE, offset_p, size_p, 1);
+}
+
+/* The "emit_ge_goto" emit_ops method for ARM.  */
+
+static void
+arm_ax_emit_arm_ge_goto (int *offset_p, int *size_p)
+{
+  arm_ax_emit_arm_cmp_lgte_goto (INST_LT, offset_p, size_p, 0);
+}
+
+/* The "emit_ops" structure for ARM.  */
+
+static struct emit_ops arm_ax_emit_arm_ops_impl =
+{
+  arm_ax_emit_arm_prologue,
+  arm_ax_emit_arm_epilogue,
+  arm_ax_emit_arm_add,
+  arm_ax_emit_arm_sub,
+  arm_ax_emit_arm_mul,
+  arm_ax_emit_arm_lsh,
+  arm_ax_emit_arm_rsh_signed,
+  arm_ax_emit_arm_rsh_unsigned,
+  arm_ax_emit_arm_ext,
+  arm_ax_emit_arm_log_not,
+  arm_ax_emit_arm_bit_and,
+  arm_ax_emit_arm_bit_or,
+  arm_ax_emit_arm_bit_xor,
+  arm_ax_emit_arm_bit_not,
+  arm_ax_emit_arm_equal,
+  arm_ax_emit_arm_less_signed,
+  arm_ax_emit_arm_less_unsigned,
+  arm_ax_emit_arm_ref,
+  arm_ax_emit_arm_if_goto,
+  arm_ax_emit_arm_goto,
+  arm_ax_arm_write_goto_address,
+  arm_ax_emit_arm_const,
+  arm_ax_emit_arm_call,
+  arm_ax_emit_arm_reg,
+  arm_ax_emit_arm_pop,
+  arm_ax_emit_arm_stack_flush,
+  arm_ax_emit_arm_zero_ext,
+  arm_ax_emit_arm_swap,
+  arm_ax_emit_arm_stack_adjust,
+  arm_ax_emit_arm_int_call_1,
+  arm_ax_emit_arm_void_call_2,
+  arm_ax_emit_arm_eq_goto,
+  arm_ax_emit_arm_ne_goto,
+  arm_ax_emit_arm_lt_goto,
+  arm_ax_emit_arm_le_goto,
+  arm_ax_emit_arm_gt_goto,
+  arm_ax_emit_arm_ge_goto,
+};
+
+/* Implementation of linux_target_ops method "emit_ops".  */
+
+static struct emit_ops *
+arm_ax_emit_arm_ops (void)
+{
+  return &arm_ax_emit_arm_ops_impl;
+}
+
 struct linux_target_ops the_low_target = {
   arm_arch_setup,
   arm_regs_info,
@@ -1979,7 +2765,7 @@ struct linux_target_ops the_low_target = {
   arm_supports_tracepoints,
   arm_get_thread_area, /* get_thread_area */
   arm_install_fast_tracepoint_jump_pad, /* install_fast_tracepoint_jump_pad */
-  NULL, /*emit_ops */
+  arm_ax_emit_arm_ops,
   arm_get_min_fast_tracepoint_insn_len, /* get_min_fast_tracepoint_insn_len */
   NULL, /* supports_range_stepping */
   arm_breakpoint_kind_from_current_state,
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 02/18] arm-tdep.c: Refactor displaced stepping relocation functions
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (4 preceding siblings ...)
  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 ` 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
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:41 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

Refactor so that arm_process_displaced_insn is the only function that
is specific to GDB.  All functions called from this function will
eventually be moved to common/, so they need to be free of anything
GDB-specific.

gdb/ChangeLog:

	arm-tdep.c (thumb_process_displaced_16bit_insn): Rename to...
	(thumb_16bit_relocate_insn): ... this, and return error code instead of
	throwing an error.
	(thumb_process_displaced_32bit_insn): Rename to...
	(thumb_32bit_relocate_insn): ... this, and return error code instead of
	throwing an error.
	(arm_relocate_insn): New function.
	(thumb_process_displaced_insn): Remove.
	(arm_process_displaced_insn): Refactor, extract some content to
	arm_relocate_insn, integrate content from thumb_process_displaced_insn.
---
 gdb/arm-tdep.c | 123 ++++++++++++++++++++++++++++++---------------------------
 1 file changed, 64 insertions(+), 59 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index d6e8858..5a0e247 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -7259,9 +7259,8 @@ thumb_copy_pop_pc_16bit (uint16_t insn1, struct arm_insn_reloc_data *data)
   return 0;
 }
 
-static void
-thumb_process_displaced_16bit_insn (uint16_t insn1,
-				    struct arm_insn_reloc_data *data)
+static int
+thumb_16bit_relocate_insn (uint16_t insn1, struct arm_insn_reloc_data *data)
 {
   unsigned short op_bit_12_15 = bits (insn1, 12, 15);
   unsigned short op_bit_10_11 = bits (insn1, 10, 11);
@@ -7350,9 +7349,7 @@ thumb_process_displaced_16bit_insn (uint16_t insn1,
       err = 1;
     }
 
-  if (err)
-    internal_error (__FILE__, __LINE__,
-		    _("thumb_process_displaced_16bit_insn: Instruction decode error"));
+  return err;
 }
 
 static int
@@ -7427,9 +7424,9 @@ decode_thumb_32bit_ld_mem_hints (uint16_t insn1, uint16_t insn2,
   return 0;
 }
 
-static void
-thumb_process_displaced_32bit_insn (uint16_t insn1, uint16_t insn2,
-				    struct arm_insn_reloc_data *data)
+static int
+thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
+			   struct arm_insn_reloc_data *data)
 {
   int err = 0;
   unsigned short op = bit (insn2, 15);
@@ -7541,34 +7538,41 @@ thumb_process_displaced_32bit_insn (uint16_t insn1, uint16_t insn2,
       err = 1;
     }
 
-  if (err)
-    internal_error (__FILE__, __LINE__,
-		    _("thumb_process_displaced_32bit_insn: Instruction decode error"));
+  return err;
 
 }
 
-static void
-thumb_process_displaced_insn (CORE_ADDR from, struct arm_insn_reloc_data *data)
+static int
+arm_relocate_insn (uint32_t insn, struct arm_insn_reloc_data *data)
 {
-  enum bfd_endian byte_order_for_code
-    = gdbarch_byte_order_for_code (data->gdbarch);
-  uint16_t insn1
-    = read_memory_unsigned_integer (from, 2, byte_order_for_code);
+  int err = 1;
 
-  if (debug_displaced)
-    fprintf_unfiltered (gdb_stdlog, "displaced: process thumb insn %.4x "
-			"at %.8lx\n", insn1, (unsigned long) from);
-
-  data->dsc->is_thumb = 1;
-  data->dsc->insn_size = thumb_insn_size (insn1);
-  if (thumb_insn_size (insn1) == 4)
+  if ((insn & 0xf0000000) == 0xf0000000)
+    err = arm_decode_unconditional (insn, data);
+  else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24))
     {
-      uint16_t insn2
-	= read_memory_unsigned_integer (from + 2, 2, byte_order_for_code);
-      thumb_process_displaced_32bit_insn (insn1, insn2, data);
+    case 0x0: case 0x1: case 0x2: case 0x3:
+      err = arm_decode_dp_misc (insn, data);
+      break;
+
+    case 0x4: case 0x5: case 0x6:
+      err = arm_decode_ld_st_word_ubyte (insn, data);
+      break;
+
+    case 0x7:
+      err = arm_decode_media (insn, data);
+      break;
+
+    case 0x8: case 0x9: case 0xa: case 0xb:
+      err = arm_decode_b_bl_ldmstm (insn, data);
+      break;
+
+    case 0xc: case 0xd: case 0xe: case 0xf:
+      err = arm_decode_svc_copro (insn, data);
+      break;
     }
-  else
-    thumb_process_displaced_16bit_insn (insn1, data);
+
+  return err;
 }
 
 void
@@ -7578,7 +7582,6 @@ arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
 {
   int err = 0;
   enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-  uint32_t insn;
   struct arm_insn_reloc_data reloc_data;
 
   reloc_data.dsc = dsc;
@@ -7593,40 +7596,42 @@ arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
   dsc->cleanup = NULL;
   dsc->wrote_to_pc = 0;
 
-  if (!displaced_in_arm_mode (regs))
-    return thumb_process_displaced_insn (from, &reloc_data);
+  if (displaced_in_arm_mode (regs))
+    {
+      uint32_t insn
+	= read_memory_unsigned_integer (from, 4, byte_order_for_code);
 
-  dsc->is_thumb = 0;
-  dsc->insn_size = 4;
-  insn = read_memory_unsigned_integer (from, 4, byte_order_for_code);
-  if (debug_displaced)
-    fprintf_unfiltered (gdb_stdlog, "displaced: stepping insn %.8lx "
-			"at %.8lx\n", (unsigned long) insn,
-			(unsigned long) from);
+      if (debug_displaced)
+        fprintf_unfiltered (gdb_stdlog, "displaced: stepping insn %.8lx "
+			    "at %.8lx\n", (unsigned long) insn,
+			    (unsigned long) from);
 
-  if ((insn & 0xf0000000) == 0xf0000000)
-    err = arm_decode_unconditional (insn, &reloc_data);
-  else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24))
-    {
-    case 0x0: case 0x1: case 0x2: case 0x3:
-      err = arm_decode_dp_misc (insn, &reloc_data);
-      break;
+      dsc->is_thumb = 0;
+      dsc->insn_size = 4;
 
-    case 0x4: case 0x5: case 0x6:
-      err = arm_decode_ld_st_word_ubyte (insn, &reloc_data);
-      break;
+      err = arm_relocate_insn (insn, &reloc_data);
+    }
+  else
+    {
+      uint16_t insn1
+	= read_memory_unsigned_integer (from, 2, byte_order_for_code);
+      unsigned int insn_size = thumb_insn_size (insn1);
 
-    case 0x7:
-      err = arm_decode_media (insn, &reloc_data);
-      break;
+      if (debug_displaced)
+        fprintf_unfiltered (gdb_stdlog, "displaced: process thumb insn %.4x "
+			    "at %.8lx\n", insn1, (unsigned long) from);
 
-    case 0x8: case 0x9: case 0xa: case 0xb:
-      err = arm_decode_b_bl_ldmstm (insn, &reloc_data);
-      break;
+      dsc->is_thumb = 1;
+      dsc->insn_size = insn_size;
 
-    case 0xc: case 0xd: case 0xe: case 0xf:
-      err = arm_decode_svc_copro (insn, &reloc_data);
-      break;
+      if (insn_size == 4)
+        {
+          uint16_t insn2
+	    = read_memory_unsigned_integer (from + 2, 2, byte_order_for_code);
+	  err = thumb_32bit_relocate_insn (insn1, insn2, &reloc_data);
+        }
+      else
+        err = thumb_16bit_relocate_insn (insn1, &reloc_data);
     }
 
   if (err)
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 01/18] arm-tdep.c: Replace arguments to decode function by a structure
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (13 preceding siblings ...)
  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 ` Antoine Tremblay
  2016-07-05 13:42 ` [PATCH v3 14/18] Fast tracepoint support for ARM on Linux Antoine Tremblay
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:42 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

This patch prepares the code so that the "decode" functions can be moved
out of arm-tdep.c.  Instead of passing the arguments that are necessary
for the relocation directly through parameters, we now carry a pointer
to a data structure containing those values.  This allows decoupling the
decoding phase, which will be shared with gdbserver, from the relocation
phrase, which is gdb specific.

gdb/ChangeLog:

	arm-tdep.c (arm_insn_reloc_data): New structure.
	(arm_copy_unmodified): Use struct arm_insn_reloc_data.
	(thumb_copy_unmodified_32bit): Likewise.
	(thumb_copy_unmodified_16bit): Likewise.
	(install_preload): Likewise.
	(arm_copy_preload): Likewise.
	(thumb2_copy_preload): Likewise.
	(install_preload_reg): Likewise.
	(arm_copy_preload_reg): Likewise.
	(install_copro_load_store): Likewise.
	(arm_copy_copro_load_store): Likewise.
	(thumb2_copy_copro_load_store): Likewise.
	(install_b_bl_blx): Likewise.
	(arm_copy_b_bl_blx): Likewise.
	(thumb2_copy_b_bl_blx): Likewise.
	(thumb_copy_b): Likewise.
	(install_bx_blx_reg): Likewise.
	(arm_copy_bx_blx_reg): Likewise.
	(thumb_copy_bx_blx_reg): Likewise.
	(arm_copy_alu_imm): Likewise.
	(thumb2_copy_alu_imm): Likewise.
	(install_alu_reg): Likewise.
	(arm_copy_alu_reg): Likewise.
	(thumb_copy_alu_reg): Likewise.
	(install_alu_shifted_reg): Likewise.
	(arm_copy_alu_shifted_reg): Likewise.
	(arm_copy_extra_ld_st): Likewise.
	(install_load_store): Likewise.
	(thumb2_copy_load_literal): Likewise.
	(thumb2_copy_load_reg_imm): Likewise.
	(arm_copy_ldr_str_ldrb_strb): Likewise.
	(arm_copy_block_xfer): Likewise.
	(thumb2_copy_block_xfer): Likewise.
	(install_svc): Likewise.
	(arm_copy_svc): Likewise.
	(thumb_copy_svc): Likewise.
	(arm_copy_undef): Likewise.
	(thumb_32bit_copy_undef): Likewise.
	(arm_copy_unpred): Likewise.
	(arm_decode_misc_memhint_neon): Likewise.
	(arm_decode_unconditional): Likewise.
	(arm_decode_miscellaneous): Likewise.
	(arm_decode_dp_misc): Likewise.
	(arm_decode_ld_st_word_ubyte): Likewise.
	(arm_decode_media): Likewise.
	(arm_decode_b_bl_ldmstm): Likewise.
	(arm_decode_ext_reg_ld_st): Likewise.
	(thumb2_decode_dp_shift_reg): Likewise.
	(thumb2_decode_ext_reg_ld_st): Likewise.
	(arm_decode_svc_copro): Likewise.
	(thumb2_decode_svc_copro): Likewise.
	(install_pc_relative): Likewise.
	(thumb_copy_pc_relative_16bit): Likewise.
	(thumb_decode_pc_relative_16bit): Likewise.
	(thumb_copy_pc_relative_32bit): Likewise.
	(thumb_copy_16bit_ldr_literal): Likewise.
	(thumb_copy_cbnz_cbz): Likewise.
	(thumb2_copy_table_branch): Likewise.
	(thumb_copy_pop_pc_16bit): Likewise.
	(thumb_process_displaced_16bit_insn): Likewise.
	(decode_thumb_32bit_ld_mem_hints): Likewise.
	(thumb_process_displaced_32bit_insn): Likewise.
	(thumb_process_displaced_insn): Likewise.
	(arm_process_displaced_insn): Likewise.
---
 gdb/arm-tdep.c | 888 +++++++++++++++++++++++++++------------------------------
 1 file changed, 420 insertions(+), 468 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index c20af82..d6e8858 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -4473,6 +4473,13 @@ arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
 #define ARM_NOP				0xe1a00000
 #define THUMB_NOP 0x4600
 
+struct arm_insn_reloc_data
+{
+  struct displaced_step_closure *dsc;
+  struct gdbarch *gdbarch;
+  struct regcache *regs;
+};
+
 /* Helper for register reads for displaced stepping.  In particular, this
    returns the PC as it would be seen by the instruction at its original
    location.  */
@@ -4681,24 +4688,25 @@ insn_references_pc (uint32_t insn, uint32_t bitmask)
    matter what address they are executed at: in those cases, use this.  */
 
 static int
-arm_copy_unmodified (struct gdbarch *gdbarch, uint32_t insn,
-		     const char *iname, struct displaced_step_closure *dsc)
+arm_copy_unmodified (uint32_t insn, const char *iname,
+		     struct arm_insn_reloc_data *data)
 {
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.8lx, "
 			"opcode/class '%s' unmodified\n", (unsigned long) insn,
 			iname);
 
-  dsc->modinsn[0] = insn;
+  data->dsc->modinsn[0] = insn;
 
   return 0;
 }
 
 static int
-thumb_copy_unmodified_32bit (struct gdbarch *gdbarch, uint16_t insn1,
-			     uint16_t insn2, const char *iname,
-			     struct displaced_step_closure *dsc)
+thumb_copy_unmodified_32bit (uint16_t insn1, uint16_t insn2, const char *iname,
+			     struct arm_insn_reloc_data *data)
 {
+  struct displaced_step_closure *dsc = data->dsc;
+
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.4x %.4x, "
 			"opcode/class '%s' unmodified\n", insn1, insn2,
@@ -4714,16 +4722,15 @@ thumb_copy_unmodified_32bit (struct gdbarch *gdbarch, uint16_t insn1,
 /* Copy 16-bit Thumb(Thumb and 16-bit Thumb-2) instruction without any
    modification.  */
 static int
-thumb_copy_unmodified_16bit (struct gdbarch *gdbarch, uint16_t insn,
-			     const char *iname,
-			     struct displaced_step_closure *dsc)
+thumb_copy_unmodified_16bit (uint16_t insn, const char *iname,
+			     struct arm_insn_reloc_data *data)
 {
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.4x, "
 			"opcode/class '%s' unmodified\n", insn,
 			iname);
 
-  dsc->modinsn[0] = insn;
+  data->dsc->modinsn[0] = insn;
 
   return 0;
 }
@@ -4740,10 +4747,12 @@ cleanup_preload (struct gdbarch *gdbarch,
 }
 
 static void
-install_preload (struct gdbarch *gdbarch, struct regcache *regs,
-		 struct displaced_step_closure *dsc, unsigned int rn)
+install_preload (struct arm_insn_reloc_data *data, unsigned int rn)
 {
   ULONGEST rn_val;
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
+
   /* Preload instructions:
 
      {pli/pld} [rn, #+/-imm]
@@ -4759,36 +4768,37 @@ install_preload (struct gdbarch *gdbarch, struct regcache *regs,
 }
 
 static int
-arm_copy_preload (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
-		  struct displaced_step_closure *dsc)
+arm_copy_preload (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int rn = bits (insn, 16, 19);
 
   if (!insn_references_pc (insn, 0x000f0000ul))
-    return arm_copy_unmodified (gdbarch, insn, "preload", dsc);
+    return arm_copy_unmodified (insn, "preload", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying preload insn %.8lx\n",
 			(unsigned long) insn);
 
-  dsc->modinsn[0] = insn & 0xfff0ffff;
+  data->dsc->modinsn[0] = insn & 0xfff0ffff;
 
-  install_preload (gdbarch, regs, dsc, rn);
+  install_preload (data, rn);
 
   return 0;
 }
 
 static int
-thumb2_copy_preload (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
-		     struct regcache *regs, struct displaced_step_closure *dsc)
+thumb2_copy_preload (uint16_t insn1, uint16_t insn2,
+		     struct arm_insn_reloc_data *data)
 {
   unsigned int rn = bits (insn1, 0, 3);
   unsigned int u_bit = bit (insn1, 7);
   int imm12 = bits (insn2, 0, 11);
   ULONGEST pc_val;
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   if (rn != ARM_PC_REGNUM)
-    return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2, "preload", dsc);
+    return thumb_copy_unmodified_32bit (insn1, insn2, "preload", data);
 
   /* PC is only allowed to use in PLI (immediate,literal) Encoding T3, and
      PLD (literal) Encoding T1.  */
@@ -4829,11 +4839,12 @@ thumb2_copy_preload (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
 /* Preload instructions with register offset.  */
 
 static void
-install_preload_reg(struct gdbarch *gdbarch, struct regcache *regs,
-		    struct displaced_step_closure *dsc, unsigned int rn,
-		    unsigned int rm)
+install_preload_reg (struct arm_insn_reloc_data *data, unsigned int rn,
+		     unsigned int rm)
 {
   ULONGEST rn_val, rm_val;
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   /* Preload register-offset instructions:
 
@@ -4853,24 +4864,22 @@ install_preload_reg(struct gdbarch *gdbarch, struct regcache *regs,
 }
 
 static int
-arm_copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn,
-		      struct regcache *regs,
-		      struct displaced_step_closure *dsc)
+arm_copy_preload_reg (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int rn = bits (insn, 16, 19);
   unsigned int rm = bits (insn, 0, 3);
 
 
   if (!insn_references_pc (insn, 0x000f000ful))
-    return arm_copy_unmodified (gdbarch, insn, "preload reg", dsc);
+    return arm_copy_unmodified (insn, "preload reg", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying preload insn %.8lx\n",
 			(unsigned long) insn);
 
-  dsc->modinsn[0] = (insn & 0xfff0fff0) | 0x1;
+  data->dsc->modinsn[0] = (insn & 0xfff0fff0) | 0x1;
 
-  install_preload_reg (gdbarch, regs, dsc, rn, rm);
+  install_preload_reg (data, rn, rm);
   return 0;
 }
 
@@ -4890,11 +4899,12 @@ cleanup_copro_load_store (struct gdbarch *gdbarch,
 }
 
 static void
-install_copro_load_store (struct gdbarch *gdbarch, struct regcache *regs,
-			  struct displaced_step_closure *dsc,
-			  int writeback, unsigned int rn)
+install_copro_load_store (struct arm_insn_reloc_data *data, int writeback,
+			  unsigned int rn)
 {
   ULONGEST rn_val;
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   /* Coprocessor load/store instructions:
 
@@ -4917,36 +4927,33 @@ install_copro_load_store (struct gdbarch *gdbarch, struct regcache *regs,
 }
 
 static int
-arm_copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn,
-			   struct regcache *regs,
-			   struct displaced_step_closure *dsc)
+arm_copy_copro_load_store (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int rn = bits (insn, 16, 19);
 
   if (!insn_references_pc (insn, 0x000f0000ul))
-    return arm_copy_unmodified (gdbarch, insn, "copro load/store", dsc);
+    return arm_copy_unmodified (insn, "copro load/store", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying coprocessor "
 			"load/store insn %.8lx\n", (unsigned long) insn);
 
-  dsc->modinsn[0] = insn & 0xfff0ffff;
+  data->dsc->modinsn[0] = insn & 0xfff0ffff;
 
-  install_copro_load_store (gdbarch, regs, dsc, bit (insn, 25), rn);
+  install_copro_load_store (data, bit (insn, 25), rn);
 
   return 0;
 }
 
 static int
-thumb2_copy_copro_load_store (struct gdbarch *gdbarch, uint16_t insn1,
-			      uint16_t insn2, struct regcache *regs,
-			      struct displaced_step_closure *dsc)
+thumb2_copy_copro_load_store (uint16_t insn1, uint16_t insn2,
+			      struct arm_insn_reloc_data *data)
 {
   unsigned int rn = bits (insn1, 0, 3);
+  struct displaced_step_closure *dsc = data->dsc;
 
   if (rn != ARM_PC_REGNUM)
-    return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-					"copro load/store", dsc);
+    return thumb_copy_unmodified_32bit (insn1, insn2, "copro load/store", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying coprocessor "
@@ -4958,7 +4965,7 @@ thumb2_copy_copro_load_store (struct gdbarch *gdbarch, uint16_t insn1,
 
   /* This function is called for copying instruction LDC/LDC2/VLDR, which
      doesn't support writeback, so pass 0.  */
-  install_copro_load_store (gdbarch, regs, dsc, 0, rn);
+  install_copro_load_store (data, 0, rn);
 
   return 0;
 }
@@ -4998,9 +5005,8 @@ cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs,
 /* Copy B/BL/BLX instructions with immediate destinations.  */
 
 static void
-install_b_bl_blx (struct gdbarch *gdbarch, struct regcache *regs,
-		  struct displaced_step_closure *dsc,
-		  unsigned int cond, int exchange, int link, long offset)
+install_b_bl_blx (struct arm_insn_reloc_data *data, unsigned int cond,
+		  int exchange, int link, long offset)
 {
   /* Implement "BL<cond> <label>" as:
 
@@ -5009,6 +5015,7 @@ install_b_bl_blx (struct gdbarch *gdbarch, struct regcache *regs,
      Cleanup: if (condition true) { r14 <- pc; pc <- label }.
 
      B<cond> similar, but don't set r14 in cleanup.  */
+  struct displaced_step_closure *dsc = data->dsc;
 
   dsc->u.branch.cond = cond;
   dsc->u.branch.link = link;
@@ -5027,8 +5034,7 @@ install_b_bl_blx (struct gdbarch *gdbarch, struct regcache *regs,
   dsc->cleanup = &cleanup_branch;
 }
 static int
-arm_copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn,
-		   struct regcache *regs, struct displaced_step_closure *dsc)
+arm_copy_b_bl_blx (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int cond = bits (insn, 28, 31);
   int exchange = (cond == 0xf);
@@ -5049,16 +5055,15 @@ arm_copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn,
   if (bit (offset, 25))
     offset = offset | ~0x3ffffff;
 
-  dsc->modinsn[0] = ARM_NOP;
+  data->dsc->modinsn[0] = ARM_NOP;
 
-  install_b_bl_blx (gdbarch, regs, dsc, cond, exchange, link, offset);
+  install_b_bl_blx (data, cond, exchange, link, offset);
   return 0;
 }
 
 static int
-thumb2_copy_b_bl_blx (struct gdbarch *gdbarch, uint16_t insn1,
-		      uint16_t insn2, struct regcache *regs,
-		      struct displaced_step_closure *dsc)
+thumb2_copy_b_bl_blx (uint16_t insn1, uint16_t insn2,
+		      struct arm_insn_reloc_data *data)
 {
   int link = bit (insn2, 14);
   int exchange = link && !bit (insn2, 12);
@@ -5104,20 +5109,20 @@ thumb2_copy_b_bl_blx (struct gdbarch *gdbarch, uint16_t insn1,
 			link ? (exchange) ? "blx" : "bl" : "b",
 			insn1, insn2, offset);
 
-  dsc->modinsn[0] = THUMB_NOP;
+  data->dsc->modinsn[0] = THUMB_NOP;
 
-  install_b_bl_blx (gdbarch, regs, dsc, cond, exchange, link, offset);
+  install_b_bl_blx (data, cond, exchange, link, offset);
   return 0;
 }
 
 /* Copy B Thumb instructions.  */
 static int
-thumb_copy_b (struct gdbarch *gdbarch, uint16_t insn,
-	      struct displaced_step_closure *dsc)
+thumb_copy_b (uint16_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int cond = 0;
   int offset = 0;
   unsigned short bit_12_15 = bits (insn, 12, 15);
+  struct displaced_step_closure *dsc = data->dsc;
   CORE_ADDR from = dsc->insn_addr;
 
   if (bit_12_15 == 0xd)
@@ -5152,8 +5157,7 @@ thumb_copy_b (struct gdbarch *gdbarch, uint16_t insn,
 /* Copy BX/BLX with register-specified destinations.  */
 
 static void
-install_bx_blx_reg (struct gdbarch *gdbarch, struct regcache *regs,
-		    struct displaced_step_closure *dsc, int link,
+install_bx_blx_reg (struct arm_insn_reloc_data *data, int link,
 		    unsigned int cond, unsigned int rm)
 {
   /* Implement {BX,BLX}<cond> <reg>" as:
@@ -5163,8 +5167,9 @@ install_bx_blx_reg (struct gdbarch *gdbarch, struct regcache *regs,
      Cleanup: if (condition true) { r14 <- pc; pc <- dest; }.
 
      Don't set r14 in cleanup for BX.  */
+  struct displaced_step_closure *dsc = data->dsc;
 
-  dsc->u.branch.dest = displaced_read_reg (regs, dsc, rm);
+  dsc->u.branch.dest = displaced_read_reg (data->regs, data->dsc, rm);
 
   dsc->u.branch.cond = cond;
   dsc->u.branch.link = link;
@@ -5175,8 +5180,7 @@ install_bx_blx_reg (struct gdbarch *gdbarch, struct regcache *regs,
 }
 
 static int
-arm_copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn,
-		     struct regcache *regs, struct displaced_step_closure *dsc)
+arm_copy_bx_blx_reg (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int cond = bits (insn, 28, 31);
   /* BX:  x12xxx1x
@@ -5188,16 +5192,14 @@ arm_copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn,
     fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.8lx",
 			(unsigned long) insn);
 
-  dsc->modinsn[0] = ARM_NOP;
+  data->dsc->modinsn[0] = ARM_NOP;
 
-  install_bx_blx_reg (gdbarch, regs, dsc, link, cond, rm);
+  install_bx_blx_reg (data, link, cond, rm);
   return 0;
 }
 
 static int
-thumb_copy_bx_blx_reg (struct gdbarch *gdbarch, uint16_t insn,
-		       struct regcache *regs,
-		       struct displaced_step_closure *dsc)
+thumb_copy_bx_blx_reg (uint16_t insn, struct arm_insn_reloc_data *data)
 {
   int link = bit (insn, 7);
   unsigned int rm = bits (insn, 3, 6);
@@ -5206,9 +5208,9 @@ thumb_copy_bx_blx_reg (struct gdbarch *gdbarch, uint16_t insn,
     fprintf_unfiltered (gdb_stdlog, "displaced: copying insn %.4x",
 			(unsigned short) insn);
 
-  dsc->modinsn[0] = THUMB_NOP;
+  data->dsc->modinsn[0] = THUMB_NOP;
 
-  install_bx_blx_reg (gdbarch, regs, dsc, link, INST_AL, rm);
+  install_bx_blx_reg (data, link, INST_AL, rm);
 
   return 0;
 }
@@ -5227,8 +5229,7 @@ cleanup_alu_imm (struct gdbarch *gdbarch,
 }
 
 static int
-arm_copy_alu_imm (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
-		  struct displaced_step_closure *dsc)
+arm_copy_alu_imm (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int rn = bits (insn, 16, 19);
   unsigned int rd = bits (insn, 12, 15);
@@ -5237,7 +5238,7 @@ arm_copy_alu_imm (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
   ULONGEST rd_val, rn_val;
 
   if (!insn_references_pc (insn, 0x000ff000ul))
-    return arm_copy_unmodified (gdbarch, insn, "ALU immediate", dsc);
+    return arm_copy_unmodified (insn, "ALU immediate", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying immediate %s insn "
@@ -5256,32 +5257,33 @@ arm_copy_alu_imm (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
      Cleanup: rd <- r0; r0 <- tmp1; r1 <- tmp2
   */
 
-  dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
-  dsc->tmp[1] = displaced_read_reg (regs, dsc, 1);
-  rn_val = displaced_read_reg (regs, dsc, rn);
-  rd_val = displaced_read_reg (regs, dsc, rd);
-  displaced_write_reg (regs, dsc, 0, rd_val, CANNOT_WRITE_PC);
-  displaced_write_reg (regs, dsc, 1, rn_val, CANNOT_WRITE_PC);
-  dsc->rd = rd;
+  data->dsc->tmp[0] = displaced_read_reg (data->regs, data->dsc, 0);
+  data->dsc->tmp[1] = displaced_read_reg (data->regs, data->dsc, 1);
+  rn_val = displaced_read_reg (data->regs, data->dsc, rn);
+  rd_val = displaced_read_reg (data->regs, data->dsc, rd);
+  displaced_write_reg (data->regs, data->dsc, 0, rd_val, CANNOT_WRITE_PC);
+  displaced_write_reg (data->regs, data->dsc, 1, rn_val, CANNOT_WRITE_PC);
+  data->dsc->rd = rd;
 
   if (is_mov)
-    dsc->modinsn[0] = insn & 0xfff00fff;
+    data->dsc->modinsn[0] = insn & 0xfff00fff;
   else
-    dsc->modinsn[0] = (insn & 0xfff00fff) | 0x10000;
+    data->dsc->modinsn[0] = (insn & 0xfff00fff) | 0x10000;
 
-  dsc->cleanup = &cleanup_alu_imm;
+  data->dsc->cleanup = &cleanup_alu_imm;
 
   return 0;
 }
 
 static int
-thumb2_copy_alu_imm (struct gdbarch *gdbarch, uint16_t insn1,
-		     uint16_t insn2, struct regcache *regs,
-		     struct displaced_step_closure *dsc)
+thumb2_copy_alu_imm (uint16_t insn1, uint16_t insn2,
+		     struct arm_insn_reloc_data *data)
 {
   unsigned int op = bits (insn1, 5, 8);
   unsigned int rn, rm, rd;
   ULONGEST rd_val, rn_val;
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   rn = bits (insn1, 0, 3); /* Rn */
   rm = bits (insn2, 0, 3); /* Rm */
@@ -5291,7 +5293,7 @@ thumb2_copy_alu_imm (struct gdbarch *gdbarch, uint16_t insn1,
   gdb_assert (op == 0x2 && rn == 0xf);
 
   if (rm != ARM_PC_REGNUM && rd != ARM_PC_REGNUM)
-    return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2, "ALU imm", dsc);
+    return thumb_copy_unmodified_32bit (insn1, insn2, "ALU imm", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying reg %s insn %.4x%.4x\n",
@@ -5344,11 +5346,12 @@ cleanup_alu_reg (struct gdbarch *gdbarch,
 }
 
 static void
-install_alu_reg (struct gdbarch *gdbarch, struct regcache *regs,
-		 struct displaced_step_closure *dsc,
-		 unsigned int rd, unsigned int rn, unsigned int rm)
+install_alu_reg (struct arm_insn_reloc_data *data, unsigned int rd,
+		 unsigned int rn, unsigned int rm)
 {
   ULONGEST rd_val, rn_val, rm_val;
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   /* Instruction is of form:
 
@@ -5377,33 +5380,30 @@ install_alu_reg (struct gdbarch *gdbarch, struct regcache *regs,
 }
 
 static int
-arm_copy_alu_reg (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
-		  struct displaced_step_closure *dsc)
+arm_copy_alu_reg (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int op = bits (insn, 21, 24);
   int is_mov = (op == 0xd);
 
   if (!insn_references_pc (insn, 0x000ff00ful))
-    return arm_copy_unmodified (gdbarch, insn, "ALU reg", dsc);
+    return arm_copy_unmodified (insn, "ALU reg", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying reg %s insn %.8lx\n",
 			is_mov ? "move" : "ALU", (unsigned long) insn);
 
   if (is_mov)
-    dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x2;
+    data->dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x2;
   else
-    dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x10002;
+    data->dsc->modinsn[0] = (insn & 0xfff00ff0) | 0x10002;
 
-  install_alu_reg (gdbarch, regs, dsc, bits (insn, 12, 15), bits (insn, 16, 19),
+  install_alu_reg (data, bits (insn, 12, 15), bits (insn, 16, 19),
 		   bits (insn, 0, 3));
   return 0;
 }
 
 static int
-thumb_copy_alu_reg (struct gdbarch *gdbarch, uint16_t insn,
-		    struct regcache *regs,
-		    struct displaced_step_closure *dsc)
+thumb_copy_alu_reg (uint16_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned rm, rd;
 
@@ -5411,15 +5411,15 @@ thumb_copy_alu_reg (struct gdbarch *gdbarch, uint16_t insn,
   rd = (bit (insn, 7) << 3) | bits (insn, 0, 2);
 
   if (rd != ARM_PC_REGNUM && rm != ARM_PC_REGNUM)
-    return thumb_copy_unmodified_16bit (gdbarch, insn, "ALU reg", dsc);
+    return thumb_copy_unmodified_16bit (insn, "ALU reg", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying ALU reg insn %.4x\n",
 			(unsigned short) insn);
 
-  dsc->modinsn[0] = ((insn & 0xff00) | 0x10);
+  data->dsc->modinsn[0] = ((insn & 0xff00) | 0x10);
 
-  install_alu_reg (gdbarch, regs, dsc, rd, rd, rm);
+  install_alu_reg (data, rd, rd, rm);
 
   return 0;
 }
@@ -5441,13 +5441,14 @@ cleanup_alu_shifted_reg (struct gdbarch *gdbarch,
 }
 
 static void
-install_alu_shifted_reg (struct gdbarch *gdbarch, struct regcache *regs,
-			 struct displaced_step_closure *dsc,
-			 unsigned int rd, unsigned int rn, unsigned int rm,
-			 unsigned rs)
+install_alu_shifted_reg (struct arm_insn_reloc_data *data, unsigned int rd,
+			 unsigned int rn, unsigned int rm, unsigned rs)
 {
   int i;
   ULONGEST rd_val, rn_val, rm_val, rs_val;
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
+
 
   /* Instruction is of form:
 
@@ -5479,16 +5480,14 @@ install_alu_shifted_reg (struct gdbarch *gdbarch, struct regcache *regs,
 }
 
 static int
-arm_copy_alu_shifted_reg (struct gdbarch *gdbarch, uint32_t insn,
-			  struct regcache *regs,
-			  struct displaced_step_closure *dsc)
+arm_copy_alu_shifted_reg (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int op = bits (insn, 21, 24);
   int is_mov = (op == 0xd);
   unsigned int rd, rn, rm, rs;
 
   if (!insn_references_pc (insn, 0x000fff0ful))
-    return arm_copy_unmodified (gdbarch, insn, "ALU shifted reg", dsc);
+    return arm_copy_unmodified (insn, "ALU shifted reg", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying shifted reg %s insn "
@@ -5501,11 +5500,11 @@ arm_copy_alu_shifted_reg (struct gdbarch *gdbarch, uint32_t insn,
   rd = bits (insn, 12, 15);
 
   if (is_mov)
-    dsc->modinsn[0] = (insn & 0xfff000f0) | 0x302;
+    data->dsc->modinsn[0] = (insn & 0xfff000f0) | 0x302;
   else
-    dsc->modinsn[0] = (insn & 0xfff000f0) | 0x10302;
+    data->dsc->modinsn[0] = (insn & 0xfff000f0) | 0x10302;
 
-  install_alu_shifted_reg (gdbarch, regs, dsc, rd, rn, rm, rs);
+  install_alu_shifted_reg (data, rd, rn, rm, rs);
 
   return 0;
 }
@@ -5565,8 +5564,8 @@ cleanup_store (struct gdbarch *gdbarch, struct regcache *regs,
    transfers, which have a different encoding to byte/word transfers.  */
 
 static int
-arm_copy_extra_ld_st (struct gdbarch *gdbarch, uint32_t insn, int unprivileged,
-		      struct regcache *regs, struct displaced_step_closure *dsc)
+arm_copy_extra_ld_st (uint32_t insn, struct arm_insn_reloc_data *data,
+		      int unprivileged)
 {
   unsigned int op1 = bits (insn, 20, 24);
   unsigned int op2 = bits (insn, 5, 6);
@@ -5578,9 +5577,11 @@ arm_copy_extra_ld_st (struct gdbarch *gdbarch, uint32_t insn, int unprivileged,
   int immed = (op1 & 0x4) != 0;
   int opcode;
   ULONGEST rt_val, rt_val2 = 0, rn_val, rm_val = 0;
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   if (!insn_references_pc (insn, 0x000ff00ful))
-    return arm_copy_unmodified (gdbarch, insn, "extra load/store", dsc);
+    return arm_copy_unmodified (insn, "extra load/store", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying %sextra load/store "
@@ -5639,12 +5640,13 @@ arm_copy_extra_ld_st (struct gdbarch *gdbarch, uint32_t insn, int unprivileged,
 /* Copy byte/half word/word loads and stores.  */
 
 static void
-install_load_store (struct gdbarch *gdbarch, struct regcache *regs,
-		    struct displaced_step_closure *dsc, int load,
-		    int immed, int writeback, int size, int usermode,
-		    int rt, int rm, int rn)
+install_load_store (struct arm_insn_reloc_data *data, int load, int immed,
+		    int writeback, int size, int usermode, int rt, int rm,
+		    int rn)
 {
   ULONGEST rt_val, rn_val, rm_val = 0;
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   dsc->tmp[0] = displaced_read_reg (regs, dsc, 0);
   dsc->tmp[2] = displaced_read_reg (regs, dsc, 2);
@@ -5694,14 +5696,15 @@ install_load_store (struct gdbarch *gdbarch, struct regcache *regs,
 
 
 static int
-thumb2_copy_load_literal (struct gdbarch *gdbarch, uint16_t insn1,
-			  uint16_t insn2, struct regcache *regs,
-			  struct displaced_step_closure *dsc, int size)
+thumb2_copy_load_literal (uint16_t insn1, uint16_t insn2,
+			  struct arm_insn_reloc_data *data, int size)
 {
   unsigned int u_bit = bit (insn1, 7);
   unsigned int rt = bits (insn2, 12, 15);
   int imm12 = bits (insn2, 0, 11);
   ULONGEST pc_val;
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog,
@@ -5750,28 +5753,27 @@ thumb2_copy_load_literal (struct gdbarch *gdbarch, uint16_t insn1,
 }
 
 static int
-thumb2_copy_load_reg_imm (struct gdbarch *gdbarch, uint16_t insn1,
-			  uint16_t insn2, struct regcache *regs,
-			  struct displaced_step_closure *dsc,
-			  int writeback, int immed)
+thumb2_copy_load_reg_imm (uint16_t insn1, uint16_t insn2,
+			  struct arm_insn_reloc_data *data, int writeback,
+			  int immed)
 {
   unsigned int rt = bits (insn2, 12, 15);
   unsigned int rn = bits (insn1, 0, 3);
   unsigned int rm = bits (insn2, 0, 3);  /* Only valid if !immed.  */
+  struct displaced_step_closure *dsc = data->dsc;
+
   /* In LDR (register), there is also a register Rm, which is not allowed to
      be PC, so we don't have to check it.  */
 
   if (rt != ARM_PC_REGNUM && rn != ARM_PC_REGNUM)
-    return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2, "load",
-					dsc);
+    return thumb_copy_unmodified_32bit (insn1, insn2, "load", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog,
 			"displaced: copying ldr r%d [r%d] insn %.4x%.4x\n",
 			 rt, rn, insn1, insn2);
 
-  install_load_store (gdbarch, regs, dsc, 1, immed, writeback, 4,
-		      0, rt, rm, rn);
+  install_load_store (data, 1, immed, writeback, 4, 0, rt, rm, rn);
 
   dsc->u.ldst.restore_r4 = 0;
 
@@ -5799,9 +5801,7 @@ thumb2_copy_load_reg_imm (struct gdbarch *gdbarch, uint16_t insn1,
 
 
 static int
-arm_copy_ldr_str_ldrb_strb (struct gdbarch *gdbarch, uint32_t insn,
-			    struct regcache *regs,
-			    struct displaced_step_closure *dsc,
+arm_copy_ldr_str_ldrb_strb (uint32_t insn, struct arm_insn_reloc_data *data,
 			    int load, int size, int usermode)
 {
   int immed = !bit (insn, 25);
@@ -5809,9 +5809,10 @@ arm_copy_ldr_str_ldrb_strb (struct gdbarch *gdbarch, uint32_t insn,
   unsigned int rt = bits (insn, 12, 15);
   unsigned int rn = bits (insn, 16, 19);
   unsigned int rm = bits (insn, 0, 3);  /* Only valid if !immed.  */
+  struct displaced_step_closure *dsc = data->dsc;
 
   if (!insn_references_pc (insn, 0x000ff00ful))
-    return arm_copy_unmodified (gdbarch, insn, "load/store", dsc);
+    return arm_copy_unmodified (insn, "load/store", data);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog,
@@ -5821,8 +5822,7 @@ arm_copy_ldr_str_ldrb_strb (struct gdbarch *gdbarch, uint32_t insn,
 			rt, rn,
 			(unsigned long) insn);
 
-  install_load_store (gdbarch, regs, dsc, load, immed, writeback, size,
-		      usermode, rt, rm, rn);
+  install_load_store (data, load, immed, writeback, size, usermode, rt, rm, rn);
 
   if (load || rt != ARM_PC_REGNUM)
     {
@@ -6075,9 +6075,7 @@ cleanup_block_load_pc (struct gdbarch *gdbarch,
    in user-level code (in particular exception return, ldm rn, {...pc}^).  */
 
 static int
-arm_copy_block_xfer (struct gdbarch *gdbarch, uint32_t insn,
-		     struct regcache *regs,
-		     struct displaced_step_closure *dsc)
+arm_copy_block_xfer (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   int load = bit (insn, 20);
   int user = bit (insn, 22);
@@ -6085,17 +6083,19 @@ arm_copy_block_xfer (struct gdbarch *gdbarch, uint32_t insn,
   int before = bit (insn, 24);
   int writeback = bit (insn, 21);
   int rn = bits (insn, 16, 19);
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   /* Block transfers which don't mention PC can be run directly
      out-of-line.  */
   if (rn != ARM_PC_REGNUM && (insn & 0x8000) == 0)
-    return arm_copy_unmodified (gdbarch, insn, "ldm/stm", dsc);
+    return arm_copy_unmodified (insn, "ldm/stm", data);
 
   if (rn == ARM_PC_REGNUM)
     {
       warning (_("displaced: Unpredictable LDM or STM with "
 		 "base register r15"));
-      return arm_copy_unmodified (gdbarch, insn, "unpredictable ldm/stm", dsc);
+      return arm_copy_unmodified (insn, "unpredictable ldm/stm", data);
     }
 
   if (debug_displaced)
@@ -6189,25 +6189,26 @@ arm_copy_block_xfer (struct gdbarch *gdbarch, uint32_t insn,
 }
 
 static int
-thumb2_copy_block_xfer (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
-			struct regcache *regs,
-			struct displaced_step_closure *dsc)
+thumb2_copy_block_xfer (uint16_t insn1, uint16_t insn2,
+			struct arm_insn_reloc_data *data)
 {
   int rn = bits (insn1, 0, 3);
   int load = bit (insn1, 4);
   int writeback = bit (insn1, 5);
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   /* Block transfers which don't mention PC can be run directly
      out-of-line.  */
   if (rn != ARM_PC_REGNUM && (insn2 & 0x8000) == 0)
-    return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2, "ldm/stm", dsc);
+    return thumb_copy_unmodified_32bit (insn1, insn2, "ldm/stm", data);
 
   if (rn == ARM_PC_REGNUM)
     {
       warning (_("displaced: Unpredictable LDM or STM with "
 		 "base register r15"));
-      return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-					  "unpredictable ldm/stm", dsc);
+      return thumb_copy_unmodified_32bit (insn1, insn2, "unpredictable ldm/stm",
+					  data);
     }
 
   if (debug_displaced)
@@ -6360,8 +6361,7 @@ cleanup_svc (struct gdbarch *gdbarch, struct regcache *regs,
 /* Common copy routine for svc instruciton.  */
 
 static int
-install_svc (struct gdbarch *gdbarch, struct regcache *regs,
-	     struct displaced_step_closure *dsc)
+install_svc (struct arm_insn_reloc_data *data)
 {
   /* Preparation: none.
      Insn: unmodified svc.
@@ -6369,6 +6369,10 @@ install_svc (struct gdbarch *gdbarch, struct regcache *regs,
 
   /* Pretend we wrote to the PC, so cleanup doesn't set PC to the next
      instruction.  */
+  struct displaced_step_closure *dsc = data->dsc;
+  struct gdbarch *gdbarch = data->gdbarch;
+  struct regcache *regs = data->regs;
+
   dsc->wrote_to_pc = 1;
 
   /* Allow OS-specific code to override SVC handling.  */
@@ -6382,53 +6386,51 @@ install_svc (struct gdbarch *gdbarch, struct regcache *regs,
 }
 
 static int
-arm_copy_svc (struct gdbarch *gdbarch, uint32_t insn,
-	      struct regcache *regs, struct displaced_step_closure *dsc)
+arm_copy_svc (uint32_t insn, struct arm_insn_reloc_data *data)
 {
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying svc insn %.8lx\n",
 			(unsigned long) insn);
 
-  dsc->modinsn[0] = insn;
+  data->dsc->modinsn[0] = insn;
 
-  return install_svc (gdbarch, regs, dsc);
+  return install_svc (data);
 }
 
 static int
-thumb_copy_svc (struct gdbarch *gdbarch, uint16_t insn,
-		struct regcache *regs, struct displaced_step_closure *dsc)
+thumb_copy_svc (uint16_t insn, struct arm_insn_reloc_data *data)
 {
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying svc insn %.4x\n",
 			insn);
 
-  dsc->modinsn[0] = insn;
+  data->dsc->modinsn[0] = insn;
 
-  return install_svc (gdbarch, regs, dsc);
+  return install_svc (data);
 }
 
 /* Copy undefined instructions.  */
 
 static int
-arm_copy_undef (struct gdbarch *gdbarch, uint32_t insn,
-		struct displaced_step_closure *dsc)
+arm_copy_undef (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog,
 			"displaced: copying undefined insn %.8lx\n",
 			(unsigned long) insn);
 
-  dsc->modinsn[0] = insn;
+  data->dsc->modinsn[0] = insn;
 
   return 0;
 }
 
 static int
-thumb_32bit_copy_undef (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
-                       struct displaced_step_closure *dsc)
+thumb_32bit_copy_undef (uint16_t insn1, uint16_t insn2,
+			struct arm_insn_reloc_data *data)
 {
+  struct displaced_step_closure *dsc = data->dsc;
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying undefined insn "
@@ -6445,14 +6447,13 @@ thumb_32bit_copy_undef (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
 /* Copy unpredictable instructions.  */
 
 static int
-arm_copy_unpred (struct gdbarch *gdbarch, uint32_t insn,
-		 struct displaced_step_closure *dsc)
+arm_copy_unpred (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying unpredictable insn "
 			"%.8lx\n", (unsigned long) insn);
 
-  dsc->modinsn[0] = insn;
+  data->dsc->modinsn[0] = insn;
 
   return 0;
 }
@@ -6461,96 +6462,91 @@ arm_copy_unpred (struct gdbarch *gdbarch, uint32_t insn,
    the presentation in the ARM ARM.  */
 
 static int
-arm_decode_misc_memhint_neon (struct gdbarch *gdbarch, uint32_t insn,
-			      struct regcache *regs,
-			      struct displaced_step_closure *dsc)
+arm_decode_misc_memhint_neon (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7);
   unsigned int rn = bits (insn, 16, 19);
 
   if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0xe) == 0x0)
-    return arm_copy_unmodified (gdbarch, insn, "cps", dsc);
+    return arm_copy_unmodified (insn, "cps", data);
   else if (op1 == 0x10 && op2 == 0x0 && (rn & 0xe) == 0x1)
-    return arm_copy_unmodified (gdbarch, insn, "setend", dsc);
+    return arm_copy_unmodified (insn, "setend", data);
   else if ((op1 & 0x60) == 0x20)
-    return arm_copy_unmodified (gdbarch, insn, "neon dataproc", dsc);
+    return arm_copy_unmodified (insn, "neon dataproc", data);
   else if ((op1 & 0x71) == 0x40)
-    return arm_copy_unmodified (gdbarch, insn, "neon elt/struct load/store",
-				dsc);
+    return arm_copy_unmodified (insn, "neon elt/struct load/store", data);
   else if ((op1 & 0x77) == 0x41)
-    return arm_copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
+    return arm_copy_unmodified (insn, "unallocated mem hint", data);
   else if ((op1 & 0x77) == 0x45)
-    return arm_copy_preload (gdbarch, insn, regs, dsc);  /* pli.  */
+    return arm_copy_preload (insn, data);  /* pli.  */
   else if ((op1 & 0x77) == 0x51)
     {
       if (rn != 0xf)
-	return arm_copy_preload (gdbarch, insn, regs, dsc);  /* pld/pldw.  */
+	return arm_copy_preload (insn, data);  /* pld/pldw.  */
       else
-	return arm_copy_unpred (gdbarch, insn, dsc);
+	return arm_copy_unpred (insn, data);
     }
   else if ((op1 & 0x77) == 0x55)
-    return arm_copy_preload (gdbarch, insn, regs, dsc);  /* pld/pldw.  */
+    return arm_copy_preload (insn, data);  /* pld/pldw.  */
   else if (op1 == 0x57)
     switch (op2)
       {
-      case 0x1: return arm_copy_unmodified (gdbarch, insn, "clrex", dsc);
-      case 0x4: return arm_copy_unmodified (gdbarch, insn, "dsb", dsc);
-      case 0x5: return arm_copy_unmodified (gdbarch, insn, "dmb", dsc);
-      case 0x6: return arm_copy_unmodified (gdbarch, insn, "isb", dsc);
-      default: return arm_copy_unpred (gdbarch, insn, dsc);
+      case 0x1: return arm_copy_unmodified (insn, "clrex", data);
+      case 0x4: return arm_copy_unmodified (insn, "dsb", data);
+      case 0x5: return arm_copy_unmodified (insn, "dmb", data);
+      case 0x6: return arm_copy_unmodified (insn, "isb", data);
+      default: return arm_copy_unpred (insn, data);
       }
   else if ((op1 & 0x63) == 0x43)
-    return arm_copy_unpred (gdbarch, insn, dsc);
+    return arm_copy_unpred (insn, data);
   else if ((op2 & 0x1) == 0x0)
     switch (op1 & ~0x80)
       {
       case 0x61:
-	return arm_copy_unmodified (gdbarch, insn, "unallocated mem hint", dsc);
+	return arm_copy_unmodified (insn, "unallocated mem hint", data);
       case 0x65:
-	return arm_copy_preload_reg (gdbarch, insn, regs, dsc);  /* pli reg.  */
+	return arm_copy_preload_reg (insn, data);  /* pli reg.  */
       case 0x71: case 0x75:
         /* pld/pldw reg.  */
-	return arm_copy_preload_reg (gdbarch, insn, regs, dsc);
+	return arm_copy_preload_reg (insn, data);
       case 0x63: case 0x67: case 0x73: case 0x77:
-	return arm_copy_unpred (gdbarch, insn, dsc);
+	return arm_copy_unpred (insn, data);
       default:
-	return arm_copy_undef (gdbarch, insn, dsc);
+	return arm_copy_undef (insn, data);
       }
   else
-    return arm_copy_undef (gdbarch, insn, dsc);  /* Probably unreachable.  */
+    return arm_copy_undef (insn, data);  /* Probably unreachable.  */
 }
 
 static int
-arm_decode_unconditional (struct gdbarch *gdbarch, uint32_t insn,
-			  struct regcache *regs,
-			  struct displaced_step_closure *dsc)
+arm_decode_unconditional (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   if (bit (insn, 27) == 0)
-    return arm_decode_misc_memhint_neon (gdbarch, insn, regs, dsc);
+    return arm_decode_misc_memhint_neon (insn, data);
   /* Switch on bits: 0bxxxxx321xxx0xxxxxxxxxxxxxxxxxxxx.  */
   else switch (((insn & 0x7000000) >> 23) | ((insn & 0x100000) >> 20))
     {
     case 0x0: case 0x2:
-      return arm_copy_unmodified (gdbarch, insn, "srs", dsc);
+      return arm_copy_unmodified (insn, "srs", data);
 
     case 0x1: case 0x3:
-      return arm_copy_unmodified (gdbarch, insn, "rfe", dsc);
+      return arm_copy_unmodified (insn, "rfe", data);
 
     case 0x4: case 0x5: case 0x6: case 0x7:
-      return arm_copy_b_bl_blx (gdbarch, insn, regs, dsc);
+      return arm_copy_b_bl_blx (insn, data);
 
     case 0x8:
       switch ((insn & 0xe00000) >> 21)
 	{
 	case 0x1: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
 	  /* stc/stc2.  */
-	  return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
+	  return arm_copy_copro_load_store (insn, data);
 
 	case 0x2:
-	  return arm_copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
+	  return arm_copy_unmodified (insn, "mcrr/mcrr2", data);
 
 	default:
-	  return arm_copy_undef (gdbarch, insn, dsc);
+	  return arm_copy_undef (insn, data);
 	}
 
     case 0x9:
@@ -6560,55 +6556,53 @@ arm_decode_unconditional (struct gdbarch *gdbarch, uint32_t insn,
 	  {
 	  case 0x1: case 0x3:
 	    /* ldc/ldc2 imm (undefined for rn == pc).  */
-	    return rn_f ? arm_copy_undef (gdbarch, insn, dsc)
-			: arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
+	    return rn_f ? arm_copy_undef (insn, data)
+			: arm_copy_copro_load_store (insn, data);
 
 	  case 0x2:
-	    return arm_copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
+	    return arm_copy_unmodified (insn, "mrrc/mrrc2", data);
 
 	  case 0x4: case 0x5: case 0x6: case 0x7:
 	    /* ldc/ldc2 lit (undefined for rn != pc).  */
-	    return rn_f ? arm_copy_copro_load_store (gdbarch, insn, regs, dsc)
-			: arm_copy_undef (gdbarch, insn, dsc);
+	    return rn_f ? arm_copy_copro_load_store (insn, data)
+			: arm_copy_undef (insn, data);
 
 	  default:
-	    return arm_copy_undef (gdbarch, insn, dsc);
+	    return arm_copy_undef (insn, data);
 	  }
       }
 
     case 0xa:
-      return arm_copy_unmodified (gdbarch, insn, "stc/stc2", dsc);
+      return arm_copy_unmodified (insn, "stc/stc2", data);
 
     case 0xb:
       if (bits (insn, 16, 19) == 0xf)
         /* ldc/ldc2 lit.  */
-	return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
+	return arm_copy_copro_load_store (insn, data);
       else
-	return arm_copy_undef (gdbarch, insn, dsc);
+	return arm_copy_undef (insn, data);
 
     case 0xc:
       if (bit (insn, 4))
-	return arm_copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
+	return arm_copy_unmodified (insn, "mcr/mcr2", data);
       else
-	return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
+	return arm_copy_unmodified (insn, "cdp/cdp2", data);
 
     case 0xd:
       if (bit (insn, 4))
-	return arm_copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
+	return arm_copy_unmodified (insn, "mrc/mrc2", data);
       else
-	return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
+	return arm_copy_unmodified (insn, "cdp/cdp2", data);
 
     default:
-      return arm_copy_undef (gdbarch, insn, dsc);
+      return arm_copy_undef (insn, data);
     }
 }
 
 /* Decode miscellaneous instructions in dp/misc encoding space.  */
 
 static int
-arm_decode_miscellaneous (struct gdbarch *gdbarch, uint32_t insn,
-			  struct regcache *regs,
-			  struct displaced_step_closure *dsc)
+arm_decode_miscellaneous (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int op2 = bits (insn, 4, 6);
   unsigned int op = bits (insn, 21, 22);
@@ -6616,85 +6610,81 @@ arm_decode_miscellaneous (struct gdbarch *gdbarch, uint32_t insn,
   switch (op2)
     {
     case 0x0:
-      return arm_copy_unmodified (gdbarch, insn, "mrs/msr", dsc);
+      return arm_copy_unmodified (insn, "mrs/msr", data);
 
     case 0x1:
       if (op == 0x1)  /* bx.  */
-	return arm_copy_bx_blx_reg (gdbarch, insn, regs, dsc);
+	return arm_copy_bx_blx_reg (insn, data);
       else if (op == 0x3)
-	return arm_copy_unmodified (gdbarch, insn, "clz", dsc);
+	return arm_copy_unmodified (insn, "clz", data);
       else
-	return arm_copy_undef (gdbarch, insn, dsc);
+	return arm_copy_undef (insn, data);
 
     case 0x2:
       if (op == 0x1)
         /* Not really supported.  */
-	return arm_copy_unmodified (gdbarch, insn, "bxj", dsc);
+	return arm_copy_unmodified (insn, "bxj", data);
       else
-	return arm_copy_undef (gdbarch, insn, dsc);
+	return arm_copy_undef (insn, data);
 
     case 0x3:
       if (op == 0x1)
-	return arm_copy_bx_blx_reg (gdbarch, insn,
-				regs, dsc);  /* blx register.  */
+	return arm_copy_bx_blx_reg (insn, data);  /* blx register.  */
       else
-	return arm_copy_undef (gdbarch, insn, dsc);
+	return arm_copy_undef (insn, data);
 
     case 0x5:
-      return arm_copy_unmodified (gdbarch, insn, "saturating add/sub", dsc);
+      return arm_copy_unmodified (insn, "saturating add/sub", data);
 
     case 0x7:
       if (op == 0x1)
-	return arm_copy_unmodified (gdbarch, insn, "bkpt", dsc);
+	return arm_copy_unmodified (insn, "bkpt", data);
       else if (op == 0x3)
         /* Not really supported.  */
-	return arm_copy_unmodified (gdbarch, insn, "smc", dsc);
+	return arm_copy_unmodified (insn, "smc", data);
 
     default:
-      return arm_copy_undef (gdbarch, insn, dsc);
+      return arm_copy_undef (insn, data);
     }
 }
 
 static int
-arm_decode_dp_misc (struct gdbarch *gdbarch, uint32_t insn,
-		    struct regcache *regs,
-		    struct displaced_step_closure *dsc)
+arm_decode_dp_misc (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   if (bit (insn, 25))
     switch (bits (insn, 20, 24))
       {
       case 0x10:
-	return arm_copy_unmodified (gdbarch, insn, "movw", dsc);
+	return arm_copy_unmodified (insn, "movw", data);
 
       case 0x14:
-	return arm_copy_unmodified (gdbarch, insn, "movt", dsc);
+	return arm_copy_unmodified (insn, "movt", data);
 
       case 0x12: case 0x16:
-	return arm_copy_unmodified (gdbarch, insn, "msr imm", dsc);
+	return arm_copy_unmodified (insn, "msr imm", data);
 
       default:
-	return arm_copy_alu_imm (gdbarch, insn, regs, dsc);
+	return arm_copy_alu_imm (insn, data);
       }
   else
     {
       uint32_t op1 = bits (insn, 20, 24), op2 = bits (insn, 4, 7);
 
       if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0)
-	return arm_copy_alu_reg (gdbarch, insn, regs, dsc);
+	return arm_copy_alu_reg (insn, data);
       else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1)
-	return arm_copy_alu_shifted_reg (gdbarch, insn, regs, dsc);
+	return arm_copy_alu_shifted_reg (insn, data);
       else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0)
-	return arm_decode_miscellaneous (gdbarch, insn, regs, dsc);
+	return arm_decode_miscellaneous (insn, data);
       else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8)
-	return arm_copy_unmodified (gdbarch, insn, "halfword mul/mla", dsc);
+	return arm_copy_unmodified (insn, "halfword mul/mla", data);
       else if ((op1 & 0x10) == 0x00 && op2 == 0x9)
-	return arm_copy_unmodified (gdbarch, insn, "mul/mla", dsc);
+	return arm_copy_unmodified (insn, "mul/mla", data);
       else if ((op1 & 0x10) == 0x10 && op2 == 0x9)
-	return arm_copy_unmodified (gdbarch, insn, "synch", dsc);
+	return arm_copy_unmodified (insn, "synch", data);
       else if (op2 == 0xb || (op2 & 0xd) == 0xd)
 	/* 2nd arg means "unprivileged".  */
-	return arm_copy_extra_ld_st (gdbarch, insn, (op1 & 0x12) == 0x02, regs,
-				     dsc);
+	return arm_copy_extra_ld_st (insn, data, (op1 & 0x12) == 0x02);
     }
 
   /* Should be unreachable.  */
@@ -6702,92 +6692,89 @@ arm_decode_dp_misc (struct gdbarch *gdbarch, uint32_t insn,
 }
 
 static int
-arm_decode_ld_st_word_ubyte (struct gdbarch *gdbarch, uint32_t insn,
-			     struct regcache *regs,
-			     struct displaced_step_closure *dsc)
+arm_decode_ld_st_word_ubyte (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   int a = bit (insn, 25), b = bit (insn, 4);
   uint32_t op1 = bits (insn, 20, 24);
 
   if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02)
       || (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b))
-    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 4, 0);
+    return arm_copy_ldr_str_ldrb_strb (insn, data, 0, 4, 0);
   else if ((!a && (op1 & 0x17) == 0x02)
 	    || (a && (op1 & 0x17) == 0x02 && !b))
-    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 4, 1);
+    return arm_copy_ldr_str_ldrb_strb (insn, data, 0, 4, 1);
   else if ((!a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03)
 	    || (a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03 && !b))
-    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 4, 0);
+    return arm_copy_ldr_str_ldrb_strb (insn, data, 1, 4, 0);
   else if ((!a && (op1 & 0x17) == 0x03)
 	   || (a && (op1 & 0x17) == 0x03 && !b))
-    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 4, 1);
+    return arm_copy_ldr_str_ldrb_strb (insn, data, 1, 4, 1);
   else if ((!a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06)
 	    || (a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06 && !b))
-    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 0);
+    return arm_copy_ldr_str_ldrb_strb (insn, data, 0, 1, 0);
   else if ((!a && (op1 & 0x17) == 0x06)
 	   || (a && (op1 & 0x17) == 0x06 && !b))
-    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 0, 1, 1);
+    return arm_copy_ldr_str_ldrb_strb (insn, data, 0, 1, 1);
   else if ((!a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07)
 	   || (a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07 && !b))
-    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 0);
+    return arm_copy_ldr_str_ldrb_strb (insn, data, 1, 1, 0);
   else if ((!a && (op1 & 0x17) == 0x07)
 	   || (a && (op1 & 0x17) == 0x07 && !b))
-    return arm_copy_ldr_str_ldrb_strb (gdbarch, insn, regs, dsc, 1, 1, 1);
+    return arm_copy_ldr_str_ldrb_strb (insn, data, 1, 1, 1);
 
   /* Should be unreachable.  */
   return 1;
 }
 
 static int
-arm_decode_media (struct gdbarch *gdbarch, uint32_t insn,
-		  struct displaced_step_closure *dsc)
+arm_decode_media (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   switch (bits (insn, 20, 24))
     {
     case 0x00: case 0x01: case 0x02: case 0x03:
-      return arm_copy_unmodified (gdbarch, insn, "parallel add/sub signed", dsc);
+      return arm_copy_unmodified (insn, "parallel add/sub signed", data);
 
     case 0x04: case 0x05: case 0x06: case 0x07:
-      return arm_copy_unmodified (gdbarch, insn, "parallel add/sub unsigned", dsc);
+      return arm_copy_unmodified (insn, "parallel add/sub unsigned", data);
 
     case 0x08: case 0x09: case 0x0a: case 0x0b:
     case 0x0c: case 0x0d: case 0x0e: case 0x0f:
-      return arm_copy_unmodified (gdbarch, insn,
-			      "decode/pack/unpack/saturate/reverse", dsc);
+      return arm_copy_unmodified (insn,
+			      "decode/pack/unpack/saturate/reverse", data);
 
     case 0x18:
       if (bits (insn, 5, 7) == 0)  /* op2.  */
 	 {
 	  if (bits (insn, 12, 15) == 0xf)
-	    return arm_copy_unmodified (gdbarch, insn, "usad8", dsc);
+	    return arm_copy_unmodified (insn, "usad8", data);
 	  else
-	    return arm_copy_unmodified (gdbarch, insn, "usada8", dsc);
+	    return arm_copy_unmodified (insn, "usada8", data);
 	}
       else
-	 return arm_copy_undef (gdbarch, insn, dsc);
+	 return arm_copy_undef (insn, data);
 
     case 0x1a: case 0x1b:
       if (bits (insn, 5, 6) == 0x2)  /* op2[1:0].  */
-	return arm_copy_unmodified (gdbarch, insn, "sbfx", dsc);
+	return arm_copy_unmodified (insn, "sbfx", data);
       else
-	return arm_copy_undef (gdbarch, insn, dsc);
+	return arm_copy_undef (insn, data);
 
     case 0x1c: case 0x1d:
       if (bits (insn, 5, 6) == 0x0)  /* op2[1:0].  */
 	 {
 	  if (bits (insn, 0, 3) == 0xf)
-	    return arm_copy_unmodified (gdbarch, insn, "bfc", dsc);
+	    return arm_copy_unmodified (insn, "bfc", data);
 	  else
-	    return arm_copy_unmodified (gdbarch, insn, "bfi", dsc);
+	    return arm_copy_unmodified (insn, "bfi", data);
 	}
       else
-	return arm_copy_undef (gdbarch, insn, dsc);
+	return arm_copy_undef (insn, data);
 
     case 0x1e: case 0x1f:
       if (bits (insn, 5, 6) == 0x2)  /* op2[1:0].  */
-	return arm_copy_unmodified (gdbarch, insn, "ubfx", dsc);
+	return arm_copy_unmodified (insn, "ubfx", data);
       else
-	return arm_copy_undef (gdbarch, insn, dsc);
+	return arm_copy_undef (insn, data);
     }
 
   /* Should be unreachable.  */
@@ -6795,41 +6782,37 @@ arm_decode_media (struct gdbarch *gdbarch, uint32_t insn,
 }
 
 static int
-arm_decode_b_bl_ldmstm (struct gdbarch *gdbarch, uint32_t insn,
-			struct regcache *regs,
-			struct displaced_step_closure *dsc)
+arm_decode_b_bl_ldmstm (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   if (bit (insn, 25))
-    return arm_copy_b_bl_blx (gdbarch, insn, regs, dsc);
+    return arm_copy_b_bl_blx (insn, data);
   else
-    return arm_copy_block_xfer (gdbarch, insn, regs, dsc);
+    return arm_copy_block_xfer (insn, data);
 }
 
 static int
-arm_decode_ext_reg_ld_st (struct gdbarch *gdbarch, uint32_t insn,
-			  struct regcache *regs,
-			  struct displaced_step_closure *dsc)
+arm_decode_ext_reg_ld_st (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int opcode = bits (insn, 20, 24);
 
   switch (opcode)
     {
     case 0x04: case 0x05:  /* VFP/Neon mrrc/mcrr.  */
-      return arm_copy_unmodified (gdbarch, insn, "vfp/neon mrrc/mcrr", dsc);
+      return arm_copy_unmodified (insn, "vfp/neon mrrc/mcrr", data);
 
     case 0x08: case 0x0a: case 0x0c: case 0x0e:
     case 0x12: case 0x16:
-      return arm_copy_unmodified (gdbarch, insn, "vfp/neon vstm/vpush", dsc);
+      return arm_copy_unmodified (insn, "vfp/neon vstm/vpush", data);
 
     case 0x09: case 0x0b: case 0x0d: case 0x0f:
     case 0x13: case 0x17:
-      return arm_copy_unmodified (gdbarch, insn, "vfp/neon vldm/vpop", dsc);
+      return arm_copy_unmodified (insn, "vfp/neon vldm/vpop", data);
 
     case 0x10: case 0x14: case 0x18: case 0x1c:  /* vstr.  */
     case 0x11: case 0x15: case 0x19: case 0x1d:  /* vldr.  */
       /* Note: no writeback for these instructions.  Bit 25 will always be
 	 zero though (via caller), so the following works OK.  */
-      return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
+      return arm_copy_copro_load_store (insn, data);
     }
 
   /* Should be unreachable.  */
@@ -6839,9 +6822,8 @@ arm_decode_ext_reg_ld_st (struct gdbarch *gdbarch, uint32_t insn,
 /* Decode shifted register instructions.  */
 
 static int
-thumb2_decode_dp_shift_reg (struct gdbarch *gdbarch, uint16_t insn1,
-			    uint16_t insn2,  struct regcache *regs,
-			    struct displaced_step_closure *dsc)
+thumb2_decode_dp_shift_reg (uint16_t insn1, uint16_t insn2,
+			    struct arm_insn_reloc_data *data)
 {
   /* PC is only allowed to be used in instruction MOV.  */
 
@@ -6849,10 +6831,9 @@ thumb2_decode_dp_shift_reg (struct gdbarch *gdbarch, uint16_t insn1,
   unsigned int rn = bits (insn1, 0, 3);
 
   if (op == 0x2 && rn == 0xf) /* MOV */
-    return thumb2_copy_alu_imm (gdbarch, insn1, insn2, regs, dsc);
+    return thumb2_copy_alu_imm (insn1, insn2, data);
   else
-    return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-					"dp (shift reg)", dsc);
+    return thumb_copy_unmodified_32bit (insn1, insn2, "dp (shift reg)", data);
 }
 
 
@@ -6860,35 +6841,32 @@ thumb2_decode_dp_shift_reg (struct gdbarch *gdbarch, uint16_t insn1,
    arm_decode_ext_reg_ld_st.  */
 
 static int
-thumb2_decode_ext_reg_ld_st (struct gdbarch *gdbarch, uint16_t insn1,
-			     uint16_t insn2,  struct regcache *regs,
-			     struct displaced_step_closure *dsc)
+thumb2_decode_ext_reg_ld_st (uint16_t insn1, uint16_t insn2,
+			     struct arm_insn_reloc_data *data)
 {
   unsigned int opcode = bits (insn1, 4, 8);
 
   switch (opcode)
     {
     case 0x04: case 0x05:
-      return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-					  "vfp/neon vmov", dsc);
+      return thumb_copy_unmodified_32bit (insn1, insn2, "vfp/neon vmov", data);
 
     case 0x08: case 0x0c: /* 01x00 */
     case 0x0a: case 0x0e: /* 01x10 */
     case 0x12: case 0x16: /* 10x10 */
-      return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-					  "vfp/neon vstm/vpush", dsc);
+      return thumb_copy_unmodified_32bit (insn1, insn2,
+					  "vfp/neon vstm/vpush", data);
 
     case 0x09: case 0x0d: /* 01x01 */
     case 0x0b: case 0x0f: /* 01x11 */
     case 0x13: case 0x17: /* 10x11 */
-      return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-					  "vfp/neon vldm/vpop", dsc);
+      return thumb_copy_unmodified_32bit (insn1, insn2,
+					  "vfp/neon vldm/vpop", data);
 
     case 0x10: case 0x14: case 0x18: case 0x1c:  /* vstr.  */
-      return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-					  "vstr", dsc);
+      return thumb_copy_unmodified_32bit (insn1, insn2, "vstr", data);
     case 0x11: case 0x15: case 0x19: case 0x1d:  /* vldr.  */
-      return thumb2_copy_copro_load_store (gdbarch, insn1, insn2, regs, dsc);
+      return thumb2_copy_copro_load_store (insn1, insn2, data);
     }
 
   /* Should be unreachable.  */
@@ -6896,54 +6874,52 @@ thumb2_decode_ext_reg_ld_st (struct gdbarch *gdbarch, uint16_t insn1,
 }
 
 static int
-arm_decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn,
-		      struct regcache *regs, struct displaced_step_closure *dsc)
+arm_decode_svc_copro (uint32_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int op1 = bits (insn, 20, 25);
   int op = bit (insn, 4);
   unsigned int coproc = bits (insn, 8, 11);
 
   if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa)
-    return arm_decode_ext_reg_ld_st (gdbarch, insn, regs, dsc);
+    return arm_decode_ext_reg_ld_st (insn, data);
   else if ((op1 & 0x21) == 0x00 && (op1 & 0x3a) != 0x00
 	   && (coproc & 0xe) != 0xa)
     /* stc/stc2.  */
-    return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
+    return arm_copy_copro_load_store (insn, data);
   else if ((op1 & 0x21) == 0x01 && (op1 & 0x3a) != 0x00
 	   && (coproc & 0xe) != 0xa)
     /* ldc/ldc2 imm/lit.  */
-    return arm_copy_copro_load_store (gdbarch, insn, regs, dsc);
+    return arm_copy_copro_load_store (insn, data);
   else if ((op1 & 0x3e) == 0x00)
-    return arm_copy_undef (gdbarch, insn, dsc);
+    return arm_copy_undef (insn, data);
   else if ((op1 & 0x3e) == 0x04 && (coproc & 0xe) == 0xa)
-    return arm_copy_unmodified (gdbarch, insn, "neon 64bit xfer", dsc);
+    return arm_copy_unmodified (insn, "neon 64bit xfer", data);
   else if (op1 == 0x04 && (coproc & 0xe) != 0xa)
-    return arm_copy_unmodified (gdbarch, insn, "mcrr/mcrr2", dsc);
+    return arm_copy_unmodified (insn, "mcrr/mcrr2", data);
   else if (op1 == 0x05 && (coproc & 0xe) != 0xa)
-    return arm_copy_unmodified (gdbarch, insn, "mrrc/mrrc2", dsc);
+    return arm_copy_unmodified (insn, "mrrc/mrrc2", data);
   else if ((op1 & 0x30) == 0x20 && !op)
     {
       if ((coproc & 0xe) == 0xa)
-	return arm_copy_unmodified (gdbarch, insn, "vfp dataproc", dsc);
+	return arm_copy_unmodified (insn, "vfp dataproc", data);
       else
-	return arm_copy_unmodified (gdbarch, insn, "cdp/cdp2", dsc);
+	return arm_copy_unmodified (insn, "cdp/cdp2", data);
     }
   else if ((op1 & 0x30) == 0x20 && op)
-    return arm_copy_unmodified (gdbarch, insn, "neon 8/16/32 bit xfer", dsc);
+    return arm_copy_unmodified (insn, "neon 8/16/32 bit xfer", data);
   else if ((op1 & 0x31) == 0x20 && op && (coproc & 0xe) != 0xa)
-    return arm_copy_unmodified (gdbarch, insn, "mcr/mcr2", dsc);
+    return arm_copy_unmodified (insn, "mcr/mcr2", data);
   else if ((op1 & 0x31) == 0x21 && op && (coproc & 0xe) != 0xa)
-    return arm_copy_unmodified (gdbarch, insn, "mrc/mrc2", dsc);
+    return arm_copy_unmodified (insn, "mrc/mrc2", data);
   else if ((op1 & 0x30) == 0x30)
-    return arm_copy_svc (gdbarch, insn, regs, dsc);
+    return arm_copy_svc (insn, data);
   else
-    return arm_copy_undef (gdbarch, insn, dsc);  /* Possibly unreachable.  */
+    return arm_copy_undef (insn, data);  /* Possibly unreachable.  */
 }
 
 static int
-thumb2_decode_svc_copro (struct gdbarch *gdbarch, uint16_t insn1,
-			 uint16_t insn2, struct regcache *regs,
-			 struct displaced_step_closure *dsc)
+thumb2_decode_svc_copro (uint16_t insn1, uint16_t insn2,
+			 struct arm_insn_reloc_data *data)
 {
   unsigned int coproc = bits (insn2, 8, 11);
   unsigned int bit_5_8 = bits (insn1, 5, 8);
@@ -6953,37 +6929,33 @@ thumb2_decode_svc_copro (struct gdbarch *gdbarch, uint16_t insn1,
   if (bit_9 == 0)
     {
       if (bit_5_8 == 2)
-	return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-					    "neon 64bit xfer/mrrc/mrrc2/mcrr/mcrr2",
-					    dsc);
+	return thumb_copy_unmodified_32bit (
+	  insn1, insn2, "neon 64bit xfer/mrrc/mrrc2/mcrr/mcrr2", data);
       else if (bit_5_8 == 0) /* UNDEFINED.  */
-	return thumb_32bit_copy_undef (gdbarch, insn1, insn2, dsc);
+	return thumb_32bit_copy_undef (insn1, insn2, data);
       else
 	{
 	   /*coproc is 101x.  SIMD/VFP, ext registers load/store.  */
 	  if ((coproc & 0xe) == 0xa)
-	    return thumb2_decode_ext_reg_ld_st (gdbarch, insn1, insn2, regs,
-						dsc);
+	    return thumb2_decode_ext_reg_ld_st (insn1, insn2, data);
 	  else /* coproc is not 101x.  */
 	    {
 	      if (bit_4 == 0) /* STC/STC2.  */
-		return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-						    "stc/stc2", dsc);
+		return thumb_copy_unmodified_32bit (insn1, insn2, "stc/stc2",
+						    data);
 	      else /* LDC/LDC2 {literal, immeidate}.  */
-		return thumb2_copy_copro_load_store (gdbarch, insn1, insn2,
-						     regs, dsc);
+		return thumb2_copy_copro_load_store (insn1, insn2, data);
 	    }
 	}
     }
   else
-    return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2, "coproc", dsc);
+    return thumb_copy_unmodified_32bit (insn1, insn2, "coproc", data);
 
   return 0;
 }
 
 static void
-install_pc_relative (struct gdbarch *gdbarch, struct regcache *regs,
-		     struct displaced_step_closure *dsc, int rd)
+install_pc_relative (struct arm_insn_reloc_data *data, int rd)
 {
   /* ADR Rd, #imm
 
@@ -6995,28 +6967,25 @@ install_pc_relative (struct gdbarch *gdbarch, struct regcache *regs,
   */
 
   /* Rd <- PC */
-  int val = displaced_read_reg (regs, dsc, ARM_PC_REGNUM);
-  displaced_write_reg (regs, dsc, rd, val, CANNOT_WRITE_PC);
+  int val = displaced_read_reg (data->regs, data->dsc, ARM_PC_REGNUM);
+  displaced_write_reg (data->regs, data->dsc, rd, val, CANNOT_WRITE_PC);
 }
 
 static int
-thumb_copy_pc_relative_16bit (struct gdbarch *gdbarch, struct regcache *regs,
-			      struct displaced_step_closure *dsc,
-			      int rd, unsigned int imm)
+thumb_copy_pc_relative_16bit (struct arm_insn_reloc_data *data, int rd,
+			      unsigned int imm)
 {
 
   /* Encoding T2: ADDS Rd, #imm */
-  dsc->modinsn[0] = (0x3000 | (rd << 8) | imm);
+  data->dsc->modinsn[0] = (0x3000 | (rd << 8) | imm);
 
-  install_pc_relative (gdbarch, regs, dsc, rd);
+  install_pc_relative (data, rd);
 
   return 0;
 }
 
 static int
-thumb_decode_pc_relative_16bit (struct gdbarch *gdbarch, uint16_t insn,
-				struct regcache *regs,
-				struct displaced_step_closure *dsc)
+thumb_decode_pc_relative_16bit (uint16_t insn, struct arm_insn_reloc_data *data)
 {
   unsigned int rd = bits (insn, 8, 10);
   unsigned int imm8 = bits (insn, 0, 7);
@@ -7026,13 +6995,12 @@ thumb_decode_pc_relative_16bit (struct gdbarch *gdbarch, uint16_t insn,
 			"displaced: copying thumb adr r%d, #%d insn %.4x\n",
 			rd, imm8, insn);
 
-  return thumb_copy_pc_relative_16bit (gdbarch, regs, dsc, rd, imm8);
+  return thumb_copy_pc_relative_16bit (data, rd, imm8);
 }
 
 static int
-thumb_copy_pc_relative_32bit (struct gdbarch *gdbarch, uint16_t insn1,
-			      uint16_t insn2, struct regcache *regs,
-			      struct displaced_step_closure *dsc)
+thumb_copy_pc_relative_32bit (uint16_t insn1, uint16_t insn2,
+			      struct arm_insn_reloc_data *data)
 {
   unsigned int rd = bits (insn2, 8, 11);
   /* Since immediate has the same encoding in ADR ADD and SUB, so we simply
@@ -7041,6 +7009,7 @@ thumb_copy_pc_relative_32bit (struct gdbarch *gdbarch, uint16_t insn1,
      set immediate into ADD.  */
   unsigned int imm_3_8 = insn2 & 0x70ff;
   unsigned int imm_i = insn1 & 0x0400; /* Clear all bits except bit 10.  */
+  struct displaced_step_closure *dsc = data->dsc;
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog,
@@ -7061,19 +7030,20 @@ thumb_copy_pc_relative_32bit (struct gdbarch *gdbarch, uint16_t insn1,
     }
   dsc->numinsns = 2;
 
-  install_pc_relative (gdbarch, regs, dsc, rd);
+  install_pc_relative (data, rd);
 
   return 0;
 }
 
 static int
-thumb_copy_16bit_ldr_literal (struct gdbarch *gdbarch, uint16_t insn1,
-			      struct regcache *regs,
-			      struct displaced_step_closure *dsc)
+thumb_copy_16bit_ldr_literal (uint16_t insn1,
+			      struct arm_insn_reloc_data *data)
 {
   unsigned int rt = bits (insn1, 8, 10);
   unsigned int pc;
   int imm8 = (bits (insn1, 0, 7) << 2);
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   /* LDR Rd, #imm8
 
@@ -7117,15 +7087,14 @@ thumb_copy_16bit_ldr_literal (struct gdbarch *gdbarch, uint16_t insn1,
 /* Copy Thumb cbnz/cbz insruction.  */
 
 static int
-thumb_copy_cbnz_cbz (struct gdbarch *gdbarch, uint16_t insn1,
-		     struct regcache *regs,
-		     struct displaced_step_closure *dsc)
+thumb_copy_cbnz_cbz (uint16_t insn1, struct arm_insn_reloc_data *data)
 {
+  struct displaced_step_closure *dsc = data->dsc;
   int non_zero = bit (insn1, 11);
   unsigned int imm5 = (bit (insn1, 9) << 6) | (bits (insn1, 3, 7) << 1);
   CORE_ADDR from = dsc->insn_addr;
   int rn = bits (insn1, 0, 2);
-  int rn_val = displaced_read_reg (regs, dsc, rn);
+  int rn_val = displaced_read_reg (data->regs, dsc, rn);
 
   dsc->u.branch.cond = (rn_val && non_zero) || (!rn_val && !non_zero);
   /* CBNZ and CBZ do not affect the condition flags.  If condition is true,
@@ -7155,14 +7124,15 @@ thumb_copy_cbnz_cbz (struct gdbarch *gdbarch, uint16_t insn1,
 
 /* Copy Table Branch Byte/Halfword */
 static int
-thumb2_copy_table_branch (struct gdbarch *gdbarch, uint16_t insn1,
-			  uint16_t insn2, struct regcache *regs,
-			  struct displaced_step_closure *dsc)
+thumb2_copy_table_branch (uint16_t insn1, uint16_t insn2,
+			  struct arm_insn_reloc_data *data)
 {
   ULONGEST rn_val, rm_val;
   int is_tbh = bit (insn2, 4);
   CORE_ADDR halfwords = 0;
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (data->gdbarch);
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
 
   rn_val = displaced_read_reg (regs, dsc, bits (insn1, 0, 3));
   rm_val = displaced_read_reg (regs, dsc, bits (insn2, 0, 3));
@@ -7216,10 +7186,11 @@ cleanup_pop_pc_16bit_all (struct gdbarch *gdbarch, struct regcache *regs,
 }
 
 static int
-thumb_copy_pop_pc_16bit (struct gdbarch *gdbarch, uint16_t insn1,
-			 struct regcache *regs,
-			 struct displaced_step_closure *dsc)
+thumb_copy_pop_pc_16bit (uint16_t insn1, struct arm_insn_reloc_data *data)
 {
+  struct displaced_step_closure *dsc = data->dsc;
+  struct regcache *regs = data->regs;
+
   dsc->u.block.regmask = insn1 & 0x00ff;
 
   /* Rewrite instruction: POP {rX, rY, ...,rZ, PC}
@@ -7289,9 +7260,8 @@ thumb_copy_pop_pc_16bit (struct gdbarch *gdbarch, uint16_t insn1,
 }
 
 static void
-thumb_process_displaced_16bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
-				    struct regcache *regs,
-				    struct displaced_step_closure *dsc)
+thumb_process_displaced_16bit_insn (uint16_t insn1,
+				    struct arm_insn_reloc_data *data)
 {
   unsigned short op_bit_12_15 = bits (insn1, 12, 15);
   unsigned short op_bit_10_11 = bits (insn1, 10, 11);
@@ -7302,85 +7272,79 @@ thumb_process_displaced_16bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
     {
       /* Shift (imme), add, subtract, move and compare.  */
     case 0: case 1: case 2: case 3:
-      err = thumb_copy_unmodified_16bit (gdbarch, insn1,
-					 "shift/add/sub/mov/cmp",
-					 dsc);
+      err = thumb_copy_unmodified_16bit (insn1, "shift/add/sub/mov/cmp", data);
       break;
     case 4:
       switch (op_bit_10_11)
 	{
 	case 0: /* Data-processing */
-	  err = thumb_copy_unmodified_16bit (gdbarch, insn1,
-					     "data-processing",
-					     dsc);
+	  err = thumb_copy_unmodified_16bit (insn1, "data-processing", data);
 	  break;
 	case 1: /* Special data instructions and branch and exchange.  */
 	  {
 	    unsigned short op = bits (insn1, 7, 9);
 	    if (op == 6 || op == 7) /* BX or BLX */
-	      err = thumb_copy_bx_blx_reg (gdbarch, insn1, regs, dsc);
+	      err = thumb_copy_bx_blx_reg (insn1, data);
 	    else if (bits (insn1, 6, 7) != 0) /* ADD/MOV/CMP high registers.  */
-	      err = thumb_copy_alu_reg (gdbarch, insn1, regs, dsc);
+	      err = thumb_copy_alu_reg (insn1, data);
 	    else
-	      err = thumb_copy_unmodified_16bit (gdbarch, insn1, "special data",
-						 dsc);
+	      err = thumb_copy_unmodified_16bit (insn1, "special data", data);
 	  }
 	  break;
 	default: /* LDR (literal) */
-	  err = thumb_copy_16bit_ldr_literal (gdbarch, insn1, regs, dsc);
+	  err = thumb_copy_16bit_ldr_literal (insn1, data);
 	}
       break;
     case 5: case 6: case 7: case 8: case 9: /* Load/Store single data item */
-      err = thumb_copy_unmodified_16bit (gdbarch, insn1, "ldr/str", dsc);
+      err = thumb_copy_unmodified_16bit (insn1, "ldr/str", data);
       break;
     case 10:
       if (op_bit_10_11 < 2) /* Generate PC-relative address */
-	err = thumb_decode_pc_relative_16bit (gdbarch, insn1, regs, dsc);
+	err = thumb_decode_pc_relative_16bit (insn1, data);
       else /* Generate SP-relative address */
-	err = thumb_copy_unmodified_16bit (gdbarch, insn1, "sp-relative", dsc);
+	err = thumb_copy_unmodified_16bit (insn1, "sp-relative", data);
       break;
     case 11: /* Misc 16-bit instructions */
       {
 	switch (bits (insn1, 8, 11))
 	  {
 	  case 1: case 3:  case 9: case 11: /* CBNZ, CBZ */
-	    err = thumb_copy_cbnz_cbz (gdbarch, insn1, regs, dsc);
+	    err = thumb_copy_cbnz_cbz (insn1, data);
 	    break;
 	  case 12: case 13: /* POP */
 	    if (bit (insn1, 8)) /* PC is in register list.  */
-	      err = thumb_copy_pop_pc_16bit (gdbarch, insn1, regs, dsc);
+	      err = thumb_copy_pop_pc_16bit (insn1, data);
 	    else
-	      err = thumb_copy_unmodified_16bit (gdbarch, insn1, "pop", dsc);
+	      err = thumb_copy_unmodified_16bit (insn1, "pop", data);
 	    break;
 	  case 15: /* If-Then, and hints */
 	    if (bits (insn1, 0, 3))
 	      /* If-Then makes up to four following instructions conditional.
 		 IT instruction itself is not conditional, so handle it as a
 		 common unmodified instruction.  */
-	      err = thumb_copy_unmodified_16bit (gdbarch, insn1, "If-Then",
-						 dsc);
+	      err = thumb_copy_unmodified_16bit (insn1, "If-Then", data);
 	    else
-	      err = thumb_copy_unmodified_16bit (gdbarch, insn1, "hints", dsc);
+	      err = thumb_copy_unmodified_16bit (insn1, "hints", data);
 	    break;
 	  default:
-	    err = thumb_copy_unmodified_16bit (gdbarch, insn1, "misc", dsc);
+	    err = thumb_copy_unmodified_16bit (insn1, "misc", data);
 	  }
       }
       break;
     case 12:
       if (op_bit_10_11 < 2) /* Store multiple registers */
-	err = thumb_copy_unmodified_16bit (gdbarch, insn1, "stm", dsc);
+	err = thumb_copy_unmodified_16bit (insn1, "stm", data);
       else /* Load multiple registers */
-	err = thumb_copy_unmodified_16bit (gdbarch, insn1, "ldm", dsc);
+	err = thumb_copy_unmodified_16bit (insn1, "ldm", data);
       break;
     case 13: /* Conditional branch and supervisor call */
       if (bits (insn1, 9, 11) != 7) /* conditional branch */
-	err = thumb_copy_b (gdbarch, insn1, dsc);
+	err = thumb_copy_b (insn1, data);
       else
-	err = thumb_copy_svc (gdbarch, insn1, regs, dsc);
+	err = thumb_copy_svc (insn1, data);
       break;
     case 14: /* Unconditional branch */
-      err = thumb_copy_b (gdbarch, insn1, dsc);
+      err = thumb_copy_b (insn1, data);
       break;
     default:
       err = 1;
@@ -7392,10 +7356,8 @@ thumb_process_displaced_16bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
 }
 
 static int
-decode_thumb_32bit_ld_mem_hints (struct gdbarch *gdbarch,
-				 uint16_t insn1, uint16_t insn2,
-				 struct regcache *regs,
-				 struct displaced_step_closure *dsc)
+decode_thumb_32bit_ld_mem_hints (uint16_t insn1, uint16_t insn2,
+				 struct arm_insn_reloc_data *data)
 {
   int rt = bits (insn2, 12, 15);
   int rn = bits (insn1, 0, 3);
@@ -7408,35 +7370,32 @@ decode_thumb_32bit_ld_mem_hints (struct gdbarch *gdbarch,
 	{
 	  if (rn == 0xf)
 	    /* PLD literal or Encoding T3 of PLI(immediate, literal).  */
-	    return thumb2_copy_preload (gdbarch, insn1, insn2, regs, dsc);
+	    return thumb2_copy_preload (insn1, insn2, data);
 	  else
-	    return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-						"pli/pld", dsc);
+	    return thumb_copy_unmodified_32bit (insn1, insn2, "pli/pld", data);
 	}
       else
 	{
 	  if (rn == 0xf) /* LDRB/LDRSB (literal) */
-	    return thumb2_copy_load_literal (gdbarch, insn1, insn2, regs, dsc,
-					     1);
+	    return thumb2_copy_load_literal (insn1, insn2, data, 1);
 	  else
-	    return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
+	    return thumb_copy_unmodified_32bit (insn1, insn2,
 						"ldrb{reg, immediate}/ldrbt",
-						dsc);
+						data);
 	}
 
       break;
     case 1: /* Load halfword and memory hints.  */
       if (rt == 0xf) /* PLD{W} and Unalloc memory hint.  */
-	return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-					    "pld/unalloc memhint", dsc);
+	return thumb_copy_unmodified_32bit (insn1, insn2, "pld/unalloc memhint",
+					    data);
       else
 	{
 	  if (rn == 0xf)
-	    return thumb2_copy_load_literal (gdbarch, insn1, insn2, regs, dsc,
-					     2);
+	    return thumb2_copy_load_literal (insn1, insn2, data, 2);
 	  else
-	    return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-						"ldrh/ldrht", dsc);
+	    return thumb_copy_unmodified_32bit (insn1, insn2, "ldrh/ldrht",
+						data);
 	}
       break;
     case 2: /* Load word */
@@ -7444,37 +7403,33 @@ decode_thumb_32bit_ld_mem_hints (struct gdbarch *gdbarch,
 	int insn2_bit_8_11 = bits (insn2, 8, 11);
 
 	if (rn == 0xf)
-	  return thumb2_copy_load_literal (gdbarch, insn1, insn2, regs, dsc, 4);
+	  return thumb2_copy_load_literal (insn1, insn2, data, 4);
 	else if (op1 == 0x1) /* Encoding T3 */
-	  return thumb2_copy_load_reg_imm (gdbarch, insn1, insn2, regs, dsc,
-					   0, 1);
+	  return thumb2_copy_load_reg_imm (insn1, insn2, data, 0, 1);
 	else /* op1 == 0x0 */
 	  {
 	    if (insn2_bit_8_11 == 0xc || (insn2_bit_8_11 & 0x9) == 0x9)
 	      /* LDR (immediate) */
-	      return thumb2_copy_load_reg_imm (gdbarch, insn1, insn2, regs,
-					       dsc, bit (insn2, 8), 1);
+	      return thumb2_copy_load_reg_imm (insn1, insn2, data,
+					       bit (insn2, 8), 1);
 	    else if (insn2_bit_8_11 == 0xe) /* LDRT */
-	      return thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-						  "ldrt", dsc);
+	      return thumb_copy_unmodified_32bit (insn1, insn2, "ldrt", data);
 	    else
 	      /* LDR (register) */
-	      return thumb2_copy_load_reg_imm (gdbarch, insn1, insn2, regs,
-					       dsc, 0, 0);
+	      return thumb2_copy_load_reg_imm (insn1, insn2, data, 0, 0);
 	  }
 	break;
       }
     default:
-      return thumb_32bit_copy_undef (gdbarch, insn1, insn2, dsc);
+      return thumb_32bit_copy_undef (insn1, insn2, data);
       break;
     }
   return 0;
 }
 
 static void
-thumb_process_displaced_32bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
-				    uint16_t insn2, struct regcache *regs,
-				    struct displaced_step_closure *dsc)
+thumb_process_displaced_32bit_insn (uint16_t insn1, uint16_t insn2,
+				    struct arm_insn_reloc_data *data)
 {
   int err = 0;
   unsigned short op = bit (insn2, 15);
@@ -7492,24 +7447,24 @@ thumb_process_displaced_32bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
 		/* Load/store {dual, execlusive}, table branch.  */
 		if (bits (insn1, 7, 8) == 1 && bits (insn1, 4, 5) == 1
 		    && bits (insn2, 5, 7) == 0)
-		  err = thumb2_copy_table_branch (gdbarch, insn1, insn2, regs,
-						  dsc);
+		  err = thumb2_copy_table_branch (insn1, insn2, data);
 		else
 		  /* PC is not allowed to use in load/store {dual, exclusive}
 		     instructions.  */
-		  err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-						     "load/store dual/ex", dsc);
+		  err = thumb_copy_unmodified_32bit (insn1, insn2,
+						     "load/store dual/ex",
+						     data);
 	      }
 	    else /* load/store multiple */
 	      {
 		switch (bits (insn1, 7, 8))
 		  {
 		  case 0: case 3: /* SRS, RFE */
-		    err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-						       "srs/rfe", dsc);
+		    err = thumb_copy_unmodified_32bit (insn1, insn2, "srs/rfe",
+						       data);
 		    break;
 		  case 1: case 2: /* LDM/STM/PUSH/POP */
-		    err = thumb2_copy_block_xfer (gdbarch, insn1, insn2, regs, dsc);
+		    err = thumb2_copy_block_xfer (insn1, insn2, data);
 		    break;
 		  }
 	      }
@@ -7517,11 +7472,10 @@ thumb_process_displaced_32bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
 
 	  case 1:
 	    /* Data-processing (shift register).  */
-	    err = thumb2_decode_dp_shift_reg (gdbarch, insn1, insn2, regs,
-					      dsc);
+	    err = thumb2_decode_dp_shift_reg (insn1, insn2, data);
 	    break;
 	  default: /* Coprocessor instructions.  */
-	    err = thumb2_decode_svc_copro (gdbarch, insn1, insn2, regs, dsc);
+	    err = thumb2_decode_svc_copro (insn1, insn2, data);
 	    break;
 	  }
       break;
@@ -7532,10 +7486,9 @@ thumb_process_displaced_32bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
 	  if (bit (insn2, 14)  /* BLX/BL */
 	      || bit (insn2, 12) /* Unconditional branch */
 	      || (bits (insn1, 7, 9) != 0x7)) /* Conditional branch */
-	    err = thumb2_copy_b_bl_blx (gdbarch, insn1, insn2, regs, dsc);
+	    err = thumb2_copy_b_bl_blx (insn1, insn2, data);
 	  else
-	    err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-					       "misc ctrl", dsc);
+	    err = thumb_copy_unmodified_32bit (insn1, insn2, "misc ctrl", data);
 	}
       else
 	{
@@ -7544,15 +7497,12 @@ thumb_process_displaced_32bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
 	      int op = bits (insn1, 4, 8);
 	      int rn = bits (insn1, 0, 3);
 	      if ((op == 0 || op == 0xa) && rn == 0xf)
-		err = thumb_copy_pc_relative_32bit (gdbarch, insn1, insn2,
-						    regs, dsc);
+		err = thumb_copy_pc_relative_32bit (insn1, insn2, data);
 	      else
-		err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-						   "dp/pb", dsc);
+		err = thumb_copy_unmodified_32bit (insn1, insn2, "dp/pb", data);
 	    }
 	  else /* Data processing (modified immeidate) */
-	    err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-					       "dp/mi", dsc);
+	    err = thumb_copy_unmodified_32bit (insn1, insn2, "dp/mi", data);
 	}
       break;
     case 3: /* op1 = 3 */
@@ -7560,32 +7510,30 @@ thumb_process_displaced_32bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
 	{
 	case 0:
 	  if (bit (insn1, 4))
-	    err = decode_thumb_32bit_ld_mem_hints (gdbarch, insn1, insn2,
-						   regs, dsc);
+	    err = decode_thumb_32bit_ld_mem_hints (insn1, insn2, data);
 	  else /* NEON Load/Store and Store single data item */
-	    err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
+	    err = thumb_copy_unmodified_32bit (insn1, insn2,
 					       "neon elt/struct load/store",
-					       dsc);
+					       data);
 	  break;
 	case 1: /* op1 = 3, bits (9, 10) == 1 */
 	  switch (bits (insn1, 7, 8))
 	    {
 	    case 0: case 1: /* Data processing (register) */
-	      err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-						 "dp(reg)", dsc);
+	      err = thumb_copy_unmodified_32bit (insn1, insn2, "dp(reg)", data);
 	      break;
 	    case 2: /* Multiply and absolute difference */
-	      err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-						 "mul/mua/diff", dsc);
+	      err = thumb_copy_unmodified_32bit (insn1, insn2, "mul/mua/diff",
+						 data);
 	      break;
 	    case 3: /* Long multiply and divide */
-	      err = thumb_copy_unmodified_32bit (gdbarch, insn1, insn2,
-						 "lmul/lmua", dsc);
+	      err = thumb_copy_unmodified_32bit (insn1, insn2, "lmul/lmua",
+						 data);
 	      break;
 	    }
 	  break;
 	default: /* Coprocessor instructions */
-	  err = thumb2_decode_svc_copro (gdbarch, insn1, insn2, regs, dsc);
+	  err = thumb2_decode_svc_copro (insn1, insn2, data);
 	  break;
 	}
       break;
@@ -7600,11 +7548,10 @@ thumb_process_displaced_32bit_insn (struct gdbarch *gdbarch, uint16_t insn1,
 }
 
 static void
-thumb_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
-			      struct regcache *regs,
-			      struct displaced_step_closure *dsc)
+thumb_process_displaced_insn (CORE_ADDR from, struct arm_insn_reloc_data *data)
 {
-  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+  enum bfd_endian byte_order_for_code
+    = gdbarch_byte_order_for_code (data->gdbarch);
   uint16_t insn1
     = read_memory_unsigned_integer (from, 2, byte_order_for_code);
 
@@ -7612,16 +7559,16 @@ thumb_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
     fprintf_unfiltered (gdb_stdlog, "displaced: process thumb insn %.4x "
 			"at %.8lx\n", insn1, (unsigned long) from);
 
-  dsc->is_thumb = 1;
-  dsc->insn_size = thumb_insn_size (insn1);
+  data->dsc->is_thumb = 1;
+  data->dsc->insn_size = thumb_insn_size (insn1);
   if (thumb_insn_size (insn1) == 4)
     {
       uint16_t insn2
 	= read_memory_unsigned_integer (from + 2, 2, byte_order_for_code);
-      thumb_process_displaced_32bit_insn (gdbarch, insn1, insn2, regs, dsc);
+      thumb_process_displaced_32bit_insn (insn1, insn2, data);
     }
   else
-    thumb_process_displaced_16bit_insn (gdbarch, insn1, regs, dsc);
+    thumb_process_displaced_16bit_insn (insn1, data);
 }
 
 void
@@ -7632,6 +7579,11 @@ arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
   int err = 0;
   enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
   uint32_t insn;
+  struct arm_insn_reloc_data reloc_data;
+
+  reloc_data.dsc = dsc;
+  reloc_data.gdbarch = gdbarch;
+  reloc_data.regs = regs;
 
   /* Most displaced instructions use a 1-instruction scratch space, so set this
      here and override below if/when necessary.  */
@@ -7642,7 +7594,7 @@ arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
   dsc->wrote_to_pc = 0;
 
   if (!displaced_in_arm_mode (regs))
-    return thumb_process_displaced_insn (gdbarch, from, regs, dsc);
+    return thumb_process_displaced_insn (from, &reloc_data);
 
   dsc->is_thumb = 0;
   dsc->insn_size = 4;
@@ -7653,27 +7605,27 @@ arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
 			(unsigned long) from);
 
   if ((insn & 0xf0000000) == 0xf0000000)
-    err = arm_decode_unconditional (gdbarch, insn, regs, dsc);
+    err = arm_decode_unconditional (insn, &reloc_data);
   else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24))
     {
     case 0x0: case 0x1: case 0x2: case 0x3:
-      err = arm_decode_dp_misc (gdbarch, insn, regs, dsc);
+      err = arm_decode_dp_misc (insn, &reloc_data);
       break;
 
     case 0x4: case 0x5: case 0x6:
-      err = arm_decode_ld_st_word_ubyte (gdbarch, insn, regs, dsc);
+      err = arm_decode_ld_st_word_ubyte (insn, &reloc_data);
       break;
 
     case 0x7:
-      err = arm_decode_media (gdbarch, insn, dsc);
+      err = arm_decode_media (insn, &reloc_data);
       break;
 
     case 0x8: case 0x9: case 0xa: case 0xb:
-      err = arm_decode_b_bl_ldmstm (gdbarch, insn, regs, dsc);
+      err = arm_decode_b_bl_ldmstm (insn, &reloc_data);
       break;
 
     case 0xc: case 0xd: case 0xe: case 0xf:
-      err = arm_decode_svc_copro (gdbarch, insn, regs, dsc);
+      err = arm_decode_svc_copro (insn, &reloc_data);
       break;
     }
 
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 07/18] Move ARM instruction decode functions to arch/arm-insn-reloc.c
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (11 preceding siblings ...)
  2016-07-05 13:42 ` [PATCH v3 17/18] arm fast tracepoints: Relocation of ARM instructions Antoine Tremblay
@ 2016-07-05 13:42 ` 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
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:42 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

This patch moves arm instruction decoding functions (for relocation
purposes) to a shared location in arch/.

No changes to the code itself.

gdb/ChangeLog:

	* Makefile.in (ALL_TARGET_OBS): Add arm-insn-reloc.o.
	(HFILES_NO_SRCDIR): Add arch/arm-insn-reloc.h
	(arm-insn-reloc.o): New rule..
	* arch/arm-insn-reloc.c: New file.
	* arch/arm-insn-reloc.h: New file.
	* configure.tgt (arm-*-*-linux*): Add arm-insn-reloc.o.
	* arm-tdep.c (struct arm_insn_reloc_visitor): Move to
	arch/arm-insn-reloc.c.
	(arm_decode_misc_memhint_neon): Likewise.
	(arm_decode_unconditional): Likewise.
	(arm_decode_miscellaneous): Likewise.
	(arm_decode_dp_misc): Likewise.
	(arm_decode_ld_st_word_ubyte): Likewise.
	(arm_decode_media): Likewise.
	(arm_decode_b_bl_ldmstm): Likewise.
	(arm_decode_ext_reg_ld_st): Likewise.
	(arm_decode_svc_copro): Likewise.
	(arm_relocate_insn_arm): Likewise.
---
 gdb/Makefile.in           |  15 +-
 gdb/arch/arm-insn-reloc.c | 472 ++++++++++++++++++++++++++++++++++++++++++++++
 gdb/arch/arm-insn-reloc.h |  49 +++++
 gdb/arm-tdep.c            | 471 +--------------------------------------------
 gdb/configure.tgt         |   2 +-
 5 files changed, 535 insertions(+), 474 deletions(-)
 create mode 100644 gdb/arch/arm-insn-reloc.c
 create mode 100644 gdb/arch/arm-insn-reloc.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 16d5f27..a83b456 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -657,8 +657,13 @@ ALL_64_TARGET_OBS = \
 
 # All other target-dependent objects files (used with --enable-targets=all).
 ALL_TARGET_OBS = \
-	armbsd-tdep.o arm.o arm-linux.o arm-linux-tdep.o \
-	arm-get-next-pcs.o arm-symbian-tdep.o \
+	armbsd-tdep.o \
+	arm.o \
+	arm-linux.o \
+	arm-linux-tdep.o \
+	arm-get-next-pcs.o \
+	arm-symbian-tdep.o \
+	arm-insn-reloc.o \
 	armnbsd-tdep.o armobsd-tdep.o \
 	arm-tdep.o arm-wince-tdep.o \
 	avr-tdep.o \
@@ -989,7 +994,7 @@ common/common-exceptions.h target/target.h common/symbol.h \
 common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \
 common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h nat/amd64-linux-siginfo.h\
 nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h arch/aarch64-insn.h \
-tid-parse.h ser-event.h
+tid-parse.h ser-event.h arch/arm-insn-reloc.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -2310,6 +2315,10 @@ arm-linux.o: ${srcdir}/arch/arm-linux.c
 	$(COMPILE) $(srcdir)/arch/arm-linux.c
 	$(POSTCOMPILE)
 
+arm-insn-reloc.o: ${srcdir}/arch/arm-insn-reloc.c
+	$(COMPILE) $(srcdir)/arch/arm-insn-reloc.c
+	$(POSTCOMPILE)
+
 arm-get-next-pcs.o: ${srcdir}/arch/arm-get-next-pcs.c
 	$(COMPILE) $(srcdir)/arch/arm-get-next-pcs.c
 	$(POSTCOMPILE)
diff --git a/gdb/arch/arm-insn-reloc.c b/gdb/arch/arm-insn-reloc.c
new file mode 100644
index 0000000..adf6243
--- /dev/null
+++ b/gdb/arch/arm-insn-reloc.c
@@ -0,0 +1,472 @@
+/* Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+
+#include "arm.h"
+#include "arm-insn-reloc.h"
+
+static int
+arm_decode_misc_memhint_neon (uint32_t insn,
+			      struct arm_insn_reloc_visitor *visitor,
+			      struct arm_insn_reloc_data *data)
+{
+  unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7);
+  unsigned int rn = bits (insn, 16, 19);
+
+  if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0xe) == 0x0)
+    return visitor->others (insn, "cps", data);
+  else if (op1 == 0x10 && op2 == 0x0 && (rn & 0xe) == 0x1)
+    return visitor->others (insn, "setend", data);
+  else if ((op1 & 0x60) == 0x20)
+    return visitor->others (insn, "neon dataproc", data);
+  else if ((op1 & 0x71) == 0x40)
+    return visitor->others (insn, "neon elt/struct load/store", data);
+  else if ((op1 & 0x77) == 0x41)
+    return visitor->others (insn, "unallocated mem hint", data);
+  else if ((op1 & 0x77) == 0x45)
+    return visitor->preload (insn, data);  /* pli.  */
+  else if ((op1 & 0x77) == 0x51)
+    {
+      if (rn != 0xf)
+	return visitor->preload (insn, data);  /* pld/pldw.  */
+      else
+	return visitor->unpred (insn, data);
+    }
+  else if ((op1 & 0x77) == 0x55)
+    return visitor->preload (insn, data);  /* pld/pldw.  */
+  else if (op1 == 0x57)
+    switch (op2)
+      {
+      case 0x1: return visitor->others (insn, "clrex", data);
+      case 0x4: return visitor->others (insn, "dsb", data);
+      case 0x5: return visitor->others (insn, "dmb", data);
+      case 0x6: return visitor->others (insn, "isb", data);
+      default: return visitor->unpred (insn, data);
+      }
+  else if ((op1 & 0x63) == 0x43)
+    return visitor->unpred (insn, data);
+  else if ((op2 & 0x1) == 0x0)
+    switch (op1 & ~0x80)
+      {
+      case 0x61:
+	return visitor->others (insn, "unallocated mem hint", data);
+      case 0x65:
+	return visitor->preload_reg (insn, data);  /* pli reg.  */
+      case 0x71: case 0x75:
+        /* pld/pldw reg.  */
+	return visitor->preload_reg (insn, data);
+      case 0x63: case 0x67: case 0x73: case 0x77:
+	return visitor->unpred (insn, data);
+      default:
+	return visitor->undef (insn, data);
+      }
+  else
+    return visitor->undef (insn, data);  /* Probably unreachable.  */
+}
+
+static int
+arm_decode_unconditional (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+			  struct arm_insn_reloc_data *data)
+{
+  if (bit (insn, 27) == 0)
+    return arm_decode_misc_memhint_neon (insn, visitor, data);
+  /* Switch on bits: 0bxxxxx321xxx0xxxxxxxxxxxxxxxxxxxx.  */
+  else switch (((insn & 0x7000000) >> 23) | ((insn & 0x100000) >> 20))
+    {
+    case 0x0: case 0x2:
+      return visitor->others (insn, "srs", data);
+
+    case 0x1: case 0x3:
+      return visitor->others (insn, "rfe", data);
+
+    case 0x4: case 0x5: case 0x6: case 0x7:
+      return visitor->b_bl_blx (insn, data);
+
+    case 0x8:
+      switch ((insn & 0xe00000) >> 21)
+	{
+	case 0x1: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
+	  /* stc/stc2.  */
+	  return visitor->copro_load_store (insn, data);
+
+	case 0x2:
+	  return visitor->others (insn, "mcrr/mcrr2", data);
+
+	default:
+	  return visitor->undef (insn, data);
+	}
+
+    case 0x9:
+      {
+	 int rn_f = (bits (insn, 16, 19) == 0xf);
+	switch ((insn & 0xe00000) >> 21)
+	  {
+	  case 0x1: case 0x3:
+	    /* ldc/ldc2 imm (undefined for rn == pc).  */
+	    return rn_f ? visitor->undef (insn, data)
+			: visitor->copro_load_store (insn, data);
+
+	  case 0x2:
+	    return visitor->others (insn, "mrrc/mrrc2", data);
+
+	  case 0x4: case 0x5: case 0x6: case 0x7:
+	    /* ldc/ldc2 lit (undefined for rn != pc).  */
+	    return rn_f ? visitor->copro_load_store (insn, data)
+			: visitor->undef (insn, data);
+
+	  default:
+	    return visitor->undef (insn, data);
+	  }
+      }
+
+    case 0xa:
+      return visitor->others (insn, "stc/stc2", data);
+
+    case 0xb:
+      if (bits (insn, 16, 19) == 0xf)
+        /* ldc/ldc2 lit.  */
+	return visitor->copro_load_store (insn, data);
+      else
+	return visitor->undef (insn, data);
+
+    case 0xc:
+      if (bit (insn, 4))
+	return visitor->others (insn, "mcr/mcr2", data);
+      else
+	return visitor->others (insn, "cdp/cdp2", data);
+
+    case 0xd:
+      if (bit (insn, 4))
+	return visitor->others (insn, "mrc/mrc2", data);
+      else
+	return visitor->others (insn, "cdp/cdp2", data);
+
+    default:
+      return visitor->undef (insn, data);
+    }
+}
+
+
+/* Decode miscellaneous instructions in dp/misc encoding space.  */
+
+static int
+arm_decode_miscellaneous (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+			  struct arm_insn_reloc_data *data)
+{
+  unsigned int op2 = bits (insn, 4, 6);
+  unsigned int op = bits (insn, 21, 22);
+
+  switch (op2)
+    {
+    case 0x0:
+      return visitor->others (insn, "mrs/msr", data);
+
+    case 0x1:
+      if (op == 0x1)  /* bx.  */
+	return visitor->bx_blx_reg (insn, data);
+      else if (op == 0x3)
+	return visitor->others (insn, "clz", data);
+      else
+	return visitor->undef (insn, data);
+
+    case 0x2:
+      if (op == 0x1)
+	/* Not really supported.  */
+	return visitor->others (insn, "bxj", data);
+      else
+	return visitor->undef (insn, data);
+
+    case 0x3:
+      if (op == 0x1)
+	return visitor->bx_blx_reg (insn, data);  /* blx register.  */
+      else
+	return visitor->undef (insn, data);
+
+    case 0x5:
+      return visitor->others (insn, "saturating add/sub", data);
+
+    case 0x7:
+      if (op == 0x1)
+	return visitor->others (insn, "bkpt", data);
+      else if (op == 0x3)
+	/* Not really supported.  */
+	return visitor->others (insn, "smc", data);
+
+    default:
+      return visitor->undef (insn, data);
+    }
+}
+
+static int
+arm_decode_dp_misc (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+		    struct arm_insn_reloc_data *data)
+{
+  if (bit (insn, 25))
+    switch (bits (insn, 20, 24))
+      {
+      case 0x10:
+	return visitor->others (insn, "movw", data);
+
+      case 0x14:
+	return visitor->others (insn, "movt", data);
+
+      case 0x12:
+      case 0x16:
+	return visitor->others (insn, "msr imm", data);
+
+      default:
+	return visitor->alu_imm (insn, data);
+      }
+  else
+    {
+      uint32_t op1 = bits (insn, 20, 24), op2 = bits (insn, 4, 7);
+
+      if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0)
+	return visitor->alu_reg (insn, data);
+      else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1)
+	return visitor->alu_shifted_reg (insn, data);
+      else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0)
+	return arm_decode_miscellaneous (insn, visitor, data);
+      else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8)
+	return visitor->others (insn, "halfword mul/mla", data);
+      else if ((op1 & 0x10) == 0x00 && op2 == 0x9)
+	return visitor->others (insn, "mul/mla", data);
+      else if ((op1 & 0x10) == 0x10 && op2 == 0x9)
+	return visitor->others (insn, "synch", data);
+      else if (op2 == 0xb || (op2 & 0xd) == 0xd)
+	/* 2nd arg means "unprivileged".  */
+	return visitor->extra_ld_st (insn, data, (op1 & 0x12) == 0x02);
+    }
+
+  /* Should be unreachable.  */
+  return 1;
+}
+
+
+static int
+arm_decode_ld_st_word_ubyte (uint32_t insn,
+			     struct arm_insn_reloc_visitor *visitor,
+			     struct arm_insn_reloc_data *data)
+{
+  int a = bit (insn, 25), b = bit (insn, 4);
+  uint32_t op1 = bits (insn, 20, 24);
+
+  if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02)
+      || (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b))
+    return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 0);
+  else if ((!a && (op1 & 0x17) == 0x02)
+	    || (a && (op1 & 0x17) == 0x02 && !b))
+    return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 1);
+  else if ((!a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03)
+	    || (a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03 && !b))
+    return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 0);
+  else if ((!a && (op1 & 0x17) == 0x03)
+	   || (a && (op1 & 0x17) == 0x03 && !b))
+    return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 1);
+  else if ((!a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06)
+	    || (a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06 && !b))
+    return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 0);
+  else if ((!a && (op1 & 0x17) == 0x06)
+	   || (a && (op1 & 0x17) == 0x06 && !b))
+    return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 1);
+  else if ((!a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07)
+	   || (a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07 && !b))
+    return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 0);
+  else if ((!a && (op1 & 0x17) == 0x07)
+	   || (a && (op1 & 0x17) == 0x07 && !b))
+    return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 1);
+
+  /* Should be unreachable.  */
+  return 1;
+}
+
+static int
+arm_decode_media (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+		  struct arm_insn_reloc_data *data)
+{
+  switch (bits (insn, 20, 24))
+    {
+    case 0x00: case 0x01: case 0x02: case 0x03:
+      return visitor->others (insn, "parallel add/sub signed", data);
+
+    case 0x04: case 0x05: case 0x06: case 0x07:
+      return visitor->others (insn, "parallel add/sub unsigned", data);
+
+    case 0x08: case 0x09: case 0x0a: case 0x0b:
+    case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+      return visitor->others (insn, "decode/pack/unpack/saturate/reverse",
+			      data);
+
+    case 0x18:
+      if (bits (insn, 5, 7) == 0)  /* op2.  */
+	 {
+	  if (bits (insn, 12, 15) == 0xf)
+	    return visitor->others (insn, "usad8", data);
+	  else
+	    return visitor->others (insn, "usada8", data);
+	}
+      else
+	 return visitor->undef (insn, data);
+
+    case 0x1a: case 0x1b:
+      if (bits (insn, 5, 6) == 0x2)  /* op2[1:0].  */
+	return visitor->others (insn, "sbfx", data);
+      else
+	return visitor->undef (insn, data);
+
+    case 0x1c: case 0x1d:
+      if (bits (insn, 5, 6) == 0x0)  /* op2[1:0].  */
+	 {
+	  if (bits (insn, 0, 3) == 0xf)
+	    return visitor->others (insn, "bfc", data);
+	  else
+	    return visitor->others (insn, "bfi", data);
+	}
+      else
+	return visitor->undef (insn, data);
+
+    case 0x1e: case 0x1f:
+      if (bits (insn, 5, 6) == 0x2)  /* op2[1:0].  */
+	return visitor->others (insn, "ubfx", data);
+      else
+	return visitor->undef (insn, data);
+    }
+
+  /* Should be unreachable.  */
+  return 1;
+}
+
+static int
+arm_decode_b_bl_ldmstm (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+			struct arm_insn_reloc_data *data)
+{
+  if (bit (insn, 25))
+    return visitor->b_bl_blx (insn, data);
+  else
+    return visitor->block_xfer (insn, data);
+}
+
+static int
+arm_decode_ext_reg_ld_st (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+			  struct arm_insn_reloc_data *data)
+{
+  unsigned int opcode = bits (insn, 20, 24);
+
+  switch (opcode)
+    {
+    case 0x04: case 0x05:  /* VFP/Neon mrrc/mcrr.  */
+      return visitor->others (insn, "vfp/neon mrrc/mcrr", data);
+
+    case 0x08: case 0x0a: case 0x0c: case 0x0e:
+    case 0x12: case 0x16:
+      return visitor->others (insn, "vfp/neon vstm/vpush", data);
+
+    case 0x09: case 0x0b: case 0x0d: case 0x0f:
+    case 0x13: case 0x17:
+      return visitor->others (insn, "vfp/neon vldm/vpop", data);
+
+    case 0x10: case 0x14: case 0x18: case 0x1c:  /* vstr.  */
+    case 0x11: case 0x15: case 0x19: case 0x1d:  /* vldr.  */
+      /* Note: no writeback for these instructions.  Bit 25 will always be
+	 zero though (via caller), so the following works OK.  */
+      return visitor->copro_load_store (insn, data);
+    }
+
+  /* Should be unreachable.  */
+  return 1;
+}
+
+
+static int
+arm_decode_svc_copro (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+		      struct arm_insn_reloc_data *data)
+{
+  unsigned int op1 = bits (insn, 20, 25);
+  int op = bit (insn, 4);
+  unsigned int coproc = bits (insn, 8, 11);
+
+  if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa)
+    return arm_decode_ext_reg_ld_st (insn, visitor, data);
+  else if ((op1 & 0x21) == 0x00 && (op1 & 0x3a) != 0x00
+	   && (coproc & 0xe) != 0xa)
+    /* stc/stc2.  */
+    return visitor->copro_load_store (insn, data);
+  else if ((op1 & 0x21) == 0x01 && (op1 & 0x3a) != 0x00
+	   && (coproc & 0xe) != 0xa)
+    /* ldc/ldc2 imm/lit.  */
+    return visitor->copro_load_store (insn, data);
+  else if ((op1 & 0x3e) == 0x00)
+    return visitor->undef (insn, data);
+  else if ((op1 & 0x3e) == 0x04 && (coproc & 0xe) == 0xa)
+    return visitor->others (insn, "neon 64bit xfer", data);
+  else if (op1 == 0x04 && (coproc & 0xe) != 0xa)
+    return visitor->others (insn, "mcrr/mcrr2", data);
+  else if (op1 == 0x05 && (coproc & 0xe) != 0xa)
+    return visitor->others (insn, "mrrc/mrrc2", data);
+  else if ((op1 & 0x30) == 0x20 && !op)
+    {
+      if ((coproc & 0xe) == 0xa)
+	return visitor->others (insn, "vfp dataproc", data);
+      else
+	return visitor->others (insn, "cdp/cdp2", data);
+    }
+  else if ((op1 & 0x30) == 0x20 && op)
+    return visitor->others (insn, "neon 8/16/32 bit xfer", data);
+  else if ((op1 & 0x31) == 0x20 && op && (coproc & 0xe) != 0xa)
+    return visitor->others (insn, "mcr/mcr2", data);
+  else if ((op1 & 0x31) == 0x21 && op && (coproc & 0xe) != 0xa)
+    return visitor->others (insn, "mrc/mrc2", data);
+  else if ((op1 & 0x30) == 0x30)
+    return visitor->svc (insn, data);
+  else
+    return visitor->undef (insn, data);  /* Possibly unreachable.  */
+}
+
+int
+arm_relocate_insn (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+		   struct arm_insn_reloc_data *data)
+{
+  int err = 1;
+
+  if ((insn & 0xf0000000) == 0xf0000000)
+    err = arm_decode_unconditional (insn, visitor, data);
+  else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24))
+    {
+    case 0x0: case 0x1: case 0x2: case 0x3:
+      err = arm_decode_dp_misc (insn, visitor, data);
+      break;
+
+    case 0x4: case 0x5: case 0x6:
+      err = arm_decode_ld_st_word_ubyte (insn, visitor, data);
+      break;
+
+    case 0x7:
+      err = arm_decode_media (insn, visitor, data);
+      break;
+
+    case 0x8: case 0x9: case 0xa: case 0xb:
+      err = arm_decode_b_bl_ldmstm (insn, visitor, data);
+      break;
+
+    case 0xc: case 0xd: case 0xe: case 0xf:
+      err = arm_decode_svc_copro (insn, visitor, data);
+      break;
+    }
+
+  return err;
+}
diff --git a/gdb/arch/arm-insn-reloc.h b/gdb/arch/arm-insn-reloc.h
new file mode 100644
index 0000000..18d3916
--- /dev/null
+++ b/gdb/arch/arm-insn-reloc.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef ARM_INSN_RELOC_H
+#define ARM_INSN_RELOC_H
+
+struct arm_insn_reloc_data;
+
+struct arm_insn_reloc_visitor
+{
+  int (*alu_imm) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*alu_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*alu_shifted_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*b_bl_blx) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*block_xfer) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*bx_blx_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*copro_load_store) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*extra_ld_st) (uint32_t insn, struct arm_insn_reloc_data *data,
+		      int unprivileged);
+  int (*ldr_str_ldrb_strb) (uint32_t insn, struct arm_insn_reloc_data *data,
+			    int load, int size, int usermode);
+  int (*others) (uint32_t insn, const char *iname,
+		 struct arm_insn_reloc_data *data);
+  int (*preload) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*preload_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*svc) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*undef) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*unpred) (uint32_t insn, struct arm_insn_reloc_data *data);
+};
+
+extern int arm_relocate_insn (uint32_t insn,
+			      struct arm_insn_reloc_visitor *visitor,
+			      struct arm_insn_reloc_data *data);
+
+#endif /* ARM_INSN_RELOC_H */
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 0f35eb3..1af4d36 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -47,6 +47,7 @@
 
 #include "arch/arm.h"
 #include "arch/arm-get-next-pcs.h"
+#include "arch/arm-insn-reloc.h"
 #include "arm-tdep.h"
 #include "gdb/sim-arm.h"
 
@@ -4480,28 +4481,6 @@ struct arm_insn_reloc_data
   struct regcache *regs;
 };
 
-struct arm_insn_reloc_visitor
-{
-  int (*alu_imm) (uint32_t insn, struct arm_insn_reloc_data *data);
-  int (*alu_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
-  int (*alu_shifted_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
-  int (*b_bl_blx) (uint32_t insn, struct arm_insn_reloc_data *data);
-  int (*block_xfer) (uint32_t insn, struct arm_insn_reloc_data *data);
-  int (*bx_blx_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
-  int (*copro_load_store) (uint32_t insn, struct arm_insn_reloc_data *data);
-  int (*extra_ld_st) (uint32_t insn, struct arm_insn_reloc_data *data,
-		      int unprivileged);
-  int (*ldr_str_ldrb_strb) (uint32_t insn, struct arm_insn_reloc_data *data,
-			    int load, int size, int usermode);
-  int (*others) (uint32_t insn, const char *iname,
-		 struct arm_insn_reloc_data *data);
-  int (*preload) (uint32_t insn, struct arm_insn_reloc_data *data);
-  int (*preload_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
-  int (*svc) (uint32_t insn, struct arm_insn_reloc_data *data);
-  int (*undef) (uint32_t insn, struct arm_insn_reloc_data *data);
-  int (*unpred) (uint32_t insn, struct arm_insn_reloc_data *data);
-};
-
 struct thumb_32bit_insn_reloc_visitor
 {
   int (*alu_imm) (uint16_t insn1, uint16_t insn2,
@@ -6525,375 +6504,6 @@ arm_copy_unpred (uint32_t insn, struct arm_insn_reloc_data *data)
 /* The decode_* functions are instruction decoding helpers.  They mostly follow
    the presentation in the ARM ARM.  */
 
-static int
-arm_decode_misc_memhint_neon (uint32_t insn,
-			      struct arm_insn_reloc_visitor *visitor,
-			      struct arm_insn_reloc_data *data)
-{
-  unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7);
-  unsigned int rn = bits (insn, 16, 19);
-
-  if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0xe) == 0x0)
-    return visitor->others (insn, "cps", data);
-  else if (op1 == 0x10 && op2 == 0x0 && (rn & 0xe) == 0x1)
-    return visitor->others (insn, "setend", data);
-  else if ((op1 & 0x60) == 0x20)
-    return visitor->others (insn, "neon dataproc", data);
-  else if ((op1 & 0x71) == 0x40)
-    return visitor->others (insn, "neon elt/struct load/store", data);
-  else if ((op1 & 0x77) == 0x41)
-    return visitor->others (insn, "unallocated mem hint", data);
-  else if ((op1 & 0x77) == 0x45)
-    return visitor->preload (insn, data);  /* pli.  */
-  else if ((op1 & 0x77) == 0x51)
-    {
-      if (rn != 0xf)
-	return visitor->preload (insn, data);  /* pld/pldw.  */
-      else
-	return visitor->unpred (insn, data);
-    }
-  else if ((op1 & 0x77) == 0x55)
-    return visitor->preload (insn, data);  /* pld/pldw.  */
-  else if (op1 == 0x57)
-    switch (op2)
-      {
-      case 0x1: return visitor->others (insn, "clrex", data);
-      case 0x4: return visitor->others (insn, "dsb", data);
-      case 0x5: return visitor->others (insn, "dmb", data);
-      case 0x6: return visitor->others (insn, "isb", data);
-      default: return visitor->unpred (insn, data);
-      }
-  else if ((op1 & 0x63) == 0x43)
-    return visitor->unpred (insn, data);
-  else if ((op2 & 0x1) == 0x0)
-    switch (op1 & ~0x80)
-      {
-      case 0x61:
-	return visitor->others (insn, "unallocated mem hint", data);
-      case 0x65:
-	return visitor->preload_reg (insn, data);  /* pli reg.  */
-      case 0x71: case 0x75:
-        /* pld/pldw reg.  */
-	return visitor->preload_reg (insn, data);
-      case 0x63: case 0x67: case 0x73: case 0x77:
-	return visitor->unpred (insn, data);
-      default:
-	return visitor->undef (insn, data);
-      }
-  else
-    return visitor->undef (insn, data);  /* Probably unreachable.  */
-}
-
-static int
-arm_decode_unconditional (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
-			  struct arm_insn_reloc_data *data)
-{
-  if (bit (insn, 27) == 0)
-    return arm_decode_misc_memhint_neon (insn, visitor, data);
-  /* Switch on bits: 0bxxxxx321xxx0xxxxxxxxxxxxxxxxxxxx.  */
-  else switch (((insn & 0x7000000) >> 23) | ((insn & 0x100000) >> 20))
-    {
-    case 0x0: case 0x2:
-      return visitor->others (insn, "srs", data);
-
-    case 0x1: case 0x3:
-      return visitor->others (insn, "rfe", data);
-
-    case 0x4: case 0x5: case 0x6: case 0x7:
-      return visitor->b_bl_blx (insn, data);
-
-    case 0x8:
-      switch ((insn & 0xe00000) >> 21)
-	{
-	case 0x1: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
-	  /* stc/stc2.  */
-	  return visitor->copro_load_store (insn, data);
-
-	case 0x2:
-	  return visitor->others (insn, "mcrr/mcrr2", data);
-
-	default:
-	  return visitor->undef (insn, data);
-	}
-
-    case 0x9:
-      {
-	 int rn_f = (bits (insn, 16, 19) == 0xf);
-	switch ((insn & 0xe00000) >> 21)
-	  {
-	  case 0x1: case 0x3:
-	    /* ldc/ldc2 imm (undefined for rn == pc).  */
-	    return rn_f ? visitor->undef (insn, data)
-			: visitor->copro_load_store (insn, data);
-
-	  case 0x2:
-	    return visitor->others (insn, "mrrc/mrrc2", data);
-
-	  case 0x4: case 0x5: case 0x6: case 0x7:
-	    /* ldc/ldc2 lit (undefined for rn != pc).  */
-	    return rn_f ? visitor->copro_load_store (insn, data)
-			: visitor->undef (insn, data);
-
-	  default:
-	    return visitor->undef (insn, data);
-	  }
-      }
-
-    case 0xa:
-      return visitor->others (insn, "stc/stc2", data);
-
-    case 0xb:
-      if (bits (insn, 16, 19) == 0xf)
-        /* ldc/ldc2 lit.  */
-	return visitor->copro_load_store (insn, data);
-      else
-	return visitor->undef (insn, data);
-
-    case 0xc:
-      if (bit (insn, 4))
-	return visitor->others (insn, "mcr/mcr2", data);
-      else
-	return visitor->others (insn, "cdp/cdp2", data);
-
-    case 0xd:
-      if (bit (insn, 4))
-	return visitor->others (insn, "mrc/mrc2", data);
-      else
-	return visitor->others (insn, "cdp/cdp2", data);
-
-    default:
-      return visitor->undef (insn, data);
-    }
-}
-
-/* Decode miscellaneous instructions in dp/misc encoding space.  */
-
-static int
-arm_decode_miscellaneous (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
-			  struct arm_insn_reloc_data *data)
-{
-  unsigned int op2 = bits (insn, 4, 6);
-  unsigned int op = bits (insn, 21, 22);
-
-  switch (op2)
-    {
-    case 0x0:
-      return visitor->others (insn, "mrs/msr", data);
-
-    case 0x1:
-      if (op == 0x1)  /* bx.  */
-	return visitor->bx_blx_reg (insn, data);
-      else if (op == 0x3)
-	return visitor->others (insn, "clz", data);
-      else
-	return visitor->undef (insn, data);
-
-    case 0x2:
-      if (op == 0x1)
-	/* Not really supported.  */
-	return visitor->others (insn, "bxj", data);
-      else
-	return visitor->undef (insn, data);
-
-    case 0x3:
-      if (op == 0x1)
-	return visitor->bx_blx_reg (insn, data);  /* blx register.  */
-      else
-	return visitor->undef (insn, data);
-
-    case 0x5:
-      return visitor->others (insn, "saturating add/sub", data);
-
-    case 0x7:
-      if (op == 0x1)
-	return visitor->others (insn, "bkpt", data);
-      else if (op == 0x3)
-	/* Not really supported.  */
-	return visitor->others (insn, "smc", data);
-
-    default:
-      return visitor->undef (insn, data);
-    }
-}
-
-static int
-arm_decode_dp_misc (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
-		    struct arm_insn_reloc_data *data)
-{
-  if (bit (insn, 25))
-    switch (bits (insn, 20, 24))
-      {
-      case 0x10:
-	return visitor->others (insn, "movw", data);
-
-      case 0x14:
-	return visitor->others (insn, "movt", data);
-
-      case 0x12:
-      case 0x16:
-	return visitor->others (insn, "msr imm", data);
-
-      default:
-	return visitor->alu_imm (insn, data);
-      }
-  else
-    {
-      uint32_t op1 = bits (insn, 20, 24), op2 = bits (insn, 4, 7);
-
-      if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0)
-	return visitor->alu_reg (insn, data);
-      else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1)
-	return visitor->alu_shifted_reg (insn, data);
-      else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0)
-	return arm_decode_miscellaneous (insn, visitor, data);
-      else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8)
-	return visitor->others (insn, "halfword mul/mla", data);
-      else if ((op1 & 0x10) == 0x00 && op2 == 0x9)
-	return visitor->others (insn, "mul/mla", data);
-      else if ((op1 & 0x10) == 0x10 && op2 == 0x9)
-	return visitor->others (insn, "synch", data);
-      else if (op2 == 0xb || (op2 & 0xd) == 0xd)
-	/* 2nd arg means "unprivileged".  */
-	return visitor->extra_ld_st (insn, data, (op1 & 0x12) == 0x02);
-    }
-
-  /* Should be unreachable.  */
-  return 1;
-}
-
-static int
-arm_decode_ld_st_word_ubyte (uint32_t insn,
-			     struct arm_insn_reloc_visitor *visitor,
-			     struct arm_insn_reloc_data *data)
-{
-  int a = bit (insn, 25), b = bit (insn, 4);
-  uint32_t op1 = bits (insn, 20, 24);
-
-  if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02)
-      || (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b))
-    return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 0);
-  else if ((!a && (op1 & 0x17) == 0x02)
-	    || (a && (op1 & 0x17) == 0x02 && !b))
-    return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 1);
-  else if ((!a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03)
-	    || (a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03 && !b))
-    return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 0);
-  else if ((!a && (op1 & 0x17) == 0x03)
-	   || (a && (op1 & 0x17) == 0x03 && !b))
-    return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 1);
-  else if ((!a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06)
-	    || (a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06 && !b))
-    return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 0);
-  else if ((!a && (op1 & 0x17) == 0x06)
-	   || (a && (op1 & 0x17) == 0x06 && !b))
-    return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 1);
-  else if ((!a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07)
-	   || (a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07 && !b))
-    return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 0);
-  else if ((!a && (op1 & 0x17) == 0x07)
-	   || (a && (op1 & 0x17) == 0x07 && !b))
-    return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 1);
-
-  /* Should be unreachable.  */
-  return 1;
-}
-
-static int
-arm_decode_media (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
-		  struct arm_insn_reloc_data *data)
-{
-  switch (bits (insn, 20, 24))
-    {
-    case 0x00: case 0x01: case 0x02: case 0x03:
-      return visitor->others (insn, "parallel add/sub signed", data);
-
-    case 0x04: case 0x05: case 0x06: case 0x07:
-      return visitor->others (insn, "parallel add/sub unsigned", data);
-
-    case 0x08: case 0x09: case 0x0a: case 0x0b:
-    case 0x0c: case 0x0d: case 0x0e: case 0x0f:
-      return visitor->others (insn, "decode/pack/unpack/saturate/reverse",
-			      data);
-
-    case 0x18:
-      if (bits (insn, 5, 7) == 0)  /* op2.  */
-	 {
-	  if (bits (insn, 12, 15) == 0xf)
-	    return visitor->others (insn, "usad8", data);
-	  else
-	    return visitor->others (insn, "usada8", data);
-	}
-      else
-	 return visitor->undef (insn, data);
-
-    case 0x1a: case 0x1b:
-      if (bits (insn, 5, 6) == 0x2)  /* op2[1:0].  */
-	return visitor->others (insn, "sbfx", data);
-      else
-	return visitor->undef (insn, data);
-
-    case 0x1c: case 0x1d:
-      if (bits (insn, 5, 6) == 0x0)  /* op2[1:0].  */
-	 {
-	  if (bits (insn, 0, 3) == 0xf)
-	    return visitor->others (insn, "bfc", data);
-	  else
-	    return visitor->others (insn, "bfi", data);
-	}
-      else
-	return visitor->undef (insn, data);
-
-    case 0x1e: case 0x1f:
-      if (bits (insn, 5, 6) == 0x2)  /* op2[1:0].  */
-	return visitor->others (insn, "ubfx", data);
-      else
-	return visitor->undef (insn, data);
-    }
-
-  /* Should be unreachable.  */
-  return 1;
-}
-
-static int
-arm_decode_b_bl_ldmstm (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
-			struct arm_insn_reloc_data *data)
-{
-  if (bit (insn, 25))
-    return visitor->b_bl_blx (insn, data);
-  else
-    return visitor->block_xfer (insn, data);
-}
-
-static int
-arm_decode_ext_reg_ld_st (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
-			  struct arm_insn_reloc_data *data)
-{
-  unsigned int opcode = bits (insn, 20, 24);
-
-  switch (opcode)
-    {
-    case 0x04: case 0x05:  /* VFP/Neon mrrc/mcrr.  */
-      return visitor->others (insn, "vfp/neon mrrc/mcrr", data);
-
-    case 0x08: case 0x0a: case 0x0c: case 0x0e:
-    case 0x12: case 0x16:
-      return visitor->others (insn, "vfp/neon vstm/vpush", data);
-
-    case 0x09: case 0x0b: case 0x0d: case 0x0f:
-    case 0x13: case 0x17:
-      return visitor->others (insn, "vfp/neon vldm/vpop", data);
-
-    case 0x10: case 0x14: case 0x18: case 0x1c:  /* vstr.  */
-    case 0x11: case 0x15: case 0x19: case 0x1d:  /* vldr.  */
-      /* Note: no writeback for these instructions.  Bit 25 will always be
-	 zero though (via caller), so the following works OK.  */
-      return visitor->copro_load_store (insn, data);
-    }
-
-  /* Should be unreachable.  */
-  return 1;
-}
-
 /* Decode shifted register instructions.  */
 
 static int
@@ -6949,51 +6559,6 @@ thumb2_decode_ext_reg_ld_st (uint16_t insn1, uint16_t insn2,
 }
 
 static int
-arm_decode_svc_copro (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
-		      struct arm_insn_reloc_data *data)
-{
-  unsigned int op1 = bits (insn, 20, 25);
-  int op = bit (insn, 4);
-  unsigned int coproc = bits (insn, 8, 11);
-
-  if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa)
-    return arm_decode_ext_reg_ld_st (insn, visitor, data);
-  else if ((op1 & 0x21) == 0x00 && (op1 & 0x3a) != 0x00
-	   && (coproc & 0xe) != 0xa)
-    /* stc/stc2.  */
-    return visitor->copro_load_store (insn, data);
-  else if ((op1 & 0x21) == 0x01 && (op1 & 0x3a) != 0x00
-	   && (coproc & 0xe) != 0xa)
-    /* ldc/ldc2 imm/lit.  */
-    return visitor->copro_load_store (insn, data);
-  else if ((op1 & 0x3e) == 0x00)
-    return visitor->undef (insn, data);
-  else if ((op1 & 0x3e) == 0x04 && (coproc & 0xe) == 0xa)
-    return visitor->others (insn, "neon 64bit xfer", data);
-  else if (op1 == 0x04 && (coproc & 0xe) != 0xa)
-    return visitor->others (insn, "mcrr/mcrr2", data);
-  else if (op1 == 0x05 && (coproc & 0xe) != 0xa)
-    return visitor->others (insn, "mrrc/mrrc2", data);
-  else if ((op1 & 0x30) == 0x20 && !op)
-    {
-      if ((coproc & 0xe) == 0xa)
-	return visitor->others (insn, "vfp dataproc", data);
-      else
-	return visitor->others (insn, "cdp/cdp2", data);
-    }
-  else if ((op1 & 0x30) == 0x20 && op)
-    return visitor->others (insn, "neon 8/16/32 bit xfer", data);
-  else if ((op1 & 0x31) == 0x20 && op && (coproc & 0xe) != 0xa)
-    return visitor->others (insn, "mcr/mcr2", data);
-  else if ((op1 & 0x31) == 0x21 && op && (coproc & 0xe) != 0xa)
-    return visitor->others (insn, "mrc/mrc2", data);
-  else if ((op1 & 0x30) == 0x30)
-    return visitor->svc (insn, data);
-  else
-    return visitor->undef (insn, data);  /* Possibly unreachable.  */
-}
-
-static int
 thumb2_decode_svc_copro (uint16_t insn1, uint16_t insn2,
 			 struct thumb_32bit_insn_reloc_visitor *visitor,
 			 struct arm_insn_reloc_data *data)
@@ -7614,40 +7179,6 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
 
 }
 
-static int
-arm_relocate_insn (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
-		   struct arm_insn_reloc_data *data)
-{
-  int err = 1;
-
-  if ((insn & 0xf0000000) == 0xf0000000)
-    err = arm_decode_unconditional (insn, visitor, data);
-  else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24))
-    {
-    case 0x0: case 0x1: case 0x2: case 0x3:
-      err = arm_decode_dp_misc (insn, visitor, data);
-      break;
-
-    case 0x4: case 0x5: case 0x6:
-      err = arm_decode_ld_st_word_ubyte (insn, visitor, data);
-      break;
-
-    case 0x7:
-      err = arm_decode_media (insn, visitor, data);
-      break;
-
-    case 0x8: case 0x9: case 0xa: case 0xb:
-      err = arm_decode_b_bl_ldmstm (insn, visitor, data);
-      break;
-
-    case 0xc: case 0xd: case 0xe: case 0xf:
-      err = arm_decode_svc_copro (insn, visitor, data);
-      break;
-    }
-
-  return err;
-}
-
 static struct arm_insn_reloc_visitor arm_insn_reloc_visitor =
 {
   arm_copy_alu_imm,
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 7f1aac3..e447356 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -91,7 +91,7 @@ arm*-wince-pe | arm*-*-mingw32ce*)
 	;;
 arm*-*-linux*)
 	# Target: ARM based machine running GNU/Linux
-	gdb_target_obs="arm.o arm-linux.o arm-get-next-pcs.o arm-tdep.o \
+	gdb_target_obs="arm.o arm-linux.o arm-get-next-pcs.o arm-insn-reloc.o arm-tdep.o \
                         arm-linux-tdep.o glibc-tdep.o \
 			solib-svr4.o symfile-mem.o linux-tdep.o linux-record.o"
 	build_gdbserver=yes
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 18/18] arm fast tracepoints: Relocation of Thumb 32-bits instructions
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (8 preceding siblings ...)
  2016-07-05 13:41 ` [PATCH v3 15/18] JIT conditions support for ARM tracepoints Antoine Tremblay
@ 2016-07-05 13:42 ` 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
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:42 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 14/18] Fast tracepoint support for ARM on Linux
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (14 preceding siblings ...)
  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 ` Antoine Tremblay
  2016-07-05 13:56 ` [PATCH v3 04/18] arm-tdep.c: Use relocation visitor in ARM instruction decoding Antoine Tremblay
  2016-07-05 13:56 ` [PATCH v3 05/18] arm-tdep.c: Use relocation visitor in Thumb 32-bits " Antoine Tremblay
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:42 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

This patch enables fast tracepoints for ARM on Linux.

There are some limitations:

 * The tracepoint insertion will fail if the distance from the
   instruction to the jump pad is big.

 * As of this patch, the implementation will reject any tracepoint
   placed on an instruction that might be PC-relative.  Later patches
   implement relocation for some selected instructions.

 * It is only possible to place fast tracepoints on 4-byte
   instructions, which also limits the valid locations in Thumb mode.

 * As of this patch, JIT compilation of condition evaluation is not
   implemented.  It is added in a later patch.

Henrik Wallin  <henrik.wallin@windriver.com>
Simon Marchi  <simon.marchi@ericsson.com>
Antoine Tremblay  <antoine.tremblay@ericsson.com>

gdb/ChangeLog:

	* arm-tdep.c (arm_fast_tracepoint_valid_at): New function.
	(arm_gdbarch_init): Initialize gdbarch_fast_tracepoint_valid_at.

gdb/gdbserver/ChangeLog:

	* Makefile.in (SFILES): Add arm-insn-reloc.c.
	(arm-core-ipa.o): New rule.
	(arm-with-neon-ipa.o): Likewise.
	(arm-with-vfpv2-ipa.o): Likewise.
	(arm-with-vfpv3-ipa.o): Likewise.
	(linux-arm-ipa.o): Likewise.
	(arm-get-next-pcs.o:): Likewise.
	(arm-insn-reloc.o): Likewise.
	* configure.srv (arm*-*-linux*): Add arm-insn-reloc.o, arm-core-ipa.o,
	arm-with-neon-ipa.o, arm-with-vfpv2-ipa.o, arm-with-vfpv3-ipa.o,
	* linux-aarch32-low.c (enum arm_breakpoint_kinds): Move to...
	* linux-aarch32-low.h (enum arm_breakpoint_kinds): ...here
	* linux-arm-ipa.c: New file.
	* linux-arm-low.c: Include inttypes.h, arch/arm-insn-utils.h,
	arch/arm-insn-emit.h, arch/arm-insn-reloc.h, ax.h.
	(enum arm_linux_tdesc): New enum.
	(append_inferior_memory): New function.
	(append_inferior_memory_32): Likewise.
	(append_inferior_memory_16): Likewise.
	(struct arm_insn_reloc_data): New struct.
	(arm_reloc_others): New function.
	(arm_reloc_alu_imm): Likewise.
	(arm_reloc_alu_reg): Likewise.
	(arm_reloc_alu_shifted_reg): Likewise.
	(arm_reloc_b_bl_blx): Likewise.
	(arm_reloc_block_xfer): Likewise.
	(arm_reloc_bx_blx_reg): Likewise.
	(arm_reloc_copro_load_store): Likwise.
	(arm_reloc_extra_ld_st): Likewise.
	(arm_reloc_ldr_str_ldrb_strb): Likewise.
	(arm_reloc_preload): Likewise.
	(arm_reloc_preload_reg): Likewise.
	(arm_reloc_svc): Likewise.
	(arm_reloc_undef): Likewise.
	(arm_reloc_unpred): Likewise.
	(struct arm_insn_reloc_visitor): New struct.
	(copy_instruction_arm): New function.
	(thumb32_reloc_others): Likewise.
	(thumb32_reloc_alu_imm): Likewise.
	(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.
	(struct thumb_32bit_insn_reloc_visitor): New struct.
	(copy_instruction_thumb32): New function.
	(arm_get_thread_area): Likewise.
	(arm_get_min_fast_tracepoint_insn_len): Likewise.
	(arm_install_fast_tracepoint_jump_pad_arm): Likewise.
	(arm_install_fast_tracepoint_jump_pad_thumb2): Likewise.
	(arm_get_ipa_tdesc_idx): Likewise.
	(struct linux_target_ops) <get_thread_area>: Initialize.
	<install_fast_tracepoint_jump_pad>: Likewise.
	<get_min_fast_tracepoint_insn_len>: Likewise.
	<supports_hardware_single_step>: Likewise.
	<get_ipa_tdesc_idx>: Likewise.
	* tracepoint.c (get_ipa_tdesc_idx): New function.
	* tracepoint.h (get_ipa_tdesc_idx): New function delcaration.

gdb/testsuite/ChangeLog:

	* lib/trace-support.exp (gdb_target_supports_fast_trace): Add
	aarch32 targets.
---
 gdb/arm-tdep.c                      |  45 ++
 gdb/gdbserver/Makefile.in           |  21 +-
 gdb/gdbserver/configure.srv         |   5 +
 gdb/gdbserver/linux-aarch32-low.c   |   8 -
 gdb/gdbserver/linux-aarch32-low.h   |   8 +
 gdb/gdbserver/linux-arm-ipa.c       | 217 +++++++++
 gdb/gdbserver/linux-arm-low.c       | 917 +++++++++++++++++++++++++++++++++++-
 gdb/gdbserver/tracepoint.c          |   7 +
 gdb/gdbserver/tracepoint.h          |   1 +
 gdb/testsuite/lib/trace-support.exp |   3 +-
 10 files changed, 1218 insertions(+), 14 deletions(-)
 create mode 100644 gdb/gdbserver/linux-arm-ipa.c

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 4a4826a..2a83b82 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -8180,6 +8180,49 @@ arm_code_of_frame_writable (struct gdbarch *gdbarch, struct frame_info *frame)
     return 1;
 }
 
+static int
+arm_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
+			      CORE_ADDR addr, char **msg)
+{
+  /* A branch instruction used for fast tracepoint takes 4 bytes.
+     (A 2 bytes branch instruction only gets us 4k away,
+     so will not be enough.)
+
+     target gdbserver will validate that the relative branch
+     distance will fit in the instructions.
+     (16M for Thumb, 32M for ARM)
+
+     We only allow to replace one instruction. (4 bytes)
+     Replacing 2 instructions is not safe. Consider
+     the case where code wants to jump to the 2nd instruction - it
+     will jump into the middle of a branch instruction.   */
+
+  if (arm_pc_is_thumb (gdbarch, addr))
+    {
+      uint16_t insn
+	= read_memory_unsigned_integer (addr, 2,
+					gdbarch_byte_order_for_code (gdbarch));
+
+      if (thumb_insn_size (insn) == 2)
+	{
+	  if (msg)
+	    *msg = xstrprintf (_ ("; instruction is only 2 bytes long, "
+				  "need 4 bytes for the jump"));
+	  return 0;
+	}
+    }
+  else
+    {
+      /* In ARM mode, all instructions are 4 bytes long, so there is
+         no restriction related to instruction length.  */
+    }
+
+  if (msg)
+    *msg = NULL;
+
+  return 1;
+}
+
 \f
 /* Initialize the current architecture based on INFO.  If possible,
    re-use an architecture from ARCHES, which is a list of
@@ -8784,6 +8827,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     user_reg_add (gdbarch, arm_register_aliases[i].name,
 		  value_of_arm_user_reg, &arm_register_aliases[i].regnum);
 
+  set_gdbarch_fast_tracepoint_valid_at (gdbarch, arm_fast_tracepoint_valid_at);
+
   return gdbarch;
 }
 
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 271f804..217a324 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -186,7 +186,8 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/fileio.c $(srcdir)/nat/linux-namespaces.c \
 	$(srcdir)/arch/arm.c $(srcdir)/common/common-regcache.c \
 	$(srcdir)/arch/arm-linux.c $(srcdir)/arch/arm-get-next-pcs.c \
-	$(srcdir)/arch/arm-insn-emit.c
+	$(srcdir)/arch/arm-insn-emit.c \
+	$(srcdir)/arch/arm-insn-reloc.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -648,6 +649,21 @@ rsp-low-ipa.o: ../common/rsp-low.c
 errors-ipa.o: ../common/errors.c
 	$(IPAGENT_COMPILE) $<
 	$(POSTCOMPILE)
+arm-core-ipa.o: reg-arm.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+arm-with-neon-ipa.o: arm-with-neon.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+arm-with-vfpv2-ipa.o: arm-with-vfpv2.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+arm-with-vfpv3-ipa.o: arm-with-vfpv3.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+linux-arm-ipa.o: linux-arm-ipa.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
 
 ax.o: ax.c
 	$(COMPILE) $(WARN_CFLAGS_NO_FORMAT) $<
@@ -731,6 +747,9 @@ arm-get-next-pcs.o: ../arch/arm-get-next-pcs.c
 arm-insn-emit.o: ../arch/arm-insn-emit.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+arm-insn-reloc.o: ../arch/arm-insn-reloc.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 
 # Native object files rules from ../nat
 
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 34d4be8..0da536f 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -78,6 +78,7 @@ case "${target}" in
 			srv_tgtobj="${srv_tgtobj} arm-get-next-pcs.o"
 			srv_tgtobj="${srv_tgtobj} arm-insn-emit.o"
 			srv_tgtobj="${srv_tgtobj} arm-insn-utils.o"
+			srv_tgtobj="${srv_tgtobj} arm-insn-reloc.o"
 			srv_xmlfiles="arm-with-iwmmxt.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv3.xml"
@@ -89,6 +90,10 @@ case "${target}" in
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
+			ipa_obj="arm-core-ipa.o arm-with-neon-ipa.o"
+			ipa_obj="${ipa_obj} arm-with-vfpv2-ipa.o"
+			ipa_obj="${ipa_obj} arm-with-vfpv3-ipa.o"
+			ipa_obj="${ipa_obj} linux-arm-ipa.o"
 			;;
   arm*-*-mingw32ce*)	srv_regobj=reg-arm.o
 			srv_tgtobj="win32-low.o win32-arm-low.o"
diff --git a/gdb/gdbserver/linux-aarch32-low.c b/gdb/gdbserver/linux-aarch32-low.c
index e6971d5..ffc7ace 100644
--- a/gdb/gdbserver/linux-aarch32-low.c
+++ b/gdb/gdbserver/linux-aarch32-low.c
@@ -215,14 +215,6 @@ arm_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
-/* Enum describing the different kinds of breakpoints.  */
-enum arm_breakpoint_kinds
-{
-   ARM_BP_KIND_THUMB = 2,
-   ARM_BP_KIND_THUMB2 = 3,
-   ARM_BP_KIND_ARM = 4,
-};
-
 /* Implementation of linux_target_ops method "breakpoint_kind_from_pc".
 
    Determine the type and size of breakpoint to insert at PCPTR.  Uses the
diff --git a/gdb/gdbserver/linux-aarch32-low.h b/gdb/gdbserver/linux-aarch32-low.h
index 434a523..ac14ef0 100644
--- a/gdb/gdbserver/linux-aarch32-low.h
+++ b/gdb/gdbserver/linux-aarch32-low.h
@@ -15,6 +15,14 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+/* Enum describing the different kinds of breakpoints.  */
+enum arm_breakpoint_kinds
+{
+  ARM_BP_KIND_THUMB = 2,
+  ARM_BP_KIND_THUMB2 = 3,
+  ARM_BP_KIND_ARM = 4,
+};
+
 extern struct regs_info regs_info_aarch32;
 
 void arm_fill_gregset (struct regcache *regcache, void *buf);
diff --git a/gdb/gdbserver/linux-arm-ipa.c b/gdb/gdbserver/linux-arm-ipa.c
new file mode 100644
index 0000000..d684b78
--- /dev/null
+++ b/gdb/gdbserver/linux-arm-ipa.c
@@ -0,0 +1,217 @@
+/* GNU/Linux/arm specific low level interface, for the in-process
+   agent library for GDB.
+
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "server.h"
+#include <stdint.h>
+#include <sys/mman.h>
+#include "tracepoint.h"
+#include <sys/auxv.h>
+
+/* ARM GNU/Linux HWCAP values.  These are in defined in
+   <asm/elf.h> in current kernels.  */
+#define HWCAP_VFP       64
+#define HWCAP_IWMMXT    512
+#define HWCAP_NEON      4096
+#define HWCAP_VFPv3     8192
+#define HWCAP_VFPv3D16  16384
+
+/* Target description indexes for the IPA.  */
+enum arm_linux_tdesc
+  {
+    ARM_TDESC_ARM = 0,
+    ARM_TDESC_ARM_WITH_VFPV2 = 1,
+    ARM_TDESC_ARM_WITH_VFPV3 = 2,
+    ARM_TDESC_ARM_WITH_NEON = 3,
+  };
+
+/* Defined in auto-generated file regs-arm.c.  */
+void init_registers_arm (void);
+extern const struct target_desc *tdesc_arm;
+
+void init_registers_arm_with_vfpv2 (void);
+extern const struct target_desc *tdesc_arm_with_vfpv2;
+
+void init_registers_arm_with_vfpv3 (void);
+extern const struct target_desc *tdesc_arm_with_vfpv3;
+
+void init_registers_arm_with_neon (void);
+extern const struct target_desc *tdesc_arm_with_neon;
+
+/* 32 bits GPR registers.  */
+#define GPR_SIZE 4
+/* 64 bits FPR registers.  */
+#define FPR_SIZE 8
+
+/* Special registers mappings.  */
+#define FT_CR_PC	0
+#define FT_CR_CPSR	1 * GPR_SIZE
+#define FT_CR_LR	15 * GPR_SIZE
+#define FT_CR_GPR_0	2 * GPR_SIZE
+#define FT_CR_FPR_0	FT_CR_LR + GPR_SIZE
+#define FT_CR_GPR(n)	(FT_CR_GPR_0 + (n * GPR_SIZE))
+#define FT_CR_FPR(n)	(FT_CR_FPR_0 + (n * FPR_SIZE))
+#define FT_CR_UNAVAIL	-1
+
+/* Mapping between registers collected by the jump pad and GDB's register
+   array layout used by regcache for arm core registers.
+
+   See linux-arm-low.c (arm_install_fast_tracepoint_jump_pad) for
+   more details.  */
+
+static const int arm_core_ft_collect_regmap[] = {
+  FT_CR_GPR (0),  FT_CR_GPR (1),  FT_CR_GPR (2), FT_CR_GPR (3), FT_CR_GPR (4),
+  FT_CR_GPR (5),  FT_CR_GPR (6),  FT_CR_GPR (7), FT_CR_GPR (8), FT_CR_GPR (9),
+  FT_CR_GPR (10), FT_CR_GPR (11), FT_CR_GPR (12),
+  /* SP is calculated rather than collected.  */
+  FT_CR_UNAVAIL,
+  FT_CR_LR, FT_CR_PC,
+  /* Legacy FPA Registers. 16 to 24.  */
+  FT_CR_UNAVAIL, FT_CR_UNAVAIL, FT_CR_UNAVAIL, FT_CR_UNAVAIL, FT_CR_UNAVAIL,
+  FT_CR_UNAVAIL, FT_CR_UNAVAIL, FT_CR_UNAVAIL, FT_CR_UNAVAIL,
+  FT_CR_CPSR,
+};
+
+/* Mapping for VFPv2 registers.  */
+static const int arm_vfpv2_ft_collect_regmap[] = {
+  FT_CR_FPR (0),  FT_CR_FPR (1),  FT_CR_FPR (2),  FT_CR_FPR (3), FT_CR_FPR (4),
+  FT_CR_FPR (5),  FT_CR_FPR (6),  FT_CR_FPR (7),  FT_CR_FPR (8), FT_CR_FPR (9),
+  FT_CR_FPR (10), FT_CR_FPR (11), FT_CR_FPR (12), FT_CR_FPR (13),
+  FT_CR_FPR (14), FT_CR_FPR (15),
+};
+
+/* Mapping for VFPv3 registers.  */
+static const int arm_vfpv3_ft_collect_regmap[] = {
+  FT_CR_FPR (0),  FT_CR_FPR (1),  FT_CR_FPR (2),  FT_CR_FPR (3),  FT_CR_FPR (4),
+  FT_CR_FPR (5),  FT_CR_FPR (6),  FT_CR_FPR (7),  FT_CR_FPR (8),  FT_CR_FPR (9),
+  FT_CR_FPR (10), FT_CR_FPR (11), FT_CR_FPR (12), FT_CR_FPR (13),
+  FT_CR_FPR (14), FT_CR_FPR (15), FT_CR_FPR (16), FT_CR_FPR (17),
+  FT_CR_FPR (18), FT_CR_FPR (19), FT_CR_FPR (20), FT_CR_FPR (21),
+  FT_CR_FPR (22), FT_CR_FPR (23), FT_CR_FPR (24), FT_CR_FPR (25),
+  FT_CR_FPR (26), FT_CR_FPR (27), FT_CR_FPR (28), FT_CR_FPR (29),
+  FT_CR_FPR (30), FT_CR_FPR (31),
+};
+
+#define ARM_CORE_NUM_FT_COLLECT_REGS \
+  (sizeof(arm_core_ft_collect_regmap) / sizeof(arm_core_ft_collect_regmap[0]))
+
+#define ARM_VFPV2_NUM_FT_COLLECT_REGS \
+  (sizeof(arm_vfpv2_ft_collect_regmap) / sizeof(arm_vfpv2_ft_collect_regmap[0]))
+
+#define ARM_VFPV3_NUM_FT_COLLECT_REGS \
+  (sizeof(arm_vfpv3_ft_collect_regmap) / sizeof(arm_vfpv3_ft_collect_regmap[0]))
+
+void
+supply_fast_tracepoint_registers (struct regcache *regcache,
+				  const unsigned char *buf)
+{
+  int i;
+  uint32_t val = 0;
+  /* Number of extention registers collected.  */
+  int num_ext_regs = 0;
+
+  for (i = 0; i < ARM_CORE_NUM_FT_COLLECT_REGS; i++)
+    {
+      int index = arm_core_ft_collect_regmap[i];
+      if (index != FT_CR_UNAVAIL)
+	supply_register (regcache, i,
+			 (char *) buf + arm_core_ft_collect_regmap[i]);
+    }
+  if (get_ipa_tdesc (get_ipa_tdesc_idx ()) == tdesc_arm_with_neon
+      || get_ipa_tdesc (get_ipa_tdesc_idx ()) == tdesc_arm_with_vfpv3)
+    {
+      num_ext_regs = ARM_VFPV3_NUM_FT_COLLECT_REGS;
+
+      for (i = 0; i < ARM_VFPV3_NUM_FT_COLLECT_REGS; i++)
+	supply_register (regcache, i + ARM_CORE_NUM_FT_COLLECT_REGS,
+			 (char *) buf + arm_vfpv3_ft_collect_regmap[i]);
+    }
+  else if (get_ipa_tdesc (get_ipa_tdesc_idx ()) == tdesc_arm_with_vfpv2)
+    {
+      num_ext_regs = ARM_VFPV2_NUM_FT_COLLECT_REGS;
+
+      for (i = 0; i < ARM_VFPV2_NUM_FT_COLLECT_REGS; i++)
+	supply_register (regcache, i + ARM_CORE_NUM_FT_COLLECT_REGS,
+			 (char *) buf + arm_vfpv2_ft_collect_regmap[i]);
+    }
+
+  /* SP calculation from stack layout.  */
+  val = (uint32_t) buf + 16 * 4 + num_ext_regs * 8;
+  supply_register (regcache, 13, &val);
+}
+
+ULONGEST
+get_raw_reg (const unsigned char *raw_regs, int regnum)
+{
+  /* Used for JIT conditions.  */
+  return 0;
+}
+
+const char *gdbserver_xmltarget;
+
+const struct target_desc *
+get_ipa_tdesc (int idx)
+{
+  switch (idx)
+    {
+    case ARM_TDESC_ARM:
+      return tdesc_arm;
+    case ARM_TDESC_ARM_WITH_NEON:
+      return tdesc_arm_with_neon;
+    case ARM_TDESC_ARM_WITH_VFPV2:
+      return tdesc_arm_with_vfpv2;
+    case ARM_TDESC_ARM_WITH_VFPV3:
+      return tdesc_arm_with_vfpv3;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      "unknown ipa tdesc index: %d", idx);
+      return tdesc_arm;
+    }
+}
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+  uintptr_t addr;
+  void *res = NULL;
+
+  /* Allocate scratch buffer aligned on a page boundary, at a low
+   address (close to the main executable's code).  */
+  for (addr = size; addr != 0; addr += size)
+    {
+      res = (char *) mmap ((void *) addr, size,
+			   PROT_READ | PROT_WRITE | PROT_EXEC,
+			   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      if (res == (void *) addr)
+	break;
+      if (res != MAP_FAILED)
+	munmap (res, size);
+    }
+  return res;
+}
+
+void
+initialize_low_tracepoint (void)
+{
+  /* Initialize the Linux target descriptions.  */
+  init_registers_arm ();
+  init_registers_arm_with_vfpv2 ();
+  init_registers_arm_with_vfpv3 ();
+  init_registers_arm_with_neon ();
+}
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index c927ad8..5294f00 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -17,10 +17,14 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
+#include <inttypes.h>
 #include "linux-low.h"
 #include "arch/arm.h"
 #include "arch/arm-linux.h"
 #include "arch/arm-get-next-pcs.h"
+#include "arch/arm-insn-utils.h"
+#include "arch/arm-insn-emit.h"
+#include "arch/arm-insn-reloc.h"
 #include "linux-aarch32-low.h"
 
 #include <sys/uio.h>
@@ -34,6 +38,7 @@
 #include <sys/syscall.h>
 
 #include "tracepoint.h"
+#include "ax.h"
 
 /* Defined in auto-generated files.  */
 void init_registers_arm (void);
@@ -67,6 +72,15 @@ extern const struct target_desc *tdesc_arm_with_vfpv3;
 #define PTRACE_SETHBPREGS 30
 #endif
 
+/* Target description indexes for the IPA.  */
+enum arm_linux_tdesc
+  {
+    ARM_TDESC_ARM = 0,
+    ARM_TDESC_ARM_WITH_VFPV2 = 1,
+    ARM_TDESC_ARM_WITH_VFPV3 = 2,
+    ARM_TDESC_ARM_WITH_NEON = 3,
+  };
+
 /* Information describing the hardware breakpoint capabilities.  */
 static struct
 {
@@ -1042,6 +1056,900 @@ arm_supports_tracepoints (void)
   return 1;
 }
 
+static int
+append_inferior_memory (CORE_ADDR *to, size_t len, const unsigned char *buf)
+{
+  if (write_inferior_memory (*to, buf, len) != 0)
+    return 1;
+
+  *to += len;
+
+  return 0;
+}
+
+static int
+append_inferior_memory_32 (CORE_ADDR *to, uint32_t val)
+{
+  return append_inferior_memory (to, 4, (unsigned char *) &val);
+}
+
+static int
+append_inferior_memory_16 (CORE_ADDR *to, uint16_t val)
+{
+  return append_inferior_memory (to, 2, (unsigned char *) &val);
+}
+
+struct arm_insn_reloc_data
+{
+  union
+  {
+    uint32_t arm;
+    uint16_t thumb32[2];
+  } insns;
+
+  /* Error message to return to the client in case the relocation fails.  */
+  const char *err;
+};
+
+static int
+arm_reloc_others (uint32_t insn, const char *iname,
+		  struct arm_insn_reloc_data *data)
+{
+  data->insns.arm = insn;
+
+  return 0;
+}
+
+static int
+arm_reloc_alu_imm (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+arm_reloc_alu_reg (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+arm_reloc_alu_shifted_reg (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+arm_reloc_b_bl_blx (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+arm_reloc_block_xfer (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+arm_reloc_bx_blx_reg (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+arm_reloc_copro_load_store (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+arm_reloc_extra_ld_st (uint32_t insn, struct arm_insn_reloc_data *data,
+		       int unprivileged)
+{
+  return 1;
+}
+
+static int
+arm_reloc_ldr_str_ldrb_strb (uint32_t insn, struct arm_insn_reloc_data *data,
+			     int load, int size, int usermode)
+{
+  return 1;
+}
+
+static int
+arm_reloc_preload (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+arm_reloc_preload_reg (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+arm_reloc_svc (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+arm_reloc_undef (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+arm_reloc_unpred (uint32_t insn, struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+struct arm_insn_reloc_visitor arm_insn_reloc_visitor = {
+  arm_reloc_alu_imm,
+  arm_reloc_alu_reg,
+  arm_reloc_alu_shifted_reg,
+  arm_reloc_b_bl_blx,
+  arm_reloc_block_xfer,
+  arm_reloc_bx_blx_reg,
+  arm_reloc_copro_load_store,
+  arm_reloc_extra_ld_st,
+  arm_reloc_ldr_str_ldrb_strb,
+  arm_reloc_others,
+  arm_reloc_preload,
+  arm_reloc_preload_reg,
+  arm_reloc_svc,
+  arm_reloc_undef,
+  arm_reloc_unpred,
+};
+
+static int
+copy_instruction_arm (CORE_ADDR *to, CORE_ADDR from, const char **err)
+{
+  uint32_t insn;
+  struct arm_insn_reloc_data data;
+  int ret;
+
+  if (read_inferior_memory (from, (unsigned char *) &insn, sizeof (insn)) != 0)
+    {
+      *err = "Error reading memory while relocating instruction.";
+      return 1;
+    }
+
+  /* Set a default generic error message, which can be overridden by the
+     relocation functions.  */
+  data.err = "Error relocating instruction.";
+
+  ret = arm_relocate_insn (insn, &arm_insn_reloc_visitor, &data);
+  if (ret != 0)
+    {
+      *err = data.err;
+      return 1;
+    }
+
+  append_inferior_memory_32 (to, data.insns.arm);
+
+  return 0;
+}
+
+static int
+thumb32_reloc_others (uint16_t insn1, uint16_t insn2, const char *iname,
+		      struct arm_insn_reloc_data *data)
+{
+  data->insns.thumb32[0] = insn1;
+  data->insns.thumb32[1] = insn2;
+
+  return 0;
+}
+
+static int
+thumb32_reloc_alu_imm (uint16_t insn1, uint16_t insn2,
+		       struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+thumb32_reloc_b_bl_blx (uint16_t insn1, uint16_t insn2,
+			struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+thumb32_reloc_block_xfer (uint16_t insn1, uint16_t insn2,
+			  struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+thumb32_reloc_copro_load_store (uint16_t insn1, uint16_t insn2,
+				struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+thumb32_reloc_load_literal (uint16_t insn1, uint16_t insn2,
+			    struct arm_insn_reloc_data *data, int size)
+{
+  return 1;
+}
+
+static int
+thumb32_reloc_load_reg_imm (uint16_t insn1, uint16_t insn2,
+			    struct arm_insn_reloc_data *data, int writeback,
+			    int immed)
+{
+  return 1;
+}
+
+static int
+thumb32_reloc_pc_relative_32bit (uint16_t insn1, uint16_t insn2,
+				 struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+thumb32_reloc_preload (uint16_t insn1, uint16_t insn2,
+		       struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+thumb32_reloc_undef (uint16_t insn1, uint16_t insn2,
+		     struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+static int
+thumb32_reloc_table_branch (uint16_t insn1, uint16_t insn2,
+			    struct arm_insn_reloc_data *data)
+{
+  return 1;
+}
+
+
+struct thumb_32bit_insn_reloc_visitor thumb_32bit_insns_reloc_visitor = {
+  thumb32_reloc_alu_imm,
+  thumb32_reloc_b_bl_blx,
+  thumb32_reloc_block_xfer,
+  thumb32_reloc_copro_load_store,
+  thumb32_reloc_load_literal,
+  thumb32_reloc_load_reg_imm,
+  thumb32_reloc_others,
+  thumb32_reloc_pc_relative_32bit,
+  thumb32_reloc_preload,
+  thumb32_reloc_undef,
+  thumb32_reloc_table_branch,
+};
+
+static int
+copy_instruction_thumb32 (CORE_ADDR *to, CORE_ADDR from, const char **err)
+{
+  uint16_t insn1, insn2;
+  struct arm_insn_reloc_data data;
+  int ret;
+
+  if (read_inferior_memory (from, (unsigned char *) &insn1, sizeof (insn1))
+      != 0)
+    {
+      *err = "Error reading memory while relocating instruction.";
+      return 1;
+    }
+
+  if (read_inferior_memory (from + sizeof (insn1), (unsigned char *) &insn2,
+			    sizeof (insn2)) != 0)
+    {
+      *err = "Error reading memory while relocating instruction.";
+      return 1;
+    }
+
+  /* Set a default generic error message, which can be overridden by the
+     relocation functions.  */
+  data.err = "Error relocating instruction.";
+
+  ret = thumb_32bit_relocate_insn (insn1, insn2,
+				   &thumb_32bit_insns_reloc_visitor, &data);
+  if (ret != 0)
+    {
+      *err = data.err;
+      return 1;
+    }
+
+  append_inferior_memory_16 (to, data.insns.thumb32[0]);
+  append_inferior_memory_16 (to, data.insns.thumb32[1]);
+
+  return 0;
+}
+
+static int
+arm_get_thread_area (int lwpid, CORE_ADDR *addr)
+{
+  uint32_t val;
+
+  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, &val) != 0)
+    return -1;
+
+  *addr = val;
+  return 0;
+}
+
+static int
+arm_get_min_fast_tracepoint_insn_len (void)
+{
+  return 4;
+}
+
+/* Core register numbers used in fast tracepoints code.  */
+static const int r0 = 0;
+static const int r1 = 1;
+static const int r2 = 2;
+static const int r3 = 3;
+static const int r4 = 4;
+static const int r5 = 5;
+static const int sp = 13;
+static const int lr = 14;
+
+static int
+arm_install_fast_tracepoint_jump_pad_arm (struct tracepoint *tp,
+					  CORE_ADDR collector,
+					  CORE_ADDR lockaddr,
+					  CORE_ADDR *jump_entry,
+					  CORE_ADDR *trampoline,
+					  ULONGEST *trampoline_size,
+					  unsigned char *jjump_pad_insn,
+					  ULONGEST *jjump_pad_insn_size,
+					  char *err)
+{
+  unsigned char buf[0x100];
+  CORE_ADDR buildaddr = *jump_entry;
+  const struct target_desc *tdesc = current_process ()->tdesc;
+  const uint32_t kuser_get_tls = 0xffff0fe0;
+  uint32_t *ptr = (uint32_t *) buf;
+  const char *copy_insn_err;
+
+  /* Push VFP registers if available.  */
+  if (tdesc == tdesc_arm_with_neon || tdesc == tdesc_arm_with_vfpv3)
+    {
+      /* vpush {d0-d15} */
+      ptr += arm_emit_arm_vpush (ptr, INST_AL, 0, 16);
+
+      /* vpush {d16-d31} */
+      ptr += arm_emit_arm_vpush (ptr, INST_AL, 16, 16);
+    }
+  else if (tdesc == tdesc_arm_with_vfpv2)
+    /* vpush {d0-d15} */
+    ptr += arm_emit_arm_vpush (ptr, INST_AL, 0, 16);
+
+  /* Function prologue, push common registers on the stack.
+     push { r0-r12,lr }  */
+  ptr
+    += arm_emit_arm_push_list (ptr, INST_AL,
+			       encode_register_list (0, 13, ENCODE (1, 1, 14)));
+
+  /* Push current processor state register (CPSR) on the stack.  */
+  ptr += arm_emit_arm_mrs (ptr, INST_AL, r0);
+
+  /* push r0 */
+  ptr += arm_emit_arm_push_one (ptr, INST_AL, r0);
+
+  /* Push replaced instruction address on the stack.  */
+  ptr += arm_emit_arm_mov_32 (ptr, r0, (uint32_t) tp->address);
+  /* push r0 (orig pc)  */
+  ptr += arm_emit_arm_push_one (ptr, INST_AL, r0);
+
+  /* Save current stack pointer for the REGS parameters of the gdb_collect
+     call later. */
+  ptr += arm_emit_arm_mov (ptr, INST_AL, r1, register_operand (sp));
+
+  /* Push current thread's local storage location on the stack.  */
+  ptr += arm_emit_arm_mov_32 (ptr, r0, kuser_get_tls);
+  ptr += arm_emit_arm_blx (ptr, INST_AL, register_operand (r0));
+  /* push r0 (tls)  */
+  ptr += arm_emit_arm_push_one (ptr, INST_AL, r0);
+
+  /* Push obj_addr_on_target on the stack.  */
+  ptr += arm_emit_arm_mov_32 (ptr, r0, (uint32_t) tp->obj_addr_on_target);
+  /* push r0 (tpoint:arg1)  */
+  ptr += arm_emit_arm_push_one (ptr, INST_AL, r0);
+
+  /* Move collector function address to r2.  */
+  ptr += arm_emit_arm_mov_32 (ptr, r2, (uint32_t) collector);
+
+  /* Move lock address to r4.  */
+  ptr += arm_emit_arm_mov_32 (ptr, r4, (uint32_t) lockaddr);
+
+  /*
+   * At this point, the stack looks like:
+   *           bottom
+   * +-------------------------------------------------+
+   * |  saved lr                                       |
+   * |  saved r12                                      |
+   * |  ...                                            |
+   * |  saved r0                                       |
+   * |  saved cpsr                                     |
+   * |  tp->address                                    | <- r1
+   * |  tls  (collecting_t.thread_area)                |
+   * |  tp->obj_addr_on_target  (collecting_t.tpoint)  | <- r5
+   * +-------------------------------------------------+
+   *            top
+   */
+
+  /* Save current sp value, so we can restore it after the call to
+     gdb_collect.  */
+  /* mov r5, sp  */
+  ptr += arm_emit_arm_mov (ptr, INST_AL, r5, register_operand (sp));
+
+  /* Spin lock on lockaddr (r4 contains address of lock) */
+
+  /* This is a full memory barrier.
+     1: dmb sy (memory barrier)  */
+  ptr += arm_emit_arm_dmb (ptr);
+  /* Load lock value in r3
+     2: ldrex r3, [r4]  */
+  ptr += arm_emit_arm_ldrex (ptr, INST_AL, r3, r4);
+
+  /* Is it already locked?
+     cmp r3, #0  */
+  ptr += arm_emit_arm_cmp (ptr, INST_AL, r3, immediate_operand (0));
+
+  /* If so, start over.
+     bne 3  */
+  ptr += arm_emit_arm_b (ptr, INST_NE, arm_arm_branch_adjusted_offset (16));
+
+  /* If not, write a value (our saved stack pointer in r5) to the location.
+     strex lr, r5, [r4]  */
+  ptr += arm_emit_arm_strex (ptr, INST_AL, lr, r5, r4);
+
+  /* Did the write succeed?
+     cmp lr, #0  */
+  ptr += arm_emit_arm_cmp (ptr, INST_AL, lr, immediate_operand (0));
+
+  /* If not, start over.
+     bne 2  */
+  ptr += arm_emit_arm_b (ptr, INST_NE, arm_arm_branch_adjusted_offset (-20));
+
+  /* A full memory barrier again.  */
+  ptr += arm_emit_arm_dmb (ptr);
+  /* bne 1  */
+  ptr += arm_emit_arm_b (ptr, INST_NE, arm_arm_branch_adjusted_offset (-32));
+
+  /* Round the stack to a multiple of 8 (section 5.2.1.2)
+     bic r3, r5, 7  */
+  ptr += arm_emit_arm_bic (ptr, INST_AL, r3, r5, immediate_operand (7));
+
+  /* mov sp, r3  */
+  ptr += arm_emit_arm_mov (ptr, INST_AL, sp, register_operand (r3));
+
+  /* Call collector (obj_addr_on_target, regs);
+	  r2 -^      r0 -^             r1 -^  */
+  ptr += arm_emit_arm_blx (ptr, INST_AL, register_operand (r2));
+
+  /* Restore sp to pre-call/rounding value.
+     mov sp, r5  */
+  ptr += arm_emit_arm_mov (ptr, INST_AL, sp, register_operand (r5));
+
+  /* Unlock the spin lock (by writing 0 to it).  */
+  ptr += arm_emit_arm_mov (ptr, INST_AL, r3, immediate_operand (0));
+
+  /* str r3, [r4]  */
+  ptr += arm_emit_arm_str (ptr, INST_AL, r3, r4,
+			   memory_operand (offset_memory_operand (0)));
+
+  /* Pop everything that was saved. */
+
+  /* tpoint, tls, tpaddr
+     add sp, sp, #12  */
+  ptr += arm_emit_arm_add (ptr, INST_AL, 0, sp, sp, immediate_operand (12));
+
+  /* cpsr
+     pop r0  */
+  ptr += arm_emit_arm_pop_one (ptr, INST_AL, r0);
+
+  /* msr cpsr,r0  */
+  ptr += arm_emit_arm_msr (ptr, INST_AL, r0);
+
+  /* r0-r12 and lr
+     pop { r0-r12,lr }  */
+  ptr += arm_emit_arm_pop_list (ptr, INST_AL,
+				encode_register_list (0, 13,
+						      ENCODE (1, 1, 14)));
+
+  /* Pop VFP registers.  */
+  if (tdesc == tdesc_arm_with_neon || tdesc == tdesc_arm_with_vfpv3)
+    {
+      /* vpop {d16-d31} */
+      ptr += arm_emit_arm_vpop (ptr, INST_AL, 16, 16);
+
+      /* vpop {d0-d15} */
+      ptr += arm_emit_arm_vpop (ptr, INST_AL, 0, 16);
+    }
+  else if (tdesc == tdesc_arm_with_vfpv2)
+    /* vpop {d0-d15} */
+    ptr += arm_emit_arm_vpop (ptr, INST_AL, 0, 16);
+
+  append_inferior_memory (&buildaddr, (uint32_t) ptr - (uint32_t) buf, buf);
+
+  tp->adjusted_insn_addr = buildaddr;
+  if (copy_instruction_arm (&buildaddr, tp->address, &copy_insn_err) != 0)
+    {
+      sprintf (err, "E%s", copy_insn_err);
+      return 1;
+    }
+  tp->adjusted_insn_addr = buildaddr;
+
+  /* Possible improvements:
+   This branch can be made non-relative:
+   B <mem location>:
+   push    {r0,r1}
+   movw    r0, #<mem location>
+   movt    r0, #<mem location>
+   str     r0, [sp, #4]
+   pop     {r0,pc}  */
+  if (!arm_arm_is_reachable (buildaddr, tp->address + 4))
+    {
+      sprintf (err,
+	       "EJump back from jump pad too far from tracepoint "
+	       "(offset 0x%" PRIx32 " cannot be encoded in 24 bits).",
+	       arm_arm_branch_relative_distance (buildaddr, tp->address + 4));
+      return 1;
+    }
+  /* b <tp_addr + 4>  */
+  arm_emit_arm_b ((uint32_t *) buf, INST_AL,
+		  arm_arm_branch_relative_distance (buildaddr,
+						    tp->address + 4));
+  append_inferior_memory (&buildaddr, 4, buf);
+
+  /* write tp instr.  */
+  if (!arm_arm_is_reachable (tp->address, *jump_entry))
+    {
+      sprintf (err,
+	       "EJump pad too far from tracepoint "
+	       "(offset 0x%" PRIx32 " cannot be encoded in 24 bits).",
+	       arm_arm_branch_relative_distance (tp->address, *jump_entry));
+      return 1;
+    }
+
+  arm_emit_arm_b ((uint32_t *) jjump_pad_insn, INST_AL,
+		  arm_arm_branch_relative_distance (tp->address, *jump_entry));
+
+  *jjump_pad_insn_size = 4;
+  *jump_entry = buildaddr;
+
+  return 0;
+}
+
+static int
+arm_install_fast_tracepoint_jump_pad_thumb2 (struct tracepoint *tp,
+					     CORE_ADDR collector,
+					     CORE_ADDR lockaddr,
+					     CORE_ADDR *jump_entry,
+					     CORE_ADDR *trampoline,
+					     ULONGEST *trampoline_size,
+					     unsigned char *jjump_pad_insn,
+					     ULONGEST *jjump_pad_insn_size,
+					     char *err)
+{
+  unsigned char buf[0x100];
+  CORE_ADDR buildaddr = *jump_entry;
+  const struct target_desc *tdesc = current_process ()->tdesc;
+  const uint32_t kuser_get_tls = 0xffff0fe0;
+  uint16_t *ptr = (uint16_t *) buf;
+  const char *copy_insn_err;
+
+  /* Push VFP registers if available.  */
+  if (tdesc == tdesc_arm_with_neon || tdesc == tdesc_arm_with_vfpv3)
+    {
+      /* vpush {d0-d15} */
+      ptr += arm_emit_thumb_vpush (ptr, 0, 16);
+      /* vpush {d16-d31} */
+      ptr += arm_emit_thumb_vpush (ptr, 16, 16);
+    }
+  else if (tdesc == tdesc_arm_with_vfpv2)
+    /* vpush {d0-d15} */
+    ptr += arm_emit_thumb_vpush (ptr, 0, 16);
+
+  /* Function prologue, push common registers on the stack.
+     push { r0-r12,lr }  */
+  ptr += arm_emit_thumb_push_list (ptr, encode_register_list (0, 13, 0), 1);
+
+  /* Push current processor state register (CPSR) on the stack.  */
+  ptr += arm_emit_thumb_mrs (ptr, r0);
+
+  /* push r0  */
+  ptr += arm_emit_thumb_push_one (ptr, ENCODE (1, 1, 0), 0);
+
+  /* Push replaced instruction address on the stack.  */
+  ptr += arm_emit_thumb_mov_32 (ptr, r0, (uint32_t) tp->address);
+
+  /* push r0 (orig pc)  */
+  ptr += arm_emit_thumb_push_one (ptr, ENCODE (1, 1, 0), 0);
+
+  /* Save current stack pointer for the REGS parameters of the gdb_collect
+     call later.
+     mov r1, sp (regs:arg2)  */
+  ptr += arm_emit_thumb_mov (ptr, r1, register_operand (sp));
+
+  /* Push current thread's local storage location on the stack.  */
+  ptr += arm_emit_thumb_mov_32 (ptr, r0, kuser_get_tls);
+  ptr += arm_emit_thumb_blx (ptr, register_operand (r0));
+  /* push r0 (tls)  */
+  ptr += arm_emit_thumb_push_one (ptr, ENCODE (1, 1, 0), 0);
+
+  /* Push obj_addr_on_target on the stack.  */
+  ptr += arm_emit_thumb_mov_32 (ptr, r0,
+				     (uint32_t) tp->obj_addr_on_target);
+  /* push r0 (tpoint:arg1)  */
+  ptr += arm_emit_thumb_push_one (ptr, ENCODE (1, 1, 0), 0);
+
+  /* Move collector function address to r2.  */
+  ptr += arm_emit_thumb_mov_32 (ptr, r2, (uint32_t) collector);
+
+  /* Move lock address to r4.  */
+  ptr += arm_emit_thumb_mov_32 (ptr, r4, (uint32_t) lockaddr);
+
+  /*
+   * At this point, the stack looks like:
+   *           bottom
+   * +-------------------------------------------------+
+   * |  saved lr                                       |
+   * |  saved r12                                      |
+   * |  ...                                            |
+   * |  saved r0                                       |
+   * |  saved cpsr                                     |
+   * |  tp->address                                    | <- r1
+   * |  tls  (collecting_t.thread_area)                |
+   * |  tp->obj_addr_on_target  (collecting_t.tpoint)  | <- r5
+   * +-------------------------------------------------+
+   *            top
+   */
+
+  /* Save current sp value, so we can restore it after the call to
+     gdb_collect.
+     mov r5, sp  */
+  ptr += arm_emit_thumb_mov (ptr, r5, register_operand (sp));
+
+  /* Spin lock on lockaddr (r4 contains address of lock) */
+
+  /* This is a full memory barrier.
+     1: dmb sy  */
+  ptr += arm_emit_thumb_dmb (ptr);
+
+  /* Load lock value in r3
+     2: ldrex   r3, [r4]  */
+  ptr += arm_emit_thumb_ldrex (ptr, r3, r4, immediate_operand (0));
+
+  /* Is it already locked?
+     cmp r3, #0  */
+  ptr += arm_emit_thumb_cmp (ptr, r3, immediate_operand (0));
+
+  /* If so, start over
+     bne.n   3	 */
+  ptr += arm_emit_thumb_b (ptr, INST_NE, arm_thumb_branch_adjusted_offset (12));
+
+  /* If not, write a value (our saved stack pointer in r5) to the location.
+     strex   r14, r5, [r4]  */
+  ptr += arm_emit_thumb_strex (ptr, lr, r5, r4, immediate_operand (0));
+
+  /* Did the write succeed?
+     cmp.w   r14, #0  */
+  ptr += arm_emit_thumb_cmpw (ptr, lr, immediate_operand (0));
+
+  /* If not, start over.
+     bne.n  2  */
+  ptr += arm_emit_thumb_b (ptr, INST_NE,
+			   arm_thumb_branch_adjusted_offset (-16));
+
+  /* A full memory barrier again.
+     3. dmb  sy  */
+  ptr += arm_emit_thumb_dmb (ptr);
+
+  /* bne.n  1  */
+  ptr += arm_emit_thumb_b (ptr, INST_NE,
+			   arm_thumb_branch_adjusted_offset (-26));
+
+  /* Round the stack to a multiple of 8 (section 5.2.1.2)
+     bic r3, r5, 7  */
+  ptr += arm_emit_thumb_bic (ptr, r3, r5, immediate_operand (7));
+
+  /* mov sp, r3  */
+  ptr += arm_emit_thumb_mov (ptr, sp, register_operand (r3));
+
+  /* Call collector (obj_addr_on_target, regs);
+		r2 -^      r0 -^     r1 -^  */
+  ptr += arm_emit_thumb_blx (ptr, register_operand (r2));
+
+  /* Restore sp to pre-call/rounding value.
+     mov sp, r5  */
+  ptr += arm_emit_thumb_mov (ptr, sp, register_operand (r5));
+
+  /* Unlock the spin lock (by writing 0 to it).
+     movw r3, #0  */
+  ptr += arm_emit_thumb_movw (ptr, r3, immediate_operand (0));
+
+  /* str r3, [r4]  */
+  ptr += arm_emit_thumb_str (ptr, r3, r4, immediate_operand (0));
+
+  /* Pop everything that was saved. */
+
+  /* tpoint, tls, tpaddr
+     add sp, sp, #12  */
+  ptr += arm_emit_thumb_add_sp (ptr, immediate_operand (12));
+
+  /* For cpsr.
+     pop r0  */
+  ptr += arm_emit_thumb_pop (ptr, ENCODE (1, 1, 0), 0);
+
+  /* msr cpsr,r0*/
+  ptr += arm_emit_thumb_msr (ptr, r0);
+
+  /* r0-r12 and lr
+     pop { r0-r12,lr }  */
+  ptr += arm_emit_thumb_popw_list (ptr, encode_register_list (0, 13, 0), 0, 1);
+
+  /* Pop VFP registers.  */
+  if (tdesc == tdesc_arm_with_neon || tdesc == tdesc_arm_with_vfpv3)
+    {
+      /* vpop {d16-d31} */
+      ptr += arm_emit_thumb_vpop (ptr, 16, 16);
+      /* vpop {d0-d15} */
+      ptr += arm_emit_thumb_vpop (ptr, 0, 16);
+    }
+  else if (tdesc == tdesc_arm_with_vfpv2)
+    {
+      /* vpop {d0-d15} */
+      ptr += arm_emit_thumb_vpop (ptr, 0, 16);
+    }
+
+  append_inferior_memory (&buildaddr, (uint32_t) ptr - (uint32_t) buf, buf);
+
+  tp->adjusted_insn_addr = buildaddr;
+  if (copy_instruction_thumb32 (&buildaddr, tp->address, &copy_insn_err) != 0)
+    {
+      sprintf (err, "E%s", copy_insn_err);
+      return 1;
+    }
+  tp->adjusted_insn_addr_end = buildaddr;
+
+  /* Possible improvements:
+     This branch can be made non-relative:
+     B <mem location>:
+     push	   {r0,r1}
+     movw	   r0, #<mem location>
+     movt	   r0, #<mem location>
+     str	   r0, [sp, #4]
+     pop	   {r0,pc}  */
+  if (!arm_thumb_is_reachable (buildaddr, tp->address + 4))
+    {
+      sprintf (err,
+	       "EJump back from jump pad too far from tracepoint "
+	       "(offset 0x%" PRIx32 " cannot be encoded in 23 bits).",
+	       arm_thumb_branch_relative_distance (buildaddr, tp->address + 4));
+      return 1;
+    }
+
+  arm_emit_thumb_bw ((uint16_t *) buf,
+		     arm_thumb_branch_relative_distance (buildaddr,
+							 tp->address + 4));
+  append_inferior_memory (&buildaddr, 4, buf);
+
+  /* write tp instr.	*/
+  if (!arm_thumb_is_reachable (tp->address, *jump_entry))
+    {
+      sprintf (err,
+	       "EJump pad too far from tracepoint "
+	       "(offset 0x%" PRIx32 " cannot be encoded in 23 bits).",
+	       arm_thumb_branch_relative_distance (tp->address, *jump_entry));
+      return 1;
+    }
+
+  arm_emit_thumb_bw ((uint16_t *) jjump_pad_insn,
+		     arm_thumb_branch_relative_distance (tp->address,
+							 *jump_entry));
+  *jjump_pad_insn_size = 4;
+  *jump_entry = buildaddr;
+
+  return 0;
+}
+
+static int
+arm_install_fast_tracepoint_jump_pad (struct tracepoint *tp,
+				      CORE_ADDR collector,
+				      CORE_ADDR lockaddr,
+				      CORE_ADDR *jump_entry,
+				      CORE_ADDR *trampoline,
+				      ULONGEST *trampoline_size,
+				      unsigned char *jjump_pad_insn,
+				      ULONGEST *jjump_pad_insn_size,
+				      char *err)
+{
+  int res = 1;
+
+  if (tp->kind == ARM_BP_KIND_ARM)
+    {
+      TRY
+	{
+	  res = arm_install_fast_tracepoint_jump_pad_arm (tp, collector,
+							  lockaddr,
+							  jump_entry,
+							  trampoline,
+							  trampoline_size,
+							  jjump_pad_insn,
+							  jjump_pad_insn_size,
+							  err);
+	}
+      CATCH (ex, RETURN_MASK_ERROR)
+	{
+	  if (ex.error == NOT_SUPPORTED_ERROR)
+	    {
+	      err = strcpy (err, ex.message);
+	      return 1;
+	    }
+	  else
+	    {
+	      throw_exception (ex);
+	    }
+	}
+      END_CATCH
+    }
+  else if (tp->kind == ARM_BP_KIND_THUMB2)
+    {
+      TRY
+	{
+	  res = arm_install_fast_tracepoint_jump_pad_thumb2
+	    (tp, collector, lockaddr, jump_entry, trampoline, trampoline_size,
+	     jjump_pad_insn, jjump_pad_insn_size, err);
+	}
+      CATCH (ex, RETURN_MASK_ERROR)
+	{
+	  if (ex.error == NOT_SUPPORTED_ERROR)
+	    {
+	      err = strcpy (err, ex.message);
+	      return 1;
+	    }
+	  else
+	    {
+	      throw_exception (ex);
+	    }
+	}
+      END_CATCH
+    }
+  else
+    {
+      strcpy (err,
+	      "ECan't put a fast tracepoint jump on a two-bytes Thumb "
+	      "instruction.");
+      return 1;
+    }
+
+  return res;
+}
+
+/* Implementation of the linux_target_ops method "get_ipa_tdesc_idx".  */
+
+static int
+arm_get_ipa_tdesc_idx (void)
+{
+  const struct target_desc *tdesc = current_process ()->tdesc;
+
+  if (tdesc == tdesc_arm)
+    return ARM_TDESC_ARM;
+  if (tdesc == tdesc_arm_with_vfpv2)
+    return ARM_TDESC_ARM_WITH_VFPV2;
+  if (tdesc == tdesc_arm_with_vfpv3)
+    return ARM_TDESC_ARM_WITH_VFPV3;
+  if (tdesc == tdesc_arm_with_neon)
+    return ARM_TDESC_ARM_WITH_NEON;
+
+  return 0;
+}
+
 struct linux_target_ops the_low_target = {
   arm_arch_setup,
   arm_regs_info,
@@ -1069,14 +1977,15 @@ struct linux_target_ops the_low_target = {
   arm_prepare_to_resume,
   NULL, /* process_qsupported */
   arm_supports_tracepoints,
-  NULL, /* get_thread_area */
-  NULL, /* install_fast_tracepoint_jump_pad */
-  NULL, /* emit_ops */
-  NULL, /* get_min_fast_tracepoint_insn_len */
+  arm_get_thread_area, /* get_thread_area */
+  arm_install_fast_tracepoint_jump_pad, /* install_fast_tracepoint_jump_pad */
+  NULL, /*emit_ops */
+  arm_get_min_fast_tracepoint_insn_len, /* get_min_fast_tracepoint_insn_len */
   NULL, /* supports_range_stepping */
   arm_breakpoint_kind_from_current_state,
   arm_supports_hardware_single_step,
   arm_get_syscall_trapinfo,
+  arm_get_ipa_tdesc_idx,
 };
 
 void
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 87211e9..95933dd 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -4658,6 +4658,13 @@ collect_data_at_step (struct tracepoint_hit_ctx *ctx,
 EXTERN_C_PUSH
 IP_AGENT_EXPORT_VAR int ipa_tdesc_idx;
 EXTERN_C_POP
+
+/* Return the current target descriptoin index.  */
+int
+get_ipa_tdesc_idx (void)
+{
+  return ipa_tdesc_idx;
+}
 #endif
 
 static struct regcache *
diff --git a/gdb/gdbserver/tracepoint.h b/gdb/gdbserver/tracepoint.h
index c45a03c..cdd315b 100644
--- a/gdb/gdbserver/tracepoint.h
+++ b/gdb/gdbserver/tracepoint.h
@@ -125,6 +125,7 @@ int handle_tracepoint_bkpts (struct thread_info *tinfo, CORE_ADDR stop_pc);
 #ifdef IN_PROCESS_AGENT
 void initialize_low_tracepoint (void);
 const struct target_desc *get_ipa_tdesc (int idx);
+int get_ipa_tdesc_idx (void);
 void supply_fast_tracepoint_registers (struct regcache *regcache,
 				       const unsigned char *regs);
 void supply_static_tracepoint_registers (struct regcache *regcache,
diff --git a/gdb/testsuite/lib/trace-support.exp b/gdb/testsuite/lib/trace-support.exp
index 9996315..e9926c9 100644
--- a/gdb/testsuite/lib/trace-support.exp
+++ b/gdb/testsuite/lib/trace-support.exp
@@ -95,7 +95,8 @@ proc gdb_target_supports_trace { } {
 proc gdb_target_supports_fast_trace { } {
     if {[istarget "x86_64-*-*"]
 	|| [istarget "i\[34567\]86-*-*"]
-	|| [is_aarch64_target]} {
+	|| [is_aarch64_target]
+	|| [is_aarch32_target]} {
 	return 1
     }
 
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 17/18] arm fast tracepoints: Relocation of ARM instructions
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (10 preceding siblings ...)
  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
  2016-07-05 13:42 ` [PATCH v3 07/18] Move ARM instruction decode functions to arch/arm-insn-reloc.c Antoine Tremblay
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:42 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

This patch adds the possibility to relocate some common ARM-mode
instructions that may depend on the current value of the PC.

Branches are very frequent and are always pc-relative, so we make sure
to support pretty much all cases.  We calculate the new relative offset,
given the old and new instruction locations.

Other instructions are rejected as soon as they reference the PC.  We
judged these cases are not frequent enough to be worth the effort of
relocating.

gdb/gdbserver/ChangeLog:

	* linux-arm-low.c (struct arm_insn_reloc_data): Add orig_loc and
	new_loc fields.
	(arm_reloc_refs_pc_error): New function.
	(arm_reloc_alu_imm): Implement.
	(arm_reloc_alu_reg): Implement.
	(arm_reloc_alu_shifted_reg): Implement.
	(arm_reloc_b_bl_blx): Implement.
	(arm_reloc_block_xfer): Implement.
	(arm_reloc_bx_blx_reg): Implement.
	(arm_reloc_copro_load_store): Implement.
	(arm_reloc_extra_ld_st): Implement.
	(arm_reloc_ldr_str_ldrb_strb): Implement.
	(arm_reloc_preload): Implement.
	(arm_reloc_preload_reg): Implement.
	(arm_reloc_svc): Implement.
	(arm_reloc_undef): Implement.
	(arm_reloc_unpred): Implement.
	(copy_instruction_arm): Assign orig_loc and new_loc.

gdb/testsuite/ChangeLog:

	* gdb.trace/ftrace-arm-insn.S: New file.
	* gdb.trace/ftrace-arm-insn.c: New file.
	* gdb.trace/ftrace-arm-insn.exp: New file.
---
 gdb/gdbserver/linux-arm-low.c               | 121 +++++++++++++--
 gdb/testsuite/gdb.trace/ftrace-arm-insn.S   | 221 ++++++++++++++++++++++++++++
 gdb/testsuite/gdb.trace/ftrace-arm-insn.c   |  78 ++++++++++
 gdb/testsuite/gdb.trace/ftrace-arm-insn.exp | 103 +++++++++++++
 4 files changed, 511 insertions(+), 12 deletions(-)
 create mode 100644 gdb/testsuite/gdb.trace/ftrace-arm-insn.S
 create mode 100644 gdb/testsuite/gdb.trace/ftrace-arm-insn.c
 create mode 100644 gdb/testsuite/gdb.trace/ftrace-arm-insn.exp

diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 53c4151..ea3fee8 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -1087,11 +1087,24 @@ struct arm_insn_reloc_data
     uint16_t thumb32[2];
   } insns;
 
+  /* The original PC of the instruction.  */
+  CORE_ADDR orig_loc;
+
+  /* The PC where the modified instruction(s) will start.  */
+  CORE_ADDR new_loc;
+
   /* Error message to return to the client in case the relocation fails.  */
   const char *err;
 };
 
 static int
+arm_reloc_refs_pc_error (struct arm_insn_reloc_data *data)
+{
+  data->err = "The instruction references the PC, couldn't relocate.";
+  return 1;
+}
+
+static int
 arm_reloc_others (uint32_t insn, const char *iname,
 		  struct arm_insn_reloc_data *data)
 {
@@ -1103,86 +1116,168 @@ arm_reloc_others (uint32_t insn, const char *iname,
 static int
 arm_reloc_alu_imm (uint32_t insn, struct arm_insn_reloc_data *data)
 {
-  return 1;
+  if (arm_insn_references_pc (insn, 0x000f0000ul))
+    return arm_reloc_refs_pc_error (data);
+
+  return arm_reloc_others (insn, "ALU immediate", data);
 }
 
 static int
 arm_reloc_alu_reg (uint32_t insn, struct arm_insn_reloc_data *data)
 {
-  return 1;
+  if (arm_insn_references_pc (insn, 0x000ff00ful))
+    return arm_reloc_refs_pc_error (data);
+
+  return arm_reloc_others (insn, "ALU reg", data);
 }
 
 static int
 arm_reloc_alu_shifted_reg (uint32_t insn, struct arm_insn_reloc_data *data)
 {
-  return 1;
+  if (arm_insn_references_pc (insn, 0x000fff0ful))
+    return arm_reloc_refs_pc_error (data);
+
+  return arm_reloc_others (insn, "ALU shifted reg", data);
 }
 
 static int
 arm_reloc_b_bl_blx (uint32_t insn, struct arm_insn_reloc_data *data)
 {
-  return 1;
+  uint32_t cond = bits (insn, 28, 31);
+  int exchange = (cond == 0xf);
+
+  if (exchange)
+    {
+      /* blx */
+      CORE_ADDR absolute_dest = BranchDest (data->orig_loc, insn);
+
+      /* Adjust the address if the H bit is set.  */
+      if (bit(insn, 24))
+	absolute_dest |= (1 << 1);
+      arm_emit_arm_blx
+	(&data->insns.arm, cond,
+	 immediate_operand (arm_arm_branch_relative_distance (data->new_loc,
+							      absolute_dest)));
+    }
+  else
+    {
+      /* b or bl */
+      CORE_ADDR absolute_dest = BranchDest (data->orig_loc, insn);
+      int link = exchange || bit (insn, 24);
+
+      if (link)
+	{
+	  arm_emit_arm_bl (&data->insns.arm, cond,
+			   arm_arm_branch_relative_distance (data->new_loc,
+							     absolute_dest));
+	}
+      else
+	{
+	  arm_emit_arm_b (&data->insns.arm, cond,
+			  arm_arm_branch_relative_distance (data->new_loc,
+							    absolute_dest));
+	}
+    }
+
+  return 0;
 }
 
 static int
 arm_reloc_block_xfer (uint32_t insn, struct arm_insn_reloc_data *data)
 {
-  return 1;
+  if (bit (insn, 20) == 1)
+    {
+      /* it's an LDM/POP-kind instruction.  If it mentions PC, the instruction
+         will result in a jump.  The destination address is absolute, so it
+         won't change the result if we execute it out of line.  */
+      return arm_reloc_others (insn, "ldm", data);
+    }
+  else
+    {
+      /* It's an STM/PUSH-kind instruction.  If it mentions PC, we will store
+         the wrong value of PC in memory.  Therefore, error out if PC is
+         mentioned.  */
+      if ((insn & (1 << 15)) != 0)
+	return arm_reloc_refs_pc_error (data);
+
+      return arm_reloc_others (insn, "stm", data);
+    }
 }
 
 static int
 arm_reloc_bx_blx_reg (uint32_t insn, struct arm_insn_reloc_data *data)
 {
-  return 1;
+  /* These instructions take an absolute address in a register, so there's
+     nothing special to do.  */
+  return arm_reloc_others(insn, "bx/blx", data);
 }
 
 static int
 arm_reloc_copro_load_store (uint32_t insn, struct arm_insn_reloc_data *data)
 {
-  return 1;
+  if (arm_insn_references_pc (insn, 0x000f0000ul))
+    return arm_reloc_refs_pc_error (data);
+
+  return arm_reloc_others (insn, "copro load/store", data);
 }
 
 static int
 arm_reloc_extra_ld_st (uint32_t insn, struct arm_insn_reloc_data *data,
 		       int unprivileged)
 {
-  return 1;
+  if (arm_insn_references_pc (insn, 0x000ff00ful))
+    return arm_reloc_refs_pc_error (data);
+
+  return arm_reloc_others (insn, "extra load/store", data);
 }
 
 static int
 arm_reloc_ldr_str_ldrb_strb (uint32_t insn, struct arm_insn_reloc_data *data,
 			     int load, int size, int usermode)
 {
-  return 1;
+  if (arm_insn_references_pc (insn, 0x000ff00ful))
+    return arm_reloc_refs_pc_error (data);
+
+  return arm_reloc_others (insn, "load/store", data);
 }
 
 static int
 arm_reloc_preload (uint32_t insn, struct arm_insn_reloc_data *data)
 {
-  return 1;
+  if (arm_insn_references_pc (insn, 0x000f0000ul))
+    return arm_reloc_refs_pc_error (data);
+
+  return arm_reloc_others (insn, "preload", data);
 }
 
 static int
 arm_reloc_preload_reg (uint32_t insn, struct arm_insn_reloc_data *data)
 {
-  return 1;
+  if (arm_insn_references_pc (insn, 0x000f000ful))
+    return arm_reloc_refs_pc_error (data);
+
+  return arm_reloc_others (insn, "preload reg", data);
 }
 
 static int
 arm_reloc_svc (uint32_t insn, struct arm_insn_reloc_data *data)
 {
-  return 1;
+  /* There is nothing PC-relative in the SVC instruction.  */
+  return arm_reloc_others(insn, "svc", data);
 }
 
 static int
 arm_reloc_undef (uint32_t insn, struct arm_insn_reloc_data *data)
 {
+
+  data->err = "The instruction is undefined, couldn't relocate.";
   return 1;
 }
 
 static int
 arm_reloc_unpred (uint32_t insn, struct arm_insn_reloc_data *data)
 {
+  data->err = "The instruction is unpredictable, couldn't relocate.";
   return 1;
 }
 
@@ -1220,6 +1315,8 @@ copy_instruction_arm (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 = arm_relocate_insn (insn, &arm_insn_reloc_visitor, &data);
   if (ret != 0)
diff --git a/gdb/testsuite/gdb.trace/ftrace-arm-insn.S b/gdb/testsuite/gdb.trace/ftrace-arm-insn.S
new file mode 100644
index 0000000..c123727
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/ftrace-arm-insn.S
@@ -0,0 +1,221 @@
+.syntax unified
+
+.text
+
+.macro prologue
+push {lr}
+.endm
+
+.macro epilogue
+pop {pc}
+.endm
+
+/* arm b imm */
+.arm
+.type func_arm_b_imm, STT_FUNC
+.global func_arm_b_imm
+func_arm_b_imm:
+	prologue
+
+insn_arm_b_imm:
+	b arm_b_imm_jump
+
+arm_b_imm_jump_back:
+	epilogue
+
+arm_b_imm_jump:
+	ldr r0, =global_variable
+	ldr r1, =magic_number
+	ldr r1, [r1]
+	str r1, [r0]
+
+	# return to the function
+	b arm_b_imm_jump_back
+
+
+/* arm b imm with a false condition */
+.arm
+.type func_arm_b_imm_cond, STT_FUNC
+.global func_arm_b_imm_cond
+func_arm_b_imm_cond:
+	prologue
+
+	/* Force a false condition.  If we mess up the condition and the branch is
+	   taken, the magic number won't get written and the test will fail.  */
+	mov r0, 0
+	cmp r0, 0
+
+insn_arm_b_imm_cond:
+	bne arm_b_imm_jump_cond
+
+	ldr r0, =global_variable
+	ldr r1, =magic_number
+	ldr r1, [r1]
+	str r1, [r0]
+
+arm_b_imm_jump_cond:
+
+	epilogue
+
+
+/* arm bl imm */
+.arm
+.type func_arm_bl_imm, STT_FUNC
+.global func_arm_bl_imm
+func_arm_bl_imm:
+	prologue
+
+insn_arm_bl_imm:
+	bl arm_bl_imm_jump
+
+	epilogue
+
+arm_bl_imm_jump:
+	ldr r0, =global_variable
+	ldr r1, =magic_number
+	ldr r1, [r1]
+	str r1, [r0]
+
+	# return to the function
+	bx lr
+
+
+/* arm blx imm */
+.arm
+.type func_arm_blx_imm, STT_FUNC
+.global func_arm_blx_imm
+func_arm_blx_imm:
+	prologue
+
+insn_arm_blx_imm:
+	blx arm_blx_imm_jump
+
+	epilogue
+
+.thumb
+arm_blx_imm_jump:
+	ldr r0, =global_variable
+	ldr r1, =magic_number
+	ldr r1, [r1]
+	str r1, [r0]
+
+	# return to the function
+	bx lr
+
+
+/* arm bx reg */
+.arm
+.type func_arm_bx_reg, STT_FUNC
+.global func_arm_bx_reg
+func_arm_bx_reg:
+	prologue
+
+	ldr r0, =arm_bx_reg_jump
+
+insn_arm_bx_reg:
+	bx r0
+
+arm_bx_reg_jump_back:
+	epilogue
+
+.thumb_func
+.thumb
+arm_bx_reg_jump:
+	ldr r0, =global_variable
+	ldr r1, =magic_number
+	ldr r1, [r1]
+	str r1, [r0]
+
+	# return to the function
+	ldr r0, =arm_bx_reg_jump_back
+	bx r0
+
+
+/* arm blx reg */
+.arm
+.type func_arm_blx_reg, STT_FUNC
+.global func_arm_blx_reg
+func_arm_blx_reg:
+	prologue
+
+	ldr r0, =arm_blx_reg_jump
+
+insn_arm_blx_reg:
+	blx r0
+
+	epilogue
+
+.thumb_func
+.thumb
+arm_blx_reg_jump:
+	ldr r0, =global_variable
+	ldr r1, =magic_number
+	ldr r1, [r1]
+	str r1, [r0]
+
+	# return to the function
+	bx lr
+
+
+/* arm ldm */
+.arm
+.type func_arm_ldm, STT_FUNC
+.global func_arm_ldm
+func_arm_ldm:
+	prologue
+
+	ldr r0, =magic_number
+	ldr r0, [r0]
+	stmfd sp!, {r0}
+
+insn_arm_ldm:
+	ldmfd sp!, {r1}
+	ldr r0, =global_variable
+	str r1, [r0]
+
+	epilogue
+
+
+/* arm ldm pc */
+.arm
+.type func_arm_ldm_pc, STT_FUNC
+.global func_arm_ldm_pc
+func_arm_ldm_pc:
+	prologue
+
+	ldr r0, =arm_ldm_pc_jump
+	stmfd sp!, {r0}
+
+insn_arm_ldm_pc:
+	ldmfd sp!, {pc}
+
+arm_ldm_pc_jump_back:
+	epilogue
+
+arm_ldm_pc_jump:
+	ldr r0, =global_variable
+	ldr r1, =magic_number
+	ldr r1, [r1]
+	str r1, [r0]
+	b arm_ldm_pc_jump_back
+
+
+/* arm stm */
+.arm
+.type func_arm_stm, STT_FUNC
+.global func_arm_stm
+func_arm_stm:
+	prologue
+
+	ldr r0, =magic_number
+	ldr r0, [r0]
+
+insn_arm_stm:
+	stmfd 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
new file mode 100644
index 0000000..ec08298
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/ftrace-arm-insn.c
@@ -0,0 +1,78 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+/* Magic number chosen at random.  */
+const uint32_t magic_number = 0x2eb2944b;
+
+static void
+break_here (void)
+{
+}
+
+void
+fail (void)
+{
+  exit (1);
+}
+
+int global_variable;
+
+#define DEF_TEST_FN(name) \
+   static void \
+   test_##name (void) \
+   { \
+      void func_##name (void); \
+      \
+      global_variable = 0; \
+      \
+      func_##name (); \
+      \
+      if (global_variable != magic_number) \
+         fail (); \
+      \
+      break_here (); \
+   }
+
+DEF_TEST_FN (arm_b_imm)
+DEF_TEST_FN (arm_b_imm_cond)
+DEF_TEST_FN (arm_bl_imm)
+DEF_TEST_FN (arm_blx_imm)
+DEF_TEST_FN (arm_bx_reg)
+DEF_TEST_FN (arm_blx_reg)
+DEF_TEST_FN (arm_ldm)
+DEF_TEST_FN (arm_ldm_pc)
+DEF_TEST_FN (arm_stm)
+
+int
+main (void)
+{
+  test_arm_b_imm ();
+  test_arm_b_imm_cond ();
+  test_arm_bl_imm ();
+  test_arm_blx_imm ();
+  test_arm_bx_reg ();
+  test_arm_blx_reg ();
+  test_arm_ldm ();
+  test_arm_ldm_pc ();
+  test_arm_stm ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.trace/ftrace-arm-insn.exp b/gdb/testsuite/gdb.trace/ftrace-arm-insn.exp
new file mode 100644
index 0000000..e78d484
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/ftrace-arm-insn.exp
@@ -0,0 +1,103 @@
+# Copyright 2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+load_lib "trace-support.exp"
+
+standard_testfile
+set expfile $testfile.exp
+
+# Some targets have leading underscores on assembly symbols.
+set additional_flags [gdb_target_symbol_prefix_flags]
+
+set c_file "$srcdir/$subdir/$srcfile"
+set asm_file "$srcdir/$subdir/$testfile.S"
+set source_files "${c_file} ${asm_file}"
+
+if { ![istarget "arm*-*-*"] } {
+    verbose "Skipping ARM-specific test."
+    return
+}
+
+if [prepare_for_testing $expfile $binfile $source_files \
+	[list debug $additional_flags]] {
+    untested "failed to prepare for trace tests"
+    return -1
+}
+
+if ![runto_main] {
+    fail "Can't run to main to check for trace support"
+    return -1
+}
+
+if ![gdb_target_supports_trace] {
+    unsupported "target does not support trace"
+    return -1
+}
+
+if {![gdb_target_supports_fast_trace]} {
+    unsupported "Target does not support fast tracepoints."
+    return -1
+}
+
+set libipa [get_in_proc_agent]
+gdb_load_shlib $libipa
+
+if ![runto_main] {
+    untested "could not run to main"
+    return -1
+}
+
+if { [gdb_compile $source_files $binfile \
+	  executable [list debug $additional_flags shlib=$libipa] ] != "" } {
+    untested "failed to compile ftrace tests"
+    return -1
+}
+
+proc do_test { insn } {
+    global binfile
+    global decimal
+    global hex
+    global asm_file
+
+    with_test_prefix $insn {
+        # The test function for this instruction
+        set test_function "test_${insn}"
+        # The instruction on which we want to install a fast tracepoint
+        set insn_location "insn_${insn}"
+
+        clean_restart ${binfile}
+        if ![runto $test_function] {
+            fail "Can't run to $test_function"
+            return 0
+        }
+        gdb_breakpoint "break_here"
+
+        gdb_test "ftrace ${insn_location}" "Fast tracepoint ${decimal} at ${hex}: file ${asm_file}, line ${decimal}."
+        gdb_test_no_output "tstart"
+        gdb_continue "break_here"
+        gdb_test_no_output "tstop"
+        gdb_test "tstatus" ".*Collected 1 trace frames.*"
+    }
+}
+
+do_test arm_b_imm
+do_test arm_b_imm_cond
+do_test arm_bl_imm
+do_test arm_blx_imm
+do_test arm_bx_reg
+do_test arm_blx_reg
+do_test arm_ldm
+do_test arm_ldm_pc
+do_test arm_stm
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 10/18] gdbserver: pass pointer to struct tracepoint to install_fast_tracepoint_jump_pad
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (12 preceding siblings ...)
  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 ` Antoine Tremblay
  2016-07-05 13:42 ` [PATCH v3 01/18] arm-tdep.c: Replace arguments to decode function by a structure Antoine Tremblay
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:42 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

We currently pass many values to install_fast_tracepoint_jump_pad that
come from fields of struct tracepoint, and we plan to add another (the
kind field).  It would be simpler to just pass a pointer to the
tracepoint and have install_fast_tracepoint_jump_pad fetch the fields
from it.

That requires moving the struct tracepoint definition to tracepoint.h.

gdb/gdbserver/ChangeLog:

	* linux-aarch64-low.c (aarch64_install_fast_tracepoint_jump_pad):
	Replaces some parameters with a struct tracepoint *.
	* linux-low.c (linux_install_fast_tracepoint_jump_pad):
	Likewise.
	* linux-low.h (struct linux_target_ops)
	<install_fast_tracepoint_jump_pad>: Likewise.
	* linux-ppc-low.c (ppc_install_fast_tracepoint_jump_pad):
	Likewise.
	* linux-s390-low.c (s390_install_fast_tracepoint_jump_pad):
	Likewise.
	* linux-x86-low.c (amd64_install_fast_tracepoint_jump_pad): Likewise.
	(i386_install_fast_tracepoint_jump_pad): Likewise.
	(x86_install_fast_tracepoint_jump_pad): Likewise.
	* target.h (struct tracepoint): New forward declaration.
	(struct target_ops) <install_fast_tracepoint_jump_pad>: Replace
	some parameters with a struct tracepoint *.
	(install_fast_tracepoint_jump_pad): Likewise.
	* tracepoint.c (enum tracepoint_type): Move to tracepoint.h.
	(struct tracepoint): Likewise.
	(install_fast_tracepoint): Adapt call to
	install_fast_tracepoint_jump_pad.
	* tracepoint.h (enum tracepoint_type) Moved from tracepoint.c.
	(struct tracepoint): Moved from tracepoint.c.
---
 gdb/gdbserver/linux-aarch64-low.c |  26 ++++----
 gdb/gdbserver/linux-arm-low.c     |   2 +
 gdb/gdbserver/linux-low.c         |  12 +---
 gdb/gdbserver/linux-low.h         |   5 +-
 gdb/gdbserver/linux-ppc-low.c     |  21 +++---
 gdb/gdbserver/linux-s390-low.c    |  13 ++--
 gdb/gdbserver/linux-x86-low.c     |  63 ++++++++----------
 gdb/gdbserver/target.h            |  26 ++++----
 gdb/gdbserver/tracepoint.c        | 131 +-------------------------------------
 gdb/gdbserver/tracepoint.h        | 125 ++++++++++++++++++++++++++++++++++++
 10 files changed, 195 insertions(+), 229 deletions(-)

diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c
index 6efa035..da8c0cc 100644
--- a/gdb/gdbserver/linux-aarch64-low.c
+++ b/gdb/gdbserver/linux-aarch64-low.c
@@ -1784,18 +1784,14 @@ static const struct aarch64_insn_visitor visitor =
    "install_fast_tracepoint_jump_pad".  */
 
 static int
-aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
-					  CORE_ADDR tpaddr,
+aarch64_install_fast_tracepoint_jump_pad (struct tracepoint *tp,
 					  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)
 {
   uint32_t buf[256];
@@ -1909,7 +1905,7 @@ aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
 
      */
 
-  p += emit_mov_addr (p, x3, tpaddr);
+  p += emit_mov_addr (p, x3, tp->address);
   p += emit_str (p, x3, sp, offset_memory_operand (3 * 16));
 
   /* Save CPSR (NZCV), FPSR and FPCR:
@@ -1944,7 +1940,7 @@ aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
 
      */
 
-  p += emit_mov_addr (p, x0, tpoint);
+  p += emit_mov_addr (p, x0, tp->obj_addr_on_target);
   p += emit_mrs (p, x1, TPIDR_EL0);
   p += emit_stp (p, x0, x1, sp, preindex_memory_operand (-16));
 
@@ -2021,7 +2017,7 @@ aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
 
      */
 
-  p += emit_mov_addr (p, x0, tpoint);
+  p += emit_mov_addr (p, x0, tp->obj_addr_on_target);
   p += emit_add (p, x1, sp, immediate_operand (16));
 
   p += emit_mov_addr (p, ip0, collector);
@@ -2105,10 +2101,10 @@ aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
   append_insns (&buildaddr, p - buf, buf);
 
   /* Now emit the relocated instruction.  */
-  *adjusted_insn_addr = buildaddr;
-  target_read_uint32 (tpaddr, &insn);
+  tp->adjusted_insn_addr = buildaddr;
+  target_read_uint32 (tp->address, &insn);
 
-  insn_data.base.insn_addr = tpaddr;
+  insn_data.base.insn_addr = tp->address;
   insn_data.new_addr = buildaddr;
   insn_data.insn_ptr = buf;
 
@@ -2120,19 +2116,19 @@ aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
     {
       sprintf (err,
 	       "E.Could not relocate instruction from %s to %s.",
-	       core_addr_to_string_nz (tpaddr),
+	       core_addr_to_string_nz (tp->address),
 	       core_addr_to_string_nz (buildaddr));
       return 1;
     }
   else
     append_insns (&buildaddr, insn_data.insn_ptr - buf, buf);
-  *adjusted_insn_addr_end = buildaddr;
+  tp->adjusted_insn_addr_end = buildaddr;
 
   /* Go back to the start of the buffer.  */
   p = buf;
 
   /* Emit a branch back from the jump pad.  */
-  offset = (tpaddr + orig_size - buildaddr);
+  offset = (tp->address + tp->orig_size - buildaddr);
   if (!can_encode_int32 (offset, 28))
     {
       sprintf (err,
@@ -2146,7 +2142,7 @@ aarch64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
   append_insns (&buildaddr, p - buf, buf);
 
   /* Give the caller a branch instruction into the jump pad.  */
-  offset = (*jump_entry - tpaddr);
+  offset = (*jump_entry - tp->address);
   if (!can_encode_int32 (offset, 28))
     {
       sprintf (err,
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index c245ec2..c927ad8 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -33,6 +33,8 @@
 #include <signal.h>
 #include <sys/syscall.h>
 
+#include "tracepoint.h"
+
 /* Defined in auto-generated files.  */
 void init_registers_arm (void);
 extern const struct target_desc *tdesc_arm;
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 0f4bb87..14e15df 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -6556,25 +6556,19 @@ linux_done_accessing_memory (void)
 }
 
 static int
-linux_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+linux_install_fast_tracepoint_jump_pad (struct tracepoint *tp,
 					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)
 {
   return (*the_low_target.install_fast_tracepoint_jump_pad)
-    (tpoint, tpaddr, collector, lockaddr, orig_size,
-     jump_entry, trampoline, trampoline_size,
-     jjump_pad_insn, jjump_pad_insn_size,
-     adjusted_insn_addr, adjusted_insn_addr_end,
-     err);
+      (tp, collector, lockaddr, jump_entry, trampoline, trampoline_size,
+       jjump_pad_insn, jjump_pad_insn_size, err);
 }
 
 static struct emit_ops *
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index 5057e66..e450331 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -211,17 +211,14 @@ struct linux_target_ops
 
   /* Install a fast tracepoint jump pad.  See target.h for
      comments.  */
-  int (*install_fast_tracepoint_jump_pad) (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+  int (*install_fast_tracepoint_jump_pad) (struct tracepoint *tp,
 					   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);
 
   /* Return the bytecode operations vector for the current inferior.
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index 1d013f1..4cc167c 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -1252,17 +1252,14 @@ ppc_relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc)
    See target.h for details.  */
 
 static int
-ppc_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+ppc_install_fast_tracepoint_jump_pad (struct tracepoint *tp,
 				      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)
 {
   uint32_t buf[256];
@@ -1271,6 +1268,8 @@ ppc_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
   CORE_ADDR buildaddr = *jump_entry;
   const CORE_ADDR entryaddr = *jump_entry;
   int rsz, min_frame, frame_size, tp_reg;
+  CORE_ADDR tpoint = tp->obj_addr_on_target;
+  CORE_ADDR tpaddr = tp->address;
 #ifdef __powerpc64__
   struct regcache *regcache = get_thread_regcache (current_thread, 0);
   int is_64 = register_size (regcache->tdesc, 0) == 8;
@@ -1407,22 +1406,22 @@ ppc_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
   write_inferior_memory (buildaddr, (unsigned char *) buf, (p - buf) * 4);
 
   /* Now, insert the original instruction to execute in the jump pad.  */
-  *adjusted_insn_addr = buildaddr + (p - buf) * 4;
-  *adjusted_insn_addr_end = *adjusted_insn_addr;
-  ppc_relocate_instruction (adjusted_insn_addr_end, tpaddr);
+  tp->adjusted_insn_addr = buildaddr + (p - buf) * 4;
+  tp->adjusted_insn_addr_end = tp->adjusted_insn_addr;
+  ppc_relocate_instruction (&tp->adjusted_insn_addr_end, tpaddr);
 
   /* Verify the relocation size.  If should be 4 for normal copy,
      8 or 12 for some conditional branch.  */
-  if ((*adjusted_insn_addr_end - *adjusted_insn_addr == 0)
-      || (*adjusted_insn_addr_end - *adjusted_insn_addr > 12))
+  if ((tp->adjusted_insn_addr_end - tp->adjusted_insn_addr == 0)
+      || (tp->adjusted_insn_addr_end - tp->adjusted_insn_addr > 12))
     {
       sprintf (err, "E.Unexpected instruction length = %d"
 		    "when relocate instruction.",
-		    (int) (*adjusted_insn_addr_end - *adjusted_insn_addr));
+		    (int) (tp->adjusted_insn_addr_end - tp->adjusted_insn_addr));
       return 1;
     }
 
-  buildaddr = *adjusted_insn_addr_end;
+  buildaddr = tp->adjusted_insn_addr_end;
   p = buf;
   /* Finally, write a jump back to the program.  */
   offset = (tpaddr + 4) - buildaddr;
diff --git a/gdb/gdbserver/linux-s390-low.c b/gdb/gdbserver/linux-s390-low.c
index 231b614..fa50393 100644
--- a/gdb/gdbserver/linux-s390-low.c
+++ b/gdb/gdbserver/linux-s390-low.c
@@ -1178,18 +1178,14 @@ s390_relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc, int is_64)
    "install_fast_tracepoint_jump_pad".  */
 
 static int
-s390_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
-				       CORE_ADDR tpaddr,
+s390_install_fast_tracepoint_jump_pad (struct tracepoint *tp,
 				       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)
 {
   int i;
@@ -1197,6 +1193,9 @@ s390_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
   int32_t offset;
   unsigned char jbuf[6] = { 0xc0, 0xf4, 0, 0, 0, 0 };	/* jg ... */
   CORE_ADDR buildaddr = *jump_entry;
+  CORE_ADDR tpaddr = tp->address;
+  CORE_ADDR tpoint = tp->obj_addr_on_target;
+  ULONGEST orig_size = tp->orig_size;
 #ifdef __s390x__
   struct regcache *regcache = get_thread_regcache (current_thread, 0);
   int is_64 = register_size (regcache->tdesc, 0) == 8;
@@ -1297,13 +1296,13 @@ s390_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint,
 
   /* Now, adjust the original instruction to execute in the jump
      pad.  */
-  *adjusted_insn_addr = buildaddr;
+  tp->adjusted_insn_addr = buildaddr;
   if (s390_relocate_instruction (&buildaddr, tpaddr, is_64))
     {
       sprintf (err, "E.Could not relocate instruction for tracepoint.");
       return 1;
     }
-  *adjusted_insn_addr_end = buildaddr;
+  tp->adjusted_insn_addr_end = buildaddr;
 
   /* Finally, write a jump back to the program.  */
 
diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c
index 5080dec..06d9a8e 100644
--- a/gdb/gdbserver/linux-x86-low.c
+++ b/gdb/gdbserver/linux-x86-low.c
@@ -1047,17 +1047,14 @@ push_opcode (unsigned char *buf, char *op)
    tracepoint address.  */
 
 static int
-amd64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+amd64_install_fast_tracepoint_jump_pad (struct tracepoint *tp,
 					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[40];
@@ -1090,7 +1087,7 @@ amd64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
   buf[i++] = 0x9c; /* pushfq */
   buf[i++] = 0x48; /* movl <addr>,%rdi */
   buf[i++] = 0xbf;
-  *((unsigned long *)(buf + i)) = (unsigned long) tpaddr;
+  *((unsigned long *)(buf + i)) = (unsigned long) tp->address;
   i += sizeof (unsigned long);
   buf[i++] = 0x57; /* push %rdi */
   append_insns (&buildaddr, i, buf);
@@ -1099,7 +1096,7 @@ amd64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
   i = 0;
   i += push_opcode (&buf[i], "48 83 ec 18");	/* sub $0x18,%rsp */
   i += push_opcode (&buf[i], "48 b8");          /* mov <tpoint>,%rax */
-  memcpy (buf + i, &tpoint, 8);
+  memcpy (buf + i, &tp->obj_addr_on_target, 8);
   i += 8;
   i += push_opcode (&buf[i], "48 89 04 24");    /* mov %rax,(%rsp) */
   i += push_opcode (&buf[i],
@@ -1129,7 +1126,7 @@ amd64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
 
   /* tpoint address may be 64-bit wide.  */
   i += push_opcode (&buf[i], "48 bf");		/* movl <addr>,%rdi */
-  memcpy (buf + i, &tpoint, 8);
+  memcpy (buf + i, &tp->obj_addr_on_target, 8);
   i += 8;
   append_insns (&buildaddr, i, buf);
 
@@ -1182,13 +1179,13 @@ amd64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
 
   /* Now, adjust the original instruction to execute in the jump
      pad.  */
-  *adjusted_insn_addr = buildaddr;
-  relocate_instruction (&buildaddr, tpaddr);
-  *adjusted_insn_addr_end = buildaddr;
+  tp->adjusted_insn_addr = buildaddr;
+  relocate_instruction (&buildaddr, tp->address);
+  tp->adjusted_insn_addr_end = buildaddr;
 
   /* Finally, write a jump back to the program.  */
 
-  loffset = (tpaddr + orig_size) - (buildaddr + sizeof (jump_insn));
+  loffset = (tp->address + tp->orig_size) - (buildaddr + sizeof (jump_insn));
   if (loffset > INT_MAX || loffset < INT_MIN)
     {
       sprintf (err,
@@ -1206,7 +1203,7 @@ amd64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
      is always done last (by our caller actually), so that we can
      install fast tracepoints with threads running.  This relies on
      the agent's atomic write support.  */
-  loffset = *jump_entry - (tpaddr + sizeof (jump_insn));
+  loffset = *jump_entry - (tp->address + sizeof (jump_insn));
   if (loffset > INT_MAX || loffset < INT_MIN)
     {
       sprintf (err,
@@ -1236,17 +1233,14 @@ amd64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
    tracepoint address.  */
 
 static int
-i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+i386_install_fast_tracepoint_jump_pad (struct tracepoint *tp,
 				       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];
@@ -1259,7 +1253,7 @@ i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
   i = 0;
   buf[i++] = 0x60; /* pushad */
   buf[i++] = 0x68; /* push tpaddr aka $pc */
-  *((int *)(buf + i)) = (int) tpaddr;
+  *((int *)(buf + i)) = (int) tp->address;
   i += 4;
   buf[i++] = 0x9c; /* pushf */
   buf[i++] = 0x1e; /* push %ds */
@@ -1278,7 +1272,7 @@ i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
 
   /* Build the object.  */
   i += push_opcode (&buf[i], "b8");		/* mov    <tpoint>,%eax */
-  memcpy (buf + i, &tpoint, 4);
+  memcpy (buf + i, &tp->obj_addr_on_target, 4);
   i += 4;
   i += push_opcode (&buf[i], "89 04 24");	   /* mov %eax,(%esp) */
 
@@ -1313,7 +1307,7 @@ i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
 
   i = 0;
   i += push_opcode (&buf[i], "c7 04 24");       /* movl <addr>,(%esp) */
-  memcpy (&buf[i], (void *) &tpoint, 4);
+  memcpy (&buf[i], (void *) &tp->obj_addr_on_target, 4);
   i += 4;
   append_insns (&buildaddr, i, buf);
 
@@ -1363,12 +1357,12 @@ i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
 
   /* Now, adjust the original instruction to execute in the jump
      pad.  */
-  *adjusted_insn_addr = buildaddr;
-  relocate_instruction (&buildaddr, tpaddr);
-  *adjusted_insn_addr_end = buildaddr;
+  tp->adjusted_insn_addr = buildaddr;
+  relocate_instruction (&buildaddr, tp->address);
+  tp->adjusted_insn_addr_end = buildaddr;
 
   /* Write the jump back to the program.  */
-  offset = (tpaddr + orig_size) - (buildaddr + sizeof (jump_insn));
+  offset = (tp->address + tp->orig_size) - (buildaddr + sizeof (jump_insn));
   memcpy (buf, jump_insn, sizeof (jump_insn));
   memcpy (buf + 1, &offset, 4);
   append_insns (&buildaddr, sizeof (jump_insn), buf);
@@ -1377,7 +1371,7 @@ i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
      is always done last (by our caller actually), so that we can
      install fast tracepoints with threads running.  This relies on
      the agent's atomic write support.  */
-  if (orig_size == 4)
+  if (tp->orig_size == 4)
     {
       /* Create a trampoline.  */
       *trampoline_size = sizeof (jump_insn);
@@ -1396,7 +1390,7 @@ i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
       write_inferior_memory (*trampoline, buf, sizeof (jump_insn));
 
       /* Use a 16-bit relative jump instruction to jump to the trampoline.  */
-      offset = (*trampoline - (tpaddr + sizeof (small_jump_insn))) & 0xffff;
+      offset = (*trampoline - (tp->address + sizeof (small_jump_insn))) & 0xffff;
       memcpy (buf, small_jump_insn, sizeof (small_jump_insn));
       memcpy (buf + 2, &offset, 2);
       memcpy (jjump_pad_insn, buf, sizeof (small_jump_insn));
@@ -1405,7 +1399,7 @@ i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
   else
     {
       /* Else use a 32-bit relative jump instruction.  */
-      offset = *jump_entry - (tpaddr + sizeof (jump_insn));
+      offset = *jump_entry - (tp->address + sizeof (jump_insn));
       memcpy (buf, jump_insn, sizeof (jump_insn));
       memcpy (buf + 1, &offset, 4);
       memcpy (jjump_pad_insn, buf, sizeof (jump_insn));
@@ -1419,40 +1413,33 @@ i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
 }
 
 static int
-x86_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+x86_install_fast_tracepoint_jump_pad (struct tracepoint *tp,
 				      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)
 {
 #ifdef __x86_64__
   if (is_64bit_tdesc ())
-    return amd64_install_fast_tracepoint_jump_pad (tpoint, tpaddr,
+    return amd64_install_fast_tracepoint_jump_pad (tp,
 						   collector, lockaddr,
-						   orig_size, jump_entry,
+						   jump_entry,
 						   trampoline, trampoline_size,
 						   jjump_pad_insn,
 						   jjump_pad_insn_size,
-						   adjusted_insn_addr,
-						   adjusted_insn_addr_end,
 						   err);
 #endif
 
-  return i386_install_fast_tracepoint_jump_pad (tpoint, tpaddr,
+  return i386_install_fast_tracepoint_jump_pad (tp,
 						collector, lockaddr,
-						orig_size, jump_entry,
+						jump_entry,
 						trampoline, trampoline_size,
 						jjump_pad_insn,
 						jjump_pad_insn_size,
-						adjusted_insn_addr,
-						adjusted_insn_addr_end,
 						err);
 }
 
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 4c14c20..e6f0542 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -32,6 +32,7 @@
 struct emit_ops;
 struct buffer;
 struct process_info;
+struct tracepoint;
 
 /* This structure describes how to resume a particular thread (or all
    threads) based on the client's request.  If thread is -1, then this
@@ -358,17 +359,14 @@ struct target_ops
      return the address range where the instruction at TPADDR was relocated
      to.  If an error occurs, the ERR may be used to pass on an error
      message.  */
-  int (*install_fast_tracepoint_jump_pad) (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+  int (*install_fast_tracepoint_jump_pad) (struct tracepoint *tp,
 					   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);
 
   /* Return the bytecode operations vector for the current inferior.
@@ -592,25 +590,23 @@ int kill_inferior (int);
 	(*the_target->stabilize_threads) ();  	\
     } while (0)
 
-#define install_fast_tracepoint_jump_pad(tpoint, tpaddr,		\
-					 collector, lockaddr,		\
-					 orig_size,			\
+#define install_fast_tracepoint_jump_pad(tp,				\
+					 collector,			\
+					 lockaddr,			\
 					 jump_entry,			\
-					 trampoline, trampoline_size,	\
+					 trampoline,			\
+					 trampoline_size,		\
 					 jjump_pad_insn,		\
 					 jjump_pad_insn_size,		\
-					 adjusted_insn_addr,		\
-					 adjusted_insn_addr_end,	\
 					 err)				\
-  (*the_target->install_fast_tracepoint_jump_pad) (tpoint, tpaddr,	\
-						   collector,lockaddr,	\
-						   orig_size, jump_entry, \
+  (*the_target->install_fast_tracepoint_jump_pad) (tp,			\
+						   collector,		\
+						   lockaddr,		\
+						   jump_entry, 		\
 						   trampoline,		\
 						   trampoline_size,	\
 						   jjump_pad_insn,	\
 						   jjump_pad_insn_size, \
-						   adjusted_insn_addr,	\
-						   adjusted_insn_addr_end, \
 						   err)
 
 #define target_emit_ops() \
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index d3ddeaf..a139f67 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -673,136 +673,11 @@ struct source_string
   struct source_string *next;
 };
 
-enum tracepoint_type
-{
-  /* Trap based tracepoint.  */
-  trap_tracepoint,
-
-  /* A fast tracepoint implemented with a jump instead of a trap.  */
-  fast_tracepoint,
-
-  /* A static tracepoint, implemented by a program call into a tracing
-     library.  */
-  static_tracepoint
-};
-
 struct tracepoint_hit_ctx;
 
 typedef enum eval_result_type (*condfn) (unsigned char *,
 					 ULONGEST *);
 
-/* The definition of a tracepoint.  */
-
-/* Tracepoints may have multiple locations, each at a different
-   address.  This can occur with optimizations, template
-   instantiation, etc.  Since the locations may be in different
-   scopes, the conditions and actions may be different for each
-   location.  Our target version of tracepoints is more like GDB's
-   notion of "breakpoint locations", but we have almost nothing that
-   is not per-location, so we bother having two kinds of objects.  The
-   key consequence is that numbers are not unique, and that it takes
-   both number and address to identify a tracepoint uniquely.  */
-
-struct tracepoint
-{
-  /* The number of the tracepoint, as specified by GDB.  Several
-     tracepoint objects here may share a number.  */
-  uint32_t number;
-
-  /* Address at which the tracepoint is supposed to trigger.  Several
-     tracepoints may share an address.  */
-  CORE_ADDR address;
-
-  /* Tracepoint type.  */
-  enum tracepoint_type type;
-
-  /* True if the tracepoint is currently enabled.  */
-  int8_t enabled;
-
-  /* The number of single steps that will be performed after each
-     tracepoint hit.  */
-  uint64_t step_count;
-
-  /* The number of times the tracepoint may be hit before it will
-     terminate the entire tracing run.  */
-  uint64_t pass_count;
-
-  /* Pointer to the agent expression that is the tracepoint's
-     conditional, or NULL if the tracepoint is unconditional.  */
-  struct agent_expr *cond;
-
-  /* The list of actions to take when the tracepoint triggers.  */
-  uint32_t numactions;
-  struct tracepoint_action **actions;
-
-  /* Count of the times we've hit this tracepoint during the run.
-     Note that while-stepping steps are not counted as "hits".  */
-  uint64_t hit_count;
-
-  /* Cached sum of the sizes of traceframes created by this point.  */
-  uint64_t traceframe_usage;
-
-  CORE_ADDR compiled_cond;
-
-  /* Link to the next tracepoint in the list.  */
-  struct tracepoint *next;
-
-  /* Optional kind of the breakpoint to be used.  Note this can mean
-     different things for different archs as z0 breakpoint command.
-     Value is -1 if not persent.  */
-  int32_t kind;
-
-#ifndef IN_PROCESS_AGENT
-  /* The list of actions to take when the tracepoint triggers, in
-     string/packet form.  */
-  char **actions_str;
-
-  /* The collection of strings that describe the tracepoint as it was
-     entered into GDB.  These are not used by the target, but are
-     reported back to GDB upon reconnection.  */
-  struct source_string *source_strings;
-
-  /* The number of bytes displaced by fast tracepoints. It may subsume
-     multiple instructions, for multi-byte fast tracepoints.  This
-     field is only valid for fast tracepoints.  */
-  uint32_t orig_size;
-
-  /* Only for fast tracepoints.  */
-  CORE_ADDR obj_addr_on_target;
-
-  /* Address range where the original instruction under a fast
-     tracepoint was relocated to.  (_end is actually one byte past
-     the end).  */
-  CORE_ADDR adjusted_insn_addr;
-  CORE_ADDR adjusted_insn_addr_end;
-
-  /* The address range of the piece of the jump pad buffer that was
-     assigned to this fast tracepoint.  (_end is actually one byte
-     past the end).*/
-  CORE_ADDR jump_pad;
-  CORE_ADDR jump_pad_end;
-
-  /* The address range of the piece of the trampoline buffer that was
-     assigned to this fast tracepoint.  (_end is actually one byte
-     past the end).  */
-  CORE_ADDR trampoline;
-  CORE_ADDR trampoline_end;
-
-  /* The list of actions to take while in a stepping loop.  These
-     fields are only valid for patch-based tracepoints.  */
-  int num_step_actions;
-  struct tracepoint_action **step_actions;
-  /* Same, but in string/packet form.  */
-  char **step_actions_str;
-
-  /* Handle returned by the breakpoint or tracepoint module when we
-     inserted the trap or jump, or hooked into a static tracepoint.
-     NULL if we haven't inserted it yet.  */
-  void *handle;
-#endif
-
-};
-
 #ifndef IN_PROCESS_AGENT
 
 /* Given `while-stepping', a thread may be collecting data for more
@@ -3117,16 +2992,12 @@ install_fast_tracepoint (struct tracepoint *tpoint, char *errbuf)
   trampoline_size = 0;
 
   /* Install the jump pad.  */
-  err = install_fast_tracepoint_jump_pad (tpoint->obj_addr_on_target,
-					  tpoint->address,
+  err = install_fast_tracepoint_jump_pad (tpoint,
 					  collect,
 					  ipa_sym_addrs.addr_collecting,
-					  tpoint->orig_size,
 					  &jentry,
 					  &trampoline, &trampoline_size,
 					  fjump, &fjump_size,
-					  &tpoint->adjusted_insn_addr,
-					  &tpoint->adjusted_insn_addr_end,
 					  errbuf);
 
   if (err)
diff --git a/gdb/gdbserver/tracepoint.h b/gdb/gdbserver/tracepoint.h
index 679a32a..c45a03c 100644
--- a/gdb/gdbserver/tracepoint.h
+++ b/gdb/gdbserver/tracepoint.h
@@ -178,4 +178,129 @@ CORE_ADDR get_get_tsv_func_addr (void);
    function in the IPA.  */
 CORE_ADDR get_set_tsv_func_addr (void);
 
+enum tracepoint_type
+{
+  /* Trap based tracepoint.  */
+  trap_tracepoint,
+
+  /* A fast tracepoint implemented with a jump instead of a trap.  */
+  fast_tracepoint,
+
+  /* A static tracepoint, implemented by a program call into a tracing
+     library.  */
+  static_tracepoint
+};
+
+/* The definition of a tracepoint.  */
+
+/* Tracepoints may have multiple locations, each at a different
+   address.  This can occur with optimizations, template
+   instantiation, etc.  Since the locations may be in different
+   scopes, the conditions and actions may be different for each
+   location.  Our target version of tracepoints is more like GDB's
+   notion of "breakpoint locations", but we have almost nothing that
+   is not per-location, so we bother having two kinds of objects.  The
+   key consequence is that numbers are not unique, and that it takes
+   both number and address to identify a tracepoint uniquely.  */
+
+struct tracepoint
+{
+  /* The number of the tracepoint, as specified by GDB.  Several
+     tracepoint objects here may share a number.  */
+  uint32_t number;
+
+  /* Address at which the tracepoint is supposed to trigger.  Several
+     tracepoints may share an address.  */
+  CORE_ADDR address;
+
+  /* Tracepoint type.  */
+  enum tracepoint_type type;
+
+  /* True if the tracepoint is currently enabled.  */
+  int8_t enabled;
+
+  /* The number of single steps that will be performed after each
+     tracepoint hit.  */
+  uint64_t step_count;
+
+  /* The number of times the tracepoint may be hit before it will
+     terminate the entire tracing run.  */
+  uint64_t pass_count;
+
+  /* Pointer to the agent expression that is the tracepoint's
+     conditional, or NULL if the tracepoint is unconditional.  */
+  struct agent_expr *cond;
+
+  /* The list of actions to take when the tracepoint triggers.  */
+  uint32_t numactions;
+  struct tracepoint_action **actions;
+
+  /* Count of the times we've hit this tracepoint during the run.
+     Note that while-stepping steps are not counted as "hits".  */
+  uint64_t hit_count;
+
+  /* Cached sum of the sizes of traceframes created by this point.  */
+  uint64_t traceframe_usage;
+
+  CORE_ADDR compiled_cond;
+
+  /* Link to the next tracepoint in the list.  */
+  struct tracepoint *next;
+
+  /* Optional kind of the breakpoint to be used
+   note this can mean different things for different archs as z0
+   breakpoint command */
+  uint32_t kind;
+
+#ifndef IN_PROCESS_AGENT
+  /* The list of actions to take when the tracepoint triggers, in
+     string/packet form.  */
+  char **actions_str;
+
+  /* The collection of strings that describe the tracepoint as it was
+     entered into GDB.  These are not used by the target, but are
+     reported back to GDB upon reconnection.  */
+  struct source_string *source_strings;
+
+  /* The number of bytes displaced by fast tracepoints. It may subsume
+     multiple instructions, for multi-byte fast tracepoints.  This
+     field is only valid for fast tracepoints.  */
+  uint32_t orig_size;
+
+  /* Only for fast tracepoints.  */
+  CORE_ADDR obj_addr_on_target;
+
+  /* Address range where the original instruction under a fast
+     tracepoint was relocated to.  (_end is actually one byte past
+     the end).  */
+  CORE_ADDR adjusted_insn_addr;
+  CORE_ADDR adjusted_insn_addr_end;
+
+  /* The address range of the piece of the jump pad buffer that was
+     assigned to this fast tracepoint.  (_end is actually one byte
+     past the end).*/
+  CORE_ADDR jump_pad;
+  CORE_ADDR jump_pad_end;
+
+  /* The address range of the piece of the trampoline buffer that was
+     assigned to this fast tracepoint.  (_end is actually one byte
+     past the end).  */
+  CORE_ADDR trampoline;
+  CORE_ADDR trampoline_end;
+
+  /* The list of actions to take while in a stepping loop.  These
+     fields are only valid for patch-based tracepoints.  */
+  int num_step_actions;
+  struct tracepoint_action **step_actions;
+  /* Same, but in string/packet form.  */
+  char **step_actions_str;
+
+  /* Handle returned by the breakpoint or tracepoint module when we
+     inserted the trap or jump, or hooked into a static tracepoint.
+     NULL if we haven't inserted it yet.  */
+  void *handle;
+#endif
+
+};
+
 #endif /* TRACEPOINT_H */
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 09/18] Move Thumb 16 bits instruction decode functions to arch/arm-insn-reloc.c
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (9 preceding siblings ...)
  2016-07-05 13:42 ` [PATCH v3 18/18] arm fast tracepoints: Relocation of Thumb 32-bits instructions Antoine Tremblay
@ 2016-07-05 13:42 ` Antoine Tremblay
  2016-07-05 13:42 ` [PATCH v3 17/18] arm fast tracepoints: Relocation of ARM instructions Antoine Tremblay
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:42 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

This patch does the same as the previous one, but for 16-bits Thumb
instructions-related functions.

gdb/ChangeLog:

	* arch/arm-insn-reloc.c (thumb_decode_pc_relative_16bit): Move
	from arm-tdep.c.
	(thumb_16bit_relocate_insn): Likewise.
	* arch/arm-insn-reloc.h (struct thumb_16bit_insn_reloc_visitor):
	Move from arm-tdep.c.
	(thumb_16bit_relocate_insn): New declaration.
	* arm-tdep.c (struct thumb_16bit_insn_reloc_visitor): Move to
	arch/arm-insn-reloc.h.
	(thumb_decode_pc_relative_16bit): Move to arch/arm-insn-reloc.c.
	(thumb_16bit_relocate_insn): Likewise.
---
 gdb/arch/arm-insn-reloc.c | 106 ++++++++++++++++++++++++++++++++++++++++
 gdb/arch/arm-insn-reloc.h |  20 ++++++++
 gdb/arm-tdep.c            | 121 ----------------------------------------------
 3 files changed, 126 insertions(+), 121 deletions(-)

diff --git a/gdb/arch/arm-insn-reloc.c b/gdb/arch/arm-insn-reloc.c
index f598c64..b6ede60 100644
--- a/gdb/arch/arm-insn-reloc.c
+++ b/gdb/arch/arm-insn-reloc.c
@@ -744,3 +744,109 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
 
   return err;
 }
+
+static int
+thumb_decode_pc_relative_16bit (uint16_t insn,
+				struct thumb_16bit_insn_reloc_visitor *visitor,
+				struct arm_insn_reloc_data *data)
+{
+  unsigned int rd = bits (insn, 8, 10);
+  unsigned int imm8 = bits (insn, 0, 7);
+
+  return visitor->pc_relative_16bit (insn, data, rd, imm8);
+}
+
+int
+thumb_16bit_relocate_insn (uint16_t insn1,
+			   struct thumb_16bit_insn_reloc_visitor *visitor,
+			   struct arm_insn_reloc_data *data)
+{
+  unsigned short op_bit_12_15 = bits (insn1, 12, 15);
+  unsigned short op_bit_10_11 = bits (insn1, 10, 11);
+  int err = 0;
+
+  /* 16-bit thumb instructions.  */
+  switch (op_bit_12_15)
+    {
+      /* Shift (imme), add, subtract, move and compare.  */
+    case 0: case 1: case 2: case 3:
+      err = visitor->others (insn1, "shift/add/sub/mov/cmp", data);
+      break;
+    case 4:
+      switch (op_bit_10_11)
+	{
+	case 0: /* Data-processing */
+	  err = visitor->others (insn1, "data-processing", data);
+	  break;
+	case 1: /* Special data instructions and branch and exchange.  */
+	  {
+	    unsigned short op = bits (insn1, 7, 9);
+	    if (op == 6 || op == 7) /* BX or BLX */
+	      err = visitor->bx_blx_reg (insn1, data);
+	    else if (bits (insn1, 6, 7) != 0) /* ADD/MOV/CMP high registers.  */
+	      err = visitor->alu_reg (insn1, data);
+	    else
+	      err = visitor->others (insn1, "special data", data);
+	  }
+	  break;
+	default: /* LDR (literal) */
+	  err = visitor->load_literal (insn1, data);
+	}
+      break;
+    case 5: case 6: case 7: case 8: case 9: /* Load/Store single data item */
+      err = visitor->others (insn1, "ldr/str", data);
+      break;
+    case 10:
+      if (op_bit_10_11 < 2) /* Generate PC-relative address */
+	err = thumb_decode_pc_relative_16bit (insn1, visitor, data);
+      else /* Generate SP-relative address */
+	err = visitor->others (insn1, "sp-relative", data);
+      break;
+    case 11: /* Misc 16-bit instructions */
+      {
+	switch (bits (insn1, 8, 11))
+	  {
+	  case 1: case 3:  case 9: case 11: /* CBNZ, CBZ */
+	    err = visitor->cbnz_cbz (insn1, data);
+	    break;
+	  case 12: case 13: /* POP */
+	    if (bit (insn1, 8)) /* PC is in register list.  */
+	      err = visitor->pop_pc_16bit (insn1, data);
+	    else
+	      err = visitor->others (insn1, "pop", data);
+	    break;
+	  case 15: /* If-Then, and hints */
+	    if (bits (insn1, 0, 3))
+	      /* If-Then makes up to four following instructions conditional.
+		 IT instruction itself is not conditional, so handle it as a
+		 common unmodified instruction.  */
+	      err = visitor->others (insn1, "If-Then", data);
+	    else
+	      err = visitor->others (insn1, "hints", data);
+	    break;
+	  default:
+	    err = visitor->others (insn1, "misc", data);
+	  }
+      }
+      break;
+    case 12:
+      if (op_bit_10_11 < 2) /* Store multiple registers */
+	err = visitor->others (insn1, "stm", data);
+      else /* Load multiple registers */
+	err = visitor->others (insn1, "ldm", data);
+      break;
+    case 13: /* Conditional branch and supervisor call */
+      if (bits (insn1, 9, 11) != 7) /* conditional branch */
+	err = visitor->b (insn1, data);
+      else
+	err = visitor->svc (insn1, data);
+      break;
+    case 14: /* Unconditional branch */
+      err = visitor->b (insn1, data);
+      break;
+    default:
+      err = 1;
+    }
+
+  return err;
+}
diff --git a/gdb/arch/arm-insn-reloc.h b/gdb/arch/arm-insn-reloc.h
index ebfc89a..6e83ad4 100644
--- a/gdb/arch/arm-insn-reloc.h
+++ b/gdb/arch/arm-insn-reloc.h
@@ -69,6 +69,21 @@ struct thumb_32bit_insn_reloc_visitor
 		       struct arm_insn_reloc_data *data);
 };
 
+struct thumb_16bit_insn_reloc_visitor
+{
+  int (*alu_reg) (uint16_t insn, struct arm_insn_reloc_data *data);
+  int (*b) (uint16_t insn, struct arm_insn_reloc_data *data);
+  int (*bx_blx_reg) (uint16_t insn, struct arm_insn_reloc_data *data);
+  int (*cbnz_cbz) (uint16_t insn1, struct arm_insn_reloc_data *data);
+  int (*load_literal) (uint16_t insn1, struct arm_insn_reloc_data *data);
+  int (*others) (uint16_t insn, const char *iname,
+		 struct arm_insn_reloc_data *data);
+  int (*pc_relative_16bit) (uint16_t insn, struct arm_insn_reloc_data *data,
+			    int rd, unsigned int imm);
+  int (*pop_pc_16bit) (uint16_t insn, struct arm_insn_reloc_data *data);
+  int (*svc) (uint16_t insn, struct arm_insn_reloc_data *data);
+};
+
 extern int arm_relocate_insn (uint32_t insn,
 			      struct arm_insn_reloc_visitor *visitor,
 			      struct arm_insn_reloc_data *data);
@@ -78,4 +93,9 @@ extern int thumb_32bit_relocate_insn (
   struct thumb_32bit_insn_reloc_visitor *visitor,
   struct arm_insn_reloc_data *data);
 
+extern int thumb_16bit_relocate_insn (
+  uint16_t insn1,
+  struct thumb_16bit_insn_reloc_visitor *visitor,
+  struct arm_insn_reloc_data *data);
+
 #endif /* ARM_INSN_RELOC_H */
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 4f4b6b2..4a4826a 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -4481,21 +4481,6 @@ struct arm_insn_reloc_data
   struct regcache *regs;
 };
 
-struct thumb_16bit_insn_reloc_visitor
-{
-  int (*alu_reg) (uint16_t insn, struct arm_insn_reloc_data *data);
-  int (*b) (uint16_t insn, struct arm_insn_reloc_data *data);
-  int (*bx_blx_reg) (uint16_t insn, struct arm_insn_reloc_data *data);
-  int (*cbnz_cbz) (uint16_t insn1, struct arm_insn_reloc_data *data);
-  int (*load_literal) (uint16_t insn1, struct arm_insn_reloc_data *data);
-  int (*others) (uint16_t insn, const char *iname,
-		 struct arm_insn_reloc_data *data);
-  int (*pc_relative_16bit) (uint16_t insn, struct arm_insn_reloc_data *data,
-			    int rd, unsigned int imm);
-  int (*pop_pc_16bit) (uint16_t insn, struct arm_insn_reloc_data *data);
-  int (*svc) (uint16_t insn, struct arm_insn_reloc_data *data);
-};
-
 /* Helper for register reads for displaced stepping.  In particular, this
    returns the PC as it would be seen by the instruction at its original
    location.  */
@@ -6512,17 +6497,6 @@ thumb_copy_pc_relative_16bit (uint16_t insn, struct arm_insn_reloc_data *data,
 }
 
 static int
-thumb_decode_pc_relative_16bit (uint16_t insn,
-				struct thumb_16bit_insn_reloc_visitor *visitor,
-				struct arm_insn_reloc_data *data)
-{
-  unsigned int rd = bits (insn, 8, 10);
-  unsigned int imm8 = bits (insn, 0, 7);
-
-  return visitor->pc_relative_16bit (insn, data, rd, imm8);
-}
-
-static int
 thumb_copy_pc_relative_32bit (uint16_t insn1, uint16_t insn2,
 			      struct arm_insn_reloc_data *data)
 {
@@ -6783,101 +6757,6 @@ thumb_copy_pop_pc_16bit (uint16_t insn1, struct arm_insn_reloc_data *data)
   return 0;
 }
 
-static int
-thumb_16bit_relocate_insn (uint16_t insn1,
-			   struct thumb_16bit_insn_reloc_visitor *visitor,
-			   struct arm_insn_reloc_data *data)
-{
-  unsigned short op_bit_12_15 = bits (insn1, 12, 15);
-  unsigned short op_bit_10_11 = bits (insn1, 10, 11);
-  int err = 0;
-
-  /* 16-bit thumb instructions.  */
-  switch (op_bit_12_15)
-    {
-      /* Shift (imme), add, subtract, move and compare.  */
-    case 0: case 1: case 2: case 3:
-      err = visitor->others (insn1, "shift/add/sub/mov/cmp", data);
-      break;
-    case 4:
-      switch (op_bit_10_11)
-	{
-	case 0: /* Data-processing */
-	  err = visitor->others (insn1, "data-processing", data);
-	  break;
-	case 1: /* Special data instructions and branch and exchange.  */
-	  {
-	    unsigned short op = bits (insn1, 7, 9);
-	    if (op == 6 || op == 7) /* BX or BLX */
-	      err = visitor->bx_blx_reg (insn1, data);
-	    else if (bits (insn1, 6, 7) != 0) /* ADD/MOV/CMP high registers.  */
-	      err = visitor->alu_reg (insn1, data);
-	    else
-	      err = visitor->others (insn1, "special data", data);
-	  }
-	  break;
-	default: /* LDR (literal) */
-	  err = visitor->load_literal (insn1, data);
-	}
-      break;
-    case 5: case 6: case 7: case 8: case 9: /* Load/Store single data item */
-      err = visitor->others (insn1, "ldr/str", data);
-      break;
-    case 10:
-      if (op_bit_10_11 < 2) /* Generate PC-relative address */
-	err = thumb_decode_pc_relative_16bit (insn1, visitor, data);
-      else /* Generate SP-relative address */
-	err = visitor->others (insn1, "sp-relative", data);
-      break;
-    case 11: /* Misc 16-bit instructions */
-      {
-	switch (bits (insn1, 8, 11))
-	  {
-	  case 1: case 3:  case 9: case 11: /* CBNZ, CBZ */
-	    err = visitor->cbnz_cbz (insn1, data);
-	    break;
-	  case 12: case 13: /* POP */
-	    if (bit (insn1, 8)) /* PC is in register list.  */
-	      err = visitor->pop_pc_16bit (insn1, data);
-	    else
-	      err = visitor->others (insn1, "pop", data);
-	    break;
-	  case 15: /* If-Then, and hints */
-	    if (bits (insn1, 0, 3))
-	      /* If-Then makes up to four following instructions conditional.
-		 IT instruction itself is not conditional, so handle it as a
-		 common unmodified instruction.  */
-	      err = visitor->others (insn1, "If-Then", data);
-	    else
-	      err = visitor->others (insn1, "hints", data);
-	    break;
-	  default:
-	    err = visitor->others (insn1, "misc", data);
-	  }
-      }
-      break;
-    case 12:
-      if (op_bit_10_11 < 2) /* Store multiple registers */
-	err = visitor->others (insn1, "stm", data);
-      else /* Load multiple registers */
-	err = visitor->others (insn1, "ldm", data);
-      break;
-    case 13: /* Conditional branch and supervisor call */
-      if (bits (insn1, 9, 11) != 7) /* conditional branch */
-	err = visitor->b (insn1, data);
-      else
-	err = visitor->svc (insn1, data);
-      break;
-    case 14: /* Unconditional branch */
-      err = visitor->b (insn1, data);
-      break;
-    default:
-      err = 1;
-    }
-
-  return err;
-}
-
 static struct arm_insn_reloc_visitor arm_insn_reloc_visitor =
 {
   arm_copy_alu_imm,
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 05/18] arm-tdep.c: Use relocation visitor in Thumb 32-bits instruction decoding
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (16 preceding siblings ...)
  2016-07-05 13:56 ` [PATCH v3 04/18] arm-tdep.c: Use relocation visitor in ARM instruction decoding Antoine Tremblay
@ 2016-07-05 13:56 ` Antoine Tremblay
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:56 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

This is the same as the previous patch, but for the 32-bits Thumb
instructions.

gdb/ChangeLog:

	* arm-tdep.c (struct thumb_32bit_insn_reloc_visitor): New.
	(thumb2_decode_dp_shift_reg): Add visitor parameter and use it.
	(thumb2_decode_ext_reg_ld_st): Likewise.
	(thumb2_decode_svc_copro): Likewise.
	(decode_thumb_32bit_ld_mem_hints): Likewise.
	(thumb_32bit_relocate_insn): Add and use visitor parameter.
	(thumb_32bit_insn_reloc_visitor): New.
	(arm_process_displaced_insn): Pass
	thumb_32bit_insn_reloc_visitor to
	thumb_32bit_relocate_insn.
---
 gdb/arm-tdep.c | 160 +++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 99 insertions(+), 61 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index dcd65eeb..6a9d110 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -4502,6 +4502,33 @@ struct arm_insn_reloc_visitor
   int (*unpred) (uint32_t insn, struct arm_insn_reloc_data *data);
 };
 
+struct thumb_32bit_insn_reloc_visitor
+{
+  int (*alu_imm) (uint16_t insn1, uint16_t insn2,
+		  struct arm_insn_reloc_data *data);
+  int (*b_bl_blx) (uint16_t insn1, uint16_t insn2,
+		   struct arm_insn_reloc_data *data);
+  int (*block_xfer) (uint16_t insn1, uint16_t insn2,
+		     struct arm_insn_reloc_data *data);
+  int (*copro_load_store) (uint16_t insn1, uint16_t insn2,
+			   struct arm_insn_reloc_data *data);
+  int (*load_literal) (uint16_t insn1, uint16_t insn2,
+		       struct arm_insn_reloc_data *data, int size);
+  int (*load_reg_imm) (uint16_t insn1, uint16_t insn2,
+		       struct arm_insn_reloc_data *data, int writeback,
+		       int immed);
+  int (*others) (uint16_t insn1, uint16_t insn2, const char *iname,
+		 struct arm_insn_reloc_data *data);
+  int (*pc_relative_32bit) (uint16_t insn1, uint16_t insn2,
+			    struct arm_insn_reloc_data *data);
+  int (*preload) (uint16_t insn1, uint16_t insn2,
+		  struct arm_insn_reloc_data *data);
+  int (*undef) (uint16_t insn1, uint16_t insn2,
+		struct arm_insn_reloc_data *data);
+  int (*table_branch) (uint16_t insn1, uint16_t insn2,
+		       struct arm_insn_reloc_data *data);
+};
+
 /* Helper for register reads for displaced stepping.  In particular, this
    returns the PC as it would be seen by the instruction at its original
    location.  */
@@ -6856,6 +6883,7 @@ arm_decode_ext_reg_ld_st (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
 
 static int
 thumb2_decode_dp_shift_reg (uint16_t insn1, uint16_t insn2,
+			    struct thumb_32bit_insn_reloc_visitor *visitor,
 			    struct arm_insn_reloc_data *data)
 {
   /* PC is only allowed to be used in instruction MOV.  */
@@ -6864,9 +6892,9 @@ thumb2_decode_dp_shift_reg (uint16_t insn1, uint16_t insn2,
   unsigned int rn = bits (insn1, 0, 3);
 
   if (op == 0x2 && rn == 0xf) /* MOV */
-    return thumb2_copy_alu_imm (insn1, insn2, data);
+    return visitor->alu_imm (insn1, insn2, data);
   else
-    return thumb_copy_unmodified_32bit (insn1, insn2, "dp (shift reg)", data);
+    return visitor->others (insn1, insn2, "dp (shift reg)", data);
 }
 
 
@@ -6875,6 +6903,7 @@ thumb2_decode_dp_shift_reg (uint16_t insn1, uint16_t insn2,
 
 static int
 thumb2_decode_ext_reg_ld_st (uint16_t insn1, uint16_t insn2,
+			     struct thumb_32bit_insn_reloc_visitor *visitor,
 			     struct arm_insn_reloc_data *data)
 {
   unsigned int opcode = bits (insn1, 4, 8);
@@ -6882,24 +6911,22 @@ thumb2_decode_ext_reg_ld_st (uint16_t insn1, uint16_t insn2,
   switch (opcode)
     {
     case 0x04: case 0x05:
-      return thumb_copy_unmodified_32bit (insn1, insn2, "vfp/neon vmov", data);
+      return visitor->others (insn1, insn2, "vfp/neon vmov", data);
 
     case 0x08: case 0x0c: /* 01x00 */
     case 0x0a: case 0x0e: /* 01x10 */
     case 0x12: case 0x16: /* 10x10 */
-      return thumb_copy_unmodified_32bit (insn1, insn2,
-					  "vfp/neon vstm/vpush", data);
+      return visitor->others (insn1, insn2, "vfp/neon vstm/vpush", data);
 
     case 0x09: case 0x0d: /* 01x01 */
     case 0x0b: case 0x0f: /* 01x11 */
     case 0x13: case 0x17: /* 10x11 */
-      return thumb_copy_unmodified_32bit (insn1, insn2,
-					  "vfp/neon vldm/vpop", data);
+      return visitor->others (insn1, insn2, "vfp/neon vldm/vpop", data);
 
     case 0x10: case 0x14: case 0x18: case 0x1c:  /* vstr.  */
-      return thumb_copy_unmodified_32bit (insn1, insn2, "vstr", data);
+      return visitor->others (insn1, insn2, "vstr", data);
     case 0x11: case 0x15: case 0x19: case 0x1d:  /* vldr.  */
-      return thumb2_copy_copro_load_store (insn1, insn2, data);
+      return visitor->copro_load_store (insn1, insn2, data);
     }
 
   /* Should be unreachable.  */
@@ -6953,6 +6980,7 @@ arm_decode_svc_copro (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
 
 static int
 thumb2_decode_svc_copro (uint16_t insn1, uint16_t insn2,
+			 struct thumb_32bit_insn_reloc_visitor *visitor,
 			 struct arm_insn_reloc_data *data)
 {
   unsigned int coproc = bits (insn2, 8, 11);
@@ -6963,27 +6991,26 @@ thumb2_decode_svc_copro (uint16_t insn1, uint16_t insn2,
   if (bit_9 == 0)
     {
       if (bit_5_8 == 2)
-	return thumb_copy_unmodified_32bit (
-	  insn1, insn2, "neon 64bit xfer/mrrc/mrrc2/mcrr/mcrr2", data);
+	return visitor->others (insn1, insn2,
+				"neon 64bit xfer/mrrc/mrrc2/mcrr/mcrr2", data);
       else if (bit_5_8 == 0) /* UNDEFINED.  */
-	return thumb_32bit_copy_undef (insn1, insn2, data);
+	return visitor->undef (insn1, insn2, data);
       else
 	{
 	   /*coproc is 101x.  SIMD/VFP, ext registers load/store.  */
 	  if ((coproc & 0xe) == 0xa)
-	    return thumb2_decode_ext_reg_ld_st (insn1, insn2, data);
+	    return thumb2_decode_ext_reg_ld_st (insn1, insn2, visitor, data);
 	  else /* coproc is not 101x.  */
 	    {
 	      if (bit_4 == 0) /* STC/STC2.  */
-		return thumb_copy_unmodified_32bit (insn1, insn2, "stc/stc2",
-						    data);
+		return visitor->others (insn1, insn2, "stc/stc2", data);
 	      else /* LDC/LDC2 {literal, immeidate}.  */
-		return thumb2_copy_copro_load_store (insn1, insn2, data);
+		return visitor->copro_load_store (insn1, insn2, data);
 	    }
 	}
     }
   else
-    return thumb_copy_unmodified_32bit (insn1, insn2, "coproc", data);
+    return visitor->others (insn1, insn2, "coproc", data);
 
   return 0;
 }
@@ -7387,6 +7414,7 @@ thumb_16bit_relocate_insn (uint16_t insn1, struct arm_insn_reloc_data *data)
 
 static int
 decode_thumb_32bit_ld_mem_hints (uint16_t insn1, uint16_t insn2,
+				 struct thumb_32bit_insn_reloc_visitor *visitor,
 				 struct arm_insn_reloc_data *data)
 {
   int rt = bits (insn2, 12, 15);
@@ -7400,32 +7428,29 @@ decode_thumb_32bit_ld_mem_hints (uint16_t insn1, uint16_t insn2,
 	{
 	  if (rn == 0xf)
 	    /* PLD literal or Encoding T3 of PLI(immediate, literal).  */
-	    return thumb2_copy_preload (insn1, insn2, data);
+	    return visitor->preload (insn1, insn2, data);
 	  else
-	    return thumb_copy_unmodified_32bit (insn1, insn2, "pli/pld", data);
+	    return visitor->others (insn1, insn2, "pli/pld", data);
 	}
       else
 	{
 	  if (rn == 0xf) /* LDRB/LDRSB (literal) */
-	    return thumb2_copy_load_literal (insn1, insn2, data, 1);
+	    return visitor->load_literal (insn1, insn2, data, 1);
 	  else
-	    return thumb_copy_unmodified_32bit (insn1, insn2,
-						"ldrb{reg, immediate}/ldrbt",
-						data);
+	    return visitor->others (insn1, insn2, "ldrb{reg, immediate}/ldrbt",
+				    data);
 	}
 
       break;
     case 1: /* Load halfword and memory hints.  */
       if (rt == 0xf) /* PLD{W} and Unalloc memory hint.  */
-	return thumb_copy_unmodified_32bit (insn1, insn2, "pld/unalloc memhint",
-					    data);
+	return visitor->others (insn1, insn2, "pld/unalloc memhint", data);
       else
 	{
 	  if (rn == 0xf)
-	    return thumb2_copy_load_literal (insn1, insn2, data, 2);
+	    return visitor->load_literal (insn1, insn2, data, 2);
 	  else
-	    return thumb_copy_unmodified_32bit (insn1, insn2, "ldrh/ldrht",
-						data);
+	    return visitor->others (insn1, insn2, "ldrh/ldrht", data);
 	}
       break;
     case 2: /* Load word */
@@ -7433,32 +7458,32 @@ decode_thumb_32bit_ld_mem_hints (uint16_t insn1, uint16_t insn2,
 	int insn2_bit_8_11 = bits (insn2, 8, 11);
 
 	if (rn == 0xf)
-	  return thumb2_copy_load_literal (insn1, insn2, data, 4);
+	  return visitor->load_literal (insn1, insn2, data, 4);
 	else if (op1 == 0x1) /* Encoding T3 */
-	  return thumb2_copy_load_reg_imm (insn1, insn2, data, 0, 1);
+	  return visitor->load_reg_imm (insn1, insn2, data, 0, 1);
 	else /* op1 == 0x0 */
 	  {
 	    if (insn2_bit_8_11 == 0xc || (insn2_bit_8_11 & 0x9) == 0x9)
 	      /* LDR (immediate) */
-	      return thumb2_copy_load_reg_imm (insn1, insn2, data,
+	      return visitor->load_reg_imm (insn1, insn2, data,
 					       bit (insn2, 8), 1);
 	    else if (insn2_bit_8_11 == 0xe) /* LDRT */
-	      return thumb_copy_unmodified_32bit (insn1, insn2, "ldrt", data);
+	      return visitor->others (insn1, insn2, "ldrt", data);
 	    else
 	      /* LDR (register) */
-	      return thumb2_copy_load_reg_imm (insn1, insn2, data, 0, 0);
+	      return visitor->load_reg_imm (insn1, insn2, data, 0, 0);
 	  }
 	break;
       }
     default:
-      return thumb_32bit_copy_undef (insn1, insn2, data);
-      break;
+      return visitor->undef (insn1, insn2, data);
     }
   return 0;
 }
 
 static int
 thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
+			   struct thumb_32bit_insn_reloc_visitor *visitor,
 			   struct arm_insn_reloc_data *data)
 {
   int err = 0;
@@ -7477,24 +7502,22 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
 		/* Load/store {dual, execlusive}, table branch.  */
 		if (bits (insn1, 7, 8) == 1 && bits (insn1, 4, 5) == 1
 		    && bits (insn2, 5, 7) == 0)
-		  err = thumb2_copy_table_branch (insn1, insn2, data);
+		  err = visitor->table_branch (insn1, insn2, data);
 		else
 		  /* PC is not allowed to use in load/store {dual, exclusive}
 		     instructions.  */
-		  err = thumb_copy_unmodified_32bit (insn1, insn2,
-						     "load/store dual/ex",
-						     data);
+		  err = visitor->others (insn1, insn2, "load/store dual/ex",
+					 data);
 	      }
 	    else /* load/store multiple */
 	      {
 		switch (bits (insn1, 7, 8))
 		  {
 		  case 0: case 3: /* SRS, RFE */
-		    err = thumb_copy_unmodified_32bit (insn1, insn2, "srs/rfe",
-						       data);
+		    err = visitor->others (insn1, insn2, "srs/rfe", data);
 		    break;
 		  case 1: case 2: /* LDM/STM/PUSH/POP */
-		    err = thumb2_copy_block_xfer (insn1, insn2, data);
+		    err = visitor->block_xfer (insn1, insn2, data);
 		    break;
 		  }
 	      }
@@ -7502,10 +7525,10 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
 
 	  case 1:
 	    /* Data-processing (shift register).  */
-	    err = thumb2_decode_dp_shift_reg (insn1, insn2, data);
+	    err = thumb2_decode_dp_shift_reg (insn1, insn2, visitor, data);
 	    break;
 	  default: /* Coprocessor instructions.  */
-	    err = thumb2_decode_svc_copro (insn1, insn2, data);
+	    err = thumb2_decode_svc_copro (insn1, insn2, visitor, data);
 	    break;
 	  }
       break;
@@ -7516,9 +7539,9 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
 	  if (bit (insn2, 14)  /* BLX/BL */
 	      || bit (insn2, 12) /* Unconditional branch */
 	      || (bits (insn1, 7, 9) != 0x7)) /* Conditional branch */
-	    err = thumb2_copy_b_bl_blx (insn1, insn2, data);
+	    err = visitor->b_bl_blx (insn1, insn2, data);
 	  else
-	    err = thumb_copy_unmodified_32bit (insn1, insn2, "misc ctrl", data);
+	    err = visitor->others (insn1, insn2, "misc ctrl", data);
 	}
       else
 	{
@@ -7527,12 +7550,12 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
 	      int op = bits (insn1, 4, 8);
 	      int rn = bits (insn1, 0, 3);
 	      if ((op == 0 || op == 0xa) && rn == 0xf)
-		err = thumb_copy_pc_relative_32bit (insn1, insn2, data);
+		err = visitor->pc_relative_32bit (insn1, insn2, data);
 	      else
-		err = thumb_copy_unmodified_32bit (insn1, insn2, "dp/pb", data);
+		err = visitor->others (insn1, insn2, "dp/pb", data);
 	    }
 	  else /* Data processing (modified immeidate) */
-	    err = thumb_copy_unmodified_32bit (insn1, insn2, "dp/mi", data);
+	    err = visitor->others (insn1, insn2, "dp/mi", data);
 	}
       break;
     case 3: /* op1 = 3 */
@@ -7540,30 +7563,27 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
 	{
 	case 0:
 	  if (bit (insn1, 4))
-	    err = decode_thumb_32bit_ld_mem_hints (insn1, insn2, data);
+	    err = decode_thumb_32bit_ld_mem_hints (insn1, insn2, visitor, data);
 	  else /* NEON Load/Store and Store single data item */
-	    err = thumb_copy_unmodified_32bit (insn1, insn2,
-					       "neon elt/struct load/store",
-					       data);
+	    err = visitor->others (insn1, insn2, "neon elt/struct load/store",
+				   data);
 	  break;
 	case 1: /* op1 = 3, bits (9, 10) == 1 */
 	  switch (bits (insn1, 7, 8))
 	    {
 	    case 0: case 1: /* Data processing (register) */
-	      err = thumb_copy_unmodified_32bit (insn1, insn2, "dp(reg)", data);
+	      err = visitor->others (insn1, insn2, "dp(reg)", data);
 	      break;
 	    case 2: /* Multiply and absolute difference */
-	      err = thumb_copy_unmodified_32bit (insn1, insn2, "mul/mua/diff",
-						 data);
+	      err = visitor->others (insn1, insn2, "mul/mua/diff", data);
 	      break;
 	    case 3: /* Long multiply and divide */
-	      err = thumb_copy_unmodified_32bit (insn1, insn2, "lmul/lmua",
-						 data);
+	      err = visitor->others (insn1, insn2, "lmul/lmua", data);
 	      break;
 	    }
 	  break;
 	default: /* Coprocessor instructions */
-	  err = thumb2_decode_svc_copro (insn1, insn2, data);
+	  err = thumb2_decode_svc_copro (insn1, insn2, visitor, data);
 	  break;
 	}
       break;
@@ -7628,6 +7648,21 @@ static struct arm_insn_reloc_visitor arm_insn_reloc_visitor =
   arm_copy_unpred,
 };
 
+static struct thumb_32bit_insn_reloc_visitor thumb_32bit_insn_reloc_visitor =
+{
+  thumb2_copy_alu_imm,
+  thumb2_copy_b_bl_blx,
+  thumb2_copy_block_xfer,
+  thumb2_copy_copro_load_store,
+  thumb2_copy_load_literal,
+  thumb2_copy_load_reg_imm,
+  thumb_copy_unmodified_32bit,
+  thumb_copy_pc_relative_32bit,
+  thumb2_copy_preload,
+  thumb2_copy_table_branch,
+  thumb_32bit_copy_undef,
+};
+
 void
 arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
 			    CORE_ADDR to, struct regcache *regs,
@@ -7681,8 +7716,11 @@ arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
         {
           uint16_t insn2
 	    = read_memory_unsigned_integer (from + 2, 2, byte_order_for_code);
-	  err = thumb_32bit_relocate_insn (insn1, insn2, &reloc_data);
-        }
+
+	  err = thumb_32bit_relocate_insn (insn1, insn2,
+					   &thumb_32bit_insn_reloc_visitor,
+					   &reloc_data);
+	}
       else
         err = thumb_16bit_relocate_insn (insn1, &reloc_data);
     }
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 04/18] arm-tdep.c: Use relocation visitor in ARM instruction decoding
  2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 Antoine Tremblay
                   ` (15 preceding siblings ...)
  2016-07-05 13:42 ` [PATCH v3 14/18] Fast tracepoint support for ARM on Linux Antoine Tremblay
@ 2016-07-05 13:56 ` Antoine Tremblay
  2016-07-05 13:56 ` [PATCH v3 05/18] arm-tdep.c: Use relocation visitor in Thumb 32-bits " Antoine Tremblay
  17 siblings, 0 replies; 19+ messages in thread
From: Antoine Tremblay @ 2016-07-05 13:56 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@ericsson.com>

In order to be able to use the instruction decoding code for other
purposes than displaced stepping, we have to decouple the decoding phase
from the relocation, which is specific to the task of displaced
stepping.  In other words, the arm_decode_* functions should not call the
arm_copy_* functions explicitly.

This is achieved by passing a structure of callback functions (the
visitor) to the decoding functions.  Each of the callback corresponds to
a type of instruction that probably needs to be modified when it is
executed at another location.  The user/caller of the decoding "subsystem"
is responsible for providing this structure of callbacks.

I renamed arm_process_displaced_insn_arm to arm_relocate_insn_arm, since
it's not longer specific do displaced stepping.

This patch shouldn't introduce functional changes, as it is only a
refactoring.

gdb/ChangeLog:

	* arm-tdep.c (struct arm_insn_reloc_visitor): New structure.
	(arm_decode_misc_memhint_neon): Add visitor parameter and use
	it.
	(arm_decode_unconditional): Likewise.
	(arm_decode_miscellaneous): Likewise.
	(arm_decode_dp_misc): Likewise.
	(arm_decode_ld_st_word_ubyte): Likewise.
	(arm_decode_media): Likewise.
	(arm_decode_b_bl_ldmstm): Likewise.
	(arm_decode_ext_reg_ld_st): Likewise.
	(arm_decode_svc_copro): Likewise.
	(arm_process_displaced_insn_arm): Rename to...
	(arm_relocate_insn_arm): ... this, add visitor parameter and use
	it.
	(arm_insn_reloc_visitor): New variable.
	(arm_process_displaced_insn): Pass pointer to
	arm_insn_reloc_visitor to arm_relocate_insn_arm.
---
 gdb/arm-tdep.c | 308 +++++++++++++++++++++++++++++++++------------------------
 1 file changed, 181 insertions(+), 127 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 0c05aae..dcd65eeb 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -4480,6 +4480,28 @@ struct arm_insn_reloc_data
   struct regcache *regs;
 };
 
+struct arm_insn_reloc_visitor
+{
+  int (*alu_imm) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*alu_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*alu_shifted_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*b_bl_blx) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*block_xfer) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*bx_blx_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*copro_load_store) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*extra_ld_st) (uint32_t insn, struct arm_insn_reloc_data *data,
+		      int unprivileged);
+  int (*ldr_str_ldrb_strb) (uint32_t insn, struct arm_insn_reloc_data *data,
+			    int load, int size, int usermode);
+  int (*others) (uint32_t insn, const char *iname,
+		 struct arm_insn_reloc_data *data);
+  int (*preload) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*preload_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*svc) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*undef) (uint32_t insn, struct arm_insn_reloc_data *data);
+  int (*unpred) (uint32_t insn, struct arm_insn_reloc_data *data);
+};
+
 /* Helper for register reads for displaced stepping.  In particular, this
    returns the PC as it would be seen by the instruction at its original
    location.  */
@@ -6462,91 +6484,94 @@ arm_copy_unpred (uint32_t insn, struct arm_insn_reloc_data *data)
    the presentation in the ARM ARM.  */
 
 static int
-arm_decode_misc_memhint_neon (uint32_t insn, struct arm_insn_reloc_data *data)
+arm_decode_misc_memhint_neon (uint32_t insn,
+			      struct arm_insn_reloc_visitor *visitor,
+			      struct arm_insn_reloc_data *data)
 {
   unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7);
   unsigned int rn = bits (insn, 16, 19);
 
   if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0xe) == 0x0)
-    return arm_copy_unmodified (insn, "cps", data);
+    return visitor->others (insn, "cps", data);
   else if (op1 == 0x10 && op2 == 0x0 && (rn & 0xe) == 0x1)
-    return arm_copy_unmodified (insn, "setend", data);
+    return visitor->others (insn, "setend", data);
   else if ((op1 & 0x60) == 0x20)
-    return arm_copy_unmodified (insn, "neon dataproc", data);
+    return visitor->others (insn, "neon dataproc", data);
   else if ((op1 & 0x71) == 0x40)
-    return arm_copy_unmodified (insn, "neon elt/struct load/store", data);
+    return visitor->others (insn, "neon elt/struct load/store", data);
   else if ((op1 & 0x77) == 0x41)
-    return arm_copy_unmodified (insn, "unallocated mem hint", data);
+    return visitor->others (insn, "unallocated mem hint", data);
   else if ((op1 & 0x77) == 0x45)
-    return arm_copy_preload (insn, data);  /* pli.  */
+    return visitor->preload (insn, data);  /* pli.  */
   else if ((op1 & 0x77) == 0x51)
     {
       if (rn != 0xf)
-	return arm_copy_preload (insn, data);  /* pld/pldw.  */
+	return visitor->preload (insn, data);  /* pld/pldw.  */
       else
-	return arm_copy_unpred (insn, data);
+	return visitor->unpred (insn, data);
     }
   else if ((op1 & 0x77) == 0x55)
-    return arm_copy_preload (insn, data);  /* pld/pldw.  */
+    return visitor->preload (insn, data);  /* pld/pldw.  */
   else if (op1 == 0x57)
     switch (op2)
       {
-      case 0x1: return arm_copy_unmodified (insn, "clrex", data);
-      case 0x4: return arm_copy_unmodified (insn, "dsb", data);
-      case 0x5: return arm_copy_unmodified (insn, "dmb", data);
-      case 0x6: return arm_copy_unmodified (insn, "isb", data);
-      default: return arm_copy_unpred (insn, data);
+      case 0x1: return visitor->others (insn, "clrex", data);
+      case 0x4: return visitor->others (insn, "dsb", data);
+      case 0x5: return visitor->others (insn, "dmb", data);
+      case 0x6: return visitor->others (insn, "isb", data);
+      default: return visitor->unpred (insn, data);
       }
   else if ((op1 & 0x63) == 0x43)
-    return arm_copy_unpred (insn, data);
+    return visitor->unpred (insn, data);
   else if ((op2 & 0x1) == 0x0)
     switch (op1 & ~0x80)
       {
       case 0x61:
-	return arm_copy_unmodified (insn, "unallocated mem hint", data);
+	return visitor->others (insn, "unallocated mem hint", data);
       case 0x65:
-	return arm_copy_preload_reg (insn, data);  /* pli reg.  */
+	return visitor->preload_reg (insn, data);  /* pli reg.  */
       case 0x71: case 0x75:
         /* pld/pldw reg.  */
-	return arm_copy_preload_reg (insn, data);
+	return visitor->preload_reg (insn, data);
       case 0x63: case 0x67: case 0x73: case 0x77:
-	return arm_copy_unpred (insn, data);
+	return visitor->unpred (insn, data);
       default:
-	return arm_copy_undef (insn, data);
+	return visitor->undef (insn, data);
       }
   else
-    return arm_copy_undef (insn, data);  /* Probably unreachable.  */
+    return visitor->undef (insn, data);  /* Probably unreachable.  */
 }
 
 static int
-arm_decode_unconditional (uint32_t insn, struct arm_insn_reloc_data *data)
+arm_decode_unconditional (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+			  struct arm_insn_reloc_data *data)
 {
   if (bit (insn, 27) == 0)
-    return arm_decode_misc_memhint_neon (insn, data);
+    return arm_decode_misc_memhint_neon (insn, visitor, data);
   /* Switch on bits: 0bxxxxx321xxx0xxxxxxxxxxxxxxxxxxxx.  */
   else switch (((insn & 0x7000000) >> 23) | ((insn & 0x100000) >> 20))
     {
     case 0x0: case 0x2:
-      return arm_copy_unmodified (insn, "srs", data);
+      return visitor->others (insn, "srs", data);
 
     case 0x1: case 0x3:
-      return arm_copy_unmodified (insn, "rfe", data);
+      return visitor->others (insn, "rfe", data);
 
     case 0x4: case 0x5: case 0x6: case 0x7:
-      return arm_copy_b_bl_blx (insn, data);
+      return visitor->b_bl_blx (insn, data);
 
     case 0x8:
       switch ((insn & 0xe00000) >> 21)
 	{
 	case 0x1: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
 	  /* stc/stc2.  */
-	  return arm_copy_copro_load_store (insn, data);
+	  return visitor->copro_load_store (insn, data);
 
 	case 0x2:
-	  return arm_copy_unmodified (insn, "mcrr/mcrr2", data);
+	  return visitor->others (insn, "mcrr/mcrr2", data);
 
 	default:
-	  return arm_copy_undef (insn, data);
+	  return visitor->undef (insn, data);
 	}
 
     case 0x9:
@@ -6556,53 +6581,54 @@ arm_decode_unconditional (uint32_t insn, struct arm_insn_reloc_data *data)
 	  {
 	  case 0x1: case 0x3:
 	    /* ldc/ldc2 imm (undefined for rn == pc).  */
-	    return rn_f ? arm_copy_undef (insn, data)
-			: arm_copy_copro_load_store (insn, data);
+	    return rn_f ? visitor->undef (insn, data)
+			: visitor->copro_load_store (insn, data);
 
 	  case 0x2:
-	    return arm_copy_unmodified (insn, "mrrc/mrrc2", data);
+	    return visitor->others (insn, "mrrc/mrrc2", data);
 
 	  case 0x4: case 0x5: case 0x6: case 0x7:
 	    /* ldc/ldc2 lit (undefined for rn != pc).  */
-	    return rn_f ? arm_copy_copro_load_store (insn, data)
-			: arm_copy_undef (insn, data);
+	    return rn_f ? visitor->copro_load_store (insn, data)
+			: visitor->undef (insn, data);
 
 	  default:
-	    return arm_copy_undef (insn, data);
+	    return visitor->undef (insn, data);
 	  }
       }
 
     case 0xa:
-      return arm_copy_unmodified (insn, "stc/stc2", data);
+      return visitor->others (insn, "stc/stc2", data);
 
     case 0xb:
       if (bits (insn, 16, 19) == 0xf)
         /* ldc/ldc2 lit.  */
-	return arm_copy_copro_load_store (insn, data);
+	return visitor->copro_load_store (insn, data);
       else
-	return arm_copy_undef (insn, data);
+	return visitor->undef (insn, data);
 
     case 0xc:
       if (bit (insn, 4))
-	return arm_copy_unmodified (insn, "mcr/mcr2", data);
+	return visitor->others (insn, "mcr/mcr2", data);
       else
-	return arm_copy_unmodified (insn, "cdp/cdp2", data);
+	return visitor->others (insn, "cdp/cdp2", data);
 
     case 0xd:
       if (bit (insn, 4))
-	return arm_copy_unmodified (insn, "mrc/mrc2", data);
+	return visitor->others (insn, "mrc/mrc2", data);
       else
-	return arm_copy_unmodified (insn, "cdp/cdp2", data);
+	return visitor->others (insn, "cdp/cdp2", data);
 
     default:
-      return arm_copy_undef (insn, data);
+      return visitor->undef (insn, data);
     }
 }
 
 /* Decode miscellaneous instructions in dp/misc encoding space.  */
 
 static int
-arm_decode_miscellaneous (uint32_t insn, struct arm_insn_reloc_data *data)
+arm_decode_miscellaneous (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+			  struct arm_insn_reloc_data *data)
 {
   unsigned int op2 = bits (insn, 4, 6);
   unsigned int op = bits (insn, 21, 22);
@@ -6610,81 +6636,83 @@ arm_decode_miscellaneous (uint32_t insn, struct arm_insn_reloc_data *data)
   switch (op2)
     {
     case 0x0:
-      return arm_copy_unmodified (insn, "mrs/msr", data);
+      return visitor->others (insn, "mrs/msr", data);
 
     case 0x1:
       if (op == 0x1)  /* bx.  */
-	return arm_copy_bx_blx_reg (insn, data);
+	return visitor->bx_blx_reg (insn, data);
       else if (op == 0x3)
-	return arm_copy_unmodified (insn, "clz", data);
+	return visitor->others (insn, "clz", data);
       else
-	return arm_copy_undef (insn, data);
+	return visitor->undef (insn, data);
 
     case 0x2:
       if (op == 0x1)
-        /* Not really supported.  */
-	return arm_copy_unmodified (insn, "bxj", data);
+	/* Not really supported.  */
+	return visitor->others (insn, "bxj", data);
       else
-	return arm_copy_undef (insn, data);
+	return visitor->undef (insn, data);
 
     case 0x3:
       if (op == 0x1)
-	return arm_copy_bx_blx_reg (insn, data);  /* blx register.  */
+	return visitor->bx_blx_reg (insn, data);  /* blx register.  */
       else
-	return arm_copy_undef (insn, data);
+	return visitor->undef (insn, data);
 
     case 0x5:
-      return arm_copy_unmodified (insn, "saturating add/sub", data);
+      return visitor->others (insn, "saturating add/sub", data);
 
     case 0x7:
       if (op == 0x1)
-	return arm_copy_unmodified (insn, "bkpt", data);
+	return visitor->others (insn, "bkpt", data);
       else if (op == 0x3)
-        /* Not really supported.  */
-	return arm_copy_unmodified (insn, "smc", data);
+	/* Not really supported.  */
+	return visitor->others (insn, "smc", data);
 
     default:
-      return arm_copy_undef (insn, data);
+      return visitor->undef (insn, data);
     }
 }
 
 static int
-arm_decode_dp_misc (uint32_t insn, struct arm_insn_reloc_data *data)
+arm_decode_dp_misc (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+		    struct arm_insn_reloc_data *data)
 {
   if (bit (insn, 25))
     switch (bits (insn, 20, 24))
       {
       case 0x10:
-	return arm_copy_unmodified (insn, "movw", data);
+	return visitor->others (insn, "movw", data);
 
       case 0x14:
-	return arm_copy_unmodified (insn, "movt", data);
+	return visitor->others (insn, "movt", data);
 
-      case 0x12: case 0x16:
-	return arm_copy_unmodified (insn, "msr imm", data);
+      case 0x12:
+      case 0x16:
+	return visitor->others (insn, "msr imm", data);
 
       default:
-	return arm_copy_alu_imm (insn, data);
+	return visitor->alu_imm (insn, data);
       }
   else
     {
       uint32_t op1 = bits (insn, 20, 24), op2 = bits (insn, 4, 7);
 
       if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0)
-	return arm_copy_alu_reg (insn, data);
+	return visitor->alu_reg (insn, data);
       else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1)
-	return arm_copy_alu_shifted_reg (insn, data);
+	return visitor->alu_shifted_reg (insn, data);
       else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0)
-	return arm_decode_miscellaneous (insn, data);
+	return arm_decode_miscellaneous (insn, visitor, data);
       else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8)
-	return arm_copy_unmodified (insn, "halfword mul/mla", data);
+	return visitor->others (insn, "halfword mul/mla", data);
       else if ((op1 & 0x10) == 0x00 && op2 == 0x9)
-	return arm_copy_unmodified (insn, "mul/mla", data);
+	return visitor->others (insn, "mul/mla", data);
       else if ((op1 & 0x10) == 0x10 && op2 == 0x9)
-	return arm_copy_unmodified (insn, "synch", data);
+	return visitor->others (insn, "synch", data);
       else if (op2 == 0xb || (op2 & 0xd) == 0xd)
 	/* 2nd arg means "unprivileged".  */
-	return arm_copy_extra_ld_st (insn, data, (op1 & 0x12) == 0x02);
+	return visitor->extra_ld_st (insn, data, (op1 & 0x12) == 0x02);
     }
 
   /* Should be unreachable.  */
@@ -6692,89 +6720,92 @@ arm_decode_dp_misc (uint32_t insn, struct arm_insn_reloc_data *data)
 }
 
 static int
-arm_decode_ld_st_word_ubyte (uint32_t insn, struct arm_insn_reloc_data *data)
+arm_decode_ld_st_word_ubyte (uint32_t insn,
+			     struct arm_insn_reloc_visitor *visitor,
+			     struct arm_insn_reloc_data *data)
 {
   int a = bit (insn, 25), b = bit (insn, 4);
   uint32_t op1 = bits (insn, 20, 24);
 
   if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02)
       || (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b))
-    return arm_copy_ldr_str_ldrb_strb (insn, data, 0, 4, 0);
+    return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 0);
   else if ((!a && (op1 & 0x17) == 0x02)
 	    || (a && (op1 & 0x17) == 0x02 && !b))
-    return arm_copy_ldr_str_ldrb_strb (insn, data, 0, 4, 1);
+    return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 1);
   else if ((!a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03)
 	    || (a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03 && !b))
-    return arm_copy_ldr_str_ldrb_strb (insn, data, 1, 4, 0);
+    return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 0);
   else if ((!a && (op1 & 0x17) == 0x03)
 	   || (a && (op1 & 0x17) == 0x03 && !b))
-    return arm_copy_ldr_str_ldrb_strb (insn, data, 1, 4, 1);
+    return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 1);
   else if ((!a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06)
 	    || (a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06 && !b))
-    return arm_copy_ldr_str_ldrb_strb (insn, data, 0, 1, 0);
+    return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 0);
   else if ((!a && (op1 & 0x17) == 0x06)
 	   || (a && (op1 & 0x17) == 0x06 && !b))
-    return arm_copy_ldr_str_ldrb_strb (insn, data, 0, 1, 1);
+    return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 1);
   else if ((!a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07)
 	   || (a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07 && !b))
-    return arm_copy_ldr_str_ldrb_strb (insn, data, 1, 1, 0);
+    return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 0);
   else if ((!a && (op1 & 0x17) == 0x07)
 	   || (a && (op1 & 0x17) == 0x07 && !b))
-    return arm_copy_ldr_str_ldrb_strb (insn, data, 1, 1, 1);
+    return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 1);
 
   /* Should be unreachable.  */
   return 1;
 }
 
 static int
-arm_decode_media (uint32_t insn, struct arm_insn_reloc_data *data)
+arm_decode_media (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+		  struct arm_insn_reloc_data *data)
 {
   switch (bits (insn, 20, 24))
     {
     case 0x00: case 0x01: case 0x02: case 0x03:
-      return arm_copy_unmodified (insn, "parallel add/sub signed", data);
+      return visitor->others (insn, "parallel add/sub signed", data);
 
     case 0x04: case 0x05: case 0x06: case 0x07:
-      return arm_copy_unmodified (insn, "parallel add/sub unsigned", data);
+      return visitor->others (insn, "parallel add/sub unsigned", data);
 
     case 0x08: case 0x09: case 0x0a: case 0x0b:
     case 0x0c: case 0x0d: case 0x0e: case 0x0f:
-      return arm_copy_unmodified (insn,
-			      "decode/pack/unpack/saturate/reverse", data);
+      return visitor->others (insn, "decode/pack/unpack/saturate/reverse",
+			      data);
 
     case 0x18:
       if (bits (insn, 5, 7) == 0)  /* op2.  */
 	 {
 	  if (bits (insn, 12, 15) == 0xf)
-	    return arm_copy_unmodified (insn, "usad8", data);
+	    return visitor->others (insn, "usad8", data);
 	  else
-	    return arm_copy_unmodified (insn, "usada8", data);
+	    return visitor->others (insn, "usada8", data);
 	}
       else
-	 return arm_copy_undef (insn, data);
+	 return visitor->undef (insn, data);
 
     case 0x1a: case 0x1b:
       if (bits (insn, 5, 6) == 0x2)  /* op2[1:0].  */
-	return arm_copy_unmodified (insn, "sbfx", data);
+	return visitor->others (insn, "sbfx", data);
       else
-	return arm_copy_undef (insn, data);
+	return visitor->undef (insn, data);
 
     case 0x1c: case 0x1d:
       if (bits (insn, 5, 6) == 0x0)  /* op2[1:0].  */
 	 {
 	  if (bits (insn, 0, 3) == 0xf)
-	    return arm_copy_unmodified (insn, "bfc", data);
+	    return visitor->others (insn, "bfc", data);
 	  else
-	    return arm_copy_unmodified (insn, "bfi", data);
+	    return visitor->others (insn, "bfi", data);
 	}
       else
-	return arm_copy_undef (insn, data);
+	return visitor->undef (insn, data);
 
     case 0x1e: case 0x1f:
       if (bits (insn, 5, 6) == 0x2)  /* op2[1:0].  */
-	return arm_copy_unmodified (insn, "ubfx", data);
+	return visitor->others (insn, "ubfx", data);
       else
-	return arm_copy_undef (insn, data);
+	return visitor->undef (insn, data);
     }
 
   /* Should be unreachable.  */
@@ -6782,37 +6813,39 @@ arm_decode_media (uint32_t insn, struct arm_insn_reloc_data *data)
 }
 
 static int
-arm_decode_b_bl_ldmstm (uint32_t insn, struct arm_insn_reloc_data *data)
+arm_decode_b_bl_ldmstm (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+			struct arm_insn_reloc_data *data)
 {
   if (bit (insn, 25))
-    return arm_copy_b_bl_blx (insn, data);
+    return visitor->b_bl_blx (insn, data);
   else
-    return arm_copy_block_xfer (insn, data);
+    return visitor->block_xfer (insn, data);
 }
 
 static int
-arm_decode_ext_reg_ld_st (uint32_t insn, struct arm_insn_reloc_data *data)
+arm_decode_ext_reg_ld_st (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+			  struct arm_insn_reloc_data *data)
 {
   unsigned int opcode = bits (insn, 20, 24);
 
   switch (opcode)
     {
     case 0x04: case 0x05:  /* VFP/Neon mrrc/mcrr.  */
-      return arm_copy_unmodified (insn, "vfp/neon mrrc/mcrr", data);
+      return visitor->others (insn, "vfp/neon mrrc/mcrr", data);
 
     case 0x08: case 0x0a: case 0x0c: case 0x0e:
     case 0x12: case 0x16:
-      return arm_copy_unmodified (insn, "vfp/neon vstm/vpush", data);
+      return visitor->others (insn, "vfp/neon vstm/vpush", data);
 
     case 0x09: case 0x0b: case 0x0d: case 0x0f:
     case 0x13: case 0x17:
-      return arm_copy_unmodified (insn, "vfp/neon vldm/vpop", data);
+      return visitor->others (insn, "vfp/neon vldm/vpop", data);
 
     case 0x10: case 0x14: case 0x18: case 0x1c:  /* vstr.  */
     case 0x11: case 0x15: case 0x19: case 0x1d:  /* vldr.  */
       /* Note: no writeback for these instructions.  Bit 25 will always be
 	 zero though (via caller), so the following works OK.  */
-      return arm_copy_copro_load_store (insn, data);
+      return visitor->copro_load_store (insn, data);
     }
 
   /* Should be unreachable.  */
@@ -6874,47 +6907,48 @@ thumb2_decode_ext_reg_ld_st (uint16_t insn1, uint16_t insn2,
 }
 
 static int
-arm_decode_svc_copro (uint32_t insn, struct arm_insn_reloc_data *data)
+arm_decode_svc_copro (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+		      struct arm_insn_reloc_data *data)
 {
   unsigned int op1 = bits (insn, 20, 25);
   int op = bit (insn, 4);
   unsigned int coproc = bits (insn, 8, 11);
 
   if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa)
-    return arm_decode_ext_reg_ld_st (insn, data);
+    return arm_decode_ext_reg_ld_st (insn, visitor, data);
   else if ((op1 & 0x21) == 0x00 && (op1 & 0x3a) != 0x00
 	   && (coproc & 0xe) != 0xa)
     /* stc/stc2.  */
-    return arm_copy_copro_load_store (insn, data);
+    return visitor->copro_load_store (insn, data);
   else if ((op1 & 0x21) == 0x01 && (op1 & 0x3a) != 0x00
 	   && (coproc & 0xe) != 0xa)
     /* ldc/ldc2 imm/lit.  */
-    return arm_copy_copro_load_store (insn, data);
+    return visitor->copro_load_store (insn, data);
   else if ((op1 & 0x3e) == 0x00)
-    return arm_copy_undef (insn, data);
+    return visitor->undef (insn, data);
   else if ((op1 & 0x3e) == 0x04 && (coproc & 0xe) == 0xa)
-    return arm_copy_unmodified (insn, "neon 64bit xfer", data);
+    return visitor->others (insn, "neon 64bit xfer", data);
   else if (op1 == 0x04 && (coproc & 0xe) != 0xa)
-    return arm_copy_unmodified (insn, "mcrr/mcrr2", data);
+    return visitor->others (insn, "mcrr/mcrr2", data);
   else if (op1 == 0x05 && (coproc & 0xe) != 0xa)
-    return arm_copy_unmodified (insn, "mrrc/mrrc2", data);
+    return visitor->others (insn, "mrrc/mrrc2", data);
   else if ((op1 & 0x30) == 0x20 && !op)
     {
       if ((coproc & 0xe) == 0xa)
-	return arm_copy_unmodified (insn, "vfp dataproc", data);
+	return visitor->others (insn, "vfp dataproc", data);
       else
-	return arm_copy_unmodified (insn, "cdp/cdp2", data);
+	return visitor->others (insn, "cdp/cdp2", data);
     }
   else if ((op1 & 0x30) == 0x20 && op)
-    return arm_copy_unmodified (insn, "neon 8/16/32 bit xfer", data);
+    return visitor->others (insn, "neon 8/16/32 bit xfer", data);
   else if ((op1 & 0x31) == 0x20 && op && (coproc & 0xe) != 0xa)
-    return arm_copy_unmodified (insn, "mcr/mcr2", data);
+    return visitor->others (insn, "mcr/mcr2", data);
   else if ((op1 & 0x31) == 0x21 && op && (coproc & 0xe) != 0xa)
-    return arm_copy_unmodified (insn, "mrc/mrc2", data);
+    return visitor->others (insn, "mrc/mrc2", data);
   else if ((op1 & 0x30) == 0x30)
-    return arm_copy_svc (insn, data);
+    return visitor->svc (insn, data);
   else
-    return arm_copy_undef (insn, data);  /* Possibly unreachable.  */
+    return visitor->undef (insn, data);  /* Possibly unreachable.  */
 }
 
 static int
@@ -7542,38 +7576,58 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
 }
 
 static int
-arm_relocate_insn (uint32_t insn, struct arm_insn_reloc_data *data)
+arm_relocate_insn (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+		   struct arm_insn_reloc_data *data)
 {
   int err = 1;
 
   if ((insn & 0xf0000000) == 0xf0000000)
-    err = arm_decode_unconditional (insn, data);
+    err = arm_decode_unconditional (insn, visitor, data);
   else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24))
     {
     case 0x0: case 0x1: case 0x2: case 0x3:
-      err = arm_decode_dp_misc (insn, data);
+      err = arm_decode_dp_misc (insn, visitor, data);
       break;
 
     case 0x4: case 0x5: case 0x6:
-      err = arm_decode_ld_st_word_ubyte (insn, data);
+      err = arm_decode_ld_st_word_ubyte (insn, visitor, data);
       break;
 
     case 0x7:
-      err = arm_decode_media (insn, data);
+      err = arm_decode_media (insn, visitor, data);
       break;
 
     case 0x8: case 0x9: case 0xa: case 0xb:
-      err = arm_decode_b_bl_ldmstm (insn, data);
+      err = arm_decode_b_bl_ldmstm (insn, visitor, data);
       break;
 
     case 0xc: case 0xd: case 0xe: case 0xf:
-      err = arm_decode_svc_copro (insn, data);
+      err = arm_decode_svc_copro (insn, visitor, data);
       break;
     }
 
   return err;
 }
 
+static struct arm_insn_reloc_visitor arm_insn_reloc_visitor =
+{
+  arm_copy_alu_imm,
+  arm_copy_alu_reg,
+  arm_copy_alu_shifted_reg,
+  arm_copy_b_bl_blx,
+  arm_copy_block_xfer,
+  arm_copy_bx_blx_reg,
+  arm_copy_copro_load_store,
+  arm_copy_extra_ld_st,
+  arm_copy_ldr_str_ldrb_strb,
+  arm_copy_unmodified,
+  arm_copy_preload,
+  arm_copy_preload_reg,
+  arm_copy_svc,
+  arm_copy_undef,
+  arm_copy_unpred,
+};
+
 void
 arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
 			    CORE_ADDR to, struct regcache *regs,
@@ -7608,7 +7662,7 @@ arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
       dsc->is_thumb = 0;
       dsc->insn_size = 4;
 
-      err = arm_relocate_insn (insn, &reloc_data);
+      err = arm_relocate_insn (insn, &arm_insn_reloc_visitor, &reloc_data);
     }
   else
     {
-- 
2.8.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2016-07-05 13:56 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-05 13:41 [PATCH v3 00/18] Fast tracepoint support for ARMv7 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: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 02/18] arm-tdep.c: Refactor displaced stepping relocation functions 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 15/18] JIT conditions support for ARM tracepoints Antoine Tremblay
2016-07-05 13:42 ` [PATCH v3 18/18] arm fast tracepoints: Relocation of Thumb 32-bits 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 ` [PATCH v3 17/18] arm fast tracepoints: Relocation of ARM instructions 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 10/18] gdbserver: pass pointer to struct tracepoint to install_fast_tracepoint_jump_pad 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 14/18] Fast tracepoint support for ARM on Linux Antoine Tremblay
2016-07-05 13:56 ` [PATCH v3 04/18] arm-tdep.c: Use relocation visitor in ARM instruction decoding Antoine Tremblay
2016-07-05 13:56 ` [PATCH v3 05/18] arm-tdep.c: Use relocation visitor in Thumb 32-bits " Antoine Tremblay

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).