1179185Sjb/*-
2210688Srpaulo * Copyright (c) 2010 The FreeBSD Foundation
3179185Sjb * Copyright (c) 2008 John Birrell (jb@freebsd.org)
4179185Sjb * All rights reserved.
5210688Srpaulo *
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 * $FreeBSD$
31179185Sjb */
32179185Sjb
33210688Srpaulo#include <sys/types.h>
34210688Srpaulo#include <sys/ptrace.h>
35210688Srpaulo#include <sys/wait.h>
36210688Srpaulo#include <err.h>
37179185Sjb#include <errno.h>
38210688Srpaulo#include <signal.h>
39210688Srpaulo#include <string.h>
40269754Smarkj#include <unistd.h>
41210688Srpaulo#include "_libproc.h"
42179185Sjb
43179185Sjbint
44179185Sjbproc_clearflags(struct proc_handle *phdl, int mask)
45179185Sjb{
46210688Srpaulo
47179185Sjb	if (phdl == NULL)
48179185Sjb		return (EINVAL);
49179185Sjb
50179185Sjb	phdl->flags &= ~mask;
51179185Sjb
52179185Sjb	return (0);
53179185Sjb}
54179185Sjb
55210688Srpaulo/*
56210688Srpaulo * NB: we return -1 as the Solaris libproc Psetrun() function.
57210688Srpaulo */
58179185Sjbint
59179185Sjbproc_continue(struct proc_handle *phdl)
60179185Sjb{
61269754Smarkj	int pending = 0;
62210688Srpaulo
63179185Sjb	if (phdl == NULL)
64210688Srpaulo		return (-1);
65179185Sjb
66269754Smarkj	if (phdl->status == PS_STOP && WSTOPSIG(phdl->wstat) != SIGTRAP)
67269754Smarkj		pending = WSTOPSIG(phdl->wstat);
68269754Smarkj	if (ptrace(PT_CONTINUE, phdl->pid, (caddr_t)(uintptr_t)1, pending) != 0)
69210688Srpaulo		return (-1);
70179185Sjb
71179185Sjb	phdl->status = PS_RUN;
72179185Sjb
73179185Sjb	return (0);
74179185Sjb}
75179185Sjb
76179185Sjbint
77210688Srpauloproc_detach(struct proc_handle *phdl, int reason)
78179185Sjb{
79210688Srpaulo	int status;
80210688Srpaulo
81179185Sjb	if (phdl == NULL)
82179185Sjb		return (EINVAL);
83210688Srpaulo	if (reason == PRELEASE_KILL) {
84210688Srpaulo		kill(phdl->pid, SIGKILL);
85210688Srpaulo		return (0);
86210688Srpaulo	}
87210688Srpaulo	if (ptrace(PT_DETACH, phdl->pid, 0, 0) != 0 && errno == ESRCH)
88210688Srpaulo		return (0);
89210688Srpaulo	if (errno == EBUSY) {
90210688Srpaulo		kill(phdl->pid, SIGSTOP);
91210688Srpaulo		waitpid(phdl->pid, &status, WUNTRACED);
92210688Srpaulo		ptrace(PT_DETACH, phdl->pid, 0, 0);
93210688Srpaulo		kill(phdl->pid, SIGCONT);
94210688Srpaulo		return (0);
95210688Srpaulo	}
96179185Sjb
97179185Sjb	return (0);
98179185Sjb}
99179185Sjb
100179185Sjbint
101179185Sjbproc_getflags(struct proc_handle *phdl)
102179185Sjb{
103210688Srpaulo
104179185Sjb	if (phdl == NULL)
105179185Sjb		return (-1);
106179185Sjb
107179185Sjb	return(phdl->flags);
108179185Sjb}
109179185Sjb
110179185Sjbint
111179185Sjbproc_setflags(struct proc_handle *phdl, int mask)
112179185Sjb{
113210688Srpaulo
114179185Sjb	if (phdl == NULL)
115179185Sjb		return (EINVAL);
116179185Sjb
117179185Sjb	phdl->flags |= mask;
118179185Sjb
119179185Sjb	return (0);
120179185Sjb}
121179185Sjb
122179185Sjbint
123179185Sjbproc_state(struct proc_handle *phdl)
124179185Sjb{
125210688Srpaulo
126179185Sjb	if (phdl == NULL)
127179185Sjb		return (-1);
128179185Sjb
129179185Sjb	return (phdl->status);
130179185Sjb}
131179185Sjb
132210688Srpaulopid_t
133210688Srpauloproc_getpid(struct proc_handle *phdl)
134179185Sjb{
135179185Sjb
136179185Sjb	if (phdl == NULL)
137210688Srpaulo		return (-1);
138179185Sjb
139210688Srpaulo	return (phdl->pid);
140210688Srpaulo}
141179185Sjb
142210688Srpauloint
143210688Srpauloproc_wstatus(struct proc_handle *phdl)
144210688Srpaulo{
145210688Srpaulo	int status;
146210688Srpaulo
147210688Srpaulo	if (phdl == NULL)
148210688Srpaulo		return (-1);
149211184Srpaulo	if (waitpid(phdl->pid, &status, WUNTRACED) < 0) {
150212831Srpaulo		if (errno != EINTR)
151259895Smarkj			DPRINTF("waitpid");
152210688Srpaulo		return (-1);
153211184Srpaulo	}
154210688Srpaulo	if (WIFSTOPPED(status))
155210688Srpaulo		phdl->status = PS_STOP;
156210688Srpaulo	if (WIFEXITED(status) || WIFSIGNALED(status))
157179185Sjb		phdl->status = PS_UNDEAD;
158210688Srpaulo	phdl->wstat = status;
159179185Sjb
160211184Srpaulo	return (phdl->status);
161179185Sjb}
162179185Sjb
163210688Srpauloint
164210688Srpauloproc_getwstat(struct proc_handle *phdl)
165179185Sjb{
166210688Srpaulo
167179185Sjb	if (phdl == NULL)
168179185Sjb		return (-1);
169179185Sjb
170210688Srpaulo	return (phdl->wstat);
171179185Sjb}
172210688Srpaulo
173210688Srpaulochar *
174210688Srpauloproc_signame(int sig, char *name, size_t namesz)
175210688Srpaulo{
176210688Srpaulo
177210688Srpaulo	strlcpy(name, strsignal(sig), namesz);
178210688Srpaulo
179210688Srpaulo	return (name);
180210688Srpaulo}
181210688Srpaulo
182210688Srpauloint
183211184Srpauloproc_read(struct proc_handle *phdl, void *buf, size_t size, size_t addr)
184210688Srpaulo{
185210688Srpaulo	struct ptrace_io_desc piod;
186210688Srpaulo
187210688Srpaulo	if (phdl == NULL)
188210688Srpaulo		return (-1);
189210688Srpaulo	piod.piod_op = PIOD_READ_D;
190210688Srpaulo	piod.piod_len = size;
191210688Srpaulo	piod.piod_addr = (void *)buf;
192210688Srpaulo	piod.piod_offs = (void *)addr;
193210688Srpaulo
194210688Srpaulo	if (ptrace(PT_IO, phdl->pid, (caddr_t)&piod, 0) < 0)
195210688Srpaulo		return (-1);
196210688Srpaulo	return (piod.piod_len);
197210688Srpaulo}
198210688Srpaulo
199210688Srpauloconst lwpstatus_t *
200210688Srpauloproc_getlwpstatus(struct proc_handle *phdl)
201210688Srpaulo{
202210688Srpaulo	struct ptrace_lwpinfo lwpinfo;
203210688Srpaulo	lwpstatus_t *psp = &phdl->lwps;
204210688Srpaulo	siginfo_t *siginfo;
205210688Srpaulo
206210688Srpaulo	if (phdl == NULL)
207210688Srpaulo		return (NULL);
208211184Srpaulo	if (ptrace(PT_LWPINFO, phdl->pid, (caddr_t)&lwpinfo,
209211184Srpaulo	    sizeof(lwpinfo)) < 0)
210210688Srpaulo		return (NULL);
211210688Srpaulo	siginfo = &lwpinfo.pl_siginfo;
212210688Srpaulo	if (lwpinfo.pl_event == PL_EVENT_SIGNAL &&
213269754Smarkj	    (lwpinfo.pl_flags & PL_FLAG_SI) != 0) {
214269754Smarkj		if (siginfo->si_signo == SIGTRAP &&
215269754Smarkj		    (siginfo->si_code == TRAP_BRKPT ||
216269754Smarkj		    siginfo->si_code == TRAP_TRACE)) {
217269754Smarkj			psp->pr_why = PR_FAULTED;
218269754Smarkj			psp->pr_what = FLTBPT;
219269754Smarkj		} else {
220269754Smarkj			psp->pr_why = PR_SIGNALLED;
221269754Smarkj			psp->pr_what = siginfo->si_signo;
222269754Smarkj		}
223210688Srpaulo	} else if (lwpinfo.pl_flags & PL_FLAG_SCE) {
224210688Srpaulo		psp->pr_why = PR_SYSENTRY;
225210688Srpaulo	} else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
226210688Srpaulo		psp->pr_why = PR_SYSEXIT;
227210688Srpaulo	}
228210688Srpaulo
229210688Srpaulo	return (psp);
230210688Srpaulo}
231