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 * 31c3aac50fSPeter Wemm * $FreeBSD$ 32df8bae1dSRodney W. Grimes */ 33df8bae1dSRodney W. Grimes 34df8bae1dSRodney W. Grimes #include <sys/param.h> 35f23b4c91SGarrett Wollman #include <sys/systm.h> 36fb919e4dSMark Murray #include <sys/lock.h> 37fb919e4dSMark Murray #include <sys/mutex.h> 38d2d3e875SBruce Evans #include <sys/sysproto.h> 39df8bae1dSRodney W. Grimes #include <sys/proc.h> 404e68ceabSDavid Greenman #include <sys/vnode.h> 414e68ceabSDavid Greenman #include <sys/ptrace.h> 421005a129SJohn Baldwin #include <sys/sx.h> 43fb919e4dSMark Murray #include <sys/user.h> 44df8bae1dSRodney W. Grimes 454e68ceabSDavid Greenman #include <machine/reg.h> 46fb919e4dSMark Murray 474e68ceabSDavid Greenman #include <vm/vm.h> 48efeaf95aSDavid Greenman #include <vm/pmap.h> 49efeaf95aSDavid Greenman #include <vm/vm_map.h> 504e68ceabSDavid Greenman #include <vm/vm_page.h> 514e68ceabSDavid Greenman 5299d300a1SRuslan Ermilov #include <fs/procfs/procfs.h> 534e68ceabSDavid Greenman 54b0281cefSPeter Wemm /* use the equivalent procfs code */ 55b0281cefSPeter Wemm #if 0 56c4cf09ffSDavid Greenman static int 574e68ceabSDavid Greenman pread (struct proc *procp, unsigned int addr, unsigned int *retval) { 584e68ceabSDavid Greenman int rv; 594e68ceabSDavid Greenman vm_map_t map, tmap; 604e68ceabSDavid Greenman vm_object_t object; 614e68ceabSDavid Greenman vm_offset_t kva = 0; 624e68ceabSDavid Greenman int page_offset; /* offset into page */ 634e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 644e68ceabSDavid Greenman vm_map_entry_t out_entry; 654e68ceabSDavid Greenman vm_prot_t out_prot; 662d8acc0fSJohn Dyson boolean_t wired; 6763c8f421SBruce Evans vm_pindex_t pindex; 684e68ceabSDavid Greenman 694e68ceabSDavid Greenman /* Map page into kernel space */ 704e68ceabSDavid Greenman 714e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 724e68ceabSDavid Greenman 734e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 744e68ceabSDavid Greenman pageno = trunc_page(addr); 754e68ceabSDavid Greenman 764e68ceabSDavid Greenman tmap = map; 774e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_READ, &out_entry, 782d8acc0fSJohn Dyson &object, &pindex, &out_prot, &wired); 794e68ceabSDavid Greenman 804e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 81c5799337SDag-Erling Smørgrav return (EINVAL); 824e68ceabSDavid Greenman 834e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 844e68ceabSDavid Greenman 854e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 86bd7e5f99SJohn Dyson rv = vm_map_find (kernel_map, object, IDX_TO_OFF(pindex), 87bd7e5f99SJohn Dyson &kva, PAGE_SIZE, 0, VM_PROT_ALL, VM_PROT_ALL, 0); 884e68ceabSDavid Greenman 894e68ceabSDavid Greenman if (!rv) { 904e68ceabSDavid Greenman vm_object_reference (object); 914e68ceabSDavid Greenman 924e68ceabSDavid Greenman rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 934e68ceabSDavid Greenman if (!rv) { 944e68ceabSDavid Greenman *retval = 0; 95f23b4c91SGarrett Wollman bcopy ((caddr_t)kva + page_offset, 96f23b4c91SGarrett Wollman retval, sizeof *retval); 974e68ceabSDavid Greenman } 984e68ceabSDavid Greenman vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 994e68ceabSDavid Greenman } 1004e68ceabSDavid Greenman 101c5799337SDag-Erling Smørgrav return (rv); 1024e68ceabSDavid Greenman } 1034e68ceabSDavid Greenman 104c4cf09ffSDavid Greenman static int 1054e68ceabSDavid Greenman pwrite (struct proc *procp, unsigned int addr, unsigned int datum) { 1064e68ceabSDavid Greenman int rv; 1074e68ceabSDavid Greenman vm_map_t map, tmap; 1084e68ceabSDavid Greenman vm_object_t object; 1094e68ceabSDavid Greenman vm_offset_t kva = 0; 1104e68ceabSDavid Greenman int page_offset; /* offset into page */ 1114e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 1124e68ceabSDavid Greenman vm_map_entry_t out_entry; 1134e68ceabSDavid Greenman vm_prot_t out_prot; 1142d8acc0fSJohn Dyson boolean_t wired; 11563c8f421SBruce Evans vm_pindex_t pindex; 1164e68ceabSDavid Greenman boolean_t fix_prot = 0; 1174e68ceabSDavid Greenman 1184e68ceabSDavid Greenman /* Map page into kernel space */ 1194e68ceabSDavid Greenman 1204e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 1214e68ceabSDavid Greenman 1224e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 1234e68ceabSDavid Greenman pageno = trunc_page(addr); 1244e68ceabSDavid Greenman 1254e68ceabSDavid Greenman /* 1264e68ceabSDavid Greenman * Check the permissions for the area we're interested in. 1274e68ceabSDavid Greenman */ 1284e68ceabSDavid Greenman 1294e68ceabSDavid Greenman if (vm_map_check_protection (map, pageno, pageno + PAGE_SIZE, 1304e68ceabSDavid Greenman VM_PROT_WRITE) == FALSE) { 1314e68ceabSDavid Greenman /* 1324e68ceabSDavid Greenman * If the page was not writable, we make it so. 1334e68ceabSDavid Greenman * XXX It is possible a page may *not* be read/executable, 1344e68ceabSDavid Greenman * if a process changes that! 1354e68ceabSDavid Greenman */ 1364e68ceabSDavid Greenman fix_prot = 1; 1374e68ceabSDavid Greenman /* The page isn't writable, so let's try making it so... */ 1384e68ceabSDavid Greenman if ((rv = vm_map_protect (map, pageno, pageno + PAGE_SIZE, 1394e68ceabSDavid Greenman VM_PROT_ALL, 0)) != KERN_SUCCESS) 140c5799337SDag-Erling Smørgrav return (EFAULT); /* I guess... */ 1414e68ceabSDavid Greenman } 1424e68ceabSDavid Greenman 1434e68ceabSDavid Greenman /* 1444e68ceabSDavid Greenman * Now we need to get the page. out_entry, out_prot, wired, and 1454e68ceabSDavid Greenman * single_use aren't used. One would think the vm code would be 1464e68ceabSDavid Greenman * a *bit* nicer... We use tmap because vm_map_lookup() can 1474e68ceabSDavid Greenman * change the map argument. 1484e68ceabSDavid Greenman */ 1494e68ceabSDavid Greenman 1504e68ceabSDavid Greenman tmap = map; 1514e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_WRITE, &out_entry, 1522d8acc0fSJohn Dyson &object, &pindex, &out_prot, &wired); 1534e68ceabSDavid Greenman if (rv != KERN_SUCCESS) { 154c5799337SDag-Erling Smørgrav return (EINVAL); 1554e68ceabSDavid Greenman } 1564e68ceabSDavid Greenman 1574e68ceabSDavid Greenman /* 1584e68ceabSDavid Greenman * Okay, we've got the page. Let's release tmap. 1594e68ceabSDavid Greenman */ 1604e68ceabSDavid Greenman 1614e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 1624e68ceabSDavid Greenman 1634e68ceabSDavid Greenman /* 1644e68ceabSDavid Greenman * Fault the page in... 1654e68ceabSDavid Greenman */ 1664e68ceabSDavid Greenman 167914a63ebSDavid Greenman rv = vm_fault(map, pageno, VM_PROT_WRITE|VM_PROT_READ, FALSE); 1684e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 169c5799337SDag-Erling Smørgrav return (EFAULT); 1704e68ceabSDavid Greenman 1714e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 172bd7e5f99SJohn Dyson rv = vm_map_find (kernel_map, object, IDX_TO_OFF(pindex), 173bd7e5f99SJohn Dyson &kva, PAGE_SIZE, 0, 174bd7e5f99SJohn Dyson VM_PROT_ALL, VM_PROT_ALL, 0); 1754e68ceabSDavid Greenman if (!rv) { 1764e68ceabSDavid Greenman vm_object_reference (object); 1774e68ceabSDavid Greenman 1784e68ceabSDavid Greenman rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 1794e68ceabSDavid Greenman if (!rv) { 180f23b4c91SGarrett Wollman bcopy (&datum, (caddr_t)kva + page_offset, sizeof datum); 1814e68ceabSDavid Greenman } 1824e68ceabSDavid Greenman vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 1834e68ceabSDavid Greenman } 1844e68ceabSDavid Greenman 1854e68ceabSDavid Greenman if (fix_prot) 1864e68ceabSDavid Greenman vm_map_protect (map, pageno, pageno + PAGE_SIZE, 1874e68ceabSDavid Greenman VM_PROT_READ|VM_PROT_EXECUTE, 0); 188c5799337SDag-Erling Smørgrav return (rv); 1894e68ceabSDavid Greenman } 190b0281cefSPeter Wemm #endif 1914e68ceabSDavid Greenman 192df8bae1dSRodney W. Grimes /* 193df8bae1dSRodney W. Grimes * Process debugging system call. 194df8bae1dSRodney W. Grimes */ 195d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 196df8bae1dSRodney W. Grimes struct ptrace_args { 197df8bae1dSRodney W. Grimes int req; 198df8bae1dSRodney W. Grimes pid_t pid; 199df8bae1dSRodney W. Grimes caddr_t addr; 200df8bae1dSRodney W. Grimes int data; 201df8bae1dSRodney W. Grimes }; 202d2d3e875SBruce Evans #endif 203df8bae1dSRodney W. Grimes 2044e68ceabSDavid Greenman int 205b40ce416SJulian Elischer ptrace(td, uap) 206b40ce416SJulian Elischer struct thread *td; 2074e68ceabSDavid Greenman struct ptrace_args *uap; 2084e68ceabSDavid Greenman { 209b40ce416SJulian Elischer struct proc *curp = td->td_proc; 2104e68ceabSDavid Greenman struct proc *p; 211b0281cefSPeter Wemm struct iovec iov; 212b0281cefSPeter Wemm struct uio uio; 213bb56ec4aSPoul-Henning Kamp int error = 0; 214b0281cefSPeter Wemm int write; 2154e68ceabSDavid Greenman 2167a0dde68SPeter Wemm write = 0; 21733a9ed9dSJohn Baldwin if (uap->req == PT_TRACE_ME) { 218b0281cefSPeter Wemm p = curp; 21933a9ed9dSJohn Baldwin PROC_LOCK(p); 22033a9ed9dSJohn Baldwin } else { 221b0281cefSPeter Wemm if ((p = pfind(uap->pid)) == NULL) 222c5799337SDag-Erling Smørgrav return (ESRCH); 2234e68ceabSDavid Greenman } 224a0f75161SRobert Watson if (p_cansee(curp, p)) { 22533a9ed9dSJohn Baldwin PROC_UNLOCK(p); 22675c13541SPoul-Henning Kamp return (ESRCH); 22733a9ed9dSJohn Baldwin } 2284e68ceabSDavid Greenman 229b0281cefSPeter Wemm /* 230b0281cefSPeter Wemm * Permissions check 231b0281cefSPeter Wemm */ 232b0281cefSPeter Wemm switch (uap->req) { 233b0281cefSPeter Wemm case PT_TRACE_ME: 234b0281cefSPeter Wemm /* Always legal. */ 235b0281cefSPeter Wemm break; 2364e68ceabSDavid Greenman 237b0281cefSPeter Wemm case PT_ATTACH: 238b0281cefSPeter Wemm /* Self */ 23933a9ed9dSJohn Baldwin if (p->p_pid == curp->p_pid) { 24033a9ed9dSJohn Baldwin PROC_UNLOCK(p); 241c5799337SDag-Erling Smørgrav return (EINVAL); 24233a9ed9dSJohn Baldwin } 243b0281cefSPeter Wemm 244b0281cefSPeter Wemm /* Already traced */ 245731a1aeaSJohn Baldwin if (p->p_flag & P_TRACED) { 246731a1aeaSJohn Baldwin PROC_UNLOCK(p); 247c5799337SDag-Erling Smørgrav return (EBUSY); 248731a1aeaSJohn Baldwin } 249b0281cefSPeter Wemm 250a0f75161SRobert Watson if ((error = p_candebug(curp, p))) { 25133a9ed9dSJohn Baldwin PROC_UNLOCK(p); 252c5799337SDag-Erling Smørgrav return (error); 25333a9ed9dSJohn Baldwin } 254ee7877dfSAlexander Langer 255b0281cefSPeter Wemm /* OK */ 256b0281cefSPeter Wemm break; 257b0281cefSPeter Wemm 258b0281cefSPeter Wemm case PT_READ_I: 259b0281cefSPeter Wemm case PT_READ_D: 260b0281cefSPeter Wemm case PT_WRITE_I: 261b0281cefSPeter Wemm case PT_WRITE_D: 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... */ 285731a1aeaSJohn Baldwin if ((p->p_flag & P_TRACED) == 0) { 286731a1aeaSJohn Baldwin PROC_UNLOCK(p); 287c5799337SDag-Erling Smørgrav return (EPERM); 288731a1aeaSJohn Baldwin } 289b0281cefSPeter Wemm 290b0281cefSPeter Wemm /* not being traced by YOU */ 29198f03f90SJake Burkholder if (p->p_pptr != curp) { 292731a1aeaSJohn Baldwin PROC_UNLOCK(p); 293c5799337SDag-Erling Smørgrav return (EBUSY); 29498f03f90SJake Burkholder } 295b0281cefSPeter Wemm 296b0281cefSPeter Wemm /* not currently stopped */ 2979ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 2980ebabc93SJohn Baldwin if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) { 2999ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 300731a1aeaSJohn Baldwin PROC_UNLOCK(p); 301c5799337SDag-Erling Smørgrav return (EBUSY); 3020ebabc93SJohn Baldwin } 3039ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 304b0281cefSPeter Wemm 305b0281cefSPeter Wemm /* OK */ 306b0281cefSPeter Wemm break; 307b0281cefSPeter Wemm 308b0281cefSPeter Wemm default: 30933a9ed9dSJohn Baldwin PROC_UNLOCK(p); 310c5799337SDag-Erling Smørgrav return (EINVAL); 3114e68ceabSDavid Greenman } 312b0281cefSPeter Wemm 31333a9ed9dSJohn Baldwin PROC_UNLOCK(p); 314b0281cefSPeter Wemm #ifdef FIX_SSTEP 315df8bae1dSRodney W. Grimes /* 316b0281cefSPeter Wemm * Single step fixup ala procfs 317b0281cefSPeter Wemm */ 318b40ce416SJulian Elischer FIX_SSTEP(&p->p_thread); /* XXXKSE */ 319b0281cefSPeter Wemm #endif 320b0281cefSPeter Wemm 321b0281cefSPeter Wemm /* 322b0281cefSPeter Wemm * Actually do the requests 323df8bae1dSRodney W. Grimes */ 3244e68ceabSDavid Greenman 325b40ce416SJulian Elischer td->td_retval[0] = 0; 3264e68ceabSDavid Greenman 327b0281cefSPeter Wemm switch (uap->req) { 328b0281cefSPeter Wemm case PT_TRACE_ME: 329b0281cefSPeter Wemm /* set my trace flag and "owner" so it can read/write me */ 3301005a129SJohn Baldwin sx_xlock(&proctree_lock); 331731a1aeaSJohn Baldwin PROC_LOCK(p); 3324e68ceabSDavid Greenman p->p_flag |= P_TRACED; 333b0281cefSPeter Wemm p->p_oppid = p->p_pptr->p_pid; 334731a1aeaSJohn Baldwin PROC_UNLOCK(p); 3351005a129SJohn Baldwin sx_xunlock(&proctree_lock); 336c5799337SDag-Erling Smørgrav return (0); 3374e68ceabSDavid Greenman 338b0281cefSPeter Wemm case PT_ATTACH: 339b0281cefSPeter Wemm /* security check done above */ 3401005a129SJohn Baldwin sx_xlock(&proctree_lock); 341731a1aeaSJohn Baldwin PROC_LOCK(p); 342731a1aeaSJohn Baldwin p->p_flag |= P_TRACED; 343b0281cefSPeter Wemm p->p_oppid = p->p_pptr->p_pid; 344b0281cefSPeter Wemm if (p->p_pptr != curp) 345b0281cefSPeter Wemm proc_reparent(p, curp); 346731a1aeaSJohn Baldwin PROC_UNLOCK(p); 3471005a129SJohn Baldwin sx_xunlock(&proctree_lock); 348b0281cefSPeter Wemm uap->data = SIGSTOP; 349b0281cefSPeter Wemm goto sendsig; /* in PT_CONTINUE below */ 350b0281cefSPeter Wemm 351b0281cefSPeter Wemm case PT_STEP: 352b0281cefSPeter Wemm case PT_CONTINUE: 3534e68ceabSDavid Greenman case PT_DETACH: 3542ec40c9aSJohn W. De Boskey if ((uap->req != PT_STEP) && ((unsigned)uap->data >= NSIG)) 355c5799337SDag-Erling Smørgrav return (EINVAL); 356b0281cefSPeter Wemm 357b0281cefSPeter Wemm PHOLD(p); 358b0281cefSPeter Wemm 359b0281cefSPeter Wemm if (uap->req == PT_STEP) { 360796ed2a6SMark Peek if ((error = ptrace_single_step (&p->p_thread))) { 361b0281cefSPeter Wemm PRELE(p); 362c5799337SDag-Erling Smørgrav return (error); 363b0281cefSPeter Wemm } 364b0281cefSPeter Wemm } 365b0281cefSPeter Wemm 366b0281cefSPeter Wemm if (uap->addr != (caddr_t)1) { 367b40ce416SJulian Elischer fill_kinfo_proc (p, &p->p_uarea->u_kproc); 368796ed2a6SMark Peek if ((error = ptrace_set_pc (&p->p_thread, 3696a206dd9SBruce Evans (u_long)(uintfptr_t)uap->addr))) { 370b0281cefSPeter Wemm PRELE(p); 371c5799337SDag-Erling Smørgrav return (error); 372b0281cefSPeter Wemm } 373b0281cefSPeter Wemm } 374b0281cefSPeter Wemm PRELE(p); 375b0281cefSPeter Wemm 376b0281cefSPeter Wemm if (uap->req == PT_DETACH) { 377b0281cefSPeter Wemm /* reset process parent */ 3781005a129SJohn Baldwin sx_xlock(&proctree_lock); 379b0281cefSPeter Wemm if (p->p_oppid != p->p_pptr->p_pid) { 380b0281cefSPeter Wemm struct proc *pp; 381b0281cefSPeter Wemm 382b0281cefSPeter Wemm pp = pfind(p->p_oppid); 3836c49a8e2SJohn Baldwin if (pp != NULL) 3846c49a8e2SJohn Baldwin PROC_UNLOCK(pp); 3856c49a8e2SJohn Baldwin else 3866c49a8e2SJohn Baldwin pp = initproc; 3876c49a8e2SJohn Baldwin PROC_LOCK(p); 3886c49a8e2SJohn Baldwin proc_reparent(p, pp); 389731a1aeaSJohn Baldwin } else 390731a1aeaSJohn Baldwin PROC_LOCK(p); 391b0281cefSPeter Wemm p->p_flag &= ~(P_TRACED | P_WAITED); 392b0281cefSPeter Wemm p->p_oppid = 0; 393b0281cefSPeter Wemm 394731a1aeaSJohn Baldwin PROC_UNLOCK(p); 3951005a129SJohn Baldwin sx_xunlock(&proctree_lock); 396731a1aeaSJohn Baldwin 397b0281cefSPeter Wemm /* should we send SIGCHLD? */ 398b0281cefSPeter Wemm 399b0281cefSPeter Wemm } 400b0281cefSPeter Wemm 401b0281cefSPeter Wemm sendsig: 402b0281cefSPeter Wemm /* deliver or queue signal */ 403731a1aeaSJohn Baldwin PROC_LOCK(p); 4049ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 4054e68ceabSDavid Greenman if (p->p_stat == SSTOP) { 4064e68ceabSDavid Greenman p->p_xstat = uap->data; 407b40ce416SJulian Elischer setrunnable(&p->p_thread); /* XXXKSE */ 4089ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 4090ebabc93SJohn Baldwin } else { 4109ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 411731a1aeaSJohn Baldwin if (uap->data) 4124e68ceabSDavid Greenman psignal(p, uap->data); 413731a1aeaSJohn Baldwin 4144e68ceabSDavid Greenman } 415731a1aeaSJohn Baldwin PROC_UNLOCK(p); 416c5799337SDag-Erling Smørgrav return (0); 4174e68ceabSDavid Greenman 4184e68ceabSDavid Greenman case PT_WRITE_I: 4194e68ceabSDavid Greenman case PT_WRITE_D: 420b0281cefSPeter Wemm write = 1; 4214e68ceabSDavid Greenman /* fallthrough */ 422b0281cefSPeter Wemm case PT_READ_I: 423b0281cefSPeter Wemm case PT_READ_D: 424b0281cefSPeter Wemm /* write = 0 set above */ 425b40ce416SJulian Elischer iov.iov_base = write ? (caddr_t)&uap->data : (caddr_t)td->td_retval; 426b0281cefSPeter Wemm iov.iov_len = sizeof(int); 427b0281cefSPeter Wemm uio.uio_iov = &iov; 428b0281cefSPeter Wemm uio.uio_iovcnt = 1; 4296a206dd9SBruce Evans uio.uio_offset = (off_t)(uintptr_t)uap->addr; 430b0281cefSPeter Wemm uio.uio_resid = sizeof(int); 431b0281cefSPeter Wemm uio.uio_segflg = UIO_SYSSPACE; /* ie: the uap */ 432b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 433b40ce416SJulian Elischer uio.uio_td = td; 4342eb80d36SPeter Wemm error = procfs_domem(curp, p, NULL, &uio); 4352eb80d36SPeter Wemm if (uio.uio_resid != 0) { 4362eb80d36SPeter Wemm /* 4372eb80d36SPeter Wemm * XXX procfs_domem() doesn't currently return ENOSPC, 4382eb80d36SPeter Wemm * so I think write() can bogusly return 0. 4392eb80d36SPeter Wemm * XXX what happens for short writes? We don't want 4402eb80d36SPeter Wemm * to write partial data. 4412eb80d36SPeter Wemm * XXX procfs_domem() returns EPERM for other invalid 4422eb80d36SPeter Wemm * addresses. Convert this to EINVAL. Does this 4432eb80d36SPeter Wemm * clobber returns of EPERM for other reasons? 4442eb80d36SPeter Wemm */ 4452eb80d36SPeter Wemm if (error == 0 || error == ENOSPC || error == EPERM) 4462eb80d36SPeter Wemm error = EINVAL; /* EOF */ 4472eb80d36SPeter Wemm } 4482eb80d36SPeter Wemm return (error); 4494e68ceabSDavid Greenman 4504e68ceabSDavid Greenman case PT_KILL: 451b0281cefSPeter Wemm uap->data = SIGKILL; 452b0281cefSPeter Wemm goto sendsig; /* in PT_CONTINUE above */ 453b0281cefSPeter Wemm 454b0281cefSPeter Wemm #ifdef PT_SETREGS 455b0281cefSPeter Wemm case PT_SETREGS: 456b0281cefSPeter Wemm write = 1; 457b0281cefSPeter Wemm /* fallthrough */ 458b0281cefSPeter Wemm #endif /* PT_SETREGS */ 4594e68ceabSDavid Greenman #ifdef PT_GETREGS 4604e68ceabSDavid Greenman case PT_GETREGS: 461b0281cefSPeter Wemm /* write = 0 above */ 462b0281cefSPeter Wemm #endif /* PT_SETREGS */ 463b0281cefSPeter Wemm #if defined(PT_SETREGS) || defined(PT_GETREGS) 464b40ce416SJulian Elischer if (!procfs_validregs(td)) /* no P_SYSTEM procs please */ 465c5799337SDag-Erling Smørgrav return (EINVAL); 466b0281cefSPeter Wemm else { 467b0281cefSPeter Wemm iov.iov_base = uap->addr; 468b0281cefSPeter Wemm iov.iov_len = sizeof(struct reg); 469b0281cefSPeter Wemm uio.uio_iov = &iov; 470b0281cefSPeter Wemm uio.uio_iovcnt = 1; 471b0281cefSPeter Wemm uio.uio_offset = 0; 472b0281cefSPeter Wemm uio.uio_resid = sizeof(struct reg); 473b0281cefSPeter Wemm uio.uio_segflg = UIO_USERSPACE; 474b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 475b40ce416SJulian Elischer uio.uio_td = td; 476b0281cefSPeter Wemm return (procfs_doregs(curp, p, NULL, &uio)); 477b0281cefSPeter Wemm } 478b0281cefSPeter Wemm #endif /* defined(PT_SETREGS) || defined(PT_GETREGS) */ 479b0281cefSPeter Wemm 480b0281cefSPeter Wemm #ifdef PT_SETFPREGS 481b0281cefSPeter Wemm case PT_SETFPREGS: 482b0281cefSPeter Wemm write = 1; 483b0281cefSPeter Wemm /* fallthrough */ 484b0281cefSPeter Wemm #endif /* PT_SETFPREGS */ 485b0281cefSPeter Wemm #ifdef PT_GETFPREGS 486b0281cefSPeter Wemm case PT_GETFPREGS: 487b0281cefSPeter Wemm /* write = 0 above */ 488b0281cefSPeter Wemm #endif /* PT_SETFPREGS */ 489b0281cefSPeter Wemm #if defined(PT_SETFPREGS) || defined(PT_GETFPREGS) 490b40ce416SJulian Elischer if (!procfs_validfpregs(td)) /* no P_SYSTEM procs please */ 491c5799337SDag-Erling Smørgrav return (EINVAL); 492b0281cefSPeter Wemm else { 493b0281cefSPeter Wemm iov.iov_base = uap->addr; 494b0281cefSPeter Wemm iov.iov_len = sizeof(struct fpreg); 495b0281cefSPeter Wemm uio.uio_iov = &iov; 496b0281cefSPeter Wemm uio.uio_iovcnt = 1; 497b0281cefSPeter Wemm uio.uio_offset = 0; 498b0281cefSPeter Wemm uio.uio_resid = sizeof(struct fpreg); 499b0281cefSPeter Wemm uio.uio_segflg = UIO_USERSPACE; 500b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 501b40ce416SJulian Elischer uio.uio_td = td; 502b0281cefSPeter Wemm return (procfs_dofpregs(curp, p, NULL, &uio)); 503b0281cefSPeter Wemm } 504b0281cefSPeter Wemm #endif /* defined(PT_SETFPREGS) || defined(PT_GETFPREGS) */ 505b0281cefSPeter Wemm 506ab001a72SJonathan Lemon #ifdef PT_SETDBREGS 507ab001a72SJonathan Lemon case PT_SETDBREGS: 508ab001a72SJonathan Lemon write = 1; 509ab001a72SJonathan Lemon /* fallthrough */ 510ab001a72SJonathan Lemon #endif /* PT_SETDBREGS */ 511ab001a72SJonathan Lemon #ifdef PT_GETDBREGS 512ab001a72SJonathan Lemon case PT_GETDBREGS: 513ab001a72SJonathan Lemon /* write = 0 above */ 514ab001a72SJonathan Lemon #endif /* PT_SETDBREGS */ 515ab001a72SJonathan Lemon #if defined(PT_SETDBREGS) || defined(PT_GETDBREGS) 516b40ce416SJulian Elischer if (!procfs_validdbregs(td)) /* no P_SYSTEM procs please */ 517c5799337SDag-Erling Smørgrav return (EINVAL); 518ab001a72SJonathan Lemon else { 519ab001a72SJonathan Lemon iov.iov_base = uap->addr; 520ab001a72SJonathan Lemon iov.iov_len = sizeof(struct dbreg); 521ab001a72SJonathan Lemon uio.uio_iov = &iov; 522ab001a72SJonathan Lemon uio.uio_iovcnt = 1; 523ab001a72SJonathan Lemon uio.uio_offset = 0; 524ab001a72SJonathan Lemon uio.uio_resid = sizeof(struct dbreg); 525ab001a72SJonathan Lemon uio.uio_segflg = UIO_USERSPACE; 526ab001a72SJonathan Lemon uio.uio_rw = write ? UIO_WRITE : UIO_READ; 527b40ce416SJulian Elischer uio.uio_td = td; 528ab001a72SJonathan Lemon return (procfs_dodbregs(curp, p, NULL, &uio)); 529ab001a72SJonathan Lemon } 530ab001a72SJonathan Lemon #endif /* defined(PT_SETDBREGS) || defined(PT_GETDBREGS) */ 531ab001a72SJonathan Lemon 5324e68ceabSDavid Greenman default: 5334e68ceabSDavid Greenman break; 5344e68ceabSDavid Greenman } 5354e68ceabSDavid Greenman 536c5799337SDag-Erling Smørgrav return (0); 537df8bae1dSRodney W. Grimes } 538df8bae1dSRodney W. Grimes 53926f9a767SRodney W. Grimes int 5404e68ceabSDavid Greenman trace_req(p) 5414e68ceabSDavid Greenman struct proc *p; 542df8bae1dSRodney W. Grimes { 543c5799337SDag-Erling Smørgrav return (1); 544df8bae1dSRodney W. Grimes } 5452a024a2bSSean Eric Fagan 5462a024a2bSSean Eric Fagan /* 5472a024a2bSSean Eric Fagan * stopevent() 5482a024a2bSSean Eric Fagan * Stop a process because of a procfs event; 5492a024a2bSSean Eric Fagan * stay stopped until p->p_step is cleared 5502a024a2bSSean Eric Fagan * (cleared by PIOCCONT in procfs). 5513897ca7cSJohn Baldwin * 5523897ca7cSJohn Baldwin * Must be called with the proc struct mutex held. 5532a024a2bSSean Eric Fagan */ 5542a024a2bSSean Eric Fagan 5552a024a2bSSean Eric Fagan void 5563897ca7cSJohn Baldwin stopevent(p, event, val) 5573897ca7cSJohn Baldwin struct proc *p; 5583897ca7cSJohn Baldwin unsigned int event; 5593897ca7cSJohn Baldwin unsigned int val; 5603897ca7cSJohn Baldwin { 5613897ca7cSJohn Baldwin 562731a1aeaSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED | MA_NOTRECURSED); 5632a024a2bSSean Eric Fagan p->p_step = 1; 5642a024a2bSSean Eric Fagan 5652a024a2bSSean Eric Fagan do { 5662a024a2bSSean Eric Fagan p->p_xstat = val; 5672a024a2bSSean Eric Fagan p->p_stype = event; /* Which event caused the stop? */ 5682a024a2bSSean Eric Fagan wakeup(&p->p_stype); /* Wake up any PIOCWAIT'ing procs */ 5693897ca7cSJohn Baldwin msleep(&p->p_step, &p->p_mtx, PWAIT, "stopevent", 0); 5702a024a2bSSean Eric Fagan } while (p->p_step); 5712a024a2bSSean Eric Fagan } 572