ARM: probes: move all probe code to dedicate directory
authorWang Nan <wangnan0@huawei.com>
Fri, 9 Jan 2015 02:19:49 +0000 (10:19 +0800)
committerJon Medhurst <tixy@linaro.org>
Fri, 9 Jan 2015 09:36:50 +0000 (09:36 +0000)
In discussion on LKML (https://lkml.org/lkml/2014/11/28/158), Russell
King suggests to move all probe related code to arch/arm/probes. This
patch does the work. Due to dependency on 'arch/arm/kernel/patch.h', this
patch also moves patch.h to 'arch/arm/include/asm/patch.h', and related
'#include' directives are also midified to '#include <asm/patch.h>'.

Following is an overview of this patch:

 ./arch/arm/kernel/               ./arch/arm/probes/
 |-- Makefile                     |-- Makefile
 |-- probes-arm.c          ==>    |-- decode-arm.c
 |-- probes-arm.h          ==>    |-- decode-arm.h
 |-- probes-thumb.c        ==>    |-- decode-thumb.c
 |-- probes-thumb.h        ==>    |-- decode-thumb.h
 |-- probes.c              ==>    |-- decode.c
 |-- probes.h              ==>    |-- decode.h
 |                                |-- kprobes
 |                                |   |-- Makefile
 |-- kprobes-arm.c         ==>    |   |-- actions-arm.c
 |-- kprobes-common.c      ==>    |   |-- actions-common.c
 |-- kprobes-thumb.c       ==>    |   |-- actions-thumb.c
 |-- kprobes.c             ==>    |   |-- core.c
 |-- kprobes.h             ==>    |   |-- core.h
 |-- kprobes-test-arm.c    ==>    |   |-- test-arm.c
 |-- kprobes-test.c        ==>    |   |-- test-core.c
 |-- kprobes-test.h        ==>    |   |-- test-core.h
 |-- kprobes-test-thumb.c  ==>    |   `-- test-thumb.c
 |                                `-- uprobes
 |                                    |-- Makefile
 |-- uprobes-arm.c         ==>        |-- actions-arm.c
 |-- uprobes.c             ==>        |-- core.c
 |-- uprobes.h             ==>        `-- core.h
 |
 `-- patch.h               ==>    arch/arm/include/asm/patch.h

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Jon Medhurst <tixy@linaro.org>
46 files changed:
arch/arm/Makefile
arch/arm/include/asm/patch.h [new file with mode: 0644]
arch/arm/kernel/Makefile
arch/arm/kernel/jump_label.c
arch/arm/kernel/kgdb.c
arch/arm/kernel/kprobes-arm.c [deleted file]
arch/arm/kernel/kprobes-common.c [deleted file]
arch/arm/kernel/kprobes-test-arm.c [deleted file]
arch/arm/kernel/kprobes-test-thumb.c [deleted file]
arch/arm/kernel/kprobes-test.c [deleted file]
arch/arm/kernel/kprobes-test.h [deleted file]
arch/arm/kernel/kprobes-thumb.c [deleted file]
arch/arm/kernel/kprobes.c [deleted file]
arch/arm/kernel/kprobes.h [deleted file]
arch/arm/kernel/patch.c
arch/arm/kernel/patch.h [deleted file]
arch/arm/kernel/probes-arm.c [deleted file]
arch/arm/kernel/probes-arm.h [deleted file]
arch/arm/kernel/probes-thumb.c [deleted file]
arch/arm/kernel/probes-thumb.h [deleted file]
arch/arm/kernel/probes.c [deleted file]
arch/arm/kernel/probes.h [deleted file]
arch/arm/kernel/uprobes-arm.c [deleted file]
arch/arm/kernel/uprobes.c [deleted file]
arch/arm/kernel/uprobes.h [deleted file]
arch/arm/probes/Makefile [new file with mode: 0644]
arch/arm/probes/decode-arm.c [new file with mode: 0644]
arch/arm/probes/decode-arm.h [new file with mode: 0644]
arch/arm/probes/decode-thumb.c [new file with mode: 0644]
arch/arm/probes/decode-thumb.h [new file with mode: 0644]
arch/arm/probes/decode.c [new file with mode: 0644]
arch/arm/probes/decode.h [new file with mode: 0644]
arch/arm/probes/kprobes/Makefile [new file with mode: 0644]
arch/arm/probes/kprobes/actions-arm.c [new file with mode: 0644]
arch/arm/probes/kprobes/actions-common.c [new file with mode: 0644]
arch/arm/probes/kprobes/actions-thumb.c [new file with mode: 0644]
arch/arm/probes/kprobes/core.c [new file with mode: 0644]
arch/arm/probes/kprobes/core.h [new file with mode: 0644]
arch/arm/probes/kprobes/test-arm.c [new file with mode: 0644]
arch/arm/probes/kprobes/test-core.c [new file with mode: 0644]
arch/arm/probes/kprobes/test-core.h [new file with mode: 0644]
arch/arm/probes/kprobes/test-thumb.c [new file with mode: 0644]
arch/arm/probes/uprobes/Makefile [new file with mode: 0644]
arch/arm/probes/uprobes/actions-arm.c [new file with mode: 0644]
arch/arm/probes/uprobes/core.c [new file with mode: 0644]
arch/arm/probes/uprobes/core.h [new file with mode: 0644]

index c1785eec2cf772e582b48fade2b7694748d381cb..7f99cd652203ce5705b22f5f0fc24f0574a82840 100644 (file)
@@ -266,6 +266,7 @@ core-$(CONFIG_KVM_ARM_HOST)         += arch/arm/kvm/
 
 # If we have a machine-specific directory, then include it in the build.
 core-y                         += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
+core-y                         += arch/arm/probes/
 core-y                         += arch/arm/net/
 core-y                         += arch/arm/crypto/
 core-y                         += arch/arm/firmware/
diff --git a/arch/arm/include/asm/patch.h b/arch/arm/include/asm/patch.h
new file mode 100644 (file)
index 0000000..77e054c
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _ARM_KERNEL_PATCH_H
+#define _ARM_KERNEL_PATCH_H
+
+void patch_text(void *addr, unsigned int insn);
+void __patch_text_real(void *addr, unsigned int insn, bool remap);
+
+static inline void __patch_text(void *addr, unsigned int insn)
+{
+       __patch_text_real(addr, insn, true);
+}
+
+static inline void __patch_text_early(void *addr, unsigned int insn)
+{
+       __patch_text_real(addr, insn, false);
+}
+
+#endif
index fb2b71ebe3f22a2823107d5d7317693141ba3cdc..9c51a433e0255246e2fdd2553c78ad739ca0d2de 100644 (file)
@@ -51,20 +51,8 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)    += ftrace.o insn.o
 obj-$(CONFIG_JUMP_LABEL)       += jump_label.o insn.o patch.o
 obj-$(CONFIG_KEXEC)            += machine_kexec.o relocate_kernel.o
-obj-$(CONFIG_UPROBES)          += probes.o probes-arm.o uprobes.o uprobes-arm.o
-obj-$(CONFIG_KPROBES)          += probes.o kprobes.o kprobes-common.o patch.o
-ifdef CONFIG_THUMB2_KERNEL
-obj-$(CONFIG_KPROBES)          += kprobes-thumb.o probes-thumb.o
-else
-obj-$(CONFIG_KPROBES)          += kprobes-arm.o probes-arm.o
-endif
-obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
-test-kprobes-objs              := kprobes-test.o
-ifdef CONFIG_THUMB2_KERNEL
-test-kprobes-objs              += kprobes-test-thumb.o
-else
-test-kprobes-objs              += kprobes-test-arm.o
-endif
+# Main staffs in KPROBES are in arch/arm/probes/ .
+obj-$(CONFIG_KPROBES)          += patch.o
 obj-$(CONFIG_OABI_COMPAT)      += sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)      += thumbee.o
 obj-$(CONFIG_KGDB)             += kgdb.o patch.o
index afeeb9ea6f439ebeb515bdea4b3acf0962a5b687..d8da075959bf384a3a1303e0bb8ac76d562d83ae 100644 (file)
@@ -1,8 +1,8 @@
 #include <linux/kernel.h>
 #include <linux/jump_label.h>
+#include <asm/patch.h>
 
 #include "insn.h"
-#include "patch.h"
 
 #ifdef HAVE_JUMP_LABEL
 
index 07db2f8a1b4505b09eb4633488d7167bb695f669..a6ad93c9bce35ea33185bbb5abb2e61867a09173 100644 (file)
 #include <linux/kgdb.h>
 #include <linux/uaccess.h>
 
+#include <asm/patch.h>
 #include <asm/traps.h>
 
-#include "patch.h"
-
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
 {
        { "r0", 4, offsetof(struct pt_regs, ARM_r0)},
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c
deleted file mode 100644 (file)
index ac300c6..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * arch/arm/kernel/kprobes-decode.c
- *
- * Copyright (C) 2006, 2007 Motorola Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-/*
- * We do not have hardware single-stepping on ARM, This
- * effort is further complicated by the ARM not having a
- * "next PC" register.  Instructions that change the PC
- * can't be safely single-stepped in a MP environment, so
- * we have a lot of work to do:
- *
- * In the prepare phase:
- *   *) If it is an instruction that does anything
- *      with the CPU mode, we reject it for a kprobe.
- *      (This is out of laziness rather than need.  The
- *      instructions could be simulated.)
- *
- *   *) Otherwise, decode the instruction rewriting its
- *      registers to take fixed, ordered registers and
- *      setting a handler for it to run the instruction.
- *
- * In the execution phase by an instruction's handler:
- *
- *   *) If the PC is written to by the instruction, the
- *      instruction must be fully simulated in software.
- *
- *   *) Otherwise, a modified form of the instruction is
- *      directly executed.  Its handler calls the
- *      instruction in insn[0].  In insn[1] is a
- *      "mov pc, lr" to return.
- *
- *      Before calling, load up the reordered registers
- *      from the original instruction's registers.  If one
- *      of the original input registers is the PC, compute
- *      and adjust the appropriate input register.
- *
- *     After call completes, copy the output registers to
- *      the original instruction's original registers.
- *
- * We don't use a real breakpoint instruction since that
- * would have us in the kernel go from SVC mode to SVC
- * mode losing the link register.  Instead we use an
- * undefined instruction.  To simplify processing, the
- * undefined instruction used for kprobes must be reserved
- * exclusively for kprobes use.
- *
- * TODO: ifdef out some instruction decoding based on architecture.
- */
-
-#include <linux/kernel.h>
-#include <linux/kprobes.h>
-#include <linux/ptrace.h>
-
-#include "kprobes.h"
-#include "probes-arm.h"
-
-#if  __LINUX_ARM_ARCH__ >= 6
-#define BLX(reg)       "blx    "reg"           \n\t"
-#else
-#define BLX(reg)       "mov    lr, pc          \n\t"   \
-                       "mov    pc, "reg"       \n\t"
-#endif
-
-static void __kprobes
-emulate_ldrdstrd(probes_opcode_t insn,
-       struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc + 4;
-       int rt = (insn >> 12) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-       int rm = insn & 0xf;
-
-       register unsigned long rtv asm("r0") = regs->uregs[rt];
-       register unsigned long rt2v asm("r1") = regs->uregs[rt+1];
-       register unsigned long rnv asm("r2") = (rn == 15) ? pc
-                                                         : regs->uregs[rn];
-       register unsigned long rmv asm("r3") = regs->uregs[rm];
-
-       __asm__ __volatile__ (
-               BLX("%[fn]")
-               : "=r" (rtv), "=r" (rt2v), "=r" (rnv)
-               : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
-                 [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rt] = rtv;
-       regs->uregs[rt+1] = rt2v;
-       if (is_writeback(insn))
-               regs->uregs[rn] = rnv;
-}
-
-static void __kprobes
-emulate_ldr(probes_opcode_t insn,
-       struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc + 4;
-       int rt = (insn >> 12) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-       int rm = insn & 0xf;
-
-       register unsigned long rtv asm("r0");
-       register unsigned long rnv asm("r2") = (rn == 15) ? pc
-                                                         : regs->uregs[rn];
-       register unsigned long rmv asm("r3") = regs->uregs[rm];
-
-       __asm__ __volatile__ (
-               BLX("%[fn]")
-               : "=r" (rtv), "=r" (rnv)
-               : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       if (rt == 15)
-               load_write_pc(rtv, regs);
-       else
-               regs->uregs[rt] = rtv;
-
-       if (is_writeback(insn))
-               regs->uregs[rn] = rnv;
-}
-
-static void __kprobes
-emulate_str(probes_opcode_t insn,
-       struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset;
-       unsigned long rnpc = regs->ARM_pc + 4;
-       int rt = (insn >> 12) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-       int rm = insn & 0xf;
-
-       register unsigned long rtv asm("r0") = (rt == 15) ? rtpc
-                                                         : regs->uregs[rt];
-       register unsigned long rnv asm("r2") = (rn == 15) ? rnpc
-                                                         : regs->uregs[rn];
-       register unsigned long rmv asm("r3") = regs->uregs[rm];
-
-       __asm__ __volatile__ (
-               BLX("%[fn]")
-               : "=r" (rnv)
-               : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       if (is_writeback(insn))
-               regs->uregs[rn] = rnv;
-}
-
-static void __kprobes
-emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
-       struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc + 4;
-       int rd = (insn >> 12) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-       int rm = insn & 0xf;
-       int rs = (insn >> 8) & 0xf;
-
-       register unsigned long rdv asm("r0") = regs->uregs[rd];
-       register unsigned long rnv asm("r2") = (rn == 15) ? pc
-                                                         : regs->uregs[rn];
-       register unsigned long rmv asm("r3") = (rm == 15) ? pc
-                                                         : regs->uregs[rm];
-       register unsigned long rsv asm("r1") = regs->uregs[rs];
-       unsigned long cpsr = regs->ARM_cpsr;
-
-       __asm__ __volatile__ (
-               "msr    cpsr_fs, %[cpsr]        \n\t"
-               BLX("%[fn]")
-               "mrs    %[cpsr], cpsr           \n\t"
-               : "=r" (rdv), [cpsr] "=r" (cpsr)
-               : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
-                 "1" (cpsr), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       if (rd == 15)
-               alu_write_pc(rdv, regs);
-       else
-               regs->uregs[rd] = rdv;
-       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
-}
-
-static void __kprobes
-emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn,
-       struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       int rd = (insn >> 12) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-       int rm = insn & 0xf;
-
-       register unsigned long rdv asm("r0") = regs->uregs[rd];
-       register unsigned long rnv asm("r2") = regs->uregs[rn];
-       register unsigned long rmv asm("r3") = regs->uregs[rm];
-       unsigned long cpsr = regs->ARM_cpsr;
-
-       __asm__ __volatile__ (
-               "msr    cpsr_fs, %[cpsr]        \n\t"
-               BLX("%[fn]")
-               "mrs    %[cpsr], cpsr           \n\t"
-               : "=r" (rdv), [cpsr] "=r" (cpsr)
-               : "0" (rdv), "r" (rnv), "r" (rmv),
-                 "1" (cpsr), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rd] = rdv;
-       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
-}
-
-static void __kprobes
-emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn,
-       struct arch_probes_insn *asi,
-       struct pt_regs *regs)
-{
-       int rd = (insn >> 16) & 0xf;
-       int rn = (insn >> 12) & 0xf;
-       int rm = insn & 0xf;
-       int rs = (insn >> 8) & 0xf;
-
-       register unsigned long rdv asm("r2") = regs->uregs[rd];
-       register unsigned long rnv asm("r0") = regs->uregs[rn];
-       register unsigned long rmv asm("r3") = regs->uregs[rm];
-       register unsigned long rsv asm("r1") = regs->uregs[rs];
-       unsigned long cpsr = regs->ARM_cpsr;
-
-       __asm__ __volatile__ (
-               "msr    cpsr_fs, %[cpsr]        \n\t"
-               BLX("%[fn]")
-               "mrs    %[cpsr], cpsr           \n\t"
-               : "=r" (rdv), [cpsr] "=r" (cpsr)
-               : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
-                 "1" (cpsr), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rd] = rdv;
-       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
-}
-
-static void __kprobes
-emulate_rd12rm0_noflags_nopc(probes_opcode_t insn,
-       struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       int rd = (insn >> 12) & 0xf;
-       int rm = insn & 0xf;
-
-       register unsigned long rdv asm("r0") = regs->uregs[rd];
-       register unsigned long rmv asm("r3") = regs->uregs[rm];
-
-       __asm__ __volatile__ (
-               BLX("%[fn]")
-               : "=r" (rdv)
-               : "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rd] = rdv;
-}
-
-static void __kprobes
-emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
-       struct arch_probes_insn *asi,
-       struct pt_regs *regs)
-{
-       int rdlo = (insn >> 12) & 0xf;
-       int rdhi = (insn >> 16) & 0xf;
-       int rn = insn & 0xf;
-       int rm = (insn >> 8) & 0xf;
-
-       register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
-       register unsigned long rdhiv asm("r2") = regs->uregs[rdhi];
-       register unsigned long rnv asm("r3") = regs->uregs[rn];
-       register unsigned long rmv asm("r1") = regs->uregs[rm];
-       unsigned long cpsr = regs->ARM_cpsr;
-
-       __asm__ __volatile__ (
-               "msr    cpsr_fs, %[cpsr]        \n\t"
-               BLX("%[fn]")
-               "mrs    %[cpsr], cpsr           \n\t"
-               : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr)
-               : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
-                 "2" (cpsr), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rdlo] = rdlov;
-       regs->uregs[rdhi] = rdhiv;
-       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
-}
-
-const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
-       [PROBES_EMULATE_NONE] = {.handler = probes_emulate_none},
-       [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
-       [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
-       [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
-       [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
-       [PROBES_MRS] = {.handler = simulate_mrs},
-       [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
-       [PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc},
-       [PROBES_SATURATING_ARITHMETIC] = {
-               .handler = emulate_rd12rn16rm0_rwflags_nopc},
-       [PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
-       [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
-       [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
-       [PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd},
-       [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr},
-       [PROBES_LOAD] = {.handler = emulate_ldr},
-       [PROBES_STORE_EXTRA] = {.handler = emulate_str},
-       [PROBES_STORE] = {.handler = emulate_str},
-       [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
-       [PROBES_DATA_PROCESSING_REG] = {
-               .handler = emulate_rd12rn16rm0rs8_rwflags},
-       [PROBES_DATA_PROCESSING_IMM] = {
-               .handler = emulate_rd12rn16rm0rs8_rwflags},
-       [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc},
-       [PROBES_SEV] = {.handler = probes_emulate_none},
-       [PROBES_WFE] = {.handler = probes_simulate_nop},
-       [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
-       [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc},
-       [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
-       [PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
-       [PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc},
-       [PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
-       [PROBES_MUL_ADD_LONG] = {
-               .handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
-       [PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
-       [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc},
-       [PROBES_BRANCH] = {.handler = simulate_bbl},
-       [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
-};
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c
deleted file mode 100644 (file)
index 0bf5d64..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * arch/arm/kernel/kprobes-common.c
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
- * Copyright (C) 2006, 2007 Motorola Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/kprobes.h>
-#include <asm/opcodes.h>
-
-#include "kprobes.h"
-
-
-static void __kprobes simulate_ldm1stm1(probes_opcode_t insn,
-               struct arch_probes_insn *asi,
-               struct pt_regs *regs)
-{
-       int rn = (insn >> 16) & 0xf;
-       int lbit = insn & (1 << 20);
-       int wbit = insn & (1 << 21);
-       int ubit = insn & (1 << 23);
-       int pbit = insn & (1 << 24);
-       long *addr = (long *)regs->uregs[rn];
-       int reg_bit_vector;
-       int reg_count;
-
-       reg_count = 0;
-       reg_bit_vector = insn & 0xffff;
-       while (reg_bit_vector) {
-               reg_bit_vector &= (reg_bit_vector - 1);
-               ++reg_count;
-       }
-
-       if (!ubit)
-               addr -= reg_count;
-       addr += (!pbit == !ubit);
-
-       reg_bit_vector = insn & 0xffff;
-       while (reg_bit_vector) {
-               int reg = __ffs(reg_bit_vector);
-               reg_bit_vector &= (reg_bit_vector - 1);
-               if (lbit)
-                       regs->uregs[reg] = *addr++;
-               else
-                       *addr++ = regs->uregs[reg];
-       }
-
-       if (wbit) {
-               if (!ubit)
-                       addr -= reg_count;
-               addr -= (!pbit == !ubit);
-               regs->uregs[rn] = (long)addr;
-       }
-}
-
-static void __kprobes simulate_stm1_pc(probes_opcode_t insn,
-       struct arch_probes_insn *asi,
-       struct pt_regs *regs)
-{
-       unsigned long addr = regs->ARM_pc - 4;
-
-       regs->ARM_pc = (long)addr + str_pc_offset;
-       simulate_ldm1stm1(insn, asi, regs);
-       regs->ARM_pc = (long)addr + 4;
-}
-
-static void __kprobes simulate_ldm1_pc(probes_opcode_t insn,
-       struct arch_probes_insn *asi,
-       struct pt_regs *regs)
-{
-       simulate_ldm1stm1(insn, asi, regs);
-       load_write_pc(regs->ARM_pc, regs);
-}
-
-static void __kprobes
-emulate_generic_r0_12_noflags(probes_opcode_t insn,
-       struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       register void *rregs asm("r1") = regs;
-       register void *rfn asm("lr") = asi->insn_fn;
-
-       __asm__ __volatile__ (
-               "stmdb  sp!, {%[regs], r11}     \n\t"
-               "ldmia  %[regs], {r0-r12}       \n\t"
-#if __LINUX_ARM_ARCH__ >= 6
-               "blx    %[fn]                   \n\t"
-#else
-               "str    %[fn], [sp, #-4]!       \n\t"
-               "adr    lr, 1f                  \n\t"
-               "ldr    pc, [sp], #4            \n\t"
-               "1:                             \n\t"
-#endif
-               "ldr    lr, [sp], #4            \n\t" /* lr = regs */
-               "stmia  lr, {r0-r12}            \n\t"
-               "ldr    r11, [sp], #4           \n\t"
-               : [regs] "=r" (rregs), [fn] "=r" (rfn)
-               : "0" (rregs), "1" (rfn)
-               : "r0", "r2", "r3", "r4", "r5", "r6", "r7",
-                 "r8", "r9", "r10", "r12", "memory", "cc"
-               );
-}
-
-static void __kprobes
-emulate_generic_r2_14_noflags(probes_opcode_t insn,
-       struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       emulate_generic_r0_12_noflags(insn, asi,
-               (struct pt_regs *)(regs->uregs+2));
-}
-
-static void __kprobes
-emulate_ldm_r3_15(probes_opcode_t insn,
-       struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       emulate_generic_r0_12_noflags(insn, asi,
-               (struct pt_regs *)(regs->uregs+3));
-       load_write_pc(regs->ARM_pc, regs);
-}
-
-enum probes_insn __kprobes
-kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
-               const struct decode_header *h)
-{
-       probes_insn_handler_t *handler = 0;
-       unsigned reglist = insn & 0xffff;
-       int is_ldm = insn & 0x100000;
-       int rn = (insn >> 16) & 0xf;
-
-       if (rn <= 12 && (reglist & 0xe000) == 0) {
-               /* Instruction only uses registers in the range R0..R12 */
-               handler = emulate_generic_r0_12_noflags;
-
-       } else if (rn >= 2 && (reglist & 0x8003) == 0) {
-               /* Instruction only uses registers in the range R2..R14 */
-               rn -= 2;
-               reglist >>= 2;
-               handler = emulate_generic_r2_14_noflags;
-
-       } else if (rn >= 3 && (reglist & 0x0007) == 0) {
-               /* Instruction only uses registers in the range R3..R15 */
-               if (is_ldm && (reglist & 0x8000)) {
-                       rn -= 3;
-                       reglist >>= 3;
-                       handler = emulate_ldm_r3_15;
-               }
-       }
-
-       if (handler) {
-               /* We can emulate the instruction in (possibly) modified form */
-               asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) |
-                                                  (rn << 16) | reglist);
-               asi->insn_handler = handler;
-               return INSN_GOOD;
-       }
-
-       /* Fallback to slower simulation... */
-       if (reglist & 0x8000)
-               handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
-       else
-               handler = simulate_ldm1stm1;
-       asi->insn_handler = handler;
-       return INSN_GOOD_NO_SLOT;
-}
-
diff --git a/arch/arm/kernel/kprobes-test-arm.c b/arch/arm/kernel/kprobes-test-arm.c
deleted file mode 100644 (file)
index cb14242..0000000
+++ /dev/null
@@ -1,1346 +0,0 @@
-/*
- * arch/arm/kernel/kprobes-test-arm.c
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/system_info.h>
-#include <asm/opcodes.h>
-
-#include "kprobes-test.h"
-
-
-#define TEST_ISA "32"
-
-#define TEST_ARM_TO_THUMB_INTERWORK_R(code1, reg, val, code2)  \
-       TESTCASE_START(code1 #reg code2)                        \
-       TEST_ARG_REG(reg, val)                                  \
-       TEST_ARG_REG(14, 99f)                                   \
-       TEST_ARG_END("")                                        \
-       "50:    nop                     \n\t"                   \
-       "1:     "code1 #reg code2"      \n\t"                   \
-       "       bx      lr              \n\t"                   \
-       ".thumb                         \n\t"                   \
-       "3:     adr     lr, 2f          \n\t"                   \
-       "       bx      lr              \n\t"                   \
-       ".arm                           \n\t"                   \
-       "2:     nop                     \n\t"                   \
-       TESTCASE_END
-
-#define TEST_ARM_TO_THUMB_INTERWORK_P(code1, reg, val, code2)  \
-       TESTCASE_START(code1 #reg code2)                        \
-       TEST_ARG_PTR(reg, val)                                  \
-       TEST_ARG_REG(14, 99f)                                   \
-       TEST_ARG_MEM(15, 3f+1)                                  \
-       TEST_ARG_END("")                                        \
-       "50:    nop                     \n\t"                   \
-       "1:     "code1 #reg code2"      \n\t"                   \
-       "       bx      lr              \n\t"                   \
-       ".thumb                         \n\t"                   \
-       "3:     adr     lr, 2f          \n\t"                   \
-       "       bx      lr              \n\t"                   \
-       ".arm                           \n\t"                   \
-       "2:     nop                     \n\t"                   \
-       TESTCASE_END
-
-
-void kprobe_arm_test_cases(void)
-{
-       kprobe_test_flags = 0;
-
-       TEST_GROUP("Data-processing (register), (register-shifted register), (immediate)")
-
-#define _DATA_PROCESSING_DNM(op,s,val)                                         \
-       TEST_RR(  op "eq" s "   r0,  r",1, VAL1,", r",2, val, "")               \
-       TEST_RR(  op "ne" s "   r1,  r",1, VAL1,", r",2, val, ", lsl #3")       \
-       TEST_RR(  op "cs" s "   r2,  r",3, VAL1,", r",2, val, ", lsr #4")       \
-       TEST_RR(  op "cc" s "   r3,  r",3, VAL1,", r",2, val, ", asr #5")       \
-       TEST_RR(  op "mi" s "   r4,  r",5, VAL1,", r",2, N(val),", asr #6")     \
-       TEST_RR(  op "pl" s "   r5,  r",5, VAL1,", r",2, val, ", ror #7")       \
-       TEST_RR(  op "vs" s "   r6,  r",7, VAL1,", r",2, val, ", rrx")          \
-       TEST_R(   op "vc" s "   r6,  r",7, VAL1,", pc, lsl #3")                 \
-       TEST_R(   op "vc" s "   r6,  r",7, VAL1,", sp, lsr #4")                 \
-       TEST_R(   op "vc" s "   r6,  pc, r",7, VAL1,", asr #5")                 \
-       TEST_R(   op "vc" s "   r6,  sp, r",7, VAL1,", ror #6")                 \
-       TEST_RRR( op "hi" s "   r8,  r",9, VAL1,", r",14,val, ", lsl r",0, 3,"")\
-       TEST_RRR( op "ls" s "   r9,  r",9, VAL1,", r",14,val, ", lsr r",7, 4,"")\
-       TEST_RRR( op "ge" s "   r10, r",11,VAL1,", r",14,val, ", asr r",7, 5,"")\
-       TEST_RRR( op "lt" s "   r11, r",11,VAL1,", r",14,N(val),", asr r",7, 6,"")\
-       TEST_RR(  op "gt" s "   r12, r13"       ", r",14,val, ", ror r",14,7,"")\
-       TEST_RR(  op "le" s "   r14, r",0, val, ", r13"       ", lsl r",14,8,"")\
-       TEST_R(   op "eq" s "   r0,  r",11,VAL1,", #0xf5")                      \
-       TEST_R(   op "ne" s "   r11, r",0, VAL1,", #0xf5000000")                \
-       TEST_R(   op s "        r7,  r",8, VAL2,", #0x000af000")                \
-       TEST(     op s "        r4,  pc"        ", #0x00005a00")
-
-#define DATA_PROCESSING_DNM(op,val)            \
-       _DATA_PROCESSING_DNM(op,"",val)         \
-       _DATA_PROCESSING_DNM(op,"s",val)
-
-#define DATA_PROCESSING_NM(op,val)                                             \
-       TEST_RR(  op "ne        r",1, VAL1,", r",2, val, "")                    \
-       TEST_RR(  op "eq        r",1, VAL1,", r",2, val, ", lsl #3")            \
-       TEST_RR(  op "cc        r",3, VAL1,", r",2, val, ", lsr #4")            \
-       TEST_RR(  op "cs        r",3, VAL1,", r",2, val, ", asr #5")            \
-       TEST_RR(  op "pl        r",5, VAL1,", r",2, N(val),", asr #6")          \
-       TEST_RR(  op "mi        r",5, VAL1,", r",2, val, ", ror #7")            \
-       TEST_RR(  op "vc        r",7, VAL1,", r",2, val, ", rrx")               \
-       TEST_R (  op "vs        r",7, VAL1,", pc, lsl #3")                      \
-       TEST_R (  op "vs        r",7, VAL1,", sp, lsr #4")                      \
-       TEST_R(   op "vs        pc, r",7, VAL1,", asr #5")                      \
-       TEST_R(   op "vs        sp, r",7, VAL1,", ror #6")                      \
-       TEST_RRR( op "ls        r",9, VAL1,", r",14,val, ", lsl r",0, 3,"")     \
-       TEST_RRR( op "hi        r",9, VAL1,", r",14,val, ", lsr r",7, 4,"")     \
-       TEST_RRR( op "lt        r",11,VAL1,", r",14,val, ", asr r",7, 5,"")     \
-       TEST_RRR( op "ge        r",11,VAL1,", r",14,N(val),", asr r",7, 6,"")   \
-       TEST_RR(  op "le        r13"       ", r",14,val, ", ror r",14,7,"")     \
-       TEST_RR(  op "gt        r",0, val, ", r13"       ", lsl r",14,8,"")     \
-       TEST_R(   op "eq        r",11,VAL1,", #0xf5")                           \
-       TEST_R(   op "ne        r",0, VAL1,", #0xf5000000")                     \
-       TEST_R(   op "  r",8, VAL2,", #0x000af000")
-
-#define _DATA_PROCESSING_DM(op,s,val)                                  \
-       TEST_R(   op "eq" s "   r0,  r",1, val, "")                     \
-       TEST_R(   op "ne" s "   r1,  r",1, val, ", lsl #3")             \
-       TEST_R(   op "cs" s "   r2,  r",3, val, ", lsr #4")             \
-       TEST_R(   op "cc" s "   r3,  r",3, val, ", asr #5")             \
-       TEST_R(   op "mi" s "   r4,  r",5, N(val),", asr #6")           \
-       TEST_R(   op "pl" s "   r5,  r",5, val, ", ror #7")             \
-       TEST_R(   op "vs" s "   r6,  r",10,val, ", rrx")                \
-       TEST(     op "vs" s "   r7,  pc, lsl #3")                       \
-       TEST(     op "vs" s "   r7,  sp, lsr #4")                       \
-       TEST_RR(  op "vc" s "   r8,  r",7, val, ", lsl r",0, 3,"")      \
-       TEST_RR(  op "hi" s "   r9,  r",9, val, ", lsr r",7, 4,"")      \
-       TEST_RR(  op "ls" s "   r10, r",9, val, ", asr r",7, 5,"")      \
-       TEST_RR(  op "ge" s "   r11, r",11,N(val),", asr r",7, 6,"")    \
-       TEST_RR(  op "lt" s "   r12, r",11,val, ", ror r",14,7,"")      \
-       TEST_R(   op "gt" s "   r14, r13"       ", lsl r",14,8,"")      \
-       TEST(     op "eq" s "   r0,  #0xf5")                            \
-       TEST(     op "ne" s "   r11, #0xf5000000")                      \
-       TEST(     op s "        r7,  #0x000af000")                      \
-       TEST(     op s "        r4,  #0x00005a00")
-
-#define DATA_PROCESSING_DM(op,val)             \
-       _DATA_PROCESSING_DM(op,"",val)          \
-       _DATA_PROCESSING_DM(op,"s",val)
-
-       DATA_PROCESSING_DNM("and",0xf00f00ff)
-       DATA_PROCESSING_DNM("eor",0xf00f00ff)
-       DATA_PROCESSING_DNM("sub",VAL2)
-       DATA_PROCESSING_DNM("rsb",VAL2)
-       DATA_PROCESSING_DNM("add",VAL2)
-       DATA_PROCESSING_DNM("adc",VAL2)
-       DATA_PROCESSING_DNM("sbc",VAL2)
-       DATA_PROCESSING_DNM("rsc",VAL2)
-       DATA_PROCESSING_NM("tst",0xf00f00ff)
-       DATA_PROCESSING_NM("teq",0xf00f00ff)
-       DATA_PROCESSING_NM("cmp",VAL2)
-       DATA_PROCESSING_NM("cmn",VAL2)
-       DATA_PROCESSING_DNM("orr",0xf00f00ff)
-       DATA_PROCESSING_DM("mov",VAL2)
-       DATA_PROCESSING_DNM("bic",0xf00f00ff)
-       DATA_PROCESSING_DM("mvn",VAL2)
-
-       TEST("mov       ip, sp") /* This has special case emulation code */
-
-       TEST_SUPPORTED("mov     pc, #0x1000");
-       TEST_SUPPORTED("mov     sp, #0x1000");
-       TEST_SUPPORTED("cmp     pc, #0x1000");
-       TEST_SUPPORTED("cmp     sp, #0x1000");
-
-       /* Data-processing with PC and a shift count in a register */
-       TEST_UNSUPPORTED(__inst_arm(0xe15c0f1e) "       @ cmp   r12, r14, asl pc")
-       TEST_UNSUPPORTED(__inst_arm(0xe1a0cf1e) "       @ mov   r12, r14, asl pc")
-       TEST_UNSUPPORTED(__inst_arm(0xe08caf1e) "       @ add   r10, r12, r14, asl pc")
-       TEST_UNSUPPORTED(__inst_arm(0xe151021f) "       @ cmp   r1, pc, lsl r2")
-       TEST_UNSUPPORTED(__inst_arm(0xe17f0211) "       @ cmn   pc, r1, lsl r2")
-       TEST_UNSUPPORTED(__inst_arm(0xe1a0121f) "       @ mov   r1, pc, lsl r2")
-       TEST_UNSUPPORTED(__inst_arm(0xe1a0f211) "       @ mov   pc, r1, lsl r2")
-       TEST_UNSUPPORTED(__inst_arm(0xe042131f) "       @ sub   r1, r2, pc, lsl r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe1cf1312) "       @ bic   r1, pc, r2, lsl r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe081f312) "       @ add   pc, r1, r2, lsl r3")
-
-       /* Data-processing with PC as a target and status registers updated */
-       TEST_UNSUPPORTED("movs  pc, r1")
-       TEST_UNSUPPORTED("movs  pc, r1, lsl r2")
-       TEST_UNSUPPORTED("movs  pc, #0x10000")
-       TEST_UNSUPPORTED("adds  pc, lr, r1")
-       TEST_UNSUPPORTED("adds  pc, lr, r1, lsl r2")
-       TEST_UNSUPPORTED("adds  pc, lr, #4")
-
-       /* Data-processing with SP as target */
-       TEST("add       sp, sp, #16")
-       TEST("sub       sp, sp, #8")
-       TEST("bic       sp, sp, #0x20")
-       TEST("orr       sp, sp, #0x20")
-       TEST_PR( "add   sp, r",10,0,", r",11,4,"")
-       TEST_PRR("add   sp, r",10,0,", r",11,4,", asl r",12,1,"")
-       TEST_P(  "mov   sp, r",10,0,"")
-       TEST_PR( "mov   sp, r",10,0,", asl r",12,0,"")
-
-       /* Data-processing with PC as target */
-       TEST_BF(   "add pc, pc, #2f-1b-8")
-       TEST_BF_R ("add pc, pc, r",14,2f-1f-8,"")
-       TEST_BF_R ("add pc, r",14,2f-1f-8,", pc")
-       TEST_BF_R ("mov pc, r",0,2f,"")
-       TEST_BF_R ("add pc, pc, r",14,(2f-1f-8)*2,", asr #1")
-       TEST_BB(   "sub pc, pc, #1b-2b+8")
-#if __LINUX_ARM_ARCH__ == 6 && !defined(CONFIG_CPU_V7)
-       TEST_BB(   "sub pc, pc, #1b-2b+8-2") /* UNPREDICTABLE before and after ARMv6 */
-#endif
-       TEST_BB_R( "sub pc, pc, r",14, 1f-2f+8,"")
-       TEST_BB_R( "rsb pc, r",14,1f-2f+8,", pc")
-       TEST_R(    "add pc, pc, r",10,-2,", asl #1")
-#ifdef CONFIG_THUMB2_KERNEL
-       TEST_ARM_TO_THUMB_INTERWORK_R("add      pc, pc, r",0,3f-1f-8+1,"")
-       TEST_ARM_TO_THUMB_INTERWORK_R("sub      pc, r",0,3f+8+1,", #8")
-#endif
-       TEST_GROUP("Miscellaneous instructions")
-
-       TEST("mrs       r0, cpsr")
-       TEST("mrspl     r7, cpsr")
-       TEST("mrs       r14, cpsr")
-       TEST_UNSUPPORTED(__inst_arm(0xe10ff000) "       @ mrs r15, cpsr")
-       TEST_UNSUPPORTED("mrs   r0, spsr")
-       TEST_UNSUPPORTED("mrs   lr, spsr")
-
-       TEST_UNSUPPORTED("msr   cpsr, r0")
-       TEST_UNSUPPORTED("msr   cpsr_f, lr")
-       TEST_UNSUPPORTED("msr   spsr, r0")
-
-       TEST_BF_R("bx   r",0,2f,"")
-       TEST_BB_R("bx   r",7,2f,"")
-       TEST_BF_R("bxeq r",14,2f,"")
-
-#if __LINUX_ARM_ARCH__ >= 5
-       TEST_R("clz     r0, r",0, 0x0,"")
-       TEST_R("clzeq   r7, r",14,0x1,"")
-       TEST_R("clz     lr, r",7, 0xffffffff,"")
-       TEST(  "clz     r4, sp")
-       TEST_UNSUPPORTED(__inst_arm(0x016fff10) "       @ clz pc, r0")
-       TEST_UNSUPPORTED(__inst_arm(0x016f0f1f) "       @ clz r0, pc")
-
-#if __LINUX_ARM_ARCH__ >= 6
-       TEST_UNSUPPORTED("bxj   r0")
-#endif
-
-       TEST_BF_R("blx  r",0,2f,"")
-       TEST_BB_R("blx  r",7,2f,"")
-       TEST_BF_R("blxeq        r",14,2f,"")
-       TEST_UNSUPPORTED(__inst_arm(0x0120003f) "       @ blx pc")
-
-       TEST_RR(   "qadd        r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(   "qaddvs      lr, r",9, VAL2,", r",8, VAL1,"")
-       TEST_R(    "qadd        lr, r",9, VAL2,", r13")
-       TEST_RR(   "qsub        r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(   "qsubvs      lr, r",9, VAL2,", r",8, VAL1,"")
-       TEST_R(    "qsub        lr, r",9, VAL2,", r13")
-       TEST_RR(   "qdadd       r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(   "qdaddvs     lr, r",9, VAL2,", r",8, VAL1,"")
-       TEST_R(    "qdadd       lr, r",9, VAL2,", r13")
-       TEST_RR(   "qdsub       r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(   "qdsubvs     lr, r",9, VAL2,", r",8, VAL1,"")
-       TEST_R(    "qdsub       lr, r",9, VAL2,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe101f050) "       @ qadd pc, r0, r1")
-       TEST_UNSUPPORTED(__inst_arm(0xe121f050) "       @ qsub pc, r0, r1")
-       TEST_UNSUPPORTED(__inst_arm(0xe141f050) "       @ qdadd pc, r0, r1")
-       TEST_UNSUPPORTED(__inst_arm(0xe161f050) "       @ qdsub pc, r0, r1")
-       TEST_UNSUPPORTED(__inst_arm(0xe16f2050) "       @ qdsub r2, r0, pc")
-       TEST_UNSUPPORTED(__inst_arm(0xe161205f) "       @ qdsub r2, pc, r1")
-
-       TEST_UNSUPPORTED("bkpt  0xffff")
-       TEST_UNSUPPORTED("bkpt  0x0000")
-
-       TEST_UNSUPPORTED(__inst_arm(0xe1600070) " @ smc #0")
-
-       TEST_GROUP("Halfword multiply and multiply-accumulate")
-
-       TEST_RRR(    "smlabb    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(    "smlabbge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RR(     "smlabb    lr, r",1, VAL2,", r",2, VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe10f3281) " @ smlabb pc, r1, r2, r3")
-       TEST_RRR(    "smlatb    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(    "smlatbge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RR(     "smlatb    lr, r",1, VAL2,", r",2, VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe10f32a1) " @ smlatb pc, r1, r2, r3")
-       TEST_RRR(    "smlabt    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(    "smlabtge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RR(     "smlabt    lr, r",1, VAL2,", r",2, VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe10f32c1) " @ smlabt pc, r1, r2, r3")
-       TEST_RRR(    "smlatt    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(    "smlattge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RR(     "smlatt    lr, r",1, VAL2,", r",2, VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe10f32e1) " @ smlatt pc, r1, r2, r3")
-
-       TEST_RRR(    "smlawb    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(    "smlawbge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RR(     "smlawb    lr, r",1, VAL2,", r",2, VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe12f3281) " @ smlawb pc, r1, r2, r3")
-       TEST_RRR(    "smlawt    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(    "smlawtge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RR(     "smlawt    lr, r",1, VAL2,", r",2, VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe12f32c1) " @ smlawt pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe12032cf) " @ smlawt r0, pc, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe1203fc1) " @ smlawt r0, r1, pc, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe120f2c1) " @ smlawt r0, r1, r2, pc")
-
-       TEST_RR(    "smulwb     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smulwbge   r7, r",8, VAL3,", r",9, VAL1,"")
-       TEST_R(     "smulwb     lr, r",1, VAL2,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe12f02a1) " @ smulwb pc, r1, r2")
-       TEST_RR(    "smulwt     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smulwtge   r7, r",8, VAL3,", r",9, VAL1,"")
-       TEST_R(     "smulwt     lr, r",1, VAL2,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe12f02e1) " @ smulwt pc, r1, r2")
-
-       TEST_RRRR(  "smlalbb    r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR(  "smlalbble  r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRR(   "smlalbb    r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe14f1382) " @ smlalbb pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe141f382) " @ smlalbb r1, pc, r2, r3")
-       TEST_RRRR(  "smlaltb    r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR(  "smlaltble  r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRR(   "smlaltb    r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe14f13a2) " @ smlaltb pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe141f3a2) " @ smlaltb r1, pc, r2, r3")
-       TEST_RRRR(  "smlalbt    r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR(  "smlalbtle  r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRR(   "smlalbt    r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe14f13c2) " @ smlalbt pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe141f3c2) " @ smlalbt r1, pc, r2, r3")
-       TEST_RRRR(  "smlaltt    r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR(  "smlalttle  r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRR(   "smlaltt    r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe14f13e2) " @ smlalbb pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe140f3e2) " @ smlalbb r0, pc, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe14013ef) " @ smlalbb r0, r1, pc, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe1401fe2) " @ smlalbb r0, r1, r2, pc")
-
-       TEST_RR(    "smulbb     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smulbbge   r7, r",8, VAL3,", r",9, VAL1,"")
-       TEST_R(     "smulbb     lr, r",1, VAL2,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe16f0281) " @ smulbb pc, r1, r2")
-       TEST_RR(    "smultb     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smultbge   r7, r",8, VAL3,", r",9, VAL1,"")
-       TEST_R(     "smultb     lr, r",1, VAL2,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe16f02a1) " @ smultb pc, r1, r2")
-       TEST_RR(    "smulbt     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smulbtge   r7, r",8, VAL3,", r",9, VAL1,"")
-       TEST_R(     "smulbt     lr, r",1, VAL2,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe16f02c1) " @ smultb pc, r1, r2")
-       TEST_RR(    "smultt     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smulttge   r7, r",8, VAL3,", r",9, VAL1,"")
-       TEST_R(     "smultt     lr, r",1, VAL2,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe16f02e1) " @ smultt pc, r1, r2")
-       TEST_UNSUPPORTED(__inst_arm(0xe16002ef) " @ smultt r0, pc, r2")
-       TEST_UNSUPPORTED(__inst_arm(0xe1600fe1) " @ smultt r0, r1, pc")
-#endif
-
-       TEST_GROUP("Multiply and multiply-accumulate")
-
-       TEST_RR(    "mul        r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "mulls      r7, r",8, VAL2,", r",9, VAL2,"")
-       TEST_R(     "mul        lr, r",4, VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe00f0291) " @ mul pc, r1, r2")
-       TEST_UNSUPPORTED(__inst_arm(0xe000029f) " @ mul r0, pc, r2")
-       TEST_UNSUPPORTED(__inst_arm(0xe0000f91) " @ mul r0, r1, pc")
-       TEST_RR(    "muls       r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "mullss     r7, r",8, VAL2,", r",9, VAL2,"")
-       TEST_R(     "muls       lr, r",4, VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe01f0291) " @ muls pc, r1, r2")
-
-       TEST_RRR(    "mla       r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(    "mlahi     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RR(     "mla       lr, r",1, VAL2,", r",2, VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe02f3291) " @ mla pc, r1, r2, r3")
-       TEST_RRR(    "mlas      r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(    "mlahis    r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RR(     "mlas      lr, r",1, VAL2,", r",2, VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe03f3291) " @ mlas pc, r1, r2, r3")
-
-#if __LINUX_ARM_ARCH__ >= 6
-       TEST_RR(  "umaal        r0, r1, r",2, VAL1,", r",3, VAL2,"")
-       TEST_RR(  "umaalls      r7, r8, r",9, VAL2,", r",10, VAL1,"")
-       TEST_R(   "umaal        lr, r12, r",11,VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe041f392) " @ umaal pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe04f0392) " @ umaal r0, pc, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe0500090) " @ undef")
-       TEST_UNSUPPORTED(__inst_arm(0xe05fff9f) " @ undef")
-#endif
-
-#if __LINUX_ARM_ARCH__ >= 7
-       TEST_RRR(  "mls         r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(  "mlshi       r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RR(   "mls         lr, r",1, VAL2,", r",2, VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe06f3291) " @ mls pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe060329f) " @ mls r0, pc, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe0603f91) " @ mls r0, r1, pc, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe060f291) " @ mls r0, r1, r2, pc")
-#endif
-
-       TEST_UNSUPPORTED(__inst_arm(0xe0700090) " @ undef")
-       TEST_UNSUPPORTED(__inst_arm(0xe07fff9f) " @ undef")
-
-       TEST_RR(  "umull        r0, r1, r",2, VAL1,", r",3, VAL2,"")
-       TEST_RR(  "umullls      r7, r8, r",9, VAL2,", r",10, VAL1,"")
-       TEST_R(   "umull        lr, r12, r",11,VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe081f392) " @ umull pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe08f1392) " @ umull r1, pc, r2, r3")
-       TEST_RR(  "umulls       r0, r1, r",2, VAL1,", r",3, VAL2,"")
-       TEST_RR(  "umulllss     r7, r8, r",9, VAL2,", r",10, VAL1,"")
-       TEST_R(   "umulls       lr, r12, r",11,VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe091f392) " @ umulls pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe09f1392) " @ umulls r1, pc, r2, r3")
-
-       TEST_RRRR(  "umlal      r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR(  "umlalle    r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRR(   "umlal      r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe0af1392) " @ umlal pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe0a1f392) " @ umlal r1, pc, r2, r3")
-       TEST_RRRR(  "umlals     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR(  "umlalles   r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRR(   "umlals     r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe0bf1392) " @ umlals pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe0b1f392) " @ umlals r1, pc, r2, r3")
-
-       TEST_RR(  "smull        r0, r1, r",2, VAL1,", r",3, VAL2,"")
-       TEST_RR(  "smullls      r7, r8, r",9, VAL2,", r",10, VAL1,"")
-       TEST_R(   "smull        lr, r12, r",11,VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe0c1f392) " @ smull pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe0cf1392) " @ smull r1, pc, r2, r3")
-       TEST_RR(  "smulls       r0, r1, r",2, VAL1,", r",3, VAL2,"")
-       TEST_RR(  "smulllss     r7, r8, r",9, VAL2,", r",10, VAL1,"")
-       TEST_R(   "smulls       lr, r12, r",11,VAL3,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe0d1f392) " @ smulls pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe0df1392) " @ smulls r1, pc, r2, r3")
-
-       TEST_RRRR(  "smlal      r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR(  "smlalle    r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRR(   "smlal      r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe0ef1392) " @ smlal pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe0e1f392) " @ smlal r1, pc, r2, r3")
-       TEST_RRRR(  "smlals     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR(  "smlalles   r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRR(   "smlals     r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
-       TEST_UNSUPPORTED(__inst_arm(0xe0ff1392) " @ smlals pc, r1, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe0f0f392) " @ smlals r0, pc, r2, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe0f0139f) " @ smlals r0, r1, pc, r3")
-       TEST_UNSUPPORTED(__inst_arm(0xe0f01f92) " @ smlals r0, r1, r2, pc")
-
-       TEST_GROUP("Synchronization primitives")
-
-#if __LINUX_ARM_ARCH__ < 6
-       TEST_RP("swp    lr, r",7,VAL2,", [r",8,0,"]")
-       TEST_R( "swpvs  r0, r",1,VAL1,", [sp]")
-       TEST_RP("swp    sp, r",14,VAL2,", [r",12,13*4,"]")
-#else
-       TEST_UNSUPPORTED(__inst_arm(0xe108e097) " @ swp lr, r7, [r8]")
-       TEST_UNSUPPORTED(__inst_arm(0x610d0091) " @ swpvs       r0, r1, [sp]")
-       TEST_UNSUPPORTED(__inst_arm(0xe10cd09e) " @ swp sp, r14 [r12]")
-#endif
-       TEST_UNSUPPORTED(__inst_arm(0xe102f091) " @ swp pc, r1, [r2]")
-       TEST_UNSUPPORTED(__inst_arm(0xe102009f) " @ swp r0, pc, [r2]")
-       TEST_UNSUPPORTED(__inst_arm(0xe10f0091) " @ swp r0, r1, [pc]")
-#if __LINUX_ARM_ARCH__ < 6
-       TEST_RP("swpb   lr, r",7,VAL2,", [r",8,0,"]")
-       TEST_R( "swpvsb r0, r",1,VAL1,", [sp]")
-#else
-       TEST_UNSUPPORTED(__inst_arm(0xe148e097) " @ swpb        lr, r7, [r8]")
-       TEST_UNSUPPORTED(__inst_arm(0x614d0091) " @ swpvsb      r0, r1, [sp]")
-#endif
-       TEST_UNSUPPORTED(__inst_arm(0xe142f091) " @ swpb pc, r1, [r2]")
-
-       TEST_UNSUPPORTED(__inst_arm(0xe1100090)) /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe1200090)) /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe1300090)) /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe1500090)) /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe1600090)) /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe1700090)) /* Unallocated space */
-#if __LINUX_ARM_ARCH__ >= 6
-       TEST_UNSUPPORTED("ldrex r2, [sp]")
-#endif
-#if (__LINUX_ARM_ARCH__ >= 7) || defined(CONFIG_CPU_32v6K)
-       TEST_UNSUPPORTED("strexd        r0, r2, r3, [sp]")
-       TEST_UNSUPPORTED("ldrexd        r2, r3, [sp]")
-       TEST_UNSUPPORTED("strexb        r0, r2, [sp]")
-       TEST_UNSUPPORTED("ldrexb        r2, [sp]")
-       TEST_UNSUPPORTED("strexh        r0, r2, [sp]")
-       TEST_UNSUPPORTED("ldrexh        r2, [sp]")
-#endif
-       TEST_GROUP("Extra load/store instructions")
-
-       TEST_RPR(  "strh        r",0, VAL1,", [r",1, 48,", -r",2, 24,"]")
-       TEST_RPR(  "streqh      r",14,VAL2,", [r",13,0, ", r",12, 48,"]")
-       TEST_RPR(  "strh        r",1, VAL1,", [r",2, 24,", r",3,  48,"]!")
-       TEST_RPR(  "strneh      r",12,VAL2,", [r",11,48,", -r",10,24,"]!")
-       TEST_RPR(  "strh        r",2, VAL1,", [r",3, 24,"], r",4, 48,"")
-       TEST_RPR(  "strh        r",10,VAL2,", [r",9, 48,"], -r",11,24,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe1afc0ba) "       @ strh r12, [pc, r10]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe089f0bb) "       @ strh pc, [r9], r11")
-       TEST_UNSUPPORTED(__inst_arm(0xe089a0bf) "       @ strh r10, [r9], pc")
-
-       TEST_PR(   "ldrh        r0, [r",0,  48,", -r",2, 24,"]")
-       TEST_PR(   "ldrcsh      r14, [r",13,0, ", r",12, 48,"]")
-       TEST_PR(   "ldrh        r1, [r",2,  24,", r",3,  48,"]!")
-       TEST_PR(   "ldrcch      r12, [r",11,48,", -r",10,24,"]!")
-       TEST_PR(   "ldrh        r2, [r",3,  24,"], r",4, 48,"")
-       TEST_PR(   "ldrh        r10, [r",9, 48,"], -r",11,24,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe1bfc0ba) "       @ ldrh r12, [pc, r10]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe099f0bb) "       @ ldrh pc, [r9], r11")
-       TEST_UNSUPPORTED(__inst_arm(0xe099a0bf) "       @ ldrh r10, [r9], pc")
-
-       TEST_RP(   "strh        r",0, VAL1,", [r",1, 24,", #-2]")
-       TEST_RP(   "strmih      r",14,VAL2,", [r",13,0, ", #2]")
-       TEST_RP(   "strh        r",1, VAL1,", [r",2, 24,", #4]!")
-       TEST_RP(   "strplh      r",12,VAL2,", [r",11,24,", #-4]!")
-       TEST_RP(   "strh        r",2, VAL1,", [r",3, 24,"], #48")
-       TEST_RP(   "strh        r",10,VAL2,", [r",9, 64,"], #-48")
-       TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) "       @ strh r12, [pc, #48]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) "       @ strh pc, [r9], #48")
-
-       TEST_P(    "ldrh        r0, [r",0,  24,", #-2]")
-       TEST_P(    "ldrvsh      r14, [r",13,0, ", #2]")
-       TEST_P(    "ldrh        r1, [r",2,  24,", #4]!")
-       TEST_P(    "ldrvch      r12, [r",11,24,", #-4]!")
-       TEST_P(    "ldrh        r2, [r",3,  24,"], #48")
-       TEST_P(    "ldrh        r10, [r",9, 64,"], #-48")
-       TEST(      "ldrh        r0, [pc, #0]")
-       TEST_UNSUPPORTED(__inst_arm(0xe1ffc3b0) "       @ ldrh r12, [pc, #48]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe0d9f3b0) "       @ ldrh pc, [r9], #48")
-
-       TEST_PR(   "ldrsb       r0, [r",0,  48,", -r",2, 24,"]")
-       TEST_PR(   "ldrhisb     r14, [r",13,0,", r",12,  48,"]")
-       TEST_PR(   "ldrsb       r1, [r",2,  24,", r",3,  48,"]!")
-       TEST_PR(   "ldrlssb     r12, [r",11,48,", -r",10,24,"]!")
-       TEST_PR(   "ldrsb       r2, [r",3,  24,"], r",4, 48,"")
-       TEST_PR(   "ldrsb       r10, [r",9, 48,"], -r",11,24,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe1bfc0da) "       @ ldrsb r12, [pc, r10]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe099f0db) "       @ ldrsb pc, [r9], r11")
-
-       TEST_P(    "ldrsb       r0, [r",0,  24,", #-1]")
-       TEST_P(    "ldrgesb     r14, [r",13,0, ", #1]")
-       TEST_P(    "ldrsb       r1, [r",2,  24,", #4]!")
-       TEST_P(    "ldrltsb     r12, [r",11,24,", #-4]!")
-       TEST_P(    "ldrsb       r2, [r",3,  24,"], #48")
-       TEST_P(    "ldrsb       r10, [r",9, 64,"], #-48")
-       TEST(      "ldrsb       r0, [pc, #0]")
-       TEST_UNSUPPORTED(__inst_arm(0xe1ffc3d0) "       @ ldrsb r12, [pc, #48]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe0d9f3d0) "       @ ldrsb pc, [r9], #48")
-
-       TEST_PR(   "ldrsh       r0, [r",0,  48,", -r",2, 24,"]")
-       TEST_PR(   "ldrgtsh     r14, [r",13,0, ", r",12, 48,"]")
-       TEST_PR(   "ldrsh       r1, [r",2,  24,", r",3,  48,"]!")
-       TEST_PR(   "ldrlesh     r12, [r",11,48,", -r",10,24,"]!")
-       TEST_PR(   "ldrsh       r2, [r",3,  24,"], r",4, 48,"")
-       TEST_PR(   "ldrsh       r10, [r",9, 48,"], -r",11,24,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe1bfc0fa) "       @ ldrsh r12, [pc, r10]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe099f0fb) "       @ ldrsh pc, [r9], r11")
-
-       TEST_P(    "ldrsh       r0, [r",0,  24,", #-1]")
-       TEST_P(    "ldreqsh     r14, [r",13,0 ,", #1]")
-       TEST_P(    "ldrsh       r1, [r",2,  24,", #4]!")
-       TEST_P(    "ldrnesh     r12, [r",11,24,", #-4]!")
-       TEST_P(    "ldrsh       r2, [r",3,  24,"], #48")
-       TEST_P(    "ldrsh       r10, [r",9, 64,"], #-48")
-       TEST(      "ldrsh       r0, [pc, #0]")
-       TEST_UNSUPPORTED(__inst_arm(0xe1ffc3f0) "       @ ldrsh r12, [pc, #48]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe0d9f3f0) "       @ ldrsh pc, [r9], #48")
-
-#if __LINUX_ARM_ARCH__ >= 7
-       TEST_UNSUPPORTED("strht r1, [r2], r3")
-       TEST_UNSUPPORTED("ldrht r1, [r2], r3")
-       TEST_UNSUPPORTED("strht r1, [r2], #48")
-       TEST_UNSUPPORTED("ldrht r1, [r2], #48")
-       TEST_UNSUPPORTED("ldrsbt        r1, [r2], r3")
-       TEST_UNSUPPORTED("ldrsbt        r1, [r2], #48")
-       TEST_UNSUPPORTED("ldrsht        r1, [r2], r3")
-       TEST_UNSUPPORTED("ldrsht        r1, [r2], #48")
-#endif
-
-#if __LINUX_ARM_ARCH__ >= 5
-       TEST_RPR(  "strd        r",0, VAL1,", [r",1, 48,", -r",2,24,"]")
-       TEST_RPR(  "strccd      r",8, VAL2,", [r",13,0, ", r",12,48,"]")
-       TEST_RPR(  "strd        r",4, VAL1,", [r",2, 24,", r",3, 48,"]!")
-       TEST_RPR(  "strcsd      r",12,VAL2,", [r",11,48,", -r",10,24,"]!")
-       TEST_RPR(  "strd        r",2, VAL1,", [r",5, 24,"], r",4,48,"")
-       TEST_RPR(  "strd        r",10,VAL2,", [r",9, 48,"], -r",7,24,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe1afc0fa) "       @ strd r12, [pc, r10]!")
-
-       TEST_PR(   "ldrd        r0, [r",0, 48,", -r",2,24,"]")
-       TEST_PR(   "ldrmid      r8, [r",13,0, ", r",12,48,"]")
-       TEST_PR(   "ldrd        r4, [r",2, 24,", r",3, 48,"]!")
-       TEST_PR(   "ldrpld      r6, [r",11,48,", -r",10,24,"]!")
-       TEST_PR(   "ldrd        r2, [r",5, 24,"], r",4,48,"")
-       TEST_PR(   "ldrd        r10, [r",9,48,"], -r",7,24,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe1afc0da) "       @ ldrd r12, [pc, r10]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe089f0db) "       @ ldrd pc, [r9], r11")
-       TEST_UNSUPPORTED(__inst_arm(0xe089e0db) "       @ ldrd lr, [r9], r11")
-       TEST_UNSUPPORTED(__inst_arm(0xe089c0df) "       @ ldrd r12, [r9], pc")
-
-       TEST_RP(   "strd        r",0, VAL1,", [r",1, 24,", #-8]")
-       TEST_RP(   "strvsd      r",8, VAL2,", [r",13,0, ", #8]")
-       TEST_RP(   "strd        r",4, VAL1,", [r",2, 24,", #16]!")
-       TEST_RP(   "strvcd      r",12,VAL2,", [r",11,24,", #-16]!")
-       TEST_RP(   "strd        r",2, VAL1,", [r",4, 24,"], #48")
-       TEST_RP(   "strd        r",10,VAL2,", [r",9, 64,"], #-48")
-       TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) "       @ strd r12, [pc, #48]!")
-
-       TEST_P(    "ldrd        r0, [r",0, 24,", #-8]")
-       TEST_P(    "ldrhid      r8, [r",13,0, ", #8]")
-       TEST_P(    "ldrd        r4, [r",2, 24,", #16]!")
-       TEST_P(    "ldrlsd      r6, [r",11,24,", #-16]!")
-       TEST_P(    "ldrd        r2, [r",5, 24,"], #48")
-       TEST_P(    "ldrd        r10, [r",9,6,"], #-48")
-       TEST_UNSUPPORTED(__inst_arm(0xe1efc3d0) "       @ ldrd r12, [pc, #48]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe0c9f3d0) "       @ ldrd pc, [r9], #48")
-       TEST_UNSUPPORTED(__inst_arm(0xe0c9e3d0) "       @ ldrd lr, [r9], #48")
-#endif
-
-       TEST_GROUP("Miscellaneous")
-
-#if __LINUX_ARM_ARCH__ >= 7
-       TEST("movw      r0, #0")
-       TEST("movw      r0, #0xffff")
-       TEST("movw      lr, #0xffff")
-       TEST_UNSUPPORTED(__inst_arm(0xe300f000) "       @ movw pc, #0")
-       TEST_R("movt    r",0, VAL1,", #0")
-       TEST_R("movt    r",0, VAL2,", #0xffff")
-       TEST_R("movt    r",14,VAL1,", #0xffff")
-       TEST_UNSUPPORTED(__inst_arm(0xe340f000) "       @ movt pc, #0")
-#endif
-
-       TEST_UNSUPPORTED("msr   cpsr, 0x13")
-       TEST_UNSUPPORTED("msr   cpsr_f, 0xf0000000")
-       TEST_UNSUPPORTED("msr   spsr, 0x13")
-
-#if __LINUX_ARM_ARCH__ >= 7
-       TEST_SUPPORTED("yield")
-       TEST("sev")
-       TEST("nop")
-       TEST("wfi")
-       TEST_SUPPORTED("wfe")
-       TEST_UNSUPPORTED("dbg #0")
-#endif
-
-       TEST_GROUP("Load/store word and unsigned byte")
-
-#define LOAD_STORE(byte)                                                       \
-       TEST_RP( "str"byte"     r",0, VAL1,", [r",1, 24,", #-2]")               \
-       TEST_RP( "str"byte"     r",14,VAL2,", [r",13,0, ", #2]")                \
-       TEST_RP( "str"byte"     r",1, VAL1,", [r",2, 24,", #4]!")               \
-       TEST_RP( "str"byte"     r",12,VAL2,", [r",11,24,", #-4]!")              \
-       TEST_RP( "str"byte"     r",2, VAL1,", [r",3, 24,"], #48")               \
-       TEST_RP( "str"byte"     r",10,VAL2,", [r",9, 64,"], #-48")              \
-       TEST_RPR("str"byte"     r",0, VAL1,", [r",1, 48,", -r",2, 24,"]")       \
-       TEST_RPR("str"byte"     r",14,VAL2,", [r",13,0, ", r",12, 48,"]")       \
-       TEST_RPR("str"byte"     r",1, VAL1,", [r",2, 24,", r",3,  48,"]!")      \
-       TEST_RPR("str"byte"     r",12,VAL2,", [r",11,48,", -r",10,24,"]!")      \
-       TEST_RPR("str"byte"     r",2, VAL1,", [r",3, 24,"], r",4, 48,"")        \
-       TEST_RPR("str"byte"     r",10,VAL2,", [r",9, 48,"], -r",11,24,"")       \
-       TEST_RPR("str"byte"     r",0, VAL1,", [r",1, 24,", r",2,  32,", asl #1]")\
-       TEST_RPR("str"byte"     r",14,VAL2,", [r",13,0, ", r",12, 32,", lsr #2]")\
-       TEST_RPR("str"byte"     r",1, VAL1,", [r",2, 24,", r",3,  32,", asr #3]!")\
-       TEST_RPR("str"byte"     r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\
-       TEST_P(  "ldr"byte"     r0, [r",0,  24,", #-2]")                        \
-       TEST_P(  "ldr"byte"     r14, [r",13,0, ", #2]")                         \
-       TEST_P(  "ldr"byte"     r1, [r",2,  24,", #4]!")                        \
-       TEST_P(  "ldr"byte"     r12, [r",11,24,", #-4]!")                       \
-       TEST_P(  "ldr"byte"     r2, [r",3,  24,"], #48")                        \
-       TEST_P(  "ldr"byte"     r10, [r",9, 64,"], #-48")                       \
-       TEST_PR( "ldr"byte"     r0, [r",0,  48,", -r",2, 24,"]")                \
-       TEST_PR( "ldr"byte"     r14, [r",13,0, ", r",12, 48,"]")                \
-       TEST_PR( "ldr"byte"     r1, [r",2,  24,", r",3, 48,"]!")                \
-       TEST_PR( "ldr"byte"     r12, [r",11,48,", -r",10,24,"]!")               \
-       TEST_PR( "ldr"byte"     r2, [r",3,  24,"], r",4, 48,"")                 \
-       TEST_PR( "ldr"byte"     r10, [r",9, 48,"], -r",11,24,"")                \
-       TEST_PR( "ldr"byte"     r0, [r",0,  24,", r",2,  32,", asl #1]")        \
-       TEST_PR( "ldr"byte"     r14, [r",13,0, ", r",12, 32,", lsr #2]")        \
-       TEST_PR( "ldr"byte"     r1, [r",2,  24,", r",3,  32,", asr #3]!")       \
-       TEST_PR( "ldr"byte"     r12, [r",11,24,", r",10, 4,", ror #31]!")       \
-       TEST(    "ldr"byte"     r0, [pc, #0]")                                  \
-       TEST_R(  "ldr"byte"     r12, [pc, r",14,0,"]")
-
-       LOAD_STORE("")
-       TEST_P(   "str  pc, [r",0,0,", #15*4]")
-       TEST_R(   "str  pc, [sp, r",2,15*4,"]")
-       TEST_BF(  "ldr  pc, [sp, #15*4]")
-       TEST_BF_R("ldr  pc, [sp, r",2,15*4,"]")
-
-       TEST_P(   "str  sp, [r",0,0,", #13*4]")
-       TEST_R(   "str  sp, [sp, r",2,13*4,"]")
-       TEST_BF(  "ldr  sp, [sp, #13*4]")
-       TEST_BF_R("ldr  sp, [sp, r",2,13*4,"]")
-
-#ifdef CONFIG_THUMB2_KERNEL
-       TEST_ARM_TO_THUMB_INTERWORK_P("ldr      pc, [r",0,0,", #15*4]")
-#endif
-       TEST_UNSUPPORTED(__inst_arm(0xe5af6008) "       @ str r6, [pc, #8]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe7af6008) "       @ str r6, [pc, r8]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe5bf6008) "       @ ldr r6, [pc, #8]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe7bf6008) "       @ ldr r6, [pc, r8]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe788600f) "       @ str r6, [r8, pc]")
-       TEST_UNSUPPORTED(__inst_arm(0xe798600f) "       @ ldr r6, [r8, pc]")
-
-       LOAD_STORE("b")
-       TEST_UNSUPPORTED(__inst_arm(0xe5f7f008) "       @ ldrb pc, [r7, #8]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe7f7f008) "       @ ldrb pc, [r7, r8]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe5ef6008) "       @ strb r6, [pc, #8]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe7ef6008) "       @ strb r6, [pc, r3]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe5ff6008) "       @ ldrb r6, [pc, #8]!")
-       TEST_UNSUPPORTED(__inst_arm(0xe7ff6008) "       @ ldrb r6, [pc, r3]!")
-
-       TEST_UNSUPPORTED("ldrt  r0, [r1], #4")
-       TEST_UNSUPPORTED("ldrt  r1, [r2], r3")
-       TEST_UNSUPPORTED("strt  r2, [r3], #4")
-       TEST_UNSUPPORTED("strt  r3, [r4], r5")
-       TEST_UNSUPPORTED("ldrbt r4, [r5], #4")
-       TEST_UNSUPPORTED("ldrbt r5, [r6], r7")
-       TEST_UNSUPPORTED("strbt r6, [r7], #4")
-       TEST_UNSUPPORTED("strbt r7, [r8], r9")
-
-#if __LINUX_ARM_ARCH__ >= 7
-       TEST_GROUP("Parallel addition and subtraction, signed")
-
-       TEST_UNSUPPORTED(__inst_arm(0xe6000010) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe60fffff) "") /* Unallocated space */
-
-       TEST_RR(    "sadd16     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "sadd16     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe61cff1a) "       @ sadd16        pc, r12, r10")
-       TEST_RR(    "sasx       r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "sasx       r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe61cff3a) "       @ sasx  pc, r12, r10")
-       TEST_RR(    "ssax       r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "ssax       r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe61cff5a) "       @ ssax  pc, r12, r10")
-       TEST_RR(    "ssub16     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "ssub16     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe61cff7a) "       @ ssub16        pc, r12, r10")
-       TEST_RR(    "sadd8      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "sadd8      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe61cff9a) "       @ sadd8 pc, r12, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe61000b0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe61fffbf) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe61000d0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe61fffdf) "") /* Unallocated space */
-       TEST_RR(    "ssub8      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "ssub8      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe61cfffa) "       @ ssub8 pc, r12, r10")
-
-       TEST_RR(    "qadd16     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "qadd16     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe62cff1a) "       @ qadd16        pc, r12, r10")
-       TEST_RR(    "qasx       r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "qasx       r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe62cff3a) "       @ qasx  pc, r12, r10")
-       TEST_RR(    "qsax       r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "qsax       r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe62cff5a) "       @ qsax  pc, r12, r10")
-       TEST_RR(    "qsub16     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "qsub16     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe62cff7a) "       @ qsub16        pc, r12, r10")
-       TEST_RR(    "qadd8      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "qadd8      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe62cff9a) "       @ qadd8 pc, r12, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe62000b0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe62fffbf) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe62000d0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe62fffdf) "") /* Unallocated space */
-       TEST_RR(    "qsub8      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "qsub8      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe62cfffa) "       @ qsub8 pc, r12, r10")
-
-       TEST_RR(    "shadd16    r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "shadd16    r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe63cff1a) "       @ shadd16       pc, r12, r10")
-       TEST_RR(    "shasx      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "shasx      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe63cff3a) "       @ shasx pc, r12, r10")
-       TEST_RR(    "shsax      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "shsax      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe63cff5a) "       @ shsax pc, r12, r10")
-       TEST_RR(    "shsub16    r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "shsub16    r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe63cff7a) "       @ shsub16       pc, r12, r10")
-       TEST_RR(    "shadd8     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "shadd8     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe63cff9a) "       @ shadd8        pc, r12, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe63000b0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe63fffbf) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe63000d0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe63fffdf) "") /* Unallocated space */
-       TEST_RR(    "shsub8     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "shsub8     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe63cfffa) "       @ shsub8        pc, r12, r10")
-
-       TEST_GROUP("Parallel addition and subtraction, unsigned")
-
-       TEST_UNSUPPORTED(__inst_arm(0xe6400010) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe64fffff) "") /* Unallocated space */
-
-       TEST_RR(    "uadd16     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uadd16     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe65cff1a) "       @ uadd16        pc, r12, r10")
-       TEST_RR(    "uasx       r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uasx       r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe65cff3a) "       @ uasx  pc, r12, r10")
-       TEST_RR(    "usax       r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "usax       r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe65cff5a) "       @ usax  pc, r12, r10")
-       TEST_RR(    "usub16     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "usub16     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe65cff7a) "       @ usub16        pc, r12, r10")
-       TEST_RR(    "uadd8      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uadd8      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe65cff9a) "       @ uadd8 pc, r12, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe65000b0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe65fffbf) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe65000d0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe65fffdf) "") /* Unallocated space */
-       TEST_RR(    "usub8      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "usub8      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe65cfffa) "       @ usub8 pc, r12, r10")
-
-       TEST_RR(    "uqadd16    r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uqadd16    r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe66cff1a) "       @ uqadd16       pc, r12, r10")
-       TEST_RR(    "uqasx      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uqasx      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe66cff3a) "       @ uqasx pc, r12, r10")
-       TEST_RR(    "uqsax      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uqsax      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe66cff5a) "       @ uqsax pc, r12, r10")
-       TEST_RR(    "uqsub16    r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uqsub16    r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe66cff7a) "       @ uqsub16       pc, r12, r10")
-       TEST_RR(    "uqadd8     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uqadd8     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe66cff9a) "       @ uqadd8        pc, r12, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe66000b0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe66fffbf) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe66000d0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe66fffdf) "") /* Unallocated space */
-       TEST_RR(    "uqsub8     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uqsub8     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe66cfffa) "       @ uqsub8        pc, r12, r10")
-
-       TEST_RR(    "uhadd16    r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uhadd16    r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe67cff1a) "       @ uhadd16       pc, r12, r10")
-       TEST_RR(    "uhasx      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uhasx      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe67cff3a) "       @ uhasx pc, r12, r10")
-       TEST_RR(    "uhsax      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uhsax      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe67cff5a) "       @ uhsax pc, r12, r10")
-       TEST_RR(    "uhsub16    r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uhsub16    r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe67cff7a) "       @ uhsub16       pc, r12, r10")
-       TEST_RR(    "uhadd8     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uhadd8     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe67cff9a) "       @ uhadd8        pc, r12, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe67000b0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe67fffbf) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe67000d0) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe67fffdf) "") /* Unallocated space */
-       TEST_RR(    "uhsub8     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uhsub8     r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe67cfffa) "       @ uhsub8        pc, r12, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe67feffa) "       @ uhsub8        r14, pc, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe67cefff) "       @ uhsub8        r14, r12, pc")
-#endif /* __LINUX_ARM_ARCH__ >= 7 */
-
-#if __LINUX_ARM_ARCH__ >= 6
-       TEST_GROUP("Packing, unpacking, saturation, and reversal")
-
-       TEST_RR(    "pkhbt      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "pkhbt      r14,r",12, HH1,", r",10,HH2,", lsl #2")
-       TEST_UNSUPPORTED(__inst_arm(0xe68cf11a) "       @ pkhbt pc, r12, r10, lsl #2")
-       TEST_RR(    "pkhtb      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "pkhtb      r14,r",12, HH1,", r",10,HH2,", asr #2")
-       TEST_UNSUPPORTED(__inst_arm(0xe68cf15a) "       @ pkhtb pc, r12, r10, asr #2")
-       TEST_UNSUPPORTED(__inst_arm(0xe68fe15a) "       @ pkhtb r14, pc, r10, asr #2")
-       TEST_UNSUPPORTED(__inst_arm(0xe68ce15f) "       @ pkhtb r14, r12, pc, asr #2")
-       TEST_UNSUPPORTED(__inst_arm(0xe6900010) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe69fffdf) "") /* Unallocated space */
-
-       TEST_R(     "ssat       r0, #24, r",0,   VAL1,"")
-       TEST_R(     "ssat       r14, #24, r",12, VAL2,"")
-       TEST_R(     "ssat       r0, #24, r",0,   VAL1,", lsl #8")
-       TEST_R(     "ssat       r14, #24, r",12, VAL2,", asr #8")
-       TEST_UNSUPPORTED(__inst_arm(0xe6b7f01c) "       @ ssat  pc, #24, r12")
-
-       TEST_R(     "usat       r0, #24, r",0,   VAL1,"")
-       TEST_R(     "usat       r14, #24, r",12, VAL2,"")
-       TEST_R(     "usat       r0, #24, r",0,   VAL1,", lsl #8")
-       TEST_R(     "usat       r14, #24, r",12, VAL2,", asr #8")
-       TEST_UNSUPPORTED(__inst_arm(0xe6f7f01c) "       @ usat  pc, #24, r12")
-
-       TEST_RR(    "sxtab16    r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "sxtab16    r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "sxtb16     r8, r",7,  HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe68cf47a) "       @ sxtab16       pc,r12, r10, ror #8")
-
-       TEST_RR(    "sel        r0, r",0,  VAL1,", r",1, VAL2,"")
-       TEST_RR(    "sel        r14, r",12,VAL1,", r",10, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe68cffba) "       @ sel   pc, r12, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe68fefba) "       @ sel   r14, pc, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe68cefbf) "       @ sel   r14, r12, pc")
-
-       TEST_R(     "ssat16     r0, #12, r",0,   HH1,"")
-       TEST_R(     "ssat16     r14, #12, r",12, HH2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe6abff3c) "       @ ssat16        pc, #12, r12")
-
-       TEST_RR(    "sxtab      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "sxtab      r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "sxtb       r8, r",7,  HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe6acf47a) "       @ sxtab pc,r12, r10, ror #8")
-
-       TEST_R(     "rev        r0, r",0,   VAL1,"")
-       TEST_R(     "rev        r14, r",12, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe6bfff3c) "       @ rev   pc, r12")
-
-       TEST_RR(    "sxtah      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "sxtah      r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "sxth       r8, r",7,  HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe6bcf47a) "       @ sxtah pc,r12, r10, ror #8")
-
-       TEST_R(     "rev16      r0, r",0,   VAL1,"")
-       TEST_R(     "rev16      r14, r",12, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe6bfffbc) "       @ rev16 pc, r12")
-
-       TEST_RR(    "uxtab16    r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uxtab16    r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "uxtb16     r8, r",7,  HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe6ccf47a) "       @ uxtab16       pc,r12, r10, ror #8")
-
-       TEST_R(     "usat16     r0, #12, r",0,   HH1,"")
-       TEST_R(     "usat16     r14, #12, r",12, HH2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe6ecff3c) "       @ usat16        pc, #12, r12")
-       TEST_UNSUPPORTED(__inst_arm(0xe6ecef3f) "       @ usat16        r14, #12, pc")
-
-       TEST_RR(    "uxtab      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uxtab      r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "uxtb       r8, r",7,  HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe6ecf47a) "       @ uxtab pc,r12, r10, ror #8")
-
-#if __LINUX_ARM_ARCH__ >= 7
-       TEST_R(     "rbit       r0, r",0,   VAL1,"")
-       TEST_R(     "rbit       r14, r",12, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe6ffff3c) "       @ rbit  pc, r12")
-#endif
-
-       TEST_RR(    "uxtah      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uxtah      r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "uxth       r8, r",7,  HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe6fff077) "       @ uxth  pc, r7")
-       TEST_UNSUPPORTED(__inst_arm(0xe6ff807f) "       @ uxth  r8, pc")
-       TEST_UNSUPPORTED(__inst_arm(0xe6fcf47a) "       @ uxtah pc, r12, r10, ror #8")
-       TEST_UNSUPPORTED(__inst_arm(0xe6fce47f) "       @ uxtah r14, r12, pc, ror #8")
-
-       TEST_R(     "revsh      r0, r",0,   VAL1,"")
-       TEST_R(     "revsh      r14, r",12, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe6ffff3c) "       @ revsh pc, r12")
-       TEST_UNSUPPORTED(__inst_arm(0xe6ffef3f) "       @ revsh r14, pc")
-
-       TEST_UNSUPPORTED(__inst_arm(0xe6900070) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe69fff7f) "") /* Unallocated space */
-
-       TEST_UNSUPPORTED(__inst_arm(0xe6d00070) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_arm(0xe6dfff7f) "") /* Unallocated space */
-#endif /* __LINUX_ARM_ARCH__ >= 6 */
-
-#if __LINUX_ARM_ARCH__ >= 6
-       TEST_GROUP("Signed multiplies")
-
-       TEST_RRR(   "smlad      r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
-       TEST_RRR(   "smlad      r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe70f8a1c) "       @ smlad pc, r12, r10, r8")
-       TEST_RRR(   "smladx     r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
-       TEST_RRR(   "smladx     r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe70f8a3c) "       @ smladx        pc, r12, r10, r8")
-
-       TEST_RR(   "smuad       r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(   "smuad       r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe70ffa1c) "       @ smuad pc, r12, r10")
-       TEST_RR(   "smuadx      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(   "smuadx      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe70ffa3c) "       @ smuadx        pc, r12, r10")
-
-       TEST_RRR(   "smlsd      r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
-       TEST_RRR(   "smlsd      r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe70f8a5c) "       @ smlsd pc, r12, r10, r8")
-       TEST_RRR(   "smlsdx     r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
-       TEST_RRR(   "smlsdx     r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe70f8a7c) "       @ smlsdx        pc, r12, r10, r8")
-
-       TEST_RR(   "smusd       r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(   "smusd       r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe70ffa5c) "       @ smusd pc, r12, r10")
-       TEST_RR(   "smusdx      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(   "smusdx      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe70ffa7c) "       @ smusdx        pc, r12, r10")
-
-       TEST_RRRR( "smlald      r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
-       TEST_RRRR( "smlald      r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
-       TEST_UNSUPPORTED(__inst_arm(0xe74af819) "       @ smlald        pc, r10, r9, r8")
-       TEST_UNSUPPORTED(__inst_arm(0xe74fb819) "       @ smlald        r11, pc, r9, r8")
-       TEST_UNSUPPORTED(__inst_arm(0xe74ab81f) "       @ smlald        r11, r10, pc, r8")
-       TEST_UNSUPPORTED(__inst_arm(0xe74abf19) "       @ smlald        r11, r10, r9, pc")
-
-       TEST_RRRR( "smlaldx     r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
-       TEST_RRRR( "smlaldx     r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
-       TEST_UNSUPPORTED(__inst_arm(0xe74af839) "       @ smlaldx       pc, r10, r9, r8")
-       TEST_UNSUPPORTED(__inst_arm(0xe74fb839) "       @ smlaldx       r11, pc, r9, r8")
-
-       TEST_RRR(  "smmla       r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
-       TEST_RRR(  "smmla       r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe75f8a1c) "       @ smmla pc, r12, r10, r8")
-       TEST_RRR(  "smmlar      r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
-       TEST_RRR(  "smmlar      r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe75f8a3c) "       @ smmlar        pc, r12, r10, r8")
-
-       TEST_RR(   "smmul       r0, r",0,  VAL1,", r",1, VAL2,"")
-       TEST_RR(   "smmul       r14, r",12,VAL2,", r",10,VAL1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe75ffa1c) "       @ smmul pc, r12, r10")
-       TEST_RR(   "smmulr      r0, r",0,  VAL1,", r",1, VAL2,"")
-       TEST_RR(   "smmulr      r14, r",12,VAL2,", r",10,VAL1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe75ffa3c) "       @ smmulr        pc, r12, r10")
-
-       TEST_RRR(  "smmls       r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
-       TEST_RRR(  "smmls       r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe75f8adc) "       @ smmls pc, r12, r10, r8")
-       TEST_RRR(  "smmlsr      r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
-       TEST_RRR(  "smmlsr      r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe75f8afc) "       @ smmlsr        pc, r12, r10, r8")
-       TEST_UNSUPPORTED(__inst_arm(0xe75e8aff) "       @ smmlsr        r14, pc, r10, r8")
-       TEST_UNSUPPORTED(__inst_arm(0xe75e8ffc) "       @ smmlsr        r14, r12, pc, r8")
-       TEST_UNSUPPORTED(__inst_arm(0xe75efafc) "       @ smmlsr        r14, r12, r10, pc")
-
-       TEST_RR(   "usad8       r0, r",0,  VAL1,", r",1, VAL2,"")
-       TEST_RR(   "usad8       r14, r",12,VAL2,", r",10,VAL1,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe75ffa1c) "       @ usad8 pc, r12, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe75efa1f) "       @ usad8 r14, pc, r10")
-       TEST_UNSUPPORTED(__inst_arm(0xe75eff1c) "       @ usad8 r14, r12, pc")
-
-       TEST_RRR(  "usada8      r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL3,"")
-       TEST_RRR(  "usada8      r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL3,"")
-       TEST_UNSUPPORTED(__inst_arm(0xe78f8a1c) "       @ usada8        pc, r12, r10, r8")
-       TEST_UNSUPPORTED(__inst_arm(0xe78e8a1f) "       @ usada8        r14, pc, r10, r8")
-       TEST_UNSUPPORTED(__inst_arm(0xe78e8f1c) "       @ usada8        r14, r12, pc, r8")
-#endif /* __LINUX_ARM_ARCH__ >= 6 */
-
-#if __LINUX_ARM_ARCH__ >= 7
-       TEST_GROUP("Bit Field")
-
-       TEST_R(     "sbfx       r0, r",0  , VAL1,", #0, #31")
-       TEST_R(     "sbfxeq     r14, r",12, VAL2,", #8, #16")
-       TEST_R(     "sbfx       r4, r",10,  VAL1,", #16, #15")
-       TEST_UNSUPPORTED(__inst_arm(0xe7aff45c) "       @ sbfx  pc, r12, #8, #16")
-
-       TEST_R(     "ubfx       r0, r",0  , VAL1,", #0, #31")
-       TEST_R(     "ubfxcs     r14, r",12, VAL2,", #8, #16")
-       TEST_R(     "ubfx       r4, r",10,  VAL1,", #16, #15")
-       TEST_UNSUPPORTED(__inst_arm(0xe7eff45c) "       @ ubfx  pc, r12, #8, #16")
-       TEST_UNSUPPORTED(__inst_arm(0xe7efc45f) "       @ ubfx  r12, pc, #8, #16")
-
-       TEST_R(     "bfc        r",0, VAL1,", #4, #20")
-       TEST_R(     "bfcvs      r",14,VAL2,", #4, #20")
-       TEST_R(     "bfc        r",7, VAL1,", #0, #31")
-       TEST_R(     "bfc        r",8, VAL2,", #0, #31")
-       TEST_UNSUPPORTED(__inst_arm(0xe7def01f) "       @ bfc   pc, #0, #31");
-
-       TEST_RR(    "bfi        r",0, VAL1,", r",0  , VAL2,", #0, #31")
-       TEST_RR(    "bfipl      r",12,VAL1,", r",14 , VAL2,", #4, #20")
-       TEST_UNSUPPORTED(__inst_arm(0xe7d7f21e) "       @ bfi   pc, r14, #4, #20")
-
-       TEST_UNSUPPORTED(__inst_arm(0x07f000f0) "")  /* Permanently UNDEFINED */
-       TEST_UNSUPPORTED(__inst_arm(0x07ffffff) "")  /* Permanently UNDEFINED */
-#endif /* __LINUX_ARM_ARCH__ >= 6 */
-
-       TEST_GROUP("Branch, branch with link, and block data transfer")
-
-       TEST_P(   "stmda        r",0, 16*4,", {r0}")
-       TEST_P(   "stmeqda      r",4, 16*4,", {r0-r15}")
-       TEST_P(   "stmneda      r",8, 16*4,"!, {r8-r15}")
-       TEST_P(   "stmda        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-       TEST_P(   "stmda        r",13,0,   "!, {pc}")
-
-       TEST_P(   "ldmda        r",0, 16*4,", {r0}")
-       TEST_BF_P("ldmcsda      r",4, 15*4,", {r0-r15}")
-       TEST_BF_P("ldmccda      r",7, 15*4,"!, {r8-r15}")
-       TEST_P(   "ldmda        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-       TEST_BF_P("ldmda        r",14,15*4,"!, {pc}")
-
-       TEST_P(   "stmia        r",0, 16*4,", {r0}")
-       TEST_P(   "stmmiia      r",4, 16*4,", {r0-r15}")
-       TEST_P(   "stmplia      r",8, 16*4,"!, {r8-r15}")
-       TEST_P(   "stmia        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-       TEST_P(   "stmia        r",14,0,   "!, {pc}")
-
-       TEST_P(   "ldmia        r",0, 16*4,", {r0}")
-       TEST_BF_P("ldmvsia      r",4, 0,   ", {r0-r15}")
-       TEST_BF_P("ldmvcia      r",7, 8*4, "!, {r8-r15}")
-       TEST_P(   "ldmia        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-       TEST_BF_P("ldmia        r",14,15*4,"!, {pc}")
-
-       TEST_P(   "stmdb        r",0, 16*4,", {r0}")
-       TEST_P(   "stmhidb      r",4, 16*4,", {r0-r15}")
-       TEST_P(   "stmlsdb      r",8, 16*4,"!, {r8-r15}")
-       TEST_P(   "stmdb        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-       TEST_P(   "stmdb        r",13,4,   "!, {pc}")
-
-       TEST_P(   "ldmdb        r",0, 16*4,", {r0}")
-       TEST_BF_P("ldmgedb      r",4, 16*4,", {r0-r15}")
-       TEST_BF_P("ldmltdb      r",7, 16*4,"!, {r8-r15}")
-       TEST_P(   "ldmdb        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-       TEST_BF_P("ldmdb        r",14,16*4,"!, {pc}")
-
-       TEST_P(   "stmib        r",0, 16*4,", {r0}")
-       TEST_P(   "stmgtib      r",4, 16*4,", {r0-r15}")
-       TEST_P(   "stmleib      r",8, 16*4,"!, {r8-r15}")
-       TEST_P(   "stmib        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-       TEST_P(   "stmib        r",13,-4,  "!, {pc}")
-
-       TEST_P(   "ldmib        r",0, 16*4,", {r0}")
-       TEST_BF_P("ldmeqib      r",4, -4,", {r0-r15}")
-       TEST_BF_P("ldmneib      r",7, 7*4,"!, {r8-r15}")
-       TEST_P(   "ldmib        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-       TEST_BF_P("ldmib        r",14,14*4,"!, {pc}")
-
-       TEST_P(   "stmdb        r",13,16*4,"!, {r3-r12,lr}")
-       TEST_P(   "stmeqdb      r",13,16*4,"!, {r3-r12}")
-       TEST_P(   "stmnedb      r",2, 16*4,", {r3-r12,lr}")
-       TEST_P(   "stmdb        r",13,16*4,"!, {r2-r12,lr}")
-       TEST_P(   "stmdb        r",0, 16*4,", {r0-r12}")
-       TEST_P(   "stmdb        r",0, 16*4,", {r0-r12,lr}")
-
-       TEST_BF_P("ldmia        r",13,5*4, "!, {r3-r12,pc}")
-       TEST_P(   "ldmccia      r",13,5*4, "!, {r3-r12}")
-       TEST_BF_P("ldmcsia      r",2, 5*4, "!, {r3-r12,pc}")
-       TEST_BF_P("ldmia        r",13,4*4, "!, {r2-r12,pc}")
-       TEST_P(   "ldmia        r",0, 16*4,", {r0-r12}")
-       TEST_P(   "ldmia        r",0, 16*4,", {r0-r12,lr}")
-
-#ifdef CONFIG_THUMB2_KERNEL
-       TEST_ARM_TO_THUMB_INTERWORK_P("ldmplia  r",0,15*4,", {pc}")
-       TEST_ARM_TO_THUMB_INTERWORK_P("ldmmiia  r",13,0,", {r0-r15}")
-#endif
-       TEST_BF("b      2f")
-       TEST_BF("bl     2f")
-       TEST_BB("b      2b")
-       TEST_BB("bl     2b")
-
-       TEST_BF("beq    2f")
-       TEST_BF("bleq   2f")
-       TEST_BB("bne    2b")
-       TEST_BB("blne   2b")
-
-       TEST_BF("bgt    2f")
-       TEST_BF("blgt   2f")
-       TEST_BB("blt    2b")
-       TEST_BB("bllt   2b")
-
-       TEST_GROUP("Supervisor Call, and coprocessor instructions")
-
-       /*
-        * We can't really test these by executing them, so all
-        * we can do is check that probes are, or are not allowed.
-        * At the moment none are allowed...
-        */
-#define TEST_COPROCESSOR(code) TEST_UNSUPPORTED(code)
-
-#define COPROCESSOR_INSTRUCTIONS_ST_LD(two,cc)                                 \
-       TEST_COPROCESSOR("stc"two"      0, cr0, [r13, #4]")                     \
-       TEST_COPROCESSOR("stc"two"      0, cr0, [r13, #-4]")                    \
-       TEST_COPROCESSOR("stc"two"      0, cr0, [r13, #4]!")                    \
-       TEST_COPROCESSOR("stc"two"      0, cr0, [r13, #-4]!")                   \
-       TEST_COPROCESSOR("stc"two"      0, cr0, [r13], #4")                     \
-       TEST_COPROCESSOR("stc"two"      0, cr0, [r13], #-4")                    \
-       TEST_COPROCESSOR("stc"two"      0, cr0, [r13], {1}")                    \
-       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13, #4]")                     \
-       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13, #-4]")                    \
-       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13, #4]!")                    \
-       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13, #-4]!")                   \
-       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13], #4")                     \
-       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13], #-4")                    \
-       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13], {1}")                    \
-       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13, #4]")                     \
-       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13, #-4]")                    \
-       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13, #4]!")                    \
-       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13, #-4]!")                   \
-       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13], #4")                     \
-       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13], #-4")                    \
-       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13], {1}")                    \
-       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13, #4]")                     \
-       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13, #-4]")                    \
-       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13, #4]!")                    \
-       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13, #-4]!")                   \
-       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13], #4")                     \
-       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13], #-4")                    \
-       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13], {1}")                    \
-                                                                               \
-       TEST_COPROCESSOR( "stc"two"     0, cr0, [r15, #4]")                     \
-       TEST_COPROCESSOR( "stc"two"     0, cr0, [r15, #-4]")                    \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##daf0001) "  @ stc"two"      0, cr0, [r15, #4]!")    \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##d2f0001) "  @ stc"two"      0, cr0, [r15, #-4]!")   \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##caf0001) "  @ stc"two"      0, cr0, [r15], #4")     \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##c2f0001) "  @ stc"two"      0, cr0, [r15], #-4")    \
-       TEST_COPROCESSOR( "stc"two"     0, cr0, [r15], {1}")                    \
-       TEST_COPROCESSOR( "stc"two"l    0, cr0, [r15, #4]")                     \
-       TEST_COPROCESSOR( "stc"two"l    0, cr0, [r15, #-4]")                    \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##def0001) "  @ stc"two"l     0, cr0, [r15, #4]!")    \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##d6f0001) "  @ stc"two"l     0, cr0, [r15, #-4]!")   \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##cef0001) "  @ stc"two"l     0, cr0, [r15], #4")     \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##c6f0001) "  @ stc"two"l     0, cr0, [r15], #-4")    \
-       TEST_COPROCESSOR( "stc"two"l    0, cr0, [r15], {1}")                    \
-       TEST_COPROCESSOR( "ldc"two"     0, cr0, [r15, #4]")                     \
-       TEST_COPROCESSOR( "ldc"two"     0, cr0, [r15, #-4]")                    \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##dbf0001) "  @ ldc"two"      0, cr0, [r15, #4]!")    \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##d3f0001) "  @ ldc"two"      0, cr0, [r15, #-4]!")   \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##cbf0001) "  @ ldc"two"      0, cr0, [r15], #4")     \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##c3f0001) "  @ ldc"two"      0, cr0, [r15], #-4")    \
-       TEST_COPROCESSOR( "ldc"two"     0, cr0, [r15], {1}")                    \
-       TEST_COPROCESSOR( "ldc"two"l    0, cr0, [r15, #4]")                     \
-       TEST_COPROCESSOR( "ldc"two"l    0, cr0, [r15, #-4]")                    \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##dff0001) "  @ ldc"two"l     0, cr0, [r15, #4]!")    \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##d7f0001) "  @ ldc"two"l     0, cr0, [r15, #-4]!")   \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##cff0001) "  @ ldc"two"l     0, cr0, [r15], #4")     \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##c7f0001) "  @ ldc"two"l     0, cr0, [r15], #-4")    \
-       TEST_COPROCESSOR( "ldc"two"l    0, cr0, [r15], {1}")
-
-#define COPROCESSOR_INSTRUCTIONS_MC_MR(two,cc)                                 \
-                                                                               \
-       TEST_COPROCESSOR( "mcrr"two"    0, 15, r0, r14, cr0")                   \
-       TEST_COPROCESSOR( "mcrr"two"    15, 0, r14, r0, cr15")                  \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##c4f00f0) "  @ mcrr"two"     0, 15, r0, r15, cr0")   \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##c40ff0f) "  @ mcrr"two"     15, 0, r15, r0, cr15")  \
-       TEST_COPROCESSOR( "mrrc"two"    0, 15, r0, r14, cr0")                   \
-       TEST_COPROCESSOR( "mrrc"two"    15, 0, r14, r0, cr15")                  \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##c5f00f0) "  @ mrrc"two"     0, 15, r0, r15, cr0")   \
-       TEST_UNSUPPORTED(__inst_arm(0x##cc##c50ff0f) "  @ mrrc"two"     15, 0, r15, r0, cr15")  \
-       TEST_COPROCESSOR( "cdp"two"     15, 15, cr15, cr15, cr15, 7")           \
-       TEST_COPROCESSOR( "cdp"two"     0, 0, cr0, cr0, cr0, 0")                \
-       TEST_COPROCESSOR( "mcr"two"     15, 7, r15, cr15, cr15, 7")             \
-       TEST_COPROCESSOR( "mcr"two"     0, 0, r0, cr0, cr0, 0")                 \
-       TEST_COPROCESSOR( "mrc"two"     15, 7, r15, cr15, cr15, 7")             \
-       TEST_COPROCESSOR( "mrc"two"     0, 0, r0, cr0, cr0, 0")
-
-       COPROCESSOR_INSTRUCTIONS_ST_LD("",e)
-#if __LINUX_ARM_ARCH__ >= 5
-       COPROCESSOR_INSTRUCTIONS_MC_MR("",e)
-#endif
-       TEST_UNSUPPORTED("svc   0")
-       TEST_UNSUPPORTED("svc   0xffffff")
-
-       TEST_UNSUPPORTED("svc   0")
-
-       TEST_GROUP("Unconditional instruction")
-
-#if __LINUX_ARM_ARCH__ >= 6
-       TEST_UNSUPPORTED("srsda sp, 0x13")
-       TEST_UNSUPPORTED("srsdb sp, 0x13")
-       TEST_UNSUPPORTED("srsia sp, 0x13")
-       TEST_UNSUPPORTED("srsib sp, 0x13")
-       TEST_UNSUPPORTED("srsda sp!, 0x13")
-       TEST_UNSUPPORTED("srsdb sp!, 0x13")
-       TEST_UNSUPPORTED("srsia sp!, 0x13")
-       TEST_UNSUPPORTED("srsib sp!, 0x13")
-
-       TEST_UNSUPPORTED("rfeda sp")
-       TEST_UNSUPPORTED("rfedb sp")
-       TEST_UNSUPPORTED("rfeia sp")
-       TEST_UNSUPPORTED("rfeib sp")
-       TEST_UNSUPPORTED("rfeda sp!")
-       TEST_UNSUPPORTED("rfedb sp!")
-       TEST_UNSUPPORTED("rfeia sp!")
-       TEST_UNSUPPORTED("rfeib sp!")
-       TEST_UNSUPPORTED(__inst_arm(0xf81d0a00) "       @ rfeda pc")
-       TEST_UNSUPPORTED(__inst_arm(0xf91d0a00) "       @ rfedb pc")
-       TEST_UNSUPPORTED(__inst_arm(0xf89d0a00) "       @ rfeia pc")
-       TEST_UNSUPPORTED(__inst_arm(0xf99d0a00) "       @ rfeib pc")
-       TEST_UNSUPPORTED(__inst_arm(0xf83d0a00) "       @ rfeda pc!")
-       TEST_UNSUPPORTED(__inst_arm(0xf93d0a00) "       @ rfedb pc!")
-       TEST_UNSUPPORTED(__inst_arm(0xf8bd0a00) "       @ rfeia pc!")
-       TEST_UNSUPPORTED(__inst_arm(0xf9bd0a00) "       @ rfeib pc!")
-#endif /* __LINUX_ARM_ARCH__ >= 6 */
-
-#if __LINUX_ARM_ARCH__ >= 6
-       TEST_X( "blx    __dummy_thumb_subroutine_even",
-               ".thumb                         \n\t"
-               ".space 4                       \n\t"
-               ".type __dummy_thumb_subroutine_even, %%function \n\t"
-               "__dummy_thumb_subroutine_even: \n\t"
-               "mov    r0, pc                  \n\t"
-               "bx     lr                      \n\t"
-               ".arm                           \n\t"
-       )
-       TEST(   "blx    __dummy_thumb_subroutine_even")
-
-       TEST_X( "blx    __dummy_thumb_subroutine_odd",
-               ".thumb                         \n\t"
-               ".space 2                       \n\t"
-               ".type __dummy_thumb_subroutine_odd, %%function \n\t"
-               "__dummy_thumb_subroutine_odd:  \n\t"
-               "mov    r0, pc                  \n\t"
-               "bx     lr                      \n\t"
-               ".arm                           \n\t"
-       )
-       TEST(   "blx    __dummy_thumb_subroutine_odd")
-#endif /* __LINUX_ARM_ARCH__ >= 6 */
-
-#if __LINUX_ARM_ARCH__ >= 5
-       COPROCESSOR_INSTRUCTIONS_ST_LD("2",f)
-#endif
-#if __LINUX_ARM_ARCH__ >= 6
-       COPROCESSOR_INSTRUCTIONS_MC_MR("2",f)
-#endif
-
-       TEST_GROUP("Miscellaneous instructions, memory hints, and Advanced SIMD instructions")
-
-#if __LINUX_ARM_ARCH__ >= 6
-       TEST_UNSUPPORTED("cps   0x13")
-       TEST_UNSUPPORTED("cpsie i")
-       TEST_UNSUPPORTED("cpsid i")
-       TEST_UNSUPPORTED("cpsie i,0x13")
-       TEST_UNSUPPORTED("cpsid i,0x13")
-       TEST_UNSUPPORTED("setend        le")
-       TEST_UNSUPPORTED("setend        be")
-#endif
-
-#if __LINUX_ARM_ARCH__ >= 7
-       TEST_P("pli     [r",0,0b,", #16]")
-       TEST(  "pli     [pc, #0]")
-       TEST_RR("pli    [r",12,0b,", r",0, 16,"]")
-       TEST_RR("pli    [r",0, 0b,", -r",12,16,", lsl #4]")
-#endif
-
-#if __LINUX_ARM_ARCH__ >= 5
-       TEST_P("pld     [r",0,32,", #-16]")
-       TEST(  "pld     [pc, #0]")
-       TEST_PR("pld    [r",7, 24, ", r",0, 16,"]")
-       TEST_PR("pld    [r",8, 24, ", -r",12,16,", lsl #4]")
-#endif
-
-#if __LINUX_ARM_ARCH__ >= 7
-       TEST_SUPPORTED(  __inst_arm(0xf590f000) "       @ pldw [r0, #0]")
-       TEST_SUPPORTED(  __inst_arm(0xf797f000) "       @ pldw  [r7, r0]")
-       TEST_SUPPORTED(  __inst_arm(0xf798f18c) "       @ pldw  [r8, r12, lsl #3]");
-#endif
-
-#if __LINUX_ARM_ARCH__ >= 7
-       TEST_UNSUPPORTED("clrex")
-       TEST_UNSUPPORTED("dsb")
-       TEST_UNSUPPORTED("dmb")
-       TEST_UNSUPPORTED("isb")
-#endif
-
-       verbose("\n");
-}
-
diff --git a/arch/arm/kernel/kprobes-test-thumb.c b/arch/arm/kernel/kprobes-test-thumb.c
deleted file mode 100644 (file)
index 844dd10..0000000
+++ /dev/null
@@ -1,1188 +0,0 @@
-/*
- * arch/arm/kernel/kprobes-test-thumb.c
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/opcodes.h>
-
-#include "kprobes-test.h"
-
-
-#define TEST_ISA "16"
-
-#define DONT_TEST_IN_ITBLOCK(tests)                    \
-       kprobe_test_flags |= TEST_FLAG_NO_ITBLOCK;      \
-       tests                                           \
-       kprobe_test_flags &= ~TEST_FLAG_NO_ITBLOCK;
-
-#define CONDITION_INSTRUCTIONS(cc_pos, tests)          \
-       kprobe_test_cc_position = cc_pos;               \
-       DONT_TEST_IN_ITBLOCK(tests)                     \
-       kprobe_test_cc_position = 0;
-
-#define TEST_ITBLOCK(code)                             \
-       kprobe_test_flags |= TEST_FLAG_FULL_ITBLOCK;    \
-       TESTCASE_START(code)                            \
-       TEST_ARG_END("")                                \
-       "50:    nop                     \n\t"           \
-       "1:     "code"                  \n\t"           \
-       "       mov r1, #0x11           \n\t"           \
-       "       mov r2, #0x22           \n\t"           \
-       "       mov r3, #0x33           \n\t"           \
-       "2:     nop                     \n\t"           \
-       TESTCASE_END                                    \
-       kprobe_test_flags &= ~TEST_FLAG_FULL_ITBLOCK;
-
-#define TEST_THUMB_TO_ARM_INTERWORK_P(code1, reg, val, code2)  \
-       TESTCASE_START(code1 #reg code2)                        \
-       TEST_ARG_PTR(reg, val)                                  \
-       TEST_ARG_REG(14, 99f+1)                                 \
-       TEST_ARG_MEM(15, 3f)                                    \
-       TEST_ARG_END("")                                        \
-       "       nop                     \n\t" /* To align 1f */ \
-       "50:    nop                     \n\t"                   \
-       "1:     "code1 #reg code2"      \n\t"                   \
-       "       bx      lr              \n\t"                   \
-       ".arm                           \n\t"                   \
-       "3:     adr     lr, 2f+1        \n\t"                   \
-       "       bx      lr              \n\t"                   \
-       ".thumb                         \n\t"                   \
-       "2:     nop                     \n\t"                   \
-       TESTCASE_END
-
-
-void kprobe_thumb16_test_cases(void)
-{
-       kprobe_test_flags = TEST_FLAG_NARROW_INSTR;
-
-       TEST_GROUP("Shift (immediate), add, subtract, move, and compare")
-
-       TEST_R(    "lsls        r7, r",0,VAL1,", #5")
-       TEST_R(    "lsls        r0, r",7,VAL2,", #11")
-       TEST_R(    "lsrs        r7, r",0,VAL1,", #5")
-       TEST_R(    "lsrs        r0, r",7,VAL2,", #11")
-       TEST_R(    "asrs        r7, r",0,VAL1,", #5")
-       TEST_R(    "asrs        r0, r",7,VAL2,", #11")
-       TEST_RR(   "adds        r2, r",0,VAL1,", r",7,VAL2,"")
-       TEST_RR(   "adds        r5, r",7,VAL2,", r",0,VAL2,"")
-       TEST_RR(   "subs        r2, r",0,VAL1,", r",7,VAL2,"")
-       TEST_RR(   "subs        r5, r",7,VAL2,", r",0,VAL2,"")
-       TEST_R(    "adds        r7, r",0,VAL1,", #5")
-       TEST_R(    "adds        r0, r",7,VAL2,", #2")
-       TEST_R(    "subs        r7, r",0,VAL1,", #5")
-       TEST_R(    "subs        r0, r",7,VAL2,", #2")
-       TEST(      "movs.n      r0, #0x5f")
-       TEST(      "movs.n      r7, #0xa0")
-       TEST_R(    "cmp.n       r",0,0x5e, ", #0x5f")
-       TEST_R(    "cmp.n       r",5,0x15f,", #0x5f")
-       TEST_R(    "cmp.n       r",7,0xa0, ", #0xa0")
-       TEST_R(    "adds.n      r",0,VAL1,", #0x5f")
-       TEST_R(    "adds.n      r",7,VAL2,", #0xa0")
-       TEST_R(    "subs.n      r",0,VAL1,", #0x5f")
-       TEST_R(    "subs.n      r",7,VAL2,", #0xa0")
-
-       TEST_GROUP("16-bit Thumb data-processing instructions")
-
-#define DATA_PROCESSING16(op,val)                      \
-       TEST_RR(   op"  r",0,VAL1,", r",7,val,"")       \
-       TEST_RR(   op"  r",7,VAL2,", r",0,val,"")
-
-       DATA_PROCESSING16("ands",0xf00f00ff)
-       DATA_PROCESSING16("eors",0xf00f00ff)
-       DATA_PROCESSING16("lsls",11)
-       DATA_PROCESSING16("lsrs",11)
-       DATA_PROCESSING16("asrs",11)
-       DATA_PROCESSING16("adcs",VAL2)
-       DATA_PROCESSING16("sbcs",VAL2)
-       DATA_PROCESSING16("rors",11)
-       DATA_PROCESSING16("tst",0xf00f00ff)
-       TEST_R("rsbs    r",0,VAL1,", #0")
-       TEST_R("rsbs    r",7,VAL2,", #0")
-       DATA_PROCESSING16("cmp",0xf00f00ff)
-       DATA_PROCESSING16("cmn",0xf00f00ff)
-       DATA_PROCESSING16("orrs",0xf00f00ff)
-       DATA_PROCESSING16("muls",VAL2)
-       DATA_PROCESSING16("bics",0xf00f00ff)
-       DATA_PROCESSING16("mvns",VAL2)
-
-       TEST_GROUP("Special data instructions and branch and exchange")
-
-       TEST_RR(  "add  r",0, VAL1,", r",7,VAL2,"")
-       TEST_RR(  "add  r",3, VAL2,", r",8,VAL3,"")
-       TEST_RR(  "add  r",8, VAL3,", r",0,VAL1,"")
-       TEST_R(   "add  sp"        ", r",8,-8,  "")
-       TEST_R(   "add  r",14,VAL1,", pc")
-       TEST_BF_R("add  pc"        ", r",0,2f-1f-8,"")
-       TEST_UNSUPPORTED(__inst_thumb16(0x44ff) "       @ add pc, pc")
-
-       TEST_RR(  "cmp  r",3,VAL1,", r",8,VAL2,"")
-       TEST_RR(  "cmp  r",8,VAL2,", r",0,VAL1,"")
-       TEST_R(   "cmp  sp"       ", r",8,-8,  "")
-
-       TEST_R(   "mov  r0, r",7,VAL2,"")
-       TEST_R(   "mov  r3, r",8,VAL3,"")
-       TEST_R(   "mov  r8, r",0,VAL1,"")
-       TEST_P(   "mov  sp, r",8,-8,  "")
-       TEST(     "mov  lr, pc")
-       TEST_BF_R("mov  pc, r",0,2f,  "")
-
-       TEST_BF_R("bx   r",0, 2f+1,"")
-       TEST_BF_R("bx   r",14,2f+1,"")
-       TESTCASE_START("bx      pc")
-               TEST_ARG_REG(14, 99f+1)
-               TEST_ARG_END("")
-               "       nop                     \n\t" /* To align the bx pc*/
-               "50:    nop                     \n\t"
-               "1:     bx      pc              \n\t"
-               "       bx      lr              \n\t"
-               ".arm                           \n\t"
-               "       adr     lr, 2f+1        \n\t"
-               "       bx      lr              \n\t"
-               ".thumb                         \n\t"
-               "2:     nop                     \n\t"
-       TESTCASE_END
-
-       TEST_BF_R("blx  r",0, 2f+1,"")
-       TEST_BB_R("blx  r",14,2f+1,"")
-       TEST_UNSUPPORTED(__inst_thumb16(0x47f8) "       @ blx pc")
-
-       TEST_GROUP("Load from Literal Pool")
-
-       TEST_X( "ldr    r0, 3f",
-               ".align                                 \n\t"
-               "3:     .word   "__stringify(VAL1))
-       TEST_X( "ldr    r7, 3f",
-               ".space 128                             \n\t"
-               ".align                                 \n\t"
-               "3:     .word   "__stringify(VAL2))
-
-       TEST_GROUP("16-bit Thumb Load/store instructions")
-
-       TEST_RPR("str   r",0, VAL1,", [r",1, 24,", r",2,  48,"]")
-       TEST_RPR("str   r",7, VAL2,", [r",6, 24,", r",5,  48,"]")
-       TEST_RPR("strh  r",0, VAL1,", [r",1, 24,", r",2,  48,"]")
-       TEST_RPR("strh  r",7, VAL2,", [r",6, 24,", r",5,  48,"]")
-       TEST_RPR("strb  r",0, VAL1,", [r",1, 24,", r",2,  48,"]")
-       TEST_RPR("strb  r",7, VAL2,", [r",6, 24,", r",5,  48,"]")
-       TEST_PR( "ldrsb r0, [r",1, 24,", r",2,  48,"]")
-       TEST_PR( "ldrsb r7, [r",6, 24,", r",5,  50,"]")
-       TEST_PR( "ldr   r0, [r",1, 24,", r",2,  48,"]")
-       TEST_PR( "ldr   r7, [r",6, 24,", r",5,  48,"]")
-       TEST_PR( "ldrh  r0, [r",1, 24,", r",2,  48,"]")
-       TEST_PR( "ldrh  r7, [r",6, 24,", r",5,  50,"]")
-       TEST_PR( "ldrb  r0, [r",1, 24,", r",2,  48,"]")
-       TEST_PR( "ldrb  r7, [r",6, 24,", r",5,  50,"]")
-       TEST_PR( "ldrsh r0, [r",1, 24,", r",2,  48,"]")
-       TEST_PR( "ldrsh r7, [r",6, 24,", r",5,  50,"]")
-
-       TEST_RP("str    r",0, VAL1,", [r",1, 24,", #120]")
-       TEST_RP("str    r",7, VAL2,", [r",6, 24,", #120]")
-       TEST_P( "ldr    r0, [r",1, 24,", #120]")
-       TEST_P( "ldr    r7, [r",6, 24,", #120]")
-       TEST_RP("strb   r",0, VAL1,", [r",1, 24,", #30]")
-       TEST_RP("strb   r",7, VAL2,", [r",6, 24,", #30]")
-       TEST_P( "ldrb   r0, [r",1, 24,", #30]")
-       TEST_P( "ldrb   r7, [r",6, 24,", #30]")
-       TEST_RP("strh   r",0, VAL1,", [r",1, 24,", #60]")
-       TEST_RP("strh   r",7, VAL2,", [r",6, 24,", #60]")
-       TEST_P( "ldrh   r0, [r",1, 24,", #60]")
-       TEST_P( "ldrh   r7, [r",6, 24,", #60]")
-
-       TEST_R( "str    r",0, VAL1,", [sp, #0]")
-       TEST_R( "str    r",7, VAL2,", [sp, #160]")
-       TEST(   "ldr    r0, [sp, #0]")
-       TEST(   "ldr    r7, [sp, #160]")
-
-       TEST_RP("str    r",0, VAL1,", [r",0, 24,"]")
-       TEST_P( "ldr    r0, [r",0, 24,"]")
-
-       TEST_GROUP("Generate PC-/SP-relative address")
-
-       TEST("add       r0, pc, #4")
-       TEST("add       r7, pc, #1020")
-       TEST("add       r0, sp, #4")
-       TEST("add       r7, sp, #1020")
-
-       TEST_GROUP("Miscellaneous 16-bit instructions")
-
-       TEST_UNSUPPORTED( "cpsie        i")
-       TEST_UNSUPPORTED( "cpsid        i")
-       TEST_UNSUPPORTED( "setend       le")
-       TEST_UNSUPPORTED( "setend       be")
-
-       TEST("add       sp, #"__stringify(TEST_MEMORY_SIZE)) /* Assumes TEST_MEMORY_SIZE < 0x400 */
-       TEST("sub       sp, #0x7f*4")
-
-DONT_TEST_IN_ITBLOCK(
-       TEST_BF_R(  "cbnz       r",0,0, ", 2f")
-       TEST_BF_R(  "cbz        r",2,-1,", 2f")
-       TEST_BF_RX( "cbnz       r",4,1, ", 2f", SPACE_0x20)
-       TEST_BF_RX( "cbz        r",7,0, ", 2f", SPACE_0x40)
-)
-       TEST_R("sxth    r0, r",7, HH1,"")
-       TEST_R("sxth    r7, r",0, HH2,"")
-       TEST_R("sxtb    r0, r",7, HH1,"")
-       TEST_R("sxtb    r7, r",0, HH2,"")
-       TEST_R("uxth    r0, r",7, HH1,"")
-       TEST_R("uxth    r7, r",0, HH2,"")
-       TEST_R("uxtb    r0, r",7, HH1,"")
-       TEST_R("uxtb    r7, r",0, HH2,"")
-       TEST_R("rev     r0, r",7, VAL1,"")
-       TEST_R("rev     r7, r",0, VAL2,"")
-       TEST_R("rev16   r0, r",7, VAL1,"")
-       TEST_R("rev16   r7, r",0, VAL2,"")
-       TEST_UNSUPPORTED(__inst_thumb16(0xba80) "")
-       TEST_UNSUPPORTED(__inst_thumb16(0xbabf) "")
-       TEST_R("revsh   r0, r",7, VAL1,"")
-       TEST_R("revsh   r7, r",0, VAL2,"")
-
-#define TEST_POPPC(code, offset)       \
-       TESTCASE_START(code)            \
-       TEST_ARG_PTR(13, offset)        \
-       TEST_ARG_END("")                \
-       TEST_BRANCH_F(code)             \
-       TESTCASE_END
-
-       TEST("push      {r0}")
-       TEST("push      {r7}")
-       TEST("push      {r14}")
-       TEST("push      {r0-r7,r14}")
-       TEST("push      {r0,r2,r4,r6,r14}")
-       TEST("push      {r1,r3,r5,r7}")
-       TEST("pop       {r0}")
-       TEST("pop       {r7}")
-       TEST("pop       {r0,r2,r4,r6}")
-       TEST_POPPC("pop {pc}",15*4)
-       TEST_POPPC("pop {r0-r7,pc}",7*4)
-       TEST_POPPC("pop {r1,r3,r5,r7,pc}",11*4)
-       TEST_THUMB_TO_ARM_INTERWORK_P("pop      {pc}    @ ",13,15*4,"")
-       TEST_THUMB_TO_ARM_INTERWORK_P("pop      {r0-r7,pc}      @ ",13,7*4,"")
-
-       TEST_UNSUPPORTED("bkpt.n        0")
-       TEST_UNSUPPORTED("bkpt.n        255")
-
-       TEST_SUPPORTED("yield")
-       TEST("sev")
-       TEST("nop")
-       TEST("wfi")
-       TEST_SUPPORTED("wfe")
-       TEST_UNSUPPORTED(__inst_thumb16(0xbf50) "") /* Unassigned hints */
-       TEST_UNSUPPORTED(__inst_thumb16(0xbff0) "") /* Unassigned hints */
-
-#define TEST_IT(code, code2)                   \
-       TESTCASE_START(code)                    \
-       TEST_ARG_END("")                        \
-       "50:    nop                     \n\t"   \
-       "1:     "code"                  \n\t"   \
-       "       "code2"                 \n\t"   \
-       "2:     nop                     \n\t"   \
-       TESTCASE_END
-
-DONT_TEST_IN_ITBLOCK(
-       TEST_IT("it     eq","moveq r0,#0")
-       TEST_IT("it     vc","movvc r0,#0")
-       TEST_IT("it     le","movle r0,#0")
-       TEST_IT("ite    eq","moveq r0,#0\n\t  movne r1,#1")
-       TEST_IT("itet   vc","movvc r0,#0\n\t  movvs r1,#1\n\t  movvc r2,#2")
-       TEST_IT("itete  le","movle r0,#0\n\t  movgt r1,#1\n\t  movle r2,#2\n\t  movgt r3,#3")
-       TEST_IT("itttt  le","movle r0,#0\n\t  movle r1,#1\n\t  movle r2,#2\n\t  movle r3,#3")
-       TEST_IT("iteee  le","movle r0,#0\n\t  movgt r1,#1\n\t  movgt r2,#2\n\t  movgt r3,#3")
-)
-
-       TEST_GROUP("Load and store multiple")
-
-       TEST_P("ldmia   r",4, 16*4,"!, {r0,r7}")
-       TEST_P("ldmia   r",7, 16*4,"!, {r0-r6}")
-       TEST_P("stmia   r",4, 16*4,"!, {r0,r7}")
-       TEST_P("stmia   r",0, 16*4,"!, {r0-r7}")
-
-       TEST_GROUP("Conditional branch and Supervisor Call instructions")
-
-CONDITION_INSTRUCTIONS(8,
-       TEST_BF("beq    2f")
-       TEST_BB("bne    2b")
-       TEST_BF("bgt    2f")
-       TEST_BB("blt    2b")
-)
-       TEST_UNSUPPORTED(__inst_thumb16(0xde00) "")
-       TEST_UNSUPPORTED(__inst_thumb16(0xdeff) "")
-       TEST_UNSUPPORTED("svc   #0x00")
-       TEST_UNSUPPORTED("svc   #0xff")
-
-       TEST_GROUP("Unconditional branch")
-
-       TEST_BF(  "b    2f")
-       TEST_BB(  "b    2b")
-       TEST_BF_X("b    2f", SPACE_0x400)
-       TEST_BB_X("b    2b", SPACE_0x400)
-
-       TEST_GROUP("Testing instructions in IT blocks")
-
-       TEST_ITBLOCK("subs.n r0, r0")
-
-       verbose("\n");
-}
-
-
-void kprobe_thumb32_test_cases(void)
-{
-       kprobe_test_flags = 0;
-
-       TEST_GROUP("Load/store multiple")
-
-       TEST_UNSUPPORTED("rfedb sp")
-       TEST_UNSUPPORTED("rfeia sp")
-       TEST_UNSUPPORTED("rfedb sp!")
-       TEST_UNSUPPORTED("rfeia sp!")
-
-       TEST_P(   "stmia        r",0, 16*4,", {r0,r8}")
-       TEST_P(   "stmia        r",4, 16*4,", {r0-r12,r14}")
-       TEST_P(   "stmia        r",7, 16*4,"!, {r8-r12,r14}")
-       TEST_P(   "stmia        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-
-       TEST_P(   "ldmia        r",0, 16*4,", {r0,r8}")
-       TEST_P(   "ldmia        r",4, 0,   ", {r0-r12,r14}")
-       TEST_BF_P("ldmia        r",5, 8*4, "!, {r6-r12,r15}")
-       TEST_P(   "ldmia        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-       TEST_BF_P("ldmia        r",14,14*4,"!, {r4,pc}")
-
-       TEST_P(   "stmdb        r",0, 16*4,", {r0,r8}")
-       TEST_P(   "stmdb        r",4, 16*4,", {r0-r12,r14}")
-       TEST_P(   "stmdb        r",5, 16*4,"!, {r8-r12,r14}")
-       TEST_P(   "stmdb        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-
-       TEST_P(   "ldmdb        r",0, 16*4,", {r0,r8}")
-       TEST_P(   "ldmdb        r",4, 16*4,", {r0-r12,r14}")
-       TEST_BF_P("ldmdb        r",5, 16*4,"!, {r6-r12,r15}")
-       TEST_P(   "ldmdb        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
-       TEST_BF_P("ldmdb        r",14,16*4,"!, {r4,pc}")
-
-       TEST_P(   "stmdb        r",13,16*4,"!, {r3-r12,lr}")
-       TEST_P(   "stmdb        r",13,16*4,"!, {r3-r12}")
-       TEST_P(   "stmdb        r",2, 16*4,", {r3-r12,lr}")
-       TEST_P(   "stmdb        r",13,16*4,"!, {r2-r12,lr}")
-       TEST_P(   "stmdb        r",0, 16*4,", {r0-r12}")
-       TEST_P(   "stmdb        r",0, 16*4,", {r0-r12,lr}")
-
-       TEST_BF_P("ldmia        r",13,5*4, "!, {r3-r12,pc}")
-       TEST_P(   "ldmia        r",13,5*4, "!, {r3-r12}")
-       TEST_BF_P("ldmia        r",2, 5*4, "!, {r3-r12,pc}")
-       TEST_BF_P("ldmia        r",13,4*4, "!, {r2-r12,pc}")
-       TEST_P(   "ldmia        r",0, 16*4,", {r0-r12}")
-       TEST_P(   "ldmia        r",0, 16*4,", {r0-r12,lr}")
-
-       TEST_THUMB_TO_ARM_INTERWORK_P("ldmia    r",0,14*4,", {r12,pc}")
-       TEST_THUMB_TO_ARM_INTERWORK_P("ldmia    r",13,2*4,", {r0-r12,pc}")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xe88f0101) "   @ stmia pc, {r0,r8}")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe92f5f00) "   @ stmdb pc!, {r8-r12,r14}")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe8bdc000) "   @ ldmia r13!, {r14,pc}")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe93ec000) "   @ ldmdb r14!, {r14,pc}")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe8a73f00) "   @ stmia r7!, {r8-r12,sp}")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe8a79f00) "   @ stmia r7!, {r8-r12,pc}")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe93e2010) "   @ ldmdb r14!, {r4,sp}")
-
-       TEST_GROUP("Load/store double or exclusive, table branch")
-
-       TEST_P(  "ldrd  r0, r1, [r",1, 24,", #-16]")
-       TEST(    "ldrd  r12, r14, [sp, #16]")
-       TEST_P(  "ldrd  r1, r0, [r",7, 24,", #-16]!")
-       TEST(    "ldrd  r14, r12, [sp, #16]!")
-       TEST_P(  "ldrd  r1, r0, [r",7, 24,"], #16")
-       TEST(    "ldrd  r7, r8, [sp], #-16")
-
-       TEST_X( "ldrd   r12, r14, 3f",
-               ".align 3                               \n\t"
-               "3:     .word   "__stringify(VAL1)"     \n\t"
-               "       .word   "__stringify(VAL2))
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xe9ffec04) "   @ ldrd  r14, r12, [pc, #16]!")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe8ffec04) "   @ ldrd  r14, r12, [pc], #16")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe9d4d800) "   @ ldrd  sp, r8, [r4]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe9d4f800) "   @ ldrd  pc, r8, [r4]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe9d47d00) "   @ ldrd  r7, sp, [r4]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe9d47f00) "   @ ldrd  r7, pc, [r4]")
-
-       TEST_RRP("strd  r",0, VAL1,", r",1, VAL2,", [r",1, 24,", #-16]")
-       TEST_RR( "strd  r",12,VAL2,", r",14,VAL1,", [sp, #16]")
-       TEST_RRP("strd  r",1, VAL1,", r",0, VAL2,", [r",7, 24,", #-16]!")
-       TEST_RR( "strd  r",14,VAL2,", r",12,VAL1,", [sp, #16]!")
-       TEST_RRP("strd  r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16")
-       TEST_RR( "strd  r",7, VAL2,", r",8, VAL1,", [sp], #-16")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) "   @ strd  r14, r12, [pc, #16]!")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) "   @ strd  r14, r12, [pc], #16")
-
-       TEST_RX("tbb    [pc, r",0, (9f-(1f+4)),"]",
-               "9:                     \n\t"
-               ".byte  (2f-1b-4)>>1    \n\t"
-               ".byte  (3f-1b-4)>>1    \n\t"
-               "3:     mvn     r0, r0  \n\t"
-               "2:     nop             \n\t")
-
-       TEST_RX("tbb    [pc, r",4, (9f-(1f+4)+1),"]",
-               "9:                     \n\t"
-               ".byte  (2f-1b-4)>>1    \n\t"
-               ".byte  (3f-1b-4)>>1    \n\t"
-               "3:     mvn     r0, r0  \n\t"
-               "2:     nop             \n\t")
-
-       TEST_RRX("tbb   [r",1,9f,", r",2,0,"]",
-               "9:                     \n\t"
-               ".byte  (2f-1b-4)>>1    \n\t"
-               ".byte  (3f-1b-4)>>1    \n\t"
-               "3:     mvn     r0, r0  \n\t"
-               "2:     nop             \n\t")
-
-       TEST_RX("tbh    [pc, r",7, (9f-(1f+4))>>1,"]",
-               "9:                     \n\t"
-               ".short (2f-1b-4)>>1    \n\t"
-               ".short (3f-1b-4)>>1    \n\t"
-               "3:     mvn     r0, r0  \n\t"
-               "2:     nop             \n\t")
-
-       TEST_RX("tbh    [pc, r",12, ((9f-(1f+4))>>1)+1,"]",
-               "9:                     \n\t"
-               ".short (2f-1b-4)>>1    \n\t"
-               ".short (3f-1b-4)>>1    \n\t"
-               "3:     mvn     r0, r0  \n\t"
-               "2:     nop             \n\t")
-
-       TEST_RRX("tbh   [r",1,9f, ", r",14,1,"]",
-               "9:                     \n\t"
-               ".short (2f-1b-4)>>1    \n\t"
-               ".short (3f-1b-4)>>1    \n\t"
-               "3:     mvn     r0, r0  \n\t"
-               "2:     nop             \n\t")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xe8d1f01f) "   @ tbh [r1, pc]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe8d1f01d) "   @ tbh [r1, sp]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xe8ddf012) "   @ tbh [sp, r2]")
-
-       TEST_UNSUPPORTED("strexb        r0, r1, [r2]")
-       TEST_UNSUPPORTED("strexh        r0, r1, [r2]")
-       TEST_UNSUPPORTED("strexd        r0, r1, [r2]")
-       TEST_UNSUPPORTED("ldrexb        r0, [r1]")
-       TEST_UNSUPPORTED("ldrexh        r0, [r1]")
-       TEST_UNSUPPORTED("ldrexd        r0, [r1]")
-
-       TEST_GROUP("Data-processing (shifted register) and (modified immediate)")
-
-#define _DATA_PROCESSING32_DNM(op,s,val)                                       \
-       TEST_RR(op s".w r0,  r",1, VAL1,", r",2, val, "")                       \
-       TEST_RR(op s"   r1,  r",1, VAL1,", r",2, val, ", lsl #3")               \
-       TEST_RR(op s"   r2,  r",3, VAL1,", r",2, val, ", lsr #4")               \
-       TEST_RR(op s"   r3,  r",3, VAL1,", r",2, val, ", asr #5")               \
-       TEST_RR(op s"   r4,  r",5, VAL1,", r",2, N(val),", asr #6")             \
-       TEST_RR(op s"   r5,  r",5, VAL1,", r",2, val, ", ror #7")               \
-       TEST_RR(op s"   r8,  r",9, VAL1,", r",10,val, ", rrx")                  \
-       TEST_R( op s"   r0,  r",11,VAL1,", #0x00010001")                        \
-       TEST_R( op s"   r11, r",0, VAL1,", #0xf5000000")                        \
-       TEST_R( op s"   r7,  r",8, VAL2,", #0x000af000")
-
-#define DATA_PROCESSING32_DNM(op,val)          \
-       _DATA_PROCESSING32_DNM(op,"",val)       \
-       _DATA_PROCESSING32_DNM(op,"s",val)
-
-#define DATA_PROCESSING32_NM(op,val)                                   \
-       TEST_RR(op".w   r",1, VAL1,", r",2, val, "")                    \
-       TEST_RR(op"     r",1, VAL1,", r",2, val, ", lsl #3")            \
-       TEST_RR(op"     r",3, VAL1,", r",2, val, ", lsr #4")            \
-       TEST_RR(op"     r",3, VAL1,", r",2, val, ", asr #5")            \
-       TEST_RR(op"     r",5, VAL1,", r",2, N(val),", asr #6")          \
-       TEST_RR(op"     r",5, VAL1,", r",2, val, ", ror #7")            \
-       TEST_RR(op"     r",9, VAL1,", r",10,val, ", rrx")               \
-       TEST_R( op"     r",11,VAL1,", #0x00010001")                     \
-       TEST_R( op"     r",0, VAL1,", #0xf5000000")                     \
-       TEST_R( op"     r",8, VAL2,", #0x000af000")
-
-#define _DATA_PROCESSING32_DM(op,s,val)                                \
-       TEST_R( op s".w r0,  r",14, val, "")                    \
-       TEST_R( op s"   r1,  r",12, val, ", lsl #3")            \
-       TEST_R( op s"   r2,  r",11, val, ", lsr #4")            \
-       TEST_R( op s"   r3,  r",10, val, ", asr #5")            \
-       TEST_R( op s"   r4,  r",9, N(val),", asr #6")           \
-       TEST_R( op s"   r5,  r",8, val, ", ror #7")             \
-       TEST_R( op s"   r8,  r",7,val, ", rrx")                 \
-       TEST(   op s"   r0,  #0x00010001")                      \
-       TEST(   op s"   r11, #0xf5000000")                      \
-       TEST(   op s"   r7,  #0x000af000")                      \
-       TEST(   op s"   r4,  #0x00005a00")
-
-#define DATA_PROCESSING32_DM(op,val)           \
-       _DATA_PROCESSING32_DM(op,"",val)        \
-       _DATA_PROCESSING32_DM(op,"s",val)
-
-       DATA_PROCESSING32_DNM("and",0xf00f00ff)
-       DATA_PROCESSING32_NM("tst",0xf00f00ff)
-       DATA_PROCESSING32_DNM("bic",0xf00f00ff)
-       DATA_PROCESSING32_DNM("orr",0xf00f00ff)
-       DATA_PROCESSING32_DM("mov",VAL2)
-       DATA_PROCESSING32_DNM("orn",0xf00f00ff)
-       DATA_PROCESSING32_DM("mvn",VAL2)
-       DATA_PROCESSING32_DNM("eor",0xf00f00ff)
-       DATA_PROCESSING32_NM("teq",0xf00f00ff)
-       DATA_PROCESSING32_DNM("add",VAL2)
-       DATA_PROCESSING32_NM("cmn",VAL2)
-       DATA_PROCESSING32_DNM("adc",VAL2)
-       DATA_PROCESSING32_DNM("sbc",VAL2)
-       DATA_PROCESSING32_DNM("sub",VAL2)
-       DATA_PROCESSING32_NM("cmp",VAL2)
-       DATA_PROCESSING32_DNM("rsb",VAL2)
-
-       TEST_RR("pkhbt  r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR("pkhbt  r14,r",12, HH1,", r",10,HH2,", lsl #2")
-       TEST_RR("pkhtb  r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR("pkhtb  r14,r",12, HH1,", r",10,HH2,", asr #2")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xea170f0d) "   @ tst.w r7, sp")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea170f0f) "   @ tst.w r7, pc")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea1d0f07) "   @ tst.w sp, r7")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea1f0f07) "   @ tst.w pc, r7")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf01d1f08) "   @ tst sp, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf01f1f08) "   @ tst pc, #0x00080008")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xea970f0d) "   @ teq.w r7, sp")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea970f0f) "   @ teq.w r7, pc")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea9d0f07) "   @ teq.w sp, r7")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea9f0f07) "   @ teq.w pc, r7")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf09d1f08) "   @ tst sp, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf09f1f08) "   @ tst pc, #0x00080008")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb170f0d) "   @ cmn.w r7, sp")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb170f0f) "   @ cmn.w r7, pc")
-       TEST_P("cmn.w   sp, r",7,0,"")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb1f0f07) "   @ cmn.w pc, r7")
-       TEST(  "cmn     sp, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf11f1f08) "   @ cmn pc, #0x00080008")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xebb70f0d) "   @ cmp.w r7, sp")
-       TEST_UNSUPPORTED(__inst_thumb32(0xebb70f0f) "   @ cmp.w r7, pc")
-       TEST_P("cmp.w   sp, r",7,0,"")
-       TEST_UNSUPPORTED(__inst_thumb32(0xebbf0f07) "   @ cmp.w pc, r7")
-       TEST(  "cmp     sp, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf1bf1f08) "   @ cmp pc, #0x00080008")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xea5f070d) "   @ movs.w r7, sp")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea5f070f) "   @ movs.w r7, pc")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea5f0d07) "   @ movs.w sp, r7")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea4f0f07) "   @ mov.w  pc, r7")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf04f1d08) "   @ mov sp, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf04f1f08) "   @ mov pc, #0x00080008")
-
-       TEST_R("add.w   r0, sp, r",1, 4,"")
-       TEST_R("adds    r0, sp, r",1, 4,", asl #3")
-       TEST_R("add     r0, sp, r",1, 4,", asl #4")
-       TEST_R("add     r0, sp, r",1, 16,", ror #1")
-       TEST_R("add.w   sp, sp, r",1, 4,"")
-       TEST_R("add     sp, sp, r",1, 4,", asl #3")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d1d01) "   @ add sp, sp, r1, asl #4")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d0d71) "   @ add sp, sp, r1, ror #1")
-       TEST(  "add.w   r0, sp, #24")
-       TEST(  "add.w   sp, sp, #24")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d0f01) "   @ add pc, sp, r1")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d000f) "   @ add r0, sp, pc")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d000d) "   @ add r0, sp, sp")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d0d0f) "   @ add sp, sp, pc")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d0d0d) "   @ add sp, sp, sp")
-
-       TEST_R("sub.w   r0, sp, r",1, 4,"")
-       TEST_R("subs    r0, sp, r",1, 4,", asl #3")
-       TEST_R("sub     r0, sp, r",1, 4,", asl #4")
-       TEST_R("sub     r0, sp, r",1, 16,", ror #1")
-       TEST_R("sub.w   sp, sp, r",1, 4,"")
-       TEST_R("sub     sp, sp, r",1, 4,", asl #3")
-       TEST_UNSUPPORTED(__inst_thumb32(0xebad1d01) "   @ sub sp, sp, r1, asl #4")
-       TEST_UNSUPPORTED(__inst_thumb32(0xebad0d71) "   @ sub sp, sp, r1, ror #1")
-       TEST_UNSUPPORTED(__inst_thumb32(0xebad0f01) "   @ sub pc, sp, r1")
-       TEST(  "sub.w   r0, sp, #24")
-       TEST(  "sub.w   sp, sp, #24")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xea02010f) "   @ and r1, r2, pc")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea0f0103) "   @ and r1, pc, r3")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea020f03) "   @ and pc, r2, r3")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea02010d) "   @ and r1, r2, sp")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea0d0103) "   @ and r1, sp, r3")
-       TEST_UNSUPPORTED(__inst_thumb32(0xea020d03) "   @ and sp, r2, r3")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf00d1108) "   @ and r1, sp, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf00f1108) "   @ and r1, pc, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf0021d08) "   @ and sp, r8, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf0021f08) "   @ and pc, r8, #0x00080008")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb02010f) "   @ add r1, r2, pc")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb0f0103) "   @ add r1, pc, r3")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb020f03) "   @ add pc, r2, r3")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb02010d) "   @ add r1, r2, sp")
-       TEST_SUPPORTED(  __inst_thumb32(0xeb0d0103) "   @ add r1, sp, r3")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb020d03) "   @ add sp, r2, r3")
-       TEST_SUPPORTED(  __inst_thumb32(0xf10d1108) "   @ add r1, sp, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf10d1f08) "   @ add pc, sp, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf10f1108) "   @ add r1, pc, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf1021d08) "   @ add sp, r8, #0x00080008")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf1021f08) "   @ add pc, r8, #0x00080008")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xeaa00000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeaf00000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb200000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeb800000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xebe00000) "")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xf0a00000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf0c00000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf0f00000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf1200000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf1800000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf1e00000) "")
-
-       TEST_GROUP("Coprocessor instructions")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xec000000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xeff00000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfc000000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfff00000) "")
-
-       TEST_GROUP("Data-processing (plain binary immediate)")
-
-       TEST_R("addw    r0,  r",1, VAL1,", #0x123")
-       TEST(  "addw    r14, sp, #0xf5a")
-       TEST(  "addw    sp, sp, #0x20")
-       TEST(  "addw    r7,  pc, #0x888")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf20f1f20) "   @ addw pc, pc, #0x120")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf20d1f20) "   @ addw pc, sp, #0x120")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf20f1d20) "   @ addw sp, pc, #0x120")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf2001d20) "   @ addw sp, r0, #0x120")
-
-       TEST_R("subw    r0,  r",1, VAL1,", #0x123")
-       TEST(  "subw    r14, sp, #0xf5a")
-       TEST(  "subw    sp, sp, #0x20")
-       TEST(  "subw    r7,  pc, #0x888")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf2af1f20) "   @ subw pc, pc, #0x120")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf2ad1f20) "   @ subw pc, sp, #0x120")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf2af1d20) "   @ subw sp, pc, #0x120")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf2a01d20) "   @ subw sp, r0, #0x120")
-
-       TEST("movw      r0, #0")
-       TEST("movw      r0, #0xffff")
-       TEST("movw      lr, #0xffff")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf2400d00) "   @ movw sp, #0")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf2400f00) "   @ movw pc, #0")
-
-       TEST_R("movt    r",0, VAL1,", #0")
-       TEST_R("movt    r",0, VAL2,", #0xffff")
-       TEST_R("movt    r",14,VAL1,", #0xffff")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf2c00d00) "   @ movt sp, #0")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf2c00f00) "   @ movt pc, #0")
-
-       TEST_R(     "ssat       r0, #24, r",0,   VAL1,"")
-       TEST_R(     "ssat       r14, #24, r",12, VAL2,"")
-       TEST_R(     "ssat       r0, #24, r",0,   VAL1,", lsl #8")
-       TEST_R(     "ssat       r14, #24, r",12, VAL2,", asr #8")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf30c0d17) "   @ ssat  sp, #24, r12")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf30c0f17) "   @ ssat  pc, #24, r12")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf30d0c17) "   @ ssat  r12, #24, sp")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf30f0c17) "   @ ssat  r12, #24, pc")
-
-       TEST_R(     "usat       r0, #24, r",0,   VAL1,"")
-       TEST_R(     "usat       r14, #24, r",12, VAL2,"")
-       TEST_R(     "usat       r0, #24, r",0,   VAL1,", lsl #8")
-       TEST_R(     "usat       r14, #24, r",12, VAL2,", asr #8")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf38c0d17) "   @ usat  sp, #24, r12")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf38c0f17) "   @ usat  pc, #24, r12")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf38d0c17) "   @ usat  r12, #24, sp")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf38f0c17) "   @ usat  r12, #24, pc")
-
-       TEST_R(     "ssat16     r0, #12, r",0,   HH1,"")
-       TEST_R(     "ssat16     r14, #12, r",12, HH2,"")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf32c0d0b) "   @ ssat16        sp, #12, r12")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf32c0f0b) "   @ ssat16        pc, #12, r12")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf32d0c0b) "   @ ssat16        r12, #12, sp")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf32f0c0b) "   @ ssat16        r12, #12, pc")
-
-       TEST_R(     "usat16     r0, #12, r",0,   HH1,"")
-       TEST_R(     "usat16     r14, #12, r",12, HH2,"")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf3ac0d0b) "   @ usat16        sp, #12, r12")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf3ac0f0b) "   @ usat16        pc, #12, r12")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf3ad0c0b) "   @ usat16        r12, #12, sp")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf3af0c0b) "   @ usat16        r12, #12, pc")
-
-       TEST_R(     "sbfx       r0, r",0  , VAL1,", #0, #31")
-       TEST_R(     "sbfx       r14, r",12, VAL2,", #8, #16")
-       TEST_R(     "sbfx       r4, r",10,  VAL1,", #16, #15")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf34c2d0f) "   @ sbfx  sp, r12, #8, #16")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf34c2f0f) "   @ sbfx  pc, r12, #8, #16")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf34d2c0f) "   @ sbfx  r12, sp, #8, #16")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf34f2c0f) "   @ sbfx  r12, pc, #8, #16")
-
-       TEST_R(     "ubfx       r0, r",0  , VAL1,", #0, #31")
-       TEST_R(     "ubfx       r14, r",12, VAL2,", #8, #16")
-       TEST_R(     "ubfx       r4, r",10,  VAL1,", #16, #15")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf3cc2d0f) "   @ ubfx  sp, r12, #8, #16")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf3cc2f0f) "   @ ubfx  pc, r12, #8, #16")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf3cd2c0f) "   @ ubfx  r12, sp, #8, #16")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf3cf2c0f) "   @ ubfx  r12, pc, #8, #16")
-
-       TEST_R(     "bfc        r",0, VAL1,", #4, #20")
-       TEST_R(     "bfc        r",14,VAL2,", #4, #20")
-       TEST_R(     "bfc        r",7, VAL1,", #0, #31")
-       TEST_R(     "bfc        r",8, VAL2,", #0, #31")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf36f0d1e) "   @ bfc   sp, #0, #31")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf36f0f1e) "   @ bfc   pc, #0, #31")
-
-       TEST_RR(    "bfi        r",0, VAL1,", r",0  , VAL2,", #0, #31")
-       TEST_RR(    "bfi        r",12,VAL1,", r",14 , VAL2,", #4, #20")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf36e1d17) "   @ bfi   sp, r14, #4, #20")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf36e1f17) "   @ bfi   pc, r14, #4, #20")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf36d1e17) "   @ bfi   r14, sp, #4, #20")
-
-       TEST_GROUP("Branches and miscellaneous control")
-
-CONDITION_INSTRUCTIONS(22,
-       TEST_BF("beq.w  2f")
-       TEST_BB("bne.w  2b")
-       TEST_BF("bgt.w  2f")
-       TEST_BB("blt.w  2b")
-       TEST_BF_X("bpl.w        2f", SPACE_0x1000)
-)
-
-       TEST_UNSUPPORTED("msr   cpsr, r0")
-       TEST_UNSUPPORTED("msr   cpsr_f, r1")
-       TEST_UNSUPPORTED("msr   spsr, r2")
-
-       TEST_UNSUPPORTED("cpsie.w       i")
-       TEST_UNSUPPORTED("cpsid.w       i")
-       TEST_UNSUPPORTED("cps   0x13")
-
-       TEST_SUPPORTED("yield.w")
-       TEST("sev.w")
-       TEST("nop.w")
-       TEST("wfi.w")
-       TEST_SUPPORTED("wfe.w")
-       TEST_UNSUPPORTED("dbg.w #0")
-
-       TEST_UNSUPPORTED("clrex")
-       TEST_UNSUPPORTED("dsb")
-       TEST_UNSUPPORTED("dmb")
-       TEST_UNSUPPORTED("isb")
-
-       TEST_UNSUPPORTED("bxj   r0")
-
-       TEST_UNSUPPORTED("subs  pc, lr, #4")
-
-       TEST("mrs       r0, cpsr")
-       TEST("mrs       r14, cpsr")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8d00) "   @ mrs   sp, spsr")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8f00) "   @ mrs   pc, spsr")
-       TEST_UNSUPPORTED("mrs   r0, spsr")
-       TEST_UNSUPPORTED("mrs   lr, spsr")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xf7f08000) " @ smc #0")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xf7f0a000) " @ undefeined")
-
-       TEST_BF(  "b.w  2f")
-       TEST_BB(  "b.w  2b")
-       TEST_BF_X("b.w  2f", SPACE_0x1000)
-
-       TEST_BF(  "bl.w 2f")
-       TEST_BB(  "bl.w 2b")
-       TEST_BB_X("bl.w 2b", SPACE_0x1000)
-
-       TEST_X( "blx    __dummy_arm_subroutine",
-               ".arm                           \n\t"
-               ".align                         \n\t"
-               ".type __dummy_arm_subroutine, %%function \n\t"
-               "__dummy_arm_subroutine:        \n\t"
-               "mov    r0, pc                  \n\t"
-               "bx     lr                      \n\t"
-               ".thumb                         \n\t"
-       )
-       TEST(   "blx    __dummy_arm_subroutine")
-
-       TEST_GROUP("Store single data item")
-
-#define SINGLE_STORE(size)                                                     \
-       TEST_RP( "str"size"     r",0, VAL1,", [r",11,-1024,", #1024]")          \
-       TEST_RP( "str"size"     r",14,VAL2,", [r",1, -1024,", #1080]")          \
-       TEST_RP( "str"size"     r",0, VAL1,", [r",11,256,  ", #-120]")          \
-       TEST_RP( "str"size"     r",14,VAL2,", [r",1, 256,  ", #-128]")          \
-       TEST_RP( "str"size"     r",0, VAL1,", [r",11,24,  "], #120")            \
-       TEST_RP( "str"size"     r",14,VAL2,", [r",1, 24,  "], #128")            \
-       TEST_RP( "str"size"     r",0, VAL1,", [r",11,24,  "], #-120")           \
-       TEST_RP( "str"size"     r",14,VAL2,", [r",1, 24,  "], #-128")           \
-       TEST_RP( "str"size"     r",0, VAL1,", [r",11,24,   ", #120]!")          \
-       TEST_RP( "str"size"     r",14,VAL2,", [r",1, 24,   ", #128]!")          \
-       TEST_RP( "str"size"     r",0, VAL1,", [r",11,256,  ", #-120]!")         \
-       TEST_RP( "str"size"     r",14,VAL2,", [r",1, 256,  ", #-128]!")         \
-       TEST_RPR("str"size".w   r",0, VAL1,", [r",1, 0,", r",2, 4,"]")          \
-       TEST_RPR("str"size"     r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]")  \
-       TEST_R(  "str"size".w   r",7, VAL1,", [sp, #24]")                       \
-       TEST_RP( "str"size".w   r",0, VAL2,", [r",0,0, "]")                     \
-       TEST_UNSUPPORTED("str"size"t    r0, [r1, #4]")
-
-       SINGLE_STORE("b")
-       SINGLE_STORE("h")
-       SINGLE_STORE("")
-
-       TEST("str       sp, [sp]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) "   @ str   r14, [pc]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) "   @ str   pc, [r14]")
-
-       TEST_GROUP("Advanced SIMD element or structure load/store instructions")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xf9000000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf92fffff) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf9800000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf9efffff) "")
-
-       TEST_GROUP("Load single data item and memory hints")
-
-#define SINGLE_LOAD(size)                                              \
-       TEST_P( "ldr"size"      r0, [r",11,-1024, ", #1024]")           \
-       TEST_P( "ldr"size"      r14, [r",1, -1024,", #1080]")           \
-       TEST_P( "ldr"size"      r0, [r",11,256,   ", #-120]")           \
-       TEST_P( "ldr"size"      r14, [r",1, 256,  ", #-128]")           \
-       TEST_P( "ldr"size"      r0, [r",11,24,   "], #120")             \
-       TEST_P( "ldr"size"      r14, [r",1, 24,  "], #128")             \
-       TEST_P( "ldr"size"      r0, [r",11,24,   "], #-120")            \
-       TEST_P( "ldr"size"      r14, [r",1,24,   "], #-128")            \
-       TEST_P( "ldr"size"      r0, [r",11,24,    ", #120]!")           \
-       TEST_P( "ldr"size"      r14, [r",1, 24,   ", #128]!")           \
-       TEST_P( "ldr"size"      r0, [r",11,256,   ", #-120]!")          \
-       TEST_P( "ldr"size"      r14, [r",1, 256,  ", #-128]!")          \
-       TEST_PR("ldr"size".w    r0, [r",1, 0,", r",2, 4,"]")            \
-       TEST_PR("ldr"size"      r14, [r",10,0,", r",11,4,", lsl #1]")   \
-       TEST_X( "ldr"size".w    r0, 3f",                                \
-               ".align 3                               \n\t"           \
-               "3:     .word   "__stringify(VAL1))                     \
-       TEST_X( "ldr"size".w    r14, 3f",                               \
-               ".align 3                               \n\t"           \
-               "3:     .word   "__stringify(VAL2))                     \
-       TEST(   "ldr"size".w    r7, 3b")                                \
-       TEST(   "ldr"size".w    r7, [sp, #24]")                         \
-       TEST_P( "ldr"size".w    r0, [r",0,0, "]")                       \
-       TEST_UNSUPPORTED("ldr"size"t    r0, [r1, #4]")
-
-       SINGLE_LOAD("b")
-       SINGLE_LOAD("sb")
-       SINGLE_LOAD("h")
-       SINGLE_LOAD("sh")
-       SINGLE_LOAD("")
-
-       TEST_BF_P("ldr  pc, [r",14, 15*4,"]")
-       TEST_P(   "ldr  sp, [r",14, 13*4,"]")
-       TEST_BF_R("ldr  pc, [sp, r",14, 15*4,"]")
-       TEST_R(   "ldr  sp, [sp, r",14, 13*4,"]")
-       TEST_THUMB_TO_ARM_INTERWORK_P("ldr      pc, [r",0,0,", #15*4]")
-       TEST_SUPPORTED("ldr     sp, 99f")
-       TEST_SUPPORTED("ldr     pc, 99f")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xf854700d) "   @ ldr   r7, [r4, sp]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf854700f) "   @ ldr   r7, [r4, pc]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf814700d) "   @ ldrb  r7, [r4, sp]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf814700f) "   @ ldrb  r7, [r4, pc]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf89fd004) "   @ ldrb  sp, 99f")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf814d008) "   @ ldrb  sp, [r4, r8]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf894d000) "   @ ldrb  sp, [r4]")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xf8600000) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xf9ffffff) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xf9500000) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xf95fffff) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xf8000800) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xf97ffaff) "") /* Unallocated space */
-
-       TEST(   "pli    [pc, #4]")
-       TEST(   "pli    [pc, #-4]")
-       TEST(   "pld    [pc, #4]")
-       TEST(   "pld    [pc, #-4]")
-
-       TEST_P( "pld    [r",0,-1024,", #1024]")
-       TEST(   __inst_thumb32(0xf8b0f400) "    @ pldw  [r0, #1024]")
-       TEST_P( "pli    [r",4, 0b,", #1024]")
-       TEST_P( "pld    [r",7, 120,", #-120]")
-       TEST(   __inst_thumb32(0xf837fc78) "    @ pldw  [r7, #-120]")
-       TEST_P( "pli    [r",11,120,", #-120]")
-       TEST(   "pld    [sp, #0]")
-
-       TEST_PR("pld    [r",7, 24, ", r",0, 16,"]")
-       TEST_PR("pld    [r",8, 24, ", r",12,16,", lsl #3]")
-       TEST_SUPPORTED(__inst_thumb32(0xf837f000) "     @ pldw  [r7, r0]")
-       TEST_SUPPORTED(__inst_thumb32(0xf838f03c) "     @ pldw  [r8, r12, lsl #3]");
-       TEST_RR("pli    [r",12,0b,", r",0, 16,"]")
-       TEST_RR("pli    [r",0, 0b,", r",12,16,", lsl #3]")
-       TEST_R( "pld    [sp, r",1, 16,"]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf817f00d) "  @pld     [r7, sp]")
-       TEST_UNSUPPORTED(__inst_thumb32(0xf817f00f) "  @pld     [r7, pc]")
-
-       TEST_GROUP("Data-processing (register)")
-
-#define SHIFTS32(op)                                   \
-       TEST_RR(op"     r0,  r",1, VAL1,", r",2, 3, "") \
-       TEST_RR(op"     r14, r",12,VAL2,", r",11,10,"")
-
-       SHIFTS32("lsl")
-       SHIFTS32("lsls")
-       SHIFTS32("lsr")
-       SHIFTS32("lsrs")
-       SHIFTS32("asr")
-       SHIFTS32("asrs")
-       SHIFTS32("ror")
-       SHIFTS32("rors")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa01ff02) "   @ lsl   pc, r1, r2")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa01fd02) "   @ lsl   sp, r1, r2")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa0ff002) "   @ lsl   r0, pc, r2")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa0df002) "   @ lsl   r0, sp, r2")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa01f00f) "   @ lsl   r0, r1, pc")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa01f00d) "   @ lsl   r0, r1, sp")
-
-       TEST_RR(    "sxtah      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "sxtah      r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "sxth       r8, r",7,  HH1,"")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa0fff87) "   @ sxth  pc, r7");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa0ffd87) "   @ sxth  sp, r7");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa0ff88f) "   @ sxth  r8, pc");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa0ff88d) "   @ sxth  r8, sp");
-
-       TEST_RR(    "uxtah      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uxtah      r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "uxth       r8, r",7,  HH1,"")
-
-       TEST_RR(    "sxtab16    r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "sxtab16    r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "sxtb16     r8, r",7,  HH1,"")
-
-       TEST_RR(    "uxtab16    r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uxtab16    r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "uxtb16     r8, r",7,  HH1,"")
-
-       TEST_RR(    "sxtab      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "sxtab      r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "sxtb       r8, r",7,  HH1,"")
-
-       TEST_RR(    "uxtab      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "uxtab      r14,r",12, HH2,", r",10,HH1,", ror #8")
-       TEST_R(     "uxtb       r8, r",7,  HH1,"")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa6000f0) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa7fffff) "")
-
-#define PARALLEL_ADD_SUB(op)                                   \
-       TEST_RR(  op"add16      r0, r",0,  HH1,", r",1, HH2,"") \
-       TEST_RR(  op"add16      r14, r",12,HH2,", r",10,HH1,"") \
-       TEST_RR(  op"asx        r0, r",0,  HH1,", r",1, HH2,"") \
-       TEST_RR(  op"asx        r14, r",12,HH2,", r",10,HH1,"") \
-       TEST_RR(  op"sax        r0, r",0,  HH1,", r",1, HH2,"") \
-       TEST_RR(  op"sax        r14, r",12,HH2,", r",10,HH1,"") \
-       TEST_RR(  op"sub16      r0, r",0,  HH1,", r",1, HH2,"") \
-       TEST_RR(  op"sub16      r14, r",12,HH2,", r",10,HH1,"") \
-       TEST_RR(  op"add8       r0, r",0,  HH1,", r",1, HH2,"") \
-       TEST_RR(  op"add8       r14, r",12,HH2,", r",10,HH1,"") \
-       TEST_RR(  op"sub8       r0, r",0,  HH1,", r",1, HH2,"") \
-       TEST_RR(  op"sub8       r14, r",12,HH2,", r",10,HH1,"")
-
-       TEST_GROUP("Parallel addition and subtraction, signed")
-
-       PARALLEL_ADD_SUB("s")
-       PARALLEL_ADD_SUB("q")
-       PARALLEL_ADD_SUB("sh")
-
-       TEST_GROUP("Parallel addition and subtraction, unsigned")
-
-       PARALLEL_ADD_SUB("u")
-       PARALLEL_ADD_SUB("uq")
-       PARALLEL_ADD_SUB("uh")
-
-       TEST_GROUP("Miscellaneous operations")
-
-       TEST_RR("qadd   r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR("qadd   lr, r",9, VAL2,", r",8, VAL1,"")
-       TEST_RR("qsub   r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR("qsub   lr, r",9, VAL2,", r",8, VAL1,"")
-       TEST_RR("qdadd  r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR("qdadd  lr, r",9, VAL2,", r",8, VAL1,"")
-       TEST_RR("qdsub  r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR("qdsub  lr, r",9, VAL2,", r",8, VAL1,"")
-
-       TEST_R("rev.w   r0, r",0,   VAL1,"")
-       TEST_R("rev     r14, r",12, VAL2,"")
-       TEST_R("rev16.w r0, r",0,   VAL1,"")
-       TEST_R("rev16   r14, r",12, VAL2,"")
-       TEST_R("rbit    r0, r",0,   VAL1,"")
-       TEST_R("rbit    r14, r",12, VAL2,"")
-       TEST_R("revsh.w r0, r",0,   VAL1,"")
-       TEST_R("revsh   r14, r",12, VAL2,"")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa9cff8c) "   @ rev   pc, r12");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa9cfd8c) "   @ rev   sp, r12");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa9ffe8f) "   @ rev   r14, pc");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa9dfe8d) "   @ rev   r14, sp");
-
-       TEST_RR("sel    r0, r",0,  VAL1,", r",1, VAL2,"")
-       TEST_RR("sel    r14, r",12,VAL1,", r",10, VAL2,"")
-
-       TEST_R("clz     r0, r",0, 0x0,"")
-       TEST_R("clz     r7, r",14,0x1,"")
-       TEST_R("clz     lr, r",7, 0xffffffff,"")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xfa80f030) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xfaffff7f) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xfab0f000) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xfaffff7f) "") /* Unallocated space */
-
-       TEST_GROUP("Multiply, multiply accumulate, and absolute difference operations")
-
-       TEST_RR(    "mul        r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "mul        r7, r",8, VAL2,", r",9, VAL2,"")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb08ff09) "   @ mul   pc, r8, r9")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb08fd09) "   @ mul   sp, r8, r9")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb0ff709) "   @ mul   r7, pc, r9")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb0df709) "   @ mul   r7, sp, r9")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb08f70f) "   @ mul   r7, r8, pc")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb08f70d) "   @ mul   r7, r8, sp")
-
-       TEST_RRR(   "mla        r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(   "mla        r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb08af09) "   @ mla   pc, r8, r9, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb08ad09) "   @ mla   sp, r8, r9, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb0fa709) "   @ mla   r7, pc, r9, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb0da709) "   @ mla   r7, sp, r9, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb08a70f) "   @ mla   r7, r8, pc, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb08a70d) "   @ mla   r7, r8, sp, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb08d709) "   @ mla   r7, r8, r9, sp");
-
-       TEST_RRR(   "mls        r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(   "mls        r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-
-       TEST_RRR(   "smlabb     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(   "smlabb     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RRR(   "smlatb     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(   "smlatb     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RRR(   "smlabt     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(   "smlabt     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RRR(   "smlatt     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(   "smlatt     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RR(    "smulbb     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smulbb     r7, r",8, VAL3,", r",9, VAL1,"")
-       TEST_RR(    "smultb     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smultb     r7, r",8, VAL3,", r",9, VAL1,"")
-       TEST_RR(    "smulbt     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smulbt     r7, r",8, VAL3,", r",9, VAL1,"")
-       TEST_RR(    "smultt     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smultt     r7, r",8, VAL3,", r",9, VAL1,"")
-
-       TEST_RRR(   "smlad      r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
-       TEST_RRR(   "smlad      r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
-       TEST_RRR(   "smladx     r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
-       TEST_RRR(   "smladx     r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
-       TEST_RR(    "smuad      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "smuad      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_RR(    "smuadx     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "smuadx     r14, r",12,HH2,", r",10,HH1,"")
-
-       TEST_RRR(   "smlawb     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(   "smlawb     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RRR(   "smlawt     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
-       TEST_RRR(   "smlawt     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
-       TEST_RR(    "smulwb     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smulwb     r7, r",8, VAL3,", r",9, VAL1,"")
-       TEST_RR(    "smulwt     r0, r",1, VAL1,", r",2, VAL2,"")
-       TEST_RR(    "smulwt     r7, r",8, VAL3,", r",9, VAL1,"")
-
-       TEST_RRR(   "smlsd      r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
-       TEST_RRR(   "smlsd      r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
-       TEST_RRR(   "smlsdx     r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
-       TEST_RRR(   "smlsdx     r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
-       TEST_RR(    "smusd      r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "smusd      r14, r",12,HH2,", r",10,HH1,"")
-       TEST_RR(    "smusdx     r0, r",0,  HH1,", r",1, HH2,"")
-       TEST_RR(    "smusdx     r14, r",12,HH2,", r",10,HH1,"")
-
-       TEST_RRR(   "smmla      r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
-       TEST_RRR(   "smmla      r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
-       TEST_RRR(   "smmlar     r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
-       TEST_RRR(   "smmlar     r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
-       TEST_RR(    "smmul      r0, r",0,  VAL1,", r",1, VAL2,"")
-       TEST_RR(    "smmul      r14, r",12,VAL2,", r",10,VAL1,"")
-       TEST_RR(    "smmulr     r0, r",0,  VAL1,", r",1, VAL2,"")
-       TEST_RR(    "smmulr     r14, r",12,VAL2,", r",10,VAL1,"")
-
-       TEST_RRR(   "smmls      r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
-       TEST_RRR(   "smmls      r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
-       TEST_RRR(   "smmlsr     r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
-       TEST_RRR(   "smmlsr     r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
-
-       TEST_RRR(   "usada8     r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL3,"")
-       TEST_RRR(   "usada8     r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL3,"")
-       TEST_RR(    "usad8      r0, r",0,  VAL1,", r",1, VAL2,"")
-       TEST_RR(    "usad8      r14, r",12,VAL2,", r",10,VAL1,"")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb00f010) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb0fff1f) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb70f010) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb7fff1f) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb700010) "") /* Unallocated space */
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb7fff1f) "") /* Unallocated space */
-
-       TEST_GROUP("Long multiply, long multiply accumulate, and divide")
-
-       TEST_RR(   "smull       r0, r1, r",2, VAL1,", r",3, VAL2,"")
-       TEST_RR(   "smull       r7, r8, r",9, VAL2,", r",10, VAL1,"")
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb89f80a) "   @ smull pc, r8, r9, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb89d80a) "   @ smull sp, r8, r9, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb897f0a) "   @ smull r7, pc, r9, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb897d0a) "   @ smull r7, sp, r9, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb8f780a) "   @ smull r7, r8, pc, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb8d780a) "   @ smull r7, r8, sp, r10");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb89780f) "   @ smull r7, r8, r9, pc");
-       TEST_UNSUPPORTED(__inst_thumb32(0xfb89780d) "   @ smull r7, r8, r9, sp");
-
-       TEST_RR(   "umull       r0, r1, r",2, VAL1,", r",3, VAL2,"")
-       TEST_RR(   "umull       r7, r8, r",9, VAL2,", r",10, VAL1,"")
-
-       TEST_RRRR( "smlal       r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR( "smlal       r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-
-       TEST_RRRR( "smlalbb     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR( "smlalbb     r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRRR( "smlalbt     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR( "smlalbt     r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRRR( "smlaltb     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR( "smlaltb     r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRRR( "smlaltt     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR( "smlaltt     r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-
-       TEST_RRRR( "smlald      r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
-       TEST_RRRR( "smlald      r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
-       TEST_RRRR( "smlaldx     r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
-       TEST_RRRR( "smlaldx     r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
-
-       TEST_RRRR( "smlsld      r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
-       TEST_RRRR( "smlsld      r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
-       TEST_RRRR( "smlsldx     r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
-       TEST_RRRR( "smlsldx     r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
-
-       TEST_RRRR( "umlal       r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR( "umlal       r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-       TEST_RRRR( "umaal       r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
-       TEST_RRRR( "umaal       r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
-
-       TEST_GROUP("Coprocessor instructions")
-
-       TEST_UNSUPPORTED(__inst_thumb32(0xfc000000) "")
-       TEST_UNSUPPORTED(__inst_thumb32(0xffffffff) "")
-
-       TEST_GROUP("Testing instructions in IT blocks")
-
-       TEST_ITBLOCK("sub.w     r0, r0")
-
-       verbose("\n");
-}
-
diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c
deleted file mode 100644 (file)
index b206d77..0000000
+++ /dev/null
@@ -1,1713 +0,0 @@
-/*
- * arch/arm/kernel/kprobes-test.c
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * This file contains test code for ARM kprobes.
- *
- * The top level function run_all_tests() executes tests for all of the
- * supported instruction sets: ARM, 16-bit Thumb, and 32-bit Thumb. These tests
- * fall into two categories; run_api_tests() checks basic functionality of the
- * kprobes API, and run_test_cases() is a comprehensive test for kprobes
- * instruction decoding and simulation.
- *
- * run_test_cases() first checks the kprobes decoding table for self consistency
- * (using table_test()) then executes a series of test cases for each of the CPU
- * instruction forms. coverage_start() and coverage_end() are used to verify
- * that these test cases cover all of the possible combinations of instructions
- * described by the kprobes decoding tables.
- *
- * The individual test cases are in kprobes-test-arm.c and kprobes-test-thumb.c
- * which use the macros defined in kprobes-test.h. The rest of this
- * documentation will describe the operation of the framework used by these
- * test cases.
- */
-
-/*
- * TESTING METHODOLOGY
- * -------------------
- *
- * The methodology used to test an ARM instruction 'test_insn' is to use
- * inline assembler like:
- *
- * test_before: nop
- * test_case:  test_insn
- * test_after: nop
- *
- * When the test case is run a kprobe is placed of each nop. The
- * post-handler of the test_before probe is used to modify the saved CPU
- * register context to that which we require for the test case. The
- * pre-handler of the of the test_after probe saves a copy of the CPU
- * register context. In this way we can execute test_insn with a specific
- * register context and see the results afterwards.
- *
- * To actually test the kprobes instruction emulation we perform the above
- * step a second time but with an additional kprobe on the test_case
- * instruction itself. If the emulation is accurate then the results seen
- * by the test_after probe will be identical to the first run which didn't
- * have a probe on test_case.
- *
- * Each test case is run several times with a variety of variations in the
- * flags value of stored in CPSR, and for Thumb code, different ITState.
- *
- * For instructions which can modify PC, a second test_after probe is used
- * like this:
- *
- * test_before: nop
- * test_case:  test_insn
- * test_after: nop
- *             b test_done
- * test_after2: nop
- * test_done:
- *
- * The test case is constructed such that test_insn branches to
- * test_after2, or, if testing a conditional instruction, it may just
- * continue to test_after. The probes inserted at both locations let us
- * determine which happened. A similar approach is used for testing
- * backwards branches...
- *
- *             b test_before
- *             b test_done  @ helps to cope with off by 1 branches
- * test_after2: nop
- *             b test_done
- * test_before: nop
- * test_case:  test_insn
- * test_after: nop
- * test_done:
- *
- * The macros used to generate the assembler instructions describe above
- * are TEST_INSTRUCTION, TEST_BRANCH_F (branch forwards) and TEST_BRANCH_B
- * (branch backwards). In these, the local variables numbered 1, 50, 2 and
- * 99 represent: test_before, test_case, test_after2 and test_done.
- *
- * FRAMEWORK
- * ---------
- *
- * Each test case is wrapped between the pair of macros TESTCASE_START and
- * TESTCASE_END. As well as performing the inline assembler boilerplate,
- * these call out to the kprobes_test_case_start() and
- * kprobes_test_case_end() functions which drive the execution of the test
- * case. The specific arguments to use for each test case are stored as
- * inline data constructed using the various TEST_ARG_* macros. Putting
- * this all together, a simple test case may look like:
- *
- *     TESTCASE_START("Testing mov r0, r7")
- *     TEST_ARG_REG(7, 0x12345678) // Set r7=0x12345678
- *     TEST_ARG_END("")
- *     TEST_INSTRUCTION("mov r0, r7")
- *     TESTCASE_END
- *
- * Note, in practice the single convenience macro TEST_R would be used for this
- * instead.
- *
- * The above would expand to assembler looking something like:
- *
- *     @ TESTCASE_START
- *     bl      __kprobes_test_case_start
- *     .pushsection .rodata
- *     "10:
- *     .ascii "mov r0, r7"     @ text title for test case
- *     .byte   0
- *     .popsection
- *     @ start of inline data...
- *     .word   10b             @ pointer to title in .rodata section
- *
- *     @ TEST_ARG_REG
- *     .byte   ARG_TYPE_REG
- *     .byte   7
- *     .short  0
- *     .word   0x1234567
- *
- *     @ TEST_ARG_END
- *     .byte   ARG_TYPE_END
- *     .byte   TEST_ISA        @ flags, including ISA being tested
- *     .short  50f-0f          @ offset of 'test_before'
- *     .short  2f-0f           @ offset of 'test_after2' (if relevent)
- *     .short  99f-0f          @ offset of 'test_done'
- *     @ start of test case code...
- *     0:
- *     .code   TEST_ISA        @ switch to ISA being tested
- *
- *     @ TEST_INSTRUCTION
- *     50:     nop             @ location for 'test_before' probe
- *     1:      mov r0, r7      @ the test case instruction 'test_insn'
- *             nop             @ location for 'test_after' probe
- *
- *     // TESTCASE_END
- *     2:
- *     99:     bl __kprobes_test_case_end_##TEST_ISA
- *     .code   NONMAL_ISA
- *
- * When the above is execute the following happens...
- *
- * __kprobes_test_case_start() is an assembler wrapper which sets up space
- * for a stack buffer and calls the C function kprobes_test_case_start().
- * This C function will do some initial processing of the inline data and
- * setup some global state. It then inserts the test_before and test_after
- * kprobes and returns a value which causes the assembler wrapper to jump
- * to the start of the test case code, (local label '0').
- *
- * When the test case code executes, the test_before probe will be hit and
- * test_before_post_handler will call setup_test_context(). This fills the
- * stack buffer and CPU registers with a test pattern and then processes
- * the test case arguments. In our example there is one TEST_ARG_REG which
- * indicates that R7 should be loaded with the value 0x12345678.
- *
- * When the test_before probe ends, the test case continues and executes
- * the "mov r0, r7" instruction. It then hits the test_after probe and the
- * pre-handler for this (test_after_pre_handler) will save a copy of the
- * CPU register context. This should now have R0 holding the same value as
- * R7.
- *
- * Finally we get to the call to __kprobes_test_case_end_{32,16}. This is
- * an assembler wrapper which switches back to the ISA used by the test
- * code and calls the C function kprobes_test_case_end().
- *
- * For each run through the test case, test_case_run_count is incremented
- * by one. For even runs, kprobes_test_case_end() saves a copy of the
- * register and stack buffer contents from the test case just run. It then
- * inserts a kprobe on the test case instruction 'test_insn' and returns a
- * value to cause the test case code to be re-run.
- *
- * For odd numbered runs, kprobes_test_case_end() compares the register and
- * stack buffer contents to those that were saved on the previous even
- * numbered run (the one without the kprobe on test_insn). These should be
- * the same if the kprobe instruction simulation routine is correct.
- *
- * The pair of test case runs is repeated with different combinations of
- * flag values in CPSR and, for Thumb, different ITState. This is
- * controlled by test_context_cpsr().
- *
- * BUILDING TEST CASES
- * -------------------
- *
- *
- * As an aid to building test cases, the stack buffer is initialised with
- * some special values:
- *
- *   [SP+13*4] Contains SP+120. This can be used to test instructions
- *             which load a value into SP.
- *
- *   [SP+15*4] When testing branching instructions using TEST_BRANCH_{F,B},
- *             this holds the target address of the branch, 'test_after2'.
- *             This can be used to test instructions which load a PC value
- *             from memory.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/kprobes.h>
-#include <linux/errno.h>
-#include <linux/stddef.h>
-#include <linux/bug.h>
-#include <asm/opcodes.h>
-
-#include "kprobes.h"
-#include "probes-arm.h"
-#include "probes-thumb.h"
-#include "kprobes-test.h"
-
-
-#define BENCHMARKING   1
-
-
-/*
- * Test basic API
- */
-
-static bool test_regs_ok;
-static int test_func_instance;
-static int pre_handler_called;
-static int post_handler_called;
-static int jprobe_func_called;
-static int kretprobe_handler_called;
-static int tests_failed;
-
-#define FUNC_ARG1 0x12345678
-#define FUNC_ARG2 0xabcdef
-
-
-#ifndef CONFIG_THUMB2_KERNEL
-
-long arm_func(long r0, long r1);
-
-static void __used __naked __arm_kprobes_test_func(void)
-{
-       __asm__ __volatile__ (
-               ".arm                                   \n\t"
-               ".type arm_func, %%function             \n\t"
-               "arm_func:                              \n\t"
-               "adds   r0, r0, r1                      \n\t"
-               "bx     lr                              \n\t"
-               ".code "NORMAL_ISA       /* Back to Thumb if necessary */
-               : : : "r0", "r1", "cc"
-       );
-}
-
-#else /* CONFIG_THUMB2_KERNEL */
-
-long thumb16_func(long r0, long r1);
-long thumb32even_func(long r0, long r1);
-long thumb32odd_func(long r0, long r1);
-
-static void __used __naked __thumb_kprobes_test_funcs(void)
-{
-       __asm__ __volatile__ (
-               ".type thumb16_func, %%function         \n\t"
-               "thumb16_func:                          \n\t"
-               "adds.n r0, r0, r1                      \n\t"
-               "bx     lr                              \n\t"
-
-               ".align                                 \n\t"
-               ".type thumb32even_func, %%function     \n\t"
-               "thumb32even_func:                      \n\t"
-               "adds.w r0, r0, r1                      \n\t"
-               "bx     lr                              \n\t"
-
-               ".align                                 \n\t"
-               "nop.n                                  \n\t"
-               ".type thumb32odd_func, %%function      \n\t"
-               "thumb32odd_func:                       \n\t"
-               "adds.w r0, r0, r1                      \n\t"
-               "bx     lr                              \n\t"
-
-               : : : "r0", "r1", "cc"
-       );
-}
-
-#endif /* CONFIG_THUMB2_KERNEL */
-
-
-static int call_test_func(long (*func)(long, long), bool check_test_regs)
-{
-       long ret;
-
-       ++test_func_instance;
-       test_regs_ok = false;
-
-       ret = (*func)(FUNC_ARG1, FUNC_ARG2);
-       if (ret != FUNC_ARG1 + FUNC_ARG2) {
-               pr_err("FAIL: call_test_func: func returned %lx\n", ret);
-               return false;
-       }
-
-       if (check_test_regs && !test_regs_ok) {
-               pr_err("FAIL: test regs not OK\n");
-               return false;
-       }
-
-       return true;
-}
-
-static int __kprobes pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       pre_handler_called = test_func_instance;
-       if (regs->ARM_r0 == FUNC_ARG1 && regs->ARM_r1 == FUNC_ARG2)
-               test_regs_ok = true;
-       return 0;
-}
-
-static void __kprobes post_handler(struct kprobe *p, struct pt_regs *regs,
-                               unsigned long flags)
-{
-       post_handler_called = test_func_instance;
-       if (regs->ARM_r0 != FUNC_ARG1 + FUNC_ARG2 || regs->ARM_r1 != FUNC_ARG2)
-               test_regs_ok = false;
-}
-
-static struct kprobe the_kprobe = {
-       .addr           = 0,
-       .pre_handler    = pre_handler,
-       .post_handler   = post_handler
-};
-
-static int test_kprobe(long (*func)(long, long))
-{
-       int ret;
-
-       the_kprobe.addr = (kprobe_opcode_t *)func;
-       ret = register_kprobe(&the_kprobe);
-       if (ret < 0) {
-               pr_err("FAIL: register_kprobe failed with %d\n", ret);
-               return ret;
-       }
-
-       ret = call_test_func(func, true);
-
-       unregister_kprobe(&the_kprobe);
-       the_kprobe.flags = 0; /* Clear disable flag to allow reuse */
-
-       if (!ret)
-               return -EINVAL;
-       if (pre_handler_called != test_func_instance) {
-               pr_err("FAIL: kprobe pre_handler not called\n");
-               return -EINVAL;
-       }
-       if (post_handler_called != test_func_instance) {
-               pr_err("FAIL: kprobe post_handler not called\n");
-               return -EINVAL;
-       }
-       if (!call_test_func(func, false))
-               return -EINVAL;
-       if (pre_handler_called == test_func_instance ||
-                               post_handler_called == test_func_instance) {
-               pr_err("FAIL: probe called after unregistering\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void __kprobes jprobe_func(long r0, long r1)
-{
-       jprobe_func_called = test_func_instance;
-       if (r0 == FUNC_ARG1 && r1 == FUNC_ARG2)
-               test_regs_ok = true;
-       jprobe_return();
-}
-
-static struct jprobe the_jprobe = {
-       .entry          = jprobe_func,
-};
-
-static int test_jprobe(long (*func)(long, long))
-{
-       int ret;
-
-       the_jprobe.kp.addr = (kprobe_opcode_t *)func;
-       ret = register_jprobe(&the_jprobe);
-       if (ret < 0) {
-               pr_err("FAIL: register_jprobe failed with %d\n", ret);
-               return ret;
-       }
-
-       ret = call_test_func(func, true);
-
-       unregister_jprobe(&the_jprobe);
-       the_jprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
-
-       if (!ret)
-               return -EINVAL;
-       if (jprobe_func_called != test_func_instance) {
-               pr_err("FAIL: jprobe handler function not called\n");
-               return -EINVAL;
-       }
-       if (!call_test_func(func, false))
-               return -EINVAL;
-       if (jprobe_func_called == test_func_instance) {
-               pr_err("FAIL: probe called after unregistering\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int __kprobes
-kretprobe_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
-{
-       kretprobe_handler_called = test_func_instance;
-       if (regs_return_value(regs) == FUNC_ARG1 + FUNC_ARG2)
-               test_regs_ok = true;
-       return 0;
-}
-
-static struct kretprobe the_kretprobe = {
-       .handler        = kretprobe_handler,
-};
-
-static int test_kretprobe(long (*func)(long, long))
-{
-       int ret;
-
-       the_kretprobe.kp.addr = (kprobe_opcode_t *)func;
-       ret = register_kretprobe(&the_kretprobe);
-       if (ret < 0) {
-               pr_err("FAIL: register_kretprobe failed with %d\n", ret);
-               return ret;
-       }
-
-       ret = call_test_func(func, true);
-
-       unregister_kretprobe(&the_kretprobe);
-       the_kretprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
-
-       if (!ret)
-               return -EINVAL;
-       if (kretprobe_handler_called != test_func_instance) {
-               pr_err("FAIL: kretprobe handler not called\n");
-               return -EINVAL;
-       }
-       if (!call_test_func(func, false))
-               return -EINVAL;
-       if (jprobe_func_called == test_func_instance) {
-               pr_err("FAIL: kretprobe called after unregistering\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int run_api_tests(long (*func)(long, long))
-{
-       int ret;
-
-       pr_info("    kprobe\n");
-       ret = test_kprobe(func);
-       if (ret < 0)
-               return ret;
-
-       pr_info("    jprobe\n");
-       ret = test_jprobe(func);
-#if defined(CONFIG_THUMB2_KERNEL) && !defined(MODULE)
-       if (ret == -EINVAL) {
-               pr_err("FAIL: Known longtime bug with jprobe on Thumb kernels\n");
-               tests_failed = ret;
-               ret = 0;
-       }
-#endif
-       if (ret < 0)
-               return ret;
-
-       pr_info("    kretprobe\n");
-       ret = test_kretprobe(func);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-
-/*
- * Benchmarking
- */
-
-#if BENCHMARKING
-
-static void __naked benchmark_nop(void)
-{
-       __asm__ __volatile__ (
-               "nop            \n\t"
-               "bx     lr"
-       );
-}
-
-#ifdef CONFIG_THUMB2_KERNEL
-#define wide ".w"
-#else
-#define wide
-#endif
-
-static void __naked benchmark_pushpop1(void)
-{
-       __asm__ __volatile__ (
-               "stmdb"wide"    sp!, {r3-r11,lr}  \n\t"
-               "ldmia"wide"    sp!, {r3-r11,pc}"
-       );
-}
-
-static void __naked benchmark_pushpop2(void)
-{
-       __asm__ __volatile__ (
-               "stmdb"wide"    sp!, {r0-r8,lr}  \n\t"
-               "ldmia"wide"    sp!, {r0-r8,pc}"
-       );
-}
-
-static void __naked benchmark_pushpop3(void)
-{
-       __asm__ __volatile__ (
-               "stmdb"wide"    sp!, {r4,lr}  \n\t"
-               "ldmia"wide"    sp!, {r4,pc}"
-       );
-}
-
-static void __naked benchmark_pushpop4(void)
-{
-       __asm__ __volatile__ (
-               "stmdb"wide"    sp!, {r0,lr}  \n\t"
-               "ldmia"wide"    sp!, {r0,pc}"
-       );
-}
-
-
-#ifdef CONFIG_THUMB2_KERNEL
-
-static void __naked benchmark_pushpop_thumb(void)
-{
-       __asm__ __volatile__ (
-               "push.n {r0-r7,lr}  \n\t"
-               "pop.n  {r0-r7,pc}"
-       );
-}
-
-#endif
-
-static int __kprobes
-benchmark_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       return 0;
-}
-
-static int benchmark(void(*fn)(void))
-{
-       unsigned n, i, t, t0;
-
-       for (n = 1000; ; n *= 2) {
-               t0 = sched_clock();
-               for (i = n; i > 0; --i)
-                       fn();
-               t = sched_clock() - t0;
-               if (t >= 250000000)
-                       break; /* Stop once we took more than 0.25 seconds */
-       }
-       return t / n; /* Time for one iteration in nanoseconds */
-};
-
-static int kprobe_benchmark(void(*fn)(void), unsigned offset)
-{
-       struct kprobe k = {
-               .addr           = (kprobe_opcode_t *)((uintptr_t)fn + offset),
-               .pre_handler    = benchmark_pre_handler,
-       };
-
-       int ret = register_kprobe(&k);
-       if (ret < 0) {
-               pr_err("FAIL: register_kprobe failed with %d\n", ret);
-               return ret;
-       }
-
-       ret = benchmark(fn);
-
-       unregister_kprobe(&k);
-       return ret;
-};
-
-struct benchmarks {
-       void            (*fn)(void);
-       unsigned        offset;
-       const char      *title;
-};
-
-static int run_benchmarks(void)
-{
-       int ret;
-       struct benchmarks list[] = {
-               {&benchmark_nop, 0, "nop"},
-               /*
-                * benchmark_pushpop{1,3} will have the optimised
-                * instruction emulation, whilst benchmark_pushpop{2,4} will
-                * be the equivalent unoptimised instructions.
-                */
-               {&benchmark_pushpop1, 0, "stmdb sp!, {r3-r11,lr}"},
-               {&benchmark_pushpop1, 4, "ldmia sp!, {r3-r11,pc}"},
-               {&benchmark_pushpop2, 0, "stmdb sp!, {r0-r8,lr}"},
-               {&benchmark_pushpop2, 4, "ldmia sp!, {r0-r8,pc}"},
-               {&benchmark_pushpop3, 0, "stmdb sp!, {r4,lr}"},
-               {&benchmark_pushpop3, 4, "ldmia sp!, {r4,pc}"},
-               {&benchmark_pushpop4, 0, "stmdb sp!, {r0,lr}"},
-               {&benchmark_pushpop4, 4, "ldmia sp!, {r0,pc}"},
-#ifdef CONFIG_THUMB2_KERNEL
-               {&benchmark_pushpop_thumb, 0, "push.n   {r0-r7,lr}"},
-               {&benchmark_pushpop_thumb, 2, "pop.n    {r0-r7,pc}"},
-#endif
-               {0}
-       };
-
-       struct benchmarks *b;
-       for (b = list; b->fn; ++b) {
-               ret = kprobe_benchmark(b->fn, b->offset);
-               if (ret < 0)
-                       return ret;
-               pr_info("    %dns for kprobe %s\n", ret, b->title);
-       }
-
-       pr_info("\n");
-       return 0;
-}
-
-#endif /* BENCHMARKING */
-
-
-/*
- * Decoding table self-consistency tests
- */
-
-static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
-       [DECODE_TYPE_TABLE]     = sizeof(struct decode_table),
-       [DECODE_TYPE_CUSTOM]    = sizeof(struct decode_custom),
-       [DECODE_TYPE_SIMULATE]  = sizeof(struct decode_simulate),
-       [DECODE_TYPE_EMULATE]   = sizeof(struct decode_emulate),
-       [DECODE_TYPE_OR]        = sizeof(struct decode_or),
-       [DECODE_TYPE_REJECT]    = sizeof(struct decode_reject)
-};
-
-static int table_iter(const union decode_item *table,
-                       int (*fn)(const struct decode_header *, void *),
-                       void *args)
-{
-       const struct decode_header *h = (struct decode_header *)table;
-       int result;
-
-       for (;;) {
-               enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
-
-               if (type == DECODE_TYPE_END)
-                       return 0;
-
-               result = fn(h, args);
-               if (result)
-                       return result;
-
-               h = (struct decode_header *)
-                       ((uintptr_t)h + decode_struct_sizes[type]);
-
-       }
-}
-
-static int table_test_fail(const struct decode_header *h, const char* message)
-{
-
-       pr_err("FAIL: kprobes test failure \"%s\" (mask %08x, value %08x)\n",
-                                       message, h->mask.bits, h->value.bits);
-       return -EINVAL;
-}
-
-struct table_test_args {
-       const union decode_item *root_table;
-       u32                     parent_mask;
-       u32                     parent_value;
-};
-
-static int table_test_fn(const struct decode_header *h, void *args)
-{
-       struct table_test_args *a = (struct table_test_args *)args;
-       enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
-
-       if (h->value.bits & ~h->mask.bits)
-               return table_test_fail(h, "Match value has bits not in mask");
-
-       if ((h->mask.bits & a->parent_mask) != a->parent_mask)
-               return table_test_fail(h, "Mask has bits not in parent mask");
-
-       if ((h->value.bits ^ a->parent_value) & a->parent_mask)
-               return table_test_fail(h, "Value is inconsistent with parent");
-
-       if (type == DECODE_TYPE_TABLE) {
-               struct decode_table *d = (struct decode_table *)h;
-               struct table_test_args args2 = *a;
-               args2.parent_mask = h->mask.bits;
-               args2.parent_value = h->value.bits;
-               return table_iter(d->table.table, table_test_fn, &args2);
-       }
-
-       return 0;
-}
-
-static int table_test(const union decode_item *table)
-{
-       struct table_test_args args = {
-               .root_table     = table,
-               .parent_mask    = 0,
-               .parent_value   = 0
-       };
-       return table_iter(args.root_table, table_test_fn, &args);
-}
-
-
-/*
- * Decoding table test coverage analysis
- *
- * coverage_start() builds a coverage_table which contains a list of
- * coverage_entry's to match each entry in the specified kprobes instruction
- * decoding table.
- *
- * When test cases are run, coverage_add() is called to process each case.
- * This looks up the corresponding entry in the coverage_table and sets it as
- * being matched, as well as clearing the regs flag appropriate for the test.
- *
- * After all test cases have been run, coverage_end() is called to check that
- * all entries in coverage_table have been matched and that all regs flags are
- * cleared. I.e. that all possible combinations of instructions described by
- * the kprobes decoding tables have had a test case executed for them.
- */
-
-bool coverage_fail;
-
-#define MAX_COVERAGE_ENTRIES 256
-
-struct coverage_entry {
-       const struct decode_header      *header;
-       unsigned                        regs;
-       unsigned                        nesting;
-       char                            matched;
-};
-
-struct coverage_table {
-       struct coverage_entry   *base;
-       unsigned                num_entries;
-       unsigned                nesting;
-};
-
-struct coverage_table coverage;
-
-#define COVERAGE_ANY_REG       (1<<0)
-#define COVERAGE_SP            (1<<1)
-#define COVERAGE_PC            (1<<2)
-#define COVERAGE_PCWB          (1<<3)
-
-static const char coverage_register_lookup[16] = {
-       [REG_TYPE_ANY]          = COVERAGE_ANY_REG | COVERAGE_SP | COVERAGE_PC,
-       [REG_TYPE_SAMEAS16]     = COVERAGE_ANY_REG,
-       [REG_TYPE_SP]           = COVERAGE_SP,
-       [REG_TYPE_PC]           = COVERAGE_PC,
-       [REG_TYPE_NOSP]         = COVERAGE_ANY_REG | COVERAGE_SP,
-       [REG_TYPE_NOSPPC]       = COVERAGE_ANY_REG | COVERAGE_SP | COVERAGE_PC,
-       [REG_TYPE_NOPC]         = COVERAGE_ANY_REG | COVERAGE_PC,
-       [REG_TYPE_NOPCWB]       = COVERAGE_ANY_REG | COVERAGE_PC | COVERAGE_PCWB,
-       [REG_TYPE_NOPCX]        = COVERAGE_ANY_REG,
-       [REG_TYPE_NOSPPCX]      = COVERAGE_ANY_REG | COVERAGE_SP,
-};
-
-unsigned coverage_start_registers(const struct decode_header *h)
-{
-       unsigned regs = 0;
-       int i;
-       for (i = 0; i < 20; i += 4) {
-               int r = (h->type_regs.bits >> (DECODE_TYPE_BITS + i)) & 0xf;
-               regs |= coverage_register_lookup[r] << i;
-       }
-       return regs;
-}
-
-static int coverage_start_fn(const struct decode_header *h, void *args)
-{
-       struct coverage_table *coverage = (struct coverage_table *)args;
-       enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
-       struct coverage_entry *entry = coverage->base + coverage->num_entries;
-
-       if (coverage->num_entries == MAX_COVERAGE_ENTRIES - 1) {
-               pr_err("FAIL: Out of space for test coverage data");
-               return -ENOMEM;
-       }
-
-       ++coverage->num_entries;
-
-       entry->header = h;
-       entry->regs = coverage_start_registers(h);
-       entry->nesting = coverage->nesting;
-       entry->matched = false;
-
-       if (type == DECODE_TYPE_TABLE) {
-               struct decode_table *d = (struct decode_table *)h;
-               int ret;
-               ++coverage->nesting;
-               ret = table_iter(d->table.table, coverage_start_fn, coverage);
-               --coverage->nesting;
-               return ret;
-       }
-
-       return 0;
-}
-
-static int coverage_start(const union decode_item *table)
-{
-       coverage.base = kmalloc(MAX_COVERAGE_ENTRIES *
-                               sizeof(struct coverage_entry), GFP_KERNEL);
-       coverage.num_entries = 0;
-       coverage.nesting = 0;
-       return table_iter(table, coverage_start_fn, &coverage);
-}
-
-static void
-coverage_add_registers(struct coverage_entry *entry, kprobe_opcode_t insn)
-{
-       int regs = entry->header->type_regs.bits >> DECODE_TYPE_BITS;
-       int i;
-       for (i = 0; i < 20; i += 4) {
-               enum decode_reg_type reg_type = (regs >> i) & 0xf;
-               int reg = (insn >> i) & 0xf;
-               int flag;
-
-               if (!reg_type)
-                       continue;
-
-               if (reg == 13)
-                       flag = COVERAGE_SP;
-               else if (reg == 15)
-                       flag = COVERAGE_PC;
-               else
-                       flag = COVERAGE_ANY_REG;
-               entry->regs &= ~(flag << i);
-
-               switch (reg_type) {
-
-               case REG_TYPE_NONE:
-               case REG_TYPE_ANY:
-               case REG_TYPE_SAMEAS16:
-                       break;
-
-               case REG_TYPE_SP:
-                       if (reg != 13)
-                               return;
-                       break;
-
-               case REG_TYPE_PC:
-                       if (reg != 15)
-                               return;
-                       break;
-
-               case REG_TYPE_NOSP:
-                       if (reg == 13)
-                               return;
-                       break;
-
-               case REG_TYPE_NOSPPC:
-               case REG_TYPE_NOSPPCX:
-                       if (reg == 13 || reg == 15)
-                               return;
-                       break;
-
-               case REG_TYPE_NOPCWB:
-                       if (!is_writeback(insn))
-                               break;
-                       if (reg == 15) {
-                               entry->regs &= ~(COVERAGE_PCWB << i);
-                               return;
-                       }
-                       break;
-
-               case REG_TYPE_NOPC:
-               case REG_TYPE_NOPCX:
-                       if (reg == 15)
-                               return;
-                       break;
-               }
-
-       }
-}
-
-static void coverage_add(kprobe_opcode_t insn)
-{
-       struct coverage_entry *entry = coverage.base;
-       struct coverage_entry *end = coverage.base + coverage.num_entries;
-       bool matched = false;
-       unsigned nesting = 0;
-
-       for (; entry < end; ++entry) {
-               const struct decode_header *h = entry->header;
-               enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
-
-               if (entry->nesting > nesting)
-                       continue; /* Skip sub-table we didn't match */
-
-               if (entry->nesting < nesting)
-                       break; /* End of sub-table we were scanning */
-
-               if (!matched) {
-                       if ((insn & h->mask.bits) != h->value.bits)
-                               continue;
-                       entry->matched = true;
-               }
-
-               switch (type) {
-
-               case DECODE_TYPE_TABLE:
-                       ++nesting;
-                       break;
-
-               case DECODE_TYPE_CUSTOM:
-               case DECODE_TYPE_SIMULATE:
-               case DECODE_TYPE_EMULATE:
-                       coverage_add_registers(entry, insn);
-                       return;
-
-               case DECODE_TYPE_OR:
-                       matched = true;
-                       break;
-
-               case DECODE_TYPE_REJECT:
-               default:
-                       return;
-               }
-
-       }
-}
-
-static void coverage_end(void)
-{
-       struct coverage_entry *entry = coverage.base;
-       struct coverage_entry *end = coverage.base + coverage.num_entries;
-
-       for (; entry < end; ++entry) {
-               u32 mask = entry->header->mask.bits;
-               u32 value = entry->header->value.bits;
-
-               if (entry->regs) {
-                       pr_err("FAIL: Register test coverage missing for %08x %08x (%05x)\n",
-                               mask, value, entry->regs);
-                       coverage_fail = true;
-               }
-               if (!entry->matched) {
-                       pr_err("FAIL: Test coverage entry missing for %08x %08x\n",
-                               mask, value);
-                       coverage_fail = true;
-               }
-       }
-
-       kfree(coverage.base);
-}
-
-
-/*
- * Framework for instruction set test cases
- */
-
-void __naked __kprobes_test_case_start(void)
-{
-       __asm__ __volatile__ (
-               "stmdb  sp!, {r4-r11}                           \n\t"
-               "sub    sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
-               "bic    r0, lr, #1  @ r0 = inline data          \n\t"
-               "mov    r1, sp                                  \n\t"
-               "bl     kprobes_test_case_start                 \n\t"
-               "bx     r0                                      \n\t"
-       );
-}
-
-#ifndef CONFIG_THUMB2_KERNEL
-
-void __naked __kprobes_test_case_end_32(void)
-{
-       __asm__ __volatile__ (
-               "mov    r4, lr                                  \n\t"
-               "bl     kprobes_test_case_end                   \n\t"
-               "cmp    r0, #0                                  \n\t"
-               "movne  pc, r0                                  \n\t"
-               "mov    r0, r4                                  \n\t"
-               "add    sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
-               "ldmia  sp!, {r4-r11}                           \n\t"
-               "mov    pc, r0                                  \n\t"
-       );
-}
-
-#else /* CONFIG_THUMB2_KERNEL */
-
-void __naked __kprobes_test_case_end_16(void)
-{
-       __asm__ __volatile__ (
-               "mov    r4, lr                                  \n\t"
-               "bl     kprobes_test_case_end                   \n\t"
-               "cmp    r0, #0                                  \n\t"
-               "bxne   r0                                      \n\t"
-               "mov    r0, r4                                  \n\t"
-               "add    sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
-               "ldmia  sp!, {r4-r11}                           \n\t"
-               "bx     r0                                      \n\t"
-       );
-}
-
-void __naked __kprobes_test_case_end_32(void)
-{
-       __asm__ __volatile__ (
-               ".arm                                           \n\t"
-               "orr    lr, lr, #1  @ will return to Thumb code \n\t"
-               "ldr    pc, 1f                                  \n\t"
-               "1:                                             \n\t"
-               ".word  __kprobes_test_case_end_16              \n\t"
-       );
-}
-
-#endif
-
-
-int kprobe_test_flags;
-int kprobe_test_cc_position;
-
-static int test_try_count;
-static int test_pass_count;
-static int test_fail_count;
-
-static struct pt_regs initial_regs;
-static struct pt_regs expected_regs;
-static struct pt_regs result_regs;
-
-static u32 expected_memory[TEST_MEMORY_SIZE/sizeof(u32)];
-
-static const char *current_title;
-static struct test_arg *current_args;
-static u32 *current_stack;
-static uintptr_t current_branch_target;
-
-static uintptr_t current_code_start;
-static kprobe_opcode_t current_instruction;
-
-
-#define TEST_CASE_PASSED -1
-#define TEST_CASE_FAILED -2
-
-static int test_case_run_count;
-static bool test_case_is_thumb;
-static int test_instance;
-
-/*
- * We ignore the state of the imprecise abort disable flag (CPSR.A) because this
- * can change randomly as the kernel doesn't take care to preserve or initialise
- * this across context switches. Also, with Security Extentions, the flag may
- * not be under control of the kernel; for this reason we ignore the state of
- * the FIQ disable flag CPSR.F as well.
- */
-#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT)
-
-static unsigned long test_check_cc(int cc, unsigned long cpsr)
-{
-       int ret = arm_check_condition(cc << 28, cpsr);
-
-       return (ret != ARM_OPCODE_CONDTEST_FAIL);
-}
-
-static int is_last_scenario;
-static int probe_should_run; /* 0 = no, 1 = yes, -1 = unknown */
-static int memory_needs_checking;
-
-static unsigned long test_context_cpsr(int scenario)
-{
-       unsigned long cpsr;
-
-       probe_should_run = 1;
-
-       /* Default case is that we cycle through 16 combinations of flags */
-       cpsr  = (scenario & 0xf) << 28; /* N,Z,C,V flags */
-       cpsr |= (scenario & 0xf) << 16; /* GE flags */
-       cpsr |= (scenario & 0x1) << 27; /* Toggle Q flag */
-
-       if (!test_case_is_thumb) {
-               /* Testing ARM code */
-               int cc = current_instruction >> 28;
-
-               probe_should_run = test_check_cc(cc, cpsr) != 0;
-               if (scenario == 15)
-                       is_last_scenario = true;
-
-       } else if (kprobe_test_flags & TEST_FLAG_NO_ITBLOCK) {
-               /* Testing Thumb code without setting ITSTATE */
-               if (kprobe_test_cc_position) {
-                       int cc = (current_instruction >> kprobe_test_cc_position) & 0xf;
-                       probe_should_run = test_check_cc(cc, cpsr) != 0;
-               }
-
-               if (scenario == 15)
-                       is_last_scenario = true;
-
-       } else if (kprobe_test_flags & TEST_FLAG_FULL_ITBLOCK) {
-               /* Testing Thumb code with all combinations of ITSTATE */
-               unsigned x = (scenario >> 4);
-               unsigned cond_base = x % 7; /* ITSTATE<7:5> */
-               unsigned mask = x / 7 + 2;  /* ITSTATE<4:0>, bits reversed */
-
-               if (mask > 0x1f) {
-                       /* Finish by testing state from instruction 'itt al' */
-                       cond_base = 7;
-                       mask = 0x4;
-                       if ((scenario & 0xf) == 0xf)
-                               is_last_scenario = true;
-               }
-
-               cpsr |= cond_base << 13;        /* ITSTATE<7:5> */
-               cpsr |= (mask & 0x1) << 12;     /* ITSTATE<4> */
-               cpsr |= (mask & 0x2) << 10;     /* ITSTATE<3> */
-               cpsr |= (mask & 0x4) << 8;      /* ITSTATE<2> */
-               cpsr |= (mask & 0x8) << 23;     /* ITSTATE<1> */
-               cpsr |= (mask & 0x10) << 21;    /* ITSTATE<0> */
-
-               probe_should_run = test_check_cc((cpsr >> 12) & 0xf, cpsr) != 0;
-
-       } else {
-               /* Testing Thumb code with several combinations of ITSTATE */
-               switch (scenario) {
-               case 16: /* Clear NZCV flags and 'it eq' state (false as Z=0) */
-                       cpsr = 0x00000800;
-                       probe_should_run = 0;
-                       break;
-               case 17: /* Set NZCV flags and 'it vc' state (false as V=1) */
-                       cpsr = 0xf0007800;
-                       probe_should_run = 0;
-                       break;
-               case 18: /* Clear NZCV flags and 'it ls' state (true as C=0) */
-                       cpsr = 0x00009800;
-                       break;
-               case 19: /* Set NZCV flags and 'it cs' state (true as C=1) */
-                       cpsr = 0xf0002800;
-                       is_last_scenario = true;
-                       break;
-               }
-       }
-
-       return cpsr;
-}
-
-static void setup_test_context(struct pt_regs *regs)
-{
-       int scenario = test_case_run_count>>1;
-       unsigned long val;
-       struct test_arg *args;
-       int i;
-
-       is_last_scenario = false;
-       memory_needs_checking = false;
-
-       /* Initialise test memory on stack */
-       val = (scenario & 1) ? VALM : ~VALM;
-       for (i = 0; i < TEST_MEMORY_SIZE / sizeof(current_stack[0]); ++i)
-               current_stack[i] = val + (i << 8);
-       /* Put target of branch on stack for tests which load PC from memory */
-       if (current_branch_target)
-               current_stack[15] = current_branch_target;
-       /* Put a value for SP on stack for tests which load SP from memory */
-       current_stack[13] = (u32)current_stack + 120;
-
-       /* Initialise register values to their default state */
-       val = (scenario & 2) ? VALR : ~VALR;
-       for (i = 0; i < 13; ++i)
-               regs->uregs[i] = val ^ (i << 8);
-       regs->ARM_lr = val ^ (14 << 8);
-       regs->ARM_cpsr &= ~(APSR_MASK | PSR_IT_MASK);
-       regs->ARM_cpsr |= test_context_cpsr(scenario);
-
-       /* Perform testcase specific register setup  */
-       args = current_args;
-       for (; args[0].type != ARG_TYPE_END; ++args)
-               switch (args[0].type) {
-               case ARG_TYPE_REG: {
-                       struct test_arg_regptr *arg =
-                               (struct test_arg_regptr *)args;
-                       regs->uregs[arg->reg] = arg->val;
-                       break;
-               }
-               case ARG_TYPE_PTR: {
-                       struct test_arg_regptr *arg =
-                               (struct test_arg_regptr *)args;
-                       regs->uregs[arg->reg] =
-                               (unsigned long)current_stack + arg->val;
-                       memory_needs_checking = true;
-                       break;
-               }
-               case ARG_TYPE_MEM: {
-                       struct test_arg_mem *arg = (struct test_arg_mem *)args;
-                       current_stack[arg->index] = arg->val;
-                       break;
-               }
-               default:
-                       break;
-               }
-}
-
-struct test_probe {
-       struct kprobe   kprobe;
-       bool            registered;
-       int             hit;
-};
-
-static void unregister_test_probe(struct test_probe *probe)
-{
-       if (probe->registered) {
-               unregister_kprobe(&probe->kprobe);
-               probe->kprobe.flags = 0; /* Clear disable flag to allow reuse */
-       }
-       probe->registered = false;
-}
-
-static int register_test_probe(struct test_probe *probe)
-{
-       int ret;
-
-       if (probe->registered)
-               BUG();
-
-       ret = register_kprobe(&probe->kprobe);
-       if (ret >= 0) {
-               probe->registered = true;
-               probe->hit = -1;
-       }
-       return ret;
-}
-
-static int __kprobes
-test_before_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       container_of(p, struct test_probe, kprobe)->hit = test_instance;
-       return 0;
-}
-
-static void __kprobes
-test_before_post_handler(struct kprobe *p, struct pt_regs *regs,
-                                                       unsigned long flags)
-{
-       setup_test_context(regs);
-       initial_regs = *regs;
-       initial_regs.ARM_cpsr &= ~PSR_IGNORE_BITS;
-}
-
-static int __kprobes
-test_case_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       container_of(p, struct test_probe, kprobe)->hit = test_instance;
-       return 0;
-}
-
-static int __kprobes
-test_after_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       if (container_of(p, struct test_probe, kprobe)->hit == test_instance)
-               return 0; /* Already run for this test instance */
-
-       result_regs = *regs;
-       result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS;
-
-       /* Undo any changes done to SP by the test case */
-       regs->ARM_sp = (unsigned long)current_stack;
-
-       container_of(p, struct test_probe, kprobe)->hit = test_instance;
-       return 0;
-}
-
-static struct test_probe test_before_probe = {
-       .kprobe.pre_handler     = test_before_pre_handler,
-       .kprobe.post_handler    = test_before_post_handler,
-};
-
-static struct test_probe test_case_probe = {
-       .kprobe.pre_handler     = test_case_pre_handler,
-};
-
-static struct test_probe test_after_probe = {
-       .kprobe.pre_handler     = test_after_pre_handler,
-};
-
-static struct test_probe test_after2_probe = {
-       .kprobe.pre_handler     = test_after_pre_handler,
-};
-
-static void test_case_cleanup(void)
-{
-       unregister_test_probe(&test_before_probe);
-       unregister_test_probe(&test_case_probe);
-       unregister_test_probe(&test_after_probe);
-       unregister_test_probe(&test_after2_probe);
-}
-
-static void print_registers(struct pt_regs *regs)
-{
-       pr_err("r0  %08lx | r1  %08lx | r2  %08lx | r3  %08lx\n",
-               regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
-       pr_err("r4  %08lx | r5  %08lx | r6  %08lx | r7  %08lx\n",
-               regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7);
-       pr_err("r8  %08lx | r9  %08lx | r10 %08lx | r11 %08lx\n",
-               regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp);
-       pr_err("r12 %08lx | sp  %08lx | lr  %08lx | pc  %08lx\n",
-               regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc);
-       pr_err("cpsr %08lx\n", regs->ARM_cpsr);
-}
-
-static void print_memory(u32 *mem, size_t size)
-{
-       int i;
-       for (i = 0; i < size / sizeof(u32); i += 4)
-               pr_err("%08x %08x %08x %08x\n", mem[i], mem[i+1],
-                                               mem[i+2], mem[i+3]);
-}
-
-static size_t expected_memory_size(u32 *sp)
-{
-       size_t size = sizeof(expected_memory);
-       int offset = (uintptr_t)sp - (uintptr_t)current_stack;
-       if (offset > 0)
-               size -= offset;
-       return size;
-}
-
-static void test_case_failed(const char *message)
-{
-       test_case_cleanup();
-
-       pr_err("FAIL: %s\n", message);
-       pr_err("FAIL: Test %s\n", current_title);
-       pr_err("FAIL: Scenario %d\n", test_case_run_count >> 1);
-}
-
-static unsigned long next_instruction(unsigned long pc)
-{
-#ifdef CONFIG_THUMB2_KERNEL
-       if ((pc & 1) &&
-           !is_wide_instruction(__mem_to_opcode_thumb16(*(u16 *)(pc - 1))))
-               return pc + 2;
-       else
-#endif
-       return pc + 4;
-}
-
-static uintptr_t __used kprobes_test_case_start(const char **title, void *stack)
-{
-       struct test_arg *args;
-       struct test_arg_end *end_arg;
-       unsigned long test_code;
-
-       current_title = *title++;
-       args = (struct test_arg *)title;
-       current_args = args;
-       current_stack = stack;
-
-       ++test_try_count;
-
-       while (args->type != ARG_TYPE_END)
-               ++args;
-       end_arg = (struct test_arg_end *)args;
-
-       test_code = (unsigned long)(args + 1); /* Code starts after args */
-
-       test_case_is_thumb = end_arg->flags & ARG_FLAG_THUMB;
-       if (test_case_is_thumb)
-               test_code |= 1;
-
-       current_code_start = test_code;
-
-       current_branch_target = 0;
-       if (end_arg->branch_offset != end_arg->end_offset)
-               current_branch_target = test_code + end_arg->branch_offset;
-
-       test_code += end_arg->code_offset;
-       test_before_probe.kprobe.addr = (kprobe_opcode_t *)test_code;
-
-       test_code = next_instruction(test_code);
-       test_case_probe.kprobe.addr = (kprobe_opcode_t *)test_code;
-
-       if (test_case_is_thumb) {
-               u16 *p = (u16 *)(test_code & ~1);
-               current_instruction = __mem_to_opcode_thumb16(p[0]);
-               if (is_wide_instruction(current_instruction)) {
-                       u16 instr2 = __mem_to_opcode_thumb16(p[1]);
-                       current_instruction = __opcode_thumb32_compose(current_instruction, instr2);
-               }
-       } else {
-               current_instruction = __mem_to_opcode_arm(*(u32 *)test_code);
-       }
-
-       if (current_title[0] == '.')
-               verbose("%s\n", current_title);
-       else
-               verbose("%s\t@ %0*x\n", current_title,
-                                       test_case_is_thumb ? 4 : 8,
-                                       current_instruction);
-
-       test_code = next_instruction(test_code);
-       test_after_probe.kprobe.addr = (kprobe_opcode_t *)test_code;
-
-       if (kprobe_test_flags & TEST_FLAG_NARROW_INSTR) {
-               if (!test_case_is_thumb ||
-                       is_wide_instruction(current_instruction)) {
-                               test_case_failed("expected 16-bit instruction");
-                               goto fail;
-               }
-       } else {
-               if (test_case_is_thumb &&
-                       !is_wide_instruction(current_instruction)) {
-                               test_case_failed("expected 32-bit instruction");
-                               goto fail;
-               }
-       }
-
-       coverage_add(current_instruction);
-
-       if (end_arg->flags & ARG_FLAG_UNSUPPORTED) {
-               if (register_test_probe(&test_case_probe) < 0)
-                       goto pass;
-               test_case_failed("registered probe for unsupported instruction");
-               goto fail;
-       }
-
-       if (end_arg->flags & ARG_FLAG_SUPPORTED) {
-               if (register_test_probe(&test_case_probe) >= 0)
-                       goto pass;
-               test_case_failed("couldn't register probe for supported instruction");
-               goto fail;
-       }
-
-       if (register_test_probe(&test_before_probe) < 0) {
-               test_case_failed("register test_before_probe failed");
-               goto fail;
-       }
-       if (register_test_probe(&test_after_probe) < 0) {
-               test_case_failed("register test_after_probe failed");
-               goto fail;
-       }
-       if (current_branch_target) {
-               test_after2_probe.kprobe.addr =
-                               (kprobe_opcode_t *)current_branch_target;
-               if (register_test_probe(&test_after2_probe) < 0) {
-                       test_case_failed("register test_after2_probe failed");
-                       goto fail;
-               }
-       }
-
-       /* Start first run of test case */
-       test_case_run_count = 0;
-       ++test_instance;
-       return current_code_start;
-pass:
-       test_case_run_count = TEST_CASE_PASSED;
-       return (uintptr_t)test_after_probe.kprobe.addr;
-fail:
-       test_case_run_count = TEST_CASE_FAILED;
-       return (uintptr_t)test_after_probe.kprobe.addr;
-}
-
-static bool check_test_results(void)
-{
-       size_t mem_size = 0;
-       u32 *mem = 0;
-
-       if (memcmp(&expected_regs, &result_regs, sizeof(expected_regs))) {
-               test_case_failed("registers differ");
-               goto fail;
-       }
-
-       if (memory_needs_checking) {
-               mem = (u32 *)result_regs.ARM_sp;
-               mem_size = expected_memory_size(mem);
-               if (memcmp(expected_memory, mem, mem_size)) {
-                       test_case_failed("test memory differs");
-                       goto fail;
-               }
-       }
-
-       return true;
-
-fail:
-       pr_err("initial_regs:\n");
-       print_registers(&initial_regs);
-       pr_err("expected_regs:\n");
-       print_registers(&expected_regs);
-       pr_err("result_regs:\n");
-       print_registers(&result_regs);
-
-       if (mem) {
-               pr_err("current_stack=%p\n", current_stack);
-               pr_err("expected_memory:\n");
-               print_memory(expected_memory, mem_size);
-               pr_err("result_memory:\n");
-               print_memory(mem, mem_size);
-       }
-
-       return false;
-}
-
-static uintptr_t __used kprobes_test_case_end(void)
-{
-       if (test_case_run_count < 0) {
-               if (test_case_run_count == TEST_CASE_PASSED)
-                       /* kprobes_test_case_start did all the needed testing */
-                       goto pass;
-               else
-                       /* kprobes_test_case_start failed */
-                       goto fail;
-       }
-
-       if (test_before_probe.hit != test_instance) {
-               test_case_failed("test_before_handler not run");
-               goto fail;
-       }
-
-       if (test_after_probe.hit != test_instance &&
-                               test_after2_probe.hit != test_instance) {
-               test_case_failed("test_after_handler not run");
-               goto fail;
-       }
-
-       /*
-        * Even numbered test runs ran without a probe on the test case so
-        * we can gather reference results. The subsequent odd numbered run
-        * will have the probe inserted.
-       */
-       if ((test_case_run_count & 1) == 0) {
-               /* Save results from run without probe */
-               u32 *mem = (u32 *)result_regs.ARM_sp;
-               expected_regs = result_regs;
-               memcpy(expected_memory, mem, expected_memory_size(mem));
-
-               /* Insert probe onto test case instruction */
-               if (register_test_probe(&test_case_probe) < 0) {
-                       test_case_failed("register test_case_probe failed");
-                       goto fail;
-               }
-       } else {
-               /* Check probe ran as expected */
-               if (probe_should_run == 1) {
-                       if (test_case_probe.hit != test_instance) {
-                               test_case_failed("test_case_handler not run");
-                               goto fail;
-                       }
-               } else if (probe_should_run == 0) {
-                       if (test_case_probe.hit == test_instance) {
-                               test_case_failed("test_case_handler ran");
-                               goto fail;
-                       }
-               }
-
-               /* Remove probe for any subsequent reference run */
-               unregister_test_probe(&test_case_probe);
-
-               if (!check_test_results())
-                       goto fail;
-
-               if (is_last_scenario)
-                       goto pass;
-       }
-
-       /* Do next test run */
-       ++test_case_run_count;
-       ++test_instance;
-       return current_code_start;
-fail:
-       ++test_fail_count;
-       goto end;
-pass:
-       ++test_pass_count;
-end:
-       test_case_cleanup();
-       return 0;
-}
-
-
-/*
- * Top level test functions
- */
-
-static int run_test_cases(void (*tests)(void), const union decode_item *table)
-{
-       int ret;
-
-       pr_info("    Check decoding tables\n");
-       ret = table_test(table);
-       if (ret)
-               return ret;
-
-       pr_info("    Run test cases\n");
-       ret = coverage_start(table);
-       if (ret)
-               return ret;
-
-       tests();
-
-       coverage_end();
-       return 0;
-}
-
-
-static int __init run_all_tests(void)
-{
-       int ret = 0;
-
-       pr_info("Beginning kprobe tests...\n");
-
-#ifndef CONFIG_THUMB2_KERNEL
-
-       pr_info("Probe ARM code\n");
-       ret = run_api_tests(arm_func);
-       if (ret)
-               goto out;
-
-       pr_info("ARM instruction simulation\n");
-       ret = run_test_cases(kprobe_arm_test_cases, probes_decode_arm_table);
-       if (ret)
-               goto out;
-
-#else /* CONFIG_THUMB2_KERNEL */
-
-       pr_info("Probe 16-bit Thumb code\n");
-       ret = run_api_tests(thumb16_func);
-       if (ret)
-               goto out;
-
-       pr_info("Probe 32-bit Thumb code, even halfword\n");
-       ret = run_api_tests(thumb32even_func);
-       if (ret)
-               goto out;
-
-       pr_info("Probe 32-bit Thumb code, odd halfword\n");
-       ret = run_api_tests(thumb32odd_func);
-       if (ret)
-               goto out;
-
-       pr_info("16-bit Thumb instruction simulation\n");
-       ret = run_test_cases(kprobe_thumb16_test_cases,
-                               probes_decode_thumb16_table);
-       if (ret)
-               goto out;
-
-       pr_info("32-bit Thumb instruction simulation\n");
-       ret = run_test_cases(kprobe_thumb32_test_cases,
-                               probes_decode_thumb32_table);
-       if (ret)
-               goto out;
-#endif
-
-       pr_info("Total instruction simulation tests=%d, pass=%d fail=%d\n",
-               test_try_count, test_pass_count, test_fail_count);
-       if (test_fail_count) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-#if BENCHMARKING
-       pr_info("Benchmarks\n");
-       ret = run_benchmarks();
-       if (ret)
-               goto out;
-#endif
-
-#if __LINUX_ARM_ARCH__ >= 7
-       /* We are able to run all test cases so coverage should be complete */
-       if (coverage_fail) {
-               pr_err("FAIL: Test coverage checks failed\n");
-               ret = -EINVAL;
-               goto out;
-       }
-#endif
-
-out:
-       if (ret == 0)
-               ret = tests_failed;
-       if (ret == 0)
-               pr_info("Finished kprobe tests OK\n");
-       else
-               pr_err("kprobe tests failed\n");
-
-       return ret;
-}
-
-
-/*
- * Module setup
- */
-
-#ifdef MODULE
-
-static void __exit kprobe_test_exit(void)
-{
-}
-
-module_init(run_all_tests)
-module_exit(kprobe_test_exit)
-MODULE_LICENSE("GPL");
-
-#else /* !MODULE */
-
-late_initcall(run_all_tests);
-
-#endif
diff --git a/arch/arm/kernel/kprobes-test.h b/arch/arm/kernel/kprobes-test.h
deleted file mode 100644 (file)
index 4430990..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * arch/arm/kernel/kprobes-test.h
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#define VERBOSE 0 /* Set to '1' for more logging of test cases */
-
-#ifdef CONFIG_THUMB2_KERNEL
-#define NORMAL_ISA "16"
-#else
-#define NORMAL_ISA "32"
-#endif
-
-
-/* Flags used in kprobe_test_flags */
-#define TEST_FLAG_NO_ITBLOCK   (1<<0)
-#define TEST_FLAG_FULL_ITBLOCK (1<<1)
-#define TEST_FLAG_NARROW_INSTR (1<<2)
-
-extern int kprobe_test_flags;
-extern int kprobe_test_cc_position;
-
-
-#define TEST_MEMORY_SIZE 256
-
-
-/*
- * Test case structures.
- *
- * The arguments given to test cases can be one of three types.
- *
- *   ARG_TYPE_REG
- *     Load a register with the given value.
- *
- *   ARG_TYPE_PTR
- *     Load a register with a pointer into the stack buffer (SP + given value).
- *
- *   ARG_TYPE_MEM
- *     Store the given value into the stack buffer at [SP+index].
- *
- */
-
-#define        ARG_TYPE_END    0
-#define        ARG_TYPE_REG    1
-#define        ARG_TYPE_PTR    2
-#define        ARG_TYPE_MEM    3
-
-#define ARG_FLAG_UNSUPPORTED   0x01
-#define ARG_FLAG_SUPPORTED     0x02
-#define ARG_FLAG_THUMB         0x10    /* Must be 16 so TEST_ISA can be used */
-#define ARG_FLAG_ARM           0x20    /* Must be 32 so TEST_ISA can be used */
-
-struct test_arg {
-       u8      type;           /* ARG_TYPE_x */
-       u8      _padding[7];
-};
-
-struct test_arg_regptr {
-       u8      type;           /* ARG_TYPE_REG or ARG_TYPE_PTR */
-       u8      reg;
-       u8      _padding[2];
-       u32     val;
-};
-
-struct test_arg_mem {
-       u8      type;           /* ARG_TYPE_MEM */
-       u8      index;
-       u8      _padding[2];
-       u32     val;
-};
-
-struct test_arg_end {
-       u8      type;           /* ARG_TYPE_END */
-       u8      flags;          /* ARG_FLAG_x */
-       u16     code_offset;
-       u16     branch_offset;
-       u16     end_offset;
-};
-
-
-/*
- * Building blocks for test cases.
- *
- * Each test case is wrapped between TESTCASE_START and TESTCASE_END.
- *
- * To specify arguments for a test case the TEST_ARG_{REG,PTR,MEM} macros are
- * used followed by a terminating TEST_ARG_END.
- *
- * After this, the instruction to be tested is defined with TEST_INSTRUCTION.
- * Or for branches, TEST_BRANCH_B and TEST_BRANCH_F (branch forwards/backwards).
- *
- * Some specific test cases may make use of other custom constructs.
- */
-
-#if VERBOSE
-#define verbose(fmt, ...) pr_info(fmt, ##__VA_ARGS__)
-#else
-#define verbose(fmt, ...)
-#endif
-
-#define TEST_GROUP(title)                                      \
-       verbose("\n");                                          \
-       verbose(title"\n");                                     \
-       verbose("---------------------------------------------------------\n");
-
-#define TESTCASE_START(title)                                  \
-       __asm__ __volatile__ (                                  \
-       "bl     __kprobes_test_case_start               \n\t"   \
-       ".pushsection .rodata                           \n\t"   \
-       "10:                                            \n\t"   \
-       /* don't use .asciz here as 'title' may be */           \
-       /* multiple strings to be concatenated.  */             \
-       ".ascii "#title"                                \n\t"   \
-       ".byte  0                                       \n\t"   \
-       ".popsection                                    \n\t"   \
-       ".word  10b                                     \n\t"
-
-#define        TEST_ARG_REG(reg, val)                                  \
-       ".byte  "__stringify(ARG_TYPE_REG)"             \n\t"   \
-       ".byte  "#reg"                                  \n\t"   \
-       ".short 0                                       \n\t"   \
-       ".word  "#val"                                  \n\t"
-
-#define        TEST_ARG_PTR(reg, val)                                  \
-       ".byte  "__stringify(ARG_TYPE_PTR)"             \n\t"   \
-       ".byte  "#reg"                                  \n\t"   \
-       ".short 0                                       \n\t"   \
-       ".word  "#val"                                  \n\t"
-
-#define        TEST_ARG_MEM(index, val)                                \
-       ".byte  "__stringify(ARG_TYPE_MEM)"             \n\t"   \
-       ".byte  "#index"                                \n\t"   \
-       ".short 0                                       \n\t"   \
-       ".word  "#val"                                  \n\t"
-
-#define        TEST_ARG_END(flags)                                     \
-       ".byte  "__stringify(ARG_TYPE_END)"             \n\t"   \
-       ".byte  "TEST_ISA flags"                        \n\t"   \
-       ".short 50f-0f                                  \n\t"   \
-       ".short 2f-0f                                   \n\t"   \
-       ".short 99f-0f                                  \n\t"   \
-       ".code "TEST_ISA"                               \n\t"   \
-       "0:                                             \n\t"
-
-#define TEST_INSTRUCTION(instruction)                          \
-       "50:    nop                                     \n\t"   \
-       "1:     "instruction"                           \n\t"   \
-       "       nop                                     \n\t"
-
-#define TEST_BRANCH_F(instruction)                             \
-       TEST_INSTRUCTION(instruction)                           \
-       "       b       99f                             \n\t"   \
-       "2:     nop                                     \n\t"
-
-#define TEST_BRANCH_B(instruction)                             \
-       "       b       50f                             \n\t"   \
-       "       b       99f                             \n\t"   \
-       "2:     nop                                     \n\t"   \
-       "       b       99f                             \n\t"   \
-       TEST_INSTRUCTION(instruction)
-
-#define TEST_BRANCH_FX(instruction, codex)                     \
-       TEST_INSTRUCTION(instruction)                           \
-       "       b       99f                             \n\t"   \
-       codex"                                          \n\t"   \
-       "       b       99f                             \n\t"   \
-       "2:     nop                                     \n\t"
-
-#define TEST_BRANCH_BX(instruction, codex)                     \
-       "       b       50f                             \n\t"   \
-       "       b       99f                             \n\t"   \
-       "2:     nop                                     \n\t"   \
-       "       b       99f                             \n\t"   \
-       codex"                                          \n\t"   \
-       TEST_INSTRUCTION(instruction)
-
-#define TESTCASE_END                                           \
-       "2:                                             \n\t"   \
-       "99:                                            \n\t"   \
-       "       bl __kprobes_test_case_end_"TEST_ISA"   \n\t"   \
-       ".code "NORMAL_ISA"                             \n\t"   \
-       : :                                                     \
-       : "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc"    \
-       );
-
-
-/*
- * Macros to define test cases.
- *
- * Those of the form TEST_{R,P,M}* can be used to define test cases
- * which take combinations of the three basic types of arguments. E.g.
- *
- *   TEST_R    One register argument
- *   TEST_RR   Two register arguments
- *   TEST_RPR  A register, a pointer, then a register argument
- *
- * For testing instructions which may branch, there are macros TEST_BF_*
- * and TEST_BB_* for branching forwards and backwards.
- *
- * TEST_SUPPORTED and TEST_UNSUPPORTED don't cause the code to be executed,
- * the just verify that a kprobe is or is not allowed on the given instruction.
- */
-
-#define TEST(code)                             \
-       TESTCASE_START(code)                    \
-       TEST_ARG_END("")                        \
-       TEST_INSTRUCTION(code)                  \
-       TESTCASE_END
-
-#define TEST_UNSUPPORTED(code)                                 \
-       TESTCASE_START(code)                                    \
-       TEST_ARG_END("|"__stringify(ARG_FLAG_UNSUPPORTED))      \
-       TEST_INSTRUCTION(code)                                  \
-       TESTCASE_END
-
-#define TEST_SUPPORTED(code)                                   \
-       TESTCASE_START(code)                                    \
-       TEST_ARG_END("|"__stringify(ARG_FLAG_SUPPORTED))        \
-       TEST_INSTRUCTION(code)                                  \
-       TESTCASE_END
-
-#define TEST_R(code1, reg, val, code2)                 \
-       TESTCASE_START(code1 #reg code2)                \
-       TEST_ARG_REG(reg, val)                          \
-       TEST_ARG_END("")                                \
-       TEST_INSTRUCTION(code1 #reg code2)              \
-       TESTCASE_END
-
-#define TEST_RR(code1, reg1, val1, code2, reg2, val2, code3)   \
-       TESTCASE_START(code1 #reg1 code2 #reg2 code3)           \
-       TEST_ARG_REG(reg1, val1)                                \
-       TEST_ARG_REG(reg2, val2)                                \
-       TEST_ARG_END("")                                        \
-       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3)         \
-       TESTCASE_END
-
-#define TEST_RRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
-       TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4)               \
-       TEST_ARG_REG(reg1, val1)                                                \
-       TEST_ARG_REG(reg2, val2)                                                \
-       TEST_ARG_REG(reg3, val3)                                                \
-       TEST_ARG_END("")                                                        \
-       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4)             \
-       TESTCASE_END
-
-#define TEST_RRRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4, reg4, val4)  \
-       TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4 #reg4)         \
-       TEST_ARG_REG(reg1, val1)                                                \
-       TEST_ARG_REG(reg2, val2)                                                \
-       TEST_ARG_REG(reg3, val3)                                                \
-       TEST_ARG_REG(reg4, val4)                                                \
-       TEST_ARG_END("")                                                        \
-       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4 #reg4)       \
-       TESTCASE_END
-
-#define TEST_P(code1, reg1, val1, code2)       \
-       TESTCASE_START(code1 #reg1 code2)       \
-       TEST_ARG_PTR(reg1, val1)                \
-       TEST_ARG_END("")                        \
-       TEST_INSTRUCTION(code1 #reg1 code2)     \
-       TESTCASE_END
-
-#define TEST_PR(code1, reg1, val1, code2, reg2, val2, code3)   \
-       TESTCASE_START(code1 #reg1 code2 #reg2 code3)           \
-       TEST_ARG_PTR(reg1, val1)                                \
-       TEST_ARG_REG(reg2, val2)                                \
-       TEST_ARG_END("")                                        \
-       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3)         \
-       TESTCASE_END
-
-#define TEST_RP(code1, reg1, val1, code2, reg2, val2, code3)   \
-       TESTCASE_START(code1 #reg1 code2 #reg2 code3)           \
-       TEST_ARG_REG(reg1, val1)                                \
-       TEST_ARG_PTR(reg2, val2)                                \
-       TEST_ARG_END("")                                        \
-       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3)         \
-       TESTCASE_END
-
-#define TEST_PRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
-       TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4)               \
-       TEST_ARG_PTR(reg1, val1)                                                \
-       TEST_ARG_REG(reg2, val2)                                                \
-       TEST_ARG_REG(reg3, val3)                                                \
-       TEST_ARG_END("")                                                        \
-       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4)             \
-       TESTCASE_END
-
-#define TEST_RPR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
-       TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4)               \
-       TEST_ARG_REG(reg1, val1)                                                \
-       TEST_ARG_PTR(reg2, val2)                                                \
-       TEST_ARG_REG(reg3, val3)                                                \
-       TEST_ARG_END("")                                                        \
-       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4)             \
-       TESTCASE_END
-
-#define TEST_RRP(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
-       TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4)               \
-       TEST_ARG_REG(reg1, val1)                                                \
-       TEST_ARG_REG(reg2, val2)                                                \
-       TEST_ARG_PTR(reg3, val3)                                                \
-       TEST_ARG_END("")                                                        \
-       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4)             \
-       TESTCASE_END
-
-#define TEST_BF_P(code1, reg1, val1, code2)    \
-       TESTCASE_START(code1 #reg1 code2)       \
-       TEST_ARG_PTR(reg1, val1)                \
-       TEST_ARG_END("")                        \
-       TEST_BRANCH_F(code1 #reg1 code2)        \
-       TESTCASE_END
-
-#define TEST_BF(code)                          \
-       TESTCASE_START(code)                    \
-       TEST_ARG_END("")                        \
-       TEST_BRANCH_F(code)                     \
-       TESTCASE_END
-
-#define TEST_BB(code)                          \
-       TESTCASE_START(code)                    \
-       TEST_ARG_END("")                        \
-       TEST_BRANCH_B(code)                     \
-       TESTCASE_END
-
-#define TEST_BF_R(code1, reg, val, code2)      \
-       TESTCASE_START(code1 #reg code2)        \
-       TEST_ARG_REG(reg, val)                  \
-       TEST_ARG_END("")                        \
-       TEST_BRANCH_F(code1 #reg code2)         \
-       TESTCASE_END
-
-#define TEST_BB_R(code1, reg, val, code2)      \
-       TESTCASE_START(code1 #reg code2)        \
-       TEST_ARG_REG(reg, val)                  \
-       TEST_ARG_END("")                        \
-       TEST_BRANCH_B(code1 #reg code2)         \
-       TESTCASE_END
-
-#define TEST_BF_RR(code1, reg1, val1, code2, reg2, val2, code3)        \
-       TESTCASE_START(code1 #reg1 code2 #reg2 code3)           \
-       TEST_ARG_REG(reg1, val1)                                \
-       TEST_ARG_REG(reg2, val2)                                \
-       TEST_ARG_END("")                                        \
-       TEST_BRANCH_F(code1 #reg1 code2 #reg2 code3)            \
-       TESTCASE_END
-
-#define TEST_BF_X(code, codex)                 \
-       TESTCASE_START(code)                    \
-       TEST_ARG_END("")                        \
-       TEST_BRANCH_FX(code, codex)             \
-       TESTCASE_END
-
-#define TEST_BB_X(code, codex)                 \
-       TESTCASE_START(code)                    \
-       TEST_ARG_END("")                        \
-       TEST_BRANCH_BX(code, codex)             \
-       TESTCASE_END
-
-#define TEST_BF_RX(code1, reg, val, code2, codex)      \
-       TESTCASE_START(code1 #reg code2)                \
-       TEST_ARG_REG(reg, val)                          \
-       TEST_ARG_END("")                                \
-       TEST_BRANCH_FX(code1 #reg code2, codex)         \
-       TESTCASE_END
-
-#define TEST_X(code, codex)                    \
-       TESTCASE_START(code)                    \
-       TEST_ARG_END("")                        \
-       TEST_INSTRUCTION(code)                  \
-       "       b       99f             \n\t"   \
-       "       "codex"                 \n\t"   \
-       TESTCASE_END
-
-#define TEST_RX(code1, reg, val, code2, codex)         \
-       TESTCASE_START(code1 #reg code2)                \
-       TEST_ARG_REG(reg, val)                          \
-       TEST_ARG_END("")                                \
-       TEST_INSTRUCTION(code1 __stringify(reg) code2)  \
-       "       b       99f             \n\t"           \
-       "       "codex"                 \n\t"           \
-       TESTCASE_END
-
-#define TEST_RRX(code1, reg1, val1, code2, reg2, val2, code3, codex)           \
-       TESTCASE_START(code1 #reg1 code2 #reg2 code3)                           \
-       TEST_ARG_REG(reg1, val1)                                                \
-       TEST_ARG_REG(reg2, val2)                                                \
-       TEST_ARG_END("")                                                        \
-       TEST_INSTRUCTION(code1 __stringify(reg1) code2 __stringify(reg2) code3) \
-       "       b       99f             \n\t"                                   \
-       "       "codex"                 \n\t"                                   \
-       TESTCASE_END
-
-
-/*
- * Macros for defining space directives spread over multiple lines.
- * These are required so the compiler guesses better the length of inline asm
- * code and will spill the literal pool early enough to avoid generating PC
- * relative loads with out of range offsets.
- */
-#define TWICE(x)       x x
-#define SPACE_0x8      TWICE(".space 4\n\t")
-#define SPACE_0x10     TWICE(SPACE_0x8)
-#define SPACE_0x20     TWICE(SPACE_0x10)
-#define SPACE_0x40     TWICE(SPACE_0x20)
-#define SPACE_0x80     TWICE(SPACE_0x40)
-#define SPACE_0x100    TWICE(SPACE_0x80)
-#define SPACE_0x200    TWICE(SPACE_0x100)
-#define SPACE_0x400    TWICE(SPACE_0x200)
-#define SPACE_0x800    TWICE(SPACE_0x400)
-#define SPACE_0x1000   TWICE(SPACE_0x800)
-
-
-/* Various values used in test cases... */
-#define N(val) (val ^ 0xffffffff)
-#define VAL1   0x12345678
-#define VAL2   N(VAL1)
-#define VAL3   0xa5f801
-#define VAL4   N(VAL3)
-#define VALM   0x456789ab
-#define VALR   0xdeaddead
-#define HH1    0x0123fecb
-#define HH2    0xa9874567
-
-
-#ifdef CONFIG_THUMB2_KERNEL
-void kprobe_thumb16_test_cases(void);
-void kprobe_thumb32_test_cases(void);
-#else
-void kprobe_arm_test_cases(void);
-#endif
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c
deleted file mode 100644 (file)
index 9495d7f..0000000
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
- * arch/arm/kernel/kprobes-thumb.c
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ptrace.h>
-#include <linux/kprobes.h>
-
-#include "kprobes.h"
-#include "probes-thumb.h"
-
-/* These emulation encodings are functionally equivalent... */
-#define t32_emulate_rd8rn16rm0ra12_noflags \
-               t32_emulate_rdlo12rdhi8rn16rm0_noflags
-
-/* t32 thumb actions */
-
-static void __kprobes
-t32_simulate_table_branch(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc;
-       int rn = (insn >> 16) & 0xf;
-       int rm = insn & 0xf;
-
-       unsigned long rnv = (rn == 15) ? pc : regs->uregs[rn];
-       unsigned long rmv = regs->uregs[rm];
-       unsigned int halfwords;
-
-       if (insn & 0x10) /* TBH */
-               halfwords = ((u16 *)rnv)[rmv];
-       else /* TBB */
-               halfwords = ((u8 *)rnv)[rmv];
-
-       regs->ARM_pc = pc + 2 * halfwords;
-}
-
-static void __kprobes
-t32_simulate_mrs(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       int rd = (insn >> 8) & 0xf;
-       unsigned long mask = 0xf8ff03df; /* Mask out execution state */
-       regs->uregs[rd] = regs->ARM_cpsr & mask;
-}
-
-static void __kprobes
-t32_simulate_cond_branch(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc;
-
-       long offset = insn & 0x7ff;             /* imm11 */
-       offset += (insn & 0x003f0000) >> 5;     /* imm6 */
-       offset += (insn & 0x00002000) << 4;     /* J1 */
-       offset += (insn & 0x00000800) << 7;     /* J2 */
-       offset -= (insn & 0x04000000) >> 7;     /* Apply sign bit */
-
-       regs->ARM_pc = pc + (offset * 2);
-}
-
-static enum probes_insn __kprobes
-t32_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
-               const struct decode_header *d)
-{
-       int cc = (insn >> 22) & 0xf;
-       asi->insn_check_cc = probes_condition_checks[cc];
-       asi->insn_handler = t32_simulate_cond_branch;
-       return INSN_GOOD_NO_SLOT;
-}
-
-static void __kprobes
-t32_simulate_branch(probes_opcode_t insn,
-                   struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc;
-
-       long offset = insn & 0x7ff;             /* imm11 */
-       offset += (insn & 0x03ff0000) >> 5;     /* imm10 */
-       offset += (insn & 0x00002000) << 9;     /* J1 */
-       offset += (insn & 0x00000800) << 10;    /* J2 */
-       if (insn & 0x04000000)
-               offset -= 0x00800000; /* Apply sign bit */
-       else
-               offset ^= 0x00600000; /* Invert J1 and J2 */
-
-       if (insn & (1 << 14)) {
-               /* BL or BLX */
-               regs->ARM_lr = regs->ARM_pc | 1;
-               if (!(insn & (1 << 12))) {
-                       /* BLX so switch to ARM mode */
-                       regs->ARM_cpsr &= ~PSR_T_BIT;
-                       pc &= ~3;
-               }
-       }
-
-       regs->ARM_pc = pc + (offset * 2);
-}
-
-static void __kprobes
-t32_simulate_ldr_literal(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long addr = regs->ARM_pc & ~3;
-       int rt = (insn >> 12) & 0xf;
-       unsigned long rtv;
-
-       long offset = insn & 0xfff;
-       if (insn & 0x00800000)
-               addr += offset;
-       else
-               addr -= offset;
-
-       if (insn & 0x00400000) {
-               /* LDR */
-               rtv = *(unsigned long *)addr;
-               if (rt == 15) {
-                       bx_write_pc(rtv, regs);
-                       return;
-               }
-       } else if (insn & 0x00200000) {
-               /* LDRH */
-               if (insn & 0x01000000)
-                       rtv = *(s16 *)addr;
-               else
-                       rtv = *(u16 *)addr;
-       } else {
-               /* LDRB */
-               if (insn & 0x01000000)
-                       rtv = *(s8 *)addr;
-               else
-                       rtv = *(u8 *)addr;
-       }
-
-       regs->uregs[rt] = rtv;
-}
-
-static enum probes_insn __kprobes
-t32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
-               const struct decode_header *d)
-{
-       enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d);
-
-       /* Fixup modified instruction to have halfwords in correct order...*/
-       insn = __mem_to_opcode_arm(asi->insn[0]);
-       ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16);
-       ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff);
-
-       return ret;
-}
-
-static void __kprobes
-t32_emulate_ldrdstrd(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc & ~3;
-       int rt1 = (insn >> 12) & 0xf;
-       int rt2 = (insn >> 8) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-
-       register unsigned long rt1v asm("r0") = regs->uregs[rt1];
-       register unsigned long rt2v asm("r1") = regs->uregs[rt2];
-       register unsigned long rnv asm("r2") = (rn == 15) ? pc
-                                                         : regs->uregs[rn];
-
-       __asm__ __volatile__ (
-               "blx    %[fn]"
-               : "=r" (rt1v), "=r" (rt2v), "=r" (rnv)
-               : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       if (rn != 15)
-               regs->uregs[rn] = rnv; /* Writeback base register */
-       regs->uregs[rt1] = rt1v;
-       regs->uregs[rt2] = rt2v;
-}
-
-static void __kprobes
-t32_emulate_ldrstr(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       int rt = (insn >> 12) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-       int rm = insn & 0xf;
-
-       register unsigned long rtv asm("r0") = regs->uregs[rt];
-       register unsigned long rnv asm("r2") = regs->uregs[rn];
-       register unsigned long rmv asm("r3") = regs->uregs[rm];
-
-       __asm__ __volatile__ (
-               "blx    %[fn]"
-               : "=r" (rtv), "=r" (rnv)
-               : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rn] = rnv; /* Writeback base register */
-       if (rt == 15) /* Can't be true for a STR as they aren't allowed */
-               bx_write_pc(rtv, regs);
-       else
-               regs->uregs[rt] = rtv;
-}
-
-static void __kprobes
-t32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       int rd = (insn >> 8) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-       int rm = insn & 0xf;
-
-       register unsigned long rdv asm("r1") = regs->uregs[rd];
-       register unsigned long rnv asm("r2") = regs->uregs[rn];
-       register unsigned long rmv asm("r3") = regs->uregs[rm];
-       unsigned long cpsr = regs->ARM_cpsr;
-
-       __asm__ __volatile__ (
-               "msr    cpsr_fs, %[cpsr]        \n\t"
-               "blx    %[fn]                   \n\t"
-               "mrs    %[cpsr], cpsr           \n\t"
-               : "=r" (rdv), [cpsr] "=r" (cpsr)
-               : "0" (rdv), "r" (rnv), "r" (rmv),
-                 "1" (cpsr), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rd] = rdv;
-       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
-}
-
-static void __kprobes
-t32_emulate_rd8pc16_noflags(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc;
-       int rd = (insn >> 8) & 0xf;
-
-       register unsigned long rdv asm("r1") = regs->uregs[rd];
-       register unsigned long rnv asm("r2") = pc & ~3;
-
-       __asm__ __volatile__ (
-               "blx    %[fn]"
-               : "=r" (rdv)
-               : "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rd] = rdv;
-}
-
-static void __kprobes
-t32_emulate_rd8rn16_noflags(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       int rd = (insn >> 8) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-
-       register unsigned long rdv asm("r1") = regs->uregs[rd];
-       register unsigned long rnv asm("r2") = regs->uregs[rn];
-
-       __asm__ __volatile__ (
-               "blx    %[fn]"
-               : "=r" (rdv)
-               : "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rd] = rdv;
-}
-
-static void __kprobes
-t32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn,
-               struct arch_probes_insn *asi,
-               struct pt_regs *regs)
-{
-       int rdlo = (insn >> 12) & 0xf;
-       int rdhi = (insn >> 8) & 0xf;
-       int rn = (insn >> 16) & 0xf;
-       int rm = insn & 0xf;
-
-       register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
-       register unsigned long rdhiv asm("r1") = regs->uregs[rdhi];
-       register unsigned long rnv asm("r2") = regs->uregs[rn];
-       register unsigned long rmv asm("r3") = regs->uregs[rm];
-
-       __asm__ __volatile__ (
-               "blx    %[fn]"
-               : "=r" (rdlov), "=r" (rdhiv)
-               : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
-                 [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rdlo] = rdlov;
-       regs->uregs[rdhi] = rdhiv;
-}
-/* t16 thumb actions */
-
-static void __kprobes
-t16_simulate_bxblx(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc + 2;
-       int rm = (insn >> 3) & 0xf;
-       unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm];
-
-       if (insn & (1 << 7)) /* BLX ? */
-               regs->ARM_lr = regs->ARM_pc | 1;
-
-       bx_write_pc(rmv, regs);
-}
-
-static void __kprobes
-t16_simulate_ldr_literal(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3);
-       long index = insn & 0xff;
-       int rt = (insn >> 8) & 0x7;
-       regs->uregs[rt] = base[index];
-}
-
-static void __kprobes
-t16_simulate_ldrstr_sp_relative(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long* base = (unsigned long *)regs->ARM_sp;
-       long index = insn & 0xff;
-       int rt = (insn >> 8) & 0x7;
-       if (insn & 0x800) /* LDR */
-               regs->uregs[rt] = base[index];
-       else /* STR */
-               base[index] = regs->uregs[rt];
-}
-
-static void __kprobes
-t16_simulate_reladr(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long base = (insn & 0x800) ? regs->ARM_sp
-                                           : ((regs->ARM_pc + 2) & ~3);
-       long offset = insn & 0xff;
-       int rt = (insn >> 8) & 0x7;
-       regs->uregs[rt] = base + offset * 4;
-}
-
-static void __kprobes
-t16_simulate_add_sp_imm(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       long imm = insn & 0x7f;
-       if (insn & 0x80) /* SUB */
-               regs->ARM_sp -= imm * 4;
-       else /* ADD */
-               regs->ARM_sp += imm * 4;
-}
-
-static void __kprobes
-t16_simulate_cbz(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       int rn = insn & 0x7;
-       probes_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn;
-       if (nonzero & 0x800) {
-               long i = insn & 0x200;
-               long imm5 = insn & 0xf8;
-               unsigned long pc = regs->ARM_pc + 2;
-               regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2);
-       }
-}
-
-static void __kprobes
-t16_simulate_it(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       /*
-        * The 8 IT state bits are split into two parts in CPSR:
-        *      ITSTATE<1:0> are in CPSR<26:25>
-        *      ITSTATE<7:2> are in CPSR<15:10>
-        * The new IT state is in the lower byte of insn.
-        */
-       unsigned long cpsr = regs->ARM_cpsr;
-       cpsr &= ~PSR_IT_MASK;
-       cpsr |= (insn & 0xfc) << 8;
-       cpsr |= (insn & 0x03) << 25;
-       regs->ARM_cpsr = cpsr;
-}
-
-static void __kprobes
-t16_singlestep_it(probes_opcode_t insn,
-                 struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       regs->ARM_pc += 2;
-       t16_simulate_it(insn, asi, regs);
-}
-
-static enum probes_insn __kprobes
-t16_decode_it(probes_opcode_t insn, struct arch_probes_insn *asi,
-               const struct decode_header *d)
-{
-       asi->insn_singlestep = t16_singlestep_it;
-       return INSN_GOOD_NO_SLOT;
-}
-
-static void __kprobes
-t16_simulate_cond_branch(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc + 2;
-       long offset = insn & 0x7f;
-       offset -= insn & 0x80; /* Apply sign bit */
-       regs->ARM_pc = pc + (offset * 2);
-}
-
-static enum probes_insn __kprobes
-t16_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
-               const struct decode_header *d)
-{
-       int cc = (insn >> 8) & 0xf;
-       asi->insn_check_cc = probes_condition_checks[cc];
-       asi->insn_handler = t16_simulate_cond_branch;
-       return INSN_GOOD_NO_SLOT;
-}
-
-static void __kprobes
-t16_simulate_branch(probes_opcode_t insn,
-                  struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc + 2;
-       long offset = insn & 0x3ff;
-       offset -= insn & 0x400; /* Apply sign bit */
-       regs->ARM_pc = pc + (offset * 2);
-}
-
-static unsigned long __kprobes
-t16_emulate_loregs(probes_opcode_t insn,
-                  struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long oldcpsr = regs->ARM_cpsr;
-       unsigned long newcpsr;
-
-       __asm__ __volatile__ (
-               "msr    cpsr_fs, %[oldcpsr]     \n\t"
-               "ldmia  %[regs], {r0-r7}        \n\t"
-               "blx    %[fn]                   \n\t"
-               "stmia  %[regs], {r0-r7}        \n\t"
-               "mrs    %[newcpsr], cpsr        \n\t"
-               : [newcpsr] "=r" (newcpsr)
-               : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs),
-                 [fn] "r" (asi->insn_fn)
-               : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
-                 "lr", "memory", "cc"
-               );
-
-       return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK);
-}
-
-static void __kprobes
-t16_emulate_loregs_rwflags(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs);
-}
-
-static void __kprobes
-t16_emulate_loregs_noitrwflags(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long cpsr = t16_emulate_loregs(insn, asi, regs);
-       if (!in_it_block(cpsr))
-               regs->ARM_cpsr = cpsr;
-}
-
-static void __kprobes
-t16_emulate_hiregs(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       unsigned long pc = regs->ARM_pc + 2;
-       int rdn = (insn & 0x7) | ((insn & 0x80) >> 4);
-       int rm = (insn >> 3) & 0xf;
-
-       register unsigned long rdnv asm("r1");
-       register unsigned long rmv asm("r0");
-       unsigned long cpsr = regs->ARM_cpsr;
-
-       rdnv = (rdn == 15) ? pc : regs->uregs[rdn];
-       rmv = (rm == 15) ? pc : regs->uregs[rm];
-
-       __asm__ __volatile__ (
-               "msr    cpsr_fs, %[cpsr]        \n\t"
-               "blx    %[fn]                   \n\t"
-               "mrs    %[cpsr], cpsr           \n\t"
-               : "=r" (rdnv), [cpsr] "=r" (cpsr)
-               : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (asi->insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       if (rdn == 15)
-               rdnv &= ~1;
-
-       regs->uregs[rdn] = rdnv;
-       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
-}
-
-static enum probes_insn __kprobes
-t16_decode_hiregs(probes_opcode_t insn, struct arch_probes_insn *asi,
-               const struct decode_header *d)
-{
-       insn &= ~0x00ff;
-       insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
-       ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn);
-       asi->insn_handler = t16_emulate_hiregs;
-       return INSN_GOOD;
-}
-
-static void __kprobes
-t16_emulate_push(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       __asm__ __volatile__ (
-               "ldr    r9, [%[regs], #13*4]    \n\t"
-               "ldr    r8, [%[regs], #14*4]    \n\t"
-               "ldmia  %[regs], {r0-r7}        \n\t"
-               "blx    %[fn]                   \n\t"
-               "str    r9, [%[regs], #13*4]    \n\t"
-               :
-               : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
-               : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
-                 "lr", "memory", "cc"
-               );
-}
-
-static enum probes_insn __kprobes
-t16_decode_push(probes_opcode_t insn, struct arch_probes_insn *asi,
-               const struct decode_header *d)
-{
-       /*
-        * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}"
-        * and call it with R9=SP and LR in the register list represented
-        * by R8.
-        */
-       /* 1st half STMDB R9!,{} */
-       ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe929);
-       /* 2nd half (register list) */
-       ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
-       asi->insn_handler = t16_emulate_push;
-       return INSN_GOOD;
-}
-
-static void __kprobes
-t16_emulate_pop_nopc(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       __asm__ __volatile__ (
-               "ldr    r9, [%[regs], #13*4]    \n\t"
-               "ldmia  %[regs], {r0-r7}        \n\t"
-               "blx    %[fn]                   \n\t"
-               "stmia  %[regs], {r0-r7}        \n\t"
-               "str    r9, [%[regs], #13*4]    \n\t"
-               :
-               : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
-               : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
-                 "lr", "memory", "cc"
-               );
-}
-
-static void __kprobes
-t16_emulate_pop_pc(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       register unsigned long pc asm("r8");
-
-       __asm__ __volatile__ (
-               "ldr    r9, [%[regs], #13*4]    \n\t"
-               "ldmia  %[regs], {r0-r7}        \n\t"
-               "blx    %[fn]                   \n\t"
-               "stmia  %[regs], {r0-r7}        \n\t"
-               "str    r9, [%[regs], #13*4]    \n\t"
-               : "=r" (pc)
-               : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
-               : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
-                 "lr", "memory", "cc"
-               );
-
-       bx_write_pc(pc, regs);
-}
-
-static enum probes_insn __kprobes
-t16_decode_pop(probes_opcode_t insn, struct arch_probes_insn *asi,
-               const struct decode_header *d)
-{
-       /*
-        * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}"
-        * and call it with R9=SP and PC in the register list represented
-        * by R8.
-        */
-       /* 1st half LDMIA R9!,{} */
-       ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe8b9);
-       /* 2nd half (register list) */
-       ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
-       asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc
-                                        : t16_emulate_pop_nopc;
-       return INSN_GOOD;
-}
-
-const union decode_action kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = {
-       [PROBES_T16_ADD_SP] = {.handler = t16_simulate_add_sp_imm},
-       [PROBES_T16_CBZ] = {.handler = t16_simulate_cbz},
-       [PROBES_T16_SIGN_EXTEND] = {.handler = t16_emulate_loregs_rwflags},
-       [PROBES_T16_PUSH] = {.decoder = t16_decode_push},
-       [PROBES_T16_POP] = {.decoder = t16_decode_pop},
-       [PROBES_T16_SEV] = {.handler = probes_emulate_none},
-       [PROBES_T16_WFE] = {.handler = probes_simulate_nop},
-       [PROBES_T16_IT] = {.decoder = t16_decode_it},
-       [PROBES_T16_CMP] = {.handler = t16_emulate_loregs_rwflags},
-       [PROBES_T16_ADDSUB] = {.handler = t16_emulate_loregs_noitrwflags},
-       [PROBES_T16_LOGICAL] = {.handler = t16_emulate_loregs_noitrwflags},
-       [PROBES_T16_LDR_LIT] = {.handler = t16_simulate_ldr_literal},
-       [PROBES_T16_BLX] = {.handler = t16_simulate_bxblx},
-       [PROBES_T16_HIREGOPS] = {.decoder = t16_decode_hiregs},
-       [PROBES_T16_LDRHSTRH] = {.handler = t16_emulate_loregs_rwflags},
-       [PROBES_T16_LDRSTR] = {.handler = t16_simulate_ldrstr_sp_relative},
-       [PROBES_T16_ADR] = {.handler = t16_simulate_reladr},
-       [PROBES_T16_LDMSTM] = {.handler = t16_emulate_loregs_rwflags},
-       [PROBES_T16_BRANCH_COND] = {.decoder = t16_decode_cond_branch},
-       [PROBES_T16_BRANCH] = {.handler = t16_simulate_branch},
-};
-
-const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
-       [PROBES_T32_LDMSTM] = {.decoder = t32_decode_ldmstm},
-       [PROBES_T32_LDRDSTRD] = {.handler = t32_emulate_ldrdstrd},
-       [PROBES_T32_TABLE_BRANCH] = {.handler = t32_simulate_table_branch},
-       [PROBES_T32_TST] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
-       [PROBES_T32_MOV] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
-       [PROBES_T32_ADDSUB] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
-       [PROBES_T32_LOGICAL] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
-       [PROBES_T32_CMP] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
-       [PROBES_T32_ADDWSUBW_PC] = {.handler = t32_emulate_rd8pc16_noflags,},
-       [PROBES_T32_ADDWSUBW] = {.handler = t32_emulate_rd8rn16_noflags},
-       [PROBES_T32_MOVW] = {.handler = t32_emulate_rd8rn16_noflags},
-       [PROBES_T32_SAT] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
-       [PROBES_T32_BITFIELD] = {.handler = t32_emulate_rd8rn16_noflags},
-       [PROBES_T32_SEV] = {.handler = probes_emulate_none},
-       [PROBES_T32_WFE] = {.handler = probes_simulate_nop},
-       [PROBES_T32_MRS] = {.handler = t32_simulate_mrs},
-       [PROBES_T32_BRANCH_COND] = {.decoder = t32_decode_cond_branch},
-       [PROBES_T32_BRANCH] = {.handler = t32_simulate_branch},
-       [PROBES_T32_PLDI] = {.handler = probes_simulate_nop},
-       [PROBES_T32_LDR_LIT] = {.handler = t32_simulate_ldr_literal},
-       [PROBES_T32_LDRSTR] = {.handler = t32_emulate_ldrstr},
-       [PROBES_T32_SIGN_EXTEND] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
-       [PROBES_T32_MEDIA] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
-       [PROBES_T32_REVERSE] = {.handler = t32_emulate_rd8rn16_noflags},
-       [PROBES_T32_MUL_ADD] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
-       [PROBES_T32_MUL_ADD2] = {.handler = t32_emulate_rd8rn16rm0ra12_noflags},
-       [PROBES_T32_MUL_ADD_LONG] = {
-               .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags},
-};
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
deleted file mode 100644 (file)
index 6d64420..0000000
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * arch/arm/kernel/kprobes.c
- *
- * Kprobes on ARM
- *
- * Abhishek Sagar <sagar.abhishek@gmail.com>
- * Copyright (C) 2006, 2007 Motorola Inc.
- *
- * Nicolas Pitre <nico@marvell.com>
- * Copyright (C) 2007 Marvell Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/kprobes.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/stop_machine.h>
-#include <linux/stringify.h>
-#include <asm/traps.h>
-#include <asm/opcodes.h>
-#include <asm/cacheflush.h>
-#include <linux/percpu.h>
-#include <linux/bug.h>
-
-#include "kprobes.h"
-#include "probes-arm.h"
-#include "probes-thumb.h"
-#include "patch.h"
-
-#define MIN_STACK_SIZE(addr)                           \
-       min((unsigned long)MAX_STACK_SIZE,              \
-           (unsigned long)current_thread_info() + THREAD_START_SP - (addr))
-
-#define flush_insns(addr, size)                                \
-       flush_icache_range((unsigned long)(addr),       \
-                          (unsigned long)(addr) +      \
-                          (size))
-
-/* Used as a marker in ARM_pc to note when we're in a jprobe. */
-#define JPROBE_MAGIC_ADDR              0xffffffff
-
-DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
-DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
-
-
-int __kprobes arch_prepare_kprobe(struct kprobe *p)
-{
-       kprobe_opcode_t insn;
-       kprobe_opcode_t tmp_insn[MAX_INSN_SIZE];
-       unsigned long addr = (unsigned long)p->addr;
-       bool thumb;
-       kprobe_decode_insn_t *decode_insn;
-       const union decode_action *actions;
-       int is;
-
-       if (in_exception_text(addr))
-               return -EINVAL;
-
-#ifdef CONFIG_THUMB2_KERNEL
-       thumb = true;
-       addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
-       insn = __mem_to_opcode_thumb16(((u16 *)addr)[0]);
-       if (is_wide_instruction(insn)) {
-               u16 inst2 = __mem_to_opcode_thumb16(((u16 *)addr)[1]);
-               insn = __opcode_thumb32_compose(insn, inst2);
-               decode_insn = thumb32_probes_decode_insn;
-               actions = kprobes_t32_actions;
-       } else {
-               decode_insn = thumb16_probes_decode_insn;
-               actions = kprobes_t16_actions;
-       }
-#else /* !CONFIG_THUMB2_KERNEL */
-       thumb = false;
-       if (addr & 0x3)
-               return -EINVAL;
-       insn = __mem_to_opcode_arm(*p->addr);
-       decode_insn = arm_probes_decode_insn;
-       actions = kprobes_arm_actions;
-#endif
-
-       p->opcode = insn;
-       p->ainsn.insn = tmp_insn;
-
-       switch ((*decode_insn)(insn, &p->ainsn, true, actions)) {
-       case INSN_REJECTED:     /* not supported */
-               return -EINVAL;
-
-       case INSN_GOOD:         /* instruction uses slot */
-               p->ainsn.insn = get_insn_slot();
-               if (!p->ainsn.insn)
-                       return -ENOMEM;
-               for (is = 0; is < MAX_INSN_SIZE; ++is)
-                       p->ainsn.insn[is] = tmp_insn[is];
-               flush_insns(p->ainsn.insn,
-                               sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE);
-               p->ainsn.insn_fn = (probes_insn_fn_t *)
-                                       ((uintptr_t)p->ainsn.insn | thumb);
-               break;
-
-       case INSN_GOOD_NO_SLOT: /* instruction doesn't need insn slot */
-               p->ainsn.insn = NULL;
-               break;
-       }
-
-       return 0;
-}
-
-void __kprobes arch_arm_kprobe(struct kprobe *p)
-{
-       unsigned int brkp;
-       void *addr;
-
-       if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
-               /* Remove any Thumb flag */
-               addr = (void *)((uintptr_t)p->addr & ~1);
-
-               if (is_wide_instruction(p->opcode))
-                       brkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
-               else
-                       brkp = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION;
-       } else {
-               kprobe_opcode_t insn = p->opcode;
-
-               addr = p->addr;
-               brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION;
-
-               if (insn >= 0xe0000000)
-                       brkp |= 0xe0000000;  /* Unconditional instruction */
-               else
-                       brkp |= insn & 0xf0000000;  /* Copy condition from insn */
-       }
-
-       patch_text(addr, brkp);
-}
-
-/*
- * The actual disarming is done here on each CPU and synchronized using
- * stop_machine. This synchronization is necessary on SMP to avoid removing
- * a probe between the moment the 'Undefined Instruction' exception is raised
- * and the moment the exception handler reads the faulting instruction from
- * memory. It is also needed to atomically set the two half-words of a 32-bit
- * Thumb breakpoint.
- */
-int __kprobes __arch_disarm_kprobe(void *p)
-{
-       struct kprobe *kp = p;
-       void *addr = (void *)((uintptr_t)kp->addr & ~1);
-
-       __patch_text(addr, kp->opcode);
-
-       return 0;
-}
-
-void __kprobes arch_disarm_kprobe(struct kprobe *p)
-{
-       stop_machine(__arch_disarm_kprobe, p, cpu_online_mask);
-}
-
-void __kprobes arch_remove_kprobe(struct kprobe *p)
-{
-       if (p->ainsn.insn) {
-               free_insn_slot(p->ainsn.insn, 0);
-               p->ainsn.insn = NULL;
-       }
-}
-
-static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
-{
-       kcb->prev_kprobe.kp = kprobe_running();
-       kcb->prev_kprobe.status = kcb->kprobe_status;
-}
-
-static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
-{
-       __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
-       kcb->kprobe_status = kcb->prev_kprobe.status;
-}
-
-static void __kprobes set_current_kprobe(struct kprobe *p)
-{
-       __this_cpu_write(current_kprobe, p);
-}
-
-static void __kprobes
-singlestep_skip(struct kprobe *p, struct pt_regs *regs)
-{
-#ifdef CONFIG_THUMB2_KERNEL
-       regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
-       if (is_wide_instruction(p->opcode))
-               regs->ARM_pc += 4;
-       else
-               regs->ARM_pc += 2;
-#else
-       regs->ARM_pc += 4;
-#endif
-}
-
-static inline void __kprobes
-singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb)
-{
-       p->ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
-}
-
-/*
- * Called with IRQs disabled. IRQs must remain disabled from that point
- * all the way until processing this kprobe is complete.  The current
- * kprobes implementation cannot process more than one nested level of
- * kprobe, and that level is reserved for user kprobe handlers, so we can't
- * risk encountering a new kprobe in an interrupt handler.
- */
-void __kprobes kprobe_handler(struct pt_regs *regs)
-{
-       struct kprobe *p, *cur;
-       struct kprobe_ctlblk *kcb;
-
-       kcb = get_kprobe_ctlblk();
-       cur = kprobe_running();
-
-#ifdef CONFIG_THUMB2_KERNEL
-       /*
-        * First look for a probe which was registered using an address with
-        * bit 0 set, this is the usual situation for pointers to Thumb code.
-        * If not found, fallback to looking for one with bit 0 clear.
-        */
-       p = get_kprobe((kprobe_opcode_t *)(regs->ARM_pc | 1));
-       if (!p)
-               p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc);
-
-#else /* ! CONFIG_THUMB2_KERNEL */
-       p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc);
-#endif
-
-       if (p) {
-               if (cur) {
-                       /* Kprobe is pending, so we're recursing. */
-                       switch (kcb->kprobe_status) {
-                       case KPROBE_HIT_ACTIVE:
-                       case KPROBE_HIT_SSDONE:
-                               /* A pre- or post-handler probe got us here. */
-                               kprobes_inc_nmissed_count(p);
-                               save_previous_kprobe(kcb);
-                               set_current_kprobe(p);
-                               kcb->kprobe_status = KPROBE_REENTER;
-                               singlestep(p, regs, kcb);
-                               restore_previous_kprobe(kcb);
-                               break;
-                       default:
-                               /* impossible cases */
-                               BUG();
-                       }
-               } else if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) {
-                       /* Probe hit and conditional execution check ok. */
-                       set_current_kprobe(p);
-                       kcb->kprobe_status = KPROBE_HIT_ACTIVE;
-
-                       /*
-                        * If we have no pre-handler or it returned 0, we
-                        * continue with normal processing.  If we have a
-                        * pre-handler and it returned non-zero, it prepped
-                        * for calling the break_handler below on re-entry,
-                        * so get out doing nothing more here.
-                        */
-                       if (!p->pre_handler || !p->pre_handler(p, regs)) {
-                               kcb->kprobe_status = KPROBE_HIT_SS;
-                               singlestep(p, regs, kcb);
-                               if (p->post_handler) {
-                                       kcb->kprobe_status = KPROBE_HIT_SSDONE;
-                                       p->post_handler(p, regs, 0);
-                               }
-                               reset_current_kprobe();
-                       }
-               } else {
-                       /*
-                        * Probe hit but conditional execution check failed,
-                        * so just skip the instruction and continue as if
-                        * nothing had happened.
-                        */
-                       singlestep_skip(p, regs);
-               }
-       } else if (cur) {
-               /* We probably hit a jprobe.  Call its break handler. */
-               if (cur->break_handler && cur->break_handler(cur, regs)) {
-                       kcb->kprobe_status = KPROBE_HIT_SS;
-                       singlestep(cur, regs, kcb);
-                       if (cur->post_handler) {
-                               kcb->kprobe_status = KPROBE_HIT_SSDONE;
-                               cur->post_handler(cur, regs, 0);
-                       }
-               }
-               reset_current_kprobe();
-       } else {
-               /*
-                * The probe was removed and a race is in progress.
-                * There is nothing we can do about it.  Let's restart
-                * the instruction.  By the time we can restart, the
-                * real instruction will be there.
-                */
-       }
-}
-
-static int __kprobes kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
-{
-       unsigned long flags;
-       local_irq_save(flags);
-       kprobe_handler(regs);
-       local_irq_restore(flags);
-       return 0;
-}
-
-int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
-{
-       struct kprobe *cur = kprobe_running();
-       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
-
-       switch (kcb->kprobe_status) {
-       case KPROBE_HIT_SS:
-       case KPROBE_REENTER:
-               /*
-                * We are here because the instruction being single
-                * stepped caused a page fault. We reset the current
-                * kprobe and the PC to point back to the probe address
-                * and allow the page fault handler to continue as a
-                * normal page fault.
-                */
-               regs->ARM_pc = (long)cur->addr;
-               if (kcb->kprobe_status == KPROBE_REENTER) {
-                       restore_previous_kprobe(kcb);
-               } else {
-                       reset_current_kprobe();
-               }
-               break;
-
-       case KPROBE_HIT_ACTIVE:
-       case KPROBE_HIT_SSDONE:
-               /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
-                       return 1;
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
-                                      unsigned long val, void *data)
-{
-       /*
-        * notify_die() is currently never called on ARM,
-        * so this callback is currently empty.
-        */
-       return NOTIFY_DONE;
-}
-
-/*
- * When a retprobed function returns, trampoline_handler() is called,
- * calling the kretprobe's handler. We construct a struct pt_regs to
- * give a view of registers r0-r11 to the user return-handler.  This is
- * not a complete pt_regs structure, but that should be plenty sufficient
- * for kretprobe handlers which should normally be interested in r0 only
- * anyway.
- */
-void __naked __kprobes kretprobe_trampoline(void)
-{
-       __asm__ __volatile__ (
-               "stmdb  sp!, {r0 - r11}         \n\t"
-               "mov    r0, sp                  \n\t"
-               "bl     trampoline_handler      \n\t"
-               "mov    lr, r0                  \n\t"
-               "ldmia  sp!, {r0 - r11}         \n\t"
-#ifdef CONFIG_THUMB2_KERNEL
-               "bx     lr                      \n\t"
-#else
-               "mov    pc, lr                  \n\t"
-#endif
-               : : : "memory");
-}
-
-/* Called from kretprobe_trampoline */
-static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
-{
-       struct kretprobe_instance *ri = NULL;
-       struct hlist_head *head, empty_rp;
-       struct hlist_node *tmp;
-       unsigned long flags, orig_ret_address = 0;
-       unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
-
-       INIT_HLIST_HEAD(&empty_rp);
-       kretprobe_hash_lock(current, &head, &flags);
-
-       /*
-        * It is possible to have multiple instances associated with a given
-        * task either because multiple functions in the call path have
-        * a return probe installed on them, and/or more than one return
-        * probe was registered for a target function.
-        *
-        * We can handle this because:
-        *     - instances are always inserted at the head of the list
-        *     - when multiple return probes are registered for the same
-        *       function, the first instance's ret_addr will point to the
-        *       real return address, and all the rest will point to
-        *       kretprobe_trampoline
-        */
-       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
-               if (ri->task != current)
-                       /* another task is sharing our hash bucket */
-                       continue;
-
-               if (ri->rp && ri->rp->handler) {
-                       __this_cpu_write(current_kprobe, &ri->rp->kp);
-                       get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
-                       ri->rp->handler(ri, regs);
-                       __this_cpu_write(current_kprobe, NULL);
-               }
-
-               orig_ret_address = (unsigned long)ri->ret_addr;
-               recycle_rp_inst(ri, &empty_rp);
-
-               if (orig_ret_address != trampoline_address)
-                       /*
-                        * This is the real return address. Any other
-                        * instances associated with this task are for
-                        * other calls deeper on the call stack
-                        */
-                       break;
-       }
-
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
-       kretprobe_hash_unlock(current, &flags);
-
-       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
-               hlist_del(&ri->hlist);
-               kfree(ri);
-       }
-
-       return (void *)orig_ret_address;
-}
-
-void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
-                                     struct pt_regs *regs)
-{
-       ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr;
-
-       /* Replace the return addr with trampoline addr. */
-       regs->ARM_lr = (unsigned long)&kretprobe_trampoline;
-}
-
-int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       struct jprobe *jp = container_of(p, struct jprobe, kp);
-       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
-       long sp_addr = regs->ARM_sp;
-       long cpsr;
-
-       kcb->jprobe_saved_regs = *regs;
-       memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr));
-       regs->ARM_pc = (long)jp->entry;
-
-       cpsr = regs->ARM_cpsr | PSR_I_BIT;
-#ifdef CONFIG_THUMB2_KERNEL
-       /* Set correct Thumb state in cpsr */
-       if (regs->ARM_pc & 1)
-               cpsr |= PSR_T_BIT;
-       else
-               cpsr &= ~PSR_T_BIT;
-#endif
-       regs->ARM_cpsr = cpsr;
-
-       preempt_disable();
-       return 1;
-}
-
-void __kprobes jprobe_return(void)
-{
-       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
-
-       __asm__ __volatile__ (
-               /*
-                * Setup an empty pt_regs. Fill SP and PC fields as
-                * they're needed by longjmp_break_handler.
-                *
-                * We allocate some slack between the original SP and start of
-                * our fabricated regs. To be precise we want to have worst case
-                * covered which is STMFD with all 16 regs so we allocate 2 *
-                * sizeof(struct_pt_regs)).
-                *
-                * This is to prevent any simulated instruction from writing
-                * over the regs when they are accessing the stack.
-                */
-#ifdef CONFIG_THUMB2_KERNEL
-               "sub    r0, %0, %1              \n\t"
-               "mov    sp, r0                  \n\t"
-#else
-               "sub    sp, %0, %1              \n\t"
-#endif
-               "ldr    r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t"
-               "str    %0, [sp, %2]            \n\t"
-               "str    r0, [sp, %3]            \n\t"
-               "mov    r0, sp                  \n\t"
-               "bl     kprobe_handler          \n\t"
-
-               /*
-                * Return to the context saved by setjmp_pre_handler
-                * and restored by longjmp_break_handler.
-                */
-#ifdef CONFIG_THUMB2_KERNEL
-               "ldr    lr, [sp, %2]            \n\t" /* lr = saved sp */
-               "ldrd   r0, r1, [sp, %5]        \n\t" /* r0,r1 = saved lr,pc */
-               "ldr    r2, [sp, %4]            \n\t" /* r2 = saved psr */
-               "stmdb  lr!, {r0, r1, r2}       \n\t" /* push saved lr and */
-                                                     /* rfe context */
-               "ldmia  sp, {r0 - r12}          \n\t"
-               "mov    sp, lr                  \n\t"
-               "ldr    lr, [sp], #4            \n\t"
-               "rfeia  sp!                     \n\t"
-#else
-               "ldr    r0, [sp, %4]            \n\t"
-               "msr    cpsr_cxsf, r0           \n\t"
-               "ldmia  sp, {r0 - pc}           \n\t"
-#endif
-               :
-               : "r" (kcb->jprobe_saved_regs.ARM_sp),
-                 "I" (sizeof(struct pt_regs) * 2),
-                 "J" (offsetof(struct pt_regs, ARM_sp)),
-                 "J" (offsetof(struct pt_regs, ARM_pc)),
-                 "J" (offsetof(struct pt_regs, ARM_cpsr)),
-                 "J" (offsetof(struct pt_regs, ARM_lr))
-               : "memory", "cc");
-}
-
-int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
-{
-       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
-       long stack_addr = kcb->jprobe_saved_regs.ARM_sp;
-       long orig_sp = regs->ARM_sp;
-       struct jprobe *jp = container_of(p, struct jprobe, kp);
-
-       if (regs->ARM_pc == JPROBE_MAGIC_ADDR) {
-               if (orig_sp != stack_addr) {
-                       struct pt_regs *saved_regs =
-                               (struct pt_regs *)kcb->jprobe_saved_regs.ARM_sp;
-                       printk("current sp %lx does not match saved sp %lx\n",
-                              orig_sp, stack_addr);
-                       printk("Saved registers for jprobe %p\n", jp);
-                       show_regs(saved_regs);
-                       printk("Current registers\n");
-                       show_regs(regs);
-                       BUG();
-               }
-               *regs = kcb->jprobe_saved_regs;
-               memcpy((void *)stack_addr, kcb->jprobes_stack,
-                      MIN_STACK_SIZE(stack_addr));
-               preempt_enable_no_resched();
-               return 1;
-       }
-       return 0;
-}
-
-int __kprobes arch_trampoline_kprobe(struct kprobe *p)
-{
-       return 0;
-}
-
-#ifdef CONFIG_THUMB2_KERNEL
-
-static struct undef_hook kprobes_thumb16_break_hook = {
-       .instr_mask     = 0xffff,
-       .instr_val      = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION,
-       .cpsr_mask      = MODE_MASK,
-       .cpsr_val       = SVC_MODE,
-       .fn             = kprobe_trap_handler,
-};
-
-static struct undef_hook kprobes_thumb32_break_hook = {
-       .instr_mask     = 0xffffffff,
-       .instr_val      = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION,
-       .cpsr_mask      = MODE_MASK,
-       .cpsr_val       = SVC_MODE,
-       .fn             = kprobe_trap_handler,
-};
-
-#else  /* !CONFIG_THUMB2_KERNEL */
-
-static struct undef_hook kprobes_arm_break_hook = {
-       .instr_mask     = 0x0fffffff,
-       .instr_val      = KPROBE_ARM_BREAKPOINT_INSTRUCTION,
-       .cpsr_mask      = MODE_MASK,
-       .cpsr_val       = SVC_MODE,
-       .fn             = kprobe_trap_handler,
-};
-
-#endif /* !CONFIG_THUMB2_KERNEL */
-
-int __init arch_init_kprobes()
-{
-       arm_probes_decode_init();
-#ifdef CONFIG_THUMB2_KERNEL
-       register_undef_hook(&kprobes_thumb16_break_hook);
-       register_undef_hook(&kprobes_thumb32_break_hook);
-#else
-       register_undef_hook(&kprobes_arm_break_hook);
-#endif
-       return 0;
-}
diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h
deleted file mode 100644 (file)
index 9a2712e..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * arch/arm/kernel/kprobes.h
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * Some contents moved here from arch/arm/include/asm/kprobes.h which is
- * Copyright (C) 2006, 2007 Motorola Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#ifndef _ARM_KERNEL_KPROBES_H
-#define _ARM_KERNEL_KPROBES_H
-
-#include "probes.h"
-
-/*
- * These undefined instructions must be unique and
- * reserved solely for kprobes' use.
- */
-#define KPROBE_ARM_BREAKPOINT_INSTRUCTION      0x07f001f8
-#define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION  0xde18
-#define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION  0xf7f0a018
-
-enum probes_insn __kprobes
-kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi,
-               const struct decode_header *h);
-
-typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t,
-                                               struct arch_probes_insn *,
-                                               bool,
-                                               const union decode_action *);
-
-#ifdef CONFIG_THUMB2_KERNEL
-
-extern const union decode_action kprobes_t32_actions[];
-extern const union decode_action kprobes_t16_actions[];
-
-#else /* !CONFIG_THUMB2_KERNEL */
-
-extern const union decode_action kprobes_arm_actions[];
-
-#endif
-
-#endif /* _ARM_KERNEL_KPROBES_H */
index 5038960e3c55abc1dc9744808f7c8c9d44eca290..69bda1a5707ee826ededa348a90a55c394ad8613 100644 (file)
@@ -8,8 +8,7 @@
 #include <asm/fixmap.h>
 #include <asm/smp_plat.h>
 #include <asm/opcodes.h>
-
-#include "patch.h"
+#include <asm/patch.h>
 
 struct patch {
        void *addr;
diff --git a/arch/arm/kernel/patch.h b/arch/arm/kernel/patch.h
deleted file mode 100644 (file)
index 77e054c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _ARM_KERNEL_PATCH_H
-#define _ARM_KERNEL_PATCH_H
-
-void patch_text(void *addr, unsigned int insn);
-void __patch_text_real(void *addr, unsigned int insn, bool remap);
-
-static inline void __patch_text(void *addr, unsigned int insn)
-{
-       __patch_text_real(addr, insn, true);
-}
-
-static inline void __patch_text_early(void *addr, unsigned int insn)
-{
-       __patch_text_real(addr, insn, false);
-}
-
-#endif
diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c
deleted file mode 100644 (file)
index 8eaef81..0000000
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- * arch/arm/kernel/probes-arm.c
- *
- * Some code moved here from arch/arm/kernel/kprobes-arm.c
- *
- * Copyright (C) 2006, 2007 Motorola Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/stddef.h>
-#include <linux/ptrace.h>
-
-#include "probes.h"
-#include "probes-arm.h"
-
-#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
-
-#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
-
-/*
- * To avoid the complications of mimicing single-stepping on a
- * processor without a Next-PC or a single-step mode, and to
- * avoid having to deal with the side-effects of boosting, we
- * simulate or emulate (almost) all ARM instructions.
- *
- * "Simulation" is where the instruction's behavior is duplicated in
- * C code.  "Emulation" is where the original instruction is rewritten
- * and executed, often by altering its registers.
- *
- * By having all behavior of the kprobe'd instruction completed before
- * returning from the kprobe_handler(), all locks (scheduler and
- * interrupt) can safely be released.  There is no need for secondary
- * breakpoints, no race with MP or preemptable kernels, nor having to
- * clean up resources counts at a later time impacting overall system
- * performance.  By rewriting the instruction, only the minimum registers
- * need to be loaded and saved back optimizing performance.
- *
- * Calling the insnslot_*_rwflags version of a function doesn't hurt
- * anything even when the CPSR flags aren't updated by the
- * instruction.  It's just a little slower in return for saving
- * a little space by not having a duplicate function that doesn't
- * update the flags.  (The same optimization can be said for
- * instructions that do or don't perform register writeback)
- * Also, instructions can either read the flags, only write the
- * flags, or read and write the flags.  To save combinations
- * rather than for sheer performance, flag functions just assume
- * read and write of flags.
- */
-
-void __kprobes simulate_bbl(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       long iaddr = (long) regs->ARM_pc - 4;
-       int disp  = branch_displacement(insn);
-
-       if (insn & (1 << 24))
-               regs->ARM_lr = iaddr + 4;
-
-       regs->ARM_pc = iaddr + 8 + disp;
-}
-
-void __kprobes simulate_blx1(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       long iaddr = (long) regs->ARM_pc - 4;
-       int disp = branch_displacement(insn);
-
-       regs->ARM_lr = iaddr + 4;
-       regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2);
-       regs->ARM_cpsr |= PSR_T_BIT;
-}
-
-void __kprobes simulate_blx2bx(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       int rm = insn & 0xf;
-       long rmv = regs->uregs[rm];
-
-       if (insn & (1 << 5))
-               regs->ARM_lr = (long) regs->ARM_pc;
-
-       regs->ARM_pc = rmv & ~0x1;
-       regs->ARM_cpsr &= ~PSR_T_BIT;
-       if (rmv & 0x1)
-               regs->ARM_cpsr |= PSR_T_BIT;
-}
-
-void __kprobes simulate_mrs(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       int rd = (insn >> 12) & 0xf;
-       unsigned long mask = 0xf8ff03df; /* Mask out execution state */
-       regs->uregs[rd] = regs->ARM_cpsr & mask;
-}
-
-void __kprobes simulate_mov_ipsp(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       regs->uregs[12] = regs->uregs[13];
-}
-
-/*
- * For the instruction masking and comparisons in all the "space_*"
- * functions below, Do _not_ rearrange the order of tests unless
- * you're very, very sure of what you are doing.  For the sake of
- * efficiency, the masks for some tests sometimes assume other test
- * have been done prior to them so the number of patterns to test
- * for an instruction set can be as broad as possible to reduce the
- * number of tests needed.
- */
-
-static const union decode_item arm_1111_table[] = {
-       /* Unconditional instructions                                   */
-
-       /* memory hint          1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */
-       /* PLDI (immediate)     1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */
-       /* PLDW (immediate)     1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */
-       /* PLD (immediate)      1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_SIMULATE (0xfe300000, 0xf4100000, PROBES_PRELOAD_IMM),
-
-       /* memory hint          1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */
-       /* PLDI (register)      1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */
-       /* PLDW (register)      1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */
-       /* PLD (register)       1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */
-       DECODE_SIMULATE (0xfe300010, 0xf6100000, PROBES_PRELOAD_REG),
-
-       /* BLX (immediate)      1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */
-       DECODE_SIMULATE (0xfe000000, 0xfa000000, PROBES_BRANCH_IMM),
-
-       /* CPS                  1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */
-       /* SETEND               1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
-       /* SRS                  1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
-       /* RFE                  1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
-
-       /* Coprocessor instructions... */
-       /* MCRR2                1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */
-       /* MRRC2                1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */
-       /* LDC2                 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
-       /* STC2                 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
-       /* CDP2                 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
-       /* MCR2                 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
-       /* MRC2                 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
-
-       /* Other unallocated instructions...                            */
-       DECODE_END
-};
-
-static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = {
-       /* Miscellaneous instructions                                   */
-
-       /* MRS cpsr             cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */
-       DECODE_SIMULATEX(0x0ff000f0, 0x01000000, PROBES_MRS,
-                                                REGS(0, NOPC, 0, 0, 0)),
-
-       /* BX                   cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */
-       DECODE_SIMULATE (0x0ff000f0, 0x01200010, PROBES_BRANCH_REG),
-
-       /* BLX (register)       cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */
-       DECODE_SIMULATEX(0x0ff000f0, 0x01200030, PROBES_BRANCH_REG,
-                                                REGS(0, 0, 0, 0, NOPC)),
-
-       /* CLZ                  cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */
-       DECODE_EMULATEX (0x0ff000f0, 0x01600010, PROBES_CLZ,
-                                                REGS(0, NOPC, 0, 0, NOPC)),
-
-       /* QADD                 cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */
-       /* QSUB                 cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */
-       /* QDADD                cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */
-       /* QDSUB                cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */
-       DECODE_EMULATEX (0x0f9000f0, 0x01000050, PROBES_SATURATING_ARITHMETIC,
-                                                REGS(NOPC, NOPC, 0, 0, NOPC)),
-
-       /* BXJ                  cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
-       /* MSR                  cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
-       /* MRS spsr             cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */
-       /* BKPT                 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
-       /* SMC                  cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */
-       /* And unallocated instructions...                              */
-       DECODE_END
-};
-
-static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = {
-       /* Halfword multiply and multiply-accumulate                    */
-
-       /* SMLALxy              cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */
-       DECODE_EMULATEX (0x0ff00090, 0x01400080, PROBES_MUL1,
-                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
-
-       /* SMULWy               cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */
-       DECODE_OR       (0x0ff000b0, 0x012000a0),
-       /* SMULxy               cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */
-       DECODE_EMULATEX (0x0ff00090, 0x01600080, PROBES_MUL2,
-                                                REGS(NOPC, 0, NOPC, 0, NOPC)),
-
-       /* SMLAxy               cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */
-       DECODE_OR       (0x0ff00090, 0x01000080),
-       /* SMLAWy               cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */
-       DECODE_EMULATEX (0x0ff000b0, 0x01200080, PROBES_MUL2,
-                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
-
-       DECODE_END
-};
-
-static const union decode_item arm_cccc_0000_____1001_table[] = {
-       /* Multiply and multiply-accumulate                             */
-
-       /* MUL                  cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */
-       /* MULS                 cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */
-       DECODE_EMULATEX (0x0fe000f0, 0x00000090, PROBES_MUL2,
-                                                REGS(NOPC, 0, NOPC, 0, NOPC)),
-
-       /* MLA                  cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */
-       /* MLAS                 cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */
-       DECODE_OR       (0x0fe000f0, 0x00200090),
-       /* MLS                  cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */
-       DECODE_EMULATEX (0x0ff000f0, 0x00600090, PROBES_MUL2,
-                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
-
-       /* UMAAL                cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */
-       DECODE_OR       (0x0ff000f0, 0x00400090),
-       /* UMULL                cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */
-       /* UMULLS               cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */
-       /* UMLAL                cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */
-       /* UMLALS               cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */
-       /* SMULL                cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */
-       /* SMULLS               cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */
-       /* SMLAL                cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */
-       /* SMLALS               cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */
-       DECODE_EMULATEX (0x0f8000f0, 0x00800090, PROBES_MUL1,
-                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
-
-       DECODE_END
-};
-
-static const union decode_item arm_cccc_0001_____1001_table[] = {
-       /* Synchronization primitives                                   */
-
-#if __LINUX_ARM_ARCH__ < 6
-       /* Deprecated on ARMv6 and may be UNDEFINED on v7               */
-       /* SMP/SWPB             cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */
-       DECODE_EMULATEX (0x0fb000f0, 0x01000090, PROBES_SWP,
-                                                REGS(NOPC, NOPC, 0, 0, NOPC)),
-#endif
-       /* LDREX/STREX{,D,B,H}  cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */
-       /* And unallocated instructions...                              */
-       DECODE_END
-};
-
-static const union decode_item arm_cccc_000x_____1xx1_table[] = {
-       /* Extra load/store instructions                                */
-
-       /* STRHT                cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */
-       /* ???                  cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */
-       /* LDRHT                cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */
-       /* LDRSBT               cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */
-       /* LDRSHT               cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */
-       DECODE_REJECT   (0x0f200090, 0x00200090),
-
-       /* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */
-       DECODE_REJECT   (0x0e10e0d0, 0x0000e0d0),
-
-       /* LDRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */
-       /* STRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */
-       DECODE_EMULATEX (0x0e5000d0, 0x000000d0, PROBES_LDRSTRD,
-                                                REGS(NOPCWB, NOPCX, 0, 0, NOPC)),
-
-       /* LDRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */
-       /* STRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */
-       DECODE_EMULATEX (0x0e5000d0, 0x004000d0, PROBES_LDRSTRD,
-                                                REGS(NOPCWB, NOPCX, 0, 0, 0)),
-
-       /* STRH (register)      cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */
-       DECODE_EMULATEX (0x0e5000f0, 0x000000b0, PROBES_STORE_EXTRA,
-                                                REGS(NOPCWB, NOPC, 0, 0, NOPC)),
-
-       /* LDRH (register)      cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */
-       /* LDRSB (register)     cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */
-       /* LDRSH (register)     cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */
-       DECODE_EMULATEX (0x0e500090, 0x00100090, PROBES_LOAD_EXTRA,
-                                                REGS(NOPCWB, NOPC, 0, 0, NOPC)),
-
-       /* STRH (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */
-       DECODE_EMULATEX (0x0e5000f0, 0x004000b0, PROBES_STORE_EXTRA,
-                                                REGS(NOPCWB, NOPC, 0, 0, 0)),
-
-       /* LDRH (immediate)     cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */
-       /* LDRSB (immediate)    cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */
-       /* LDRSH (immediate)    cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */
-       DECODE_EMULATEX (0x0e500090, 0x00500090, PROBES_LOAD_EXTRA,
-                                                REGS(NOPCWB, NOPC, 0, 0, 0)),
-
-       DECODE_END
-};
-
-static const union decode_item arm_cccc_000x_table[] = {
-       /* Data-processing (register)                                   */
-
-       /* <op>S PC, ...        cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */
-       DECODE_REJECT   (0x0e10f000, 0x0010f000),
-
-       /* MOV IP, SP           1110 0001 1010 0000 1100 0000 0000 1101 */
-       DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, PROBES_MOV_IP_SP),
-
-       /* TST (register)       cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */
-       /* TEQ (register)       cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */
-       /* CMP (register)       cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */
-       /* CMN (register)       cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */
-       DECODE_EMULATEX (0x0f900010, 0x01100000, PROBES_DATA_PROCESSING_REG,
-                                                REGS(ANY, 0, 0, 0, ANY)),
-
-       /* MOV (register)       cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */
-       /* MVN (register)       cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */
-       DECODE_EMULATEX (0x0fa00010, 0x01a00000, PROBES_DATA_PROCESSING_REG,
-                                                REGS(0, ANY, 0, 0, ANY)),
-
-       /* AND (register)       cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */
-       /* EOR (register)       cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */
-       /* SUB (register)       cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */
-       /* RSB (register)       cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */
-       /* ADD (register)       cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */
-       /* ADC (register)       cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */
-       /* SBC (register)       cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */
-       /* RSC (register)       cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */
-       /* ORR (register)       cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */
-       /* BIC (register)       cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */
-       DECODE_EMULATEX (0x0e000010, 0x00000000, PROBES_DATA_PROCESSING_REG,
-                                                REGS(ANY, ANY, 0, 0, ANY)),
-
-       /* TST (reg-shift reg)  cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */
-       /* TEQ (reg-shift reg)  cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */
-       /* CMP (reg-shift reg)  cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */
-       /* CMN (reg-shift reg)  cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */
-       DECODE_EMULATEX (0x0f900090, 0x01100010, PROBES_DATA_PROCESSING_REG,
-                                                REGS(NOPC, 0, NOPC, 0, NOPC)),
-
-       /* MOV (reg-shift reg)  cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */
-       /* MVN (reg-shift reg)  cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */
-       DECODE_EMULATEX (0x0fa00090, 0x01a00010, PROBES_DATA_PROCESSING_REG,
-                                                REGS(0, NOPC, NOPC, 0, NOPC)),
-
-       /* AND (reg-shift reg)  cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */
-       /* EOR (reg-shift reg)  cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */
-       /* SUB (reg-shift reg)  cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */
-       /* RSB (reg-shift reg)  cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */
-       /* ADD (reg-shift reg)  cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */
-       /* ADC (reg-shift reg)  cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */
-       /* SBC (reg-shift reg)  cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */
-       /* RSC (reg-shift reg)  cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */
-       /* ORR (reg-shift reg)  cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */
-       /* BIC (reg-shift reg)  cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */
-       DECODE_EMULATEX (0x0e000090, 0x00000010, PROBES_DATA_PROCESSING_REG,
-                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
-
-       DECODE_END
-};
-
-static const union decode_item arm_cccc_001x_table[] = {
-       /* Data-processing (immediate)                                  */
-
-       /* MOVW                 cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */
-       /* MOVT                 cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_DATA_PROCESSING_IMM,
-                                                REGS(0, NOPC, 0, 0, 0)),
-
-       /* YIELD                cccc 0011 0010 0000 xxxx xxxx 0000 0001 */
-       DECODE_OR       (0x0fff00ff, 0x03200001),
-       /* SEV                  cccc 0011 0010 0000 xxxx xxxx 0000 0100 */
-       DECODE_EMULATE  (0x0fff00ff, 0x03200004, PROBES_EMULATE_NONE),
-       /* NOP                  cccc 0011 0010 0000 xxxx xxxx 0000 0000 */
-       /* WFE                  cccc 0011 0010 0000 xxxx xxxx 0000 0010 */
-       /* WFI                  cccc 0011 0010 0000 xxxx xxxx 0000 0011 */
-       DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_SIMULATE_NOP),
-       /* DBG                  cccc 0011 0010 0000 xxxx xxxx ffff xxxx */
-       /* unallocated hints    cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */
-       /* MSR (immediate)      cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0x0fb00000, 0x03200000),
-
-       /* <op>S PC, ...        cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */
-       DECODE_REJECT   (0x0e10f000, 0x0210f000),
-
-       /* TST (immediate)      cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */
-       /* TEQ (immediate)      cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */
-       /* CMP (immediate)      cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */
-       /* CMN (immediate)      cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0x0f900000, 0x03100000, PROBES_DATA_PROCESSING_IMM,
-                                                REGS(ANY, 0, 0, 0, 0)),
-
-       /* MOV (immediate)      cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */
-       /* MVN (immediate)      cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0x0fa00000, 0x03a00000, PROBES_DATA_PROCESSING_IMM,
-                                                REGS(0, ANY, 0, 0, 0)),
-
-       /* AND (immediate)      cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */
-       /* EOR (immediate)      cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */
-       /* SUB (immediate)      cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */
-       /* RSB (immediate)      cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */
-       /* ADD (immediate)      cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */
-       /* ADC (immediate)      cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */
-       /* SBC (immediate)      cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */
-       /* RSC (immediate)      cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */
-       /* ORR (immediate)      cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */
-       /* BIC (immediate)      cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0x0e000000, 0x02000000, PROBES_DATA_PROCESSING_IMM,
-                                                REGS(ANY, ANY, 0, 0, 0)),
-
-       DECODE_END
-};
-
-static const union decode_item arm_cccc_0110_____xxx1_table[] = {
-       /* Media instructions                                           */
-
-       /* SEL                  cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */
-       DECODE_EMULATEX (0x0ff000f0, 0x068000b0, PROBES_SATURATE,
-                                                REGS(NOPC, NOPC, 0, 0, NOPC)),
-
-       /* SSAT                 cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */
-       /* USAT                 cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */
-       DECODE_OR(0x0fa00030, 0x06a00010),
-       /* SSAT16               cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */
-       /* USAT16               cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */
-       DECODE_EMULATEX (0x0fb000f0, 0x06a00030, PROBES_SATURATE,
-                                                REGS(0, NOPC, 0, 0, NOPC)),
-
-       /* REV                  cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */
-       /* REV16                cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */
-       /* RBIT                 cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */
-       /* REVSH                cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */
-       DECODE_EMULATEX (0x0fb00070, 0x06b00030, PROBES_REV,
-                                                REGS(0, NOPC, 0, 0, NOPC)),
-
-       /* ???                  cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */
-       DECODE_REJECT   (0x0fb00010, 0x06000010),
-       /* ???                  cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */
-       DECODE_REJECT   (0x0f8000f0, 0x060000b0),
-       /* ???                  cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */
-       DECODE_REJECT   (0x0f8000f0, 0x060000d0),
-       /* SADD16               cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */
-       /* SADDSUBX             cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */
-       /* SSUBADDX             cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */
-       /* SSUB16               cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */
-       /* SADD8                cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */
-       /* SSUB8                cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */
-       /* QADD16               cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */
-       /* QADDSUBX             cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */
-       /* QSUBADDX             cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */
-       /* QSUB16               cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */
-       /* QADD8                cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */
-       /* QSUB8                cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */
-       /* SHADD16              cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */
-       /* SHADDSUBX            cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */
-       /* SHSUBADDX            cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */
-       /* SHSUB16              cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */
-       /* SHADD8               cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */
-       /* SHSUB8               cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */
-       /* UADD16               cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */
-       /* UADDSUBX             cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */
-       /* USUBADDX             cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */
-       /* USUB16               cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */
-       /* UADD8                cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */
-       /* USUB8                cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */
-       /* UQADD16              cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */
-       /* UQADDSUBX            cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */
-       /* UQSUBADDX            cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */
-       /* UQSUB16              cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */
-       /* UQADD8               cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */
-       /* UQSUB8               cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */
-       /* UHADD16              cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */
-       /* UHADDSUBX            cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */
-       /* UHSUBADDX            cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */
-       /* UHSUB16              cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */
-       /* UHADD8               cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */
-       /* UHSUB8               cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */
-       DECODE_EMULATEX (0x0f800010, 0x06000010, PROBES_MMI,
-                                                REGS(NOPC, NOPC, 0, 0, NOPC)),
-
-       /* PKHBT                cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */
-       /* PKHTB                cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */
-       DECODE_EMULATEX (0x0ff00030, 0x06800010, PROBES_PACK,
-                                                REGS(NOPC, NOPC, 0, 0, NOPC)),
-
-       /* ???                  cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */
-       /* ???                  cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */
-       DECODE_REJECT   (0x0fb000f0, 0x06900070),
-
-       /* SXTB16               cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */
-       /* SXTB                 cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */
-       /* SXTH                 cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */
-       /* UXTB16               cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */
-       /* UXTB                 cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */
-       /* UXTH                 cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */
-       DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, PROBES_EXTEND,
-                                                REGS(0, NOPC, 0, 0, NOPC)),
-
-       /* SXTAB16              cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */
-       /* SXTAB                cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */
-       /* SXTAH                cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */
-       /* UXTAB16              cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */
-       /* UXTAB                cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */
-       /* UXTAH                cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */
-       DECODE_EMULATEX (0x0f8000f0, 0x06800070, PROBES_EXTEND_ADD,
-                                                REGS(NOPCX, NOPC, 0, 0, NOPC)),
-
-       DECODE_END
-};
-
-static const union decode_item arm_cccc_0111_____xxx1_table[] = {
-       /* Media instructions                                           */
-
-       /* UNDEFINED            cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */
-       DECODE_REJECT   (0x0ff000f0, 0x07f000f0),
-
-       /* SMLALD               cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */
-       /* SMLSLD               cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */
-       DECODE_EMULATEX (0x0ff00090, 0x07400010, PROBES_MUL_ADD_LONG,
-                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
-
-       /* SMUAD                cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */
-       /* SMUSD                cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */
-       DECODE_OR       (0x0ff0f090, 0x0700f010),
-       /* SMMUL                cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */
-       DECODE_OR       (0x0ff0f0d0, 0x0750f010),
-       /* USAD8                cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */
-       DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, PROBES_MUL_ADD,
-                                                REGS(NOPC, 0, NOPC, 0, NOPC)),
-
-       /* SMLAD                cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */
-       /* SMLSD                cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */
-       DECODE_OR       (0x0ff00090, 0x07000010),
-       /* SMMLA                cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */
-       DECODE_OR       (0x0ff000d0, 0x07500010),
-       /* USADA8               cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */
-       DECODE_EMULATEX (0x0ff000f0, 0x07800010, PROBES_MUL_ADD,
-                                                REGS(NOPC, NOPCX, NOPC, 0, NOPC)),
-
-       /* SMMLS                cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */
-       DECODE_EMULATEX (0x0ff000d0, 0x075000d0, PROBES_MUL_ADD,
-                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
-
-       /* SBFX                 cccc 0111 101x xxxx xxxx xxxx x101 xxxx */
-       /* UBFX                 cccc 0111 111x xxxx xxxx xxxx x101 xxxx */
-       DECODE_EMULATEX (0x0fa00070, 0x07a00050, PROBES_BITFIELD,
-                                                REGS(0, NOPC, 0, 0, NOPC)),
-
-       /* BFC                  cccc 0111 110x xxxx xxxx xxxx x001 1111 */
-       DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, PROBES_BITFIELD,
-                                                REGS(0, NOPC, 0, 0, 0)),
-
-       /* BFI                  cccc 0111 110x xxxx xxxx xxxx x001 xxxx */
-       DECODE_EMULATEX (0x0fe00070, 0x07c00010, PROBES_BITFIELD,
-                                                REGS(0, NOPC, 0, 0, NOPCX)),
-
-       DECODE_END
-};
-
-static const union decode_item arm_cccc_01xx_table[] = {
-       /* Load/store word and unsigned byte                            */
-
-       /* LDRB/STRB pc,[...]   cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0x0c40f000, 0x0440f000),
-
-       /* STRT                 cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */
-       /* LDRT                 cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */
-       /* STRBT                cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */
-       /* LDRBT                cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0x0d200000, 0x04200000),
-
-       /* STR (immediate)      cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */
-       /* STRB (immediate)     cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0x0e100000, 0x04000000, PROBES_STORE,
-                                                REGS(NOPCWB, ANY, 0, 0, 0)),
-
-       /* LDR (immediate)      cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */
-       /* LDRB (immediate)     cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0x0e100000, 0x04100000, PROBES_LOAD,
-                                                REGS(NOPCWB, ANY, 0, 0, 0)),
-
-       /* STR (register)       cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */
-       /* STRB (register)      cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0x0e100000, 0x06000000, PROBES_STORE,
-                                                REGS(NOPCWB, ANY, 0, 0, NOPC)),
-
-       /* LDR (register)       cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */
-       /* LDRB (register)      cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0x0e100000, 0x06100000, PROBES_LOAD,
-                                                REGS(NOPCWB, ANY, 0, 0, NOPC)),
-
-       DECODE_END
-};
-
-static const union decode_item arm_cccc_100x_table[] = {
-       /* Block data transfer instructions                             */
-
-       /* LDM                  cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
-       /* STM                  cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_CUSTOM   (0x0e400000, 0x08000000, PROBES_LDMSTM),
-
-       /* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
-       /* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */
-       /* LDM (exception ret)  cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */
-       DECODE_END
-};
-
-const union decode_item probes_decode_arm_table[] = {
-       /*
-        * Unconditional instructions
-        *                      1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xf0000000, 0xf0000000, arm_1111_table),
-
-       /*
-        * Miscellaneous instructions
-        *                      cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx
-        */
-       DECODE_TABLE    (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table),
-
-       /*
-        * Halfword multiply and multiply-accumulate
-        *                      cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx
-        */
-       DECODE_TABLE    (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table),
-
-       /*
-        * Multiply and multiply-accumulate
-        *                      cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx
-        */
-       DECODE_TABLE    (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table),
-
-       /*
-        * Synchronization primitives
-        *                      cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx
-        */
-       DECODE_TABLE    (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table),
-
-       /*
-        * Extra load/store instructions
-        *                      cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx
-        */
-       DECODE_TABLE    (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table),
-
-       /*
-        * Data-processing (register)
-        *                      cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx
-        * Data-processing (register-shifted register)
-        *                      cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx
-        */
-       DECODE_TABLE    (0x0e000000, 0x00000000, arm_cccc_000x_table),
-
-       /*
-        * Data-processing (immediate)
-        *                      cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0x0e000000, 0x02000000, arm_cccc_001x_table),
-
-       /*
-        * Media instructions
-        *                      cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx
-        */
-       DECODE_TABLE    (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table),
-       DECODE_TABLE    (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table),
-
-       /*
-        * Load/store word and unsigned byte
-        *                      cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0x0c000000, 0x04000000, arm_cccc_01xx_table),
-
-       /*
-        * Block data transfer instructions
-        *                      cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0x0e000000, 0x08000000, arm_cccc_100x_table),
-
-       /* B                    cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */
-       /* BL                   cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */
-       DECODE_SIMULATE (0x0e000000, 0x0a000000, PROBES_BRANCH),
-
-       /*
-        * Supervisor Call, and coprocessor instructions
-        */
-
-       /* MCRR                 cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */
-       /* MRRC                 cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */
-       /* LDC                  cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
-       /* STC                  cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
-       /* CDP                  cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
-       /* MCR                  cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
-       /* MRC                  cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
-       /* SVC                  cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0x0c000000, 0x0c000000),
-
-       DECODE_END
-};
-#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
-EXPORT_SYMBOL_GPL(probes_decode_arm_table);
-#endif
-
-static void __kprobes arm_singlestep(probes_opcode_t insn,
-               struct arch_probes_insn *asi, struct pt_regs *regs)
-{
-       regs->ARM_pc += 4;
-       asi->insn_handler(insn, asi, regs);
-}
-
-/* Return:
- *   INSN_REJECTED     If instruction is one not allowed to kprobe,
- *   INSN_GOOD         If instruction is supported and uses instruction slot,
- *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
- *
- * For instructions we don't want to kprobe (INSN_REJECTED return result):
- *   These are generally ones that modify the processor state making
- *   them "hard" to simulate such as switches processor modes or
- *   make accesses in alternate modes.  Any of these could be simulated
- *   if the work was put into it, but low return considering they
- *   should also be very rare.
- */
-enum probes_insn __kprobes
-arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
-                      bool emulate, const union decode_action *actions)
-{
-       asi->insn_singlestep = arm_singlestep;
-       asi->insn_check_cc = probes_condition_checks[insn>>28];
-       return probes_decode_insn(insn, asi, probes_decode_arm_table, false,
-                                 emulate, actions);
-}
diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h
deleted file mode 100644 (file)
index ace6572..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * arch/arm/kernel/probes-arm.h
- *
- * Copyright 2013 Linaro Ltd.
- * Written by: David A. Long
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef _ARM_KERNEL_PROBES_ARM_H
-#define  _ARM_KERNEL_PROBES_ARM_H
-
-enum probes_arm_action {
-       PROBES_EMULATE_NONE,
-       PROBES_SIMULATE_NOP,
-       PROBES_PRELOAD_IMM,
-       PROBES_PRELOAD_REG,
-       PROBES_BRANCH_IMM,
-       PROBES_BRANCH_REG,
-       PROBES_MRS,
-       PROBES_CLZ,
-       PROBES_SATURATING_ARITHMETIC,
-       PROBES_MUL1,
-       PROBES_MUL2,
-       PROBES_SWP,
-       PROBES_LDRSTRD,
-       PROBES_LOAD,
-       PROBES_STORE,
-       PROBES_LOAD_EXTRA,
-       PROBES_STORE_EXTRA,
-       PROBES_MOV_IP_SP,
-       PROBES_DATA_PROCESSING_REG,
-       PROBES_DATA_PROCESSING_IMM,
-       PROBES_MOV_HALFWORD,
-       PROBES_SEV,
-       PROBES_WFE,
-       PROBES_SATURATE,
-       PROBES_REV,
-       PROBES_MMI,
-       PROBES_PACK,
-       PROBES_EXTEND,
-       PROBES_EXTEND_ADD,
-       PROBES_MUL_ADD_LONG,
-       PROBES_MUL_ADD,
-       PROBES_BITFIELD,
-       PROBES_BRANCH,
-       PROBES_LDMSTM,
-       NUM_PROBES_ARM_ACTIONS
-};
-
-void __kprobes simulate_bbl(probes_opcode_t opcode,
-       struct arch_probes_insn *asi, struct pt_regs *regs);
-void __kprobes simulate_blx1(probes_opcode_t opcode,
-       struct arch_probes_insn *asi, struct pt_regs *regs);
-void __kprobes simulate_blx2bx(probes_opcode_t opcode,
-       struct arch_probes_insn *asi, struct pt_regs *regs);
-void __kprobes simulate_mrs(probes_opcode_t opcode,
-       struct arch_probes_insn *asi, struct pt_regs *regs);
-void __kprobes simulate_mov_ipsp(probes_opcode_t opcode,
-       struct arch_probes_insn *asi, struct pt_regs *regs);
-
-extern const union decode_item probes_decode_arm_table[];
-
-enum probes_insn arm_probes_decode_insn(probes_opcode_t,
-               struct arch_probes_insn *, bool emulate,
-               const union decode_action *actions);
-
-#endif
diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c
deleted file mode 100644 (file)
index 4131351..0000000
+++ /dev/null
@@ -1,882 +0,0 @@
-/*
- * arch/arm/kernel/probes-thumb.c
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "probes.h"
-#include "probes-thumb.h"
-
-
-static const union decode_item t32_table_1110_100x_x0xx[] = {
-       /* Load/store multiple instructions */
-
-       /* Rn is PC             1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xfe4f0000, 0xe80f0000),
-
-       /* SRS                  1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */
-       /* RFE                  1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xffc00000, 0xe8000000),
-       /* SRS                  1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */
-       /* RFE                  1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xffc00000, 0xe9800000),
-
-       /* STM Rn, {...pc}      1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xfe508000, 0xe8008000),
-       /* LDM Rn, {...lr,pc}   1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xfe50c000, 0xe810c000),
-       /* LDM/STM Rn, {...sp}  1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */
-       DECODE_REJECT   (0xfe402000, 0xe8002000),
-
-       /* STMIA                1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */
-       /* LDMIA                1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */
-       /* STMDB                1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */
-       /* LDMDB                1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_CUSTOM   (0xfe400000, 0xe8000000, PROBES_T32_LDMSTM),
-
-       DECODE_END
-};
-
-static const union decode_item t32_table_1110_100x_x1xx[] = {
-       /* Load/store dual, load/store exclusive, table branch */
-
-       /* STRD (immediate)     1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */
-       /* LDRD (immediate)     1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_OR       (0xff600000, 0xe8600000),
-       /* STRD (immediate)     1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */
-       /* LDRD (immediate)     1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xff400000, 0xe9400000, PROBES_T32_LDRDSTRD,
-                                                REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)),
-
-       /* TBB                  1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */
-       /* TBH                  1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */
-       DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, PROBES_T32_TABLE_BRANCH,
-                                                REGS(NOSP, 0, 0, 0, NOSPPC)),
-
-       /* STREX                1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */
-       /* LDREX                1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */
-       /* STREXB               1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */
-       /* STREXH               1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */
-       /* STREXD               1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */
-       /* LDREXB               1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */
-       /* LDREXH               1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */
-       /* LDREXD               1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */
-       /* And unallocated instructions...                              */
-       DECODE_END
-};
-
-static const union decode_item t32_table_1110_101x[] = {
-       /* Data-processing (shifted register)                           */
-
-       /* TST                  1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */
-       /* TEQ                  1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */
-       DECODE_EMULATEX (0xff700f00, 0xea100f00, PROBES_T32_TST,
-                                                REGS(NOSPPC, 0, 0, 0, NOSPPC)),
-
-       /* CMN                  1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */
-       DECODE_OR       (0xfff00f00, 0xeb100f00),
-       /* CMP                  1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */
-       DECODE_EMULATEX (0xfff00f00, 0xebb00f00, PROBES_T32_TST,
-                                                REGS(NOPC, 0, 0, 0, NOSPPC)),
-
-       /* MOV                  1110 1010 010x 1111 xxxx xxxx xxxx xxxx */
-       /* MVN                  1110 1010 011x 1111 xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xffcf0000, 0xea4f0000, PROBES_T32_MOV,
-                                                REGS(0, 0, NOSPPC, 0, NOSPPC)),
-
-       /* ???                  1110 1010 101x xxxx xxxx xxxx xxxx xxxx */
-       /* ???                  1110 1010 111x xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xffa00000, 0xeaa00000),
-       /* ???                  1110 1011 001x xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xffe00000, 0xeb200000),
-       /* ???                  1110 1011 100x xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xffe00000, 0xeb800000),
-       /* ???                  1110 1011 111x xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xffe00000, 0xebe00000),
-
-       /* ADD/SUB SP, SP, Rm, LSL #0..3                                */
-       /*                      1110 1011 x0xx 1101 x000 1101 xx00 xxxx */
-       DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, PROBES_T32_ADDSUB,
-                                                REGS(SP, 0, SP, 0, NOSPPC)),
-
-       /* ADD/SUB SP, SP, Rm, shift                                    */
-       /*                      1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */
-       DECODE_REJECT   (0xff4f0f00, 0xeb0d0d00),
-
-       /* ADD/SUB Rd, SP, Rm, shift                                    */
-       /*                      1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, PROBES_T32_ADDSUB,
-                                                REGS(SP, 0, NOPC, 0, NOSPPC)),
-
-       /* AND                  1110 1010 000x xxxx xxxx xxxx xxxx xxxx */
-       /* BIC                  1110 1010 001x xxxx xxxx xxxx xxxx xxxx */
-       /* ORR                  1110 1010 010x xxxx xxxx xxxx xxxx xxxx */
-       /* ORN                  1110 1010 011x xxxx xxxx xxxx xxxx xxxx */
-       /* EOR                  1110 1010 100x xxxx xxxx xxxx xxxx xxxx */
-       /* PKH                  1110 1010 110x xxxx xxxx xxxx xxxx xxxx */
-       /* ADD                  1110 1011 000x xxxx xxxx xxxx xxxx xxxx */
-       /* ADC                  1110 1011 010x xxxx xxxx xxxx xxxx xxxx */
-       /* SBC                  1110 1011 011x xxxx xxxx xxxx xxxx xxxx */
-       /* SUB                  1110 1011 101x xxxx xxxx xxxx xxxx xxxx */
-       /* RSB                  1110 1011 110x xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfe000000, 0xea000000, PROBES_T32_LOGICAL,
-                                                REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)),
-
-       DECODE_END
-};
-
-static const union decode_item t32_table_1111_0x0x___0[] = {
-       /* Data-processing (modified immediate)                         */
-
-       /* TST                  1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */
-       /* TEQ                  1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */
-       DECODE_EMULATEX (0xfb708f00, 0xf0100f00, PROBES_T32_TST,
-                                                REGS(NOSPPC, 0, 0, 0, 0)),
-
-       /* CMN                  1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */
-       DECODE_OR       (0xfbf08f00, 0xf1100f00),
-       /* CMP                  1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */
-       DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, PROBES_T32_CMP,
-                                                REGS(NOPC, 0, 0, 0, 0)),
-
-       /* MOV                  1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */
-       /* MVN                  1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, PROBES_T32_MOV,
-                                                REGS(0, 0, NOSPPC, 0, 0)),
-
-       /* ???                  1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xfbe08000, 0xf0a00000),
-       /* ???                  1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */
-       /* ???                  1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xfbc08000, 0xf0c00000),
-       /* ???                  1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xfbe08000, 0xf1200000),
-       /* ???                  1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xfbe08000, 0xf1800000),
-       /* ???                  1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xfbe08000, 0xf1e00000),
-
-       /* ADD Rd, SP, #imm     1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */
-       /* SUB Rd, SP, #imm     1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, PROBES_T32_ADDSUB,
-                                                REGS(SP, 0, NOPC, 0, 0)),
-
-       /* AND                  1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */
-       /* BIC                  1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */
-       /* ORR                  1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */
-       /* ORN                  1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */
-       /* EOR                  1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */
-       /* ADD                  1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */
-       /* ADC                  1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */
-       /* SBC                  1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */
-       /* SUB                  1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */
-       /* RSB                  1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfa008000, 0xf0000000, PROBES_T32_LOGICAL,
-                                                REGS(NOSPPC, 0, NOSPPC, 0, 0)),
-
-       DECODE_END
-};
-
-static const union decode_item t32_table_1111_0x1x___0[] = {
-       /* Data-processing (plain binary immediate)                     */
-
-       /* ADDW Rd, PC, #imm    1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */
-       DECODE_OR       (0xfbff8000, 0xf20f0000),
-       /* SUBW Rd, PC, #imm    1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfbff8000, 0xf2af0000, PROBES_T32_ADDWSUBW_PC,
-                                                REGS(PC, 0, NOSPPC, 0, 0)),
-
-       /* ADDW SP, SP, #imm    1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */
-       DECODE_OR       (0xfbff8f00, 0xf20d0d00),
-       /* SUBW SP, SP, #imm    1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */
-       DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, PROBES_T32_ADDWSUBW,
-                                                REGS(SP, 0, SP, 0, 0)),
-
-       /* ADDW                 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_OR       (0xfbf08000, 0xf2000000),
-       /* SUBW                 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfbf08000, 0xf2a00000, PROBES_T32_ADDWSUBW,
-                                                REGS(NOPCX, 0, NOSPPC, 0, 0)),
-
-       /* MOVW                 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */
-       /* MOVT                 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfb708000, 0xf2400000, PROBES_T32_MOVW,
-                                                REGS(0, 0, NOSPPC, 0, 0)),
-
-       /* SSAT16               1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */
-       /* SSAT                 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */
-       /* USAT16               1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */
-       /* USAT                 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfb508000, 0xf3000000, PROBES_T32_SAT,
-                                                REGS(NOSPPC, 0, NOSPPC, 0, 0)),
-
-       /* SFBX                 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */
-       /* UFBX                 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfb708000, 0xf3400000, PROBES_T32_BITFIELD,
-                                                REGS(NOSPPC, 0, NOSPPC, 0, 0)),
-
-       /* BFC                  1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfbff8000, 0xf36f0000, PROBES_T32_BITFIELD,
-                                                REGS(0, 0, NOSPPC, 0, 0)),
-
-       /* BFI                  1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfbf08000, 0xf3600000, PROBES_T32_BITFIELD,
-                                                REGS(NOSPPCX, 0, NOSPPC, 0, 0)),
-
-       DECODE_END
-};
-
-static const union decode_item t32_table_1111_0xxx___1[] = {
-       /* Branches and miscellaneous control                           */
-
-       /* YIELD                1111 0011 1010 xxxx 10x0 x000 0000 0001 */
-       DECODE_OR       (0xfff0d7ff, 0xf3a08001),
-       /* SEV                  1111 0011 1010 xxxx 10x0 x000 0000 0100 */
-       DECODE_EMULATE  (0xfff0d7ff, 0xf3a08004, PROBES_T32_SEV),
-       /* NOP                  1111 0011 1010 xxxx 10x0 x000 0000 0000 */
-       /* WFE                  1111 0011 1010 xxxx 10x0 x000 0000 0010 */
-       /* WFI                  1111 0011 1010 xxxx 10x0 x000 0000 0011 */
-       DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, PROBES_T32_WFE),
-
-       /* MRS Rd, CPSR         1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */
-       DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, PROBES_T32_MRS,
-                                                REGS(0, 0, NOSPPC, 0, 0)),
-
-       /*
-        * Unsupported instructions
-        *                      1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx
-        *
-        * MSR                  1111 0011 100x xxxx 10x0 xxxx xxxx xxxx
-        * DBG hint             1111 0011 1010 xxxx 10x0 x000 1111 xxxx
-        * Unallocated hints    1111 0011 1010 xxxx 10x0 x000 xxxx xxxx
-        * CPS                  1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx
-        * CLREX/DSB/DMB/ISB    1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx
-        * BXJ                  1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx
-        * SUBS PC,LR,#<imm8>   1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx
-        * MRS Rd, SPSR         1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx
-        * SMC                  1111 0111 1111 xxxx 1000 xxxx xxxx xxxx
-        * UNDEFINED            1111 0111 1111 xxxx 1010 xxxx xxxx xxxx
-        * ???                  1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx
-        */
-       DECODE_REJECT   (0xfb80d000, 0xf3808000),
-
-       /* Bcc                  1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */
-       DECODE_CUSTOM   (0xf800d000, 0xf0008000, PROBES_T32_BRANCH_COND),
-
-       /* BLX                  1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */
-       DECODE_OR       (0xf800d001, 0xf000c000),
-       /* B                    1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */
-       /* BL                   1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */
-       DECODE_SIMULATE (0xf8009000, 0xf0009000, PROBES_T32_BRANCH),
-
-       DECODE_END
-};
-
-static const union decode_item t32_table_1111_100x_x0x1__1111[] = {
-       /* Memory hints                                                 */
-
-       /* PLD (literal)        1111 1000 x001 1111 1111 xxxx xxxx xxxx */
-       /* PLI (literal)        1111 1001 x001 1111 1111 xxxx xxxx xxxx */
-       DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, PROBES_T32_PLDI),
-
-       /* PLD{W} (immediate)   1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */
-       DECODE_OR       (0xffd0f000, 0xf890f000),
-       /* PLD{W} (immediate)   1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */
-       DECODE_OR       (0xffd0ff00, 0xf810fc00),
-       /* PLI (immediate)      1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */
-       DECODE_OR       (0xfff0f000, 0xf990f000),
-       /* PLI (immediate)      1111 1001 0001 xxxx 1111 1100 xxxx xxxx */
-       DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, PROBES_T32_PLDI,
-                                                REGS(NOPCX, 0, 0, 0, 0)),
-
-       /* PLD{W} (register)    1111 1000 00x1 xxxx 1111 0000 00xx xxxx */
-       DECODE_OR       (0xffd0ffc0, 0xf810f000),
-       /* PLI (register)       1111 1001 0001 xxxx 1111 0000 00xx xxxx */
-       DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, PROBES_T32_PLDI,
-                                                REGS(NOPCX, 0, 0, 0, NOSPPC)),
-
-       /* Other unallocated instructions...                            */
-       DECODE_END
-};
-
-static const union decode_item t32_table_1111_100x[] = {
-       /* Store/Load single data item                                  */
-
-       /* ???                  1111 100x x11x xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xfe600000, 0xf8600000),
-
-       /* ???                  1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xfff00000, 0xf9500000),
-
-       /* ???                  1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */
-       DECODE_REJECT   (0xfe800d00, 0xf8000800),
-
-       /* STRBT                1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */
-       /* STRHT                1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */
-       /* STRT                 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */
-       /* LDRBT                1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */
-       /* LDRSBT               1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */
-       /* LDRHT                1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */
-       /* LDRSHT               1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */
-       /* LDRT                 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */
-       DECODE_REJECT   (0xfe800f00, 0xf8000e00),
-
-       /* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */
-       DECODE_REJECT   (0xff1f0000, 0xf80f0000),
-
-       /* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */
-       DECODE_REJECT   (0xff10f000, 0xf800f000),
-
-       /* LDR (literal)        1111 1000 x101 1111 xxxx xxxx xxxx xxxx */
-       DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, PROBES_T32_LDR_LIT,
-                                                REGS(PC, ANY, 0, 0, 0)),
-
-       /* STR (immediate)      1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */
-       /* LDR (immediate)      1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */
-       DECODE_OR       (0xffe00800, 0xf8400800),
-       /* STR (immediate)      1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */
-       /* LDR (immediate)      1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xffe00000, 0xf8c00000, PROBES_T32_LDRSTR,
-                                                REGS(NOPCX, ANY, 0, 0, 0)),
-
-       /* STR (register)       1111 1000 0100 xxxx xxxx 0000 00xx xxxx */
-       /* LDR (register)       1111 1000 0101 xxxx xxxx 0000 00xx xxxx */
-       DECODE_EMULATEX (0xffe00fc0, 0xf8400000, PROBES_T32_LDRSTR,
-                                                REGS(NOPCX, ANY, 0, 0, NOSPPC)),
-
-       /* LDRB (literal)       1111 1000 x001 1111 xxxx xxxx xxxx xxxx */
-       /* LDRSB (literal)      1111 1001 x001 1111 xxxx xxxx xxxx xxxx */
-       /* LDRH (literal)       1111 1000 x011 1111 xxxx xxxx xxxx xxxx */
-       /* LDRSH (literal)      1111 1001 x011 1111 xxxx xxxx xxxx xxxx */
-       DECODE_SIMULATEX(0xfe5f0000, 0xf81f0000, PROBES_T32_LDR_LIT,
-                                                REGS(PC, NOSPPCX, 0, 0, 0)),
-
-       /* STRB (immediate)     1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */
-       /* STRH (immediate)     1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */
-       /* LDRB (immediate)     1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */
-       /* LDRSB (immediate)    1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */
-       /* LDRH (immediate)     1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */
-       /* LDRSH (immediate)    1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */
-       DECODE_OR       (0xfec00800, 0xf8000800),
-       /* STRB (immediate)     1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */
-       /* STRH (immediate)     1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */
-       /* LDRB (immediate)     1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */
-       /* LDRSB (immediate)    1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */
-       /* LDRH (immediate)     1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */
-       /* LDRSH (immediate)    1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */
-       DECODE_EMULATEX (0xfec00000, 0xf8800000, PROBES_T32_LDRSTR,
-                                                REGS(NOPCX, NOSPPCX, 0, 0, 0)),
-
-       /* STRB (register)      1111 1000 0000 xxxx xxxx 0000 00xx xxxx */
-       /* STRH (register)      1111 1000 0010 xxxx xxxx 0000 00xx xxxx */
-       /* LDRB (register)      1111 1000 0001 xxxx xxxx 0000 00xx xxxx */
-       /* LDRSB (register)     1111 1001 0001 xxxx xxxx 0000 00xx xxxx */
-       /* LDRH (register)      1111 1000 0011 xxxx xxxx 0000 00xx xxxx */
-       /* LDRSH (register)     1111 1001 0011 xxxx xxxx 0000 00xx xxxx */
-       DECODE_EMULATEX (0xfe800fc0, 0xf8000000, PROBES_T32_LDRSTR,
-                                                REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)),
-
-       /* Other unallocated instructions...                            */
-       DECODE_END
-};
-
-static const union decode_item t32_table_1111_1010___1111[] = {
-       /* Data-processing (register)                                   */
-
-       /* ???                  1111 1010 011x xxxx 1111 xxxx 1xxx xxxx */
-       DECODE_REJECT   (0xffe0f080, 0xfa60f080),
-
-       /* SXTH                 1111 1010 0000 1111 1111 xxxx 1xxx xxxx */
-       /* UXTH                 1111 1010 0001 1111 1111 xxxx 1xxx xxxx */
-       /* SXTB16               1111 1010 0010 1111 1111 xxxx 1xxx xxxx */
-       /* UXTB16               1111 1010 0011 1111 1111 xxxx 1xxx xxxx */
-       /* SXTB                 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */
-       /* UXTB                 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */
-       DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, PROBES_T32_SIGN_EXTEND,
-                                                REGS(0, 0, NOSPPC, 0, NOSPPC)),
-
-
-       /* ???                  1111 1010 1xxx xxxx 1111 xxxx 0x11 xxxx */
-       DECODE_REJECT   (0xff80f0b0, 0xfa80f030),
-       /* ???                  1111 1010 1x11 xxxx 1111 xxxx 0xxx xxxx */
-       DECODE_REJECT   (0xffb0f080, 0xfab0f000),
-
-       /* SADD16               1111 1010 1001 xxxx 1111 xxxx 0000 xxxx */
-       /* SASX                 1111 1010 1010 xxxx 1111 xxxx 0000 xxxx */
-       /* SSAX                 1111 1010 1110 xxxx 1111 xxxx 0000 xxxx */
-       /* SSUB16               1111 1010 1101 xxxx 1111 xxxx 0000 xxxx */
-       /* SADD8                1111 1010 1000 xxxx 1111 xxxx 0000 xxxx */
-       /* SSUB8                1111 1010 1100 xxxx 1111 xxxx 0000 xxxx */
-
-       /* QADD16               1111 1010 1001 xxxx 1111 xxxx 0001 xxxx */
-       /* QASX                 1111 1010 1010 xxxx 1111 xxxx 0001 xxxx */
-       /* QSAX                 1111 1010 1110 xxxx 1111 xxxx 0001 xxxx */
-       /* QSUB16               1111 1010 1101 xxxx 1111 xxxx 0001 xxxx */
-       /* QADD8                1111 1010 1000 xxxx 1111 xxxx 0001 xxxx */
-       /* QSUB8                1111 1010 1100 xxxx 1111 xxxx 0001 xxxx */
-
-       /* SHADD16              1111 1010 1001 xxxx 1111 xxxx 0010 xxxx */
-       /* SHASX                1111 1010 1010 xxxx 1111 xxxx 0010 xxxx */
-       /* SHSAX                1111 1010 1110 xxxx 1111 xxxx 0010 xxxx */
-       /* SHSUB16              1111 1010 1101 xxxx 1111 xxxx 0010 xxxx */
-       /* SHADD8               1111 1010 1000 xxxx 1111 xxxx 0010 xxxx */
-       /* SHSUB8               1111 1010 1100 xxxx 1111 xxxx 0010 xxxx */
-
-       /* UADD16               1111 1010 1001 xxxx 1111 xxxx 0100 xxxx */
-       /* UASX                 1111 1010 1010 xxxx 1111 xxxx 0100 xxxx */
-       /* USAX                 1111 1010 1110 xxxx 1111 xxxx 0100 xxxx */
-       /* USUB16               1111 1010 1101 xxxx 1111 xxxx 0100 xxxx */
-       /* UADD8                1111 1010 1000 xxxx 1111 xxxx 0100 xxxx */
-       /* USUB8                1111 1010 1100 xxxx 1111 xxxx 0100 xxxx */
-
-       /* UQADD16              1111 1010 1001 xxxx 1111 xxxx 0101 xxxx */
-       /* UQASX                1111 1010 1010 xxxx 1111 xxxx 0101 xxxx */
-       /* UQSAX                1111 1010 1110 xxxx 1111 xxxx 0101 xxxx */
-       /* UQSUB16              1111 1010 1101 xxxx 1111 xxxx 0101 xxxx */
-       /* UQADD8               1111 1010 1000 xxxx 1111 xxxx 0101 xxxx */
-       /* UQSUB8               1111 1010 1100 xxxx 1111 xxxx 0101 xxxx */
-
-       /* UHADD16              1111 1010 1001 xxxx 1111 xxxx 0110 xxxx */
-       /* UHASX                1111 1010 1010 xxxx 1111 xxxx 0110 xxxx */
-       /* UHSAX                1111 1010 1110 xxxx 1111 xxxx 0110 xxxx */
-       /* UHSUB16              1111 1010 1101 xxxx 1111 xxxx 0110 xxxx */
-       /* UHADD8               1111 1010 1000 xxxx 1111 xxxx 0110 xxxx */
-       /* UHSUB8               1111 1010 1100 xxxx 1111 xxxx 0110 xxxx */
-       DECODE_OR       (0xff80f080, 0xfa80f000),
-
-       /* SXTAH                1111 1010 0000 xxxx 1111 xxxx 1xxx xxxx */
-       /* UXTAH                1111 1010 0001 xxxx 1111 xxxx 1xxx xxxx */
-       /* SXTAB16              1111 1010 0010 xxxx 1111 xxxx 1xxx xxxx */
-       /* UXTAB16              1111 1010 0011 xxxx 1111 xxxx 1xxx xxxx */
-       /* SXTAB                1111 1010 0100 xxxx 1111 xxxx 1xxx xxxx */
-       /* UXTAB                1111 1010 0101 xxxx 1111 xxxx 1xxx xxxx */
-       DECODE_OR       (0xff80f080, 0xfa00f080),
-
-       /* QADD                 1111 1010 1000 xxxx 1111 xxxx 1000 xxxx */
-       /* QDADD                1111 1010 1000 xxxx 1111 xxxx 1001 xxxx */
-       /* QSUB                 1111 1010 1000 xxxx 1111 xxxx 1010 xxxx */
-       /* QDSUB                1111 1010 1000 xxxx 1111 xxxx 1011 xxxx */
-       DECODE_OR       (0xfff0f0c0, 0xfa80f080),
-
-       /* SEL                  1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */
-       DECODE_OR       (0xfff0f0f0, 0xfaa0f080),
-
-       /* LSL                  1111 1010 000x xxxx 1111 xxxx 0000 xxxx */
-       /* LSR                  1111 1010 001x xxxx 1111 xxxx 0000 xxxx */
-       /* ASR                  1111 1010 010x xxxx 1111 xxxx 0000 xxxx */
-       /* ROR                  1111 1010 011x xxxx 1111 xxxx 0000 xxxx */
-       DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, PROBES_T32_MEDIA,
-                                                REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)),
-
-       /* CLZ                  1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */
-       DECODE_OR       (0xfff0f0f0, 0xfab0f080),
-
-       /* REV                  1111 1010 1001 xxxx 1111 xxxx 1000 xxxx */
-       /* REV16                1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */
-       /* RBIT                 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */
-       /* REVSH                1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */
-       DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, PROBES_T32_REVERSE,
-                                                REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)),
-
-       /* Other unallocated instructions...                            */
-       DECODE_END
-};
-
-static const union decode_item t32_table_1111_1011_0[] = {
-       /* Multiply, multiply accumulate, and absolute difference       */
-
-       /* ???                  1111 1011 0000 xxxx 1111 xxxx 0001 xxxx */
-       DECODE_REJECT   (0xfff0f0f0, 0xfb00f010),
-       /* ???                  1111 1011 0111 xxxx 1111 xxxx 0001 xxxx */
-       DECODE_REJECT   (0xfff0f0f0, 0xfb70f010),
-
-       /* SMULxy               1111 1011 0001 xxxx 1111 xxxx 00xx xxxx */
-       DECODE_OR       (0xfff0f0c0, 0xfb10f000),
-       /* MUL                  1111 1011 0000 xxxx 1111 xxxx 0000 xxxx */
-       /* SMUAD{X}             1111 1011 0010 xxxx 1111 xxxx 000x xxxx */
-       /* SMULWy               1111 1011 0011 xxxx 1111 xxxx 000x xxxx */
-       /* SMUSD{X}             1111 1011 0100 xxxx 1111 xxxx 000x xxxx */
-       /* SMMUL{R}             1111 1011 0101 xxxx 1111 xxxx 000x xxxx */
-       /* USAD8                1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */
-       DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, PROBES_T32_MUL_ADD,
-                                                REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)),
-
-       /* ???                  1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */
-       DECODE_REJECT   (0xfff000f0, 0xfb700010),
-
-       /* SMLAxy               1111 1011 0001 xxxx xxxx xxxx 00xx xxxx */
-       DECODE_OR       (0xfff000c0, 0xfb100000),
-       /* MLA                  1111 1011 0000 xxxx xxxx xxxx 0000 xxxx */
-       /* MLS                  1111 1011 0000 xxxx xxxx xxxx 0001 xxxx */
-       /* SMLAD{X}             1111 1011 0010 xxxx xxxx xxxx 000x xxxx */
-       /* SMLAWy               1111 1011 0011 xxxx xxxx xxxx 000x xxxx */
-       /* SMLSD{X}             1111 1011 0100 xxxx xxxx xxxx 000x xxxx */
-       /* SMMLA{R}             1111 1011 0101 xxxx xxxx xxxx 000x xxxx */
-       /* SMMLS{R}             1111 1011 0110 xxxx xxxx xxxx 000x xxxx */
-       /* USADA8               1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */
-       DECODE_EMULATEX (0xff8000c0, 0xfb000000,  PROBES_T32_MUL_ADD2,
-                                                REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)),
-
-       /* Other unallocated instructions...                            */
-       DECODE_END
-};
-
-static const union decode_item t32_table_1111_1011_1[] = {
-       /* Long multiply, long multiply accumulate, and divide          */
-
-       /* UMAAL                1111 1011 1110 xxxx xxxx xxxx 0110 xxxx */
-       DECODE_OR       (0xfff000f0, 0xfbe00060),
-       /* SMLALxy              1111 1011 1100 xxxx xxxx xxxx 10xx xxxx */
-       DECODE_OR       (0xfff000c0, 0xfbc00080),
-       /* SMLALD{X}            1111 1011 1100 xxxx xxxx xxxx 110x xxxx */
-       /* SMLSLD{X}            1111 1011 1101 xxxx xxxx xxxx 110x xxxx */
-       DECODE_OR       (0xffe000e0, 0xfbc000c0),
-       /* SMULL                1111 1011 1000 xxxx xxxx xxxx 0000 xxxx */
-       /* UMULL                1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */
-       /* SMLAL                1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */
-       /* UMLAL                1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */
-       DECODE_EMULATEX (0xff9000f0, 0xfb800000, PROBES_T32_MUL_ADD_LONG,
-                                                REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)),
-
-       /* SDIV                 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */
-       /* UDIV                 1111 1011 1011 xxxx xxxx xxxx 1111 xxxx */
-       /* Other unallocated instructions...                            */
-       DECODE_END
-};
-
-const union decode_item probes_decode_thumb32_table[] = {
-
-       /*
-        * Load/store multiple instructions
-        *                      1110 100x x0xx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx),
-
-       /*
-        * Load/store dual, load/store exclusive, table branch
-        *                      1110 100x x1xx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx),
-
-       /*
-        * Data-processing (shifted register)
-        *                      1110 101x xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xfe000000, 0xea000000, t32_table_1110_101x),
-
-       /*
-        * Coprocessor instructions
-        *                      1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_REJECT   (0xfc000000, 0xec000000),
-
-       /*
-        * Data-processing (modified immediate)
-        *                      1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0),
-
-       /*
-        * Data-processing (plain binary immediate)
-        *                      1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0),
-
-       /*
-        * Branches and miscellaneous control
-        *                      1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1),
-
-       /*
-        * Advanced SIMD element or structure load/store instructions
-        *                      1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_REJECT   (0xff100000, 0xf9000000),
-
-       /*
-        * Memory hints
-        *                      1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111),
-
-       /*
-        * Store single data item
-        *                      1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx
-        * Load single data items
-        *                      1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xfe000000, 0xf8000000, t32_table_1111_100x),
-
-       /*
-        * Data-processing (register)
-        *                      1111 1010 xxxx xxxx 1111 xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xff00f000, 0xfa00f000, t32_table_1111_1010___1111),
-
-       /*
-        * Multiply, multiply accumulate, and absolute difference
-        *                      1111 1011 0xxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xff800000, 0xfb000000, t32_table_1111_1011_0),
-
-       /*
-        * Long multiply, long multiply accumulate, and divide
-        *                      1111 1011 1xxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xff800000, 0xfb800000, t32_table_1111_1011_1),
-
-       /*
-        * Coprocessor instructions
-        *                      1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx
-        */
-       DECODE_END
-};
-#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
-EXPORT_SYMBOL_GPL(probes_decode_thumb32_table);
-#endif
-
-static const union decode_item t16_table_1011[] = {
-       /* Miscellaneous 16-bit instructions                */
-
-       /* ADD (SP plus immediate)      1011 0000 0xxx xxxx */
-       /* SUB (SP minus immediate)     1011 0000 1xxx xxxx */
-       DECODE_SIMULATE (0xff00, 0xb000, PROBES_T16_ADD_SP),
-
-       /* CBZ                          1011 00x1 xxxx xxxx */
-       /* CBNZ                         1011 10x1 xxxx xxxx */
-       DECODE_SIMULATE (0xf500, 0xb100, PROBES_T16_CBZ),
-
-       /* SXTH                         1011 0010 00xx xxxx */
-       /* SXTB                         1011 0010 01xx xxxx */
-       /* UXTH                         1011 0010 10xx xxxx */
-       /* UXTB                         1011 0010 11xx xxxx */
-       /* REV                          1011 1010 00xx xxxx */
-       /* REV16                        1011 1010 01xx xxxx */
-       /* ???                          1011 1010 10xx xxxx */
-       /* REVSH                        1011 1010 11xx xxxx */
-       DECODE_REJECT   (0xffc0, 0xba80),
-       DECODE_EMULATE  (0xf500, 0xb000, PROBES_T16_SIGN_EXTEND),
-
-       /* PUSH                         1011 010x xxxx xxxx */
-       DECODE_CUSTOM   (0xfe00, 0xb400, PROBES_T16_PUSH),
-       /* POP                          1011 110x xxxx xxxx */
-       DECODE_CUSTOM   (0xfe00, 0xbc00, PROBES_T16_POP),
-
-       /*
-        * If-Then, and hints
-        *                              1011 1111 xxxx xxxx
-        */
-
-       /* YIELD                        1011 1111 0001 0000 */
-       DECODE_OR       (0xffff, 0xbf10),
-       /* SEV                          1011 1111 0100 0000 */
-       DECODE_EMULATE  (0xffff, 0xbf40, PROBES_T16_SEV),
-       /* NOP                          1011 1111 0000 0000 */
-       /* WFE                          1011 1111 0010 0000 */
-       /* WFI                          1011 1111 0011 0000 */
-       DECODE_SIMULATE (0xffcf, 0xbf00, PROBES_T16_WFE),
-       /* Unassigned hints             1011 1111 xxxx 0000 */
-       DECODE_REJECT   (0xff0f, 0xbf00),
-       /* IT                           1011 1111 xxxx xxxx */
-       DECODE_CUSTOM   (0xff00, 0xbf00, PROBES_T16_IT),
-
-       /* SETEND                       1011 0110 010x xxxx */
-       /* CPS                          1011 0110 011x xxxx */
-       /* BKPT                         1011 1110 xxxx xxxx */
-       /* And unallocated instructions...                  */
-       DECODE_END
-};
-
-const union decode_item probes_decode_thumb16_table[] = {
-
-       /*
-        * Shift (immediate), add, subtract, move, and compare
-        *                              00xx xxxx xxxx xxxx
-        */
-
-       /* CMP (immediate)              0010 1xxx xxxx xxxx */
-       DECODE_EMULATE  (0xf800, 0x2800, PROBES_T16_CMP),
-
-       /* ADD (register)               0001 100x xxxx xxxx */
-       /* SUB (register)               0001 101x xxxx xxxx */
-       /* LSL (immediate)              0000 0xxx xxxx xxxx */
-       /* LSR (immediate)              0000 1xxx xxxx xxxx */
-       /* ASR (immediate)              0001 0xxx xxxx xxxx */
-       /* ADD (immediate, Thumb)       0001 110x xxxx xxxx */
-       /* SUB (immediate, Thumb)       0001 111x xxxx xxxx */
-       /* MOV (immediate)              0010 0xxx xxxx xxxx */
-       /* ADD (immediate, Thumb)       0011 0xxx xxxx xxxx */
-       /* SUB (immediate, Thumb)       0011 1xxx xxxx xxxx */
-       DECODE_EMULATE  (0xc000, 0x0000, PROBES_T16_ADDSUB),
-
-       /*
-        * 16-bit Thumb data-processing instructions
-        *                              0100 00xx xxxx xxxx
-        */
-
-       /* TST (register)               0100 0010 00xx xxxx */
-       DECODE_EMULATE  (0xffc0, 0x4200, PROBES_T16_CMP),
-       /* CMP (register)               0100 0010 10xx xxxx */
-       /* CMN (register)               0100 0010 11xx xxxx */
-       DECODE_EMULATE  (0xff80, 0x4280, PROBES_T16_CMP),
-       /* AND (register)               0100 0000 00xx xxxx */
-       /* EOR (register)               0100 0000 01xx xxxx */
-       /* LSL (register)               0100 0000 10xx xxxx */
-       /* LSR (register)               0100 0000 11xx xxxx */
-       /* ASR (register)               0100 0001 00xx xxxx */
-       /* ADC (register)               0100 0001 01xx xxxx */
-       /* SBC (register)               0100 0001 10xx xxxx */
-       /* ROR (register)               0100 0001 11xx xxxx */
-       /* RSB (immediate)              0100 0010 01xx xxxx */
-       /* ORR (register)               0100 0011 00xx xxxx */
-       /* MUL                          0100 0011 00xx xxxx */
-       /* BIC (register)               0100 0011 10xx xxxx */
-       /* MVN (register)               0100 0011 10xx xxxx */
-       DECODE_EMULATE  (0xfc00, 0x4000, PROBES_T16_LOGICAL),
-
-       /*
-        * Special data instructions and branch and exchange
-        *                              0100 01xx xxxx xxxx
-        */
-
-       /* BLX pc                       0100 0111 1111 1xxx */
-       DECODE_REJECT   (0xfff8, 0x47f8),
-
-       /* BX (register)                0100 0111 0xxx xxxx */
-       /* BLX (register)               0100 0111 1xxx xxxx */
-       DECODE_SIMULATE (0xff00, 0x4700, PROBES_T16_BLX),
-
-       /* ADD pc, pc                   0100 0100 1111 1111 */
-       DECODE_REJECT   (0xffff, 0x44ff),
-
-       /* ADD (register)               0100 0100 xxxx xxxx */
-       /* CMP (register)               0100 0101 xxxx xxxx */
-       /* MOV (register)               0100 0110 xxxx xxxx */
-       DECODE_CUSTOM   (0xfc00, 0x4400, PROBES_T16_HIREGOPS),
-
-       /*
-        * Load from Literal Pool
-        * LDR (literal)                0100 1xxx xxxx xxxx
-        */
-       DECODE_SIMULATE (0xf800, 0x4800, PROBES_T16_LDR_LIT),
-
-       /*
-        * 16-bit Thumb Load/store instructions
-        *                              0101 xxxx xxxx xxxx
-        *                              011x xxxx xxxx xxxx
-        *                              100x xxxx xxxx xxxx
-        */
-
-       /* STR (register)               0101 000x xxxx xxxx */
-       /* STRH (register)              0101 001x xxxx xxxx */
-       /* STRB (register)              0101 010x xxxx xxxx */
-       /* LDRSB (register)             0101 011x xxxx xxxx */
-       /* LDR (register)               0101 100x xxxx xxxx */
-       /* LDRH (register)              0101 101x xxxx xxxx */
-       /* LDRB (register)              0101 110x xxxx xxxx */
-       /* LDRSH (register)             0101 111x xxxx xxxx */
-       /* STR (immediate, Thumb)       0110 0xxx xxxx xxxx */
-       /* LDR (immediate, Thumb)       0110 1xxx xxxx xxxx */
-       /* STRB (immediate, Thumb)      0111 0xxx xxxx xxxx */
-       /* LDRB (immediate, Thumb)      0111 1xxx xxxx xxxx */
-       DECODE_EMULATE  (0xc000, 0x4000, PROBES_T16_LDRHSTRH),
-       /* STRH (immediate, Thumb)      1000 0xxx xxxx xxxx */
-       /* LDRH (immediate, Thumb)      1000 1xxx xxxx xxxx */
-       DECODE_EMULATE  (0xf000, 0x8000, PROBES_T16_LDRHSTRH),
-       /* STR (immediate, Thumb)       1001 0xxx xxxx xxxx */
-       /* LDR (immediate, Thumb)       1001 1xxx xxxx xxxx */
-       DECODE_SIMULATE (0xf000, 0x9000, PROBES_T16_LDRSTR),
-
-       /*
-        * Generate PC-/SP-relative address
-        * ADR (literal)                1010 0xxx xxxx xxxx
-        * ADD (SP plus immediate)      1010 1xxx xxxx xxxx
-        */
-       DECODE_SIMULATE (0xf000, 0xa000, PROBES_T16_ADR),
-
-       /*
-        * Miscellaneous 16-bit instructions
-        *                              1011 xxxx xxxx xxxx
-        */
-       DECODE_TABLE    (0xf000, 0xb000, t16_table_1011),
-
-       /* STM                          1100 0xxx xxxx xxxx */
-       /* LDM                          1100 1xxx xxxx xxxx */
-       DECODE_EMULATE  (0xf000, 0xc000, PROBES_T16_LDMSTM),
-
-       /*
-        * Conditional branch, and Supervisor Call
-        */
-
-       /* Permanently UNDEFINED        1101 1110 xxxx xxxx */
-       /* SVC                          1101 1111 xxxx xxxx */
-       DECODE_REJECT   (0xfe00, 0xde00),
-
-       /* Conditional branch           1101 xxxx xxxx xxxx */
-       DECODE_CUSTOM   (0xf000, 0xd000, PROBES_T16_BRANCH_COND),
-
-       /*
-        * Unconditional branch
-        * B                            1110 0xxx xxxx xxxx
-        */
-       DECODE_SIMULATE (0xf800, 0xe000, PROBES_T16_BRANCH),
-
-       DECODE_END
-};
-#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
-EXPORT_SYMBOL_GPL(probes_decode_thumb16_table);
-#endif
-
-static unsigned long __kprobes thumb_check_cc(unsigned long cpsr)
-{
-       if (unlikely(in_it_block(cpsr)))
-               return probes_condition_checks[current_cond(cpsr)](cpsr);
-       return true;
-}
-
-static void __kprobes thumb16_singlestep(probes_opcode_t opcode,
-               struct arch_probes_insn *asi,
-               struct pt_regs *regs)
-{
-       regs->ARM_pc += 2;
-       asi->insn_handler(opcode, asi, regs);
-       regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
-}
-
-static void __kprobes thumb32_singlestep(probes_opcode_t opcode,
-               struct arch_probes_insn *asi,
-               struct pt_regs *regs)
-{
-       regs->ARM_pc += 4;
-       asi->insn_handler(opcode, asi, regs);
-       regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
-}
-
-enum probes_insn __kprobes
-thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
-                          bool emulate, const union decode_action *actions)
-{
-       asi->insn_singlestep = thumb16_singlestep;
-       asi->insn_check_cc = thumb_check_cc;
-       return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true,
-                                 emulate, actions);
-}
-
-enum probes_insn __kprobes
-thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
-                          bool emulate, const union decode_action *actions)
-{
-       asi->insn_singlestep = thumb32_singlestep;
-       asi->insn_check_cc = thumb_check_cc;
-       return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true,
-                                 emulate, actions);
-}
diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h
deleted file mode 100644 (file)
index 7c6f6eb..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * arch/arm/kernel/probes-thumb.h
- *
- * Copyright 2013 Linaro Ltd.
- * Written by: David A. Long
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef _ARM_KERNEL_PROBES_THUMB_H
-#define  _ARM_KERNEL_PROBES_THUMB_H
-
-/*
- * True if current instruction is in an IT block.
- */
-#define in_it_block(cpsr)      ((cpsr & 0x06000c00) != 0x00000000)
-
-/*
- * Return the condition code to check for the currently executing instruction.
- * This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if
- * in_it_block returns true.
- */
-#define current_cond(cpsr)     ((cpsr >> 12) & 0xf)
-
-enum probes_t32_action {
-       PROBES_T32_EMULATE_NONE,
-       PROBES_T32_SIMULATE_NOP,
-       PROBES_T32_LDMSTM,
-       PROBES_T32_LDRDSTRD,
-       PROBES_T32_TABLE_BRANCH,
-       PROBES_T32_TST,
-       PROBES_T32_CMP,
-       PROBES_T32_MOV,
-       PROBES_T32_ADDSUB,
-       PROBES_T32_LOGICAL,
-       PROBES_T32_ADDWSUBW_PC,
-       PROBES_T32_ADDWSUBW,
-       PROBES_T32_MOVW,
-       PROBES_T32_SAT,
-       PROBES_T32_BITFIELD,
-       PROBES_T32_SEV,
-       PROBES_T32_WFE,
-       PROBES_T32_MRS,
-       PROBES_T32_BRANCH_COND,
-       PROBES_T32_BRANCH,
-       PROBES_T32_PLDI,
-       PROBES_T32_LDR_LIT,
-       PROBES_T32_LDRSTR,
-       PROBES_T32_SIGN_EXTEND,
-       PROBES_T32_MEDIA,
-       PROBES_T32_REVERSE,
-       PROBES_T32_MUL_ADD,
-       PROBES_T32_MUL_ADD2,
-       PROBES_T32_MUL_ADD_LONG,
-       NUM_PROBES_T32_ACTIONS
-};
-
-enum probes_t16_action {
-       PROBES_T16_ADD_SP,
-       PROBES_T16_CBZ,
-       PROBES_T16_SIGN_EXTEND,
-       PROBES_T16_PUSH,
-       PROBES_T16_POP,
-       PROBES_T16_SEV,
-       PROBES_T16_WFE,
-       PROBES_T16_IT,
-       PROBES_T16_CMP,
-       PROBES_T16_ADDSUB,
-       PROBES_T16_LOGICAL,
-       PROBES_T16_BLX,
-       PROBES_T16_HIREGOPS,
-       PROBES_T16_LDR_LIT,
-       PROBES_T16_LDRHSTRH,
-       PROBES_T16_LDRSTR,
-       PROBES_T16_ADR,
-       PROBES_T16_LDMSTM,
-       PROBES_T16_BRANCH_COND,
-       PROBES_T16_BRANCH,
-       NUM_PROBES_T16_ACTIONS
-};
-
-extern const union decode_item probes_decode_thumb32_table[];
-extern const union decode_item probes_decode_thumb16_table[];
-
-enum probes_insn __kprobes
-thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
-               bool emulate, const union decode_action *actions);
-enum probes_insn __kprobes
-thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
-               bool emulate, const union decode_action *actions);
-
-#endif
diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c
deleted file mode 100644 (file)
index a8ab540..0000000
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * arch/arm/kernel/probes.c
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
- * Copyright (C) 2006, 2007 Motorola Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/system_info.h>
-#include <asm/ptrace.h>
-#include <linux/bug.h>
-
-#include "probes.h"
-
-
-#ifndef find_str_pc_offset
-
-/*
- * For STR and STM instructions, an ARM core may choose to use either
- * a +8 or a +12 displacement from the current instruction's address.
- * Whichever value is chosen for a given core, it must be the same for
- * both instructions and may not change.  This function measures it.
- */
-
-int str_pc_offset;
-
-void __init find_str_pc_offset(void)
-{
-       int addr, scratch, ret;
-
-       __asm__ (
-               "sub    %[ret], pc, #4          \n\t"
-               "str    pc, %[addr]             \n\t"
-               "ldr    %[scr], %[addr]         \n\t"
-               "sub    %[ret], %[scr], %[ret]  \n\t"
-               : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr));
-
-       str_pc_offset = ret;
-}
-
-#endif /* !find_str_pc_offset */
-
-
-#ifndef test_load_write_pc_interworking
-
-bool load_write_pc_interworks;
-
-void __init test_load_write_pc_interworking(void)
-{
-       int arch = cpu_architecture();
-       BUG_ON(arch == CPU_ARCH_UNKNOWN);
-       load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T;
-}
-
-#endif /* !test_load_write_pc_interworking */
-
-
-#ifndef test_alu_write_pc_interworking
-
-bool alu_write_pc_interworks;
-
-void __init test_alu_write_pc_interworking(void)
-{
-       int arch = cpu_architecture();
-       BUG_ON(arch == CPU_ARCH_UNKNOWN);
-       alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7;
-}
-
-#endif /* !test_alu_write_pc_interworking */
-
-
-void __init arm_probes_decode_init(void)
-{
-       find_str_pc_offset();
-       test_load_write_pc_interworking();
-       test_alu_write_pc_interworking();
-}
-
-
-static unsigned long __kprobes __check_eq(unsigned long cpsr)
-{
-       return cpsr & PSR_Z_BIT;
-}
-
-static unsigned long __kprobes __check_ne(unsigned long cpsr)
-{
-       return (~cpsr) & PSR_Z_BIT;
-}
-
-static unsigned long __kprobes __check_cs(unsigned long cpsr)
-{
-       return cpsr & PSR_C_BIT;
-}
-
-static unsigned long __kprobes __check_cc(unsigned long cpsr)
-{
-       return (~cpsr) & PSR_C_BIT;
-}
-
-static unsigned long __kprobes __check_mi(unsigned long cpsr)
-{
-       return cpsr & PSR_N_BIT;
-}
-
-static unsigned long __kprobes __check_pl(unsigned long cpsr)
-{
-       return (~cpsr) & PSR_N_BIT;
-}
-
-static unsigned long __kprobes __check_vs(unsigned long cpsr)
-{
-       return cpsr & PSR_V_BIT;
-}
-
-static unsigned long __kprobes __check_vc(unsigned long cpsr)
-{
-       return (~cpsr) & PSR_V_BIT;
-}
-
-static unsigned long __kprobes __check_hi(unsigned long cpsr)
-{
-       cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
-       return cpsr & PSR_C_BIT;
-}
-
-static unsigned long __kprobes __check_ls(unsigned long cpsr)
-{
-       cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
-       return (~cpsr) & PSR_C_BIT;
-}
-
-static unsigned long __kprobes __check_ge(unsigned long cpsr)
-{
-       cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
-       return (~cpsr) & PSR_N_BIT;
-}
-
-static unsigned long __kprobes __check_lt(unsigned long cpsr)
-{
-       cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
-       return cpsr & PSR_N_BIT;
-}
-
-static unsigned long __kprobes __check_gt(unsigned long cpsr)
-{
-       unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
-       temp |= (cpsr << 1);                     /* PSR_N_BIT |= PSR_Z_BIT */
-       return (~temp) & PSR_N_BIT;
-}
-
-static unsigned long __kprobes __check_le(unsigned long cpsr)
-{
-       unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
-       temp |= (cpsr << 1);                     /* PSR_N_BIT |= PSR_Z_BIT */
-       return temp & PSR_N_BIT;
-}
-
-static unsigned long __kprobes __check_al(unsigned long cpsr)
-{
-       return true;
-}
-
-probes_check_cc * const probes_condition_checks[16] = {
-       &__check_eq, &__check_ne, &__check_cs, &__check_cc,
-       &__check_mi, &__check_pl, &__check_vs, &__check_vc,
-       &__check_hi, &__check_ls, &__check_ge, &__check_lt,
-       &__check_gt, &__check_le, &__check_al, &__check_al
-};
-
-
-void __kprobes probes_simulate_nop(probes_opcode_t opcode,
-       struct arch_probes_insn *asi,
-       struct pt_regs *regs)
-{
-}
-
-void __kprobes probes_emulate_none(probes_opcode_t opcode,
-       struct arch_probes_insn *asi,
-       struct pt_regs *regs)
-{
-       asi->insn_fn();
-}
-
-/*
- * Prepare an instruction slot to receive an instruction for emulating.
- * This is done by placing a subroutine return after the location where the
- * instruction will be placed. We also modify ARM instructions to be
- * unconditional as the condition code will already be checked before any
- * emulation handler is called.
- */
-static probes_opcode_t __kprobes
-prepare_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
-                     bool thumb)
-{
-#ifdef CONFIG_THUMB2_KERNEL
-       if (thumb) {
-               u16 *thumb_insn = (u16 *)asi->insn;
-               /* Thumb bx lr */
-               thumb_insn[1] = __opcode_to_mem_thumb16(0x4770);
-               thumb_insn[2] = __opcode_to_mem_thumb16(0x4770);
-               return insn;
-       }
-       asi->insn[1] = __opcode_to_mem_arm(0xe12fff1e); /* ARM bx lr */
-#else
-       asi->insn[1] = __opcode_to_mem_arm(0xe1a0f00e); /* mov pc, lr */
-#endif
-       /* Make an ARM instruction unconditional */
-       if (insn < 0xe0000000)
-               insn = (insn | 0xe0000000) & ~0x10000000;
-       return insn;
-}
-
-/*
- * Write a (probably modified) instruction into the slot previously prepared by
- * prepare_emulated_insn
- */
-static void  __kprobes
-set_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
-                 bool thumb)
-{
-#ifdef CONFIG_THUMB2_KERNEL
-       if (thumb) {
-               u16 *ip = (u16 *)asi->insn;
-               if (is_wide_instruction(insn))
-                       *ip++ = __opcode_to_mem_thumb16(insn >> 16);
-               *ip++ = __opcode_to_mem_thumb16(insn);
-               return;
-       }
-#endif
-       asi->insn[0] = __opcode_to_mem_arm(insn);
-}
-
-/*
- * When we modify the register numbers encoded in an instruction to be emulated,
- * the new values come from this define. For ARM and 32-bit Thumb instructions
- * this gives...
- *
- *     bit position      16  12   8   4   0
- *     ---------------+---+---+---+---+---+
- *     register         r2  r0  r1  --  r3
- */
-#define INSN_NEW_BITS          0x00020103
-
-/* Each nibble has same value as that at INSN_NEW_BITS bit 16 */
-#define INSN_SAMEAS16_BITS     0x22222222
-
-/*
- * Validate and modify each of the registers encoded in an instruction.
- *
- * Each nibble in regs contains a value from enum decode_reg_type. For each
- * non-zero value, the corresponding nibble in pinsn is validated and modified
- * according to the type.
- */
-static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs, bool modify)
-{
-       probes_opcode_t insn = *pinsn;
-       probes_opcode_t mask = 0xf; /* Start at least significant nibble */
-
-       for (; regs != 0; regs >>= 4, mask <<= 4) {
-
-               probes_opcode_t new_bits = INSN_NEW_BITS;
-
-               switch (regs & 0xf) {
-
-               case REG_TYPE_NONE:
-                       /* Nibble not a register, skip to next */
-                       continue;
-
-               case REG_TYPE_ANY:
-                       /* Any register is allowed */
-                       break;
-
-               case REG_TYPE_SAMEAS16:
-                       /* Replace register with same as at bit position 16 */
-                       new_bits = INSN_SAMEAS16_BITS;
-                       break;
-
-               case REG_TYPE_SP:
-                       /* Only allow SP (R13) */
-                       if ((insn ^ 0xdddddddd) & mask)
-                               goto reject;
-                       break;
-
-               case REG_TYPE_PC:
-                       /* Only allow PC (R15) */
-                       if ((insn ^ 0xffffffff) & mask)
-                               goto reject;
-                       break;
-
-               case REG_TYPE_NOSP:
-                       /* Reject SP (R13) */
-                       if (((insn ^ 0xdddddddd) & mask) == 0)
-                               goto reject;
-                       break;
-
-               case REG_TYPE_NOSPPC:
-               case REG_TYPE_NOSPPCX:
-                       /* Reject SP and PC (R13 and R15) */
-                       if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0)
-                               goto reject;
-                       break;
-
-               case REG_TYPE_NOPCWB:
-                       if (!is_writeback(insn))
-                               break; /* No writeback, so any register is OK */
-                       /* fall through... */
-               case REG_TYPE_NOPC:
-               case REG_TYPE_NOPCX:
-                       /* Reject PC (R15) */
-                       if (((insn ^ 0xffffffff) & mask) == 0)
-                               goto reject;
-                       break;
-               }
-
-               /* Replace value of nibble with new register number... */
-               insn &= ~mask;
-               insn |= new_bits & mask;
-       }
-
-       if (modify)
-               *pinsn = insn;
-
-       return true;
-
-reject:
-       return false;
-}
-
-static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
-       [DECODE_TYPE_TABLE]     = sizeof(struct decode_table),
-       [DECODE_TYPE_CUSTOM]    = sizeof(struct decode_custom),
-       [DECODE_TYPE_SIMULATE]  = sizeof(struct decode_simulate),
-       [DECODE_TYPE_EMULATE]   = sizeof(struct decode_emulate),
-       [DECODE_TYPE_OR]        = sizeof(struct decode_or),
-       [DECODE_TYPE_REJECT]    = sizeof(struct decode_reject)
-};
-
-/*
- * probes_decode_insn operates on data tables in order to decode an ARM
- * architecture instruction onto which a kprobe has been placed.
- *
- * These instruction decoding tables are a concatenation of entries each
- * of which consist of one of the following structs:
- *
- *     decode_table
- *     decode_custom
- *     decode_simulate
- *     decode_emulate
- *     decode_or
- *     decode_reject
- *
- * Each of these starts with a struct decode_header which has the following
- * fields:
- *
- *     type_regs
- *     mask
- *     value
- *
- * The least significant DECODE_TYPE_BITS of type_regs contains a value
- * from enum decode_type, this indicates which of the decode_* structs
- * the entry contains. The value DECODE_TYPE_END indicates the end of the
- * table.
- *
- * When the table is parsed, each entry is checked in turn to see if it
- * matches the instruction to be decoded using the test:
- *
- *     (insn & mask) == value
- *
- * If no match is found before the end of the table is reached then decoding
- * fails with INSN_REJECTED.
- *
- * When a match is found, decode_regs() is called to validate and modify each
- * of the registers encoded in the instruction; the data it uses to do this
- * is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding
- * to fail with INSN_REJECTED.
- *
- * Once the instruction has passed the above tests, further processing
- * depends on the type of the table entry's decode struct.
- *
- */
-int __kprobes
-probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
-                  const union decode_item *table, bool thumb,
-                  bool emulate, const union decode_action *actions)
-{
-       const struct decode_header *h = (struct decode_header *)table;
-       const struct decode_header *next;
-       bool matched = false;
-
-       if (emulate)
-               insn = prepare_emulated_insn(insn, asi, thumb);
-
-       for (;; h = next) {
-               enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
-               u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
-
-               if (type == DECODE_TYPE_END)
-                       return INSN_REJECTED;
-
-               next = (struct decode_header *)
-                               ((uintptr_t)h + decode_struct_sizes[type]);
-
-               if (!matched && (insn & h->mask.bits) != h->value.bits)
-                       continue;
-
-               if (!decode_regs(&insn, regs, emulate))
-                       return INSN_REJECTED;
-
-               switch (type) {
-
-               case DECODE_TYPE_TABLE: {
-                       struct decode_table *d = (struct decode_table *)h;
-                       next = (struct decode_header *)d->table.table;
-                       break;
-               }
-
-               case DECODE_TYPE_CUSTOM: {
-                       struct decode_custom *d = (struct decode_custom *)h;
-                       return actions[d->decoder.action].decoder(insn, asi, h);
-               }
-
-               case DECODE_TYPE_SIMULATE: {
-                       struct decode_simulate *d = (struct decode_simulate *)h;
-                       asi->insn_handler = actions[d->handler.action].handler;
-                       return INSN_GOOD_NO_SLOT;
-               }
-
-               case DECODE_TYPE_EMULATE: {
-                       struct decode_emulate *d = (struct decode_emulate *)h;
-
-                       if (!emulate)
-                               return actions[d->handler.action].decoder(insn,
-                                       asi, h);
-
-                       asi->insn_handler = actions[d->handler.action].handler;
-                       set_emulated_insn(insn, asi, thumb);
-                       return INSN_GOOD;
-               }
-
-               case DECODE_TYPE_OR:
-                       matched = true;
-                       break;
-
-               case DECODE_TYPE_REJECT:
-               default:
-                       return INSN_REJECTED;
-               }
-       }
-}
diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h
deleted file mode 100644 (file)
index dba9f24..0000000
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * arch/arm/kernel/probes.h
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * Some contents moved here from arch/arm/include/asm/kprobes.h which is
- * Copyright (C) 2006, 2007 Motorola Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#ifndef _ARM_KERNEL_PROBES_H
-#define  _ARM_KERNEL_PROBES_H
-
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <asm/probes.h>
-
-void __init arm_probes_decode_init(void);
-
-extern probes_check_cc * const probes_condition_checks[16];
-
-#if __LINUX_ARM_ARCH__ >= 7
-
-/* str_pc_offset is architecturally defined from ARMv7 onwards */
-#define str_pc_offset 8
-#define find_str_pc_offset()
-
-#else /* __LINUX_ARM_ARCH__ < 7 */
-
-/* We need a run-time check to determine str_pc_offset */
-extern int str_pc_offset;
-void __init find_str_pc_offset(void);
-
-#endif
-
-
-/*
- * Update ITSTATE after normal execution of an IT block instruction.
- *
- * The 8 IT state bits are split into two parts in CPSR:
- *     ITSTATE<1:0> are in CPSR<26:25>
- *     ITSTATE<7:2> are in CPSR<15:10>
- */
-static inline unsigned long it_advance(unsigned long cpsr)
-       {
-       if ((cpsr & 0x06000400) == 0) {
-               /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
-               cpsr &= ~PSR_IT_MASK;
-       } else {
-               /* We need to shift left ITSTATE<4:0> */
-               const unsigned long mask = 0x06001c00;  /* Mask ITSTATE<4:0> */
-               unsigned long it = cpsr & mask;
-               it <<= 1;
-               it |= it >> (27 - 10);  /* Carry ITSTATE<2> to correct place */
-               it &= mask;
-               cpsr &= ~mask;
-               cpsr |= it;
-       }
-       return cpsr;
-}
-
-static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs)
-{
-       long cpsr = regs->ARM_cpsr;
-       if (pcv & 0x1) {
-               cpsr |= PSR_T_BIT;
-               pcv &= ~0x1;
-       } else {
-               cpsr &= ~PSR_T_BIT;
-               pcv &= ~0x2;    /* Avoid UNPREDICTABLE address allignment */
-       }
-       regs->ARM_cpsr = cpsr;
-       regs->ARM_pc = pcv;
-}
-
-
-#if __LINUX_ARM_ARCH__ >= 6
-
-/* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */
-#define load_write_pc_interworks true
-#define test_load_write_pc_interworking()
-
-#else /* __LINUX_ARM_ARCH__ < 6 */
-
-/* We need run-time testing to determine if load_write_pc() should interwork. */
-extern bool load_write_pc_interworks;
-void __init test_load_write_pc_interworking(void);
-
-#endif
-
-static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs)
-{
-       if (load_write_pc_interworks)
-               bx_write_pc(pcv, regs);
-       else
-               regs->ARM_pc = pcv;
-}
-
-
-#if __LINUX_ARM_ARCH__ >= 7
-
-#define alu_write_pc_interworks true
-#define test_alu_write_pc_interworking()
-
-#elif __LINUX_ARM_ARCH__ <= 5
-
-/* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */
-#define alu_write_pc_interworks false
-#define test_alu_write_pc_interworking()
-
-#else /* __LINUX_ARM_ARCH__ == 6 */
-
-/* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */
-extern bool alu_write_pc_interworks;
-void __init test_alu_write_pc_interworking(void);
-
-#endif /* __LINUX_ARM_ARCH__ == 6 */
-
-static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs)
-{
-       if (alu_write_pc_interworks)
-               bx_write_pc(pcv, regs);
-       else
-               regs->ARM_pc = pcv;
-}
-
-
-/*
- * Test if load/store instructions writeback the address register.
- * if P (bit 24) == 0 or W (bit 21) == 1
- */
-#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000)
-
-/*
- * The following definitions and macros are used to build instruction
- * decoding tables for use by probes_decode_insn.
- *
- * These tables are a concatenation of entries each of which consist of one of
- * the decode_* structs. All of the fields in every type of decode structure
- * are of the union type decode_item, therefore the entire decode table can be
- * viewed as an array of these and declared like:
- *
- *     static const union decode_item table_name[] = {};
- *
- * In order to construct each entry in the table, macros are used to
- * initialise a number of sequential decode_item values in a layout which
- * matches the relevant struct. E.g. DECODE_SIMULATE initialise a struct
- * decode_simulate by initialising four decode_item objects like this...
- *
- *     {.bits = _type},
- *     {.bits = _mask},
- *     {.bits = _value},
- *     {.action = _handler},
- *
- * Initialising a specified member of the union means that the compiler
- * will produce a warning if the argument is of an incorrect type.
- *
- * Below is a list of each of the macros used to initialise entries and a
- * description of the action performed when that entry is matched to an
- * instruction. A match is found when (instruction & mask) == value.
- *
- * DECODE_TABLE(mask, value, table)
- *     Instruction decoding jumps to parsing the new sub-table 'table'.
- *
- * DECODE_CUSTOM(mask, value, decoder)
- *     The value of 'decoder' is used as an index into the array of
- *     action functions, and the retrieved decoder function is invoked
- *     to complete decoding of the instruction.
- *
- * DECODE_SIMULATE(mask, value, handler)
- *     The probes instruction handler is set to the value found by
- *     indexing into the action array using the value of 'handler'. This
- *     will be used to simulate the instruction when the probe is hit.
- *     Decoding returns with INSN_GOOD_NO_SLOT.
- *
- * DECODE_EMULATE(mask, value, handler)
- *     The probes instruction handler is set to the value found by
- *     indexing into the action array using the value of 'handler'. This
- *     will be used to emulate the instruction when the probe is hit. The
- *     modified instruction (see below) is placed in the probes instruction
- *     slot so it may be called by the emulation code. Decoding returns
- *     with INSN_GOOD.
- *
- * DECODE_REJECT(mask, value)
- *     Instruction decoding fails with INSN_REJECTED
- *
- * DECODE_OR(mask, value)
- *     This allows the mask/value test of multiple table entries to be
- *     logically ORed. Once an 'or' entry is matched the decoding action to
- *     be performed is that of the next entry which isn't an 'or'. E.g.
- *
- *             DECODE_OR       (mask1, value1)
- *             DECODE_OR       (mask2, value2)
- *             DECODE_SIMULATE (mask3, value3, simulation_handler)
- *
- *     This means that if any of the three mask/value pairs match the
- *     instruction being decoded, then 'simulation_handler' will be used
- *     for it.
- *
- * Both the SIMULATE and EMULATE macros have a second form which take an
- * additional 'regs' argument.
- *
- *     DECODE_SIMULATEX(mask, value, handler, regs)
- *     DECODE_EMULATEX (mask, value, handler, regs)
- *
- * These are used to specify what kind of CPU register is encoded in each of the
- * least significant 5 nibbles of the instruction being decoded. The regs value
- * is specified using the REGS macro, this takes any of the REG_TYPE_* values
- * from enum decode_reg_type as arguments; only the '*' part of the name is
- * given. E.g.
- *
- *     REGS(0, ANY, NOPC, 0, ANY)
- *
- * This indicates an instruction is encoded like:
- *
- *     bits 19..16     ignore
- *     bits 15..12     any register allowed here
- *     bits 11.. 8     any register except PC allowed here
- *     bits  7.. 4     ignore
- *     bits  3.. 0     any register allowed here
- *
- * This register specification is checked after a decode table entry is found to
- * match an instruction (through the mask/value test). Any invalid register then
- * found in the instruction will cause decoding to fail with INSN_REJECTED. In
- * the above example this would happen if bits 11..8 of the instruction were
- * 1111, indicating R15 or PC.
- *
- * As well as checking for legal combinations of registers, this data is also
- * used to modify the registers encoded in the instructions so that an
- * emulation routines can use it. (See decode_regs() and INSN_NEW_BITS.)
- *
- * Here is a real example which matches ARM instructions of the form
- * "AND <Rd>,<Rn>,<Rm>,<shift> <Rs>"
- *
- *     DECODE_EMULATEX (0x0e000090, 0x00000010, PROBES_DATA_PROCESSING_REG,
- *                                              REGS(ANY, ANY, NOPC, 0, ANY)),
- *                                                   ^    ^    ^        ^
- *                                                   Rn   Rd   Rs       Rm
- *
- * Decoding the instruction "AND R4, R5, R6, ASL R15" will be rejected because
- * Rs == R15
- *
- * Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the
- * instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into
- * the kprobes instruction slot. This can then be called later by the handler
- * function emulate_rd12rn16rm0rs8_rwflags (a pointer to which is retrieved from
- * the indicated slot in the action array), in order to simulate the instruction.
- */
-
-enum decode_type {
-       DECODE_TYPE_END,
-       DECODE_TYPE_TABLE,
-       DECODE_TYPE_CUSTOM,
-       DECODE_TYPE_SIMULATE,
-       DECODE_TYPE_EMULATE,
-       DECODE_TYPE_OR,
-       DECODE_TYPE_REJECT,
-       NUM_DECODE_TYPES /* Must be last enum */
-};
-
-#define DECODE_TYPE_BITS       4
-#define DECODE_TYPE_MASK       ((1 << DECODE_TYPE_BITS) - 1)
-
-enum decode_reg_type {
-       REG_TYPE_NONE = 0, /* Not a register, ignore */
-       REG_TYPE_ANY,      /* Any register allowed */
-       REG_TYPE_SAMEAS16, /* Register should be same as that at bits 19..16 */
-       REG_TYPE_SP,       /* Register must be SP */
-       REG_TYPE_PC,       /* Register must be PC */
-       REG_TYPE_NOSP,     /* Register must not be SP */
-       REG_TYPE_NOSPPC,   /* Register must not be SP or PC */
-       REG_TYPE_NOPC,     /* Register must not be PC */
-       REG_TYPE_NOPCWB,   /* No PC if load/store write-back flag also set */
-
-       /* The following types are used when the encoding for PC indicates
-        * another instruction form. This distiction only matters for test
-        * case coverage checks.
-        */
-       REG_TYPE_NOPCX,    /* Register must not be PC */
-       REG_TYPE_NOSPPCX,  /* Register must not be SP or PC */
-
-       /* Alias to allow '0' arg to be used in REGS macro. */
-       REG_TYPE_0 = REG_TYPE_NONE
-};
-
-#define REGS(r16, r12, r8, r4, r0)     \
-       (((REG_TYPE_##r16) << 16) +     \
-       ((REG_TYPE_##r12) << 12) +      \
-       ((REG_TYPE_##r8) << 8) +        \
-       ((REG_TYPE_##r4) << 4) +        \
-       (REG_TYPE_##r0))
-
-union decode_item {
-       u32                     bits;
-       const union decode_item *table;
-       int                     action;
-};
-
-struct decode_header;
-typedef enum probes_insn (probes_custom_decode_t)(probes_opcode_t,
-                                                 struct arch_probes_insn *,
-                                                 const struct decode_header *);
-
-union decode_action {
-       probes_insn_handler_t   *handler;
-       probes_custom_decode_t  *decoder;
-};
-
-#define DECODE_END                     \
-       {.bits = DECODE_TYPE_END}
-
-
-struct decode_header {
-       union decode_item       type_regs;
-       union decode_item       mask;
-       union decode_item       value;
-};
-
-#define DECODE_HEADER(_type, _mask, _value, _regs)             \
-       {.bits = (_type) | ((_regs) << DECODE_TYPE_BITS)},      \
-       {.bits = (_mask)},                                      \
-       {.bits = (_value)}
-
-
-struct decode_table {
-       struct decode_header    header;
-       union decode_item       table;
-};
-
-#define DECODE_TABLE(_mask, _value, _table)                    \
-       DECODE_HEADER(DECODE_TYPE_TABLE, _mask, _value, 0),     \
-       {.table = (_table)}
-
-
-struct decode_custom {
-       struct decode_header    header;
-       union decode_item       decoder;
-};
-
-#define DECODE_CUSTOM(_mask, _value, _decoder)                 \
-       DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0),    \
-       {.action = (_decoder)}
-
-
-struct decode_simulate {
-       struct decode_header    header;
-       union decode_item       handler;
-};
-
-#define DECODE_SIMULATEX(_mask, _value, _handler, _regs)               \
-       DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs),      \
-       {.action = (_handler)}
-
-#define DECODE_SIMULATE(_mask, _value, _handler)       \
-       DECODE_SIMULATEX(_mask, _value, _handler, 0)
-
-
-struct decode_emulate {
-       struct decode_header    header;
-       union decode_item       handler;
-};
-
-#define DECODE_EMULATEX(_mask, _value, _handler, _regs)                        \
-       DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs),       \
-       {.action = (_handler)}
-
-#define DECODE_EMULATE(_mask, _value, _handler)                \
-       DECODE_EMULATEX(_mask, _value, _handler, 0)
-
-
-struct decode_or {
-       struct decode_header    header;
-};
-
-#define DECODE_OR(_mask, _value)                               \
-       DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0)
-
-enum probes_insn {
-       INSN_REJECTED,
-       INSN_GOOD,
-       INSN_GOOD_NO_SLOT
-};
-
-struct decode_reject {
-       struct decode_header    header;
-};
-
-#define DECODE_REJECT(_mask, _value)                           \
-       DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0)
-
-probes_insn_handler_t probes_simulate_nop;
-probes_insn_handler_t probes_emulate_none;
-
-int __kprobes
-probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
-               const union decode_item *table, bool thumb, bool emulate,
-               const union decode_action *actions);
-
-#endif
diff --git a/arch/arm/kernel/uprobes-arm.c b/arch/arm/kernel/uprobes-arm.c
deleted file mode 100644 (file)
index d3b655f..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/wait.h>
-#include <linux/uprobes.h>
-#include <linux/module.h>
-
-#include "probes.h"
-#include "probes-arm.h"
-#include "uprobes.h"
-
-static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs)
-{
-       probes_opcode_t insn = __mem_to_opcode_arm(*pinsn);
-       probes_opcode_t temp;
-       probes_opcode_t mask;
-       int freereg;
-       u32 free = 0xffff;
-       u32 regs;
-
-       for (regs = oregs; regs; regs >>= 4, insn >>= 4) {
-               if ((regs & 0xf) == REG_TYPE_NONE)
-                       continue;
-
-               free &= ~(1 << (insn & 0xf));
-       }
-
-       /* No PC, no problem */
-       if (free & (1 << 15))
-               return 15;
-
-       if (!free)
-               return -1;
-
-       /*
-        * fls instead of ffs ensures that for "ldrd r0, r1, [pc]" we would
-        * pick LR instead of R1.
-        */
-       freereg = free = fls(free) - 1;
-
-       temp = __mem_to_opcode_arm(*pinsn);
-       insn = temp;
-       regs = oregs;
-       mask = 0xf;
-
-       for (; regs; regs >>= 4, mask <<= 4, free <<= 4, temp >>= 4) {
-               if ((regs & 0xf) == REG_TYPE_NONE)
-                       continue;
-
-               if ((temp & 0xf) != 15)
-                       continue;
-
-               insn &= ~mask;
-               insn |= free & mask;
-       }
-
-       *pinsn = __opcode_to_mem_arm(insn);
-       return freereg;
-}
-
-static void uprobe_set_pc(struct arch_uprobe *auprobe,
-                         struct arch_uprobe_task *autask,
-                         struct pt_regs *regs)
-{
-       u32 pcreg = auprobe->pcreg;
-
-       autask->backup = regs->uregs[pcreg];
-       regs->uregs[pcreg] = regs->ARM_pc + 8;
-}
-
-static void uprobe_unset_pc(struct arch_uprobe *auprobe,
-                           struct arch_uprobe_task *autask,
-                           struct pt_regs *regs)
-{
-       /* PC will be taken care of by common code */
-       regs->uregs[auprobe->pcreg] = autask->backup;
-}
-
-static void uprobe_aluwrite_pc(struct arch_uprobe *auprobe,
-                              struct arch_uprobe_task *autask,
-                              struct pt_regs *regs)
-{
-       u32 pcreg = auprobe->pcreg;
-
-       alu_write_pc(regs->uregs[pcreg], regs);
-       regs->uregs[pcreg] = autask->backup;
-}
-
-static void uprobe_write_pc(struct arch_uprobe *auprobe,
-                           struct arch_uprobe_task *autask,
-                           struct pt_regs *regs)
-{
-       u32 pcreg = auprobe->pcreg;
-
-       load_write_pc(regs->uregs[pcreg], regs);
-       regs->uregs[pcreg] = autask->backup;
-}
-
-enum probes_insn
-decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi,
-            const struct decode_header *d)
-{
-       struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
-                                                  asi);
-       struct decode_emulate *decode = (struct decode_emulate *) d;
-       u32 regs = decode->header.type_regs.bits >> DECODE_TYPE_BITS;
-       int reg;
-
-       reg = uprobes_substitute_pc(&auprobe->ixol[0], regs);
-       if (reg == 15)
-               return INSN_GOOD;
-
-       if (reg == -1)
-               return INSN_REJECTED;
-
-       auprobe->pcreg = reg;
-       auprobe->prehandler = uprobe_set_pc;
-       auprobe->posthandler = uprobe_unset_pc;
-
-       return INSN_GOOD;
-}
-
-enum probes_insn
-decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi,
-            const struct decode_header *d, bool alu)
-{
-       struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
-                                                  asi);
-       enum probes_insn ret = decode_pc_ro(insn, asi, d);
-
-       if (((insn >> 12) & 0xf) == 15)
-               auprobe->posthandler = alu ? uprobe_aluwrite_pc
-                                          : uprobe_write_pc;
-
-       return ret;
-}
-
-enum probes_insn
-decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
-                             struct arch_probes_insn *asi,
-                             const struct decode_header *d)
-{
-       return decode_wb_pc(insn, asi, d, true);
-}
-
-enum probes_insn
-decode_ldr(probes_opcode_t insn, struct arch_probes_insn *asi,
-          const struct decode_header *d)
-{
-       return decode_wb_pc(insn, asi, d, false);
-}
-
-enum probes_insn
-uprobe_decode_ldmstm(probes_opcode_t insn,
-                    struct arch_probes_insn *asi,
-                    const struct decode_header *d)
-{
-       struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
-                                                  asi);
-       unsigned reglist = insn & 0xffff;
-       int rn = (insn >> 16) & 0xf;
-       int lbit = insn & (1 << 20);
-       unsigned used = reglist | (1 << rn);
-
-       if (rn == 15)
-               return INSN_REJECTED;
-
-       if (!(used & (1 << 15)))
-               return INSN_GOOD;
-
-       if (used & (1 << 14))
-               return INSN_REJECTED;
-
-       /* Use LR instead of PC */
-       insn ^= 0xc000;
-
-       auprobe->pcreg = 14;
-       auprobe->ixol[0] = __opcode_to_mem_arm(insn);
-
-       auprobe->prehandler = uprobe_set_pc;
-       if (lbit)
-               auprobe->posthandler = uprobe_write_pc;
-       else
-               auprobe->posthandler = uprobe_unset_pc;
-
-       return INSN_GOOD;
-}
-
-const union decode_action uprobes_probes_actions[] = {
-       [PROBES_EMULATE_NONE] = {.handler = probes_simulate_nop},
-       [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
-       [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
-       [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
-       [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
-       [PROBES_MRS] = {.handler = simulate_mrs},
-       [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
-       [PROBES_CLZ] = {.handler = probes_simulate_nop},
-       [PROBES_SATURATING_ARITHMETIC] = {.handler = probes_simulate_nop},
-       [PROBES_MUL1] = {.handler = probes_simulate_nop},
-       [PROBES_MUL2] = {.handler = probes_simulate_nop},
-       [PROBES_SWP] = {.handler = probes_simulate_nop},
-       [PROBES_LDRSTRD] = {.decoder = decode_pc_ro},
-       [PROBES_LOAD_EXTRA] = {.decoder = decode_pc_ro},
-       [PROBES_LOAD] = {.decoder = decode_ldr},
-       [PROBES_STORE_EXTRA] = {.decoder = decode_pc_ro},
-       [PROBES_STORE] = {.decoder = decode_pc_ro},
-       [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
-       [PROBES_DATA_PROCESSING_REG] = {
-               .decoder = decode_rd12rn16rm0rs8_rwflags},
-       [PROBES_DATA_PROCESSING_IMM] = {
-               .decoder = decode_rd12rn16rm0rs8_rwflags},
-       [PROBES_MOV_HALFWORD] = {.handler = probes_simulate_nop},
-       [PROBES_SEV] = {.handler = probes_simulate_nop},
-       [PROBES_WFE] = {.handler = probes_simulate_nop},
-       [PROBES_SATURATE] = {.handler = probes_simulate_nop},
-       [PROBES_REV] = {.handler = probes_simulate_nop},
-       [PROBES_MMI] = {.handler = probes_simulate_nop},
-       [PROBES_PACK] = {.handler = probes_simulate_nop},
-       [PROBES_EXTEND] = {.handler = probes_simulate_nop},
-       [PROBES_EXTEND_ADD] = {.handler = probes_simulate_nop},
-       [PROBES_MUL_ADD_LONG] = {.handler = probes_simulate_nop},
-       [PROBES_MUL_ADD] = {.handler = probes_simulate_nop},
-       [PROBES_BITFIELD] = {.handler = probes_simulate_nop},
-       [PROBES_BRANCH] = {.handler = simulate_bbl},
-       [PROBES_LDMSTM] = {.decoder = uprobe_decode_ldmstm}
-};
diff --git a/arch/arm/kernel/uprobes.c b/arch/arm/kernel/uprobes.c
deleted file mode 100644 (file)
index 56adf9c..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <linux/highmem.h>
-#include <linux/sched.h>
-#include <linux/uprobes.h>
-#include <linux/notifier.h>
-
-#include <asm/opcodes.h>
-#include <asm/traps.h>
-
-#include "probes.h"
-#include "probes-arm.h"
-#include "uprobes.h"
-
-#define UPROBE_TRAP_NR UINT_MAX
-
-bool is_swbp_insn(uprobe_opcode_t *insn)
-{
-       return (__mem_to_opcode_arm(*insn) & 0x0fffffff) ==
-               (UPROBE_SWBP_ARM_INSN & 0x0fffffff);
-}
-
-int set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm,
-            unsigned long vaddr)
-{
-       return uprobe_write_opcode(mm, vaddr,
-                  __opcode_to_mem_arm(auprobe->bpinsn));
-}
-
-bool arch_uprobe_ignore(struct arch_uprobe *auprobe, struct pt_regs *regs)
-{
-       if (!auprobe->asi.insn_check_cc(regs->ARM_cpsr)) {
-               regs->ARM_pc += 4;
-               return true;
-       }
-
-       return false;
-}
-
-bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
-{
-       probes_opcode_t opcode;
-
-       if (!auprobe->simulate)
-               return false;
-
-       opcode = __mem_to_opcode_arm(*(unsigned int *) auprobe->insn);
-
-       auprobe->asi.insn_singlestep(opcode, &auprobe->asi, regs);
-
-       return true;
-}
-
-unsigned long
-arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
-                                 struct pt_regs *regs)
-{
-       unsigned long orig_ret_vaddr;
-
-       orig_ret_vaddr = regs->ARM_lr;
-       /* Replace the return addr with trampoline addr */
-       regs->ARM_lr = trampoline_vaddr;
-       return orig_ret_vaddr;
-}
-
-int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
-                            unsigned long addr)
-{
-       unsigned int insn;
-       unsigned int bpinsn;
-       enum probes_insn ret;
-
-       /* Thumb not yet support */
-       if (addr & 0x3)
-               return -EINVAL;
-
-       insn = __mem_to_opcode_arm(*(unsigned int *)auprobe->insn);
-       auprobe->ixol[0] = __opcode_to_mem_arm(insn);
-       auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN);
-
-       ret = arm_probes_decode_insn(insn, &auprobe->asi, false,
-                                    uprobes_probes_actions);
-       switch (ret) {
-       case INSN_REJECTED:
-               return -EINVAL;
-
-       case INSN_GOOD_NO_SLOT:
-               auprobe->simulate = true;
-               break;
-
-       case INSN_GOOD:
-       default:
-               break;
-       }
-
-       bpinsn = UPROBE_SWBP_ARM_INSN & 0x0fffffff;
-       if (insn >= 0xe0000000)
-               bpinsn |= 0xe0000000;  /* Unconditional instruction */
-       else
-               bpinsn |= insn & 0xf0000000;  /* Copy condition from insn */
-
-       auprobe->bpinsn = bpinsn;
-
-       return 0;
-}
-
-void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
-                          void *src, unsigned long len)
-{
-       void *xol_page_kaddr = kmap_atomic(page);
-       void *dst = xol_page_kaddr + (vaddr & ~PAGE_MASK);
-
-       preempt_disable();
-
-       /* Initialize the slot */
-       memcpy(dst, src, len);
-
-       /* flush caches (dcache/icache) */
-       flush_uprobe_xol_access(page, vaddr, dst, len);
-
-       preempt_enable();
-
-       kunmap_atomic(xol_page_kaddr);
-}
-
-
-int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
-{
-       struct uprobe_task *utask = current->utask;
-
-       if (auprobe->prehandler)
-               auprobe->prehandler(auprobe, &utask->autask, regs);
-
-       utask->autask.saved_trap_no = current->thread.trap_no;
-       current->thread.trap_no = UPROBE_TRAP_NR;
-       regs->ARM_pc = utask->xol_vaddr;
-
-       return 0;
-}
-
-int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
-{
-       struct uprobe_task *utask = current->utask;
-
-       WARN_ON_ONCE(current->thread.trap_no != UPROBE_TRAP_NR);
-
-       current->thread.trap_no = utask->autask.saved_trap_no;
-       regs->ARM_pc = utask->vaddr + 4;
-
-       if (auprobe->posthandler)
-               auprobe->posthandler(auprobe, &utask->autask, regs);
-
-       return 0;
-}
-
-bool arch_uprobe_xol_was_trapped(struct task_struct *t)
-{
-       if (t->thread.trap_no != UPROBE_TRAP_NR)
-               return true;
-
-       return false;
-}
-
-void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
-{
-       struct uprobe_task *utask = current->utask;
-
-       current->thread.trap_no = utask->autask.saved_trap_no;
-       instruction_pointer_set(regs, utask->vaddr);
-}
-
-int arch_uprobe_exception_notify(struct notifier_block *self,
-                                unsigned long val, void *data)
-{
-       return NOTIFY_DONE;
-}
-
-static int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       instr &= 0x0fffffff;
-       if (instr == (UPROBE_SWBP_ARM_INSN & 0x0fffffff))
-               uprobe_pre_sstep_notifier(regs);
-       else if (instr == (UPROBE_SS_ARM_INSN & 0x0fffffff))
-               uprobe_post_sstep_notifier(regs);
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
-{
-       return instruction_pointer(regs);
-}
-
-static struct undef_hook uprobes_arm_break_hook = {
-       .instr_mask     = 0x0fffffff,
-       .instr_val      = (UPROBE_SWBP_ARM_INSN & 0x0fffffff),
-       .cpsr_mask      = MODE_MASK,
-       .cpsr_val       = USR_MODE,
-       .fn             = uprobe_trap_handler,
-};
-
-static struct undef_hook uprobes_arm_ss_hook = {
-       .instr_mask     = 0x0fffffff,
-       .instr_val      = (UPROBE_SS_ARM_INSN & 0x0fffffff),
-       .cpsr_mask      = MODE_MASK,
-       .cpsr_val       = USR_MODE,
-       .fn             = uprobe_trap_handler,
-};
-
-static int arch_uprobes_init(void)
-{
-       register_undef_hook(&uprobes_arm_break_hook);
-       register_undef_hook(&uprobes_arm_ss_hook);
-
-       return 0;
-}
-device_initcall(arch_uprobes_init);
diff --git a/arch/arm/kernel/uprobes.h b/arch/arm/kernel/uprobes.h
deleted file mode 100644 (file)
index 1d0c12d..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ARM_KERNEL_UPROBES_H
-#define __ARM_KERNEL_UPROBES_H
-
-enum probes_insn uprobe_decode_ldmstm(probes_opcode_t insn,
-                                     struct arch_probes_insn *asi,
-                                     const struct decode_header *d);
-
-enum probes_insn decode_ldr(probes_opcode_t insn,
-                           struct arch_probes_insn *asi,
-                           const struct decode_header *d);
-
-enum probes_insn
-decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
-                             struct arch_probes_insn *asi,
-                             const struct decode_header *d);
-
-enum probes_insn
-decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi,
-            const struct decode_header *d, bool alu);
-
-enum probes_insn
-decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi,
-            const struct decode_header *d);
-
-extern const union decode_action uprobes_probes_actions[];
-
-#endif
diff --git a/arch/arm/probes/Makefile b/arch/arm/probes/Makefile
new file mode 100644 (file)
index 0000000..aa1f859
--- /dev/null
@@ -0,0 +1,7 @@
+obj-$(CONFIG_UPROBES)          += decode.o decode-arm.o uprobes/
+obj-$(CONFIG_KPROBES)          += decode.o kprobes/
+ifdef CONFIG_THUMB2_KERNEL
+obj-$(CONFIG_KPROBES)          += decode-thumb.o
+else
+obj-$(CONFIG_KPROBES)          += decode-arm.o
+endif
diff --git a/arch/arm/probes/decode-arm.c b/arch/arm/probes/decode-arm.c
new file mode 100644 (file)
index 0000000..e39cc75
--- /dev/null
@@ -0,0 +1,735 @@
+/*
+ *
+ * arch/arm/probes/decode-arm.c
+ *
+ * Some code moved here from arch/arm/kernel/kprobes-arm.c
+ *
+ * Copyright (C) 2006, 2007 Motorola Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/ptrace.h>
+
+#include "decode.h"
+#include "decode-arm.h"
+
+#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
+
+#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
+
+/*
+ * To avoid the complications of mimicing single-stepping on a
+ * processor without a Next-PC or a single-step mode, and to
+ * avoid having to deal with the side-effects of boosting, we
+ * simulate or emulate (almost) all ARM instructions.
+ *
+ * "Simulation" is where the instruction's behavior is duplicated in
+ * C code.  "Emulation" is where the original instruction is rewritten
+ * and executed, often by altering its registers.
+ *
+ * By having all behavior of the kprobe'd instruction completed before
+ * returning from the kprobe_handler(), all locks (scheduler and
+ * interrupt) can safely be released.  There is no need for secondary
+ * breakpoints, no race with MP or preemptable kernels, nor having to
+ * clean up resources counts at a later time impacting overall system
+ * performance.  By rewriting the instruction, only the minimum registers
+ * need to be loaded and saved back optimizing performance.
+ *
+ * Calling the insnslot_*_rwflags version of a function doesn't hurt
+ * anything even when the CPSR flags aren't updated by the
+ * instruction.  It's just a little slower in return for saving
+ * a little space by not having a duplicate function that doesn't
+ * update the flags.  (The same optimization can be said for
+ * instructions that do or don't perform register writeback)
+ * Also, instructions can either read the flags, only write the
+ * flags, or read and write the flags.  To save combinations
+ * rather than for sheer performance, flag functions just assume
+ * read and write of flags.
+ */
+
+void __kprobes simulate_bbl(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       long iaddr = (long) regs->ARM_pc - 4;
+       int disp  = branch_displacement(insn);
+
+       if (insn & (1 << 24))
+               regs->ARM_lr = iaddr + 4;
+
+       regs->ARM_pc = iaddr + 8 + disp;
+}
+
+void __kprobes simulate_blx1(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       long iaddr = (long) regs->ARM_pc - 4;
+       int disp = branch_displacement(insn);
+
+       regs->ARM_lr = iaddr + 4;
+       regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2);
+       regs->ARM_cpsr |= PSR_T_BIT;
+}
+
+void __kprobes simulate_blx2bx(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       int rm = insn & 0xf;
+       long rmv = regs->uregs[rm];
+
+       if (insn & (1 << 5))
+               regs->ARM_lr = (long) regs->ARM_pc;
+
+       regs->ARM_pc = rmv & ~0x1;
+       regs->ARM_cpsr &= ~PSR_T_BIT;
+       if (rmv & 0x1)
+               regs->ARM_cpsr |= PSR_T_BIT;
+}
+
+void __kprobes simulate_mrs(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       int rd = (insn >> 12) & 0xf;
+       unsigned long mask = 0xf8ff03df; /* Mask out execution state */
+       regs->uregs[rd] = regs->ARM_cpsr & mask;
+}
+
+void __kprobes simulate_mov_ipsp(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       regs->uregs[12] = regs->uregs[13];
+}
+
+/*
+ * For the instruction masking and comparisons in all the "space_*"
+ * functions below, Do _not_ rearrange the order of tests unless
+ * you're very, very sure of what you are doing.  For the sake of
+ * efficiency, the masks for some tests sometimes assume other test
+ * have been done prior to them so the number of patterns to test
+ * for an instruction set can be as broad as possible to reduce the
+ * number of tests needed.
+ */
+
+static const union decode_item arm_1111_table[] = {
+       /* Unconditional instructions                                   */
+
+       /* memory hint          1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */
+       /* PLDI (immediate)     1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */
+       /* PLDW (immediate)     1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */
+       /* PLD (immediate)      1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_SIMULATE (0xfe300000, 0xf4100000, PROBES_PRELOAD_IMM),
+
+       /* memory hint          1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */
+       /* PLDI (register)      1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */
+       /* PLDW (register)      1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */
+       /* PLD (register)       1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */
+       DECODE_SIMULATE (0xfe300010, 0xf6100000, PROBES_PRELOAD_REG),
+
+       /* BLX (immediate)      1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */
+       DECODE_SIMULATE (0xfe000000, 0xfa000000, PROBES_BRANCH_IMM),
+
+       /* CPS                  1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */
+       /* SETEND               1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
+       /* SRS                  1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
+       /* RFE                  1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
+
+       /* Coprocessor instructions... */
+       /* MCRR2                1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */
+       /* MRRC2                1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */
+       /* LDC2                 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
+       /* STC2                 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
+       /* CDP2                 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
+       /* MCR2                 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
+       /* MRC2                 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
+
+       /* Other unallocated instructions...                            */
+       DECODE_END
+};
+
+static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = {
+       /* Miscellaneous instructions                                   */
+
+       /* MRS cpsr             cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */
+       DECODE_SIMULATEX(0x0ff000f0, 0x01000000, PROBES_MRS,
+                                                REGS(0, NOPC, 0, 0, 0)),
+
+       /* BX                   cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */
+       DECODE_SIMULATE (0x0ff000f0, 0x01200010, PROBES_BRANCH_REG),
+
+       /* BLX (register)       cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */
+       DECODE_SIMULATEX(0x0ff000f0, 0x01200030, PROBES_BRANCH_REG,
+                                                REGS(0, 0, 0, 0, NOPC)),
+
+       /* CLZ                  cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */
+       DECODE_EMULATEX (0x0ff000f0, 0x01600010, PROBES_CLZ,
+                                                REGS(0, NOPC, 0, 0, NOPC)),
+
+       /* QADD                 cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */
+       /* QSUB                 cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */
+       /* QDADD                cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */
+       /* QDSUB                cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */
+       DECODE_EMULATEX (0x0f9000f0, 0x01000050, PROBES_SATURATING_ARITHMETIC,
+                                                REGS(NOPC, NOPC, 0, 0, NOPC)),
+
+       /* BXJ                  cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
+       /* MSR                  cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
+       /* MRS spsr             cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */
+       /* BKPT                 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
+       /* SMC                  cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */
+       /* And unallocated instructions...                              */
+       DECODE_END
+};
+
+static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = {
+       /* Halfword multiply and multiply-accumulate                    */
+
+       /* SMLALxy              cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */
+       DECODE_EMULATEX (0x0ff00090, 0x01400080, PROBES_MUL1,
+                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
+
+       /* SMULWy               cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */
+       DECODE_OR       (0x0ff000b0, 0x012000a0),
+       /* SMULxy               cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */
+       DECODE_EMULATEX (0x0ff00090, 0x01600080, PROBES_MUL2,
+                                                REGS(NOPC, 0, NOPC, 0, NOPC)),
+
+       /* SMLAxy               cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */
+       DECODE_OR       (0x0ff00090, 0x01000080),
+       /* SMLAWy               cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */
+       DECODE_EMULATEX (0x0ff000b0, 0x01200080, PROBES_MUL2,
+                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
+
+       DECODE_END
+};
+
+static const union decode_item arm_cccc_0000_____1001_table[] = {
+       /* Multiply and multiply-accumulate                             */
+
+       /* MUL                  cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */
+       /* MULS                 cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */
+       DECODE_EMULATEX (0x0fe000f0, 0x00000090, PROBES_MUL2,
+                                                REGS(NOPC, 0, NOPC, 0, NOPC)),
+
+       /* MLA                  cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */
+       /* MLAS                 cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */
+       DECODE_OR       (0x0fe000f0, 0x00200090),
+       /* MLS                  cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */
+       DECODE_EMULATEX (0x0ff000f0, 0x00600090, PROBES_MUL2,
+                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
+
+       /* UMAAL                cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */
+       DECODE_OR       (0x0ff000f0, 0x00400090),
+       /* UMULL                cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */
+       /* UMULLS               cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */
+       /* UMLAL                cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */
+       /* UMLALS               cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */
+       /* SMULL                cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */
+       /* SMULLS               cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */
+       /* SMLAL                cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */
+       /* SMLALS               cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */
+       DECODE_EMULATEX (0x0f8000f0, 0x00800090, PROBES_MUL1,
+                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
+
+       DECODE_END
+};
+
+static const union decode_item arm_cccc_0001_____1001_table[] = {
+       /* Synchronization primitives                                   */
+
+#if __LINUX_ARM_ARCH__ < 6
+       /* Deprecated on ARMv6 and may be UNDEFINED on v7               */
+       /* SMP/SWPB             cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */
+       DECODE_EMULATEX (0x0fb000f0, 0x01000090, PROBES_SWP,
+                                                REGS(NOPC, NOPC, 0, 0, NOPC)),
+#endif
+       /* LDREX/STREX{,D,B,H}  cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */
+       /* And unallocated instructions...                              */
+       DECODE_END
+};
+
+static const union decode_item arm_cccc_000x_____1xx1_table[] = {
+       /* Extra load/store instructions                                */
+
+       /* STRHT                cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */
+       /* ???                  cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */
+       /* LDRHT                cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */
+       /* LDRSBT               cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */
+       /* LDRSHT               cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */
+       DECODE_REJECT   (0x0f200090, 0x00200090),
+
+       /* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */
+       DECODE_REJECT   (0x0e10e0d0, 0x0000e0d0),
+
+       /* LDRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */
+       /* STRD (register)      cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */
+       DECODE_EMULATEX (0x0e5000d0, 0x000000d0, PROBES_LDRSTRD,
+                                                REGS(NOPCWB, NOPCX, 0, 0, NOPC)),
+
+       /* LDRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */
+       /* STRD (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */
+       DECODE_EMULATEX (0x0e5000d0, 0x004000d0, PROBES_LDRSTRD,
+                                                REGS(NOPCWB, NOPCX, 0, 0, 0)),
+
+       /* STRH (register)      cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */
+       DECODE_EMULATEX (0x0e5000f0, 0x000000b0, PROBES_STORE_EXTRA,
+                                                REGS(NOPCWB, NOPC, 0, 0, NOPC)),
+
+       /* LDRH (register)      cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */
+       /* LDRSB (register)     cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */
+       /* LDRSH (register)     cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */
+       DECODE_EMULATEX (0x0e500090, 0x00100090, PROBES_LOAD_EXTRA,
+                                                REGS(NOPCWB, NOPC, 0, 0, NOPC)),
+
+       /* STRH (immediate)     cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */
+       DECODE_EMULATEX (0x0e5000f0, 0x004000b0, PROBES_STORE_EXTRA,
+                                                REGS(NOPCWB, NOPC, 0, 0, 0)),
+
+       /* LDRH (immediate)     cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */
+       /* LDRSB (immediate)    cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */
+       /* LDRSH (immediate)    cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */
+       DECODE_EMULATEX (0x0e500090, 0x00500090, PROBES_LOAD_EXTRA,
+                                                REGS(NOPCWB, NOPC, 0, 0, 0)),
+
+       DECODE_END
+};
+
+static const union decode_item arm_cccc_000x_table[] = {
+       /* Data-processing (register)                                   */
+
+       /* <op>S PC, ...        cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */
+       DECODE_REJECT   (0x0e10f000, 0x0010f000),
+
+       /* MOV IP, SP           1110 0001 1010 0000 1100 0000 0000 1101 */
+       DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, PROBES_MOV_IP_SP),
+
+       /* TST (register)       cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */
+       /* TEQ (register)       cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */
+       /* CMP (register)       cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */
+       /* CMN (register)       cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */
+       DECODE_EMULATEX (0x0f900010, 0x01100000, PROBES_DATA_PROCESSING_REG,
+                                                REGS(ANY, 0, 0, 0, ANY)),
+
+       /* MOV (register)       cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */
+       /* MVN (register)       cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */
+       DECODE_EMULATEX (0x0fa00010, 0x01a00000, PROBES_DATA_PROCESSING_REG,
+                                                REGS(0, ANY, 0, 0, ANY)),
+
+       /* AND (register)       cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */
+       /* EOR (register)       cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */
+       /* SUB (register)       cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */
+       /* RSB (register)       cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */
+       /* ADD (register)       cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */
+       /* ADC (register)       cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */
+       /* SBC (register)       cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */
+       /* RSC (register)       cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */
+       /* ORR (register)       cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */
+       /* BIC (register)       cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */
+       DECODE_EMULATEX (0x0e000010, 0x00000000, PROBES_DATA_PROCESSING_REG,
+                                                REGS(ANY, ANY, 0, 0, ANY)),
+
+       /* TST (reg-shift reg)  cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */
+       /* TEQ (reg-shift reg)  cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */
+       /* CMP (reg-shift reg)  cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */
+       /* CMN (reg-shift reg)  cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */
+       DECODE_EMULATEX (0x0f900090, 0x01100010, PROBES_DATA_PROCESSING_REG,
+                                                REGS(NOPC, 0, NOPC, 0, NOPC)),
+
+       /* MOV (reg-shift reg)  cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */
+       /* MVN (reg-shift reg)  cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */
+       DECODE_EMULATEX (0x0fa00090, 0x01a00010, PROBES_DATA_PROCESSING_REG,
+                                                REGS(0, NOPC, NOPC, 0, NOPC)),
+
+       /* AND (reg-shift reg)  cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */
+       /* EOR (reg-shift reg)  cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */
+       /* SUB (reg-shift reg)  cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */
+       /* RSB (reg-shift reg)  cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */
+       /* ADD (reg-shift reg)  cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */
+       /* ADC (reg-shift reg)  cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */
+       /* SBC (reg-shift reg)  cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */
+       /* RSC (reg-shift reg)  cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */
+       /* ORR (reg-shift reg)  cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */
+       /* BIC (reg-shift reg)  cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */
+       DECODE_EMULATEX (0x0e000090, 0x00000010, PROBES_DATA_PROCESSING_REG,
+                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
+
+       DECODE_END
+};
+
+static const union decode_item arm_cccc_001x_table[] = {
+       /* Data-processing (immediate)                                  */
+
+       /* MOVW                 cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */
+       /* MOVT                 cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_DATA_PROCESSING_IMM,
+                                                REGS(0, NOPC, 0, 0, 0)),
+
+       /* YIELD                cccc 0011 0010 0000 xxxx xxxx 0000 0001 */
+       DECODE_OR       (0x0fff00ff, 0x03200001),
+       /* SEV                  cccc 0011 0010 0000 xxxx xxxx 0000 0100 */
+       DECODE_EMULATE  (0x0fff00ff, 0x03200004, PROBES_EMULATE_NONE),
+       /* NOP                  cccc 0011 0010 0000 xxxx xxxx 0000 0000 */
+       /* WFE                  cccc 0011 0010 0000 xxxx xxxx 0000 0010 */
+       /* WFI                  cccc 0011 0010 0000 xxxx xxxx 0000 0011 */
+       DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_SIMULATE_NOP),
+       /* DBG                  cccc 0011 0010 0000 xxxx xxxx ffff xxxx */
+       /* unallocated hints    cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */
+       /* MSR (immediate)      cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0x0fb00000, 0x03200000),
+
+       /* <op>S PC, ...        cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */
+       DECODE_REJECT   (0x0e10f000, 0x0210f000),
+
+       /* TST (immediate)      cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */
+       /* TEQ (immediate)      cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */
+       /* CMP (immediate)      cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */
+       /* CMN (immediate)      cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0x0f900000, 0x03100000, PROBES_DATA_PROCESSING_IMM,
+                                                REGS(ANY, 0, 0, 0, 0)),
+
+       /* MOV (immediate)      cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */
+       /* MVN (immediate)      cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0x0fa00000, 0x03a00000, PROBES_DATA_PROCESSING_IMM,
+                                                REGS(0, ANY, 0, 0, 0)),
+
+       /* AND (immediate)      cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */
+       /* EOR (immediate)      cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */
+       /* SUB (immediate)      cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */
+       /* RSB (immediate)      cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */
+       /* ADD (immediate)      cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */
+       /* ADC (immediate)      cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */
+       /* SBC (immediate)      cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */
+       /* RSC (immediate)      cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */
+       /* ORR (immediate)      cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */
+       /* BIC (immediate)      cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0x0e000000, 0x02000000, PROBES_DATA_PROCESSING_IMM,
+                                                REGS(ANY, ANY, 0, 0, 0)),
+
+       DECODE_END
+};
+
+static const union decode_item arm_cccc_0110_____xxx1_table[] = {
+       /* Media instructions                                           */
+
+       /* SEL                  cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */
+       DECODE_EMULATEX (0x0ff000f0, 0x068000b0, PROBES_SATURATE,
+                                                REGS(NOPC, NOPC, 0, 0, NOPC)),
+
+       /* SSAT                 cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */
+       /* USAT                 cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */
+       DECODE_OR(0x0fa00030, 0x06a00010),
+       /* SSAT16               cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */
+       /* USAT16               cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */
+       DECODE_EMULATEX (0x0fb000f0, 0x06a00030, PROBES_SATURATE,
+                                                REGS(0, NOPC, 0, 0, NOPC)),
+
+       /* REV                  cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */
+       /* REV16                cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */
+       /* RBIT                 cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */
+       /* REVSH                cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */
+       DECODE_EMULATEX (0x0fb00070, 0x06b00030, PROBES_REV,
+                                                REGS(0, NOPC, 0, 0, NOPC)),
+
+       /* ???                  cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */
+       DECODE_REJECT   (0x0fb00010, 0x06000010),
+       /* ???                  cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */
+       DECODE_REJECT   (0x0f8000f0, 0x060000b0),
+       /* ???                  cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */
+       DECODE_REJECT   (0x0f8000f0, 0x060000d0),
+       /* SADD16               cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */
+       /* SADDSUBX             cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */
+       /* SSUBADDX             cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */
+       /* SSUB16               cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */
+       /* SADD8                cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */
+       /* SSUB8                cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */
+       /* QADD16               cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */
+       /* QADDSUBX             cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */
+       /* QSUBADDX             cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */
+       /* QSUB16               cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */
+       /* QADD8                cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */
+       /* QSUB8                cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */
+       /* SHADD16              cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */
+       /* SHADDSUBX            cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */
+       /* SHSUBADDX            cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */
+       /* SHSUB16              cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */
+       /* SHADD8               cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */
+       /* SHSUB8               cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */
+       /* UADD16               cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */
+       /* UADDSUBX             cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */
+       /* USUBADDX             cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */
+       /* USUB16               cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */
+       /* UADD8                cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */
+       /* USUB8                cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */
+       /* UQADD16              cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */
+       /* UQADDSUBX            cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */
+       /* UQSUBADDX            cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */
+       /* UQSUB16              cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */
+       /* UQADD8               cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */
+       /* UQSUB8               cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */
+       /* UHADD16              cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */
+       /* UHADDSUBX            cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */
+       /* UHSUBADDX            cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */
+       /* UHSUB16              cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */
+       /* UHADD8               cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */
+       /* UHSUB8               cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */
+       DECODE_EMULATEX (0x0f800010, 0x06000010, PROBES_MMI,
+                                                REGS(NOPC, NOPC, 0, 0, NOPC)),
+
+       /* PKHBT                cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */
+       /* PKHTB                cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */
+       DECODE_EMULATEX (0x0ff00030, 0x06800010, PROBES_PACK,
+                                                REGS(NOPC, NOPC, 0, 0, NOPC)),
+
+       /* ???                  cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */
+       /* ???                  cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */
+       DECODE_REJECT   (0x0fb000f0, 0x06900070),
+
+       /* SXTB16               cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */
+       /* SXTB                 cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */
+       /* SXTH                 cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */
+       /* UXTB16               cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */
+       /* UXTB                 cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */
+       /* UXTH                 cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */
+       DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, PROBES_EXTEND,
+                                                REGS(0, NOPC, 0, 0, NOPC)),
+
+       /* SXTAB16              cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */
+       /* SXTAB                cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */
+       /* SXTAH                cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */
+       /* UXTAB16              cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */
+       /* UXTAB                cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */
+       /* UXTAH                cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */
+       DECODE_EMULATEX (0x0f8000f0, 0x06800070, PROBES_EXTEND_ADD,
+                                                REGS(NOPCX, NOPC, 0, 0, NOPC)),
+
+       DECODE_END
+};
+
+static const union decode_item arm_cccc_0111_____xxx1_table[] = {
+       /* Media instructions                                           */
+
+       /* UNDEFINED            cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */
+       DECODE_REJECT   (0x0ff000f0, 0x07f000f0),
+
+       /* SMLALD               cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */
+       /* SMLSLD               cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */
+       DECODE_EMULATEX (0x0ff00090, 0x07400010, PROBES_MUL_ADD_LONG,
+                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
+
+       /* SMUAD                cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */
+       /* SMUSD                cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */
+       DECODE_OR       (0x0ff0f090, 0x0700f010),
+       /* SMMUL                cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */
+       DECODE_OR       (0x0ff0f0d0, 0x0750f010),
+       /* USAD8                cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */
+       DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, PROBES_MUL_ADD,
+                                                REGS(NOPC, 0, NOPC, 0, NOPC)),
+
+       /* SMLAD                cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */
+       /* SMLSD                cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */
+       DECODE_OR       (0x0ff00090, 0x07000010),
+       /* SMMLA                cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */
+       DECODE_OR       (0x0ff000d0, 0x07500010),
+       /* USADA8               cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */
+       DECODE_EMULATEX (0x0ff000f0, 0x07800010, PROBES_MUL_ADD,
+                                                REGS(NOPC, NOPCX, NOPC, 0, NOPC)),
+
+       /* SMMLS                cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */
+       DECODE_EMULATEX (0x0ff000d0, 0x075000d0, PROBES_MUL_ADD,
+                                                REGS(NOPC, NOPC, NOPC, 0, NOPC)),
+
+       /* SBFX                 cccc 0111 101x xxxx xxxx xxxx x101 xxxx */
+       /* UBFX                 cccc 0111 111x xxxx xxxx xxxx x101 xxxx */
+       DECODE_EMULATEX (0x0fa00070, 0x07a00050, PROBES_BITFIELD,
+                                                REGS(0, NOPC, 0, 0, NOPC)),
+
+       /* BFC                  cccc 0111 110x xxxx xxxx xxxx x001 1111 */
+       DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, PROBES_BITFIELD,
+                                                REGS(0, NOPC, 0, 0, 0)),
+
+       /* BFI                  cccc 0111 110x xxxx xxxx xxxx x001 xxxx */
+       DECODE_EMULATEX (0x0fe00070, 0x07c00010, PROBES_BITFIELD,
+                                                REGS(0, NOPC, 0, 0, NOPCX)),
+
+       DECODE_END
+};
+
+static const union decode_item arm_cccc_01xx_table[] = {
+       /* Load/store word and unsigned byte                            */
+
+       /* LDRB/STRB pc,[...]   cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0x0c40f000, 0x0440f000),
+
+       /* STRT                 cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */
+       /* LDRT                 cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */
+       /* STRBT                cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */
+       /* LDRBT                cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0x0d200000, 0x04200000),
+
+       /* STR (immediate)      cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */
+       /* STRB (immediate)     cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0x0e100000, 0x04000000, PROBES_STORE,
+                                                REGS(NOPCWB, ANY, 0, 0, 0)),
+
+       /* LDR (immediate)      cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */
+       /* LDRB (immediate)     cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0x0e100000, 0x04100000, PROBES_LOAD,
+                                                REGS(NOPCWB, ANY, 0, 0, 0)),
+
+       /* STR (register)       cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */
+       /* STRB (register)      cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0x0e100000, 0x06000000, PROBES_STORE,
+                                                REGS(NOPCWB, ANY, 0, 0, NOPC)),
+
+       /* LDR (register)       cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */
+       /* LDRB (register)      cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0x0e100000, 0x06100000, PROBES_LOAD,
+                                                REGS(NOPCWB, ANY, 0, 0, NOPC)),
+
+       DECODE_END
+};
+
+static const union decode_item arm_cccc_100x_table[] = {
+       /* Block data transfer instructions                             */
+
+       /* LDM                  cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
+       /* STM                  cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_CUSTOM   (0x0e400000, 0x08000000, PROBES_LDMSTM),
+
+       /* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
+       /* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */
+       /* LDM (exception ret)  cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */
+       DECODE_END
+};
+
+const union decode_item probes_decode_arm_table[] = {
+       /*
+        * Unconditional instructions
+        *                      1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xf0000000, 0xf0000000, arm_1111_table),
+
+       /*
+        * Miscellaneous instructions
+        *                      cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx
+        */
+       DECODE_TABLE    (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table),
+
+       /*
+        * Halfword multiply and multiply-accumulate
+        *                      cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx
+        */
+       DECODE_TABLE    (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table),
+
+       /*
+        * Multiply and multiply-accumulate
+        *                      cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx
+        */
+       DECODE_TABLE    (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table),
+
+       /*
+        * Synchronization primitives
+        *                      cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx
+        */
+       DECODE_TABLE    (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table),
+
+       /*
+        * Extra load/store instructions
+        *                      cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx
+        */
+       DECODE_TABLE    (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table),
+
+       /*
+        * Data-processing (register)
+        *                      cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx
+        * Data-processing (register-shifted register)
+        *                      cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx
+        */
+       DECODE_TABLE    (0x0e000000, 0x00000000, arm_cccc_000x_table),
+
+       /*
+        * Data-processing (immediate)
+        *                      cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0x0e000000, 0x02000000, arm_cccc_001x_table),
+
+       /*
+        * Media instructions
+        *                      cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx
+        */
+       DECODE_TABLE    (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table),
+       DECODE_TABLE    (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table),
+
+       /*
+        * Load/store word and unsigned byte
+        *                      cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0x0c000000, 0x04000000, arm_cccc_01xx_table),
+
+       /*
+        * Block data transfer instructions
+        *                      cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0x0e000000, 0x08000000, arm_cccc_100x_table),
+
+       /* B                    cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */
+       /* BL                   cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */
+       DECODE_SIMULATE (0x0e000000, 0x0a000000, PROBES_BRANCH),
+
+       /*
+        * Supervisor Call, and coprocessor instructions
+        */
+
+       /* MCRR                 cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */
+       /* MRRC                 cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */
+       /* LDC                  cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
+       /* STC                  cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
+       /* CDP                  cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
+       /* MCR                  cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
+       /* MRC                  cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
+       /* SVC                  cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0x0c000000, 0x0c000000),
+
+       DECODE_END
+};
+#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
+EXPORT_SYMBOL_GPL(probes_decode_arm_table);
+#endif
+
+static void __kprobes arm_singlestep(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       regs->ARM_pc += 4;
+       asi->insn_handler(insn, asi, regs);
+}
+
+/* Return:
+ *   INSN_REJECTED     If instruction is one not allowed to kprobe,
+ *   INSN_GOOD         If instruction is supported and uses instruction slot,
+ *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
+ *
+ * For instructions we don't want to kprobe (INSN_REJECTED return result):
+ *   These are generally ones that modify the processor state making
+ *   them "hard" to simulate such as switches processor modes or
+ *   make accesses in alternate modes.  Any of these could be simulated
+ *   if the work was put into it, but low return considering they
+ *   should also be very rare.
+ */
+enum probes_insn __kprobes
+arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
+                      bool emulate, const union decode_action *actions)
+{
+       asi->insn_singlestep = arm_singlestep;
+       asi->insn_check_cc = probes_condition_checks[insn>>28];
+       return probes_decode_insn(insn, asi, probes_decode_arm_table, false,
+                                 emulate, actions);
+}
diff --git a/arch/arm/probes/decode-arm.h b/arch/arm/probes/decode-arm.h
new file mode 100644 (file)
index 0000000..9c56b40
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * arch/arm/probes/decode-arm.h
+ *
+ * Copyright 2013 Linaro Ltd.
+ * Written by: David A. Long
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _ARM_KERNEL_PROBES_ARM_H
+#define  _ARM_KERNEL_PROBES_ARM_H
+
+#include "decode.h"
+
+enum probes_arm_action {
+       PROBES_EMULATE_NONE,
+       PROBES_SIMULATE_NOP,
+       PROBES_PRELOAD_IMM,
+       PROBES_PRELOAD_REG,
+       PROBES_BRANCH_IMM,
+       PROBES_BRANCH_REG,
+       PROBES_MRS,
+       PROBES_CLZ,
+       PROBES_SATURATING_ARITHMETIC,
+       PROBES_MUL1,
+       PROBES_MUL2,
+       PROBES_SWP,
+       PROBES_LDRSTRD,
+       PROBES_LOAD,
+       PROBES_STORE,
+       PROBES_LOAD_EXTRA,
+       PROBES_STORE_EXTRA,
+       PROBES_MOV_IP_SP,
+       PROBES_DATA_PROCESSING_REG,
+       PROBES_DATA_PROCESSING_IMM,
+       PROBES_MOV_HALFWORD,
+       PROBES_SEV,
+       PROBES_WFE,
+       PROBES_SATURATE,
+       PROBES_REV,
+       PROBES_MMI,
+       PROBES_PACK,
+       PROBES_EXTEND,
+       PROBES_EXTEND_ADD,
+       PROBES_MUL_ADD_LONG,
+       PROBES_MUL_ADD,
+       PROBES_BITFIELD,
+       PROBES_BRANCH,
+       PROBES_LDMSTM,
+       NUM_PROBES_ARM_ACTIONS
+};
+
+void __kprobes simulate_bbl(probes_opcode_t opcode,
+       struct arch_probes_insn *asi, struct pt_regs *regs);
+void __kprobes simulate_blx1(probes_opcode_t opcode,
+       struct arch_probes_insn *asi, struct pt_regs *regs);
+void __kprobes simulate_blx2bx(probes_opcode_t opcode,
+       struct arch_probes_insn *asi, struct pt_regs *regs);
+void __kprobes simulate_mrs(probes_opcode_t opcode,
+       struct arch_probes_insn *asi, struct pt_regs *regs);
+void __kprobes simulate_mov_ipsp(probes_opcode_t opcode,
+       struct arch_probes_insn *asi, struct pt_regs *regs);
+
+extern const union decode_item probes_decode_arm_table[];
+
+enum probes_insn arm_probes_decode_insn(probes_opcode_t,
+               struct arch_probes_insn *, bool emulate,
+               const union decode_action *actions);
+
+#endif
diff --git a/arch/arm/probes/decode-thumb.c b/arch/arm/probes/decode-thumb.c
new file mode 100644 (file)
index 0000000..2f0453a
--- /dev/null
@@ -0,0 +1,882 @@
+/*
+ * arch/arm/probes/decode-thumb.c
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "decode.h"
+#include "decode-thumb.h"
+
+
+static const union decode_item t32_table_1110_100x_x0xx[] = {
+       /* Load/store multiple instructions */
+
+       /* Rn is PC             1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xfe4f0000, 0xe80f0000),
+
+       /* SRS                  1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */
+       /* RFE                  1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xffc00000, 0xe8000000),
+       /* SRS                  1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */
+       /* RFE                  1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xffc00000, 0xe9800000),
+
+       /* STM Rn, {...pc}      1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xfe508000, 0xe8008000),
+       /* LDM Rn, {...lr,pc}   1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xfe50c000, 0xe810c000),
+       /* LDM/STM Rn, {...sp}  1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */
+       DECODE_REJECT   (0xfe402000, 0xe8002000),
+
+       /* STMIA                1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */
+       /* LDMIA                1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */
+       /* STMDB                1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */
+       /* LDMDB                1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_CUSTOM   (0xfe400000, 0xe8000000, PROBES_T32_LDMSTM),
+
+       DECODE_END
+};
+
+static const union decode_item t32_table_1110_100x_x1xx[] = {
+       /* Load/store dual, load/store exclusive, table branch */
+
+       /* STRD (immediate)     1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */
+       /* LDRD (immediate)     1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_OR       (0xff600000, 0xe8600000),
+       /* STRD (immediate)     1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */
+       /* LDRD (immediate)     1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xff400000, 0xe9400000, PROBES_T32_LDRDSTRD,
+                                                REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)),
+
+       /* TBB                  1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */
+       /* TBH                  1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */
+       DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, PROBES_T32_TABLE_BRANCH,
+                                                REGS(NOSP, 0, 0, 0, NOSPPC)),
+
+       /* STREX                1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */
+       /* LDREX                1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */
+       /* STREXB               1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */
+       /* STREXH               1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */
+       /* STREXD               1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */
+       /* LDREXB               1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */
+       /* LDREXH               1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */
+       /* LDREXD               1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */
+       /* And unallocated instructions...                              */
+       DECODE_END
+};
+
+static const union decode_item t32_table_1110_101x[] = {
+       /* Data-processing (shifted register)                           */
+
+       /* TST                  1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */
+       /* TEQ                  1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */
+       DECODE_EMULATEX (0xff700f00, 0xea100f00, PROBES_T32_TST,
+                                                REGS(NOSPPC, 0, 0, 0, NOSPPC)),
+
+       /* CMN                  1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */
+       DECODE_OR       (0xfff00f00, 0xeb100f00),
+       /* CMP                  1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */
+       DECODE_EMULATEX (0xfff00f00, 0xebb00f00, PROBES_T32_TST,
+                                                REGS(NOPC, 0, 0, 0, NOSPPC)),
+
+       /* MOV                  1110 1010 010x 1111 xxxx xxxx xxxx xxxx */
+       /* MVN                  1110 1010 011x 1111 xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xffcf0000, 0xea4f0000, PROBES_T32_MOV,
+                                                REGS(0, 0, NOSPPC, 0, NOSPPC)),
+
+       /* ???                  1110 1010 101x xxxx xxxx xxxx xxxx xxxx */
+       /* ???                  1110 1010 111x xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xffa00000, 0xeaa00000),
+       /* ???                  1110 1011 001x xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xffe00000, 0xeb200000),
+       /* ???                  1110 1011 100x xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xffe00000, 0xeb800000),
+       /* ???                  1110 1011 111x xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xffe00000, 0xebe00000),
+
+       /* ADD/SUB SP, SP, Rm, LSL #0..3                                */
+       /*                      1110 1011 x0xx 1101 x000 1101 xx00 xxxx */
+       DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, PROBES_T32_ADDSUB,
+                                                REGS(SP, 0, SP, 0, NOSPPC)),
+
+       /* ADD/SUB SP, SP, Rm, shift                                    */
+       /*                      1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */
+       DECODE_REJECT   (0xff4f0f00, 0xeb0d0d00),
+
+       /* ADD/SUB Rd, SP, Rm, shift                                    */
+       /*                      1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, PROBES_T32_ADDSUB,
+                                                REGS(SP, 0, NOPC, 0, NOSPPC)),
+
+       /* AND                  1110 1010 000x xxxx xxxx xxxx xxxx xxxx */
+       /* BIC                  1110 1010 001x xxxx xxxx xxxx xxxx xxxx */
+       /* ORR                  1110 1010 010x xxxx xxxx xxxx xxxx xxxx */
+       /* ORN                  1110 1010 011x xxxx xxxx xxxx xxxx xxxx */
+       /* EOR                  1110 1010 100x xxxx xxxx xxxx xxxx xxxx */
+       /* PKH                  1110 1010 110x xxxx xxxx xxxx xxxx xxxx */
+       /* ADD                  1110 1011 000x xxxx xxxx xxxx xxxx xxxx */
+       /* ADC                  1110 1011 010x xxxx xxxx xxxx xxxx xxxx */
+       /* SBC                  1110 1011 011x xxxx xxxx xxxx xxxx xxxx */
+       /* SUB                  1110 1011 101x xxxx xxxx xxxx xxxx xxxx */
+       /* RSB                  1110 1011 110x xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfe000000, 0xea000000, PROBES_T32_LOGICAL,
+                                                REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)),
+
+       DECODE_END
+};
+
+static const union decode_item t32_table_1111_0x0x___0[] = {
+       /* Data-processing (modified immediate)                         */
+
+       /* TST                  1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */
+       /* TEQ                  1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */
+       DECODE_EMULATEX (0xfb708f00, 0xf0100f00, PROBES_T32_TST,
+                                                REGS(NOSPPC, 0, 0, 0, 0)),
+
+       /* CMN                  1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */
+       DECODE_OR       (0xfbf08f00, 0xf1100f00),
+       /* CMP                  1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */
+       DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, PROBES_T32_CMP,
+                                                REGS(NOPC, 0, 0, 0, 0)),
+
+       /* MOV                  1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */
+       /* MVN                  1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, PROBES_T32_MOV,
+                                                REGS(0, 0, NOSPPC, 0, 0)),
+
+       /* ???                  1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xfbe08000, 0xf0a00000),
+       /* ???                  1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */
+       /* ???                  1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xfbc08000, 0xf0c00000),
+       /* ???                  1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xfbe08000, 0xf1200000),
+       /* ???                  1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xfbe08000, 0xf1800000),
+       /* ???                  1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xfbe08000, 0xf1e00000),
+
+       /* ADD Rd, SP, #imm     1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */
+       /* SUB Rd, SP, #imm     1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, PROBES_T32_ADDSUB,
+                                                REGS(SP, 0, NOPC, 0, 0)),
+
+       /* AND                  1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */
+       /* BIC                  1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */
+       /* ORR                  1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */
+       /* ORN                  1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */
+       /* EOR                  1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */
+       /* ADD                  1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */
+       /* ADC                  1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */
+       /* SBC                  1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */
+       /* SUB                  1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */
+       /* RSB                  1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfa008000, 0xf0000000, PROBES_T32_LOGICAL,
+                                                REGS(NOSPPC, 0, NOSPPC, 0, 0)),
+
+       DECODE_END
+};
+
+static const union decode_item t32_table_1111_0x1x___0[] = {
+       /* Data-processing (plain binary immediate)                     */
+
+       /* ADDW Rd, PC, #imm    1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */
+       DECODE_OR       (0xfbff8000, 0xf20f0000),
+       /* SUBW Rd, PC, #imm    1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfbff8000, 0xf2af0000, PROBES_T32_ADDWSUBW_PC,
+                                                REGS(PC, 0, NOSPPC, 0, 0)),
+
+       /* ADDW SP, SP, #imm    1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */
+       DECODE_OR       (0xfbff8f00, 0xf20d0d00),
+       /* SUBW SP, SP, #imm    1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */
+       DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, PROBES_T32_ADDWSUBW,
+                                                REGS(SP, 0, SP, 0, 0)),
+
+       /* ADDW                 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_OR       (0xfbf08000, 0xf2000000),
+       /* SUBW                 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfbf08000, 0xf2a00000, PROBES_T32_ADDWSUBW,
+                                                REGS(NOPCX, 0, NOSPPC, 0, 0)),
+
+       /* MOVW                 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */
+       /* MOVT                 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfb708000, 0xf2400000, PROBES_T32_MOVW,
+                                                REGS(0, 0, NOSPPC, 0, 0)),
+
+       /* SSAT16               1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */
+       /* SSAT                 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */
+       /* USAT16               1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */
+       /* USAT                 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfb508000, 0xf3000000, PROBES_T32_SAT,
+                                                REGS(NOSPPC, 0, NOSPPC, 0, 0)),
+
+       /* SFBX                 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */
+       /* UFBX                 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfb708000, 0xf3400000, PROBES_T32_BITFIELD,
+                                                REGS(NOSPPC, 0, NOSPPC, 0, 0)),
+
+       /* BFC                  1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfbff8000, 0xf36f0000, PROBES_T32_BITFIELD,
+                                                REGS(0, 0, NOSPPC, 0, 0)),
+
+       /* BFI                  1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfbf08000, 0xf3600000, PROBES_T32_BITFIELD,
+                                                REGS(NOSPPCX, 0, NOSPPC, 0, 0)),
+
+       DECODE_END
+};
+
+static const union decode_item t32_table_1111_0xxx___1[] = {
+       /* Branches and miscellaneous control                           */
+
+       /* YIELD                1111 0011 1010 xxxx 10x0 x000 0000 0001 */
+       DECODE_OR       (0xfff0d7ff, 0xf3a08001),
+       /* SEV                  1111 0011 1010 xxxx 10x0 x000 0000 0100 */
+       DECODE_EMULATE  (0xfff0d7ff, 0xf3a08004, PROBES_T32_SEV),
+       /* NOP                  1111 0011 1010 xxxx 10x0 x000 0000 0000 */
+       /* WFE                  1111 0011 1010 xxxx 10x0 x000 0000 0010 */
+       /* WFI                  1111 0011 1010 xxxx 10x0 x000 0000 0011 */
+       DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, PROBES_T32_WFE),
+
+       /* MRS Rd, CPSR         1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */
+       DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, PROBES_T32_MRS,
+                                                REGS(0, 0, NOSPPC, 0, 0)),
+
+       /*
+        * Unsupported instructions
+        *                      1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx
+        *
+        * MSR                  1111 0011 100x xxxx 10x0 xxxx xxxx xxxx
+        * DBG hint             1111 0011 1010 xxxx 10x0 x000 1111 xxxx
+        * Unallocated hints    1111 0011 1010 xxxx 10x0 x000 xxxx xxxx
+        * CPS                  1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx
+        * CLREX/DSB/DMB/ISB    1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx
+        * BXJ                  1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx
+        * SUBS PC,LR,#<imm8>   1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx
+        * MRS Rd, SPSR         1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx
+        * SMC                  1111 0111 1111 xxxx 1000 xxxx xxxx xxxx
+        * UNDEFINED            1111 0111 1111 xxxx 1010 xxxx xxxx xxxx
+        * ???                  1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx
+        */
+       DECODE_REJECT   (0xfb80d000, 0xf3808000),
+
+       /* Bcc                  1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */
+       DECODE_CUSTOM   (0xf800d000, 0xf0008000, PROBES_T32_BRANCH_COND),
+
+       /* BLX                  1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */
+       DECODE_OR       (0xf800d001, 0xf000c000),
+       /* B                    1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */
+       /* BL                   1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */
+       DECODE_SIMULATE (0xf8009000, 0xf0009000, PROBES_T32_BRANCH),
+
+       DECODE_END
+};
+
+static const union decode_item t32_table_1111_100x_x0x1__1111[] = {
+       /* Memory hints                                                 */
+
+       /* PLD (literal)        1111 1000 x001 1111 1111 xxxx xxxx xxxx */
+       /* PLI (literal)        1111 1001 x001 1111 1111 xxxx xxxx xxxx */
+       DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, PROBES_T32_PLDI),
+
+       /* PLD{W} (immediate)   1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */
+       DECODE_OR       (0xffd0f000, 0xf890f000),
+       /* PLD{W} (immediate)   1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */
+       DECODE_OR       (0xffd0ff00, 0xf810fc00),
+       /* PLI (immediate)      1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */
+       DECODE_OR       (0xfff0f000, 0xf990f000),
+       /* PLI (immediate)      1111 1001 0001 xxxx 1111 1100 xxxx xxxx */
+       DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, PROBES_T32_PLDI,
+                                                REGS(NOPCX, 0, 0, 0, 0)),
+
+       /* PLD{W} (register)    1111 1000 00x1 xxxx 1111 0000 00xx xxxx */
+       DECODE_OR       (0xffd0ffc0, 0xf810f000),
+       /* PLI (register)       1111 1001 0001 xxxx 1111 0000 00xx xxxx */
+       DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, PROBES_T32_PLDI,
+                                                REGS(NOPCX, 0, 0, 0, NOSPPC)),
+
+       /* Other unallocated instructions...                            */
+       DECODE_END
+};
+
+static const union decode_item t32_table_1111_100x[] = {
+       /* Store/Load single data item                                  */
+
+       /* ???                  1111 100x x11x xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xfe600000, 0xf8600000),
+
+       /* ???                  1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xfff00000, 0xf9500000),
+
+       /* ???                  1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */
+       DECODE_REJECT   (0xfe800d00, 0xf8000800),
+
+       /* STRBT                1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */
+       /* STRHT                1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */
+       /* STRT                 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */
+       /* LDRBT                1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */
+       /* LDRSBT               1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */
+       /* LDRHT                1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */
+       /* LDRSHT               1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */
+       /* LDRT                 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */
+       DECODE_REJECT   (0xfe800f00, 0xf8000e00),
+
+       /* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */
+       DECODE_REJECT   (0xff1f0000, 0xf80f0000),
+
+       /* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */
+       DECODE_REJECT   (0xff10f000, 0xf800f000),
+
+       /* LDR (literal)        1111 1000 x101 1111 xxxx xxxx xxxx xxxx */
+       DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, PROBES_T32_LDR_LIT,
+                                                REGS(PC, ANY, 0, 0, 0)),
+
+       /* STR (immediate)      1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */
+       /* LDR (immediate)      1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */
+       DECODE_OR       (0xffe00800, 0xf8400800),
+       /* STR (immediate)      1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */
+       /* LDR (immediate)      1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xffe00000, 0xf8c00000, PROBES_T32_LDRSTR,
+                                                REGS(NOPCX, ANY, 0, 0, 0)),
+
+       /* STR (register)       1111 1000 0100 xxxx xxxx 0000 00xx xxxx */
+       /* LDR (register)       1111 1000 0101 xxxx xxxx 0000 00xx xxxx */
+       DECODE_EMULATEX (0xffe00fc0, 0xf8400000, PROBES_T32_LDRSTR,
+                                                REGS(NOPCX, ANY, 0, 0, NOSPPC)),
+
+       /* LDRB (literal)       1111 1000 x001 1111 xxxx xxxx xxxx xxxx */
+       /* LDRSB (literal)      1111 1001 x001 1111 xxxx xxxx xxxx xxxx */
+       /* LDRH (literal)       1111 1000 x011 1111 xxxx xxxx xxxx xxxx */
+       /* LDRSH (literal)      1111 1001 x011 1111 xxxx xxxx xxxx xxxx */
+       DECODE_SIMULATEX(0xfe5f0000, 0xf81f0000, PROBES_T32_LDR_LIT,
+                                                REGS(PC, NOSPPCX, 0, 0, 0)),
+
+       /* STRB (immediate)     1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */
+       /* STRH (immediate)     1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */
+       /* LDRB (immediate)     1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */
+       /* LDRSB (immediate)    1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */
+       /* LDRH (immediate)     1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */
+       /* LDRSH (immediate)    1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */
+       DECODE_OR       (0xfec00800, 0xf8000800),
+       /* STRB (immediate)     1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */
+       /* STRH (immediate)     1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */
+       /* LDRB (immediate)     1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */
+       /* LDRSB (immediate)    1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */
+       /* LDRH (immediate)     1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */
+       /* LDRSH (immediate)    1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */
+       DECODE_EMULATEX (0xfec00000, 0xf8800000, PROBES_T32_LDRSTR,
+                                                REGS(NOPCX, NOSPPCX, 0, 0, 0)),
+
+       /* STRB (register)      1111 1000 0000 xxxx xxxx 0000 00xx xxxx */
+       /* STRH (register)      1111 1000 0010 xxxx xxxx 0000 00xx xxxx */
+       /* LDRB (register)      1111 1000 0001 xxxx xxxx 0000 00xx xxxx */
+       /* LDRSB (register)     1111 1001 0001 xxxx xxxx 0000 00xx xxxx */
+       /* LDRH (register)      1111 1000 0011 xxxx xxxx 0000 00xx xxxx */
+       /* LDRSH (register)     1111 1001 0011 xxxx xxxx 0000 00xx xxxx */
+       DECODE_EMULATEX (0xfe800fc0, 0xf8000000, PROBES_T32_LDRSTR,
+                                                REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)),
+
+       /* Other unallocated instructions...                            */
+       DECODE_END
+};
+
+static const union decode_item t32_table_1111_1010___1111[] = {
+       /* Data-processing (register)                                   */
+
+       /* ???                  1111 1010 011x xxxx 1111 xxxx 1xxx xxxx */
+       DECODE_REJECT   (0xffe0f080, 0xfa60f080),
+
+       /* SXTH                 1111 1010 0000 1111 1111 xxxx 1xxx xxxx */
+       /* UXTH                 1111 1010 0001 1111 1111 xxxx 1xxx xxxx */
+       /* SXTB16               1111 1010 0010 1111 1111 xxxx 1xxx xxxx */
+       /* UXTB16               1111 1010 0011 1111 1111 xxxx 1xxx xxxx */
+       /* SXTB                 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */
+       /* UXTB                 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */
+       DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, PROBES_T32_SIGN_EXTEND,
+                                                REGS(0, 0, NOSPPC, 0, NOSPPC)),
+
+
+       /* ???                  1111 1010 1xxx xxxx 1111 xxxx 0x11 xxxx */
+       DECODE_REJECT   (0xff80f0b0, 0xfa80f030),
+       /* ???                  1111 1010 1x11 xxxx 1111 xxxx 0xxx xxxx */
+       DECODE_REJECT   (0xffb0f080, 0xfab0f000),
+
+       /* SADD16               1111 1010 1001 xxxx 1111 xxxx 0000 xxxx */
+       /* SASX                 1111 1010 1010 xxxx 1111 xxxx 0000 xxxx */
+       /* SSAX                 1111 1010 1110 xxxx 1111 xxxx 0000 xxxx */
+       /* SSUB16               1111 1010 1101 xxxx 1111 xxxx 0000 xxxx */
+       /* SADD8                1111 1010 1000 xxxx 1111 xxxx 0000 xxxx */
+       /* SSUB8                1111 1010 1100 xxxx 1111 xxxx 0000 xxxx */
+
+       /* QADD16               1111 1010 1001 xxxx 1111 xxxx 0001 xxxx */
+       /* QASX                 1111 1010 1010 xxxx 1111 xxxx 0001 xxxx */
+       /* QSAX                 1111 1010 1110 xxxx 1111 xxxx 0001 xxxx */
+       /* QSUB16               1111 1010 1101 xxxx 1111 xxxx 0001 xxxx */
+       /* QADD8                1111 1010 1000 xxxx 1111 xxxx 0001 xxxx */
+       /* QSUB8                1111 1010 1100 xxxx 1111 xxxx 0001 xxxx */
+
+       /* SHADD16              1111 1010 1001 xxxx 1111 xxxx 0010 xxxx */
+       /* SHASX                1111 1010 1010 xxxx 1111 xxxx 0010 xxxx */
+       /* SHSAX                1111 1010 1110 xxxx 1111 xxxx 0010 xxxx */
+       /* SHSUB16              1111 1010 1101 xxxx 1111 xxxx 0010 xxxx */
+       /* SHADD8               1111 1010 1000 xxxx 1111 xxxx 0010 xxxx */
+       /* SHSUB8               1111 1010 1100 xxxx 1111 xxxx 0010 xxxx */
+
+       /* UADD16               1111 1010 1001 xxxx 1111 xxxx 0100 xxxx */
+       /* UASX                 1111 1010 1010 xxxx 1111 xxxx 0100 xxxx */
+       /* USAX                 1111 1010 1110 xxxx 1111 xxxx 0100 xxxx */
+       /* USUB16               1111 1010 1101 xxxx 1111 xxxx 0100 xxxx */
+       /* UADD8                1111 1010 1000 xxxx 1111 xxxx 0100 xxxx */
+       /* USUB8                1111 1010 1100 xxxx 1111 xxxx 0100 xxxx */
+
+       /* UQADD16              1111 1010 1001 xxxx 1111 xxxx 0101 xxxx */
+       /* UQASX                1111 1010 1010 xxxx 1111 xxxx 0101 xxxx */
+       /* UQSAX                1111 1010 1110 xxxx 1111 xxxx 0101 xxxx */
+       /* UQSUB16              1111 1010 1101 xxxx 1111 xxxx 0101 xxxx */
+       /* UQADD8               1111 1010 1000 xxxx 1111 xxxx 0101 xxxx */
+       /* UQSUB8               1111 1010 1100 xxxx 1111 xxxx 0101 xxxx */
+
+       /* UHADD16              1111 1010 1001 xxxx 1111 xxxx 0110 xxxx */
+       /* UHASX                1111 1010 1010 xxxx 1111 xxxx 0110 xxxx */
+       /* UHSAX                1111 1010 1110 xxxx 1111 xxxx 0110 xxxx */
+       /* UHSUB16              1111 1010 1101 xxxx 1111 xxxx 0110 xxxx */
+       /* UHADD8               1111 1010 1000 xxxx 1111 xxxx 0110 xxxx */
+       /* UHSUB8               1111 1010 1100 xxxx 1111 xxxx 0110 xxxx */
+       DECODE_OR       (0xff80f080, 0xfa80f000),
+
+       /* SXTAH                1111 1010 0000 xxxx 1111 xxxx 1xxx xxxx */
+       /* UXTAH                1111 1010 0001 xxxx 1111 xxxx 1xxx xxxx */
+       /* SXTAB16              1111 1010 0010 xxxx 1111 xxxx 1xxx xxxx */
+       /* UXTAB16              1111 1010 0011 xxxx 1111 xxxx 1xxx xxxx */
+       /* SXTAB                1111 1010 0100 xxxx 1111 xxxx 1xxx xxxx */
+       /* UXTAB                1111 1010 0101 xxxx 1111 xxxx 1xxx xxxx */
+       DECODE_OR       (0xff80f080, 0xfa00f080),
+
+       /* QADD                 1111 1010 1000 xxxx 1111 xxxx 1000 xxxx */
+       /* QDADD                1111 1010 1000 xxxx 1111 xxxx 1001 xxxx */
+       /* QSUB                 1111 1010 1000 xxxx 1111 xxxx 1010 xxxx */
+       /* QDSUB                1111 1010 1000 xxxx 1111 xxxx 1011 xxxx */
+       DECODE_OR       (0xfff0f0c0, 0xfa80f080),
+
+       /* SEL                  1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */
+       DECODE_OR       (0xfff0f0f0, 0xfaa0f080),
+
+       /* LSL                  1111 1010 000x xxxx 1111 xxxx 0000 xxxx */
+       /* LSR                  1111 1010 001x xxxx 1111 xxxx 0000 xxxx */
+       /* ASR                  1111 1010 010x xxxx 1111 xxxx 0000 xxxx */
+       /* ROR                  1111 1010 011x xxxx 1111 xxxx 0000 xxxx */
+       DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, PROBES_T32_MEDIA,
+                                                REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)),
+
+       /* CLZ                  1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */
+       DECODE_OR       (0xfff0f0f0, 0xfab0f080),
+
+       /* REV                  1111 1010 1001 xxxx 1111 xxxx 1000 xxxx */
+       /* REV16                1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */
+       /* RBIT                 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */
+       /* REVSH                1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */
+       DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, PROBES_T32_REVERSE,
+                                                REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)),
+
+       /* Other unallocated instructions...                            */
+       DECODE_END
+};
+
+static const union decode_item t32_table_1111_1011_0[] = {
+       /* Multiply, multiply accumulate, and absolute difference       */
+
+       /* ???                  1111 1011 0000 xxxx 1111 xxxx 0001 xxxx */
+       DECODE_REJECT   (0xfff0f0f0, 0xfb00f010),
+       /* ???                  1111 1011 0111 xxxx 1111 xxxx 0001 xxxx */
+       DECODE_REJECT   (0xfff0f0f0, 0xfb70f010),
+
+       /* SMULxy               1111 1011 0001 xxxx 1111 xxxx 00xx xxxx */
+       DECODE_OR       (0xfff0f0c0, 0xfb10f000),
+       /* MUL                  1111 1011 0000 xxxx 1111 xxxx 0000 xxxx */
+       /* SMUAD{X}             1111 1011 0010 xxxx 1111 xxxx 000x xxxx */
+       /* SMULWy               1111 1011 0011 xxxx 1111 xxxx 000x xxxx */
+       /* SMUSD{X}             1111 1011 0100 xxxx 1111 xxxx 000x xxxx */
+       /* SMMUL{R}             1111 1011 0101 xxxx 1111 xxxx 000x xxxx */
+       /* USAD8                1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */
+       DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, PROBES_T32_MUL_ADD,
+                                                REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)),
+
+       /* ???                  1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */
+       DECODE_REJECT   (0xfff000f0, 0xfb700010),
+
+       /* SMLAxy               1111 1011 0001 xxxx xxxx xxxx 00xx xxxx */
+       DECODE_OR       (0xfff000c0, 0xfb100000),
+       /* MLA                  1111 1011 0000 xxxx xxxx xxxx 0000 xxxx */
+       /* MLS                  1111 1011 0000 xxxx xxxx xxxx 0001 xxxx */
+       /* SMLAD{X}             1111 1011 0010 xxxx xxxx xxxx 000x xxxx */
+       /* SMLAWy               1111 1011 0011 xxxx xxxx xxxx 000x xxxx */
+       /* SMLSD{X}             1111 1011 0100 xxxx xxxx xxxx 000x xxxx */
+       /* SMMLA{R}             1111 1011 0101 xxxx xxxx xxxx 000x xxxx */
+       /* SMMLS{R}             1111 1011 0110 xxxx xxxx xxxx 000x xxxx */
+       /* USADA8               1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */
+       DECODE_EMULATEX (0xff8000c0, 0xfb000000,  PROBES_T32_MUL_ADD2,
+                                                REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)),
+
+       /* Other unallocated instructions...                            */
+       DECODE_END
+};
+
+static const union decode_item t32_table_1111_1011_1[] = {
+       /* Long multiply, long multiply accumulate, and divide          */
+
+       /* UMAAL                1111 1011 1110 xxxx xxxx xxxx 0110 xxxx */
+       DECODE_OR       (0xfff000f0, 0xfbe00060),
+       /* SMLALxy              1111 1011 1100 xxxx xxxx xxxx 10xx xxxx */
+       DECODE_OR       (0xfff000c0, 0xfbc00080),
+       /* SMLALD{X}            1111 1011 1100 xxxx xxxx xxxx 110x xxxx */
+       /* SMLSLD{X}            1111 1011 1101 xxxx xxxx xxxx 110x xxxx */
+       DECODE_OR       (0xffe000e0, 0xfbc000c0),
+       /* SMULL                1111 1011 1000 xxxx xxxx xxxx 0000 xxxx */
+       /* UMULL                1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */
+       /* SMLAL                1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */
+       /* UMLAL                1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */
+       DECODE_EMULATEX (0xff9000f0, 0xfb800000, PROBES_T32_MUL_ADD_LONG,
+                                                REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)),
+
+       /* SDIV                 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */
+       /* UDIV                 1111 1011 1011 xxxx xxxx xxxx 1111 xxxx */
+       /* Other unallocated instructions...                            */
+       DECODE_END
+};
+
+const union decode_item probes_decode_thumb32_table[] = {
+
+       /*
+        * Load/store multiple instructions
+        *                      1110 100x x0xx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx),
+
+       /*
+        * Load/store dual, load/store exclusive, table branch
+        *                      1110 100x x1xx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx),
+
+       /*
+        * Data-processing (shifted register)
+        *                      1110 101x xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xfe000000, 0xea000000, t32_table_1110_101x),
+
+       /*
+        * Coprocessor instructions
+        *                      1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_REJECT   (0xfc000000, 0xec000000),
+
+       /*
+        * Data-processing (modified immediate)
+        *                      1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0),
+
+       /*
+        * Data-processing (plain binary immediate)
+        *                      1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0),
+
+       /*
+        * Branches and miscellaneous control
+        *                      1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1),
+
+       /*
+        * Advanced SIMD element or structure load/store instructions
+        *                      1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_REJECT   (0xff100000, 0xf9000000),
+
+       /*
+        * Memory hints
+        *                      1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111),
+
+       /*
+        * Store single data item
+        *                      1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx
+        * Load single data items
+        *                      1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xfe000000, 0xf8000000, t32_table_1111_100x),
+
+       /*
+        * Data-processing (register)
+        *                      1111 1010 xxxx xxxx 1111 xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xff00f000, 0xfa00f000, t32_table_1111_1010___1111),
+
+       /*
+        * Multiply, multiply accumulate, and absolute difference
+        *                      1111 1011 0xxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xff800000, 0xfb000000, t32_table_1111_1011_0),
+
+       /*
+        * Long multiply, long multiply accumulate, and divide
+        *                      1111 1011 1xxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xff800000, 0xfb800000, t32_table_1111_1011_1),
+
+       /*
+        * Coprocessor instructions
+        *                      1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx
+        */
+       DECODE_END
+};
+#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
+EXPORT_SYMBOL_GPL(probes_decode_thumb32_table);
+#endif
+
+static const union decode_item t16_table_1011[] = {
+       /* Miscellaneous 16-bit instructions                */
+
+       /* ADD (SP plus immediate)      1011 0000 0xxx xxxx */
+       /* SUB (SP minus immediate)     1011 0000 1xxx xxxx */
+       DECODE_SIMULATE (0xff00, 0xb000, PROBES_T16_ADD_SP),
+
+       /* CBZ                          1011 00x1 xxxx xxxx */
+       /* CBNZ                         1011 10x1 xxxx xxxx */
+       DECODE_SIMULATE (0xf500, 0xb100, PROBES_T16_CBZ),
+
+       /* SXTH                         1011 0010 00xx xxxx */
+       /* SXTB                         1011 0010 01xx xxxx */
+       /* UXTH                         1011 0010 10xx xxxx */
+       /* UXTB                         1011 0010 11xx xxxx */
+       /* REV                          1011 1010 00xx xxxx */
+       /* REV16                        1011 1010 01xx xxxx */
+       /* ???                          1011 1010 10xx xxxx */
+       /* REVSH                        1011 1010 11xx xxxx */
+       DECODE_REJECT   (0xffc0, 0xba80),
+       DECODE_EMULATE  (0xf500, 0xb000, PROBES_T16_SIGN_EXTEND),
+
+       /* PUSH                         1011 010x xxxx xxxx */
+       DECODE_CUSTOM   (0xfe00, 0xb400, PROBES_T16_PUSH),
+       /* POP                          1011 110x xxxx xxxx */
+       DECODE_CUSTOM   (0xfe00, 0xbc00, PROBES_T16_POP),
+
+       /*
+        * If-Then, and hints
+        *                              1011 1111 xxxx xxxx
+        */
+
+       /* YIELD                        1011 1111 0001 0000 */
+       DECODE_OR       (0xffff, 0xbf10),
+       /* SEV                          1011 1111 0100 0000 */
+       DECODE_EMULATE  (0xffff, 0xbf40, PROBES_T16_SEV),
+       /* NOP                          1011 1111 0000 0000 */
+       /* WFE                          1011 1111 0010 0000 */
+       /* WFI                          1011 1111 0011 0000 */
+       DECODE_SIMULATE (0xffcf, 0xbf00, PROBES_T16_WFE),
+       /* Unassigned hints             1011 1111 xxxx 0000 */
+       DECODE_REJECT   (0xff0f, 0xbf00),
+       /* IT                           1011 1111 xxxx xxxx */
+       DECODE_CUSTOM   (0xff00, 0xbf00, PROBES_T16_IT),
+
+       /* SETEND                       1011 0110 010x xxxx */
+       /* CPS                          1011 0110 011x xxxx */
+       /* BKPT                         1011 1110 xxxx xxxx */
+       /* And unallocated instructions...                  */
+       DECODE_END
+};
+
+const union decode_item probes_decode_thumb16_table[] = {
+
+       /*
+        * Shift (immediate), add, subtract, move, and compare
+        *                              00xx xxxx xxxx xxxx
+        */
+
+       /* CMP (immediate)              0010 1xxx xxxx xxxx */
+       DECODE_EMULATE  (0xf800, 0x2800, PROBES_T16_CMP),
+
+       /* ADD (register)               0001 100x xxxx xxxx */
+       /* SUB (register)               0001 101x xxxx xxxx */
+       /* LSL (immediate)              0000 0xxx xxxx xxxx */
+       /* LSR (immediate)              0000 1xxx xxxx xxxx */
+       /* ASR (immediate)              0001 0xxx xxxx xxxx */
+       /* ADD (immediate, Thumb)       0001 110x xxxx xxxx */
+       /* SUB (immediate, Thumb)       0001 111x xxxx xxxx */
+       /* MOV (immediate)              0010 0xxx xxxx xxxx */
+       /* ADD (immediate, Thumb)       0011 0xxx xxxx xxxx */
+       /* SUB (immediate, Thumb)       0011 1xxx xxxx xxxx */
+       DECODE_EMULATE  (0xc000, 0x0000, PROBES_T16_ADDSUB),
+
+       /*
+        * 16-bit Thumb data-processing instructions
+        *                              0100 00xx xxxx xxxx
+        */
+
+       /* TST (register)               0100 0010 00xx xxxx */
+       DECODE_EMULATE  (0xffc0, 0x4200, PROBES_T16_CMP),
+       /* CMP (register)               0100 0010 10xx xxxx */
+       /* CMN (register)               0100 0010 11xx xxxx */
+       DECODE_EMULATE  (0xff80, 0x4280, PROBES_T16_CMP),
+       /* AND (register)               0100 0000 00xx xxxx */
+       /* EOR (register)               0100 0000 01xx xxxx */
+       /* LSL (register)               0100 0000 10xx xxxx */
+       /* LSR (register)               0100 0000 11xx xxxx */
+       /* ASR (register)               0100 0001 00xx xxxx */
+       /* ADC (register)               0100 0001 01xx xxxx */
+       /* SBC (register)               0100 0001 10xx xxxx */
+       /* ROR (register)               0100 0001 11xx xxxx */
+       /* RSB (immediate)              0100 0010 01xx xxxx */
+       /* ORR (register)               0100 0011 00xx xxxx */
+       /* MUL                          0100 0011 00xx xxxx */
+       /* BIC (register)               0100 0011 10xx xxxx */
+       /* MVN (register)               0100 0011 10xx xxxx */
+       DECODE_EMULATE  (0xfc00, 0x4000, PROBES_T16_LOGICAL),
+
+       /*
+        * Special data instructions and branch and exchange
+        *                              0100 01xx xxxx xxxx
+        */
+
+       /* BLX pc                       0100 0111 1111 1xxx */
+       DECODE_REJECT   (0xfff8, 0x47f8),
+
+       /* BX (register)                0100 0111 0xxx xxxx */
+       /* BLX (register)               0100 0111 1xxx xxxx */
+       DECODE_SIMULATE (0xff00, 0x4700, PROBES_T16_BLX),
+
+       /* ADD pc, pc                   0100 0100 1111 1111 */
+       DECODE_REJECT   (0xffff, 0x44ff),
+
+       /* ADD (register)               0100 0100 xxxx xxxx */
+       /* CMP (register)               0100 0101 xxxx xxxx */
+       /* MOV (register)               0100 0110 xxxx xxxx */
+       DECODE_CUSTOM   (0xfc00, 0x4400, PROBES_T16_HIREGOPS),
+
+       /*
+        * Load from Literal Pool
+        * LDR (literal)                0100 1xxx xxxx xxxx
+        */
+       DECODE_SIMULATE (0xf800, 0x4800, PROBES_T16_LDR_LIT),
+
+       /*
+        * 16-bit Thumb Load/store instructions
+        *                              0101 xxxx xxxx xxxx
+        *                              011x xxxx xxxx xxxx
+        *                              100x xxxx xxxx xxxx
+        */
+
+       /* STR (register)               0101 000x xxxx xxxx */
+       /* STRH (register)              0101 001x xxxx xxxx */
+       /* STRB (register)              0101 010x xxxx xxxx */
+       /* LDRSB (register)             0101 011x xxxx xxxx */
+       /* LDR (register)               0101 100x xxxx xxxx */
+       /* LDRH (register)              0101 101x xxxx xxxx */
+       /* LDRB (register)              0101 110x xxxx xxxx */
+       /* LDRSH (register)             0101 111x xxxx xxxx */
+       /* STR (immediate, Thumb)       0110 0xxx xxxx xxxx */
+       /* LDR (immediate, Thumb)       0110 1xxx xxxx xxxx */
+       /* STRB (immediate, Thumb)      0111 0xxx xxxx xxxx */
+       /* LDRB (immediate, Thumb)      0111 1xxx xxxx xxxx */
+       DECODE_EMULATE  (0xc000, 0x4000, PROBES_T16_LDRHSTRH),
+       /* STRH (immediate, Thumb)      1000 0xxx xxxx xxxx */
+       /* LDRH (immediate, Thumb)      1000 1xxx xxxx xxxx */
+       DECODE_EMULATE  (0xf000, 0x8000, PROBES_T16_LDRHSTRH),
+       /* STR (immediate, Thumb)       1001 0xxx xxxx xxxx */
+       /* LDR (immediate, Thumb)       1001 1xxx xxxx xxxx */
+       DECODE_SIMULATE (0xf000, 0x9000, PROBES_T16_LDRSTR),
+
+       /*
+        * Generate PC-/SP-relative address
+        * ADR (literal)                1010 0xxx xxxx xxxx
+        * ADD (SP plus immediate)      1010 1xxx xxxx xxxx
+        */
+       DECODE_SIMULATE (0xf000, 0xa000, PROBES_T16_ADR),
+
+       /*
+        * Miscellaneous 16-bit instructions
+        *                              1011 xxxx xxxx xxxx
+        */
+       DECODE_TABLE    (0xf000, 0xb000, t16_table_1011),
+
+       /* STM                          1100 0xxx xxxx xxxx */
+       /* LDM                          1100 1xxx xxxx xxxx */
+       DECODE_EMULATE  (0xf000, 0xc000, PROBES_T16_LDMSTM),
+
+       /*
+        * Conditional branch, and Supervisor Call
+        */
+
+       /* Permanently UNDEFINED        1101 1110 xxxx xxxx */
+       /* SVC                          1101 1111 xxxx xxxx */
+       DECODE_REJECT   (0xfe00, 0xde00),
+
+       /* Conditional branch           1101 xxxx xxxx xxxx */
+       DECODE_CUSTOM   (0xf000, 0xd000, PROBES_T16_BRANCH_COND),
+
+       /*
+        * Unconditional branch
+        * B                            1110 0xxx xxxx xxxx
+        */
+       DECODE_SIMULATE (0xf800, 0xe000, PROBES_T16_BRANCH),
+
+       DECODE_END
+};
+#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
+EXPORT_SYMBOL_GPL(probes_decode_thumb16_table);
+#endif
+
+static unsigned long __kprobes thumb_check_cc(unsigned long cpsr)
+{
+       if (unlikely(in_it_block(cpsr)))
+               return probes_condition_checks[current_cond(cpsr)](cpsr);
+       return true;
+}
+
+static void __kprobes thumb16_singlestep(probes_opcode_t opcode,
+               struct arch_probes_insn *asi,
+               struct pt_regs *regs)
+{
+       regs->ARM_pc += 2;
+       asi->insn_handler(opcode, asi, regs);
+       regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
+}
+
+static void __kprobes thumb32_singlestep(probes_opcode_t opcode,
+               struct arch_probes_insn *asi,
+               struct pt_regs *regs)
+{
+       regs->ARM_pc += 4;
+       asi->insn_handler(opcode, asi, regs);
+       regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
+}
+
+enum probes_insn __kprobes
+thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
+                          bool emulate, const union decode_action *actions)
+{
+       asi->insn_singlestep = thumb16_singlestep;
+       asi->insn_check_cc = thumb_check_cc;
+       return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true,
+                                 emulate, actions);
+}
+
+enum probes_insn __kprobes
+thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
+                          bool emulate, const union decode_action *actions)
+{
+       asi->insn_singlestep = thumb32_singlestep;
+       asi->insn_check_cc = thumb_check_cc;
+       return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true,
+                                 emulate, actions);
+}
diff --git a/arch/arm/probes/decode-thumb.h b/arch/arm/probes/decode-thumb.h
new file mode 100644 (file)
index 0000000..039013c
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * arch/arm/probes/decode-thumb.h
+ *
+ * Copyright 2013 Linaro Ltd.
+ * Written by: David A. Long
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _ARM_KERNEL_PROBES_THUMB_H
+#define  _ARM_KERNEL_PROBES_THUMB_H
+
+#include "decode.h"
+
+/*
+ * True if current instruction is in an IT block.
+ */
+#define in_it_block(cpsr)      ((cpsr & 0x06000c00) != 0x00000000)
+
+/*
+ * Return the condition code to check for the currently executing instruction.
+ * This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if
+ * in_it_block returns true.
+ */
+#define current_cond(cpsr)     ((cpsr >> 12) & 0xf)
+
+enum probes_t32_action {
+       PROBES_T32_EMULATE_NONE,
+       PROBES_T32_SIMULATE_NOP,
+       PROBES_T32_LDMSTM,
+       PROBES_T32_LDRDSTRD,
+       PROBES_T32_TABLE_BRANCH,
+       PROBES_T32_TST,
+       PROBES_T32_CMP,
+       PROBES_T32_MOV,
+       PROBES_T32_ADDSUB,
+       PROBES_T32_LOGICAL,
+       PROBES_T32_ADDWSUBW_PC,
+       PROBES_T32_ADDWSUBW,
+       PROBES_T32_MOVW,
+       PROBES_T32_SAT,
+       PROBES_T32_BITFIELD,
+       PROBES_T32_SEV,
+       PROBES_T32_WFE,
+       PROBES_T32_MRS,
+       PROBES_T32_BRANCH_COND,
+       PROBES_T32_BRANCH,
+       PROBES_T32_PLDI,
+       PROBES_T32_LDR_LIT,
+       PROBES_T32_LDRSTR,
+       PROBES_T32_SIGN_EXTEND,
+       PROBES_T32_MEDIA,
+       PROBES_T32_REVERSE,
+       PROBES_T32_MUL_ADD,
+       PROBES_T32_MUL_ADD2,
+       PROBES_T32_MUL_ADD_LONG,
+       NUM_PROBES_T32_ACTIONS
+};
+
+enum probes_t16_action {
+       PROBES_T16_ADD_SP,
+       PROBES_T16_CBZ,
+       PROBES_T16_SIGN_EXTEND,
+       PROBES_T16_PUSH,
+       PROBES_T16_POP,
+       PROBES_T16_SEV,
+       PROBES_T16_WFE,
+       PROBES_T16_IT,
+       PROBES_T16_CMP,
+       PROBES_T16_ADDSUB,
+       PROBES_T16_LOGICAL,
+       PROBES_T16_BLX,
+       PROBES_T16_HIREGOPS,
+       PROBES_T16_LDR_LIT,
+       PROBES_T16_LDRHSTRH,
+       PROBES_T16_LDRSTR,
+       PROBES_T16_ADR,
+       PROBES_T16_LDMSTM,
+       PROBES_T16_BRANCH_COND,
+       PROBES_T16_BRANCH,
+       NUM_PROBES_T16_ACTIONS
+};
+
+extern const union decode_item probes_decode_thumb32_table[];
+extern const union decode_item probes_decode_thumb16_table[];
+
+enum probes_insn __kprobes
+thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
+               bool emulate, const union decode_action *actions);
+enum probes_insn __kprobes
+thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
+               bool emulate, const union decode_action *actions);
+
+#endif
diff --git a/arch/arm/probes/decode.c b/arch/arm/probes/decode.c
new file mode 100644 (file)
index 0000000..3b05d57
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * arch/arm/probes/decode.c
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
+ * Copyright (C) 2006, 2007 Motorola Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/system_info.h>
+#include <asm/ptrace.h>
+#include <linux/bug.h>
+
+#include "decode.h"
+
+
+#ifndef find_str_pc_offset
+
+/*
+ * For STR and STM instructions, an ARM core may choose to use either
+ * a +8 or a +12 displacement from the current instruction's address.
+ * Whichever value is chosen for a given core, it must be the same for
+ * both instructions and may not change.  This function measures it.
+ */
+
+int str_pc_offset;
+
+void __init find_str_pc_offset(void)
+{
+       int addr, scratch, ret;
+
+       __asm__ (
+               "sub    %[ret], pc, #4          \n\t"
+               "str    pc, %[addr]             \n\t"
+               "ldr    %[scr], %[addr]         \n\t"
+               "sub    %[ret], %[scr], %[ret]  \n\t"
+               : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr));
+
+       str_pc_offset = ret;
+}
+
+#endif /* !find_str_pc_offset */
+
+
+#ifndef test_load_write_pc_interworking
+
+bool load_write_pc_interworks;
+
+void __init test_load_write_pc_interworking(void)
+{
+       int arch = cpu_architecture();
+       BUG_ON(arch == CPU_ARCH_UNKNOWN);
+       load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T;
+}
+
+#endif /* !test_load_write_pc_interworking */
+
+
+#ifndef test_alu_write_pc_interworking
+
+bool alu_write_pc_interworks;
+
+void __init test_alu_write_pc_interworking(void)
+{
+       int arch = cpu_architecture();
+       BUG_ON(arch == CPU_ARCH_UNKNOWN);
+       alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7;
+}
+
+#endif /* !test_alu_write_pc_interworking */
+
+
+void __init arm_probes_decode_init(void)
+{
+       find_str_pc_offset();
+       test_load_write_pc_interworking();
+       test_alu_write_pc_interworking();
+}
+
+
+static unsigned long __kprobes __check_eq(unsigned long cpsr)
+{
+       return cpsr & PSR_Z_BIT;
+}
+
+static unsigned long __kprobes __check_ne(unsigned long cpsr)
+{
+       return (~cpsr) & PSR_Z_BIT;
+}
+
+static unsigned long __kprobes __check_cs(unsigned long cpsr)
+{
+       return cpsr & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_cc(unsigned long cpsr)
+{
+       return (~cpsr) & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_mi(unsigned long cpsr)
+{
+       return cpsr & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_pl(unsigned long cpsr)
+{
+       return (~cpsr) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_vs(unsigned long cpsr)
+{
+       return cpsr & PSR_V_BIT;
+}
+
+static unsigned long __kprobes __check_vc(unsigned long cpsr)
+{
+       return (~cpsr) & PSR_V_BIT;
+}
+
+static unsigned long __kprobes __check_hi(unsigned long cpsr)
+{
+       cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
+       return cpsr & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_ls(unsigned long cpsr)
+{
+       cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
+       return (~cpsr) & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_ge(unsigned long cpsr)
+{
+       cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+       return (~cpsr) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_lt(unsigned long cpsr)
+{
+       cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+       return cpsr & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_gt(unsigned long cpsr)
+{
+       unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+       temp |= (cpsr << 1);                     /* PSR_N_BIT |= PSR_Z_BIT */
+       return (~temp) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_le(unsigned long cpsr)
+{
+       unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+       temp |= (cpsr << 1);                     /* PSR_N_BIT |= PSR_Z_BIT */
+       return temp & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_al(unsigned long cpsr)
+{
+       return true;
+}
+
+probes_check_cc * const probes_condition_checks[16] = {
+       &__check_eq, &__check_ne, &__check_cs, &__check_cc,
+       &__check_mi, &__check_pl, &__check_vs, &__check_vc,
+       &__check_hi, &__check_ls, &__check_ge, &__check_lt,
+       &__check_gt, &__check_le, &__check_al, &__check_al
+};
+
+
+void __kprobes probes_simulate_nop(probes_opcode_t opcode,
+       struct arch_probes_insn *asi,
+       struct pt_regs *regs)
+{
+}
+
+void __kprobes probes_emulate_none(probes_opcode_t opcode,
+       struct arch_probes_insn *asi,
+       struct pt_regs *regs)
+{
+       asi->insn_fn();
+}
+
+/*
+ * Prepare an instruction slot to receive an instruction for emulating.
+ * This is done by placing a subroutine return after the location where the
+ * instruction will be placed. We also modify ARM instructions to be
+ * unconditional as the condition code will already be checked before any
+ * emulation handler is called.
+ */
+static probes_opcode_t __kprobes
+prepare_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
+                     bool thumb)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+       if (thumb) {
+               u16 *thumb_insn = (u16 *)asi->insn;
+               /* Thumb bx lr */
+               thumb_insn[1] = __opcode_to_mem_thumb16(0x4770);
+               thumb_insn[2] = __opcode_to_mem_thumb16(0x4770);
+               return insn;
+       }
+       asi->insn[1] = __opcode_to_mem_arm(0xe12fff1e); /* ARM bx lr */
+#else
+       asi->insn[1] = __opcode_to_mem_arm(0xe1a0f00e); /* mov pc, lr */
+#endif
+       /* Make an ARM instruction unconditional */
+       if (insn < 0xe0000000)
+               insn = (insn | 0xe0000000) & ~0x10000000;
+       return insn;
+}
+
+/*
+ * Write a (probably modified) instruction into the slot previously prepared by
+ * prepare_emulated_insn
+ */
+static void  __kprobes
+set_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
+                 bool thumb)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+       if (thumb) {
+               u16 *ip = (u16 *)asi->insn;
+               if (is_wide_instruction(insn))
+                       *ip++ = __opcode_to_mem_thumb16(insn >> 16);
+               *ip++ = __opcode_to_mem_thumb16(insn);
+               return;
+       }
+#endif
+       asi->insn[0] = __opcode_to_mem_arm(insn);
+}
+
+/*
+ * When we modify the register numbers encoded in an instruction to be emulated,
+ * the new values come from this define. For ARM and 32-bit Thumb instructions
+ * this gives...
+ *
+ *     bit position      16  12   8   4   0
+ *     ---------------+---+---+---+---+---+
+ *     register         r2  r0  r1  --  r3
+ */
+#define INSN_NEW_BITS          0x00020103
+
+/* Each nibble has same value as that at INSN_NEW_BITS bit 16 */
+#define INSN_SAMEAS16_BITS     0x22222222
+
+/*
+ * Validate and modify each of the registers encoded in an instruction.
+ *
+ * Each nibble in regs contains a value from enum decode_reg_type. For each
+ * non-zero value, the corresponding nibble in pinsn is validated and modified
+ * according to the type.
+ */
+static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs, bool modify)
+{
+       probes_opcode_t insn = *pinsn;
+       probes_opcode_t mask = 0xf; /* Start at least significant nibble */
+
+       for (; regs != 0; regs >>= 4, mask <<= 4) {
+
+               probes_opcode_t new_bits = INSN_NEW_BITS;
+
+               switch (regs & 0xf) {
+
+               case REG_TYPE_NONE:
+                       /* Nibble not a register, skip to next */
+                       continue;
+
+               case REG_TYPE_ANY:
+                       /* Any register is allowed */
+                       break;
+
+               case REG_TYPE_SAMEAS16:
+                       /* Replace register with same as at bit position 16 */
+                       new_bits = INSN_SAMEAS16_BITS;
+                       break;
+
+               case REG_TYPE_SP:
+                       /* Only allow SP (R13) */
+                       if ((insn ^ 0xdddddddd) & mask)
+                               goto reject;
+                       break;
+
+               case REG_TYPE_PC:
+                       /* Only allow PC (R15) */
+                       if ((insn ^ 0xffffffff) & mask)
+                               goto reject;
+                       break;
+
+               case REG_TYPE_NOSP:
+                       /* Reject SP (R13) */
+                       if (((insn ^ 0xdddddddd) & mask) == 0)
+                               goto reject;
+                       break;
+
+               case REG_TYPE_NOSPPC:
+               case REG_TYPE_NOSPPCX:
+                       /* Reject SP and PC (R13 and R15) */
+                       if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0)
+                               goto reject;
+                       break;
+
+               case REG_TYPE_NOPCWB:
+                       if (!is_writeback(insn))
+                               break; /* No writeback, so any register is OK */
+                       /* fall through... */
+               case REG_TYPE_NOPC:
+               case REG_TYPE_NOPCX:
+                       /* Reject PC (R15) */
+                       if (((insn ^ 0xffffffff) & mask) == 0)
+                               goto reject;
+                       break;
+               }
+
+               /* Replace value of nibble with new register number... */
+               insn &= ~mask;
+               insn |= new_bits & mask;
+       }
+
+       if (modify)
+               *pinsn = insn;
+
+       return true;
+
+reject:
+       return false;
+}
+
+static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
+       [DECODE_TYPE_TABLE]     = sizeof(struct decode_table),
+       [DECODE_TYPE_CUSTOM]    = sizeof(struct decode_custom),
+       [DECODE_TYPE_SIMULATE]  = sizeof(struct decode_simulate),
+       [DECODE_TYPE_EMULATE]   = sizeof(struct decode_emulate),
+       [DECODE_TYPE_OR]        = sizeof(struct decode_or),
+       [DECODE_TYPE_REJECT]    = sizeof(struct decode_reject)
+};
+
+/*
+ * probes_decode_insn operates on data tables in order to decode an ARM
+ * architecture instruction onto which a kprobe has been placed.
+ *
+ * These instruction decoding tables are a concatenation of entries each
+ * of which consist of one of the following structs:
+ *
+ *     decode_table
+ *     decode_custom
+ *     decode_simulate
+ *     decode_emulate
+ *     decode_or
+ *     decode_reject
+ *
+ * Each of these starts with a struct decode_header which has the following
+ * fields:
+ *
+ *     type_regs
+ *     mask
+ *     value
+ *
+ * The least significant DECODE_TYPE_BITS of type_regs contains a value
+ * from enum decode_type, this indicates which of the decode_* structs
+ * the entry contains. The value DECODE_TYPE_END indicates the end of the
+ * table.
+ *
+ * When the table is parsed, each entry is checked in turn to see if it
+ * matches the instruction to be decoded using the test:
+ *
+ *     (insn & mask) == value
+ *
+ * If no match is found before the end of the table is reached then decoding
+ * fails with INSN_REJECTED.
+ *
+ * When a match is found, decode_regs() is called to validate and modify each
+ * of the registers encoded in the instruction; the data it uses to do this
+ * is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding
+ * to fail with INSN_REJECTED.
+ *
+ * Once the instruction has passed the above tests, further processing
+ * depends on the type of the table entry's decode struct.
+ *
+ */
+int __kprobes
+probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
+                  const union decode_item *table, bool thumb,
+                  bool emulate, const union decode_action *actions)
+{
+       const struct decode_header *h = (struct decode_header *)table;
+       const struct decode_header *next;
+       bool matched = false;
+
+       if (emulate)
+               insn = prepare_emulated_insn(insn, asi, thumb);
+
+       for (;; h = next) {
+               enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
+               u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
+
+               if (type == DECODE_TYPE_END)
+                       return INSN_REJECTED;
+
+               next = (struct decode_header *)
+                               ((uintptr_t)h + decode_struct_sizes[type]);
+
+               if (!matched && (insn & h->mask.bits) != h->value.bits)
+                       continue;
+
+               if (!decode_regs(&insn, regs, emulate))
+                       return INSN_REJECTED;
+
+               switch (type) {
+
+               case DECODE_TYPE_TABLE: {
+                       struct decode_table *d = (struct decode_table *)h;
+                       next = (struct decode_header *)d->table.table;
+                       break;
+               }
+
+               case DECODE_TYPE_CUSTOM: {
+                       struct decode_custom *d = (struct decode_custom *)h;
+                       return actions[d->decoder.action].decoder(insn, asi, h);
+               }
+
+               case DECODE_TYPE_SIMULATE: {
+                       struct decode_simulate *d = (struct decode_simulate *)h;
+                       asi->insn_handler = actions[d->handler.action].handler;
+                       return INSN_GOOD_NO_SLOT;
+               }
+
+               case DECODE_TYPE_EMULATE: {
+                       struct decode_emulate *d = (struct decode_emulate *)h;
+
+                       if (!emulate)
+                               return actions[d->handler.action].decoder(insn,
+                                       asi, h);
+
+                       asi->insn_handler = actions[d->handler.action].handler;
+                       set_emulated_insn(insn, asi, thumb);
+                       return INSN_GOOD;
+               }
+
+               case DECODE_TYPE_OR:
+                       matched = true;
+                       break;
+
+               case DECODE_TYPE_REJECT:
+               default:
+                       return INSN_REJECTED;
+               }
+       }
+}
diff --git a/arch/arm/probes/decode.h b/arch/arm/probes/decode.h
new file mode 100644 (file)
index 0000000..1d0b531
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * arch/arm/probes/decode.h
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * Some contents moved here from arch/arm/include/asm/kprobes.h which is
+ * Copyright (C) 2006, 2007 Motorola Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _ARM_KERNEL_PROBES_H
+#define  _ARM_KERNEL_PROBES_H
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <asm/probes.h>
+
+void __init arm_probes_decode_init(void);
+
+extern probes_check_cc * const probes_condition_checks[16];
+
+#if __LINUX_ARM_ARCH__ >= 7
+
+/* str_pc_offset is architecturally defined from ARMv7 onwards */
+#define str_pc_offset 8
+#define find_str_pc_offset()
+
+#else /* __LINUX_ARM_ARCH__ < 7 */
+
+/* We need a run-time check to determine str_pc_offset */
+extern int str_pc_offset;
+void __init find_str_pc_offset(void);
+
+#endif
+
+
+/*
+ * Update ITSTATE after normal execution of an IT block instruction.
+ *
+ * The 8 IT state bits are split into two parts in CPSR:
+ *     ITSTATE<1:0> are in CPSR<26:25>
+ *     ITSTATE<7:2> are in CPSR<15:10>
+ */
+static inline unsigned long it_advance(unsigned long cpsr)
+       {
+       if ((cpsr & 0x06000400) == 0) {
+               /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
+               cpsr &= ~PSR_IT_MASK;
+       } else {
+               /* We need to shift left ITSTATE<4:0> */
+               const unsigned long mask = 0x06001c00;  /* Mask ITSTATE<4:0> */
+               unsigned long it = cpsr & mask;
+               it <<= 1;
+               it |= it >> (27 - 10);  /* Carry ITSTATE<2> to correct place */
+               it &= mask;
+               cpsr &= ~mask;
+               cpsr |= it;
+       }
+       return cpsr;
+}
+
+static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs)
+{
+       long cpsr = regs->ARM_cpsr;
+       if (pcv & 0x1) {
+               cpsr |= PSR_T_BIT;
+               pcv &= ~0x1;
+       } else {
+               cpsr &= ~PSR_T_BIT;
+               pcv &= ~0x2;    /* Avoid UNPREDICTABLE address allignment */
+       }
+       regs->ARM_cpsr = cpsr;
+       regs->ARM_pc = pcv;
+}
+
+
+#if __LINUX_ARM_ARCH__ >= 6
+
+/* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */
+#define load_write_pc_interworks true
+#define test_load_write_pc_interworking()
+
+#else /* __LINUX_ARM_ARCH__ < 6 */
+
+/* We need run-time testing to determine if load_write_pc() should interwork. */
+extern bool load_write_pc_interworks;
+void __init test_load_write_pc_interworking(void);
+
+#endif
+
+static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs)
+{
+       if (load_write_pc_interworks)
+               bx_write_pc(pcv, regs);
+       else
+               regs->ARM_pc = pcv;
+}
+
+
+#if __LINUX_ARM_ARCH__ >= 7
+
+#define alu_write_pc_interworks true
+#define test_alu_write_pc_interworking()
+
+#elif __LINUX_ARM_ARCH__ <= 5
+
+/* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */
+#define alu_write_pc_interworks false
+#define test_alu_write_pc_interworking()
+
+#else /* __LINUX_ARM_ARCH__ == 6 */
+
+/* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */
+extern bool alu_write_pc_interworks;
+void __init test_alu_write_pc_interworking(void);
+
+#endif /* __LINUX_ARM_ARCH__ == 6 */
+
+static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs)
+{
+       if (alu_write_pc_interworks)
+               bx_write_pc(pcv, regs);
+       else
+               regs->ARM_pc = pcv;
+}
+
+
+/*
+ * Test if load/store instructions writeback the address register.
+ * if P (bit 24) == 0 or W (bit 21) == 1
+ */
+#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000)
+
+/*
+ * The following definitions and macros are used to build instruction
+ * decoding tables for use by probes_decode_insn.
+ *
+ * These tables are a concatenation of entries each of which consist of one of
+ * the decode_* structs. All of the fields in every type of decode structure
+ * are of the union type decode_item, therefore the entire decode table can be
+ * viewed as an array of these and declared like:
+ *
+ *     static const union decode_item table_name[] = {};
+ *
+ * In order to construct each entry in the table, macros are used to
+ * initialise a number of sequential decode_item values in a layout which
+ * matches the relevant struct. E.g. DECODE_SIMULATE initialise a struct
+ * decode_simulate by initialising four decode_item objects like this...
+ *
+ *     {.bits = _type},
+ *     {.bits = _mask},
+ *     {.bits = _value},
+ *     {.action = _handler},
+ *
+ * Initialising a specified member of the union means that the compiler
+ * will produce a warning if the argument is of an incorrect type.
+ *
+ * Below is a list of each of the macros used to initialise entries and a
+ * description of the action performed when that entry is matched to an
+ * instruction. A match is found when (instruction & mask) == value.
+ *
+ * DECODE_TABLE(mask, value, table)
+ *     Instruction decoding jumps to parsing the new sub-table 'table'.
+ *
+ * DECODE_CUSTOM(mask, value, decoder)
+ *     The value of 'decoder' is used as an index into the array of
+ *     action functions, and the retrieved decoder function is invoked
+ *     to complete decoding of the instruction.
+ *
+ * DECODE_SIMULATE(mask, value, handler)
+ *     The probes instruction handler is set to the value found by
+ *     indexing into the action array using the value of 'handler'. This
+ *     will be used to simulate the instruction when the probe is hit.
+ *     Decoding returns with INSN_GOOD_NO_SLOT.
+ *
+ * DECODE_EMULATE(mask, value, handler)
+ *     The probes instruction handler is set to the value found by
+ *     indexing into the action array using the value of 'handler'. This
+ *     will be used to emulate the instruction when the probe is hit. The
+ *     modified instruction (see below) is placed in the probes instruction
+ *     slot so it may be called by the emulation code. Decoding returns
+ *     with INSN_GOOD.
+ *
+ * DECODE_REJECT(mask, value)
+ *     Instruction decoding fails with INSN_REJECTED
+ *
+ * DECODE_OR(mask, value)
+ *     This allows the mask/value test of multiple table entries to be
+ *     logically ORed. Once an 'or' entry is matched the decoding action to
+ *     be performed is that of the next entry which isn't an 'or'. E.g.
+ *
+ *             DECODE_OR       (mask1, value1)
+ *             DECODE_OR       (mask2, value2)
+ *             DECODE_SIMULATE (mask3, value3, simulation_handler)
+ *
+ *     This means that if any of the three mask/value pairs match the
+ *     instruction being decoded, then 'simulation_handler' will be used
+ *     for it.
+ *
+ * Both the SIMULATE and EMULATE macros have a second form which take an
+ * additional 'regs' argument.
+ *
+ *     DECODE_SIMULATEX(mask, value, handler, regs)
+ *     DECODE_EMULATEX (mask, value, handler, regs)
+ *
+ * These are used to specify what kind of CPU register is encoded in each of the
+ * least significant 5 nibbles of the instruction being decoded. The regs value
+ * is specified using the REGS macro, this takes any of the REG_TYPE_* values
+ * from enum decode_reg_type as arguments; only the '*' part of the name is
+ * given. E.g.
+ *
+ *     REGS(0, ANY, NOPC, 0, ANY)
+ *
+ * This indicates an instruction is encoded like:
+ *
+ *     bits 19..16     ignore
+ *     bits 15..12     any register allowed here
+ *     bits 11.. 8     any register except PC allowed here
+ *     bits  7.. 4     ignore
+ *     bits  3.. 0     any register allowed here
+ *
+ * This register specification is checked after a decode table entry is found to
+ * match an instruction (through the mask/value test). Any invalid register then
+ * found in the instruction will cause decoding to fail with INSN_REJECTED. In
+ * the above example this would happen if bits 11..8 of the instruction were
+ * 1111, indicating R15 or PC.
+ *
+ * As well as checking for legal combinations of registers, this data is also
+ * used to modify the registers encoded in the instructions so that an
+ * emulation routines can use it. (See decode_regs() and INSN_NEW_BITS.)
+ *
+ * Here is a real example which matches ARM instructions of the form
+ * "AND <Rd>,<Rn>,<Rm>,<shift> <Rs>"
+ *
+ *     DECODE_EMULATEX (0x0e000090, 0x00000010, PROBES_DATA_PROCESSING_REG,
+ *                                              REGS(ANY, ANY, NOPC, 0, ANY)),
+ *                                                   ^    ^    ^        ^
+ *                                                   Rn   Rd   Rs       Rm
+ *
+ * Decoding the instruction "AND R4, R5, R6, ASL R15" will be rejected because
+ * Rs == R15
+ *
+ * Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the
+ * instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into
+ * the kprobes instruction slot. This can then be called later by the handler
+ * function emulate_rd12rn16rm0rs8_rwflags (a pointer to which is retrieved from
+ * the indicated slot in the action array), in order to simulate the instruction.
+ */
+
+enum decode_type {
+       DECODE_TYPE_END,
+       DECODE_TYPE_TABLE,
+       DECODE_TYPE_CUSTOM,
+       DECODE_TYPE_SIMULATE,
+       DECODE_TYPE_EMULATE,
+       DECODE_TYPE_OR,
+       DECODE_TYPE_REJECT,
+       NUM_DECODE_TYPES /* Must be last enum */
+};
+
+#define DECODE_TYPE_BITS       4
+#define DECODE_TYPE_MASK       ((1 << DECODE_TYPE_BITS) - 1)
+
+enum decode_reg_type {
+       REG_TYPE_NONE = 0, /* Not a register, ignore */
+       REG_TYPE_ANY,      /* Any register allowed */
+       REG_TYPE_SAMEAS16, /* Register should be same as that at bits 19..16 */
+       REG_TYPE_SP,       /* Register must be SP */
+       REG_TYPE_PC,       /* Register must be PC */
+       REG_TYPE_NOSP,     /* Register must not be SP */
+       REG_TYPE_NOSPPC,   /* Register must not be SP or PC */
+       REG_TYPE_NOPC,     /* Register must not be PC */
+       REG_TYPE_NOPCWB,   /* No PC if load/store write-back flag also set */
+
+       /* The following types are used when the encoding for PC indicates
+        * another instruction form. This distiction only matters for test
+        * case coverage checks.
+        */
+       REG_TYPE_NOPCX,    /* Register must not be PC */
+       REG_TYPE_NOSPPCX,  /* Register must not be SP or PC */
+
+       /* Alias to allow '0' arg to be used in REGS macro. */
+       REG_TYPE_0 = REG_TYPE_NONE
+};
+
+#define REGS(r16, r12, r8, r4, r0)     \
+       (((REG_TYPE_##r16) << 16) +     \
+       ((REG_TYPE_##r12) << 12) +      \
+       ((REG_TYPE_##r8) << 8) +        \
+       ((REG_TYPE_##r4) << 4) +        \
+       (REG_TYPE_##r0))
+
+union decode_item {
+       u32                     bits;
+       const union decode_item *table;
+       int                     action;
+};
+
+struct decode_header;
+typedef enum probes_insn (probes_custom_decode_t)(probes_opcode_t,
+                                                 struct arch_probes_insn *,
+                                                 const struct decode_header *);
+
+union decode_action {
+       probes_insn_handler_t   *handler;
+       probes_custom_decode_t  *decoder;
+};
+
+#define DECODE_END                     \
+       {.bits = DECODE_TYPE_END}
+
+
+struct decode_header {
+       union decode_item       type_regs;
+       union decode_item       mask;
+       union decode_item       value;
+};
+
+#define DECODE_HEADER(_type, _mask, _value, _regs)             \
+       {.bits = (_type) | ((_regs) << DECODE_TYPE_BITS)},      \
+       {.bits = (_mask)},                                      \
+       {.bits = (_value)}
+
+
+struct decode_table {
+       struct decode_header    header;
+       union decode_item       table;
+};
+
+#define DECODE_TABLE(_mask, _value, _table)                    \
+       DECODE_HEADER(DECODE_TYPE_TABLE, _mask, _value, 0),     \
+       {.table = (_table)}
+
+
+struct decode_custom {
+       struct decode_header    header;
+       union decode_item       decoder;
+};
+
+#define DECODE_CUSTOM(_mask, _value, _decoder)                 \
+       DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0),    \
+       {.action = (_decoder)}
+
+
+struct decode_simulate {
+       struct decode_header    header;
+       union decode_item       handler;
+};
+
+#define DECODE_SIMULATEX(_mask, _value, _handler, _regs)               \
+       DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs),      \
+       {.action = (_handler)}
+
+#define DECODE_SIMULATE(_mask, _value, _handler)       \
+       DECODE_SIMULATEX(_mask, _value, _handler, 0)
+
+
+struct decode_emulate {
+       struct decode_header    header;
+       union decode_item       handler;
+};
+
+#define DECODE_EMULATEX(_mask, _value, _handler, _regs)                        \
+       DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs),       \
+       {.action = (_handler)}
+
+#define DECODE_EMULATE(_mask, _value, _handler)                \
+       DECODE_EMULATEX(_mask, _value, _handler, 0)
+
+
+struct decode_or {
+       struct decode_header    header;
+};
+
+#define DECODE_OR(_mask, _value)                               \
+       DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0)
+
+enum probes_insn {
+       INSN_REJECTED,
+       INSN_GOOD,
+       INSN_GOOD_NO_SLOT
+};
+
+struct decode_reject {
+       struct decode_header    header;
+};
+
+#define DECODE_REJECT(_mask, _value)                           \
+       DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0)
+
+probes_insn_handler_t probes_simulate_nop;
+probes_insn_handler_t probes_emulate_none;
+
+int __kprobes
+probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
+               const union decode_item *table, bool thumb, bool emulate,
+               const union decode_action *actions);
+
+#endif
diff --git a/arch/arm/probes/kprobes/Makefile b/arch/arm/probes/kprobes/Makefile
new file mode 100644 (file)
index 0000000..eb38a42
--- /dev/null
@@ -0,0 +1,11 @@
+obj-$(CONFIG_KPROBES)          += core.o actions-common.o
+obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
+test-kprobes-objs              := test-core.o
+
+ifdef CONFIG_THUMB2_KERNEL
+obj-$(CONFIG_KPROBES)          += actions-thumb.o
+test-kprobes-objs              += test-thumb.o
+else
+obj-$(CONFIG_KPROBES)          += actions-arm.o
+test-kprobes-objs              += test-arm.o
+endif
diff --git a/arch/arm/probes/kprobes/actions-arm.c b/arch/arm/probes/kprobes/actions-arm.c
new file mode 100644 (file)
index 0000000..8797879
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * arch/arm/probes/kprobes/actions-arm.c
+ *
+ * Copyright (C) 2006, 2007 Motorola Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * We do not have hardware single-stepping on ARM, This
+ * effort is further complicated by the ARM not having a
+ * "next PC" register.  Instructions that change the PC
+ * can't be safely single-stepped in a MP environment, so
+ * we have a lot of work to do:
+ *
+ * In the prepare phase:
+ *   *) If it is an instruction that does anything
+ *      with the CPU mode, we reject it for a kprobe.
+ *      (This is out of laziness rather than need.  The
+ *      instructions could be simulated.)
+ *
+ *   *) Otherwise, decode the instruction rewriting its
+ *      registers to take fixed, ordered registers and
+ *      setting a handler for it to run the instruction.
+ *
+ * In the execution phase by an instruction's handler:
+ *
+ *   *) If the PC is written to by the instruction, the
+ *      instruction must be fully simulated in software.
+ *
+ *   *) Otherwise, a modified form of the instruction is
+ *      directly executed.  Its handler calls the
+ *      instruction in insn[0].  In insn[1] is a
+ *      "mov pc, lr" to return.
+ *
+ *      Before calling, load up the reordered registers
+ *      from the original instruction's registers.  If one
+ *      of the original input registers is the PC, compute
+ *      and adjust the appropriate input register.
+ *
+ *     After call completes, copy the output registers to
+ *      the original instruction's original registers.
+ *
+ * We don't use a real breakpoint instruction since that
+ * would have us in the kernel go from SVC mode to SVC
+ * mode losing the link register.  Instead we use an
+ * undefined instruction.  To simplify processing, the
+ * undefined instruction used for kprobes must be reserved
+ * exclusively for kprobes use.
+ *
+ * TODO: ifdef out some instruction decoding based on architecture.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/ptrace.h>
+
+#include "../decode-arm.h"
+#include "core.h"
+
+#if  __LINUX_ARM_ARCH__ >= 6
+#define BLX(reg)       "blx    "reg"           \n\t"
+#else
+#define BLX(reg)       "mov    lr, pc          \n\t"   \
+                       "mov    pc, "reg"       \n\t"
+#endif
+
+static void __kprobes
+emulate_ldrdstrd(probes_opcode_t insn,
+       struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc + 4;
+       int rt = (insn >> 12) & 0xf;
+       int rn = (insn >> 16) & 0xf;
+       int rm = insn & 0xf;
+
+       register unsigned long rtv asm("r0") = regs->uregs[rt];
+       register unsigned long rt2v asm("r1") = regs->uregs[rt+1];
+       register unsigned long rnv asm("r2") = (rn == 15) ? pc
+                                                         : regs->uregs[rn];
+       register unsigned long rmv asm("r3") = regs->uregs[rm];
+
+       __asm__ __volatile__ (
+               BLX("%[fn]")
+               : "=r" (rtv), "=r" (rt2v), "=r" (rnv)
+               : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
+                 [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rt] = rtv;
+       regs->uregs[rt+1] = rt2v;
+       if (is_writeback(insn))
+               regs->uregs[rn] = rnv;
+}
+
+static void __kprobes
+emulate_ldr(probes_opcode_t insn,
+       struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc + 4;
+       int rt = (insn >> 12) & 0xf;
+       int rn = (insn >> 16) & 0xf;
+       int rm = insn & 0xf;
+
+       register unsigned long rtv asm("r0");
+       register unsigned long rnv asm("r2") = (rn == 15) ? pc
+                                                         : regs->uregs[rn];
+       register unsigned long rmv asm("r3") = regs->uregs[rm];
+
+       __asm__ __volatile__ (
+               BLX("%[fn]")
+               : "=r" (rtv), "=r" (rnv)
+               : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       if (rt == 15)
+               load_write_pc(rtv, regs);
+       else
+               regs->uregs[rt] = rtv;
+
+       if (is_writeback(insn))
+               regs->uregs[rn] = rnv;
+}
+
+static void __kprobes
+emulate_str(probes_opcode_t insn,
+       struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset;
+       unsigned long rnpc = regs->ARM_pc + 4;
+       int rt = (insn >> 12) & 0xf;
+       int rn = (insn >> 16) & 0xf;
+       int rm = insn & 0xf;
+
+       register unsigned long rtv asm("r0") = (rt == 15) ? rtpc
+                                                         : regs->uregs[rt];
+       register unsigned long rnv asm("r2") = (rn == 15) ? rnpc
+                                                         : regs->uregs[rn];
+       register unsigned long rmv asm("r3") = regs->uregs[rm];
+
+       __asm__ __volatile__ (
+               BLX("%[fn]")
+               : "=r" (rnv)
+               : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       if (is_writeback(insn))
+               regs->uregs[rn] = rnv;
+}
+
+static void __kprobes
+emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
+       struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc + 4;
+       int rd = (insn >> 12) & 0xf;
+       int rn = (insn >> 16) & 0xf;
+       int rm = insn & 0xf;
+       int rs = (insn >> 8) & 0xf;
+
+       register unsigned long rdv asm("r0") = regs->uregs[rd];
+       register unsigned long rnv asm("r2") = (rn == 15) ? pc
+                                                         : regs->uregs[rn];
+       register unsigned long rmv asm("r3") = (rm == 15) ? pc
+                                                         : regs->uregs[rm];
+       register unsigned long rsv asm("r1") = regs->uregs[rs];
+       unsigned long cpsr = regs->ARM_cpsr;
+
+       __asm__ __volatile__ (
+               "msr    cpsr_fs, %[cpsr]        \n\t"
+               BLX("%[fn]")
+               "mrs    %[cpsr], cpsr           \n\t"
+               : "=r" (rdv), [cpsr] "=r" (cpsr)
+               : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
+                 "1" (cpsr), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       if (rd == 15)
+               alu_write_pc(rdv, regs);
+       else
+               regs->uregs[rd] = rdv;
+       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
+}
+
+static void __kprobes
+emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn,
+       struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       int rd = (insn >> 12) & 0xf;
+       int rn = (insn >> 16) & 0xf;
+       int rm = insn & 0xf;
+
+       register unsigned long rdv asm("r0") = regs->uregs[rd];
+       register unsigned long rnv asm("r2") = regs->uregs[rn];
+       register unsigned long rmv asm("r3") = regs->uregs[rm];
+       unsigned long cpsr = regs->ARM_cpsr;
+
+       __asm__ __volatile__ (
+               "msr    cpsr_fs, %[cpsr]        \n\t"
+               BLX("%[fn]")
+               "mrs    %[cpsr], cpsr           \n\t"
+               : "=r" (rdv), [cpsr] "=r" (cpsr)
+               : "0" (rdv), "r" (rnv), "r" (rmv),
+                 "1" (cpsr), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rd] = rdv;
+       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
+}
+
+static void __kprobes
+emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn,
+       struct arch_probes_insn *asi,
+       struct pt_regs *regs)
+{
+       int rd = (insn >> 16) & 0xf;
+       int rn = (insn >> 12) & 0xf;
+       int rm = insn & 0xf;
+       int rs = (insn >> 8) & 0xf;
+
+       register unsigned long rdv asm("r2") = regs->uregs[rd];
+       register unsigned long rnv asm("r0") = regs->uregs[rn];
+       register unsigned long rmv asm("r3") = regs->uregs[rm];
+       register unsigned long rsv asm("r1") = regs->uregs[rs];
+       unsigned long cpsr = regs->ARM_cpsr;
+
+       __asm__ __volatile__ (
+               "msr    cpsr_fs, %[cpsr]        \n\t"
+               BLX("%[fn]")
+               "mrs    %[cpsr], cpsr           \n\t"
+               : "=r" (rdv), [cpsr] "=r" (cpsr)
+               : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
+                 "1" (cpsr), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rd] = rdv;
+       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
+}
+
+static void __kprobes
+emulate_rd12rm0_noflags_nopc(probes_opcode_t insn,
+       struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       int rd = (insn >> 12) & 0xf;
+       int rm = insn & 0xf;
+
+       register unsigned long rdv asm("r0") = regs->uregs[rd];
+       register unsigned long rmv asm("r3") = regs->uregs[rm];
+
+       __asm__ __volatile__ (
+               BLX("%[fn]")
+               : "=r" (rdv)
+               : "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rd] = rdv;
+}
+
+static void __kprobes
+emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
+       struct arch_probes_insn *asi,
+       struct pt_regs *regs)
+{
+       int rdlo = (insn >> 12) & 0xf;
+       int rdhi = (insn >> 16) & 0xf;
+       int rn = insn & 0xf;
+       int rm = (insn >> 8) & 0xf;
+
+       register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
+       register unsigned long rdhiv asm("r2") = regs->uregs[rdhi];
+       register unsigned long rnv asm("r3") = regs->uregs[rn];
+       register unsigned long rmv asm("r1") = regs->uregs[rm];
+       unsigned long cpsr = regs->ARM_cpsr;
+
+       __asm__ __volatile__ (
+               "msr    cpsr_fs, %[cpsr]        \n\t"
+               BLX("%[fn]")
+               "mrs    %[cpsr], cpsr           \n\t"
+               : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr)
+               : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
+                 "2" (cpsr), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rdlo] = rdlov;
+       regs->uregs[rdhi] = rdhiv;
+       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
+}
+
+const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
+       [PROBES_EMULATE_NONE] = {.handler = probes_emulate_none},
+       [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
+       [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
+       [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
+       [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
+       [PROBES_MRS] = {.handler = simulate_mrs},
+       [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
+       [PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc},
+       [PROBES_SATURATING_ARITHMETIC] = {
+               .handler = emulate_rd12rn16rm0_rwflags_nopc},
+       [PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
+       [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
+       [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
+       [PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd},
+       [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr},
+       [PROBES_LOAD] = {.handler = emulate_ldr},
+       [PROBES_STORE_EXTRA] = {.handler = emulate_str},
+       [PROBES_STORE] = {.handler = emulate_str},
+       [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
+       [PROBES_DATA_PROCESSING_REG] = {
+               .handler = emulate_rd12rn16rm0rs8_rwflags},
+       [PROBES_DATA_PROCESSING_IMM] = {
+               .handler = emulate_rd12rn16rm0rs8_rwflags},
+       [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc},
+       [PROBES_SEV] = {.handler = probes_emulate_none},
+       [PROBES_WFE] = {.handler = probes_simulate_nop},
+       [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
+       [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc},
+       [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
+       [PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
+       [PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc},
+       [PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
+       [PROBES_MUL_ADD_LONG] = {
+               .handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
+       [PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
+       [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc},
+       [PROBES_BRANCH] = {.handler = simulate_bbl},
+       [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
+};
diff --git a/arch/arm/probes/kprobes/actions-common.c b/arch/arm/probes/kprobes/actions-common.c
new file mode 100644 (file)
index 0000000..bd20a71
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * arch/arm/probes/kprobes/actions-common.c
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
+ * Copyright (C) 2006, 2007 Motorola Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <asm/opcodes.h>
+
+#include "core.h"
+
+
+static void __kprobes simulate_ldm1stm1(probes_opcode_t insn,
+               struct arch_probes_insn *asi,
+               struct pt_regs *regs)
+{
+       int rn = (insn >> 16) & 0xf;
+       int lbit = insn & (1 << 20);
+       int wbit = insn & (1 << 21);
+       int ubit = insn & (1 << 23);
+       int pbit = insn & (1 << 24);
+       long *addr = (long *)regs->uregs[rn];
+       int reg_bit_vector;
+       int reg_count;
+
+       reg_count = 0;
+       reg_bit_vector = insn & 0xffff;
+       while (reg_bit_vector) {
+               reg_bit_vector &= (reg_bit_vector - 1);
+               ++reg_count;
+       }
+
+       if (!ubit)
+               addr -= reg_count;
+       addr += (!pbit == !ubit);
+
+       reg_bit_vector = insn & 0xffff;
+       while (reg_bit_vector) {
+               int reg = __ffs(reg_bit_vector);
+               reg_bit_vector &= (reg_bit_vector - 1);
+               if (lbit)
+                       regs->uregs[reg] = *addr++;
+               else
+                       *addr++ = regs->uregs[reg];
+       }
+
+       if (wbit) {
+               if (!ubit)
+                       addr -= reg_count;
+               addr -= (!pbit == !ubit);
+               regs->uregs[rn] = (long)addr;
+       }
+}
+
+static void __kprobes simulate_stm1_pc(probes_opcode_t insn,
+       struct arch_probes_insn *asi,
+       struct pt_regs *regs)
+{
+       unsigned long addr = regs->ARM_pc - 4;
+
+       regs->ARM_pc = (long)addr + str_pc_offset;
+       simulate_ldm1stm1(insn, asi, regs);
+       regs->ARM_pc = (long)addr + 4;
+}
+
+static void __kprobes simulate_ldm1_pc(probes_opcode_t insn,
+       struct arch_probes_insn *asi,
+       struct pt_regs *regs)
+{
+       simulate_ldm1stm1(insn, asi, regs);
+       load_write_pc(regs->ARM_pc, regs);
+}
+
+static void __kprobes
+emulate_generic_r0_12_noflags(probes_opcode_t insn,
+       struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       register void *rregs asm("r1") = regs;
+       register void *rfn asm("lr") = asi->insn_fn;
+
+       __asm__ __volatile__ (
+               "stmdb  sp!, {%[regs], r11}     \n\t"
+               "ldmia  %[regs], {r0-r12}       \n\t"
+#if __LINUX_ARM_ARCH__ >= 6
+               "blx    %[fn]                   \n\t"
+#else
+               "str    %[fn], [sp, #-4]!       \n\t"
+               "adr    lr, 1f                  \n\t"
+               "ldr    pc, [sp], #4            \n\t"
+               "1:                             \n\t"
+#endif
+               "ldr    lr, [sp], #4            \n\t" /* lr = regs */
+               "stmia  lr, {r0-r12}            \n\t"
+               "ldr    r11, [sp], #4           \n\t"
+               : [regs] "=r" (rregs), [fn] "=r" (rfn)
+               : "0" (rregs), "1" (rfn)
+               : "r0", "r2", "r3", "r4", "r5", "r6", "r7",
+                 "r8", "r9", "r10", "r12", "memory", "cc"
+               );
+}
+
+static void __kprobes
+emulate_generic_r2_14_noflags(probes_opcode_t insn,
+       struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       emulate_generic_r0_12_noflags(insn, asi,
+               (struct pt_regs *)(regs->uregs+2));
+}
+
+static void __kprobes
+emulate_ldm_r3_15(probes_opcode_t insn,
+       struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       emulate_generic_r0_12_noflags(insn, asi,
+               (struct pt_regs *)(regs->uregs+3));
+       load_write_pc(regs->ARM_pc, regs);
+}
+
+enum probes_insn __kprobes
+kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
+               const struct decode_header *h)
+{
+       probes_insn_handler_t *handler = 0;
+       unsigned reglist = insn & 0xffff;
+       int is_ldm = insn & 0x100000;
+       int rn = (insn >> 16) & 0xf;
+
+       if (rn <= 12 && (reglist & 0xe000) == 0) {
+               /* Instruction only uses registers in the range R0..R12 */
+               handler = emulate_generic_r0_12_noflags;
+
+       } else if (rn >= 2 && (reglist & 0x8003) == 0) {
+               /* Instruction only uses registers in the range R2..R14 */
+               rn -= 2;
+               reglist >>= 2;
+               handler = emulate_generic_r2_14_noflags;
+
+       } else if (rn >= 3 && (reglist & 0x0007) == 0) {
+               /* Instruction only uses registers in the range R3..R15 */
+               if (is_ldm && (reglist & 0x8000)) {
+                       rn -= 3;
+                       reglist >>= 3;
+                       handler = emulate_ldm_r3_15;
+               }
+       }
+
+       if (handler) {
+               /* We can emulate the instruction in (possibly) modified form */
+               asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) |
+                                                  (rn << 16) | reglist);
+               asi->insn_handler = handler;
+               return INSN_GOOD;
+       }
+
+       /* Fallback to slower simulation... */
+       if (reglist & 0x8000)
+               handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
+       else
+               handler = simulate_ldm1stm1;
+       asi->insn_handler = handler;
+       return INSN_GOOD_NO_SLOT;
+}
+
diff --git a/arch/arm/probes/kprobes/actions-thumb.c b/arch/arm/probes/kprobes/actions-thumb.c
new file mode 100644 (file)
index 0000000..6c4e60b
--- /dev/null
@@ -0,0 +1,666 @@
+/*
+ * arch/arm/probes/kprobes/actions-thumb.c
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <linux/kprobes.h>
+
+#include "../decode-thumb.h"
+#include "core.h"
+
+/* These emulation encodings are functionally equivalent... */
+#define t32_emulate_rd8rn16rm0ra12_noflags \
+               t32_emulate_rdlo12rdhi8rn16rm0_noflags
+
+/* t32 thumb actions */
+
+static void __kprobes
+t32_simulate_table_branch(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc;
+       int rn = (insn >> 16) & 0xf;
+       int rm = insn & 0xf;
+
+       unsigned long rnv = (rn == 15) ? pc : regs->uregs[rn];
+       unsigned long rmv = regs->uregs[rm];
+       unsigned int halfwords;
+
+       if (insn & 0x10) /* TBH */
+               halfwords = ((u16 *)rnv)[rmv];
+       else /* TBB */
+               halfwords = ((u8 *)rnv)[rmv];
+
+       regs->ARM_pc = pc + 2 * halfwords;
+}
+
+static void __kprobes
+t32_simulate_mrs(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       int rd = (insn >> 8) & 0xf;
+       unsigned long mask = 0xf8ff03df; /* Mask out execution state */
+       regs->uregs[rd] = regs->ARM_cpsr & mask;
+}
+
+static void __kprobes
+t32_simulate_cond_branch(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc;
+
+       long offset = insn & 0x7ff;             /* imm11 */
+       offset += (insn & 0x003f0000) >> 5;     /* imm6 */
+       offset += (insn & 0x00002000) << 4;     /* J1 */
+       offset += (insn & 0x00000800) << 7;     /* J2 */
+       offset -= (insn & 0x04000000) >> 7;     /* Apply sign bit */
+
+       regs->ARM_pc = pc + (offset * 2);
+}
+
+static enum probes_insn __kprobes
+t32_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
+               const struct decode_header *d)
+{
+       int cc = (insn >> 22) & 0xf;
+       asi->insn_check_cc = probes_condition_checks[cc];
+       asi->insn_handler = t32_simulate_cond_branch;
+       return INSN_GOOD_NO_SLOT;
+}
+
+static void __kprobes
+t32_simulate_branch(probes_opcode_t insn,
+                   struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc;
+
+       long offset = insn & 0x7ff;             /* imm11 */
+       offset += (insn & 0x03ff0000) >> 5;     /* imm10 */
+       offset += (insn & 0x00002000) << 9;     /* J1 */
+       offset += (insn & 0x00000800) << 10;    /* J2 */
+       if (insn & 0x04000000)
+               offset -= 0x00800000; /* Apply sign bit */
+       else
+               offset ^= 0x00600000; /* Invert J1 and J2 */
+
+       if (insn & (1 << 14)) {
+               /* BL or BLX */
+               regs->ARM_lr = regs->ARM_pc | 1;
+               if (!(insn & (1 << 12))) {
+                       /* BLX so switch to ARM mode */
+                       regs->ARM_cpsr &= ~PSR_T_BIT;
+                       pc &= ~3;
+               }
+       }
+
+       regs->ARM_pc = pc + (offset * 2);
+}
+
+static void __kprobes
+t32_simulate_ldr_literal(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long addr = regs->ARM_pc & ~3;
+       int rt = (insn >> 12) & 0xf;
+       unsigned long rtv;
+
+       long offset = insn & 0xfff;
+       if (insn & 0x00800000)
+               addr += offset;
+       else
+               addr -= offset;
+
+       if (insn & 0x00400000) {
+               /* LDR */
+               rtv = *(unsigned long *)addr;
+               if (rt == 15) {
+                       bx_write_pc(rtv, regs);
+                       return;
+               }
+       } else if (insn & 0x00200000) {
+               /* LDRH */
+               if (insn & 0x01000000)
+                       rtv = *(s16 *)addr;
+               else
+                       rtv = *(u16 *)addr;
+       } else {
+               /* LDRB */
+               if (insn & 0x01000000)
+                       rtv = *(s8 *)addr;
+               else
+                       rtv = *(u8 *)addr;
+       }
+
+       regs->uregs[rt] = rtv;
+}
+
+static enum probes_insn __kprobes
+t32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
+               const struct decode_header *d)
+{
+       enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d);
+
+       /* Fixup modified instruction to have halfwords in correct order...*/
+       insn = __mem_to_opcode_arm(asi->insn[0]);
+       ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16);
+       ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff);
+
+       return ret;
+}
+
+static void __kprobes
+t32_emulate_ldrdstrd(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc & ~3;
+       int rt1 = (insn >> 12) & 0xf;
+       int rt2 = (insn >> 8) & 0xf;
+       int rn = (insn >> 16) & 0xf;
+
+       register unsigned long rt1v asm("r0") = regs->uregs[rt1];
+       register unsigned long rt2v asm("r1") = regs->uregs[rt2];
+       register unsigned long rnv asm("r2") = (rn == 15) ? pc
+                                                         : regs->uregs[rn];
+
+       __asm__ __volatile__ (
+               "blx    %[fn]"
+               : "=r" (rt1v), "=r" (rt2v), "=r" (rnv)
+               : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       if (rn != 15)
+               regs->uregs[rn] = rnv; /* Writeback base register */
+       regs->uregs[rt1] = rt1v;
+       regs->uregs[rt2] = rt2v;
+}
+
+static void __kprobes
+t32_emulate_ldrstr(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       int rt = (insn >> 12) & 0xf;
+       int rn = (insn >> 16) & 0xf;
+       int rm = insn & 0xf;
+
+       register unsigned long rtv asm("r0") = regs->uregs[rt];
+       register unsigned long rnv asm("r2") = regs->uregs[rn];
+       register unsigned long rmv asm("r3") = regs->uregs[rm];
+
+       __asm__ __volatile__ (
+               "blx    %[fn]"
+               : "=r" (rtv), "=r" (rnv)
+               : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rn] = rnv; /* Writeback base register */
+       if (rt == 15) /* Can't be true for a STR as they aren't allowed */
+               bx_write_pc(rtv, regs);
+       else
+               regs->uregs[rt] = rtv;
+}
+
+static void __kprobes
+t32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       int rd = (insn >> 8) & 0xf;
+       int rn = (insn >> 16) & 0xf;
+       int rm = insn & 0xf;
+
+       register unsigned long rdv asm("r1") = regs->uregs[rd];
+       register unsigned long rnv asm("r2") = regs->uregs[rn];
+       register unsigned long rmv asm("r3") = regs->uregs[rm];
+       unsigned long cpsr = regs->ARM_cpsr;
+
+       __asm__ __volatile__ (
+               "msr    cpsr_fs, %[cpsr]        \n\t"
+               "blx    %[fn]                   \n\t"
+               "mrs    %[cpsr], cpsr           \n\t"
+               : "=r" (rdv), [cpsr] "=r" (cpsr)
+               : "0" (rdv), "r" (rnv), "r" (rmv),
+                 "1" (cpsr), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rd] = rdv;
+       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
+}
+
+static void __kprobes
+t32_emulate_rd8pc16_noflags(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc;
+       int rd = (insn >> 8) & 0xf;
+
+       register unsigned long rdv asm("r1") = regs->uregs[rd];
+       register unsigned long rnv asm("r2") = pc & ~3;
+
+       __asm__ __volatile__ (
+               "blx    %[fn]"
+               : "=r" (rdv)
+               : "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rd] = rdv;
+}
+
+static void __kprobes
+t32_emulate_rd8rn16_noflags(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       int rd = (insn >> 8) & 0xf;
+       int rn = (insn >> 16) & 0xf;
+
+       register unsigned long rdv asm("r1") = regs->uregs[rd];
+       register unsigned long rnv asm("r2") = regs->uregs[rn];
+
+       __asm__ __volatile__ (
+               "blx    %[fn]"
+               : "=r" (rdv)
+               : "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rd] = rdv;
+}
+
+static void __kprobes
+t32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn,
+               struct arch_probes_insn *asi,
+               struct pt_regs *regs)
+{
+       int rdlo = (insn >> 12) & 0xf;
+       int rdhi = (insn >> 8) & 0xf;
+       int rn = (insn >> 16) & 0xf;
+       int rm = insn & 0xf;
+
+       register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
+       register unsigned long rdhiv asm("r1") = regs->uregs[rdhi];
+       register unsigned long rnv asm("r2") = regs->uregs[rn];
+       register unsigned long rmv asm("r3") = regs->uregs[rm];
+
+       __asm__ __volatile__ (
+               "blx    %[fn]"
+               : "=r" (rdlov), "=r" (rdhiv)
+               : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
+                 [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rdlo] = rdlov;
+       regs->uregs[rdhi] = rdhiv;
+}
+/* t16 thumb actions */
+
+static void __kprobes
+t16_simulate_bxblx(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc + 2;
+       int rm = (insn >> 3) & 0xf;
+       unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm];
+
+       if (insn & (1 << 7)) /* BLX ? */
+               regs->ARM_lr = regs->ARM_pc | 1;
+
+       bx_write_pc(rmv, regs);
+}
+
+static void __kprobes
+t16_simulate_ldr_literal(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3);
+       long index = insn & 0xff;
+       int rt = (insn >> 8) & 0x7;
+       regs->uregs[rt] = base[index];
+}
+
+static void __kprobes
+t16_simulate_ldrstr_sp_relative(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long* base = (unsigned long *)regs->ARM_sp;
+       long index = insn & 0xff;
+       int rt = (insn >> 8) & 0x7;
+       if (insn & 0x800) /* LDR */
+               regs->uregs[rt] = base[index];
+       else /* STR */
+               base[index] = regs->uregs[rt];
+}
+
+static void __kprobes
+t16_simulate_reladr(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long base = (insn & 0x800) ? regs->ARM_sp
+                                           : ((regs->ARM_pc + 2) & ~3);
+       long offset = insn & 0xff;
+       int rt = (insn >> 8) & 0x7;
+       regs->uregs[rt] = base + offset * 4;
+}
+
+static void __kprobes
+t16_simulate_add_sp_imm(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       long imm = insn & 0x7f;
+       if (insn & 0x80) /* SUB */
+               regs->ARM_sp -= imm * 4;
+       else /* ADD */
+               regs->ARM_sp += imm * 4;
+}
+
+static void __kprobes
+t16_simulate_cbz(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       int rn = insn & 0x7;
+       probes_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn;
+       if (nonzero & 0x800) {
+               long i = insn & 0x200;
+               long imm5 = insn & 0xf8;
+               unsigned long pc = regs->ARM_pc + 2;
+               regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2);
+       }
+}
+
+static void __kprobes
+t16_simulate_it(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       /*
+        * The 8 IT state bits are split into two parts in CPSR:
+        *      ITSTATE<1:0> are in CPSR<26:25>
+        *      ITSTATE<7:2> are in CPSR<15:10>
+        * The new IT state is in the lower byte of insn.
+        */
+       unsigned long cpsr = regs->ARM_cpsr;
+       cpsr &= ~PSR_IT_MASK;
+       cpsr |= (insn & 0xfc) << 8;
+       cpsr |= (insn & 0x03) << 25;
+       regs->ARM_cpsr = cpsr;
+}
+
+static void __kprobes
+t16_singlestep_it(probes_opcode_t insn,
+                 struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       regs->ARM_pc += 2;
+       t16_simulate_it(insn, asi, regs);
+}
+
+static enum probes_insn __kprobes
+t16_decode_it(probes_opcode_t insn, struct arch_probes_insn *asi,
+               const struct decode_header *d)
+{
+       asi->insn_singlestep = t16_singlestep_it;
+       return INSN_GOOD_NO_SLOT;
+}
+
+static void __kprobes
+t16_simulate_cond_branch(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc + 2;
+       long offset = insn & 0x7f;
+       offset -= insn & 0x80; /* Apply sign bit */
+       regs->ARM_pc = pc + (offset * 2);
+}
+
+static enum probes_insn __kprobes
+t16_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
+               const struct decode_header *d)
+{
+       int cc = (insn >> 8) & 0xf;
+       asi->insn_check_cc = probes_condition_checks[cc];
+       asi->insn_handler = t16_simulate_cond_branch;
+       return INSN_GOOD_NO_SLOT;
+}
+
+static void __kprobes
+t16_simulate_branch(probes_opcode_t insn,
+                  struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc + 2;
+       long offset = insn & 0x3ff;
+       offset -= insn & 0x400; /* Apply sign bit */
+       regs->ARM_pc = pc + (offset * 2);
+}
+
+static unsigned long __kprobes
+t16_emulate_loregs(probes_opcode_t insn,
+                  struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long oldcpsr = regs->ARM_cpsr;
+       unsigned long newcpsr;
+
+       __asm__ __volatile__ (
+               "msr    cpsr_fs, %[oldcpsr]     \n\t"
+               "ldmia  %[regs], {r0-r7}        \n\t"
+               "blx    %[fn]                   \n\t"
+               "stmia  %[regs], {r0-r7}        \n\t"
+               "mrs    %[newcpsr], cpsr        \n\t"
+               : [newcpsr] "=r" (newcpsr)
+               : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs),
+                 [fn] "r" (asi->insn_fn)
+               : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+                 "lr", "memory", "cc"
+               );
+
+       return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK);
+}
+
+static void __kprobes
+t16_emulate_loregs_rwflags(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs);
+}
+
+static void __kprobes
+t16_emulate_loregs_noitrwflags(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long cpsr = t16_emulate_loregs(insn, asi, regs);
+       if (!in_it_block(cpsr))
+               regs->ARM_cpsr = cpsr;
+}
+
+static void __kprobes
+t16_emulate_hiregs(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       unsigned long pc = regs->ARM_pc + 2;
+       int rdn = (insn & 0x7) | ((insn & 0x80) >> 4);
+       int rm = (insn >> 3) & 0xf;
+
+       register unsigned long rdnv asm("r1");
+       register unsigned long rmv asm("r0");
+       unsigned long cpsr = regs->ARM_cpsr;
+
+       rdnv = (rdn == 15) ? pc : regs->uregs[rdn];
+       rmv = (rm == 15) ? pc : regs->uregs[rm];
+
+       __asm__ __volatile__ (
+               "msr    cpsr_fs, %[cpsr]        \n\t"
+               "blx    %[fn]                   \n\t"
+               "mrs    %[cpsr], cpsr           \n\t"
+               : "=r" (rdnv), [cpsr] "=r" (cpsr)
+               : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (asi->insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       if (rdn == 15)
+               rdnv &= ~1;
+
+       regs->uregs[rdn] = rdnv;
+       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
+}
+
+static enum probes_insn __kprobes
+t16_decode_hiregs(probes_opcode_t insn, struct arch_probes_insn *asi,
+               const struct decode_header *d)
+{
+       insn &= ~0x00ff;
+       insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
+       ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn);
+       asi->insn_handler = t16_emulate_hiregs;
+       return INSN_GOOD;
+}
+
+static void __kprobes
+t16_emulate_push(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       __asm__ __volatile__ (
+               "ldr    r9, [%[regs], #13*4]    \n\t"
+               "ldr    r8, [%[regs], #14*4]    \n\t"
+               "ldmia  %[regs], {r0-r7}        \n\t"
+               "blx    %[fn]                   \n\t"
+               "str    r9, [%[regs], #13*4]    \n\t"
+               :
+               : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
+               : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
+                 "lr", "memory", "cc"
+               );
+}
+
+static enum probes_insn __kprobes
+t16_decode_push(probes_opcode_t insn, struct arch_probes_insn *asi,
+               const struct decode_header *d)
+{
+       /*
+        * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}"
+        * and call it with R9=SP and LR in the register list represented
+        * by R8.
+        */
+       /* 1st half STMDB R9!,{} */
+       ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe929);
+       /* 2nd half (register list) */
+       ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
+       asi->insn_handler = t16_emulate_push;
+       return INSN_GOOD;
+}
+
+static void __kprobes
+t16_emulate_pop_nopc(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       __asm__ __volatile__ (
+               "ldr    r9, [%[regs], #13*4]    \n\t"
+               "ldmia  %[regs], {r0-r7}        \n\t"
+               "blx    %[fn]                   \n\t"
+               "stmia  %[regs], {r0-r7}        \n\t"
+               "str    r9, [%[regs], #13*4]    \n\t"
+               :
+               : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
+               : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
+                 "lr", "memory", "cc"
+               );
+}
+
+static void __kprobes
+t16_emulate_pop_pc(probes_opcode_t insn,
+               struct arch_probes_insn *asi, struct pt_regs *regs)
+{
+       register unsigned long pc asm("r8");
+
+       __asm__ __volatile__ (
+               "ldr    r9, [%[regs], #13*4]    \n\t"
+               "ldmia  %[regs], {r0-r7}        \n\t"
+               "blx    %[fn]                   \n\t"
+               "stmia  %[regs], {r0-r7}        \n\t"
+               "str    r9, [%[regs], #13*4]    \n\t"
+               : "=r" (pc)
+               : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
+               : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
+                 "lr", "memory", "cc"
+               );
+
+       bx_write_pc(pc, regs);
+}
+
+static enum probes_insn __kprobes
+t16_decode_pop(probes_opcode_t insn, struct arch_probes_insn *asi,
+               const struct decode_header *d)
+{
+       /*
+        * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}"
+        * and call it with R9=SP and PC in the register list represented
+        * by R8.
+        */
+       /* 1st half LDMIA R9!,{} */
+       ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe8b9);
+       /* 2nd half (register list) */
+       ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
+       asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc
+                                        : t16_emulate_pop_nopc;
+       return INSN_GOOD;
+}
+
+const union decode_action kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = {
+       [PROBES_T16_ADD_SP] = {.handler = t16_simulate_add_sp_imm},
+       [PROBES_T16_CBZ] = {.handler = t16_simulate_cbz},
+       [PROBES_T16_SIGN_EXTEND] = {.handler = t16_emulate_loregs_rwflags},
+       [PROBES_T16_PUSH] = {.decoder = t16_decode_push},
+       [PROBES_T16_POP] = {.decoder = t16_decode_pop},
+       [PROBES_T16_SEV] = {.handler = probes_emulate_none},
+       [PROBES_T16_WFE] = {.handler = probes_simulate_nop},
+       [PROBES_T16_IT] = {.decoder = t16_decode_it},
+       [PROBES_T16_CMP] = {.handler = t16_emulate_loregs_rwflags},
+       [PROBES_T16_ADDSUB] = {.handler = t16_emulate_loregs_noitrwflags},
+       [PROBES_T16_LOGICAL] = {.handler = t16_emulate_loregs_noitrwflags},
+       [PROBES_T16_LDR_LIT] = {.handler = t16_simulate_ldr_literal},
+       [PROBES_T16_BLX] = {.handler = t16_simulate_bxblx},
+       [PROBES_T16_HIREGOPS] = {.decoder = t16_decode_hiregs},
+       [PROBES_T16_LDRHSTRH] = {.handler = t16_emulate_loregs_rwflags},
+       [PROBES_T16_LDRSTR] = {.handler = t16_simulate_ldrstr_sp_relative},
+       [PROBES_T16_ADR] = {.handler = t16_simulate_reladr},
+       [PROBES_T16_LDMSTM] = {.handler = t16_emulate_loregs_rwflags},
+       [PROBES_T16_BRANCH_COND] = {.decoder = t16_decode_cond_branch},
+       [PROBES_T16_BRANCH] = {.handler = t16_simulate_branch},
+};
+
+const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
+       [PROBES_T32_LDMSTM] = {.decoder = t32_decode_ldmstm},
+       [PROBES_T32_LDRDSTRD] = {.handler = t32_emulate_ldrdstrd},
+       [PROBES_T32_TABLE_BRANCH] = {.handler = t32_simulate_table_branch},
+       [PROBES_T32_TST] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
+       [PROBES_T32_MOV] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
+       [PROBES_T32_ADDSUB] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
+       [PROBES_T32_LOGICAL] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
+       [PROBES_T32_CMP] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
+       [PROBES_T32_ADDWSUBW_PC] = {.handler = t32_emulate_rd8pc16_noflags,},
+       [PROBES_T32_ADDWSUBW] = {.handler = t32_emulate_rd8rn16_noflags},
+       [PROBES_T32_MOVW] = {.handler = t32_emulate_rd8rn16_noflags},
+       [PROBES_T32_SAT] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
+       [PROBES_T32_BITFIELD] = {.handler = t32_emulate_rd8rn16_noflags},
+       [PROBES_T32_SEV] = {.handler = probes_emulate_none},
+       [PROBES_T32_WFE] = {.handler = probes_simulate_nop},
+       [PROBES_T32_MRS] = {.handler = t32_simulate_mrs},
+       [PROBES_T32_BRANCH_COND] = {.decoder = t32_decode_cond_branch},
+       [PROBES_T32_BRANCH] = {.handler = t32_simulate_branch},
+       [PROBES_T32_PLDI] = {.handler = probes_simulate_nop},
+       [PROBES_T32_LDR_LIT] = {.handler = t32_simulate_ldr_literal},
+       [PROBES_T32_LDRSTR] = {.handler = t32_emulate_ldrstr},
+       [PROBES_T32_SIGN_EXTEND] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
+       [PROBES_T32_MEDIA] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
+       [PROBES_T32_REVERSE] = {.handler = t32_emulate_rd8rn16_noflags},
+       [PROBES_T32_MUL_ADD] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
+       [PROBES_T32_MUL_ADD2] = {.handler = t32_emulate_rd8rn16rm0ra12_noflags},
+       [PROBES_T32_MUL_ADD_LONG] = {
+               .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags},
+};
diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c
new file mode 100644 (file)
index 0000000..701f49d
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+ * arch/arm/kernel/kprobes.c
+ *
+ * Kprobes on ARM
+ *
+ * Abhishek Sagar <sagar.abhishek@gmail.com>
+ * Copyright (C) 2006, 2007 Motorola Inc.
+ *
+ * Nicolas Pitre <nico@marvell.com>
+ * Copyright (C) 2007 Marvell Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/stop_machine.h>
+#include <linux/stringify.h>
+#include <asm/traps.h>
+#include <asm/opcodes.h>
+#include <asm/cacheflush.h>
+#include <linux/percpu.h>
+#include <linux/bug.h>
+#include <asm/patch.h>
+
+#include "../decode-arm.h"
+#include "../decode-thumb.h"
+#include "core.h"
+
+#define MIN_STACK_SIZE(addr)                           \
+       min((unsigned long)MAX_STACK_SIZE,              \
+           (unsigned long)current_thread_info() + THREAD_START_SP - (addr))
+
+#define flush_insns(addr, size)                                \
+       flush_icache_range((unsigned long)(addr),       \
+                          (unsigned long)(addr) +      \
+                          (size))
+
+/* Used as a marker in ARM_pc to note when we're in a jprobe. */
+#define JPROBE_MAGIC_ADDR              0xffffffff
+
+DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
+DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+
+
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
+{
+       kprobe_opcode_t insn;
+       kprobe_opcode_t tmp_insn[MAX_INSN_SIZE];
+       unsigned long addr = (unsigned long)p->addr;
+       bool thumb;
+       kprobe_decode_insn_t *decode_insn;
+       const union decode_action *actions;
+       int is;
+
+       if (in_exception_text(addr))
+               return -EINVAL;
+
+#ifdef CONFIG_THUMB2_KERNEL
+       thumb = true;
+       addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
+       insn = __mem_to_opcode_thumb16(((u16 *)addr)[0]);
+       if (is_wide_instruction(insn)) {
+               u16 inst2 = __mem_to_opcode_thumb16(((u16 *)addr)[1]);
+               insn = __opcode_thumb32_compose(insn, inst2);
+               decode_insn = thumb32_probes_decode_insn;
+               actions = kprobes_t32_actions;
+       } else {
+               decode_insn = thumb16_probes_decode_insn;
+               actions = kprobes_t16_actions;
+       }
+#else /* !CONFIG_THUMB2_KERNEL */
+       thumb = false;
+       if (addr & 0x3)
+               return -EINVAL;
+       insn = __mem_to_opcode_arm(*p->addr);
+       decode_insn = arm_probes_decode_insn;
+       actions = kprobes_arm_actions;
+#endif
+
+       p->opcode = insn;
+       p->ainsn.insn = tmp_insn;
+
+       switch ((*decode_insn)(insn, &p->ainsn, true, actions)) {
+       case INSN_REJECTED:     /* not supported */
+               return -EINVAL;
+
+       case INSN_GOOD:         /* instruction uses slot */
+               p->ainsn.insn = get_insn_slot();
+               if (!p->ainsn.insn)
+                       return -ENOMEM;
+               for (is = 0; is < MAX_INSN_SIZE; ++is)
+                       p->ainsn.insn[is] = tmp_insn[is];
+               flush_insns(p->ainsn.insn,
+                               sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE);
+               p->ainsn.insn_fn = (probes_insn_fn_t *)
+                                       ((uintptr_t)p->ainsn.insn | thumb);
+               break;
+
+       case INSN_GOOD_NO_SLOT: /* instruction doesn't need insn slot */
+               p->ainsn.insn = NULL;
+               break;
+       }
+
+       return 0;
+}
+
+void __kprobes arch_arm_kprobe(struct kprobe *p)
+{
+       unsigned int brkp;
+       void *addr;
+
+       if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+               /* Remove any Thumb flag */
+               addr = (void *)((uintptr_t)p->addr & ~1);
+
+               if (is_wide_instruction(p->opcode))
+                       brkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
+               else
+                       brkp = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION;
+       } else {
+               kprobe_opcode_t insn = p->opcode;
+
+               addr = p->addr;
+               brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION;
+
+               if (insn >= 0xe0000000)
+                       brkp |= 0xe0000000;  /* Unconditional instruction */
+               else
+                       brkp |= insn & 0xf0000000;  /* Copy condition from insn */
+       }
+
+       patch_text(addr, brkp);
+}
+
+/*
+ * The actual disarming is done here on each CPU and synchronized using
+ * stop_machine. This synchronization is necessary on SMP to avoid removing
+ * a probe between the moment the 'Undefined Instruction' exception is raised
+ * and the moment the exception handler reads the faulting instruction from
+ * memory. It is also needed to atomically set the two half-words of a 32-bit
+ * Thumb breakpoint.
+ */
+int __kprobes __arch_disarm_kprobe(void *p)
+{
+       struct kprobe *kp = p;
+       void *addr = (void *)((uintptr_t)kp->addr & ~1);
+
+       __patch_text(addr, kp->opcode);
+
+       return 0;
+}
+
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
+{
+       stop_machine(__arch_disarm_kprobe, p, cpu_online_mask);
+}
+
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+       if (p->ainsn.insn) {
+               free_insn_slot(p->ainsn.insn, 0);
+               p->ainsn.insn = NULL;
+       }
+}
+
+static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+       kcb->prev_kprobe.kp = kprobe_running();
+       kcb->prev_kprobe.status = kcb->kprobe_status;
+}
+
+static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+       __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
+       kcb->kprobe_status = kcb->prev_kprobe.status;
+}
+
+static void __kprobes set_current_kprobe(struct kprobe *p)
+{
+       __this_cpu_write(current_kprobe, p);
+}
+
+static void __kprobes
+singlestep_skip(struct kprobe *p, struct pt_regs *regs)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+       regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
+       if (is_wide_instruction(p->opcode))
+               regs->ARM_pc += 4;
+       else
+               regs->ARM_pc += 2;
+#else
+       regs->ARM_pc += 4;
+#endif
+}
+
+static inline void __kprobes
+singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb)
+{
+       p->ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
+}
+
+/*
+ * Called with IRQs disabled. IRQs must remain disabled from that point
+ * all the way until processing this kprobe is complete.  The current
+ * kprobes implementation cannot process more than one nested level of
+ * kprobe, and that level is reserved for user kprobe handlers, so we can't
+ * risk encountering a new kprobe in an interrupt handler.
+ */
+void __kprobes kprobe_handler(struct pt_regs *regs)
+{
+       struct kprobe *p, *cur;
+       struct kprobe_ctlblk *kcb;
+
+       kcb = get_kprobe_ctlblk();
+       cur = kprobe_running();
+
+#ifdef CONFIG_THUMB2_KERNEL
+       /*
+        * First look for a probe which was registered using an address with
+        * bit 0 set, this is the usual situation for pointers to Thumb code.
+        * If not found, fallback to looking for one with bit 0 clear.
+        */
+       p = get_kprobe((kprobe_opcode_t *)(regs->ARM_pc | 1));
+       if (!p)
+               p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc);
+
+#else /* ! CONFIG_THUMB2_KERNEL */
+       p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc);
+#endif
+
+       if (p) {
+               if (cur) {
+                       /* Kprobe is pending, so we're recursing. */
+                       switch (kcb->kprobe_status) {
+                       case KPROBE_HIT_ACTIVE:
+                       case KPROBE_HIT_SSDONE:
+                               /* A pre- or post-handler probe got us here. */
+                               kprobes_inc_nmissed_count(p);
+                               save_previous_kprobe(kcb);
+                               set_current_kprobe(p);
+                               kcb->kprobe_status = KPROBE_REENTER;
+                               singlestep(p, regs, kcb);
+                               restore_previous_kprobe(kcb);
+                               break;
+                       default:
+                               /* impossible cases */
+                               BUG();
+                       }
+               } else if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) {
+                       /* Probe hit and conditional execution check ok. */
+                       set_current_kprobe(p);
+                       kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+                       /*
+                        * If we have no pre-handler or it returned 0, we
+                        * continue with normal processing.  If we have a
+                        * pre-handler and it returned non-zero, it prepped
+                        * for calling the break_handler below on re-entry,
+                        * so get out doing nothing more here.
+                        */
+                       if (!p->pre_handler || !p->pre_handler(p, regs)) {
+                               kcb->kprobe_status = KPROBE_HIT_SS;
+                               singlestep(p, regs, kcb);
+                               if (p->post_handler) {
+                                       kcb->kprobe_status = KPROBE_HIT_SSDONE;
+                                       p->post_handler(p, regs, 0);
+                               }
+                               reset_current_kprobe();
+                       }
+               } else {
+                       /*
+                        * Probe hit but conditional execution check failed,
+                        * so just skip the instruction and continue as if
+                        * nothing had happened.
+                        */
+                       singlestep_skip(p, regs);
+               }
+       } else if (cur) {
+               /* We probably hit a jprobe.  Call its break handler. */
+               if (cur->break_handler && cur->break_handler(cur, regs)) {
+                       kcb->kprobe_status = KPROBE_HIT_SS;
+                       singlestep(cur, regs, kcb);
+                       if (cur->post_handler) {
+                               kcb->kprobe_status = KPROBE_HIT_SSDONE;
+                               cur->post_handler(cur, regs, 0);
+                       }
+               }
+               reset_current_kprobe();
+       } else {
+               /*
+                * The probe was removed and a race is in progress.
+                * There is nothing we can do about it.  Let's restart
+                * the instruction.  By the time we can restart, the
+                * real instruction will be there.
+                */
+       }
+}
+
+static int __kprobes kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       kprobe_handler(regs);
+       local_irq_restore(flags);
+       return 0;
+}
+
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
+{
+       struct kprobe *cur = kprobe_running();
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+       switch (kcb->kprobe_status) {
+       case KPROBE_HIT_SS:
+       case KPROBE_REENTER:
+               /*
+                * We are here because the instruction being single
+                * stepped caused a page fault. We reset the current
+                * kprobe and the PC to point back to the probe address
+                * and allow the page fault handler to continue as a
+                * normal page fault.
+                */
+               regs->ARM_pc = (long)cur->addr;
+               if (kcb->kprobe_status == KPROBE_REENTER) {
+                       restore_previous_kprobe(kcb);
+               } else {
+                       reset_current_kprobe();
+               }
+               break;
+
+       case KPROBE_HIT_ACTIVE:
+       case KPROBE_HIT_SSDONE:
+               /*
+                * We increment the nmissed count for accounting,
+                * we can also use npre/npostfault count for accounting
+                * these specific fault cases.
+                */
+               kprobes_inc_nmissed_count(cur);
+
+               /*
+                * We come here because instructions in the pre/post
+                * handler caused the page_fault, this could happen
+                * if handler tries to access user space by
+                * copy_from_user(), get_user() etc. Let the
+                * user-specified handler try to fix it.
+                */
+               if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
+                       return 1;
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+                                      unsigned long val, void *data)
+{
+       /*
+        * notify_die() is currently never called on ARM,
+        * so this callback is currently empty.
+        */
+       return NOTIFY_DONE;
+}
+
+/*
+ * When a retprobed function returns, trampoline_handler() is called,
+ * calling the kretprobe's handler. We construct a struct pt_regs to
+ * give a view of registers r0-r11 to the user return-handler.  This is
+ * not a complete pt_regs structure, but that should be plenty sufficient
+ * for kretprobe handlers which should normally be interested in r0 only
+ * anyway.
+ */
+void __naked __kprobes kretprobe_trampoline(void)
+{
+       __asm__ __volatile__ (
+               "stmdb  sp!, {r0 - r11}         \n\t"
+               "mov    r0, sp                  \n\t"
+               "bl     trampoline_handler      \n\t"
+               "mov    lr, r0                  \n\t"
+               "ldmia  sp!, {r0 - r11}         \n\t"
+#ifdef CONFIG_THUMB2_KERNEL
+               "bx     lr                      \n\t"
+#else
+               "mov    pc, lr                  \n\t"
+#endif
+               : : : "memory");
+}
+
+/* Called from kretprobe_trampoline */
+static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
+{
+       struct kretprobe_instance *ri = NULL;
+       struct hlist_head *head, empty_rp;
+       struct hlist_node *tmp;
+       unsigned long flags, orig_ret_address = 0;
+       unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+
+       INIT_HLIST_HEAD(&empty_rp);
+       kretprobe_hash_lock(current, &head, &flags);
+
+       /*
+        * It is possible to have multiple instances associated with a given
+        * task either because multiple functions in the call path have
+        * a return probe installed on them, and/or more than one return
+        * probe was registered for a target function.
+        *
+        * We can handle this because:
+        *     - instances are always inserted at the head of the list
+        *     - when multiple return probes are registered for the same
+        *       function, the first instance's ret_addr will point to the
+        *       real return address, and all the rest will point to
+        *       kretprobe_trampoline
+        */
+       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
+               if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                       continue;
+
+               if (ri->rp && ri->rp->handler) {
+                       __this_cpu_write(current_kprobe, &ri->rp->kp);
+                       get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
+                       ri->rp->handler(ri, regs);
+                       __this_cpu_write(current_kprobe, NULL);
+               }
+
+               orig_ret_address = (unsigned long)ri->ret_addr;
+               recycle_rp_inst(ri, &empty_rp);
+
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+       }
+
+       kretprobe_assert(ri, orig_ret_address, trampoline_address);
+       kretprobe_hash_unlock(current, &flags);
+
+       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
+               hlist_del(&ri->hlist);
+               kfree(ri);
+       }
+
+       return (void *)orig_ret_address;
+}
+
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
+                                     struct pt_regs *regs)
+{
+       ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr;
+
+       /* Replace the return addr with trampoline addr. */
+       regs->ARM_lr = (unsigned long)&kretprobe_trampoline;
+}
+
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+       long sp_addr = regs->ARM_sp;
+       long cpsr;
+
+       kcb->jprobe_saved_regs = *regs;
+       memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr));
+       regs->ARM_pc = (long)jp->entry;
+
+       cpsr = regs->ARM_cpsr | PSR_I_BIT;
+#ifdef CONFIG_THUMB2_KERNEL
+       /* Set correct Thumb state in cpsr */
+       if (regs->ARM_pc & 1)
+               cpsr |= PSR_T_BIT;
+       else
+               cpsr &= ~PSR_T_BIT;
+#endif
+       regs->ARM_cpsr = cpsr;
+
+       preempt_disable();
+       return 1;
+}
+
+void __kprobes jprobe_return(void)
+{
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+       __asm__ __volatile__ (
+               /*
+                * Setup an empty pt_regs. Fill SP and PC fields as
+                * they're needed by longjmp_break_handler.
+                *
+                * We allocate some slack between the original SP and start of
+                * our fabricated regs. To be precise we want to have worst case
+                * covered which is STMFD with all 16 regs so we allocate 2 *
+                * sizeof(struct_pt_regs)).
+                *
+                * This is to prevent any simulated instruction from writing
+                * over the regs when they are accessing the stack.
+                */
+#ifdef CONFIG_THUMB2_KERNEL
+               "sub    r0, %0, %1              \n\t"
+               "mov    sp, r0                  \n\t"
+#else
+               "sub    sp, %0, %1              \n\t"
+#endif
+               "ldr    r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t"
+               "str    %0, [sp, %2]            \n\t"
+               "str    r0, [sp, %3]            \n\t"
+               "mov    r0, sp                  \n\t"
+               "bl     kprobe_handler          \n\t"
+
+               /*
+                * Return to the context saved by setjmp_pre_handler
+                * and restored by longjmp_break_handler.
+                */
+#ifdef CONFIG_THUMB2_KERNEL
+               "ldr    lr, [sp, %2]            \n\t" /* lr = saved sp */
+               "ldrd   r0, r1, [sp, %5]        \n\t" /* r0,r1 = saved lr,pc */
+               "ldr    r2, [sp, %4]            \n\t" /* r2 = saved psr */
+               "stmdb  lr!, {r0, r1, r2}       \n\t" /* push saved lr and */
+                                                     /* rfe context */
+               "ldmia  sp, {r0 - r12}          \n\t"
+               "mov    sp, lr                  \n\t"
+               "ldr    lr, [sp], #4            \n\t"
+               "rfeia  sp!                     \n\t"
+#else
+               "ldr    r0, [sp, %4]            \n\t"
+               "msr    cpsr_cxsf, r0           \n\t"
+               "ldmia  sp, {r0 - pc}           \n\t"
+#endif
+               :
+               : "r" (kcb->jprobe_saved_regs.ARM_sp),
+                 "I" (sizeof(struct pt_regs) * 2),
+                 "J" (offsetof(struct pt_regs, ARM_sp)),
+                 "J" (offsetof(struct pt_regs, ARM_pc)),
+                 "J" (offsetof(struct pt_regs, ARM_cpsr)),
+                 "J" (offsetof(struct pt_regs, ARM_lr))
+               : "memory", "cc");
+}
+
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+       long stack_addr = kcb->jprobe_saved_regs.ARM_sp;
+       long orig_sp = regs->ARM_sp;
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+
+       if (regs->ARM_pc == JPROBE_MAGIC_ADDR) {
+               if (orig_sp != stack_addr) {
+                       struct pt_regs *saved_regs =
+                               (struct pt_regs *)kcb->jprobe_saved_regs.ARM_sp;
+                       printk("current sp %lx does not match saved sp %lx\n",
+                              orig_sp, stack_addr);
+                       printk("Saved registers for jprobe %p\n", jp);
+                       show_regs(saved_regs);
+                       printk("Current registers\n");
+                       show_regs(regs);
+                       BUG();
+               }
+               *regs = kcb->jprobe_saved_regs;
+               memcpy((void *)stack_addr, kcb->jprobes_stack,
+                      MIN_STACK_SIZE(stack_addr));
+               preempt_enable_no_resched();
+               return 1;
+       }
+       return 0;
+}
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+       return 0;
+}
+
+#ifdef CONFIG_THUMB2_KERNEL
+
+static struct undef_hook kprobes_thumb16_break_hook = {
+       .instr_mask     = 0xffff,
+       .instr_val      = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION,
+       .cpsr_mask      = MODE_MASK,
+       .cpsr_val       = SVC_MODE,
+       .fn             = kprobe_trap_handler,
+};
+
+static struct undef_hook kprobes_thumb32_break_hook = {
+       .instr_mask     = 0xffffffff,
+       .instr_val      = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION,
+       .cpsr_mask      = MODE_MASK,
+       .cpsr_val       = SVC_MODE,
+       .fn             = kprobe_trap_handler,
+};
+
+#else  /* !CONFIG_THUMB2_KERNEL */
+
+static struct undef_hook kprobes_arm_break_hook = {
+       .instr_mask     = 0x0fffffff,
+       .instr_val      = KPROBE_ARM_BREAKPOINT_INSTRUCTION,
+       .cpsr_mask      = MODE_MASK,
+       .cpsr_val       = SVC_MODE,
+       .fn             = kprobe_trap_handler,
+};
+
+#endif /* !CONFIG_THUMB2_KERNEL */
+
+int __init arch_init_kprobes()
+{
+       arm_probes_decode_init();
+#ifdef CONFIG_THUMB2_KERNEL
+       register_undef_hook(&kprobes_thumb16_break_hook);
+       register_undef_hook(&kprobes_thumb32_break_hook);
+#else
+       register_undef_hook(&kprobes_arm_break_hook);
+#endif
+       return 0;
+}
diff --git a/arch/arm/probes/kprobes/core.h b/arch/arm/probes/kprobes/core.h
new file mode 100644 (file)
index 0000000..2e1e5a3
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * arch/arm/kernel/kprobes.h
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * Some contents moved here from arch/arm/include/asm/kprobes.h which is
+ * Copyright (C) 2006, 2007 Motorola Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _ARM_KERNEL_KPROBES_H
+#define _ARM_KERNEL_KPROBES_H
+
+#include <asm/kprobes.h>
+#include "../decode.h"
+
+/*
+ * These undefined instructions must be unique and
+ * reserved solely for kprobes' use.
+ */
+#define KPROBE_ARM_BREAKPOINT_INSTRUCTION      0x07f001f8
+#define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION  0xde18
+#define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION  0xf7f0a018
+
+enum probes_insn __kprobes
+kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi,
+               const struct decode_header *h);
+
+typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t,
+                                               struct arch_probes_insn *,
+                                               bool,
+                                               const union decode_action *);
+
+#ifdef CONFIG_THUMB2_KERNEL
+
+extern const union decode_action kprobes_t32_actions[];
+extern const union decode_action kprobes_t16_actions[];
+
+#else /* !CONFIG_THUMB2_KERNEL */
+
+extern const union decode_action kprobes_arm_actions[];
+
+#endif
+
+#endif /* _ARM_KERNEL_KPROBES_H */
diff --git a/arch/arm/probes/kprobes/test-arm.c b/arch/arm/probes/kprobes/test-arm.c
new file mode 100644 (file)
index 0000000..d9a1255
--- /dev/null
@@ -0,0 +1,1346 @@
+/*
+ * arch/arm/kernel/kprobes-test-arm.c
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/system_info.h>
+#include <asm/opcodes.h>
+
+#include "test-core.h"
+
+
+#define TEST_ISA "32"
+
+#define TEST_ARM_TO_THUMB_INTERWORK_R(code1, reg, val, code2)  \
+       TESTCASE_START(code1 #reg code2)                        \
+       TEST_ARG_REG(reg, val)                                  \
+       TEST_ARG_REG(14, 99f)                                   \
+       TEST_ARG_END("")                                        \
+       "50:    nop                     \n\t"                   \
+       "1:     "code1 #reg code2"      \n\t"                   \
+       "       bx      lr              \n\t"                   \
+       ".thumb                         \n\t"                   \
+       "3:     adr     lr, 2f          \n\t"                   \
+       "       bx      lr              \n\t"                   \
+       ".arm                           \n\t"                   \
+       "2:     nop                     \n\t"                   \
+       TESTCASE_END
+
+#define TEST_ARM_TO_THUMB_INTERWORK_P(code1, reg, val, code2)  \
+       TESTCASE_START(code1 #reg code2)                        \
+       TEST_ARG_PTR(reg, val)                                  \
+       TEST_ARG_REG(14, 99f)                                   \
+       TEST_ARG_MEM(15, 3f+1)                                  \
+       TEST_ARG_END("")                                        \
+       "50:    nop                     \n\t"                   \
+       "1:     "code1 #reg code2"      \n\t"                   \
+       "       bx      lr              \n\t"                   \
+       ".thumb                         \n\t"                   \
+       "3:     adr     lr, 2f          \n\t"                   \
+       "       bx      lr              \n\t"                   \
+       ".arm                           \n\t"                   \
+       "2:     nop                     \n\t"                   \
+       TESTCASE_END
+
+
+void kprobe_arm_test_cases(void)
+{
+       kprobe_test_flags = 0;
+
+       TEST_GROUP("Data-processing (register), (register-shifted register), (immediate)")
+
+#define _DATA_PROCESSING_DNM(op,s,val)                                         \
+       TEST_RR(  op "eq" s "   r0,  r",1, VAL1,", r",2, val, "")               \
+       TEST_RR(  op "ne" s "   r1,  r",1, VAL1,", r",2, val, ", lsl #3")       \
+       TEST_RR(  op "cs" s "   r2,  r",3, VAL1,", r",2, val, ", lsr #4")       \
+       TEST_RR(  op "cc" s "   r3,  r",3, VAL1,", r",2, val, ", asr #5")       \
+       TEST_RR(  op "mi" s "   r4,  r",5, VAL1,", r",2, N(val),", asr #6")     \
+       TEST_RR(  op "pl" s "   r5,  r",5, VAL1,", r",2, val, ", ror #7")       \
+       TEST_RR(  op "vs" s "   r6,  r",7, VAL1,", r",2, val, ", rrx")          \
+       TEST_R(   op "vc" s "   r6,  r",7, VAL1,", pc, lsl #3")                 \
+       TEST_R(   op "vc" s "   r6,  r",7, VAL1,", sp, lsr #4")                 \
+       TEST_R(   op "vc" s "   r6,  pc, r",7, VAL1,", asr #5")                 \
+       TEST_R(   op "vc" s "   r6,  sp, r",7, VAL1,", ror #6")                 \
+       TEST_RRR( op "hi" s "   r8,  r",9, VAL1,", r",14,val, ", lsl r",0, 3,"")\
+       TEST_RRR( op "ls" s "   r9,  r",9, VAL1,", r",14,val, ", lsr r",7, 4,"")\
+       TEST_RRR( op "ge" s "   r10, r",11,VAL1,", r",14,val, ", asr r",7, 5,"")\
+       TEST_RRR( op "lt" s "   r11, r",11,VAL1,", r",14,N(val),", asr r",7, 6,"")\
+       TEST_RR(  op "gt" s "   r12, r13"       ", r",14,val, ", ror r",14,7,"")\
+       TEST_RR(  op "le" s "   r14, r",0, val, ", r13"       ", lsl r",14,8,"")\
+       TEST_R(   op "eq" s "   r0,  r",11,VAL1,", #0xf5")                      \
+       TEST_R(   op "ne" s "   r11, r",0, VAL1,", #0xf5000000")                \
+       TEST_R(   op s "        r7,  r",8, VAL2,", #0x000af000")                \
+       TEST(     op s "        r4,  pc"        ", #0x00005a00")
+
+#define DATA_PROCESSING_DNM(op,val)            \
+       _DATA_PROCESSING_DNM(op,"",val)         \
+       _DATA_PROCESSING_DNM(op,"s",val)
+
+#define DATA_PROCESSING_NM(op,val)                                             \
+       TEST_RR(  op "ne        r",1, VAL1,", r",2, val, "")                    \
+       TEST_RR(  op "eq        r",1, VAL1,", r",2, val, ", lsl #3")            \
+       TEST_RR(  op "cc        r",3, VAL1,", r",2, val, ", lsr #4")            \
+       TEST_RR(  op "cs        r",3, VAL1,", r",2, val, ", asr #5")            \
+       TEST_RR(  op "pl        r",5, VAL1,", r",2, N(val),", asr #6")          \
+       TEST_RR(  op "mi        r",5, VAL1,", r",2, val, ", ror #7")            \
+       TEST_RR(  op "vc        r",7, VAL1,", r",2, val, ", rrx")               \
+       TEST_R (  op "vs        r",7, VAL1,", pc, lsl #3")                      \
+       TEST_R (  op "vs        r",7, VAL1,", sp, lsr #4")                      \
+       TEST_R(   op "vs        pc, r",7, VAL1,", asr #5")                      \
+       TEST_R(   op "vs        sp, r",7, VAL1,", ror #6")                      \
+       TEST_RRR( op "ls        r",9, VAL1,", r",14,val, ", lsl r",0, 3,"")     \
+       TEST_RRR( op "hi        r",9, VAL1,", r",14,val, ", lsr r",7, 4,"")     \
+       TEST_RRR( op "lt        r",11,VAL1,", r",14,val, ", asr r",7, 5,"")     \
+       TEST_RRR( op "ge        r",11,VAL1,", r",14,N(val),", asr r",7, 6,"")   \
+       TEST_RR(  op "le        r13"       ", r",14,val, ", ror r",14,7,"")     \
+       TEST_RR(  op "gt        r",0, val, ", r13"       ", lsl r",14,8,"")     \
+       TEST_R(   op "eq        r",11,VAL1,", #0xf5")                           \
+       TEST_R(   op "ne        r",0, VAL1,", #0xf5000000")                     \
+       TEST_R(   op "  r",8, VAL2,", #0x000af000")
+
+#define _DATA_PROCESSING_DM(op,s,val)                                  \
+       TEST_R(   op "eq" s "   r0,  r",1, val, "")                     \
+       TEST_R(   op "ne" s "   r1,  r",1, val, ", lsl #3")             \
+       TEST_R(   op "cs" s "   r2,  r",3, val, ", lsr #4")             \
+       TEST_R(   op "cc" s "   r3,  r",3, val, ", asr #5")             \
+       TEST_R(   op "mi" s "   r4,  r",5, N(val),", asr #6")           \
+       TEST_R(   op "pl" s "   r5,  r",5, val, ", ror #7")             \
+       TEST_R(   op "vs" s "   r6,  r",10,val, ", rrx")                \
+       TEST(     op "vs" s "   r7,  pc, lsl #3")                       \
+       TEST(     op "vs" s "   r7,  sp, lsr #4")                       \
+       TEST_RR(  op "vc" s "   r8,  r",7, val, ", lsl r",0, 3,"")      \
+       TEST_RR(  op "hi" s "   r9,  r",9, val, ", lsr r",7, 4,"")      \
+       TEST_RR(  op "ls" s "   r10, r",9, val, ", asr r",7, 5,"")      \
+       TEST_RR(  op "ge" s "   r11, r",11,N(val),", asr r",7, 6,"")    \
+       TEST_RR(  op "lt" s "   r12, r",11,val, ", ror r",14,7,"")      \
+       TEST_R(   op "gt" s "   r14, r13"       ", lsl r",14,8,"")      \
+       TEST(     op "eq" s "   r0,  #0xf5")                            \
+       TEST(     op "ne" s "   r11, #0xf5000000")                      \
+       TEST(     op s "        r7,  #0x000af000")                      \
+       TEST(     op s "        r4,  #0x00005a00")
+
+#define DATA_PROCESSING_DM(op,val)             \
+       _DATA_PROCESSING_DM(op,"",val)          \
+       _DATA_PROCESSING_DM(op,"s",val)
+
+       DATA_PROCESSING_DNM("and",0xf00f00ff)
+       DATA_PROCESSING_DNM("eor",0xf00f00ff)
+       DATA_PROCESSING_DNM("sub",VAL2)
+       DATA_PROCESSING_DNM("rsb",VAL2)
+       DATA_PROCESSING_DNM("add",VAL2)
+       DATA_PROCESSING_DNM("adc",VAL2)
+       DATA_PROCESSING_DNM("sbc",VAL2)
+       DATA_PROCESSING_DNM("rsc",VAL2)
+       DATA_PROCESSING_NM("tst",0xf00f00ff)
+       DATA_PROCESSING_NM("teq",0xf00f00ff)
+       DATA_PROCESSING_NM("cmp",VAL2)
+       DATA_PROCESSING_NM("cmn",VAL2)
+       DATA_PROCESSING_DNM("orr",0xf00f00ff)
+       DATA_PROCESSING_DM("mov",VAL2)
+       DATA_PROCESSING_DNM("bic",0xf00f00ff)
+       DATA_PROCESSING_DM("mvn",VAL2)
+
+       TEST("mov       ip, sp") /* This has special case emulation code */
+
+       TEST_SUPPORTED("mov     pc, #0x1000");
+       TEST_SUPPORTED("mov     sp, #0x1000");
+       TEST_SUPPORTED("cmp     pc, #0x1000");
+       TEST_SUPPORTED("cmp     sp, #0x1000");
+
+       /* Data-processing with PC and a shift count in a register */
+       TEST_UNSUPPORTED(__inst_arm(0xe15c0f1e) "       @ cmp   r12, r14, asl pc")
+       TEST_UNSUPPORTED(__inst_arm(0xe1a0cf1e) "       @ mov   r12, r14, asl pc")
+       TEST_UNSUPPORTED(__inst_arm(0xe08caf1e) "       @ add   r10, r12, r14, asl pc")
+       TEST_UNSUPPORTED(__inst_arm(0xe151021f) "       @ cmp   r1, pc, lsl r2")
+       TEST_UNSUPPORTED(__inst_arm(0xe17f0211) "       @ cmn   pc, r1, lsl r2")
+       TEST_UNSUPPORTED(__inst_arm(0xe1a0121f) "       @ mov   r1, pc, lsl r2")
+       TEST_UNSUPPORTED(__inst_arm(0xe1a0f211) "       @ mov   pc, r1, lsl r2")
+       TEST_UNSUPPORTED(__inst_arm(0xe042131f) "       @ sub   r1, r2, pc, lsl r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe1cf1312) "       @ bic   r1, pc, r2, lsl r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe081f312) "       @ add   pc, r1, r2, lsl r3")
+
+       /* Data-processing with PC as a target and status registers updated */
+       TEST_UNSUPPORTED("movs  pc, r1")
+       TEST_UNSUPPORTED("movs  pc, r1, lsl r2")
+       TEST_UNSUPPORTED("movs  pc, #0x10000")
+       TEST_UNSUPPORTED("adds  pc, lr, r1")
+       TEST_UNSUPPORTED("adds  pc, lr, r1, lsl r2")
+       TEST_UNSUPPORTED("adds  pc, lr, #4")
+
+       /* Data-processing with SP as target */
+       TEST("add       sp, sp, #16")
+       TEST("sub       sp, sp, #8")
+       TEST("bic       sp, sp, #0x20")
+       TEST("orr       sp, sp, #0x20")
+       TEST_PR( "add   sp, r",10,0,", r",11,4,"")
+       TEST_PRR("add   sp, r",10,0,", r",11,4,", asl r",12,1,"")
+       TEST_P(  "mov   sp, r",10,0,"")
+       TEST_PR( "mov   sp, r",10,0,", asl r",12,0,"")
+
+       /* Data-processing with PC as target */
+       TEST_BF(   "add pc, pc, #2f-1b-8")
+       TEST_BF_R ("add pc, pc, r",14,2f-1f-8,"")
+       TEST_BF_R ("add pc, r",14,2f-1f-8,", pc")
+       TEST_BF_R ("mov pc, r",0,2f,"")
+       TEST_BF_R ("add pc, pc, r",14,(2f-1f-8)*2,", asr #1")
+       TEST_BB(   "sub pc, pc, #1b-2b+8")
+#if __LINUX_ARM_ARCH__ == 6 && !defined(CONFIG_CPU_V7)
+       TEST_BB(   "sub pc, pc, #1b-2b+8-2") /* UNPREDICTABLE before and after ARMv6 */
+#endif
+       TEST_BB_R( "sub pc, pc, r",14, 1f-2f+8,"")
+       TEST_BB_R( "rsb pc, r",14,1f-2f+8,", pc")
+       TEST_R(    "add pc, pc, r",10,-2,", asl #1")
+#ifdef CONFIG_THUMB2_KERNEL
+       TEST_ARM_TO_THUMB_INTERWORK_R("add      pc, pc, r",0,3f-1f-8+1,"")
+       TEST_ARM_TO_THUMB_INTERWORK_R("sub      pc, r",0,3f+8+1,", #8")
+#endif
+       TEST_GROUP("Miscellaneous instructions")
+
+       TEST("mrs       r0, cpsr")
+       TEST("mrspl     r7, cpsr")
+       TEST("mrs       r14, cpsr")
+       TEST_UNSUPPORTED(__inst_arm(0xe10ff000) "       @ mrs r15, cpsr")
+       TEST_UNSUPPORTED("mrs   r0, spsr")
+       TEST_UNSUPPORTED("mrs   lr, spsr")
+
+       TEST_UNSUPPORTED("msr   cpsr, r0")
+       TEST_UNSUPPORTED("msr   cpsr_f, lr")
+       TEST_UNSUPPORTED("msr   spsr, r0")
+
+       TEST_BF_R("bx   r",0,2f,"")
+       TEST_BB_R("bx   r",7,2f,"")
+       TEST_BF_R("bxeq r",14,2f,"")
+
+#if __LINUX_ARM_ARCH__ >= 5
+       TEST_R("clz     r0, r",0, 0x0,"")
+       TEST_R("clzeq   r7, r",14,0x1,"")
+       TEST_R("clz     lr, r",7, 0xffffffff,"")
+       TEST(  "clz     r4, sp")
+       TEST_UNSUPPORTED(__inst_arm(0x016fff10) "       @ clz pc, r0")
+       TEST_UNSUPPORTED(__inst_arm(0x016f0f1f) "       @ clz r0, pc")
+
+#if __LINUX_ARM_ARCH__ >= 6
+       TEST_UNSUPPORTED("bxj   r0")
+#endif
+
+       TEST_BF_R("blx  r",0,2f,"")
+       TEST_BB_R("blx  r",7,2f,"")
+       TEST_BF_R("blxeq        r",14,2f,"")
+       TEST_UNSUPPORTED(__inst_arm(0x0120003f) "       @ blx pc")
+
+       TEST_RR(   "qadd        r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(   "qaddvs      lr, r",9, VAL2,", r",8, VAL1,"")
+       TEST_R(    "qadd        lr, r",9, VAL2,", r13")
+       TEST_RR(   "qsub        r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(   "qsubvs      lr, r",9, VAL2,", r",8, VAL1,"")
+       TEST_R(    "qsub        lr, r",9, VAL2,", r13")
+       TEST_RR(   "qdadd       r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(   "qdaddvs     lr, r",9, VAL2,", r",8, VAL1,"")
+       TEST_R(    "qdadd       lr, r",9, VAL2,", r13")
+       TEST_RR(   "qdsub       r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(   "qdsubvs     lr, r",9, VAL2,", r",8, VAL1,"")
+       TEST_R(    "qdsub       lr, r",9, VAL2,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe101f050) "       @ qadd pc, r0, r1")
+       TEST_UNSUPPORTED(__inst_arm(0xe121f050) "       @ qsub pc, r0, r1")
+       TEST_UNSUPPORTED(__inst_arm(0xe141f050) "       @ qdadd pc, r0, r1")
+       TEST_UNSUPPORTED(__inst_arm(0xe161f050) "       @ qdsub pc, r0, r1")
+       TEST_UNSUPPORTED(__inst_arm(0xe16f2050) "       @ qdsub r2, r0, pc")
+       TEST_UNSUPPORTED(__inst_arm(0xe161205f) "       @ qdsub r2, pc, r1")
+
+       TEST_UNSUPPORTED("bkpt  0xffff")
+       TEST_UNSUPPORTED("bkpt  0x0000")
+
+       TEST_UNSUPPORTED(__inst_arm(0xe1600070) " @ smc #0")
+
+       TEST_GROUP("Halfword multiply and multiply-accumulate")
+
+       TEST_RRR(    "smlabb    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(    "smlabbge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RR(     "smlabb    lr, r",1, VAL2,", r",2, VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe10f3281) " @ smlabb pc, r1, r2, r3")
+       TEST_RRR(    "smlatb    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(    "smlatbge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RR(     "smlatb    lr, r",1, VAL2,", r",2, VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe10f32a1) " @ smlatb pc, r1, r2, r3")
+       TEST_RRR(    "smlabt    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(    "smlabtge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RR(     "smlabt    lr, r",1, VAL2,", r",2, VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe10f32c1) " @ smlabt pc, r1, r2, r3")
+       TEST_RRR(    "smlatt    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(    "smlattge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RR(     "smlatt    lr, r",1, VAL2,", r",2, VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe10f32e1) " @ smlatt pc, r1, r2, r3")
+
+       TEST_RRR(    "smlawb    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(    "smlawbge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RR(     "smlawb    lr, r",1, VAL2,", r",2, VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe12f3281) " @ smlawb pc, r1, r2, r3")
+       TEST_RRR(    "smlawt    r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(    "smlawtge  r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RR(     "smlawt    lr, r",1, VAL2,", r",2, VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe12f32c1) " @ smlawt pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe12032cf) " @ smlawt r0, pc, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe1203fc1) " @ smlawt r0, r1, pc, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe120f2c1) " @ smlawt r0, r1, r2, pc")
+
+       TEST_RR(    "smulwb     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smulwbge   r7, r",8, VAL3,", r",9, VAL1,"")
+       TEST_R(     "smulwb     lr, r",1, VAL2,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe12f02a1) " @ smulwb pc, r1, r2")
+       TEST_RR(    "smulwt     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smulwtge   r7, r",8, VAL3,", r",9, VAL1,"")
+       TEST_R(     "smulwt     lr, r",1, VAL2,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe12f02e1) " @ smulwt pc, r1, r2")
+
+       TEST_RRRR(  "smlalbb    r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR(  "smlalbble  r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRR(   "smlalbb    r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe14f1382) " @ smlalbb pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe141f382) " @ smlalbb r1, pc, r2, r3")
+       TEST_RRRR(  "smlaltb    r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR(  "smlaltble  r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRR(   "smlaltb    r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe14f13a2) " @ smlaltb pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe141f3a2) " @ smlaltb r1, pc, r2, r3")
+       TEST_RRRR(  "smlalbt    r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR(  "smlalbtle  r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRR(   "smlalbt    r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe14f13c2) " @ smlalbt pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe141f3c2) " @ smlalbt r1, pc, r2, r3")
+       TEST_RRRR(  "smlaltt    r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR(  "smlalttle  r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRR(   "smlaltt    r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe14f13e2) " @ smlalbb pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe140f3e2) " @ smlalbb r0, pc, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe14013ef) " @ smlalbb r0, r1, pc, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe1401fe2) " @ smlalbb r0, r1, r2, pc")
+
+       TEST_RR(    "smulbb     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smulbbge   r7, r",8, VAL3,", r",9, VAL1,"")
+       TEST_R(     "smulbb     lr, r",1, VAL2,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe16f0281) " @ smulbb pc, r1, r2")
+       TEST_RR(    "smultb     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smultbge   r7, r",8, VAL3,", r",9, VAL1,"")
+       TEST_R(     "smultb     lr, r",1, VAL2,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe16f02a1) " @ smultb pc, r1, r2")
+       TEST_RR(    "smulbt     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smulbtge   r7, r",8, VAL3,", r",9, VAL1,"")
+       TEST_R(     "smulbt     lr, r",1, VAL2,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe16f02c1) " @ smultb pc, r1, r2")
+       TEST_RR(    "smultt     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smulttge   r7, r",8, VAL3,", r",9, VAL1,"")
+       TEST_R(     "smultt     lr, r",1, VAL2,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe16f02e1) " @ smultt pc, r1, r2")
+       TEST_UNSUPPORTED(__inst_arm(0xe16002ef) " @ smultt r0, pc, r2")
+       TEST_UNSUPPORTED(__inst_arm(0xe1600fe1) " @ smultt r0, r1, pc")
+#endif
+
+       TEST_GROUP("Multiply and multiply-accumulate")
+
+       TEST_RR(    "mul        r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "mulls      r7, r",8, VAL2,", r",9, VAL2,"")
+       TEST_R(     "mul        lr, r",4, VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe00f0291) " @ mul pc, r1, r2")
+       TEST_UNSUPPORTED(__inst_arm(0xe000029f) " @ mul r0, pc, r2")
+       TEST_UNSUPPORTED(__inst_arm(0xe0000f91) " @ mul r0, r1, pc")
+       TEST_RR(    "muls       r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "mullss     r7, r",8, VAL2,", r",9, VAL2,"")
+       TEST_R(     "muls       lr, r",4, VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe01f0291) " @ muls pc, r1, r2")
+
+       TEST_RRR(    "mla       r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(    "mlahi     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RR(     "mla       lr, r",1, VAL2,", r",2, VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe02f3291) " @ mla pc, r1, r2, r3")
+       TEST_RRR(    "mlas      r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(    "mlahis    r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RR(     "mlas      lr, r",1, VAL2,", r",2, VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe03f3291) " @ mlas pc, r1, r2, r3")
+
+#if __LINUX_ARM_ARCH__ >= 6
+       TEST_RR(  "umaal        r0, r1, r",2, VAL1,", r",3, VAL2,"")
+       TEST_RR(  "umaalls      r7, r8, r",9, VAL2,", r",10, VAL1,"")
+       TEST_R(   "umaal        lr, r12, r",11,VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe041f392) " @ umaal pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe04f0392) " @ umaal r0, pc, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe0500090) " @ undef")
+       TEST_UNSUPPORTED(__inst_arm(0xe05fff9f) " @ undef")
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 7
+       TEST_RRR(  "mls         r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(  "mlshi       r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RR(   "mls         lr, r",1, VAL2,", r",2, VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe06f3291) " @ mls pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe060329f) " @ mls r0, pc, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe0603f91) " @ mls r0, r1, pc, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe060f291) " @ mls r0, r1, r2, pc")
+#endif
+
+       TEST_UNSUPPORTED(__inst_arm(0xe0700090) " @ undef")
+       TEST_UNSUPPORTED(__inst_arm(0xe07fff9f) " @ undef")
+
+       TEST_RR(  "umull        r0, r1, r",2, VAL1,", r",3, VAL2,"")
+       TEST_RR(  "umullls      r7, r8, r",9, VAL2,", r",10, VAL1,"")
+       TEST_R(   "umull        lr, r12, r",11,VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe081f392) " @ umull pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe08f1392) " @ umull r1, pc, r2, r3")
+       TEST_RR(  "umulls       r0, r1, r",2, VAL1,", r",3, VAL2,"")
+       TEST_RR(  "umulllss     r7, r8, r",9, VAL2,", r",10, VAL1,"")
+       TEST_R(   "umulls       lr, r12, r",11,VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe091f392) " @ umulls pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe09f1392) " @ umulls r1, pc, r2, r3")
+
+       TEST_RRRR(  "umlal      r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR(  "umlalle    r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRR(   "umlal      r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe0af1392) " @ umlal pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe0a1f392) " @ umlal r1, pc, r2, r3")
+       TEST_RRRR(  "umlals     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR(  "umlalles   r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRR(   "umlals     r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe0bf1392) " @ umlals pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe0b1f392) " @ umlals r1, pc, r2, r3")
+
+       TEST_RR(  "smull        r0, r1, r",2, VAL1,", r",3, VAL2,"")
+       TEST_RR(  "smullls      r7, r8, r",9, VAL2,", r",10, VAL1,"")
+       TEST_R(   "smull        lr, r12, r",11,VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe0c1f392) " @ smull pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe0cf1392) " @ smull r1, pc, r2, r3")
+       TEST_RR(  "smulls       r0, r1, r",2, VAL1,", r",3, VAL2,"")
+       TEST_RR(  "smulllss     r7, r8, r",9, VAL2,", r",10, VAL1,"")
+       TEST_R(   "smulls       lr, r12, r",11,VAL3,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe0d1f392) " @ smulls pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe0df1392) " @ smulls r1, pc, r2, r3")
+
+       TEST_RRRR(  "smlal      r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR(  "smlalle    r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRR(   "smlal      r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe0ef1392) " @ smlal pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe0e1f392) " @ smlal r1, pc, r2, r3")
+       TEST_RRRR(  "smlals     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR(  "smlalles   r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRR(   "smlals     r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+       TEST_UNSUPPORTED(__inst_arm(0xe0ff1392) " @ smlals pc, r1, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe0f0f392) " @ smlals r0, pc, r2, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe0f0139f) " @ smlals r0, r1, pc, r3")
+       TEST_UNSUPPORTED(__inst_arm(0xe0f01f92) " @ smlals r0, r1, r2, pc")
+
+       TEST_GROUP("Synchronization primitives")
+
+#if __LINUX_ARM_ARCH__ < 6
+       TEST_RP("swp    lr, r",7,VAL2,", [r",8,0,"]")
+       TEST_R( "swpvs  r0, r",1,VAL1,", [sp]")
+       TEST_RP("swp    sp, r",14,VAL2,", [r",12,13*4,"]")
+#else
+       TEST_UNSUPPORTED(__inst_arm(0xe108e097) " @ swp lr, r7, [r8]")
+       TEST_UNSUPPORTED(__inst_arm(0x610d0091) " @ swpvs       r0, r1, [sp]")
+       TEST_UNSUPPORTED(__inst_arm(0xe10cd09e) " @ swp sp, r14 [r12]")
+#endif
+       TEST_UNSUPPORTED(__inst_arm(0xe102f091) " @ swp pc, r1, [r2]")
+       TEST_UNSUPPORTED(__inst_arm(0xe102009f) " @ swp r0, pc, [r2]")
+       TEST_UNSUPPORTED(__inst_arm(0xe10f0091) " @ swp r0, r1, [pc]")
+#if __LINUX_ARM_ARCH__ < 6
+       TEST_RP("swpb   lr, r",7,VAL2,", [r",8,0,"]")
+       TEST_R( "swpvsb r0, r",1,VAL1,", [sp]")
+#else
+       TEST_UNSUPPORTED(__inst_arm(0xe148e097) " @ swpb        lr, r7, [r8]")
+       TEST_UNSUPPORTED(__inst_arm(0x614d0091) " @ swpvsb      r0, r1, [sp]")
+#endif
+       TEST_UNSUPPORTED(__inst_arm(0xe142f091) " @ swpb pc, r1, [r2]")
+
+       TEST_UNSUPPORTED(__inst_arm(0xe1100090)) /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe1200090)) /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe1300090)) /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe1500090)) /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe1600090)) /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe1700090)) /* Unallocated space */
+#if __LINUX_ARM_ARCH__ >= 6
+       TEST_UNSUPPORTED("ldrex r2, [sp]")
+#endif
+#if (__LINUX_ARM_ARCH__ >= 7) || defined(CONFIG_CPU_32v6K)
+       TEST_UNSUPPORTED("strexd        r0, r2, r3, [sp]")
+       TEST_UNSUPPORTED("ldrexd        r2, r3, [sp]")
+       TEST_UNSUPPORTED("strexb        r0, r2, [sp]")
+       TEST_UNSUPPORTED("ldrexb        r2, [sp]")
+       TEST_UNSUPPORTED("strexh        r0, r2, [sp]")
+       TEST_UNSUPPORTED("ldrexh        r2, [sp]")
+#endif
+       TEST_GROUP("Extra load/store instructions")
+
+       TEST_RPR(  "strh        r",0, VAL1,", [r",1, 48,", -r",2, 24,"]")
+       TEST_RPR(  "streqh      r",14,VAL2,", [r",13,0, ", r",12, 48,"]")
+       TEST_RPR(  "strh        r",1, VAL1,", [r",2, 24,", r",3,  48,"]!")
+       TEST_RPR(  "strneh      r",12,VAL2,", [r",11,48,", -r",10,24,"]!")
+       TEST_RPR(  "strh        r",2, VAL1,", [r",3, 24,"], r",4, 48,"")
+       TEST_RPR(  "strh        r",10,VAL2,", [r",9, 48,"], -r",11,24,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe1afc0ba) "       @ strh r12, [pc, r10]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe089f0bb) "       @ strh pc, [r9], r11")
+       TEST_UNSUPPORTED(__inst_arm(0xe089a0bf) "       @ strh r10, [r9], pc")
+
+       TEST_PR(   "ldrh        r0, [r",0,  48,", -r",2, 24,"]")
+       TEST_PR(   "ldrcsh      r14, [r",13,0, ", r",12, 48,"]")
+       TEST_PR(   "ldrh        r1, [r",2,  24,", r",3,  48,"]!")
+       TEST_PR(   "ldrcch      r12, [r",11,48,", -r",10,24,"]!")
+       TEST_PR(   "ldrh        r2, [r",3,  24,"], r",4, 48,"")
+       TEST_PR(   "ldrh        r10, [r",9, 48,"], -r",11,24,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe1bfc0ba) "       @ ldrh r12, [pc, r10]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe099f0bb) "       @ ldrh pc, [r9], r11")
+       TEST_UNSUPPORTED(__inst_arm(0xe099a0bf) "       @ ldrh r10, [r9], pc")
+
+       TEST_RP(   "strh        r",0, VAL1,", [r",1, 24,", #-2]")
+       TEST_RP(   "strmih      r",14,VAL2,", [r",13,0, ", #2]")
+       TEST_RP(   "strh        r",1, VAL1,", [r",2, 24,", #4]!")
+       TEST_RP(   "strplh      r",12,VAL2,", [r",11,24,", #-4]!")
+       TEST_RP(   "strh        r",2, VAL1,", [r",3, 24,"], #48")
+       TEST_RP(   "strh        r",10,VAL2,", [r",9, 64,"], #-48")
+       TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) "       @ strh r12, [pc, #48]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) "       @ strh pc, [r9], #48")
+
+       TEST_P(    "ldrh        r0, [r",0,  24,", #-2]")
+       TEST_P(    "ldrvsh      r14, [r",13,0, ", #2]")
+       TEST_P(    "ldrh        r1, [r",2,  24,", #4]!")
+       TEST_P(    "ldrvch      r12, [r",11,24,", #-4]!")
+       TEST_P(    "ldrh        r2, [r",3,  24,"], #48")
+       TEST_P(    "ldrh        r10, [r",9, 64,"], #-48")
+       TEST(      "ldrh        r0, [pc, #0]")
+       TEST_UNSUPPORTED(__inst_arm(0xe1ffc3b0) "       @ ldrh r12, [pc, #48]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe0d9f3b0) "       @ ldrh pc, [r9], #48")
+
+       TEST_PR(   "ldrsb       r0, [r",0,  48,", -r",2, 24,"]")
+       TEST_PR(   "ldrhisb     r14, [r",13,0,", r",12,  48,"]")
+       TEST_PR(   "ldrsb       r1, [r",2,  24,", r",3,  48,"]!")
+       TEST_PR(   "ldrlssb     r12, [r",11,48,", -r",10,24,"]!")
+       TEST_PR(   "ldrsb       r2, [r",3,  24,"], r",4, 48,"")
+       TEST_PR(   "ldrsb       r10, [r",9, 48,"], -r",11,24,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe1bfc0da) "       @ ldrsb r12, [pc, r10]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe099f0db) "       @ ldrsb pc, [r9], r11")
+
+       TEST_P(    "ldrsb       r0, [r",0,  24,", #-1]")
+       TEST_P(    "ldrgesb     r14, [r",13,0, ", #1]")
+       TEST_P(    "ldrsb       r1, [r",2,  24,", #4]!")
+       TEST_P(    "ldrltsb     r12, [r",11,24,", #-4]!")
+       TEST_P(    "ldrsb       r2, [r",3,  24,"], #48")
+       TEST_P(    "ldrsb       r10, [r",9, 64,"], #-48")
+       TEST(      "ldrsb       r0, [pc, #0]")
+       TEST_UNSUPPORTED(__inst_arm(0xe1ffc3d0) "       @ ldrsb r12, [pc, #48]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe0d9f3d0) "       @ ldrsb pc, [r9], #48")
+
+       TEST_PR(   "ldrsh       r0, [r",0,  48,", -r",2, 24,"]")
+       TEST_PR(   "ldrgtsh     r14, [r",13,0, ", r",12, 48,"]")
+       TEST_PR(   "ldrsh       r1, [r",2,  24,", r",3,  48,"]!")
+       TEST_PR(   "ldrlesh     r12, [r",11,48,", -r",10,24,"]!")
+       TEST_PR(   "ldrsh       r2, [r",3,  24,"], r",4, 48,"")
+       TEST_PR(   "ldrsh       r10, [r",9, 48,"], -r",11,24,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe1bfc0fa) "       @ ldrsh r12, [pc, r10]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe099f0fb) "       @ ldrsh pc, [r9], r11")
+
+       TEST_P(    "ldrsh       r0, [r",0,  24,", #-1]")
+       TEST_P(    "ldreqsh     r14, [r",13,0 ,", #1]")
+       TEST_P(    "ldrsh       r1, [r",2,  24,", #4]!")
+       TEST_P(    "ldrnesh     r12, [r",11,24,", #-4]!")
+       TEST_P(    "ldrsh       r2, [r",3,  24,"], #48")
+       TEST_P(    "ldrsh       r10, [r",9, 64,"], #-48")
+       TEST(      "ldrsh       r0, [pc, #0]")
+       TEST_UNSUPPORTED(__inst_arm(0xe1ffc3f0) "       @ ldrsh r12, [pc, #48]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe0d9f3f0) "       @ ldrsh pc, [r9], #48")
+
+#if __LINUX_ARM_ARCH__ >= 7
+       TEST_UNSUPPORTED("strht r1, [r2], r3")
+       TEST_UNSUPPORTED("ldrht r1, [r2], r3")
+       TEST_UNSUPPORTED("strht r1, [r2], #48")
+       TEST_UNSUPPORTED("ldrht r1, [r2], #48")
+       TEST_UNSUPPORTED("ldrsbt        r1, [r2], r3")
+       TEST_UNSUPPORTED("ldrsbt        r1, [r2], #48")
+       TEST_UNSUPPORTED("ldrsht        r1, [r2], r3")
+       TEST_UNSUPPORTED("ldrsht        r1, [r2], #48")
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 5
+       TEST_RPR(  "strd        r",0, VAL1,", [r",1, 48,", -r",2,24,"]")
+       TEST_RPR(  "strccd      r",8, VAL2,", [r",13,0, ", r",12,48,"]")
+       TEST_RPR(  "strd        r",4, VAL1,", [r",2, 24,", r",3, 48,"]!")
+       TEST_RPR(  "strcsd      r",12,VAL2,", [r",11,48,", -r",10,24,"]!")
+       TEST_RPR(  "strd        r",2, VAL1,", [r",5, 24,"], r",4,48,"")
+       TEST_RPR(  "strd        r",10,VAL2,", [r",9, 48,"], -r",7,24,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe1afc0fa) "       @ strd r12, [pc, r10]!")
+
+       TEST_PR(   "ldrd        r0, [r",0, 48,", -r",2,24,"]")
+       TEST_PR(   "ldrmid      r8, [r",13,0, ", r",12,48,"]")
+       TEST_PR(   "ldrd        r4, [r",2, 24,", r",3, 48,"]!")
+       TEST_PR(   "ldrpld      r6, [r",11,48,", -r",10,24,"]!")
+       TEST_PR(   "ldrd        r2, [r",5, 24,"], r",4,48,"")
+       TEST_PR(   "ldrd        r10, [r",9,48,"], -r",7,24,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe1afc0da) "       @ ldrd r12, [pc, r10]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe089f0db) "       @ ldrd pc, [r9], r11")
+       TEST_UNSUPPORTED(__inst_arm(0xe089e0db) "       @ ldrd lr, [r9], r11")
+       TEST_UNSUPPORTED(__inst_arm(0xe089c0df) "       @ ldrd r12, [r9], pc")
+
+       TEST_RP(   "strd        r",0, VAL1,", [r",1, 24,", #-8]")
+       TEST_RP(   "strvsd      r",8, VAL2,", [r",13,0, ", #8]")
+       TEST_RP(   "strd        r",4, VAL1,", [r",2, 24,", #16]!")
+       TEST_RP(   "strvcd      r",12,VAL2,", [r",11,24,", #-16]!")
+       TEST_RP(   "strd        r",2, VAL1,", [r",4, 24,"], #48")
+       TEST_RP(   "strd        r",10,VAL2,", [r",9, 64,"], #-48")
+       TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) "       @ strd r12, [pc, #48]!")
+
+       TEST_P(    "ldrd        r0, [r",0, 24,", #-8]")
+       TEST_P(    "ldrhid      r8, [r",13,0, ", #8]")
+       TEST_P(    "ldrd        r4, [r",2, 24,", #16]!")
+       TEST_P(    "ldrlsd      r6, [r",11,24,", #-16]!")
+       TEST_P(    "ldrd        r2, [r",5, 24,"], #48")
+       TEST_P(    "ldrd        r10, [r",9,6,"], #-48")
+       TEST_UNSUPPORTED(__inst_arm(0xe1efc3d0) "       @ ldrd r12, [pc, #48]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe0c9f3d0) "       @ ldrd pc, [r9], #48")
+       TEST_UNSUPPORTED(__inst_arm(0xe0c9e3d0) "       @ ldrd lr, [r9], #48")
+#endif
+
+       TEST_GROUP("Miscellaneous")
+
+#if __LINUX_ARM_ARCH__ >= 7
+       TEST("movw      r0, #0")
+       TEST("movw      r0, #0xffff")
+       TEST("movw      lr, #0xffff")
+       TEST_UNSUPPORTED(__inst_arm(0xe300f000) "       @ movw pc, #0")
+       TEST_R("movt    r",0, VAL1,", #0")
+       TEST_R("movt    r",0, VAL2,", #0xffff")
+       TEST_R("movt    r",14,VAL1,", #0xffff")
+       TEST_UNSUPPORTED(__inst_arm(0xe340f000) "       @ movt pc, #0")
+#endif
+
+       TEST_UNSUPPORTED("msr   cpsr, 0x13")
+       TEST_UNSUPPORTED("msr   cpsr_f, 0xf0000000")
+       TEST_UNSUPPORTED("msr   spsr, 0x13")
+
+#if __LINUX_ARM_ARCH__ >= 7
+       TEST_SUPPORTED("yield")
+       TEST("sev")
+       TEST("nop")
+       TEST("wfi")
+       TEST_SUPPORTED("wfe")
+       TEST_UNSUPPORTED("dbg #0")
+#endif
+
+       TEST_GROUP("Load/store word and unsigned byte")
+
+#define LOAD_STORE(byte)                                                       \
+       TEST_RP( "str"byte"     r",0, VAL1,", [r",1, 24,", #-2]")               \
+       TEST_RP( "str"byte"     r",14,VAL2,", [r",13,0, ", #2]")                \
+       TEST_RP( "str"byte"     r",1, VAL1,", [r",2, 24,", #4]!")               \
+       TEST_RP( "str"byte"     r",12,VAL2,", [r",11,24,", #-4]!")              \
+       TEST_RP( "str"byte"     r",2, VAL1,", [r",3, 24,"], #48")               \
+       TEST_RP( "str"byte"     r",10,VAL2,", [r",9, 64,"], #-48")              \
+       TEST_RPR("str"byte"     r",0, VAL1,", [r",1, 48,", -r",2, 24,"]")       \
+       TEST_RPR("str"byte"     r",14,VAL2,", [r",13,0, ", r",12, 48,"]")       \
+       TEST_RPR("str"byte"     r",1, VAL1,", [r",2, 24,", r",3,  48,"]!")      \
+       TEST_RPR("str"byte"     r",12,VAL2,", [r",11,48,", -r",10,24,"]!")      \
+       TEST_RPR("str"byte"     r",2, VAL1,", [r",3, 24,"], r",4, 48,"")        \
+       TEST_RPR("str"byte"     r",10,VAL2,", [r",9, 48,"], -r",11,24,"")       \
+       TEST_RPR("str"byte"     r",0, VAL1,", [r",1, 24,", r",2,  32,", asl #1]")\
+       TEST_RPR("str"byte"     r",14,VAL2,", [r",13,0, ", r",12, 32,", lsr #2]")\
+       TEST_RPR("str"byte"     r",1, VAL1,", [r",2, 24,", r",3,  32,", asr #3]!")\
+       TEST_RPR("str"byte"     r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\
+       TEST_P(  "ldr"byte"     r0, [r",0,  24,", #-2]")                        \
+       TEST_P(  "ldr"byte"     r14, [r",13,0, ", #2]")                         \
+       TEST_P(  "ldr"byte"     r1, [r",2,  24,", #4]!")                        \
+       TEST_P(  "ldr"byte"     r12, [r",11,24,", #-4]!")                       \
+       TEST_P(  "ldr"byte"     r2, [r",3,  24,"], #48")                        \
+       TEST_P(  "ldr"byte"     r10, [r",9, 64,"], #-48")                       \
+       TEST_PR( "ldr"byte"     r0, [r",0,  48,", -r",2, 24,"]")                \
+       TEST_PR( "ldr"byte"     r14, [r",13,0, ", r",12, 48,"]")                \
+       TEST_PR( "ldr"byte"     r1, [r",2,  24,", r",3, 48,"]!")                \
+       TEST_PR( "ldr"byte"     r12, [r",11,48,", -r",10,24,"]!")               \
+       TEST_PR( "ldr"byte"     r2, [r",3,  24,"], r",4, 48,"")                 \
+       TEST_PR( "ldr"byte"     r10, [r",9, 48,"], -r",11,24,"")                \
+       TEST_PR( "ldr"byte"     r0, [r",0,  24,", r",2,  32,", asl #1]")        \
+       TEST_PR( "ldr"byte"     r14, [r",13,0, ", r",12, 32,", lsr #2]")        \
+       TEST_PR( "ldr"byte"     r1, [r",2,  24,", r",3,  32,", asr #3]!")       \
+       TEST_PR( "ldr"byte"     r12, [r",11,24,", r",10, 4,", ror #31]!")       \
+       TEST(    "ldr"byte"     r0, [pc, #0]")                                  \
+       TEST_R(  "ldr"byte"     r12, [pc, r",14,0,"]")
+
+       LOAD_STORE("")
+       TEST_P(   "str  pc, [r",0,0,", #15*4]")
+       TEST_R(   "str  pc, [sp, r",2,15*4,"]")
+       TEST_BF(  "ldr  pc, [sp, #15*4]")
+       TEST_BF_R("ldr  pc, [sp, r",2,15*4,"]")
+
+       TEST_P(   "str  sp, [r",0,0,", #13*4]")
+       TEST_R(   "str  sp, [sp, r",2,13*4,"]")
+       TEST_BF(  "ldr  sp, [sp, #13*4]")
+       TEST_BF_R("ldr  sp, [sp, r",2,13*4,"]")
+
+#ifdef CONFIG_THUMB2_KERNEL
+       TEST_ARM_TO_THUMB_INTERWORK_P("ldr      pc, [r",0,0,", #15*4]")
+#endif
+       TEST_UNSUPPORTED(__inst_arm(0xe5af6008) "       @ str r6, [pc, #8]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe7af6008) "       @ str r6, [pc, r8]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe5bf6008) "       @ ldr r6, [pc, #8]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe7bf6008) "       @ ldr r6, [pc, r8]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe788600f) "       @ str r6, [r8, pc]")
+       TEST_UNSUPPORTED(__inst_arm(0xe798600f) "       @ ldr r6, [r8, pc]")
+
+       LOAD_STORE("b")
+       TEST_UNSUPPORTED(__inst_arm(0xe5f7f008) "       @ ldrb pc, [r7, #8]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe7f7f008) "       @ ldrb pc, [r7, r8]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe5ef6008) "       @ strb r6, [pc, #8]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe7ef6008) "       @ strb r6, [pc, r3]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe5ff6008) "       @ ldrb r6, [pc, #8]!")
+       TEST_UNSUPPORTED(__inst_arm(0xe7ff6008) "       @ ldrb r6, [pc, r3]!")
+
+       TEST_UNSUPPORTED("ldrt  r0, [r1], #4")
+       TEST_UNSUPPORTED("ldrt  r1, [r2], r3")
+       TEST_UNSUPPORTED("strt  r2, [r3], #4")
+       TEST_UNSUPPORTED("strt  r3, [r4], r5")
+       TEST_UNSUPPORTED("ldrbt r4, [r5], #4")
+       TEST_UNSUPPORTED("ldrbt r5, [r6], r7")
+       TEST_UNSUPPORTED("strbt r6, [r7], #4")
+       TEST_UNSUPPORTED("strbt r7, [r8], r9")
+
+#if __LINUX_ARM_ARCH__ >= 7
+       TEST_GROUP("Parallel addition and subtraction, signed")
+
+       TEST_UNSUPPORTED(__inst_arm(0xe6000010) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe60fffff) "") /* Unallocated space */
+
+       TEST_RR(    "sadd16     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "sadd16     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe61cff1a) "       @ sadd16        pc, r12, r10")
+       TEST_RR(    "sasx       r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "sasx       r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe61cff3a) "       @ sasx  pc, r12, r10")
+       TEST_RR(    "ssax       r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "ssax       r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe61cff5a) "       @ ssax  pc, r12, r10")
+       TEST_RR(    "ssub16     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "ssub16     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe61cff7a) "       @ ssub16        pc, r12, r10")
+       TEST_RR(    "sadd8      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "sadd8      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe61cff9a) "       @ sadd8 pc, r12, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe61000b0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe61fffbf) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe61000d0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe61fffdf) "") /* Unallocated space */
+       TEST_RR(    "ssub8      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "ssub8      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe61cfffa) "       @ ssub8 pc, r12, r10")
+
+       TEST_RR(    "qadd16     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "qadd16     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe62cff1a) "       @ qadd16        pc, r12, r10")
+       TEST_RR(    "qasx       r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "qasx       r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe62cff3a) "       @ qasx  pc, r12, r10")
+       TEST_RR(    "qsax       r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "qsax       r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe62cff5a) "       @ qsax  pc, r12, r10")
+       TEST_RR(    "qsub16     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "qsub16     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe62cff7a) "       @ qsub16        pc, r12, r10")
+       TEST_RR(    "qadd8      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "qadd8      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe62cff9a) "       @ qadd8 pc, r12, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe62000b0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe62fffbf) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe62000d0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe62fffdf) "") /* Unallocated space */
+       TEST_RR(    "qsub8      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "qsub8      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe62cfffa) "       @ qsub8 pc, r12, r10")
+
+       TEST_RR(    "shadd16    r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "shadd16    r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe63cff1a) "       @ shadd16       pc, r12, r10")
+       TEST_RR(    "shasx      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "shasx      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe63cff3a) "       @ shasx pc, r12, r10")
+       TEST_RR(    "shsax      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "shsax      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe63cff5a) "       @ shsax pc, r12, r10")
+       TEST_RR(    "shsub16    r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "shsub16    r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe63cff7a) "       @ shsub16       pc, r12, r10")
+       TEST_RR(    "shadd8     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "shadd8     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe63cff9a) "       @ shadd8        pc, r12, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe63000b0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe63fffbf) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe63000d0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe63fffdf) "") /* Unallocated space */
+       TEST_RR(    "shsub8     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "shsub8     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe63cfffa) "       @ shsub8        pc, r12, r10")
+
+       TEST_GROUP("Parallel addition and subtraction, unsigned")
+
+       TEST_UNSUPPORTED(__inst_arm(0xe6400010) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe64fffff) "") /* Unallocated space */
+
+       TEST_RR(    "uadd16     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uadd16     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe65cff1a) "       @ uadd16        pc, r12, r10")
+       TEST_RR(    "uasx       r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uasx       r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe65cff3a) "       @ uasx  pc, r12, r10")
+       TEST_RR(    "usax       r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "usax       r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe65cff5a) "       @ usax  pc, r12, r10")
+       TEST_RR(    "usub16     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "usub16     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe65cff7a) "       @ usub16        pc, r12, r10")
+       TEST_RR(    "uadd8      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uadd8      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe65cff9a) "       @ uadd8 pc, r12, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe65000b0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe65fffbf) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe65000d0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe65fffdf) "") /* Unallocated space */
+       TEST_RR(    "usub8      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "usub8      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe65cfffa) "       @ usub8 pc, r12, r10")
+
+       TEST_RR(    "uqadd16    r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uqadd16    r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe66cff1a) "       @ uqadd16       pc, r12, r10")
+       TEST_RR(    "uqasx      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uqasx      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe66cff3a) "       @ uqasx pc, r12, r10")
+       TEST_RR(    "uqsax      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uqsax      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe66cff5a) "       @ uqsax pc, r12, r10")
+       TEST_RR(    "uqsub16    r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uqsub16    r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe66cff7a) "       @ uqsub16       pc, r12, r10")
+       TEST_RR(    "uqadd8     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uqadd8     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe66cff9a) "       @ uqadd8        pc, r12, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe66000b0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe66fffbf) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe66000d0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe66fffdf) "") /* Unallocated space */
+       TEST_RR(    "uqsub8     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uqsub8     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe66cfffa) "       @ uqsub8        pc, r12, r10")
+
+       TEST_RR(    "uhadd16    r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uhadd16    r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe67cff1a) "       @ uhadd16       pc, r12, r10")
+       TEST_RR(    "uhasx      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uhasx      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe67cff3a) "       @ uhasx pc, r12, r10")
+       TEST_RR(    "uhsax      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uhsax      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe67cff5a) "       @ uhsax pc, r12, r10")
+       TEST_RR(    "uhsub16    r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uhsub16    r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe67cff7a) "       @ uhsub16       pc, r12, r10")
+       TEST_RR(    "uhadd8     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uhadd8     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe67cff9a) "       @ uhadd8        pc, r12, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe67000b0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe67fffbf) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe67000d0) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe67fffdf) "") /* Unallocated space */
+       TEST_RR(    "uhsub8     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uhsub8     r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe67cfffa) "       @ uhsub8        pc, r12, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe67feffa) "       @ uhsub8        r14, pc, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe67cefff) "       @ uhsub8        r14, r12, pc")
+#endif /* __LINUX_ARM_ARCH__ >= 7 */
+
+#if __LINUX_ARM_ARCH__ >= 6
+       TEST_GROUP("Packing, unpacking, saturation, and reversal")
+
+       TEST_RR(    "pkhbt      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "pkhbt      r14,r",12, HH1,", r",10,HH2,", lsl #2")
+       TEST_UNSUPPORTED(__inst_arm(0xe68cf11a) "       @ pkhbt pc, r12, r10, lsl #2")
+       TEST_RR(    "pkhtb      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "pkhtb      r14,r",12, HH1,", r",10,HH2,", asr #2")
+       TEST_UNSUPPORTED(__inst_arm(0xe68cf15a) "       @ pkhtb pc, r12, r10, asr #2")
+       TEST_UNSUPPORTED(__inst_arm(0xe68fe15a) "       @ pkhtb r14, pc, r10, asr #2")
+       TEST_UNSUPPORTED(__inst_arm(0xe68ce15f) "       @ pkhtb r14, r12, pc, asr #2")
+       TEST_UNSUPPORTED(__inst_arm(0xe6900010) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe69fffdf) "") /* Unallocated space */
+
+       TEST_R(     "ssat       r0, #24, r",0,   VAL1,"")
+       TEST_R(     "ssat       r14, #24, r",12, VAL2,"")
+       TEST_R(     "ssat       r0, #24, r",0,   VAL1,", lsl #8")
+       TEST_R(     "ssat       r14, #24, r",12, VAL2,", asr #8")
+       TEST_UNSUPPORTED(__inst_arm(0xe6b7f01c) "       @ ssat  pc, #24, r12")
+
+       TEST_R(     "usat       r0, #24, r",0,   VAL1,"")
+       TEST_R(     "usat       r14, #24, r",12, VAL2,"")
+       TEST_R(     "usat       r0, #24, r",0,   VAL1,", lsl #8")
+       TEST_R(     "usat       r14, #24, r",12, VAL2,", asr #8")
+       TEST_UNSUPPORTED(__inst_arm(0xe6f7f01c) "       @ usat  pc, #24, r12")
+
+       TEST_RR(    "sxtab16    r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "sxtab16    r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "sxtb16     r8, r",7,  HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe68cf47a) "       @ sxtab16       pc,r12, r10, ror #8")
+
+       TEST_RR(    "sel        r0, r",0,  VAL1,", r",1, VAL2,"")
+       TEST_RR(    "sel        r14, r",12,VAL1,", r",10, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe68cffba) "       @ sel   pc, r12, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe68fefba) "       @ sel   r14, pc, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe68cefbf) "       @ sel   r14, r12, pc")
+
+       TEST_R(     "ssat16     r0, #12, r",0,   HH1,"")
+       TEST_R(     "ssat16     r14, #12, r",12, HH2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe6abff3c) "       @ ssat16        pc, #12, r12")
+
+       TEST_RR(    "sxtab      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "sxtab      r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "sxtb       r8, r",7,  HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe6acf47a) "       @ sxtab pc,r12, r10, ror #8")
+
+       TEST_R(     "rev        r0, r",0,   VAL1,"")
+       TEST_R(     "rev        r14, r",12, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe6bfff3c) "       @ rev   pc, r12")
+
+       TEST_RR(    "sxtah      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "sxtah      r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "sxth       r8, r",7,  HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe6bcf47a) "       @ sxtah pc,r12, r10, ror #8")
+
+       TEST_R(     "rev16      r0, r",0,   VAL1,"")
+       TEST_R(     "rev16      r14, r",12, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe6bfffbc) "       @ rev16 pc, r12")
+
+       TEST_RR(    "uxtab16    r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uxtab16    r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "uxtb16     r8, r",7,  HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe6ccf47a) "       @ uxtab16       pc,r12, r10, ror #8")
+
+       TEST_R(     "usat16     r0, #12, r",0,   HH1,"")
+       TEST_R(     "usat16     r14, #12, r",12, HH2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe6ecff3c) "       @ usat16        pc, #12, r12")
+       TEST_UNSUPPORTED(__inst_arm(0xe6ecef3f) "       @ usat16        r14, #12, pc")
+
+       TEST_RR(    "uxtab      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uxtab      r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "uxtb       r8, r",7,  HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe6ecf47a) "       @ uxtab pc,r12, r10, ror #8")
+
+#if __LINUX_ARM_ARCH__ >= 7
+       TEST_R(     "rbit       r0, r",0,   VAL1,"")
+       TEST_R(     "rbit       r14, r",12, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe6ffff3c) "       @ rbit  pc, r12")
+#endif
+
+       TEST_RR(    "uxtah      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uxtah      r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "uxth       r8, r",7,  HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe6fff077) "       @ uxth  pc, r7")
+       TEST_UNSUPPORTED(__inst_arm(0xe6ff807f) "       @ uxth  r8, pc")
+       TEST_UNSUPPORTED(__inst_arm(0xe6fcf47a) "       @ uxtah pc, r12, r10, ror #8")
+       TEST_UNSUPPORTED(__inst_arm(0xe6fce47f) "       @ uxtah r14, r12, pc, ror #8")
+
+       TEST_R(     "revsh      r0, r",0,   VAL1,"")
+       TEST_R(     "revsh      r14, r",12, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe6ffff3c) "       @ revsh pc, r12")
+       TEST_UNSUPPORTED(__inst_arm(0xe6ffef3f) "       @ revsh r14, pc")
+
+       TEST_UNSUPPORTED(__inst_arm(0xe6900070) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe69fff7f) "") /* Unallocated space */
+
+       TEST_UNSUPPORTED(__inst_arm(0xe6d00070) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_arm(0xe6dfff7f) "") /* Unallocated space */
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
+#if __LINUX_ARM_ARCH__ >= 6
+       TEST_GROUP("Signed multiplies")
+
+       TEST_RRR(   "smlad      r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
+       TEST_RRR(   "smlad      r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe70f8a1c) "       @ smlad pc, r12, r10, r8")
+       TEST_RRR(   "smladx     r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
+       TEST_RRR(   "smladx     r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe70f8a3c) "       @ smladx        pc, r12, r10, r8")
+
+       TEST_RR(   "smuad       r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(   "smuad       r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe70ffa1c) "       @ smuad pc, r12, r10")
+       TEST_RR(   "smuadx      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(   "smuadx      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe70ffa3c) "       @ smuadx        pc, r12, r10")
+
+       TEST_RRR(   "smlsd      r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
+       TEST_RRR(   "smlsd      r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe70f8a5c) "       @ smlsd pc, r12, r10, r8")
+       TEST_RRR(   "smlsdx     r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
+       TEST_RRR(   "smlsdx     r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe70f8a7c) "       @ smlsdx        pc, r12, r10, r8")
+
+       TEST_RR(   "smusd       r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(   "smusd       r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe70ffa5c) "       @ smusd pc, r12, r10")
+       TEST_RR(   "smusdx      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(   "smusdx      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe70ffa7c) "       @ smusdx        pc, r12, r10")
+
+       TEST_RRRR( "smlald      r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+       TEST_RRRR( "smlald      r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+       TEST_UNSUPPORTED(__inst_arm(0xe74af819) "       @ smlald        pc, r10, r9, r8")
+       TEST_UNSUPPORTED(__inst_arm(0xe74fb819) "       @ smlald        r11, pc, r9, r8")
+       TEST_UNSUPPORTED(__inst_arm(0xe74ab81f) "       @ smlald        r11, r10, pc, r8")
+       TEST_UNSUPPORTED(__inst_arm(0xe74abf19) "       @ smlald        r11, r10, r9, pc")
+
+       TEST_RRRR( "smlaldx     r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+       TEST_RRRR( "smlaldx     r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+       TEST_UNSUPPORTED(__inst_arm(0xe74af839) "       @ smlaldx       pc, r10, r9, r8")
+       TEST_UNSUPPORTED(__inst_arm(0xe74fb839) "       @ smlaldx       r11, pc, r9, r8")
+
+       TEST_RRR(  "smmla       r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
+       TEST_RRR(  "smmla       r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe75f8a1c) "       @ smmla pc, r12, r10, r8")
+       TEST_RRR(  "smmlar      r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
+       TEST_RRR(  "smmlar      r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe75f8a3c) "       @ smmlar        pc, r12, r10, r8")
+
+       TEST_RR(   "smmul       r0, r",0,  VAL1,", r",1, VAL2,"")
+       TEST_RR(   "smmul       r14, r",12,VAL2,", r",10,VAL1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe75ffa1c) "       @ smmul pc, r12, r10")
+       TEST_RR(   "smmulr      r0, r",0,  VAL1,", r",1, VAL2,"")
+       TEST_RR(   "smmulr      r14, r",12,VAL2,", r",10,VAL1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe75ffa3c) "       @ smmulr        pc, r12, r10")
+
+       TEST_RRR(  "smmls       r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
+       TEST_RRR(  "smmls       r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe75f8adc) "       @ smmls pc, r12, r10, r8")
+       TEST_RRR(  "smmlsr      r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
+       TEST_RRR(  "smmlsr      r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe75f8afc) "       @ smmlsr        pc, r12, r10, r8")
+       TEST_UNSUPPORTED(__inst_arm(0xe75e8aff) "       @ smmlsr        r14, pc, r10, r8")
+       TEST_UNSUPPORTED(__inst_arm(0xe75e8ffc) "       @ smmlsr        r14, r12, pc, r8")
+       TEST_UNSUPPORTED(__inst_arm(0xe75efafc) "       @ smmlsr        r14, r12, r10, pc")
+
+       TEST_RR(   "usad8       r0, r",0,  VAL1,", r",1, VAL2,"")
+       TEST_RR(   "usad8       r14, r",12,VAL2,", r",10,VAL1,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe75ffa1c) "       @ usad8 pc, r12, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe75efa1f) "       @ usad8 r14, pc, r10")
+       TEST_UNSUPPORTED(__inst_arm(0xe75eff1c) "       @ usad8 r14, r12, pc")
+
+       TEST_RRR(  "usada8      r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL3,"")
+       TEST_RRR(  "usada8      r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL3,"")
+       TEST_UNSUPPORTED(__inst_arm(0xe78f8a1c) "       @ usada8        pc, r12, r10, r8")
+       TEST_UNSUPPORTED(__inst_arm(0xe78e8a1f) "       @ usada8        r14, pc, r10, r8")
+       TEST_UNSUPPORTED(__inst_arm(0xe78e8f1c) "       @ usada8        r14, r12, pc, r8")
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
+#if __LINUX_ARM_ARCH__ >= 7
+       TEST_GROUP("Bit Field")
+
+       TEST_R(     "sbfx       r0, r",0  , VAL1,", #0, #31")
+       TEST_R(     "sbfxeq     r14, r",12, VAL2,", #8, #16")
+       TEST_R(     "sbfx       r4, r",10,  VAL1,", #16, #15")
+       TEST_UNSUPPORTED(__inst_arm(0xe7aff45c) "       @ sbfx  pc, r12, #8, #16")
+
+       TEST_R(     "ubfx       r0, r",0  , VAL1,", #0, #31")
+       TEST_R(     "ubfxcs     r14, r",12, VAL2,", #8, #16")
+       TEST_R(     "ubfx       r4, r",10,  VAL1,", #16, #15")
+       TEST_UNSUPPORTED(__inst_arm(0xe7eff45c) "       @ ubfx  pc, r12, #8, #16")
+       TEST_UNSUPPORTED(__inst_arm(0xe7efc45f) "       @ ubfx  r12, pc, #8, #16")
+
+       TEST_R(     "bfc        r",0, VAL1,", #4, #20")
+       TEST_R(     "bfcvs      r",14,VAL2,", #4, #20")
+       TEST_R(     "bfc        r",7, VAL1,", #0, #31")
+       TEST_R(     "bfc        r",8, VAL2,", #0, #31")
+       TEST_UNSUPPORTED(__inst_arm(0xe7def01f) "       @ bfc   pc, #0, #31");
+
+       TEST_RR(    "bfi        r",0, VAL1,", r",0  , VAL2,", #0, #31")
+       TEST_RR(    "bfipl      r",12,VAL1,", r",14 , VAL2,", #4, #20")
+       TEST_UNSUPPORTED(__inst_arm(0xe7d7f21e) "       @ bfi   pc, r14, #4, #20")
+
+       TEST_UNSUPPORTED(__inst_arm(0x07f000f0) "")  /* Permanently UNDEFINED */
+       TEST_UNSUPPORTED(__inst_arm(0x07ffffff) "")  /* Permanently UNDEFINED */
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
+       TEST_GROUP("Branch, branch with link, and block data transfer")
+
+       TEST_P(   "stmda        r",0, 16*4,", {r0}")
+       TEST_P(   "stmeqda      r",4, 16*4,", {r0-r15}")
+       TEST_P(   "stmneda      r",8, 16*4,"!, {r8-r15}")
+       TEST_P(   "stmda        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+       TEST_P(   "stmda        r",13,0,   "!, {pc}")
+
+       TEST_P(   "ldmda        r",0, 16*4,", {r0}")
+       TEST_BF_P("ldmcsda      r",4, 15*4,", {r0-r15}")
+       TEST_BF_P("ldmccda      r",7, 15*4,"!, {r8-r15}")
+       TEST_P(   "ldmda        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+       TEST_BF_P("ldmda        r",14,15*4,"!, {pc}")
+
+       TEST_P(   "stmia        r",0, 16*4,", {r0}")
+       TEST_P(   "stmmiia      r",4, 16*4,", {r0-r15}")
+       TEST_P(   "stmplia      r",8, 16*4,"!, {r8-r15}")
+       TEST_P(   "stmia        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+       TEST_P(   "stmia        r",14,0,   "!, {pc}")
+
+       TEST_P(   "ldmia        r",0, 16*4,", {r0}")
+       TEST_BF_P("ldmvsia      r",4, 0,   ", {r0-r15}")
+       TEST_BF_P("ldmvcia      r",7, 8*4, "!, {r8-r15}")
+       TEST_P(   "ldmia        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+       TEST_BF_P("ldmia        r",14,15*4,"!, {pc}")
+
+       TEST_P(   "stmdb        r",0, 16*4,", {r0}")
+       TEST_P(   "stmhidb      r",4, 16*4,", {r0-r15}")
+       TEST_P(   "stmlsdb      r",8, 16*4,"!, {r8-r15}")
+       TEST_P(   "stmdb        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+       TEST_P(   "stmdb        r",13,4,   "!, {pc}")
+
+       TEST_P(   "ldmdb        r",0, 16*4,", {r0}")
+       TEST_BF_P("ldmgedb      r",4, 16*4,", {r0-r15}")
+       TEST_BF_P("ldmltdb      r",7, 16*4,"!, {r8-r15}")
+       TEST_P(   "ldmdb        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+       TEST_BF_P("ldmdb        r",14,16*4,"!, {pc}")
+
+       TEST_P(   "stmib        r",0, 16*4,", {r0}")
+       TEST_P(   "stmgtib      r",4, 16*4,", {r0-r15}")
+       TEST_P(   "stmleib      r",8, 16*4,"!, {r8-r15}")
+       TEST_P(   "stmib        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+       TEST_P(   "stmib        r",13,-4,  "!, {pc}")
+
+       TEST_P(   "ldmib        r",0, 16*4,", {r0}")
+       TEST_BF_P("ldmeqib      r",4, -4,", {r0-r15}")
+       TEST_BF_P("ldmneib      r",7, 7*4,"!, {r8-r15}")
+       TEST_P(   "ldmib        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+       TEST_BF_P("ldmib        r",14,14*4,"!, {pc}")
+
+       TEST_P(   "stmdb        r",13,16*4,"!, {r3-r12,lr}")
+       TEST_P(   "stmeqdb      r",13,16*4,"!, {r3-r12}")
+       TEST_P(   "stmnedb      r",2, 16*4,", {r3-r12,lr}")
+       TEST_P(   "stmdb        r",13,16*4,"!, {r2-r12,lr}")
+       TEST_P(   "stmdb        r",0, 16*4,", {r0-r12}")
+       TEST_P(   "stmdb        r",0, 16*4,", {r0-r12,lr}")
+
+       TEST_BF_P("ldmia        r",13,5*4, "!, {r3-r12,pc}")
+       TEST_P(   "ldmccia      r",13,5*4, "!, {r3-r12}")
+       TEST_BF_P("ldmcsia      r",2, 5*4, "!, {r3-r12,pc}")
+       TEST_BF_P("ldmia        r",13,4*4, "!, {r2-r12,pc}")
+       TEST_P(   "ldmia        r",0, 16*4,", {r0-r12}")
+       TEST_P(   "ldmia        r",0, 16*4,", {r0-r12,lr}")
+
+#ifdef CONFIG_THUMB2_KERNEL
+       TEST_ARM_TO_THUMB_INTERWORK_P("ldmplia  r",0,15*4,", {pc}")
+       TEST_ARM_TO_THUMB_INTERWORK_P("ldmmiia  r",13,0,", {r0-r15}")
+#endif
+       TEST_BF("b      2f")
+       TEST_BF("bl     2f")
+       TEST_BB("b      2b")
+       TEST_BB("bl     2b")
+
+       TEST_BF("beq    2f")
+       TEST_BF("bleq   2f")
+       TEST_BB("bne    2b")
+       TEST_BB("blne   2b")
+
+       TEST_BF("bgt    2f")
+       TEST_BF("blgt   2f")
+       TEST_BB("blt    2b")
+       TEST_BB("bllt   2b")
+
+       TEST_GROUP("Supervisor Call, and coprocessor instructions")
+
+       /*
+        * We can't really test these by executing them, so all
+        * we can do is check that probes are, or are not allowed.
+        * At the moment none are allowed...
+        */
+#define TEST_COPROCESSOR(code) TEST_UNSUPPORTED(code)
+
+#define COPROCESSOR_INSTRUCTIONS_ST_LD(two,cc)                                 \
+       TEST_COPROCESSOR("stc"two"      0, cr0, [r13, #4]")                     \
+       TEST_COPROCESSOR("stc"two"      0, cr0, [r13, #-4]")                    \
+       TEST_COPROCESSOR("stc"two"      0, cr0, [r13, #4]!")                    \
+       TEST_COPROCESSOR("stc"two"      0, cr0, [r13, #-4]!")                   \
+       TEST_COPROCESSOR("stc"two"      0, cr0, [r13], #4")                     \
+       TEST_COPROCESSOR("stc"two"      0, cr0, [r13], #-4")                    \
+       TEST_COPROCESSOR("stc"two"      0, cr0, [r13], {1}")                    \
+       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13, #4]")                     \
+       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13, #-4]")                    \
+       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13, #4]!")                    \
+       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13, #-4]!")                   \
+       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13], #4")                     \
+       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13], #-4")                    \
+       TEST_COPROCESSOR("stc"two"l     0, cr0, [r13], {1}")                    \
+       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13, #4]")                     \
+       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13, #-4]")                    \
+       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13, #4]!")                    \
+       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13, #-4]!")                   \
+       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13], #4")                     \
+       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13], #-4")                    \
+       TEST_COPROCESSOR("ldc"two"      0, cr0, [r13], {1}")                    \
+       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13, #4]")                     \
+       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13, #-4]")                    \
+       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13, #4]!")                    \
+       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13, #-4]!")                   \
+       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13], #4")                     \
+       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13], #-4")                    \
+       TEST_COPROCESSOR("ldc"two"l     0, cr0, [r13], {1}")                    \
+                                                                               \
+       TEST_COPROCESSOR( "stc"two"     0, cr0, [r15, #4]")                     \
+       TEST_COPROCESSOR( "stc"two"     0, cr0, [r15, #-4]")                    \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##daf0001) "  @ stc"two"      0, cr0, [r15, #4]!")    \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##d2f0001) "  @ stc"two"      0, cr0, [r15, #-4]!")   \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##caf0001) "  @ stc"two"      0, cr0, [r15], #4")     \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##c2f0001) "  @ stc"two"      0, cr0, [r15], #-4")    \
+       TEST_COPROCESSOR( "stc"two"     0, cr0, [r15], {1}")                    \
+       TEST_COPROCESSOR( "stc"two"l    0, cr0, [r15, #4]")                     \
+       TEST_COPROCESSOR( "stc"two"l    0, cr0, [r15, #-4]")                    \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##def0001) "  @ stc"two"l     0, cr0, [r15, #4]!")    \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##d6f0001) "  @ stc"two"l     0, cr0, [r15, #-4]!")   \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##cef0001) "  @ stc"two"l     0, cr0, [r15], #4")     \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##c6f0001) "  @ stc"two"l     0, cr0, [r15], #-4")    \
+       TEST_COPROCESSOR( "stc"two"l    0, cr0, [r15], {1}")                    \
+       TEST_COPROCESSOR( "ldc"two"     0, cr0, [r15, #4]")                     \
+       TEST_COPROCESSOR( "ldc"two"     0, cr0, [r15, #-4]")                    \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##dbf0001) "  @ ldc"two"      0, cr0, [r15, #4]!")    \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##d3f0001) "  @ ldc"two"      0, cr0, [r15, #-4]!")   \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##cbf0001) "  @ ldc"two"      0, cr0, [r15], #4")     \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##c3f0001) "  @ ldc"two"      0, cr0, [r15], #-4")    \
+       TEST_COPROCESSOR( "ldc"two"     0, cr0, [r15], {1}")                    \
+       TEST_COPROCESSOR( "ldc"two"l    0, cr0, [r15, #4]")                     \
+       TEST_COPROCESSOR( "ldc"two"l    0, cr0, [r15, #-4]")                    \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##dff0001) "  @ ldc"two"l     0, cr0, [r15, #4]!")    \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##d7f0001) "  @ ldc"two"l     0, cr0, [r15, #-4]!")   \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##cff0001) "  @ ldc"two"l     0, cr0, [r15], #4")     \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##c7f0001) "  @ ldc"two"l     0, cr0, [r15], #-4")    \
+       TEST_COPROCESSOR( "ldc"two"l    0, cr0, [r15], {1}")
+
+#define COPROCESSOR_INSTRUCTIONS_MC_MR(two,cc)                                 \
+                                                                               \
+       TEST_COPROCESSOR( "mcrr"two"    0, 15, r0, r14, cr0")                   \
+       TEST_COPROCESSOR( "mcrr"two"    15, 0, r14, r0, cr15")                  \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##c4f00f0) "  @ mcrr"two"     0, 15, r0, r15, cr0")   \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##c40ff0f) "  @ mcrr"two"     15, 0, r15, r0, cr15")  \
+       TEST_COPROCESSOR( "mrrc"two"    0, 15, r0, r14, cr0")                   \
+       TEST_COPROCESSOR( "mrrc"two"    15, 0, r14, r0, cr15")                  \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##c5f00f0) "  @ mrrc"two"     0, 15, r0, r15, cr0")   \
+       TEST_UNSUPPORTED(__inst_arm(0x##cc##c50ff0f) "  @ mrrc"two"     15, 0, r15, r0, cr15")  \
+       TEST_COPROCESSOR( "cdp"two"     15, 15, cr15, cr15, cr15, 7")           \
+       TEST_COPROCESSOR( "cdp"two"     0, 0, cr0, cr0, cr0, 0")                \
+       TEST_COPROCESSOR( "mcr"two"     15, 7, r15, cr15, cr15, 7")             \
+       TEST_COPROCESSOR( "mcr"two"     0, 0, r0, cr0, cr0, 0")                 \
+       TEST_COPROCESSOR( "mrc"two"     15, 7, r15, cr15, cr15, 7")             \
+       TEST_COPROCESSOR( "mrc"two"     0, 0, r0, cr0, cr0, 0")
+
+       COPROCESSOR_INSTRUCTIONS_ST_LD("",e)
+#if __LINUX_ARM_ARCH__ >= 5
+       COPROCESSOR_INSTRUCTIONS_MC_MR("",e)
+#endif
+       TEST_UNSUPPORTED("svc   0")
+       TEST_UNSUPPORTED("svc   0xffffff")
+
+       TEST_UNSUPPORTED("svc   0")
+
+       TEST_GROUP("Unconditional instruction")
+
+#if __LINUX_ARM_ARCH__ >= 6
+       TEST_UNSUPPORTED("srsda sp, 0x13")
+       TEST_UNSUPPORTED("srsdb sp, 0x13")
+       TEST_UNSUPPORTED("srsia sp, 0x13")
+       TEST_UNSUPPORTED("srsib sp, 0x13")
+       TEST_UNSUPPORTED("srsda sp!, 0x13")
+       TEST_UNSUPPORTED("srsdb sp!, 0x13")
+       TEST_UNSUPPORTED("srsia sp!, 0x13")
+       TEST_UNSUPPORTED("srsib sp!, 0x13")
+
+       TEST_UNSUPPORTED("rfeda sp")
+       TEST_UNSUPPORTED("rfedb sp")
+       TEST_UNSUPPORTED("rfeia sp")
+       TEST_UNSUPPORTED("rfeib sp")
+       TEST_UNSUPPORTED("rfeda sp!")
+       TEST_UNSUPPORTED("rfedb sp!")
+       TEST_UNSUPPORTED("rfeia sp!")
+       TEST_UNSUPPORTED("rfeib sp!")
+       TEST_UNSUPPORTED(__inst_arm(0xf81d0a00) "       @ rfeda pc")
+       TEST_UNSUPPORTED(__inst_arm(0xf91d0a00) "       @ rfedb pc")
+       TEST_UNSUPPORTED(__inst_arm(0xf89d0a00) "       @ rfeia pc")
+       TEST_UNSUPPORTED(__inst_arm(0xf99d0a00) "       @ rfeib pc")
+       TEST_UNSUPPORTED(__inst_arm(0xf83d0a00) "       @ rfeda pc!")
+       TEST_UNSUPPORTED(__inst_arm(0xf93d0a00) "       @ rfedb pc!")
+       TEST_UNSUPPORTED(__inst_arm(0xf8bd0a00) "       @ rfeia pc!")
+       TEST_UNSUPPORTED(__inst_arm(0xf9bd0a00) "       @ rfeib pc!")
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
+#if __LINUX_ARM_ARCH__ >= 6
+       TEST_X( "blx    __dummy_thumb_subroutine_even",
+               ".thumb                         \n\t"
+               ".space 4                       \n\t"
+               ".type __dummy_thumb_subroutine_even, %%function \n\t"
+               "__dummy_thumb_subroutine_even: \n\t"
+               "mov    r0, pc                  \n\t"
+               "bx     lr                      \n\t"
+               ".arm                           \n\t"
+       )
+       TEST(   "blx    __dummy_thumb_subroutine_even")
+
+       TEST_X( "blx    __dummy_thumb_subroutine_odd",
+               ".thumb                         \n\t"
+               ".space 2                       \n\t"
+               ".type __dummy_thumb_subroutine_odd, %%function \n\t"
+               "__dummy_thumb_subroutine_odd:  \n\t"
+               "mov    r0, pc                  \n\t"
+               "bx     lr                      \n\t"
+               ".arm                           \n\t"
+       )
+       TEST(   "blx    __dummy_thumb_subroutine_odd")
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
+#if __LINUX_ARM_ARCH__ >= 5
+       COPROCESSOR_INSTRUCTIONS_ST_LD("2",f)
+#endif
+#if __LINUX_ARM_ARCH__ >= 6
+       COPROCESSOR_INSTRUCTIONS_MC_MR("2",f)
+#endif
+
+       TEST_GROUP("Miscellaneous instructions, memory hints, and Advanced SIMD instructions")
+
+#if __LINUX_ARM_ARCH__ >= 6
+       TEST_UNSUPPORTED("cps   0x13")
+       TEST_UNSUPPORTED("cpsie i")
+       TEST_UNSUPPORTED("cpsid i")
+       TEST_UNSUPPORTED("cpsie i,0x13")
+       TEST_UNSUPPORTED("cpsid i,0x13")
+       TEST_UNSUPPORTED("setend        le")
+       TEST_UNSUPPORTED("setend        be")
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 7
+       TEST_P("pli     [r",0,0b,", #16]")
+       TEST(  "pli     [pc, #0]")
+       TEST_RR("pli    [r",12,0b,", r",0, 16,"]")
+       TEST_RR("pli    [r",0, 0b,", -r",12,16,", lsl #4]")
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 5
+       TEST_P("pld     [r",0,32,", #-16]")
+       TEST(  "pld     [pc, #0]")
+       TEST_PR("pld    [r",7, 24, ", r",0, 16,"]")
+       TEST_PR("pld    [r",8, 24, ", -r",12,16,", lsl #4]")
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 7
+       TEST_SUPPORTED(  __inst_arm(0xf590f000) "       @ pldw [r0, #0]")
+       TEST_SUPPORTED(  __inst_arm(0xf797f000) "       @ pldw  [r7, r0]")
+       TEST_SUPPORTED(  __inst_arm(0xf798f18c) "       @ pldw  [r8, r12, lsl #3]");
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 7
+       TEST_UNSUPPORTED("clrex")
+       TEST_UNSUPPORTED("dsb")
+       TEST_UNSUPPORTED("dmb")
+       TEST_UNSUPPORTED("isb")
+#endif
+
+       verbose("\n");
+}
+
diff --git a/arch/arm/probes/kprobes/test-core.c b/arch/arm/probes/kprobes/test-core.c
new file mode 100644 (file)
index 0000000..7ab633d
--- /dev/null
@@ -0,0 +1,1713 @@
+/*
+ * arch/arm/kernel/kprobes-test.c
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This file contains test code for ARM kprobes.
+ *
+ * The top level function run_all_tests() executes tests for all of the
+ * supported instruction sets: ARM, 16-bit Thumb, and 32-bit Thumb. These tests
+ * fall into two categories; run_api_tests() checks basic functionality of the
+ * kprobes API, and run_test_cases() is a comprehensive test for kprobes
+ * instruction decoding and simulation.
+ *
+ * run_test_cases() first checks the kprobes decoding table for self consistency
+ * (using table_test()) then executes a series of test cases for each of the CPU
+ * instruction forms. coverage_start() and coverage_end() are used to verify
+ * that these test cases cover all of the possible combinations of instructions
+ * described by the kprobes decoding tables.
+ *
+ * The individual test cases are in kprobes-test-arm.c and kprobes-test-thumb.c
+ * which use the macros defined in kprobes-test.h. The rest of this
+ * documentation will describe the operation of the framework used by these
+ * test cases.
+ */
+
+/*
+ * TESTING METHODOLOGY
+ * -------------------
+ *
+ * The methodology used to test an ARM instruction 'test_insn' is to use
+ * inline assembler like:
+ *
+ * test_before: nop
+ * test_case:  test_insn
+ * test_after: nop
+ *
+ * When the test case is run a kprobe is placed of each nop. The
+ * post-handler of the test_before probe is used to modify the saved CPU
+ * register context to that which we require for the test case. The
+ * pre-handler of the of the test_after probe saves a copy of the CPU
+ * register context. In this way we can execute test_insn with a specific
+ * register context and see the results afterwards.
+ *
+ * To actually test the kprobes instruction emulation we perform the above
+ * step a second time but with an additional kprobe on the test_case
+ * instruction itself. If the emulation is accurate then the results seen
+ * by the test_after probe will be identical to the first run which didn't
+ * have a probe on test_case.
+ *
+ * Each test case is run several times with a variety of variations in the
+ * flags value of stored in CPSR, and for Thumb code, different ITState.
+ *
+ * For instructions which can modify PC, a second test_after probe is used
+ * like this:
+ *
+ * test_before: nop
+ * test_case:  test_insn
+ * test_after: nop
+ *             b test_done
+ * test_after2: nop
+ * test_done:
+ *
+ * The test case is constructed such that test_insn branches to
+ * test_after2, or, if testing a conditional instruction, it may just
+ * continue to test_after. The probes inserted at both locations let us
+ * determine which happened. A similar approach is used for testing
+ * backwards branches...
+ *
+ *             b test_before
+ *             b test_done  @ helps to cope with off by 1 branches
+ * test_after2: nop
+ *             b test_done
+ * test_before: nop
+ * test_case:  test_insn
+ * test_after: nop
+ * test_done:
+ *
+ * The macros used to generate the assembler instructions describe above
+ * are TEST_INSTRUCTION, TEST_BRANCH_F (branch forwards) and TEST_BRANCH_B
+ * (branch backwards). In these, the local variables numbered 1, 50, 2 and
+ * 99 represent: test_before, test_case, test_after2 and test_done.
+ *
+ * FRAMEWORK
+ * ---------
+ *
+ * Each test case is wrapped between the pair of macros TESTCASE_START and
+ * TESTCASE_END. As well as performing the inline assembler boilerplate,
+ * these call out to the kprobes_test_case_start() and
+ * kprobes_test_case_end() functions which drive the execution of the test
+ * case. The specific arguments to use for each test case are stored as
+ * inline data constructed using the various TEST_ARG_* macros. Putting
+ * this all together, a simple test case may look like:
+ *
+ *     TESTCASE_START("Testing mov r0, r7")
+ *     TEST_ARG_REG(7, 0x12345678) // Set r7=0x12345678
+ *     TEST_ARG_END("")
+ *     TEST_INSTRUCTION("mov r0, r7")
+ *     TESTCASE_END
+ *
+ * Note, in practice the single convenience macro TEST_R would be used for this
+ * instead.
+ *
+ * The above would expand to assembler looking something like:
+ *
+ *     @ TESTCASE_START
+ *     bl      __kprobes_test_case_start
+ *     .pushsection .rodata
+ *     "10:
+ *     .ascii "mov r0, r7"     @ text title for test case
+ *     .byte   0
+ *     .popsection
+ *     @ start of inline data...
+ *     .word   10b             @ pointer to title in .rodata section
+ *
+ *     @ TEST_ARG_REG
+ *     .byte   ARG_TYPE_REG
+ *     .byte   7
+ *     .short  0
+ *     .word   0x1234567
+ *
+ *     @ TEST_ARG_END
+ *     .byte   ARG_TYPE_END
+ *     .byte   TEST_ISA        @ flags, including ISA being tested
+ *     .short  50f-0f          @ offset of 'test_before'
+ *     .short  2f-0f           @ offset of 'test_after2' (if relevent)
+ *     .short  99f-0f          @ offset of 'test_done'
+ *     @ start of test case code...
+ *     0:
+ *     .code   TEST_ISA        @ switch to ISA being tested
+ *
+ *     @ TEST_INSTRUCTION
+ *     50:     nop             @ location for 'test_before' probe
+ *     1:      mov r0, r7      @ the test case instruction 'test_insn'
+ *             nop             @ location for 'test_after' probe
+ *
+ *     // TESTCASE_END
+ *     2:
+ *     99:     bl __kprobes_test_case_end_##TEST_ISA
+ *     .code   NONMAL_ISA
+ *
+ * When the above is execute the following happens...
+ *
+ * __kprobes_test_case_start() is an assembler wrapper which sets up space
+ * for a stack buffer and calls the C function kprobes_test_case_start().
+ * This C function will do some initial processing of the inline data and
+ * setup some global state. It then inserts the test_before and test_after
+ * kprobes and returns a value which causes the assembler wrapper to jump
+ * to the start of the test case code, (local label '0').
+ *
+ * When the test case code executes, the test_before probe will be hit and
+ * test_before_post_handler will call setup_test_context(). This fills the
+ * stack buffer and CPU registers with a test pattern and then processes
+ * the test case arguments. In our example there is one TEST_ARG_REG which
+ * indicates that R7 should be loaded with the value 0x12345678.
+ *
+ * When the test_before probe ends, the test case continues and executes
+ * the "mov r0, r7" instruction. It then hits the test_after probe and the
+ * pre-handler for this (test_after_pre_handler) will save a copy of the
+ * CPU register context. This should now have R0 holding the same value as
+ * R7.
+ *
+ * Finally we get to the call to __kprobes_test_case_end_{32,16}. This is
+ * an assembler wrapper which switches back to the ISA used by the test
+ * code and calls the C function kprobes_test_case_end().
+ *
+ * For each run through the test case, test_case_run_count is incremented
+ * by one. For even runs, kprobes_test_case_end() saves a copy of the
+ * register and stack buffer contents from the test case just run. It then
+ * inserts a kprobe on the test case instruction 'test_insn' and returns a
+ * value to cause the test case code to be re-run.
+ *
+ * For odd numbered runs, kprobes_test_case_end() compares the register and
+ * stack buffer contents to those that were saved on the previous even
+ * numbered run (the one without the kprobe on test_insn). These should be
+ * the same if the kprobe instruction simulation routine is correct.
+ *
+ * The pair of test case runs is repeated with different combinations of
+ * flag values in CPSR and, for Thumb, different ITState. This is
+ * controlled by test_context_cpsr().
+ *
+ * BUILDING TEST CASES
+ * -------------------
+ *
+ *
+ * As an aid to building test cases, the stack buffer is initialised with
+ * some special values:
+ *
+ *   [SP+13*4] Contains SP+120. This can be used to test instructions
+ *             which load a value into SP.
+ *
+ *   [SP+15*4] When testing branching instructions using TEST_BRANCH_{F,B},
+ *             this holds the target address of the branch, 'test_after2'.
+ *             This can be used to test instructions which load a PC value
+ *             from memory.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kprobes.h>
+#include <linux/errno.h>
+#include <linux/stddef.h>
+#include <linux/bug.h>
+#include <asm/opcodes.h>
+
+#include "core.h"
+#include "test-core.h"
+#include "../decode-arm.h"
+#include "../decode-thumb.h"
+
+
+#define BENCHMARKING   1
+
+
+/*
+ * Test basic API
+ */
+
+static bool test_regs_ok;
+static int test_func_instance;
+static int pre_handler_called;
+static int post_handler_called;
+static int jprobe_func_called;
+static int kretprobe_handler_called;
+static int tests_failed;
+
+#define FUNC_ARG1 0x12345678
+#define FUNC_ARG2 0xabcdef
+
+
+#ifndef CONFIG_THUMB2_KERNEL
+
+long arm_func(long r0, long r1);
+
+static void __used __naked __arm_kprobes_test_func(void)
+{
+       __asm__ __volatile__ (
+               ".arm                                   \n\t"
+               ".type arm_func, %%function             \n\t"
+               "arm_func:                              \n\t"
+               "adds   r0, r0, r1                      \n\t"
+               "bx     lr                              \n\t"
+               ".code "NORMAL_ISA       /* Back to Thumb if necessary */
+               : : : "r0", "r1", "cc"
+       );
+}
+
+#else /* CONFIG_THUMB2_KERNEL */
+
+long thumb16_func(long r0, long r1);
+long thumb32even_func(long r0, long r1);
+long thumb32odd_func(long r0, long r1);
+
+static void __used __naked __thumb_kprobes_test_funcs(void)
+{
+       __asm__ __volatile__ (
+               ".type thumb16_func, %%function         \n\t"
+               "thumb16_func:                          \n\t"
+               "adds.n r0, r0, r1                      \n\t"
+               "bx     lr                              \n\t"
+
+               ".align                                 \n\t"
+               ".type thumb32even_func, %%function     \n\t"
+               "thumb32even_func:                      \n\t"
+               "adds.w r0, r0, r1                      \n\t"
+               "bx     lr                              \n\t"
+
+               ".align                                 \n\t"
+               "nop.n                                  \n\t"
+               ".type thumb32odd_func, %%function      \n\t"
+               "thumb32odd_func:                       \n\t"
+               "adds.w r0, r0, r1                      \n\t"
+               "bx     lr                              \n\t"
+
+               : : : "r0", "r1", "cc"
+       );
+}
+
+#endif /* CONFIG_THUMB2_KERNEL */
+
+
+static int call_test_func(long (*func)(long, long), bool check_test_regs)
+{
+       long ret;
+
+       ++test_func_instance;
+       test_regs_ok = false;
+
+       ret = (*func)(FUNC_ARG1, FUNC_ARG2);
+       if (ret != FUNC_ARG1 + FUNC_ARG2) {
+               pr_err("FAIL: call_test_func: func returned %lx\n", ret);
+               return false;
+       }
+
+       if (check_test_regs && !test_regs_ok) {
+               pr_err("FAIL: test regs not OK\n");
+               return false;
+       }
+
+       return true;
+}
+
+static int __kprobes pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       pre_handler_called = test_func_instance;
+       if (regs->ARM_r0 == FUNC_ARG1 && regs->ARM_r1 == FUNC_ARG2)
+               test_regs_ok = true;
+       return 0;
+}
+
+static void __kprobes post_handler(struct kprobe *p, struct pt_regs *regs,
+                               unsigned long flags)
+{
+       post_handler_called = test_func_instance;
+       if (regs->ARM_r0 != FUNC_ARG1 + FUNC_ARG2 || regs->ARM_r1 != FUNC_ARG2)
+               test_regs_ok = false;
+}
+
+static struct kprobe the_kprobe = {
+       .addr           = 0,
+       .pre_handler    = pre_handler,
+       .post_handler   = post_handler
+};
+
+static int test_kprobe(long (*func)(long, long))
+{
+       int ret;
+
+       the_kprobe.addr = (kprobe_opcode_t *)func;
+       ret = register_kprobe(&the_kprobe);
+       if (ret < 0) {
+               pr_err("FAIL: register_kprobe failed with %d\n", ret);
+               return ret;
+       }
+
+       ret = call_test_func(func, true);
+
+       unregister_kprobe(&the_kprobe);
+       the_kprobe.flags = 0; /* Clear disable flag to allow reuse */
+
+       if (!ret)
+               return -EINVAL;
+       if (pre_handler_called != test_func_instance) {
+               pr_err("FAIL: kprobe pre_handler not called\n");
+               return -EINVAL;
+       }
+       if (post_handler_called != test_func_instance) {
+               pr_err("FAIL: kprobe post_handler not called\n");
+               return -EINVAL;
+       }
+       if (!call_test_func(func, false))
+               return -EINVAL;
+       if (pre_handler_called == test_func_instance ||
+                               post_handler_called == test_func_instance) {
+               pr_err("FAIL: probe called after unregistering\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void __kprobes jprobe_func(long r0, long r1)
+{
+       jprobe_func_called = test_func_instance;
+       if (r0 == FUNC_ARG1 && r1 == FUNC_ARG2)
+               test_regs_ok = true;
+       jprobe_return();
+}
+
+static struct jprobe the_jprobe = {
+       .entry          = jprobe_func,
+};
+
+static int test_jprobe(long (*func)(long, long))
+{
+       int ret;
+
+       the_jprobe.kp.addr = (kprobe_opcode_t *)func;
+       ret = register_jprobe(&the_jprobe);
+       if (ret < 0) {
+               pr_err("FAIL: register_jprobe failed with %d\n", ret);
+               return ret;
+       }
+
+       ret = call_test_func(func, true);
+
+       unregister_jprobe(&the_jprobe);
+       the_jprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
+
+       if (!ret)
+               return -EINVAL;
+       if (jprobe_func_called != test_func_instance) {
+               pr_err("FAIL: jprobe handler function not called\n");
+               return -EINVAL;
+       }
+       if (!call_test_func(func, false))
+               return -EINVAL;
+       if (jprobe_func_called == test_func_instance) {
+               pr_err("FAIL: probe called after unregistering\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int __kprobes
+kretprobe_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       kretprobe_handler_called = test_func_instance;
+       if (regs_return_value(regs) == FUNC_ARG1 + FUNC_ARG2)
+               test_regs_ok = true;
+       return 0;
+}
+
+static struct kretprobe the_kretprobe = {
+       .handler        = kretprobe_handler,
+};
+
+static int test_kretprobe(long (*func)(long, long))
+{
+       int ret;
+
+       the_kretprobe.kp.addr = (kprobe_opcode_t *)func;
+       ret = register_kretprobe(&the_kretprobe);
+       if (ret < 0) {
+               pr_err("FAIL: register_kretprobe failed with %d\n", ret);
+               return ret;
+       }
+
+       ret = call_test_func(func, true);
+
+       unregister_kretprobe(&the_kretprobe);
+       the_kretprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
+
+       if (!ret)
+               return -EINVAL;
+       if (kretprobe_handler_called != test_func_instance) {
+               pr_err("FAIL: kretprobe handler not called\n");
+               return -EINVAL;
+       }
+       if (!call_test_func(func, false))
+               return -EINVAL;
+       if (jprobe_func_called == test_func_instance) {
+               pr_err("FAIL: kretprobe called after unregistering\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int run_api_tests(long (*func)(long, long))
+{
+       int ret;
+
+       pr_info("    kprobe\n");
+       ret = test_kprobe(func);
+       if (ret < 0)
+               return ret;
+
+       pr_info("    jprobe\n");
+       ret = test_jprobe(func);
+#if defined(CONFIG_THUMB2_KERNEL) && !defined(MODULE)
+       if (ret == -EINVAL) {
+               pr_err("FAIL: Known longtime bug with jprobe on Thumb kernels\n");
+               tests_failed = ret;
+               ret = 0;
+       }
+#endif
+       if (ret < 0)
+               return ret;
+
+       pr_info("    kretprobe\n");
+       ret = test_kretprobe(func);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+
+/*
+ * Benchmarking
+ */
+
+#if BENCHMARKING
+
+static void __naked benchmark_nop(void)
+{
+       __asm__ __volatile__ (
+               "nop            \n\t"
+               "bx     lr"
+       );
+}
+
+#ifdef CONFIG_THUMB2_KERNEL
+#define wide ".w"
+#else
+#define wide
+#endif
+
+static void __naked benchmark_pushpop1(void)
+{
+       __asm__ __volatile__ (
+               "stmdb"wide"    sp!, {r3-r11,lr}  \n\t"
+               "ldmia"wide"    sp!, {r3-r11,pc}"
+       );
+}
+
+static void __naked benchmark_pushpop2(void)
+{
+       __asm__ __volatile__ (
+               "stmdb"wide"    sp!, {r0-r8,lr}  \n\t"
+               "ldmia"wide"    sp!, {r0-r8,pc}"
+       );
+}
+
+static void __naked benchmark_pushpop3(void)
+{
+       __asm__ __volatile__ (
+               "stmdb"wide"    sp!, {r4,lr}  \n\t"
+               "ldmia"wide"    sp!, {r4,pc}"
+       );
+}
+
+static void __naked benchmark_pushpop4(void)
+{
+       __asm__ __volatile__ (
+               "stmdb"wide"    sp!, {r0,lr}  \n\t"
+               "ldmia"wide"    sp!, {r0,pc}"
+       );
+}
+
+
+#ifdef CONFIG_THUMB2_KERNEL
+
+static void __naked benchmark_pushpop_thumb(void)
+{
+       __asm__ __volatile__ (
+               "push.n {r0-r7,lr}  \n\t"
+               "pop.n  {r0-r7,pc}"
+       );
+}
+
+#endif
+
+static int __kprobes
+benchmark_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       return 0;
+}
+
+static int benchmark(void(*fn)(void))
+{
+       unsigned n, i, t, t0;
+
+       for (n = 1000; ; n *= 2) {
+               t0 = sched_clock();
+               for (i = n; i > 0; --i)
+                       fn();
+               t = sched_clock() - t0;
+               if (t >= 250000000)
+                       break; /* Stop once we took more than 0.25 seconds */
+       }
+       return t / n; /* Time for one iteration in nanoseconds */
+};
+
+static int kprobe_benchmark(void(*fn)(void), unsigned offset)
+{
+       struct kprobe k = {
+               .addr           = (kprobe_opcode_t *)((uintptr_t)fn + offset),
+               .pre_handler    = benchmark_pre_handler,
+       };
+
+       int ret = register_kprobe(&k);
+       if (ret < 0) {
+               pr_err("FAIL: register_kprobe failed with %d\n", ret);
+               return ret;
+       }
+
+       ret = benchmark(fn);
+
+       unregister_kprobe(&k);
+       return ret;
+};
+
+struct benchmarks {
+       void            (*fn)(void);
+       unsigned        offset;
+       const char      *title;
+};
+
+static int run_benchmarks(void)
+{
+       int ret;
+       struct benchmarks list[] = {
+               {&benchmark_nop, 0, "nop"},
+               /*
+                * benchmark_pushpop{1,3} will have the optimised
+                * instruction emulation, whilst benchmark_pushpop{2,4} will
+                * be the equivalent unoptimised instructions.
+                */
+               {&benchmark_pushpop1, 0, "stmdb sp!, {r3-r11,lr}"},
+               {&benchmark_pushpop1, 4, "ldmia sp!, {r3-r11,pc}"},
+               {&benchmark_pushpop2, 0, "stmdb sp!, {r0-r8,lr}"},
+               {&benchmark_pushpop2, 4, "ldmia sp!, {r0-r8,pc}"},
+               {&benchmark_pushpop3, 0, "stmdb sp!, {r4,lr}"},
+               {&benchmark_pushpop3, 4, "ldmia sp!, {r4,pc}"},
+               {&benchmark_pushpop4, 0, "stmdb sp!, {r0,lr}"},
+               {&benchmark_pushpop4, 4, "ldmia sp!, {r0,pc}"},
+#ifdef CONFIG_THUMB2_KERNEL
+               {&benchmark_pushpop_thumb, 0, "push.n   {r0-r7,lr}"},
+               {&benchmark_pushpop_thumb, 2, "pop.n    {r0-r7,pc}"},
+#endif
+               {0}
+       };
+
+       struct benchmarks *b;
+       for (b = list; b->fn; ++b) {
+               ret = kprobe_benchmark(b->fn, b->offset);
+               if (ret < 0)
+                       return ret;
+               pr_info("    %dns for kprobe %s\n", ret, b->title);
+       }
+
+       pr_info("\n");
+       return 0;
+}
+
+#endif /* BENCHMARKING */
+
+
+/*
+ * Decoding table self-consistency tests
+ */
+
+static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
+       [DECODE_TYPE_TABLE]     = sizeof(struct decode_table),
+       [DECODE_TYPE_CUSTOM]    = sizeof(struct decode_custom),
+       [DECODE_TYPE_SIMULATE]  = sizeof(struct decode_simulate),
+       [DECODE_TYPE_EMULATE]   = sizeof(struct decode_emulate),
+       [DECODE_TYPE_OR]        = sizeof(struct decode_or),
+       [DECODE_TYPE_REJECT]    = sizeof(struct decode_reject)
+};
+
+static int table_iter(const union decode_item *table,
+                       int (*fn)(const struct decode_header *, void *),
+                       void *args)
+{
+       const struct decode_header *h = (struct decode_header *)table;
+       int result;
+
+       for (;;) {
+               enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
+
+               if (type == DECODE_TYPE_END)
+                       return 0;
+
+               result = fn(h, args);
+               if (result)
+                       return result;
+
+               h = (struct decode_header *)
+                       ((uintptr_t)h + decode_struct_sizes[type]);
+
+       }
+}
+
+static int table_test_fail(const struct decode_header *h, const char* message)
+{
+
+       pr_err("FAIL: kprobes test failure \"%s\" (mask %08x, value %08x)\n",
+                                       message, h->mask.bits, h->value.bits);
+       return -EINVAL;
+}
+
+struct table_test_args {
+       const union decode_item *root_table;
+       u32                     parent_mask;
+       u32                     parent_value;
+};
+
+static int table_test_fn(const struct decode_header *h, void *args)
+{
+       struct table_test_args *a = (struct table_test_args *)args;
+       enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
+
+       if (h->value.bits & ~h->mask.bits)
+               return table_test_fail(h, "Match value has bits not in mask");
+
+       if ((h->mask.bits & a->parent_mask) != a->parent_mask)
+               return table_test_fail(h, "Mask has bits not in parent mask");
+
+       if ((h->value.bits ^ a->parent_value) & a->parent_mask)
+               return table_test_fail(h, "Value is inconsistent with parent");
+
+       if (type == DECODE_TYPE_TABLE) {
+               struct decode_table *d = (struct decode_table *)h;
+               struct table_test_args args2 = *a;
+               args2.parent_mask = h->mask.bits;
+               args2.parent_value = h->value.bits;
+               return table_iter(d->table.table, table_test_fn, &args2);
+       }
+
+       return 0;
+}
+
+static int table_test(const union decode_item *table)
+{
+       struct table_test_args args = {
+               .root_table     = table,
+               .parent_mask    = 0,
+               .parent_value   = 0
+       };
+       return table_iter(args.root_table, table_test_fn, &args);
+}
+
+
+/*
+ * Decoding table test coverage analysis
+ *
+ * coverage_start() builds a coverage_table which contains a list of
+ * coverage_entry's to match each entry in the specified kprobes instruction
+ * decoding table.
+ *
+ * When test cases are run, coverage_add() is called to process each case.
+ * This looks up the corresponding entry in the coverage_table and sets it as
+ * being matched, as well as clearing the regs flag appropriate for the test.
+ *
+ * After all test cases have been run, coverage_end() is called to check that
+ * all entries in coverage_table have been matched and that all regs flags are
+ * cleared. I.e. that all possible combinations of instructions described by
+ * the kprobes decoding tables have had a test case executed for them.
+ */
+
+bool coverage_fail;
+
+#define MAX_COVERAGE_ENTRIES 256
+
+struct coverage_entry {
+       const struct decode_header      *header;
+       unsigned                        regs;
+       unsigned                        nesting;
+       char                            matched;
+};
+
+struct coverage_table {
+       struct coverage_entry   *base;
+       unsigned                num_entries;
+       unsigned                nesting;
+};
+
+struct coverage_table coverage;
+
+#define COVERAGE_ANY_REG       (1<<0)
+#define COVERAGE_SP            (1<<1)
+#define COVERAGE_PC            (1<<2)
+#define COVERAGE_PCWB          (1<<3)
+
+static const char coverage_register_lookup[16] = {
+       [REG_TYPE_ANY]          = COVERAGE_ANY_REG | COVERAGE_SP | COVERAGE_PC,
+       [REG_TYPE_SAMEAS16]     = COVERAGE_ANY_REG,
+       [REG_TYPE_SP]           = COVERAGE_SP,
+       [REG_TYPE_PC]           = COVERAGE_PC,
+       [REG_TYPE_NOSP]         = COVERAGE_ANY_REG | COVERAGE_SP,
+       [REG_TYPE_NOSPPC]       = COVERAGE_ANY_REG | COVERAGE_SP | COVERAGE_PC,
+       [REG_TYPE_NOPC]         = COVERAGE_ANY_REG | COVERAGE_PC,
+       [REG_TYPE_NOPCWB]       = COVERAGE_ANY_REG | COVERAGE_PC | COVERAGE_PCWB,
+       [REG_TYPE_NOPCX]        = COVERAGE_ANY_REG,
+       [REG_TYPE_NOSPPCX]      = COVERAGE_ANY_REG | COVERAGE_SP,
+};
+
+unsigned coverage_start_registers(const struct decode_header *h)
+{
+       unsigned regs = 0;
+       int i;
+       for (i = 0; i < 20; i += 4) {
+               int r = (h->type_regs.bits >> (DECODE_TYPE_BITS + i)) & 0xf;
+               regs |= coverage_register_lookup[r] << i;
+       }
+       return regs;
+}
+
+static int coverage_start_fn(const struct decode_header *h, void *args)
+{
+       struct coverage_table *coverage = (struct coverage_table *)args;
+       enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
+       struct coverage_entry *entry = coverage->base + coverage->num_entries;
+
+       if (coverage->num_entries == MAX_COVERAGE_ENTRIES - 1) {
+               pr_err("FAIL: Out of space for test coverage data");
+               return -ENOMEM;
+       }
+
+       ++coverage->num_entries;
+
+       entry->header = h;
+       entry->regs = coverage_start_registers(h);
+       entry->nesting = coverage->nesting;
+       entry->matched = false;
+
+       if (type == DECODE_TYPE_TABLE) {
+               struct decode_table *d = (struct decode_table *)h;
+               int ret;
+               ++coverage->nesting;
+               ret = table_iter(d->table.table, coverage_start_fn, coverage);
+               --coverage->nesting;
+               return ret;
+       }
+
+       return 0;
+}
+
+static int coverage_start(const union decode_item *table)
+{
+       coverage.base = kmalloc(MAX_COVERAGE_ENTRIES *
+                               sizeof(struct coverage_entry), GFP_KERNEL);
+       coverage.num_entries = 0;
+       coverage.nesting = 0;
+       return table_iter(table, coverage_start_fn, &coverage);
+}
+
+static void
+coverage_add_registers(struct coverage_entry *entry, kprobe_opcode_t insn)
+{
+       int regs = entry->header->type_regs.bits >> DECODE_TYPE_BITS;
+       int i;
+       for (i = 0; i < 20; i += 4) {
+               enum decode_reg_type reg_type = (regs >> i) & 0xf;
+               int reg = (insn >> i) & 0xf;
+               int flag;
+
+               if (!reg_type)
+                       continue;
+
+               if (reg == 13)
+                       flag = COVERAGE_SP;
+               else if (reg == 15)
+                       flag = COVERAGE_PC;
+               else
+                       flag = COVERAGE_ANY_REG;
+               entry->regs &= ~(flag << i);
+
+               switch (reg_type) {
+
+               case REG_TYPE_NONE:
+               case REG_TYPE_ANY:
+               case REG_TYPE_SAMEAS16:
+                       break;
+
+               case REG_TYPE_SP:
+                       if (reg != 13)
+                               return;
+                       break;
+
+               case REG_TYPE_PC:
+                       if (reg != 15)
+                               return;
+                       break;
+
+               case REG_TYPE_NOSP:
+                       if (reg == 13)
+                               return;
+                       break;
+
+               case REG_TYPE_NOSPPC:
+               case REG_TYPE_NOSPPCX:
+                       if (reg == 13 || reg == 15)
+                               return;
+                       break;
+
+               case REG_TYPE_NOPCWB:
+                       if (!is_writeback(insn))
+                               break;
+                       if (reg == 15) {
+                               entry->regs &= ~(COVERAGE_PCWB << i);
+                               return;
+                       }
+                       break;
+
+               case REG_TYPE_NOPC:
+               case REG_TYPE_NOPCX:
+                       if (reg == 15)
+                               return;
+                       break;
+               }
+
+       }
+}
+
+static void coverage_add(kprobe_opcode_t insn)
+{
+       struct coverage_entry *entry = coverage.base;
+       struct coverage_entry *end = coverage.base + coverage.num_entries;
+       bool matched = false;
+       unsigned nesting = 0;
+
+       for (; entry < end; ++entry) {
+               const struct decode_header *h = entry->header;
+               enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
+
+               if (entry->nesting > nesting)
+                       continue; /* Skip sub-table we didn't match */
+
+               if (entry->nesting < nesting)
+                       break; /* End of sub-table we were scanning */
+
+               if (!matched) {
+                       if ((insn & h->mask.bits) != h->value.bits)
+                               continue;
+                       entry->matched = true;
+               }
+
+               switch (type) {
+
+               case DECODE_TYPE_TABLE:
+                       ++nesting;
+                       break;
+
+               case DECODE_TYPE_CUSTOM:
+               case DECODE_TYPE_SIMULATE:
+               case DECODE_TYPE_EMULATE:
+                       coverage_add_registers(entry, insn);
+                       return;
+
+               case DECODE_TYPE_OR:
+                       matched = true;
+                       break;
+
+               case DECODE_TYPE_REJECT:
+               default:
+                       return;
+               }
+
+       }
+}
+
+static void coverage_end(void)
+{
+       struct coverage_entry *entry = coverage.base;
+       struct coverage_entry *end = coverage.base + coverage.num_entries;
+
+       for (; entry < end; ++entry) {
+               u32 mask = entry->header->mask.bits;
+               u32 value = entry->header->value.bits;
+
+               if (entry->regs) {
+                       pr_err("FAIL: Register test coverage missing for %08x %08x (%05x)\n",
+                               mask, value, entry->regs);
+                       coverage_fail = true;
+               }
+               if (!entry->matched) {
+                       pr_err("FAIL: Test coverage entry missing for %08x %08x\n",
+                               mask, value);
+                       coverage_fail = true;
+               }
+       }
+
+       kfree(coverage.base);
+}
+
+
+/*
+ * Framework for instruction set test cases
+ */
+
+void __naked __kprobes_test_case_start(void)
+{
+       __asm__ __volatile__ (
+               "stmdb  sp!, {r4-r11}                           \n\t"
+               "sub    sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
+               "bic    r0, lr, #1  @ r0 = inline data          \n\t"
+               "mov    r1, sp                                  \n\t"
+               "bl     kprobes_test_case_start                 \n\t"
+               "bx     r0                                      \n\t"
+       );
+}
+
+#ifndef CONFIG_THUMB2_KERNEL
+
+void __naked __kprobes_test_case_end_32(void)
+{
+       __asm__ __volatile__ (
+               "mov    r4, lr                                  \n\t"
+               "bl     kprobes_test_case_end                   \n\t"
+               "cmp    r0, #0                                  \n\t"
+               "movne  pc, r0                                  \n\t"
+               "mov    r0, r4                                  \n\t"
+               "add    sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
+               "ldmia  sp!, {r4-r11}                           \n\t"
+               "mov    pc, r0                                  \n\t"
+       );
+}
+
+#else /* CONFIG_THUMB2_KERNEL */
+
+void __naked __kprobes_test_case_end_16(void)
+{
+       __asm__ __volatile__ (
+               "mov    r4, lr                                  \n\t"
+               "bl     kprobes_test_case_end                   \n\t"
+               "cmp    r0, #0                                  \n\t"
+               "bxne   r0                                      \n\t"
+               "mov    r0, r4                                  \n\t"
+               "add    sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
+               "ldmia  sp!, {r4-r11}                           \n\t"
+               "bx     r0                                      \n\t"
+       );
+}
+
+void __naked __kprobes_test_case_end_32(void)
+{
+       __asm__ __volatile__ (
+               ".arm                                           \n\t"
+               "orr    lr, lr, #1  @ will return to Thumb code \n\t"
+               "ldr    pc, 1f                                  \n\t"
+               "1:                                             \n\t"
+               ".word  __kprobes_test_case_end_16              \n\t"
+       );
+}
+
+#endif
+
+
+int kprobe_test_flags;
+int kprobe_test_cc_position;
+
+static int test_try_count;
+static int test_pass_count;
+static int test_fail_count;
+
+static struct pt_regs initial_regs;
+static struct pt_regs expected_regs;
+static struct pt_regs result_regs;
+
+static u32 expected_memory[TEST_MEMORY_SIZE/sizeof(u32)];
+
+static const char *current_title;
+static struct test_arg *current_args;
+static u32 *current_stack;
+static uintptr_t current_branch_target;
+
+static uintptr_t current_code_start;
+static kprobe_opcode_t current_instruction;
+
+
+#define TEST_CASE_PASSED -1
+#define TEST_CASE_FAILED -2
+
+static int test_case_run_count;
+static bool test_case_is_thumb;
+static int test_instance;
+
+/*
+ * We ignore the state of the imprecise abort disable flag (CPSR.A) because this
+ * can change randomly as the kernel doesn't take care to preserve or initialise
+ * this across context switches. Also, with Security Extentions, the flag may
+ * not be under control of the kernel; for this reason we ignore the state of
+ * the FIQ disable flag CPSR.F as well.
+ */
+#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT)
+
+static unsigned long test_check_cc(int cc, unsigned long cpsr)
+{
+       int ret = arm_check_condition(cc << 28, cpsr);
+
+       return (ret != ARM_OPCODE_CONDTEST_FAIL);
+}
+
+static int is_last_scenario;
+static int probe_should_run; /* 0 = no, 1 = yes, -1 = unknown */
+static int memory_needs_checking;
+
+static unsigned long test_context_cpsr(int scenario)
+{
+       unsigned long cpsr;
+
+       probe_should_run = 1;
+
+       /* Default case is that we cycle through 16 combinations of flags */
+       cpsr  = (scenario & 0xf) << 28; /* N,Z,C,V flags */
+       cpsr |= (scenario & 0xf) << 16; /* GE flags */
+       cpsr |= (scenario & 0x1) << 27; /* Toggle Q flag */
+
+       if (!test_case_is_thumb) {
+               /* Testing ARM code */
+               int cc = current_instruction >> 28;
+
+               probe_should_run = test_check_cc(cc, cpsr) != 0;
+               if (scenario == 15)
+                       is_last_scenario = true;
+
+       } else if (kprobe_test_flags & TEST_FLAG_NO_ITBLOCK) {
+               /* Testing Thumb code without setting ITSTATE */
+               if (kprobe_test_cc_position) {
+                       int cc = (current_instruction >> kprobe_test_cc_position) & 0xf;
+                       probe_should_run = test_check_cc(cc, cpsr) != 0;
+               }
+
+               if (scenario == 15)
+                       is_last_scenario = true;
+
+       } else if (kprobe_test_flags & TEST_FLAG_FULL_ITBLOCK) {
+               /* Testing Thumb code with all combinations of ITSTATE */
+               unsigned x = (scenario >> 4);
+               unsigned cond_base = x % 7; /* ITSTATE<7:5> */
+               unsigned mask = x / 7 + 2;  /* ITSTATE<4:0>, bits reversed */
+
+               if (mask > 0x1f) {
+                       /* Finish by testing state from instruction 'itt al' */
+                       cond_base = 7;
+                       mask = 0x4;
+                       if ((scenario & 0xf) == 0xf)
+                               is_last_scenario = true;
+               }
+
+               cpsr |= cond_base << 13;        /* ITSTATE<7:5> */
+               cpsr |= (mask & 0x1) << 12;     /* ITSTATE<4> */
+               cpsr |= (mask & 0x2) << 10;     /* ITSTATE<3> */
+               cpsr |= (mask & 0x4) << 8;      /* ITSTATE<2> */
+               cpsr |= (mask & 0x8) << 23;     /* ITSTATE<1> */
+               cpsr |= (mask & 0x10) << 21;    /* ITSTATE<0> */
+
+               probe_should_run = test_check_cc((cpsr >> 12) & 0xf, cpsr) != 0;
+
+       } else {
+               /* Testing Thumb code with several combinations of ITSTATE */
+               switch (scenario) {
+               case 16: /* Clear NZCV flags and 'it eq' state (false as Z=0) */
+                       cpsr = 0x00000800;
+                       probe_should_run = 0;
+                       break;
+               case 17: /* Set NZCV flags and 'it vc' state (false as V=1) */
+                       cpsr = 0xf0007800;
+                       probe_should_run = 0;
+                       break;
+               case 18: /* Clear NZCV flags and 'it ls' state (true as C=0) */
+                       cpsr = 0x00009800;
+                       break;
+               case 19: /* Set NZCV flags and 'it cs' state (true as C=1) */
+                       cpsr = 0xf0002800;
+                       is_last_scenario = true;
+                       break;
+               }
+       }
+
+       return cpsr;
+}
+
+static void setup_test_context(struct pt_regs *regs)
+{
+       int scenario = test_case_run_count>>1;
+       unsigned long val;
+       struct test_arg *args;
+       int i;
+
+       is_last_scenario = false;
+       memory_needs_checking = false;
+
+       /* Initialise test memory on stack */
+       val = (scenario & 1) ? VALM : ~VALM;
+       for (i = 0; i < TEST_MEMORY_SIZE / sizeof(current_stack[0]); ++i)
+               current_stack[i] = val + (i << 8);
+       /* Put target of branch on stack for tests which load PC from memory */
+       if (current_branch_target)
+               current_stack[15] = current_branch_target;
+       /* Put a value for SP on stack for tests which load SP from memory */
+       current_stack[13] = (u32)current_stack + 120;
+
+       /* Initialise register values to their default state */
+       val = (scenario & 2) ? VALR : ~VALR;
+       for (i = 0; i < 13; ++i)
+               regs->uregs[i] = val ^ (i << 8);
+       regs->ARM_lr = val ^ (14 << 8);
+       regs->ARM_cpsr &= ~(APSR_MASK | PSR_IT_MASK);
+       regs->ARM_cpsr |= test_context_cpsr(scenario);
+
+       /* Perform testcase specific register setup  */
+       args = current_args;
+       for (; args[0].type != ARG_TYPE_END; ++args)
+               switch (args[0].type) {
+               case ARG_TYPE_REG: {
+                       struct test_arg_regptr *arg =
+                               (struct test_arg_regptr *)args;
+                       regs->uregs[arg->reg] = arg->val;
+                       break;
+               }
+               case ARG_TYPE_PTR: {
+                       struct test_arg_regptr *arg =
+                               (struct test_arg_regptr *)args;
+                       regs->uregs[arg->reg] =
+                               (unsigned long)current_stack + arg->val;
+                       memory_needs_checking = true;
+                       break;
+               }
+               case ARG_TYPE_MEM: {
+                       struct test_arg_mem *arg = (struct test_arg_mem *)args;
+                       current_stack[arg->index] = arg->val;
+                       break;
+               }
+               default:
+                       break;
+               }
+}
+
+struct test_probe {
+       struct kprobe   kprobe;
+       bool            registered;
+       int             hit;
+};
+
+static void unregister_test_probe(struct test_probe *probe)
+{
+       if (probe->registered) {
+               unregister_kprobe(&probe->kprobe);
+               probe->kprobe.flags = 0; /* Clear disable flag to allow reuse */
+       }
+       probe->registered = false;
+}
+
+static int register_test_probe(struct test_probe *probe)
+{
+       int ret;
+
+       if (probe->registered)
+               BUG();
+
+       ret = register_kprobe(&probe->kprobe);
+       if (ret >= 0) {
+               probe->registered = true;
+               probe->hit = -1;
+       }
+       return ret;
+}
+
+static int __kprobes
+test_before_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       container_of(p, struct test_probe, kprobe)->hit = test_instance;
+       return 0;
+}
+
+static void __kprobes
+test_before_post_handler(struct kprobe *p, struct pt_regs *regs,
+                                                       unsigned long flags)
+{
+       setup_test_context(regs);
+       initial_regs = *regs;
+       initial_regs.ARM_cpsr &= ~PSR_IGNORE_BITS;
+}
+
+static int __kprobes
+test_case_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       container_of(p, struct test_probe, kprobe)->hit = test_instance;
+       return 0;
+}
+
+static int __kprobes
+test_after_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       if (container_of(p, struct test_probe, kprobe)->hit == test_instance)
+               return 0; /* Already run for this test instance */
+
+       result_regs = *regs;
+       result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS;
+
+       /* Undo any changes done to SP by the test case */
+       regs->ARM_sp = (unsigned long)current_stack;
+
+       container_of(p, struct test_probe, kprobe)->hit = test_instance;
+       return 0;
+}
+
+static struct test_probe test_before_probe = {
+       .kprobe.pre_handler     = test_before_pre_handler,
+       .kprobe.post_handler    = test_before_post_handler,
+};
+
+static struct test_probe test_case_probe = {
+       .kprobe.pre_handler     = test_case_pre_handler,
+};
+
+static struct test_probe test_after_probe = {
+       .kprobe.pre_handler     = test_after_pre_handler,
+};
+
+static struct test_probe test_after2_probe = {
+       .kprobe.pre_handler     = test_after_pre_handler,
+};
+
+static void test_case_cleanup(void)
+{
+       unregister_test_probe(&test_before_probe);
+       unregister_test_probe(&test_case_probe);
+       unregister_test_probe(&test_after_probe);
+       unregister_test_probe(&test_after2_probe);
+}
+
+static void print_registers(struct pt_regs *regs)
+{
+       pr_err("r0  %08lx | r1  %08lx | r2  %08lx | r3  %08lx\n",
+               regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
+       pr_err("r4  %08lx | r5  %08lx | r6  %08lx | r7  %08lx\n",
+               regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7);
+       pr_err("r8  %08lx | r9  %08lx | r10 %08lx | r11 %08lx\n",
+               regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp);
+       pr_err("r12 %08lx | sp  %08lx | lr  %08lx | pc  %08lx\n",
+               regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc);
+       pr_err("cpsr %08lx\n", regs->ARM_cpsr);
+}
+
+static void print_memory(u32 *mem, size_t size)
+{
+       int i;
+       for (i = 0; i < size / sizeof(u32); i += 4)
+               pr_err("%08x %08x %08x %08x\n", mem[i], mem[i+1],
+                                               mem[i+2], mem[i+3]);
+}
+
+static size_t expected_memory_size(u32 *sp)
+{
+       size_t size = sizeof(expected_memory);
+       int offset = (uintptr_t)sp - (uintptr_t)current_stack;
+       if (offset > 0)
+               size -= offset;
+       return size;
+}
+
+static void test_case_failed(const char *message)
+{
+       test_case_cleanup();
+
+       pr_err("FAIL: %s\n", message);
+       pr_err("FAIL: Test %s\n", current_title);
+       pr_err("FAIL: Scenario %d\n", test_case_run_count >> 1);
+}
+
+static unsigned long next_instruction(unsigned long pc)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+       if ((pc & 1) &&
+           !is_wide_instruction(__mem_to_opcode_thumb16(*(u16 *)(pc - 1))))
+               return pc + 2;
+       else
+#endif
+       return pc + 4;
+}
+
+static uintptr_t __used kprobes_test_case_start(const char **title, void *stack)
+{
+       struct test_arg *args;
+       struct test_arg_end *end_arg;
+       unsigned long test_code;
+
+       current_title = *title++;
+       args = (struct test_arg *)title;
+       current_args = args;
+       current_stack = stack;
+
+       ++test_try_count;
+
+       while (args->type != ARG_TYPE_END)
+               ++args;
+       end_arg = (struct test_arg_end *)args;
+
+       test_code = (unsigned long)(args + 1); /* Code starts after args */
+
+       test_case_is_thumb = end_arg->flags & ARG_FLAG_THUMB;
+       if (test_case_is_thumb)
+               test_code |= 1;
+
+       current_code_start = test_code;
+
+       current_branch_target = 0;
+       if (end_arg->branch_offset != end_arg->end_offset)
+               current_branch_target = test_code + end_arg->branch_offset;
+
+       test_code += end_arg->code_offset;
+       test_before_probe.kprobe.addr = (kprobe_opcode_t *)test_code;
+
+       test_code = next_instruction(test_code);
+       test_case_probe.kprobe.addr = (kprobe_opcode_t *)test_code;
+
+       if (test_case_is_thumb) {
+               u16 *p = (u16 *)(test_code & ~1);
+               current_instruction = __mem_to_opcode_thumb16(p[0]);
+               if (is_wide_instruction(current_instruction)) {
+                       u16 instr2 = __mem_to_opcode_thumb16(p[1]);
+                       current_instruction = __opcode_thumb32_compose(current_instruction, instr2);
+               }
+       } else {
+               current_instruction = __mem_to_opcode_arm(*(u32 *)test_code);
+       }
+
+       if (current_title[0] == '.')
+               verbose("%s\n", current_title);
+       else
+               verbose("%s\t@ %0*x\n", current_title,
+                                       test_case_is_thumb ? 4 : 8,
+                                       current_instruction);
+
+       test_code = next_instruction(test_code);
+       test_after_probe.kprobe.addr = (kprobe_opcode_t *)test_code;
+
+       if (kprobe_test_flags & TEST_FLAG_NARROW_INSTR) {
+               if (!test_case_is_thumb ||
+                       is_wide_instruction(current_instruction)) {
+                               test_case_failed("expected 16-bit instruction");
+                               goto fail;
+               }
+       } else {
+               if (test_case_is_thumb &&
+                       !is_wide_instruction(current_instruction)) {
+                               test_case_failed("expected 32-bit instruction");
+                               goto fail;
+               }
+       }
+
+       coverage_add(current_instruction);
+
+       if (end_arg->flags & ARG_FLAG_UNSUPPORTED) {
+               if (register_test_probe(&test_case_probe) < 0)
+                       goto pass;
+               test_case_failed("registered probe for unsupported instruction");
+               goto fail;
+       }
+
+       if (end_arg->flags & ARG_FLAG_SUPPORTED) {
+               if (register_test_probe(&test_case_probe) >= 0)
+                       goto pass;
+               test_case_failed("couldn't register probe for supported instruction");
+               goto fail;
+       }
+
+       if (register_test_probe(&test_before_probe) < 0) {
+               test_case_failed("register test_before_probe failed");
+               goto fail;
+       }
+       if (register_test_probe(&test_after_probe) < 0) {
+               test_case_failed("register test_after_probe failed");
+               goto fail;
+       }
+       if (current_branch_target) {
+               test_after2_probe.kprobe.addr =
+                               (kprobe_opcode_t *)current_branch_target;
+               if (register_test_probe(&test_after2_probe) < 0) {
+                       test_case_failed("register test_after2_probe failed");
+                       goto fail;
+               }
+       }
+
+       /* Start first run of test case */
+       test_case_run_count = 0;
+       ++test_instance;
+       return current_code_start;
+pass:
+       test_case_run_count = TEST_CASE_PASSED;
+       return (uintptr_t)test_after_probe.kprobe.addr;
+fail:
+       test_case_run_count = TEST_CASE_FAILED;
+       return (uintptr_t)test_after_probe.kprobe.addr;
+}
+
+static bool check_test_results(void)
+{
+       size_t mem_size = 0;
+       u32 *mem = 0;
+
+       if (memcmp(&expected_regs, &result_regs, sizeof(expected_regs))) {
+               test_case_failed("registers differ");
+               goto fail;
+       }
+
+       if (memory_needs_checking) {
+               mem = (u32 *)result_regs.ARM_sp;
+               mem_size = expected_memory_size(mem);
+               if (memcmp(expected_memory, mem, mem_size)) {
+                       test_case_failed("test memory differs");
+                       goto fail;
+               }
+       }
+
+       return true;
+
+fail:
+       pr_err("initial_regs:\n");
+       print_registers(&initial_regs);
+       pr_err("expected_regs:\n");
+       print_registers(&expected_regs);
+       pr_err("result_regs:\n");
+       print_registers(&result_regs);
+
+       if (mem) {
+               pr_err("current_stack=%p\n", current_stack);
+               pr_err("expected_memory:\n");
+               print_memory(expected_memory, mem_size);
+               pr_err("result_memory:\n");
+               print_memory(mem, mem_size);
+       }
+
+       return false;
+}
+
+static uintptr_t __used kprobes_test_case_end(void)
+{
+       if (test_case_run_count < 0) {
+               if (test_case_run_count == TEST_CASE_PASSED)
+                       /* kprobes_test_case_start did all the needed testing */
+                       goto pass;
+               else
+                       /* kprobes_test_case_start failed */
+                       goto fail;
+       }
+
+       if (test_before_probe.hit != test_instance) {
+               test_case_failed("test_before_handler not run");
+               goto fail;
+       }
+
+       if (test_after_probe.hit != test_instance &&
+                               test_after2_probe.hit != test_instance) {
+               test_case_failed("test_after_handler not run");
+               goto fail;
+       }
+
+       /*
+        * Even numbered test runs ran without a probe on the test case so
+        * we can gather reference results. The subsequent odd numbered run
+        * will have the probe inserted.
+       */
+       if ((test_case_run_count & 1) == 0) {
+               /* Save results from run without probe */
+               u32 *mem = (u32 *)result_regs.ARM_sp;
+               expected_regs = result_regs;
+               memcpy(expected_memory, mem, expected_memory_size(mem));
+
+               /* Insert probe onto test case instruction */
+               if (register_test_probe(&test_case_probe) < 0) {
+                       test_case_failed("register test_case_probe failed");
+                       goto fail;
+               }
+       } else {
+               /* Check probe ran as expected */
+               if (probe_should_run == 1) {
+                       if (test_case_probe.hit != test_instance) {
+                               test_case_failed("test_case_handler not run");
+                               goto fail;
+                       }
+               } else if (probe_should_run == 0) {
+                       if (test_case_probe.hit == test_instance) {
+                               test_case_failed("test_case_handler ran");
+                               goto fail;
+                       }
+               }
+
+               /* Remove probe for any subsequent reference run */
+               unregister_test_probe(&test_case_probe);
+
+               if (!check_test_results())
+                       goto fail;
+
+               if (is_last_scenario)
+                       goto pass;
+       }
+
+       /* Do next test run */
+       ++test_case_run_count;
+       ++test_instance;
+       return current_code_start;
+fail:
+       ++test_fail_count;
+       goto end;
+pass:
+       ++test_pass_count;
+end:
+       test_case_cleanup();
+       return 0;
+}
+
+
+/*
+ * Top level test functions
+ */
+
+static int run_test_cases(void (*tests)(void), const union decode_item *table)
+{
+       int ret;
+
+       pr_info("    Check decoding tables\n");
+       ret = table_test(table);
+       if (ret)
+               return ret;
+
+       pr_info("    Run test cases\n");
+       ret = coverage_start(table);
+       if (ret)
+               return ret;
+
+       tests();
+
+       coverage_end();
+       return 0;
+}
+
+
+static int __init run_all_tests(void)
+{
+       int ret = 0;
+
+       pr_info("Beginning kprobe tests...\n");
+
+#ifndef CONFIG_THUMB2_KERNEL
+
+       pr_info("Probe ARM code\n");
+       ret = run_api_tests(arm_func);
+       if (ret)
+               goto out;
+
+       pr_info("ARM instruction simulation\n");
+       ret = run_test_cases(kprobe_arm_test_cases, probes_decode_arm_table);
+       if (ret)
+               goto out;
+
+#else /* CONFIG_THUMB2_KERNEL */
+
+       pr_info("Probe 16-bit Thumb code\n");
+       ret = run_api_tests(thumb16_func);
+       if (ret)
+               goto out;
+
+       pr_info("Probe 32-bit Thumb code, even halfword\n");
+       ret = run_api_tests(thumb32even_func);
+       if (ret)
+               goto out;
+
+       pr_info("Probe 32-bit Thumb code, odd halfword\n");
+       ret = run_api_tests(thumb32odd_func);
+       if (ret)
+               goto out;
+
+       pr_info("16-bit Thumb instruction simulation\n");
+       ret = run_test_cases(kprobe_thumb16_test_cases,
+                               probes_decode_thumb16_table);
+       if (ret)
+               goto out;
+
+       pr_info("32-bit Thumb instruction simulation\n");
+       ret = run_test_cases(kprobe_thumb32_test_cases,
+                               probes_decode_thumb32_table);
+       if (ret)
+               goto out;
+#endif
+
+       pr_info("Total instruction simulation tests=%d, pass=%d fail=%d\n",
+               test_try_count, test_pass_count, test_fail_count);
+       if (test_fail_count) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+#if BENCHMARKING
+       pr_info("Benchmarks\n");
+       ret = run_benchmarks();
+       if (ret)
+               goto out;
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 7
+       /* We are able to run all test cases so coverage should be complete */
+       if (coverage_fail) {
+               pr_err("FAIL: Test coverage checks failed\n");
+               ret = -EINVAL;
+               goto out;
+       }
+#endif
+
+out:
+       if (ret == 0)
+               ret = tests_failed;
+       if (ret == 0)
+               pr_info("Finished kprobe tests OK\n");
+       else
+               pr_err("kprobe tests failed\n");
+
+       return ret;
+}
+
+
+/*
+ * Module setup
+ */
+
+#ifdef MODULE
+
+static void __exit kprobe_test_exit(void)
+{
+}
+
+module_init(run_all_tests)
+module_exit(kprobe_test_exit)
+MODULE_LICENSE("GPL");
+
+#else /* !MODULE */
+
+late_initcall(run_all_tests);
+
+#endif
diff --git a/arch/arm/probes/kprobes/test-core.h b/arch/arm/probes/kprobes/test-core.h
new file mode 100644 (file)
index 0000000..9991754
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * arch/arm/probes/kprobes/test-core.h
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define VERBOSE 0 /* Set to '1' for more logging of test cases */
+
+#ifdef CONFIG_THUMB2_KERNEL
+#define NORMAL_ISA "16"
+#else
+#define NORMAL_ISA "32"
+#endif
+
+
+/* Flags used in kprobe_test_flags */
+#define TEST_FLAG_NO_ITBLOCK   (1<<0)
+#define TEST_FLAG_FULL_ITBLOCK (1<<1)
+#define TEST_FLAG_NARROW_INSTR (1<<2)
+
+extern int kprobe_test_flags;
+extern int kprobe_test_cc_position;
+
+
+#define TEST_MEMORY_SIZE 256
+
+
+/*
+ * Test case structures.
+ *
+ * The arguments given to test cases can be one of three types.
+ *
+ *   ARG_TYPE_REG
+ *     Load a register with the given value.
+ *
+ *   ARG_TYPE_PTR
+ *     Load a register with a pointer into the stack buffer (SP + given value).
+ *
+ *   ARG_TYPE_MEM
+ *     Store the given value into the stack buffer at [SP+index].
+ *
+ */
+
+#define        ARG_TYPE_END    0
+#define        ARG_TYPE_REG    1
+#define        ARG_TYPE_PTR    2
+#define        ARG_TYPE_MEM    3
+
+#define ARG_FLAG_UNSUPPORTED   0x01
+#define ARG_FLAG_SUPPORTED     0x02
+#define ARG_FLAG_THUMB         0x10    /* Must be 16 so TEST_ISA can be used */
+#define ARG_FLAG_ARM           0x20    /* Must be 32 so TEST_ISA can be used */
+
+struct test_arg {
+       u8      type;           /* ARG_TYPE_x */
+       u8      _padding[7];
+};
+
+struct test_arg_regptr {
+       u8      type;           /* ARG_TYPE_REG or ARG_TYPE_PTR */
+       u8      reg;
+       u8      _padding[2];
+       u32     val;
+};
+
+struct test_arg_mem {
+       u8      type;           /* ARG_TYPE_MEM */
+       u8      index;
+       u8      _padding[2];
+       u32     val;
+};
+
+struct test_arg_end {
+       u8      type;           /* ARG_TYPE_END */
+       u8      flags;          /* ARG_FLAG_x */
+       u16     code_offset;
+       u16     branch_offset;
+       u16     end_offset;
+};
+
+
+/*
+ * Building blocks for test cases.
+ *
+ * Each test case is wrapped between TESTCASE_START and TESTCASE_END.
+ *
+ * To specify arguments for a test case the TEST_ARG_{REG,PTR,MEM} macros are
+ * used followed by a terminating TEST_ARG_END.
+ *
+ * After this, the instruction to be tested is defined with TEST_INSTRUCTION.
+ * Or for branches, TEST_BRANCH_B and TEST_BRANCH_F (branch forwards/backwards).
+ *
+ * Some specific test cases may make use of other custom constructs.
+ */
+
+#if VERBOSE
+#define verbose(fmt, ...) pr_info(fmt, ##__VA_ARGS__)
+#else
+#define verbose(fmt, ...)
+#endif
+
+#define TEST_GROUP(title)                                      \
+       verbose("\n");                                          \
+       verbose(title"\n");                                     \
+       verbose("---------------------------------------------------------\n");
+
+#define TESTCASE_START(title)                                  \
+       __asm__ __volatile__ (                                  \
+       "bl     __kprobes_test_case_start               \n\t"   \
+       ".pushsection .rodata                           \n\t"   \
+       "10:                                            \n\t"   \
+       /* don't use .asciz here as 'title' may be */           \
+       /* multiple strings to be concatenated.  */             \
+       ".ascii "#title"                                \n\t"   \
+       ".byte  0                                       \n\t"   \
+       ".popsection                                    \n\t"   \
+       ".word  10b                                     \n\t"
+
+#define        TEST_ARG_REG(reg, val)                                  \
+       ".byte  "__stringify(ARG_TYPE_REG)"             \n\t"   \
+       ".byte  "#reg"                                  \n\t"   \
+       ".short 0                                       \n\t"   \
+       ".word  "#val"                                  \n\t"
+
+#define        TEST_ARG_PTR(reg, val)                                  \
+       ".byte  "__stringify(ARG_TYPE_PTR)"             \n\t"   \
+       ".byte  "#reg"                                  \n\t"   \
+       ".short 0                                       \n\t"   \
+       ".word  "#val"                                  \n\t"
+
+#define        TEST_ARG_MEM(index, val)                                \
+       ".byte  "__stringify(ARG_TYPE_MEM)"             \n\t"   \
+       ".byte  "#index"                                \n\t"   \
+       ".short 0                                       \n\t"   \
+       ".word  "#val"                                  \n\t"
+
+#define        TEST_ARG_END(flags)                                     \
+       ".byte  "__stringify(ARG_TYPE_END)"             \n\t"   \
+       ".byte  "TEST_ISA flags"                        \n\t"   \
+       ".short 50f-0f                                  \n\t"   \
+       ".short 2f-0f                                   \n\t"   \
+       ".short 99f-0f                                  \n\t"   \
+       ".code "TEST_ISA"                               \n\t"   \
+       "0:                                             \n\t"
+
+#define TEST_INSTRUCTION(instruction)                          \
+       "50:    nop                                     \n\t"   \
+       "1:     "instruction"                           \n\t"   \
+       "       nop                                     \n\t"
+
+#define TEST_BRANCH_F(instruction)                             \
+       TEST_INSTRUCTION(instruction)                           \
+       "       b       99f                             \n\t"   \
+       "2:     nop                                     \n\t"
+
+#define TEST_BRANCH_B(instruction)                             \
+       "       b       50f                             \n\t"   \
+       "       b       99f                             \n\t"   \
+       "2:     nop                                     \n\t"   \
+       "       b       99f                             \n\t"   \
+       TEST_INSTRUCTION(instruction)
+
+#define TEST_BRANCH_FX(instruction, codex)                     \
+       TEST_INSTRUCTION(instruction)                           \
+       "       b       99f                             \n\t"   \
+       codex"                                          \n\t"   \
+       "       b       99f                             \n\t"   \
+       "2:     nop                                     \n\t"
+
+#define TEST_BRANCH_BX(instruction, codex)                     \
+       "       b       50f                             \n\t"   \
+       "       b       99f                             \n\t"   \
+       "2:     nop                                     \n\t"   \
+       "       b       99f                             \n\t"   \
+       codex"                                          \n\t"   \
+       TEST_INSTRUCTION(instruction)
+
+#define TESTCASE_END                                           \
+       "2:                                             \n\t"   \
+       "99:                                            \n\t"   \
+       "       bl __kprobes_test_case_end_"TEST_ISA"   \n\t"   \
+       ".code "NORMAL_ISA"                             \n\t"   \
+       : :                                                     \
+       : "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc"    \
+       );
+
+
+/*
+ * Macros to define test cases.
+ *
+ * Those of the form TEST_{R,P,M}* can be used to define test cases
+ * which take combinations of the three basic types of arguments. E.g.
+ *
+ *   TEST_R    One register argument
+ *   TEST_RR   Two register arguments
+ *   TEST_RPR  A register, a pointer, then a register argument
+ *
+ * For testing instructions which may branch, there are macros TEST_BF_*
+ * and TEST_BB_* for branching forwards and backwards.
+ *
+ * TEST_SUPPORTED and TEST_UNSUPPORTED don't cause the code to be executed,
+ * the just verify that a kprobe is or is not allowed on the given instruction.
+ */
+
+#define TEST(code)                             \
+       TESTCASE_START(code)                    \
+       TEST_ARG_END("")                        \
+       TEST_INSTRUCTION(code)                  \
+       TESTCASE_END
+
+#define TEST_UNSUPPORTED(code)                                 \
+       TESTCASE_START(code)                                    \
+       TEST_ARG_END("|"__stringify(ARG_FLAG_UNSUPPORTED))      \
+       TEST_INSTRUCTION(code)                                  \
+       TESTCASE_END
+
+#define TEST_SUPPORTED(code)                                   \
+       TESTCASE_START(code)                                    \
+       TEST_ARG_END("|"__stringify(ARG_FLAG_SUPPORTED))        \
+       TEST_INSTRUCTION(code)                                  \
+       TESTCASE_END
+
+#define TEST_R(code1, reg, val, code2)                 \
+       TESTCASE_START(code1 #reg code2)                \
+       TEST_ARG_REG(reg, val)                          \
+       TEST_ARG_END("")                                \
+       TEST_INSTRUCTION(code1 #reg code2)              \
+       TESTCASE_END
+
+#define TEST_RR(code1, reg1, val1, code2, reg2, val2, code3)   \
+       TESTCASE_START(code1 #reg1 code2 #reg2 code3)           \
+       TEST_ARG_REG(reg1, val1)                                \
+       TEST_ARG_REG(reg2, val2)                                \
+       TEST_ARG_END("")                                        \
+       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3)         \
+       TESTCASE_END
+
+#define TEST_RRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
+       TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4)               \
+       TEST_ARG_REG(reg1, val1)                                                \
+       TEST_ARG_REG(reg2, val2)                                                \
+       TEST_ARG_REG(reg3, val3)                                                \
+       TEST_ARG_END("")                                                        \
+       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4)             \
+       TESTCASE_END
+
+#define TEST_RRRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4, reg4, val4)  \
+       TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4 #reg4)         \
+       TEST_ARG_REG(reg1, val1)                                                \
+       TEST_ARG_REG(reg2, val2)                                                \
+       TEST_ARG_REG(reg3, val3)                                                \
+       TEST_ARG_REG(reg4, val4)                                                \
+       TEST_ARG_END("")                                                        \
+       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4 #reg4)       \
+       TESTCASE_END
+
+#define TEST_P(code1, reg1, val1, code2)       \
+       TESTCASE_START(code1 #reg1 code2)       \
+       TEST_ARG_PTR(reg1, val1)                \
+       TEST_ARG_END("")                        \
+       TEST_INSTRUCTION(code1 #reg1 code2)     \
+       TESTCASE_END
+
+#define TEST_PR(code1, reg1, val1, code2, reg2, val2, code3)   \
+       TESTCASE_START(code1 #reg1 code2 #reg2 code3)           \
+       TEST_ARG_PTR(reg1, val1)                                \
+       TEST_ARG_REG(reg2, val2)                                \
+       TEST_ARG_END("")                                        \
+       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3)         \
+       TESTCASE_END
+
+#define TEST_RP(code1, reg1, val1, code2, reg2, val2, code3)   \
+       TESTCASE_START(code1 #reg1 code2 #reg2 code3)           \
+       TEST_ARG_REG(reg1, val1)                                \
+       TEST_ARG_PTR(reg2, val2)                                \
+       TEST_ARG_END("")                                        \
+       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3)         \
+       TESTCASE_END
+
+#define TEST_PRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
+       TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4)               \
+       TEST_ARG_PTR(reg1, val1)                                                \
+       TEST_ARG_REG(reg2, val2)                                                \
+       TEST_ARG_REG(reg3, val3)                                                \
+       TEST_ARG_END("")                                                        \
+       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4)             \
+       TESTCASE_END
+
+#define TEST_RPR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
+       TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4)               \
+       TEST_ARG_REG(reg1, val1)                                                \
+       TEST_ARG_PTR(reg2, val2)                                                \
+       TEST_ARG_REG(reg3, val3)                                                \
+       TEST_ARG_END("")                                                        \
+       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4)             \
+       TESTCASE_END
+
+#define TEST_RRP(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
+       TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4)               \
+       TEST_ARG_REG(reg1, val1)                                                \
+       TEST_ARG_REG(reg2, val2)                                                \
+       TEST_ARG_PTR(reg3, val3)                                                \
+       TEST_ARG_END("")                                                        \
+       TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4)             \
+       TESTCASE_END
+
+#define TEST_BF_P(code1, reg1, val1, code2)    \
+       TESTCASE_START(code1 #reg1 code2)       \
+       TEST_ARG_PTR(reg1, val1)                \
+       TEST_ARG_END("")                        \
+       TEST_BRANCH_F(code1 #reg1 code2)        \
+       TESTCASE_END
+
+#define TEST_BF(code)                          \
+       TESTCASE_START(code)                    \
+       TEST_ARG_END("")                        \
+       TEST_BRANCH_F(code)                     \
+       TESTCASE_END
+
+#define TEST_BB(code)                          \
+       TESTCASE_START(code)                    \
+       TEST_ARG_END("")                        \
+       TEST_BRANCH_B(code)                     \
+       TESTCASE_END
+
+#define TEST_BF_R(code1, reg, val, code2)      \
+       TESTCASE_START(code1 #reg code2)        \
+       TEST_ARG_REG(reg, val)                  \
+       TEST_ARG_END("")                        \
+       TEST_BRANCH_F(code1 #reg code2)         \
+       TESTCASE_END
+
+#define TEST_BB_R(code1, reg, val, code2)      \
+       TESTCASE_START(code1 #reg code2)        \
+       TEST_ARG_REG(reg, val)                  \
+       TEST_ARG_END("")                        \
+       TEST_BRANCH_B(code1 #reg code2)         \
+       TESTCASE_END
+
+#define TEST_BF_RR(code1, reg1, val1, code2, reg2, val2, code3)        \
+       TESTCASE_START(code1 #reg1 code2 #reg2 code3)           \
+       TEST_ARG_REG(reg1, val1)                                \
+       TEST_ARG_REG(reg2, val2)                                \
+       TEST_ARG_END("")                                        \
+       TEST_BRANCH_F(code1 #reg1 code2 #reg2 code3)            \
+       TESTCASE_END
+
+#define TEST_BF_X(code, codex)                 \
+       TESTCASE_START(code)                    \
+       TEST_ARG_END("")                        \
+       TEST_BRANCH_FX(code, codex)             \
+       TESTCASE_END
+
+#define TEST_BB_X(code, codex)                 \
+       TESTCASE_START(code)                    \
+       TEST_ARG_END("")                        \
+       TEST_BRANCH_BX(code, codex)             \
+       TESTCASE_END
+
+#define TEST_BF_RX(code1, reg, val, code2, codex)      \
+       TESTCASE_START(code1 #reg code2)                \
+       TEST_ARG_REG(reg, val)                          \
+       TEST_ARG_END("")                                \
+       TEST_BRANCH_FX(code1 #reg code2, codex)         \
+       TESTCASE_END
+
+#define TEST_X(code, codex)                    \
+       TESTCASE_START(code)                    \
+       TEST_ARG_END("")                        \
+       TEST_INSTRUCTION(code)                  \
+       "       b       99f             \n\t"   \
+       "       "codex"                 \n\t"   \
+       TESTCASE_END
+
+#define TEST_RX(code1, reg, val, code2, codex)         \
+       TESTCASE_START(code1 #reg code2)                \
+       TEST_ARG_REG(reg, val)                          \
+       TEST_ARG_END("")                                \
+       TEST_INSTRUCTION(code1 __stringify(reg) code2)  \
+       "       b       99f             \n\t"           \
+       "       "codex"                 \n\t"           \
+       TESTCASE_END
+
+#define TEST_RRX(code1, reg1, val1, code2, reg2, val2, code3, codex)           \
+       TESTCASE_START(code1 #reg1 code2 #reg2 code3)                           \
+       TEST_ARG_REG(reg1, val1)                                                \
+       TEST_ARG_REG(reg2, val2)                                                \
+       TEST_ARG_END("")                                                        \
+       TEST_INSTRUCTION(code1 __stringify(reg1) code2 __stringify(reg2) code3) \
+       "       b       99f             \n\t"                                   \
+       "       "codex"                 \n\t"                                   \
+       TESTCASE_END
+
+
+/*
+ * Macros for defining space directives spread over multiple lines.
+ * These are required so the compiler guesses better the length of inline asm
+ * code and will spill the literal pool early enough to avoid generating PC
+ * relative loads with out of range offsets.
+ */
+#define TWICE(x)       x x
+#define SPACE_0x8      TWICE(".space 4\n\t")
+#define SPACE_0x10     TWICE(SPACE_0x8)
+#define SPACE_0x20     TWICE(SPACE_0x10)
+#define SPACE_0x40     TWICE(SPACE_0x20)
+#define SPACE_0x80     TWICE(SPACE_0x40)
+#define SPACE_0x100    TWICE(SPACE_0x80)
+#define SPACE_0x200    TWICE(SPACE_0x100)
+#define SPACE_0x400    TWICE(SPACE_0x200)
+#define SPACE_0x800    TWICE(SPACE_0x400)
+#define SPACE_0x1000   TWICE(SPACE_0x800)
+
+
+/* Various values used in test cases... */
+#define N(val) (val ^ 0xffffffff)
+#define VAL1   0x12345678
+#define VAL2   N(VAL1)
+#define VAL3   0xa5f801
+#define VAL4   N(VAL3)
+#define VALM   0x456789ab
+#define VALR   0xdeaddead
+#define HH1    0x0123fecb
+#define HH2    0xa9874567
+
+
+#ifdef CONFIG_THUMB2_KERNEL
+void kprobe_thumb16_test_cases(void);
+void kprobe_thumb32_test_cases(void);
+#else
+void kprobe_arm_test_cases(void);
+#endif
diff --git a/arch/arm/probes/kprobes/test-thumb.c b/arch/arm/probes/kprobes/test-thumb.c
new file mode 100644 (file)
index 0000000..6c6e9a9
--- /dev/null
@@ -0,0 +1,1188 @@
+/*
+ * arch/arm/probes/kprobes/test-thumb.c
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/opcodes.h>
+
+#include "test-core.h"
+
+
+#define TEST_ISA "16"
+
+#define DONT_TEST_IN_ITBLOCK(tests)                    \
+       kprobe_test_flags |= TEST_FLAG_NO_ITBLOCK;      \
+       tests                                           \
+       kprobe_test_flags &= ~TEST_FLAG_NO_ITBLOCK;
+
+#define CONDITION_INSTRUCTIONS(cc_pos, tests)          \
+       kprobe_test_cc_position = cc_pos;               \
+       DONT_TEST_IN_ITBLOCK(tests)                     \
+       kprobe_test_cc_position = 0;
+
+#define TEST_ITBLOCK(code)                             \
+       kprobe_test_flags |= TEST_FLAG_FULL_ITBLOCK;    \
+       TESTCASE_START(code)                            \
+       TEST_ARG_END("")                                \
+       "50:    nop                     \n\t"           \
+       "1:     "code"                  \n\t"           \
+       "       mov r1, #0x11           \n\t"           \
+       "       mov r2, #0x22           \n\t"           \
+       "       mov r3, #0x33           \n\t"           \
+       "2:     nop                     \n\t"           \
+       TESTCASE_END                                    \
+       kprobe_test_flags &= ~TEST_FLAG_FULL_ITBLOCK;
+
+#define TEST_THUMB_TO_ARM_INTERWORK_P(code1, reg, val, code2)  \
+       TESTCASE_START(code1 #reg code2)                        \
+       TEST_ARG_PTR(reg, val)                                  \
+       TEST_ARG_REG(14, 99f+1)                                 \
+       TEST_ARG_MEM(15, 3f)                                    \
+       TEST_ARG_END("")                                        \
+       "       nop                     \n\t" /* To align 1f */ \
+       "50:    nop                     \n\t"                   \
+       "1:     "code1 #reg code2"      \n\t"                   \
+       "       bx      lr              \n\t"                   \
+       ".arm                           \n\t"                   \
+       "3:     adr     lr, 2f+1        \n\t"                   \
+       "       bx      lr              \n\t"                   \
+       ".thumb                         \n\t"                   \
+       "2:     nop                     \n\t"                   \
+       TESTCASE_END
+
+
+void kprobe_thumb16_test_cases(void)
+{
+       kprobe_test_flags = TEST_FLAG_NARROW_INSTR;
+
+       TEST_GROUP("Shift (immediate), add, subtract, move, and compare")
+
+       TEST_R(    "lsls        r7, r",0,VAL1,", #5")
+       TEST_R(    "lsls        r0, r",7,VAL2,", #11")
+       TEST_R(    "lsrs        r7, r",0,VAL1,", #5")
+       TEST_R(    "lsrs        r0, r",7,VAL2,", #11")
+       TEST_R(    "asrs        r7, r",0,VAL1,", #5")
+       TEST_R(    "asrs        r0, r",7,VAL2,", #11")
+       TEST_RR(   "adds        r2, r",0,VAL1,", r",7,VAL2,"")
+       TEST_RR(   "adds        r5, r",7,VAL2,", r",0,VAL2,"")
+       TEST_RR(   "subs        r2, r",0,VAL1,", r",7,VAL2,"")
+       TEST_RR(   "subs        r5, r",7,VAL2,", r",0,VAL2,"")
+       TEST_R(    "adds        r7, r",0,VAL1,", #5")
+       TEST_R(    "adds        r0, r",7,VAL2,", #2")
+       TEST_R(    "subs        r7, r",0,VAL1,", #5")
+       TEST_R(    "subs        r0, r",7,VAL2,", #2")
+       TEST(      "movs.n      r0, #0x5f")
+       TEST(      "movs.n      r7, #0xa0")
+       TEST_R(    "cmp.n       r",0,0x5e, ", #0x5f")
+       TEST_R(    "cmp.n       r",5,0x15f,", #0x5f")
+       TEST_R(    "cmp.n       r",7,0xa0, ", #0xa0")
+       TEST_R(    "adds.n      r",0,VAL1,", #0x5f")
+       TEST_R(    "adds.n      r",7,VAL2,", #0xa0")
+       TEST_R(    "subs.n      r",0,VAL1,", #0x5f")
+       TEST_R(    "subs.n      r",7,VAL2,", #0xa0")
+
+       TEST_GROUP("16-bit Thumb data-processing instructions")
+
+#define DATA_PROCESSING16(op,val)                      \
+       TEST_RR(   op"  r",0,VAL1,", r",7,val,"")       \
+       TEST_RR(   op"  r",7,VAL2,", r",0,val,"")
+
+       DATA_PROCESSING16("ands",0xf00f00ff)
+       DATA_PROCESSING16("eors",0xf00f00ff)
+       DATA_PROCESSING16("lsls",11)
+       DATA_PROCESSING16("lsrs",11)
+       DATA_PROCESSING16("asrs",11)
+       DATA_PROCESSING16("adcs",VAL2)
+       DATA_PROCESSING16("sbcs",VAL2)
+       DATA_PROCESSING16("rors",11)
+       DATA_PROCESSING16("tst",0xf00f00ff)
+       TEST_R("rsbs    r",0,VAL1,", #0")
+       TEST_R("rsbs    r",7,VAL2,", #0")
+       DATA_PROCESSING16("cmp",0xf00f00ff)
+       DATA_PROCESSING16("cmn",0xf00f00ff)
+       DATA_PROCESSING16("orrs",0xf00f00ff)
+       DATA_PROCESSING16("muls",VAL2)
+       DATA_PROCESSING16("bics",0xf00f00ff)
+       DATA_PROCESSING16("mvns",VAL2)
+
+       TEST_GROUP("Special data instructions and branch and exchange")
+
+       TEST_RR(  "add  r",0, VAL1,", r",7,VAL2,"")
+       TEST_RR(  "add  r",3, VAL2,", r",8,VAL3,"")
+       TEST_RR(  "add  r",8, VAL3,", r",0,VAL1,"")
+       TEST_R(   "add  sp"        ", r",8,-8,  "")
+       TEST_R(   "add  r",14,VAL1,", pc")
+       TEST_BF_R("add  pc"        ", r",0,2f-1f-8,"")
+       TEST_UNSUPPORTED(__inst_thumb16(0x44ff) "       @ add pc, pc")
+
+       TEST_RR(  "cmp  r",3,VAL1,", r",8,VAL2,"")
+       TEST_RR(  "cmp  r",8,VAL2,", r",0,VAL1,"")
+       TEST_R(   "cmp  sp"       ", r",8,-8,  "")
+
+       TEST_R(   "mov  r0, r",7,VAL2,"")
+       TEST_R(   "mov  r3, r",8,VAL3,"")
+       TEST_R(   "mov  r8, r",0,VAL1,"")
+       TEST_P(   "mov  sp, r",8,-8,  "")
+       TEST(     "mov  lr, pc")
+       TEST_BF_R("mov  pc, r",0,2f,  "")
+
+       TEST_BF_R("bx   r",0, 2f+1,"")
+       TEST_BF_R("bx   r",14,2f+1,"")
+       TESTCASE_START("bx      pc")
+               TEST_ARG_REG(14, 99f+1)
+               TEST_ARG_END("")
+               "       nop                     \n\t" /* To align the bx pc*/
+               "50:    nop                     \n\t"
+               "1:     bx      pc              \n\t"
+               "       bx      lr              \n\t"
+               ".arm                           \n\t"
+               "       adr     lr, 2f+1        \n\t"
+               "       bx      lr              \n\t"
+               ".thumb                         \n\t"
+               "2:     nop                     \n\t"
+       TESTCASE_END
+
+       TEST_BF_R("blx  r",0, 2f+1,"")
+       TEST_BB_R("blx  r",14,2f+1,"")
+       TEST_UNSUPPORTED(__inst_thumb16(0x47f8) "       @ blx pc")
+
+       TEST_GROUP("Load from Literal Pool")
+
+       TEST_X( "ldr    r0, 3f",
+               ".align                                 \n\t"
+               "3:     .word   "__stringify(VAL1))
+       TEST_X( "ldr    r7, 3f",
+               ".space 128                             \n\t"
+               ".align                                 \n\t"
+               "3:     .word   "__stringify(VAL2))
+
+       TEST_GROUP("16-bit Thumb Load/store instructions")
+
+       TEST_RPR("str   r",0, VAL1,", [r",1, 24,", r",2,  48,"]")
+       TEST_RPR("str   r",7, VAL2,", [r",6, 24,", r",5,  48,"]")
+       TEST_RPR("strh  r",0, VAL1,", [r",1, 24,", r",2,  48,"]")
+       TEST_RPR("strh  r",7, VAL2,", [r",6, 24,", r",5,  48,"]")
+       TEST_RPR("strb  r",0, VAL1,", [r",1, 24,", r",2,  48,"]")
+       TEST_RPR("strb  r",7, VAL2,", [r",6, 24,", r",5,  48,"]")
+       TEST_PR( "ldrsb r0, [r",1, 24,", r",2,  48,"]")
+       TEST_PR( "ldrsb r7, [r",6, 24,", r",5,  50,"]")
+       TEST_PR( "ldr   r0, [r",1, 24,", r",2,  48,"]")
+       TEST_PR( "ldr   r7, [r",6, 24,", r",5,  48,"]")
+       TEST_PR( "ldrh  r0, [r",1, 24,", r",2,  48,"]")
+       TEST_PR( "ldrh  r7, [r",6, 24,", r",5,  50,"]")
+       TEST_PR( "ldrb  r0, [r",1, 24,", r",2,  48,"]")
+       TEST_PR( "ldrb  r7, [r",6, 24,", r",5,  50,"]")
+       TEST_PR( "ldrsh r0, [r",1, 24,", r",2,  48,"]")
+       TEST_PR( "ldrsh r7, [r",6, 24,", r",5,  50,"]")
+
+       TEST_RP("str    r",0, VAL1,", [r",1, 24,", #120]")
+       TEST_RP("str    r",7, VAL2,", [r",6, 24,", #120]")
+       TEST_P( "ldr    r0, [r",1, 24,", #120]")
+       TEST_P( "ldr    r7, [r",6, 24,", #120]")
+       TEST_RP("strb   r",0, VAL1,", [r",1, 24,", #30]")
+       TEST_RP("strb   r",7, VAL2,", [r",6, 24,", #30]")
+       TEST_P( "ldrb   r0, [r",1, 24,", #30]")
+       TEST_P( "ldrb   r7, [r",6, 24,", #30]")
+       TEST_RP("strh   r",0, VAL1,", [r",1, 24,", #60]")
+       TEST_RP("strh   r",7, VAL2,", [r",6, 24,", #60]")
+       TEST_P( "ldrh   r0, [r",1, 24,", #60]")
+       TEST_P( "ldrh   r7, [r",6, 24,", #60]")
+
+       TEST_R( "str    r",0, VAL1,", [sp, #0]")
+       TEST_R( "str    r",7, VAL2,", [sp, #160]")
+       TEST(   "ldr    r0, [sp, #0]")
+       TEST(   "ldr    r7, [sp, #160]")
+
+       TEST_RP("str    r",0, VAL1,", [r",0, 24,"]")
+       TEST_P( "ldr    r0, [r",0, 24,"]")
+
+       TEST_GROUP("Generate PC-/SP-relative address")
+
+       TEST("add       r0, pc, #4")
+       TEST("add       r7, pc, #1020")
+       TEST("add       r0, sp, #4")
+       TEST("add       r7, sp, #1020")
+
+       TEST_GROUP("Miscellaneous 16-bit instructions")
+
+       TEST_UNSUPPORTED( "cpsie        i")
+       TEST_UNSUPPORTED( "cpsid        i")
+       TEST_UNSUPPORTED( "setend       le")
+       TEST_UNSUPPORTED( "setend       be")
+
+       TEST("add       sp, #"__stringify(TEST_MEMORY_SIZE)) /* Assumes TEST_MEMORY_SIZE < 0x400 */
+       TEST("sub       sp, #0x7f*4")
+
+DONT_TEST_IN_ITBLOCK(
+       TEST_BF_R(  "cbnz       r",0,0, ", 2f")
+       TEST_BF_R(  "cbz        r",2,-1,", 2f")
+       TEST_BF_RX( "cbnz       r",4,1, ", 2f", SPACE_0x20)
+       TEST_BF_RX( "cbz        r",7,0, ", 2f", SPACE_0x40)
+)
+       TEST_R("sxth    r0, r",7, HH1,"")
+       TEST_R("sxth    r7, r",0, HH2,"")
+       TEST_R("sxtb    r0, r",7, HH1,"")
+       TEST_R("sxtb    r7, r",0, HH2,"")
+       TEST_R("uxth    r0, r",7, HH1,"")
+       TEST_R("uxth    r7, r",0, HH2,"")
+       TEST_R("uxtb    r0, r",7, HH1,"")
+       TEST_R("uxtb    r7, r",0, HH2,"")
+       TEST_R("rev     r0, r",7, VAL1,"")
+       TEST_R("rev     r7, r",0, VAL2,"")
+       TEST_R("rev16   r0, r",7, VAL1,"")
+       TEST_R("rev16   r7, r",0, VAL2,"")
+       TEST_UNSUPPORTED(__inst_thumb16(0xba80) "")
+       TEST_UNSUPPORTED(__inst_thumb16(0xbabf) "")
+       TEST_R("revsh   r0, r",7, VAL1,"")
+       TEST_R("revsh   r7, r",0, VAL2,"")
+
+#define TEST_POPPC(code, offset)       \
+       TESTCASE_START(code)            \
+       TEST_ARG_PTR(13, offset)        \
+       TEST_ARG_END("")                \
+       TEST_BRANCH_F(code)             \
+       TESTCASE_END
+
+       TEST("push      {r0}")
+       TEST("push      {r7}")
+       TEST("push      {r14}")
+       TEST("push      {r0-r7,r14}")
+       TEST("push      {r0,r2,r4,r6,r14}")
+       TEST("push      {r1,r3,r5,r7}")
+       TEST("pop       {r0}")
+       TEST("pop       {r7}")
+       TEST("pop       {r0,r2,r4,r6}")
+       TEST_POPPC("pop {pc}",15*4)
+       TEST_POPPC("pop {r0-r7,pc}",7*4)
+       TEST_POPPC("pop {r1,r3,r5,r7,pc}",11*4)
+       TEST_THUMB_TO_ARM_INTERWORK_P("pop      {pc}    @ ",13,15*4,"")
+       TEST_THUMB_TO_ARM_INTERWORK_P("pop      {r0-r7,pc}      @ ",13,7*4,"")
+
+       TEST_UNSUPPORTED("bkpt.n        0")
+       TEST_UNSUPPORTED("bkpt.n        255")
+
+       TEST_SUPPORTED("yield")
+       TEST("sev")
+       TEST("nop")
+       TEST("wfi")
+       TEST_SUPPORTED("wfe")
+       TEST_UNSUPPORTED(__inst_thumb16(0xbf50) "") /* Unassigned hints */
+       TEST_UNSUPPORTED(__inst_thumb16(0xbff0) "") /* Unassigned hints */
+
+#define TEST_IT(code, code2)                   \
+       TESTCASE_START(code)                    \
+       TEST_ARG_END("")                        \
+       "50:    nop                     \n\t"   \
+       "1:     "code"                  \n\t"   \
+       "       "code2"                 \n\t"   \
+       "2:     nop                     \n\t"   \
+       TESTCASE_END
+
+DONT_TEST_IN_ITBLOCK(
+       TEST_IT("it     eq","moveq r0,#0")
+       TEST_IT("it     vc","movvc r0,#0")
+       TEST_IT("it     le","movle r0,#0")
+       TEST_IT("ite    eq","moveq r0,#0\n\t  movne r1,#1")
+       TEST_IT("itet   vc","movvc r0,#0\n\t  movvs r1,#1\n\t  movvc r2,#2")
+       TEST_IT("itete  le","movle r0,#0\n\t  movgt r1,#1\n\t  movle r2,#2\n\t  movgt r3,#3")
+       TEST_IT("itttt  le","movle r0,#0\n\t  movle r1,#1\n\t  movle r2,#2\n\t  movle r3,#3")
+       TEST_IT("iteee  le","movle r0,#0\n\t  movgt r1,#1\n\t  movgt r2,#2\n\t  movgt r3,#3")
+)
+
+       TEST_GROUP("Load and store multiple")
+
+       TEST_P("ldmia   r",4, 16*4,"!, {r0,r7}")
+       TEST_P("ldmia   r",7, 16*4,"!, {r0-r6}")
+       TEST_P("stmia   r",4, 16*4,"!, {r0,r7}")
+       TEST_P("stmia   r",0, 16*4,"!, {r0-r7}")
+
+       TEST_GROUP("Conditional branch and Supervisor Call instructions")
+
+CONDITION_INSTRUCTIONS(8,
+       TEST_BF("beq    2f")
+       TEST_BB("bne    2b")
+       TEST_BF("bgt    2f")
+       TEST_BB("blt    2b")
+)
+       TEST_UNSUPPORTED(__inst_thumb16(0xde00) "")
+       TEST_UNSUPPORTED(__inst_thumb16(0xdeff) "")
+       TEST_UNSUPPORTED("svc   #0x00")
+       TEST_UNSUPPORTED("svc   #0xff")
+
+       TEST_GROUP("Unconditional branch")
+
+       TEST_BF(  "b    2f")
+       TEST_BB(  "b    2b")
+       TEST_BF_X("b    2f", SPACE_0x400)
+       TEST_BB_X("b    2b", SPACE_0x400)
+
+       TEST_GROUP("Testing instructions in IT blocks")
+
+       TEST_ITBLOCK("subs.n r0, r0")
+
+       verbose("\n");
+}
+
+
+void kprobe_thumb32_test_cases(void)
+{
+       kprobe_test_flags = 0;
+
+       TEST_GROUP("Load/store multiple")
+
+       TEST_UNSUPPORTED("rfedb sp")
+       TEST_UNSUPPORTED("rfeia sp")
+       TEST_UNSUPPORTED("rfedb sp!")
+       TEST_UNSUPPORTED("rfeia sp!")
+
+       TEST_P(   "stmia        r",0, 16*4,", {r0,r8}")
+       TEST_P(   "stmia        r",4, 16*4,", {r0-r12,r14}")
+       TEST_P(   "stmia        r",7, 16*4,"!, {r8-r12,r14}")
+       TEST_P(   "stmia        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+
+       TEST_P(   "ldmia        r",0, 16*4,", {r0,r8}")
+       TEST_P(   "ldmia        r",4, 0,   ", {r0-r12,r14}")
+       TEST_BF_P("ldmia        r",5, 8*4, "!, {r6-r12,r15}")
+       TEST_P(   "ldmia        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+       TEST_BF_P("ldmia        r",14,14*4,"!, {r4,pc}")
+
+       TEST_P(   "stmdb        r",0, 16*4,", {r0,r8}")
+       TEST_P(   "stmdb        r",4, 16*4,", {r0-r12,r14}")
+       TEST_P(   "stmdb        r",5, 16*4,"!, {r8-r12,r14}")
+       TEST_P(   "stmdb        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+
+       TEST_P(   "ldmdb        r",0, 16*4,", {r0,r8}")
+       TEST_P(   "ldmdb        r",4, 16*4,", {r0-r12,r14}")
+       TEST_BF_P("ldmdb        r",5, 16*4,"!, {r6-r12,r15}")
+       TEST_P(   "ldmdb        r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+       TEST_BF_P("ldmdb        r",14,16*4,"!, {r4,pc}")
+
+       TEST_P(   "stmdb        r",13,16*4,"!, {r3-r12,lr}")
+       TEST_P(   "stmdb        r",13,16*4,"!, {r3-r12}")
+       TEST_P(   "stmdb        r",2, 16*4,", {r3-r12,lr}")
+       TEST_P(   "stmdb        r",13,16*4,"!, {r2-r12,lr}")
+       TEST_P(   "stmdb        r",0, 16*4,", {r0-r12}")
+       TEST_P(   "stmdb        r",0, 16*4,", {r0-r12,lr}")
+
+       TEST_BF_P("ldmia        r",13,5*4, "!, {r3-r12,pc}")
+       TEST_P(   "ldmia        r",13,5*4, "!, {r3-r12}")
+       TEST_BF_P("ldmia        r",2, 5*4, "!, {r3-r12,pc}")
+       TEST_BF_P("ldmia        r",13,4*4, "!, {r2-r12,pc}")
+       TEST_P(   "ldmia        r",0, 16*4,", {r0-r12}")
+       TEST_P(   "ldmia        r",0, 16*4,", {r0-r12,lr}")
+
+       TEST_THUMB_TO_ARM_INTERWORK_P("ldmia    r",0,14*4,", {r12,pc}")
+       TEST_THUMB_TO_ARM_INTERWORK_P("ldmia    r",13,2*4,", {r0-r12,pc}")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xe88f0101) "   @ stmia pc, {r0,r8}")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe92f5f00) "   @ stmdb pc!, {r8-r12,r14}")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe8bdc000) "   @ ldmia r13!, {r14,pc}")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe93ec000) "   @ ldmdb r14!, {r14,pc}")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe8a73f00) "   @ stmia r7!, {r8-r12,sp}")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe8a79f00) "   @ stmia r7!, {r8-r12,pc}")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe93e2010) "   @ ldmdb r14!, {r4,sp}")
+
+       TEST_GROUP("Load/store double or exclusive, table branch")
+
+       TEST_P(  "ldrd  r0, r1, [r",1, 24,", #-16]")
+       TEST(    "ldrd  r12, r14, [sp, #16]")
+       TEST_P(  "ldrd  r1, r0, [r",7, 24,", #-16]!")
+       TEST(    "ldrd  r14, r12, [sp, #16]!")
+       TEST_P(  "ldrd  r1, r0, [r",7, 24,"], #16")
+       TEST(    "ldrd  r7, r8, [sp], #-16")
+
+       TEST_X( "ldrd   r12, r14, 3f",
+               ".align 3                               \n\t"
+               "3:     .word   "__stringify(VAL1)"     \n\t"
+               "       .word   "__stringify(VAL2))
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xe9ffec04) "   @ ldrd  r14, r12, [pc, #16]!")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe8ffec04) "   @ ldrd  r14, r12, [pc], #16")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe9d4d800) "   @ ldrd  sp, r8, [r4]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe9d4f800) "   @ ldrd  pc, r8, [r4]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe9d47d00) "   @ ldrd  r7, sp, [r4]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe9d47f00) "   @ ldrd  r7, pc, [r4]")
+
+       TEST_RRP("strd  r",0, VAL1,", r",1, VAL2,", [r",1, 24,", #-16]")
+       TEST_RR( "strd  r",12,VAL2,", r",14,VAL1,", [sp, #16]")
+       TEST_RRP("strd  r",1, VAL1,", r",0, VAL2,", [r",7, 24,", #-16]!")
+       TEST_RR( "strd  r",14,VAL2,", r",12,VAL1,", [sp, #16]!")
+       TEST_RRP("strd  r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16")
+       TEST_RR( "strd  r",7, VAL2,", r",8, VAL1,", [sp], #-16")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) "   @ strd  r14, r12, [pc, #16]!")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) "   @ strd  r14, r12, [pc], #16")
+
+       TEST_RX("tbb    [pc, r",0, (9f-(1f+4)),"]",
+               "9:                     \n\t"
+               ".byte  (2f-1b-4)>>1    \n\t"
+               ".byte  (3f-1b-4)>>1    \n\t"
+               "3:     mvn     r0, r0  \n\t"
+               "2:     nop             \n\t")
+
+       TEST_RX("tbb    [pc, r",4, (9f-(1f+4)+1),"]",
+               "9:                     \n\t"
+               ".byte  (2f-1b-4)>>1    \n\t"
+               ".byte  (3f-1b-4)>>1    \n\t"
+               "3:     mvn     r0, r0  \n\t"
+               "2:     nop             \n\t")
+
+       TEST_RRX("tbb   [r",1,9f,", r",2,0,"]",
+               "9:                     \n\t"
+               ".byte  (2f-1b-4)>>1    \n\t"
+               ".byte  (3f-1b-4)>>1    \n\t"
+               "3:     mvn     r0, r0  \n\t"
+               "2:     nop             \n\t")
+
+       TEST_RX("tbh    [pc, r",7, (9f-(1f+4))>>1,"]",
+               "9:                     \n\t"
+               ".short (2f-1b-4)>>1    \n\t"
+               ".short (3f-1b-4)>>1    \n\t"
+               "3:     mvn     r0, r0  \n\t"
+               "2:     nop             \n\t")
+
+       TEST_RX("tbh    [pc, r",12, ((9f-(1f+4))>>1)+1,"]",
+               "9:                     \n\t"
+               ".short (2f-1b-4)>>1    \n\t"
+               ".short (3f-1b-4)>>1    \n\t"
+               "3:     mvn     r0, r0  \n\t"
+               "2:     nop             \n\t")
+
+       TEST_RRX("tbh   [r",1,9f, ", r",14,1,"]",
+               "9:                     \n\t"
+               ".short (2f-1b-4)>>1    \n\t"
+               ".short (3f-1b-4)>>1    \n\t"
+               "3:     mvn     r0, r0  \n\t"
+               "2:     nop             \n\t")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xe8d1f01f) "   @ tbh [r1, pc]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe8d1f01d) "   @ tbh [r1, sp]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xe8ddf012) "   @ tbh [sp, r2]")
+
+       TEST_UNSUPPORTED("strexb        r0, r1, [r2]")
+       TEST_UNSUPPORTED("strexh        r0, r1, [r2]")
+       TEST_UNSUPPORTED("strexd        r0, r1, [r2]")
+       TEST_UNSUPPORTED("ldrexb        r0, [r1]")
+       TEST_UNSUPPORTED("ldrexh        r0, [r1]")
+       TEST_UNSUPPORTED("ldrexd        r0, [r1]")
+
+       TEST_GROUP("Data-processing (shifted register) and (modified immediate)")
+
+#define _DATA_PROCESSING32_DNM(op,s,val)                                       \
+       TEST_RR(op s".w r0,  r",1, VAL1,", r",2, val, "")                       \
+       TEST_RR(op s"   r1,  r",1, VAL1,", r",2, val, ", lsl #3")               \
+       TEST_RR(op s"   r2,  r",3, VAL1,", r",2, val, ", lsr #4")               \
+       TEST_RR(op s"   r3,  r",3, VAL1,", r",2, val, ", asr #5")               \
+       TEST_RR(op s"   r4,  r",5, VAL1,", r",2, N(val),", asr #6")             \
+       TEST_RR(op s"   r5,  r",5, VAL1,", r",2, val, ", ror #7")               \
+       TEST_RR(op s"   r8,  r",9, VAL1,", r",10,val, ", rrx")                  \
+       TEST_R( op s"   r0,  r",11,VAL1,", #0x00010001")                        \
+       TEST_R( op s"   r11, r",0, VAL1,", #0xf5000000")                        \
+       TEST_R( op s"   r7,  r",8, VAL2,", #0x000af000")
+
+#define DATA_PROCESSING32_DNM(op,val)          \
+       _DATA_PROCESSING32_DNM(op,"",val)       \
+       _DATA_PROCESSING32_DNM(op,"s",val)
+
+#define DATA_PROCESSING32_NM(op,val)                                   \
+       TEST_RR(op".w   r",1, VAL1,", r",2, val, "")                    \
+       TEST_RR(op"     r",1, VAL1,", r",2, val, ", lsl #3")            \
+       TEST_RR(op"     r",3, VAL1,", r",2, val, ", lsr #4")            \
+       TEST_RR(op"     r",3, VAL1,", r",2, val, ", asr #5")            \
+       TEST_RR(op"     r",5, VAL1,", r",2, N(val),", asr #6")          \
+       TEST_RR(op"     r",5, VAL1,", r",2, val, ", ror #7")            \
+       TEST_RR(op"     r",9, VAL1,", r",10,val, ", rrx")               \
+       TEST_R( op"     r",11,VAL1,", #0x00010001")                     \
+       TEST_R( op"     r",0, VAL1,", #0xf5000000")                     \
+       TEST_R( op"     r",8, VAL2,", #0x000af000")
+
+#define _DATA_PROCESSING32_DM(op,s,val)                                \
+       TEST_R( op s".w r0,  r",14, val, "")                    \
+       TEST_R( op s"   r1,  r",12, val, ", lsl #3")            \
+       TEST_R( op s"   r2,  r",11, val, ", lsr #4")            \
+       TEST_R( op s"   r3,  r",10, val, ", asr #5")            \
+       TEST_R( op s"   r4,  r",9, N(val),", asr #6")           \
+       TEST_R( op s"   r5,  r",8, val, ", ror #7")             \
+       TEST_R( op s"   r8,  r",7,val, ", rrx")                 \
+       TEST(   op s"   r0,  #0x00010001")                      \
+       TEST(   op s"   r11, #0xf5000000")                      \
+       TEST(   op s"   r7,  #0x000af000")                      \
+       TEST(   op s"   r4,  #0x00005a00")
+
+#define DATA_PROCESSING32_DM(op,val)           \
+       _DATA_PROCESSING32_DM(op,"",val)        \
+       _DATA_PROCESSING32_DM(op,"s",val)
+
+       DATA_PROCESSING32_DNM("and",0xf00f00ff)
+       DATA_PROCESSING32_NM("tst",0xf00f00ff)
+       DATA_PROCESSING32_DNM("bic",0xf00f00ff)
+       DATA_PROCESSING32_DNM("orr",0xf00f00ff)
+       DATA_PROCESSING32_DM("mov",VAL2)
+       DATA_PROCESSING32_DNM("orn",0xf00f00ff)
+       DATA_PROCESSING32_DM("mvn",VAL2)
+       DATA_PROCESSING32_DNM("eor",0xf00f00ff)
+       DATA_PROCESSING32_NM("teq",0xf00f00ff)
+       DATA_PROCESSING32_DNM("add",VAL2)
+       DATA_PROCESSING32_NM("cmn",VAL2)
+       DATA_PROCESSING32_DNM("adc",VAL2)
+       DATA_PROCESSING32_DNM("sbc",VAL2)
+       DATA_PROCESSING32_DNM("sub",VAL2)
+       DATA_PROCESSING32_NM("cmp",VAL2)
+       DATA_PROCESSING32_DNM("rsb",VAL2)
+
+       TEST_RR("pkhbt  r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR("pkhbt  r14,r",12, HH1,", r",10,HH2,", lsl #2")
+       TEST_RR("pkhtb  r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR("pkhtb  r14,r",12, HH1,", r",10,HH2,", asr #2")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xea170f0d) "   @ tst.w r7, sp")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea170f0f) "   @ tst.w r7, pc")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea1d0f07) "   @ tst.w sp, r7")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea1f0f07) "   @ tst.w pc, r7")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf01d1f08) "   @ tst sp, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf01f1f08) "   @ tst pc, #0x00080008")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xea970f0d) "   @ teq.w r7, sp")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea970f0f) "   @ teq.w r7, pc")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea9d0f07) "   @ teq.w sp, r7")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea9f0f07) "   @ teq.w pc, r7")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf09d1f08) "   @ tst sp, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf09f1f08) "   @ tst pc, #0x00080008")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb170f0d) "   @ cmn.w r7, sp")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb170f0f) "   @ cmn.w r7, pc")
+       TEST_P("cmn.w   sp, r",7,0,"")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb1f0f07) "   @ cmn.w pc, r7")
+       TEST(  "cmn     sp, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf11f1f08) "   @ cmn pc, #0x00080008")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xebb70f0d) "   @ cmp.w r7, sp")
+       TEST_UNSUPPORTED(__inst_thumb32(0xebb70f0f) "   @ cmp.w r7, pc")
+       TEST_P("cmp.w   sp, r",7,0,"")
+       TEST_UNSUPPORTED(__inst_thumb32(0xebbf0f07) "   @ cmp.w pc, r7")
+       TEST(  "cmp     sp, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf1bf1f08) "   @ cmp pc, #0x00080008")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xea5f070d) "   @ movs.w r7, sp")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea5f070f) "   @ movs.w r7, pc")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea5f0d07) "   @ movs.w sp, r7")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea4f0f07) "   @ mov.w  pc, r7")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf04f1d08) "   @ mov sp, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf04f1f08) "   @ mov pc, #0x00080008")
+
+       TEST_R("add.w   r0, sp, r",1, 4,"")
+       TEST_R("adds    r0, sp, r",1, 4,", asl #3")
+       TEST_R("add     r0, sp, r",1, 4,", asl #4")
+       TEST_R("add     r0, sp, r",1, 16,", ror #1")
+       TEST_R("add.w   sp, sp, r",1, 4,"")
+       TEST_R("add     sp, sp, r",1, 4,", asl #3")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d1d01) "   @ add sp, sp, r1, asl #4")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d0d71) "   @ add sp, sp, r1, ror #1")
+       TEST(  "add.w   r0, sp, #24")
+       TEST(  "add.w   sp, sp, #24")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d0f01) "   @ add pc, sp, r1")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d000f) "   @ add r0, sp, pc")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d000d) "   @ add r0, sp, sp")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d0d0f) "   @ add sp, sp, pc")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb0d0d0d) "   @ add sp, sp, sp")
+
+       TEST_R("sub.w   r0, sp, r",1, 4,"")
+       TEST_R("subs    r0, sp, r",1, 4,", asl #3")
+       TEST_R("sub     r0, sp, r",1, 4,", asl #4")
+       TEST_R("sub     r0, sp, r",1, 16,", ror #1")
+       TEST_R("sub.w   sp, sp, r",1, 4,"")
+       TEST_R("sub     sp, sp, r",1, 4,", asl #3")
+       TEST_UNSUPPORTED(__inst_thumb32(0xebad1d01) "   @ sub sp, sp, r1, asl #4")
+       TEST_UNSUPPORTED(__inst_thumb32(0xebad0d71) "   @ sub sp, sp, r1, ror #1")
+       TEST_UNSUPPORTED(__inst_thumb32(0xebad0f01) "   @ sub pc, sp, r1")
+       TEST(  "sub.w   r0, sp, #24")
+       TEST(  "sub.w   sp, sp, #24")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xea02010f) "   @ and r1, r2, pc")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea0f0103) "   @ and r1, pc, r3")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea020f03) "   @ and pc, r2, r3")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea02010d) "   @ and r1, r2, sp")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea0d0103) "   @ and r1, sp, r3")
+       TEST_UNSUPPORTED(__inst_thumb32(0xea020d03) "   @ and sp, r2, r3")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf00d1108) "   @ and r1, sp, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf00f1108) "   @ and r1, pc, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf0021d08) "   @ and sp, r8, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf0021f08) "   @ and pc, r8, #0x00080008")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb02010f) "   @ add r1, r2, pc")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb0f0103) "   @ add r1, pc, r3")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb020f03) "   @ add pc, r2, r3")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb02010d) "   @ add r1, r2, sp")
+       TEST_SUPPORTED(  __inst_thumb32(0xeb0d0103) "   @ add r1, sp, r3")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb020d03) "   @ add sp, r2, r3")
+       TEST_SUPPORTED(  __inst_thumb32(0xf10d1108) "   @ add r1, sp, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf10d1f08) "   @ add pc, sp, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf10f1108) "   @ add r1, pc, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf1021d08) "   @ add sp, r8, #0x00080008")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf1021f08) "   @ add pc, r8, #0x00080008")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xeaa00000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeaf00000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb200000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeb800000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xebe00000) "")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xf0a00000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf0c00000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf0f00000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf1200000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf1800000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf1e00000) "")
+
+       TEST_GROUP("Coprocessor instructions")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xec000000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xeff00000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfc000000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfff00000) "")
+
+       TEST_GROUP("Data-processing (plain binary immediate)")
+
+       TEST_R("addw    r0,  r",1, VAL1,", #0x123")
+       TEST(  "addw    r14, sp, #0xf5a")
+       TEST(  "addw    sp, sp, #0x20")
+       TEST(  "addw    r7,  pc, #0x888")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf20f1f20) "   @ addw pc, pc, #0x120")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf20d1f20) "   @ addw pc, sp, #0x120")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf20f1d20) "   @ addw sp, pc, #0x120")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf2001d20) "   @ addw sp, r0, #0x120")
+
+       TEST_R("subw    r0,  r",1, VAL1,", #0x123")
+       TEST(  "subw    r14, sp, #0xf5a")
+       TEST(  "subw    sp, sp, #0x20")
+       TEST(  "subw    r7,  pc, #0x888")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf2af1f20) "   @ subw pc, pc, #0x120")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf2ad1f20) "   @ subw pc, sp, #0x120")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf2af1d20) "   @ subw sp, pc, #0x120")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf2a01d20) "   @ subw sp, r0, #0x120")
+
+       TEST("movw      r0, #0")
+       TEST("movw      r0, #0xffff")
+       TEST("movw      lr, #0xffff")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf2400d00) "   @ movw sp, #0")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf2400f00) "   @ movw pc, #0")
+
+       TEST_R("movt    r",0, VAL1,", #0")
+       TEST_R("movt    r",0, VAL2,", #0xffff")
+       TEST_R("movt    r",14,VAL1,", #0xffff")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf2c00d00) "   @ movt sp, #0")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf2c00f00) "   @ movt pc, #0")
+
+       TEST_R(     "ssat       r0, #24, r",0,   VAL1,"")
+       TEST_R(     "ssat       r14, #24, r",12, VAL2,"")
+       TEST_R(     "ssat       r0, #24, r",0,   VAL1,", lsl #8")
+       TEST_R(     "ssat       r14, #24, r",12, VAL2,", asr #8")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf30c0d17) "   @ ssat  sp, #24, r12")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf30c0f17) "   @ ssat  pc, #24, r12")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf30d0c17) "   @ ssat  r12, #24, sp")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf30f0c17) "   @ ssat  r12, #24, pc")
+
+       TEST_R(     "usat       r0, #24, r",0,   VAL1,"")
+       TEST_R(     "usat       r14, #24, r",12, VAL2,"")
+       TEST_R(     "usat       r0, #24, r",0,   VAL1,", lsl #8")
+       TEST_R(     "usat       r14, #24, r",12, VAL2,", asr #8")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf38c0d17) "   @ usat  sp, #24, r12")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf38c0f17) "   @ usat  pc, #24, r12")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf38d0c17) "   @ usat  r12, #24, sp")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf38f0c17) "   @ usat  r12, #24, pc")
+
+       TEST_R(     "ssat16     r0, #12, r",0,   HH1,"")
+       TEST_R(     "ssat16     r14, #12, r",12, HH2,"")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf32c0d0b) "   @ ssat16        sp, #12, r12")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf32c0f0b) "   @ ssat16        pc, #12, r12")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf32d0c0b) "   @ ssat16        r12, #12, sp")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf32f0c0b) "   @ ssat16        r12, #12, pc")
+
+       TEST_R(     "usat16     r0, #12, r",0,   HH1,"")
+       TEST_R(     "usat16     r14, #12, r",12, HH2,"")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf3ac0d0b) "   @ usat16        sp, #12, r12")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf3ac0f0b) "   @ usat16        pc, #12, r12")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf3ad0c0b) "   @ usat16        r12, #12, sp")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf3af0c0b) "   @ usat16        r12, #12, pc")
+
+       TEST_R(     "sbfx       r0, r",0  , VAL1,", #0, #31")
+       TEST_R(     "sbfx       r14, r",12, VAL2,", #8, #16")
+       TEST_R(     "sbfx       r4, r",10,  VAL1,", #16, #15")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf34c2d0f) "   @ sbfx  sp, r12, #8, #16")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf34c2f0f) "   @ sbfx  pc, r12, #8, #16")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf34d2c0f) "   @ sbfx  r12, sp, #8, #16")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf34f2c0f) "   @ sbfx  r12, pc, #8, #16")
+
+       TEST_R(     "ubfx       r0, r",0  , VAL1,", #0, #31")
+       TEST_R(     "ubfx       r14, r",12, VAL2,", #8, #16")
+       TEST_R(     "ubfx       r4, r",10,  VAL1,", #16, #15")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf3cc2d0f) "   @ ubfx  sp, r12, #8, #16")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf3cc2f0f) "   @ ubfx  pc, r12, #8, #16")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf3cd2c0f) "   @ ubfx  r12, sp, #8, #16")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf3cf2c0f) "   @ ubfx  r12, pc, #8, #16")
+
+       TEST_R(     "bfc        r",0, VAL1,", #4, #20")
+       TEST_R(     "bfc        r",14,VAL2,", #4, #20")
+       TEST_R(     "bfc        r",7, VAL1,", #0, #31")
+       TEST_R(     "bfc        r",8, VAL2,", #0, #31")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf36f0d1e) "   @ bfc   sp, #0, #31")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf36f0f1e) "   @ bfc   pc, #0, #31")
+
+       TEST_RR(    "bfi        r",0, VAL1,", r",0  , VAL2,", #0, #31")
+       TEST_RR(    "bfi        r",12,VAL1,", r",14 , VAL2,", #4, #20")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf36e1d17) "   @ bfi   sp, r14, #4, #20")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf36e1f17) "   @ bfi   pc, r14, #4, #20")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf36d1e17) "   @ bfi   r14, sp, #4, #20")
+
+       TEST_GROUP("Branches and miscellaneous control")
+
+CONDITION_INSTRUCTIONS(22,
+       TEST_BF("beq.w  2f")
+       TEST_BB("bne.w  2b")
+       TEST_BF("bgt.w  2f")
+       TEST_BB("blt.w  2b")
+       TEST_BF_X("bpl.w        2f", SPACE_0x1000)
+)
+
+       TEST_UNSUPPORTED("msr   cpsr, r0")
+       TEST_UNSUPPORTED("msr   cpsr_f, r1")
+       TEST_UNSUPPORTED("msr   spsr, r2")
+
+       TEST_UNSUPPORTED("cpsie.w       i")
+       TEST_UNSUPPORTED("cpsid.w       i")
+       TEST_UNSUPPORTED("cps   0x13")
+
+       TEST_SUPPORTED("yield.w")
+       TEST("sev.w")
+       TEST("nop.w")
+       TEST("wfi.w")
+       TEST_SUPPORTED("wfe.w")
+       TEST_UNSUPPORTED("dbg.w #0")
+
+       TEST_UNSUPPORTED("clrex")
+       TEST_UNSUPPORTED("dsb")
+       TEST_UNSUPPORTED("dmb")
+       TEST_UNSUPPORTED("isb")
+
+       TEST_UNSUPPORTED("bxj   r0")
+
+       TEST_UNSUPPORTED("subs  pc, lr, #4")
+
+       TEST("mrs       r0, cpsr")
+       TEST("mrs       r14, cpsr")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8d00) "   @ mrs   sp, spsr")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8f00) "   @ mrs   pc, spsr")
+       TEST_UNSUPPORTED("mrs   r0, spsr")
+       TEST_UNSUPPORTED("mrs   lr, spsr")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xf7f08000) " @ smc #0")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xf7f0a000) " @ undefeined")
+
+       TEST_BF(  "b.w  2f")
+       TEST_BB(  "b.w  2b")
+       TEST_BF_X("b.w  2f", SPACE_0x1000)
+
+       TEST_BF(  "bl.w 2f")
+       TEST_BB(  "bl.w 2b")
+       TEST_BB_X("bl.w 2b", SPACE_0x1000)
+
+       TEST_X( "blx    __dummy_arm_subroutine",
+               ".arm                           \n\t"
+               ".align                         \n\t"
+               ".type __dummy_arm_subroutine, %%function \n\t"
+               "__dummy_arm_subroutine:        \n\t"
+               "mov    r0, pc                  \n\t"
+               "bx     lr                      \n\t"
+               ".thumb                         \n\t"
+       )
+       TEST(   "blx    __dummy_arm_subroutine")
+
+       TEST_GROUP("Store single data item")
+
+#define SINGLE_STORE(size)                                                     \
+       TEST_RP( "str"size"     r",0, VAL1,", [r",11,-1024,", #1024]")          \
+       TEST_RP( "str"size"     r",14,VAL2,", [r",1, -1024,", #1080]")          \
+       TEST_RP( "str"size"     r",0, VAL1,", [r",11,256,  ", #-120]")          \
+       TEST_RP( "str"size"     r",14,VAL2,", [r",1, 256,  ", #-128]")          \
+       TEST_RP( "str"size"     r",0, VAL1,", [r",11,24,  "], #120")            \
+       TEST_RP( "str"size"     r",14,VAL2,", [r",1, 24,  "], #128")            \
+       TEST_RP( "str"size"     r",0, VAL1,", [r",11,24,  "], #-120")           \
+       TEST_RP( "str"size"     r",14,VAL2,", [r",1, 24,  "], #-128")           \
+       TEST_RP( "str"size"     r",0, VAL1,", [r",11,24,   ", #120]!")          \
+       TEST_RP( "str"size"     r",14,VAL2,", [r",1, 24,   ", #128]!")          \
+       TEST_RP( "str"size"     r",0, VAL1,", [r",11,256,  ", #-120]!")         \
+       TEST_RP( "str"size"     r",14,VAL2,", [r",1, 256,  ", #-128]!")         \
+       TEST_RPR("str"size".w   r",0, VAL1,", [r",1, 0,", r",2, 4,"]")          \
+       TEST_RPR("str"size"     r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]")  \
+       TEST_R(  "str"size".w   r",7, VAL1,", [sp, #24]")                       \
+       TEST_RP( "str"size".w   r",0, VAL2,", [r",0,0, "]")                     \
+       TEST_UNSUPPORTED("str"size"t    r0, [r1, #4]")
+
+       SINGLE_STORE("b")
+       SINGLE_STORE("h")
+       SINGLE_STORE("")
+
+       TEST("str       sp, [sp]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) "   @ str   r14, [pc]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) "   @ str   pc, [r14]")
+
+       TEST_GROUP("Advanced SIMD element or structure load/store instructions")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xf9000000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf92fffff) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf9800000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf9efffff) "")
+
+       TEST_GROUP("Load single data item and memory hints")
+
+#define SINGLE_LOAD(size)                                              \
+       TEST_P( "ldr"size"      r0, [r",11,-1024, ", #1024]")           \
+       TEST_P( "ldr"size"      r14, [r",1, -1024,", #1080]")           \
+       TEST_P( "ldr"size"      r0, [r",11,256,   ", #-120]")           \
+       TEST_P( "ldr"size"      r14, [r",1, 256,  ", #-128]")           \
+       TEST_P( "ldr"size"      r0, [r",11,24,   "], #120")             \
+       TEST_P( "ldr"size"      r14, [r",1, 24,  "], #128")             \
+       TEST_P( "ldr"size"      r0, [r",11,24,   "], #-120")            \
+       TEST_P( "ldr"size"      r14, [r",1,24,   "], #-128")            \
+       TEST_P( "ldr"size"      r0, [r",11,24,    ", #120]!")           \
+       TEST_P( "ldr"size"      r14, [r",1, 24,   ", #128]!")           \
+       TEST_P( "ldr"size"      r0, [r",11,256,   ", #-120]!")          \
+       TEST_P( "ldr"size"      r14, [r",1, 256,  ", #-128]!")          \
+       TEST_PR("ldr"size".w    r0, [r",1, 0,", r",2, 4,"]")            \
+       TEST_PR("ldr"size"      r14, [r",10,0,", r",11,4,", lsl #1]")   \
+       TEST_X( "ldr"size".w    r0, 3f",                                \
+               ".align 3                               \n\t"           \
+               "3:     .word   "__stringify(VAL1))                     \
+       TEST_X( "ldr"size".w    r14, 3f",                               \
+               ".align 3                               \n\t"           \
+               "3:     .word   "__stringify(VAL2))                     \
+       TEST(   "ldr"size".w    r7, 3b")                                \
+       TEST(   "ldr"size".w    r7, [sp, #24]")                         \
+       TEST_P( "ldr"size".w    r0, [r",0,0, "]")                       \
+       TEST_UNSUPPORTED("ldr"size"t    r0, [r1, #4]")
+
+       SINGLE_LOAD("b")
+       SINGLE_LOAD("sb")
+       SINGLE_LOAD("h")
+       SINGLE_LOAD("sh")
+       SINGLE_LOAD("")
+
+       TEST_BF_P("ldr  pc, [r",14, 15*4,"]")
+       TEST_P(   "ldr  sp, [r",14, 13*4,"]")
+       TEST_BF_R("ldr  pc, [sp, r",14, 15*4,"]")
+       TEST_R(   "ldr  sp, [sp, r",14, 13*4,"]")
+       TEST_THUMB_TO_ARM_INTERWORK_P("ldr      pc, [r",0,0,", #15*4]")
+       TEST_SUPPORTED("ldr     sp, 99f")
+       TEST_SUPPORTED("ldr     pc, 99f")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xf854700d) "   @ ldr   r7, [r4, sp]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf854700f) "   @ ldr   r7, [r4, pc]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf814700d) "   @ ldrb  r7, [r4, sp]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf814700f) "   @ ldrb  r7, [r4, pc]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf89fd004) "   @ ldrb  sp, 99f")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf814d008) "   @ ldrb  sp, [r4, r8]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf894d000) "   @ ldrb  sp, [r4]")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xf8600000) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xf9ffffff) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xf9500000) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xf95fffff) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xf8000800) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xf97ffaff) "") /* Unallocated space */
+
+       TEST(   "pli    [pc, #4]")
+       TEST(   "pli    [pc, #-4]")
+       TEST(   "pld    [pc, #4]")
+       TEST(   "pld    [pc, #-4]")
+
+       TEST_P( "pld    [r",0,-1024,", #1024]")
+       TEST(   __inst_thumb32(0xf8b0f400) "    @ pldw  [r0, #1024]")
+       TEST_P( "pli    [r",4, 0b,", #1024]")
+       TEST_P( "pld    [r",7, 120,", #-120]")
+       TEST(   __inst_thumb32(0xf837fc78) "    @ pldw  [r7, #-120]")
+       TEST_P( "pli    [r",11,120,", #-120]")
+       TEST(   "pld    [sp, #0]")
+
+       TEST_PR("pld    [r",7, 24, ", r",0, 16,"]")
+       TEST_PR("pld    [r",8, 24, ", r",12,16,", lsl #3]")
+       TEST_SUPPORTED(__inst_thumb32(0xf837f000) "     @ pldw  [r7, r0]")
+       TEST_SUPPORTED(__inst_thumb32(0xf838f03c) "     @ pldw  [r8, r12, lsl #3]");
+       TEST_RR("pli    [r",12,0b,", r",0, 16,"]")
+       TEST_RR("pli    [r",0, 0b,", r",12,16,", lsl #3]")
+       TEST_R( "pld    [sp, r",1, 16,"]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf817f00d) "  @pld     [r7, sp]")
+       TEST_UNSUPPORTED(__inst_thumb32(0xf817f00f) "  @pld     [r7, pc]")
+
+       TEST_GROUP("Data-processing (register)")
+
+#define SHIFTS32(op)                                   \
+       TEST_RR(op"     r0,  r",1, VAL1,", r",2, 3, "") \
+       TEST_RR(op"     r14, r",12,VAL2,", r",11,10,"")
+
+       SHIFTS32("lsl")
+       SHIFTS32("lsls")
+       SHIFTS32("lsr")
+       SHIFTS32("lsrs")
+       SHIFTS32("asr")
+       SHIFTS32("asrs")
+       SHIFTS32("ror")
+       SHIFTS32("rors")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa01ff02) "   @ lsl   pc, r1, r2")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa01fd02) "   @ lsl   sp, r1, r2")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa0ff002) "   @ lsl   r0, pc, r2")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa0df002) "   @ lsl   r0, sp, r2")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa01f00f) "   @ lsl   r0, r1, pc")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa01f00d) "   @ lsl   r0, r1, sp")
+
+       TEST_RR(    "sxtah      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "sxtah      r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "sxth       r8, r",7,  HH1,"")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa0fff87) "   @ sxth  pc, r7");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa0ffd87) "   @ sxth  sp, r7");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa0ff88f) "   @ sxth  r8, pc");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa0ff88d) "   @ sxth  r8, sp");
+
+       TEST_RR(    "uxtah      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uxtah      r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "uxth       r8, r",7,  HH1,"")
+
+       TEST_RR(    "sxtab16    r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "sxtab16    r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "sxtb16     r8, r",7,  HH1,"")
+
+       TEST_RR(    "uxtab16    r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uxtab16    r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "uxtb16     r8, r",7,  HH1,"")
+
+       TEST_RR(    "sxtab      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "sxtab      r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "sxtb       r8, r",7,  HH1,"")
+
+       TEST_RR(    "uxtab      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "uxtab      r14,r",12, HH2,", r",10,HH1,", ror #8")
+       TEST_R(     "uxtb       r8, r",7,  HH1,"")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa6000f0) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa7fffff) "")
+
+#define PARALLEL_ADD_SUB(op)                                   \
+       TEST_RR(  op"add16      r0, r",0,  HH1,", r",1, HH2,"") \
+       TEST_RR(  op"add16      r14, r",12,HH2,", r",10,HH1,"") \
+       TEST_RR(  op"asx        r0, r",0,  HH1,", r",1, HH2,"") \
+       TEST_RR(  op"asx        r14, r",12,HH2,", r",10,HH1,"") \
+       TEST_RR(  op"sax        r0, r",0,  HH1,", r",1, HH2,"") \
+       TEST_RR(  op"sax        r14, r",12,HH2,", r",10,HH1,"") \
+       TEST_RR(  op"sub16      r0, r",0,  HH1,", r",1, HH2,"") \
+       TEST_RR(  op"sub16      r14, r",12,HH2,", r",10,HH1,"") \
+       TEST_RR(  op"add8       r0, r",0,  HH1,", r",1, HH2,"") \
+       TEST_RR(  op"add8       r14, r",12,HH2,", r",10,HH1,"") \
+       TEST_RR(  op"sub8       r0, r",0,  HH1,", r",1, HH2,"") \
+       TEST_RR(  op"sub8       r14, r",12,HH2,", r",10,HH1,"")
+
+       TEST_GROUP("Parallel addition and subtraction, signed")
+
+       PARALLEL_ADD_SUB("s")
+       PARALLEL_ADD_SUB("q")
+       PARALLEL_ADD_SUB("sh")
+
+       TEST_GROUP("Parallel addition and subtraction, unsigned")
+
+       PARALLEL_ADD_SUB("u")
+       PARALLEL_ADD_SUB("uq")
+       PARALLEL_ADD_SUB("uh")
+
+       TEST_GROUP("Miscellaneous operations")
+
+       TEST_RR("qadd   r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR("qadd   lr, r",9, VAL2,", r",8, VAL1,"")
+       TEST_RR("qsub   r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR("qsub   lr, r",9, VAL2,", r",8, VAL1,"")
+       TEST_RR("qdadd  r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR("qdadd  lr, r",9, VAL2,", r",8, VAL1,"")
+       TEST_RR("qdsub  r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR("qdsub  lr, r",9, VAL2,", r",8, VAL1,"")
+
+       TEST_R("rev.w   r0, r",0,   VAL1,"")
+       TEST_R("rev     r14, r",12, VAL2,"")
+       TEST_R("rev16.w r0, r",0,   VAL1,"")
+       TEST_R("rev16   r14, r",12, VAL2,"")
+       TEST_R("rbit    r0, r",0,   VAL1,"")
+       TEST_R("rbit    r14, r",12, VAL2,"")
+       TEST_R("revsh.w r0, r",0,   VAL1,"")
+       TEST_R("revsh   r14, r",12, VAL2,"")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa9cff8c) "   @ rev   pc, r12");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa9cfd8c) "   @ rev   sp, r12");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa9ffe8f) "   @ rev   r14, pc");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa9dfe8d) "   @ rev   r14, sp");
+
+       TEST_RR("sel    r0, r",0,  VAL1,", r",1, VAL2,"")
+       TEST_RR("sel    r14, r",12,VAL1,", r",10, VAL2,"")
+
+       TEST_R("clz     r0, r",0, 0x0,"")
+       TEST_R("clz     r7, r",14,0x1,"")
+       TEST_R("clz     lr, r",7, 0xffffffff,"")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xfa80f030) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xfaffff7f) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xfab0f000) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xfaffff7f) "") /* Unallocated space */
+
+       TEST_GROUP("Multiply, multiply accumulate, and absolute difference operations")
+
+       TEST_RR(    "mul        r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "mul        r7, r",8, VAL2,", r",9, VAL2,"")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb08ff09) "   @ mul   pc, r8, r9")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb08fd09) "   @ mul   sp, r8, r9")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb0ff709) "   @ mul   r7, pc, r9")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb0df709) "   @ mul   r7, sp, r9")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb08f70f) "   @ mul   r7, r8, pc")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb08f70d) "   @ mul   r7, r8, sp")
+
+       TEST_RRR(   "mla        r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(   "mla        r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb08af09) "   @ mla   pc, r8, r9, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb08ad09) "   @ mla   sp, r8, r9, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb0fa709) "   @ mla   r7, pc, r9, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb0da709) "   @ mla   r7, sp, r9, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb08a70f) "   @ mla   r7, r8, pc, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb08a70d) "   @ mla   r7, r8, sp, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb08d709) "   @ mla   r7, r8, r9, sp");
+
+       TEST_RRR(   "mls        r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(   "mls        r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+
+       TEST_RRR(   "smlabb     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(   "smlabb     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RRR(   "smlatb     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(   "smlatb     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RRR(   "smlabt     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(   "smlabt     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RRR(   "smlatt     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(   "smlatt     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RR(    "smulbb     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smulbb     r7, r",8, VAL3,", r",9, VAL1,"")
+       TEST_RR(    "smultb     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smultb     r7, r",8, VAL3,", r",9, VAL1,"")
+       TEST_RR(    "smulbt     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smulbt     r7, r",8, VAL3,", r",9, VAL1,"")
+       TEST_RR(    "smultt     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smultt     r7, r",8, VAL3,", r",9, VAL1,"")
+
+       TEST_RRR(   "smlad      r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
+       TEST_RRR(   "smlad      r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+       TEST_RRR(   "smladx     r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
+       TEST_RRR(   "smladx     r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+       TEST_RR(    "smuad      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "smuad      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_RR(    "smuadx     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "smuadx     r14, r",12,HH2,", r",10,HH1,"")
+
+       TEST_RRR(   "smlawb     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(   "smlawb     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RRR(   "smlawt     r0, r",1, VAL1,", r",2, VAL2,", r",3,  VAL3,"")
+       TEST_RRR(   "smlawt     r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+       TEST_RR(    "smulwb     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smulwb     r7, r",8, VAL3,", r",9, VAL1,"")
+       TEST_RR(    "smulwt     r0, r",1, VAL1,", r",2, VAL2,"")
+       TEST_RR(    "smulwt     r7, r",8, VAL3,", r",9, VAL1,"")
+
+       TEST_RRR(   "smlsd      r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
+       TEST_RRR(   "smlsd      r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+       TEST_RRR(   "smlsdx     r0, r",0,  HH1,", r",1, HH2,", r",2, VAL1,"")
+       TEST_RRR(   "smlsdx     r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+       TEST_RR(    "smusd      r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "smusd      r14, r",12,HH2,", r",10,HH1,"")
+       TEST_RR(    "smusdx     r0, r",0,  HH1,", r",1, HH2,"")
+       TEST_RR(    "smusdx     r14, r",12,HH2,", r",10,HH1,"")
+
+       TEST_RRR(   "smmla      r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
+       TEST_RRR(   "smmla      r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+       TEST_RRR(   "smmlar     r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
+       TEST_RRR(   "smmlar     r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+       TEST_RR(    "smmul      r0, r",0,  VAL1,", r",1, VAL2,"")
+       TEST_RR(    "smmul      r14, r",12,VAL2,", r",10,VAL1,"")
+       TEST_RR(    "smmulr     r0, r",0,  VAL1,", r",1, VAL2,"")
+       TEST_RR(    "smmulr     r14, r",12,VAL2,", r",10,VAL1,"")
+
+       TEST_RRR(   "smmls      r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
+       TEST_RRR(   "smmls      r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+       TEST_RRR(   "smmlsr     r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL1,"")
+       TEST_RRR(   "smmlsr     r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+
+       TEST_RRR(   "usada8     r0, r",0,  VAL1,", r",1, VAL2,", r",2, VAL3,"")
+       TEST_RRR(   "usada8     r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL3,"")
+       TEST_RR(    "usad8      r0, r",0,  VAL1,", r",1, VAL2,"")
+       TEST_RR(    "usad8      r14, r",12,VAL2,", r",10,VAL1,"")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb00f010) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb0fff1f) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb70f010) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb7fff1f) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb700010) "") /* Unallocated space */
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb7fff1f) "") /* Unallocated space */
+
+       TEST_GROUP("Long multiply, long multiply accumulate, and divide")
+
+       TEST_RR(   "smull       r0, r1, r",2, VAL1,", r",3, VAL2,"")
+       TEST_RR(   "smull       r7, r8, r",9, VAL2,", r",10, VAL1,"")
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb89f80a) "   @ smull pc, r8, r9, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb89d80a) "   @ smull sp, r8, r9, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb897f0a) "   @ smull r7, pc, r9, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb897d0a) "   @ smull r7, sp, r9, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb8f780a) "   @ smull r7, r8, pc, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb8d780a) "   @ smull r7, r8, sp, r10");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb89780f) "   @ smull r7, r8, r9, pc");
+       TEST_UNSUPPORTED(__inst_thumb32(0xfb89780d) "   @ smull r7, r8, r9, sp");
+
+       TEST_RR(   "umull       r0, r1, r",2, VAL1,", r",3, VAL2,"")
+       TEST_RR(   "umull       r7, r8, r",9, VAL2,", r",10, VAL1,"")
+
+       TEST_RRRR( "smlal       r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR( "smlal       r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+
+       TEST_RRRR( "smlalbb     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR( "smlalbb     r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRRR( "smlalbt     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR( "smlalbt     r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRRR( "smlaltb     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR( "smlaltb     r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRRR( "smlaltt     r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR( "smlaltt     r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+
+       TEST_RRRR( "smlald      r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+       TEST_RRRR( "smlald      r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+       TEST_RRRR( "smlaldx     r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+       TEST_RRRR( "smlaldx     r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+
+       TEST_RRRR( "smlsld      r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+       TEST_RRRR( "smlsld      r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+       TEST_RRRR( "smlsldx     r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+       TEST_RRRR( "smlsldx     r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+
+       TEST_RRRR( "umlal       r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR( "umlal       r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+       TEST_RRRR( "umaal       r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+       TEST_RRRR( "umaal       r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+
+       TEST_GROUP("Coprocessor instructions")
+
+       TEST_UNSUPPORTED(__inst_thumb32(0xfc000000) "")
+       TEST_UNSUPPORTED(__inst_thumb32(0xffffffff) "")
+
+       TEST_GROUP("Testing instructions in IT blocks")
+
+       TEST_ITBLOCK("sub.w     r0, r0")
+
+       verbose("\n");
+}
+
diff --git a/arch/arm/probes/uprobes/Makefile b/arch/arm/probes/uprobes/Makefile
new file mode 100644 (file)
index 0000000..e1dc3d0
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_UPROBES)          += core.o actions-arm.o
diff --git a/arch/arm/probes/uprobes/actions-arm.c b/arch/arm/probes/uprobes/actions-arm.c
new file mode 100644 (file)
index 0000000..1dd4916
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/wait.h>
+#include <linux/uprobes.h>
+#include <linux/module.h>
+
+#include "../decode.h"
+#include "../decode-arm.h"
+#include "core.h"
+
+static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs)
+{
+       probes_opcode_t insn = __mem_to_opcode_arm(*pinsn);
+       probes_opcode_t temp;
+       probes_opcode_t mask;
+       int freereg;
+       u32 free = 0xffff;
+       u32 regs;
+
+       for (regs = oregs; regs; regs >>= 4, insn >>= 4) {
+               if ((regs & 0xf) == REG_TYPE_NONE)
+                       continue;
+
+               free &= ~(1 << (insn & 0xf));
+       }
+
+       /* No PC, no problem */
+       if (free & (1 << 15))
+               return 15;
+
+       if (!free)
+               return -1;
+
+       /*
+        * fls instead of ffs ensures that for "ldrd r0, r1, [pc]" we would
+        * pick LR instead of R1.
+        */
+       freereg = free = fls(free) - 1;
+
+       temp = __mem_to_opcode_arm(*pinsn);
+       insn = temp;
+       regs = oregs;
+       mask = 0xf;
+
+       for (; regs; regs >>= 4, mask <<= 4, free <<= 4, temp >>= 4) {
+               if ((regs & 0xf) == REG_TYPE_NONE)
+                       continue;
+
+               if ((temp & 0xf) != 15)
+                       continue;
+
+               insn &= ~mask;
+               insn |= free & mask;
+       }
+
+       *pinsn = __opcode_to_mem_arm(insn);
+       return freereg;
+}
+
+static void uprobe_set_pc(struct arch_uprobe *auprobe,
+                         struct arch_uprobe_task *autask,
+                         struct pt_regs *regs)
+{
+       u32 pcreg = auprobe->pcreg;
+
+       autask->backup = regs->uregs[pcreg];
+       regs->uregs[pcreg] = regs->ARM_pc + 8;
+}
+
+static void uprobe_unset_pc(struct arch_uprobe *auprobe,
+                           struct arch_uprobe_task *autask,
+                           struct pt_regs *regs)
+{
+       /* PC will be taken care of by common code */
+       regs->uregs[auprobe->pcreg] = autask->backup;
+}
+
+static void uprobe_aluwrite_pc(struct arch_uprobe *auprobe,
+                              struct arch_uprobe_task *autask,
+                              struct pt_regs *regs)
+{
+       u32 pcreg = auprobe->pcreg;
+
+       alu_write_pc(regs->uregs[pcreg], regs);
+       regs->uregs[pcreg] = autask->backup;
+}
+
+static void uprobe_write_pc(struct arch_uprobe *auprobe,
+                           struct arch_uprobe_task *autask,
+                           struct pt_regs *regs)
+{
+       u32 pcreg = auprobe->pcreg;
+
+       load_write_pc(regs->uregs[pcreg], regs);
+       regs->uregs[pcreg] = autask->backup;
+}
+
+enum probes_insn
+decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi,
+            const struct decode_header *d)
+{
+       struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
+                                                  asi);
+       struct decode_emulate *decode = (struct decode_emulate *) d;
+       u32 regs = decode->header.type_regs.bits >> DECODE_TYPE_BITS;
+       int reg;
+
+       reg = uprobes_substitute_pc(&auprobe->ixol[0], regs);
+       if (reg == 15)
+               return INSN_GOOD;
+
+       if (reg == -1)
+               return INSN_REJECTED;
+
+       auprobe->pcreg = reg;
+       auprobe->prehandler = uprobe_set_pc;
+       auprobe->posthandler = uprobe_unset_pc;
+
+       return INSN_GOOD;
+}
+
+enum probes_insn
+decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi,
+            const struct decode_header *d, bool alu)
+{
+       struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
+                                                  asi);
+       enum probes_insn ret = decode_pc_ro(insn, asi, d);
+
+       if (((insn >> 12) & 0xf) == 15)
+               auprobe->posthandler = alu ? uprobe_aluwrite_pc
+                                          : uprobe_write_pc;
+
+       return ret;
+}
+
+enum probes_insn
+decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
+                             struct arch_probes_insn *asi,
+                             const struct decode_header *d)
+{
+       return decode_wb_pc(insn, asi, d, true);
+}
+
+enum probes_insn
+decode_ldr(probes_opcode_t insn, struct arch_probes_insn *asi,
+          const struct decode_header *d)
+{
+       return decode_wb_pc(insn, asi, d, false);
+}
+
+enum probes_insn
+uprobe_decode_ldmstm(probes_opcode_t insn,
+                    struct arch_probes_insn *asi,
+                    const struct decode_header *d)
+{
+       struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
+                                                  asi);
+       unsigned reglist = insn & 0xffff;
+       int rn = (insn >> 16) & 0xf;
+       int lbit = insn & (1 << 20);
+       unsigned used = reglist | (1 << rn);
+
+       if (rn == 15)
+               return INSN_REJECTED;
+
+       if (!(used & (1 << 15)))
+               return INSN_GOOD;
+
+       if (used & (1 << 14))
+               return INSN_REJECTED;
+
+       /* Use LR instead of PC */
+       insn ^= 0xc000;
+
+       auprobe->pcreg = 14;
+       auprobe->ixol[0] = __opcode_to_mem_arm(insn);
+
+       auprobe->prehandler = uprobe_set_pc;
+       if (lbit)
+               auprobe->posthandler = uprobe_write_pc;
+       else
+               auprobe->posthandler = uprobe_unset_pc;
+
+       return INSN_GOOD;
+}
+
+const union decode_action uprobes_probes_actions[] = {
+       [PROBES_EMULATE_NONE] = {.handler = probes_simulate_nop},
+       [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
+       [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
+       [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
+       [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
+       [PROBES_MRS] = {.handler = simulate_mrs},
+       [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
+       [PROBES_CLZ] = {.handler = probes_simulate_nop},
+       [PROBES_SATURATING_ARITHMETIC] = {.handler = probes_simulate_nop},
+       [PROBES_MUL1] = {.handler = probes_simulate_nop},
+       [PROBES_MUL2] = {.handler = probes_simulate_nop},
+       [PROBES_SWP] = {.handler = probes_simulate_nop},
+       [PROBES_LDRSTRD] = {.decoder = decode_pc_ro},
+       [PROBES_LOAD_EXTRA] = {.decoder = decode_pc_ro},
+       [PROBES_LOAD] = {.decoder = decode_ldr},
+       [PROBES_STORE_EXTRA] = {.decoder = decode_pc_ro},
+       [PROBES_STORE] = {.decoder = decode_pc_ro},
+       [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
+       [PROBES_DATA_PROCESSING_REG] = {
+               .decoder = decode_rd12rn16rm0rs8_rwflags},
+       [PROBES_DATA_PROCESSING_IMM] = {
+               .decoder = decode_rd12rn16rm0rs8_rwflags},
+       [PROBES_MOV_HALFWORD] = {.handler = probes_simulate_nop},
+       [PROBES_SEV] = {.handler = probes_simulate_nop},
+       [PROBES_WFE] = {.handler = probes_simulate_nop},
+       [PROBES_SATURATE] = {.handler = probes_simulate_nop},
+       [PROBES_REV] = {.handler = probes_simulate_nop},
+       [PROBES_MMI] = {.handler = probes_simulate_nop},
+       [PROBES_PACK] = {.handler = probes_simulate_nop},
+       [PROBES_EXTEND] = {.handler = probes_simulate_nop},
+       [PROBES_EXTEND_ADD] = {.handler = probes_simulate_nop},
+       [PROBES_MUL_ADD_LONG] = {.handler = probes_simulate_nop},
+       [PROBES_MUL_ADD] = {.handler = probes_simulate_nop},
+       [PROBES_BITFIELD] = {.handler = probes_simulate_nop},
+       [PROBES_BRANCH] = {.handler = simulate_bbl},
+       [PROBES_LDMSTM] = {.decoder = uprobe_decode_ldmstm}
+};
diff --git a/arch/arm/probes/uprobes/core.c b/arch/arm/probes/uprobes/core.c
new file mode 100644 (file)
index 0000000..b2954f6
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/errno.h>
+#include <linux/highmem.h>
+#include <linux/sched.h>
+#include <linux/uprobes.h>
+#include <linux/notifier.h>
+
+#include <asm/opcodes.h>
+#include <asm/traps.h>
+
+#include "../decode.h"
+#include "../decode-arm.h"
+#include "core.h"
+
+#define UPROBE_TRAP_NR UINT_MAX
+
+bool is_swbp_insn(uprobe_opcode_t *insn)
+{
+       return (__mem_to_opcode_arm(*insn) & 0x0fffffff) ==
+               (UPROBE_SWBP_ARM_INSN & 0x0fffffff);
+}
+
+int set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm,
+            unsigned long vaddr)
+{
+       return uprobe_write_opcode(mm, vaddr,
+                  __opcode_to_mem_arm(auprobe->bpinsn));
+}
+
+bool arch_uprobe_ignore(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+       if (!auprobe->asi.insn_check_cc(regs->ARM_cpsr)) {
+               regs->ARM_pc += 4;
+               return true;
+       }
+
+       return false;
+}
+
+bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+       probes_opcode_t opcode;
+
+       if (!auprobe->simulate)
+               return false;
+
+       opcode = __mem_to_opcode_arm(*(unsigned int *) auprobe->insn);
+
+       auprobe->asi.insn_singlestep(opcode, &auprobe->asi, regs);
+
+       return true;
+}
+
+unsigned long
+arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
+                                 struct pt_regs *regs)
+{
+       unsigned long orig_ret_vaddr;
+
+       orig_ret_vaddr = regs->ARM_lr;
+       /* Replace the return addr with trampoline addr */
+       regs->ARM_lr = trampoline_vaddr;
+       return orig_ret_vaddr;
+}
+
+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
+                            unsigned long addr)
+{
+       unsigned int insn;
+       unsigned int bpinsn;
+       enum probes_insn ret;
+
+       /* Thumb not yet support */
+       if (addr & 0x3)
+               return -EINVAL;
+
+       insn = __mem_to_opcode_arm(*(unsigned int *)auprobe->insn);
+       auprobe->ixol[0] = __opcode_to_mem_arm(insn);
+       auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN);
+
+       ret = arm_probes_decode_insn(insn, &auprobe->asi, false,
+                                    uprobes_probes_actions);
+       switch (ret) {
+       case INSN_REJECTED:
+               return -EINVAL;
+
+       case INSN_GOOD_NO_SLOT:
+               auprobe->simulate = true;
+               break;
+
+       case INSN_GOOD:
+       default:
+               break;
+       }
+
+       bpinsn = UPROBE_SWBP_ARM_INSN & 0x0fffffff;
+       if (insn >= 0xe0000000)
+               bpinsn |= 0xe0000000;  /* Unconditional instruction */
+       else
+               bpinsn |= insn & 0xf0000000;  /* Copy condition from insn */
+
+       auprobe->bpinsn = bpinsn;
+
+       return 0;
+}
+
+void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
+                          void *src, unsigned long len)
+{
+       void *xol_page_kaddr = kmap_atomic(page);
+       void *dst = xol_page_kaddr + (vaddr & ~PAGE_MASK);
+
+       preempt_disable();
+
+       /* Initialize the slot */
+       memcpy(dst, src, len);
+
+       /* flush caches (dcache/icache) */
+       flush_uprobe_xol_access(page, vaddr, dst, len);
+
+       preempt_enable();
+
+       kunmap_atomic(xol_page_kaddr);
+}
+
+
+int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+       struct uprobe_task *utask = current->utask;
+
+       if (auprobe->prehandler)
+               auprobe->prehandler(auprobe, &utask->autask, regs);
+
+       utask->autask.saved_trap_no = current->thread.trap_no;
+       current->thread.trap_no = UPROBE_TRAP_NR;
+       regs->ARM_pc = utask->xol_vaddr;
+
+       return 0;
+}
+
+int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+       struct uprobe_task *utask = current->utask;
+
+       WARN_ON_ONCE(current->thread.trap_no != UPROBE_TRAP_NR);
+
+       current->thread.trap_no = utask->autask.saved_trap_no;
+       regs->ARM_pc = utask->vaddr + 4;
+
+       if (auprobe->posthandler)
+               auprobe->posthandler(auprobe, &utask->autask, regs);
+
+       return 0;
+}
+
+bool arch_uprobe_xol_was_trapped(struct task_struct *t)
+{
+       if (t->thread.trap_no != UPROBE_TRAP_NR)
+               return true;
+
+       return false;
+}
+
+void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+       struct uprobe_task *utask = current->utask;
+
+       current->thread.trap_no = utask->autask.saved_trap_no;
+       instruction_pointer_set(regs, utask->vaddr);
+}
+
+int arch_uprobe_exception_notify(struct notifier_block *self,
+                                unsigned long val, void *data)
+{
+       return NOTIFY_DONE;
+}
+
+static int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       instr &= 0x0fffffff;
+       if (instr == (UPROBE_SWBP_ARM_INSN & 0x0fffffff))
+               uprobe_pre_sstep_notifier(regs);
+       else if (instr == (UPROBE_SS_ARM_INSN & 0x0fffffff))
+               uprobe_post_sstep_notifier(regs);
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
+{
+       return instruction_pointer(regs);
+}
+
+static struct undef_hook uprobes_arm_break_hook = {
+       .instr_mask     = 0x0fffffff,
+       .instr_val      = (UPROBE_SWBP_ARM_INSN & 0x0fffffff),
+       .cpsr_mask      = MODE_MASK,
+       .cpsr_val       = USR_MODE,
+       .fn             = uprobe_trap_handler,
+};
+
+static struct undef_hook uprobes_arm_ss_hook = {
+       .instr_mask     = 0x0fffffff,
+       .instr_val      = (UPROBE_SS_ARM_INSN & 0x0fffffff),
+       .cpsr_mask      = MODE_MASK,
+       .cpsr_val       = USR_MODE,
+       .fn             = uprobe_trap_handler,
+};
+
+static int arch_uprobes_init(void)
+{
+       register_undef_hook(&uprobes_arm_break_hook);
+       register_undef_hook(&uprobes_arm_ss_hook);
+
+       return 0;
+}
+device_initcall(arch_uprobes_init);
diff --git a/arch/arm/probes/uprobes/core.h b/arch/arm/probes/uprobes/core.h
new file mode 100644 (file)
index 0000000..1d0c12d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARM_KERNEL_UPROBES_H
+#define __ARM_KERNEL_UPROBES_H
+
+enum probes_insn uprobe_decode_ldmstm(probes_opcode_t insn,
+                                     struct arch_probes_insn *asi,
+                                     const struct decode_header *d);
+
+enum probes_insn decode_ldr(probes_opcode_t insn,
+                           struct arch_probes_insn *asi,
+                           const struct decode_header *d);
+
+enum probes_insn
+decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
+                             struct arch_probes_insn *asi,
+                             const struct decode_header *d);
+
+enum probes_insn
+decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi,
+            const struct decode_header *d, bool alu);
+
+enum probes_insn
+decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi,
+            const struct decode_header *d);
+
+extern const union decode_action uprobes_probes_actions[];
+
+#endif