staticvoid __kprobes resume_execution(struct kprobe *p, unsignedlong addr, struct pt_regs *regs)
{ /* Remove the trap instructions inserted for single step and * restore the original instructions
*/ if (p->ainsn.t1_addr) {
*(p->ainsn.t1_addr) = p->ainsn.t1_opcode;
/* Copy the opcode back to the kprobe location and execute the * instruction. Because of this we will not be able to get into the * same kprobe until this kprobe is done
*/
*(p->addr) = p->opcode;
/* Now we insert the trap at the next location after this instruction to * single step. If it is a branch we insert the trap at possible branch * targets
*/
bta = regs->bta;
if (regs->status32 & 0x40) { /* We are in a delay slot with the branch taken */
next_pc = bta & ~0x01;
if (!p->ainsn.is_short) { if (bta & 0x01)
regs->blink += 2; else { /* Branch not taken */
next_pc += 2;
/* next pc is taken from bta after executing the * delay slot instruction
*/
regs->bta += 2;
}
}
kcb = get_kprobe_ctlblk();
p = get_kprobe((unsignedlong *)addr);
if (p) { /* * We have reentered the kprobe_handler, since another kprobe * was hit while within the handler, we save the original * kprobes and single step on the instruction of the new probe * without calling any user handlers to avoid recursive * kprobes.
*/ if (kprobe_running()) {
save_previous_kprobe(kcb);
set_current_kprobe(p);
kprobes_inc_nmissed_count(p);
setup_singlestep(p, regs);
kcb->kprobe_status = KPROBE_REENTER; return 1;
}
/* 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 - which means user handler setup registers to exit * to another instruction, we must skip the single stepping.
*/ if (!p->pre_handler || !p->pre_handler(p, regs)) {
setup_singlestep(p, regs);
kcb->kprobe_status = KPROBE_HIT_SS;
} else {
reset_current_kprobe();
preempt_enable_no_resched();
}
/* * When we return from trap instruction we go to the next instruction * We restored the actual instruction in resume_exectuiont and we to * return to the same address and execute it
*/
regs->ret = addr;
if (kcb->kprobe_status == KPROBE_REENTER) {
restore_previous_kprobe(kcb); goto out;
}
reset_current_kprobe();
out:
preempt_enable_no_resched(); return 1;
}
/* * Fault can be for the instruction being single stepped or for the * pre/post handlers in the module. * This is applicable for applications like user probes, where we have the * probe in user space and the handlers in the kernel
*/
switch (kcb->kprobe_status) { case KPROBE_HIT_SS: case KPROBE_REENTER: /* * We are here because the instruction being single stepped * caused the fault. We reset the current kprobe and allow the * exception handler as if it is regular exception. In our * case it doesn't matter because the system will be halted
*/
resume_execution(cur, (unsignedlong)cur->addr, regs);
if (kcb->kprobe_status == KPROBE_REENTER)
restore_previous_kprobe(kcb); else
reset_current_kprobe();
preempt_enable_no_resched(); break;
case KPROBE_HIT_ACTIVE: case KPROBE_HIT_SSDONE: /* * We are here because the instructions in the pre/post handler * caused the fault.
*/
/* * In case the user-specified fault handler returned zero, * try to fix up.
*/ if (fixup_exception(regs)) return 1;
/* * fixup_exception() could not handle it, * Let do_page_fault() fix it.
*/ break;
default: break;
} return 0;
}
int __kprobes kprobe_exceptions_notify(struct notifier_block *self, unsignedlong val, void *data)
{ struct die_args *args = data; unsignedlong addr = args->err; int ret = NOTIFY_DONE;
switch (val) { case DIE_IERR: if (arc_kprobe_handler(addr, args->regs)) return NOTIFY_STOP; break;
case DIE_TRAP: if (arc_post_kprobe_handler(addr, args->regs)) return NOTIFY_STOP; break;
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.