Commit 3e6cd394 authored by David A. Long's avatar David A. Long

ARM: use a function table for determining instruction interpreter action

Make the instruction interpreter call back to semantic action functions
through a function pointer array provided by the invoker.  The interpreter
decodes the instructions into groups and uses the group number to index
into the supplied array.  kprobes and uprobes code will each supply their
own array of functions.
Signed-off-by: default avatarDavid A. Long <dave.long@linaro.org>
Acked-by: default avatarJon Medhurst <tixy@linaro.org>
parent 87abef63
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
#endif #endif
void __kprobes static void __kprobes
emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs)
{ {
kprobe_opcode_t insn = p->opcode; kprobe_opcode_t insn = p->opcode;
...@@ -102,7 +102,7 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) ...@@ -102,7 +102,7 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs)
regs->uregs[rn] = rnv; regs->uregs[rn] = rnv;
} }
void __kprobes static void __kprobes
emulate_ldr(struct kprobe *p, struct pt_regs *regs) emulate_ldr(struct kprobe *p, struct pt_regs *regs)
{ {
kprobe_opcode_t insn = p->opcode; kprobe_opcode_t insn = p->opcode;
...@@ -132,7 +132,7 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs) ...@@ -132,7 +132,7 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs)
regs->uregs[rn] = rnv; regs->uregs[rn] = rnv;
} }
void __kprobes static void __kprobes
emulate_str(struct kprobe *p, struct pt_regs *regs) emulate_str(struct kprobe *p, struct pt_regs *regs)
{ {
kprobe_opcode_t insn = p->opcode; kprobe_opcode_t insn = p->opcode;
...@@ -159,7 +159,7 @@ emulate_str(struct kprobe *p, struct pt_regs *regs) ...@@ -159,7 +159,7 @@ emulate_str(struct kprobe *p, struct pt_regs *regs)
regs->uregs[rn] = rnv; regs->uregs[rn] = rnv;
} }
void __kprobes static void __kprobes
emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs)
{ {
kprobe_opcode_t insn = p->opcode; kprobe_opcode_t insn = p->opcode;
...@@ -194,7 +194,7 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) ...@@ -194,7 +194,7 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs)
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
} }
void __kprobes static void __kprobes
emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
{ {
kprobe_opcode_t insn = p->opcode; kprobe_opcode_t insn = p->opcode;
...@@ -221,7 +221,7 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) ...@@ -221,7 +221,7 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
} }
void __kprobes static void __kprobes
emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
{ {
kprobe_opcode_t insn = p->opcode; kprobe_opcode_t insn = p->opcode;
...@@ -250,7 +250,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) ...@@ -250,7 +250,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
} }
void __kprobes static void __kprobes
emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs)
{ {
kprobe_opcode_t insn = p->opcode; kprobe_opcode_t insn = p->opcode;
...@@ -270,7 +270,7 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) ...@@ -270,7 +270,7 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs)
regs->uregs[rd] = rdv; regs->uregs[rd] = rdv;
} }
void __kprobes static void __kprobes
emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
{ {
kprobe_opcode_t insn = p->opcode; kprobe_opcode_t insn = p->opcode;
...@@ -299,3 +299,44 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) ...@@ -299,3 +299,44 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
regs->uregs[rdhi] = rdhiv; regs->uregs[rdhi] = rdhiv;
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); 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 = kprobe_emulate_none},
[PROBES_SIMULATE_NOP] = {.handler = kprobe_simulate_nop},
[PROBES_PRELOAD_IMM] = {.handler = kprobe_simulate_nop},
[PROBES_PRELOAD_REG] = {.handler = kprobe_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 = kprobe_emulate_none},
[PROBES_WFE] = {.handler = kprobe_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}
};
...@@ -112,7 +112,8 @@ emulate_ldm_r3_15(struct kprobe *p, struct pt_regs *regs) ...@@ -112,7 +112,8 @@ emulate_ldm_r3_15(struct kprobe *p, struct pt_regs *regs)
} }
enum kprobe_insn __kprobes enum kprobe_insn __kprobes
kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi,
const struct decode_header *h)
{ {
kprobe_insn_handler_t *handler = 0; kprobe_insn_handler_t *handler = 0;
unsigned reglist = insn & 0xffff; unsigned reglist = insn & 0xffff;
......
This diff is collapsed.
...@@ -56,6 +56,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -56,6 +56,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
unsigned long addr = (unsigned long)p->addr; unsigned long addr = (unsigned long)p->addr;
bool thumb; bool thumb;
kprobe_decode_insn_t *decode_insn; kprobe_decode_insn_t *decode_insn;
const union decode_action *actions;
int is; int is;
if (in_exception_text(addr)) if (in_exception_text(addr))
...@@ -69,20 +70,24 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -69,20 +70,24 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
insn <<= 16; insn <<= 16;
insn |= ((u16 *)addr)[1]; insn |= ((u16 *)addr)[1];
decode_insn = thumb32_kprobe_decode_insn; decode_insn = thumb32_kprobe_decode_insn;
} else actions = kprobes_t32_actions;
} else {
decode_insn = thumb16_kprobe_decode_insn; decode_insn = thumb16_kprobe_decode_insn;
actions = kprobes_t16_actions;
}
#else /* !CONFIG_THUMB2_KERNEL */ #else /* !CONFIG_THUMB2_KERNEL */
thumb = false; thumb = false;
if (addr & 0x3) if (addr & 0x3)
return -EINVAL; return -EINVAL;
insn = *p->addr; insn = *p->addr;
decode_insn = arm_kprobe_decode_insn; decode_insn = arm_kprobe_decode_insn;
actions = kprobes_arm_actions;
#endif #endif
p->opcode = insn; p->opcode = insn;
p->ainsn.insn = tmp_insn; p->ainsn.insn = tmp_insn;
switch ((*decode_insn)(insn, &p->ainsn)) { switch ((*decode_insn)(insn, &p->ainsn, actions)) {
case INSN_REJECTED: /* not supported */ case INSN_REJECTED: /* not supported */
return -EINVAL; return -EINVAL;
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18 #define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18
#define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018
struct decode_header;
union decode_action;
enum kprobe_insn { enum kprobe_insn {
INSN_REJECTED, INSN_REJECTED,
...@@ -35,19 +37,24 @@ enum kprobe_insn { ...@@ -35,19 +37,24 @@ enum kprobe_insn {
}; };
typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t, typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t,
struct arch_specific_insn *); struct arch_specific_insn *,
const union decode_action *);
#ifdef CONFIG_THUMB2_KERNEL #ifdef CONFIG_THUMB2_KERNEL
enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t, enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t,
struct arch_specific_insn *); struct arch_specific_insn *,
const union decode_action *);
enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t, enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t,
struct arch_specific_insn *); struct arch_specific_insn *,
const union decode_action *);
#else /* !CONFIG_THUMB2_KERNEL */ #else /* !CONFIG_THUMB2_KERNEL */
enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t, enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t,
struct arch_specific_insn *); struct arch_specific_insn *,
const union decode_action *);
#endif #endif
void __init arm_kprobe_decode_init(void); void __init arm_kprobe_decode_init(void);
......
This diff is collapsed.
...@@ -15,24 +15,48 @@ ...@@ -15,24 +15,48 @@
#ifndef _ARM_KERNEL_PROBES_ARM_H #ifndef _ARM_KERNEL_PROBES_ARM_H
#define _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(struct kprobe *p, struct pt_regs *regs); 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_blx1(struct kprobe *p, struct pt_regs *regs);
void __kprobes simulate_blx2bx(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_mrs(struct kprobe *p, struct pt_regs *regs);
void __kprobes simulate_mov_ipsp(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 #endif
This diff is collapsed.
...@@ -27,55 +27,61 @@ ...@@ -27,55 +27,61 @@
*/ */
#define current_cond(cpsr) ((cpsr >> 12) & 0xf) #define current_cond(cpsr) ((cpsr >> 12) & 0xf)
void __kprobes t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs); enum probes_t32_action {
void __kprobes t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs); PROBES_T32_EMULATE_NONE,
void __kprobes t16_simulate_ldrstr_sp_relative(struct kprobe *p, PROBES_T32_SIMULATE_NOP,
struct pt_regs *regs); PROBES_T32_LDMSTM,
void __kprobes t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs); PROBES_T32_LDRDSTRD,
void __kprobes t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs); PROBES_T32_TABLE_BRANCH,
void __kprobes t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs); PROBES_T32_TST,
void __kprobes t16_simulate_it(struct kprobe *p, struct pt_regs *regs); PROBES_T32_CMP,
void __kprobes t16_singlestep_it(struct kprobe *p, struct pt_regs *regs); PROBES_T32_MOV,
enum kprobe_insn __kprobes t16_decode_it(kprobe_opcode_t insn, PROBES_T32_ADDSUB,
struct arch_specific_insn *asi); PROBES_T32_LOGICAL,
void __kprobes t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs); PROBES_T32_ADDWSUBW_PC,
enum kprobe_insn __kprobes t16_decode_cond_branch(kprobe_opcode_t insn, PROBES_T32_ADDWSUBW,
struct arch_specific_insn *asi); PROBES_T32_MOVW,
void __kprobes t16_simulate_branch(struct kprobe *p, struct pt_regs *regs); PROBES_T32_SAT,
void __kprobes t16_emulate_loregs_rwflags(struct kprobe *p, PROBES_T32_BITFIELD,
struct pt_regs *regs); PROBES_T32_SEV,
void __kprobes t16_emulate_loregs_noitrwflags(struct kprobe *p, PROBES_T32_WFE,
struct pt_regs *regs); PROBES_T32_MRS,
void __kprobes t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs); PROBES_T32_BRANCH_COND,
enum kprobe_insn __kprobes t16_decode_hiregs(kprobe_opcode_t insn, PROBES_T32_BRANCH,
struct arch_specific_insn *asi); PROBES_T32_PLDI,
void __kprobes t16_emulate_push(struct kprobe *p, struct pt_regs *regs); PROBES_T32_LDR_LIT,
enum kprobe_insn __kprobes t16_decode_push(kprobe_opcode_t insn, PROBES_T32_LDRSTR,
struct arch_specific_insn *asi); PROBES_T32_SIGN_EXTEND,
void __kprobes t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs); PROBES_T32_MEDIA,
void __kprobes t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs); PROBES_T32_REVERSE,
enum kprobe_insn __kprobes t16_decode_pop(kprobe_opcode_t insn, PROBES_T32_MUL_ADD,
struct arch_specific_insn *asi); PROBES_T32_MUL_ADD2,
PROBES_T32_MUL_ADD_LONG,
NUM_PROBES_T32_ACTIONS
};
void __kprobes t32_simulate_table_branch(struct kprobe *p, enum probes_t16_action {
struct pt_regs *regs); PROBES_T16_ADD_SP,
void __kprobes t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs); PROBES_T16_CBZ,
void __kprobes t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs); PROBES_T16_SIGN_EXTEND,
enum kprobe_insn __kprobes t32_decode_cond_branch(kprobe_opcode_t insn, PROBES_T16_PUSH,
struct arch_specific_insn *asi); PROBES_T16_POP,
void __kprobes t32_simulate_branch(struct kprobe *p, struct pt_regs *regs); PROBES_T16_SEV,
void __kprobes t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs); PROBES_T16_WFE,
enum kprobe_insn __kprobes t32_decode_ldmstm(kprobe_opcode_t insn, PROBES_T16_IT,
struct arch_specific_insn *asi); PROBES_T16_CMP,
void __kprobes t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs); PROBES_T16_ADDSUB,
void __kprobes t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs); PROBES_T16_LOGICAL,
void __kprobes t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, PROBES_T16_BLX,
struct pt_regs *regs); PROBES_T16_HIREGOPS,
void __kprobes t32_emulate_rd8pc16_noflags(struct kprobe *p, PROBES_T16_LDR_LIT,
struct pt_regs *regs); PROBES_T16_LDRHSTRH,
void __kprobes t32_emulate_rd8rn16_noflags(struct kprobe *p, PROBES_T16_LDRSTR,
struct pt_regs *regs); PROBES_T16_ADR,
void __kprobes t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, PROBES_T16_LDMSTM,
struct pt_regs *regs); PROBES_T16_BRANCH_COND,
PROBES_T16_BRANCH,
NUM_PROBES_T16_ACTIONS
};
#endif #endif
...@@ -381,7 +381,8 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { ...@@ -381,7 +381,8 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
*/ */
int __kprobes int __kprobes
kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
const union decode_item *table, bool thumb) const union decode_item *table, bool thumb,
const union decode_action *actions)
{ {
const struct decode_header *h = (struct decode_header *)table; const struct decode_header *h = (struct decode_header *)table;
const struct decode_header *next; const struct decode_header *next;
...@@ -415,18 +416,18 @@ kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, ...@@ -415,18 +416,18 @@ kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
case DECODE_TYPE_CUSTOM: { case DECODE_TYPE_CUSTOM: {
struct decode_custom *d = (struct decode_custom *)h; struct decode_custom *d = (struct decode_custom *)h;
return (*d->decoder.decoder)(insn, asi); return actions[d->decoder.action].decoder(insn, asi, h);
} }
case DECODE_TYPE_SIMULATE: { case DECODE_TYPE_SIMULATE: {
struct decode_simulate *d = (struct decode_simulate *)h; struct decode_simulate *d = (struct decode_simulate *)h;
asi->insn_handler = d->handler.handler; asi->insn_handler = actions[d->handler.action].handler;
return INSN_GOOD_NO_SLOT; return INSN_GOOD_NO_SLOT;
} }
case DECODE_TYPE_EMULATE: { case DECODE_TYPE_EMULATE: {
struct decode_emulate *d = (struct decode_emulate *)h; struct decode_emulate *d = (struct decode_emulate *)h;
asi->insn_handler = d->handler.handler; asi->insn_handler = actions[d->handler.action].handler;
set_emulated_insn(insn, asi, thumb); set_emulated_insn(insn, asi, thumb);
return INSN_GOOD; return INSN_GOOD;
} }
......
...@@ -133,7 +133,8 @@ void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); ...@@ -133,7 +133,8 @@ 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 kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs);
enum kprobe_insn __kprobes enum kprobe_insn __kprobes
kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi,
const struct decode_header *h);
/* /*
* Test if load/store instructions writeback the address register. * Test if load/store instructions writeback the address register.
...@@ -160,7 +161,7 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); ...@@ -160,7 +161,7 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi);
* {.bits = _type}, * {.bits = _type},
* {.bits = _mask}, * {.bits = _mask},
* {.bits = _value}, * {.bits = _value},
* {.handler = _handler}, * {.action = _handler},
* *
* Initialising a specified member of the union means that the compiler * Initialising a specified member of the union means that the compiler
* will produce a warning if the argument is of an incorrect type. * will produce a warning if the argument is of an incorrect type.
...@@ -173,19 +174,23 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); ...@@ -173,19 +174,23 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi);
* Instruction decoding jumps to parsing the new sub-table 'table'. * Instruction decoding jumps to parsing the new sub-table 'table'.
* *
* DECODE_CUSTOM(mask, value, decoder) * DECODE_CUSTOM(mask, value, decoder)
* The custom function 'decoder' is called to the complete decoding * The value of 'decoder' is used as an index into the array of
* of an instruction. * action functions, and the retrieved decoder function is invoked
* to complete decoding of the instruction.
* *
* DECODE_SIMULATE(mask, value, handler) * DECODE_SIMULATE(mask, value, handler)
* Set the probes instruction handler to 'handler', this will be used * The probes instruction handler is set to the value found by
* to simulate the instruction when the probe is hit. Decoding returns * indexing into the action array using the value of 'handler'. This
* with INSN_GOOD_NO_SLOT. * will be used to simulate the instruction when the probe is hit.
* Decoding returns with INSN_GOOD_NO_SLOT.
* *
* DECODE_EMULATE(mask, value, handler) * DECODE_EMULATE(mask, value, handler)
* Set the probes instruction handler to 'handler', this will be used * The probes instruction handler is set to the value found by
* to emulate the instruction when the probe is hit. The modified * indexing into the action array using the value of 'handler'. This
* instruction (see below) is placed in the probes instruction slot so it * will be used to emulate the instruction when the probe is hit. The
* may be called by the emulation code. Decoding returns with INSN_GOOD. * 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) * DECODE_REJECT(mask, value)
* Instruction decoding fails with INSN_REJECTED * Instruction decoding fails with INSN_REJECTED
...@@ -238,7 +243,7 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); ...@@ -238,7 +243,7 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi);
* Here is a real example which matches ARM instructions of the form * Here is a real example which matches ARM instructions of the form
* "AND <Rd>,<Rn>,<Rm>,<shift> <Rs>" * "AND <Rd>,<Rn>,<Rm>,<shift> <Rs>"
* *
* DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, * DECODE_EMULATEX (0x0e000090, 0x00000010, PROBES_DATA_PROCESSING_REG,
* REGS(ANY, ANY, NOPC, 0, ANY)), * REGS(ANY, ANY, NOPC, 0, ANY)),
* ^ ^ ^ ^ * ^ ^ ^ ^
* Rn Rd Rs Rm * Rn Rd Rs Rm
...@@ -249,7 +254,8 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); ...@@ -249,7 +254,8 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi);
* Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the * 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 * 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 * the kprobes instruction slot. This can then be called later by the handler
* function emulate_rd12rn16rm0rs8_rwflags in order to simulate the instruction. * 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 { enum decode_type {
...@@ -298,10 +304,17 @@ enum decode_reg_type { ...@@ -298,10 +304,17 @@ enum decode_reg_type {
union decode_item { union decode_item {
u32 bits; u32 bits;
const union decode_item *table; const union decode_item *table;
kprobe_insn_handler_t *handler; int action;
kprobe_decode_insn_t *decoder;
}; };
typedef enum kprobe_insn (probes_custom_decode_t)(kprobe_opcode_t,
struct arch_specific_insn *,
const struct decode_header *);
union decode_action {
kprobe_insn_handler_t *handler;
probes_custom_decode_t *decoder;
};
#define DECODE_END \ #define DECODE_END \
{.bits = DECODE_TYPE_END} {.bits = DECODE_TYPE_END}
...@@ -336,7 +349,7 @@ struct decode_custom { ...@@ -336,7 +349,7 @@ struct decode_custom {
#define DECODE_CUSTOM(_mask, _value, _decoder) \ #define DECODE_CUSTOM(_mask, _value, _decoder) \
DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \ DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \
{.decoder = (_decoder)} {.action = (_decoder)}
struct decode_simulate { struct decode_simulate {
...@@ -346,7 +359,7 @@ struct decode_simulate { ...@@ -346,7 +359,7 @@ struct decode_simulate {
#define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \ #define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \
DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \ DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \
{.handler = (_handler)} {.action = (_handler)}
#define DECODE_SIMULATE(_mask, _value, _handler) \ #define DECODE_SIMULATE(_mask, _value, _handler) \
DECODE_SIMULATEX(_mask, _value, _handler, 0) DECODE_SIMULATEX(_mask, _value, _handler, 0)
...@@ -359,7 +372,7 @@ struct decode_emulate { ...@@ -359,7 +372,7 @@ struct decode_emulate {
#define DECODE_EMULATEX(_mask, _value, _handler, _regs) \ #define DECODE_EMULATEX(_mask, _value, _handler, _regs) \
DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \ DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \
{.handler = (_handler)} {.action = (_handler)}
#define DECODE_EMULATE(_mask, _value, _handler) \ #define DECODE_EMULATE(_mask, _value, _handler) \
DECODE_EMULATEX(_mask, _value, _handler, 0) DECODE_EMULATEX(_mask, _value, _handler, 0)
...@@ -384,14 +397,18 @@ struct decode_reject { ...@@ -384,14 +397,18 @@ struct decode_reject {
#ifdef CONFIG_THUMB2_KERNEL #ifdef CONFIG_THUMB2_KERNEL
extern const union decode_item kprobe_decode_thumb16_table[]; extern const union decode_item kprobe_decode_thumb16_table[];
extern const union decode_item kprobe_decode_thumb32_table[]; extern const union decode_item kprobe_decode_thumb32_table[];
extern const union decode_action kprobes_t32_actions[];
extern const union decode_action kprobes_t16_actions[];
#else #else
extern const union decode_item kprobe_decode_arm_table[]; extern const union decode_item kprobe_decode_arm_table[];
extern const union decode_action kprobes_arm_actions[];
#endif #endif
extern kprobe_check_cc * const kprobe_condition_checks[16]; extern kprobe_check_cc * const kprobe_condition_checks[16];
int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
const union decode_item *table, bool thumb16); const union decode_item *table, bool thumb16,
const union decode_action *actions);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment