1fbcd1dd1Schristos /*-
2fbcd1dd1Schristos * Copyright (c) 2010 The FreeBSD Foundation
3fbcd1dd1Schristos * Copyright (c) 2008 John Birrell (jb@freebsd.org)
4fbcd1dd1Schristos * All rights reserved.
5fbcd1dd1Schristos *
6fbcd1dd1Schristos * Portions of this software were developed by Rui Paulo under sponsorship
7fbcd1dd1Schristos * from the FreeBSD Foundation.
8fbcd1dd1Schristos *
9fbcd1dd1Schristos * Redistribution and use in source and binary forms, with or without
10fbcd1dd1Schristos * modification, are permitted provided that the following conditions
11fbcd1dd1Schristos * are met:
12fbcd1dd1Schristos * 1. Redistributions of source code must retain the above copyright
13fbcd1dd1Schristos * notice, this list of conditions and the following disclaimer.
14fbcd1dd1Schristos * 2. Redistributions in binary form must reproduce the above copyright
15fbcd1dd1Schristos * notice, this list of conditions and the following disclaimer in the
16fbcd1dd1Schristos * documentation and/or other materials provided with the distribution.
17fbcd1dd1Schristos *
18fbcd1dd1Schristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19fbcd1dd1Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20fbcd1dd1Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21fbcd1dd1Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22fbcd1dd1Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23fbcd1dd1Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24fbcd1dd1Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25fbcd1dd1Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26fbcd1dd1Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27fbcd1dd1Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28fbcd1dd1Schristos * SUCH DAMAGE.
29fbcd1dd1Schristos *
30fbcd1dd1Schristos * $FreeBSD: head/lib/libproc/proc_util.c 265308 2014-05-04 03:34:32Z markj $
31fbcd1dd1Schristos */
32fbcd1dd1Schristos
33fbcd1dd1Schristos #include <sys/types.h>
34fbcd1dd1Schristos #include <sys/ptrace.h>
35fbcd1dd1Schristos #include <sys/wait.h>
36fbcd1dd1Schristos #include <err.h>
37fbcd1dd1Schristos #include <errno.h>
38fbcd1dd1Schristos #include <signal.h>
39b222cea9Schs #include <stdbool.h>
40fbcd1dd1Schristos #include <string.h>
41fbcd1dd1Schristos #include <unistd.h>
42fbcd1dd1Schristos #include "_libproc.h"
43fbcd1dd1Schristos
44fbcd1dd1Schristos int
proc_clearflags(struct proc_handle * phdl,int mask)45fbcd1dd1Schristos proc_clearflags(struct proc_handle *phdl, int mask)
46fbcd1dd1Schristos {
47fbcd1dd1Schristos
48fbcd1dd1Schristos if (phdl == NULL)
49fbcd1dd1Schristos return (EINVAL);
50fbcd1dd1Schristos
51fbcd1dd1Schristos phdl->flags &= ~mask;
52fbcd1dd1Schristos
53fbcd1dd1Schristos return (0);
54fbcd1dd1Schristos }
55fbcd1dd1Schristos
56fbcd1dd1Schristos /*
57fbcd1dd1Schristos * NB: we return -1 as the Solaris libproc Psetrun() function.
58fbcd1dd1Schristos */
59fbcd1dd1Schristos int
proc_continue(struct proc_handle * phdl)60fbcd1dd1Schristos proc_continue(struct proc_handle *phdl)
61fbcd1dd1Schristos {
62fbcd1dd1Schristos int pending = 0;
63fbcd1dd1Schristos
64fbcd1dd1Schristos if (phdl == NULL)
65fbcd1dd1Schristos return (-1);
66fbcd1dd1Schristos
67fbcd1dd1Schristos if (phdl->status == PS_STOP && WSTOPSIG(phdl->wstat) != SIGTRAP)
68fbcd1dd1Schristos pending = WSTOPSIG(phdl->wstat);
69800ae963Schristos if (ptrace(PT_CONTINUE, phdl->pid, (void *)(uintptr_t)1, pending) != 0)
70fbcd1dd1Schristos return (-1);
71fbcd1dd1Schristos
72fbcd1dd1Schristos phdl->status = PS_RUN;
73fbcd1dd1Schristos
74fbcd1dd1Schristos return (0);
75fbcd1dd1Schristos }
76fbcd1dd1Schristos
77fbcd1dd1Schristos int
proc_detach(struct proc_handle * phdl,int reason)78fbcd1dd1Schristos proc_detach(struct proc_handle *phdl, int reason)
79fbcd1dd1Schristos {
80fbcd1dd1Schristos int status;
81fbcd1dd1Schristos
82fbcd1dd1Schristos if (phdl == NULL)
83800ae963Schristos return EINVAL;
84fbcd1dd1Schristos if (reason == PRELEASE_KILL) {
85800ae963Schristos ptrace(PT_DETACH, phdl->pid, (void *)(uintptr_t)1, 0);
86fbcd1dd1Schristos kill(phdl->pid, SIGKILL);
87800ae963Schristos return 0;
88fbcd1dd1Schristos }
89800ae963Schristos if (ptrace(PT_DETACH, phdl->pid, (void *)(uintptr_t)1, 0) == 0)
90800ae963Schristos return 0;
91800ae963Schristos
92800ae963Schristos switch (errno) {
93800ae963Schristos case ESRCH:
94800ae963Schristos return 0;
95800ae963Schristos case EBUSY:
96800ae963Schristos break;
97800ae963Schristos default:
98800ae963Schristos return -1;
99fbcd1dd1Schristos }
100fbcd1dd1Schristos
101800ae963Schristos if (kill(phdl->pid, SIGSTOP) == -1)
102800ae963Schristos return -1;
103800ae963Schristos
104800ae963Schristos waitpid(phdl->pid, &status, WUNTRACED);
105800ae963Schristos
106800ae963Schristos if (ptrace(PT_DETACH, phdl->pid, (void *)(uintptr_t)1, 0) == -1)
107800ae963Schristos return -1;
108800ae963Schristos
109800ae963Schristos if (kill(phdl->pid, SIGCONT) == -1)
110800ae963Schristos return -1;
111800ae963Schristos
112800ae963Schristos return 0;
113fbcd1dd1Schristos }
114fbcd1dd1Schristos
115fbcd1dd1Schristos int
proc_getflags(struct proc_handle * phdl)116fbcd1dd1Schristos proc_getflags(struct proc_handle *phdl)
117fbcd1dd1Schristos {
118fbcd1dd1Schristos
119fbcd1dd1Schristos if (phdl == NULL)
120fbcd1dd1Schristos return (-1);
121fbcd1dd1Schristos
122fbcd1dd1Schristos return(phdl->flags);
123fbcd1dd1Schristos }
124fbcd1dd1Schristos
125fbcd1dd1Schristos int
proc_setflags(struct proc_handle * phdl,int mask)126fbcd1dd1Schristos proc_setflags(struct proc_handle *phdl, int mask)
127fbcd1dd1Schristos {
128fbcd1dd1Schristos
129fbcd1dd1Schristos if (phdl == NULL)
130fbcd1dd1Schristos return (EINVAL);
131fbcd1dd1Schristos
132fbcd1dd1Schristos phdl->flags |= mask;
133fbcd1dd1Schristos
134fbcd1dd1Schristos return (0);
135fbcd1dd1Schristos }
136fbcd1dd1Schristos
137fbcd1dd1Schristos int
proc_state(struct proc_handle * phdl)138fbcd1dd1Schristos proc_state(struct proc_handle *phdl)
139fbcd1dd1Schristos {
140fbcd1dd1Schristos
141fbcd1dd1Schristos if (phdl == NULL)
142fbcd1dd1Schristos return (-1);
143fbcd1dd1Schristos
144fbcd1dd1Schristos return (phdl->status);
145fbcd1dd1Schristos }
146fbcd1dd1Schristos
14749f0a76dSchs int
proc_getmodel(struct proc_handle * phdl)14849f0a76dSchs proc_getmodel(struct proc_handle *phdl)
14949f0a76dSchs {
15049f0a76dSchs
15149f0a76dSchs if (phdl == NULL)
15249f0a76dSchs return (-1);
15349f0a76dSchs
15449f0a76dSchs return (phdl->model);
15549f0a76dSchs }
15649f0a76dSchs
157fbcd1dd1Schristos pid_t
proc_getpid(struct proc_handle * phdl)158fbcd1dd1Schristos proc_getpid(struct proc_handle *phdl)
159fbcd1dd1Schristos {
160fbcd1dd1Schristos
161fbcd1dd1Schristos if (phdl == NULL)
162fbcd1dd1Schristos return (-1);
163fbcd1dd1Schristos
164fbcd1dd1Schristos return (phdl->pid);
165fbcd1dd1Schristos }
166fbcd1dd1Schristos
167fbcd1dd1Schristos int
proc_wstatus(struct proc_handle * phdl)168fbcd1dd1Schristos proc_wstatus(struct proc_handle *phdl)
169fbcd1dd1Schristos {
170fbcd1dd1Schristos int status;
171fbcd1dd1Schristos
172fbcd1dd1Schristos if (phdl == NULL)
173fbcd1dd1Schristos return (-1);
174fbcd1dd1Schristos if (waitpid(phdl->pid, &status, WUNTRACED) < 0) {
175fbcd1dd1Schristos if (errno != EINTR)
176fbcd1dd1Schristos DPRINTF("waitpid");
177fbcd1dd1Schristos return (-1);
178fbcd1dd1Schristos }
179fbcd1dd1Schristos if (WIFSTOPPED(status))
180fbcd1dd1Schristos phdl->status = PS_STOP;
181fbcd1dd1Schristos if (WIFEXITED(status) || WIFSIGNALED(status))
182fbcd1dd1Schristos phdl->status = PS_UNDEAD;
183fbcd1dd1Schristos phdl->wstat = status;
184fbcd1dd1Schristos
185fbcd1dd1Schristos return (phdl->status);
186fbcd1dd1Schristos }
187fbcd1dd1Schristos
188fbcd1dd1Schristos int
proc_getwstat(struct proc_handle * phdl)189fbcd1dd1Schristos proc_getwstat(struct proc_handle *phdl)
190fbcd1dd1Schristos {
191fbcd1dd1Schristos
192fbcd1dd1Schristos if (phdl == NULL)
193fbcd1dd1Schristos return (-1);
194fbcd1dd1Schristos
195fbcd1dd1Schristos return (phdl->wstat);
196fbcd1dd1Schristos }
197fbcd1dd1Schristos
198fbcd1dd1Schristos char *
proc_signame(int sig,char * name,size_t namesz)199fbcd1dd1Schristos proc_signame(int sig, char *name, size_t namesz)
200fbcd1dd1Schristos {
201fbcd1dd1Schristos
202fbcd1dd1Schristos strlcpy(name, strsignal(sig), namesz);
203fbcd1dd1Schristos
204fbcd1dd1Schristos return (name);
205fbcd1dd1Schristos }
206fbcd1dd1Schristos
207fbcd1dd1Schristos int
proc_read(struct proc_handle * phdl,void * buf,size_t size,size_t addr)208fbcd1dd1Schristos proc_read(struct proc_handle *phdl, void *buf, size_t size, size_t addr)
209fbcd1dd1Schristos {
210fbcd1dd1Schristos struct ptrace_io_desc piod;
211fbcd1dd1Schristos
212fbcd1dd1Schristos if (phdl == NULL)
213fbcd1dd1Schristos return (-1);
214fbcd1dd1Schristos piod.piod_op = PIOD_READ_D;
215fbcd1dd1Schristos piod.piod_len = size;
216fbcd1dd1Schristos piod.piod_addr = (void *)buf;
217fbcd1dd1Schristos piod.piod_offs = (void *)addr;
218fbcd1dd1Schristos
219800ae963Schristos if (ptrace(PT_IO, phdl->pid, (void *)&piod, 0) < 0)
220fbcd1dd1Schristos return (-1);
221fbcd1dd1Schristos return (piod.piod_len);
222fbcd1dd1Schristos }
223fbcd1dd1Schristos
224fbcd1dd1Schristos const lwpstatus_t *
proc_getlwpstatus(struct proc_handle * phdl)225fbcd1dd1Schristos proc_getlwpstatus(struct proc_handle *phdl)
226fbcd1dd1Schristos {
227fbcd1dd1Schristos lwpstatus_t *psp = &phdl->lwps;
228fbcd1dd1Schristos siginfo_t *siginfo;
229fbcd1dd1Schristos
230b222cea9Schs #ifdef PT_GET_SIGINFO
231b222cea9Schs struct ptrace_siginfo si;
232b222cea9Schs
233b222cea9Schs if (ptrace(PT_GET_SIGINFO, phdl->pid, (void *)&si,
234b222cea9Schs sizeof(si)) < 0)
235b222cea9Schs return (NULL);
236b222cea9Schs
237b222cea9Schs siginfo = &si.psi_siginfo;
238*1826c369Skamil if (siginfo->si_signo == SIGTRAP &&
239*1826c369Skamil (siginfo->si_code == TRAP_BRKPT ||
240*1826c369Skamil siginfo->si_code == TRAP_TRACE)) {
241*1826c369Skamil psp->pr_why = PR_FAULTED;
242*1826c369Skamil psp->pr_what = FLTBPT;
243*1826c369Skamil } else if (siginfo->si_signo == SIGTRAP &&
244*1826c369Skamil (siginfo->si_code == TRAP_SCE)) {
245*1826c369Skamil psp->pr_why = PR_SYSENTRY;
246*1826c369Skamil } else if (siginfo->si_signo == SIGTRAP &&
247*1826c369Skamil (siginfo->si_code == TRAP_SCX)) {
248*1826c369Skamil psp->pr_why = PR_SYSEXIT;
249*1826c369Skamil } else {
250*1826c369Skamil psp->pr_why = PR_SIGNALLED;
251*1826c369Skamil psp->pr_what = siginfo->si_signo;
252*1826c369Skamil }
253*1826c369Skamil #else
254*1826c369Skamil struct ptrace_lwpinfo lwpinfo;
255*1826c369Skamil bool have_siginfo, sysentry, sysexit;
256*1826c369Skamil
257*1826c369Skamil if (phdl == NULL)
258*1826c369Skamil return (NULL);
259*1826c369Skamil
260*1826c369Skamil lwpinfo.pl_lwpid = 0;
261*1826c369Skamil if (ptrace(PT_LWPINFO, phdl->pid, (void *)&lwpinfo,
262*1826c369Skamil sizeof(lwpinfo)) < 0)
263*1826c369Skamil return (NULL);
264*1826c369Skamil
265*1826c369Skamil have_siginfo = (lwpinfo.pl_flags & PL_FLAG_SI) != 0;
266*1826c369Skamil sysentry = (lwpinfo.pl_flags & PL_FLAG_SCE) != 0;
267*1826c369Skamil sysexit = (lwpinfo.pl_flags & PL_FLAG_SCX) != 0;
268*1826c369Skamil
269*1826c369Skamil if (lwpinfo.pl_event == PL_EVENT_SIGNAL && have_siginfo) {
270*1826c369Skamil siginfo = &lwpinfo.pl_siginfo;
271fbcd1dd1Schristos if (siginfo->si_signo == SIGTRAP &&
272fbcd1dd1Schristos (siginfo->si_code == TRAP_BRKPT ||
273fbcd1dd1Schristos siginfo->si_code == TRAP_TRACE)) {
274fbcd1dd1Schristos psp->pr_why = PR_FAULTED;
275fbcd1dd1Schristos psp->pr_what = FLTBPT;
276fbcd1dd1Schristos } else {
277fbcd1dd1Schristos psp->pr_why = PR_SIGNALLED;
278fbcd1dd1Schristos psp->pr_what = siginfo->si_signo;
279fbcd1dd1Schristos }
280b222cea9Schs } else if (sysentry) {
281fbcd1dd1Schristos psp->pr_why = PR_SYSENTRY;
282b222cea9Schs } else if (sysexit) {
283fbcd1dd1Schristos psp->pr_why = PR_SYSEXIT;
284fbcd1dd1Schristos }
285*1826c369Skamil #endif
286fbcd1dd1Schristos return (psp);
287fbcd1dd1Schristos }
288