/* * Interrupts need to be disabled before single-step mode is set, * and not reenabled until after single-step mode ends. * Without disabling interrupt on local CPU, there is a chance of * interrupt occurrence in the period of exception return and start * of out-of-line single-step, that result in wrongly single stepping * into the interrupt handler.
*/ staticvoid save_local_irqflag(struct kprobe_ctlblk *kcb, struct pt_regs *regs)
{
kcb->saved_status = regs->csr_prmd;
regs->csr_prmd &= ~CSR_PRMD_PIE;
}
NOKPROBE_SYMBOL(save_local_irqflag);
/* restore back original saved kprobe variables and continue */ if (kcb->kprobe_status == KPROBE_REENTER) {
restore_previous_kprobe(kcb);
preempt_enable_no_resched(); return;
}
/* * update the kcb status even if the cur->post_handler is * not set because reset_curent_kprobe() doesn't update kcb.
*/
kcb->kprobe_status = KPROBE_HIT_SSDONE; if (cur->post_handler)
cur->post_handler(cur, regs, 0);
if (p->ainsn.insn) { /* IRQs and single stepping do not mix well */
save_local_irqflag(kcb, regs); /* set ip register to prepare for single stepping */
regs->csr_era = (unsignedlong)p->ainsn.insn;
} else { /* simulate single steping */
insn.word = p->opcode;
arch_simulate_insn(insn, regs); /* now go for post processing */
post_kprobe_handler(p, kcb, regs);
}
}
NOKPROBE_SYMBOL(setup_singlestep);
staticbool reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb)
{ switch (kcb->kprobe_status) { case KPROBE_HIT_SS: case KPROBE_HIT_SSDONE: case KPROBE_HIT_ACTIVE:
kprobes_inc_nmissed_count(p);
setup_singlestep(p, regs, kcb, 1); break; case KPROBE_REENTER:
pr_warn("Failed to recover from reentered kprobes.\n");
dump_kprobe(p);
WARN_ON_ONCE(1); break; default:
WARN_ON(1); returnfalse;
}
/* * We don't want to be preempted for the entire * duration of kprobe processing.
*/
preempt_disable();
kcb = get_kprobe_ctlblk();
cur_kprobe = kprobe_running();
p = get_kprobe(addr); if (p) { if (cur_kprobe) { if (reenter_kprobe(p, regs, kcb)) returntrue;
} else { /* Probe hit */
set_current_kprobe(p);
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
/* * If we have no pre-handler or it returned 0, we * continue with normal processing. If we have a * pre-handler and it returned non-zero, it will * modify the execution path and no need to single * stepping. Let's just reset current kprobe and exit. * * pre_handler can hit a breakpoint and can step thru * before return.
*/ if (!p->pre_handler || !p->pre_handler(p, regs)) {
setup_singlestep(p, regs, kcb, 0);
} else {
reset_current_kprobe();
preempt_enable_no_resched();
} returntrue;
}
}
if (*addr != KPROBE_BP_INSN) { /* * 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. * Return back to original instruction, and continue.
*/
regs->csr_era = (unsignedlong)addr;
preempt_enable_no_resched(); returntrue;
}
switch (kcb->kprobe_status) { case KPROBE_HIT_SS: case KPROBE_REENTER: /* * We are here because the instruction being single * stepped caused a page fault. We reset the current * kprobe and the ip points back to the probe address * and allow the page fault handler to continue as a * normal page fault.
*/
regs->csr_era = (unsignedlong)cur->addr;
WARN_ON_ONCE(!instruction_pointer(regs));
/* * Provide a blacklist of symbols identifying ranges which cannot be kprobed. * This blacklist is exposed to userspace via debugfs (kprobes/blacklist).
*/ int __init arch_populate_kprobe_blacklist(void)
{ return kprobe_add_area_blacklist((unsignedlong)__irqentry_text_start,
(unsignedlong)__irqentry_text_end);
}
int __init arch_init_kprobes(void)
{ return 0;
}
int arch_trampoline_kprobe(struct kprobe *p)
{ return 0;
}
NOKPROBE_SYMBOL(arch_trampoline_kprobe);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.