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