aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/kprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/kprobes.c')
-rw-r--r--arch/powerpc/kernel/kprobes.c71
1 files changed, 60 insertions, 11 deletions
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index cfab48566db1..ad7a90212204 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -1,6 +1,5 @@
1/* 1/*
2 * Kernel Probes (KProbes) 2 * Kernel Probes (KProbes)
3 * arch/ppc64/kernel/kprobes.c
4 * 3 *
5 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 5 * it under the terms of the GNU General Public License as published by
@@ -31,9 +30,11 @@
31#include <linux/kprobes.h> 30#include <linux/kprobes.h>
32#include <linux/ptrace.h> 31#include <linux/ptrace.h>
33#include <linux/preempt.h> 32#include <linux/preempt.h>
33#include <linux/module.h>
34#include <asm/cacheflush.h> 34#include <asm/cacheflush.h>
35#include <asm/kdebug.h> 35#include <asm/kdebug.h>
36#include <asm/sstep.h> 36#include <asm/sstep.h>
37#include <asm/uaccess.h>
37 38
38DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; 39DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
39DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); 40DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -82,9 +83,9 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
82 83
83void __kprobes arch_remove_kprobe(struct kprobe *p) 84void __kprobes arch_remove_kprobe(struct kprobe *p)
84{ 85{
85 down(&kprobe_mutex); 86 mutex_lock(&kprobe_mutex);
86 free_insn_slot(p->ainsn.insn); 87 free_insn_slot(p->ainsn.insn);
87 up(&kprobe_mutex); 88 mutex_unlock(&kprobe_mutex);
88} 89}
89 90
90static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 91static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
@@ -373,17 +374,62 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
373{ 374{
374 struct kprobe *cur = kprobe_running(); 375 struct kprobe *cur = kprobe_running();
375 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 376 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
376 377 const struct exception_table_entry *entry;
377 if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) 378
378 return 1; 379 switch(kcb->kprobe_status) {
379 380 case KPROBE_HIT_SS:
380 if (kcb->kprobe_status & KPROBE_HIT_SS) { 381 case KPROBE_REENTER:
381 resume_execution(cur, regs); 382 /*
383 * We are here because the instruction being single
384 * stepped caused a page fault. We reset the current
385 * kprobe and the nip points back to the probe address
386 * and allow the page fault handler to continue as a
387 * normal page fault.
388 */
389 regs->nip = (unsigned long)cur->addr;
382 regs->msr &= ~MSR_SE; 390 regs->msr &= ~MSR_SE;
383 regs->msr |= kcb->kprobe_saved_msr; 391 regs->msr |= kcb->kprobe_saved_msr;
384 392 if (kcb->kprobe_status == KPROBE_REENTER)
385 reset_current_kprobe(); 393 restore_previous_kprobe(kcb);
394 else
395 reset_current_kprobe();
386 preempt_enable_no_resched(); 396 preempt_enable_no_resched();
397 break;
398 case KPROBE_HIT_ACTIVE:
399 case KPROBE_HIT_SSDONE:
400 /*
401 * We increment the nmissed count for accounting,
402 * we can also use npre/npostfault count for accouting
403 * these specific fault cases.
404 */
405 kprobes_inc_nmissed_count(cur);
406
407 /*
408 * We come here because instructions in the pre/post
409 * handler caused the page_fault, this could happen
410 * if handler tries to access user space by
411 * copy_from_user(), get_user() etc. Let the
412 * user-specified handler try to fix it first.
413 */
414 if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
415 return 1;
416
417 /*
418 * In case the user-specified fault handler returned
419 * zero, try to fix up.
420 */
421 if ((entry = search_exception_tables(regs->nip)) != NULL) {
422 regs->nip = entry->fixup;
423 return 1;
424 }
425
426 /*
427 * fixup_exception() could not handle it,
428 * Let do_page_fault() fix it.
429 */
430 break;
431 default:
432 break;
387 } 433 }
388 return 0; 434 return 0;
389} 435}
@@ -397,6 +443,9 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
397 struct die_args *args = (struct die_args *)data; 443 struct die_args *args = (struct die_args *)data;
398 int ret = NOTIFY_DONE; 444 int ret = NOTIFY_DONE;
399 445
446 if (args->regs && user_mode(args->regs))
447 return ret;
448
400 switch (val) { 449 switch (val) {
401 case DIE_BPT: 450 case DIE_BPT:
402 if (kprobe_handler(args->regs)) 451 if (kprobe_handler(args->regs))