aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnanth N Mavinakayanahalli <ananth@in.ibm.com>2005-11-07 04:00:10 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 10:53:45 -0500
commit0dc036c91ac11b2b76bb91b59d8c7af919aa4a8d (patch)
tree88318deadc78c7dd416b60f2fac4b8eef1f61a28
parent8a5c4dc5e5d72b7802f5647082ccf3861a94f013 (diff)
[PATCH] Kprobes: Track kprobe on a per_cpu basis - ppc64 changes
PPC64 changes to track kprobe execution on a per-cpu basis. We now track the kprobe state machine independently on each cpu using an arch specific kprobe control block. Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/ppc64/kernel/kprobes.c94
-rw-r--r--include/asm-powerpc/kprobes.h15
2 files changed, 69 insertions, 40 deletions
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c
index 6071ee99f5cb..3f89f3e5584a 100644
--- a/arch/ppc64/kernel/kprobes.c
+++ b/arch/ppc64/kernel/kprobes.c
@@ -37,12 +37,8 @@
37#include <asm/sstep.h> 37#include <asm/sstep.h>
38 38
39static DECLARE_MUTEX(kprobe_mutex); 39static DECLARE_MUTEX(kprobe_mutex);
40 40DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
41static struct kprobe *current_kprobe; 41DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
42static unsigned long kprobe_status, kprobe_saved_msr;
43static struct kprobe *kprobe_prev;
44static unsigned long kprobe_status_prev, kprobe_saved_msr_prev;
45static struct pt_regs jprobe_saved_regs;
46 42
47int __kprobes arch_prepare_kprobe(struct kprobe *p) 43int __kprobes arch_prepare_kprobe(struct kprobe *p)
48{ 44{
@@ -108,18 +104,25 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
108 regs->nip = (unsigned long)p->ainsn.insn; 104 regs->nip = (unsigned long)p->ainsn.insn;
109} 105}
110 106
111static inline void save_previous_kprobe(void) 107static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb)
108{
109 kcb->prev_kprobe.kp = kprobe_running();
110 kcb->prev_kprobe.status = kcb->kprobe_status;
111 kcb->prev_kprobe.saved_msr = kcb->kprobe_saved_msr;
112}
113
114static inline void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
112{ 115{
113 kprobe_prev = current_kprobe; 116 __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
114 kprobe_status_prev = kprobe_status; 117 kcb->kprobe_status = kcb->prev_kprobe.status;
115 kprobe_saved_msr_prev = kprobe_saved_msr; 118 kcb->kprobe_saved_msr = kcb->prev_kprobe.saved_msr;
116} 119}
117 120
118static inline void restore_previous_kprobe(void) 121static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
122 struct kprobe_ctlblk *kcb)
119{ 123{
120 current_kprobe = kprobe_prev; 124 __get_cpu_var(current_kprobe) = p;
121 kprobe_status = kprobe_status_prev; 125 kcb->kprobe_saved_msr = regs->msr;
122 kprobe_saved_msr = kprobe_saved_msr_prev;
123} 126}
124 127
125void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, 128void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
@@ -145,6 +148,7 @@ static inline int kprobe_handler(struct pt_regs *regs)
145 struct kprobe *p; 148 struct kprobe *p;
146 int ret = 0; 149 int ret = 0;
147 unsigned int *addr = (unsigned int *)regs->nip; 150 unsigned int *addr = (unsigned int *)regs->nip;
151 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
148 152
149 /* Check we're not actually recursing */ 153 /* Check we're not actually recursing */
150 if (kprobe_running()) { 154 if (kprobe_running()) {
@@ -153,10 +157,10 @@ static inline int kprobe_handler(struct pt_regs *regs)
153 p = get_kprobe(addr); 157 p = get_kprobe(addr);
154 if (p) { 158 if (p) {
155 kprobe_opcode_t insn = *p->ainsn.insn; 159 kprobe_opcode_t insn = *p->ainsn.insn;
156 if (kprobe_status == KPROBE_HIT_SS && 160 if (kcb->kprobe_status == KPROBE_HIT_SS &&
157 is_trap(insn)) { 161 is_trap(insn)) {
158 regs->msr &= ~MSR_SE; 162 regs->msr &= ~MSR_SE;
159 regs->msr |= kprobe_saved_msr; 163 regs->msr |= kcb->kprobe_saved_msr;
160 unlock_kprobes(); 164 unlock_kprobes();
161 goto no_kprobe; 165 goto no_kprobe;
162 } 166 }
@@ -166,15 +170,15 @@ static inline int kprobe_handler(struct pt_regs *regs)
166 * just single step on the instruction of the new probe 170 * just single step on the instruction of the new probe
167 * without calling any user handlers. 171 * without calling any user handlers.
168 */ 172 */
169 save_previous_kprobe(); 173 save_previous_kprobe(kcb);
170 current_kprobe = p; 174 set_current_kprobe(p, regs, kcb);
171 kprobe_saved_msr = regs->msr; 175 kcb->kprobe_saved_msr = regs->msr;
172 p->nmissed++; 176 p->nmissed++;
173 prepare_singlestep(p, regs); 177 prepare_singlestep(p, regs);
174 kprobe_status = KPROBE_REENTER; 178 kcb->kprobe_status = KPROBE_REENTER;
175 return 1; 179 return 1;
176 } else { 180 } else {
177 p = current_kprobe; 181 p = __get_cpu_var(current_kprobe);
178 if (p->break_handler && p->break_handler(p, regs)) { 182 if (p->break_handler && p->break_handler(p, regs)) {
179 goto ss_probe; 183 goto ss_probe;
180 } 184 }
@@ -214,16 +218,15 @@ static inline int kprobe_handler(struct pt_regs *regs)
214 * in post_kprobe_handler(). 218 * in post_kprobe_handler().
215 */ 219 */
216 preempt_disable(); 220 preempt_disable();
217 kprobe_status = KPROBE_HIT_ACTIVE; 221 kcb->kprobe_status = KPROBE_HIT_ACTIVE;
218 current_kprobe = p; 222 set_current_kprobe(p, regs, kcb);
219 kprobe_saved_msr = regs->msr;
220 if (p->pre_handler && p->pre_handler(p, regs)) 223 if (p->pre_handler && p->pre_handler(p, regs))
221 /* handler has already set things up, so skip ss setup */ 224 /* handler has already set things up, so skip ss setup */
222 return 1; 225 return 1;
223 226
224ss_probe: 227ss_probe:
225 prepare_singlestep(p, regs); 228 prepare_singlestep(p, regs);
226 kprobe_status = KPROBE_HIT_SS; 229 kcb->kprobe_status = KPROBE_HIT_SS;
227 return 1; 230 return 1;
228 231
229no_kprobe: 232no_kprobe:
@@ -292,6 +295,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
292 BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); 295 BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
293 regs->nip = orig_ret_address; 296 regs->nip = orig_ret_address;
294 297
298 reset_current_kprobe();
295 unlock_kprobes(); 299 unlock_kprobes();
296 preempt_enable_no_resched(); 300 preempt_enable_no_resched();
297 301
@@ -324,22 +328,26 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
324 328
325static inline int post_kprobe_handler(struct pt_regs *regs) 329static inline int post_kprobe_handler(struct pt_regs *regs)
326{ 330{
327 if (!kprobe_running()) 331 struct kprobe *cur = kprobe_running();
332 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
333
334 if (!cur)
328 return 0; 335 return 0;
329 336
330 if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { 337 if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
331 kprobe_status = KPROBE_HIT_SSDONE; 338 kcb->kprobe_status = KPROBE_HIT_SSDONE;
332 current_kprobe->post_handler(current_kprobe, regs, 0); 339 cur->post_handler(cur, regs, 0);
333 } 340 }
334 341
335 resume_execution(current_kprobe, regs); 342 resume_execution(cur, regs);
336 regs->msr |= kprobe_saved_msr; 343 regs->msr |= kcb->kprobe_saved_msr;
337 344
338 /*Restore back the original saved kprobes variables and continue. */ 345 /*Restore back the original saved kprobes variables and continue. */
339 if (kprobe_status == KPROBE_REENTER) { 346 if (kcb->kprobe_status == KPROBE_REENTER) {
340 restore_previous_kprobe(); 347 restore_previous_kprobe(kcb);
341 goto out; 348 goto out;
342 } 349 }
350 reset_current_kprobe();
343 unlock_kprobes(); 351 unlock_kprobes();
344out: 352out:
345 preempt_enable_no_resched(); 353 preempt_enable_no_resched();
@@ -358,15 +366,18 @@ out:
358/* Interrupts disabled, kprobe_lock held. */ 366/* Interrupts disabled, kprobe_lock held. */
359static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) 367static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
360{ 368{
361 if (current_kprobe->fault_handler 369 struct kprobe *cur = kprobe_running();
362 && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) 370 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
371
372 if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
363 return 1; 373 return 1;
364 374
365 if (kprobe_status & KPROBE_HIT_SS) { 375 if (kcb->kprobe_status & KPROBE_HIT_SS) {
366 resume_execution(current_kprobe, regs); 376 resume_execution(cur, regs);
367 regs->msr &= ~MSR_SE; 377 regs->msr &= ~MSR_SE;
368 regs->msr |= kprobe_saved_msr; 378 regs->msr |= kcb->kprobe_saved_msr;
369 379
380 reset_current_kprobe();
370 unlock_kprobes(); 381 unlock_kprobes();
371 preempt_enable_no_resched(); 382 preempt_enable_no_resched();
372 } 383 }
@@ -411,8 +422,9 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
411int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) 422int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
412{ 423{
413 struct jprobe *jp = container_of(p, struct jprobe, kp); 424 struct jprobe *jp = container_of(p, struct jprobe, kp);
425 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
414 426
415 memcpy(&jprobe_saved_regs, regs, sizeof(struct pt_regs)); 427 memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs));
416 428
417 /* setup return addr to the jprobe handler routine */ 429 /* setup return addr to the jprobe handler routine */
418 regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry); 430 regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry);
@@ -432,12 +444,14 @@ void __kprobes jprobe_return_end(void)
432 444
433int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) 445int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
434{ 446{
447 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
448
435 /* 449 /*
436 * FIXME - we should ideally be validating that we got here 'cos 450 * FIXME - we should ideally be validating that we got here 'cos
437 * of the "trap" in jprobe_return() above, before restoring the 451 * of the "trap" in jprobe_return() above, before restoring the
438 * saved regs... 452 * saved regs...
439 */ 453 */
440 memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs)); 454 memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs));
441 return 1; 455 return 1;
442} 456}
443 457
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index b2f09f17fbe0..6cd0a3bfa280 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -27,6 +27,7 @@
27 */ 27 */
28#include <linux/types.h> 28#include <linux/types.h>
29#include <linux/ptrace.h> 29#include <linux/ptrace.h>
30#include <linux/percpu.h>
30 31
31struct pt_regs; 32struct pt_regs;
32 33
@@ -53,6 +54,20 @@ struct arch_specific_insn {
53 kprobe_opcode_t *insn; 54 kprobe_opcode_t *insn;
54}; 55};
55 56
57struct prev_kprobe {
58 struct kprobe *kp;
59 unsigned long status;
60 unsigned long saved_msr;
61};
62
63/* per-cpu kprobe control block */
64struct kprobe_ctlblk {
65 unsigned long kprobe_status;
66 unsigned long kprobe_saved_msr;
67 struct pt_regs jprobe_saved_regs;
68 struct prev_kprobe prev_kprobe;
69};
70
56#ifdef CONFIG_KPROBES 71#ifdef CONFIG_KPROBES
57extern int kprobe_exceptions_notify(struct notifier_block *self, 72extern int kprobe_exceptions_notify(struct notifier_block *self,
58 unsigned long val, void *data); 73 unsigned long val, void *data);