len = insn_length(*p->addr >> 8);
memcpy(&insn, p->addr, len);
p->opcode = insn[0]; if (probe_is_insn_relative_long(&insn[0])) { /* * For pc-relative instructions in RIL-b or RIL-c format patch * the RI2 displacement field. The insn slot for the to be * patched instruction is within the same 4GB area like the * original instruction. Therefore the new displacement will * always fit.
*/
disp = *(s32 *)&insn[1];
addr = (u64)(unsignedlong)p->addr;
new_addr = (u64)(unsignedlong)p->ainsn.insn;
new_disp = ((addr + (disp * 2)) - new_addr) / 2;
*(s32 *)&insn[1] = new_disp;
}
s390_kernel_write(p->ainsn.insn, &insn, len);
}
NOKPROBE_SYMBOL(copy_instruction);
/* Check if paddr is at an instruction boundary */ staticbool can_probe(unsignedlong paddr)
{ unsignedlong addr, offset = 0;
kprobe_opcode_t insn; struct kprobe *kp;
if (paddr & 0x01) returnfalse;
if (!kallsyms_lookup_size_offset(paddr, NULL, &offset)) returnfalse;
/* Decode instructions */
addr = paddr - offset; while (addr < paddr) { if (copy_from_kernel_nofault(&insn, (void *)addr, sizeof(insn))) returnfalse;
if (insn >> 8 == 0) { if (insn != BREAKPOINT_INSTRUCTION) { /* * Note that QEMU inserts opcode 0x0000 to implement * software breakpoints for guests. Since the size of * the original instruction is unknown, stop following * instructions and prevent setting a kprobe.
*/ returnfalse;
} /* * Check if the instruction has been modified by another * kprobe, in which case the original instruction is * decoded.
*/
kp = get_kprobe((void *)addr); if (!kp) { /* not a kprobe */ returnfalse;
}
insn = kp->opcode;
}
addr += insn_length(insn >> 8);
} return addr == paddr;
}
int arch_prepare_kprobe(struct kprobe *p)
{ if (!can_probe((unsignedlong)p->addr)) return -EINVAL; /* Make sure the probe isn't going on a difficult instruction */ if (probe_is_prohibited_opcode(p->addr)) return -EINVAL;
p->ainsn.insn = get_insn_slot(); if (!p->ainsn.insn) return -ENOMEM;
copy_instruction(p); return 0;
}
NOKPROBE_SYMBOL(arch_prepare_kprobe);
/* Set up the PER control registers %cr9-%cr11 */
per_kprobe.control.val = PER_EVENT_IFETCH;
per_kprobe.start.val = ip;
per_kprobe.end.val = ip;
/* Save control regs and psw mask */
__local_ctl_store(9, 11, kcb->kprobe_saved_ctl);
kcb->kprobe_saved_imask = regs->psw.mask &
(PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);
/* Set PER control regs, turns on single step for the given address */
__local_ctl_load(9, 11, per_kprobe.regs);
regs->psw.mask |= PSW_MASK_PER;
regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
regs->psw.addr = ip;
}
NOKPROBE_SYMBOL(enable_singlestep);
staticvoid disable_singlestep(struct kprobe_ctlblk *kcb, struct pt_regs *regs, unsignedlong ip)
{ /* Restore control regs and psw mask, set new psw address */
__local_ctl_load(9, 11, kcb->kprobe_saved_ctl);
regs->psw.mask &= ~PSW_MASK_PER;
regs->psw.mask |= kcb->kprobe_saved_imask;
regs->psw.addr = ip;
}
NOKPROBE_SYMBOL(disable_singlestep);
/* * 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.
*/ staticvoid push_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p)
{
kcb->prev_kprobe.kp = __this_cpu_read(current_kprobe);
kcb->prev_kprobe.status = kcb->kprobe_status;
__this_cpu_write(current_kprobe, p);
}
NOKPROBE_SYMBOL(push_kprobe);
/* * 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.
*/ staticvoid pop_kprobe(struct kprobe_ctlblk *kcb)
{
__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
kcb->kprobe_status = kcb->prev_kprobe.status;
kcb->prev_kprobe.kp = NULL;
}
NOKPROBE_SYMBOL(pop_kprobe);
staticvoid kprobe_reenter_check(struct kprobe_ctlblk *kcb, struct kprobe *p)
{ switch (kcb->kprobe_status) { case KPROBE_HIT_SSDONE: case KPROBE_HIT_ACTIVE:
kprobes_inc_nmissed_count(p); break; case KPROBE_HIT_SS: case KPROBE_REENTER: default: /* * A kprobe on the code path to single step an instruction * is a BUG. The code path resides in the .kprobes.text * section and is executed with interrupts disabled.
*/
pr_err("Failed to recover from reentered kprobes.\n");
dump_kprobe(p);
BUG();
}
}
NOKPROBE_SYMBOL(kprobe_reenter_check);
/* * We want to disable preemption for the entire duration of kprobe * processing. That includes the calls to the pre/post handlers * and single stepping the kprobe instruction.
*/
preempt_disable();
kcb = get_kprobe_ctlblk();
p = get_kprobe((void *)(regs->psw.addr - 2));
if (p) { if (kprobe_running()) { /* * 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.
*/
kprobe_reenter_check(kcb, p);
push_kprobe(kcb, p);
kcb->kprobe_status = KPROBE_REENTER;
} else { /* * If we have no pre-handler or it returned 0, we * continue with single stepping. If we have a * pre-handler and it returned non-zero, it prepped * for changing execution path, so get out doing * nothing more here.
*/
push_kprobe(kcb, p);
kcb->kprobe_status = KPROBE_HIT_ACTIVE; if (p->pre_handler && p->pre_handler(p, regs)) {
pop_kprobe(kcb);
preempt_enable_no_resched(); return 1;
}
kcb->kprobe_status = KPROBE_HIT_SS;
}
enable_singlestep(kcb, regs, (unsignedlong) p->ainsn.insn); return 1;
} /* else: * No kprobe at this address and no active kprobe. The trap has * not been caused by a kprobe breakpoint. The race of breakpoint * vs. kprobe remove does not exist because on s390 as we use * stop_machine to arm/disarm the breakpoints.
*/
preempt_enable_no_resched(); return 0;
}
NOKPROBE_SYMBOL(kprobe_handler);
/* * Called after single-stepping. p->addr is the address of the * instruction whose first byte has been replaced by the "breakpoint" * instruction. To avoid the SMP problems that can occur when we * temporarily put back the original opcode to single-step, we * single-stepped a copy of the instruction. The address of this * copy is p->ainsn.insn.
*/ staticvoid resume_execution(struct kprobe *p, struct pt_regs *regs)
{ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); unsignedlong ip = regs->psw.addr; int fixup = probe_get_fixup_type(p->ainsn.insn);
if (fixup & FIXUP_PSW_NORMAL)
ip += (unsignedlong) p->addr - (unsignedlong) p->ainsn.insn;
if (fixup & FIXUP_BRANCH_NOT_TAKEN) { int ilen = insn_length(p->ainsn.insn[0] >> 8); if (ip - (unsignedlong) p->ainsn.insn == ilen)
ip = (unsignedlong) p->addr + ilen;
}
/* * if somebody else is singlestepping across a probe point, psw mask * will have PER set, in which case, continue the remaining processing * of do_single_step, as if this is not a probe hit.
*/ if (regs->psw.mask & PSW_MASK_PER) return 0;
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 nip points back to the probe address * and allow the page fault handler to continue as a * normal page fault.
*/
disable_singlestep(kcb, regs, (unsignedlong) p->addr);
pop_kprobe(kcb);
preempt_enable_no_resched(); break; case KPROBE_HIT_ACTIVE: case KPROBE_HIT_SSDONE: /* * 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;
}
NOKPROBE_SYMBOL(kprobe_trap_handler);
int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{ int ret;
if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
local_irq_disable();
ret = kprobe_trap_handler(regs, trapnr); if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
local_irq_restore(regs->psw.mask & ~PSW_MASK_PER); return ret;
}
NOKPROBE_SYMBOL(kprobe_fault_handler);
/* * Wrapper routine to for handling exceptions.
*/ int kprobe_exceptions_notify(struct notifier_block *self, unsignedlong val, void *data)
{ struct die_args *args = (struct die_args *) data; struct pt_regs *regs = args->regs; int ret = NOTIFY_DONE;
if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
local_irq_disable();
switch (val) { case DIE_BPT: if (kprobe_handler(regs))
ret = NOTIFY_STOP; break; case DIE_SSTEP: if (post_kprobe_handler(regs))
ret = NOTIFY_STOP; break; case DIE_TRAP: if (!preemptible() && kprobe_running() &&
kprobe_trap_handler(regs, args->trapnr))
ret = NOTIFY_STOP; break; default: break;
}
if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
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.