xref: /freebsd/sys/kern/sys_process.c (revision feabaaf9956aa2e9bbe5e877ab1a1cf5eae476c0)
19454b2d8SWarner Losh /*-
28a36da99SPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
38a36da99SPedro F. Giffuni  *
44e68ceabSDavid Greenman  * Copyright (c) 1994, Sean Eric Fagan
54e68ceabSDavid Greenman  * All rights reserved.
6df8bae1dSRodney W. Grimes  *
7df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
8df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
9df8bae1dSRodney W. Grimes  * are met:
10df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
12df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
13df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
14df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
16df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
174e68ceabSDavid Greenman  *	This product includes software developed by Sean Eric Fagan.
184e68ceabSDavid Greenman  * 4. The name of the author may not be used to endorse or promote products
194e68ceabSDavid Greenman  *    derived from this software without specific prior written permission.
20df8bae1dSRodney W. Grimes  *
214e68ceabSDavid Greenman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
244e68ceabSDavid Greenman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
32df8bae1dSRodney W. Grimes  */
33df8bae1dSRodney W. Grimes 
34677b542eSDavid E. O'Brien #include <sys/cdefs.h>
35677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
36677b542eSDavid E. O'Brien 
37df8bae1dSRodney W. Grimes #include <sys/param.h>
38f23b4c91SGarrett Wollman #include <sys/systm.h>
39daec9284SConrad Meyer #include <sys/ktr.h>
4091898857SMark Johnston #include <sys/limits.h>
41fb919e4dSMark Murray #include <sys/lock.h>
42fb919e4dSMark Murray #include <sys/mutex.h>
43012e544fSIan Dowse #include <sys/syscallsubr.h>
442883703eSKonstantin Belousov #include <sys/sysent.h>
45d2d3e875SBruce Evans #include <sys/sysproto.h>
4655648840SJohn Baldwin #include <sys/priv.h>
47df8bae1dSRodney W. Grimes #include <sys/proc.h>
484e68ceabSDavid Greenman #include <sys/vnode.h>
494e68ceabSDavid Greenman #include <sys/ptrace.h>
5089f6b863SAttilio Rao #include <sys/rwlock.h>
511005a129SJohn Baldwin #include <sys/sx.h>
52ef9457beSDavid Xu #include <sys/malloc.h>
536004362eSDavid Schultz #include <sys/signalvar.h>
54df8bae1dSRodney W. Grimes 
554e68ceabSDavid Greenman #include <machine/reg.h>
56fb919e4dSMark Murray 
57085a0d43SWayne Salamon #include <security/audit/audit.h>
58085a0d43SWayne Salamon 
594e68ceabSDavid Greenman #include <vm/vm.h>
60efeaf95aSDavid Greenman #include <vm/pmap.h>
613da32491SDag-Erling Smørgrav #include <vm/vm_extern.h>
62efeaf95aSDavid Greenman #include <vm/vm_map.h>
633da32491SDag-Erling Smørgrav #include <vm/vm_kern.h>
643da32491SDag-Erling Smørgrav #include <vm/vm_object.h>
654e68ceabSDavid Greenman #include <vm/vm_page.h>
663364c323SKonstantin Belousov #include <vm/vm_param.h>
674e68ceabSDavid Greenman 
68841c0c7eSNathan Whitehorn #ifdef COMPAT_FREEBSD32
6962919d78SPeter Wemm #include <sys/procfs.h>
7062919d78SPeter Wemm #endif
7162919d78SPeter Wemm 
724b1aa58bSBruce Evans /*
734b1aa58bSBruce Evans  * Functions implemented using PROC_ACTION():
744b1aa58bSBruce Evans  *
754b1aa58bSBruce Evans  * proc_read_regs(proc, regs)
764b1aa58bSBruce Evans  *	Get the current user-visible register set from the process
774b1aa58bSBruce Evans  *	and copy it into the regs structure (<machine/reg.h>).
784b1aa58bSBruce Evans  *	The process is stopped at the time read_regs is called.
794b1aa58bSBruce Evans  *
804b1aa58bSBruce Evans  * proc_write_regs(proc, regs)
814b1aa58bSBruce Evans  *	Update the current register set from the passed in regs
824b1aa58bSBruce Evans  *	structure.  Take care to avoid clobbering special CPU
834b1aa58bSBruce Evans  *	registers or privileged bits in the PSL.
844b1aa58bSBruce Evans  *	Depending on the architecture this may have fix-up work to do,
854b1aa58bSBruce Evans  *	especially if the IAR or PCW are modified.
864b1aa58bSBruce Evans  *	The process is stopped at the time write_regs is called.
874b1aa58bSBruce Evans  *
884b1aa58bSBruce Evans  * proc_read_fpregs, proc_write_fpregs
894b1aa58bSBruce Evans  *	deal with the floating point register set, otherwise as above.
904b1aa58bSBruce Evans  *
914b1aa58bSBruce Evans  * proc_read_dbregs, proc_write_dbregs
924b1aa58bSBruce Evans  *	deal with the processor debug register set, otherwise as above.
934b1aa58bSBruce Evans  *
944b1aa58bSBruce Evans  * proc_sstep(proc)
954b1aa58bSBruce Evans  *	Arrange for the process to trap after executing a single instruction.
964b1aa58bSBruce Evans  */
974b1aa58bSBruce Evans 
984b1aa58bSBruce Evans #define	PROC_ACTION(action) do {					\
997c629906SDag-Erling Smørgrav 	int error;							\
1007c629906SDag-Erling Smørgrav 									\
101eeec6babSJohn Baldwin 	PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);			\
102b61ce5b0SJeff Roberson 	if ((td->td_proc->p_flag & P_INMEM) == 0)			\
1034b1aa58bSBruce Evans 		error = EIO;						\
1044b1aa58bSBruce Evans 	else								\
1054b1aa58bSBruce Evans 		error = (action);					\
1067c629906SDag-Erling Smørgrav 	return (error);							\
1074b1aa58bSBruce Evans } while(0)
1084b1aa58bSBruce Evans 
1094b1aa58bSBruce Evans int
1104b1aa58bSBruce Evans proc_read_regs(struct thread *td, struct reg *regs)
1114b1aa58bSBruce Evans {
1124b1aa58bSBruce Evans 
1134b1aa58bSBruce Evans 	PROC_ACTION(fill_regs(td, regs));
1147c629906SDag-Erling Smørgrav }
1157c629906SDag-Erling Smørgrav 
1164b1aa58bSBruce Evans int
1174b1aa58bSBruce Evans proc_write_regs(struct thread *td, struct reg *regs)
1184b1aa58bSBruce Evans {
1194b1aa58bSBruce Evans 
1204b1aa58bSBruce Evans 	PROC_ACTION(set_regs(td, regs));
1214b1aa58bSBruce Evans }
1224b1aa58bSBruce Evans 
1234b1aa58bSBruce Evans int
1244b1aa58bSBruce Evans proc_read_dbregs(struct thread *td, struct dbreg *dbregs)
1254b1aa58bSBruce Evans {
1264b1aa58bSBruce Evans 
1274b1aa58bSBruce Evans 	PROC_ACTION(fill_dbregs(td, dbregs));
1284b1aa58bSBruce Evans }
1294b1aa58bSBruce Evans 
1304b1aa58bSBruce Evans int
1314b1aa58bSBruce Evans proc_write_dbregs(struct thread *td, struct dbreg *dbregs)
1324b1aa58bSBruce Evans {
1334b1aa58bSBruce Evans 
1344b1aa58bSBruce Evans 	PROC_ACTION(set_dbregs(td, dbregs));
1354b1aa58bSBruce Evans }
1364b1aa58bSBruce Evans 
1374b1aa58bSBruce Evans /*
1384b1aa58bSBruce Evans  * Ptrace doesn't support fpregs at all, and there are no security holes
1394b1aa58bSBruce Evans  * or translations for fpregs, so we can just copy them.
1404b1aa58bSBruce Evans  */
1414b1aa58bSBruce Evans int
1424b1aa58bSBruce Evans proc_read_fpregs(struct thread *td, struct fpreg *fpregs)
1434b1aa58bSBruce Evans {
1444b1aa58bSBruce Evans 
1454b1aa58bSBruce Evans 	PROC_ACTION(fill_fpregs(td, fpregs));
1464b1aa58bSBruce Evans }
1474b1aa58bSBruce Evans 
1484b1aa58bSBruce Evans int
1494b1aa58bSBruce Evans proc_write_fpregs(struct thread *td, struct fpreg *fpregs)
1504b1aa58bSBruce Evans {
1514b1aa58bSBruce Evans 
1524b1aa58bSBruce Evans 	PROC_ACTION(set_fpregs(td, fpregs));
1534b1aa58bSBruce Evans }
1547c629906SDag-Erling Smørgrav 
155841c0c7eSNathan Whitehorn #ifdef COMPAT_FREEBSD32
15662919d78SPeter Wemm /* For 32 bit binaries, we need to expose the 32 bit regs layouts. */
15762919d78SPeter Wemm int
15862919d78SPeter Wemm proc_read_regs32(struct thread *td, struct reg32 *regs32)
15962919d78SPeter Wemm {
16062919d78SPeter Wemm 
16162919d78SPeter Wemm 	PROC_ACTION(fill_regs32(td, regs32));
16262919d78SPeter Wemm }
16362919d78SPeter Wemm 
16462919d78SPeter Wemm int
16562919d78SPeter Wemm proc_write_regs32(struct thread *td, struct reg32 *regs32)
16662919d78SPeter Wemm {
16762919d78SPeter Wemm 
16862919d78SPeter Wemm 	PROC_ACTION(set_regs32(td, regs32));
16962919d78SPeter Wemm }
17062919d78SPeter Wemm 
17162919d78SPeter Wemm int
17262919d78SPeter Wemm proc_read_dbregs32(struct thread *td, struct dbreg32 *dbregs32)
17362919d78SPeter Wemm {
17462919d78SPeter Wemm 
17562919d78SPeter Wemm 	PROC_ACTION(fill_dbregs32(td, dbregs32));
17662919d78SPeter Wemm }
17762919d78SPeter Wemm 
17862919d78SPeter Wemm int
17962919d78SPeter Wemm proc_write_dbregs32(struct thread *td, struct dbreg32 *dbregs32)
18062919d78SPeter Wemm {
18162919d78SPeter Wemm 
18262919d78SPeter Wemm 	PROC_ACTION(set_dbregs32(td, dbregs32));
18362919d78SPeter Wemm }
18462919d78SPeter Wemm 
18562919d78SPeter Wemm int
18662919d78SPeter Wemm proc_read_fpregs32(struct thread *td, struct fpreg32 *fpregs32)
18762919d78SPeter Wemm {
18862919d78SPeter Wemm 
18962919d78SPeter Wemm 	PROC_ACTION(fill_fpregs32(td, fpregs32));
19062919d78SPeter Wemm }
19162919d78SPeter Wemm 
19262919d78SPeter Wemm int
19362919d78SPeter Wemm proc_write_fpregs32(struct thread *td, struct fpreg32 *fpregs32)
19462919d78SPeter Wemm {
19562919d78SPeter Wemm 
19662919d78SPeter Wemm 	PROC_ACTION(set_fpregs32(td, fpregs32));
19762919d78SPeter Wemm }
19862919d78SPeter Wemm #endif
19962919d78SPeter Wemm 
2007c629906SDag-Erling Smørgrav int
2017c629906SDag-Erling Smørgrav proc_sstep(struct thread *td)
2027c629906SDag-Erling Smørgrav {
2037c629906SDag-Erling Smørgrav 
2044b1aa58bSBruce Evans 	PROC_ACTION(ptrace_single_step(td));
2057c629906SDag-Erling Smørgrav }
2067c629906SDag-Erling Smørgrav 
2073da32491SDag-Erling Smørgrav int
2083da32491SDag-Erling Smørgrav proc_rwmem(struct proc *p, struct uio *uio)
20950f74e92SDag-Erling Smørgrav {
2103da32491SDag-Erling Smørgrav 	vm_map_t map;
211a6d42a0dSAlan Cox 	vm_offset_t pageno;		/* page number */
2123da32491SDag-Erling Smørgrav 	vm_prot_t reqprot;
213acd11c74SAlan Cox 	int error, fault_flags, page_offset, writing;
2144e68ceabSDavid Greenman 
2154e68ceabSDavid Greenman 	/*
21606ad42b2SJohn Baldwin 	 * Assert that someone has locked this vmspace.  (Should be
21706ad42b2SJohn Baldwin 	 * curthread but we can't assert that.)  This keeps the process
21806ad42b2SJohn Baldwin 	 * from exiting out from under us until this operation completes.
2194e68ceabSDavid Greenman 	 */
220d2871337SMark Johnston 	PROC_ASSERT_HELD(p);
221711fbd17SMark Johnston 	PROC_LOCK_ASSERT(p, MA_NOTOWNED);
2221a276a3fSAlan Cox 
2233da32491SDag-Erling Smørgrav 	/*
2243da32491SDag-Erling Smørgrav 	 * The map we want...
2253da32491SDag-Erling Smørgrav 	 */
22606ad42b2SJohn Baldwin 	map = &p->p_vmspace->vm_map;
2274e68ceabSDavid Greenman 
228acd11c74SAlan Cox 	/*
229acd11c74SAlan Cox 	 * If we are writing, then we request vm_fault() to create a private
230acd11c74SAlan Cox 	 * copy of each page.  Since these copies will not be writeable by the
231acd11c74SAlan Cox 	 * process, we must explicity request that they be dirtied.
232acd11c74SAlan Cox 	 */
2333da32491SDag-Erling Smørgrav 	writing = uio->uio_rw == UIO_WRITE;
234a6d42a0dSAlan Cox 	reqprot = writing ? VM_PROT_COPY | VM_PROT_READ : VM_PROT_READ;
235acd11c74SAlan Cox 	fault_flags = writing ? VM_FAULT_DIRTY : VM_FAULT_NORMAL;
2363da32491SDag-Erling Smørgrav 
2373da32491SDag-Erling Smørgrav 	/*
2383da32491SDag-Erling Smørgrav 	 * Only map in one page at a time.  We don't have to, but it
2393da32491SDag-Erling Smørgrav 	 * makes things easier.  This way is trivial - right?
2403da32491SDag-Erling Smørgrav 	 */
2413da32491SDag-Erling Smørgrav 	do {
2423da32491SDag-Erling Smørgrav 		vm_offset_t uva;
2433da32491SDag-Erling Smørgrav 		u_int len;
2443da32491SDag-Erling Smørgrav 		vm_page_t m;
2453da32491SDag-Erling Smørgrav 
2463da32491SDag-Erling Smørgrav 		uva = (vm_offset_t)uio->uio_offset;
2473da32491SDag-Erling Smørgrav 
2483da32491SDag-Erling Smørgrav 		/*
2493da32491SDag-Erling Smørgrav 		 * Get the page number of this segment.
2503da32491SDag-Erling Smørgrav 		 */
2513da32491SDag-Erling Smørgrav 		pageno = trunc_page(uva);
2523da32491SDag-Erling Smørgrav 		page_offset = uva - pageno;
2533da32491SDag-Erling Smørgrav 
2543da32491SDag-Erling Smørgrav 		/*
2553da32491SDag-Erling Smørgrav 		 * How many bytes to copy
2563da32491SDag-Erling Smørgrav 		 */
2573da32491SDag-Erling Smørgrav 		len = min(PAGE_SIZE - page_offset, uio->uio_resid);
2583da32491SDag-Erling Smørgrav 
2593da32491SDag-Erling Smørgrav 		/*
260be996836SAttilio Rao 		 * Fault and hold the page on behalf of the process.
2613da32491SDag-Erling Smørgrav 		 */
262df08823dSKonstantin Belousov 		error = vm_fault(map, pageno, reqprot, fault_flags, &m);
263acd11c74SAlan Cox 		if (error != KERN_SUCCESS) {
2643364c323SKonstantin Belousov 			if (error == KERN_RESOURCE_SHORTAGE)
2653364c323SKonstantin Belousov 				error = ENOMEM;
2663364c323SKonstantin Belousov 			else
2673da32491SDag-Erling Smørgrav 				error = EFAULT;
2683da32491SDag-Erling Smørgrav 			break;
2693da32491SDag-Erling Smørgrav 		}
2703da32491SDag-Erling Smørgrav 
2713da32491SDag-Erling Smørgrav 		/*
2723da32491SDag-Erling Smørgrav 		 * Now do the i/o move.
2733da32491SDag-Erling Smørgrav 		 */
2742b63e7f3SAlan Cox 		error = uiomove_fromphys(&m, page_offset, len, uio);
2753da32491SDag-Erling Smørgrav 
2761a4fcaebSMarcel Moolenaar 		/* Make the I-cache coherent for breakpoints. */
277acd11c74SAlan Cox 		if (writing && error == 0) {
278acd11c74SAlan Cox 			vm_map_lock_read(map);
279acd11c74SAlan Cox 			if (vm_map_check_protection(map, pageno, pageno +
280acd11c74SAlan Cox 			    PAGE_SIZE, VM_PROT_EXECUTE))
2811a4fcaebSMarcel Moolenaar 				vm_sync_icache(map, uva, len);
282acd11c74SAlan Cox 			vm_map_unlock_read(map);
283acd11c74SAlan Cox 		}
2841a4fcaebSMarcel Moolenaar 
2853da32491SDag-Erling Smørgrav 		/*
286c6eb850aSAlan Cox 		 * Release the page.
2873da32491SDag-Erling Smørgrav 		 */
288fee2a2faSMark Johnston 		vm_page_unwire(m, PQ_ACTIVE);
2893da32491SDag-Erling Smørgrav 
2903da32491SDag-Erling Smørgrav 	} while (error == 0 && uio->uio_resid > 0);
2913da32491SDag-Erling Smørgrav 
2923da32491SDag-Erling Smørgrav 	return (error);
2934e68ceabSDavid Greenman }
2944e68ceabSDavid Greenman 
295711fbd17SMark Johnston static ssize_t
296711fbd17SMark Johnston proc_iop(struct thread *td, struct proc *p, vm_offset_t va, void *buf,
297711fbd17SMark Johnston     size_t len, enum uio_rw rw)
298711fbd17SMark Johnston {
299711fbd17SMark Johnston 	struct iovec iov;
300711fbd17SMark Johnston 	struct uio uio;
301711fbd17SMark Johnston 	ssize_t slen;
302711fbd17SMark Johnston 
303711fbd17SMark Johnston 	MPASS(len < SSIZE_MAX);
304711fbd17SMark Johnston 	slen = (ssize_t)len;
305711fbd17SMark Johnston 
306711fbd17SMark Johnston 	iov.iov_base = (caddr_t)buf;
307711fbd17SMark Johnston 	iov.iov_len = len;
308711fbd17SMark Johnston 	uio.uio_iov = &iov;
309711fbd17SMark Johnston 	uio.uio_iovcnt = 1;
310711fbd17SMark Johnston 	uio.uio_offset = va;
311711fbd17SMark Johnston 	uio.uio_resid = slen;
312711fbd17SMark Johnston 	uio.uio_segflg = UIO_SYSSPACE;
313711fbd17SMark Johnston 	uio.uio_rw = rw;
314711fbd17SMark Johnston 	uio.uio_td = td;
315ac8b2d5cSMatt Macy 	proc_rwmem(p, &uio);
316711fbd17SMark Johnston 	if (uio.uio_resid == slen)
317711fbd17SMark Johnston 		return (-1);
318711fbd17SMark Johnston 	return (slen - uio.uio_resid);
319711fbd17SMark Johnston }
320711fbd17SMark Johnston 
321711fbd17SMark Johnston ssize_t
322711fbd17SMark Johnston proc_readmem(struct thread *td, struct proc *p, vm_offset_t va, void *buf,
323711fbd17SMark Johnston     size_t len)
324711fbd17SMark Johnston {
325711fbd17SMark Johnston 
326711fbd17SMark Johnston 	return (proc_iop(td, p, va, buf, len, UIO_READ));
327711fbd17SMark Johnston }
328711fbd17SMark Johnston 
329711fbd17SMark Johnston ssize_t
330711fbd17SMark Johnston proc_writemem(struct thread *td, struct proc *p, vm_offset_t va, void *buf,
331711fbd17SMark Johnston     size_t len)
332711fbd17SMark Johnston {
333711fbd17SMark Johnston 
334711fbd17SMark Johnston 	return (proc_iop(td, p, va, buf, len, UIO_WRITE));
335711fbd17SMark Johnston }
336711fbd17SMark Johnston 
33790b4621aSMarcel Moolenaar static int
33890b4621aSMarcel Moolenaar ptrace_vm_entry(struct thread *td, struct proc *p, struct ptrace_vm_entry *pve)
33990b4621aSMarcel Moolenaar {
34016211027SMarcel Moolenaar 	struct vattr vattr;
34190b4621aSMarcel Moolenaar 	vm_map_t map;
34290b4621aSMarcel Moolenaar 	vm_map_entry_t entry;
34390b4621aSMarcel Moolenaar 	vm_object_t obj, tobj, lobj;
34416211027SMarcel Moolenaar 	struct vmspace *vm;
34590b4621aSMarcel Moolenaar 	struct vnode *vp;
34690b4621aSMarcel Moolenaar 	char *freepath, *fullpath;
34790b4621aSMarcel Moolenaar 	u_int pathlen;
3485050aa86SKonstantin Belousov 	int error, index;
34990b4621aSMarcel Moolenaar 
35016211027SMarcel Moolenaar 	error = 0;
35116211027SMarcel Moolenaar 	obj = NULL;
35216211027SMarcel Moolenaar 
35316211027SMarcel Moolenaar 	vm = vmspace_acquire_ref(p);
35416211027SMarcel Moolenaar 	map = &vm->vm_map;
35516211027SMarcel Moolenaar 	vm_map_lock_read(map);
35616211027SMarcel Moolenaar 
35716211027SMarcel Moolenaar 	do {
3582203c46dSMark Johnston 		KASSERT((map->header.eflags & MAP_ENTRY_IS_SUB_MAP) == 0,
3592203c46dSMark Johnston 		    ("Submap in map header"));
3602288078cSDoug Moore 		index = 0;
3612288078cSDoug Moore 		VM_MAP_ENTRY_FOREACH(entry, map) {
3622288078cSDoug Moore 			if (index >= pve->pve_entry &&
3632288078cSDoug Moore 			    (entry->eflags & MAP_ENTRY_IS_SUB_MAP) == 0)
3642288078cSDoug Moore 				break;
36516211027SMarcel Moolenaar 			index++;
36616211027SMarcel Moolenaar 		}
3672288078cSDoug Moore 		if (index < pve->pve_entry) {
3682288078cSDoug Moore 			error = EINVAL;
3692288078cSDoug Moore 			break;
3702288078cSDoug Moore 		}
37116211027SMarcel Moolenaar 		if (entry == &map->header) {
37216211027SMarcel Moolenaar 			error = ENOENT;
37316211027SMarcel Moolenaar 			break;
37416211027SMarcel Moolenaar 		}
37590b4621aSMarcel Moolenaar 
37690b4621aSMarcel Moolenaar 		/* We got an entry. */
37716211027SMarcel Moolenaar 		pve->pve_entry = index + 1;
37816211027SMarcel Moolenaar 		pve->pve_timestamp = map->timestamp;
37990b4621aSMarcel Moolenaar 		pve->pve_start = entry->start;
38090b4621aSMarcel Moolenaar 		pve->pve_end = entry->end - 1;
38190b4621aSMarcel Moolenaar 		pve->pve_offset = entry->offset;
38290b4621aSMarcel Moolenaar 		pve->pve_prot = entry->protection;
38390b4621aSMarcel Moolenaar 
38490b4621aSMarcel Moolenaar 		/* Backing object's path needed? */
38590b4621aSMarcel Moolenaar 		if (pve->pve_pathlen == 0)
38616211027SMarcel Moolenaar 			break;
38790b4621aSMarcel Moolenaar 
38890b4621aSMarcel Moolenaar 		pathlen = pve->pve_pathlen;
38990b4621aSMarcel Moolenaar 		pve->pve_pathlen = 0;
39090b4621aSMarcel Moolenaar 
39190b4621aSMarcel Moolenaar 		obj = entry->object.vm_object;
39216211027SMarcel Moolenaar 		if (obj != NULL)
393bc403f03SAttilio Rao 			VM_OBJECT_RLOCK(obj);
39416211027SMarcel Moolenaar 	} while (0);
39516211027SMarcel Moolenaar 
39616211027SMarcel Moolenaar 	vm_map_unlock_read(map);
39716211027SMarcel Moolenaar 
398af002ab8SMarcel Moolenaar 	pve->pve_fsid = VNOVAL;
399af002ab8SMarcel Moolenaar 	pve->pve_fileid = VNOVAL;
400af002ab8SMarcel Moolenaar 
40116211027SMarcel Moolenaar 	if (error == 0 && obj != NULL) {
40216211027SMarcel Moolenaar 		lobj = obj;
40316211027SMarcel Moolenaar 		for (tobj = obj; tobj != NULL; tobj = tobj->backing_object) {
40490b4621aSMarcel Moolenaar 			if (tobj != obj)
405bc403f03SAttilio Rao 				VM_OBJECT_RLOCK(tobj);
40690b4621aSMarcel Moolenaar 			if (lobj != obj)
407bc403f03SAttilio Rao 				VM_OBJECT_RUNLOCK(lobj);
40890b4621aSMarcel Moolenaar 			lobj = tobj;
40990b4621aSMarcel Moolenaar 			pve->pve_offset += tobj->backing_object_offset;
41090b4621aSMarcel Moolenaar 		}
41163e4c6cdSEric van Gyzen 		vp = vm_object_vnode(lobj);
41290b4621aSMarcel Moolenaar 		if (vp != NULL)
41390b4621aSMarcel Moolenaar 			vref(vp);
41490b4621aSMarcel Moolenaar 		if (lobj != obj)
415bc403f03SAttilio Rao 			VM_OBJECT_RUNLOCK(lobj);
416bc403f03SAttilio Rao 		VM_OBJECT_RUNLOCK(obj);
41790b4621aSMarcel Moolenaar 
41816211027SMarcel Moolenaar 		if (vp != NULL) {
41990b4621aSMarcel Moolenaar 			freepath = NULL;
42090b4621aSMarcel Moolenaar 			fullpath = NULL;
421*feabaaf9SMateusz Guzik 			vn_fullpath(vp, &fullpath, &freepath);
42216211027SMarcel Moolenaar 			vn_lock(vp, LK_SHARED | LK_RETRY);
42316211027SMarcel Moolenaar 			if (VOP_GETATTR(vp, &vattr, td->td_ucred) == 0) {
42416211027SMarcel Moolenaar 				pve->pve_fileid = vattr.va_fileid;
42516211027SMarcel Moolenaar 				pve->pve_fsid = vattr.va_fsid;
42616211027SMarcel Moolenaar 			}
42716211027SMarcel Moolenaar 			vput(vp);
42890b4621aSMarcel Moolenaar 
42990b4621aSMarcel Moolenaar 			if (fullpath != NULL) {
43090b4621aSMarcel Moolenaar 				pve->pve_pathlen = strlen(fullpath) + 1;
43190b4621aSMarcel Moolenaar 				if (pve->pve_pathlen <= pathlen) {
43290b4621aSMarcel Moolenaar 					error = copyout(fullpath, pve->pve_path,
43390b4621aSMarcel Moolenaar 					    pve->pve_pathlen);
43490b4621aSMarcel Moolenaar 				} else
43590b4621aSMarcel Moolenaar 					error = ENAMETOOLONG;
43690b4621aSMarcel Moolenaar 			}
43790b4621aSMarcel Moolenaar 			if (freepath != NULL)
43890b4621aSMarcel Moolenaar 				free(freepath, M_TEMP);
43916211027SMarcel Moolenaar 		}
44016211027SMarcel Moolenaar 	}
441f470cca5SKonstantin Belousov 	vmspace_free(vm);
442515b7a0bSJohn Baldwin 	if (error == 0)
443515b7a0bSJohn Baldwin 		CTR3(KTR_PTRACE, "PT_VM_ENTRY: pid %d, entry %d, start %p",
444515b7a0bSJohn Baldwin 		    p->p_pid, pve->pve_entry, pve->pve_start);
44516211027SMarcel Moolenaar 
44690b4621aSMarcel Moolenaar 	return (error);
44790b4621aSMarcel Moolenaar }
44890b4621aSMarcel Moolenaar 
449df8bae1dSRodney W. Grimes /*
450df8bae1dSRodney W. Grimes  * Process debugging system call.
451df8bae1dSRodney W. Grimes  */
452d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
453df8bae1dSRodney W. Grimes struct ptrace_args {
454df8bae1dSRodney W. Grimes 	int	req;
455df8bae1dSRodney W. Grimes 	pid_t	pid;
456df8bae1dSRodney W. Grimes 	caddr_t	addr;
457df8bae1dSRodney W. Grimes 	int	data;
458df8bae1dSRodney W. Grimes };
459d2d3e875SBruce Evans #endif
460df8bae1dSRodney W. Grimes 
4614e68ceabSDavid Greenman int
4628451d0ddSKip Macy sys_ptrace(struct thread *td, struct ptrace_args *uap)
4634e68ceabSDavid Greenman {
46419610b66SBruce Evans 	/*
46519610b66SBruce Evans 	 * XXX this obfuscation is to reduce stack usage, but the register
46619610b66SBruce Evans 	 * structs may be too large to put on the stack anyway.
46719610b66SBruce Evans 	 */
4683da32491SDag-Erling Smørgrav 	union {
4698bc814e6SDag-Erling Smørgrav 		struct ptrace_io_desc piod;
470fbc3247dSMarcel Moolenaar 		struct ptrace_lwpinfo pl;
47190b4621aSMarcel Moolenaar 		struct ptrace_vm_entry pve;
4723da32491SDag-Erling Smørgrav 		struct dbreg dbreg;
4733da32491SDag-Erling Smørgrav 		struct fpreg fpreg;
47419610b66SBruce Evans 		struct reg reg;
475352aaa51SMark Johnston 		char args[sizeof(td->td_sa.args)];
47632451fb9SJohn Baldwin 		struct ptrace_sc_ret psr;
4778d570f64SJohn Baldwin 		int ptevents;
4783da32491SDag-Erling Smørgrav 	} r;
479012e544fSIan Dowse 	void *addr;
480012e544fSIan Dowse 	int error = 0;
481012e544fSIan Dowse 
48214961ba7SRobert Watson 	AUDIT_ARG_PID(uap->pid);
48314961ba7SRobert Watson 	AUDIT_ARG_CMD(uap->req);
48414961ba7SRobert Watson 	AUDIT_ARG_VALUE(uap->data);
485012e544fSIan Dowse 	addr = &r;
486012e544fSIan Dowse 	switch (uap->req) {
4878d570f64SJohn Baldwin 	case PT_GET_EVENT_MASK:
488fbc3247dSMarcel Moolenaar 	case PT_LWPINFO:
489b43ce76cSKonstantin Belousov 	case PT_GET_SC_ARGS:
49032451fb9SJohn Baldwin 	case PT_GET_SC_RET:
491012e544fSIan Dowse 		break;
492352aaa51SMark Johnston 	case PT_GETREGS:
49358b552dcSJohn Baldwin 		bzero(&r.reg, sizeof(r.reg));
494352aaa51SMark Johnston 		break;
495352aaa51SMark Johnston 	case PT_GETFPREGS:
49658b552dcSJohn Baldwin 		bzero(&r.fpreg, sizeof(r.fpreg));
497352aaa51SMark Johnston 		break;
498352aaa51SMark Johnston 	case PT_GETDBREGS:
49958b552dcSJohn Baldwin 		bzero(&r.dbreg, sizeof(r.dbreg));
500352aaa51SMark Johnston 		break;
501012e544fSIan Dowse 	case PT_SETREGS:
50258b552dcSJohn Baldwin 		error = copyin(uap->addr, &r.reg, sizeof(r.reg));
503012e544fSIan Dowse 		break;
504012e544fSIan Dowse 	case PT_SETFPREGS:
50558b552dcSJohn Baldwin 		error = copyin(uap->addr, &r.fpreg, sizeof(r.fpreg));
506012e544fSIan Dowse 		break;
507012e544fSIan Dowse 	case PT_SETDBREGS:
50858b552dcSJohn Baldwin 		error = copyin(uap->addr, &r.dbreg, sizeof(r.dbreg));
509012e544fSIan Dowse 		break;
5108d570f64SJohn Baldwin 	case PT_SET_EVENT_MASK:
5118d570f64SJohn Baldwin 		if (uap->data != sizeof(r.ptevents))
5128d570f64SJohn Baldwin 			error = EINVAL;
5138d570f64SJohn Baldwin 		else
5148d570f64SJohn Baldwin 			error = copyin(uap->addr, &r.ptevents, uap->data);
5158d570f64SJohn Baldwin 		break;
516012e544fSIan Dowse 	case PT_IO:
51758b552dcSJohn Baldwin 		error = copyin(uap->addr, &r.piod, sizeof(r.piod));
518012e544fSIan Dowse 		break;
51990b4621aSMarcel Moolenaar 	case PT_VM_ENTRY:
52058b552dcSJohn Baldwin 		error = copyin(uap->addr, &r.pve, sizeof(r.pve));
52190b4621aSMarcel Moolenaar 		break;
522012e544fSIan Dowse 	default:
523012e544fSIan Dowse 		addr = uap->addr;
5241c843354SMarcel Moolenaar 		break;
525012e544fSIan Dowse 	}
526012e544fSIan Dowse 	if (error)
527012e544fSIan Dowse 		return (error);
528012e544fSIan Dowse 
529012e544fSIan Dowse 	error = kern_ptrace(td, uap->req, uap->pid, addr, uap->data);
530012e544fSIan Dowse 	if (error)
531012e544fSIan Dowse 		return (error);
532012e544fSIan Dowse 
533012e544fSIan Dowse 	switch (uap->req) {
53490b4621aSMarcel Moolenaar 	case PT_VM_ENTRY:
53558b552dcSJohn Baldwin 		error = copyout(&r.pve, uap->addr, sizeof(r.pve));
53690b4621aSMarcel Moolenaar 		break;
537012e544fSIan Dowse 	case PT_IO:
53858b552dcSJohn Baldwin 		error = copyout(&r.piod, uap->addr, sizeof(r.piod));
539012e544fSIan Dowse 		break;
540012e544fSIan Dowse 	case PT_GETREGS:
54158b552dcSJohn Baldwin 		error = copyout(&r.reg, uap->addr, sizeof(r.reg));
542012e544fSIan Dowse 		break;
543012e544fSIan Dowse 	case PT_GETFPREGS:
54458b552dcSJohn Baldwin 		error = copyout(&r.fpreg, uap->addr, sizeof(r.fpreg));
545012e544fSIan Dowse 		break;
546012e544fSIan Dowse 	case PT_GETDBREGS:
54758b552dcSJohn Baldwin 		error = copyout(&r.dbreg, uap->addr, sizeof(r.dbreg));
548012e544fSIan Dowse 		break;
5498d570f64SJohn Baldwin 	case PT_GET_EVENT_MASK:
5508d570f64SJohn Baldwin 		/* NB: The size in uap->data is validated in kern_ptrace(). */
5518d570f64SJohn Baldwin 		error = copyout(&r.ptevents, uap->addr, uap->data);
5528d570f64SJohn Baldwin 		break;
553fbc3247dSMarcel Moolenaar 	case PT_LWPINFO:
5548d570f64SJohn Baldwin 		/* NB: The size in uap->data is validated in kern_ptrace(). */
555fbc3247dSMarcel Moolenaar 		error = copyout(&r.pl, uap->addr, uap->data);
556fbc3247dSMarcel Moolenaar 		break;
557b43ce76cSKonstantin Belousov 	case PT_GET_SC_ARGS:
558b43ce76cSKonstantin Belousov 		error = copyout(r.args, uap->addr, MIN(uap->data,
559b43ce76cSKonstantin Belousov 		    sizeof(r.args)));
560b43ce76cSKonstantin Belousov 		break;
56132451fb9SJohn Baldwin 	case PT_GET_SC_RET:
56232451fb9SJohn Baldwin 		error = copyout(&r.psr, uap->addr, MIN(uap->data,
56332451fb9SJohn Baldwin 		    sizeof(r.psr)));
56432451fb9SJohn Baldwin 		break;
565012e544fSIan Dowse 	}
566012e544fSIan Dowse 
567012e544fSIan Dowse 	return (error);
568012e544fSIan Dowse }
56962919d78SPeter Wemm 
570841c0c7eSNathan Whitehorn #ifdef COMPAT_FREEBSD32
57162919d78SPeter Wemm /*
57262919d78SPeter Wemm  *   PROC_READ(regs, td2, addr);
57362919d78SPeter Wemm  * becomes either:
57462919d78SPeter Wemm  *   proc_read_regs(td2, addr);
57562919d78SPeter Wemm  * or
57662919d78SPeter Wemm  *   proc_read_regs32(td2, addr);
57762919d78SPeter Wemm  * .. except this is done at runtime.  There is an additional
57862919d78SPeter Wemm  * complication in that PROC_WRITE disallows 32 bit consumers
57962919d78SPeter Wemm  * from writing to 64 bit address space targets.
58062919d78SPeter Wemm  */
58162919d78SPeter Wemm #define	PROC_READ(w, t, a)	wrap32 ? \
58262919d78SPeter Wemm 	proc_read_ ## w ## 32(t, a) : \
58362919d78SPeter Wemm 	proc_read_ ## w (t, a)
58462919d78SPeter Wemm #define	PROC_WRITE(w, t, a)	wrap32 ? \
58562919d78SPeter Wemm 	(safe ? proc_write_ ## w ## 32(t, a) : EINVAL ) : \
58662919d78SPeter Wemm 	proc_write_ ## w (t, a)
58762919d78SPeter Wemm #else
58862919d78SPeter Wemm #define	PROC_READ(w, t, a)	proc_read_ ## w (t, a)
58962919d78SPeter Wemm #define	PROC_WRITE(w, t, a)	proc_write_ ## w (t, a)
59062919d78SPeter Wemm #endif
591012e544fSIan Dowse 
592b7a25e63SKonstantin Belousov void
593e5574e09SMark Johnston proc_set_traced(struct proc *p, bool stop)
594b7a25e63SKonstantin Belousov {
595b7a25e63SKonstantin Belousov 
596ac4bc0c1SKonstantin Belousov 	sx_assert(&proctree_lock, SX_XLOCKED);
597b7a25e63SKonstantin Belousov 	PROC_LOCK_ASSERT(p, MA_OWNED);
598b7a25e63SKonstantin Belousov 	p->p_flag |= P_TRACED;
599e5574e09SMark Johnston 	if (stop)
600b7a25e63SKonstantin Belousov 		p->p_flag2 |= P2_PTRACE_FSTP;
601b7a25e63SKonstantin Belousov 	p->p_ptevents = PTRACE_DEFAULT;
602b7a25e63SKonstantin Belousov }
603b7a25e63SKonstantin Belousov 
604012e544fSIan Dowse int
605012e544fSIan Dowse kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
606012e544fSIan Dowse {
607012e544fSIan Dowse 	struct iovec iov;
608012e544fSIan Dowse 	struct uio uio;
60946e12b42SAlfred Perlstein 	struct proc *curp, *p, *pp;
6105985d615SDavid Xu 	struct thread *td2 = NULL, *td3;
61162919d78SPeter Wemm 	struct ptrace_io_desc *piod = NULL;
612fbc3247dSMarcel Moolenaar 	struct ptrace_lwpinfo *pl;
61332451fb9SJohn Baldwin 	struct ptrace_sc_ret *psr;
614711fbd17SMark Johnston 	int error, num, tmp;
6156871a6c8SJohn Baldwin 	int proctree_locked = 0;
616ef9457beSDavid Xu 	lwpid_t tid = 0, *buf;
617841c0c7eSNathan Whitehorn #ifdef COMPAT_FREEBSD32
61862919d78SPeter Wemm 	int wrap32 = 0, safe = 0;
61962919d78SPeter Wemm #endif
6204e68ceabSDavid Greenman 
62146e12b42SAlfred Perlstein 	curp = td->td_proc;
62246e12b42SAlfred Perlstein 
623012e544fSIan Dowse 	/* Lock proctree before locking the process. */
624012e544fSIan Dowse 	switch (req) {
6256871a6c8SJohn Baldwin 	case PT_TRACE_ME:
6266871a6c8SJohn Baldwin 	case PT_ATTACH:
6276871a6c8SJohn Baldwin 	case PT_STEP:
6286871a6c8SJohn Baldwin 	case PT_CONTINUE:
629ea924c4cSRobert Drehmel 	case PT_TO_SCE:
630ea924c4cSRobert Drehmel 	case PT_TO_SCX:
631f7fdcd45SDavid Schultz 	case PT_SYSCALL:
6326fa39a73SKonstantin Belousov 	case PT_FOLLOW_FORK:
6335fcfab6eSJohn Baldwin 	case PT_LWP_EVENTS:
6348d570f64SJohn Baldwin 	case PT_GET_EVENT_MASK:
6358d570f64SJohn Baldwin 	case PT_SET_EVENT_MASK:
6366871a6c8SJohn Baldwin 	case PT_DETACH:
637b43ce76cSKonstantin Belousov 	case PT_GET_SC_ARGS:
6386871a6c8SJohn Baldwin 		sx_xlock(&proctree_lock);
6396871a6c8SJohn Baldwin 		proctree_locked = 1;
6406871a6c8SJohn Baldwin 		break;
6416871a6c8SJohn Baldwin 	default:
6429daa5b14SMarcel Moolenaar 		break;
6436871a6c8SJohn Baldwin 	}
6446871a6c8SJohn Baldwin 
645012e544fSIan Dowse 	if (req == PT_TRACE_ME) {
6466871a6c8SJohn Baldwin 		p = td->td_proc;
64733a9ed9dSJohn Baldwin 		PROC_LOCK(p);
64833a9ed9dSJohn Baldwin 	} else {
649f3b929bfSDavid Xu 		if (pid <= PID_MAX) {
650012e544fSIan Dowse 			if ((p = pfind(pid)) == NULL) {
6516871a6c8SJohn Baldwin 				if (proctree_locked)
6526871a6c8SJohn Baldwin 					sx_xunlock(&proctree_lock);
653c5799337SDag-Erling Smørgrav 				return (ESRCH);
6544e68ceabSDavid Greenman 			}
655f3b929bfSDavid Xu 		} else {
656cf7d9a8cSDavid Xu 			td2 = tdfind(pid, -1);
657cf7d9a8cSDavid Xu 			if (td2 == NULL) {
658f3b929bfSDavid Xu 				if (proctree_locked)
659f3b929bfSDavid Xu 					sx_xunlock(&proctree_lock);
660f3b929bfSDavid Xu 				return (ESRCH);
661f3b929bfSDavid Xu 			}
662cf7d9a8cSDavid Xu 			p = td2->td_proc;
663f3b929bfSDavid Xu 			tid = pid;
664f3b929bfSDavid Xu 			pid = p->p_pid;
665f3b929bfSDavid Xu 		}
66633a9ed9dSJohn Baldwin 	}
66714961ba7SRobert Watson 	AUDIT_ARG_PROCESS(p);
66806ad42b2SJohn Baldwin 
66906ad42b2SJohn Baldwin 	if ((p->p_flag & P_WEXIT) != 0) {
67006ad42b2SJohn Baldwin 		error = ESRCH;
67106ad42b2SJohn Baldwin 		goto fail;
67206ad42b2SJohn Baldwin 	}
6734f18efe2SRobert Watson 	if ((error = p_cansee(td, p)) != 0)
6746871a6c8SJohn Baldwin 		goto fail;
6753da32491SDag-Erling Smørgrav 
676f44d9e24SJohn Baldwin 	if ((error = p_candebug(td, p)) != 0)
6776871a6c8SJohn Baldwin 		goto fail;
6786871a6c8SJohn Baldwin 
6793da32491SDag-Erling Smørgrav 	/*
68019610b66SBruce Evans 	 * System processes can't be debugged.
6813da32491SDag-Erling Smørgrav 	 */
6823da32491SDag-Erling Smørgrav 	if ((p->p_flag & P_SYSTEM) != 0) {
6836871a6c8SJohn Baldwin 		error = EINVAL;
6846871a6c8SJohn Baldwin 		goto fail;
6853da32491SDag-Erling Smørgrav 	}
6863da32491SDag-Erling Smørgrav 
687f3b929bfSDavid Xu 	if (tid == 0) {
688d7bc12b0SDavid Xu 		if ((p->p_flag & P_STOPPED_TRACE) != 0) {
689d7bc12b0SDavid Xu 			KASSERT(p->p_xthread != NULL, ("NULL p_xthread"));
690d7bc12b0SDavid Xu 			td2 = p->p_xthread;
691d7bc12b0SDavid Xu 		} else {
692f3b929bfSDavid Xu 			td2 = FIRST_THREAD_IN_PROC(p);
693d7bc12b0SDavid Xu 		}
694f3b929bfSDavid Xu 		tid = td2->td_tid;
695f3b929bfSDavid Xu 	}
696f3b929bfSDavid Xu 
697841c0c7eSNathan Whitehorn #ifdef COMPAT_FREEBSD32
69862919d78SPeter Wemm 	/*
69962919d78SPeter Wemm 	 * Test if we're a 32 bit client and what the target is.
70062919d78SPeter Wemm 	 * Set the wrap controls accordingly.
70162919d78SPeter Wemm 	 */
7022883703eSKonstantin Belousov 	if (SV_CURPROC_FLAG(SV_ILP32)) {
703a5c1afadSDmitry Chagin 		if (SV_PROC_FLAG(td2->td_proc, SV_ILP32))
70462919d78SPeter Wemm 			safe = 1;
70562919d78SPeter Wemm 		wrap32 = 1;
70662919d78SPeter Wemm 	}
70762919d78SPeter Wemm #endif
708b0281cefSPeter Wemm 	/*
709b0281cefSPeter Wemm 	 * Permissions check
710b0281cefSPeter Wemm 	 */
711012e544fSIan Dowse 	switch (req) {
712b0281cefSPeter Wemm 	case PT_TRACE_ME:
71377b9bec3SKonstantin Belousov 		/*
71477b9bec3SKonstantin Belousov 		 * Always legal, when there is a parent process which
71577b9bec3SKonstantin Belousov 		 * could trace us.  Otherwise, reject.
71677b9bec3SKonstantin Belousov 		 */
71777b9bec3SKonstantin Belousov 		if ((p->p_flag & P_TRACED) != 0) {
71877b9bec3SKonstantin Belousov 			error = EBUSY;
71977b9bec3SKonstantin Belousov 			goto fail;
72077b9bec3SKonstantin Belousov 		}
72177b9bec3SKonstantin Belousov 		if (p->p_pptr == initproc) {
72277b9bec3SKonstantin Belousov 			error = EPERM;
72377b9bec3SKonstantin Belousov 			goto fail;
72477b9bec3SKonstantin Belousov 		}
725b0281cefSPeter Wemm 		break;
7264e68ceabSDavid Greenman 
727b0281cefSPeter Wemm 	case PT_ATTACH:
728b0281cefSPeter Wemm 		/* Self */
7291ed2e49bSKonstantin Belousov 		if (p == td->td_proc) {
7306871a6c8SJohn Baldwin 			error = EINVAL;
7316871a6c8SJohn Baldwin 			goto fail;
73233a9ed9dSJohn Baldwin 		}
733b0281cefSPeter Wemm 
734b0281cefSPeter Wemm 		/* Already traced */
735731a1aeaSJohn Baldwin 		if (p->p_flag & P_TRACED) {
7366871a6c8SJohn Baldwin 			error = EBUSY;
7376871a6c8SJohn Baldwin 			goto fail;
738731a1aeaSJohn Baldwin 		}
739b0281cefSPeter Wemm 
74046e12b42SAlfred Perlstein 		/* Can't trace an ancestor if you're being traced. */
74146e12b42SAlfred Perlstein 		if (curp->p_flag & P_TRACED) {
74246e12b42SAlfred Perlstein 			for (pp = curp->p_pptr; pp != NULL; pp = pp->p_pptr) {
74346e12b42SAlfred Perlstein 				if (pp == p) {
74446e12b42SAlfred Perlstein 					error = EINVAL;
74546e12b42SAlfred Perlstein 					goto fail;
74646e12b42SAlfred Perlstein 				}
74746e12b42SAlfred Perlstein 			}
74846e12b42SAlfred Perlstein 		}
74946e12b42SAlfred Perlstein 
750b0281cefSPeter Wemm 		/* OK */
751b0281cefSPeter Wemm 		break;
752b0281cefSPeter Wemm 
753ef9457beSDavid Xu 	case PT_CLEARSTEP:
754ef9457beSDavid Xu 		/* Allow thread to clear single step for itself */
755ef9457beSDavid Xu 		if (td->td_tid == tid)
756ef9457beSDavid Xu 			break;
757ef9457beSDavid Xu 
758ef9457beSDavid Xu 		/* FALLTHROUGH */
7591c843354SMarcel Moolenaar 	default:
760b0281cefSPeter Wemm 		/* not being traced... */
761731a1aeaSJohn Baldwin 		if ((p->p_flag & P_TRACED) == 0) {
7626871a6c8SJohn Baldwin 			error = EPERM;
7636871a6c8SJohn Baldwin 			goto fail;
764731a1aeaSJohn Baldwin 		}
765b0281cefSPeter Wemm 
766b0281cefSPeter Wemm 		/* not being traced by YOU */
7676871a6c8SJohn Baldwin 		if (p->p_pptr != td->td_proc) {
7686871a6c8SJohn Baldwin 			error = EBUSY;
7696871a6c8SJohn Baldwin 			goto fail;
77098f03f90SJake Burkholder 		}
771b0281cefSPeter Wemm 
772b0281cefSPeter Wemm 		/* not currently stopped */
773feeaec18SJohn Baldwin 		if ((p->p_flag & P_STOPPED_TRACE) == 0 ||
774d7bc12b0SDavid Xu 		    p->p_suspcount != p->p_numthreads  ||
775ef9457beSDavid Xu 		    (p->p_flag & P_WAITED) == 0) {
7766871a6c8SJohn Baldwin 			error = EBUSY;
7776871a6c8SJohn Baldwin 			goto fail;
7780ebabc93SJohn Baldwin 		}
779b0281cefSPeter Wemm 
780b0281cefSPeter Wemm 		/* OK */
781b0281cefSPeter Wemm 		break;
7824e68ceabSDavid Greenman 	}
783b0281cefSPeter Wemm 
78406ad42b2SJohn Baldwin 	/* Keep this process around until we finish this request. */
78506ad42b2SJohn Baldwin 	_PHOLD(p);
78606ad42b2SJohn Baldwin 
787b0281cefSPeter Wemm #ifdef FIX_SSTEP
788df8bae1dSRodney W. Grimes 	/*
789b0281cefSPeter Wemm 	 * Single step fixup ala procfs
790b0281cefSPeter Wemm 	 */
79106ad42b2SJohn Baldwin 	FIX_SSTEP(td2);
792b0281cefSPeter Wemm #endif
793b0281cefSPeter Wemm 
794b0281cefSPeter Wemm 	/*
795b0281cefSPeter Wemm 	 * Actually do the requests
796df8bae1dSRodney W. Grimes 	 */
7974e68ceabSDavid Greenman 
798b40ce416SJulian Elischer 	td->td_retval[0] = 0;
7994e68ceabSDavid Greenman 
800012e544fSIan Dowse 	switch (req) {
801b0281cefSPeter Wemm 	case PT_TRACE_ME:
802b0281cefSPeter Wemm 		/* set my trace flag and "owner" so it can read/write me */
803e5574e09SMark Johnston 		proc_set_traced(p, false);
804888d4d4fSKonstantin Belousov 		if (p->p_flag & P_PPWAIT)
805888d4d4fSKonstantin Belousov 			p->p_flag |= P_PPTRACE;
806515b7a0bSJohn Baldwin 		CTR1(KTR_PTRACE, "PT_TRACE_ME: pid %d", p->p_pid);
80706ad42b2SJohn Baldwin 		break;
8084e68ceabSDavid Greenman 
809b0281cefSPeter Wemm 	case PT_ATTACH:
810b0281cefSPeter Wemm 		/* security check done above */
81152e95a64SDavid E. O'Brien 		/*
81252e95a64SDavid E. O'Brien 		 * It would be nice if the tracing relationship was separate
81352e95a64SDavid E. O'Brien 		 * from the parent relationship but that would require
81452e95a64SDavid E. O'Brien 		 * another set of links in the proc struct or for "wait"
81552e95a64SDavid E. O'Brien 		 * to scan the entire proc table.  To make life easier,
81652e95a64SDavid E. O'Brien 		 * we just re-parent the process we're trying to trace.
81752e95a64SDavid E. O'Brien 		 * The old parent is remembered so we can put things back
81852e95a64SDavid E. O'Brien 		 * on a "detach".
81952e95a64SDavid E. O'Brien 		 */
820e5574e09SMark Johnston 		proc_set_traced(p, true);
8212c054ce9SMateusz Guzik 		proc_reparent(p, td->td_proc, false);
822515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_ATTACH: pid %d, oppid %d", p->p_pid,
823515b7a0bSJohn Baldwin 		    p->p_oppid);
8242a2b23caSJohn Baldwin 
8252a2b23caSJohn Baldwin 		sx_xunlock(&proctree_lock);
8262a2b23caSJohn Baldwin 		proctree_locked = 0;
8272a2b23caSJohn Baldwin 		MPASS(p->p_xthread == NULL);
8282a2b23caSJohn Baldwin 		MPASS((p->p_flag & P_STOPPED_TRACE) == 0);
8292a2b23caSJohn Baldwin 
8302a2b23caSJohn Baldwin 		/*
8312a2b23caSJohn Baldwin 		 * If already stopped due to a stop signal, clear the
8322a2b23caSJohn Baldwin 		 * existing stop before triggering a traced SIGSTOP.
8332a2b23caSJohn Baldwin 		 */
8342a2b23caSJohn Baldwin 		if ((p->p_flag & P_STOPPED_SIG) != 0) {
8352a2b23caSJohn Baldwin 			PROC_SLOCK(p);
8362a2b23caSJohn Baldwin 			p->p_flag &= ~(P_STOPPED_SIG | P_WAITED);
8372a2b23caSJohn Baldwin 			thread_unsuspend(p);
8382a2b23caSJohn Baldwin 			PROC_SUNLOCK(p);
8392a2b23caSJohn Baldwin 		}
8402a2b23caSJohn Baldwin 
8412a2b23caSJohn Baldwin 		kern_psignal(p, SIGSTOP);
8422a2b23caSJohn Baldwin 		break;
843b0281cefSPeter Wemm 
844ef9457beSDavid Xu 	case PT_CLEARSTEP:
845515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_CLEARSTEP: tid %d (pid %d)", td2->td_tid,
846515b7a0bSJohn Baldwin 		    p->p_pid);
847ef9457beSDavid Xu 		error = ptrace_clear_single_step(td2);
84806ad42b2SJohn Baldwin 		break;
849ef9457beSDavid Xu 
850ef9457beSDavid Xu 	case PT_SETSTEP:
851515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_SETSTEP: tid %d (pid %d)", td2->td_tid,
852515b7a0bSJohn Baldwin 		    p->p_pid);
853ef9457beSDavid Xu 		error = ptrace_single_step(td2);
85406ad42b2SJohn Baldwin 		break;
855ef9457beSDavid Xu 
856ef9457beSDavid Xu 	case PT_SUSPEND:
857515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_SUSPEND: tid %d (pid %d)", td2->td_tid,
858515b7a0bSJohn Baldwin 		    p->p_pid);
859904c5ec4SDavid Xu 		td2->td_dbgflags |= TDB_SUSPEND;
860982d11f8SJeff Roberson 		thread_lock(td2);
861904c5ec4SDavid Xu 		td2->td_flags |= TDF_NEEDSUSPCHK;
862982d11f8SJeff Roberson 		thread_unlock(td2);
86306ad42b2SJohn Baldwin 		break;
864ef9457beSDavid Xu 
865ef9457beSDavid Xu 	case PT_RESUME:
866515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_RESUME: tid %d (pid %d)", td2->td_tid,
867515b7a0bSJohn Baldwin 		    p->p_pid);
868904c5ec4SDavid Xu 		td2->td_dbgflags &= ~TDB_SUSPEND;
86906ad42b2SJohn Baldwin 		break;
870ef9457beSDavid Xu 
8716fa39a73SKonstantin Belousov 	case PT_FOLLOW_FORK:
872515b7a0bSJohn Baldwin 		CTR3(KTR_PTRACE, "PT_FOLLOW_FORK: pid %d %s -> %s", p->p_pid,
8738d570f64SJohn Baldwin 		    p->p_ptevents & PTRACE_FORK ? "enabled" : "disabled",
874515b7a0bSJohn Baldwin 		    data ? "enabled" : "disabled");
8756fa39a73SKonstantin Belousov 		if (data)
8768d570f64SJohn Baldwin 			p->p_ptevents |= PTRACE_FORK;
8776fa39a73SKonstantin Belousov 		else
8788d570f64SJohn Baldwin 			p->p_ptevents &= ~PTRACE_FORK;
8796fa39a73SKonstantin Belousov 		break;
8806fa39a73SKonstantin Belousov 
8815fcfab6eSJohn Baldwin 	case PT_LWP_EVENTS:
8825fcfab6eSJohn Baldwin 		CTR3(KTR_PTRACE, "PT_LWP_EVENTS: pid %d %s -> %s", p->p_pid,
8838d570f64SJohn Baldwin 		    p->p_ptevents & PTRACE_LWP ? "enabled" : "disabled",
8845fcfab6eSJohn Baldwin 		    data ? "enabled" : "disabled");
8855fcfab6eSJohn Baldwin 		if (data)
8868d570f64SJohn Baldwin 			p->p_ptevents |= PTRACE_LWP;
8875fcfab6eSJohn Baldwin 		else
8888d570f64SJohn Baldwin 			p->p_ptevents &= ~PTRACE_LWP;
8898d570f64SJohn Baldwin 		break;
8908d570f64SJohn Baldwin 
8918d570f64SJohn Baldwin 	case PT_GET_EVENT_MASK:
8928d570f64SJohn Baldwin 		if (data != sizeof(p->p_ptevents)) {
8938d570f64SJohn Baldwin 			error = EINVAL;
8948d570f64SJohn Baldwin 			break;
8958d570f64SJohn Baldwin 		}
8968d570f64SJohn Baldwin 		CTR2(KTR_PTRACE, "PT_GET_EVENT_MASK: pid %d mask %#x", p->p_pid,
8978d570f64SJohn Baldwin 		    p->p_ptevents);
8988d570f64SJohn Baldwin 		*(int *)addr = p->p_ptevents;
8998d570f64SJohn Baldwin 		break;
9008d570f64SJohn Baldwin 
9018d570f64SJohn Baldwin 	case PT_SET_EVENT_MASK:
9028d570f64SJohn Baldwin 		if (data != sizeof(p->p_ptevents)) {
9038d570f64SJohn Baldwin 			error = EINVAL;
9048d570f64SJohn Baldwin 			break;
9058d570f64SJohn Baldwin 		}
9068d570f64SJohn Baldwin 		tmp = *(int *)addr;
9078d570f64SJohn Baldwin 		if ((tmp & ~(PTRACE_EXEC | PTRACE_SCE | PTRACE_SCX |
908fc4f075aSJohn Baldwin 		    PTRACE_FORK | PTRACE_LWP | PTRACE_VFORK)) != 0) {
9098d570f64SJohn Baldwin 			error = EINVAL;
9108d570f64SJohn Baldwin 			break;
9118d570f64SJohn Baldwin 		}
9128d570f64SJohn Baldwin 		CTR3(KTR_PTRACE, "PT_SET_EVENT_MASK: pid %d mask %#x -> %#x",
9138d570f64SJohn Baldwin 		    p->p_pid, p->p_ptevents, tmp);
9148d570f64SJohn Baldwin 		p->p_ptevents = tmp;
9155fcfab6eSJohn Baldwin 		break;
9165fcfab6eSJohn Baldwin 
917b43ce76cSKonstantin Belousov 	case PT_GET_SC_ARGS:
918b43ce76cSKonstantin Belousov 		CTR1(KTR_PTRACE, "PT_GET_SC_ARGS: pid %d", p->p_pid);
919b43ce76cSKonstantin Belousov 		if ((td2->td_dbgflags & (TDB_SCE | TDB_SCX)) == 0
920b43ce76cSKonstantin Belousov #ifdef COMPAT_FREEBSD32
921b43ce76cSKonstantin Belousov 		    || (wrap32 && !safe)
922b43ce76cSKonstantin Belousov #endif
923b43ce76cSKonstantin Belousov 		    ) {
924b43ce76cSKonstantin Belousov 			error = EINVAL;
925b43ce76cSKonstantin Belousov 			break;
926b43ce76cSKonstantin Belousov 		}
927b43ce76cSKonstantin Belousov 		bzero(addr, sizeof(td2->td_sa.args));
928b43ce76cSKonstantin Belousov 		bcopy(td2->td_sa.args, addr, td2->td_sa.narg *
929b43ce76cSKonstantin Belousov 		    sizeof(register_t));
930b43ce76cSKonstantin Belousov 		break;
931b43ce76cSKonstantin Belousov 
93232451fb9SJohn Baldwin 	case PT_GET_SC_RET:
93332451fb9SJohn Baldwin 		if ((td2->td_dbgflags & (TDB_SCX)) == 0
93432451fb9SJohn Baldwin #ifdef COMPAT_FREEBSD32
93532451fb9SJohn Baldwin 		    || (wrap32 && !safe)
93632451fb9SJohn Baldwin #endif
93732451fb9SJohn Baldwin 		    ) {
93832451fb9SJohn Baldwin 			error = EINVAL;
93932451fb9SJohn Baldwin 			break;
94032451fb9SJohn Baldwin 		}
94132451fb9SJohn Baldwin 		psr = addr;
94232451fb9SJohn Baldwin 		bzero(psr, sizeof(*psr));
94332451fb9SJohn Baldwin 		psr->sr_error = td2->td_errno;
94432451fb9SJohn Baldwin 		if (psr->sr_error == 0) {
94532451fb9SJohn Baldwin 			psr->sr_retval[0] = td2->td_retval[0];
94632451fb9SJohn Baldwin 			psr->sr_retval[1] = td2->td_retval[1];
94732451fb9SJohn Baldwin 		}
94832451fb9SJohn Baldwin 		CTR4(KTR_PTRACE,
94932451fb9SJohn Baldwin 		    "PT_GET_SC_RET: pid %d error %d retval %#lx,%#lx",
95032451fb9SJohn Baldwin 		    p->p_pid, psr->sr_error, psr->sr_retval[0],
95132451fb9SJohn Baldwin 		    psr->sr_retval[1]);
95232451fb9SJohn Baldwin 		break;
95332451fb9SJohn Baldwin 
954b0281cefSPeter Wemm 	case PT_STEP:
955b0281cefSPeter Wemm 	case PT_CONTINUE:
956ea924c4cSRobert Drehmel 	case PT_TO_SCE:
957ea924c4cSRobert Drehmel 	case PT_TO_SCX:
958f7fdcd45SDavid Schultz 	case PT_SYSCALL:
9594e68ceabSDavid Greenman 	case PT_DETACH:
960007e25d9SJacques Vidrine 		/* Zero means do not send any signal */
961007e25d9SJacques Vidrine 		if (data < 0 || data > _SIG_MAXSIG) {
9626871a6c8SJohn Baldwin 			error = EINVAL;
96306ad42b2SJohn Baldwin 			break;
9646871a6c8SJohn Baldwin 		}
965b0281cefSPeter Wemm 
966ea924c4cSRobert Drehmel 		switch (req) {
967ea924c4cSRobert Drehmel 		case PT_STEP:
96809f3bb87SJohn Baldwin 			CTR3(KTR_PTRACE, "PT_STEP: tid %d (pid %d), sig = %d",
96909f3bb87SJohn Baldwin 			    td2->td_tid, p->p_pid, data);
970fe0d0493SPeter Wemm 			error = ptrace_single_step(td2);
97106ad42b2SJohn Baldwin 			if (error)
97206ad42b2SJohn Baldwin 				goto out;
973ea924c4cSRobert Drehmel 			break;
9740bfbf4d2SJohn Baldwin 		case PT_CONTINUE:
9750bfbf4d2SJohn Baldwin 		case PT_TO_SCE:
9760bfbf4d2SJohn Baldwin 		case PT_TO_SCX:
9770bfbf4d2SJohn Baldwin 		case PT_SYSCALL:
9780bfbf4d2SJohn Baldwin 			if (addr != (void *)1) {
9790bfbf4d2SJohn Baldwin 				error = ptrace_set_pc(td2,
9800bfbf4d2SJohn Baldwin 				    (u_long)(uintfptr_t)addr);
9810bfbf4d2SJohn Baldwin 				if (error)
9820bfbf4d2SJohn Baldwin 					goto out;
9830bfbf4d2SJohn Baldwin 			}
9840bfbf4d2SJohn Baldwin 			switch (req) {
985ea924c4cSRobert Drehmel 			case PT_TO_SCE:
9868d570f64SJohn Baldwin 				p->p_ptevents |= PTRACE_SCE;
9873edd0fffSJohn Baldwin 				CTR4(KTR_PTRACE,
9888d570f64SJohn Baldwin 		    "PT_TO_SCE: pid %d, events = %#x, PC = %#lx, sig = %d",
9898d570f64SJohn Baldwin 				    p->p_pid, p->p_ptevents,
9903edd0fffSJohn Baldwin 				    (u_long)(uintfptr_t)addr, data);
991ea924c4cSRobert Drehmel 				break;
992ea924c4cSRobert Drehmel 			case PT_TO_SCX:
9938d570f64SJohn Baldwin 				p->p_ptevents |= PTRACE_SCX;
9943edd0fffSJohn Baldwin 				CTR4(KTR_PTRACE,
9958d570f64SJohn Baldwin 		    "PT_TO_SCX: pid %d, events = %#x, PC = %#lx, sig = %d",
9968d570f64SJohn Baldwin 				    p->p_pid, p->p_ptevents,
9973edd0fffSJohn Baldwin 				    (u_long)(uintfptr_t)addr, data);
998ea924c4cSRobert Drehmel 				break;
999ea924c4cSRobert Drehmel 			case PT_SYSCALL:
10008d570f64SJohn Baldwin 				p->p_ptevents |= PTRACE_SYSCALL;
10013edd0fffSJohn Baldwin 				CTR4(KTR_PTRACE,
10028d570f64SJohn Baldwin 		    "PT_SYSCALL: pid %d, events = %#x, PC = %#lx, sig = %d",
10038d570f64SJohn Baldwin 				    p->p_pid, p->p_ptevents,
10043edd0fffSJohn Baldwin 				    (u_long)(uintfptr_t)addr, data);
1005515b7a0bSJohn Baldwin 				break;
1006515b7a0bSJohn Baldwin 			case PT_CONTINUE:
10073edd0fffSJohn Baldwin 				CTR3(KTR_PTRACE,
10083edd0fffSJohn Baldwin 				    "PT_CONTINUE: pid %d, PC = %#lx, sig = %d",
10093edd0fffSJohn Baldwin 				    p->p_pid, (u_long)(uintfptr_t)addr, data);
1010ea924c4cSRobert Drehmel 				break;
1011b0281cefSPeter Wemm 			}
101206ad42b2SJohn Baldwin 			break;
10130bfbf4d2SJohn Baldwin 		case PT_DETACH:
101498685dc8SJohn Baldwin 			/*
101598685dc8SJohn Baldwin 			 * Reset the process parent.
101698685dc8SJohn Baldwin 			 *
101798685dc8SJohn Baldwin 			 * NB: This clears P_TRACED before reparenting
101898685dc8SJohn Baldwin 			 * a detached process back to its original
101998685dc8SJohn Baldwin 			 * parent.  Otherwise the debugee will be set
102098685dc8SJohn Baldwin 			 * as an orphan of the debugger.
102198685dc8SJohn Baldwin 			 */
10228d570f64SJohn Baldwin 			p->p_flag &= ~(P_TRACED | P_WAITED);
1023b0281cefSPeter Wemm 			if (p->p_oppid != p->p_pptr->p_pid) {
1024c20cedbfSDavid Xu 				PROC_LOCK(p->p_pptr);
1025c20cedbfSDavid Xu 				sigqueue_take(p->p_ksi);
1026c20cedbfSDavid Xu 				PROC_UNLOCK(p->p_pptr);
1027c20cedbfSDavid Xu 
1028d7359980SKonstantin Belousov 				pp = proc_realparent(p);
10292c054ce9SMateusz Guzik 				proc_reparent(p, pp, false);
1030cf93aa16SDon Lewis 				if (pp == initproc)
103155b5f2a2SDon Lewis 					p->p_sigparent = SIGCHLD;
10323edd0fffSJohn Baldwin 				CTR3(KTR_PTRACE,
10333edd0fffSJohn Baldwin 			    "PT_DETACH: pid %d reparented to pid %d, sig %d",
10343edd0fffSJohn Baldwin 				    p->p_pid, pp->p_pid, data);
1035515b7a0bSJohn Baldwin 			} else
10363edd0fffSJohn Baldwin 				CTR2(KTR_PTRACE, "PT_DETACH: pid %d, sig %d",
10373edd0fffSJohn Baldwin 				    p->p_pid, data);
10388d570f64SJohn Baldwin 			p->p_ptevents = 0;
1039b7a25e63SKonstantin Belousov 			FOREACH_THREAD_IN_PROC(p, td3) {
1040b7a25e63SKonstantin Belousov 				if ((td3->td_dbgflags & TDB_FSTP) != 0) {
1041b7a25e63SKonstantin Belousov 					sigqueue_delete(&td3->td_sigqueue,
1042b7a25e63SKonstantin Belousov 					    SIGSTOP);
1043b7a25e63SKonstantin Belousov 				}
10447e3e3606SJohn Baldwin 				td3->td_dbgflags &= ~(TDB_XSIG | TDB_FSTP |
10457e3e3606SJohn Baldwin 				    TDB_SUSPEND);
1046b7a25e63SKonstantin Belousov 			}
10477e3e3606SJohn Baldwin 
1048b7a25e63SKonstantin Belousov 			if ((p->p_flag2 & P2_PTRACE_FSTP) != 0) {
1049b7a25e63SKonstantin Belousov 				sigqueue_delete(&p->p_sigqueue, SIGSTOP);
1050b7a25e63SKonstantin Belousov 				p->p_flag2 &= ~P2_PTRACE_FSTP;
1051b7a25e63SKonstantin Belousov 			}
1052731a1aeaSJohn Baldwin 
1053b0281cefSPeter Wemm 			/* should we send SIGCHLD? */
1054c20cedbfSDavid Xu 			/* childproc_continued(p); */
10550bfbf4d2SJohn Baldwin 			break;
1056b0281cefSPeter Wemm 		}
1057b0281cefSPeter Wemm 
1058feeaec18SJohn Baldwin 		sx_xunlock(&proctree_lock);
1059feeaec18SJohn Baldwin 		proctree_locked = 0;
10602a2b23caSJohn Baldwin 
10612a2b23caSJohn Baldwin 	sendsig:
10622a2b23caSJohn Baldwin 		MPASS(proctree_locked == 0);
1063feeaec18SJohn Baldwin 
1064e012fe34SJohn Baldwin 		/*
1065e012fe34SJohn Baldwin 		 * Clear the pending event for the thread that just
1066e012fe34SJohn Baldwin 		 * reported its event (p_xthread).  This may not be
1067e012fe34SJohn Baldwin 		 * the thread passed to PT_CONTINUE, PT_STEP, etc. if
1068e012fe34SJohn Baldwin 		 * the debugger is resuming a different thread.
1069feeaec18SJohn Baldwin 		 *
1070feeaec18SJohn Baldwin 		 * Deliver any pending signal via the reporting thread.
1071e012fe34SJohn Baldwin 		 */
1072feeaec18SJohn Baldwin 		MPASS(p->p_xthread != NULL);
1073feeaec18SJohn Baldwin 		p->p_xthread->td_dbgflags &= ~TDB_XSIG;
1074feeaec18SJohn Baldwin 		p->p_xthread->td_xsig = data;
10758753688fSJeff Roberson 		p->p_xthread = NULL;
1076feeaec18SJohn Baldwin 		p->p_xsig = data;
10778753688fSJeff Roberson 
107882a4538fSEric Badger 		/*
10792a2b23caSJohn Baldwin 		 * P_WKILLED is insurance that a PT_KILL/SIGKILL
10802a2b23caSJohn Baldwin 		 * always works immediately, even if another thread is
10812a2b23caSJohn Baldwin 		 * unsuspended first and attempts to handle a
10822a2b23caSJohn Baldwin 		 * different signal or if the POSIX.1b style signal
10832a2b23caSJohn Baldwin 		 * queue cannot accommodate any new signals.
108482a4538fSEric Badger 		 */
108582a4538fSEric Badger 		if (data == SIGKILL)
1086a70e9a13SKonstantin Belousov 			proc_wkilled(p);
108782a4538fSEric Badger 
1088ef9457beSDavid Xu 		/*
1089feeaec18SJohn Baldwin 		 * Unsuspend all threads.  To leave a thread
10902a2b23caSJohn Baldwin 		 * suspended, use PT_SUSPEND to suspend it before
10912a2b23caSJohn Baldwin 		 * continuing the process.
1092ef9457beSDavid Xu 		 */
10937b4a950aSDavid Xu 		PROC_SLOCK(p);
1094d7bc12b0SDavid Xu 		p->p_flag &= ~(P_STOPPED_TRACE | P_STOPPED_SIG | P_WAITED);
10958c6d7a8dSDavid Xu 		thread_unsuspend(p);
10967b4a950aSDavid Xu 		PROC_SUNLOCK(p);
109706ad42b2SJohn Baldwin 		break;
10984e68ceabSDavid Greenman 
10994e68ceabSDavid Greenman 	case PT_WRITE_I:
11004e68ceabSDavid Greenman 	case PT_WRITE_D:
11015b1162b9SKonstantin Belousov 		td2->td_dbgflags |= TDB_USERWR;
1102711fbd17SMark Johnston 		PROC_UNLOCK(p);
1103711fbd17SMark Johnston 		error = 0;
1104711fbd17SMark Johnston 		if (proc_writemem(td, p, (off_t)(uintptr_t)addr, &data,
1105711fbd17SMark Johnston 		    sizeof(int)) != sizeof(int))
1106711fbd17SMark Johnston 			error = ENOMEM;
1107711fbd17SMark Johnston 		else
1108711fbd17SMark Johnston 			CTR3(KTR_PTRACE, "PT_WRITE: pid %d: %p <= %#x",
1109711fbd17SMark Johnston 			    p->p_pid, addr, data);
1110711fbd17SMark Johnston 		PROC_LOCK(p);
1111711fbd17SMark Johnston 		break;
1112711fbd17SMark Johnston 
1113b0281cefSPeter Wemm 	case PT_READ_I:
1114b0281cefSPeter Wemm 	case PT_READ_D:
11156871a6c8SJohn Baldwin 		PROC_UNLOCK(p);
1116711fbd17SMark Johnston 		error = tmp = 0;
1117711fbd17SMark Johnston 		if (proc_readmem(td, p, (off_t)(uintptr_t)addr, &tmp,
1118711fbd17SMark Johnston 		    sizeof(int)) != sizeof(int))
1119711fbd17SMark Johnston 			error = ENOMEM;
1120515b7a0bSJohn Baldwin 		else
1121515b7a0bSJohn Baldwin 			CTR3(KTR_PTRACE, "PT_READ: pid %d: %p >= %#x",
1122515b7a0bSJohn Baldwin 			    p->p_pid, addr, tmp);
1123711fbd17SMark Johnston 		td->td_retval[0] = tmp;
112406ad42b2SJohn Baldwin 		PROC_LOCK(p);
112506ad42b2SJohn Baldwin 		break;
11264e68ceabSDavid Greenman 
11278bc814e6SDag-Erling Smørgrav 	case PT_IO:
1128012e544fSIan Dowse 		piod = addr;
1129012e544fSIan Dowse 		iov.iov_base = piod->piod_addr;
1130012e544fSIan Dowse 		iov.iov_len = piod->piod_len;
1131012e544fSIan Dowse 		uio.uio_offset = (off_t)(uintptr_t)piod->piod_offs;
1132012e544fSIan Dowse 		uio.uio_resid = piod->piod_len;
113362919d78SPeter Wemm 		uio.uio_iov = &iov;
113462919d78SPeter Wemm 		uio.uio_iovcnt = 1;
11358bc814e6SDag-Erling Smørgrav 		uio.uio_segflg = UIO_USERSPACE;
11368bc814e6SDag-Erling Smørgrav 		uio.uio_td = td;
113758b552dcSJohn Baldwin 		switch (piod->piod_op) {
11388bc814e6SDag-Erling Smørgrav 		case PIOD_READ_D:
11398bc814e6SDag-Erling Smørgrav 		case PIOD_READ_I:
1140515b7a0bSJohn Baldwin 			CTR3(KTR_PTRACE, "PT_IO: pid %d: READ (%p, %#x)",
1141515b7a0bSJohn Baldwin 			    p->p_pid, (uintptr_t)uio.uio_offset, uio.uio_resid);
11428bc814e6SDag-Erling Smørgrav 			uio.uio_rw = UIO_READ;
11438bc814e6SDag-Erling Smørgrav 			break;
11448bc814e6SDag-Erling Smørgrav 		case PIOD_WRITE_D:
11458bc814e6SDag-Erling Smørgrav 		case PIOD_WRITE_I:
1146515b7a0bSJohn Baldwin 			CTR3(KTR_PTRACE, "PT_IO: pid %d: WRITE (%p, %#x)",
1147515b7a0bSJohn Baldwin 			    p->p_pid, (uintptr_t)uio.uio_offset, uio.uio_resid);
11485b1162b9SKonstantin Belousov 			td2->td_dbgflags |= TDB_USERWR;
11498bc814e6SDag-Erling Smørgrav 			uio.uio_rw = UIO_WRITE;
11508bc814e6SDag-Erling Smørgrav 			break;
11518bc814e6SDag-Erling Smørgrav 		default:
115206ad42b2SJohn Baldwin 			error = EINVAL;
115306ad42b2SJohn Baldwin 			goto out;
11548bc814e6SDag-Erling Smørgrav 		}
115506ad42b2SJohn Baldwin 		PROC_UNLOCK(p);
11568bc814e6SDag-Erling Smørgrav 		error = proc_rwmem(p, &uio);
1157012e544fSIan Dowse 		piod->piod_len -= uio.uio_resid;
115806ad42b2SJohn Baldwin 		PROC_LOCK(p);
115906ad42b2SJohn Baldwin 		break;
11608bc814e6SDag-Erling Smørgrav 
11614e68ceabSDavid Greenman 	case PT_KILL:
1162515b7a0bSJohn Baldwin 		CTR1(KTR_PTRACE, "PT_KILL: pid %d", p->p_pid);
1163012e544fSIan Dowse 		data = SIGKILL;
1164b0281cefSPeter Wemm 		goto sendsig;	/* in PT_CONTINUE above */
1165b0281cefSPeter Wemm 
1166b0281cefSPeter Wemm 	case PT_SETREGS:
1167515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_SETREGS: tid %d (pid %d)", td2->td_tid,
1168515b7a0bSJohn Baldwin 		    p->p_pid);
11695b1162b9SKonstantin Belousov 		td2->td_dbgflags |= TDB_USERWR;
117062919d78SPeter Wemm 		error = PROC_WRITE(regs, td2, addr);
117106ad42b2SJohn Baldwin 		break;
11723da32491SDag-Erling Smørgrav 
11734e68ceabSDavid Greenman 	case PT_GETREGS:
1174515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_GETREGS: tid %d (pid %d)", td2->td_tid,
1175515b7a0bSJohn Baldwin 		    p->p_pid);
117662919d78SPeter Wemm 		error = PROC_READ(regs, td2, addr);
117706ad42b2SJohn Baldwin 		break;
1178b0281cefSPeter Wemm 
1179b0281cefSPeter Wemm 	case PT_SETFPREGS:
1180515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_SETFPREGS: tid %d (pid %d)", td2->td_tid,
1181515b7a0bSJohn Baldwin 		    p->p_pid);
11825b1162b9SKonstantin Belousov 		td2->td_dbgflags |= TDB_USERWR;
118362919d78SPeter Wemm 		error = PROC_WRITE(fpregs, td2, addr);
118406ad42b2SJohn Baldwin 		break;
11853da32491SDag-Erling Smørgrav 
1186b0281cefSPeter Wemm 	case PT_GETFPREGS:
1187515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_GETFPREGS: tid %d (pid %d)", td2->td_tid,
1188515b7a0bSJohn Baldwin 		    p->p_pid);
118962919d78SPeter Wemm 		error = PROC_READ(fpregs, td2, addr);
119006ad42b2SJohn Baldwin 		break;
1191b0281cefSPeter Wemm 
1192ab001a72SJonathan Lemon 	case PT_SETDBREGS:
1193515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_SETDBREGS: tid %d (pid %d)", td2->td_tid,
1194515b7a0bSJohn Baldwin 		    p->p_pid);
11955b1162b9SKonstantin Belousov 		td2->td_dbgflags |= TDB_USERWR;
119662919d78SPeter Wemm 		error = PROC_WRITE(dbregs, td2, addr);
119706ad42b2SJohn Baldwin 		break;
11983da32491SDag-Erling Smørgrav 
1199ab001a72SJonathan Lemon 	case PT_GETDBREGS:
1200515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_GETDBREGS: tid %d (pid %d)", td2->td_tid,
1201515b7a0bSJohn Baldwin 		    p->p_pid);
120262919d78SPeter Wemm 		error = PROC_READ(dbregs, td2, addr);
120306ad42b2SJohn Baldwin 		break;
1204ab001a72SJonathan Lemon 
1205fbc3247dSMarcel Moolenaar 	case PT_LWPINFO:
120658b552dcSJohn Baldwin 		if (data <= 0 || data > sizeof(*pl)) {
120706ad42b2SJohn Baldwin 			error = EINVAL;
120806ad42b2SJohn Baldwin 			break;
120906ad42b2SJohn Baldwin 		}
1210fbc3247dSMarcel Moolenaar 		pl = addr;
12119acf7b13SKonstantin Belousov 		bzero(pl, sizeof(*pl));
1212ef9457beSDavid Xu 		pl->pl_lwpid = td2->td_tid;
1213c0c6e95fSKonstantin Belousov 		pl->pl_event = PL_EVENT_NONE;
12141f2eac6cSDavid Xu 		pl->pl_flags = 0;
12158a260079SKonstantin Belousov 		if (td2->td_dbgflags & TDB_XSIG) {
12168a260079SKonstantin Belousov 			pl->pl_event = PL_EVENT_SIGNAL;
121786be94fcSTycho Nightingale 			if (td2->td_si.si_signo != 0 &&
12188a260079SKonstantin Belousov 			    data >= offsetof(struct ptrace_lwpinfo, pl_siginfo)
121958b552dcSJohn Baldwin 			    + sizeof(pl->pl_siginfo)){
12208a260079SKonstantin Belousov 				pl->pl_flags |= PL_FLAG_SI;
122186be94fcSTycho Nightingale 				pl->pl_siginfo = td2->td_si;
12228a260079SKonstantin Belousov 			}
12238a260079SKonstantin Belousov 		}
1224afe1a688SKonstantin Belousov 		if (td2->td_dbgflags & TDB_SCE)
1225afe1a688SKonstantin Belousov 			pl->pl_flags |= PL_FLAG_SCE;
1226afe1a688SKonstantin Belousov 		else if (td2->td_dbgflags & TDB_SCX)
1227afe1a688SKonstantin Belousov 			pl->pl_flags |= PL_FLAG_SCX;
1228afe1a688SKonstantin Belousov 		if (td2->td_dbgflags & TDB_EXEC)
1229afe1a688SKonstantin Belousov 			pl->pl_flags |= PL_FLAG_EXEC;
12306fa39a73SKonstantin Belousov 		if (td2->td_dbgflags & TDB_FORK) {
12316fa39a73SKonstantin Belousov 			pl->pl_flags |= PL_FLAG_FORKED;
12326fa39a73SKonstantin Belousov 			pl->pl_child_pid = td2->td_dbg_forked;
1233fc4f075aSJohn Baldwin 			if (td2->td_dbgflags & TDB_VFORK)
1234fc4f075aSJohn Baldwin 				pl->pl_flags |= PL_FLAG_VFORKED;
1235fc4f075aSJohn Baldwin 		} else if ((td2->td_dbgflags & (TDB_SCX | TDB_VFORK)) ==
1236fc4f075aSJohn Baldwin 		    TDB_VFORK)
1237fc4f075aSJohn Baldwin 			pl->pl_flags |= PL_FLAG_VFORK_DONE;
1238db327339SKonstantin Belousov 		if (td2->td_dbgflags & TDB_CHILD)
1239db327339SKonstantin Belousov 			pl->pl_flags |= PL_FLAG_CHILD;
12405fcfab6eSJohn Baldwin 		if (td2->td_dbgflags & TDB_BORN)
12415fcfab6eSJohn Baldwin 			pl->pl_flags |= PL_FLAG_BORN;
12425fcfab6eSJohn Baldwin 		if (td2->td_dbgflags & TDB_EXIT)
12435fcfab6eSJohn Baldwin 			pl->pl_flags |= PL_FLAG_EXITED;
1244ea8e65b0SDavid Xu 		pl->pl_sigmask = td2->td_sigmask;
1245ea8e65b0SDavid Xu 		pl->pl_siglist = td2->td_siglist;
12467f08176eSAttilio Rao 		strcpy(pl->pl_tdname, td2->td_name);
1247183b68f7SJohn Baldwin 		if ((td2->td_dbgflags & (TDB_SCE | TDB_SCX)) != 0) {
12482d88da2fSKonstantin Belousov 			pl->pl_syscall_code = td2->td_sa.code;
12492d88da2fSKonstantin Belousov 			pl->pl_syscall_narg = td2->td_sa.narg;
1250183b68f7SJohn Baldwin 		} else {
1251183b68f7SJohn Baldwin 			pl->pl_syscall_code = 0;
1252183b68f7SJohn Baldwin 			pl->pl_syscall_narg = 0;
1253183b68f7SJohn Baldwin 		}
12543edd0fffSJohn Baldwin 		CTR6(KTR_PTRACE,
12553edd0fffSJohn Baldwin     "PT_LWPINFO: tid %d (pid %d) event %d flags %#x child pid %d syscall %d",
1256515b7a0bSJohn Baldwin 		    td2->td_tid, p->p_pid, pl->pl_event, pl->pl_flags,
12573edd0fffSJohn Baldwin 		    pl->pl_child_pid, pl->pl_syscall_code);
125806ad42b2SJohn Baldwin 		break;
1259fbc3247dSMarcel Moolenaar 
1260ef9457beSDavid Xu 	case PT_GETNUMLWPS:
1261515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_GETNUMLWPS: pid %d: %d threads", p->p_pid,
1262515b7a0bSJohn Baldwin 		    p->p_numthreads);
1263ef9457beSDavid Xu 		td->td_retval[0] = p->p_numthreads;
126406ad42b2SJohn Baldwin 		break;
1265ef9457beSDavid Xu 
1266ef9457beSDavid Xu 	case PT_GETLWPLIST:
1267515b7a0bSJohn Baldwin 		CTR3(KTR_PTRACE, "PT_GETLWPLIST: pid %d: data %d, actual %d",
1268515b7a0bSJohn Baldwin 		    p->p_pid, data, p->p_numthreads);
1269ef9457beSDavid Xu 		if (data <= 0) {
127006ad42b2SJohn Baldwin 			error = EINVAL;
127106ad42b2SJohn Baldwin 			break;
1272ef9457beSDavid Xu 		}
1273ef9457beSDavid Xu 		num = imin(p->p_numthreads, data);
1274ef9457beSDavid Xu 		PROC_UNLOCK(p);
1275ef9457beSDavid Xu 		buf = malloc(num * sizeof(lwpid_t), M_TEMP, M_WAITOK);
1276ef9457beSDavid Xu 		tmp = 0;
1277ef9457beSDavid Xu 		PROC_LOCK(p);
1278ef9457beSDavid Xu 		FOREACH_THREAD_IN_PROC(p, td2) {
1279ef9457beSDavid Xu 			if (tmp >= num)
1280ef9457beSDavid Xu 				break;
1281ef9457beSDavid Xu 			buf[tmp++] = td2->td_tid;
1282ef9457beSDavid Xu 		}
1283ef9457beSDavid Xu 		PROC_UNLOCK(p);
1284ef9457beSDavid Xu 		error = copyout(buf, addr, tmp * sizeof(lwpid_t));
1285ef9457beSDavid Xu 		free(buf, M_TEMP);
1286ef9457beSDavid Xu 		if (!error)
1287f51bf07aSTom Rhodes 			td->td_retval[0] = tmp;
128806ad42b2SJohn Baldwin 		PROC_LOCK(p);
128906ad42b2SJohn Baldwin 		break;
1290ef9457beSDavid Xu 
129190b4621aSMarcel Moolenaar 	case PT_VM_TIMESTAMP:
1292515b7a0bSJohn Baldwin 		CTR2(KTR_PTRACE, "PT_VM_TIMESTAMP: pid %d: timestamp %d",
1293515b7a0bSJohn Baldwin 		    p->p_pid, p->p_vmspace->vm_map.timestamp);
129490b4621aSMarcel Moolenaar 		td->td_retval[0] = p->p_vmspace->vm_map.timestamp;
129590b4621aSMarcel Moolenaar 		break;
129690b4621aSMarcel Moolenaar 
129790b4621aSMarcel Moolenaar 	case PT_VM_ENTRY:
129890b4621aSMarcel Moolenaar 		PROC_UNLOCK(p);
129990b4621aSMarcel Moolenaar 		error = ptrace_vm_entry(td, p, addr);
130090b4621aSMarcel Moolenaar 		PROC_LOCK(p);
130190b4621aSMarcel Moolenaar 		break;
130290b4621aSMarcel Moolenaar 
13034e68ceabSDavid Greenman 	default:
13041c843354SMarcel Moolenaar #ifdef __HAVE_PTRACE_MACHDEP
13051c843354SMarcel Moolenaar 		if (req >= PT_FIRSTMACH) {
13061c843354SMarcel Moolenaar 			PROC_UNLOCK(p);
13078ac61436SJohn Baldwin 			error = cpu_ptrace(td2, req, addr, data);
130806ad42b2SJohn Baldwin 			PROC_LOCK(p);
130906ad42b2SJohn Baldwin 		} else
13101c843354SMarcel Moolenaar #endif
131106ad42b2SJohn Baldwin 			/* Unknown request. */
131206ad42b2SJohn Baldwin 			error = EINVAL;
13134e68ceabSDavid Greenman 		break;
13144e68ceabSDavid Greenman 	}
13154e68ceabSDavid Greenman 
131606ad42b2SJohn Baldwin out:
131706ad42b2SJohn Baldwin 	/* Drop our hold on this process now that the request has completed. */
131806ad42b2SJohn Baldwin 	_PRELE(p);
13196871a6c8SJohn Baldwin fail:
13206871a6c8SJohn Baldwin 	PROC_UNLOCK(p);
13216871a6c8SJohn Baldwin 	if (proctree_locked)
13226871a6c8SJohn Baldwin 		sx_xunlock(&proctree_lock);
13236871a6c8SJohn Baldwin 	return (error);
1324df8bae1dSRodney W. Grimes }
132562919d78SPeter Wemm #undef PROC_READ
132662919d78SPeter Wemm #undef PROC_WRITE
1327