xref: /netbsd-src/external/bsd/libproc/dist/proc_util.c (revision 1826c369722d453b8a95ed5e7c1923416fe6e9ec)
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