[PATCH v2 12/17] Add ARM/Thumb instruction assembler for fast tracepoints

Antoine Tremblay
2016-06-09T12:57:14Z

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 3440e44..1ce071a 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 \
@@ -993,7 +996,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.

@@ -2313,6 +2317,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)
@@ -2395,6 +2403,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 88fcf4b..dde9a4d 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>
+
+ 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>
+
+ 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>
+ 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>
+ 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
+ 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
+ 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>
+ 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>
+ 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>
+ 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 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 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 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> , [<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> , [<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>, , [<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>, , [<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> , [<Rn>{, #+/-<imm12>}]
+ STR<c> , [<Rn>], #+/-<imm12>
+ STR<c> , [<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> , [<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 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
+
+ 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
+
+ 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> , [<Rn>{, #+/-<imm12>}]
+ LDR<c> , [<Rn>], #+/-<imm12>
+ LDR<c> , [<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> , [<Rn>{, #+/-<imm12>}]
+ LDRB<c> , [<Rn>], #+/-<imm12>
+ LDRB<c> , [<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> , [<Rn>{, #+/-<imm8>}]
+ LDRH<c> , [<Rn>], #+/-<imm8>
+ LDRH<c> , [<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> , <Rt2>, [<Rn>{, #+/-<imm8>}]
+ LDRD<c> , <Rt2>, [<Rn>], #+/-<imm8>
+ LDRD<c> , <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 b33d76d..d9bc5ac 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 a83459c..2cf79c1 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"
@@ -583,19 +584,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
@@ -672,39 +667,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.

@@ -752,7 +714,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;
@@ -807,7 +769,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);
}
@@ -826,7 +788,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);
}
@@ -889,7 +851,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);
}
@@ -908,7 +870,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);
}
@@ -929,7 +891,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