aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2007-12-03 17:22:36 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-01-26 10:25:17 -0500
commit796969104cab0d454dbc792ad0d12a4f365a8564 (patch)
tree214eebbe0c8cdee597184feb365c60b574650f6a
parent785d3cd286f0bf67d1bf692559b9ae5de12678f5 (diff)
ARM kprobes: special hook for the kprobes breakpoint handler
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>
-rw-r--r--arch/arm/kernel/kprobes.c8
-rw-r--r--arch/arm/kernel/traps.c12
-rw-r--r--include/asm-arm/kprobes.h7
3 files changed, 20 insertions, 7 deletions
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
index 450ee2cbfe17..a22a98c43ca5 100644
--- a/arch/arm/kernel/kprobes.c
+++ b/arch/arm/kernel/kprobes.c
@@ -26,12 +26,6 @@
26#include <asm/traps.h> 26#include <asm/traps.h>
27#include <asm/cacheflush.h> 27#include <asm/cacheflush.h>
28 28
29/*
30 * This undefined instruction must be unique and
31 * reserved solely for kprobes' use.
32 */
33#define KPROBE_BREAKPOINT_INSTRUCTION 0xe7f001f8
34
35#define MIN_STACK_SIZE(addr) \ 29#define MIN_STACK_SIZE(addr) \
36 min((unsigned long)MAX_STACK_SIZE, \ 30 min((unsigned long)MAX_STACK_SIZE, \
37 (unsigned long)current_thread_info() + THREAD_START_SP - (addr)) 31 (unsigned long)current_thread_info() + THREAD_START_SP - (addr))
@@ -206,7 +200,7 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
206 } 200 }
207} 201}
208 202
209static int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr) 203int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
210{ 204{
211 kprobe_handler(regs); 205 kprobe_handler(regs);
212 return 0; 206 return 0;
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 65bb762b2d80..5595fdd75e82 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -19,6 +19,7 @@
19#include <linux/kallsyms.h> 19#include <linux/kallsyms.h>
20#include <linux/delay.h> 20#include <linux/delay.h>
21#include <linux/init.h> 21#include <linux/init.h>
22#include <linux/kprobes.h>
22 23
23#include <asm/atomic.h> 24#include <asm/atomic.h>
24#include <asm/cacheflush.h> 25#include <asm/cacheflush.h>
@@ -313,6 +314,17 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
313 get_user(instr, (u32 __user *)pc); 314 get_user(instr, (u32 __user *)pc);
314 } 315 }
315 316
317#ifdef CONFIG_KPROBES
318 /*
319 * It is possible to have recursive kprobes, so we can't call
320 * the kprobe trap handler with the undef_lock held.
321 */
322 if (instr == KPROBE_BREAKPOINT_INSTRUCTION && !user_mode(regs)) {
323 kprobe_trap_handler(regs, instr);
324 return;
325 }
326#endif
327
316 spin_lock_irqsave(&undef_lock, flags); 328 spin_lock_irqsave(&undef_lock, flags);
317 list_for_each_entry(hook, &undef_hook, node) { 329 list_for_each_entry(hook, &undef_hook, node) {
318 if ((instr & hook->instr_mask) == hook->instr_val && 330 if ((instr & hook->instr_mask) == hook->instr_val &&
diff --git a/include/asm-arm/kprobes.h b/include/asm-arm/kprobes.h
index 273f37413ee6..4e7bd32288ae 100644
--- a/include/asm-arm/kprobes.h
+++ b/include/asm-arm/kprobes.h
@@ -25,6 +25,12 @@
25#define MAX_INSN_SIZE 2 25#define MAX_INSN_SIZE 2
26#define MAX_STACK_SIZE 64 /* 32 would probably be OK */ 26#define MAX_STACK_SIZE 64 /* 32 would probably be OK */
27 27
28/*
29 * This undefined instruction must be unique and
30 * reserved solely for kprobes' use.
31 */
32#define KPROBE_BREAKPOINT_INSTRUCTION 0xe7f001f8
33
28#define regs_return_value(regs) ((regs)->ARM_r0) 34#define regs_return_value(regs) ((regs)->ARM_r0)
29#define flush_insn_slot(p) do { } while (0) 35#define flush_insn_slot(p) do { } while (0)
30#define kretprobe_blacklist_size 0 36#define kretprobe_blacklist_size 0
@@ -55,6 +61,7 @@ struct kprobe_ctlblk {
55 61
56void arch_remove_kprobe(struct kprobe *); 62void arch_remove_kprobe(struct kprobe *);
57 63
64int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr);
58int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr); 65int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
59int kprobe_exceptions_notify(struct notifier_block *self, 66int kprobe_exceptions_notify(struct notifier_block *self,
60 unsigned long val, void *data); 67 unsigned long val, void *data);