Commit b9599798 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Martin Schwidefsky
Browse files

[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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent ba640a59
Loading
Loading
Loading
Loading
+27 −32
Original line number Diff line number Diff line
@@ -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: