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

📄 ptrace.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ptrace.c *//* By Ross Biro 1/23/92 *//* * Pentium III FXSR, SSE support *	Gareth Hughes <gareth@valinux.com>, May 2000 */#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/security.h>#include <linux/audit.h>#include <linux/seccomp.h>#include <linux/signal.h>#include <asm/uaccess.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/processor.h>#include <asm/i387.h>#include <asm/debugreg.h>#include <asm/ldt.h>#include <asm/desc.h>/* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. *//* determines which flags the user has access to. *//* 1 = access 0 = no access */#define FLAG_MASK 0x00044dd5/* set's the trap flag. */#define TRAP_FLAG 0x100/* * Offset of eflags on child stack.. */#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))static inline struct pt_regs *get_child_regs(struct task_struct *task){	void *stack_top = (void *)task->thread.esp0;	return stack_top - sizeof(struct pt_regs);}/* * this routine will get a word off of the processes privileged stack.  * the offset is how far from the base addr as stored in the TSS.   * this routine assumes that all the privileged stacks are in our * data space. */   static inline int get_stack_long(struct task_struct *task, int offset){	unsigned char *stack;	stack = (unsigned char *)task->thread.esp0;	stack += offset;	return (*((int *)stack));}/* * this routine will put a word on the processes privileged stack.  * the offset is how far from the base addr as stored in the TSS.   * this routine assumes that all the privileged stacks are in our * data space. */static inline int put_stack_long(struct task_struct *task, int offset,	unsigned long data){	unsigned char * stack;	stack = (unsigned char *) task->thread.esp0;	stack += offset;	*(unsigned long *) stack = data;	return 0;}static int putreg(struct task_struct *child,	unsigned long regno, unsigned long value){	switch (regno >> 2) {		case FS:			if (value && (value & 3) != 3)				return -EIO;			child->thread.fs = value;			return 0;		case GS:			if (value && (value & 3) != 3)				return -EIO;			child->thread.gs = value;			return 0;		case DS:		case ES:			if (value && (value & 3) != 3)				return -EIO;			value &= 0xffff;			break;		case SS:		case CS:			if ((value & 3) != 3)				return -EIO;			value &= 0xffff;			break;		case EFL:			value &= FLAG_MASK;			value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;			break;	}	if (regno > GS*4)		regno -= 2*4;	put_stack_long(child, regno - sizeof(struct pt_regs), value);	return 0;}static unsigned long getreg(struct task_struct *child,	unsigned long regno){	unsigned long retval = ~0UL;	switch (regno >> 2) {		case FS:			retval = child->thread.fs;			break;		case GS:			retval = child->thread.gs;			break;		case DS:		case ES:		case SS:		case CS:			retval = 0xffff;			/* fall through */		default:			if (regno > GS*4)				regno -= 2*4;			regno = regno - sizeof(struct pt_regs);			retval &= get_stack_long(child, regno);	}	return retval;}#define LDT_SEGMENT 4static unsigned long convert_eip_to_linear(struct task_struct *child, struct pt_regs *regs){	unsigned long addr, seg;	addr = regs->eip;	seg = regs->xcs & 0xffff;	if (regs->eflags & VM_MASK) {		addr = (addr & 0xffff) + (seg << 4);		return addr;	}	/*	 * We'll assume that the code segments in the GDT	 * are all zero-based. That is largely true: the	 * TLS segments are used for data, and the PNPBIOS	 * and APM bios ones we just ignore here.	 */	if (seg & LDT_SEGMENT) {		u32 *desc;		unsigned long base;		down(&child->mm->context.sem);		desc = child->mm->context.ldt + (seg & ~7);		base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);		/* 16-bit code segment? */		if (!((desc[1] >> 22) & 1))			addr &= 0xffff;		addr += base;		up(&child->mm->context.sem);	}	return addr;}static inline int is_at_popf(struct task_struct *child, struct pt_regs *regs){	int i, copied;	unsigned char opcode[16];	unsigned long addr = convert_eip_to_linear(child, regs);	copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);	for (i = 0; i < copied; i++) {		switch (opcode[i]) {		/* popf */		case 0x9d:			return 1;		/* opcode and address size prefixes */		case 0x66: case 0x67:			continue;		/* irrelevant prefixes (segment overrides and repeats) */		case 0x26: case 0x2e:		case 0x36: case 0x3e:		case 0x64: case 0x65:		case 0xf0: case 0xf2: case 0xf3:			continue;		/*		 * pushf: NOTE! We should probably not let		 * the user see the TF bit being set. But		 * it's more pain than it's worth to avoid		 * it, and a debugger could emulate this		 * all in user space if it _really_ cares.		 */		case 0x9c:		default:			return 0;		}	}	return 0;}static void set_singlestep(struct task_struct *child){	struct pt_regs *regs = get_child_regs(child);	/*	 * Always set TIF_SINGLESTEP - this guarantees that 	 * we single-step system calls etc..  This will also	 * cause us to set TF when returning to user mode.	 */	set_tsk_thread_flag(child, TIF_SINGLESTEP);	/*	 * If TF was already set, don't do anything else	 */	if (regs->eflags & TRAP_FLAG)		return;	/* Set TF on the kernel stack.. */	regs->eflags |= TRAP_FLAG;	/*	 * ..but if TF is changed by the instruction we will trace,	 * don't mark it as being "us" that set it, so that we	 * won't clear it by hand later.	 */	if (is_at_popf(child, regs))		return;		child->ptrace |= PT_DTRACE;}static void clear_singlestep(struct task_struct *child){	/* Always clear TIF_SINGLESTEP... */	clear_tsk_thread_flag(child, TIF_SINGLESTEP);	/* But touch TF only if it was set by us.. */	if (child->ptrace & PT_DTRACE) {		struct pt_regs *regs = get_child_regs(child);		regs->eflags &= ~TRAP_FLAG;		child->ptrace &= ~PT_DTRACE;	}}/* * Called by kernel/ptrace.c when detaching.. * * Make sure the single step bit is not set. */void ptrace_disable(struct task_struct *child){ 	clear_singlestep(child);	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);}/* * Perform get_thread_area on behalf of the traced child. */static intptrace_get_thread_area(struct task_struct *child,		       int idx, struct user_desc __user *user_desc){	struct user_desc info;	struct desc_struct *desc;/* * Get the current Thread-Local Storage area: */#define GET_BASE(desc) ( \	(((desc)->a >> 16) & 0x0000ffff) | \	(((desc)->b << 16) & 0x00ff0000) | \	( (desc)->b        & 0xff000000)   )#define GET_LIMIT(desc) ( \	((desc)->a & 0x0ffff) | \	 ((desc)->b & 0xf0000) )#define GET_32BIT(desc)		(((desc)->b >> 22) & 1)#define GET_CONTENTS(desc)	(((desc)->b >> 10) & 3)#define GET_WRITABLE(desc)	(((desc)->b >>  9) & 1)#define GET_LIMIT_PAGES(desc)	(((desc)->b >> 23) & 1)#define GET_PRESENT(desc)	(((desc)->b >> 15) & 1)#define GET_USEABLE(desc)	(((desc)->b >> 20) & 1)	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)		return -EINVAL;	desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;	info.entry_number = idx;	info.base_addr = GET_BASE(desc);	info.limit = GET_LIMIT(desc);	info.seg_32bit = GET_32BIT(desc);	info.contents = GET_CONTENTS(desc);	info.read_exec_only = !GET_WRITABLE(desc);	info.limit_in_pages = GET_LIMIT_PAGES(desc);	info.seg_not_present = !GET_PRESENT(desc);	info.useable = GET_USEABLE(desc);	if (copy_to_user(user_desc, &info, sizeof(info)))		return -EFAULT;	return 0;}/* * Perform set_thread_area on behalf of the traced child. */static intptrace_set_thread_area(struct task_struct *child,		       int idx, struct user_desc __user *user_desc){	struct user_desc info;	struct desc_struct *desc;	if (copy_from_user(&info, user_desc, sizeof(info)))		return -EFAULT;	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)		return -EINVAL;	desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;	if (LDT_empty(&info)) {		desc->a = 0;		desc->b = 0;	} else {		desc->a = LDT_entry_a(&info);		desc->b = LDT_entry_b(&info);	}	return 0;}long arch_ptrace(struct task_struct *child, long request, long addr, long data){	struct user * dummy = NULL;	int i, ret;	unsigned long __user *datap = (unsigned long __user *)data;	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: {

⌨️ 快捷键说明

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