diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index cb05cb76b217..1dafb61ea7f9 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -1,11 +1,6 @@ -/*- - * Copyright (c) 1982, 1986, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. +/* + * Copyright (c) 1994, Sean Eric Fagan + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -17,16 +12,14 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * This product includes software developed by Sean Eric Fagan. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -35,14 +28,163 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: @(#)sys_process.c 8.1 (Berkeley) 6/10/93 - * $Id$ + * $Id$ */ #include #include +#include +#include #include +#include +#include +#include +#include +#include + +#include "user.h" + +int +pread (struct proc *procp, unsigned int addr, unsigned int *retval) { + int rv; + vm_map_t map, tmap; + vm_object_t object; + vm_offset_t kva = 0; + int page_offset; /* offset into page */ + vm_offset_t pageno; /* page number */ + vm_map_entry_t out_entry; + vm_prot_t out_prot; + boolean_t wired, single_use; + vm_offset_t off; + + /* Map page into kernel space */ + + map = &procp->p_vmspace->vm_map; + + page_offset = addr - trunc_page(addr); + pageno = trunc_page(addr); + + tmap = map; + rv = vm_map_lookup (&tmap, pageno, VM_PROT_READ, &out_entry, + &object, &off, &out_prot, &wired, &single_use); + + if (rv != KERN_SUCCESS) + return EINVAL; + + vm_map_lookup_done (tmap, out_entry); + + /* Find space in kernel_map for the page we're interested in */ + rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); + + if (!rv) { + vm_object_reference (object); + + rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); + if (!rv) { + *retval = 0; + bcopy (kva + page_offset, retval, sizeof *retval); + } + vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); + } + + return rv; +} + +int +pwrite (struct proc *procp, unsigned int addr, unsigned int datum) { + int rv; + vm_map_t map, tmap; + vm_object_t object; + vm_offset_t kva = 0; + int page_offset; /* offset into page */ + vm_offset_t pageno; /* page number */ + vm_map_entry_t out_entry; + vm_prot_t out_prot; + boolean_t wired, single_use; + vm_offset_t off; + boolean_t fix_prot = 0; + + /* Map page into kernel space */ + + map = &procp->p_vmspace->vm_map; + + page_offset = addr - trunc_page(addr); + pageno = trunc_page(addr); + + /* + * Check the permissions for the area we're interested in. + */ + + if (vm_map_check_protection (map, pageno, pageno + PAGE_SIZE, + VM_PROT_WRITE) == FALSE) { + /* + * If the page was not writable, we make it so. + * XXX It is possible a page may *not* be read/executable, + * if a process changes that! + */ + fix_prot = 1; + /* The page isn't writable, so let's try making it so... */ + if ((rv = vm_map_protect (map, pageno, pageno + PAGE_SIZE, + VM_PROT_ALL, 0)) != KERN_SUCCESS) + return EFAULT; /* I guess... */ + } + + /* + * Now we need to get the page. out_entry, out_prot, wired, and + * single_use aren't used. One would think the vm code would be + * a *bit* nicer... We use tmap because vm_map_lookup() can + * change the map argument. + */ + + tmap = map; + rv = vm_map_lookup (&tmap, pageno, VM_PROT_WRITE, &out_entry, + &object, &off, &out_prot, &wired, &single_use); + if (rv != KERN_SUCCESS) { + return EINVAL; + } + + /* + * Okay, we've got the page. Let's release tmap. + */ + + vm_map_lookup_done (tmap, out_entry); + + /* + * Fault the page in... + */ + + rv = vm_fault (map, pageno, VM_PROT_WRITE, FALSE); + if (rv != KERN_SUCCESS) + return EFAULT; + + /* + * The page may need to be faulted in again, it seems. + * This covers COW pages, I believe. + */ + + if (!rv) + rv = vm_fault (map, pageno, VM_PROT_WRITE, 0); + + /* Find space in kernel_map for the page we're interested in */ + rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); + + if (!rv) { + vm_object_reference (object); + + rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); + if (!rv) { + bcopy (&datum, kva + page_offset, sizeof datum); + } + vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); + } + + if (fix_prot) + vm_map_protect (map, pageno, pageno + PAGE_SIZE, + VM_PROT_READ|VM_PROT_EXECUTE, 0); + return rv; +} + /* * Process debugging system call. */ @@ -52,26 +194,171 @@ struct ptrace_args { caddr_t addr; int data; }; -int -ptrace(a1, a2, a3) - struct proc *a1; - struct ptrace_args *a2; - int *a3; -{ +int +ptrace(curp, uap, retval) + struct proc *curp; + struct ptrace_args *uap; + int *retval; +{ + struct proc *p; + int s, error = 0; + + *retval = 0; + if (uap->req == PT_TRACE_ME) { + curp->p_flag |= P_TRACED; + return 0; + } + if ((p = pfind(uap->pid)) == NULL) { + return ESRCH; + } + +#ifdef PT_ATTACH + if (uap->req != PT_ATTACH && ( + (p->p_flag & P_TRACED) == 0 || + (p->p_tptr && curp != p->p_tptr) || + (!p->p_tptr && curp != p->p_pptr))) + + return ESRCH; +#endif +#ifdef PT_ATTACH + if (uap->req != PT_ATTACH) { +#endif + if ((p->p_flag & P_TRACED) == 0) + return EPERM; + if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) + return EBUSY; +#ifdef PT_ATTACH + } +#endif /* - * Body deleted. + * XXX The PT_ATTACH code is completely broken. It will + * be obsoleted by a /proc filesystem, so is it worth it + * to fix it? (Answer, probably. So that'll be next, + * I guess.) */ - return (ENOSYS); + + switch (uap->req) { +#ifdef PT_ATTACH + case PT_ATTACH: + if (curp->p_ucred->cr_uid != 0 && ( + curp->p_ucred->cr_uid != p->p_ucred->cr_uid || + curp->p_ucred->cr_uid != p->p_cred->p_svuid)) + return EACCES; + + p->p_tptr = curp; + p->p_flag |= P_TRACED; + psignal(p, SIGSTOP); + return 0; + + case PT_DETACH: + if ((unsigned)uap->data >= NSIG) + return EINVAL; + p->p_flag &= ~P_TRACED; + p->p_tptr = NULL; + psignal(p->p_pptr, SIGCHLD); + wakeup((caddr_t)p->p_pptr); + s = splhigh(); + if (p->p_stat == SSTOP) { + p->p_xstat = uap->data; + setrunnable(p); + } else if (uap->data) { + psignal(p, uap->data); + } + splx(s); + return 0; + +# ifdef PT_INHERIT + case PT_INHERIT: + if ((p->p_flag & P_TRACED) == 0) + return ESRCH; + return 0; +# endif /* PT_INHERIT */ +#endif /* PT_ATTACH */ + + case PT_READ_I: + case PT_READ_D: + if (error = pread (p, (unsigned int)uap->addr, retval)) + return error; + return 0; + case PT_WRITE_I: + case PT_WRITE_D: + if (error = pwrite (p, (unsigned int)uap->addr, + (unsigned int)uap->data)) + return error; + return 0; + case PT_STEP: + if (error = ptrace_single_step (p)) + return error; + /* fallthrough */ + case PT_CONTINUE: + /* + * Continue at addr uap->addr with signal + * uap->data; if uap->addr is 1, then we just + * let the chips fall where they may. + * + * The only check I'll make right now is for + * uap->data to be larger than NSIG; if so, we return + * EINVAL. + */ + if (uap->data >= NSIG) + return EINVAL; + + if (uap->addr != (caddr_t)1) { + fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); + if (error = ptrace_set_pc (p, uap->addr)) + return error; + } + + p->p_xstat = uap->data; + +/* if (p->p_stat == SSTOP) */ + setrunnable (p); + return 0; + case PT_READ_U: + if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { + return EFAULT; + } + p->p_addr->u_kproc.kp_proc = *p; + fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); + *retval = *(int*)((u_int)p->p_addr + (u_int)uap->addr); + return 0; + case PT_WRITE_U: + if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { + return EFAULT; + } + p->p_addr->u_kproc.kp_proc = *p; + fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); + *(int*)((u_int)p->p_addr + (u_int)uap->addr) = uap->data; + return 0; + case PT_KILL: + p->p_xstat = SIGKILL; + setrunnable(p); + return 0; +#ifdef PT_GETREGS + case PT_GETREGS: + /* + * copyout the registers into addr. There's no + * size constraint!!! *GRRR* + */ + return ptrace_getregs(p, uap->addr); + case PT_SETREGS: + /* + * copyin the registers from addr. Again, no + * size constraint!!! *GRRRR* + */ + return ptrace_setregs (p, uap->addr); +#endif /* PT_GETREGS */ + default: + break; + } + + return 0; } int -trace_req(a1) - struct proc *a1; +trace_req(p) + struct proc *p; { - - /* - * Body deleted. - */ - return (0); + return 1; } diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index d25655bb5c83..db29a9be67e8 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ptrace.h 8.2 (Berkeley) 1/4/94 - * $Id$ + * $Id: ptrace.h,v 1.2 1994/08/02 07:53:24 davidg Exp $ */ #ifndef _SYS_PTRACE_H_ @@ -47,8 +47,11 @@ #define PT_CONTINUE 7 /* continue the child */ #define PT_KILL 8 /* kill the child process */ #define PT_STEP 9 /* single step the child */ + +#ifdef notdef #define PT_ATTACH 10 /* trace some running process */ #define PT_DETACH 11 /* stop tracing a process */ +#endif #define PT_FIRSTMACH 32 /* for machine-specific requests */ #include /* machine-specific requests, if any */