ia64/linux-2.6.18-xen.hg

diff arch/sparc64/kernel/ptrace.c @ 0:831230e53067

Import 2.6.18 from kernel.org tarball.
author Ian Campbell <ian.campbell@xensource.com>
date Wed Apr 11 14:15:44 2007 +0100 (2007-04-11)
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/arch/sparc64/kernel/ptrace.c	Wed Apr 11 14:15:44 2007 +0100
     1.3 @@ -0,0 +1,688 @@
     1.4 +/* ptrace.c: Sparc process tracing support.
     1.5 + *
     1.6 + * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
     1.7 + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
     1.8 + *
     1.9 + * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
    1.10 + * and David Mosberger.
    1.11 + *
    1.12 + * Added Linux support -miguel (weird, eh?, the original code was meant
    1.13 + * to emulate SunOS).
    1.14 + */
    1.15 +
    1.16 +#include <linux/kernel.h>
    1.17 +#include <linux/sched.h>
    1.18 +#include <linux/mm.h>
    1.19 +#include <linux/errno.h>
    1.20 +#include <linux/ptrace.h>
    1.21 +#include <linux/user.h>
    1.22 +#include <linux/smp.h>
    1.23 +#include <linux/smp_lock.h>
    1.24 +#include <linux/security.h>
    1.25 +#include <linux/seccomp.h>
    1.26 +#include <linux/audit.h>
    1.27 +#include <linux/signal.h>
    1.28 +
    1.29 +#include <asm/asi.h>
    1.30 +#include <asm/pgtable.h>
    1.31 +#include <asm/system.h>
    1.32 +#include <asm/uaccess.h>
    1.33 +#include <asm/psrcompat.h>
    1.34 +#include <asm/visasm.h>
    1.35 +#include <asm/spitfire.h>
    1.36 +#include <asm/page.h>
    1.37 +#include <asm/cpudata.h>
    1.38 +
    1.39 +/* Returning from ptrace is a bit tricky because the syscall return
    1.40 + * low level code assumes any value returned which is negative and
    1.41 + * is a valid errno will mean setting the condition codes to indicate
    1.42 + * an error return.  This doesn't work, so we have this hook.
    1.43 + */
    1.44 +static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
    1.45 +{
    1.46 +	regs->u_regs[UREG_I0] = error;
    1.47 +	regs->tstate |= (TSTATE_ICARRY | TSTATE_XCARRY);
    1.48 +	regs->tpc = regs->tnpc;
    1.49 +	regs->tnpc += 4;
    1.50 +}
    1.51 +
    1.52 +static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
    1.53 +{
    1.54 +	regs->u_regs[UREG_I0] = value;
    1.55 +	regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
    1.56 +	regs->tpc = regs->tnpc;
    1.57 +	regs->tnpc += 4;
    1.58 +}
    1.59 +
    1.60 +static inline void
    1.61 +pt_succ_return_linux(struct pt_regs *regs, unsigned long value, void __user *addr)
    1.62 +{
    1.63 +	if (test_thread_flag(TIF_32BIT)) {
    1.64 +		if (put_user(value, (unsigned int __user *) addr)) {
    1.65 +			pt_error_return(regs, EFAULT);
    1.66 +			return;
    1.67 +		}
    1.68 +	} else {
    1.69 +		if (put_user(value, (long __user *) addr)) {
    1.70 +			pt_error_return(regs, EFAULT);
    1.71 +			return;
    1.72 +		}
    1.73 +	}
    1.74 +	regs->u_regs[UREG_I0] = 0;
    1.75 +	regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
    1.76 +	regs->tpc = regs->tnpc;
    1.77 +	regs->tnpc += 4;
    1.78 +}
    1.79 +
    1.80 +static void
    1.81 +pt_os_succ_return (struct pt_regs *regs, unsigned long val, void __user *addr)
    1.82 +{
    1.83 +	if (current->personality == PER_SUNOS)
    1.84 +		pt_succ_return (regs, val);
    1.85 +	else
    1.86 +		pt_succ_return_linux (regs, val, addr);
    1.87 +}
    1.88 +
    1.89 +/* #define ALLOW_INIT_TRACING */
    1.90 +/* #define DEBUG_PTRACE */
    1.91 +
    1.92 +#ifdef DEBUG_PTRACE
    1.93 +char *pt_rq [] = {
    1.94 +	/* 0  */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR",
    1.95 +	/* 4  */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT",
    1.96 +	/* 8  */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH",
    1.97 +	/* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS",
    1.98 +	/* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT",
    1.99 +	/* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown",
   1.100 +	/* 24 */ "SYSCALL", ""
   1.101 +};
   1.102 +#endif
   1.103 +
   1.104 +/*
   1.105 + * Called by kernel/ptrace.c when detaching..
   1.106 + *
   1.107 + * Make sure single step bits etc are not set.
   1.108 + */
   1.109 +void ptrace_disable(struct task_struct *child)
   1.110 +{
   1.111 +	/* nothing to do */
   1.112 +}
   1.113 +
   1.114 +/* To get the necessary page struct, access_process_vm() first calls
   1.115 + * get_user_pages().  This has done a flush_dcache_page() on the
   1.116 + * accessed page.  Then our caller (copy_{to,from}_user_page()) did
   1.117 + * to memcpy to read/write the data from that page.
   1.118 + *
   1.119 + * Now, the only thing we have to do is:
   1.120 + * 1) flush the D-cache if it's possible than an illegal alias
   1.121 + *    has been created
   1.122 + * 2) flush the I-cache if this is pre-cheetah and we did a write
   1.123 + */
   1.124 +void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
   1.125 +			 unsigned long uaddr, void *kaddr,
   1.126 +			 unsigned long len, int write)
   1.127 +{
   1.128 +	BUG_ON(len > PAGE_SIZE);
   1.129 +
   1.130 +	if (tlb_type == hypervisor)
   1.131 +		return;
   1.132 +
   1.133 +#ifdef DCACHE_ALIASING_POSSIBLE
   1.134 +	/* If bit 13 of the kernel address we used to access the
   1.135 +	 * user page is the same as the virtual address that page
   1.136 +	 * is mapped to in the user's address space, we can skip the
   1.137 +	 * D-cache flush.
   1.138 +	 */
   1.139 +	if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) {
   1.140 +		unsigned long start = __pa(kaddr);
   1.141 +		unsigned long end = start + len;
   1.142 +		unsigned long dcache_line_size;
   1.143 +
   1.144 +		dcache_line_size = local_cpu_data().dcache_line_size;
   1.145 +
   1.146 +		if (tlb_type == spitfire) {
   1.147 +			for (; start < end; start += dcache_line_size)
   1.148 +				spitfire_put_dcache_tag(start & 0x3fe0, 0x0);
   1.149 +		} else {
   1.150 +			start &= ~(dcache_line_size - 1);
   1.151 +			for (; start < end; start += dcache_line_size)
   1.152 +				__asm__ __volatile__(
   1.153 +					"stxa %%g0, [%0] %1\n\t"
   1.154 +					"membar #Sync"
   1.155 +					: /* no outputs */
   1.156 +					: "r" (start),
   1.157 +					"i" (ASI_DCACHE_INVALIDATE));
   1.158 +		}
   1.159 +	}
   1.160 +#endif
   1.161 +	if (write && tlb_type == spitfire) {
   1.162 +		unsigned long start = (unsigned long) kaddr;
   1.163 +		unsigned long end = start + len;
   1.164 +		unsigned long icache_line_size;
   1.165 +
   1.166 +		icache_line_size = local_cpu_data().icache_line_size;
   1.167 +
   1.168 +		for (; start < end; start += icache_line_size)
   1.169 +			flushi(start);
   1.170 +	}
   1.171 +}
   1.172 +
   1.173 +asmlinkage void do_ptrace(struct pt_regs *regs)
   1.174 +{
   1.175 +	int request = regs->u_regs[UREG_I0];
   1.176 +	pid_t pid = regs->u_regs[UREG_I1];
   1.177 +	unsigned long addr = regs->u_regs[UREG_I2];
   1.178 +	unsigned long data = regs->u_regs[UREG_I3];
   1.179 +	unsigned long addr2 = regs->u_regs[UREG_I4];
   1.180 +	struct task_struct *child;
   1.181 +	int ret;
   1.182 +
   1.183 +	if (test_thread_flag(TIF_32BIT)) {
   1.184 +		addr &= 0xffffffffUL;
   1.185 +		data &= 0xffffffffUL;
   1.186 +		addr2 &= 0xffffffffUL;
   1.187 +	}
   1.188 +	lock_kernel();
   1.189 +#ifdef DEBUG_PTRACE
   1.190 +	{
   1.191 +		char *s;
   1.192 +
   1.193 +		if ((request >= 0) && (request <= 24))
   1.194 +			s = pt_rq [request];
   1.195 +		else
   1.196 +			s = "unknown";
   1.197 +
   1.198 +		if (request == PTRACE_POKEDATA && data == 0x91d02001){
   1.199 +			printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n",
   1.200 +				pid, addr, addr2);
   1.201 +		} else 
   1.202 +			printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n",
   1.203 +			       s, request, pid, addr, data, addr2);
   1.204 +	}
   1.205 +#endif
   1.206 +	if (request == PTRACE_TRACEME) {
   1.207 +		ret = ptrace_traceme();
   1.208 +		pt_succ_return(regs, 0);
   1.209 +		goto out;
   1.210 +	}
   1.211 +
   1.212 +	child = ptrace_get_task_struct(pid);
   1.213 +	if (IS_ERR(child)) {
   1.214 +		ret = PTR_ERR(child);
   1.215 +		pt_error_return(regs, -ret);
   1.216 +		goto out;
   1.217 +	}
   1.218 +
   1.219 +	if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
   1.220 +	    || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
   1.221 +		if (ptrace_attach(child)) {
   1.222 +			pt_error_return(regs, EPERM);
   1.223 +			goto out_tsk;
   1.224 +		}
   1.225 +		pt_succ_return(regs, 0);
   1.226 +		goto out_tsk;
   1.227 +	}
   1.228 +
   1.229 +	ret = ptrace_check_attach(child, request == PTRACE_KILL);
   1.230 +	if (ret < 0) {
   1.231 +		pt_error_return(regs, -ret);
   1.232 +		goto out_tsk;
   1.233 +	}
   1.234 +
   1.235 +	if (!(test_thread_flag(TIF_32BIT))	&&
   1.236 +	    ((request == PTRACE_READDATA64)		||
   1.237 +	     (request == PTRACE_WRITEDATA64)		||
   1.238 +	     (request == PTRACE_READTEXT64)		||
   1.239 +	     (request == PTRACE_WRITETEXT64)		||
   1.240 +	     (request == PTRACE_PEEKTEXT64)		||
   1.241 +	     (request == PTRACE_POKETEXT64)		||
   1.242 +	     (request == PTRACE_PEEKDATA64)		||
   1.243 +	     (request == PTRACE_POKEDATA64))) {
   1.244 +		addr = regs->u_regs[UREG_G2];
   1.245 +		addr2 = regs->u_regs[UREG_G3];
   1.246 +		request -= 30; /* wheee... */
   1.247 +	}
   1.248 +
   1.249 +	switch(request) {
   1.250 +	case PTRACE_PEEKUSR:
   1.251 +		if (addr != 0)
   1.252 +			pt_error_return(regs, EIO);
   1.253 +		else
   1.254 +			pt_succ_return(regs, 0);
   1.255 +		goto out_tsk;
   1.256 +
   1.257 +	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
   1.258 +	case PTRACE_PEEKDATA: {
   1.259 +		unsigned long tmp64;
   1.260 +		unsigned int tmp32;
   1.261 +		int res, copied;
   1.262 +
   1.263 +		res = -EIO;
   1.264 +		if (test_thread_flag(TIF_32BIT)) {
   1.265 +			copied = access_process_vm(child, addr,
   1.266 +						   &tmp32, sizeof(tmp32), 0);
   1.267 +			tmp64 = (unsigned long) tmp32;
   1.268 +			if (copied == sizeof(tmp32))
   1.269 +				res = 0;
   1.270 +		} else {
   1.271 +			copied = access_process_vm(child, addr,
   1.272 +						   &tmp64, sizeof(tmp64), 0);
   1.273 +			if (copied == sizeof(tmp64))
   1.274 +				res = 0;
   1.275 +		}
   1.276 +		if (res < 0)
   1.277 +			pt_error_return(regs, -res);
   1.278 +		else
   1.279 +			pt_os_succ_return(regs, tmp64, (void __user *) data);
   1.280 +		goto out_tsk;
   1.281 +	}
   1.282 +
   1.283 +	case PTRACE_POKETEXT: /* write the word at location addr. */
   1.284 +	case PTRACE_POKEDATA: {
   1.285 +		unsigned long tmp64;
   1.286 +		unsigned int tmp32;
   1.287 +		int copied, res = -EIO;
   1.288 +
   1.289 +		if (test_thread_flag(TIF_32BIT)) {
   1.290 +			tmp32 = data;
   1.291 +			copied = access_process_vm(child, addr,
   1.292 +						   &tmp32, sizeof(tmp32), 1);
   1.293 +			if (copied == sizeof(tmp32))
   1.294 +				res = 0;
   1.295 +		} else {
   1.296 +			tmp64 = data;
   1.297 +			copied = access_process_vm(child, addr,
   1.298 +						   &tmp64, sizeof(tmp64), 1);
   1.299 +			if (copied == sizeof(tmp64))
   1.300 +				res = 0;
   1.301 +		}
   1.302 +		if (res < 0)
   1.303 +			pt_error_return(regs, -res);
   1.304 +		else
   1.305 +			pt_succ_return(regs, res);
   1.306 +		goto out_tsk;
   1.307 +	}
   1.308 +
   1.309 +	case PTRACE_GETREGS: {
   1.310 +		struct pt_regs32 __user *pregs =
   1.311 +			(struct pt_regs32 __user *) addr;
   1.312 +		struct pt_regs *cregs = task_pt_regs(child);
   1.313 +		int rval;
   1.314 +
   1.315 +		if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
   1.316 +		    __put_user(cregs->tpc, (&pregs->pc)) ||
   1.317 +		    __put_user(cregs->tnpc, (&pregs->npc)) ||
   1.318 +		    __put_user(cregs->y, (&pregs->y))) {
   1.319 +			pt_error_return(regs, EFAULT);
   1.320 +			goto out_tsk;
   1.321 +		}
   1.322 +		for (rval = 1; rval < 16; rval++)
   1.323 +			if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
   1.324 +				pt_error_return(regs, EFAULT);
   1.325 +				goto out_tsk;
   1.326 +			}
   1.327 +		pt_succ_return(regs, 0);
   1.328 +#ifdef DEBUG_PTRACE
   1.329 +		printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
   1.330 +#endif
   1.331 +		goto out_tsk;
   1.332 +	}
   1.333 +
   1.334 +	case PTRACE_GETREGS64: {
   1.335 +		struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
   1.336 +		struct pt_regs *cregs = task_pt_regs(child);
   1.337 +		unsigned long tpc = cregs->tpc;
   1.338 +		int rval;
   1.339 +
   1.340 +		if ((task_thread_info(child)->flags & _TIF_32BIT) != 0)
   1.341 +			tpc &= 0xffffffff;
   1.342 +		if (__put_user(cregs->tstate, (&pregs->tstate)) ||
   1.343 +		    __put_user(tpc, (&pregs->tpc)) ||
   1.344 +		    __put_user(cregs->tnpc, (&pregs->tnpc)) ||
   1.345 +		    __put_user(cregs->y, (&pregs->y))) {
   1.346 +			pt_error_return(regs, EFAULT);
   1.347 +			goto out_tsk;
   1.348 +		}
   1.349 +		for (rval = 1; rval < 16; rval++)
   1.350 +			if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
   1.351 +				pt_error_return(regs, EFAULT);
   1.352 +				goto out_tsk;
   1.353 +			}
   1.354 +		pt_succ_return(regs, 0);
   1.355 +#ifdef DEBUG_PTRACE
   1.356 +		printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
   1.357 +#endif
   1.358 +		goto out_tsk;
   1.359 +	}
   1.360 +
   1.361 +	case PTRACE_SETREGS: {
   1.362 +		struct pt_regs32 __user *pregs =
   1.363 +			(struct pt_regs32 __user *) addr;
   1.364 +		struct pt_regs *cregs = task_pt_regs(child);
   1.365 +		unsigned int psr, pc, npc, y;
   1.366 +		int i;
   1.367 +
   1.368 +		/* Must be careful, tracing process can only set certain
   1.369 +		 * bits in the psr.
   1.370 +		 */
   1.371 +		if (__get_user(psr, (&pregs->psr)) ||
   1.372 +		    __get_user(pc, (&pregs->pc)) ||
   1.373 +		    __get_user(npc, (&pregs->npc)) ||
   1.374 +		    __get_user(y, (&pregs->y))) {
   1.375 +			pt_error_return(regs, EFAULT);
   1.376 +			goto out_tsk;
   1.377 +		}
   1.378 +		cregs->tstate &= ~(TSTATE_ICC);
   1.379 +		cregs->tstate |= psr_to_tstate_icc(psr);
   1.380 +               	if (!((pc | npc) & 3)) {
   1.381 +			cregs->tpc = pc;
   1.382 +			cregs->tnpc = npc;
   1.383 +		}
   1.384 +		cregs->y = y;
   1.385 +		for (i = 1; i < 16; i++) {
   1.386 +			if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
   1.387 +				pt_error_return(regs, EFAULT);
   1.388 +				goto out_tsk;
   1.389 +			}
   1.390 +		}
   1.391 +		pt_succ_return(regs, 0);
   1.392 +		goto out_tsk;
   1.393 +	}
   1.394 +
   1.395 +	case PTRACE_SETREGS64: {
   1.396 +		struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
   1.397 +		struct pt_regs *cregs = task_pt_regs(child);
   1.398 +		unsigned long tstate, tpc, tnpc, y;
   1.399 +		int i;
   1.400 +
   1.401 +		/* Must be careful, tracing process can only set certain
   1.402 +		 * bits in the psr.
   1.403 +		 */
   1.404 +		if (__get_user(tstate, (&pregs->tstate)) ||
   1.405 +		    __get_user(tpc, (&pregs->tpc)) ||
   1.406 +		    __get_user(tnpc, (&pregs->tnpc)) ||
   1.407 +		    __get_user(y, (&pregs->y))) {
   1.408 +			pt_error_return(regs, EFAULT);
   1.409 +			goto out_tsk;
   1.410 +		}
   1.411 +		if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) {
   1.412 +			tpc &= 0xffffffff;
   1.413 +			tnpc &= 0xffffffff;
   1.414 +		}
   1.415 +		tstate &= (TSTATE_ICC | TSTATE_XCC);
   1.416 +		cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
   1.417 +		cregs->tstate |= tstate;
   1.418 +		if (!((tpc | tnpc) & 3)) {
   1.419 +			cregs->tpc = tpc;
   1.420 +			cregs->tnpc = tnpc;
   1.421 +		}
   1.422 +		cregs->y = y;
   1.423 +		for (i = 1; i < 16; i++) {
   1.424 +			if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
   1.425 +				pt_error_return(regs, EFAULT);
   1.426 +				goto out_tsk;
   1.427 +			}
   1.428 +		}
   1.429 +		pt_succ_return(regs, 0);
   1.430 +		goto out_tsk;
   1.431 +	}
   1.432 +
   1.433 +	case PTRACE_GETFPREGS: {
   1.434 +		struct fps {
   1.435 +			unsigned int regs[32];
   1.436 +			unsigned int fsr;
   1.437 +			unsigned int flags;
   1.438 +			unsigned int extra;
   1.439 +			unsigned int fpqd;
   1.440 +			struct fq {
   1.441 +				unsigned int insnaddr;
   1.442 +				unsigned int insn;
   1.443 +			} fpq[16];
   1.444 +		};
   1.445 +		struct fps __user *fps = (struct fps __user *) addr;
   1.446 +		unsigned long *fpregs = task_thread_info(child)->fpregs;
   1.447 +
   1.448 +		if (copy_to_user(&fps->regs[0], fpregs,
   1.449 +				 (32 * sizeof(unsigned int))) ||
   1.450 +		    __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr)) ||
   1.451 +		    __put_user(0, (&fps->fpqd)) ||
   1.452 +		    __put_user(0, (&fps->flags)) ||
   1.453 +		    __put_user(0, (&fps->extra)) ||
   1.454 +		    clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) {
   1.455 +			pt_error_return(regs, EFAULT);
   1.456 +			goto out_tsk;
   1.457 +		}
   1.458 +		pt_succ_return(regs, 0);
   1.459 +		goto out_tsk;
   1.460 +	}
   1.461 +
   1.462 +	case PTRACE_GETFPREGS64: {
   1.463 +		struct fps {
   1.464 +			unsigned int regs[64];
   1.465 +			unsigned long fsr;
   1.466 +		};
   1.467 +		struct fps __user *fps = (struct fps __user *) addr;
   1.468 +		unsigned long *fpregs = task_thread_info(child)->fpregs;
   1.469 +
   1.470 +		if (copy_to_user(&fps->regs[0], fpregs,
   1.471 +				 (64 * sizeof(unsigned int))) ||
   1.472 +		    __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) {
   1.473 +			pt_error_return(regs, EFAULT);
   1.474 +			goto out_tsk;
   1.475 +		}
   1.476 +		pt_succ_return(regs, 0);
   1.477 +		goto out_tsk;
   1.478 +	}
   1.479 +
   1.480 +	case PTRACE_SETFPREGS: {
   1.481 +		struct fps {
   1.482 +			unsigned int regs[32];
   1.483 +			unsigned int fsr;
   1.484 +			unsigned int flags;
   1.485 +			unsigned int extra;
   1.486 +			unsigned int fpqd;
   1.487 +			struct fq {
   1.488 +				unsigned int insnaddr;
   1.489 +				unsigned int insn;
   1.490 +			} fpq[16];
   1.491 +		};
   1.492 +		struct fps __user *fps = (struct fps __user *) addr;
   1.493 +		unsigned long *fpregs = task_thread_info(child)->fpregs;
   1.494 +		unsigned fsr;
   1.495 +
   1.496 +		if (copy_from_user(fpregs, &fps->regs[0],
   1.497 +				   (32 * sizeof(unsigned int))) ||
   1.498 +		    __get_user(fsr, (&fps->fsr))) {
   1.499 +			pt_error_return(regs, EFAULT);
   1.500 +			goto out_tsk;
   1.501 +		}
   1.502 +		task_thread_info(child)->xfsr[0] &= 0xffffffff00000000UL;
   1.503 +		task_thread_info(child)->xfsr[0] |= fsr;
   1.504 +		if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF))
   1.505 +			task_thread_info(child)->gsr[0] = 0;
   1.506 +		task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL);
   1.507 +		pt_succ_return(regs, 0);
   1.508 +		goto out_tsk;
   1.509 +	}
   1.510 +
   1.511 +	case PTRACE_SETFPREGS64: {
   1.512 +		struct fps {
   1.513 +			unsigned int regs[64];
   1.514 +			unsigned long fsr;
   1.515 +		};
   1.516 +		struct fps __user *fps = (struct fps __user *) addr;
   1.517 +		unsigned long *fpregs = task_thread_info(child)->fpregs;
   1.518 +
   1.519 +		if (copy_from_user(fpregs, &fps->regs[0],
   1.520 +				   (64 * sizeof(unsigned int))) ||
   1.521 +		    __get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) {
   1.522 +			pt_error_return(regs, EFAULT);
   1.523 +			goto out_tsk;
   1.524 +		}
   1.525 +		if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF))
   1.526 +			task_thread_info(child)->gsr[0] = 0;
   1.527 +		task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
   1.528 +		pt_succ_return(regs, 0);
   1.529 +		goto out_tsk;
   1.530 +	}
   1.531 +
   1.532 +	case PTRACE_READTEXT:
   1.533 +	case PTRACE_READDATA: {
   1.534 +		int res = ptrace_readdata(child, addr,
   1.535 +					  (char __user *)addr2, data);
   1.536 +		if (res == data) {
   1.537 +			pt_succ_return(regs, 0);
   1.538 +			goto out_tsk;
   1.539 +		}
   1.540 +		if (res >= 0)
   1.541 +			res = -EIO;
   1.542 +		pt_error_return(regs, -res);
   1.543 +		goto out_tsk;
   1.544 +	}
   1.545 +
   1.546 +	case PTRACE_WRITETEXT:
   1.547 +	case PTRACE_WRITEDATA: {
   1.548 +		int res = ptrace_writedata(child, (char __user *) addr2,
   1.549 +					   addr, data);
   1.550 +		if (res == data) {
   1.551 +			pt_succ_return(regs, 0);
   1.552 +			goto out_tsk;
   1.553 +		}
   1.554 +		if (res >= 0)
   1.555 +			res = -EIO;
   1.556 +		pt_error_return(regs, -res);
   1.557 +		goto out_tsk;
   1.558 +	}
   1.559 +	case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
   1.560 +		addr = 1;
   1.561 +
   1.562 +	case PTRACE_CONT: { /* restart after signal. */
   1.563 +		if (!valid_signal(data)) {
   1.564 +			pt_error_return(regs, EIO);
   1.565 +			goto out_tsk;
   1.566 +		}
   1.567 +
   1.568 +		if (request == PTRACE_SYSCALL) {
   1.569 +			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
   1.570 +		} else {
   1.571 +			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
   1.572 +		}
   1.573 +
   1.574 +		child->exit_code = data;
   1.575 +#ifdef DEBUG_PTRACE
   1.576 +		printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
   1.577 +			child->pid, child->exit_code,
   1.578 +			task_pt_regs(child)->tpc,
   1.579 +			task_pt_regs(child)->tnpc);
   1.580 +		       
   1.581 +#endif
   1.582 +		wake_up_process(child);
   1.583 +		pt_succ_return(regs, 0);
   1.584 +		goto out_tsk;
   1.585 +	}
   1.586 +
   1.587 +/*
   1.588 + * make the child exit.  Best I can do is send it a sigkill. 
   1.589 + * perhaps it should be put in the status that it wants to 
   1.590 + * exit.
   1.591 + */
   1.592 +	case PTRACE_KILL: {
   1.593 +		if (child->exit_state == EXIT_ZOMBIE) {	/* already dead */
   1.594 +			pt_succ_return(regs, 0);
   1.595 +			goto out_tsk;
   1.596 +		}
   1.597 +		child->exit_code = SIGKILL;
   1.598 +		wake_up_process(child);
   1.599 +		pt_succ_return(regs, 0);
   1.600 +		goto out_tsk;
   1.601 +	}
   1.602 +
   1.603 +	case PTRACE_SUNDETACH: { /* detach a process that was attached. */
   1.604 +		int error = ptrace_detach(child, data);
   1.605 +		if (error) {
   1.606 +			pt_error_return(regs, EIO);
   1.607 +			goto out_tsk;
   1.608 +		}
   1.609 +		pt_succ_return(regs, 0);
   1.610 +		goto out_tsk;
   1.611 +	}
   1.612 +
   1.613 +	/* PTRACE_DUMPCORE unsupported... */
   1.614 +
   1.615 +	case PTRACE_GETEVENTMSG: {
   1.616 +		int err;
   1.617 +
   1.618 +		if (test_thread_flag(TIF_32BIT))
   1.619 +			err = put_user(child->ptrace_message,
   1.620 +				       (unsigned int __user *) data);
   1.621 +		else
   1.622 +			err = put_user(child->ptrace_message,
   1.623 +				       (unsigned long __user *) data);
   1.624 +		if (err)
   1.625 +			pt_error_return(regs, -err);
   1.626 +		else
   1.627 +			pt_succ_return(regs, 0);
   1.628 +		break;
   1.629 +	}
   1.630 +
   1.631 +	default: {
   1.632 +		int err = ptrace_request(child, request, addr, data);
   1.633 +		if (err)
   1.634 +			pt_error_return(regs, -err);
   1.635 +		else
   1.636 +			pt_succ_return(regs, 0);
   1.637 +		goto out_tsk;
   1.638 +	}
   1.639 +	}
   1.640 +out_tsk:
   1.641 +	if (child)
   1.642 +		put_task_struct(child);
   1.643 +out:
   1.644 +	unlock_kernel();
   1.645 +}
   1.646 +
   1.647 +asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
   1.648 +{
   1.649 +	/* do the secure computing check first */
   1.650 +	secure_computing(regs->u_regs[UREG_G1]);
   1.651 +
   1.652 +	if (unlikely(current->audit_context) && syscall_exit_p) {
   1.653 +		unsigned long tstate = regs->tstate;
   1.654 +		int result = AUDITSC_SUCCESS;
   1.655 +
   1.656 +		if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
   1.657 +			result = AUDITSC_FAILURE;
   1.658 +
   1.659 +		audit_syscall_exit(result, regs->u_regs[UREG_I0]);
   1.660 +	}
   1.661 +
   1.662 +	if (!(current->ptrace & PT_PTRACED))
   1.663 +		goto out;
   1.664 +
   1.665 +	if (!test_thread_flag(TIF_SYSCALL_TRACE))
   1.666 +		goto out;
   1.667 +
   1.668 +	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
   1.669 +				 ? 0x80 : 0));
   1.670 +
   1.671 +	/*
   1.672 +	 * this isn't the same as continuing with a signal, but it will do
   1.673 +	 * for normal use.  strace only continues with a signal if the
   1.674 +	 * stopping signal is not SIGTRAP.  -brl
   1.675 +	 */
   1.676 +	if (current->exit_code) {
   1.677 +		send_sig(current->exit_code, current, 1);
   1.678 +		current->exit_code = 0;
   1.679 +	}
   1.680 +
   1.681 +out:
   1.682 +	if (unlikely(current->audit_context) && !syscall_exit_p)
   1.683 +		audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
   1.684 +				     AUDIT_ARCH_SPARC :
   1.685 +				     AUDIT_ARCH_SPARC64),
   1.686 +				    regs->u_regs[UREG_G1],
   1.687 +				    regs->u_regs[UREG_I0],
   1.688 +				    regs->u_regs[UREG_I1],
   1.689 +				    regs->u_regs[UREG_I2],
   1.690 +				    regs->u_regs[UREG_I3]);
   1.691 +}