in kernel/kprobes.c [695:791]
static int __kprobes pre_kprobes_handler(struct die_args *args)
{
struct kprobe *p;
int ret = 0;
struct pt_regs *regs = args->regs;
kprobe_opcode_t *addr = (kprobe_opcode_t *)instruction_pointer(regs);
struct kprobe_ctlblk *kcb;
/*
* We don't want to be preempted for the entire
* duration of kprobe processing
*/
preempt_disable();
kcb = get_kprobe_ctlblk();
/* Handle recursion cases */
if (kprobe_running()) {
p = get_kprobe(addr);
if (p) {
if ((kcb->kprobe_status == KPROBE_HIT_SS) &&
(p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) {
ia64_psr(regs)->ss = 0;
goto no_kprobe;
}
/* We have reentered the pre_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.
*/
save_previous_kprobe(kcb);
set_current_kprobe(p, kcb);
kprobes_inc_nmissed_count(p);
prepare_ss(p, regs);
kcb->kprobe_status = KPROBE_REENTER;
return 1;
} else if (!is_ia64_break_inst(regs)) {
/* The breakpoint instruction was removed by
* another cpu right after we hit, no further
* handling of this interrupt is appropriate
*/
ret = 1;
goto no_kprobe;
} else {
/* Not our break */
goto no_kprobe;
}
}
p = get_kprobe(addr);
if (!p) {
if (!is_ia64_break_inst(regs)) {
/*
* The breakpoint instruction was removed right
* after we hit it. Another cpu has removed
* either a probepoint or a debugger breakpoint
* at this address. In either case, no further
* handling of this interrupt is appropriate.
*/
ret = 1;
}
/* Not one of our break, let kernel handle it */
goto no_kprobe;
}
set_current_kprobe(p, kcb);
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
if (p->pre_handler && p->pre_handler(p, regs)) {
reset_current_kprobe();
preempt_enable_no_resched();
return 1;
}
#if !defined(CONFIG_PREEMPTION)
if (p->ainsn.inst_flag == INST_FLAG_BOOSTABLE && !p->post_handler) {
/* Boost up -- we can execute copied instructions directly */
ia64_psr(regs)->ri = p->ainsn.slot;
regs->cr_iip = (unsigned long)&p->ainsn.insn->bundle & ~0xFULL;
/* turn single stepping off */
ia64_psr(regs)->ss = 0;
reset_current_kprobe();
preempt_enable_no_resched();
return 1;
}
#endif
prepare_ss(p, regs);
kcb->kprobe_status = KPROBE_HIT_SS;
return 1;
no_kprobe:
preempt_enable_no_resched();
return ret;
}