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

📄 ptrace.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
		case 0x1: /* BNE */		case 0x8: /* BEQZ */		case 0x9: /* BNEZ */		case 0xa: /* BLTZ */		case 0xb: /* BGEZ */		case 0xc: /* BLEZ */		case 0xd: /* BGTZ */			regno1 = ((insn >> 24) & 0xf);			regno2 = ((insn >> 16) & 0xf);			if (check_condition_src(op2, regno1, regno2, child)) {				disp = (long)(insn << 16) >> 14;				*next_pc = (pc & ~0x3) + disp;				return;			}			break;		}	}	*next_pc = pc + 4;}static inline voidcompute_next_pc(unsigned long insn, unsigned long pc,		unsigned long *next_pc, struct task_struct *child){	if (insn & 0x80000000)		compute_next_pc_for_32bit_insn(insn, pc, next_pc, child);	else		compute_next_pc_for_16bit_insn(insn, pc, next_pc, child);}static intregister_debug_trap(struct task_struct *child, unsigned long next_pc,	unsigned long next_insn, unsigned long *code){	struct debug_trap *p = &child->thread.debug_trap;	unsigned long addr = next_pc & ~3;	if (p->nr_trap == MAX_TRAPS) {		printk("kernel BUG at %s %d: p->nr_trap = %d\n",					__FILE__, __LINE__, p->nr_trap);		return -1;	}	p->addr[p->nr_trap] = addr;	p->insn[p->nr_trap] = next_insn;	p->nr_trap++;	if (next_pc & 3) {		*code = (next_insn & 0xffff0000) | 0x10f1;		/* xxx --> TRAP1 */	} else {		if ((next_insn & 0x80000000) || (next_insn & 0x8000)) {			*code = 0x10f17000;			/* TRAP1 --> NOP */		} else {			*code = (next_insn & 0xffff) | 0x10f10000;			/* TRAP1 --> xxx */		}	}	return 0;}static intunregister_debug_trap(struct task_struct *child, unsigned long addr,		      unsigned long *code){	struct debug_trap *p = &child->thread.debug_trap;        int i;	/* Search debug trap entry. */	for (i = 0; i < p->nr_trap; i++) {		if (p->addr[i] == addr)			break;	}	if (i >= p->nr_trap) {		/* The trap may be requested from debugger.		 * ptrace should do nothing in this case.		 */		return 0;	}	/* Recover orignal instruction code. */	*code = p->insn[i];	/* Shift debug trap entries. */	while (i < p->nr_trap - 1) {		p->insn[i] = p->insn[i + 1];		p->addr[i] = p->addr[i + 1];		i++;	}	p->nr_trap--;	return 1;}static voidunregister_all_debug_traps(struct task_struct *child){	struct debug_trap *p = &child->thread.debug_trap;	int i;	for (i = 0; i < p->nr_trap; i++)		access_process_vm(child, p->addr[i], &p->insn[i], sizeof(p->insn[i]), 1);	p->nr_trap = 0;}static inline voidinvalidate_cache(void){#if defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_OPSP)	_flush_cache_copyback_all();#else	/* ! CONFIG_CHIP_M32700 */	/* Invalidate cache */	__asm__ __volatile__ (                "ldi    r0, #-1					\n\t"                "ldi    r1, #0					\n\t"                "stb    r1, @r0		; cache off		\n\t"                ";						\n\t"                "ldi    r0, #-2					\n\t"                "ldi    r1, #1					\n\t"                "stb    r1, @r0		; cache invalidate	\n\t"                ".fillinsn					\n"                "0:						\n\t"                "ldb    r1, @r0		; invalidate check	\n\t"                "bnez   r1, 0b					\n\t"                ";						\n\t"                "ldi    r0, #-1					\n\t"                "ldi    r1, #1					\n\t"                "stb    r1, @r0		; cache on		\n\t"		: : : "r0", "r1", "memory"	);	/* FIXME: copying-back d-cache and invalidating i-cache are needed.	 */#endif	/* CONFIG_CHIP_M32700 */}/* Embed a debug trap (TRAP1) code */static intembed_debug_trap(struct task_struct *child, unsigned long next_pc){	unsigned long next_insn, code;	unsigned long addr = next_pc & ~3;	if (access_process_vm(child, addr, &next_insn, sizeof(next_insn), 0)	    != sizeof(next_insn)) {		return -1; /* error */	}	/* Set a trap code. */	if (register_debug_trap(child, next_pc, next_insn, &code)) {		return -1; /* error */	}	if (access_process_vm(child, addr, &code, sizeof(code), 1)	    != sizeof(code)) {		return -1; /* error */	}	return 0; /* success */}voidwithdraw_debug_trap(struct pt_regs *regs){	unsigned long addr;	unsigned long code; 	addr = (regs->bpc - 2) & ~3;	regs->bpc -= 2;	if (unregister_debug_trap(current, addr, &code)) {	    access_process_vm(current, addr, &code, sizeof(code), 1);	    invalidate_cache();	}}static voidinit_debug_traps(struct task_struct *child){	struct debug_trap *p = &child->thread.debug_trap;	int i;	p->nr_trap = 0;	for (i = 0; i < MAX_TRAPS; i++) {		p->addr[i] = 0;		p->insn[i] = 0;	}}/* * Called by kernel/ptrace.c when detaching.. * * Make sure single step bits etc are not set. */void ptrace_disable(struct task_struct *child){	/* nothing to do.. */}static intdo_ptrace(long request, struct task_struct *child, long addr, long data){	unsigned long tmp;	int ret;	switch (request) {	/*	 * read word at location "addr" in the child process.	 */	case PTRACE_PEEKTEXT:	case PTRACE_PEEKDATA:		ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);		if (ret == sizeof(tmp))			ret = put_user(tmp,(unsigned long __user *) data);		else			ret = -EIO;		break;	/*	 * read the word at location addr in the USER area.	 */	case PTRACE_PEEKUSR:		ret = ptrace_read_user(child, addr,				       (unsigned long __user *)data);		break;	/*	 * write the word at location addr.	 */	case PTRACE_POKETEXT:	case PTRACE_POKEDATA:		ret = access_process_vm(child, addr, &data, sizeof(data), 1);		if (ret == sizeof(data)) {			ret = 0;			if (request == PTRACE_POKETEXT) {				invalidate_cache();			}		} else {			ret = -EIO;		}		break;	/*	 * write the word at location addr in the USER area.	 */	case PTRACE_POKEUSR:		ret = ptrace_write_user(child, addr, data);		break;	/*	 * continue/restart and stop at next (return from) syscall	 */	case PTRACE_SYSCALL:	case PTRACE_CONT:		ret = -EIO;		if (!valid_signal(data))			break;		if (request == PTRACE_SYSCALL)			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);		else			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);		child->exit_code = data;		wake_up_process(child);		ret = 0;		break;	/*	 * make the child exit.  Best I can do is send it a sigkill.	 * perhaps it should be put in the status that it wants to	 * exit.	 */	case PTRACE_KILL: {		ret = 0;		unregister_all_debug_traps(child);		invalidate_cache();		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */			break;		child->exit_code = SIGKILL;		wake_up_process(child);		break;	}	/*	 * execute single instruction.	 */	case PTRACE_SINGLESTEP: {		unsigned long next_pc;		unsigned long pc, insn;		ret = -EIO;		if (!valid_signal(data))			break;		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);		if ((child->ptrace & PT_DTRACE) == 0) {			/* Spurious delayed TF traps may occur */			child->ptrace |= PT_DTRACE;		}		/* Compute next pc.  */		pc = get_stack_long(child, PT_BPC);		if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0)		    != sizeof(insn))			break;		compute_next_pc(insn, pc, &next_pc, child);		if (next_pc & 0x80000000)			break;		if (embed_debug_trap(child, next_pc))			break;		invalidate_cache();		child->exit_code = data;		/* give it a chance to run. */		wake_up_process(child);		ret = 0;		break;	}	/*	 * detach a process that was attached.	 */	case PTRACE_DETACH:		ret = 0;		ret = ptrace_detach(child, data);		break;	case PTRACE_GETREGS:		ret = ptrace_getregs(child, (void __user *)data);		break;	case PTRACE_SETREGS:		ret = ptrace_setregs(child, (void __user *)data);		break;	default:		ret = ptrace_request(child, request, addr, data);		break;	}	return ret;}asmlinkage long sys_ptrace(long request, long pid, long addr, long data){	struct task_struct *child;	int ret;	lock_kernel();	ret = -EPERM;	if (request == PTRACE_TRACEME) {		/* are we already being traced? */		if (current->ptrace & PT_PTRACED)			goto out;		/* set the ptrace bit in the process flags. */		current->ptrace |= PT_PTRACED;		ret = 0;		goto out;	}	ret = -ESRCH;	read_lock(&tasklist_lock);	child = find_task_by_pid(pid);	if (child)		get_task_struct(child);	read_unlock(&tasklist_lock);	if (!child)		goto out;	ret = -EPERM;	if (pid == 1)		/* you may not mess with init */		goto out;	if (request == PTRACE_ATTACH) {		ret = ptrace_attach(child);		if (ret == 0)			init_debug_traps(child);		goto out_tsk;	}	ret = ptrace_check_attach(child, request == PTRACE_KILL);	if (ret == 0)		ret = do_ptrace(request, child, addr, data);out_tsk:	put_task_struct(child);out:	unlock_kernel();	return ret;}/* notification of system call entry/exit * - triggered by current->work.syscall_trace */void do_syscall_trace(void){	if (!test_thread_flag(TIF_SYSCALL_TRACE))		return;	if (!(current->ptrace & PT_PTRACED))		return;	/* the 0x80 provides a way for the tracing parent to distinguish	   between a syscall stop and SIGTRAP delivery */	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)				 ? 0x80 : 0));	/*	 * this isn't the same as continuing with a signal, but it will do	 * for normal use.  strace only continues with a signal if the	 * stopping signal is not SIGTRAP.  -brl	 */	if (current->exit_code) {		send_sig(current->exit_code, current, 1);		current->exit_code = 0;	}}

⌨️ 快捷键说明

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