@@ -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
#
@@ -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);
@@ -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;
@@ -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
new file mode 100644
@@ -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."));
+ }
+}
new file mode 100644
@@ -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 */
new file mode 100644
@@ -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 };
+}
new file mode 100644
@@ -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
@@ -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
;;
@@ -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)
@@ -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"
@@ -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);
}