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 * 313c4dd356SDavid Greenman * $Id$ 32df8bae1dSRodney W. Grimes */ 33df8bae1dSRodney W. Grimes 34df8bae1dSRodney W. Grimes #include <sys/param.h> 35df8bae1dSRodney W. Grimes #include <sys/proc.h> 364e68ceabSDavid Greenman #include <sys/vnode.h> 374e68ceabSDavid Greenman #include <sys/ptrace.h> 38df8bae1dSRodney W. Grimes #include <sys/errno.h> 39df8bae1dSRodney W. Grimes 404e68ceabSDavid Greenman #include <machine/reg.h> 414e68ceabSDavid Greenman #include <machine/psl.h> 424e68ceabSDavid Greenman #include <vm/vm.h> 434e68ceabSDavid Greenman #include <vm/vm_page.h> 444e68ceabSDavid Greenman #include <vm/vm_kern.h> 454e68ceabSDavid Greenman 464e68ceabSDavid Greenman #include "user.h" 474e68ceabSDavid Greenman 484e68ceabSDavid Greenman int 494e68ceabSDavid Greenman pread (struct proc *procp, unsigned int addr, unsigned int *retval) { 504e68ceabSDavid Greenman int rv; 514e68ceabSDavid Greenman vm_map_t map, tmap; 524e68ceabSDavid Greenman vm_object_t object; 534e68ceabSDavid Greenman vm_offset_t kva = 0; 544e68ceabSDavid Greenman int page_offset; /* offset into page */ 554e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 564e68ceabSDavid Greenman vm_map_entry_t out_entry; 574e68ceabSDavid Greenman vm_prot_t out_prot; 584e68ceabSDavid Greenman boolean_t wired, single_use; 594e68ceabSDavid Greenman vm_offset_t off; 604e68ceabSDavid Greenman 614e68ceabSDavid Greenman /* Map page into kernel space */ 624e68ceabSDavid Greenman 634e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 644e68ceabSDavid Greenman 654e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 664e68ceabSDavid Greenman pageno = trunc_page(addr); 674e68ceabSDavid Greenman 684e68ceabSDavid Greenman tmap = map; 694e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_READ, &out_entry, 704e68ceabSDavid Greenman &object, &off, &out_prot, &wired, &single_use); 714e68ceabSDavid Greenman 724e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 734e68ceabSDavid Greenman return EINVAL; 744e68ceabSDavid Greenman 754e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 764e68ceabSDavid Greenman 774e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 784e68ceabSDavid Greenman rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); 794e68ceabSDavid Greenman 804e68ceabSDavid Greenman if (!rv) { 814e68ceabSDavid Greenman vm_object_reference (object); 824e68ceabSDavid Greenman 834e68ceabSDavid Greenman rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 844e68ceabSDavid Greenman if (!rv) { 854e68ceabSDavid Greenman *retval = 0; 864e68ceabSDavid Greenman bcopy (kva + page_offset, retval, sizeof *retval); 874e68ceabSDavid Greenman } 884e68ceabSDavid Greenman vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 894e68ceabSDavid Greenman } 904e68ceabSDavid Greenman 914e68ceabSDavid Greenman return rv; 924e68ceabSDavid Greenman } 934e68ceabSDavid Greenman 944e68ceabSDavid Greenman int 954e68ceabSDavid Greenman pwrite (struct proc *procp, unsigned int addr, unsigned int datum) { 964e68ceabSDavid Greenman int rv; 974e68ceabSDavid Greenman vm_map_t map, tmap; 984e68ceabSDavid Greenman vm_object_t object; 994e68ceabSDavid Greenman vm_offset_t kva = 0; 1004e68ceabSDavid Greenman int page_offset; /* offset into page */ 1014e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 1024e68ceabSDavid Greenman vm_map_entry_t out_entry; 1034e68ceabSDavid Greenman vm_prot_t out_prot; 1044e68ceabSDavid Greenman boolean_t wired, single_use; 1054e68ceabSDavid Greenman vm_offset_t off; 1064e68ceabSDavid Greenman boolean_t fix_prot = 0; 1074e68ceabSDavid Greenman 1084e68ceabSDavid Greenman /* Map page into kernel space */ 1094e68ceabSDavid Greenman 1104e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 1114e68ceabSDavid Greenman 1124e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 1134e68ceabSDavid Greenman pageno = trunc_page(addr); 1144e68ceabSDavid Greenman 1154e68ceabSDavid Greenman /* 1164e68ceabSDavid Greenman * Check the permissions for the area we're interested in. 1174e68ceabSDavid Greenman */ 1184e68ceabSDavid Greenman 1194e68ceabSDavid Greenman if (vm_map_check_protection (map, pageno, pageno + PAGE_SIZE, 1204e68ceabSDavid Greenman VM_PROT_WRITE) == FALSE) { 1214e68ceabSDavid Greenman /* 1224e68ceabSDavid Greenman * If the page was not writable, we make it so. 1234e68ceabSDavid Greenman * XXX It is possible a page may *not* be read/executable, 1244e68ceabSDavid Greenman * if a process changes that! 1254e68ceabSDavid Greenman */ 1264e68ceabSDavid Greenman fix_prot = 1; 1274e68ceabSDavid Greenman /* The page isn't writable, so let's try making it so... */ 1284e68ceabSDavid Greenman if ((rv = vm_map_protect (map, pageno, pageno + PAGE_SIZE, 1294e68ceabSDavid Greenman VM_PROT_ALL, 0)) != KERN_SUCCESS) 1304e68ceabSDavid Greenman return EFAULT; /* I guess... */ 1314e68ceabSDavid Greenman } 1324e68ceabSDavid Greenman 1334e68ceabSDavid Greenman /* 1344e68ceabSDavid Greenman * Now we need to get the page. out_entry, out_prot, wired, and 1354e68ceabSDavid Greenman * single_use aren't used. One would think the vm code would be 1364e68ceabSDavid Greenman * a *bit* nicer... We use tmap because vm_map_lookup() can 1374e68ceabSDavid Greenman * change the map argument. 1384e68ceabSDavid Greenman */ 1394e68ceabSDavid Greenman 1404e68ceabSDavid Greenman tmap = map; 1414e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_WRITE, &out_entry, 1424e68ceabSDavid Greenman &object, &off, &out_prot, &wired, &single_use); 1434e68ceabSDavid Greenman if (rv != KERN_SUCCESS) { 1444e68ceabSDavid Greenman return EINVAL; 1454e68ceabSDavid Greenman } 1464e68ceabSDavid Greenman 1474e68ceabSDavid Greenman /* 1484e68ceabSDavid Greenman * Okay, we've got the page. Let's release tmap. 1494e68ceabSDavid Greenman */ 1504e68ceabSDavid Greenman 1514e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 1524e68ceabSDavid Greenman 1534e68ceabSDavid Greenman /* 1544e68ceabSDavid Greenman * Fault the page in... 1554e68ceabSDavid Greenman */ 1564e68ceabSDavid Greenman 1574e68ceabSDavid Greenman rv = vm_fault (map, pageno, VM_PROT_WRITE, FALSE); 1584e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 1594e68ceabSDavid Greenman return EFAULT; 1604e68ceabSDavid Greenman 1614e68ceabSDavid Greenman /* 1624e68ceabSDavid Greenman * The page may need to be faulted in again, it seems. 1634e68ceabSDavid Greenman * This covers COW pages, I believe. 1644e68ceabSDavid Greenman */ 1654e68ceabSDavid Greenman 1664e68ceabSDavid Greenman if (!rv) 1674e68ceabSDavid Greenman rv = vm_fault (map, pageno, VM_PROT_WRITE, 0); 1684e68ceabSDavid Greenman 1694e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 1704e68ceabSDavid Greenman rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); 1714e68ceabSDavid Greenman 1724e68ceabSDavid Greenman if (!rv) { 1734e68ceabSDavid Greenman vm_object_reference (object); 1744e68ceabSDavid Greenman 1754e68ceabSDavid Greenman rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 1764e68ceabSDavid Greenman if (!rv) { 1774e68ceabSDavid Greenman bcopy (&datum, kva + page_offset, sizeof datum); 1784e68ceabSDavid Greenman } 1794e68ceabSDavid Greenman vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 1804e68ceabSDavid Greenman } 1814e68ceabSDavid Greenman 1824e68ceabSDavid Greenman if (fix_prot) 1834e68ceabSDavid Greenman vm_map_protect (map, pageno, pageno + PAGE_SIZE, 1844e68ceabSDavid Greenman VM_PROT_READ|VM_PROT_EXECUTE, 0); 1854e68ceabSDavid Greenman return rv; 1864e68ceabSDavid Greenman } 1874e68ceabSDavid Greenman 188df8bae1dSRodney W. Grimes /* 189df8bae1dSRodney W. Grimes * Process debugging system call. 190df8bae1dSRodney W. Grimes */ 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 }; 197df8bae1dSRodney W. Grimes 1984e68ceabSDavid Greenman int 1994e68ceabSDavid Greenman ptrace(curp, uap, retval) 2004e68ceabSDavid Greenman struct proc *curp; 2014e68ceabSDavid Greenman struct ptrace_args *uap; 2024e68ceabSDavid Greenman int *retval; 2034e68ceabSDavid Greenman { 2044e68ceabSDavid Greenman struct proc *p; 2054e68ceabSDavid Greenman int s, error = 0; 2064e68ceabSDavid Greenman 2074e68ceabSDavid Greenman *retval = 0; 2084e68ceabSDavid Greenman if (uap->req == PT_TRACE_ME) { 2094e68ceabSDavid Greenman curp->p_flag |= P_TRACED; 2104e68ceabSDavid Greenman return 0; 2114e68ceabSDavid Greenman } 2124e68ceabSDavid Greenman if ((p = pfind(uap->pid)) == NULL) { 2134e68ceabSDavid Greenman return ESRCH; 2144e68ceabSDavid Greenman } 2154e68ceabSDavid Greenman 2164e68ceabSDavid Greenman #ifdef PT_ATTACH 2174e68ceabSDavid Greenman if (uap->req != PT_ATTACH && ( 2184e68ceabSDavid Greenman (p->p_flag & P_TRACED) == 0 || 2194e68ceabSDavid Greenman (p->p_tptr && curp != p->p_tptr) || 2204e68ceabSDavid Greenman (!p->p_tptr && curp != p->p_pptr))) 2214e68ceabSDavid Greenman 2224e68ceabSDavid Greenman return ESRCH; 2234e68ceabSDavid Greenman #endif 2244e68ceabSDavid Greenman #ifdef PT_ATTACH 2254e68ceabSDavid Greenman if (uap->req != PT_ATTACH) { 2264e68ceabSDavid Greenman #endif 2274e68ceabSDavid Greenman if ((p->p_flag & P_TRACED) == 0) 2284e68ceabSDavid Greenman return EPERM; 2294e68ceabSDavid Greenman if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) 2304e68ceabSDavid Greenman return EBUSY; 2314e68ceabSDavid Greenman #ifdef PT_ATTACH 2324e68ceabSDavid Greenman } 2334e68ceabSDavid Greenman #endif 234df8bae1dSRodney W. Grimes /* 2354e68ceabSDavid Greenman * XXX The PT_ATTACH code is completely broken. It will 2364e68ceabSDavid Greenman * be obsoleted by a /proc filesystem, so is it worth it 2374e68ceabSDavid Greenman * to fix it? (Answer, probably. So that'll be next, 2384e68ceabSDavid Greenman * I guess.) 239df8bae1dSRodney W. Grimes */ 2404e68ceabSDavid Greenman 2414e68ceabSDavid Greenman switch (uap->req) { 2424e68ceabSDavid Greenman #ifdef PT_ATTACH 2434e68ceabSDavid Greenman case PT_ATTACH: 2444e68ceabSDavid Greenman if (curp->p_ucred->cr_uid != 0 && ( 2454e68ceabSDavid Greenman curp->p_ucred->cr_uid != p->p_ucred->cr_uid || 2464e68ceabSDavid Greenman curp->p_ucred->cr_uid != p->p_cred->p_svuid)) 2474e68ceabSDavid Greenman return EACCES; 2484e68ceabSDavid Greenman 2494e68ceabSDavid Greenman p->p_tptr = curp; 2504e68ceabSDavid Greenman p->p_flag |= P_TRACED; 2514e68ceabSDavid Greenman psignal(p, SIGSTOP); 2524e68ceabSDavid Greenman return 0; 2534e68ceabSDavid Greenman 2544e68ceabSDavid Greenman case PT_DETACH: 2554e68ceabSDavid Greenman if ((unsigned)uap->data >= NSIG) 2564e68ceabSDavid Greenman return EINVAL; 2574e68ceabSDavid Greenman p->p_flag &= ~P_TRACED; 2584e68ceabSDavid Greenman p->p_tptr = NULL; 2594e68ceabSDavid Greenman psignal(p->p_pptr, SIGCHLD); 2604e68ceabSDavid Greenman wakeup((caddr_t)p->p_pptr); 2614e68ceabSDavid Greenman s = splhigh(); 2624e68ceabSDavid Greenman if (p->p_stat == SSTOP) { 2634e68ceabSDavid Greenman p->p_xstat = uap->data; 2644e68ceabSDavid Greenman setrunnable(p); 2654e68ceabSDavid Greenman } else if (uap->data) { 2664e68ceabSDavid Greenman psignal(p, uap->data); 2674e68ceabSDavid Greenman } 2684e68ceabSDavid Greenman splx(s); 2694e68ceabSDavid Greenman return 0; 2704e68ceabSDavid Greenman 2714e68ceabSDavid Greenman # ifdef PT_INHERIT 2724e68ceabSDavid Greenman case PT_INHERIT: 2734e68ceabSDavid Greenman if ((p->p_flag & P_TRACED) == 0) 2744e68ceabSDavid Greenman return ESRCH; 2754e68ceabSDavid Greenman return 0; 2764e68ceabSDavid Greenman # endif /* PT_INHERIT */ 2774e68ceabSDavid Greenman #endif /* PT_ATTACH */ 2784e68ceabSDavid Greenman 2794e68ceabSDavid Greenman case PT_READ_I: 2804e68ceabSDavid Greenman case PT_READ_D: 2814e68ceabSDavid Greenman if (error = pread (p, (unsigned int)uap->addr, retval)) 2824e68ceabSDavid Greenman return error; 2834e68ceabSDavid Greenman return 0; 2844e68ceabSDavid Greenman case PT_WRITE_I: 2854e68ceabSDavid Greenman case PT_WRITE_D: 2864e68ceabSDavid Greenman if (error = pwrite (p, (unsigned int)uap->addr, 2874e68ceabSDavid Greenman (unsigned int)uap->data)) 2884e68ceabSDavid Greenman return error; 2894e68ceabSDavid Greenman return 0; 2904e68ceabSDavid Greenman case PT_STEP: 2914e68ceabSDavid Greenman if (error = ptrace_single_step (p)) 2924e68ceabSDavid Greenman return error; 2934e68ceabSDavid Greenman /* fallthrough */ 2944e68ceabSDavid Greenman case PT_CONTINUE: 2954e68ceabSDavid Greenman /* 2964e68ceabSDavid Greenman * Continue at addr uap->addr with signal 2974e68ceabSDavid Greenman * uap->data; if uap->addr is 1, then we just 2984e68ceabSDavid Greenman * let the chips fall where they may. 2994e68ceabSDavid Greenman * 3004e68ceabSDavid Greenman * The only check I'll make right now is for 3014e68ceabSDavid Greenman * uap->data to be larger than NSIG; if so, we return 3024e68ceabSDavid Greenman * EINVAL. 3034e68ceabSDavid Greenman */ 3044e68ceabSDavid Greenman if (uap->data >= NSIG) 3054e68ceabSDavid Greenman return EINVAL; 3064e68ceabSDavid Greenman 3074e68ceabSDavid Greenman if (uap->addr != (caddr_t)1) { 3084e68ceabSDavid Greenman fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 3094e68ceabSDavid Greenman if (error = ptrace_set_pc (p, uap->addr)) 3104e68ceabSDavid Greenman return error; 3114e68ceabSDavid Greenman } 3124e68ceabSDavid Greenman 3134e68ceabSDavid Greenman p->p_xstat = uap->data; 3144e68ceabSDavid Greenman 3154e68ceabSDavid Greenman /* if (p->p_stat == SSTOP) */ 3164e68ceabSDavid Greenman setrunnable (p); 3174e68ceabSDavid Greenman return 0; 3184e68ceabSDavid Greenman case PT_READ_U: 3194e68ceabSDavid Greenman if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { 3204e68ceabSDavid Greenman return EFAULT; 3214e68ceabSDavid Greenman } 3224e68ceabSDavid Greenman p->p_addr->u_kproc.kp_proc = *p; 3234e68ceabSDavid Greenman fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 3244e68ceabSDavid Greenman *retval = *(int*)((u_int)p->p_addr + (u_int)uap->addr); 3254e68ceabSDavid Greenman return 0; 3264e68ceabSDavid Greenman case PT_WRITE_U: 3274e68ceabSDavid Greenman if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { 3284e68ceabSDavid Greenman return EFAULT; 3294e68ceabSDavid Greenman } 3304e68ceabSDavid Greenman p->p_addr->u_kproc.kp_proc = *p; 3314e68ceabSDavid Greenman fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 3324e68ceabSDavid Greenman *(int*)((u_int)p->p_addr + (u_int)uap->addr) = uap->data; 3334e68ceabSDavid Greenman return 0; 3344e68ceabSDavid Greenman case PT_KILL: 3354e68ceabSDavid Greenman p->p_xstat = SIGKILL; 3364e68ceabSDavid Greenman setrunnable(p); 3374e68ceabSDavid Greenman return 0; 3384e68ceabSDavid Greenman #ifdef PT_GETREGS 3394e68ceabSDavid Greenman case PT_GETREGS: 3404e68ceabSDavid Greenman /* 3414e68ceabSDavid Greenman * copyout the registers into addr. There's no 3424e68ceabSDavid Greenman * size constraint!!! *GRRR* 3434e68ceabSDavid Greenman */ 3444e68ceabSDavid Greenman return ptrace_getregs(p, uap->addr); 3454e68ceabSDavid Greenman case PT_SETREGS: 3464e68ceabSDavid Greenman /* 3474e68ceabSDavid Greenman * copyin the registers from addr. Again, no 3484e68ceabSDavid Greenman * size constraint!!! *GRRRR* 3494e68ceabSDavid Greenman */ 3504e68ceabSDavid Greenman return ptrace_setregs (p, uap->addr); 3514e68ceabSDavid Greenman #endif /* PT_GETREGS */ 3524e68ceabSDavid Greenman default: 3534e68ceabSDavid Greenman break; 3544e68ceabSDavid Greenman } 3554e68ceabSDavid Greenman 3564e68ceabSDavid Greenman return 0; 357df8bae1dSRodney W. Grimes } 358df8bae1dSRodney W. Grimes 35926f9a767SRodney W. Grimes int 3604e68ceabSDavid Greenman trace_req(p) 3614e68ceabSDavid Greenman struct proc *p; 362df8bae1dSRodney W. Grimes { 3634e68ceabSDavid Greenman return 1; 364df8bae1dSRodney W. Grimes } 365