From b9599798f953084774da926caa8bafd7e244948e Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 5 Jan 2011 12:47:20 +0100 Subject: [PATCH] [S390] kprobes: activation and deactivation Replace set_current_kprobe/reset_current_kprobe/save_previous_kprobe/ restore_previous_kprobe with a simpler scheme push_kprobe/pop_kprobe. The mini kprobes stack can store up to two active kprobes. Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/kprobes.c | 59 +++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index fcbc25836879..f68eaaaa8062 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -214,25 +214,29 @@ static void __kprobes disable_singlestep(struct kprobe_ctlblk *kcb, regs->psw.addr = ip | PSW_ADDR_AMODE; } - -static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) +/* + * Activate a kprobe by storing its pointer to current_kprobe. The + * previous kprobe is stored in kcb->prev_kprobe. A stack of up to + * two kprobes can be active, see KPROBE_REENTER. + */ +static void __kprobes push_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p) { - kcb->prev_kprobe.kp = kprobe_running(); + kcb->prev_kprobe.kp = __get_cpu_var(current_kprobe); kcb->prev_kprobe.status = kcb->kprobe_status; + __get_cpu_var(current_kprobe) = p; } -static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) +/* + * Deactivate a kprobe by backing up to the previous state. If the + * current state is KPROBE_REENTER prev_kprobe.kp will be non-NULL, + * for any other state prev_kprobe.kp will be NULL. + */ +static void __kprobes pop_kprobe(struct kprobe_ctlblk *kcb) { __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; kcb->kprobe_status = kcb->prev_kprobe.status; } -static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, - struct kprobe_ctlblk *kcb) -{ - __get_cpu_var(current_kprobe) = p; -} - void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { @@ -261,14 +265,16 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) if (kprobe_running()) { p = get_kprobe(addr); if (p) { - /* We have reentered the kprobe_handler(), since - * another probe was hit while within the handler. - * We here save the original kprobes variables and - * just single step on the instruction of the new probe - * without calling any user handlers. + /* + * We have hit a kprobe while another is still + * active. This can happen in the pre and post + * handler. Single step the instruction of the + * new probe but do not call any handler function + * of this secondary kprobe. + * push_kprobe and pop_kprobe saves and restores + * the currently active kprobe. */ - save_previous_kprobe(kcb); - set_current_kprobe(p, regs, kcb); + push_kprobe(kcb, p); kprobes_inc_nmissed_count(p); enable_singlestep(kcb, regs, (unsigned long) p->ainsn.insn); @@ -294,7 +300,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) goto no_kprobe; kcb->kprobe_status = KPROBE_HIT_ACTIVE; - set_current_kprobe(p, regs, kcb); + push_kprobe(kcb, p); if (p->pre_handler && p->pre_handler(p, regs)) /* handler has already set things up, so skip ss setup */ return 1; @@ -395,7 +401,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE; - reset_current_kprobe(); + pop_kprobe(get_kprobe_ctlblk()); kretprobe_hash_unlock(current, &flags); preempt_enable_no_resched(); @@ -457,14 +463,7 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) } resume_execution(cur, regs); - - /*Restore back the original saved kprobes variables and continue. */ - if (kcb->kprobe_status == KPROBE_REENTER) { - restore_previous_kprobe(kcb); - goto out; - } - reset_current_kprobe(); -out: + pop_kprobe(kcb); preempt_enable_no_resched(); /* @@ -499,11 +498,7 @@ static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr) * normal page fault. */ disable_singlestep(kcb, regs, (unsigned long) cur->addr); - if (kcb->kprobe_status == KPROBE_REENTER) - restore_previous_kprobe(kcb); - else { - reset_current_kprobe(); - } + pop_kprobe(kcb); preempt_enable_no_resched(); break; case KPROBE_HIT_ACTIVE: