ptrace.c

来自「linux 内核源代码」· C语言 代码 · 共 662 行 · 第 1/2 页

C
662
字号
		unsigned long __user *tmp = (unsigned long __user *)addr;		CHECK_FULL_REGS(child->thread.regs);		for (i = 0; i < 32; i++) {			ret = put_user(*reg, tmp);			if (ret)				break;			reg++;			tmp++;		}		break;	}	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */		int i;		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];		unsigned long __user *tmp = (unsigned long __user *)addr;		CHECK_FULL_REGS(child->thread.regs);		for (i = 0; i < 32; i++) {			ret = get_user(*reg, tmp);			if (ret)				break;			reg++;			tmp++;		}		break;	}	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */		flush_fp_to_thread(child);		ret = get_fpregs((void __user *)addr, child, 0);		break;	}	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */		flush_fp_to_thread(child);		ret = set_fpregs((void __user *)addr, child, 0);		break;	}	}	return ret;}long arch_ptrace(struct task_struct *child, long request, long addr, long data){	int ret = -EPERM;	switch (request) {	/* when I and D space are separate, these will need to be fixed. */	case PTRACE_PEEKTEXT: /* read word at location addr. */	case PTRACE_PEEKDATA:		ret = generic_ptrace_peekdata(child, addr, data);		break;	/* read the word at location addr in the USER area. */	case PTRACE_PEEKUSR: {		unsigned long index, tmp;		ret = -EIO;		/* convert to index and check */#ifdef CONFIG_PPC32		index = (unsigned long) addr >> 2;		if ((addr & 3) || (index > PT_FPSCR)		    || (child->thread.regs == NULL))#else		index = (unsigned long) addr >> 3;		if ((addr & 7) || (index > PT_FPSCR))#endif			break;		CHECK_FULL_REGS(child->thread.regs);		if (index < PT_FPR0) {			tmp = ptrace_get_reg(child, (int) index);		} else {			flush_fp_to_thread(child);			tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];		}		ret = put_user(tmp,(unsigned long __user *) data);		break;	}	/* If I and D space are separate, this will have to be fixed. */	case PTRACE_POKETEXT: /* write the word at location addr. */	case PTRACE_POKEDATA:		ret = generic_ptrace_pokedata(child, addr, data);		break;	/* write the word at location addr in the USER area */	case PTRACE_POKEUSR: {		unsigned long index;		ret = -EIO;		/* convert to index and check */#ifdef CONFIG_PPC32		index = (unsigned long) addr >> 2;		if ((addr & 3) || (index > PT_FPSCR)		    || (child->thread.regs == NULL))#else		index = (unsigned long) addr >> 3;		if ((addr & 7) || (index > PT_FPSCR))#endif			break;		CHECK_FULL_REGS(child->thread.regs);		if (index < PT_FPR0) {			ret = ptrace_put_reg(child, index, data);		} else {			flush_fp_to_thread(child);			((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;			ret = 0;		}		break;	}	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */	case PTRACE_CONT: { /* restart after signal. */		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;		/* make sure the single step bit is not set. */		clear_single_step(child);		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;		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */			break;		child->exit_code = SIGKILL;		/* make sure the single step bit is not set. */		clear_single_step(child);		wake_up_process(child);		break;	}	case PTRACE_SINGLESTEP: {  /* set the trap flag. */		ret = -EIO;		if (!valid_signal(data))			break;		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);		set_single_step(child);		child->exit_code = data;		/* give it a chance to run. */		wake_up_process(child);		ret = 0;		break;	}	case PTRACE_GET_DEBUGREG: {		ret = -EINVAL;		/* We only support one DABR and no IABRS at the moment */		if (addr > 0)			break;		ret = put_user(child->thread.dabr,			       (unsigned long __user *)data);		break;	}	case PTRACE_SET_DEBUGREG:		ret = ptrace_set_debugreg(child, addr, data);		break;#ifdef CONFIG_PPC64	case PTRACE_GETREGS64:#endif	case PTRACE_GETREGS: { /* Get all pt_regs from the child. */		int ui;	  	if (!access_ok(VERIFY_WRITE, (void __user *)data,			       sizeof(struct pt_regs))) {			ret = -EIO;			break;		}		CHECK_FULL_REGS(child->thread.regs);		ret = 0;		for (ui = 0; ui < PT_REGS_COUNT; ui ++) {			ret |= __put_user(ptrace_get_reg(child, ui),					  (unsigned long __user *) data);			data += sizeof(long);		}		break;	}#ifdef CONFIG_PPC64	case PTRACE_SETREGS64:#endif	case PTRACE_SETREGS: { /* Set all gp regs in the child. */		unsigned long tmp;		int ui;	  	if (!access_ok(VERIFY_READ, (void __user *)data,			       sizeof(struct pt_regs))) {			ret = -EIO;			break;		}		CHECK_FULL_REGS(child->thread.regs);		ret = 0;		for (ui = 0; ui < PT_REGS_COUNT; ui ++) {			ret = __get_user(tmp, (unsigned long __user *) data);			if (ret)				break;			ptrace_put_reg(child, ui, tmp);			data += sizeof(long);		}		break;	}	case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */		flush_fp_to_thread(child);		ret = get_fpregs((void __user *)data, child, 1);		break;	}	case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */		flush_fp_to_thread(child);		ret = set_fpregs((void __user *)data, child, 1);		break;	}#ifdef CONFIG_ALTIVEC	case PTRACE_GETVRREGS:		/* Get the child altivec register state. */		flush_altivec_to_thread(child);		ret = get_vrregs((unsigned long __user *)data, child);		break;	case PTRACE_SETVRREGS:		/* Set the child altivec register state. */		flush_altivec_to_thread(child);		ret = set_vrregs(child, (unsigned long __user *)data);		break;#endif#ifdef CONFIG_SPE	case PTRACE_GETEVRREGS:		/* Get the child spe register state. */		flush_spe_to_thread(child);		ret = get_evrregs((unsigned long __user *)data, child);		break;	case PTRACE_SETEVRREGS:		/* Set the child spe register state. */		/* this is to clear the MSR_SPE bit to force a reload		 * of register state from memory */		flush_spe_to_thread(child);		ret = set_evrregs(child, (unsigned long __user *)data);		break;#endif	/* Old reverse args ptrace callss */	case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */	case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */	case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */	case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */		ret = arch_ptrace_old(child, request, addr, data);		break;	default:		ret = ptrace_request(child, request, addr, data);		break;	}	return ret;}static void do_syscall_trace(void){	/* 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;	}}void do_syscall_trace_enter(struct pt_regs *regs){	secure_computing(regs->gpr[0]);	if (test_thread_flag(TIF_SYSCALL_TRACE)	    && (current->ptrace & PT_PTRACED))		do_syscall_trace();	if (unlikely(current->audit_context)) {#ifdef CONFIG_PPC64		if (!test_thread_flag(TIF_32BIT))			audit_syscall_entry(AUDIT_ARCH_PPC64,					    regs->gpr[0],					    regs->gpr[3], regs->gpr[4],					    regs->gpr[5], regs->gpr[6]);		else#endif			audit_syscall_entry(AUDIT_ARCH_PPC,					    regs->gpr[0],					    regs->gpr[3] & 0xffffffff,					    regs->gpr[4] & 0xffffffff,					    regs->gpr[5] & 0xffffffff,					    regs->gpr[6] & 0xffffffff);	}}void do_syscall_trace_leave(struct pt_regs *regs){	if (unlikely(current->audit_context))		audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,				   regs->result);	if ((test_thread_flag(TIF_SYSCALL_TRACE)	     || test_thread_flag(TIF_SINGLESTEP))	    && (current->ptrace & PT_PTRACED))		do_syscall_trace();}

⌨️ 快捷键说明

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