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

📄 ptrace.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  arch/s390/kernel/ptrace.c * *  S390 version *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), *               Martin Schwidefsky (schwidefsky@de.ibm.com) * *  Based on PowerPC version  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * *  Derived from "arch/m68k/kernel/ptrace.c" *  Copyright (C) 1994 by Hamish Macdonald *  Taken from linux/kernel/ptrace.c and modified for M680x0. *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds * * Modified by Cort Dougan (cort@cs.nmt.edu)  * * * This file is subject to the terms and conditions of the GNU General * Public License.  See the file README.legal in the main directory of * this archive for more details. */#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/signal.h>#include <asm/segment.h>#include <asm/page.h>#include <asm/pgtable.h>#include <asm/pgalloc.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/unistd.h>#ifdef CONFIG_S390_SUPPORT#include "compat_ptrace.h"#endifstatic voidFixPerRegisters(struct task_struct *task){	struct pt_regs *regs;	per_struct *per_info;	regs = __KSTK_PTREGS(task);	per_info = (per_struct *) &task->thread.per_info;	per_info->control_regs.bits.em_instruction_fetch =		per_info->single_step | per_info->instruction_fetch;		if (per_info->single_step) {		per_info->control_regs.bits.starting_addr = 0;#ifdef CONFIG_S390_SUPPORT		if (test_thread_flag(TIF_31BIT))			per_info->control_regs.bits.ending_addr = 0x7fffffffUL;		else#endif			per_info->control_regs.bits.ending_addr = PSW_ADDR_INSN;	} else {		per_info->control_regs.bits.starting_addr =			per_info->starting_addr;		per_info->control_regs.bits.ending_addr =			per_info->ending_addr;	}	/*	 * if any of the control reg tracing bits are on 	 * we switch on per in the psw	 */	if (per_info->control_regs.words.cr[0] & PER_EM_MASK)		regs->psw.mask |= PSW_MASK_PER;	else		regs->psw.mask &= ~PSW_MASK_PER;	if (per_info->control_regs.bits.em_storage_alteration)		per_info->control_regs.bits.storage_alt_space_ctl = 1;	else		per_info->control_regs.bits.storage_alt_space_ctl = 0;}voidset_single_step(struct task_struct *task){	task->thread.per_info.single_step = 1;	FixPerRegisters(task);}voidclear_single_step(struct task_struct *task){	task->thread.per_info.single_step = 0;	FixPerRegisters(task);}/* * Called by kernel/ptrace.c when detaching.. * * Make sure single step bits etc are not set. */voidptrace_disable(struct task_struct *child){	/* make sure the single step bit is not set. */	clear_single_step(child);}#ifndef CONFIG_ARCH_S390X# define __ADDR_MASK 3#else# define __ADDR_MASK 7#endif/* * Read the word at offset addr from the user area of a process. The * trouble here is that the information is littered over different * locations. The process registers are found on the kernel stack, * the floating point stuff and the trace settings are stored in * the task structure. In addition the different structures in * struct user contain pad bytes that should be read as zeroes. * Lovely... */static intpeek_user(struct task_struct *child, addr_t addr, addr_t data){	struct user *dummy = NULL;	addr_t offset, tmp, mask;	/*	 * Stupid gdb peeks/pokes the access registers in 64 bit with	 * an alignment of 4. Programmers from hell...	 */	mask = __ADDR_MASK;#ifdef CONFIG_ARCH_S390X	if (addr >= (addr_t) &dummy->regs.acrs &&	    addr < (addr_t) &dummy->regs.orig_gpr2)		mask = 3;#endif	if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)		return -EIO;	if (addr < (addr_t) &dummy->regs.acrs) {		/*		 * psw and gprs are stored on the stack		 */		tmp = *(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr);		if (addr == (addr_t) &dummy->regs.psw.mask)			/* Remove per bit from user psw. */			tmp &= ~PSW_MASK_PER;	} else if (addr < (addr_t) &dummy->regs.orig_gpr2) {		/*		 * access registers are stored in the thread structure		 */		offset = addr - (addr_t) &dummy->regs.acrs;#ifdef CONFIG_ARCH_S390X		/*		 * Very special case: old & broken 64 bit gdb reading		 * from acrs[15]. Result is a 64 bit value. Read the		 * 32 bit acrs[15] value and shift it by 32. Sick...		 */		if (addr == (addr_t) &dummy->regs.acrs[15])			tmp = ((unsigned long) child->thread.acrs[15]) << 32;		else#endif		tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset);	} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {		/*		 * orig_gpr2 is stored on the kernel stack		 */		tmp = (addr_t) __KSTK_PTREGS(child)->orig_gpr2;	} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {		/* 		 * floating point regs. are stored in the thread structure		 */		offset = addr - (addr_t) &dummy->regs.fp_regs;		tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset);		if (addr == (addr_t) &dummy->regs.fp_regs.fpc)			tmp &= (unsigned long) FPC_VALID_MASK				<< (BITS_PER_LONG - 32);	} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {		/*		 * per_info is found in the thread structure		 */		offset = addr - (addr_t) &dummy->regs.per_info;		tmp = *(addr_t *)((addr_t) &child->thread.per_info + offset);	} else		tmp = 0;	return put_user(tmp, (addr_t __user *) data);}/* * Write a word to the user area of a process at location addr. This * operation does have an additional problem compared to peek_user. * Stores to the program status word and on the floating point * control register needs to get checked for validity. */static intpoke_user(struct task_struct *child, addr_t addr, addr_t data){	struct user *dummy = NULL;	addr_t offset, mask;	/*	 * Stupid gdb peeks/pokes the access registers in 64 bit with	 * an alignment of 4. Programmers from hell indeed...	 */	mask = __ADDR_MASK;#ifdef CONFIG_ARCH_S390X	if (addr >= (addr_t) &dummy->regs.acrs &&	    addr < (addr_t) &dummy->regs.orig_gpr2)		mask = 3;#endif	if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)		return -EIO;	if (addr < (addr_t) &dummy->regs.acrs) {		/*		 * psw and gprs are stored on the stack		 */		if (addr == (addr_t) &dummy->regs.psw.mask &&#ifdef CONFIG_S390_SUPPORT		    data != PSW_MASK_MERGE(PSW_USER32_BITS, data) &&#endif		    data != PSW_MASK_MERGE(PSW_USER_BITS, data))			/* Invalid psw mask. */			return -EINVAL;#ifndef CONFIG_ARCH_S390X		if (addr == (addr_t) &dummy->regs.psw.addr)			/* I'd like to reject addresses without the			   high order bit but older gdb's rely on it */			data |= PSW_ADDR_AMODE;#endif		*(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr) = data;	} else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) {		/*		 * access registers are stored in the thread structure		 */		offset = addr - (addr_t) &dummy->regs.acrs;#ifdef CONFIG_ARCH_S390X		/*		 * Very special case: old & broken 64 bit gdb writing		 * to acrs[15] with a 64 bit value. Ignore the lower		 * half of the value and write the upper 32 bit to		 * acrs[15]. Sick...		 */		if (addr == (addr_t) &dummy->regs.acrs[15])			child->thread.acrs[15] = (unsigned int) (data >> 32);		else#endif		*(addr_t *)((addr_t) &child->thread.acrs + offset) = data;	} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {		/*		 * orig_gpr2 is stored on the kernel stack		 */		__KSTK_PTREGS(child)->orig_gpr2 = data;	} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {		/*		 * floating point regs. are stored in the thread structure		 */		if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&		    (data & ~((unsigned long) FPC_VALID_MASK			      << (BITS_PER_LONG - 32))) != 0)			return -EINVAL;		offset = addr - (addr_t) &dummy->regs.fp_regs;		*(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data;	} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {		/*		 * per_info is found in the thread structure 		 */		offset = addr - (addr_t) &dummy->regs.per_info;		*(addr_t *)((addr_t) &child->thread.per_info + offset) = data;	}	FixPerRegisters(child);	return 0;}static intdo_ptrace_normal(struct task_struct *child, long request, long addr, long data){	unsigned long tmp;	ptrace_area parea; 	int copied, ret;	switch (request) {	case PTRACE_PEEKTEXT:	case PTRACE_PEEKDATA:		/* Remove high order bit from address (only for 31 bit). */		addr &= PSW_ADDR_INSN;		/* read word at location addr. */		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);		if (copied != sizeof(tmp))			return -EIO;		return put_user(tmp, (unsigned long __user *) data);	case PTRACE_PEEKUSR:		/* read the word at location addr in the USER area. */		return peek_user(child, addr, data);	case PTRACE_POKETEXT:	case PTRACE_POKEDATA:		/* Remove high order bit from address (only for 31 bit). */		addr &= PSW_ADDR_INSN;		/* write the word at location addr. */		copied = access_process_vm(child, addr, &data, sizeof(data),1);		if (copied != sizeof(data))			return -EIO;		return 0;	case PTRACE_POKEUSR:		/* write the word at location addr in the USER area */		return poke_user(child, addr, data);	case PTRACE_PEEKUSR_AREA:	case PTRACE_POKEUSR_AREA:		if (copy_from_user(&parea, (void __user *) addr,							sizeof(parea)))			return -EFAULT;		addr = parea.kernel_addr;		data = parea.process_addr;		copied = 0;		while (copied < parea.len) {			if (request == PTRACE_PEEKUSR_AREA)				ret = peek_user(child, addr, data);			else {				addr_t tmp;				if (get_user (tmp, (addr_t __user *) data))					return -EFAULT;				ret = poke_user(child, addr, tmp);			}			if (ret)				return ret;			addr += sizeof(unsigned long);			data += sizeof(unsigned long);			copied += sizeof(unsigned long);		}		return 0;	}	return ptrace_request(child, request, addr, data);}#ifdef CONFIG_S390_SUPPORT/* * Now the fun part starts... a 31 bit program running in the * 31 bit emulation tracing another program. PTRACE_PEEKTEXT, * PTRACE_PEEKDATA, PTRACE_POKETEXT and PTRACE_POKEDATA are easy * to handle, the difference to the 64 bit versions of the requests * is that the access is done in multiples of 4 byte instead of * 8 bytes (sizeof(unsigned long) on 31/64 bit). * The ugly part are PTRACE_PEEKUSR, PTRACE_PEEKUSR_AREA, * PTRACE_POKEUSR and PTRACE_POKEUSR_AREA. If the traced program * is a 31 bit program too, the content of struct user can be * emulated. A 31 bit program peeking into the struct user of * a 64 bit program is a no-no. *//* * Same as peek_user but for a 31 bit program. */static intpeek_user_emu31(struct task_struct *child, addr_t addr, addr_t data){	struct user32 *dummy32 = NULL;	per_struct32 *dummy_per32 = NULL;	addr_t offset;	__u32 tmp;	if (!test_thread_flag(TIF_31BIT) ||	    (addr & 3) || addr > sizeof(struct user) - 3)		return -EIO;	if (addr < (addr_t) &dummy32->regs.acrs) {		/*		 * psw and gprs are stored on the stack		 */

⌨️ 快捷键说明

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