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> 40df8bae1dSRodney W. Grimes 414e68ceabSDavid Greenman #include <machine/reg.h> 424e68ceabSDavid Greenman #include <vm/vm.h> 43996c772fSJohn Dyson #include <sys/lock.h> 44efeaf95aSDavid Greenman #include <vm/pmap.h> 45efeaf95aSDavid Greenman #include <vm/vm_map.h> 464e68ceabSDavid Greenman #include <vm/vm_page.h> 474e68ceabSDavid Greenman 48f540b106SGarrett Wollman #include <sys/user.h> 49b0281cefSPeter Wemm #include <miscfs/procfs/procfs.h> 504e68ceabSDavid Greenman 51b0281cefSPeter Wemm /* use the equivalent procfs code */ 52b0281cefSPeter Wemm #if 0 53c4cf09ffSDavid Greenman static int 544e68ceabSDavid Greenman pread (struct proc *procp, unsigned int addr, unsigned int *retval) { 554e68ceabSDavid Greenman int rv; 564e68ceabSDavid Greenman vm_map_t map, tmap; 574e68ceabSDavid Greenman vm_object_t object; 584e68ceabSDavid Greenman vm_offset_t kva = 0; 594e68ceabSDavid Greenman int page_offset; /* offset into page */ 604e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 614e68ceabSDavid Greenman vm_map_entry_t out_entry; 624e68ceabSDavid Greenman vm_prot_t out_prot; 632d8acc0fSJohn Dyson boolean_t wired; 6463c8f421SBruce Evans vm_pindex_t pindex; 654e68ceabSDavid Greenman 664e68ceabSDavid Greenman /* Map page into kernel space */ 674e68ceabSDavid Greenman 684e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 694e68ceabSDavid Greenman 704e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 714e68ceabSDavid Greenman pageno = trunc_page(addr); 724e68ceabSDavid Greenman 734e68ceabSDavid Greenman tmap = map; 744e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_READ, &out_entry, 752d8acc0fSJohn Dyson &object, &pindex, &out_prot, &wired); 764e68ceabSDavid Greenman 774e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 784e68ceabSDavid Greenman return EINVAL; 794e68ceabSDavid Greenman 804e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 814e68ceabSDavid Greenman 824e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 83bd7e5f99SJohn Dyson rv = vm_map_find (kernel_map, object, IDX_TO_OFF(pindex), 84bd7e5f99SJohn Dyson &kva, PAGE_SIZE, 0, VM_PROT_ALL, VM_PROT_ALL, 0); 854e68ceabSDavid Greenman 864e68ceabSDavid Greenman if (!rv) { 874e68ceabSDavid Greenman vm_object_reference (object); 884e68ceabSDavid Greenman 894e68ceabSDavid Greenman rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); 904e68ceabSDavid Greenman if (!rv) { 914e68ceabSDavid Greenman *retval = 0; 92f23b4c91SGarrett Wollman bcopy ((caddr_t)kva + page_offset, 93f23b4c91SGarrett Wollman retval, sizeof *retval); 944e68ceabSDavid Greenman } 954e68ceabSDavid Greenman vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); 964e68ceabSDavid Greenman } 974e68ceabSDavid Greenman 984e68ceabSDavid Greenman return rv; 994e68ceabSDavid Greenman } 1004e68ceabSDavid Greenman 101c4cf09ffSDavid Greenman static int 1024e68ceabSDavid Greenman pwrite (struct proc *procp, unsigned int addr, unsigned int datum) { 1034e68ceabSDavid Greenman int rv; 1044e68ceabSDavid Greenman vm_map_t map, tmap; 1054e68ceabSDavid Greenman vm_object_t object; 1064e68ceabSDavid Greenman vm_offset_t kva = 0; 1074e68ceabSDavid Greenman int page_offset; /* offset into page */ 1084e68ceabSDavid Greenman vm_offset_t pageno; /* page number */ 1094e68ceabSDavid Greenman vm_map_entry_t out_entry; 1104e68ceabSDavid Greenman vm_prot_t out_prot; 1112d8acc0fSJohn Dyson boolean_t wired; 11263c8f421SBruce Evans vm_pindex_t pindex; 1134e68ceabSDavid Greenman boolean_t fix_prot = 0; 1144e68ceabSDavid Greenman 1154e68ceabSDavid Greenman /* Map page into kernel space */ 1164e68ceabSDavid Greenman 1174e68ceabSDavid Greenman map = &procp->p_vmspace->vm_map; 1184e68ceabSDavid Greenman 1194e68ceabSDavid Greenman page_offset = addr - trunc_page(addr); 1204e68ceabSDavid Greenman pageno = trunc_page(addr); 1214e68ceabSDavid Greenman 1224e68ceabSDavid Greenman /* 1234e68ceabSDavid Greenman * Check the permissions for the area we're interested in. 1244e68ceabSDavid Greenman */ 1254e68ceabSDavid Greenman 1264e68ceabSDavid Greenman if (vm_map_check_protection (map, pageno, pageno + PAGE_SIZE, 1274e68ceabSDavid Greenman VM_PROT_WRITE) == FALSE) { 1284e68ceabSDavid Greenman /* 1294e68ceabSDavid Greenman * If the page was not writable, we make it so. 1304e68ceabSDavid Greenman * XXX It is possible a page may *not* be read/executable, 1314e68ceabSDavid Greenman * if a process changes that! 1324e68ceabSDavid Greenman */ 1334e68ceabSDavid Greenman fix_prot = 1; 1344e68ceabSDavid Greenman /* The page isn't writable, so let's try making it so... */ 1354e68ceabSDavid Greenman if ((rv = vm_map_protect (map, pageno, pageno + PAGE_SIZE, 1364e68ceabSDavid Greenman VM_PROT_ALL, 0)) != KERN_SUCCESS) 1374e68ceabSDavid Greenman return EFAULT; /* I guess... */ 1384e68ceabSDavid Greenman } 1394e68ceabSDavid Greenman 1404e68ceabSDavid Greenman /* 1414e68ceabSDavid Greenman * Now we need to get the page. out_entry, out_prot, wired, and 1424e68ceabSDavid Greenman * single_use aren't used. One would think the vm code would be 1434e68ceabSDavid Greenman * a *bit* nicer... We use tmap because vm_map_lookup() can 1444e68ceabSDavid Greenman * change the map argument. 1454e68ceabSDavid Greenman */ 1464e68ceabSDavid Greenman 1474e68ceabSDavid Greenman tmap = map; 1484e68ceabSDavid Greenman rv = vm_map_lookup (&tmap, pageno, VM_PROT_WRITE, &out_entry, 1492d8acc0fSJohn Dyson &object, &pindex, &out_prot, &wired); 1504e68ceabSDavid Greenman if (rv != KERN_SUCCESS) { 1514e68ceabSDavid Greenman return EINVAL; 1524e68ceabSDavid Greenman } 1534e68ceabSDavid Greenman 1544e68ceabSDavid Greenman /* 1554e68ceabSDavid Greenman * Okay, we've got the page. Let's release tmap. 1564e68ceabSDavid Greenman */ 1574e68ceabSDavid Greenman 1584e68ceabSDavid Greenman vm_map_lookup_done (tmap, out_entry); 1594e68ceabSDavid Greenman 1604e68ceabSDavid Greenman /* 1614e68ceabSDavid Greenman * Fault the page in... 1624e68ceabSDavid Greenman */ 1634e68ceabSDavid Greenman 164914a63ebSDavid Greenman rv = vm_fault(map, pageno, VM_PROT_WRITE|VM_PROT_READ, FALSE); 1654e68ceabSDavid Greenman if (rv != KERN_SUCCESS) 1664e68ceabSDavid Greenman return EFAULT; 1674e68ceabSDavid Greenman 1684e68ceabSDavid Greenman /* Find space in kernel_map for the page we're interested in */ 169bd7e5f99SJohn Dyson rv = vm_map_find (kernel_map, object, IDX_TO_OFF(pindex), 170bd7e5f99SJohn Dyson &kva, PAGE_SIZE, 0, 171bd7e5f99SJohn Dyson VM_PROT_ALL, VM_PROT_ALL, 0); 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) { 177f23b4c91SGarrett Wollman bcopy (&datum, (caddr_t)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 } 187b0281cefSPeter Wemm #endif 1884e68ceabSDavid Greenman 189df8bae1dSRodney W. Grimes /* 190df8bae1dSRodney W. Grimes * Process debugging system call. 191df8bae1dSRodney W. Grimes */ 192d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 193df8bae1dSRodney W. Grimes struct ptrace_args { 194df8bae1dSRodney W. Grimes int req; 195df8bae1dSRodney W. Grimes pid_t pid; 196df8bae1dSRodney W. Grimes caddr_t addr; 197df8bae1dSRodney W. Grimes int data; 198df8bae1dSRodney W. Grimes }; 199d2d3e875SBruce Evans #endif 200df8bae1dSRodney W. Grimes 2014e68ceabSDavid Greenman int 202cb226aaaSPoul-Henning Kamp ptrace(curp, uap) 2034e68ceabSDavid Greenman struct proc *curp; 2044e68ceabSDavid Greenman struct ptrace_args *uap; 2054e68ceabSDavid Greenman { 2064e68ceabSDavid Greenman struct proc *p; 207b0281cefSPeter Wemm struct iovec iov; 208b0281cefSPeter Wemm struct uio uio; 209bb56ec4aSPoul-Henning Kamp int error = 0; 210b0281cefSPeter Wemm int write; 2114e68ceabSDavid Greenman 2127a0dde68SPeter Wemm write = 0; 213b0281cefSPeter Wemm if (uap->req == PT_TRACE_ME) 214b0281cefSPeter Wemm p = curp; 215b0281cefSPeter Wemm else { 216b0281cefSPeter Wemm if ((p = pfind(uap->pid)) == NULL) 2174e68ceabSDavid Greenman return ESRCH; 2184e68ceabSDavid Greenman } 219387d2c03SRobert Watson if (p_can(curp, p, P_CAN_SEE, NULL)) 22075c13541SPoul-Henning Kamp return (ESRCH); 2214e68ceabSDavid Greenman 222b0281cefSPeter Wemm /* 223b0281cefSPeter Wemm * Permissions check 224b0281cefSPeter Wemm */ 225b0281cefSPeter Wemm switch (uap->req) { 226b0281cefSPeter Wemm case PT_TRACE_ME: 227b0281cefSPeter Wemm /* Always legal. */ 228b0281cefSPeter Wemm break; 2294e68ceabSDavid Greenman 230b0281cefSPeter Wemm case PT_ATTACH: 231b0281cefSPeter Wemm /* Self */ 232b0281cefSPeter Wemm if (p->p_pid == curp->p_pid) 233b0281cefSPeter Wemm return EINVAL; 234b0281cefSPeter Wemm 235b0281cefSPeter Wemm /* Already traced */ 236731a1aeaSJohn Baldwin PROC_LOCK(p); 237731a1aeaSJohn Baldwin if (p->p_flag & P_TRACED) { 238731a1aeaSJohn Baldwin PROC_UNLOCK(p); 239b0281cefSPeter Wemm return EBUSY; 240731a1aeaSJohn Baldwin } 241731a1aeaSJohn Baldwin PROC_UNLOCK(p); 242b0281cefSPeter Wemm 243387d2c03SRobert Watson if ((error = p_can(curp, p, P_CAN_DEBUG, NULL))) 244b0281cefSPeter Wemm return error; 245ee7877dfSAlexander Langer 246b0281cefSPeter Wemm /* OK */ 247b0281cefSPeter Wemm break; 248b0281cefSPeter Wemm 249b0281cefSPeter Wemm case PT_READ_I: 250b0281cefSPeter Wemm case PT_READ_D: 251b0281cefSPeter Wemm case PT_READ_U: 252b0281cefSPeter Wemm case PT_WRITE_I: 253b0281cefSPeter Wemm case PT_WRITE_D: 254b0281cefSPeter Wemm case PT_WRITE_U: 255b0281cefSPeter Wemm case PT_CONTINUE: 256b0281cefSPeter Wemm case PT_KILL: 257b0281cefSPeter Wemm case PT_STEP: 258b0281cefSPeter Wemm case PT_DETACH: 259b0281cefSPeter Wemm #ifdef PT_GETREGS 260b0281cefSPeter Wemm case PT_GETREGS: 2614e68ceabSDavid Greenman #endif 262b0281cefSPeter Wemm #ifdef PT_SETREGS 263b0281cefSPeter Wemm case PT_SETREGS: 2644e68ceabSDavid Greenman #endif 265b0281cefSPeter Wemm #ifdef PT_GETFPREGS 266b0281cefSPeter Wemm case PT_GETFPREGS: 267b0281cefSPeter Wemm #endif 268b0281cefSPeter Wemm #ifdef PT_SETFPREGS 269b0281cefSPeter Wemm case PT_SETFPREGS: 270b0281cefSPeter Wemm #endif 271ab001a72SJonathan Lemon #ifdef PT_GETDBREGS 272ab001a72SJonathan Lemon case PT_GETDBREGS: 273ab001a72SJonathan Lemon #endif 274ab001a72SJonathan Lemon #ifdef PT_SETDBREGS 275ab001a72SJonathan Lemon case PT_SETDBREGS: 276ab001a72SJonathan Lemon #endif 277b0281cefSPeter Wemm /* not being traced... */ 278731a1aeaSJohn Baldwin PROC_LOCK(p); 279731a1aeaSJohn Baldwin if ((p->p_flag & P_TRACED) == 0) { 280731a1aeaSJohn Baldwin PROC_UNLOCK(p); 2814e68ceabSDavid Greenman return EPERM; 282731a1aeaSJohn Baldwin } 283b0281cefSPeter Wemm 284b0281cefSPeter Wemm /* not being traced by YOU */ 28598f03f90SJake Burkholder if (p->p_pptr != curp) { 286731a1aeaSJohn Baldwin PROC_UNLOCK(p); 287b0281cefSPeter Wemm return EBUSY; 28898f03f90SJake Burkholder } 289b0281cefSPeter Wemm 290b0281cefSPeter Wemm /* not currently stopped */ 2919ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 2920ebabc93SJohn Baldwin if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) { 2939ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 294731a1aeaSJohn Baldwin PROC_UNLOCK(p); 2954e68ceabSDavid Greenman return EBUSY; 2960ebabc93SJohn Baldwin } 2979ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 298731a1aeaSJohn Baldwin PROC_UNLOCK(p); 299b0281cefSPeter Wemm 300b0281cefSPeter Wemm /* OK */ 301b0281cefSPeter Wemm break; 302b0281cefSPeter Wemm 303b0281cefSPeter Wemm default: 304b0281cefSPeter Wemm return EINVAL; 3054e68ceabSDavid Greenman } 306b0281cefSPeter Wemm 307b0281cefSPeter Wemm #ifdef FIX_SSTEP 308df8bae1dSRodney W. Grimes /* 309b0281cefSPeter Wemm * Single step fixup ala procfs 310b0281cefSPeter Wemm */ 311b0281cefSPeter Wemm FIX_SSTEP(p); 312b0281cefSPeter Wemm #endif 313b0281cefSPeter Wemm 314b0281cefSPeter Wemm /* 315b0281cefSPeter Wemm * Actually do the requests 316df8bae1dSRodney W. Grimes */ 3174e68ceabSDavid Greenman 318d72ec665STor Egge curp->p_retval[0] = 0; 3194e68ceabSDavid Greenman 320b0281cefSPeter Wemm switch (uap->req) { 321b0281cefSPeter Wemm case PT_TRACE_ME: 322b0281cefSPeter Wemm /* set my trace flag and "owner" so it can read/write me */ 323731a1aeaSJohn Baldwin PROCTREE_LOCK(PT_EXCLUSIVE); 324731a1aeaSJohn Baldwin PROC_LOCK(p); 3254e68ceabSDavid Greenman p->p_flag |= P_TRACED; 326b0281cefSPeter Wemm p->p_oppid = p->p_pptr->p_pid; 327731a1aeaSJohn Baldwin PROC_UNLOCK(p); 32898f03f90SJake Burkholder PROCTREE_LOCK(PT_RELEASE); 3294e68ceabSDavid Greenman return 0; 3304e68ceabSDavid Greenman 331b0281cefSPeter Wemm case PT_ATTACH: 332b0281cefSPeter Wemm /* security check done above */ 33398f03f90SJake Burkholder PROCTREE_LOCK(PT_EXCLUSIVE); 334731a1aeaSJohn Baldwin PROC_LOCK(p); 335731a1aeaSJohn Baldwin p->p_flag |= P_TRACED; 336b0281cefSPeter Wemm p->p_oppid = p->p_pptr->p_pid; 337b0281cefSPeter Wemm if (p->p_pptr != curp) 338b0281cefSPeter Wemm proc_reparent(p, curp); 339731a1aeaSJohn Baldwin PROC_UNLOCK(p); 34098f03f90SJake Burkholder PROCTREE_LOCK(PT_RELEASE); 341b0281cefSPeter Wemm uap->data = SIGSTOP; 342b0281cefSPeter Wemm goto sendsig; /* in PT_CONTINUE below */ 343b0281cefSPeter Wemm 344b0281cefSPeter Wemm case PT_STEP: 345b0281cefSPeter Wemm case PT_CONTINUE: 3464e68ceabSDavid Greenman case PT_DETACH: 3472ec40c9aSJohn W. De Boskey if ((uap->req != PT_STEP) && ((unsigned)uap->data >= NSIG)) 3484e68ceabSDavid Greenman return EINVAL; 349b0281cefSPeter Wemm 350b0281cefSPeter Wemm PHOLD(p); 351b0281cefSPeter Wemm 352b0281cefSPeter Wemm if (uap->req == PT_STEP) { 353b0281cefSPeter Wemm if ((error = ptrace_single_step (p))) { 354b0281cefSPeter Wemm PRELE(p); 355b0281cefSPeter Wemm return error; 356b0281cefSPeter Wemm } 357b0281cefSPeter Wemm } 358b0281cefSPeter Wemm 359b0281cefSPeter Wemm if (uap->addr != (caddr_t)1) { 3601f7d2501SKirk McKusick fill_kinfo_proc (p, &p->p_addr->u_kproc); 3616a206dd9SBruce Evans if ((error = ptrace_set_pc (p, 3626a206dd9SBruce Evans (u_long)(uintfptr_t)uap->addr))) { 363b0281cefSPeter Wemm PRELE(p); 364b0281cefSPeter Wemm return error; 365b0281cefSPeter Wemm } 366b0281cefSPeter Wemm } 367b0281cefSPeter Wemm PRELE(p); 368b0281cefSPeter Wemm 369b0281cefSPeter Wemm if (uap->req == PT_DETACH) { 370b0281cefSPeter Wemm /* reset process parent */ 37198f03f90SJake Burkholder PROCTREE_LOCK(PT_EXCLUSIVE); 372b0281cefSPeter Wemm if (p->p_oppid != p->p_pptr->p_pid) { 373b0281cefSPeter Wemm struct proc *pp; 374b0281cefSPeter Wemm 375b0281cefSPeter Wemm pp = pfind(p->p_oppid); 376731a1aeaSJohn Baldwin PROC_LOCK(p); 377b0281cefSPeter Wemm proc_reparent(p, pp ? pp : initproc); 378731a1aeaSJohn Baldwin } else 379731a1aeaSJohn Baldwin PROC_LOCK(p); 380b0281cefSPeter Wemm p->p_flag &= ~(P_TRACED | P_WAITED); 381b0281cefSPeter Wemm p->p_oppid = 0; 382b0281cefSPeter Wemm 383731a1aeaSJohn Baldwin PROC_UNLOCK(p); 384731a1aeaSJohn Baldwin PROCTREE_LOCK(PT_RELEASE); 385731a1aeaSJohn Baldwin 386b0281cefSPeter Wemm /* should we send SIGCHLD? */ 387b0281cefSPeter Wemm 388b0281cefSPeter Wemm } 389b0281cefSPeter Wemm 390b0281cefSPeter Wemm sendsig: 391b0281cefSPeter Wemm /* deliver or queue signal */ 392731a1aeaSJohn Baldwin PROC_LOCK(p); 3939ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 3944e68ceabSDavid Greenman if (p->p_stat == SSTOP) { 3954e68ceabSDavid Greenman p->p_xstat = uap->data; 3964e68ceabSDavid Greenman setrunnable(p); 3979ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 3980ebabc93SJohn Baldwin } else { 3999ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 400731a1aeaSJohn Baldwin if (uap->data) 4014e68ceabSDavid Greenman psignal(p, uap->data); 402731a1aeaSJohn Baldwin 4034e68ceabSDavid Greenman } 404731a1aeaSJohn Baldwin PROC_UNLOCK(p); 4054e68ceabSDavid Greenman return 0; 4064e68ceabSDavid Greenman 4074e68ceabSDavid Greenman case PT_WRITE_I: 4084e68ceabSDavid Greenman case PT_WRITE_D: 409b0281cefSPeter Wemm write = 1; 4104e68ceabSDavid Greenman /* fallthrough */ 411b0281cefSPeter Wemm case PT_READ_I: 412b0281cefSPeter Wemm case PT_READ_D: 413b0281cefSPeter Wemm /* write = 0 set above */ 414d72ec665STor Egge iov.iov_base = write ? (caddr_t)&uap->data : (caddr_t)curp->p_retval; 415b0281cefSPeter Wemm iov.iov_len = sizeof(int); 416b0281cefSPeter Wemm uio.uio_iov = &iov; 417b0281cefSPeter Wemm uio.uio_iovcnt = 1; 4186a206dd9SBruce Evans uio.uio_offset = (off_t)(uintptr_t)uap->addr; 419b0281cefSPeter Wemm uio.uio_resid = sizeof(int); 420b0281cefSPeter Wemm uio.uio_segflg = UIO_SYSSPACE; /* ie: the uap */ 421b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 422b0281cefSPeter Wemm uio.uio_procp = p; 4232eb80d36SPeter Wemm error = procfs_domem(curp, p, NULL, &uio); 4242eb80d36SPeter Wemm if (uio.uio_resid != 0) { 4252eb80d36SPeter Wemm /* 4262eb80d36SPeter Wemm * XXX procfs_domem() doesn't currently return ENOSPC, 4272eb80d36SPeter Wemm * so I think write() can bogusly return 0. 4282eb80d36SPeter Wemm * XXX what happens for short writes? We don't want 4292eb80d36SPeter Wemm * to write partial data. 4302eb80d36SPeter Wemm * XXX procfs_domem() returns EPERM for other invalid 4312eb80d36SPeter Wemm * addresses. Convert this to EINVAL. Does this 4322eb80d36SPeter Wemm * clobber returns of EPERM for other reasons? 4332eb80d36SPeter Wemm */ 4342eb80d36SPeter Wemm if (error == 0 || error == ENOSPC || error == EPERM) 4352eb80d36SPeter Wemm error = EINVAL; /* EOF */ 4362eb80d36SPeter Wemm } 4372eb80d36SPeter Wemm return (error); 4384e68ceabSDavid Greenman 4394e68ceabSDavid Greenman case PT_READ_U: 440dae63452SDoug Rabson if ((uintptr_t)uap->addr > UPAGES * PAGE_SIZE - sizeof(int)) { 441dae63452SDoug Rabson return EFAULT; 442dae63452SDoug Rabson } 443dae63452SDoug Rabson if ((uintptr_t)uap->addr & (sizeof(int) - 1)) { 4444e68ceabSDavid Greenman return EFAULT; 4454e68ceabSDavid Greenman } 446afc6ea23STor Egge if (ptrace_read_u_check(p,(vm_offset_t) uap->addr, 447a9e0361bSPoul-Henning Kamp sizeof(int))) { 448afc6ea23STor Egge return EFAULT; 449afc6ea23STor Egge } 450b0281cefSPeter Wemm error = 0; 451b0281cefSPeter Wemm PHOLD(p); /* user had damn well better be incore! */ 4529ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 4533897ca7cSJohn Baldwin if (p->p_sflag & PS_INMEM) { 4549ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 4551f7d2501SKirk McKusick fill_kinfo_proc (p, &p->p_addr->u_kproc); 4568a8a13c8SDoug Rabson curp->p_retval[0] = *(int *) 4576a206dd9SBruce Evans ((uintptr_t)p->p_addr + (uintptr_t)uap->addr); 458b0281cefSPeter Wemm } else { 4599ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 460d72ec665STor Egge curp->p_retval[0] = 0; 461b0281cefSPeter Wemm error = EFAULT; 462b0281cefSPeter Wemm } 463b0281cefSPeter Wemm PRELE(p); 464b0281cefSPeter Wemm return error; 465b0281cefSPeter Wemm 4664e68ceabSDavid Greenman case PT_WRITE_U: 467b0281cefSPeter Wemm PHOLD(p); /* user had damn well better be incore! */ 4689ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 4693897ca7cSJohn Baldwin if (p->p_sflag & PS_INMEM) { 4709ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 4711f7d2501SKirk McKusick fill_kinfo_proc (p, &p->p_addr->u_kproc); 472b0281cefSPeter Wemm error = ptrace_write_u(p, (vm_offset_t)uap->addr, uap->data); 473b0281cefSPeter Wemm } else { 4749ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 475b0281cefSPeter Wemm error = EFAULT; 476b0281cefSPeter Wemm } 477b0281cefSPeter Wemm PRELE(p); 478b0281cefSPeter Wemm return error; 479b0281cefSPeter Wemm 4804e68ceabSDavid Greenman case PT_KILL: 481b0281cefSPeter Wemm uap->data = SIGKILL; 482b0281cefSPeter Wemm goto sendsig; /* in PT_CONTINUE above */ 483b0281cefSPeter Wemm 484b0281cefSPeter Wemm #ifdef PT_SETREGS 485b0281cefSPeter Wemm case PT_SETREGS: 486b0281cefSPeter Wemm write = 1; 487b0281cefSPeter Wemm /* fallthrough */ 488b0281cefSPeter Wemm #endif /* PT_SETREGS */ 4894e68ceabSDavid Greenman #ifdef PT_GETREGS 4904e68ceabSDavid Greenman case PT_GETREGS: 491b0281cefSPeter Wemm /* write = 0 above */ 492b0281cefSPeter Wemm #endif /* PT_SETREGS */ 493b0281cefSPeter Wemm #if defined(PT_SETREGS) || defined(PT_GETREGS) 494b0281cefSPeter Wemm if (!procfs_validregs(p)) /* no P_SYSTEM procs please */ 495b0281cefSPeter Wemm return EINVAL; 496b0281cefSPeter Wemm else { 497b0281cefSPeter Wemm iov.iov_base = uap->addr; 498b0281cefSPeter Wemm iov.iov_len = sizeof(struct reg); 499b0281cefSPeter Wemm uio.uio_iov = &iov; 500b0281cefSPeter Wemm uio.uio_iovcnt = 1; 501b0281cefSPeter Wemm uio.uio_offset = 0; 502b0281cefSPeter Wemm uio.uio_resid = sizeof(struct reg); 503b0281cefSPeter Wemm uio.uio_segflg = UIO_USERSPACE; 504b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 505b0281cefSPeter Wemm uio.uio_procp = curp; 506b0281cefSPeter Wemm return (procfs_doregs(curp, p, NULL, &uio)); 507b0281cefSPeter Wemm } 508b0281cefSPeter Wemm #endif /* defined(PT_SETREGS) || defined(PT_GETREGS) */ 509b0281cefSPeter Wemm 510b0281cefSPeter Wemm #ifdef PT_SETFPREGS 511b0281cefSPeter Wemm case PT_SETFPREGS: 512b0281cefSPeter Wemm write = 1; 513b0281cefSPeter Wemm /* fallthrough */ 514b0281cefSPeter Wemm #endif /* PT_SETFPREGS */ 515b0281cefSPeter Wemm #ifdef PT_GETFPREGS 516b0281cefSPeter Wemm case PT_GETFPREGS: 517b0281cefSPeter Wemm /* write = 0 above */ 518b0281cefSPeter Wemm #endif /* PT_SETFPREGS */ 519b0281cefSPeter Wemm #if defined(PT_SETFPREGS) || defined(PT_GETFPREGS) 520b0281cefSPeter Wemm if (!procfs_validfpregs(p)) /* no P_SYSTEM procs please */ 521b0281cefSPeter Wemm return EINVAL; 522b0281cefSPeter Wemm else { 523b0281cefSPeter Wemm iov.iov_base = uap->addr; 524b0281cefSPeter Wemm iov.iov_len = sizeof(struct fpreg); 525b0281cefSPeter Wemm uio.uio_iov = &iov; 526b0281cefSPeter Wemm uio.uio_iovcnt = 1; 527b0281cefSPeter Wemm uio.uio_offset = 0; 528b0281cefSPeter Wemm uio.uio_resid = sizeof(struct fpreg); 529b0281cefSPeter Wemm uio.uio_segflg = UIO_USERSPACE; 530b0281cefSPeter Wemm uio.uio_rw = write ? UIO_WRITE : UIO_READ; 531b0281cefSPeter Wemm uio.uio_procp = curp; 532b0281cefSPeter Wemm return (procfs_dofpregs(curp, p, NULL, &uio)); 533b0281cefSPeter Wemm } 534b0281cefSPeter Wemm #endif /* defined(PT_SETFPREGS) || defined(PT_GETFPREGS) */ 535b0281cefSPeter Wemm 536ab001a72SJonathan Lemon #ifdef PT_SETDBREGS 537ab001a72SJonathan Lemon case PT_SETDBREGS: 538ab001a72SJonathan Lemon write = 1; 539ab001a72SJonathan Lemon /* fallthrough */ 540ab001a72SJonathan Lemon #endif /* PT_SETDBREGS */ 541ab001a72SJonathan Lemon #ifdef PT_GETDBREGS 542ab001a72SJonathan Lemon case PT_GETDBREGS: 543ab001a72SJonathan Lemon /* write = 0 above */ 544ab001a72SJonathan Lemon #endif /* PT_SETDBREGS */ 545ab001a72SJonathan Lemon #if defined(PT_SETDBREGS) || defined(PT_GETDBREGS) 546ab001a72SJonathan Lemon if (!procfs_validdbregs(p)) /* no P_SYSTEM procs please */ 547ab001a72SJonathan Lemon return EINVAL; 548ab001a72SJonathan Lemon else { 549ab001a72SJonathan Lemon iov.iov_base = uap->addr; 550ab001a72SJonathan Lemon iov.iov_len = sizeof(struct dbreg); 551ab001a72SJonathan Lemon uio.uio_iov = &iov; 552ab001a72SJonathan Lemon uio.uio_iovcnt = 1; 553ab001a72SJonathan Lemon uio.uio_offset = 0; 554ab001a72SJonathan Lemon uio.uio_resid = sizeof(struct dbreg); 555ab001a72SJonathan Lemon uio.uio_segflg = UIO_USERSPACE; 556ab001a72SJonathan Lemon uio.uio_rw = write ? UIO_WRITE : UIO_READ; 557ab001a72SJonathan Lemon uio.uio_procp = curp; 558ab001a72SJonathan Lemon return (procfs_dodbregs(curp, p, NULL, &uio)); 559ab001a72SJonathan Lemon } 560ab001a72SJonathan Lemon #endif /* defined(PT_SETDBREGS) || defined(PT_GETDBREGS) */ 561ab001a72SJonathan Lemon 5624e68ceabSDavid Greenman default: 5634e68ceabSDavid Greenman break; 5644e68ceabSDavid Greenman } 5654e68ceabSDavid Greenman 5664e68ceabSDavid Greenman return 0; 567df8bae1dSRodney W. Grimes } 568df8bae1dSRodney W. Grimes 56926f9a767SRodney W. Grimes int 5704e68ceabSDavid Greenman trace_req(p) 5714e68ceabSDavid Greenman struct proc *p; 572df8bae1dSRodney W. Grimes { 5734e68ceabSDavid Greenman return 1; 574df8bae1dSRodney W. Grimes } 5752a024a2bSSean Eric Fagan 5762a024a2bSSean Eric Fagan /* 5772a024a2bSSean Eric Fagan * stopevent() 5782a024a2bSSean Eric Fagan * Stop a process because of a procfs event; 5792a024a2bSSean Eric Fagan * stay stopped until p->p_step is cleared 5802a024a2bSSean Eric Fagan * (cleared by PIOCCONT in procfs). 5813897ca7cSJohn Baldwin * 5823897ca7cSJohn Baldwin * Must be called with the proc struct mutex held. 5832a024a2bSSean Eric Fagan */ 5842a024a2bSSean Eric Fagan 5852a024a2bSSean Eric Fagan void 5863897ca7cSJohn Baldwin stopevent(p, event, val) 5873897ca7cSJohn Baldwin struct proc *p; 5883897ca7cSJohn Baldwin unsigned int event; 5893897ca7cSJohn Baldwin unsigned int val; 5903897ca7cSJohn Baldwin { 5913897ca7cSJohn Baldwin 592731a1aeaSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED | MA_NOTRECURSED); 5932a024a2bSSean Eric Fagan p->p_step = 1; 5942a024a2bSSean Eric Fagan 5952a024a2bSSean Eric Fagan do { 5962a024a2bSSean Eric Fagan p->p_xstat = val; 5972a024a2bSSean Eric Fagan p->p_stype = event; /* Which event caused the stop? */ 5982a024a2bSSean Eric Fagan wakeup(&p->p_stype); /* Wake up any PIOCWAIT'ing procs */ 5993897ca7cSJohn Baldwin msleep(&p->p_step, &p->p_mtx, PWAIT, "stopevent", 0); 6002a024a2bSSean Eric Fagan } while (p->p_step); 6012a024a2bSSean Eric Fagan } 602