1179185Sjb/*-
2210688Srpaulo * Copyright (c) 2010 The FreeBSD Foundation
3179185Sjb * Copyright (c) 2008 John Birrell (jb@freebsd.org)
4179185Sjb * All rights reserved.
5316713Smarkj *
6210688Srpaulo * Portions of this software were developed by Rui Paulo under sponsorship
7210688Srpaulo * from the FreeBSD Foundation.
8179185Sjb *
9179185Sjb * Redistribution and use in source and binary forms, with or without
10179185Sjb * modification, are permitted provided that the following conditions
11179185Sjb * are met:
12179185Sjb * 1. Redistributions of source code must retain the above copyright
13179185Sjb *    notice, this list of conditions and the following disclaimer.
14179185Sjb * 2. Redistributions in binary form must reproduce the above copyright
15179185Sjb *    notice, this list of conditions and the following disclaimer in the
16179185Sjb *    documentation and/or other materials provided with the distribution.
17179185Sjb *
18179185Sjb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19179185Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20179185Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21179185Sjb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22179185Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23179185Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24179185Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25179185Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26179185Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27179185Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28179185Sjb * SUCH DAMAGE.
29179185Sjb */
30179185Sjb
31316713Smarkj#include <sys/cdefs.h>
32316713Smarkj__FBSDID("$FreeBSD: stable/11/lib/libproc/proc_util.c 316713 2017-04-11 17:36:19Z markj $");
33316713Smarkj
34210688Srpaulo#include <sys/types.h>
35210688Srpaulo#include <sys/ptrace.h>
36210688Srpaulo#include <sys/wait.h>
37316713Smarkj
38210688Srpaulo#include <err.h>
39179185Sjb#include <errno.h>
40210688Srpaulo#include <signal.h>
41210688Srpaulo#include <string.h>
42265308Smarkj#include <unistd.h>
43316713Smarkj
44210688Srpaulo#include "_libproc.h"
45179185Sjb
46179185Sjbint
47179185Sjbproc_clearflags(struct proc_handle *phdl, int mask)
48179185Sjb{
49210688Srpaulo
50179185Sjb	if (phdl == NULL)
51179185Sjb		return (EINVAL);
52179185Sjb
53179185Sjb	phdl->flags &= ~mask;
54179185Sjb
55179185Sjb	return (0);
56179185Sjb}
57179185Sjb
58210688Srpaulo/*
59210688Srpaulo * NB: we return -1 as the Solaris libproc Psetrun() function.
60210688Srpaulo */
61179185Sjbint
62179185Sjbproc_continue(struct proc_handle *phdl)
63179185Sjb{
64316713Smarkj	int pending;
65210688Srpaulo
66179185Sjb	if (phdl == NULL)
67210688Srpaulo		return (-1);
68179185Sjb
69265308Smarkj	if (phdl->status == PS_STOP && WSTOPSIG(phdl->wstat) != SIGTRAP)
70265308Smarkj		pending = WSTOPSIG(phdl->wstat);
71316713Smarkj	else
72316713Smarkj		pending = 0;
73265308Smarkj	if (ptrace(PT_CONTINUE, phdl->pid, (caddr_t)(uintptr_t)1, pending) != 0)
74210688Srpaulo		return (-1);
75179185Sjb
76179185Sjb	phdl->status = PS_RUN;
77179185Sjb
78179185Sjb	return (0);
79179185Sjb}
80179185Sjb
81179185Sjbint
82210688Srpauloproc_detach(struct proc_handle *phdl, int reason)
83179185Sjb{
84210688Srpaulo	int status;
85210688Srpaulo
86179185Sjb	if (phdl == NULL)
87179185Sjb		return (EINVAL);
88210688Srpaulo	if (reason == PRELEASE_KILL) {
89210688Srpaulo		kill(phdl->pid, SIGKILL);
90210688Srpaulo		return (0);
91210688Srpaulo	}
92210688Srpaulo	if (ptrace(PT_DETACH, phdl->pid, 0, 0) != 0 && errno == ESRCH)
93210688Srpaulo		return (0);
94210688Srpaulo	if (errno == EBUSY) {
95210688Srpaulo		kill(phdl->pid, SIGSTOP);
96210688Srpaulo		waitpid(phdl->pid, &status, WUNTRACED);
97210688Srpaulo		ptrace(PT_DETACH, phdl->pid, 0, 0);
98210688Srpaulo		kill(phdl->pid, SIGCONT);
99210688Srpaulo		return (0);
100210688Srpaulo	}
101179185Sjb
102179185Sjb	return (0);
103179185Sjb}
104179185Sjb
105179185Sjbint
106179185Sjbproc_getflags(struct proc_handle *phdl)
107179185Sjb{
108210688Srpaulo
109179185Sjb	if (phdl == NULL)
110179185Sjb		return (-1);
111179185Sjb
112316713Smarkj	return (phdl->flags);
113179185Sjb}
114179185Sjb
115179185Sjbint
116179185Sjbproc_setflags(struct proc_handle *phdl, int mask)
117179185Sjb{
118210688Srpaulo
119179185Sjb	if (phdl == NULL)
120179185Sjb		return (EINVAL);
121179185Sjb
122179185Sjb	phdl->flags |= mask;
123179185Sjb
124179185Sjb	return (0);
125179185Sjb}
126179185Sjb
127179185Sjbint
128179185Sjbproc_state(struct proc_handle *phdl)
129179185Sjb{
130210688Srpaulo
131179185Sjb	if (phdl == NULL)
132179185Sjb		return (-1);
133179185Sjb
134179185Sjb	return (phdl->status);
135179185Sjb}
136179185Sjb
137210688Srpaulopid_t
138210688Srpauloproc_getpid(struct proc_handle *phdl)
139179185Sjb{
140179185Sjb
141179185Sjb	if (phdl == NULL)
142210688Srpaulo		return (-1);
143179185Sjb
144210688Srpaulo	return (phdl->pid);
145210688Srpaulo}
146179185Sjb
147210688Srpauloint
148210688Srpauloproc_wstatus(struct proc_handle *phdl)
149210688Srpaulo{
150210688Srpaulo	int status;
151210688Srpaulo
152210688Srpaulo	if (phdl == NULL)
153210688Srpaulo		return (-1);
154211184Srpaulo	if (waitpid(phdl->pid, &status, WUNTRACED) < 0) {
155257298Smarkj		if (errno != EINTR)
156257222Smarkj			DPRINTF("waitpid");
157210688Srpaulo		return (-1);
158211184Srpaulo	}
159210688Srpaulo	if (WIFSTOPPED(status))
160210688Srpaulo		phdl->status = PS_STOP;
161210688Srpaulo	if (WIFEXITED(status) || WIFSIGNALED(status))
162179185Sjb		phdl->status = PS_UNDEAD;
163210688Srpaulo	phdl->wstat = status;
164179185Sjb
165211184Srpaulo	return (phdl->status);
166179185Sjb}
167179185Sjb
168210688Srpauloint
169210688Srpauloproc_getwstat(struct proc_handle *phdl)
170179185Sjb{
171210688Srpaulo
172179185Sjb	if (phdl == NULL)
173179185Sjb		return (-1);
174179185Sjb
175210688Srpaulo	return (phdl->wstat);
176179185Sjb}
177210688Srpaulo
178210688Srpaulochar *
179210688Srpauloproc_signame(int sig, char *name, size_t namesz)
180210688Srpaulo{
181210688Srpaulo
182210688Srpaulo	strlcpy(name, strsignal(sig), namesz);
183210688Srpaulo
184210688Srpaulo	return (name);
185210688Srpaulo}
186210688Srpaulo
187210688Srpauloint
188211184Srpauloproc_read(struct proc_handle *phdl, void *buf, size_t size, size_t addr)
189210688Srpaulo{
190210688Srpaulo	struct ptrace_io_desc piod;
191210688Srpaulo
192210688Srpaulo	if (phdl == NULL)
193210688Srpaulo		return (-1);
194210688Srpaulo	piod.piod_op = PIOD_READ_D;
195210688Srpaulo	piod.piod_len = size;
196210688Srpaulo	piod.piod_addr = (void *)buf;
197210688Srpaulo	piod.piod_offs = (void *)addr;
198210688Srpaulo
199210688Srpaulo	if (ptrace(PT_IO, phdl->pid, (caddr_t)&piod, 0) < 0)
200210688Srpaulo		return (-1);
201210688Srpaulo	return (piod.piod_len);
202210688Srpaulo}
203210688Srpaulo
204210688Srpauloconst lwpstatus_t *
205210688Srpauloproc_getlwpstatus(struct proc_handle *phdl)
206210688Srpaulo{
207210688Srpaulo	struct ptrace_lwpinfo lwpinfo;
208210688Srpaulo	lwpstatus_t *psp = &phdl->lwps;
209210688Srpaulo	siginfo_t *siginfo;
210210688Srpaulo
211210688Srpaulo	if (phdl == NULL)
212210688Srpaulo		return (NULL);
213211184Srpaulo	if (ptrace(PT_LWPINFO, phdl->pid, (caddr_t)&lwpinfo,
214211184Srpaulo	    sizeof(lwpinfo)) < 0)
215210688Srpaulo		return (NULL);
216210688Srpaulo	siginfo = &lwpinfo.pl_siginfo;
217210688Srpaulo	if (lwpinfo.pl_event == PL_EVENT_SIGNAL &&
218265308Smarkj	    (lwpinfo.pl_flags & PL_FLAG_SI) != 0) {
219265308Smarkj		if (siginfo->si_signo == SIGTRAP &&
220265308Smarkj		    (siginfo->si_code == TRAP_BRKPT ||
221265308Smarkj		    siginfo->si_code == TRAP_TRACE)) {
222265308Smarkj			psp->pr_why = PR_FAULTED;
223265308Smarkj			psp->pr_what = FLTBPT;
224265308Smarkj		} else {
225265308Smarkj			psp->pr_why = PR_SIGNALLED;
226265308Smarkj			psp->pr_what = siginfo->si_signo;
227265308Smarkj		}
228210688Srpaulo	} else if (lwpinfo.pl_flags & PL_FLAG_SCE) {
229210688Srpaulo		psp->pr_why = PR_SYSENTRY;
230210688Srpaulo	} else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
231210688Srpaulo		psp->pr_why = PR_SYSEXIT;
232210688Srpaulo	}
233210688Srpaulo
234210688Srpaulo	return (psp);
235210688Srpaulo}
236