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

📄 kprobes.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	p->ainsn.insn = get_insn_slot();	if (!p->ainsn.insn)		return -ENOMEM;	memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t));	memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t));	prepare_break_inst(template, slot, major_opcode, kprobe_inst, p, qp);	return 0;}void __kprobes arch_arm_kprobe(struct kprobe *p){	unsigned long arm_addr;	bundle_t *src, *dest;	arm_addr = ((unsigned long)p->addr) & ~0xFUL;	dest = &((kprobe_opcode_t *)arm_addr)->bundle;	src = &p->opcode.bundle;	flush_icache_range((unsigned long)p->ainsn.insn,			(unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));	switch (p->ainsn.slot) {		case 0:			dest->quad0.slot0 = src->quad0.slot0;			break;		case 1:			dest->quad1.slot1_p1 = src->quad1.slot1_p1;			break;		case 2:			dest->quad1.slot2 = src->quad1.slot2;			break;	}	flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));}void __kprobes arch_disarm_kprobe(struct kprobe *p){	unsigned long arm_addr;	bundle_t *src, *dest;	arm_addr = ((unsigned long)p->addr) & ~0xFUL;	dest = &((kprobe_opcode_t *)arm_addr)->bundle;	/* p->ainsn.insn contains the original unaltered kprobe_opcode_t */	src = &p->ainsn.insn->bundle;	switch (p->ainsn.slot) {		case 0:			dest->quad0.slot0 = src->quad0.slot0;			break;		case 1:			dest->quad1.slot1_p1 = src->quad1.slot1_p1;			break;		case 2:			dest->quad1.slot2 = src->quad1.slot2;			break;	}	flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));}void __kprobes arch_remove_kprobe(struct kprobe *p){	mutex_lock(&kprobe_mutex);	free_insn_slot(p->ainsn.insn, 0);	mutex_unlock(&kprobe_mutex);}/* * We are resuming execution after a single step fault, so the pt_regs * structure reflects the register state after we executed the instruction * located in the kprobe (p->ainsn.insn.bundle).  We still need to adjust * the ip to point back to the original stack address. To set the IP address * to original stack address, handle the case where we need to fixup the * relative IP address and/or fixup branch register. */static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs){	unsigned long bundle_addr = (unsigned long) (&p->ainsn.insn->bundle);	unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL;	unsigned long template;	int slot = ((unsigned long)p->addr & 0xf);	template = p->ainsn.insn->bundle.quad0.template;	if (slot == 1 && bundle_encoding[template][1] == L)		slot = 2;	if (p->ainsn.inst_flag) {		if (p->ainsn.inst_flag & INST_FLAG_FIX_RELATIVE_IP_ADDR) {			/* Fix relative IP address */			regs->cr_iip = (regs->cr_iip - bundle_addr) +					resume_addr;		}		if (p->ainsn.inst_flag & INST_FLAG_FIX_BRANCH_REG) {		/*		 * Fix target branch register, software convention is		 * to use either b0 or b6 or b7, so just checking		 * only those registers		 */			switch (p->ainsn.target_br_reg) {			case 0:				if ((regs->b0 == bundle_addr) ||					(regs->b0 == bundle_addr + 0x10)) {					regs->b0 = (regs->b0 - bundle_addr) +						resume_addr;				}				break;			case 6:				if ((regs->b6 == bundle_addr) ||					(regs->b6 == bundle_addr + 0x10)) {					regs->b6 = (regs->b6 - bundle_addr) +						resume_addr;				}				break;			case 7:				if ((regs->b7 == bundle_addr) ||					(regs->b7 == bundle_addr + 0x10)) {					regs->b7 = (regs->b7 - bundle_addr) +						resume_addr;				}				break;			} /* end switch */		}		goto turn_ss_off;	}	if (slot == 2) {		if (regs->cr_iip == bundle_addr + 0x10) {			regs->cr_iip = resume_addr + 0x10;		}	} else {		if (regs->cr_iip == bundle_addr) {			regs->cr_iip = resume_addr;		}	}turn_ss_off:	/* Turn off Single Step bit */	ia64_psr(regs)->ss = 0;}static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs){	unsigned long bundle_addr = (unsigned long) &p->ainsn.insn->bundle;	unsigned long slot = (unsigned long)p->addr & 0xf;	/* single step inline if break instruction */	if (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)		regs->cr_iip = (unsigned long)p->addr & ~0xFULL;	else		regs->cr_iip = bundle_addr & ~0xFULL;	if (slot > 2)		slot = 0;	ia64_psr(regs)->ri = slot;	/* turn on single stepping */	ia64_psr(regs)->ss = 1;}static int __kprobes is_ia64_break_inst(struct pt_regs *regs){	unsigned int slot = ia64_psr(regs)->ri;	unsigned int template, major_opcode;	unsigned long kprobe_inst;	unsigned long *kprobe_addr = (unsigned long *)regs->cr_iip;	bundle_t bundle;	memcpy(&bundle, kprobe_addr, sizeof(bundle_t));	template = bundle.quad0.template;	/* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */	if (slot == 1 && bundle_encoding[template][1] == L)		slot++;	/* Get Kprobe probe instruction at given slot*/	get_kprobe_inst(&bundle, slot, &kprobe_inst, &major_opcode);	/* For break instruction,	 * Bits 37:40 Major opcode to be zero	 * Bits 27:32 X6 to be zero	 * Bits 32:35 X3 to be zero	 */	if (major_opcode || ((kprobe_inst >> 27) & 0x1FF) ) {		/* Not a break instruction */		return 0;	}	/* Is a break instruction */	return 1;}static int __kprobes pre_kprobes_handler(struct die_args *args){	struct kprobe *p;	int ret = 0;	struct pt_regs *regs = args->regs;	kprobe_opcode_t *addr = (kprobe_opcode_t *)instruction_pointer(regs);	struct kprobe_ctlblk *kcb;	/*	 * We don't want to be preempted for the entire	 * duration of kprobe processing	 */	preempt_disable();	kcb = get_kprobe_ctlblk();	/* Handle recursion cases */	if (kprobe_running()) {		p = get_kprobe(addr);		if (p) {			if ((kcb->kprobe_status == KPROBE_HIT_SS) &&	 		     (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) {				ia64_psr(regs)->ss = 0;				goto no_kprobe;			}			/* We have reentered the pre_kprobe_handler(), since			 * another probe was hit while within the handler.			 * We here save the original kprobes variables and			 * just single step on the instruction of the new probe			 * without calling any user handlers.			 */			save_previous_kprobe(kcb);			set_current_kprobe(p, kcb);			kprobes_inc_nmissed_count(p);			prepare_ss(p, regs);			kcb->kprobe_status = KPROBE_REENTER;			return 1;		} else if (args->err == __IA64_BREAK_JPROBE) {			/*			 * jprobe instrumented function just completed			 */			p = __get_cpu_var(current_kprobe);			if (p->break_handler && p->break_handler(p, regs)) {				goto ss_probe;			}		} else if (!is_ia64_break_inst(regs)) {			/* The breakpoint instruction was removed by			 * another cpu right after we hit, no further			 * handling of this interrupt is appropriate			 */			ret = 1;			goto no_kprobe;		} else {			/* Not our break */			goto no_kprobe;		}	}	p = get_kprobe(addr);	if (!p) {		if (!is_ia64_break_inst(regs)) {			/*			 * 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.			 */			ret = 1;		}		/* Not one of our break, let kernel handle it */		goto no_kprobe;	}	set_current_kprobe(p, kcb);	kcb->kprobe_status = KPROBE_HIT_ACTIVE;	if (p->pre_handler && p->pre_handler(p, regs))		/*		 * Our pre-handler is specifically requesting that we just		 * do a return.  This is used for both the jprobe pre-handler		 * and the kretprobe trampoline		 */		return 1;ss_probe:	prepare_ss(p, regs);	kcb->kprobe_status = KPROBE_HIT_SS;	return 1;no_kprobe:	preempt_enable_no_resched();	return ret;}static int __kprobes post_kprobes_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();	return 1;}int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr){	struct kprobe *cur = kprobe_running();	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	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 instruction pointer points back to		 * the probe address and allow the page fault handler		 * to continue as a normal page fault.		 */		regs->cr_iip = ((unsigned long)cur->addr) & ~0xFULL;		ia64_psr(regs)->ri = ((unsigned long)cur->addr) & 0xf;		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.		 */		if (ia64_done_with_exception(regs))			return 1;		/*		 * Let ia64_do_page_fault() fix it.		 */		break;	default:		break;	}	return 0;}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;	if (args->regs && user_mode(args->regs))		return ret;	switch(val) {	case DIE_BREAK:		/* err is break number from ia64_bad_break() */		if ((args->err >> 12) == (__IA64_BREAK_KPROBE >> 12)			|| args->err == __IA64_BREAK_JPROBE			|| args->err == 0)			if (pre_kprobes_handler(args))				ret = NOTIFY_STOP;		break;	case DIE_FAULT:		/* err is vector number from ia64_fault() */		if (args->err == 36)			if (post_kprobes_handler(args->regs))				ret = NOTIFY_STOP;		break;	default:		break;	}	return ret;}struct param_bsp_cfm {	unsigned long ip;	unsigned long *bsp;	unsigned long cfm;};static void ia64_get_bsp_cfm(struct unw_frame_info *info, void *arg){	unsigned long ip;	struct param_bsp_cfm *lp = arg;	do {		unw_get_ip(info, &ip);		if (ip == 0)			break;		if (ip == lp->ip) {			unw_get_bsp(info, (unsigned long*)&lp->bsp);			unw_get_cfm(info, (unsigned long*)&lp->cfm);			return;		}	} while (unw_unwind(info) >= 0);	lp->bsp = NULL;	lp->cfm = 0;	return;}unsigned long arch_deref_entry_point(void *entry){	return ((struct fnptr *)entry)->ip;}int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs){	struct jprobe *jp = container_of(p, struct jprobe, kp);	unsigned long addr = arch_deref_entry_point(jp->entry);	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	struct param_bsp_cfm pa;	int bytes;	/*	 * Callee owns the argument space and could overwrite it, eg	 * tail call optimization. So to be absolutely safe	 * we save the argument space before transferring the control	 * to instrumented jprobe function which runs in	 * the process context	 */	pa.ip = regs->cr_iip;	unw_init_running(ia64_get_bsp_cfm, &pa);	bytes = (char *)ia64_rse_skip_regs(pa.bsp, pa.cfm & 0x3f)				- (char *)pa.bsp;	memcpy( kcb->jprobes_saved_stacked_regs,		pa.bsp,		bytes );	kcb->bsp = pa.bsp;	kcb->cfm = pa.cfm;	/* save architectural state */	kcb->jprobe_saved_regs = *regs;	/* after rfi, execute the jprobe instrumented function */	regs->cr_iip = addr & ~0xFULL;	ia64_psr(regs)->ri = addr & 0xf;	regs->r1 = ((struct fnptr *)(jp->entry))->gp;	/*	 * fix the return address to our jprobe_inst_return() function	 * in the jprobes.S file	 */	regs->b0 = ((struct fnptr *)(jprobe_inst_return))->ip;	return 1;}int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs){	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	int bytes;	/* restoring architectural state */	*regs = kcb->jprobe_saved_regs;	/* restoring the original argument space */	flush_register_stack();	bytes = (char *)ia64_rse_skip_regs(kcb->bsp, kcb->cfm & 0x3f)				- (char *)kcb->bsp;	memcpy( kcb->bsp,		kcb->jprobes_saved_stacked_regs,		bytes );	invalidate_stacked_regs();	preempt_enable_no_resched();	return 1;}static struct kprobe trampoline_p = {	.pre_handler = trampoline_probe_handler};int __init arch_init_kprobes(void){	trampoline_p.addr =		(kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip;	return register_kprobe(&trampoline_p);}int __kprobes arch_trampoline_kprobe(struct kprobe *p){	if (p->addr ==		(kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip)		return 1;	return 0;}

⌨️ 快捷键说明

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