/* Fallback to the original non-dot symbol lookup */ if (!addr && dot_appended)
addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); #else
addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); #endif
return addr;
}
staticbool arch_kprobe_on_func_entry(unsignedlong addr, unsignedlong offset)
{ unsignedlong ip = ftrace_location(addr);
if (ip) return offset <= (ip - addr); if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2) && !IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) return offset <= 8; return !offset;
}
/* XXX try and fold the magic of kprobe_lookup_name() in this */
kprobe_opcode_t *arch_adjust_kprobe_addr(unsignedlong addr, unsignedlong offset, bool *on_func_entry)
{
*on_func_entry = arch_kprobe_on_func_entry(addr, offset); return (kprobe_opcode_t *)(addr + offset);
}
int arch_prepare_kprobe(struct kprobe *p)
{ int ret = 0; struct kprobe *prev;
ppc_inst_t insn = ppc_inst_read(p->addr);
if ((unsignedlong)p->addr & 0x03) {
printk("Attempt to register kprobe at an unaligned address\n");
ret = -EINVAL;
} elseif (!can_single_step(ppc_inst_val(insn))) {
printk("Cannot register a kprobe on instructions that can't be single stepped\n");
ret = -EINVAL;
} elseif ((unsignedlong)p->addr & ~PAGE_MASK &&
ppc_inst_prefixed(ppc_inst_read(p->addr - 1))) {
printk("Cannot register a kprobe on the second word of prefixed instruction\n");
ret = -EINVAL;
}
prev = get_kprobe(p->addr - 1);
/* *Whenprevisaftrace-basedkprobe,wedon'thaveaninsn,andit *doesn'tprobeforprefixedinstruction.
*/ if (prev && !kprobe_ftrace(prev) &&
ppc_inst_prefixed(ppc_inst_read(prev->ainsn.insn))) {
printk("Cannot register a kprobe on the second word of prefixed instruction\n");
ret = -EINVAL;
}
/* insn must be on a special executable page on ppc64. This is
* not explicitly required on ppc32 (right now), but it doesn't hurt */ if (!ret) {
p->ainsn.insn = get_insn_slot(); if (!p->ainsn.insn)
ret = -ENOMEM;
}
if (!ret) {
patch_instruction(p->ainsn.insn, insn);
p->opcode = ppc_inst_val(insn);
}
p = get_kprobe(addr); if (!p) { unsignedint instr;
if (get_kernel_nofault(instr, addr)) goto no_kprobe;
if (instr != BREAKPOINT_INSTRUCTION) { /* *PowerPChasmultiplevariantsofthe"trap" *instruction.Ifthecurrentinstructionisa *trapvariant,itcouldbelongtosomeoneelse
*/ if (is_trap(instr)) goto no_kprobe; /* *Thebreakpointinstructionwasremovedright *afterwehitit.Anothercpuhasremoved *eitheraprobepointoradebuggerbreakpoint *atthisaddress.Ineithercase,nofurther *handlingofthisinterruptisappropriate.
*/
ret = 1;
} /* Not one of ours: let kernel handle it */ goto no_kprobe;
}
/* Check we're not actually recursing */ if (kprobe_running()) {
kprobe_opcode_t insn = *p->ainsn.insn; if (kcb->kprobe_status == KPROBE_HIT_SS && is_trap(insn)) { /* Turn off 'trace' bits */
regs_set_return_msr(regs,
(regs->msr & ~MSR_SINGLESTEP) |
kcb->kprobe_saved_msr); goto no_kprobe;
}
len = ppc_inst_len(ppc_inst_read(cur->ainsn.insn)); /* make sure we got here for instruction we have a kprobe on */ if (((unsignedlong)cur->ainsn.insn + len) != regs->nip) return0;
/* Adjust nip to after the single-stepped instruction */
regs_set_return_ip(regs, (unsignedlong)cur->addr + len);
regs_set_return_msr(regs, regs->msr | kcb->kprobe_saved_msr);
/*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:
preempt_enable();
/* *ifsomebodyelseissinglesteppingacrossaprobepoint,msr *willhaveDE/SEset,inwhichcase,continuetheremainingprocessing *ofdo_debug,asifthisisnotaprobehit.
*/ if (regs->msr & MSR_SINGLESTEP) return0;
return1;
}
NOKPROBE_SYMBOL(kprobe_post_handler);
int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{ struct kprobe *cur = kprobe_running(); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); conststruct exception_table_entry *entry;
switch(kcb->kprobe_status) { case KPROBE_HIT_SS: case KPROBE_REENTER: /* *Weareherebecausetheinstructionbeingsingle *steppedcausedapagefault.Weresetthecurrent *kprobeandthenippointsbacktotheprobeaddress *andallowthepagefaulthandlertocontinueasa *normalpagefault.
*/
regs_set_return_ip(regs, (unsignedlong)cur->addr); /* Turn off 'trace' bits */
regs_set_return_msr(regs,
(regs->msr & ~MSR_SINGLESTEP) |
kcb->kprobe_saved_msr); if (kcb->kprobe_status == KPROBE_REENTER)
restore_previous_kprobe(kcb); else
reset_current_kprobe();
preempt_enable(); break; case KPROBE_HIT_ACTIVE: case KPROBE_HIT_SSDONE: /* *Incasetheuser-specifiedfaulthandlerreturned *zero,trytofixup.
*/ if ((entry = search_exception_tables(regs->nip)) != NULL) {
regs_set_return_ip(regs, extable_fixup(entry)); return1;
}
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.