proc_util.c revision 211184
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: head/lib/libproc/proc_util.c 211184 2010-08-11 17:33:26Z rpaulo $
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>
38179185Sjb#include <unistd.h>
39179185Sjb#include <stdio.h>
40210688Srpaulo#include <signal.h>
41210688Srpaulo#include <string.h>
42210688Srpaulo#include "_libproc.h"
43179185Sjb
44179185Sjbint
45179185Sjbproc_clearflags(struct proc_handle *phdl, int mask)
46179185Sjb{
47210688Srpaulo
48179185Sjb	if (phdl == NULL)
49179185Sjb		return (EINVAL);
50179185Sjb
51179185Sjb	phdl->flags &= ~mask;
52179185Sjb
53179185Sjb	return (0);
54179185Sjb}
55179185Sjb
56210688Srpaulo/*
57210688Srpaulo * NB: we return -1 as the Solaris libproc Psetrun() function.
58210688Srpaulo */
59179185Sjbint
60179185Sjbproc_continue(struct proc_handle *phdl)
61179185Sjb{
62210688Srpaulo
63179185Sjb	if (phdl == NULL)
64210688Srpaulo		return (-1);
65179185Sjb
66179185Sjb	if (ptrace(PT_CONTINUE, phdl->pid, (caddr_t)(uintptr_t) 1, 0) != 0)
67210688Srpaulo		return (-1);
68179185Sjb
69179185Sjb	phdl->status = PS_RUN;
70179185Sjb
71179185Sjb	return (0);
72179185Sjb}
73179185Sjb
74179185Sjbint
75210688Srpauloproc_detach(struct proc_handle *phdl, int reason)
76179185Sjb{
77210688Srpaulo	int status;
78210688Srpaulo
79179185Sjb	if (phdl == NULL)
80179185Sjb		return (EINVAL);
81210688Srpaulo	if (reason == PRELEASE_KILL) {
82210688Srpaulo		kill(phdl->pid, SIGKILL);
83210688Srpaulo		return (0);
84210688Srpaulo	}
85210688Srpaulo	if (ptrace(PT_DETACH, phdl->pid, 0, 0) != 0 && errno == ESRCH)
86210688Srpaulo		return (0);
87210688Srpaulo	if (errno == EBUSY) {
88210688Srpaulo		kill(phdl->pid, SIGSTOP);
89210688Srpaulo		waitpid(phdl->pid, &status, WUNTRACED);
90210688Srpaulo		ptrace(PT_DETACH, phdl->pid, 0, 0);
91210688Srpaulo		kill(phdl->pid, SIGCONT);
92210688Srpaulo		return (0);
93210688Srpaulo	}
94179185Sjb
95179185Sjb	return (0);
96179185Sjb}
97179185Sjb
98179185Sjbint
99179185Sjbproc_getflags(struct proc_handle *phdl)
100179185Sjb{
101210688Srpaulo
102179185Sjb	if (phdl == NULL)
103179185Sjb		return (-1);
104179185Sjb
105179185Sjb	return(phdl->flags);
106179185Sjb}
107179185Sjb
108179185Sjbint
109179185Sjbproc_setflags(struct proc_handle *phdl, int mask)
110179185Sjb{
111210688Srpaulo
112179185Sjb	if (phdl == NULL)
113179185Sjb		return (EINVAL);
114179185Sjb
115179185Sjb	phdl->flags |= mask;
116179185Sjb
117179185Sjb	return (0);
118179185Sjb}
119179185Sjb
120179185Sjbint
121179185Sjbproc_state(struct proc_handle *phdl)
122179185Sjb{
123210688Srpaulo
124179185Sjb	if (phdl == NULL)
125179185Sjb		return (-1);
126179185Sjb
127179185Sjb	return (phdl->status);
128179185Sjb}
129179185Sjb
130210688Srpaulopid_t
131210688Srpauloproc_getpid(struct proc_handle *phdl)
132179185Sjb{
133179185Sjb
134179185Sjb	if (phdl == NULL)
135210688Srpaulo		return (-1);
136179185Sjb
137210688Srpaulo	return (phdl->pid);
138210688Srpaulo}
139179185Sjb
140210688Srpauloint
141210688Srpauloproc_wstatus(struct proc_handle *phdl)
142210688Srpaulo{
143210688Srpaulo	int status;
144210688Srpaulo
145210688Srpaulo	if (phdl == NULL)
146210688Srpaulo		return (-1);
147211184Srpaulo	if (waitpid(phdl->pid, &status, WUNTRACED) < 0) {
148211184Srpaulo		warn("waitpid");
149210688Srpaulo		return (-1);
150211184Srpaulo	}
151210688Srpaulo	if (WIFSTOPPED(status))
152210688Srpaulo		phdl->status = PS_STOP;
153210688Srpaulo	if (WIFEXITED(status) || WIFSIGNALED(status))
154179185Sjb		phdl->status = PS_UNDEAD;
155210688Srpaulo	phdl->wstat = status;
156179185Sjb
157211184Srpaulo	return (phdl->status);
158179185Sjb}
159179185Sjb
160210688Srpauloint
161210688Srpauloproc_getwstat(struct proc_handle *phdl)
162179185Sjb{
163210688Srpaulo
164179185Sjb	if (phdl == NULL)
165179185Sjb		return (-1);
166179185Sjb
167210688Srpaulo	return (phdl->wstat);
168179185Sjb}
169210688Srpaulo
170210688Srpaulochar *
171210688Srpauloproc_signame(int sig, char *name, size_t namesz)
172210688Srpaulo{
173210688Srpaulo
174210688Srpaulo	strlcpy(name, strsignal(sig), namesz);
175210688Srpaulo
176210688Srpaulo	return (name);
177210688Srpaulo}
178210688Srpaulo
179210688Srpauloint
180211184Srpauloproc_read(struct proc_handle *phdl, void *buf, size_t size, size_t addr)
181210688Srpaulo{
182210688Srpaulo	struct ptrace_io_desc piod;
183210688Srpaulo
184210688Srpaulo	if (phdl == NULL)
185210688Srpaulo		return (-1);
186210688Srpaulo	piod.piod_op = PIOD_READ_D;
187210688Srpaulo	piod.piod_len = size;
188210688Srpaulo	piod.piod_addr = (void *)buf;
189210688Srpaulo	piod.piod_offs = (void *)addr;
190210688Srpaulo
191210688Srpaulo	if (ptrace(PT_IO, phdl->pid, (caddr_t)&piod, 0) < 0)
192210688Srpaulo		return (-1);
193210688Srpaulo	return (piod.piod_len);
194210688Srpaulo}
195210688Srpaulo
196210688Srpauloconst lwpstatus_t *
197210688Srpauloproc_getlwpstatus(struct proc_handle *phdl)
198210688Srpaulo{
199210688Srpaulo	struct ptrace_lwpinfo lwpinfo;
200210688Srpaulo	lwpstatus_t *psp = &phdl->lwps;
201210688Srpaulo	siginfo_t *siginfo;
202210688Srpaulo
203210688Srpaulo	if (phdl == NULL)
204210688Srpaulo		return (NULL);
205211184Srpaulo	if (ptrace(PT_LWPINFO, phdl->pid, (caddr_t)&lwpinfo,
206211184Srpaulo	    sizeof(lwpinfo)) < 0)
207210688Srpaulo		return (NULL);
208210688Srpaulo	siginfo = &lwpinfo.pl_siginfo;
209210688Srpaulo	if (lwpinfo.pl_event == PL_EVENT_SIGNAL &&
210210688Srpaulo	    (lwpinfo.pl_flags & PL_FLAG_SI) &&
211210688Srpaulo	    siginfo->si_signo == SIGTRAP &&
212210688Srpaulo	    (siginfo->si_code == TRAP_BRKPT ||
213210688Srpaulo	    siginfo->si_code == TRAP_TRACE)) {
214210688Srpaulo		psp->pr_why = PR_FAULTED;
215210688Srpaulo		psp->pr_what = FLTBPT;
216210688Srpaulo	} else if (lwpinfo.pl_flags & PL_FLAG_SCE) {
217210688Srpaulo		psp->pr_why = PR_SYSENTRY;
218210688Srpaulo	} else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
219210688Srpaulo		psp->pr_why = PR_SYSEXIT;
220210688Srpaulo	}
221210688Srpaulo
222210688Srpaulo	return (psp);
223210688Srpaulo}
224