aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPrasanna S Panchamukhi <prasanna@in.ibm.com>2006-03-26 04:38:25 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-26 11:57:04 -0500
commitc04c1c81e211c2c95b548add7923e1d4ba4847ab (patch)
tree15ce6f9c86785226e41b2385d4f8e6db7b48e980
parent50e21f2b2861711b6df0b72ffef4a70d1532b023 (diff)
[PATCH] kprobes: fix broken fault handling for ia64
Provide proper kprobes fault handling, if a user-specified pre/post handlers tries to access user address space, through copy_from_user(), get_user() etc. The user-specified fault handler gets called only if the fault occurs while executing user-specified handlers. In such a case user-specified handler is allowed to fix it first, later if the user-specifed fault handler does not fix it, we try to fix it by calling fix_exception(). The user-specified handler will not be called if the fault happens when single stepping the original instruction, instead we reset the current probe and allow the system page fault handler to fix it up. Signed-off-by: Prasanna S Panchamukhi <prasanna@in.ibm.com> Acked-by: Anil S Keshavamurthy<anil.s.keshavamurthy@intel.com> Cc: "Luck, Tony" <tony.luck@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/ia64/kernel/kprobes.c48
1 files changed, 43 insertions, 5 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 45b8479c9864..789881ca83d4 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -34,6 +34,7 @@
34#include <asm/pgtable.h> 34#include <asm/pgtable.h>
35#include <asm/kdebug.h> 35#include <asm/kdebug.h>
36#include <asm/sections.h> 36#include <asm/sections.h>
37#include <asm/uaccess.h>
37 38
38extern void jprobe_inst_return(void); 39extern void jprobe_inst_return(void);
39 40
@@ -722,13 +723,50 @@ static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr)
722 struct kprobe *cur = kprobe_running(); 723 struct kprobe *cur = kprobe_running();
723 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 724 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
724 725
725 if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
726 return 1;
727 726
728 if (kcb->kprobe_status & KPROBE_HIT_SS) { 727 switch(kcb->kprobe_status) {
729 resume_execution(cur, regs); 728 case KPROBE_HIT_SS:
730 reset_current_kprobe(); 729 case KPROBE_REENTER:
730 /*
731 * We are here because the instruction being single
732 * stepped caused a page fault. We reset the current
733 * kprobe and the instruction pointer points back to
734 * the probe address and allow the page fault handler
735 * to continue as a normal page fault.
736 */
737 regs->cr_iip = ((unsigned long)cur->addr) & ~0xFULL;
738 ia64_psr(regs)->ri = ((unsigned long)cur->addr) & 0xf;
739 if (kcb->kprobe_status == KPROBE_REENTER)
740 restore_previous_kprobe(kcb);
741 else
742 reset_current_kprobe();
731 preempt_enable_no_resched(); 743 preempt_enable_no_resched();
744 break;
745 case KPROBE_HIT_ACTIVE:
746 case KPROBE_HIT_SSDONE:
747 /*
748 * We increment the nmissed count for accounting,
749 * we can also use npre/npostfault count for accouting
750 * these specific fault cases.
751 */
752 kprobes_inc_nmissed_count(cur);
753
754 /*
755 * We come here because instructions in the pre/post
756 * handler caused the page_fault, this could happen
757 * if handler tries to access user space by
758 * copy_from_user(), get_user() etc. Let the
759 * user-specified handler try to fix it first.
760 */
761 if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
762 return 1;
763
764 /*
765 * Let ia64_do_page_fault() fix it.
766 */
767 break;
768 default:
769 break;
732 } 770 }
733 771
734 return 0; 772 return 0;