Commit 0e917cc3 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Martin Schwidefsky

[S390] kprobes: restructure handler function

Restructure the kprobe breakpoint handler function. Add comments to
make it more comprehensible and add a sanity check for re-entering
kprobes.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 92b8cbf1
...@@ -238,25 +238,44 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ...@@ -238,25 +238,44 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
regs->gprs[14] = (unsigned long)&kretprobe_trampoline; regs->gprs[14] = (unsigned long)&kretprobe_trampoline;
} }
static void __kprobes kprobe_reenter_check(struct kprobe_ctlblk *kcb,
struct kprobe *p)
{
switch (kcb->kprobe_status) {
case KPROBE_HIT_SSDONE:
case KPROBE_HIT_ACTIVE:
kprobes_inc_nmissed_count(p);
break;
case KPROBE_HIT_SS:
case KPROBE_REENTER:
default:
/*
* A kprobe on the code path to single step an instruction
* is a BUG. The code path resides in the .kprobes.text
* section and is executed with interrupts disabled.
*/
printk(KERN_EMERG "Invalid kprobe detected at %p.\n", p->addr);
dump_kprobe(p);
BUG();
}
}
static int __kprobes kprobe_handler(struct pt_regs *regs) static int __kprobes kprobe_handler(struct pt_regs *regs)
{ {
struct kprobe *p;
int ret = 0;
unsigned long *addr = (unsigned long *)
((regs->psw.addr & PSW_ADDR_INSN) - 2);
struct kprobe_ctlblk *kcb; struct kprobe_ctlblk *kcb;
struct kprobe *p;
/* /*
* We don't want to be preempted for the entire * We want to disable preemption for the entire duration of kprobe
* duration of kprobe processing * processing. That includes the calls to the pre/post handlers
* and single stepping the kprobe instruction.
*/ */
preempt_disable(); preempt_disable();
kcb = get_kprobe_ctlblk(); kcb = get_kprobe_ctlblk();
p = get_kprobe((void *)((regs->psw.addr & PSW_ADDR_INSN) - 2));
/* Check we're not actually recursing */
if (kprobe_running()) {
p = get_kprobe(addr);
if (p) { if (p) {
if (kprobe_running()) {
/* /*
* We have hit a kprobe while another is still * We have hit a kprobe while another is still
* active. This can happen in the pre and post * active. This can happen in the pre and post
...@@ -266,45 +285,54 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) ...@@ -266,45 +285,54 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
* push_kprobe and pop_kprobe saves and restores * push_kprobe and pop_kprobe saves and restores
* the currently active kprobe. * the currently active kprobe.
*/ */
kprobe_reenter_check(kcb, p);
push_kprobe(kcb, p); push_kprobe(kcb, p);
kprobes_inc_nmissed_count(p);
enable_singlestep(kcb, regs,
(unsigned long) p->ainsn.insn);
kcb->kprobe_status = KPROBE_REENTER; kcb->kprobe_status = KPROBE_REENTER;
return 1;
} else { } else {
p = __get_cpu_var(current_kprobe);
if (p->break_handler && p->break_handler(p, regs)) {
goto ss_probe;
}
}
goto no_kprobe;
}
p = get_kprobe(addr);
if (!p)
/* /*
* No kprobe at this address. The fault has not been * If we have no pre-handler or it returned 0, we
* caused by a kprobe breakpoint. The race of breakpoint * continue with single stepping. If we have a
* vs. kprobe remove does not exist because on s390 we * pre-handler and it returned non-zero, it prepped
* use stop_machine to arm/disarm the breakpoints. * for calling the break_handler below on re-entry
* for jprobe processing, so get out doing nothing
* more here.
*/ */
goto no_kprobe;
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
push_kprobe(kcb, p); push_kprobe(kcb, p);
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
if (p->pre_handler && p->pre_handler(p, regs)) if (p->pre_handler && p->pre_handler(p, regs))
/* handler has already set things up, so skip ss setup */
return 1; return 1;
kcb->kprobe_status = KPROBE_HIT_SS;
ss_probe: }
enable_singlestep(kcb, regs, (unsigned long) p->ainsn.insn); enable_singlestep(kcb, regs, (unsigned long) p->ainsn.insn);
return 1;
} else if (kprobe_running()) {
p = __get_cpu_var(current_kprobe);
if (p->break_handler && p->break_handler(p, regs)) {
/*
* Continuation after the jprobe completed and
* caused the jprobe_return trap. The jprobe
* break_handler "returns" to the original
* function that still has the kprobe breakpoint
* installed. We continue with single stepping.
*/
kcb->kprobe_status = KPROBE_HIT_SS; kcb->kprobe_status = KPROBE_HIT_SS;
enable_singlestep(kcb, regs,
(unsigned long) p->ainsn.insn);
return 1; return 1;
} /* else:
no_kprobe: * No kprobe at this address and the current kprobe
* has no break handler (no jprobe!). The kernel just
* exploded, let the standard trap handler pick up the
* pieces.
*/
} /* else:
* No kprobe at this address and no active kprobe. The trap has
* not been caused by a kprobe breakpoint. The race of breakpoint
* vs. kprobe remove does not exist because on s390 as we use
* stop_machine to arm/disarm the breakpoints.
*/
preempt_enable_no_resched(); preempt_enable_no_resched();
return ret; return 0;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment