|
@@ -30,6 +30,7 @@
|
|
|
#include <asm/sections.h>
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/slab.h>
|
|
|
+#include <linux/hardirq.h>
|
|
|
|
|
|
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
|
|
|
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
|
|
@@ -212,7 +213,7 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
|
|
|
/* Set the PER control regs, turns on single step for this address */
|
|
|
__ctl_load(kprobe_per_regs, 9, 11);
|
|
|
regs->psw.mask |= PSW_MASK_PER;
|
|
|
- regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
|
|
|
+ regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
|
|
|
}
|
|
|
|
|
|
static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
|
|
@@ -239,7 +240,7 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
|
|
|
__get_cpu_var(current_kprobe) = p;
|
|
|
/* Save the interrupt and per flags */
|
|
|
kcb->kprobe_saved_imask = regs->psw.mask &
|
|
|
- (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
|
|
|
+ (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);
|
|
|
/* Save the control regs that govern PER */
|
|
|
__ctl_store(kcb->kprobe_saved_ctl, 9, 11);
|
|
|
}
|
|
@@ -316,8 +317,6 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
|
|
|
return 1;
|
|
|
|
|
|
ss_probe:
|
|
|
- if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
|
|
|
- local_irq_disable();
|
|
|
prepare_singlestep(p, regs);
|
|
|
kcb->kprobe_status = KPROBE_HIT_SS;
|
|
|
return 1;
|
|
@@ -465,8 +464,6 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
|
|
|
goto out;
|
|
|
}
|
|
|
reset_current_kprobe();
|
|
|
- if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
|
|
|
- local_irq_enable();
|
|
|
out:
|
|
|
preempt_enable_no_resched();
|
|
|
|
|
@@ -482,7 +479,7 @@ out:
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
|
|
+static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
|
|
|
{
|
|
|
struct kprobe *cur = kprobe_running();
|
|
|
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
|
@@ -508,8 +505,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
|
|
restore_previous_kprobe(kcb);
|
|
|
else {
|
|
|
reset_current_kprobe();
|
|
|
- if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
|
|
|
- local_irq_enable();
|
|
|
}
|
|
|
preempt_enable_no_resched();
|
|
|
break;
|
|
@@ -553,6 +548,18 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
|
|
|
+ local_irq_disable();
|
|
|
+ ret = kprobe_trap_handler(regs, trapnr);
|
|
|
+ if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
|
|
|
+ local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Wrapper routine to for handling exceptions.
|
|
|
*/
|
|
@@ -560,8 +567,12 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
|
|
|
unsigned long val, void *data)
|
|
|
{
|
|
|
struct die_args *args = (struct die_args *)data;
|
|
|
+ struct pt_regs *regs = args->regs;
|
|
|
int ret = NOTIFY_DONE;
|
|
|
|
|
|
+ if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
|
|
|
+ local_irq_disable();
|
|
|
+
|
|
|
switch (val) {
|
|
|
case DIE_BPT:
|
|
|
if (kprobe_handler(args->regs))
|
|
@@ -572,16 +583,17 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
|
|
|
ret = NOTIFY_STOP;
|
|
|
break;
|
|
|
case DIE_TRAP:
|
|
|
- /* kprobe_running() needs smp_processor_id() */
|
|
|
- preempt_disable();
|
|
|
- if (kprobe_running() &&
|
|
|
- kprobe_fault_handler(args->regs, args->trapnr))
|
|
|
+ if (!preemptible() && kprobe_running() &&
|
|
|
+ kprobe_trap_handler(args->regs, args->trapnr))
|
|
|
ret = NOTIFY_STOP;
|
|
|
- preempt_enable();
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
+ if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
|
|
|
+ local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
|
|
|
+
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -595,6 +607,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
|
|
|
|
|
/* setup return addr to the jprobe handler routine */
|
|
|
regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE;
|
|
|
+ regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
|
|
|
|
|
|
/* r14 is the function return address */
|
|
|
kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14];
|