14e68ceabSDavid Greenman /* 24e68ceabSDavid Greenman * Copyright (c) 1994, Sean Eric Fagan 34e68ceabSDavid Greenman * All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 154e68ceabSDavid Greenman * This product includes software developed by Sean Eric Fagan. 164e68ceabSDavid Greenman * 4. The name of the author may not be used to endorse or promote products 174e68ceabSDavid Greenman * derived from this software without specific prior written permission. 18df8bae1dSRodney W. Grimes * 194e68ceabSDavid Greenman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 224e68ceabSDavid Greenman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29df8bae1dSRodney W. Grimes * SUCH DAMAGE. 30df8bae1dSRodney W. Grimes * 31d2d3e875SBruce Evans * $Id: sys_process.c,v 1.14 1995/05/30 08:05:58 rgrimes Exp $ 32df8bae1dSRodney W. Grimes */ 33df8bae1dSRodney W. Grimes 34df8bae1dSRodney W. Grimes #include <sys/param.h> 35f23b4c91SGarrett Wollman #include <sys/systm.h> 36d2d3e875SBruce Evans #include <sys/sysproto.h> 37df8bae1dSRodney W. Grimes #include <sys/proc.h> 384e68ceabSDavid Greenman #include <sys/vnode.h> 394e68ceabSDavid Greenman #include <sys/ptrace.h> 40df8bae1dSRodney W. Grimes #include <sys/errno.h> 41df8bae1dSRodney W. Grimes 424e68ceabSDavid Greenman #include <machine/reg.h> 434e68ceabSDavid Greenman #include <machine/psl.h> 444e68ceabSDavid Greenman #include <vm/vm.h> 454e68ceabSDavid Greenman #include <vm/vm_page.h> 464e68ceabSDavid Greenman #include <vm/vm_kern.h> 474e68ceabSDavid Greenman 48f540b106SGarrett Wollman #include <sys/user.h> 494e68ceabSDavid Greenman 50c4cf09ffSDavid Greenman static int 514e68ceabSDavid Greenman pread (struct proc *procp, unsigned int addr, unsigned int *retval) { 524e68ceabSDavid Greenman int rv; 534e68ceabSDavid Greenman vm_map_t map, tmap; 544e68ceabSDavid Greenman vm_object_t object; 554e68ceabSDavid Greenman vm_offset_t kva = 0; 564e68ceabSDavid Greenman int page_offset; /* offset into page */ 574e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 584e68ceabSDavid Greenman vm_map_entry_t out_entry; 594e68ceabSDavid Greenman vm_prot_t out_prot; 604e68ceabSDavid Greenman boolean_t wired, single_use; 614e68ceabSDavid Greenman vm_offset_t off; 624e68ceabSDavid Greenman 634e68ceabSDavid Greenman /* Map page into kernel space */ 644e68ceabSDavid Greenman 654e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 664e68ceabSDavid Greenman 674e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 684e68ceabSDavid Greenman pageno = trunc_page(addr); 694e68ceabSDavid Greenman 704e68ceabSDavid Greenman tmap = map; 714e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_READ, &out_entry, 724e68ceabSDavid Greenman &object, &off, &out_prot, &wired, &single_use); 734e68ceabSDavid Greenman 744e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 754e68ceabSDavid Greenman return EINVAL; 764e68ceabSDavid Greenman 774e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 784e68ceabSDavid Greenman 794e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 804e68ceabSDavid Greenman rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); 814e68ceabSDavid Greenman 824e68ceabSDavid Greenman if (!rv) { 834e68ceabSDavid Greenman vm_object_reference (object); 844e68ceabSDavid Greenman 854e68ceabSDavid Greenman rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 864e68ceabSDavid Greenman if (!rv) { 874e68ceabSDavid Greenman *retval = 0; 88f23b4c91SGarrett Wollman bcopy ((caddr_t)kva + page_offset, 89f23b4c91SGarrett Wollman retval, sizeof *retval); 904e68ceabSDavid Greenman } 914e68ceabSDavid Greenman vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 924e68ceabSDavid Greenman } 934e68ceabSDavid Greenman 944e68ceabSDavid Greenman return rv; 954e68ceabSDavid Greenman } 964e68ceabSDavid Greenman 97c4cf09ffSDavid Greenman static int 984e68ceabSDavid Greenman pwrite (struct proc *procp, unsigned int addr, unsigned int datum) { 994e68ceabSDavid Greenman int rv; 1004e68ceabSDavid Greenman vm_map_t map, tmap; 1014e68ceabSDavid Greenman vm_object_t object; 1024e68ceabSDavid Greenman vm_offset_t kva = 0; 1034e68ceabSDavid Greenman int page_offset; /* offset into page */ 1044e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 1054e68ceabSDavid Greenman vm_map_entry_t out_entry; 1064e68ceabSDavid Greenman vm_prot_t out_prot; 1074e68ceabSDavid Greenman boolean_t wired, single_use; 1084e68ceabSDavid Greenman vm_offset_t off; 1094e68ceabSDavid Greenman boolean_t fix_prot = 0; 1104e68ceabSDavid Greenman 1114e68ceabSDavid Greenman /* Map page into kernel space */ 1124e68ceabSDavid Greenman 1134e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 1144e68ceabSDavid Greenman 1154e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 1164e68ceabSDavid Greenman pageno = trunc_page(addr); 1174e68ceabSDavid Greenman 1184e68ceabSDavid Greenman /* 1194e68ceabSDavid Greenman * Check the permissions for the area we're interested in. 1204e68ceabSDavid Greenman */ 1214e68ceabSDavid Greenman 1224e68ceabSDavid Greenman if (vm_map_check_protection (map, pageno, pageno + PAGE_SIZE, 1234e68ceabSDavid Greenman VM_PROT_WRITE) == FALSE) { 1244e68ceabSDavid Greenman /* 1254e68ceabSDavid Greenman * If the page was not writable, we make it so. 1264e68ceabSDavid Greenman * XXX It is possible a page may *not* be read/executable, 1274e68ceabSDavid Greenman * if a process changes that! 1284e68ceabSDavid Greenman */ 1294e68ceabSDavid Greenman fix_prot = 1; 1304e68ceabSDavid Greenman /* The page isn't writable, so let's try making it so... */ 1314e68ceabSDavid Greenman if ((rv = vm_map_protect (map, pageno, pageno + PAGE_SIZE, 1324e68ceabSDavid Greenman VM_PROT_ALL, 0)) != KERN_SUCCESS) 1334e68ceabSDavid Greenman return EFAULT; /* I guess... */ 1344e68ceabSDavid Greenman } 1354e68ceabSDavid Greenman 1364e68ceabSDavid Greenman /* 1374e68ceabSDavid Greenman * Now we need to get the page. out_entry, out_prot, wired, and 1384e68ceabSDavid Greenman * single_use aren't used. One would think the vm code would be 1394e68ceabSDavid Greenman * a *bit* nicer... We use tmap because vm_map_lookup() can 1404e68ceabSDavid Greenman * change the map argument. 1414e68ceabSDavid Greenman */ 1424e68ceabSDavid Greenman 1434e68ceabSDavid Greenman tmap = map; 1444e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_WRITE, &out_entry, 1454e68ceabSDavid Greenman &object, &off, &out_prot, &wired, &single_use); 1464e68ceabSDavid Greenman if (rv != KERN_SUCCESS) { 1474e68ceabSDavid Greenman return EINVAL; 1484e68ceabSDavid Greenman } 1494e68ceabSDavid Greenman 1504e68ceabSDavid Greenman /* 1514e68ceabSDavid Greenman * Okay, we've got the page. Let's release tmap. 1524e68ceabSDavid Greenman */ 1534e68ceabSDavid Greenman 1544e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 1554e68ceabSDavid Greenman 1564e68ceabSDavid Greenman /* 1574e68ceabSDavid Greenman * Fault the page in... 1584e68ceabSDavid Greenman */ 1594e68ceabSDavid Greenman 1609219d44eSDavid Greenman vm_map_pageable(map, trunc_page(vtopte(pageno)), 1619219d44eSDavid Greenman trunc_page(vtopte(pageno)) + PAGE_SIZE, FALSE); 162914a63ebSDavid Greenman rv = vm_fault(map, pageno, VM_PROT_WRITE|VM_PROT_READ, FALSE); 1639219d44eSDavid Greenman vm_map_pageable(map, trunc_page(vtopte(pageno)), 1649219d44eSDavid Greenman trunc_page(vtopte(pageno)) + PAGE_SIZE, TRUE); 1654e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 1664e68ceabSDavid Greenman return EFAULT; 1674e68ceabSDavid Greenman 1684e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 1694e68ceabSDavid Greenman rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); 1704e68ceabSDavid Greenman 1714e68ceabSDavid Greenman if (!rv) { 1724e68ceabSDavid Greenman vm_object_reference (object); 1734e68ceabSDavid Greenman 1744e68ceabSDavid Greenman rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 1754e68ceabSDavid Greenman if (!rv) { 176f23b4c91SGarrett Wollman bcopy (&datum, (caddr_t)kva + page_offset, sizeof datum); 1774e68ceabSDavid Greenman } 1784e68ceabSDavid Greenman vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 1794e68ceabSDavid Greenman } 1804e68ceabSDavid Greenman 1814e68ceabSDavid Greenman if (fix_prot) 1824e68ceabSDavid Greenman vm_map_protect (map, pageno, pageno + PAGE_SIZE, 1834e68ceabSDavid Greenman VM_PROT_READ|VM_PROT_EXECUTE, 0); 1844e68ceabSDavid Greenman return rv; 1854e68ceabSDavid Greenman } 1864e68ceabSDavid Greenman 187df8bae1dSRodney W. Grimes /* 188df8bae1dSRodney W. Grimes * Process debugging system call. 189df8bae1dSRodney W. Grimes */ 190d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 191df8bae1dSRodney W. Grimes struct ptrace_args { 192df8bae1dSRodney W. Grimes int req; 193df8bae1dSRodney W. Grimes pid_t pid; 194df8bae1dSRodney W. Grimes caddr_t addr; 195df8bae1dSRodney W. Grimes int data; 196df8bae1dSRodney W. Grimes }; 197d2d3e875SBruce Evans #endif 198df8bae1dSRodney W. Grimes 1994e68ceabSDavid Greenman int 2004e68ceabSDavid Greenman ptrace(curp, uap, retval) 2014e68ceabSDavid Greenman struct proc *curp; 2024e68ceabSDavid Greenman struct ptrace_args *uap; 2034e68ceabSDavid Greenman int *retval; 2044e68ceabSDavid Greenman { 2054e68ceabSDavid Greenman struct proc *p; 206bb56ec4aSPoul-Henning Kamp int error = 0; 2074e68ceabSDavid Greenman 2084e68ceabSDavid Greenman *retval = 0; 2094e68ceabSDavid Greenman if (uap->req == PT_TRACE_ME) { 2104e68ceabSDavid Greenman curp->p_flag |= P_TRACED; 2114e68ceabSDavid Greenman return 0; 2124e68ceabSDavid Greenman } 2134e68ceabSDavid Greenman if ((p = pfind(uap->pid)) == NULL) { 2144e68ceabSDavid Greenman return ESRCH; 2154e68ceabSDavid Greenman } 2164e68ceabSDavid Greenman 2174e68ceabSDavid Greenman #ifdef PT_ATTACH 2184e68ceabSDavid Greenman if (uap->req != PT_ATTACH && ( 2194e68ceabSDavid Greenman (p->p_flag & P_TRACED) == 0 || 2204e68ceabSDavid Greenman (p->p_tptr && curp != p->p_tptr) || 2214e68ceabSDavid Greenman (!p->p_tptr && curp != p->p_pptr))) 2224e68ceabSDavid Greenman 2234e68ceabSDavid Greenman return ESRCH; 2244e68ceabSDavid Greenman #endif 2254e68ceabSDavid Greenman #ifdef PT_ATTACH 2264e68ceabSDavid Greenman if (uap->req != PT_ATTACH) { 2274e68ceabSDavid Greenman #endif 2284e68ceabSDavid Greenman if ((p->p_flag & P_TRACED) == 0) 2294e68ceabSDavid Greenman return EPERM; 2304e68ceabSDavid Greenman if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) 2314e68ceabSDavid Greenman return EBUSY; 2324e68ceabSDavid Greenman #ifdef PT_ATTACH 2334e68ceabSDavid Greenman } 2344e68ceabSDavid Greenman #endif 235df8bae1dSRodney W. Grimes /* 2364e68ceabSDavid Greenman * XXX The PT_ATTACH code is completely broken. It will 2374e68ceabSDavid Greenman * be obsoleted by a /proc filesystem, so is it worth it 2384e68ceabSDavid Greenman * to fix it? (Answer, probably. So that'll be next, 2394e68ceabSDavid Greenman * I guess.) 240df8bae1dSRodney W. Grimes */ 2414e68ceabSDavid Greenman 2424e68ceabSDavid Greenman switch (uap->req) { 2434e68ceabSDavid Greenman #ifdef PT_ATTACH 2444e68ceabSDavid Greenman case PT_ATTACH: 2454e68ceabSDavid Greenman if (curp->p_ucred->cr_uid != 0 && ( 2464e68ceabSDavid Greenman curp->p_ucred->cr_uid != p->p_ucred->cr_uid || 2474e68ceabSDavid Greenman curp->p_ucred->cr_uid != p->p_cred->p_svuid)) 2484e68ceabSDavid Greenman return EACCES; 2494e68ceabSDavid Greenman 2504e68ceabSDavid Greenman p->p_tptr = curp; 2514e68ceabSDavid Greenman p->p_flag |= P_TRACED; 2524e68ceabSDavid Greenman psignal(p, SIGSTOP); 2534e68ceabSDavid Greenman return 0; 2544e68ceabSDavid Greenman 2554e68ceabSDavid Greenman case PT_DETACH: 2564e68ceabSDavid Greenman if ((unsigned)uap->data >= NSIG) 2574e68ceabSDavid Greenman return EINVAL; 2584e68ceabSDavid Greenman p->p_flag &= ~P_TRACED; 2594e68ceabSDavid Greenman p->p_tptr = NULL; 2604e68ceabSDavid Greenman psignal(p->p_pptr, SIGCHLD); 2614e68ceabSDavid Greenman wakeup((caddr_t)p->p_pptr); 2624e68ceabSDavid Greenman s = splhigh(); 2634e68ceabSDavid Greenman if (p->p_stat == SSTOP) { 2644e68ceabSDavid Greenman p->p_xstat = uap->data; 2654e68ceabSDavid Greenman setrunnable(p); 2664e68ceabSDavid Greenman } else if (uap->data) { 2674e68ceabSDavid Greenman psignal(p, uap->data); 2684e68ceabSDavid Greenman } 2694e68ceabSDavid Greenman splx(s); 2704e68ceabSDavid Greenman return 0; 2714e68ceabSDavid Greenman 2724e68ceabSDavid Greenman # ifdef PT_INHERIT 2734e68ceabSDavid Greenman case PT_INHERIT: 2744e68ceabSDavid Greenman if ((p->p_flag & P_TRACED) == 0) 2754e68ceabSDavid Greenman return ESRCH; 2764e68ceabSDavid Greenman return 0; 2774e68ceabSDavid Greenman # endif /* PT_INHERIT */ 2784e68ceabSDavid Greenman #endif /* PT_ATTACH */ 2794e68ceabSDavid Greenman 2804e68ceabSDavid Greenman case PT_READ_I: 2814e68ceabSDavid Greenman case PT_READ_D: 282bb56ec4aSPoul-Henning Kamp if ((error = pread (p, (unsigned int)uap->addr, retval))) 2834e68ceabSDavid Greenman return error; 2844e68ceabSDavid Greenman return 0; 2854e68ceabSDavid Greenman case PT_WRITE_I: 2864e68ceabSDavid Greenman case PT_WRITE_D: 287bb56ec4aSPoul-Henning Kamp if ((error = pwrite (p, (unsigned int)uap->addr, 288bb56ec4aSPoul-Henning Kamp (unsigned int)uap->data))) 2894e68ceabSDavid Greenman return error; 2904e68ceabSDavid Greenman return 0; 2914e68ceabSDavid Greenman case PT_STEP: 292bb56ec4aSPoul-Henning Kamp if ((error = ptrace_single_step (p))) 2934e68ceabSDavid Greenman return error; 2944e68ceabSDavid Greenman /* fallthrough */ 2954e68ceabSDavid Greenman case PT_CONTINUE: 2964e68ceabSDavid Greenman /* 2974e68ceabSDavid Greenman * Continue at addr uap->addr with signal 2984e68ceabSDavid Greenman * uap->data; if uap->addr is 1, then we just 2994e68ceabSDavid Greenman * let the chips fall where they may. 3004e68ceabSDavid Greenman * 3014e68ceabSDavid Greenman * The only check I'll make right now is for 3024e68ceabSDavid Greenman * uap->data to be larger than NSIG; if so, we return 3034e68ceabSDavid Greenman * EINVAL. 3044e68ceabSDavid Greenman */ 3054e68ceabSDavid Greenman if (uap->data >= NSIG) 3064e68ceabSDavid Greenman return EINVAL; 3074e68ceabSDavid Greenman 3084e68ceabSDavid Greenman if (uap->addr != (caddr_t)1) { 3094e68ceabSDavid Greenman fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 310b5e8ce9fSBruce Evans if ((error = ptrace_set_pc (p, (u_int)uap->addr))) 3114e68ceabSDavid Greenman return error; 3124e68ceabSDavid Greenman } 3134e68ceabSDavid Greenman 3144e68ceabSDavid Greenman p->p_xstat = uap->data; 3154e68ceabSDavid Greenman 3164e68ceabSDavid Greenman /* if (p->p_stat == SSTOP) */ 3174e68ceabSDavid Greenman setrunnable (p); 3184e68ceabSDavid Greenman return 0; 3194e68ceabSDavid Greenman case PT_READ_U: 3204e68ceabSDavid Greenman if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { 3214e68ceabSDavid Greenman return EFAULT; 3224e68ceabSDavid Greenman } 3234e68ceabSDavid Greenman p->p_addr->u_kproc.kp_proc = *p; 3244e68ceabSDavid Greenman fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 3254e68ceabSDavid Greenman *retval = *(int*)((u_int)p->p_addr + (u_int)uap->addr); 3264e68ceabSDavid Greenman return 0; 3274e68ceabSDavid Greenman case PT_WRITE_U: 3284e68ceabSDavid Greenman p->p_addr->u_kproc.kp_proc = *p; 3294e68ceabSDavid Greenman fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 33020415301SBruce Evans return ptrace_write_u(p, (vm_offset_t)uap->addr, uap->data); 3314e68ceabSDavid Greenman case PT_KILL: 3324e68ceabSDavid Greenman p->p_xstat = SIGKILL; 3334e68ceabSDavid Greenman setrunnable(p); 3344e68ceabSDavid Greenman return 0; 3354e68ceabSDavid Greenman #ifdef PT_GETREGS 3364e68ceabSDavid Greenman case PT_GETREGS: 3374e68ceabSDavid Greenman /* 3384e68ceabSDavid Greenman * copyout the registers into addr. There's no 3394e68ceabSDavid Greenman * size constraint!!! *GRRR* 3404e68ceabSDavid Greenman */ 3414e68ceabSDavid Greenman return ptrace_getregs(p, uap->addr); 3424e68ceabSDavid Greenman case PT_SETREGS: 3434e68ceabSDavid Greenman /* 3444e68ceabSDavid Greenman * copyin the registers from addr. Again, no 3454e68ceabSDavid Greenman * size constraint!!! *GRRRR* 3464e68ceabSDavid Greenman */ 3474e68ceabSDavid Greenman return ptrace_setregs (p, uap->addr); 3484e68ceabSDavid Greenman #endif /* PT_GETREGS */ 3494e68ceabSDavid Greenman default: 3504e68ceabSDavid Greenman break; 3514e68ceabSDavid Greenman } 3524e68ceabSDavid Greenman 3534e68ceabSDavid Greenman return 0; 354df8bae1dSRodney W. Grimes } 355df8bae1dSRodney W. Grimes 35626f9a767SRodney W. Grimes int 3574e68ceabSDavid Greenman trace_req(p) 3584e68ceabSDavid Greenman struct proc *p; 359df8bae1dSRodney W. Grimes { 3604e68ceabSDavid Greenman return 1; 361df8bae1dSRodney W. Grimes } 362