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

📄 kprobes.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	 *     - 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);		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;	}	BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));	regs->eip = orig_ret_address;	reset_current_kprobe();	spin_unlock_irqrestore(&kretprobe_lock, flags);	preempt_enable_no_resched();	/*	 * 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 "int 3" * 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. * * This function prepares to return from the post-single-step * interrupt.  We have to fix up the stack as follows: * * 0) Except in the case of absolute or indirect jump or call instructions, * the new eip is relative to the copied instruction.  We need to make * it relative to the original instruction. * * 1) If the single-stepped instruction was pushfl, then the TF and IF * flags are set in the just-pushed eflags, and may need to be cleared. * * 2) If the single-stepped instruction was a call, the return address * that is atop the stack is the address following the copied instruction. * We need to make it the address following the original instruction. */static void __kprobes resume_execution(struct kprobe *p,		struct pt_regs *regs, struct kprobe_ctlblk *kcb){	unsigned long *tos = (unsigned long *)&regs->esp;	unsigned long next_eip = 0;	unsigned long copy_eip = (unsigned long)&p->ainsn.insn;	unsigned long orig_eip = (unsigned long)p->addr;	switch (p->ainsn.insn[0]) {	case 0x9c:		/* pushfl */		*tos &= ~(TF_MASK | IF_MASK);		*tos |= kcb->kprobe_old_eflags;		break;	case 0xc3:		/* ret/lret */	case 0xcb:	case 0xc2:	case 0xca:		regs->eflags &= ~TF_MASK;		/* eip is already adjusted, no more changes required*/		return;	case 0xe8:		/* call relative - Fix return addr */		*tos = orig_eip + (*tos - copy_eip);		break;	case 0xff:		if ((p->ainsn.insn[1] & 0x30) == 0x10) {			/* call absolute, indirect */			/* Fix return addr; eip is correct. */			next_eip = regs->eip;			*tos = orig_eip + (*tos - copy_eip);		} else if (((p->ainsn.insn[1] & 0x31) == 0x20) ||	/* jmp near, absolute indirect */			   ((p->ainsn.insn[1] & 0x31) == 0x21)) {	/* jmp far, absolute indirect */			/* eip is correct. */			next_eip = regs->eip;		}		break;	case 0xea:		/* jmp absolute -- eip is correct */		next_eip = regs->eip;		break;	default:		break;	}	regs->eflags &= ~TF_MASK;	if (next_eip) {		regs->eip = next_eip;	} else {		regs->eip = orig_eip + (regs->eip - copy_eip);	}}/* * Interrupts are disabled on entry as trap1 is an interrupt gate and they * remain disabled thoroughout this function. */static inline int 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, kcb);	regs->eflags |= kcb->kprobe_saved_eflags;	/*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, eflags	 * will have TF set, in which case, continue the remaining processing	 * of do_debug, as if this is not a probe hit.	 */	if (regs->eflags & TF_MASK)		return 0;	return 1;}static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr){	struct kprobe *cur = kprobe_running();	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))		return 1;	if (kcb->kprobe_status & KPROBE_HIT_SS) {		resume_execution(cur, regs, kcb);		regs->eflags |= kcb->kprobe_old_eflags;		reset_current_kprobe();		preempt_enable_no_resched();	}	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_INT3:		if (kprobe_handler(args->regs))			ret = NOTIFY_STOP;		break;	case DIE_DEBUG:		if (post_kprobe_handler(args->regs))			ret = NOTIFY_STOP;		break;	case DIE_GPF:	case DIE_PAGE_FAULT:		/* 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();	kcb->jprobe_saved_regs = *regs;	kcb->jprobe_saved_esp = &regs->esp;	addr = (unsigned long)(kcb->jprobe_saved_esp);	/*	 * TBD: As Linus pointed out, gcc assumes that the callee	 * owns the argument space and could overwrite it, e.g.	 * tailcall optimization. So, to be absolutely safe	 * we also save and restore enough stack bytes to cover	 * the argument area.	 */	memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,			MIN_STACK_SIZE(addr));	regs->eflags &= ~IF_MASK;	regs->eip = (unsigned long)(jp->entry);	return 1;}void __kprobes jprobe_return(void){	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	asm volatile ("       xchgl   %%ebx,%%esp     \n"		      "       int3			\n"		      "       .globl jprobe_return_end	\n"		      "       jprobe_return_end:	\n"		      "       nop			\n"::"b"		      (kcb->jprobe_saved_esp):"memory");}int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs){	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();	u8 *addr = (u8 *) (regs->eip - 1);	unsigned long stack_addr = (unsigned long)(kcb->jprobe_saved_esp);	struct jprobe *jp = container_of(p, struct jprobe, kp);	if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) {		if (&regs->esp != kcb->jprobe_saved_esp) {			struct pt_regs *saved_regs =			    container_of(kcb->jprobe_saved_esp,					    struct pt_regs, esp);			printk("current esp %p does not match saved esp %p\n",			       &regs->esp, kcb->jprobe_saved_esp);			printk("Saved registers for jprobe %p\n", jp);			show_registers(saved_regs);			printk("Current registers\n");			show_registers(regs);			BUG();		}		*regs = kcb->jprobe_saved_regs;		memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack,		       MIN_STACK_SIZE(stack_addr));		preempt_enable_no_resched();		return 1;	}	return 0;}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);}

⌨️ 快捷键说明

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