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 * 31ab001a72SJonathan Lemon * $Id: sys_process.c,v 1.46 1999/07/01 22:52:40 peter 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 414e68ceabSDavid Greenman #include <machine/reg.h> 424e68ceabSDavid Greenman #include <vm/vm.h> 43efeaf95aSDavid Greenman #include <vm/vm_prot.h> 44996c772fSJohn Dyson #include <sys/lock.h> 45efeaf95aSDavid Greenman #include <vm/pmap.h> 46efeaf95aSDavid Greenman #include <vm/vm_map.h> 474e68ceabSDavid Greenman #include <vm/vm_page.h> 48efeaf95aSDavid Greenman #include <vm/vm_extern.h> 494e68ceabSDavid Greenman 50f540b106SGarrett Wollman #include <sys/user.h> 51b0281cefSPeter Wemm #include <miscfs/procfs/procfs.h> 524e68ceabSDavid Greenman 53b0281cefSPeter Wemm /* use the equivalent procfs code */ 54b0281cefSPeter Wemm #if 0 55c4cf09ffSDavid Greenman static int 564e68ceabSDavid Greenman pread (struct proc *procp, unsigned int addr, unsigned int *retval) { 574e68ceabSDavid Greenman int rv; 584e68ceabSDavid Greenman vm_map_t map, tmap; 594e68ceabSDavid Greenman vm_object_t object; 604e68ceabSDavid Greenman vm_offset_t kva = 0; 614e68ceabSDavid Greenman int page_offset; /* offset into page */ 624e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 634e68ceabSDavid Greenman vm_map_entry_t out_entry; 644e68ceabSDavid Greenman vm_prot_t out_prot; 652d8acc0fSJohn Dyson boolean_t wired; 6663c8f421SBruce Evans vm_pindex_t pindex; 674e68ceabSDavid Greenman 684e68ceabSDavid Greenman /* Map page into kernel space */ 694e68ceabSDavid Greenman 704e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 714e68ceabSDavid Greenman 724e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 734e68ceabSDavid Greenman pageno = trunc_page(addr); 744e68ceabSDavid Greenman 754e68ceabSDavid Greenman tmap = map; 764e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_READ, &out_entry, 772d8acc0fSJohn Dyson &object, &pindex, &out_prot, &wired); 784e68ceabSDavid Greenman 794e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 804e68ceabSDavid Greenman return EINVAL; 814e68ceabSDavid Greenman 824e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 834e68ceabSDavid Greenman 844e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 85bd7e5f99SJohn Dyson rv = vm_map_find (kernel_map, object, IDX_TO_OFF(pindex), 86bd7e5f99SJohn Dyson &kva, PAGE_SIZE, 0, VM_PROT_ALL, VM_PROT_ALL, 0); 874e68ceabSDavid Greenman 884e68ceabSDavid Greenman if (!rv) { 894e68ceabSDavid Greenman vm_object_reference (object); 904e68ceabSDavid Greenman 914e68ceabSDavid Greenman rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 924e68ceabSDavid Greenman if (!rv) { 934e68ceabSDavid Greenman *retval = 0; 94f23b4c91SGarrett Wollman bcopy ((caddr_t)kva + page_offset, 95f23b4c91SGarrett Wollman retval, sizeof *retval); 964e68ceabSDavid Greenman } 974e68ceabSDavid Greenman vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 984e68ceabSDavid Greenman } 994e68ceabSDavid Greenman 1004e68ceabSDavid Greenman return rv; 1014e68ceabSDavid Greenman } 1024e68ceabSDavid Greenman 103c4cf09ffSDavid Greenman static int 1044e68ceabSDavid Greenman pwrite (struct proc *procp, unsigned int addr, unsigned int datum) { 1054e68ceabSDavid Greenman int rv; 1064e68ceabSDavid Greenman vm_map_t map, tmap; 1074e68ceabSDavid Greenman vm_object_t object; 1084e68ceabSDavid Greenman vm_offset_t kva = 0; 1094e68ceabSDavid Greenman int page_offset; /* offset into page */ 1104e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 1114e68ceabSDavid Greenman vm_map_entry_t out_entry; 1124e68ceabSDavid Greenman vm_prot_t out_prot; 1132d8acc0fSJohn Dyson boolean_t wired; 11463c8f421SBruce Evans vm_pindex_t pindex; 1154e68ceabSDavid Greenman boolean_t fix_prot = 0; 1164e68ceabSDavid Greenman 1174e68ceabSDavid Greenman /* Map page into kernel space */ 1184e68ceabSDavid Greenman 1194e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 1204e68ceabSDavid Greenman 1214e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 1224e68ceabSDavid Greenman pageno = trunc_page(addr); 1234e68ceabSDavid Greenman 1244e68ceabSDavid Greenman /* 1254e68ceabSDavid Greenman * Check the permissions for the area we're interested in. 1264e68ceabSDavid Greenman */ 1274e68ceabSDavid Greenman 1284e68ceabSDavid Greenman if (vm_map_check_protection (map, pageno, pageno + PAGE_SIZE, 1294e68ceabSDavid Greenman VM_PROT_WRITE) == FALSE) { 1304e68ceabSDavid Greenman /* 1314e68ceabSDavid Greenman * If the page was not writable, we make it so. 1324e68ceabSDavid Greenman * XXX It is possible a page may *not* be read/executable, 1334e68ceabSDavid Greenman * if a process changes that! 1344e68ceabSDavid Greenman */ 1354e68ceabSDavid Greenman fix_prot = 1; 1364e68ceabSDavid Greenman /* The page isn't writable, so let's try making it so... */ 1374e68ceabSDavid Greenman if ((rv = vm_map_protect (map, pageno, pageno + PAGE_SIZE, 1384e68ceabSDavid Greenman VM_PROT_ALL, 0)) != KERN_SUCCESS) 1394e68ceabSDavid Greenman return EFAULT; /* I guess... */ 1404e68ceabSDavid Greenman } 1414e68ceabSDavid Greenman 1424e68ceabSDavid Greenman /* 1434e68ceabSDavid Greenman * Now we need to get the page. out_entry, out_prot, wired, and 1444e68ceabSDavid Greenman * single_use aren't used. One would think the vm code would be 1454e68ceabSDavid Greenman * a *bit* nicer... We use tmap because vm_map_lookup() can 1464e68ceabSDavid Greenman * change the map argument. 1474e68ceabSDavid Greenman */ 1484e68ceabSDavid Greenman 1494e68ceabSDavid Greenman tmap = map; 1504e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_WRITE, &out_entry, 1512d8acc0fSJohn Dyson &object, &pindex, &out_prot, &wired); 1524e68ceabSDavid Greenman if (rv != KERN_SUCCESS) { 1534e68ceabSDavid Greenman return EINVAL; 1544e68ceabSDavid Greenman } 1554e68ceabSDavid Greenman 1564e68ceabSDavid Greenman /* 1574e68ceabSDavid Greenman * Okay, we've got the page. Let's release tmap. 1584e68ceabSDavid Greenman */ 1594e68ceabSDavid Greenman 1604e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 1614e68ceabSDavid Greenman 1624e68ceabSDavid Greenman /* 1634e68ceabSDavid Greenman * Fault the page in... 1644e68ceabSDavid Greenman */ 1654e68ceabSDavid Greenman 166914a63ebSDavid Greenman rv = vm_fault(map, pageno, VM_PROT_WRITE|VM_PROT_READ, FALSE); 1674e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 1684e68ceabSDavid Greenman return EFAULT; 1694e68ceabSDavid Greenman 1704e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 171bd7e5f99SJohn Dyson rv = vm_map_find (kernel_map, object, IDX_TO_OFF(pindex), 172bd7e5f99SJohn Dyson &kva, PAGE_SIZE, 0, 173bd7e5f99SJohn Dyson VM_PROT_ALL, VM_PROT_ALL, 0); 1744e68ceabSDavid Greenman if (!rv) { 1754e68ceabSDavid Greenman vm_object_reference (object); 1764e68ceabSDavid Greenman 1774e68ceabSDavid Greenman rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 1784e68ceabSDavid Greenman if (!rv) { 179f23b4c91SGarrett Wollman bcopy (&datum, (caddr_t)kva + page_offset, sizeof datum); 1804e68ceabSDavid Greenman } 1814e68ceabSDavid Greenman vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 1824e68ceabSDavid Greenman } 1834e68ceabSDavid Greenman 1844e68ceabSDavid Greenman if (fix_prot) 1854e68ceabSDavid Greenman vm_map_protect (map, pageno, pageno + PAGE_SIZE, 1864e68ceabSDavid Greenman VM_PROT_READ|VM_PROT_EXECUTE, 0); 1874e68ceabSDavid Greenman return rv; 1884e68ceabSDavid Greenman } 189b0281cefSPeter Wemm #endif 1904e68ceabSDavid Greenman 191df8bae1dSRodney W. Grimes /* 192df8bae1dSRodney W. Grimes * Process debugging system call. 193df8bae1dSRodney W. Grimes */ 194d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 195df8bae1dSRodney W. Grimes struct ptrace_args { 196df8bae1dSRodney W. Grimes int req; 197df8bae1dSRodney W. Grimes pid_t pid; 198df8bae1dSRodney W. Grimes caddr_t addr; 199df8bae1dSRodney W. Grimes int data; 200df8bae1dSRodney W. Grimes }; 201d2d3e875SBruce Evans #endif 202df8bae1dSRodney W. Grimes 2034e68ceabSDavid Greenman int 204cb226aaaSPoul-Henning Kamp ptrace(curp, uap) 2054e68ceabSDavid Greenman struct proc *curp; 2064e68ceabSDavid Greenman struct ptrace_args *uap; 2074e68ceabSDavid Greenman { 2084e68ceabSDavid Greenman struct proc *p; 209b0281cefSPeter Wemm struct iovec iov; 210b0281cefSPeter Wemm struct uio uio; 211bb56ec4aSPoul-Henning Kamp int error = 0; 212b0281cefSPeter Wemm int write; 213b0281cefSPeter Wemm int s; 2144e68ceabSDavid Greenman 2157a0dde68SPeter Wemm write = 0; 216b0281cefSPeter Wemm if (uap->req == PT_TRACE_ME) 217b0281cefSPeter Wemm p = curp; 218b0281cefSPeter Wemm else { 219b0281cefSPeter Wemm if ((p = pfind(uap->pid)) == NULL) 2204e68ceabSDavid Greenman return ESRCH; 2214e68ceabSDavid Greenman } 22275c13541SPoul-Henning Kamp if (!PRISON_CHECK(curp, p)) 22375c13541SPoul-Henning Kamp return (ESRCH); 2244e68ceabSDavid Greenman 225b0281cefSPeter Wemm /* 226b0281cefSPeter Wemm * Permissions check 227b0281cefSPeter Wemm */ 228b0281cefSPeter Wemm switch (uap->req) { 229b0281cefSPeter Wemm case PT_TRACE_ME: 230b0281cefSPeter Wemm /* Always legal. */ 231b0281cefSPeter Wemm break; 2324e68ceabSDavid Greenman 233b0281cefSPeter Wemm case PT_ATTACH: 234b0281cefSPeter Wemm /* Self */ 235b0281cefSPeter Wemm if (p->p_pid == curp->p_pid) 236b0281cefSPeter Wemm return EINVAL; 237b0281cefSPeter Wemm 238b0281cefSPeter Wemm /* Already traced */ 239b0281cefSPeter Wemm if (p->p_flag & P_TRACED) 240b0281cefSPeter Wemm return EBUSY; 241b0281cefSPeter Wemm 242b0281cefSPeter Wemm /* not owned by you, has done setuid (unless you're root) */ 243b0281cefSPeter Wemm if ((p->p_cred->p_ruid != curp->p_cred->p_ruid) || 244b0281cefSPeter Wemm (p->p_flag & P_SUGID)) { 245f711d546SPoul-Henning Kamp if ((error = suser(curp)) != 0) 246b0281cefSPeter Wemm return error; 247b0281cefSPeter Wemm } 248b0281cefSPeter Wemm 249ee7877dfSAlexander Langer /* can't trace init when securelevel > 0 */ 250ee7877dfSAlexander Langer if (securelevel > 0 && p->p_pid == 1) 251ee7877dfSAlexander Langer return EPERM; 252ee7877dfSAlexander Langer 253b0281cefSPeter Wemm /* OK */ 254b0281cefSPeter Wemm break; 255b0281cefSPeter Wemm 256b0281cefSPeter Wemm case PT_READ_I: 257b0281cefSPeter Wemm case PT_READ_D: 258b0281cefSPeter Wemm case PT_READ_U: 259b0281cefSPeter Wemm case PT_WRITE_I: 260b0281cefSPeter Wemm case PT_WRITE_D: 261b0281cefSPeter Wemm case PT_WRITE_U: 262b0281cefSPeter Wemm case PT_CONTINUE: 263b0281cefSPeter Wemm case PT_KILL: 264b0281cefSPeter Wemm case PT_STEP: 265b0281cefSPeter Wemm case PT_DETACH: 266b0281cefSPeter Wemm #ifdef PT_GETREGS 267b0281cefSPeter Wemm case PT_GETREGS: 2684e68ceabSDavid Greenman #endif 269b0281cefSPeter Wemm #ifdef PT_SETREGS 270b0281cefSPeter Wemm case PT_SETREGS: 2714e68ceabSDavid Greenman #endif 272b0281cefSPeter Wemm #ifdef PT_GETFPREGS 273b0281cefSPeter Wemm case PT_GETFPREGS: 274b0281cefSPeter Wemm #endif 275b0281cefSPeter Wemm #ifdef PT_SETFPREGS 276b0281cefSPeter Wemm case PT_SETFPREGS: 277b0281cefSPeter Wemm #endif 278ab001a72SJonathan Lemon #ifdef PT_GETDBREGS 279ab001a72SJonathan Lemon case PT_GETDBREGS: 280ab001a72SJonathan Lemon #endif 281ab001a72SJonathan Lemon #ifdef PT_SETDBREGS 282ab001a72SJonathan Lemon case PT_SETDBREGS: 283ab001a72SJonathan Lemon #endif 284b0281cefSPeter Wemm /* not being traced... */ 2854e68ceabSDavid Greenman if ((p->p_flag & P_TRACED) == 0) 2864e68ceabSDavid Greenman return EPERM; 287b0281cefSPeter Wemm 288b0281cefSPeter Wemm /* not being traced by YOU */ 289b0281cefSPeter Wemm if (p->p_pptr != curp) 290b0281cefSPeter Wemm return EBUSY; 291b0281cefSPeter Wemm 292b0281cefSPeter Wemm /* not currently stopped */ 2934e68ceabSDavid Greenman if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) 2944e68ceabSDavid Greenman return EBUSY; 295b0281cefSPeter Wemm 296b0281cefSPeter Wemm /* OK */ 297b0281cefSPeter Wemm break; 298b0281cefSPeter Wemm 299b0281cefSPeter Wemm default: 300b0281cefSPeter Wemm return EINVAL; 3014e68ceabSDavid Greenman } 302b0281cefSPeter Wemm 303b0281cefSPeter Wemm #ifdef FIX_SSTEP 304df8bae1dSRodney W. Grimes /* 305b0281cefSPeter Wemm * Single step fixup ala procfs 306b0281cefSPeter Wemm */ 307b0281cefSPeter Wemm FIX_SSTEP(p); 308b0281cefSPeter Wemm #endif 309b0281cefSPeter Wemm 310b0281cefSPeter Wemm /* 311b0281cefSPeter Wemm * Actually do the requests 312df8bae1dSRodney W. Grimes */ 3134e68ceabSDavid Greenman 314d72ec665STor Egge curp->p_retval[0] = 0; 3154e68ceabSDavid Greenman 316b0281cefSPeter Wemm switch (uap->req) { 317b0281cefSPeter Wemm case PT_TRACE_ME: 318b0281cefSPeter Wemm /* set my trace flag and "owner" so it can read/write me */ 3194e68ceabSDavid Greenman p->p_flag |= P_TRACED; 320b0281cefSPeter Wemm p->p_oppid = p->p_pptr->p_pid; 3214e68ceabSDavid Greenman return 0; 3224e68ceabSDavid Greenman 323b0281cefSPeter Wemm case PT_ATTACH: 324b0281cefSPeter Wemm /* security check done above */ 325b0281cefSPeter Wemm p->p_flag |= P_TRACED; 326b0281cefSPeter Wemm p->p_oppid = p->p_pptr->p_pid; 327b0281cefSPeter Wemm if (p->p_pptr != curp) 328b0281cefSPeter Wemm proc_reparent(p, curp); 329b0281cefSPeter Wemm uap->data = SIGSTOP; 330b0281cefSPeter Wemm goto sendsig; /* in PT_CONTINUE below */ 331b0281cefSPeter Wemm 332b0281cefSPeter Wemm case PT_STEP: 333b0281cefSPeter Wemm case PT_CONTINUE: 3344e68ceabSDavid Greenman case PT_DETACH: 3354e68ceabSDavid Greenman if ((unsigned)uap->data >= NSIG) 3364e68ceabSDavid Greenman return EINVAL; 337b0281cefSPeter Wemm 338b0281cefSPeter Wemm PHOLD(p); 339b0281cefSPeter Wemm 340b0281cefSPeter Wemm if (uap->req == PT_STEP) { 341b0281cefSPeter Wemm if ((error = ptrace_single_step (p))) { 342b0281cefSPeter Wemm PRELE(p); 343b0281cefSPeter Wemm return error; 344b0281cefSPeter Wemm } 345b0281cefSPeter Wemm } 346b0281cefSPeter Wemm 347b0281cefSPeter Wemm if (uap->addr != (caddr_t)1) { 348b0281cefSPeter Wemm fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 3496a206dd9SBruce Evans if ((error = ptrace_set_pc (p, 3506a206dd9SBruce Evans (u_long)(uintfptr_t)uap->addr))) { 351b0281cefSPeter Wemm PRELE(p); 352b0281cefSPeter Wemm return error; 353b0281cefSPeter Wemm } 354b0281cefSPeter Wemm } 355b0281cefSPeter Wemm PRELE(p); 356b0281cefSPeter Wemm 357b0281cefSPeter Wemm if (uap->req == PT_DETACH) { 358b0281cefSPeter Wemm /* reset process parent */ 359b0281cefSPeter Wemm if (p->p_oppid != p->p_pptr->p_pid) { 360b0281cefSPeter Wemm struct proc *pp; 361b0281cefSPeter Wemm 362b0281cefSPeter Wemm pp = pfind(p->p_oppid); 363b0281cefSPeter Wemm proc_reparent(p, pp ? pp : initproc); 364b0281cefSPeter Wemm } 365b0281cefSPeter Wemm 366b0281cefSPeter Wemm p->p_flag &= ~(P_TRACED | P_WAITED); 367b0281cefSPeter Wemm p->p_oppid = 0; 368b0281cefSPeter Wemm 369b0281cefSPeter Wemm /* should we send SIGCHLD? */ 370b0281cefSPeter Wemm 371b0281cefSPeter Wemm } 372b0281cefSPeter Wemm 373b0281cefSPeter Wemm sendsig: 374b0281cefSPeter Wemm /* deliver or queue signal */ 3754e68ceabSDavid Greenman s = splhigh(); 3764e68ceabSDavid Greenman if (p->p_stat == SSTOP) { 3774e68ceabSDavid Greenman p->p_xstat = uap->data; 3784e68ceabSDavid Greenman setrunnable(p); 3794e68ceabSDavid Greenman } else if (uap->data) { 3804e68ceabSDavid Greenman psignal(p, uap->data); 3814e68ceabSDavid Greenman } 3824e68ceabSDavid Greenman splx(s); 3834e68ceabSDavid Greenman return 0; 3844e68ceabSDavid Greenman 3854e68ceabSDavid Greenman case PT_WRITE_I: 3864e68ceabSDavid Greenman case PT_WRITE_D: 387b0281cefSPeter Wemm write = 1; 3884e68ceabSDavid Greenman /* fallthrough */ 389b0281cefSPeter Wemm case PT_READ_I: 390b0281cefSPeter Wemm case PT_READ_D: 391b0281cefSPeter Wemm /* write = 0 set above */ 392d72ec665STor Egge iov.iov_base = write ? (caddr_t)&uap->data : (caddr_t)curp->p_retval; 393b0281cefSPeter Wemm iov.iov_len = sizeof(int); 394b0281cefSPeter Wemm uio.uio_iov = &iov; 395b0281cefSPeter Wemm uio.uio_iovcnt = 1; 3966a206dd9SBruce Evans uio.uio_offset = (off_t)(uintptr_t)uap->addr; 397b0281cefSPeter Wemm uio.uio_resid = sizeof(int); 398b0281cefSPeter Wemm uio.uio_segflg = UIO_SYSSPACE; /* ie: the uap */ 399b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 400b0281cefSPeter Wemm uio.uio_procp = p; 4012eb80d36SPeter Wemm error = procfs_domem(curp, p, NULL, &uio); 4022eb80d36SPeter Wemm if (uio.uio_resid != 0) { 4032eb80d36SPeter Wemm /* 4042eb80d36SPeter Wemm * XXX procfs_domem() doesn't currently return ENOSPC, 4052eb80d36SPeter Wemm * so I think write() can bogusly return 0. 4062eb80d36SPeter Wemm * XXX what happens for short writes? We don't want 4072eb80d36SPeter Wemm * to write partial data. 4082eb80d36SPeter Wemm * XXX procfs_domem() returns EPERM for other invalid 4092eb80d36SPeter Wemm * addresses. Convert this to EINVAL. Does this 4102eb80d36SPeter Wemm * clobber returns of EPERM for other reasons? 4112eb80d36SPeter Wemm */ 4122eb80d36SPeter Wemm if (error == 0 || error == ENOSPC || error == EPERM) 4132eb80d36SPeter Wemm error = EINVAL; /* EOF */ 4142eb80d36SPeter Wemm } 4152eb80d36SPeter Wemm return (error); 4164e68ceabSDavid Greenman 4174e68ceabSDavid Greenman case PT_READ_U: 418dae63452SDoug Rabson if ((uintptr_t)uap->addr > UPAGES * PAGE_SIZE - sizeof(int)) { 419dae63452SDoug Rabson return EFAULT; 420dae63452SDoug Rabson } 421dae63452SDoug Rabson if ((uintptr_t)uap->addr & (sizeof(int) - 1)) { 4224e68ceabSDavid Greenman return EFAULT; 4234e68ceabSDavid Greenman } 424afc6ea23STor Egge if (ptrace_read_u_check(p,(vm_offset_t) uap->addr, 42567e7cb89SDoug Rabson sizeof(int)) && 426afc6ea23STor Egge !procfs_kmemaccess(curp)) { 427afc6ea23STor Egge return EFAULT; 428afc6ea23STor Egge } 429b0281cefSPeter Wemm error = 0; 430b0281cefSPeter Wemm PHOLD(p); /* user had damn well better be incore! */ 431b0281cefSPeter Wemm if (p->p_flag & P_INMEM) { 4324e68ceabSDavid Greenman p->p_addr->u_kproc.kp_proc = *p; 4334e68ceabSDavid Greenman fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 4348a8a13c8SDoug Rabson curp->p_retval[0] = *(int *) 4356a206dd9SBruce Evans ((uintptr_t)p->p_addr + (uintptr_t)uap->addr); 436b0281cefSPeter Wemm } else { 437d72ec665STor Egge curp->p_retval[0] = 0; 438b0281cefSPeter Wemm error = EFAULT; 439b0281cefSPeter Wemm } 440b0281cefSPeter Wemm PRELE(p); 441b0281cefSPeter Wemm return error; 442b0281cefSPeter Wemm 4434e68ceabSDavid Greenman case PT_WRITE_U: 444b0281cefSPeter Wemm PHOLD(p); /* user had damn well better be incore! */ 445b0281cefSPeter Wemm if (p->p_flag & P_INMEM) { 4464e68ceabSDavid Greenman p->p_addr->u_kproc.kp_proc = *p; 4474e68ceabSDavid Greenman fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 448b0281cefSPeter Wemm error = ptrace_write_u(p, (vm_offset_t)uap->addr, uap->data); 449b0281cefSPeter Wemm } else { 450b0281cefSPeter Wemm error = EFAULT; 451b0281cefSPeter Wemm } 452b0281cefSPeter Wemm PRELE(p); 453b0281cefSPeter Wemm return error; 454b0281cefSPeter Wemm 4554e68ceabSDavid Greenman case PT_KILL: 456b0281cefSPeter Wemm uap->data = SIGKILL; 457b0281cefSPeter Wemm goto sendsig; /* in PT_CONTINUE above */ 458b0281cefSPeter Wemm 459b0281cefSPeter Wemm #ifdef PT_SETREGS 460b0281cefSPeter Wemm case PT_SETREGS: 461b0281cefSPeter Wemm write = 1; 462b0281cefSPeter Wemm /* fallthrough */ 463b0281cefSPeter Wemm #endif /* PT_SETREGS */ 4644e68ceabSDavid Greenman #ifdef PT_GETREGS 4654e68ceabSDavid Greenman case PT_GETREGS: 466b0281cefSPeter Wemm /* write = 0 above */ 467b0281cefSPeter Wemm #endif /* PT_SETREGS */ 468b0281cefSPeter Wemm #if defined(PT_SETREGS) || defined(PT_GETREGS) 469b0281cefSPeter Wemm if (!procfs_validregs(p)) /* no P_SYSTEM procs please */ 470b0281cefSPeter Wemm return EINVAL; 471b0281cefSPeter Wemm else { 472b0281cefSPeter Wemm iov.iov_base = uap->addr; 473b0281cefSPeter Wemm iov.iov_len = sizeof(struct reg); 474b0281cefSPeter Wemm uio.uio_iov = &iov; 475b0281cefSPeter Wemm uio.uio_iovcnt = 1; 476b0281cefSPeter Wemm uio.uio_offset = 0; 477b0281cefSPeter Wemm uio.uio_resid = sizeof(struct reg); 478b0281cefSPeter Wemm uio.uio_segflg = UIO_USERSPACE; 479b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 480b0281cefSPeter Wemm uio.uio_procp = curp; 481b0281cefSPeter Wemm return (procfs_doregs(curp, p, NULL, &uio)); 482b0281cefSPeter Wemm } 483b0281cefSPeter Wemm #endif /* defined(PT_SETREGS) || defined(PT_GETREGS) */ 484b0281cefSPeter Wemm 485b0281cefSPeter Wemm #ifdef PT_SETFPREGS 486b0281cefSPeter Wemm case PT_SETFPREGS: 487b0281cefSPeter Wemm write = 1; 488b0281cefSPeter Wemm /* fallthrough */ 489b0281cefSPeter Wemm #endif /* PT_SETFPREGS */ 490b0281cefSPeter Wemm #ifdef PT_GETFPREGS 491b0281cefSPeter Wemm case PT_GETFPREGS: 492b0281cefSPeter Wemm /* write = 0 above */ 493b0281cefSPeter Wemm #endif /* PT_SETFPREGS */ 494b0281cefSPeter Wemm #if defined(PT_SETFPREGS) || defined(PT_GETFPREGS) 495b0281cefSPeter Wemm if (!procfs_validfpregs(p)) /* no P_SYSTEM procs please */ 496b0281cefSPeter Wemm return EINVAL; 497b0281cefSPeter Wemm else { 498b0281cefSPeter Wemm iov.iov_base = uap->addr; 499b0281cefSPeter Wemm iov.iov_len = sizeof(struct fpreg); 500b0281cefSPeter Wemm uio.uio_iov = &iov; 501b0281cefSPeter Wemm uio.uio_iovcnt = 1; 502b0281cefSPeter Wemm uio.uio_offset = 0; 503b0281cefSPeter Wemm uio.uio_resid = sizeof(struct fpreg); 504b0281cefSPeter Wemm uio.uio_segflg = UIO_USERSPACE; 505b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 506b0281cefSPeter Wemm uio.uio_procp = curp; 507b0281cefSPeter Wemm return (procfs_dofpregs(curp, p, NULL, &uio)); 508b0281cefSPeter Wemm } 509b0281cefSPeter Wemm #endif /* defined(PT_SETFPREGS) || defined(PT_GETFPREGS) */ 510b0281cefSPeter Wemm 511ab001a72SJonathan Lemon #ifdef PT_SETDBREGS 512ab001a72SJonathan Lemon case PT_SETDBREGS: 513ab001a72SJonathan Lemon write = 1; 514ab001a72SJonathan Lemon /* fallthrough */ 515ab001a72SJonathan Lemon #endif /* PT_SETDBREGS */ 516ab001a72SJonathan Lemon #ifdef PT_GETDBREGS 517ab001a72SJonathan Lemon case PT_GETDBREGS: 518ab001a72SJonathan Lemon /* write = 0 above */ 519ab001a72SJonathan Lemon #endif /* PT_SETDBREGS */ 520ab001a72SJonathan Lemon #if defined(PT_SETDBREGS) || defined(PT_GETDBREGS) 521ab001a72SJonathan Lemon if (!procfs_validdbregs(p)) /* no P_SYSTEM procs please */ 522ab001a72SJonathan Lemon return EINVAL; 523ab001a72SJonathan Lemon else { 524ab001a72SJonathan Lemon iov.iov_base = uap->addr; 525ab001a72SJonathan Lemon iov.iov_len = sizeof(struct dbreg); 526ab001a72SJonathan Lemon uio.uio_iov = &iov; 527ab001a72SJonathan Lemon uio.uio_iovcnt = 1; 528ab001a72SJonathan Lemon uio.uio_offset = 0; 529ab001a72SJonathan Lemon uio.uio_resid = sizeof(struct dbreg); 530ab001a72SJonathan Lemon uio.uio_segflg = UIO_USERSPACE; 531ab001a72SJonathan Lemon uio.uio_rw = write ? UIO_WRITE : UIO_READ; 532ab001a72SJonathan Lemon uio.uio_procp = curp; 533ab001a72SJonathan Lemon return (procfs_dodbregs(curp, p, NULL, &uio)); 534ab001a72SJonathan Lemon } 535ab001a72SJonathan Lemon #endif /* defined(PT_SETDBREGS) || defined(PT_GETDBREGS) */ 536ab001a72SJonathan Lemon 5374e68ceabSDavid Greenman default: 5384e68ceabSDavid Greenman break; 5394e68ceabSDavid Greenman } 5404e68ceabSDavid Greenman 5414e68ceabSDavid Greenman return 0; 542df8bae1dSRodney W. Grimes } 543df8bae1dSRodney W. Grimes 54426f9a767SRodney W. Grimes int 5454e68ceabSDavid Greenman trace_req(p) 5464e68ceabSDavid Greenman struct proc *p; 547df8bae1dSRodney W. Grimes { 5484e68ceabSDavid Greenman return 1; 549df8bae1dSRodney W. Grimes } 5502a024a2bSSean Eric Fagan 5512a024a2bSSean Eric Fagan /* 5522a024a2bSSean Eric Fagan * stopevent() 5532a024a2bSSean Eric Fagan * Stop a process because of a procfs event; 5542a024a2bSSean Eric Fagan * stay stopped until p->p_step is cleared 5552a024a2bSSean Eric Fagan * (cleared by PIOCCONT in procfs). 5562a024a2bSSean Eric Fagan */ 5572a024a2bSSean Eric Fagan 5582a024a2bSSean Eric Fagan void 5592a024a2bSSean Eric Fagan stopevent(struct proc *p, unsigned int event, unsigned int val) { 5602a024a2bSSean Eric Fagan p->p_step = 1; 5612a024a2bSSean Eric Fagan 5622a024a2bSSean Eric Fagan do { 5632a024a2bSSean Eric Fagan p->p_xstat = val; 5642a024a2bSSean Eric Fagan p->p_stype = event; /* Which event caused the stop? */ 5652a024a2bSSean Eric Fagan wakeup(&p->p_stype); /* Wake up any PIOCWAIT'ing procs */ 5662a024a2bSSean Eric Fagan tsleep(&p->p_step, PWAIT, "stopevent", 0); 5672a024a2bSSean Eric Fagan } while (p->p_step); 5682a024a2bSSean Eric Fagan } 569