aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/i386/kernel/kprobes.c19
-rw-r--r--arch/ppc64/kernel/kprobes.c19
-rw-r--r--arch/sparc64/kernel/kprobes.c31
-rw-r--r--arch/x86_64/kernel/kprobes.c26
-rw-r--r--include/linux/kprobes.h2
-rw-r--r--kernel/kprobes.c12
6 files changed, 72 insertions, 37 deletions
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index 048f754bbe23..2314d8d306fd 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -33,6 +33,7 @@
33#include <linux/ptrace.h> 33#include <linux/ptrace.h>
34#include <linux/spinlock.h> 34#include <linux/spinlock.h>
35#include <linux/preempt.h> 35#include <linux/preempt.h>
36#include <asm/cacheflush.h>
36#include <asm/kdebug.h> 37#include <asm/kdebug.h>
37#include <asm/desc.h> 38#include <asm/desc.h>
38 39
@@ -71,16 +72,25 @@ int arch_prepare_kprobe(struct kprobe *p)
71void arch_copy_kprobe(struct kprobe *p) 72void arch_copy_kprobe(struct kprobe *p)
72{ 73{
73 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); 74 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
75 p->opcode = *p->addr;
74} 76}
75 77
76void arch_remove_kprobe(struct kprobe *p) 78void arch_arm_kprobe(struct kprobe *p)
77{ 79{
80 *p->addr = BREAKPOINT_INSTRUCTION;
81 flush_icache_range((unsigned long) p->addr,
82 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
78} 83}
79 84
80static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) 85void arch_disarm_kprobe(struct kprobe *p)
81{ 86{
82 *p->addr = p->opcode; 87 *p->addr = p->opcode;
83 regs->eip = (unsigned long)p->addr; 88 flush_icache_range((unsigned long) p->addr,
89 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
90}
91
92void arch_remove_kprobe(struct kprobe *p)
93{
84} 94}
85 95
86static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 96static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
@@ -177,7 +187,8 @@ static int kprobe_handler(struct pt_regs *regs)
177 unlock_kprobes(); 187 unlock_kprobes();
178 goto no_kprobe; 188 goto no_kprobe;
179 } 189 }
180 disarm_kprobe(p, regs); 190 arch_disarm_kprobe(p);
191 regs->eip = (unsigned long)p->addr;
181 ret = 1; 192 ret = 1;
182 } else { 193 } else {
183 p = current_kprobe; 194 p = current_kprobe;
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c
index e950a2058a19..8c0920a6d03e 100644
--- a/arch/ppc64/kernel/kprobes.c
+++ b/arch/ppc64/kernel/kprobes.c
@@ -32,6 +32,7 @@
32#include <linux/ptrace.h> 32#include <linux/ptrace.h>
33#include <linux/spinlock.h> 33#include <linux/spinlock.h>
34#include <linux/preempt.h> 34#include <linux/preempt.h>
35#include <asm/cacheflush.h>
35#include <asm/kdebug.h> 36#include <asm/kdebug.h>
36#include <asm/sstep.h> 37#include <asm/sstep.h>
37 38
@@ -61,16 +62,25 @@ int arch_prepare_kprobe(struct kprobe *p)
61void arch_copy_kprobe(struct kprobe *p) 62void arch_copy_kprobe(struct kprobe *p)
62{ 63{
63 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); 64 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
65 p->opcode = *p->addr;
64} 66}
65 67
66void arch_remove_kprobe(struct kprobe *p) 68void arch_arm_kprobe(struct kprobe *p)
67{ 69{
70 *p->addr = BREAKPOINT_INSTRUCTION;
71 flush_icache_range((unsigned long) p->addr,
72 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
68} 73}
69 74
70static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) 75void arch_disarm_kprobe(struct kprobe *p)
71{ 76{
72 *p->addr = p->opcode; 77 *p->addr = p->opcode;
73 regs->nip = (unsigned long)p->addr; 78 flush_icache_range((unsigned long) p->addr,
79 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
80}
81
82void arch_remove_kprobe(struct kprobe *p)
83{
74} 84}
75 85
76static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 86static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
@@ -101,7 +111,8 @@ static inline int kprobe_handler(struct pt_regs *regs)
101 unlock_kprobes(); 111 unlock_kprobes();
102 goto no_kprobe; 112 goto no_kprobe;
103 } 113 }
104 disarm_kprobe(p, regs); 114 arch_disarm_kprobe(p);
115 regs->nip = (unsigned long)p->addr;
105 ret = 1; 116 ret = 1;
106 } else { 117 } else {
107 p = current_kprobe; 118 p = current_kprobe;
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index 7066d7ba667a..d67195ba3fa2 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -6,7 +6,6 @@
6#include <linux/config.h> 6#include <linux/config.h>
7#include <linux/kernel.h> 7#include <linux/kernel.h>
8#include <linux/kprobes.h> 8#include <linux/kprobes.h>
9
10#include <asm/kdebug.h> 9#include <asm/kdebug.h>
11#include <asm/signal.h> 10#include <asm/signal.h>
12 11
@@ -47,6 +46,19 @@ void arch_copy_kprobe(struct kprobe *p)
47{ 46{
48 p->ainsn.insn[0] = *p->addr; 47 p->ainsn.insn[0] = *p->addr;
49 p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2; 48 p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
49 p->opcode = *p->addr;
50}
51
52void arch_arm_kprobe(struct kprobe *p)
53{
54 *p->addr = BREAKPOINT_INSTRUCTION;
55 flushi(p->addr);
56}
57
58void arch_disarm_kprobe(struct kprobe *p)
59{
60 *p->addr = p->opcode;
61 flushi(p->addr);
50} 62}
51 63
52void arch_remove_kprobe(struct kprobe *p) 64void arch_remove_kprobe(struct kprobe *p)
@@ -78,17 +90,6 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
78 } 90 }
79} 91}
80 92
81static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
82{
83 *p->addr = p->opcode;
84 flushi(p->addr);
85
86 regs->tpc = (unsigned long) p->addr;
87 regs->tnpc = current_kprobe_orig_tnpc;
88 regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
89 current_kprobe_orig_tstate_pil);
90}
91
92static int kprobe_handler(struct pt_regs *regs) 93static int kprobe_handler(struct pt_regs *regs)
93{ 94{
94 struct kprobe *p; 95 struct kprobe *p;
@@ -109,7 +110,11 @@ static int kprobe_handler(struct pt_regs *regs)
109 unlock_kprobes(); 110 unlock_kprobes();
110 goto no_kprobe; 111 goto no_kprobe;
111 } 112 }
112 disarm_kprobe(p, regs); 113 arch_disarm_kprobe(p);
114 regs->tpc = (unsigned long) p->addr;
115 regs->tnpc = current_kprobe_orig_tnpc;
116 regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
117 current_kprobe_orig_tstate_pil);
113 ret = 1; 118 ret = 1;
114 } else { 119 } else {
115 p = current_kprobe; 120 p = current_kprobe;
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index 203672ca7401..324bf57925a9 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -39,7 +39,7 @@
39#include <linux/slab.h> 39#include <linux/slab.h>
40#include <linux/preempt.h> 40#include <linux/preempt.h>
41#include <linux/moduleloader.h> 41#include <linux/moduleloader.h>
42 42#include <asm/cacheflush.h>
43#include <asm/pgtable.h> 43#include <asm/pgtable.h>
44#include <asm/kdebug.h> 44#include <asm/kdebug.h>
45 45
@@ -216,19 +216,28 @@ void arch_copy_kprobe(struct kprobe *p)
216 BUG_ON((s64) (s32) disp != disp); /* Sanity check. */ 216 BUG_ON((s64) (s32) disp != disp); /* Sanity check. */
217 *ripdisp = disp; 217 *ripdisp = disp;
218 } 218 }
219 p->opcode = *p->addr;
219} 220}
220 221
221void arch_remove_kprobe(struct kprobe *p) 222void arch_arm_kprobe(struct kprobe *p)
222{ 223{
223 up(&kprobe_mutex); 224 *p->addr = BREAKPOINT_INSTRUCTION;
224 free_insn_slot(p->ainsn.insn); 225 flush_icache_range((unsigned long) p->addr,
225 down(&kprobe_mutex); 226 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
226} 227}
227 228
228static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs) 229void arch_disarm_kprobe(struct kprobe *p)
229{ 230{
230 *p->addr = p->opcode; 231 *p->addr = p->opcode;
231 regs->rip = (unsigned long)p->addr; 232 flush_icache_range((unsigned long) p->addr,
233 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
234}
235
236void arch_remove_kprobe(struct kprobe *p)
237{
238 up(&kprobe_mutex);
239 free_insn_slot(p->ainsn.insn);
240 down(&kprobe_mutex);
232} 241}
233 242
234static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 243static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
@@ -311,7 +320,8 @@ int kprobe_handler(struct pt_regs *regs)
311 unlock_kprobes(); 320 unlock_kprobes();
312 goto no_kprobe; 321 goto no_kprobe;
313 } 322 }
314 disarm_kprobe(p, regs); 323 arch_disarm_kprobe(p);
324 regs->rip = (unsigned long)p->addr;
315 ret = 1; 325 ret = 1;
316 } else { 326 } else {
317 p = current_kprobe; 327 p = current_kprobe;
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index fba39f87efec..0f90466fb8b0 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -165,6 +165,8 @@ static inline int kprobe_running(void)
165 165
166extern int arch_prepare_kprobe(struct kprobe *p); 166extern int arch_prepare_kprobe(struct kprobe *p);
167extern void arch_copy_kprobe(struct kprobe *p); 167extern void arch_copy_kprobe(struct kprobe *p);
168extern void arch_arm_kprobe(struct kprobe *p);
169extern void arch_disarm_kprobe(struct kprobe *p);
168extern void arch_remove_kprobe(struct kprobe *p); 170extern void arch_remove_kprobe(struct kprobe *p);
169extern void show_registers(struct pt_regs *regs); 171extern void show_registers(struct pt_regs *regs);
170 172
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 692fbf75ab49..e8e0ae8a6e14 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -261,7 +261,7 @@ static inline void free_rp_inst(struct kretprobe *rp)
261static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p) 261static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
262{ 262{
263 ap->addr = p->addr; 263 ap->addr = p->addr;
264 ap->opcode = p->opcode; 264 memcpy(&ap->opcode, &p->opcode, sizeof(kprobe_opcode_t));
265 memcpy(&ap->ainsn, &p->ainsn, sizeof(struct arch_specific_insn)); 265 memcpy(&ap->ainsn, &p->ainsn, sizeof(struct arch_specific_insn));
266 266
267 ap->pre_handler = aggr_pre_handler; 267 ap->pre_handler = aggr_pre_handler;
@@ -304,10 +304,8 @@ static int register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p)
304/* kprobe removal house-keeping routines */ 304/* kprobe removal house-keeping routines */
305static inline void cleanup_kprobe(struct kprobe *p, unsigned long flags) 305static inline void cleanup_kprobe(struct kprobe *p, unsigned long flags)
306{ 306{
307 *p->addr = p->opcode; 307 arch_disarm_kprobe(p);
308 hlist_del(&p->hlist); 308 hlist_del(&p->hlist);
309 flush_icache_range((unsigned long) p->addr,
310 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
311 spin_unlock_irqrestore(&kprobe_lock, flags); 309 spin_unlock_irqrestore(&kprobe_lock, flags);
312 arch_remove_kprobe(p); 310 arch_remove_kprobe(p);
313} 311}
@@ -344,10 +342,8 @@ int register_kprobe(struct kprobe *p)
344 hlist_add_head(&p->hlist, 342 hlist_add_head(&p->hlist,
345 &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]); 343 &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
346 344
347 p->opcode = *p->addr; 345 arch_arm_kprobe(p);
348 *p->addr = BREAKPOINT_INSTRUCTION; 346
349 flush_icache_range((unsigned long) p->addr,
350 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
351out: 347out:
352 spin_unlock_irqrestore(&kprobe_lock, flags); 348 spin_unlock_irqrestore(&kprobe_lock, flags);
353rm_kprobe: 349rm_kprobe: