ARM kprobes: special hook for the kprobes breakpoint handler
authorNicolas Pitre <nico@cam.org>
Mon, 3 Dec 2007 22:22:36 +0000 (17:22 -0500)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sat, 26 Jan 2008 15:25:17 +0000 (15:25 +0000)
The kprobes code is already able to cope with reentrant probes, so its
handler must be called outside of the region protected by undef_lock.

If ever this lock is released when handlers are called then this commit
could be reverted.

Signed-off-by: Nicolas Pitre <nico@marvell.com>
arch/arm/kernel/kprobes.c
arch/arm/kernel/traps.c
include/asm-arm/kprobes.h

index 450ee2cbfe17ebfca26b856388c25880955f70c5..a22a98c43ca5911e9b8f9328509fbd4b9a973ca3 100644 (file)
 #include <asm/traps.h>
 #include <asm/cacheflush.h>
 
-/*
- * This undefined instruction must be unique and
- * reserved solely for kprobes' use.
- */
-#define KPROBE_BREAKPOINT_INSTRUCTION  0xe7f001f8
-
 #define MIN_STACK_SIZE(addr)                           \
        min((unsigned long)MAX_STACK_SIZE,              \
            (unsigned long)current_thread_info() + THREAD_START_SP - (addr))
@@ -206,7 +200,7 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
        }
 }
 
-static int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
+int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
 {
        kprobe_handler(regs);
        return 0;
index 65bb762b2d804fed04730ec6986e9bf88bb16bba..5595fdd75e8200ec0e8d5ea8a54c750ed0398e1f 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kallsyms.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/kprobes.h>
 
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
@@ -313,6 +314,17 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
                get_user(instr, (u32 __user *)pc);
        }
 
+#ifdef CONFIG_KPROBES
+       /*
+        * It is possible to have recursive kprobes, so we can't call
+        * the kprobe trap handler with the undef_lock held.
+        */
+       if (instr == KPROBE_BREAKPOINT_INSTRUCTION && !user_mode(regs)) {
+               kprobe_trap_handler(regs, instr);
+               return;
+       }
+#endif
+
        spin_lock_irqsave(&undef_lock, flags);
        list_for_each_entry(hook, &undef_hook, node) {
                if ((instr & hook->instr_mask) == hook->instr_val &&
index 273f37413ee6fd9cd2921775d6803d434a3fabaa..4e7bd32288ae6196a2fa5082173d5510cacd0b7a 100644 (file)
 #define MAX_INSN_SIZE                  2
 #define MAX_STACK_SIZE                 64      /* 32 would probably be OK */
 
+/*
+ * This undefined instruction must be unique and
+ * reserved solely for kprobes' use.
+ */
+#define KPROBE_BREAKPOINT_INSTRUCTION  0xe7f001f8
+
 #define regs_return_value(regs)                ((regs)->ARM_r0)
 #define flush_insn_slot(p)             do { } while (0)
 #define kretprobe_blacklist_size       0
@@ -55,6 +61,7 @@ struct kprobe_ctlblk {
 
 void arch_remove_kprobe(struct kprobe *);
 
+int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr);
 int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
 int kprobe_exceptions_notify(struct notifier_block *self,
                             unsigned long val, void *data);