⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kprobes.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		 */		goto no_kprobe;	kcb->kprobe_status = KPROBE_HIT_ACTIVE;	set_current_kprobe(p, regs, kcb);	if (p->pre_handler && p->pre_handler(p, regs))		/* handler has already set things up, so skip ss setup */		return 1;ss_probe:	prepare_singlestep(p, regs);	kcb->kprobe_status = KPROBE_HIT_SS;	return 1;no_kprobe:	preempt_enable_no_resched();	return ret;}/* * Function return probe trampoline: *	- init_kprobes() establishes a probepoint here *	- When the probed function returns, this probe *		causes the handlers to fire */void kretprobe_trampoline_holder(void){	asm volatile(".global kretprobe_trampoline\n"		     "kretprobe_trampoline: bcr 0,0\n");}/* * Called when the probe at kretprobe trampoline is hit */static int __kprobes trampoline_probe_handler(struct kprobe *p,					      struct pt_regs *regs){	struct kretprobe_instance *ri = NULL;	struct hlist_head *head, empty_rp;	struct hlist_node *node, *tmp;	unsigned long flags, orig_ret_address = 0;	unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;	INIT_HLIST_HEAD(&empty_rp);	spin_lock_irqsave(&kretprobe_lock, flags);	head = kretprobe_inst_table_head(current);	/*	 * It is possible to have multiple instances associated with a given	 * task either because an multiple functions in the call path	 * have a return probe installed on them, and/or more then one return	 * return probe was registered for a target function.	 *	 * We can handle this because:	 *     - instances are always inserted at the head of the list	 *     - when multiple return probes are registered for the same	 *	 function, the first instance's ret_addr will point to the	 *	 real return address, and all the rest will point to	 *	 kretprobe_trampoline	 */	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {		if (ri->task != current)			/* another task is sharing our hash bucket */			continue;		if (ri->rp && ri->rp->handler)			ri->rp->handler(ri, regs);		orig_ret_address = (unsigned long)ri->ret_addr;		recycle_rp_inst(ri, &empty_rp);		if (orig_ret_address != trampoline_address) {			/*			 * This is the real return address. Any other			 * instances associated with this task are for			 * other calls deeper on the call stack			 */			break;		}	}	kretprobe_assert(ri, orig_ret_address, trampoline_address);	regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE;	reset_current_kprobe();	spin_unlock_irqrestore(&kretprobe_lock, flags);	preempt_enable_no_resched();	hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {		hlist_del(&ri->hlist);		kfree(ri);	}	/*	 * By returning a non-zero value, we are telling	 * kprobe_handler() that we don't want the post_handler	 * to run (and have re-enabled preemption)	 */	return 1;}/* * 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. */static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs){	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	regs->psw.addr &= PSW_ADDR_INSN;	if (p->ainsn.fixup & FIXUP_PSW_NORMAL)		regs->psw.addr = (unsigned long)p->addr +				((unsigned long)regs->psw.addr -				 (unsigned long)p->ainsn.insn);	if (p->ainsn.fixup & FIXUP_BRANCH_NOT_TAKEN)		if ((unsigned long)regs->psw.addr -		    (unsigned long)p->ainsn.insn == p->ainsn.ilen)			regs->psw.addr = (unsigned long)p->addr + p->ainsn.ilen;	if (p->ainsn.fixup & FIXUP_RETURN_REGISTER)		regs->gprs[p->ainsn.reg] = ((unsigned long)p->addr +						(regs->gprs[p->ainsn.reg] -						(unsigned long)p->ainsn.insn))						| PSW_ADDR_AMODE;	regs->psw.addr |= PSW_ADDR_AMODE;	/* turn off PER mode */	regs->psw.mask &= ~PSW_MASK_PER;	/* Restore the original per control regs */	__ctl_load(kcb->kprobe_saved_ctl, 9, 11);	regs->psw.mask |= kcb->kprobe_saved_imask;}static int __kprobes post_kprobe_handler(struct pt_regs *regs){	struct kprobe *cur = kprobe_running();	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	if (!cur)		return 0;	if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {		kcb->kprobe_status = KPROBE_HIT_SSDONE;		cur->post_handler(cur, regs, 0);	}	resume_execution(cur, regs);	/*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_no_resched();	/*	 * 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;	}	return 1;}int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr){	struct kprobe *cur = kprobe_running();	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	const struct exception_table_entry *entry;	switch(kcb->kprobe_status) {	case KPROBE_SWAP_INST:		/* We are here because the instruction replacement failed */		return 0;	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.		 */		regs->psw.addr = (unsigned long)cur->addr | PSW_ADDR_AMODE;		regs->psw.mask &= ~PSW_MASK_PER;		regs->psw.mask |= kcb->kprobe_saved_imask;		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 increment the nmissed count for accounting,		 * we can also use npre/npostfault count for accouting		 * these specific fault cases.		 */		kprobes_inc_nmissed_count(cur);		/*		 * We come here because instructions in the pre/post		 * handler caused the page_fault, this could happen		 * if handler tries to access user space by		 * copy_from_user(), get_user() etc. Let the		 * user-specified handler try to fix it first.		 */		if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))			return 1;		/*		 * In case the user-specified fault handler returned		 * zero, try to fix up.		 */		entry = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);		if (entry) {			regs->psw.addr = entry->fixup | PSW_ADDR_AMODE;			return 1;		}		/*		 * fixup_exception() could not handle it,		 * Let do_page_fault() fix it.		 */		break;	default:		break;	}	return 0;}/* * Wrapper routine to for handling exceptions. */int __kprobes kprobe_exceptions_notify(struct notifier_block *self,				       unsigned long val, void *data){	struct die_args *args = (struct die_args *)data;	int ret = NOTIFY_DONE;	switch (val) {	case DIE_BPT:		if (kprobe_handler(args->regs))			ret = NOTIFY_STOP;		break;	case DIE_SSTEP:		if (post_kprobe_handler(args->regs))			ret = NOTIFY_STOP;		break;	case DIE_TRAP:		/* kprobe_running() needs smp_processor_id() */		preempt_disable();		if (kprobe_running() &&		    kprobe_fault_handler(args->regs, args->trapnr))			ret = NOTIFY_STOP;		preempt_enable();		break;	default:		break;	}	return ret;}int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs){	struct jprobe *jp = container_of(p, struct jprobe, kp);	unsigned long addr;	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs));	/* setup return addr to the jprobe handler routine */	regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE;	/* r14 is the function return address */	kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14];	/* r15 is the stack pointer */	kcb->jprobe_saved_r15 = (unsigned long)regs->gprs[15];	addr = (unsigned long)kcb->jprobe_saved_r15;	memcpy(kcb->jprobes_stack, (kprobe_opcode_t *) addr,	       MIN_STACK_SIZE(addr));	return 1;}void __kprobes jprobe_return(void){	asm volatile(".word 0x0002");}void __kprobes jprobe_return_end(void){	asm volatile("bcr 0,0");}int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs){	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	unsigned long stack_addr = (unsigned long)(kcb->jprobe_saved_r15);	/* Put the regs back */	memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs));	/* put the stack back */	memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack,	       MIN_STACK_SIZE(stack_addr));	preempt_enable_no_resched();	return 1;}static struct kprobe trampoline_p = {	.addr = (kprobe_opcode_t *) & kretprobe_trampoline,	.pre_handler = trampoline_probe_handler};int __init arch_init_kprobes(void){	return register_kprobe(&trampoline_p);}int __kprobes arch_trampoline_kprobe(struct kprobe *p){	if (p->addr == (kprobe_opcode_t *) & kretprobe_trampoline)		return 1;	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -