From: "David A. Long" <[email protected]>

Separate the kprobe-only functions from the functions needed by
both kprobes and uprobes.

Signed-off-by: David A. Long <[email protected]>
---
 arch/arm/kernel/Makefile         |   2 +-
 arch/arm/kernel/kprobes-arm.c    | 298 +------------------------------------
 arch/arm/kernel/kprobes-common.c | 266 ---------------------------------
 arch/arm/kernel/kprobes-thumb.c  |  14 +-
 arch/arm/kernel/kprobes.h        |   4 +-
 arch/arm/kernel/probes-arm.c     | 311 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/probes.c         | 286 +++++++++++++++++++++++++++++++++++
 arch/arm/kernel/probes.h         |  23 +++
 8 files changed, 635 insertions(+), 569 deletions(-)
 create mode 100644 arch/arm/kernel/probes-arm.c
 create mode 100644 arch/arm/kernel/probes.c
 create mode 100644 arch/arm/kernel/probes.h

diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 86d10dd..3292023 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -49,7 +49,7 @@ 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_KPROBES)          += kprobes.o kprobes-common.o patch.o
+obj-$(CONFIG_KPROBES)          += probes.o probes-arm.o kprobes.o 
kprobes-common.o patch.o
 ifdef CONFIG_THUMB2_KERNEL
 obj-$(CONFIG_KPROBES)          += kprobes-thumb.o
 else
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c
index 8a30c89..d6503cc 100644
--- a/arch/arm/kernel/kprobes-arm.c
+++ b/arch/arm/kernel/kprobes-arm.c
@@ -62,19 +62,9 @@
 #include <linux/kprobes.h>
 #include <linux/module.h>
 
+#include "probes.h"
 #include "kprobes.h"
 
-#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
-
-#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
-
-#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
-
 /*
  * To avoid the complications of mimicing single-stepping on a
  * processor without a Next-PC or a single-step mode, and to
@@ -105,284 +95,6 @@
  * read and write of flags.
  */
 
-static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       long iaddr = (long)p->addr;
-       int disp  = branch_displacement(insn);
-
-       if (insn & (1 << 24))
-               regs->ARM_lr = iaddr + 4;
-
-       regs->ARM_pc = iaddr + 8 + disp;
-}
-
-static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       long iaddr = (long)p->addr;
-       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;
-}
-
-static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       int rm = insn & 0xf;
-       long rmv = regs->uregs[rm];
-
-       if (insn & (1 << 5))
-               regs->ARM_lr = (long)p->addr + 4;
-
-       regs->ARM_pc = rmv & ~0x1;
-       regs->ARM_cpsr &= ~PSR_T_BIT;
-       if (rmv & 0x1)
-               regs->ARM_cpsr |= PSR_T_BIT;
-}
-
-static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       int rd = (insn >> 12) & 0xf;
-       unsigned long mask = 0xf8ff03df; /* Mask out execution state */
-       regs->uregs[rd] = regs->ARM_cpsr & mask;
-}
-
-static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs)
-{
-       regs->uregs[12] = regs->uregs[13];
-}
-
-static void __kprobes
-emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       unsigned long pc = (unsigned long)p->addr + 8;
-       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" (p->ainsn.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(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       unsigned long pc = (unsigned long)p->addr + 8;
-       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" (p->ainsn.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(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       unsigned long rtpc = (unsigned long)p->addr + str_pc_offset;
-       unsigned long rnpc = (unsigned long)p->addr + 8;
-       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" (p->ainsn.insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       if (is_writeback(insn))
-               regs->uregs[rn] = rnv;
-}
-
-static void __kprobes
-emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       unsigned long pc = (unsigned long)p->addr + 8;
-       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" (p->ainsn.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(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       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" (p->ainsn.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(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       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" (p->ainsn.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(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       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" (p->ainsn.insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rd] = rdv;
-}
-
-static void __kprobes
-emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
-{
-       kprobe_opcode_t insn = p->opcode;
-       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" (p->ainsn.insn_fn)
-               : "lr", "memory", "cc"
-       );
-
-       regs->uregs[rdlo] = rdlov;
-       regs->uregs[rdhi] = rdhiv;
-       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
-}
-
 /*
  * For the instruction masking and comparisons in all the "space_*"
  * functions below, Do _not_ rearrange the order of tests unless
@@ -400,13 +112,13 @@ static const union decode_item arm_1111_table[] = {
        /* 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, kprobe_simulate_nop),
+       DECODE_SIMULATE (0xfe300000, 0xf4100000, probes_simulate_nop),
 
        /* 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, kprobe_simulate_nop),
+       DECODE_SIMULATE (0xfe300010, 0xf6100000, probes_simulate_nop),
 
        /* BLX (immediate)      1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */
        DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1),
@@ -649,11 +361,11 @@ static const union decode_item arm_cccc_001x_table[] = {
        /* 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, kprobe_emulate_none),
+       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, kprobe_simulate_nop),
+       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 */
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c
index 18a7628..b66e9f7 100644
--- a/arch/arm/kernel/kprobes-common.c
+++ b/arch/arm/kernel/kprobes-common.c
@@ -173,15 +173,6 @@ kprobe_check_cc * const kprobe_condition_checks[16] = {
 };
 
 
-void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs)
-{
-}
-
-void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs)
-{
-       p->ainsn.insn_fn();
-}
-
 static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
 {
        kprobe_opcode_t insn = p->opcode;
@@ -319,260 +310,3 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct 
arch_specific_insn *asi)
        return INSN_GOOD_NO_SLOT;
 }
 
-
-/*
- * 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 kprobe_opcode_t __kprobes
-prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
-                                                               bool thumb)
-{
-#ifdef CONFIG_THUMB2_KERNEL
-       if (thumb) {
-               u16 *thumb_insn = (u16 *)asi->insn;
-               thumb_insn[1] = 0x4770; /* Thumb bx lr */
-               thumb_insn[2] = 0x4770; /* Thumb bx lr */
-               return insn;
-       }
-       asi->insn[1] = 0xe12fff1e; /* ARM bx lr */
-#else
-       asi->insn[1] = 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(kprobe_opcode_t insn, struct arch_specific_insn *asi,
-                                                               bool thumb)
-{
-#ifdef CONFIG_THUMB2_KERNEL
-       if (thumb) {
-               u16 *ip = (u16 *)asi->insn;
-               if (is_wide_instruction(insn))
-                       *ip++ = insn >> 16;
-               *ip++ = insn;
-               return;
-       }
-#endif
-       asi->insn[0] = 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(kprobe_opcode_t* pinsn, u32 regs)
-{
-       kprobe_opcode_t insn = *pinsn;
-       kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */
-
-       for (; regs != 0; regs >>= 4, mask <<= 4) {
-
-               kprobe_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;
-       }
-
-       *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)
-};
-
-/*
- * kprobe_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
-kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
-                               const union decode_item *table, bool thumb)
-{
-       const struct decode_header *h = (struct decode_header *)table;
-       const struct decode_header *next;
-       bool matched = false;
-
-       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))
-                       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 (*d->decoder.decoder)(insn, asi);
-               }
-
-               case DECODE_TYPE_SIMULATE: {
-                       struct decode_simulate *d = (struct decode_simulate *)h;
-                       asi->insn_handler = d->handler.handler;
-                       return INSN_GOOD_NO_SLOT;
-               }
-
-               case DECODE_TYPE_EMULATE: {
-                       struct decode_emulate *d = (struct decode_emulate *)h;
-                       asi->insn_handler = d->handler.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/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c
index 6123daf..173b2bc 100644
--- a/arch/arm/kernel/kprobes-thumb.c
+++ b/arch/arm/kernel/kprobes-thumb.c
@@ -544,11 +544,11 @@ static const union decode_item t32_table_1111_0xxx___1[] 
= {
        /* 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, kprobe_emulate_none),
+       DECODE_EMULATE  (0xfff0d7ff, 0xf3a08004, probes_emulate_none),
        /* 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, kprobe_simulate_nop),
+       DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, probes_simulate_nop),
 
        /* MRS Rd, CPSR         1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */
        DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs,
@@ -589,7 +589,7 @@ static const union decode_item 
t32_table_1111_100x_x0x1__1111[] = {
 
        /* PLD (literal)        1111 1000 x001 1111 1111 xxxx xxxx xxxx */
        /* PLI (literal)        1111 1001 x001 1111 1111 xxxx xxxx xxxx */
-       DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop),
+       DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, probes_simulate_nop),
 
        /* PLD{W} (immediate)   1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */
        DECODE_OR       (0xffd0f000, 0xf890f000),
@@ -598,13 +598,13 @@ static const union decode_item 
t32_table_1111_100x_x0x1__1111[] = {
        /* 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, kprobe_simulate_nop,
+       DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, probes_simulate_nop,
                                                 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, kprobe_simulate_nop,
+       DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, probes_simulate_nop,
                                                 REGS(NOPCX, 0, 0, 0, NOSPPC)),
 
        /* Other unallocated instructions...                            */
@@ -1274,11 +1274,11 @@ static const union decode_item t16_table_1011[] = {
        /* YIELD                        1011 1111 0001 0000 */
        DECODE_OR       (0xffff, 0xbf10),
        /* SEV                          1011 1111 0100 0000 */
-       DECODE_EMULATE  (0xffff, 0xbf40, kprobe_emulate_none),
+       DECODE_EMULATE  (0xffff, 0xbf40, probes_emulate_none),
        /* NOP                          1011 1111 0000 0000 */
        /* WFE                          1011 1111 0010 0000 */
        /* WFI                          1011 1111 0011 0000 */
-       DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop),
+       DECODE_SIMULATE (0xffcf, 0xbf00, probes_simulate_nop),
        /* Unassigned hints             1011 1111 xxxx 0000 */
        DECODE_REJECT   (0xff0f, 0xbf00),
        /* IT                           1011 1111 xxxx xxxx */
diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h
index 38945f7..9aa2f15 100644
--- a/arch/arm/kernel/kprobes.h
+++ b/arch/arm/kernel/kprobes.h
@@ -161,8 +161,8 @@ static inline void __kprobes alu_write_pc(long pcv, struct 
pt_regs *regs)
 }
 
 
-void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs);
-void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs);
+void __kprobes probes_simulate_nop(struct kprobe *p, struct pt_regs *regs);
+void __kprobes probes_emulate_none(struct kprobe *p, struct pt_regs *regs);
 
 enum kprobe_insn __kprobes
 kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi);
diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c
new file mode 100644
index 0000000..e1b1a6e
--- /dev/null
+++ b/arch/arm/kernel/probes-arm.c
@@ -0,0 +1,311 @@
+/*
+ * 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/kprobes.h>
+
+#include "probes.h"
+#include "kprobes.h"
+
+#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
+
+#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
+
+#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
+
+void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       long iaddr = (long)p->addr;
+       int disp  = branch_displacement(insn);
+
+       if (insn & (1 << 24))
+               regs->ARM_lr = iaddr + 4;
+
+       regs->ARM_pc = iaddr + 8 + disp;
+}
+
+void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       long iaddr = (long)p->addr;
+       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(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       int rm = insn & 0xf;
+       long rmv = regs->uregs[rm];
+
+       if (insn & (1 << 5))
+               regs->ARM_lr = (long)p->addr + 4;
+
+       regs->ARM_pc = rmv & ~0x1;
+       regs->ARM_cpsr &= ~PSR_T_BIT;
+       if (rmv & 0x1)
+               regs->ARM_cpsr |= PSR_T_BIT;
+}
+
+void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       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(struct kprobe *p, struct pt_regs *regs)
+{
+       regs->uregs[12] = regs->uregs[13];
+}
+
+void __kprobes
+emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       unsigned long pc = (unsigned long)p->addr + 8;
+       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" (p->ainsn.insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rt] = rtv;
+       regs->uregs[rt+1] = rt2v;
+       if (is_writeback(insn))
+               regs->uregs[rn] = rnv;
+}
+
+void __kprobes
+emulate_ldr(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       unsigned long pc = (unsigned long)p->addr + 8;
+       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" (p->ainsn.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;
+}
+
+void __kprobes
+emulate_str(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       unsigned long rtpc = (unsigned long)p->addr + str_pc_offset;
+       unsigned long rnpc = (unsigned long)p->addr + 8;
+       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" (p->ainsn.insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       if (is_writeback(insn))
+               regs->uregs[rn] = rnv;
+}
+
+void __kprobes
+emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       unsigned long pc = (unsigned long)p->addr + 8;
+       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" (p->ainsn.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);
+}
+
+void __kprobes
+emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       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" (p->ainsn.insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rd] = rdv;
+       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
+}
+
+void __kprobes
+emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       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" (p->ainsn.insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rd] = rdv;
+       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
+}
+
+void __kprobes
+emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       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" (p->ainsn.insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rd] = rdv;
+}
+
+void __kprobes
+emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
+{
+       kprobe_opcode_t insn = p->opcode;
+       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" (p->ainsn.insn_fn)
+               : "lr", "memory", "cc"
+       );
+
+       regs->uregs[rdlo] = rdlov;
+       regs->uregs[rdhi] = rdhiv;
+       regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
+}
diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c
new file mode 100644
index 0000000..86c63f3
--- /dev/null
+++ b/arch/arm/kernel/probes.c
@@ -0,0 +1,286 @@
+/*
+ * arch/arm/kernel/probes.c
+ *
+ * Some contents moved here from arch/arm/include/asm/kprobes-common.c
+ *
+ * Copyright (C) 2011 Jon Medhurst <[email protected]>.
+ *
+ * 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 "probes.h"
+#include "kprobes.h"
+
+void __kprobes probes_simulate_nop(struct kprobe *p, struct pt_regs *regs)
+{
+}
+
+void __kprobes probes_emulate_none(struct kprobe *p, struct pt_regs *regs)
+{
+       p->ainsn.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 kprobe_opcode_t __kprobes
+prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
+                                                               bool thumb)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+       if (thumb) {
+               u16 *thumb_insn = (u16 *)asi->insn;
+               thumb_insn[1] = 0x4770; /* Thumb bx lr */
+               thumb_insn[2] = 0x4770; /* Thumb bx lr */
+               return insn;
+       }
+       asi->insn[1] = 0xe12fff1e; /* ARM bx lr */
+#else
+       asi->insn[1] = 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(kprobe_opcode_t insn, struct arch_specific_insn *asi,
+                                                               bool thumb)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+       if (thumb) {
+               u16 *ip = (u16 *)asi->insn;
+               if (is_wide_instruction(insn))
+                       *ip++ = insn >> 16;
+               *ip++ = insn;
+               return;
+       }
+#endif
+       asi->insn[0] = 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(kprobe_opcode_t *pinsn, u32 regs)
+{
+       kprobe_opcode_t insn = *pinsn;
+       kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */
+
+       for (; regs != 0; regs >>= 4, mask <<= 4) {
+
+               kprobe_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;
+       }
+
+       *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)
+};
+
+/*
+ * kprobe_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
+kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
+                               const union decode_item *table, bool thumb)
+{
+       const struct decode_header *h = (struct decode_header *)table;
+       const struct decode_header *next;
+       bool matched = false;
+
+       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))
+                       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 (*d->decoder.decoder)(insn, asi);
+               }
+
+               case DECODE_TYPE_SIMULATE: {
+                       struct decode_simulate *d = (struct decode_simulate *)h;
+                       asi->insn_handler = d->handler.handler;
+                       return INSN_GOOD_NO_SLOT;
+               }
+
+               case DECODE_TYPE_EMULATE: {
+                       struct decode_emulate *d = (struct decode_emulate *)h;
+                       asi->insn_handler = d->handler.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
new file mode 100644
index 0000000..56eec12
--- /dev/null
+++ b/arch/arm/kernel/probes.h
@@ -0,0 +1,23 @@
+#ifndef _ARM_KERNEL_PROBES_H
+#define  _ARM_KERNEL_PROBES_H
+
+void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs);
+void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs);
+void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs);
+void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs);
+void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs);
+void __kprobes emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs);
+void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs);
+void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs);
+void __kprobes emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p,
+                                             struct pt_regs *regs);
+void __kprobes emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p,
+                                               struct pt_regs *regs);
+void __kprobes emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p,
+                                                  struct pt_regs *regs);
+void __kprobes emulate_rd12rm0_noflags_nopc(struct kprobe *p,
+                                           struct pt_regs *regs);
+void __kprobes emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p,
+                                                      struct pt_regs *regs);
+
+#endif
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to