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

📄 ptrace.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/arch/m32r/kernel/ptrace.c * * Copyright (C) 2002  Hirokazu Takata, Takeo Takahashi * Copyright (C) 2004  Hirokazu Takata, Kei Sakamoto * * Original x86 implementation: *	By Ross Biro 1/23/92 *	edited by Linus Torvalds * * Some code taken from sh version: *   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka * Some code taken from arm version: *   Copyright (C) 2000 Russell King */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/ptrace.h>#include <linux/user.h>#include <linux/string.h>#include <linux/signal.h>#include <asm/cacheflush.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/processor.h>#include <asm/mmu_context.h>/* * Get the address of the live pt_regs for the specified task. * These are saved onto the top kernel stack when the process * is not running. * * Note: if a user thread is execve'd from kernel space, the * kernel stack will not be empty on entry to the kernel, so * ptracing these tasks will fail. */static inline struct pt_regs *get_user_regs(struct task_struct *task){        return (struct pt_regs *)                ((unsigned long)task->thread_info + THREAD_SIZE                 - sizeof(struct pt_regs));}/* * This routine will get a word off of the process kernel stack. */static inline unsigned long intget_stack_long(struct task_struct *task, int offset){	unsigned long *stack;	stack = (unsigned long *)get_user_regs(task);	return stack[offset];}/* * This routine will put a word on the process kernel stack. */static inline intput_stack_long(struct task_struct *task, int offset, unsigned long data){	unsigned long *stack;	stack = (unsigned long *)get_user_regs(task);	stack[offset] = data;	return 0;}static int reg_offset[] = {	PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7,	PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_FP, PT_LR, PT_SPU,};/* * Read the word at offset "off" into the "struct user".  We * actually access the pt_regs stored on the kernel stack. */static int ptrace_read_user(struct task_struct *tsk, unsigned long off,			    unsigned long __user *data){	unsigned long tmp;#ifndef NO_FPU	struct user * dummy = NULL;#endif	if ((off & 3) || (off < 0) || (off > sizeof(struct user) - 3))		return -EIO;	off >>= 2;	switch (off) {	case PT_EVB:		__asm__ __volatile__ (			"mvfc	%0, cr5 \n\t"	 		: "=r" (tmp)		);		break;	case PT_CBR: {			unsigned long psw;			psw = get_stack_long(tsk, PT_PSW);			tmp = ((psw >> 8) & 1);		}		break;	case PT_PSW: {			unsigned long psw, bbpsw;			psw = get_stack_long(tsk, PT_PSW);			bbpsw = get_stack_long(tsk, PT_BBPSW);			tmp = ((psw >> 8) & 0xff) | ((bbpsw & 0xff) << 8);		}		break;	case PT_PC:		tmp = get_stack_long(tsk, PT_BPC);		break;	case PT_BPC:		off = PT_BBPC;		/* fall through */	default:		if (off < (sizeof(struct pt_regs) >> 2))			tmp = get_stack_long(tsk, off);#ifndef NO_FPU		else if (off >= (long)(&dummy->fpu >> 2) &&			 off < (long)(&dummy->u_fpvalid >> 2)) {			if (!tsk_used_math(tsk)) {				if (off == (long)(&dummy->fpu.fpscr >> 2))					tmp = FPSCR_INIT;				else					tmp = 0;			} else				tmp = ((long *)(&tsk->thread.fpu >> 2))					[off - (long)&dummy->fpu];		} else if (off == (long)(&dummy->u_fpvalid >> 2))			tmp = !!tsk_used_math(tsk);#endif /* not NO_FPU */		else			tmp = 0;	}	return put_user(tmp, data);}static int ptrace_write_user(struct task_struct *tsk, unsigned long off,			     unsigned long data){	int ret = -EIO;#ifndef NO_FPU	struct user * dummy = NULL;#endif	if ((off & 3) || off < 0 ||	    off > sizeof(struct user) - 3)		return -EIO;	off >>= 2;	switch (off) {	case PT_EVB:	case PT_BPC:	case PT_SPI:		/* We don't allow to modify evb. */		ret = 0;		break;	case PT_PSW:	case PT_CBR: {			/* We allow to modify only cbr in psw */			unsigned long psw;			psw = get_stack_long(tsk, PT_PSW);			psw = (psw & ~0x100) | ((data & 1) << 8);			ret = put_stack_long(tsk, PT_PSW, psw);		}		break;	case PT_PC:		off = PT_BPC;		data &= ~1;		/* fall through */	default:		if (off < (sizeof(struct pt_regs) >> 2))			ret = put_stack_long(tsk, off, data);#ifndef NO_FPU		else if (off >= (long)(&dummy->fpu >> 2) &&			 off < (long)(&dummy->u_fpvalid >> 2)) {			set_stopped_child_used_math(tsk);			((long *)&tsk->thread.fpu)				[off - (long)&dummy->fpu] = data;			ret = 0;		} else if (off == (long)(&dummy->u_fpvalid >> 2)) {			conditional_stopped_child_used_math(data, tsk);			ret = 0;		}#endif /* not NO_FPU */		break;	}	return ret;}/* * Get all user integer registers. */static int ptrace_getregs(struct task_struct *tsk, void __user *uregs){	struct pt_regs *regs = get_user_regs(tsk);	return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;}/* * Set all user integer registers. */static int ptrace_setregs(struct task_struct *tsk, void __user *uregs){	struct pt_regs newregs;	int ret;	ret = -EFAULT;	if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) {		struct pt_regs *regs = get_user_regs(tsk);		*regs = newregs;		ret = 0;	}	return ret;}static inline intcheck_condition_bit(struct task_struct *child){	return (int)((get_stack_long(child, PT_PSW) >> 8) & 1);}static intcheck_condition_src(unsigned long op, unsigned long regno1,		    unsigned long regno2, struct task_struct *child){	unsigned long reg1, reg2;	reg2 = get_stack_long(child, reg_offset[regno2]);	switch (op) {	case 0x0: /* BEQ */		reg1 = get_stack_long(child, reg_offset[regno1]);		return reg1 == reg2;	case 0x1: /* BNE */		reg1 = get_stack_long(child, reg_offset[regno1]);		return reg1 != reg2;	case 0x8: /* BEQZ */		return reg2 == 0;	case 0x9: /* BNEZ */		return reg2 != 0;	case 0xa: /* BLTZ */		return (int)reg2 < 0;	case 0xb: /* BGEZ */		return (int)reg2 >= 0;	case 0xc: /* BLEZ */		return (int)reg2 <= 0;	case 0xd: /* BGTZ */		return (int)reg2 > 0;	default:		/* never reached */		return 0;	}}static voidcompute_next_pc_for_16bit_insn(unsigned long insn, unsigned long pc,			       unsigned long *next_pc,			       struct task_struct *child){	unsigned long op, op2, op3;	unsigned long disp;	unsigned long regno;	int parallel = 0;	if (insn & 0x00008000)		parallel = 1;	if (pc & 3)		insn &= 0x7fff;	/* right slot */	else		insn >>= 16;	/* left slot */	op = (insn >> 12) & 0xf;	op2 = (insn >> 8) & 0xf;	op3 = (insn >> 4) & 0xf;	if (op == 0x7) {		switch (op2) {		case 0xd: /* BNC */		case 0x9: /* BNCL */			if (!check_condition_bit(child)) {				disp = (long)(insn << 24) >> 22;				*next_pc = (pc & ~0x3) + disp;				return;			}			break;		case 0x8: /* BCL */		case 0xc: /* BC */			if (check_condition_bit(child)) {				disp = (long)(insn << 24) >> 22;				*next_pc = (pc & ~0x3) + disp;				return;			}			break;		case 0xe: /* BL */		case 0xf: /* BRA */			disp = (long)(insn << 24) >> 22;			*next_pc = (pc & ~0x3) + disp;			return;			break;		}	} else if (op == 0x1) {		switch (op2) {		case 0x0:			if (op3 == 0xf) { /* TRAP */#if 1				/* pass through */#else 				/* kernel space is not allowed as next_pc */				unsigned long evb;				unsigned long trapno;				trapno = insn & 0xf;				__asm__ __volatile__ (					"mvfc %0, cr5\n"		 			:"=r"(evb)		 			:				);				*next_pc = evb + (trapno << 2);				return;#endif			} else if (op3 == 0xd) { /* RTE */				*next_pc = get_stack_long(child, PT_BPC);				return;			}			break;		case 0xc: /* JC */			if (op3 == 0xc && check_condition_bit(child)) {				regno = insn & 0xf;				*next_pc = get_stack_long(child,							  reg_offset[regno]);				return;			}			break;		case 0xd: /* JNC */			if (op3 == 0xc && !check_condition_bit(child)) {				regno = insn & 0xf;				*next_pc = get_stack_long(child,							  reg_offset[regno]);				return;			}			break;		case 0xe: /* JL */		case 0xf: /* JMP */			if (op3 == 0xc) { /* JMP */				regno = insn & 0xf;				*next_pc = get_stack_long(child,							  reg_offset[regno]);				return;			}			break;		}	}	if (parallel)		*next_pc = pc + 4;	else		*next_pc = pc + 2;}static voidcompute_next_pc_for_32bit_insn(unsigned long insn, unsigned long pc,			       unsigned long *next_pc,			       struct task_struct *child){	unsigned long op;	unsigned long op2;	unsigned long disp;	unsigned long regno1, regno2;	op = (insn >> 28) & 0xf;	if (op == 0xf) { 	/* branch 24-bit relative */		op2 = (insn >> 24) & 0xf;		switch (op2) {		case 0xd:	/* BNC */		case 0x9:	/* BNCL */			if (!check_condition_bit(child)) {				disp = (long)(insn << 8) >> 6;				*next_pc = (pc & ~0x3) + disp;				return;			}			break;		case 0x8:	/* BCL */		case 0xc:	/* BC */			if (check_condition_bit(child)) {				disp = (long)(insn << 8) >> 6;				*next_pc = (pc & ~0x3) + disp;				return;			}			break;		case 0xe:	/* BL */		case 0xf:	/* BRA */			disp = (long)(insn << 8) >> 6;			*next_pc = (pc & ~0x3) + disp;			return;		}	} else if (op == 0xb) { /* branch 16-bit relative */		op2 = (insn >> 20) & 0xf;		switch (op2) {		case 0x0: /* BEQ */

⌨️ 快捷键说明

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