xref: /freebsd/tools/test/ptrace/scescx.c (revision 6403a140243d4f5377f589f93aeb44fe75ea8d59)
1e1976efdSKonstantin Belousov /*-
2e1976efdSKonstantin Belousov  * Copyright (c) 2011, 2012 Konstantin Belousov <kib@FreeBSD.org>
3e1976efdSKonstantin Belousov  *
4e1976efdSKonstantin Belousov  * Redistribution and use in source and binary forms, with or without
5e1976efdSKonstantin Belousov  * modification, are permitted provided that the following conditions
6e1976efdSKonstantin Belousov  * are met:
7e1976efdSKonstantin Belousov  * 1. Redistributions of source code must retain the above copyright
8e1976efdSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer.
9e1976efdSKonstantin Belousov  * 2. Redistributions in binary form must reproduce the above copyright
10e1976efdSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer in the
11e1976efdSKonstantin Belousov  *    documentation and/or other materials provided with the distribution.
12e1976efdSKonstantin Belousov  *
13e1976efdSKonstantin Belousov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14e1976efdSKonstantin Belousov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15e1976efdSKonstantin Belousov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16e1976efdSKonstantin Belousov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17e1976efdSKonstantin Belousov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18e1976efdSKonstantin Belousov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19e1976efdSKonstantin Belousov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20e1976efdSKonstantin Belousov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21e1976efdSKonstantin Belousov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22e1976efdSKonstantin Belousov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23e1976efdSKonstantin Belousov  * SUCH DAMAGE.
24e1976efdSKonstantin Belousov  */
25e1976efdSKonstantin Belousov 
26e1976efdSKonstantin Belousov #include <sys/cdefs.h>
27e1976efdSKonstantin Belousov __FBSDID("$FreeBSD$");
28e1976efdSKonstantin Belousov 
29e1976efdSKonstantin Belousov #include <sys/types.h>
30e1976efdSKonstantin Belousov #include <sys/ptrace.h>
31*6403a140SKonstantin Belousov #include <sys/syscall.h>
32e1976efdSKonstantin Belousov #include <sys/sysctl.h>
33e1976efdSKonstantin Belousov #include <sys/wait.h>
34e1976efdSKonstantin Belousov #include <assert.h>
35e1976efdSKonstantin Belousov #include <errno.h>
36e1976efdSKonstantin Belousov #include <signal.h>
37e1976efdSKonstantin Belousov #include <stdio.h>
38e1976efdSKonstantin Belousov #include <stdlib.h>
39e1976efdSKonstantin Belousov #include <string.h>
40e1976efdSKonstantin Belousov #include <unistd.h>
41e1976efdSKonstantin Belousov 
42e1976efdSKonstantin Belousov #define TRACE	">>>> "
43e1976efdSKonstantin Belousov 
44e1976efdSKonstantin Belousov static const char *
45e1976efdSKonstantin Belousov decode_wait_status(int status)
46e1976efdSKonstantin Belousov {
47e1976efdSKonstantin Belousov 	static char c[128];
48e1976efdSKonstantin Belousov 	char b[32];
49e1976efdSKonstantin Belousov 	int first;
50e1976efdSKonstantin Belousov 
51e1976efdSKonstantin Belousov 	c[0] = '\0';
52e1976efdSKonstantin Belousov 	first = 1;
53e1976efdSKonstantin Belousov 	if (WIFCONTINUED(status)) {
54e1976efdSKonstantin Belousov 		first = 0;
55e1976efdSKonstantin Belousov 		strlcat(c, "CONT", sizeof(c));
56e1976efdSKonstantin Belousov 	}
57e1976efdSKonstantin Belousov 	if (WIFEXITED(status)) {
58e1976efdSKonstantin Belousov 		if (first)
59e1976efdSKonstantin Belousov 			first = 0;
60e1976efdSKonstantin Belousov 		else
61e1976efdSKonstantin Belousov 			strlcat(c, ",", sizeof(c));
62e1976efdSKonstantin Belousov 		snprintf(b, sizeof(b), "EXIT(%d)", WEXITSTATUS(status));
63e1976efdSKonstantin Belousov 		strlcat(c, b, sizeof(c));
64e1976efdSKonstantin Belousov 	}
65e1976efdSKonstantin Belousov 	if (WIFSIGNALED(status)) {
66e1976efdSKonstantin Belousov 		if (first)
67e1976efdSKonstantin Belousov 			first = 0;
68e1976efdSKonstantin Belousov 		else
69e1976efdSKonstantin Belousov 			strlcat(c, ",", sizeof(c));
70e1976efdSKonstantin Belousov 		snprintf(b, sizeof(b), "SIG(%s)", strsignal(WTERMSIG(status)));
71e1976efdSKonstantin Belousov 		strlcat(c, b, sizeof(c));
72e1976efdSKonstantin Belousov 		if (WCOREDUMP(status))
73e1976efdSKonstantin Belousov 			strlcat(c, ",CORE", sizeof(c));
74e1976efdSKonstantin Belousov 	}
75e1976efdSKonstantin Belousov 	if (WIFSTOPPED(status)) {
76e1976efdSKonstantin Belousov 		if (first)
77e1976efdSKonstantin Belousov 			first = 0;
78e1976efdSKonstantin Belousov 		else
79e1976efdSKonstantin Belousov 			strlcat(c, ",", sizeof(c));
80e1976efdSKonstantin Belousov 		snprintf(b, sizeof(b), "SIG(%s)", strsignal(WSTOPSIG(status)));
81e1976efdSKonstantin Belousov 		strlcat(c, b, sizeof(c));
82e1976efdSKonstantin Belousov 	}
83e1976efdSKonstantin Belousov 	return (c);
84e1976efdSKonstantin Belousov }
85e1976efdSKonstantin Belousov 
86e1976efdSKonstantin Belousov static const char *
87e1976efdSKonstantin Belousov decode_pl_flags(struct ptrace_lwpinfo *lwpinfo)
88e1976efdSKonstantin Belousov {
89e1976efdSKonstantin Belousov 	static char c[128];
90e1976efdSKonstantin Belousov 	static struct decode_tag {
91e1976efdSKonstantin Belousov 		int flag;
92e1976efdSKonstantin Belousov 		const char *desc;
93e1976efdSKonstantin Belousov 	} decode[] = {
94e1976efdSKonstantin Belousov 		{ PL_FLAG_SA, "SA" },
95e1976efdSKonstantin Belousov 		{ PL_FLAG_BOUND, "BOUND" },
96e1976efdSKonstantin Belousov 		{ PL_FLAG_SCE, "SCE" },
97e1976efdSKonstantin Belousov 		{ PL_FLAG_SCX, "SCX" },
98e1976efdSKonstantin Belousov 		{ PL_FLAG_EXEC, "EXEC" },
99e1976efdSKonstantin Belousov 		{ PL_FLAG_SI, "SI" },
100e1976efdSKonstantin Belousov 		{ PL_FLAG_FORKED, "FORKED" },
101b275edf7SKonstantin Belousov 		{ PL_FLAG_CHILD, "CHILD" },
102b275edf7SKonstantin Belousov 		{ PL_FLAG_BORN, "LWPBORN" },
103b275edf7SKonstantin Belousov 		{ PL_FLAG_EXITED, "LWPEXITED" },
104b275edf7SKonstantin Belousov 		{ PL_FLAG_VFORKED, "VFORKED" },
105b275edf7SKonstantin Belousov 		{ PL_FLAG_VFORK_DONE, "VFORKDONE" },
106e1976efdSKonstantin Belousov 	};
107e1976efdSKonstantin Belousov 	char de[32];
108e1976efdSKonstantin Belousov 	unsigned first, flags, i;
109e1976efdSKonstantin Belousov 
110e1976efdSKonstantin Belousov 	c[0] = '\0';
111e1976efdSKonstantin Belousov 	first = 1;
112e1976efdSKonstantin Belousov 	flags = lwpinfo->pl_flags;
113e1976efdSKonstantin Belousov 	for (i = 0; i < sizeof(decode) / sizeof(decode[0]); i++) {
114e1976efdSKonstantin Belousov 		if ((flags & decode[i].flag) != 0) {
115e1976efdSKonstantin Belousov 			if (first)
116e1976efdSKonstantin Belousov 				first = 0;
117e1976efdSKonstantin Belousov 			else
118e1976efdSKonstantin Belousov 				strlcat(c, ",", sizeof(c));
119e1976efdSKonstantin Belousov 			strlcat(c, decode[i].desc, sizeof(c));
120e1976efdSKonstantin Belousov 			flags &= ~decode[i].flag;
121e1976efdSKonstantin Belousov 		}
122e1976efdSKonstantin Belousov 	}
123e1976efdSKonstantin Belousov 	for (i = 0; i < sizeof(flags) * NBBY; i++) {
124e1976efdSKonstantin Belousov 		if ((flags & (1 << i)) != 0) {
125e1976efdSKonstantin Belousov 			if (first)
126e1976efdSKonstantin Belousov 				first = 0;
127e1976efdSKonstantin Belousov 			else
128e1976efdSKonstantin Belousov 				strlcat(c, ",", sizeof(c));
129e1976efdSKonstantin Belousov 			snprintf(de, sizeof(de), "<%d>", i);
130e1976efdSKonstantin Belousov 			strlcat(c, de, sizeof(c));
131e1976efdSKonstantin Belousov 		}
132e1976efdSKonstantin Belousov 	}
133e1976efdSKonstantin Belousov 	return (c);
134e1976efdSKonstantin Belousov }
135e1976efdSKonstantin Belousov 
136e1976efdSKonstantin Belousov static const char *
137e1976efdSKonstantin Belousov decode_pl_event(struct ptrace_lwpinfo *lwpinfo)
138e1976efdSKonstantin Belousov {
139e1976efdSKonstantin Belousov 
140e1976efdSKonstantin Belousov 	switch (lwpinfo->pl_event) {
141e1976efdSKonstantin Belousov 	case PL_EVENT_NONE:
142e1976efdSKonstantin Belousov 		return ("NONE");
143e1976efdSKonstantin Belousov 
144e1976efdSKonstantin Belousov 	case PL_EVENT_SIGNAL:
145e1976efdSKonstantin Belousov 		return ("SIG");
146e1976efdSKonstantin Belousov 
147e1976efdSKonstantin Belousov 	default:
148e1976efdSKonstantin Belousov 		return ("UNKNOWN");
149e1976efdSKonstantin Belousov 	}
150e1976efdSKonstantin Belousov }
151e1976efdSKonstantin Belousov 
152e1976efdSKonstantin Belousov static void
153e1976efdSKonstantin Belousov get_pathname(pid_t pid)
154e1976efdSKonstantin Belousov {
155e1976efdSKonstantin Belousov 	char pathname[PATH_MAX];
156e1976efdSKonstantin Belousov 	int error, name[4];
157e1976efdSKonstantin Belousov 	size_t len;
158e1976efdSKonstantin Belousov 
159e1976efdSKonstantin Belousov 	name[0] = CTL_KERN;
160e1976efdSKonstantin Belousov 	name[1] = KERN_PROC;
161e1976efdSKonstantin Belousov 	name[2] = KERN_PROC_PATHNAME;
162e1976efdSKonstantin Belousov 	name[3] = pid;
163e1976efdSKonstantin Belousov 
164e1976efdSKonstantin Belousov 	len = sizeof(pathname);
165e1976efdSKonstantin Belousov 	error = sysctl(name, 4, pathname, &len, NULL, 0);
166e1976efdSKonstantin Belousov 	if (error < 0) {
167e1976efdSKonstantin Belousov 		if (errno != ESRCH) {
168e1976efdSKonstantin Belousov 			fprintf(stderr, "sysctl kern.proc.pathname.%d: %s\n",
169e1976efdSKonstantin Belousov 			    pid, strerror(errno));
170e1976efdSKonstantin Belousov 			return;
171e1976efdSKonstantin Belousov 		}
172e1976efdSKonstantin Belousov 		fprintf(stderr, "pid %d exited\n", pid);
173e1976efdSKonstantin Belousov 		return;
174e1976efdSKonstantin Belousov 	}
175e1976efdSKonstantin Belousov 	if (len == 0 || strlen(pathname) == 0) {
176e1976efdSKonstantin Belousov 		fprintf(stderr, "No cached pathname for process %d\n", pid);
177e1976efdSKonstantin Belousov 		return;
178e1976efdSKonstantin Belousov 	}
179e1976efdSKonstantin Belousov 	printf(TRACE "pid %d path %s\n", pid, pathname);
180e1976efdSKonstantin Belousov }
181e1976efdSKonstantin Belousov 
182e1976efdSKonstantin Belousov static void
183e1976efdSKonstantin Belousov wait_info(int pid, int status, struct ptrace_lwpinfo *lwpinfo)
184e1976efdSKonstantin Belousov {
185965ee749SKonstantin Belousov 	long *args;
186965ee749SKonstantin Belousov 	int error, i;
187e1976efdSKonstantin Belousov 
188e1976efdSKonstantin Belousov 	printf(TRACE "pid %d wait %s", pid,
189e1976efdSKonstantin Belousov 	    decode_wait_status(status));
190e1976efdSKonstantin Belousov 	if (lwpinfo != NULL) {
191e1976efdSKonstantin Belousov 		printf(" event %s flags %s",
192e1976efdSKonstantin Belousov 		    decode_pl_event(lwpinfo), decode_pl_flags(lwpinfo));
193965ee749SKonstantin Belousov 		if ((lwpinfo->pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)) != 0) {
194965ee749SKonstantin Belousov 			printf(" sc%d", lwpinfo->pl_syscall_code);
195965ee749SKonstantin Belousov 			args = calloc(lwpinfo->pl_syscall_narg, sizeof(long));
196965ee749SKonstantin Belousov 			error = ptrace(PT_GET_SC_ARGS, lwpinfo->pl_lwpid,
197965ee749SKonstantin Belousov 			    (caddr_t)args, lwpinfo->pl_syscall_narg *
198965ee749SKonstantin Belousov 			    sizeof(long));
199965ee749SKonstantin Belousov 			if (error == 0) {
2009a8eb5dbSKonstantin Belousov 				printf("(");
201965ee749SKonstantin Belousov 				for (i = 0; i < (int)lwpinfo->pl_syscall_narg;
202965ee749SKonstantin Belousov 				    i++) {
2039a8eb5dbSKonstantin Belousov 					printf("%s%#lx", i == 0 ? "" : ",",
204965ee749SKonstantin Belousov 					    args[i]);
205965ee749SKonstantin Belousov 				}
2069a8eb5dbSKonstantin Belousov 				printf(")");
207965ee749SKonstantin Belousov 			} else {
208965ee749SKonstantin Belousov 				fprintf(stderr, "PT_GET_SC_ARGS failed: %s",
209965ee749SKonstantin Belousov 				    strerror(errno));
210965ee749SKonstantin Belousov 			}
211965ee749SKonstantin Belousov 			free(args);
212965ee749SKonstantin Belousov 		}
213e1976efdSKonstantin Belousov 	}
214e1976efdSKonstantin Belousov 	printf("\n");
215e1976efdSKonstantin Belousov }
216e1976efdSKonstantin Belousov 
217*6403a140SKonstantin Belousov static int trace_syscalls = 1;
218*6403a140SKonstantin Belousov static int remote_getpid = 0;
219*6403a140SKonstantin Belousov 
220e1976efdSKonstantin Belousov static int
221e1976efdSKonstantin Belousov trace_sc(int pid)
222e1976efdSKonstantin Belousov {
223*6403a140SKonstantin Belousov 	struct ptrace_sc_remote pscr;
224e1976efdSKonstantin Belousov 	struct ptrace_lwpinfo lwpinfo;
225e1976efdSKonstantin Belousov 	int status;
226e1976efdSKonstantin Belousov 
227e1976efdSKonstantin Belousov 	if (ptrace(PT_TO_SCE, pid, (caddr_t)1, 0) < 0) {
228e1976efdSKonstantin Belousov 		perror("PT_TO_SCE");
229e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
230e1976efdSKonstantin Belousov 		return (-1);
231e1976efdSKonstantin Belousov 	}
232e1976efdSKonstantin Belousov 
233e1976efdSKonstantin Belousov 	if (waitpid(pid, &status, 0) == -1) {
234e1976efdSKonstantin Belousov 		perror("waitpid");
235e1976efdSKonstantin Belousov 		return (-1);
236e1976efdSKonstantin Belousov 	}
237e1976efdSKonstantin Belousov 	if (WIFEXITED(status) || WIFSIGNALED(status)) {
238e1976efdSKonstantin Belousov 		wait_info(pid, status, NULL);
239e1976efdSKonstantin Belousov 		return (-1);
240e1976efdSKonstantin Belousov 	}
241e1976efdSKonstantin Belousov 	assert(WIFSTOPPED(status));
242e1976efdSKonstantin Belousov 	assert(WSTOPSIG(status) == SIGTRAP);
243e1976efdSKonstantin Belousov 
244e1976efdSKonstantin Belousov 	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
245e1976efdSKonstantin Belousov 		perror("PT_LWPINFO");
246e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
247e1976efdSKonstantin Belousov 		return (-1);
248e1976efdSKonstantin Belousov 	}
249e1976efdSKonstantin Belousov 	wait_info(pid, status, &lwpinfo);
250e1976efdSKonstantin Belousov 	assert(lwpinfo.pl_flags & PL_FLAG_SCE);
251e1976efdSKonstantin Belousov 
252e1976efdSKonstantin Belousov 	if (ptrace(PT_TO_SCX, pid, (caddr_t)1, 0) < 0) {
253e1976efdSKonstantin Belousov 		perror("PT_TO_SCX");
254e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
255e1976efdSKonstantin Belousov 		return (-1);
256e1976efdSKonstantin Belousov 	}
257e1976efdSKonstantin Belousov 
258e1976efdSKonstantin Belousov 	if (waitpid(pid, &status, 0) == -1) {
259e1976efdSKonstantin Belousov 		perror("waitpid");
260e1976efdSKonstantin Belousov 		return (-1);
261e1976efdSKonstantin Belousov 	}
262e1976efdSKonstantin Belousov 	if (WIFEXITED(status) || WIFSIGNALED(status)) {
263e1976efdSKonstantin Belousov 		wait_info(pid, status, NULL);
264e1976efdSKonstantin Belousov 		return (-1);
265e1976efdSKonstantin Belousov 	}
266e1976efdSKonstantin Belousov 	assert(WIFSTOPPED(status));
267e1976efdSKonstantin Belousov 	assert(WSTOPSIG(status) == SIGTRAP);
268e1976efdSKonstantin Belousov 
269e1976efdSKonstantin Belousov 	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
270e1976efdSKonstantin Belousov 		perror("PT_LWPINFO");
271e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
272e1976efdSKonstantin Belousov 		return (-1);
273e1976efdSKonstantin Belousov 	}
274e1976efdSKonstantin Belousov 	wait_info(pid, status, &lwpinfo);
275e1976efdSKonstantin Belousov 	assert(lwpinfo.pl_flags & PL_FLAG_SCX);
276e1976efdSKonstantin Belousov 
277*6403a140SKonstantin Belousov 	if (remote_getpid) {
278*6403a140SKonstantin Belousov 		memset(&pscr, 0, sizeof(pscr));
279*6403a140SKonstantin Belousov 		pscr.pscr_syscall = SYS_getpid;
280*6403a140SKonstantin Belousov 		pscr.pscr_nargs = 0;
281*6403a140SKonstantin Belousov 		if (ptrace(PT_SC_REMOTE, pid, (caddr_t)&pscr,
282*6403a140SKonstantin Belousov 		    sizeof(pscr)) < 0) {
283*6403a140SKonstantin Belousov 			perror("PT_SC_REMOTE");
284*6403a140SKonstantin Belousov 			ptrace(PT_KILL, pid, NULL, 0);
285*6403a140SKonstantin Belousov 			return (-1);
286*6403a140SKonstantin Belousov 		} else {
287*6403a140SKonstantin Belousov 			printf(TRACE "remote getpid %ld errno %d\n",
288*6403a140SKonstantin Belousov 			    pscr.pscr_ret.sr_retval[0], pscr.pscr_ret.sr_error);
289*6403a140SKonstantin Belousov 			if (waitpid(pid, &status, 0) == -1) {
290*6403a140SKonstantin Belousov 			  perror("waitpid");
291*6403a140SKonstantin Belousov 			  return (-1);
292*6403a140SKonstantin Belousov 			}
293*6403a140SKonstantin Belousov 		}
294*6403a140SKonstantin Belousov 	}
295e1976efdSKonstantin Belousov 	if (lwpinfo.pl_flags & PL_FLAG_EXEC)
296e1976efdSKonstantin Belousov 		get_pathname(pid);
297e1976efdSKonstantin Belousov 
298e1976efdSKonstantin Belousov 	if (lwpinfo.pl_flags & PL_FLAG_FORKED) {
299e1976efdSKonstantin Belousov 		printf(TRACE "forked child %d\n", lwpinfo.pl_child_pid);
300e1976efdSKonstantin Belousov 		return (lwpinfo.pl_child_pid);
301e1976efdSKonstantin Belousov 	}
302e1976efdSKonstantin Belousov 	return (0);
303e1976efdSKonstantin Belousov }
304e1976efdSKonstantin Belousov 
305e1976efdSKonstantin Belousov static int
306e1976efdSKonstantin Belousov trace_cont(int pid)
307e1976efdSKonstantin Belousov {
308e1976efdSKonstantin Belousov 	struct ptrace_lwpinfo lwpinfo;
309e1976efdSKonstantin Belousov 	int status;
310e1976efdSKonstantin Belousov 
311e1976efdSKonstantin Belousov 	if (ptrace(PT_CONTINUE, pid, (caddr_t)1, 0) < 0) {
312e1976efdSKonstantin Belousov 		perror("PT_CONTINUE");
313e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
314e1976efdSKonstantin Belousov 		return (-1);
315e1976efdSKonstantin Belousov 	}
316e1976efdSKonstantin Belousov 
317e1976efdSKonstantin Belousov 	if (waitpid(pid, &status, 0) == -1) {
318e1976efdSKonstantin Belousov 		perror("waitpid");
319e1976efdSKonstantin Belousov 		return (-1);
320e1976efdSKonstantin Belousov 	}
321e1976efdSKonstantin Belousov 	if (WIFEXITED(status) || WIFSIGNALED(status)) {
322e1976efdSKonstantin Belousov 		wait_info(pid, status, NULL);
323e1976efdSKonstantin Belousov 		return (-1);
324e1976efdSKonstantin Belousov 	}
325e1976efdSKonstantin Belousov 	assert(WIFSTOPPED(status));
326e1976efdSKonstantin Belousov 	assert(WSTOPSIG(status) == SIGTRAP);
327e1976efdSKonstantin Belousov 
328e1976efdSKonstantin Belousov 	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
329e1976efdSKonstantin Belousov 		perror("PT_LWPINFO");
330e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
331e1976efdSKonstantin Belousov 		return (-1);
332e1976efdSKonstantin Belousov 	}
333e1976efdSKonstantin Belousov 	wait_info(pid, status, &lwpinfo);
334e1976efdSKonstantin Belousov 
335e1976efdSKonstantin Belousov 	if ((lwpinfo.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) ==
336e1976efdSKonstantin Belousov 	    (PL_FLAG_EXEC | PL_FLAG_SCX))
337e1976efdSKonstantin Belousov 		get_pathname(pid);
338e1976efdSKonstantin Belousov 
339e1976efdSKonstantin Belousov 	if ((lwpinfo.pl_flags & (PL_FLAG_FORKED | PL_FLAG_SCX)) ==
340e1976efdSKonstantin Belousov 	    (PL_FLAG_FORKED | PL_FLAG_SCX)) {
341e1976efdSKonstantin Belousov 		printf(TRACE "forked child %d\n", lwpinfo.pl_child_pid);
342e1976efdSKonstantin Belousov 		return (lwpinfo.pl_child_pid);
343e1976efdSKonstantin Belousov 	}
344e1976efdSKonstantin Belousov 
345e1976efdSKonstantin Belousov 	return (0);
346e1976efdSKonstantin Belousov }
347e1976efdSKonstantin Belousov 
348e1976efdSKonstantin Belousov static int
349e1976efdSKonstantin Belousov trace(pid_t pid)
350e1976efdSKonstantin Belousov {
351e1976efdSKonstantin Belousov 
352e1976efdSKonstantin Belousov 	return (trace_syscalls ? trace_sc(pid) : trace_cont(pid));
353e1976efdSKonstantin Belousov }
354e1976efdSKonstantin Belousov 
355e1976efdSKonstantin Belousov 
356e1976efdSKonstantin Belousov int
357e1976efdSKonstantin Belousov main(int argc, char *argv[])
358e1976efdSKonstantin Belousov {
359e1976efdSKonstantin Belousov 	struct ptrace_lwpinfo lwpinfo;
360e1976efdSKonstantin Belousov 	int c, status, use_vfork;
361e1976efdSKonstantin Belousov 	pid_t pid, pid1;
362e1976efdSKonstantin Belousov 
363e1976efdSKonstantin Belousov 	trace_syscalls = 1;
364*6403a140SKonstantin Belousov 	remote_getpid = 0;
365e1976efdSKonstantin Belousov 	use_vfork = 0;
366*6403a140SKonstantin Belousov 	while ((c = getopt(argc, argv, "crsv")) != -1) {
367e1976efdSKonstantin Belousov 		switch (c) {
368e1976efdSKonstantin Belousov 		case 'c':
369e1976efdSKonstantin Belousov 			trace_syscalls = 0;
370e1976efdSKonstantin Belousov 			break;
371*6403a140SKonstantin Belousov 		case 'r':
372*6403a140SKonstantin Belousov 			remote_getpid = 1;
373*6403a140SKonstantin Belousov 			break;
374e1976efdSKonstantin Belousov 		case 's':
375e1976efdSKonstantin Belousov 			trace_syscalls = 1;
376e1976efdSKonstantin Belousov 			break;
377e1976efdSKonstantin Belousov 		case 'v':
378e1976efdSKonstantin Belousov 			use_vfork = 1;
379e1976efdSKonstantin Belousov 			break;
380e1976efdSKonstantin Belousov 		default:
381e1976efdSKonstantin Belousov 		case '?':
382*6403a140SKonstantin Belousov 			fprintf(stderr, "Usage: %s [-c] [-r] [-s] [-v]\n",
383*6403a140SKonstantin Belousov 			    argv[0]);
384e1976efdSKonstantin Belousov 			return (2);
385e1976efdSKonstantin Belousov 		}
386e1976efdSKonstantin Belousov 	}
387e1976efdSKonstantin Belousov 
388e1976efdSKonstantin Belousov 	if ((pid = fork()) < 0) {
389e1976efdSKonstantin Belousov 		perror("fork");
390e1976efdSKonstantin Belousov 		return 1;
391e1976efdSKonstantin Belousov 	}
392e1976efdSKonstantin Belousov 	else if (pid == 0) {
393e1976efdSKonstantin Belousov 		if (ptrace(PT_TRACE_ME, 0, NULL, 0) < 0) {
394e1976efdSKonstantin Belousov 			perror("PT_TRACE_ME");
395e1976efdSKonstantin Belousov 			_exit(1);
396e1976efdSKonstantin Belousov 		}
397e1976efdSKonstantin Belousov 		kill(getpid(), SIGSTOP);
398e1976efdSKonstantin Belousov 		getpid();
399e1976efdSKonstantin Belousov 		if ((pid1 = use_vfork ? vfork() : fork()) < 0) {
400e1976efdSKonstantin Belousov 			perror("fork1");
401e1976efdSKonstantin Belousov 			return (1);
402e1976efdSKonstantin Belousov 		} else if (pid1 == 0) {
403e1976efdSKonstantin Belousov 			printf("Hi from child %d\n", getpid());
404e1976efdSKonstantin Belousov 			execl("/bin/ls", "ls", "/", (char *)NULL);
405e1976efdSKonstantin Belousov 		}
406e1976efdSKonstantin Belousov 	}
407e1976efdSKonstantin Belousov 	else { /* parent */
408e1976efdSKonstantin Belousov 		if (waitpid(pid, &status, 0) == -1) {
409e1976efdSKonstantin Belousov 			perror("waitpid");
410e1976efdSKonstantin Belousov 			return (-1);
411e1976efdSKonstantin Belousov 		}
412e1976efdSKonstantin Belousov 		assert(WIFSTOPPED(status));
413e1976efdSKonstantin Belousov 		assert(WSTOPSIG(status) == SIGSTOP);
414e1976efdSKonstantin Belousov 
415e1976efdSKonstantin Belousov 		if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo,
416e1976efdSKonstantin Belousov 		    sizeof(lwpinfo)) < 0) {
417e1976efdSKonstantin Belousov 			perror("PT_LWPINFO");
418e1976efdSKonstantin Belousov 			ptrace(PT_KILL, pid, NULL, 0);
419e1976efdSKonstantin Belousov 			return (-1);
420e1976efdSKonstantin Belousov 		}
421e1976efdSKonstantin Belousov 		wait_info(pid, status, &lwpinfo);
422e1976efdSKonstantin Belousov 
423e1976efdSKonstantin Belousov 		if (ptrace(PT_FOLLOW_FORK, pid, 0, 1) < 0) {
424e1976efdSKonstantin Belousov 			perror("PT_FOLLOW_FORK");
425e1976efdSKonstantin Belousov 			ptrace(PT_KILL, pid, NULL, 0);
426e1976efdSKonstantin Belousov 			return (2);
427e1976efdSKonstantin Belousov 		}
428e1976efdSKonstantin Belousov 
429e1976efdSKonstantin Belousov 		while ((pid1 = trace(pid)) >= 0) {
430e1976efdSKonstantin Belousov 			if (pid1 != 0) {
431e1976efdSKonstantin Belousov 				printf(TRACE "attached to pid %d\n", pid1);
432e1976efdSKonstantin Belousov #if 0
433e1976efdSKonstantin Belousov 				kill(pid1, SIGCONT);
434e1976efdSKonstantin Belousov #endif
435e1976efdSKonstantin Belousov 				if (waitpid(pid1, &status, 0) == -1) {
436e1976efdSKonstantin Belousov 					perror("waitpid");
437e1976efdSKonstantin Belousov 					return (-1);
438e1976efdSKonstantin Belousov 				}
439e1976efdSKonstantin Belousov 				printf(TRACE "nested loop, pid %d status %s\n",
440e1976efdSKonstantin Belousov 				    pid1, decode_wait_status(status));
441e1976efdSKonstantin Belousov 				assert(WIFSTOPPED(status));
442e1976efdSKonstantin Belousov 				assert(WSTOPSIG(status) == SIGSTOP);
443e1976efdSKonstantin Belousov 				if (ptrace(PT_LWPINFO, pid1, (caddr_t)&lwpinfo,
444e1976efdSKonstantin Belousov 				    sizeof(lwpinfo)) < 0) {
445e1976efdSKonstantin Belousov 					perror("PT_LWPINFO");
446e1976efdSKonstantin Belousov 					ptrace(PT_KILL, pid1, NULL, 0);
447e1976efdSKonstantin Belousov 					return (-1);
448e1976efdSKonstantin Belousov 				}
449e1976efdSKonstantin Belousov 				wait_info(pid1, status, &lwpinfo);
450e1976efdSKonstantin Belousov 
451e1976efdSKonstantin Belousov 				while (trace(pid1) >= 0)
452e1976efdSKonstantin Belousov 					;
453e1976efdSKonstantin Belousov 			}
454e1976efdSKonstantin Belousov 		}
455e1976efdSKonstantin Belousov 
456e1976efdSKonstantin Belousov 		ptrace(PT_CONTINUE, pid, (caddr_t)1, 0);
457e1976efdSKonstantin Belousov 	}
458e1976efdSKonstantin Belousov 	return (0);
459e1976efdSKonstantin Belousov }
460