xref: /freebsd/lib/libproc/proc_util.c (revision fcf9fc109edfef9d3bbd6f03bd796ac728cb9258)
12c633af4SJohn Birrell /*-
28eb20f36SRui Paulo  * Copyright (c) 2010 The FreeBSD Foundation
32c633af4SJohn Birrell  * Copyright (c) 2008 John Birrell (jb@freebsd.org)
42c633af4SJohn Birrell  * All rights reserved.
52c633af4SJohn Birrell  *
68eb20f36SRui Paulo  * Portions of this software were developed by Rui Paulo under sponsorship
78eb20f36SRui Paulo  * from the FreeBSD Foundation.
88eb20f36SRui Paulo  *
92c633af4SJohn Birrell  * Redistribution and use in source and binary forms, with or without
102c633af4SJohn Birrell  * modification, are permitted provided that the following conditions
112c633af4SJohn Birrell  * are met:
122c633af4SJohn Birrell  * 1. Redistributions of source code must retain the above copyright
132c633af4SJohn Birrell  *    notice, this list of conditions and the following disclaimer.
142c633af4SJohn Birrell  * 2. Redistributions in binary form must reproduce the above copyright
152c633af4SJohn Birrell  *    notice, this list of conditions and the following disclaimer in the
162c633af4SJohn Birrell  *    documentation and/or other materials provided with the distribution.
172c633af4SJohn Birrell  *
182c633af4SJohn Birrell  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
192c633af4SJohn Birrell  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
202c633af4SJohn Birrell  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
212c633af4SJohn Birrell  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
222c633af4SJohn Birrell  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
232c633af4SJohn Birrell  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
242c633af4SJohn Birrell  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
252c633af4SJohn Birrell  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
262c633af4SJohn Birrell  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
272c633af4SJohn Birrell  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
282c633af4SJohn Birrell  * SUCH DAMAGE.
292c633af4SJohn Birrell  */
302c633af4SJohn Birrell 
31*fcf9fc10SMark Johnston #include <sys/cdefs.h>
32*fcf9fc10SMark Johnston __FBSDID("$FreeBSD$");
33*fcf9fc10SMark Johnston 
348eb20f36SRui Paulo #include <sys/types.h>
352c633af4SJohn Birrell #include <sys/ptrace.h>
362c633af4SJohn Birrell #include <sys/wait.h>
37*fcf9fc10SMark Johnston 
388eb20f36SRui Paulo #include <err.h>
398eb20f36SRui Paulo #include <errno.h>
408eb20f36SRui Paulo #include <signal.h>
418eb20f36SRui Paulo #include <string.h>
4292f92525SMark Johnston #include <unistd.h>
43*fcf9fc10SMark Johnston 
448eb20f36SRui Paulo #include "_libproc.h"
452c633af4SJohn Birrell 
462c633af4SJohn Birrell int
472c633af4SJohn Birrell proc_clearflags(struct proc_handle *phdl, int mask)
482c633af4SJohn Birrell {
498eb20f36SRui Paulo 
502c633af4SJohn Birrell 	if (phdl == NULL)
512c633af4SJohn Birrell 		return (EINVAL);
522c633af4SJohn Birrell 
532c633af4SJohn Birrell 	phdl->flags &= ~mask;
542c633af4SJohn Birrell 
552c633af4SJohn Birrell 	return (0);
562c633af4SJohn Birrell }
572c633af4SJohn Birrell 
588eb20f36SRui Paulo /*
598eb20f36SRui Paulo  * NB: we return -1 as the Solaris libproc Psetrun() function.
608eb20f36SRui Paulo  */
612c633af4SJohn Birrell int
622c633af4SJohn Birrell proc_continue(struct proc_handle *phdl)
632c633af4SJohn Birrell {
64*fcf9fc10SMark Johnston 	int pending;
658eb20f36SRui Paulo 
662c633af4SJohn Birrell 	if (phdl == NULL)
678eb20f36SRui Paulo 		return (-1);
682c633af4SJohn Birrell 
6992f92525SMark Johnston 	if (phdl->status == PS_STOP && WSTOPSIG(phdl->wstat) != SIGTRAP)
7092f92525SMark Johnston 		pending = WSTOPSIG(phdl->wstat);
71*fcf9fc10SMark Johnston 	else
72*fcf9fc10SMark Johnston 		pending = 0;
7392f92525SMark Johnston 	if (ptrace(PT_CONTINUE, phdl->pid, (caddr_t)(uintptr_t)1, 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
828eb20f36SRui Paulo proc_detach(struct proc_handle *phdl, int reason)
832c633af4SJohn Birrell {
848eb20f36SRui Paulo 	int status;
858eb20f36SRui Paulo 
862c633af4SJohn Birrell 	if (phdl == NULL)
872c633af4SJohn Birrell 		return (EINVAL);
888eb20f36SRui Paulo 	if (reason == PRELEASE_KILL) {
898eb20f36SRui Paulo 		kill(phdl->pid, SIGKILL);
908eb20f36SRui Paulo 		return (0);
918eb20f36SRui Paulo 	}
928eb20f36SRui Paulo 	if (ptrace(PT_DETACH, phdl->pid, 0, 0) != 0 && errno == ESRCH)
938eb20f36SRui Paulo 		return (0);
948eb20f36SRui Paulo 	if (errno == EBUSY) {
958eb20f36SRui Paulo 		kill(phdl->pid, SIGSTOP);
968eb20f36SRui Paulo 		waitpid(phdl->pid, &status, WUNTRACED);
978eb20f36SRui Paulo 		ptrace(PT_DETACH, phdl->pid, 0, 0);
988eb20f36SRui Paulo 		kill(phdl->pid, SIGCONT);
998eb20f36SRui Paulo 		return (0);
1008eb20f36SRui Paulo 	}
1012c633af4SJohn Birrell 
1022c633af4SJohn Birrell 	return (0);
1032c633af4SJohn Birrell }
1042c633af4SJohn Birrell 
1052c633af4SJohn Birrell int
1062c633af4SJohn Birrell proc_getflags(struct proc_handle *phdl)
1072c633af4SJohn Birrell {
1088eb20f36SRui Paulo 
1092c633af4SJohn Birrell 	if (phdl == NULL)
1102c633af4SJohn Birrell 		return (-1);
1112c633af4SJohn Birrell 
1122c633af4SJohn Birrell 	return (phdl->flags);
1132c633af4SJohn Birrell }
1142c633af4SJohn Birrell 
1152c633af4SJohn Birrell int
1162c633af4SJohn Birrell proc_setflags(struct proc_handle *phdl, int mask)
1172c633af4SJohn Birrell {
1188eb20f36SRui Paulo 
1192c633af4SJohn Birrell 	if (phdl == NULL)
1202c633af4SJohn Birrell 		return (EINVAL);
1212c633af4SJohn Birrell 
1222c633af4SJohn Birrell 	phdl->flags |= mask;
1232c633af4SJohn Birrell 
1242c633af4SJohn Birrell 	return (0);
1252c633af4SJohn Birrell }
1262c633af4SJohn Birrell 
1272c633af4SJohn Birrell int
1282c633af4SJohn Birrell proc_state(struct proc_handle *phdl)
1292c633af4SJohn Birrell {
1308eb20f36SRui Paulo 
1312c633af4SJohn Birrell 	if (phdl == NULL)
1322c633af4SJohn Birrell 		return (-1);
1332c633af4SJohn Birrell 
1342c633af4SJohn Birrell 	return (phdl->status);
1352c633af4SJohn Birrell }
1362c633af4SJohn Birrell 
1372c633af4SJohn Birrell pid_t
1382c633af4SJohn Birrell proc_getpid(struct proc_handle *phdl)
1392c633af4SJohn Birrell {
1408eb20f36SRui Paulo 
1412c633af4SJohn Birrell 	if (phdl == NULL)
1422c633af4SJohn Birrell 		return (-1);
1432c633af4SJohn Birrell 
1442c633af4SJohn Birrell 	return (phdl->pid);
1452c633af4SJohn Birrell }
1468eb20f36SRui Paulo 
1478eb20f36SRui Paulo int
1484808a678SMark Johnston proc_getmodel(struct proc_handle *phdl)
1494808a678SMark Johnston {
1504808a678SMark Johnston 
1514808a678SMark Johnston 	if (phdl == NULL)
1524808a678SMark Johnston 		return (-1);
1534808a678SMark Johnston 
1544808a678SMark Johnston 	return (phdl->model);
1554808a678SMark Johnston }
1564808a678SMark Johnston 
1574808a678SMark Johnston int
1588eb20f36SRui Paulo proc_wstatus(struct proc_handle *phdl)
1598eb20f36SRui Paulo {
1608eb20f36SRui Paulo 	int status;
1618eb20f36SRui Paulo 
1628eb20f36SRui Paulo 	if (phdl == NULL)
1638eb20f36SRui Paulo 		return (-1);
1644c74b245SRui Paulo 	if (waitpid(phdl->pid, &status, WUNTRACED) < 0) {
165fb15925cSMark Johnston 		if (errno != EINTR)
16630e81f7eSMark Johnston 			DPRINTF("waitpid");
1678eb20f36SRui Paulo 		return (-1);
1684c74b245SRui Paulo 	}
1698eb20f36SRui Paulo 	if (WIFSTOPPED(status))
1708eb20f36SRui Paulo 		phdl->status = PS_STOP;
1718eb20f36SRui Paulo 	if (WIFEXITED(status) || WIFSIGNALED(status))
1728eb20f36SRui Paulo 		phdl->status = PS_UNDEAD;
1738eb20f36SRui Paulo 	phdl->wstat = status;
1748eb20f36SRui Paulo 
1754c74b245SRui Paulo 	return (phdl->status);
1768eb20f36SRui Paulo }
1778eb20f36SRui Paulo 
1788eb20f36SRui Paulo int
1798eb20f36SRui Paulo proc_getwstat(struct proc_handle *phdl)
1808eb20f36SRui Paulo {
1818eb20f36SRui Paulo 
1828eb20f36SRui Paulo 	if (phdl == NULL)
1838eb20f36SRui Paulo 		return (-1);
1848eb20f36SRui Paulo 
1858eb20f36SRui Paulo 	return (phdl->wstat);
1868eb20f36SRui Paulo }
1878eb20f36SRui Paulo 
1888eb20f36SRui Paulo char *
1898eb20f36SRui Paulo proc_signame(int sig, char *name, size_t namesz)
1908eb20f36SRui Paulo {
1918eb20f36SRui Paulo 
1928eb20f36SRui Paulo 	strlcpy(name, strsignal(sig), namesz);
1938eb20f36SRui Paulo 
1948eb20f36SRui Paulo 	return (name);
1958eb20f36SRui Paulo }
1968eb20f36SRui Paulo 
1978eb20f36SRui Paulo int
1984c74b245SRui Paulo proc_read(struct proc_handle *phdl, void *buf, size_t size, size_t addr)
1998eb20f36SRui Paulo {
2008eb20f36SRui Paulo 	struct ptrace_io_desc piod;
2018eb20f36SRui Paulo 
2028eb20f36SRui Paulo 	if (phdl == NULL)
2038eb20f36SRui Paulo 		return (-1);
2048eb20f36SRui Paulo 	piod.piod_op = PIOD_READ_D;
2058eb20f36SRui Paulo 	piod.piod_len = size;
2068eb20f36SRui Paulo 	piod.piod_addr = (void *)buf;
2078eb20f36SRui Paulo 	piod.piod_offs = (void *)addr;
2088eb20f36SRui Paulo 
2098eb20f36SRui Paulo 	if (ptrace(PT_IO, phdl->pid, (caddr_t)&piod, 0) < 0)
2108eb20f36SRui Paulo 		return (-1);
2118eb20f36SRui Paulo 	return (piod.piod_len);
2128eb20f36SRui Paulo }
2138eb20f36SRui Paulo 
2148eb20f36SRui Paulo const lwpstatus_t *
2158eb20f36SRui Paulo proc_getlwpstatus(struct proc_handle *phdl)
2168eb20f36SRui Paulo {
2178eb20f36SRui Paulo 	struct ptrace_lwpinfo lwpinfo;
2188eb20f36SRui Paulo 	lwpstatus_t *psp = &phdl->lwps;
2198eb20f36SRui Paulo 	siginfo_t *siginfo;
2208eb20f36SRui Paulo 
2218eb20f36SRui Paulo 	if (phdl == NULL)
2228eb20f36SRui Paulo 		return (NULL);
2234c74b245SRui Paulo 	if (ptrace(PT_LWPINFO, phdl->pid, (caddr_t)&lwpinfo,
2244c74b245SRui Paulo 	    sizeof(lwpinfo)) < 0)
2258eb20f36SRui Paulo 		return (NULL);
2268eb20f36SRui Paulo 	siginfo = &lwpinfo.pl_siginfo;
2278eb20f36SRui Paulo 	if (lwpinfo.pl_event == PL_EVENT_SIGNAL &&
22892f92525SMark Johnston 	    (lwpinfo.pl_flags & PL_FLAG_SI) != 0) {
22992f92525SMark Johnston 		if (siginfo->si_signo == SIGTRAP &&
2308eb20f36SRui Paulo 		    (siginfo->si_code == TRAP_BRKPT ||
2318eb20f36SRui Paulo 		    siginfo->si_code == TRAP_TRACE)) {
2328eb20f36SRui Paulo 			psp->pr_why = PR_FAULTED;
2338eb20f36SRui Paulo 			psp->pr_what = FLTBPT;
23492f92525SMark Johnston 		} else {
23592f92525SMark Johnston 			psp->pr_why = PR_SIGNALLED;
23692f92525SMark Johnston 			psp->pr_what = siginfo->si_signo;
23792f92525SMark Johnston 		}
2388eb20f36SRui Paulo 	} else if (lwpinfo.pl_flags & PL_FLAG_SCE) {
2398eb20f36SRui Paulo 		psp->pr_why = PR_SYSENTRY;
2408eb20f36SRui Paulo 	} else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
2418eb20f36SRui Paulo 		psp->pr_why = PR_SYSEXIT;
2428eb20f36SRui Paulo 	}
2438eb20f36SRui Paulo 
2448eb20f36SRui Paulo 	return (psp);
2458eb20f36SRui Paulo }
246