ARM: kprobes: Extend arch_specific_insn to add pointer to emulated instruction
authorJon Medhurst <tixy@yxit.co.uk>
Thu, 9 Jun 2011 13:05:51 +0000 (14:05 +0100)
committerTixy <tixy@medhuaa1.miniserver.com>
Wed, 13 Jul 2011 17:32:42 +0000 (17:32 +0000)
When we come to emulating Thumb instructions then, to interwork
correctly, the code on in the instruction slot must be invoked with a
function pointer which has the least significant bit set. Rather that
set this by hand in every Thumb emulation function we will add a new
field for this purpose to arch_specific_insn, called insn_fn.

This also enables us to seamlessly share emulation functions between ARM
and Thumb code.

Signed-off-by: Jon Medhurst <tixy@yxit.co.uk>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
arch/arm/include/asm/kprobes.h
arch/arm/kernel/kprobes.c

index 1e9ff56..feec867 100644 (file)
@@ -34,6 +34,7 @@ struct kprobe;
 typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *);
 typedef unsigned long (kprobe_check_cc)(unsigned long);
 typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *);
+typedef void (kprobe_insn_fn_t)(void);
 
 /* Architecture specific copy of original instruction. */
 struct arch_specific_insn {
@@ -41,6 +42,7 @@ struct arch_specific_insn {
        kprobe_insn_handler_t           *insn_handler;
        kprobe_check_cc                 *insn_check_cc;
        kprobe_insn_singlestep_t        *insn_singlestep;
+       kprobe_insn_fn_t                *insn_fn;
 };
 
 struct prev_kprobe {
index 77b7c69..129c116 100644 (file)
@@ -51,6 +51,7 @@ 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;
        int is;
 
@@ -58,6 +59,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
                return -EINVAL;
 
 #ifdef CONFIG_THUMB2_KERNEL
+       thumb = true;
        addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
        insn = ((u16 *)addr)[0];
        if (is_wide_instruction(insn)) {
@@ -67,6 +69,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
        } else
                decode_insn = thumb16_kprobe_decode_insn;
 #else /* !CONFIG_THUMB2_KERNEL */
+       thumb = false;
        if (addr & 0x3)
                return -EINVAL;
        insn = *p->addr;
@@ -88,6 +91,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
                        p->ainsn.insn[is] = tmp_insn[is];
                flush_insns(p->ainsn.insn,
                                sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE);
+               p->ainsn.insn_fn = (kprobe_insn_fn_t *)
+                                       ((uintptr_t)p->ainsn.insn | thumb);
                break;
 
        case INSN_GOOD_NO_SLOT: /* instruction doesn't need insn slot */