[PATCH v2 07/17] Move ARM instruction decode functions to arch/arm-insn-reloc.c

Antoine Tremblay
2016-06-09T12:56:49Z

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

No changes to the code itself.

gdb/ChangeLog:

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

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 60cfc97..3440e44 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -657,8 +657,13 @@ ALL_64_TARGET_OBS = \

# All other target-dependent objects files (used with --enable-targets=all).
ALL_TARGET_OBS = \
- armbsd-tdep.o arm.o arm-linux.o arm-linux-tdep.o \
- arm-get-next-pcs.o arm-symbian-tdep.o \
+ armbsd-tdep.o \
+ arm.o \
+ arm-linux.o \
+ arm-linux-tdep.o \
+ arm-get-next-pcs.o \
+ arm-symbian-tdep.o \
+ arm-insn-reloc.o \
armnbsd-tdep.o armobsd-tdep.o \
arm-tdep.o arm-wince-tdep.o \
avr-tdep.o \
@@ -988,7 +993,7 @@ common/common-exceptions.h target/target.h common/symbol.h \
common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \
common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h nat/amd64-linux-siginfo.h\
nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h arch/aarch64-insn.h \
-tid-parse.h ser-event.h
+tid-parse.h ser-event.h arch/arm-insn-reloc.h

# Header files that already have srcdir in them, or which are in objdir.

@@ -2308,6 +2313,10 @@ arm-linux.o: ${srcdir}/arch/arm-linux.c
$(COMPILE) $(srcdir)/arch/arm-linux.c
$(POSTCOMPILE)

+arm-insn-reloc.o: ${srcdir}/arch/arm-insn-reloc.c
+ $(COMPILE) $(srcdir)/arch/arm-insn-reloc.c
+ $(POSTCOMPILE)
+
arm-get-next-pcs.o: ${srcdir}/arch/arm-get-next-pcs.c
$(COMPILE) $(srcdir)/arch/arm-get-next-pcs.c
$(POSTCOMPILE)
diff --git a/gdb/arch/arm-insn-reloc.c b/gdb/arch/arm-insn-reloc.c
new file mode 100644
index 0000000..adf6243
--- /dev/null
+++ b/gdb/arch/arm-insn-reloc.c
@@ -0,0 +1,472 @@
+/* Copyright (C) 2016 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "common-defs.h"
+
+#include "arm.h"
+#include "arm-insn-reloc.h"
+
+static int
+arm_decode_misc_memhint_neon (uint32_t insn,
+ struct arm_insn_reloc_visitor *visitor,
+ struct arm_insn_reloc_data *data)
+{
+ unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7);
+ unsigned int rn = bits (insn, 16, 19);
+
+ if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0xe) == 0x0)
+ return visitor->others (insn, "cps", data);
+ else if (op1 == 0x10 && op2 == 0x0 && (rn & 0xe) == 0x1)
+ return visitor->others (insn, "setend", data);
+ else if ((op1 & 0x60) == 0x20)
+ return visitor->others (insn, "neon dataproc", data);
+ else if ((op1 & 0x71) == 0x40)
+ return visitor->others (insn, "neon elt/struct load/store", data);
+ else if ((op1 & 0x77) == 0x41)
+ return visitor->others (insn, "unallocated mem hint", data);
+ else if ((op1 & 0x77) == 0x45)
+ return visitor->preload (insn, data); /* pli. */
+ else if ((op1 & 0x77) == 0x51)
+ {
+ if (rn != 0xf)
+ return visitor->preload (insn, data); /* pld/pldw. */
+ else
+ return visitor->unpred (insn, data);
+ }
+ else if ((op1 & 0x77) == 0x55)
+ return visitor->preload (insn, data); /* pld/pldw. */
+ else if (op1 == 0x57)
+ switch (op2)
+ {
+ case 0x1: return visitor->others (insn, "clrex", data);
+ case 0x4: return visitor->others (insn, "dsb", data);
+ case 0x5: return visitor->others (insn, "dmb", data);
+ case 0x6: return visitor->others (insn, "isb", data);
+ default: return visitor->unpred (insn, data);
+ }
+ else if ((op1 & 0x63) == 0x43)
+ return visitor->unpred (insn, data);
+ else if ((op2 & 0x1) == 0x0)
+ switch (op1 & ~0x80)
+ {
+ case 0x61:
+ return visitor->others (insn, "unallocated mem hint", data);
+ case 0x65:
+ return visitor->preload_reg (insn, data); /* pli reg. */
+ case 0x71: case 0x75:
+ /* pld/pldw reg. */
+ return visitor->preload_reg (insn, data);
+ case 0x63: case 0x67: case 0x73: case 0x77:
+ return visitor->unpred (insn, data);
+ default:
+ return visitor->undef (insn, data);
+ }
+ else
+ return visitor->undef (insn, data); /* Probably unreachable. */
+}
+
+static int
+arm_decode_unconditional (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+ struct arm_insn_reloc_data *data)
+{
+ if (bit (insn, 27) == 0)
+ return arm_decode_misc_memhint_neon (insn, visitor, data);
+ /* Switch on bits: 0bxxxxx321xxx0xxxxxxxxxxxxxxxxxxxx. */
+ else switch (((insn & 0x7000000) >> 23) | ((insn & 0x100000) >> 20))
+ {
+ case 0x0: case 0x2:
+ return visitor->others (insn, "srs", data);
+
+ case 0x1: case 0x3:
+ return visitor->others (insn, "rfe", data);
+
+ case 0x4: case 0x5: case 0x6: case 0x7:
+ return visitor->b_bl_blx (insn, data);
+
+ case 0x8:
+ switch ((insn & 0xe00000) >> 21)
+ {
+ case 0x1: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
+ /* stc/stc2. */
+ return visitor->copro_load_store (insn, data);
+
+ case 0x2:
+ return visitor->others (insn, "mcrr/mcrr2", data);
+
+ default:
+ return visitor->undef (insn, data);
+ }
+
+ case 0x9:
+ {
+ int rn_f = (bits (insn, 16, 19) == 0xf);
+ switch ((insn & 0xe00000) >> 21)
+ {
+ case 0x1: case 0x3:
+ /* ldc/ldc2 imm (undefined for rn == pc). */
+ return rn_f ? visitor->undef (insn, data)
+ : visitor->copro_load_store (insn, data);
+
+ case 0x2:
+ return visitor->others (insn, "mrrc/mrrc2", data);
+
+ case 0x4: case 0x5: case 0x6: case 0x7:
+ /* ldc/ldc2 lit (undefined for rn != pc). */
+ return rn_f ? visitor->copro_load_store (insn, data)
+ : visitor->undef (insn, data);
+
+ default:
+ return visitor->undef (insn, data);
+ }
+ }
+
+ case 0xa:
+ return visitor->others (insn, "stc/stc2", data);
+
+ case 0xb:
+ if (bits (insn, 16, 19) == 0xf)
+ /* ldc/ldc2 lit. */
+ return visitor->copro_load_store (insn, data);
+ else
+ return visitor->undef (insn, data);
+
+ case 0xc:
+ if (bit (insn, 4))
+ return visitor->others (insn, "mcr/mcr2", data);
+ else
+ return visitor->others (insn, "cdp/cdp2", data);
+
+ case 0xd:
+ if (bit (insn, 4))
+ return visitor->others (insn, "mrc/mrc2", data);
+ else
+ return visitor->others (insn, "cdp/cdp2", data);
+
+ default:
+ return visitor->undef (insn, data);
+ }
+}
+
+
+/* Decode miscellaneous instructions in dp/misc encoding space. */
+
+static int
+arm_decode_miscellaneous (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+ struct arm_insn_reloc_data *data)
+{
+ unsigned int op2 = bits (insn, 4, 6);
+ unsigned int op = bits (insn, 21, 22);
+
+ switch (op2)
+ {
+ case 0x0:
+ return visitor->others (insn, "mrs/msr", data);
+
+ case 0x1:
+ if (op == 0x1) /* bx. */
+ return visitor->bx_blx_reg (insn, data);
+ else if (op == 0x3)
+ return visitor->others (insn, "clz", data);
+ else
+ return visitor->undef (insn, data);
+
+ case 0x2:
+ if (op == 0x1)
+ /* Not really supported. */
+ return visitor->others (insn, "bxj", data);
+ else
+ return visitor->undef (insn, data);
+
+ case 0x3:
+ if (op == 0x1)
+ return visitor->bx_blx_reg (insn, data); /* blx register. */
+ else
+ return visitor->undef (insn, data);
+
+ case 0x5:
+ return visitor->others (insn, "saturating add/sub", data);
+
+ case 0x7:
+ if (op == 0x1)
+ return visitor->others (insn, "bkpt", data);
+ else if (op == 0x3)
+ /* Not really supported. */
+ return visitor->others (insn, "smc", data);
+
+ default:
+ return visitor->undef (insn, data);
+ }
+}
+
+static int
+arm_decode_dp_misc (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+ struct arm_insn_reloc_data *data)
+{
+ if (bit (insn, 25))
+ switch (bits (insn, 20, 24))
+ {
+ case 0x10:
+ return visitor->others (insn, "movw", data);
+
+ case 0x14:
+ return visitor->others (insn, "movt", data);
+
+ case 0x12:
+ case 0x16:
+ return visitor->others (insn, "msr imm", data);
+
+ default:
+ return visitor->alu_imm (insn, data);
+ }
+ else
+ {
+ uint32_t op1 = bits (insn, 20, 24), op2 = bits (insn, 4, 7);
+
+ if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0)
+ return visitor->alu_reg (insn, data);
+ else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1)
+ return visitor->alu_shifted_reg (insn, data);
+ else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0)
+ return arm_decode_miscellaneous (insn, visitor, data);
+ else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8)
+ return visitor->others (insn, "halfword mul/mla", data);
+ else if ((op1 & 0x10) == 0x00 && op2 == 0x9)
+ return visitor->others (insn, "mul/mla", data);
+ else if ((op1 & 0x10) == 0x10 && op2 == 0x9)
+ return visitor->others (insn, "synch", data);
+ else if (op2 == 0xb || (op2 & 0xd) == 0xd)
+ /* 2nd arg means "unprivileged". */
+ return visitor->extra_ld_st (insn, data, (op1 & 0x12) == 0x02);
+ }
+
+ /* Should be unreachable. */
+ return 1;
+}
+
+
+static int
+arm_decode_ld_st_word_ubyte (uint32_t insn,
+ struct arm_insn_reloc_visitor *visitor,
+ struct arm_insn_reloc_data *data)
+{
+ int a = bit (insn, 25), b = bit (insn, 4);
+ uint32_t op1 = bits (insn, 20, 24);
+
+ if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02)
+ || (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b))
+ return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 0);
+ else if ((!a && (op1 & 0x17) == 0x02)
+ || (a && (op1 & 0x17) == 0x02 && !b))
+ return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 1);
+ else if ((!a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03)
+ || (a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03 && !b))
+ return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 0);
+ else if ((!a && (op1 & 0x17) == 0x03)
+ || (a && (op1 & 0x17) == 0x03 && !b))
+ return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 1);
+ else if ((!a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06)
+ || (a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06 && !b))
+ return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 0);
+ else if ((!a && (op1 & 0x17) == 0x06)
+ || (a && (op1 & 0x17) == 0x06 && !b))
+ return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 1);
+ else if ((!a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07)
+ || (a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07 && !b))
+ return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 0);
+ else if ((!a && (op1 & 0x17) == 0x07)
+ || (a && (op1 & 0x17) == 0x07 && !b))
+ return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 1);
+
+ /* Should be unreachable. */
+ return 1;
+}
+
+static int
+arm_decode_media (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+ struct arm_insn_reloc_data *data)
+{
+ switch (bits (insn, 20, 24))
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ return visitor->others (insn, "parallel add/sub signed", data);
+
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ return visitor->others (insn, "parallel add/sub unsigned", data);
+
+ case 0x08: case 0x09: case 0x0a: case 0x0b:
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ return visitor->others (insn, "decode/pack/unpack/saturate/reverse",
+ data);
+
+ case 0x18:
+ if (bits (insn, 5, 7) == 0) /* op2. */
+ {
+ if (bits (insn, 12, 15) == 0xf)
+ return visitor->others (insn, "usad8", data);
+ else
+ return visitor->others (insn, "usada8", data);
+ }
+ else
+ return visitor->undef (insn, data);
+
+ case 0x1a: case 0x1b:
+ if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */
+ return visitor->others (insn, "sbfx", data);
+ else
+ return visitor->undef (insn, data);
+
+ case 0x1c: case 0x1d:
+ if (bits (insn, 5, 6) == 0x0) /* op2[1:0]. */
+ {
+ if (bits (insn, 0, 3) == 0xf)
+ return visitor->others (insn, "bfc", data);
+ else
+ return visitor->others (insn, "bfi", data);
+ }
+ else
+ return visitor->undef (insn, data);
+
+ case 0x1e: case 0x1f:
+ if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */
+ return visitor->others (insn, "ubfx", data);
+ else
+ return visitor->undef (insn, data);
+ }
+
+ /* Should be unreachable. */
+ return 1;
+}
+
+static int
+arm_decode_b_bl_ldmstm (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+ struct arm_insn_reloc_data *data)
+{
+ if (bit (insn, 25))
+ return visitor->b_bl_blx (insn, data);
+ else
+ return visitor->block_xfer (insn, data);
+}
+
+static int
+arm_decode_ext_reg_ld_st (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+ struct arm_insn_reloc_data *data)
+{
+ unsigned int opcode = bits (insn, 20, 24);
+
+ switch (opcode)
+ {
+ case 0x04: case 0x05: /* VFP/Neon mrrc/mcrr. */
+ return visitor->others (insn, "vfp/neon mrrc/mcrr", data);
+
+ case 0x08: case 0x0a: case 0x0c: case 0x0e:
+ case 0x12: case 0x16:
+ return visitor->others (insn, "vfp/neon vstm/vpush", data);
+
+ case 0x09: case 0x0b: case 0x0d: case 0x0f:
+ case 0x13: case 0x17:
+ return visitor->others (insn, "vfp/neon vldm/vpop", data);
+
+ case 0x10: case 0x14: case 0x18: case 0x1c: /* vstr. */
+ case 0x11: case 0x15: case 0x19: case 0x1d: /* vldr. */
+ /* Note: no writeback for these instructions. Bit 25 will always be
+ zero though (via caller), so the following works OK. */
+ return visitor->copro_load_store (insn, data);
+ }
+
+ /* Should be unreachable. */
+ return 1;
+}
+
+
+static int
+arm_decode_svc_copro (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+ struct arm_insn_reloc_data *data)
+{
+ unsigned int op1 = bits (insn, 20, 25);
+ int op = bit (insn, 4);
+ unsigned int coproc = bits (insn, 8, 11);
+
+ if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa)
+ return arm_decode_ext_reg_ld_st (insn, visitor, data);
+ else if ((op1 & 0x21) == 0x00 && (op1 & 0x3a) != 0x00
+ && (coproc & 0xe) != 0xa)
+ /* stc/stc2. */
+ return visitor->copro_load_store (insn, data);
+ else if ((op1 & 0x21) == 0x01 && (op1 & 0x3a) != 0x00
+ && (coproc & 0xe) != 0xa)
+ /* ldc/ldc2 imm/lit. */
+ return visitor->copro_load_store (insn, data);
+ else if ((op1 & 0x3e) == 0x00)
+ return visitor->undef (insn, data);
+ else if ((op1 & 0x3e) == 0x04 && (coproc & 0xe) == 0xa)
+ return visitor->others (insn, "neon 64bit xfer", data);
+ else if (op1 == 0x04 && (coproc & 0xe) != 0xa)
+ return visitor->others (insn, "mcrr/mcrr2", data);
+ else if (op1 == 0x05 && (coproc & 0xe) != 0xa)
+ return visitor->others (insn, "mrrc/mrrc2", data);
+ else if ((op1 & 0x30) == 0x20 && !op)
+ {
+ if ((coproc & 0xe) == 0xa)
+ return visitor->others (insn, "vfp dataproc", data);
+ else
+ return visitor->others (insn, "cdp/cdp2", data);
+ }
+ else if ((op1 & 0x30) == 0x20 && op)
+ return visitor->others (insn, "neon 8/16/32 bit xfer", data);
+ else if ((op1 & 0x31) == 0x20 && op && (coproc & 0xe) != 0xa)
+ return visitor->others (insn, "mcr/mcr2", data);
+ else if ((op1 & 0x31) == 0x21 && op && (coproc & 0xe) != 0xa)
+ return visitor->others (insn, "mrc/mrc2", data);
+ else if ((op1 & 0x30) == 0x30)
+ return visitor->svc (insn, data);
+ else
+ return visitor->undef (insn, data); /* Possibly unreachable. */
+}
+
+int
+arm_relocate_insn (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
+ struct arm_insn_reloc_data *data)
+{
+ int err = 1;
+
+ if ((insn & 0xf0000000) == 0xf0000000)
+ err = arm_decode_unconditional (insn, visitor, data);
+ else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24))
+ {
+ case 0x0: case 0x1: case 0x2: case 0x3:
+ err = arm_decode_dp_misc (insn, visitor, data);
+ break;
+
+ case 0x4: case 0x5: case 0x6:
+ err = arm_decode_ld_st_word_ubyte (insn, visitor, data);
+ break;
+
+ case 0x7:
+ err = arm_decode_media (insn, visitor, data);
+ break;
+
+ case 0x8: case 0x9: case 0xa: case 0xb:
+ err = arm_decode_b_bl_ldmstm (insn, visitor, data);
+ break;
+
+ case 0xc: case 0xd: case 0xe: case 0xf:
+ err = arm_decode_svc_copro (insn, visitor, data);
+ break;
+ }
+
+ return err;
+}
diff --git a/gdb/arch/arm-insn-reloc.h b/gdb/arch/arm-insn-reloc.h
new file mode 100644
index 0000000..18d3916
--- /dev/null
+++ b/gdb/arch/arm-insn-reloc.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2016 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef ARM_INSN_RELOC_H
+#define ARM_INSN_RELOC_H
+
+struct arm_insn_reloc_data;
+
+struct arm_insn_reloc_visitor
+{
+ int (*alu_imm) (uint32_t insn, struct arm_insn_reloc_data *data);
+ int (*alu_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+ int (*alu_shifted_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+ int (*b_bl_blx) (uint32_t insn, struct arm_insn_reloc_data *data);
+ int (*block_xfer) (uint32_t insn, struct arm_insn_reloc_data *data);
+ int (*bx_blx_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+ int (*copro_load_store) (uint32_t insn, struct arm_insn_reloc_data *data);
+ int (*extra_ld_st) (uint32_t insn, struct arm_insn_reloc_data *data,
+ int unprivileged);
+ int (*ldr_str_ldrb_strb) (uint32_t insn, struct arm_insn_reloc_data *data,
+ int load, int size, int usermode);
+ int (*others) (uint32_t insn, const char *iname,
+ struct arm_insn_reloc_data *data);
+ int (*preload) (uint32_t insn, struct arm_insn_reloc_data *data);
+ int (*preload_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
+ int (*svc) (uint32_t insn, struct arm_insn_reloc_data *data);
+ int (*undef) (uint32_t insn, struct arm_insn_reloc_data *data);
+ int (*unpred) (uint32_t insn, struct arm_insn_reloc_data *data);
+};
+
+extern int arm_relocate_insn (uint32_t insn,
+ struct arm_insn_reloc_visitor *visitor,
+ struct arm_insn_reloc_data *data);
+
+#endif /* ARM_INSN_RELOC_H */
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 0f35eb3..1af4d36 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -47,6 +47,7 @@

#include "arch/arm.h"
#include "arch/arm-get-next-pcs.h"
+#include "arch/arm-insn-reloc.h"
#include "arm-tdep.h"
#include "gdb/sim-arm.h"

@@ -4480,28 +4481,6 @@ struct arm_insn_reloc_data
struct regcache *regs;
};

-struct arm_insn_reloc_visitor
-{
- int (*alu_imm) (uint32_t insn, struct arm_insn_reloc_data *data);
- int (*alu_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
- int (*alu_shifted_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
- int (*b_bl_blx) (uint32_t insn, struct arm_insn_reloc_data *data);
- int (*block_xfer) (uint32_t insn, struct arm_insn_reloc_data *data);
- int (*bx_blx_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
- int (*copro_load_store) (uint32_t insn, struct arm_insn_reloc_data *data);
- int (*extra_ld_st) (uint32_t insn, struct arm_insn_reloc_data *data,
- int unprivileged);
- int (*ldr_str_ldrb_strb) (uint32_t insn, struct arm_insn_reloc_data *data,
- int load, int size, int usermode);
- int (*others) (uint32_t insn, const char *iname,
- struct arm_insn_reloc_data *data);
- int (*preload) (uint32_t insn, struct arm_insn_reloc_data *data);
- int (*preload_reg) (uint32_t insn, struct arm_insn_reloc_data *data);
- int (*svc) (uint32_t insn, struct arm_insn_reloc_data *data);
- int (*undef) (uint32_t insn, struct arm_insn_reloc_data *data);
- int (*unpred) (uint32_t insn, struct arm_insn_reloc_data *data);
-};
-
struct thumb_32bit_insn_reloc_visitor
{
int (*alu_imm) (uint16_t insn1, uint16_t insn2,
@@ -6525,375 +6504,6 @@ arm_copy_unpred (uint32_t insn, struct arm_insn_reloc_data *data)
/* The decode_* functions are instruction decoding helpers. They mostly follow
the presentation in the ARM ARM. */

-static int
-arm_decode_misc_memhint_neon (uint32_t insn,
- struct arm_insn_reloc_visitor *visitor,
- struct arm_insn_reloc_data *data)
-{
- unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7);
- unsigned int rn = bits (insn, 16, 19);
-
- if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0xe) == 0x0)
- return visitor->others (insn, "cps", data);
- else if (op1 == 0x10 && op2 == 0x0 && (rn & 0xe) == 0x1)
- return visitor->others (insn, "setend", data);
- else if ((op1 & 0x60) == 0x20)
- return visitor->others (insn, "neon dataproc", data);
- else if ((op1 & 0x71) == 0x40)
- return visitor->others (insn, "neon elt/struct load/store", data);
- else if ((op1 & 0x77) == 0x41)
- return visitor->others (insn, "unallocated mem hint", data);
- else if ((op1 & 0x77) == 0x45)
- return visitor->preload (insn, data); /* pli. */
- else if ((op1 & 0x77) == 0x51)
- {
- if (rn != 0xf)
- return visitor->preload (insn, data); /* pld/pldw. */
- else
- return visitor->unpred (insn, data);
- }
- else if ((op1 & 0x77) == 0x55)
- return visitor->preload (insn, data); /* pld/pldw. */
- else if (op1 == 0x57)
- switch (op2)
- {
- case 0x1: return visitor->others (insn, "clrex", data);
- case 0x4: return visitor->others (insn, "dsb", data);
- case 0x5: return visitor->others (insn, "dmb", data);
- case 0x6: return visitor->others (insn, "isb", data);
- default: return visitor->unpred (insn, data);
- }
- else if ((op1 & 0x63) == 0x43)
- return visitor->unpred (insn, data);
- else if ((op2 & 0x1) == 0x0)
- switch (op1 & ~0x80)
- {
- case 0x61:
- return visitor->others (insn, "unallocated mem hint", data);
- case 0x65:
- return visitor->preload_reg (insn, data); /* pli reg. */
- case 0x71: case 0x75:
- /* pld/pldw reg. */
- return visitor->preload_reg (insn, data);
- case 0x63: case 0x67: case 0x73: case 0x77:
- return visitor->unpred (insn, data);
- default:
- return visitor->undef (insn, data);
- }
- else
- return visitor->undef (insn, data); /* Probably unreachable. */
-}
-
-static int
-arm_decode_unconditional (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
- struct arm_insn_reloc_data *data)
-{
- if (bit (insn, 27) == 0)
- return arm_decode_misc_memhint_neon (insn, visitor, data);
- /* Switch on bits: 0bxxxxx321xxx0xxxxxxxxxxxxxxxxxxxx. */
- else switch (((insn & 0x7000000) >> 23) | ((insn & 0x100000) >> 20))
- {
- case 0x0: case 0x2:
- return visitor->others (insn, "srs", data);
-
- case 0x1: case 0x3:
- return visitor->others (insn, "rfe", data);
-
- case 0x4: case 0x5: case 0x6: case 0x7:
- return visitor->b_bl_blx (insn, data);
-
- case 0x8:
- switch ((insn & 0xe00000) >> 21)
- {
- case 0x1: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
- /* stc/stc2. */
- return visitor->copro_load_store (insn, data);
-
- case 0x2:
- return visitor->others (insn, "mcrr/mcrr2", data);
-
- default:
- return visitor->undef (insn, data);
- }
-
- case 0x9:
- {
- int rn_f = (bits (insn, 16, 19) == 0xf);
- switch ((insn & 0xe00000) >> 21)
- {
- case 0x1: case 0x3:
- /* ldc/ldc2 imm (undefined for rn == pc). */
- return rn_f ? visitor->undef (insn, data)
- : visitor->copro_load_store (insn, data);
-
- case 0x2:
- return visitor->others (insn, "mrrc/mrrc2", data);
-
- case 0x4: case 0x5: case 0x6: case 0x7:
- /* ldc/ldc2 lit (undefined for rn != pc). */
- return rn_f ? visitor->copro_load_store (insn, data)
- : visitor->undef (insn, data);
-
- default:
- return visitor->undef (insn, data);
- }
- }
-
- case 0xa:
- return visitor->others (insn, "stc/stc2", data);
-
- case 0xb:
- if (bits (insn, 16, 19) == 0xf)
- /* ldc/ldc2 lit. */
- return visitor->copro_load_store (insn, data);
- else
- return visitor->undef (insn, data);
-
- case 0xc:
- if (bit (insn, 4))
- return visitor->others (insn, "mcr/mcr2", data);
- else
- return visitor->others (insn, "cdp/cdp2", data);
-
- case 0xd:
- if (bit (insn, 4))
- return visitor->others (insn, "mrc/mrc2", data);
- else
- return visitor->others (insn, "cdp/cdp2", data);
-
- default:
- return visitor->undef (insn, data);
- }
-}
-
-/* Decode miscellaneous instructions in dp/misc encoding space. */
-
-static int
-arm_decode_miscellaneous (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
- struct arm_insn_reloc_data *data)
-{
- unsigned int op2 = bits (insn, 4, 6);
- unsigned int op = bits (insn, 21, 22);
-
- switch (op2)
- {
- case 0x0:
- return visitor->others (insn, "mrs/msr", data);
-
- case 0x1:
- if (op == 0x1) /* bx. */
- return visitor->bx_blx_reg (insn, data);
- else if (op == 0x3)
- return visitor->others (insn, "clz", data);
- else
- return visitor->undef (insn, data);
-
- case 0x2:
- if (op == 0x1)
- /* Not really supported. */
- return visitor->others (insn, "bxj", data);
- else
- return visitor->undef (insn, data);
-
- case 0x3:
- if (op == 0x1)
- return visitor->bx_blx_reg (insn, data); /* blx register. */
- else
- return visitor->undef (insn, data);
-
- case 0x5:
- return visitor->others (insn, "saturating add/sub", data);
-
- case 0x7:
- if (op == 0x1)
- return visitor->others (insn, "bkpt", data);
- else if (op == 0x3)
- /* Not really supported. */
- return visitor->others (insn, "smc", data);
-
- default:
- return visitor->undef (insn, data);
- }
-}
-
-static int
-arm_decode_dp_misc (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
- struct arm_insn_reloc_data *data)
-{
- if (bit (insn, 25))
- switch (bits (insn, 20, 24))
- {
- case 0x10:
- return visitor->others (insn, "movw", data);
-
- case 0x14:
- return visitor->others (insn, "movt", data);
-
- case 0x12:
- case 0x16:
- return visitor->others (insn, "msr imm", data);
-
- default:
- return visitor->alu_imm (insn, data);
- }
- else
- {
- uint32_t op1 = bits (insn, 20, 24), op2 = bits (insn, 4, 7);
-
- if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0x0)
- return visitor->alu_reg (insn, data);
- else if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1)
- return visitor->alu_shifted_reg (insn, data);
- else if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0x0)
- return arm_decode_miscellaneous (insn, visitor, data);
- else if ((op1 & 0x19) == 0x10 && (op2 & 0x9) == 0x8)
- return visitor->others (insn, "halfword mul/mla", data);
- else if ((op1 & 0x10) == 0x00 && op2 == 0x9)
- return visitor->others (insn, "mul/mla", data);
- else if ((op1 & 0x10) == 0x10 && op2 == 0x9)
- return visitor->others (insn, "synch", data);
- else if (op2 == 0xb || (op2 & 0xd) == 0xd)
- /* 2nd arg means "unprivileged". */
- return visitor->extra_ld_st (insn, data, (op1 & 0x12) == 0x02);
- }
-
- /* Should be unreachable. */
- return 1;
-}
-
-static int
-arm_decode_ld_st_word_ubyte (uint32_t insn,
- struct arm_insn_reloc_visitor *visitor,
- struct arm_insn_reloc_data *data)
-{
- int a = bit (insn, 25), b = bit (insn, 4);
- uint32_t op1 = bits (insn, 20, 24);
-
- if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02)
- || (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b))
- return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 0);
- else if ((!a && (op1 & 0x17) == 0x02)
- || (a && (op1 & 0x17) == 0x02 && !b))
- return visitor->ldr_str_ldrb_strb (insn, data, 0, 4, 1);
- else if ((!a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03)
- || (a && (op1 & 0x05) == 0x01 && (op1 & 0x17) != 0x03 && !b))
- return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 0);
- else if ((!a && (op1 & 0x17) == 0x03)
- || (a && (op1 & 0x17) == 0x03 && !b))
- return visitor->ldr_str_ldrb_strb (insn, data, 1, 4, 1);
- else if ((!a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06)
- || (a && (op1 & 0x05) == 0x04 && (op1 & 0x17) != 0x06 && !b))
- return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 0);
- else if ((!a && (op1 & 0x17) == 0x06)
- || (a && (op1 & 0x17) == 0x06 && !b))
- return visitor->ldr_str_ldrb_strb (insn, data, 0, 1, 1);
- else if ((!a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07)
- || (a && (op1 & 0x05) == 0x05 && (op1 & 0x17) != 0x07 && !b))
- return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 0);
- else if ((!a && (op1 & 0x17) == 0x07)
- || (a && (op1 & 0x17) == 0x07 && !b))
- return visitor->ldr_str_ldrb_strb (insn, data, 1, 1, 1);
-
- /* Should be unreachable. */
- return 1;
-}
-
-static int
-arm_decode_media (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
- struct arm_insn_reloc_data *data)
-{
- switch (bits (insn, 20, 24))
- {
- case 0x00: case 0x01: case 0x02: case 0x03:
- return visitor->others (insn, "parallel add/sub signed", data);
-
- case 0x04: case 0x05: case 0x06: case 0x07:
- return visitor->others (insn, "parallel add/sub unsigned", data);
-
- case 0x08: case 0x09: case 0x0a: case 0x0b:
- case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- return visitor->others (insn, "decode/pack/unpack/saturate/reverse",
- data);
-
- case 0x18:
- if (bits (insn, 5, 7) == 0) /* op2. */
- {
- if (bits (insn, 12, 15) == 0xf)
- return visitor->others (insn, "usad8", data);
- else
- return visitor->others (insn, "usada8", data);
- }
- else
- return visitor->undef (insn, data);
-
- case 0x1a: case 0x1b:
- if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */
- return visitor->others (insn, "sbfx", data);
- else
- return visitor->undef (insn, data);
-
- case 0x1c: case 0x1d:
- if (bits (insn, 5, 6) == 0x0) /* op2[1:0]. */
- {
- if (bits (insn, 0, 3) == 0xf)
- return visitor->others (insn, "bfc", data);
- else
- return visitor->others (insn, "bfi", data);
- }
- else
- return visitor->undef (insn, data);
-
- case 0x1e: case 0x1f:
- if (bits (insn, 5, 6) == 0x2) /* op2[1:0]. */
- return visitor->others (insn, "ubfx", data);
- else
- return visitor->undef (insn, data);
- }
-
- /* Should be unreachable. */
- return 1;
-}
-
-static int
-arm_decode_b_bl_ldmstm (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
- struct arm_insn_reloc_data *data)
-{
- if (bit (insn, 25))
- return visitor->b_bl_blx (insn, data);
- else
- return visitor->block_xfer (insn, data);
-}
-
-static int
-arm_decode_ext_reg_ld_st (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
- struct arm_insn_reloc_data *data)
-{
- unsigned int opcode = bits (insn, 20, 24);
-
- switch (opcode)
- {
- case 0x04: case 0x05: /* VFP/Neon mrrc/mcrr. */
- return visitor->others (insn, "vfp/neon mrrc/mcrr", data);
-
- case 0x08: case 0x0a: case 0x0c: case 0x0e:
- case 0x12: case 0x16:
- return visitor->others (insn, "vfp/neon vstm/vpush", data);
-
- case 0x09: case 0x0b: case 0x0d: case 0x0f:
- case 0x13: case 0x17:
- return visitor->others (insn, "vfp/neon vldm/vpop", data);
-
- case 0x10: case 0x14: case 0x18: case 0x1c: /* vstr. */
- case 0x11: case 0x15: case 0x19: case 0x1d: /* vldr. */
- /* Note: no writeback for these instructions. Bit 25 will always be
- zero though (via caller), so the following works OK. */
- return visitor->copro_load_store (insn, data);
- }
-
- /* Should be unreachable. */
- return 1;
-}
-
/* Decode shifted register instructions. */

static int
@@ -6949,51 +6559,6 @@ thumb2_decode_ext_reg_ld_st (uint16_t insn1, uint16_t insn2,
}

static int
-arm_decode_svc_copro (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
- struct arm_insn_reloc_data *data)
-{
- unsigned int op1 = bits (insn, 20, 25);
- int op = bit (insn, 4);
- unsigned int coproc = bits (insn, 8, 11);
-
- if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa)
- return arm_decode_ext_reg_ld_st (insn, visitor, data);
- else if ((op1 & 0x21) == 0x00 && (op1 & 0x3a) != 0x00
- && (coproc & 0xe) != 0xa)
- /* stc/stc2. */
- return visitor->copro_load_store (insn, data);
- else if ((op1 & 0x21) == 0x01 && (op1 & 0x3a) != 0x00
- && (coproc & 0xe) != 0xa)
- /* ldc/ldc2 imm/lit. */
- return visitor->copro_load_store (insn, data);
- else if ((op1 & 0x3e) == 0x00)
- return visitor->undef (insn, data);
- else if ((op1 & 0x3e) == 0x04 && (coproc & 0xe) == 0xa)
- return visitor->others (insn, "neon 64bit xfer", data);
- else if (op1 == 0x04 && (coproc & 0xe) != 0xa)
- return visitor->others (insn, "mcrr/mcrr2", data);
- else if (op1 == 0x05 && (coproc & 0xe) != 0xa)
- return visitor->others (insn, "mrrc/mrrc2", data);
- else if ((op1 & 0x30) == 0x20 && !op)
- {
- if ((coproc & 0xe) == 0xa)
- return visitor->others (insn, "vfp dataproc", data);
- else
- return visitor->others (insn, "cdp/cdp2", data);
- }
- else if ((op1 & 0x30) == 0x20 && op)
- return visitor->others (insn, "neon 8/16/32 bit xfer", data);
- else if ((op1 & 0x31) == 0x20 && op && (coproc & 0xe) != 0xa)
- return visitor->others (insn, "mcr/mcr2", data);
- else if ((op1 & 0x31) == 0x21 && op && (coproc & 0xe) != 0xa)
- return visitor->others (insn, "mrc/mrc2", data);
- else if ((op1 & 0x30) == 0x30)
- return visitor->svc (insn, data);
- else
- return visitor->undef (insn, data); /* Possibly unreachable. */
-}
-
-static int
thumb2_decode_svc_copro (uint16_t insn1, uint16_t insn2,
struct thumb_32bit_insn_reloc_visitor *visitor,
struct arm_insn_reloc_data *data)
@@ -7614,40 +7179,6 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,

}

-static int
-arm_relocate_insn (uint32_t insn, struct arm_insn_reloc_visitor *visitor,
- struct arm_insn_reloc_data *data)
-{
- int err = 1;
-
- if ((insn & 0xf0000000) == 0xf0000000)
- err = arm_decode_unconditional (insn, visitor, data);
- else switch (((insn & 0x10) >> 4) | ((insn & 0xe000000) >> 24))
- {
- case 0x0: case 0x1: case 0x2: case 0x3:
- err = arm_decode_dp_misc (insn, visitor, data);
- break;
-
- case 0x4: case 0x5: case 0x6:
- err = arm_decode_ld_st_word_ubyte (insn, visitor, data);
- break;
-
- case 0x7:
- err = arm_decode_media (insn, visitor, data);
- break;
-
- case 0x8: case 0x9: case 0xa: case 0xb:
- err = arm_decode_b_bl_ldmstm (insn, visitor, data);
- break;
-
- case 0xc: case 0xd: case 0xe: case 0xf:
- err = arm_decode_svc_copro (insn, visitor, data);
- break;
- }
-
- return err;
-}
-
static struct arm_insn_reloc_visitor arm_insn_reloc_visitor =
{
arm_copy_alu_imm,
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index cd8e05d..b33d76d 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -91,7 +91,7 @@ arm*-wince-pe | arm*-*-mingw32ce*)
;;
arm*-*-linux*)
# Target: ARM based machine running GNU/Linux
- gdb_target_obs="arm.o arm-linux.o arm-get-next-pcs.o arm-tdep.o \
+ gdb_target_obs="arm.o arm-linux.o arm-get-next-pcs.o arm-insn-reloc.o arm-tdep.o \
arm-linux-tdep.o glibc-tdep.o \
solib-svr4.o symfile-mem.o linux-tdep.o linux-record.o"
build_gdbserver=yes
--
2.8.1