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> 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> 401005a129SJohn Baldwin #include <sys/sx.h> 41df8bae1dSRodney W. Grimes 424e68ceabSDavid Greenman #include <machine/reg.h> 434e68ceabSDavid Greenman #include <vm/vm.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> 484e68ceabSDavid Greenman 49f540b106SGarrett Wollman #include <sys/user.h> 50b0281cefSPeter Wemm #include <miscfs/procfs/procfs.h> 514e68ceabSDavid Greenman 52b0281cefSPeter Wemm /* use the equivalent procfs code */ 53b0281cefSPeter Wemm #if 0 54c4cf09ffSDavid Greenman static int 554e68ceabSDavid Greenman pread (struct proc *procp, unsigned int addr, unsigned int *retval) { 564e68ceabSDavid Greenman int rv; 574e68ceabSDavid Greenman vm_map_t map, tmap; 584e68ceabSDavid Greenman vm_object_t object; 594e68ceabSDavid Greenman vm_offset_t kva = 0; 604e68ceabSDavid Greenman int page_offset; /* offset into page */ 614e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 624e68ceabSDavid Greenman vm_map_entry_t out_entry; 634e68ceabSDavid Greenman vm_prot_t out_prot; 642d8acc0fSJohn Dyson boolean_t wired; 6563c8f421SBruce Evans vm_pindex_t pindex; 664e68ceabSDavid Greenman 674e68ceabSDavid Greenman /* Map page into kernel space */ 684e68ceabSDavid Greenman 694e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 704e68ceabSDavid Greenman 714e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 724e68ceabSDavid Greenman pageno = trunc_page(addr); 734e68ceabSDavid Greenman 744e68ceabSDavid Greenman tmap = map; 754e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_READ, &out_entry, 762d8acc0fSJohn Dyson &object, &pindex, &out_prot, &wired); 774e68ceabSDavid Greenman 784e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 794e68ceabSDavid Greenman return EINVAL; 804e68ceabSDavid Greenman 814e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 824e68ceabSDavid Greenman 834e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 84bd7e5f99SJohn Dyson rv = vm_map_find (kernel_map, object, IDX_TO_OFF(pindex), 85bd7e5f99SJohn Dyson &kva, PAGE_SIZE, 0, VM_PROT_ALL, VM_PROT_ALL, 0); 864e68ceabSDavid Greenman 874e68ceabSDavid Greenman if (!rv) { 884e68ceabSDavid Greenman vm_object_reference (object); 894e68ceabSDavid Greenman 904e68ceabSDavid Greenman rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 914e68ceabSDavid Greenman if (!rv) { 924e68ceabSDavid Greenman *retval = 0; 93f23b4c91SGarrett Wollman bcopy ((caddr_t)kva + page_offset, 94f23b4c91SGarrett Wollman retval, sizeof *retval); 954e68ceabSDavid Greenman } 964e68ceabSDavid Greenman vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 974e68ceabSDavid Greenman } 984e68ceabSDavid Greenman 994e68ceabSDavid Greenman return rv; 1004e68ceabSDavid Greenman } 1014e68ceabSDavid Greenman 102c4cf09ffSDavid Greenman static int 1034e68ceabSDavid Greenman pwrite (struct proc *procp, unsigned int addr, unsigned int datum) { 1044e68ceabSDavid Greenman int rv; 1054e68ceabSDavid Greenman vm_map_t map, tmap; 1064e68ceabSDavid Greenman vm_object_t object; 1074e68ceabSDavid Greenman vm_offset_t kva = 0; 1084e68ceabSDavid Greenman int page_offset; /* offset into page */ 1094e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 1104e68ceabSDavid Greenman vm_map_entry_t out_entry; 1114e68ceabSDavid Greenman vm_prot_t out_prot; 1122d8acc0fSJohn Dyson boolean_t wired; 11363c8f421SBruce Evans vm_pindex_t pindex; 1144e68ceabSDavid Greenman boolean_t fix_prot = 0; 1154e68ceabSDavid Greenman 1164e68ceabSDavid Greenman /* Map page into kernel space */ 1174e68ceabSDavid Greenman 1184e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 1194e68ceabSDavid Greenman 1204e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 1214e68ceabSDavid Greenman pageno = trunc_page(addr); 1224e68ceabSDavid Greenman 1234e68ceabSDavid Greenman /* 1244e68ceabSDavid Greenman * Check the permissions for the area we're interested in. 1254e68ceabSDavid Greenman */ 1264e68ceabSDavid Greenman 1274e68ceabSDavid Greenman if (vm_map_check_protection (map, pageno, pageno + PAGE_SIZE, 1284e68ceabSDavid Greenman VM_PROT_WRITE) == FALSE) { 1294e68ceabSDavid Greenman /* 1304e68ceabSDavid Greenman * If the page was not writable, we make it so. 1314e68ceabSDavid Greenman * XXX It is possible a page may *not* be read/executable, 1324e68ceabSDavid Greenman * if a process changes that! 1334e68ceabSDavid Greenman */ 1344e68ceabSDavid Greenman fix_prot = 1; 1354e68ceabSDavid Greenman /* The page isn't writable, so let's try making it so... */ 1364e68ceabSDavid Greenman if ((rv = vm_map_protect (map, pageno, pageno + PAGE_SIZE, 1374e68ceabSDavid Greenman VM_PROT_ALL, 0)) != KERN_SUCCESS) 1384e68ceabSDavid Greenman return EFAULT; /* I guess... */ 1394e68ceabSDavid Greenman } 1404e68ceabSDavid Greenman 1414e68ceabSDavid Greenman /* 1424e68ceabSDavid Greenman * Now we need to get the page. out_entry, out_prot, wired, and 1434e68ceabSDavid Greenman * single_use aren't used. One would think the vm code would be 1444e68ceabSDavid Greenman * a *bit* nicer... We use tmap because vm_map_lookup() can 1454e68ceabSDavid Greenman * change the map argument. 1464e68ceabSDavid Greenman */ 1474e68ceabSDavid Greenman 1484e68ceabSDavid Greenman tmap = map; 1494e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_WRITE, &out_entry, 1502d8acc0fSJohn Dyson &object, &pindex, &out_prot, &wired); 1514e68ceabSDavid Greenman if (rv != KERN_SUCCESS) { 1524e68ceabSDavid Greenman return EINVAL; 1534e68ceabSDavid Greenman } 1544e68ceabSDavid Greenman 1554e68ceabSDavid Greenman /* 1564e68ceabSDavid Greenman * Okay, we've got the page. Let's release tmap. 1574e68ceabSDavid Greenman */ 1584e68ceabSDavid Greenman 1594e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 1604e68ceabSDavid Greenman 1614e68ceabSDavid Greenman /* 1624e68ceabSDavid Greenman * Fault the page in... 1634e68ceabSDavid Greenman */ 1644e68ceabSDavid Greenman 165914a63ebSDavid Greenman rv = vm_fault(map, pageno, VM_PROT_WRITE|VM_PROT_READ, FALSE); 1664e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 1674e68ceabSDavid Greenman return EFAULT; 1684e68ceabSDavid Greenman 1694e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 170bd7e5f99SJohn Dyson rv = vm_map_find (kernel_map, object, IDX_TO_OFF(pindex), 171bd7e5f99SJohn Dyson &kva, PAGE_SIZE, 0, 172bd7e5f99SJohn Dyson VM_PROT_ALL, VM_PROT_ALL, 0); 1734e68ceabSDavid Greenman if (!rv) { 1744e68ceabSDavid Greenman vm_object_reference (object); 1754e68ceabSDavid Greenman 1764e68ceabSDavid Greenman rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 1774e68ceabSDavid Greenman if (!rv) { 178f23b4c91SGarrett Wollman bcopy (&datum, (caddr_t)kva + page_offset, sizeof datum); 1794e68ceabSDavid Greenman } 1804e68ceabSDavid Greenman vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 1814e68ceabSDavid Greenman } 1824e68ceabSDavid Greenman 1834e68ceabSDavid Greenman if (fix_prot) 1844e68ceabSDavid Greenman vm_map_protect (map, pageno, pageno + PAGE_SIZE, 1854e68ceabSDavid Greenman VM_PROT_READ|VM_PROT_EXECUTE, 0); 1864e68ceabSDavid Greenman return rv; 1874e68ceabSDavid Greenman } 188b0281cefSPeter Wemm #endif 1894e68ceabSDavid Greenman 190df8bae1dSRodney W. Grimes /* 191df8bae1dSRodney W. Grimes * Process debugging system call. 192df8bae1dSRodney W. Grimes */ 193d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 194df8bae1dSRodney W. Grimes struct ptrace_args { 195df8bae1dSRodney W. Grimes int req; 196df8bae1dSRodney W. Grimes pid_t pid; 197df8bae1dSRodney W. Grimes caddr_t addr; 198df8bae1dSRodney W. Grimes int data; 199df8bae1dSRodney W. Grimes }; 200d2d3e875SBruce Evans #endif 201df8bae1dSRodney W. Grimes 2024e68ceabSDavid Greenman int 203cb226aaaSPoul-Henning Kamp ptrace(curp, uap) 2044e68ceabSDavid Greenman struct proc *curp; 2054e68ceabSDavid Greenman struct ptrace_args *uap; 2064e68ceabSDavid Greenman { 2074e68ceabSDavid Greenman struct proc *p; 208b0281cefSPeter Wemm struct iovec iov; 209b0281cefSPeter Wemm struct uio uio; 210bb56ec4aSPoul-Henning Kamp int error = 0; 211b0281cefSPeter Wemm int write; 2124e68ceabSDavid Greenman 2137a0dde68SPeter Wemm write = 0; 21433a9ed9dSJohn Baldwin if (uap->req == PT_TRACE_ME) { 215b0281cefSPeter Wemm p = curp; 21633a9ed9dSJohn Baldwin PROC_LOCK(p); 21733a9ed9dSJohn Baldwin } else { 218b0281cefSPeter Wemm if ((p = pfind(uap->pid)) == NULL) 2194e68ceabSDavid Greenman return ESRCH; 2204e68ceabSDavid Greenman } 22133a9ed9dSJohn Baldwin if (p_can(curp, p, P_CAN_SEE, NULL)) { 22233a9ed9dSJohn Baldwin PROC_UNLOCK(p); 22375c13541SPoul-Henning Kamp return (ESRCH); 22433a9ed9dSJohn Baldwin } 2254e68ceabSDavid Greenman 226b0281cefSPeter Wemm /* 227b0281cefSPeter Wemm * Permissions check 228b0281cefSPeter Wemm */ 229b0281cefSPeter Wemm switch (uap->req) { 230b0281cefSPeter Wemm case PT_TRACE_ME: 231b0281cefSPeter Wemm /* Always legal. */ 232b0281cefSPeter Wemm break; 2334e68ceabSDavid Greenman 234b0281cefSPeter Wemm case PT_ATTACH: 235b0281cefSPeter Wemm /* Self */ 23633a9ed9dSJohn Baldwin if (p->p_pid == curp->p_pid) { 23733a9ed9dSJohn Baldwin PROC_UNLOCK(p); 238b0281cefSPeter Wemm return EINVAL; 23933a9ed9dSJohn Baldwin } 240b0281cefSPeter Wemm 241b0281cefSPeter Wemm /* Already traced */ 242731a1aeaSJohn Baldwin if (p->p_flag & P_TRACED) { 243731a1aeaSJohn Baldwin PROC_UNLOCK(p); 244b0281cefSPeter Wemm return EBUSY; 245731a1aeaSJohn Baldwin } 246b0281cefSPeter Wemm 24733a9ed9dSJohn Baldwin if ((error = p_can(curp, p, P_CAN_DEBUG, NULL))) { 24833a9ed9dSJohn Baldwin PROC_UNLOCK(p); 249b0281cefSPeter Wemm return error; 25033a9ed9dSJohn Baldwin } 251ee7877dfSAlexander Langer 252b0281cefSPeter Wemm /* OK */ 253b0281cefSPeter Wemm break; 254b0281cefSPeter Wemm 255b0281cefSPeter Wemm case PT_READ_I: 256b0281cefSPeter Wemm case PT_READ_D: 257b0281cefSPeter Wemm case PT_READ_U: 258b0281cefSPeter Wemm case PT_WRITE_I: 259b0281cefSPeter Wemm case PT_WRITE_D: 260b0281cefSPeter Wemm case PT_WRITE_U: 261b0281cefSPeter Wemm case PT_CONTINUE: 262b0281cefSPeter Wemm case PT_KILL: 263b0281cefSPeter Wemm case PT_STEP: 264b0281cefSPeter Wemm case PT_DETACH: 265b0281cefSPeter Wemm #ifdef PT_GETREGS 266b0281cefSPeter Wemm case PT_GETREGS: 2674e68ceabSDavid Greenman #endif 268b0281cefSPeter Wemm #ifdef PT_SETREGS 269b0281cefSPeter Wemm case PT_SETREGS: 2704e68ceabSDavid Greenman #endif 271b0281cefSPeter Wemm #ifdef PT_GETFPREGS 272b0281cefSPeter Wemm case PT_GETFPREGS: 273b0281cefSPeter Wemm #endif 274b0281cefSPeter Wemm #ifdef PT_SETFPREGS 275b0281cefSPeter Wemm case PT_SETFPREGS: 276b0281cefSPeter Wemm #endif 277ab001a72SJonathan Lemon #ifdef PT_GETDBREGS 278ab001a72SJonathan Lemon case PT_GETDBREGS: 279ab001a72SJonathan Lemon #endif 280ab001a72SJonathan Lemon #ifdef PT_SETDBREGS 281ab001a72SJonathan Lemon case PT_SETDBREGS: 282ab001a72SJonathan Lemon #endif 283b0281cefSPeter Wemm /* not being traced... */ 284731a1aeaSJohn Baldwin if ((p->p_flag & P_TRACED) == 0) { 285731a1aeaSJohn Baldwin PROC_UNLOCK(p); 2864e68ceabSDavid Greenman return EPERM; 287731a1aeaSJohn Baldwin } 288b0281cefSPeter Wemm 289b0281cefSPeter Wemm /* not being traced by YOU */ 29098f03f90SJake Burkholder if (p->p_pptr != curp) { 291731a1aeaSJohn Baldwin PROC_UNLOCK(p); 292b0281cefSPeter Wemm return EBUSY; 29398f03f90SJake Burkholder } 294b0281cefSPeter Wemm 295b0281cefSPeter Wemm /* not currently stopped */ 2969ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 2970ebabc93SJohn Baldwin if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) { 2989ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 299731a1aeaSJohn Baldwin PROC_UNLOCK(p); 3004e68ceabSDavid Greenman return EBUSY; 3010ebabc93SJohn Baldwin } 3029ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 303b0281cefSPeter Wemm 304b0281cefSPeter Wemm /* OK */ 305b0281cefSPeter Wemm break; 306b0281cefSPeter Wemm 307b0281cefSPeter Wemm default: 30833a9ed9dSJohn Baldwin PROC_UNLOCK(p); 309b0281cefSPeter Wemm return EINVAL; 3104e68ceabSDavid Greenman } 311b0281cefSPeter Wemm 31233a9ed9dSJohn Baldwin PROC_UNLOCK(p); 313b0281cefSPeter Wemm #ifdef FIX_SSTEP 314df8bae1dSRodney W. Grimes /* 315b0281cefSPeter Wemm * Single step fixup ala procfs 316b0281cefSPeter Wemm */ 317b0281cefSPeter Wemm FIX_SSTEP(p); 318b0281cefSPeter Wemm #endif 319b0281cefSPeter Wemm 320b0281cefSPeter Wemm /* 321b0281cefSPeter Wemm * Actually do the requests 322df8bae1dSRodney W. Grimes */ 3234e68ceabSDavid Greenman 324d72ec665STor Egge curp->p_retval[0] = 0; 3254e68ceabSDavid Greenman 326b0281cefSPeter Wemm switch (uap->req) { 327b0281cefSPeter Wemm case PT_TRACE_ME: 328b0281cefSPeter Wemm /* set my trace flag and "owner" so it can read/write me */ 3291005a129SJohn Baldwin sx_xlock(&proctree_lock); 330731a1aeaSJohn Baldwin PROC_LOCK(p); 3314e68ceabSDavid Greenman p->p_flag |= P_TRACED; 332b0281cefSPeter Wemm p->p_oppid = p->p_pptr->p_pid; 333731a1aeaSJohn Baldwin PROC_UNLOCK(p); 3341005a129SJohn Baldwin sx_xunlock(&proctree_lock); 3354e68ceabSDavid Greenman return 0; 3364e68ceabSDavid Greenman 337b0281cefSPeter Wemm case PT_ATTACH: 338b0281cefSPeter Wemm /* security check done above */ 3391005a129SJohn Baldwin sx_xlock(&proctree_lock); 340731a1aeaSJohn Baldwin PROC_LOCK(p); 341731a1aeaSJohn Baldwin p->p_flag |= P_TRACED; 342b0281cefSPeter Wemm p->p_oppid = p->p_pptr->p_pid; 343b0281cefSPeter Wemm if (p->p_pptr != curp) 344b0281cefSPeter Wemm proc_reparent(p, curp); 345731a1aeaSJohn Baldwin PROC_UNLOCK(p); 3461005a129SJohn Baldwin sx_xunlock(&proctree_lock); 347b0281cefSPeter Wemm uap->data = SIGSTOP; 348b0281cefSPeter Wemm goto sendsig; /* in PT_CONTINUE below */ 349b0281cefSPeter Wemm 350b0281cefSPeter Wemm case PT_STEP: 351b0281cefSPeter Wemm case PT_CONTINUE: 3524e68ceabSDavid Greenman case PT_DETACH: 3532ec40c9aSJohn W. De Boskey if ((uap->req != PT_STEP) && ((unsigned)uap->data >= NSIG)) 3544e68ceabSDavid Greenman return EINVAL; 355b0281cefSPeter Wemm 356b0281cefSPeter Wemm PHOLD(p); 357b0281cefSPeter Wemm 358b0281cefSPeter Wemm if (uap->req == PT_STEP) { 359b0281cefSPeter Wemm if ((error = ptrace_single_step (p))) { 360b0281cefSPeter Wemm PRELE(p); 361b0281cefSPeter Wemm return error; 362b0281cefSPeter Wemm } 363b0281cefSPeter Wemm } 364b0281cefSPeter Wemm 365b0281cefSPeter Wemm if (uap->addr != (caddr_t)1) { 3661f7d2501SKirk McKusick fill_kinfo_proc (p, &p->p_addr->u_kproc); 3676a206dd9SBruce Evans if ((error = ptrace_set_pc (p, 3686a206dd9SBruce Evans (u_long)(uintfptr_t)uap->addr))) { 369b0281cefSPeter Wemm PRELE(p); 370b0281cefSPeter Wemm return error; 371b0281cefSPeter Wemm } 372b0281cefSPeter Wemm } 373b0281cefSPeter Wemm PRELE(p); 374b0281cefSPeter Wemm 375b0281cefSPeter Wemm if (uap->req == PT_DETACH) { 376b0281cefSPeter Wemm /* reset process parent */ 3771005a129SJohn Baldwin sx_xlock(&proctree_lock); 378b0281cefSPeter Wemm if (p->p_oppid != p->p_pptr->p_pid) { 379b0281cefSPeter Wemm struct proc *pp; 380b0281cefSPeter Wemm 381b0281cefSPeter Wemm pp = pfind(p->p_oppid); 382b0281cefSPeter Wemm proc_reparent(p, pp ? pp : initproc); 383731a1aeaSJohn Baldwin } else 384731a1aeaSJohn Baldwin PROC_LOCK(p); 385b0281cefSPeter Wemm p->p_flag &= ~(P_TRACED | P_WAITED); 386b0281cefSPeter Wemm p->p_oppid = 0; 387b0281cefSPeter Wemm 388731a1aeaSJohn Baldwin PROC_UNLOCK(p); 3891005a129SJohn Baldwin sx_xunlock(&proctree_lock); 390731a1aeaSJohn Baldwin 391b0281cefSPeter Wemm /* should we send SIGCHLD? */ 392b0281cefSPeter Wemm 393b0281cefSPeter Wemm } 394b0281cefSPeter Wemm 395b0281cefSPeter Wemm sendsig: 396b0281cefSPeter Wemm /* deliver or queue signal */ 397731a1aeaSJohn Baldwin PROC_LOCK(p); 3989ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 3994e68ceabSDavid Greenman if (p->p_stat == SSTOP) { 4004e68ceabSDavid Greenman p->p_xstat = uap->data; 4014e68ceabSDavid Greenman setrunnable(p); 4029ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 4030ebabc93SJohn Baldwin } else { 4049ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 405731a1aeaSJohn Baldwin if (uap->data) 4064e68ceabSDavid Greenman psignal(p, uap->data); 407731a1aeaSJohn Baldwin 4084e68ceabSDavid Greenman } 409731a1aeaSJohn Baldwin PROC_UNLOCK(p); 4104e68ceabSDavid Greenman return 0; 4114e68ceabSDavid Greenman 4124e68ceabSDavid Greenman case PT_WRITE_I: 4134e68ceabSDavid Greenman case PT_WRITE_D: 414b0281cefSPeter Wemm write = 1; 4154e68ceabSDavid Greenman /* fallthrough */ 416b0281cefSPeter Wemm case PT_READ_I: 417b0281cefSPeter Wemm case PT_READ_D: 418b0281cefSPeter Wemm /* write = 0 set above */ 419d72ec665STor Egge iov.iov_base = write ? (caddr_t)&uap->data : (caddr_t)curp->p_retval; 420b0281cefSPeter Wemm iov.iov_len = sizeof(int); 421b0281cefSPeter Wemm uio.uio_iov = &iov; 422b0281cefSPeter Wemm uio.uio_iovcnt = 1; 4236a206dd9SBruce Evans uio.uio_offset = (off_t)(uintptr_t)uap->addr; 424b0281cefSPeter Wemm uio.uio_resid = sizeof(int); 425b0281cefSPeter Wemm uio.uio_segflg = UIO_SYSSPACE; /* ie: the uap */ 426b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 427b0281cefSPeter Wemm uio.uio_procp = p; 4282eb80d36SPeter Wemm error = procfs_domem(curp, p, NULL, &uio); 4292eb80d36SPeter Wemm if (uio.uio_resid != 0) { 4302eb80d36SPeter Wemm /* 4312eb80d36SPeter Wemm * XXX procfs_domem() doesn't currently return ENOSPC, 4322eb80d36SPeter Wemm * so I think write() can bogusly return 0. 4332eb80d36SPeter Wemm * XXX what happens for short writes? We don't want 4342eb80d36SPeter Wemm * to write partial data. 4352eb80d36SPeter Wemm * XXX procfs_domem() returns EPERM for other invalid 4362eb80d36SPeter Wemm * addresses. Convert this to EINVAL. Does this 4372eb80d36SPeter Wemm * clobber returns of EPERM for other reasons? 4382eb80d36SPeter Wemm */ 4392eb80d36SPeter Wemm if (error == 0 || error == ENOSPC || error == EPERM) 4402eb80d36SPeter Wemm error = EINVAL; /* EOF */ 4412eb80d36SPeter Wemm } 4422eb80d36SPeter Wemm return (error); 4434e68ceabSDavid Greenman 4444e68ceabSDavid Greenman case PT_READ_U: 445dae63452SDoug Rabson if ((uintptr_t)uap->addr > UPAGES * PAGE_SIZE - sizeof(int)) { 446dae63452SDoug Rabson return EFAULT; 447dae63452SDoug Rabson } 448dae63452SDoug Rabson if ((uintptr_t)uap->addr & (sizeof(int) - 1)) { 4494e68ceabSDavid Greenman return EFAULT; 4504e68ceabSDavid Greenman } 451afc6ea23STor Egge if (ptrace_read_u_check(p,(vm_offset_t) uap->addr, 452a9e0361bSPoul-Henning Kamp sizeof(int))) { 453afc6ea23STor Egge return EFAULT; 454afc6ea23STor Egge } 455b0281cefSPeter Wemm error = 0; 456b0281cefSPeter Wemm PHOLD(p); /* user had damn well better be incore! */ 4579ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 4583897ca7cSJohn Baldwin if (p->p_sflag & PS_INMEM) { 4599ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 4601f7d2501SKirk McKusick fill_kinfo_proc (p, &p->p_addr->u_kproc); 4618a8a13c8SDoug Rabson curp->p_retval[0] = *(int *) 4626a206dd9SBruce Evans ((uintptr_t)p->p_addr + (uintptr_t)uap->addr); 463b0281cefSPeter Wemm } else { 4649ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 465d72ec665STor Egge curp->p_retval[0] = 0; 466b0281cefSPeter Wemm error = EFAULT; 467b0281cefSPeter Wemm } 468b0281cefSPeter Wemm PRELE(p); 469b0281cefSPeter Wemm return error; 470b0281cefSPeter Wemm 4714e68ceabSDavid Greenman case PT_WRITE_U: 472b0281cefSPeter Wemm PHOLD(p); /* user had damn well better be incore! */ 4739ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 4743897ca7cSJohn Baldwin if (p->p_sflag & PS_INMEM) { 4759ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 4761f7d2501SKirk McKusick fill_kinfo_proc (p, &p->p_addr->u_kproc); 477b0281cefSPeter Wemm error = ptrace_write_u(p, (vm_offset_t)uap->addr, uap->data); 478b0281cefSPeter Wemm } else { 4799ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 480b0281cefSPeter Wemm error = EFAULT; 481b0281cefSPeter Wemm } 482b0281cefSPeter Wemm PRELE(p); 483b0281cefSPeter Wemm return error; 484b0281cefSPeter Wemm 4854e68ceabSDavid Greenman case PT_KILL: 486b0281cefSPeter Wemm uap->data = SIGKILL; 487b0281cefSPeter Wemm goto sendsig; /* in PT_CONTINUE above */ 488b0281cefSPeter Wemm 489b0281cefSPeter Wemm #ifdef PT_SETREGS 490b0281cefSPeter Wemm case PT_SETREGS: 491b0281cefSPeter Wemm write = 1; 492b0281cefSPeter Wemm /* fallthrough */ 493b0281cefSPeter Wemm #endif /* PT_SETREGS */ 4944e68ceabSDavid Greenman #ifdef PT_GETREGS 4954e68ceabSDavid Greenman case PT_GETREGS: 496b0281cefSPeter Wemm /* write = 0 above */ 497b0281cefSPeter Wemm #endif /* PT_SETREGS */ 498b0281cefSPeter Wemm #if defined(PT_SETREGS) || defined(PT_GETREGS) 499b0281cefSPeter Wemm if (!procfs_validregs(p)) /* no P_SYSTEM procs please */ 500b0281cefSPeter Wemm return EINVAL; 501b0281cefSPeter Wemm else { 502b0281cefSPeter Wemm iov.iov_base = uap->addr; 503b0281cefSPeter Wemm iov.iov_len = sizeof(struct reg); 504b0281cefSPeter Wemm uio.uio_iov = &iov; 505b0281cefSPeter Wemm uio.uio_iovcnt = 1; 506b0281cefSPeter Wemm uio.uio_offset = 0; 507b0281cefSPeter Wemm uio.uio_resid = sizeof(struct reg); 508b0281cefSPeter Wemm uio.uio_segflg = UIO_USERSPACE; 509b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 510b0281cefSPeter Wemm uio.uio_procp = curp; 511b0281cefSPeter Wemm return (procfs_doregs(curp, p, NULL, &uio)); 512b0281cefSPeter Wemm } 513b0281cefSPeter Wemm #endif /* defined(PT_SETREGS) || defined(PT_GETREGS) */ 514b0281cefSPeter Wemm 515b0281cefSPeter Wemm #ifdef PT_SETFPREGS 516b0281cefSPeter Wemm case PT_SETFPREGS: 517b0281cefSPeter Wemm write = 1; 518b0281cefSPeter Wemm /* fallthrough */ 519b0281cefSPeter Wemm #endif /* PT_SETFPREGS */ 520b0281cefSPeter Wemm #ifdef PT_GETFPREGS 521b0281cefSPeter Wemm case PT_GETFPREGS: 522b0281cefSPeter Wemm /* write = 0 above */ 523b0281cefSPeter Wemm #endif /* PT_SETFPREGS */ 524b0281cefSPeter Wemm #if defined(PT_SETFPREGS) || defined(PT_GETFPREGS) 525b0281cefSPeter Wemm if (!procfs_validfpregs(p)) /* no P_SYSTEM procs please */ 526b0281cefSPeter Wemm return EINVAL; 527b0281cefSPeter Wemm else { 528b0281cefSPeter Wemm iov.iov_base = uap->addr; 529b0281cefSPeter Wemm iov.iov_len = sizeof(struct fpreg); 530b0281cefSPeter Wemm uio.uio_iov = &iov; 531b0281cefSPeter Wemm uio.uio_iovcnt = 1; 532b0281cefSPeter Wemm uio.uio_offset = 0; 533b0281cefSPeter Wemm uio.uio_resid = sizeof(struct fpreg); 534b0281cefSPeter Wemm uio.uio_segflg = UIO_USERSPACE; 535b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 536b0281cefSPeter Wemm uio.uio_procp = curp; 537b0281cefSPeter Wemm return (procfs_dofpregs(curp, p, NULL, &uio)); 538b0281cefSPeter Wemm } 539b0281cefSPeter Wemm #endif /* defined(PT_SETFPREGS) || defined(PT_GETFPREGS) */ 540b0281cefSPeter Wemm 541ab001a72SJonathan Lemon #ifdef PT_SETDBREGS 542ab001a72SJonathan Lemon case PT_SETDBREGS: 543ab001a72SJonathan Lemon write = 1; 544ab001a72SJonathan Lemon /* fallthrough */ 545ab001a72SJonathan Lemon #endif /* PT_SETDBREGS */ 546ab001a72SJonathan Lemon #ifdef PT_GETDBREGS 547ab001a72SJonathan Lemon case PT_GETDBREGS: 548ab001a72SJonathan Lemon /* write = 0 above */ 549ab001a72SJonathan Lemon #endif /* PT_SETDBREGS */ 550ab001a72SJonathan Lemon #if defined(PT_SETDBREGS) || defined(PT_GETDBREGS) 551ab001a72SJonathan Lemon if (!procfs_validdbregs(p)) /* no P_SYSTEM procs please */ 552ab001a72SJonathan Lemon return EINVAL; 553ab001a72SJonathan Lemon else { 554ab001a72SJonathan Lemon iov.iov_base = uap->addr; 555ab001a72SJonathan Lemon iov.iov_len = sizeof(struct dbreg); 556ab001a72SJonathan Lemon uio.uio_iov = &iov; 557ab001a72SJonathan Lemon uio.uio_iovcnt = 1; 558ab001a72SJonathan Lemon uio.uio_offset = 0; 559ab001a72SJonathan Lemon uio.uio_resid = sizeof(struct dbreg); 560ab001a72SJonathan Lemon uio.uio_segflg = UIO_USERSPACE; 561ab001a72SJonathan Lemon uio.uio_rw = write ? UIO_WRITE : UIO_READ; 562ab001a72SJonathan Lemon uio.uio_procp = curp; 563ab001a72SJonathan Lemon return (procfs_dodbregs(curp, p, NULL, &uio)); 564ab001a72SJonathan Lemon } 565ab001a72SJonathan Lemon #endif /* defined(PT_SETDBREGS) || defined(PT_GETDBREGS) */ 566ab001a72SJonathan Lemon 5674e68ceabSDavid Greenman default: 5684e68ceabSDavid Greenman break; 5694e68ceabSDavid Greenman } 5704e68ceabSDavid Greenman 5714e68ceabSDavid Greenman return 0; 572df8bae1dSRodney W. Grimes } 573df8bae1dSRodney W. Grimes 57426f9a767SRodney W. Grimes int 5754e68ceabSDavid Greenman trace_req(p) 5764e68ceabSDavid Greenman struct proc *p; 577df8bae1dSRodney W. Grimes { 5784e68ceabSDavid Greenman return 1; 579df8bae1dSRodney W. Grimes } 5802a024a2bSSean Eric Fagan 5812a024a2bSSean Eric Fagan /* 5822a024a2bSSean Eric Fagan * stopevent() 5832a024a2bSSean Eric Fagan * Stop a process because of a procfs event; 5842a024a2bSSean Eric Fagan * stay stopped until p->p_step is cleared 5852a024a2bSSean Eric Fagan * (cleared by PIOCCONT in procfs). 5863897ca7cSJohn Baldwin * 5873897ca7cSJohn Baldwin * Must be called with the proc struct mutex held. 5882a024a2bSSean Eric Fagan */ 5892a024a2bSSean Eric Fagan 5902a024a2bSSean Eric Fagan void 5913897ca7cSJohn Baldwin stopevent(p, event, val) 5923897ca7cSJohn Baldwin struct proc *p; 5933897ca7cSJohn Baldwin unsigned int event; 5943897ca7cSJohn Baldwin unsigned int val; 5953897ca7cSJohn Baldwin { 5963897ca7cSJohn Baldwin 597731a1aeaSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED | MA_NOTRECURSED); 5982a024a2bSSean Eric Fagan p->p_step = 1; 5992a024a2bSSean Eric Fagan 6002a024a2bSSean Eric Fagan do { 6012a024a2bSSean Eric Fagan p->p_xstat = val; 6022a024a2bSSean Eric Fagan p->p_stype = event; /* Which event caused the stop? */ 6032a024a2bSSean Eric Fagan wakeup(&p->p_stype); /* Wake up any PIOCWAIT'ing procs */ 6043897ca7cSJohn Baldwin msleep(&p->p_step, &p->p_mtx, PWAIT, "stopevent", 0); 6052a024a2bSSean Eric Fagan } while (p->p_step); 6062a024a2bSSean Eric Fagan } 607