xref: /freebsd/lib/libproc/proc_util.c (revision a2f733abcff64628b7771a47089628b7327a88bd)
12c633af4SJohn Birrell /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni  *
48eb20f36SRui Paulo  * Copyright (c) 2010 The FreeBSD Foundation
52c633af4SJohn Birrell  * Copyright (c) 2008 John Birrell (jb@freebsd.org)
62c633af4SJohn Birrell  * All rights reserved.
72c633af4SJohn Birrell  *
88eb20f36SRui Paulo  * Portions of this software were developed by Rui Paulo under sponsorship
98eb20f36SRui Paulo  * from the FreeBSD Foundation.
108eb20f36SRui Paulo  *
112c633af4SJohn Birrell  * Redistribution and use in source and binary forms, with or without
122c633af4SJohn Birrell  * modification, are permitted provided that the following conditions
132c633af4SJohn Birrell  * are met:
142c633af4SJohn Birrell  * 1. Redistributions of source code must retain the above copyright
152c633af4SJohn Birrell  *    notice, this list of conditions and the following disclaimer.
162c633af4SJohn Birrell  * 2. Redistributions in binary form must reproduce the above copyright
172c633af4SJohn Birrell  *    notice, this list of conditions and the following disclaimer in the
182c633af4SJohn Birrell  *    documentation and/or other materials provided with the distribution.
192c633af4SJohn Birrell  *
202c633af4SJohn Birrell  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
212c633af4SJohn Birrell  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
222c633af4SJohn Birrell  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
232c633af4SJohn Birrell  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
242c633af4SJohn Birrell  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
252c633af4SJohn Birrell  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
262c633af4SJohn Birrell  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
272c633af4SJohn Birrell  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
282c633af4SJohn Birrell  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
292c633af4SJohn Birrell  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
302c633af4SJohn Birrell  * SUCH DAMAGE.
312c633af4SJohn Birrell  */
322c633af4SJohn Birrell 
338eb20f36SRui Paulo #include <sys/types.h>
342c633af4SJohn Birrell #include <sys/ptrace.h>
352c633af4SJohn Birrell #include <sys/wait.h>
36fcf9fc10SMark Johnston 
378eb20f36SRui Paulo #include <err.h>
388eb20f36SRui Paulo #include <errno.h>
398eb20f36SRui Paulo #include <signal.h>
408eb20f36SRui Paulo #include <string.h>
4192f92525SMark Johnston #include <unistd.h>
42fcf9fc10SMark Johnston 
438eb20f36SRui Paulo #include "_libproc.h"
442c633af4SJohn Birrell 
452c633af4SJohn Birrell int
proc_clearflags(struct proc_handle * phdl,int mask)462c633af4SJohn Birrell proc_clearflags(struct proc_handle *phdl, int mask)
472c633af4SJohn Birrell {
488eb20f36SRui Paulo 
492c633af4SJohn Birrell 	if (phdl == NULL)
502c633af4SJohn Birrell 		return (EINVAL);
512c633af4SJohn Birrell 
522c633af4SJohn Birrell 	phdl->flags &= ~mask;
532c633af4SJohn Birrell 
542c633af4SJohn Birrell 	return (0);
552c633af4SJohn Birrell }
562c633af4SJohn Birrell 
578eb20f36SRui Paulo /*
588eb20f36SRui Paulo  * NB: we return -1 as the Solaris libproc Psetrun() function.
598eb20f36SRui Paulo  */
602c633af4SJohn Birrell int
proc_continue(struct proc_handle * phdl)612c633af4SJohn Birrell proc_continue(struct proc_handle *phdl)
622c633af4SJohn Birrell {
63fcf9fc10SMark Johnston 	int pending;
648eb20f36SRui Paulo 
652c633af4SJohn Birrell 	if (phdl == NULL)
668eb20f36SRui Paulo 		return (-1);
672c633af4SJohn Birrell 
6892f92525SMark Johnston 	if (phdl->status == PS_STOP && WSTOPSIG(phdl->wstat) != SIGTRAP)
6992f92525SMark Johnston 		pending = WSTOPSIG(phdl->wstat);
70fcf9fc10SMark Johnston 	else
71fcf9fc10SMark Johnston 		pending = 0;
72b1bb30e5SMark Johnston 	if (ptrace(PT_CONTINUE, proc_getpid(phdl), (caddr_t)(uintptr_t)1,
73b1bb30e5SMark Johnston 	    pending) != 0)
748eb20f36SRui Paulo 		return (-1);
752c633af4SJohn Birrell 
762c633af4SJohn Birrell 	phdl->status = PS_RUN;
772c633af4SJohn Birrell 
782c633af4SJohn Birrell 	return (0);
792c633af4SJohn Birrell }
802c633af4SJohn Birrell 
812c633af4SJohn Birrell int
proc_detach(struct proc_handle * phdl,int reason)828eb20f36SRui Paulo proc_detach(struct proc_handle *phdl, int reason)
832c633af4SJohn Birrell {
848eb20f36SRui Paulo 	int status;
85*be1dd8e6SEric van Gyzen 	int request;
86b1bb30e5SMark Johnston 	pid_t pid;
878eb20f36SRui Paulo 
882c633af4SJohn Birrell 	if (phdl == NULL)
892c633af4SJohn Birrell 		return (EINVAL);
90b043b5dcSMark Johnston 	if (reason == PRELEASE_HANG)
91b043b5dcSMark Johnston 		return (EINVAL);
92b043b5dcSMark Johnston 	if ((phdl->flags & PATTACH_RDONLY) != 0)
93b043b5dcSMark Johnston 		goto free;
94*be1dd8e6SEric van Gyzen 	request = (reason == PRELEASE_KILL) ? PT_KILL : PT_DETACH;
95b1bb30e5SMark Johnston 	pid = proc_getpid(phdl);
96*be1dd8e6SEric van Gyzen 	if (ptrace(request, pid, 0, 0) != 0 && errno == EBUSY) {
97b1bb30e5SMark Johnston 		kill(pid, SIGSTOP);
98b1bb30e5SMark Johnston 		waitpid(pid, &status, WUNTRACED);
99*be1dd8e6SEric van Gyzen 		ptrace(request, pid, 0, 0);
100b1bb30e5SMark Johnston 		kill(pid, SIGCONT);
1018eb20f36SRui Paulo 	}
102b043b5dcSMark Johnston free:
103b043b5dcSMark Johnston 	proc_free(phdl);
1042c633af4SJohn Birrell 	return (0);
1052c633af4SJohn Birrell }
1062c633af4SJohn Birrell 
1072c633af4SJohn Birrell int
proc_getflags(struct proc_handle * phdl)1082c633af4SJohn Birrell proc_getflags(struct proc_handle *phdl)
1092c633af4SJohn Birrell {
1108eb20f36SRui Paulo 
1112c633af4SJohn Birrell 	if (phdl == NULL)
1122c633af4SJohn Birrell 		return (-1);
1132c633af4SJohn Birrell 
1142c633af4SJohn Birrell 	return (phdl->flags);
1152c633af4SJohn Birrell }
1162c633af4SJohn Birrell 
1172c633af4SJohn Birrell int
proc_setflags(struct proc_handle * phdl,int mask)1182c633af4SJohn Birrell proc_setflags(struct proc_handle *phdl, int mask)
1192c633af4SJohn Birrell {
1208eb20f36SRui Paulo 
1212c633af4SJohn Birrell 	if (phdl == NULL)
1222c633af4SJohn Birrell 		return (EINVAL);
1232c633af4SJohn Birrell 
1242c633af4SJohn Birrell 	phdl->flags |= mask;
1252c633af4SJohn Birrell 
1262c633af4SJohn Birrell 	return (0);
1272c633af4SJohn Birrell }
1282c633af4SJohn Birrell 
1292c633af4SJohn Birrell int
proc_state(struct proc_handle * phdl)1302c633af4SJohn Birrell proc_state(struct proc_handle *phdl)
1312c633af4SJohn Birrell {
1328eb20f36SRui Paulo 
1332c633af4SJohn Birrell 	if (phdl == NULL)
1342c633af4SJohn Birrell 		return (-1);
1352c633af4SJohn Birrell 
1362c633af4SJohn Birrell 	return (phdl->status);
1372c633af4SJohn Birrell }
1382c633af4SJohn Birrell 
1398eb20f36SRui Paulo int
proc_getmodel(struct proc_handle * phdl)1404808a678SMark Johnston proc_getmodel(struct proc_handle *phdl)
1414808a678SMark Johnston {
1424808a678SMark Johnston 
1434808a678SMark Johnston 	if (phdl == NULL)
1444808a678SMark Johnston 		return (-1);
1454808a678SMark Johnston 
1464808a678SMark Johnston 	return (phdl->model);
1474808a678SMark Johnston }
1484808a678SMark Johnston 
1494808a678SMark Johnston int
proc_wstatus(struct proc_handle * phdl)1508eb20f36SRui Paulo proc_wstatus(struct proc_handle *phdl)
1518eb20f36SRui Paulo {
1528eb20f36SRui Paulo 	int status;
1538eb20f36SRui Paulo 
1548eb20f36SRui Paulo 	if (phdl == NULL)
1558eb20f36SRui Paulo 		return (-1);
156b1bb30e5SMark Johnston 	if (waitpid(proc_getpid(phdl), &status, WUNTRACED) < 0) {
157fb15925cSMark Johnston 		if (errno != EINTR)
15830e81f7eSMark Johnston 			DPRINTF("waitpid");
1598eb20f36SRui Paulo 		return (-1);
1604c74b245SRui Paulo 	}
1618eb20f36SRui Paulo 	if (WIFSTOPPED(status))
1628eb20f36SRui Paulo 		phdl->status = PS_STOP;
1638eb20f36SRui Paulo 	if (WIFEXITED(status) || WIFSIGNALED(status))
1648eb20f36SRui Paulo 		phdl->status = PS_UNDEAD;
1658eb20f36SRui Paulo 	phdl->wstat = status;
1668eb20f36SRui Paulo 
1674c74b245SRui Paulo 	return (phdl->status);
1688eb20f36SRui Paulo }
1698eb20f36SRui Paulo 
1708eb20f36SRui Paulo int
proc_getwstat(struct proc_handle * phdl)1718eb20f36SRui Paulo proc_getwstat(struct proc_handle *phdl)
1728eb20f36SRui Paulo {
1738eb20f36SRui Paulo 
1748eb20f36SRui Paulo 	if (phdl == NULL)
1758eb20f36SRui Paulo 		return (-1);
1768eb20f36SRui Paulo 
1778eb20f36SRui Paulo 	return (phdl->wstat);
1788eb20f36SRui Paulo }
1798eb20f36SRui Paulo 
1808eb20f36SRui Paulo char *
proc_signame(int sig,char * name,size_t namesz)1818eb20f36SRui Paulo proc_signame(int sig, char *name, size_t namesz)
1828eb20f36SRui Paulo {
1838eb20f36SRui Paulo 
1848eb20f36SRui Paulo 	strlcpy(name, strsignal(sig), namesz);
1858eb20f36SRui Paulo 
1868eb20f36SRui Paulo 	return (name);
1878eb20f36SRui Paulo }
1888eb20f36SRui Paulo 
1898eb20f36SRui Paulo int
proc_read(struct proc_handle * phdl,void * buf,size_t size,size_t addr)1904c74b245SRui Paulo proc_read(struct proc_handle *phdl, void *buf, size_t size, size_t addr)
1918eb20f36SRui Paulo {
1928eb20f36SRui Paulo 	struct ptrace_io_desc piod;
1938eb20f36SRui Paulo 
1948eb20f36SRui Paulo 	if (phdl == NULL)
1958eb20f36SRui Paulo 		return (-1);
1968eb20f36SRui Paulo 	piod.piod_op = PIOD_READ_D;
1978eb20f36SRui Paulo 	piod.piod_len = size;
1988eb20f36SRui Paulo 	piod.piod_addr = (void *)buf;
1998eb20f36SRui Paulo 	piod.piod_offs = (void *)addr;
2008eb20f36SRui Paulo 
201b1bb30e5SMark Johnston 	if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0)
2028eb20f36SRui Paulo 		return (-1);
2038eb20f36SRui Paulo 	return (piod.piod_len);
2048eb20f36SRui Paulo }
2058eb20f36SRui Paulo 
2068eb20f36SRui Paulo const lwpstatus_t *
proc_getlwpstatus(struct proc_handle * phdl)2078eb20f36SRui Paulo proc_getlwpstatus(struct proc_handle *phdl)
2088eb20f36SRui Paulo {
2098eb20f36SRui Paulo 	struct ptrace_lwpinfo lwpinfo;
2108eb20f36SRui Paulo 	lwpstatus_t *psp = &phdl->lwps;
2118eb20f36SRui Paulo 	siginfo_t *siginfo;
2128eb20f36SRui Paulo 
2138eb20f36SRui Paulo 	if (phdl == NULL)
2148eb20f36SRui Paulo 		return (NULL);
215b1bb30e5SMark Johnston 	if (ptrace(PT_LWPINFO, proc_getpid(phdl), (caddr_t)&lwpinfo,
2164c74b245SRui Paulo 	    sizeof(lwpinfo)) < 0)
2178eb20f36SRui Paulo 		return (NULL);
2188eb20f36SRui Paulo 	siginfo = &lwpinfo.pl_siginfo;
2198eb20f36SRui Paulo 	if (lwpinfo.pl_event == PL_EVENT_SIGNAL &&
22092f92525SMark Johnston 	    (lwpinfo.pl_flags & PL_FLAG_SI) != 0) {
22192f92525SMark Johnston 		if (siginfo->si_signo == SIGTRAP &&
2228eb20f36SRui Paulo 		    (siginfo->si_code == TRAP_BRKPT ||
2238eb20f36SRui Paulo 		    siginfo->si_code == TRAP_TRACE)) {
2248eb20f36SRui Paulo 			psp->pr_why = PR_FAULTED;
2258eb20f36SRui Paulo 			psp->pr_what = FLTBPT;
22692f92525SMark Johnston 		} else {
22792f92525SMark Johnston 			psp->pr_why = PR_SIGNALLED;
22892f92525SMark Johnston 			psp->pr_what = siginfo->si_signo;
22992f92525SMark Johnston 		}
2308eb20f36SRui Paulo 	} else if (lwpinfo.pl_flags & PL_FLAG_SCE) {
2318eb20f36SRui Paulo 		psp->pr_why = PR_SYSENTRY;
2328eb20f36SRui Paulo 	} else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
2338eb20f36SRui Paulo 		psp->pr_why = PR_SYSEXIT;
2348eb20f36SRui Paulo 	}
2358eb20f36SRui Paulo 
2368eb20f36SRui Paulo 	return (psp);
2378eb20f36SRui Paulo }
238