xref: /freebsd/tools/test/ptrace/scescx.c (revision 6bfca4dcab07dad45a805879d954876b353c0810)
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/types.h>
27e1976efdSKonstantin Belousov #include <sys/ptrace.h>
28*6403a140SKonstantin Belousov #include <sys/syscall.h>
29e1976efdSKonstantin Belousov #include <sys/sysctl.h>
30e1976efdSKonstantin Belousov #include <sys/wait.h>
31e1976efdSKonstantin Belousov #include <assert.h>
32e1976efdSKonstantin Belousov #include <errno.h>
33e1976efdSKonstantin Belousov #include <signal.h>
34e1976efdSKonstantin Belousov #include <stdio.h>
35e1976efdSKonstantin Belousov #include <stdlib.h>
36e1976efdSKonstantin Belousov #include <string.h>
37e1976efdSKonstantin Belousov #include <unistd.h>
38e1976efdSKonstantin Belousov 
39e1976efdSKonstantin Belousov #define TRACE	">>>> "
40e1976efdSKonstantin Belousov 
41e1976efdSKonstantin Belousov static const char *
decode_wait_status(int status)42e1976efdSKonstantin Belousov decode_wait_status(int status)
43e1976efdSKonstantin Belousov {
44e1976efdSKonstantin Belousov 	static char c[128];
45e1976efdSKonstantin Belousov 	char b[32];
46e1976efdSKonstantin Belousov 	int first;
47e1976efdSKonstantin Belousov 
48e1976efdSKonstantin Belousov 	c[0] = '\0';
49e1976efdSKonstantin Belousov 	first = 1;
50e1976efdSKonstantin Belousov 	if (WIFCONTINUED(status)) {
51e1976efdSKonstantin Belousov 		first = 0;
52e1976efdSKonstantin Belousov 		strlcat(c, "CONT", sizeof(c));
53e1976efdSKonstantin Belousov 	}
54e1976efdSKonstantin Belousov 	if (WIFEXITED(status)) {
55e1976efdSKonstantin Belousov 		if (first)
56e1976efdSKonstantin Belousov 			first = 0;
57e1976efdSKonstantin Belousov 		else
58e1976efdSKonstantin Belousov 			strlcat(c, ",", sizeof(c));
59e1976efdSKonstantin Belousov 		snprintf(b, sizeof(b), "EXIT(%d)", WEXITSTATUS(status));
60e1976efdSKonstantin Belousov 		strlcat(c, b, sizeof(c));
61e1976efdSKonstantin Belousov 	}
62e1976efdSKonstantin Belousov 	if (WIFSIGNALED(status)) {
63e1976efdSKonstantin Belousov 		if (first)
64e1976efdSKonstantin Belousov 			first = 0;
65e1976efdSKonstantin Belousov 		else
66e1976efdSKonstantin Belousov 			strlcat(c, ",", sizeof(c));
67e1976efdSKonstantin Belousov 		snprintf(b, sizeof(b), "SIG(%s)", strsignal(WTERMSIG(status)));
68e1976efdSKonstantin Belousov 		strlcat(c, b, sizeof(c));
69e1976efdSKonstantin Belousov 		if (WCOREDUMP(status))
70e1976efdSKonstantin Belousov 			strlcat(c, ",CORE", sizeof(c));
71e1976efdSKonstantin Belousov 	}
72e1976efdSKonstantin Belousov 	if (WIFSTOPPED(status)) {
73e1976efdSKonstantin Belousov 		if (first)
74e1976efdSKonstantin Belousov 			first = 0;
75e1976efdSKonstantin Belousov 		else
76e1976efdSKonstantin Belousov 			strlcat(c, ",", sizeof(c));
77e1976efdSKonstantin Belousov 		snprintf(b, sizeof(b), "SIG(%s)", strsignal(WSTOPSIG(status)));
78e1976efdSKonstantin Belousov 		strlcat(c, b, sizeof(c));
79e1976efdSKonstantin Belousov 	}
80e1976efdSKonstantin Belousov 	return (c);
81e1976efdSKonstantin Belousov }
82e1976efdSKonstantin Belousov 
83e1976efdSKonstantin Belousov static const char *
decode_pl_flags(struct ptrace_lwpinfo * lwpinfo)84e1976efdSKonstantin Belousov decode_pl_flags(struct ptrace_lwpinfo *lwpinfo)
85e1976efdSKonstantin Belousov {
86e1976efdSKonstantin Belousov 	static char c[128];
87e1976efdSKonstantin Belousov 	static struct decode_tag {
88e1976efdSKonstantin Belousov 		int flag;
89e1976efdSKonstantin Belousov 		const char *desc;
90e1976efdSKonstantin Belousov 	} decode[] = {
91e1976efdSKonstantin Belousov 		{ PL_FLAG_SA, "SA" },
92e1976efdSKonstantin Belousov 		{ PL_FLAG_BOUND, "BOUND" },
93e1976efdSKonstantin Belousov 		{ PL_FLAG_SCE, "SCE" },
94e1976efdSKonstantin Belousov 		{ PL_FLAG_SCX, "SCX" },
95e1976efdSKonstantin Belousov 		{ PL_FLAG_EXEC, "EXEC" },
96e1976efdSKonstantin Belousov 		{ PL_FLAG_SI, "SI" },
97e1976efdSKonstantin Belousov 		{ PL_FLAG_FORKED, "FORKED" },
98b275edf7SKonstantin Belousov 		{ PL_FLAG_CHILD, "CHILD" },
99b275edf7SKonstantin Belousov 		{ PL_FLAG_BORN, "LWPBORN" },
100b275edf7SKonstantin Belousov 		{ PL_FLAG_EXITED, "LWPEXITED" },
101b275edf7SKonstantin Belousov 		{ PL_FLAG_VFORKED, "VFORKED" },
102b275edf7SKonstantin Belousov 		{ PL_FLAG_VFORK_DONE, "VFORKDONE" },
103e1976efdSKonstantin Belousov 	};
104e1976efdSKonstantin Belousov 	char de[32];
105e1976efdSKonstantin Belousov 	unsigned first, flags, i;
106e1976efdSKonstantin Belousov 
107e1976efdSKonstantin Belousov 	c[0] = '\0';
108e1976efdSKonstantin Belousov 	first = 1;
109e1976efdSKonstantin Belousov 	flags = lwpinfo->pl_flags;
110e1976efdSKonstantin Belousov 	for (i = 0; i < sizeof(decode) / sizeof(decode[0]); i++) {
111e1976efdSKonstantin Belousov 		if ((flags & decode[i].flag) != 0) {
112e1976efdSKonstantin Belousov 			if (first)
113e1976efdSKonstantin Belousov 				first = 0;
114e1976efdSKonstantin Belousov 			else
115e1976efdSKonstantin Belousov 				strlcat(c, ",", sizeof(c));
116e1976efdSKonstantin Belousov 			strlcat(c, decode[i].desc, sizeof(c));
117e1976efdSKonstantin Belousov 			flags &= ~decode[i].flag;
118e1976efdSKonstantin Belousov 		}
119e1976efdSKonstantin Belousov 	}
120e1976efdSKonstantin Belousov 	for (i = 0; i < sizeof(flags) * NBBY; i++) {
121e1976efdSKonstantin Belousov 		if ((flags & (1 << i)) != 0) {
122e1976efdSKonstantin Belousov 			if (first)
123e1976efdSKonstantin Belousov 				first = 0;
124e1976efdSKonstantin Belousov 			else
125e1976efdSKonstantin Belousov 				strlcat(c, ",", sizeof(c));
126e1976efdSKonstantin Belousov 			snprintf(de, sizeof(de), "<%d>", i);
127e1976efdSKonstantin Belousov 			strlcat(c, de, sizeof(c));
128e1976efdSKonstantin Belousov 		}
129e1976efdSKonstantin Belousov 	}
130e1976efdSKonstantin Belousov 	return (c);
131e1976efdSKonstantin Belousov }
132e1976efdSKonstantin Belousov 
133e1976efdSKonstantin Belousov static const char *
decode_pl_event(struct ptrace_lwpinfo * lwpinfo)134e1976efdSKonstantin Belousov decode_pl_event(struct ptrace_lwpinfo *lwpinfo)
135e1976efdSKonstantin Belousov {
136e1976efdSKonstantin Belousov 
137e1976efdSKonstantin Belousov 	switch (lwpinfo->pl_event) {
138e1976efdSKonstantin Belousov 	case PL_EVENT_NONE:
139e1976efdSKonstantin Belousov 		return ("NONE");
140e1976efdSKonstantin Belousov 
141e1976efdSKonstantin Belousov 	case PL_EVENT_SIGNAL:
142e1976efdSKonstantin Belousov 		return ("SIG");
143e1976efdSKonstantin Belousov 
144e1976efdSKonstantin Belousov 	default:
145e1976efdSKonstantin Belousov 		return ("UNKNOWN");
146e1976efdSKonstantin Belousov 	}
147e1976efdSKonstantin Belousov }
148e1976efdSKonstantin Belousov 
149e1976efdSKonstantin Belousov static void
get_pathname(pid_t pid)150e1976efdSKonstantin Belousov get_pathname(pid_t pid)
151e1976efdSKonstantin Belousov {
152e1976efdSKonstantin Belousov 	char pathname[PATH_MAX];
153e1976efdSKonstantin Belousov 	int error, name[4];
154e1976efdSKonstantin Belousov 	size_t len;
155e1976efdSKonstantin Belousov 
156e1976efdSKonstantin Belousov 	name[0] = CTL_KERN;
157e1976efdSKonstantin Belousov 	name[1] = KERN_PROC;
158e1976efdSKonstantin Belousov 	name[2] = KERN_PROC_PATHNAME;
159e1976efdSKonstantin Belousov 	name[3] = pid;
160e1976efdSKonstantin Belousov 
161e1976efdSKonstantin Belousov 	len = sizeof(pathname);
162e1976efdSKonstantin Belousov 	error = sysctl(name, 4, pathname, &len, NULL, 0);
163e1976efdSKonstantin Belousov 	if (error < 0) {
164e1976efdSKonstantin Belousov 		if (errno != ESRCH) {
165e1976efdSKonstantin Belousov 			fprintf(stderr, "sysctl kern.proc.pathname.%d: %s\n",
166e1976efdSKonstantin Belousov 			    pid, strerror(errno));
167e1976efdSKonstantin Belousov 			return;
168e1976efdSKonstantin Belousov 		}
169e1976efdSKonstantin Belousov 		fprintf(stderr, "pid %d exited\n", pid);
170e1976efdSKonstantin Belousov 		return;
171e1976efdSKonstantin Belousov 	}
172e1976efdSKonstantin Belousov 	if (len == 0 || strlen(pathname) == 0) {
173e1976efdSKonstantin Belousov 		fprintf(stderr, "No cached pathname for process %d\n", pid);
174e1976efdSKonstantin Belousov 		return;
175e1976efdSKonstantin Belousov 	}
176e1976efdSKonstantin Belousov 	printf(TRACE "pid %d path %s\n", pid, pathname);
177e1976efdSKonstantin Belousov }
178e1976efdSKonstantin Belousov 
179e1976efdSKonstantin Belousov static void
wait_info(int pid,int status,struct ptrace_lwpinfo * lwpinfo)180e1976efdSKonstantin Belousov wait_info(int pid, int status, struct ptrace_lwpinfo *lwpinfo)
181e1976efdSKonstantin Belousov {
182965ee749SKonstantin Belousov 	long *args;
183965ee749SKonstantin Belousov 	int error, i;
184e1976efdSKonstantin Belousov 
185e1976efdSKonstantin Belousov 	printf(TRACE "pid %d wait %s", pid,
186e1976efdSKonstantin Belousov 	    decode_wait_status(status));
187e1976efdSKonstantin Belousov 	if (lwpinfo != NULL) {
188e1976efdSKonstantin Belousov 		printf(" event %s flags %s",
189e1976efdSKonstantin Belousov 		    decode_pl_event(lwpinfo), decode_pl_flags(lwpinfo));
190965ee749SKonstantin Belousov 		if ((lwpinfo->pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)) != 0) {
191965ee749SKonstantin Belousov 			printf(" sc%d", lwpinfo->pl_syscall_code);
192965ee749SKonstantin Belousov 			args = calloc(lwpinfo->pl_syscall_narg, sizeof(long));
193965ee749SKonstantin Belousov 			error = ptrace(PT_GET_SC_ARGS, lwpinfo->pl_lwpid,
194965ee749SKonstantin Belousov 			    (caddr_t)args, lwpinfo->pl_syscall_narg *
195965ee749SKonstantin Belousov 			    sizeof(long));
196965ee749SKonstantin Belousov 			if (error == 0) {
1979a8eb5dbSKonstantin Belousov 				printf("(");
198965ee749SKonstantin Belousov 				for (i = 0; i < (int)lwpinfo->pl_syscall_narg;
199965ee749SKonstantin Belousov 				    i++) {
2009a8eb5dbSKonstantin Belousov 					printf("%s%#lx", i == 0 ? "" : ",",
201965ee749SKonstantin Belousov 					    args[i]);
202965ee749SKonstantin Belousov 				}
2039a8eb5dbSKonstantin Belousov 				printf(")");
204965ee749SKonstantin Belousov 			} else {
205965ee749SKonstantin Belousov 				fprintf(stderr, "PT_GET_SC_ARGS failed: %s",
206965ee749SKonstantin Belousov 				    strerror(errno));
207965ee749SKonstantin Belousov 			}
208965ee749SKonstantin Belousov 			free(args);
209965ee749SKonstantin Belousov 		}
210e1976efdSKonstantin Belousov 	}
211e1976efdSKonstantin Belousov 	printf("\n");
212e1976efdSKonstantin Belousov }
213e1976efdSKonstantin Belousov 
214*6403a140SKonstantin Belousov static int trace_syscalls = 1;
215*6403a140SKonstantin Belousov static int remote_getpid = 0;
216*6403a140SKonstantin Belousov 
217e1976efdSKonstantin Belousov static int
trace_sc(int pid)218e1976efdSKonstantin Belousov trace_sc(int pid)
219e1976efdSKonstantin Belousov {
220*6403a140SKonstantin Belousov 	struct ptrace_sc_remote pscr;
221e1976efdSKonstantin Belousov 	struct ptrace_lwpinfo lwpinfo;
222e1976efdSKonstantin Belousov 	int status;
223e1976efdSKonstantin Belousov 
224e1976efdSKonstantin Belousov 	if (ptrace(PT_TO_SCE, pid, (caddr_t)1, 0) < 0) {
225e1976efdSKonstantin Belousov 		perror("PT_TO_SCE");
226e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
227e1976efdSKonstantin Belousov 		return (-1);
228e1976efdSKonstantin Belousov 	}
229e1976efdSKonstantin Belousov 
230e1976efdSKonstantin Belousov 	if (waitpid(pid, &status, 0) == -1) {
231e1976efdSKonstantin Belousov 		perror("waitpid");
232e1976efdSKonstantin Belousov 		return (-1);
233e1976efdSKonstantin Belousov 	}
234e1976efdSKonstantin Belousov 	if (WIFEXITED(status) || WIFSIGNALED(status)) {
235e1976efdSKonstantin Belousov 		wait_info(pid, status, NULL);
236e1976efdSKonstantin Belousov 		return (-1);
237e1976efdSKonstantin Belousov 	}
238e1976efdSKonstantin Belousov 	assert(WIFSTOPPED(status));
239e1976efdSKonstantin Belousov 	assert(WSTOPSIG(status) == SIGTRAP);
240e1976efdSKonstantin Belousov 
241e1976efdSKonstantin Belousov 	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
242e1976efdSKonstantin Belousov 		perror("PT_LWPINFO");
243e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
244e1976efdSKonstantin Belousov 		return (-1);
245e1976efdSKonstantin Belousov 	}
246e1976efdSKonstantin Belousov 	wait_info(pid, status, &lwpinfo);
247e1976efdSKonstantin Belousov 	assert(lwpinfo.pl_flags & PL_FLAG_SCE);
248e1976efdSKonstantin Belousov 
249e1976efdSKonstantin Belousov 	if (ptrace(PT_TO_SCX, pid, (caddr_t)1, 0) < 0) {
250e1976efdSKonstantin Belousov 		perror("PT_TO_SCX");
251e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
252e1976efdSKonstantin Belousov 		return (-1);
253e1976efdSKonstantin Belousov 	}
254e1976efdSKonstantin Belousov 
255e1976efdSKonstantin Belousov 	if (waitpid(pid, &status, 0) == -1) {
256e1976efdSKonstantin Belousov 		perror("waitpid");
257e1976efdSKonstantin Belousov 		return (-1);
258e1976efdSKonstantin Belousov 	}
259e1976efdSKonstantin Belousov 	if (WIFEXITED(status) || WIFSIGNALED(status)) {
260e1976efdSKonstantin Belousov 		wait_info(pid, status, NULL);
261e1976efdSKonstantin Belousov 		return (-1);
262e1976efdSKonstantin Belousov 	}
263e1976efdSKonstantin Belousov 	assert(WIFSTOPPED(status));
264e1976efdSKonstantin Belousov 	assert(WSTOPSIG(status) == SIGTRAP);
265e1976efdSKonstantin Belousov 
266e1976efdSKonstantin Belousov 	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
267e1976efdSKonstantin Belousov 		perror("PT_LWPINFO");
268e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
269e1976efdSKonstantin Belousov 		return (-1);
270e1976efdSKonstantin Belousov 	}
271e1976efdSKonstantin Belousov 	wait_info(pid, status, &lwpinfo);
272e1976efdSKonstantin Belousov 	assert(lwpinfo.pl_flags & PL_FLAG_SCX);
273e1976efdSKonstantin Belousov 
274*6403a140SKonstantin Belousov 	if (remote_getpid) {
275*6403a140SKonstantin Belousov 		memset(&pscr, 0, sizeof(pscr));
276*6403a140SKonstantin Belousov 		pscr.pscr_syscall = SYS_getpid;
277*6403a140SKonstantin Belousov 		pscr.pscr_nargs = 0;
278*6403a140SKonstantin Belousov 		if (ptrace(PT_SC_REMOTE, pid, (caddr_t)&pscr,
279*6403a140SKonstantin Belousov 		    sizeof(pscr)) < 0) {
280*6403a140SKonstantin Belousov 			perror("PT_SC_REMOTE");
281*6403a140SKonstantin Belousov 			ptrace(PT_KILL, pid, NULL, 0);
282*6403a140SKonstantin Belousov 			return (-1);
283*6403a140SKonstantin Belousov 		} else {
284*6403a140SKonstantin Belousov 			printf(TRACE "remote getpid %ld errno %d\n",
285*6403a140SKonstantin Belousov 			    pscr.pscr_ret.sr_retval[0], pscr.pscr_ret.sr_error);
286*6403a140SKonstantin Belousov 			if (waitpid(pid, &status, 0) == -1) {
287*6403a140SKonstantin Belousov 			  perror("waitpid");
288*6403a140SKonstantin Belousov 			  return (-1);
289*6403a140SKonstantin Belousov 			}
290*6403a140SKonstantin Belousov 		}
291*6403a140SKonstantin Belousov 	}
292e1976efdSKonstantin Belousov 	if (lwpinfo.pl_flags & PL_FLAG_EXEC)
293e1976efdSKonstantin Belousov 		get_pathname(pid);
294e1976efdSKonstantin Belousov 
295e1976efdSKonstantin Belousov 	if (lwpinfo.pl_flags & PL_FLAG_FORKED) {
296e1976efdSKonstantin Belousov 		printf(TRACE "forked child %d\n", lwpinfo.pl_child_pid);
297e1976efdSKonstantin Belousov 		return (lwpinfo.pl_child_pid);
298e1976efdSKonstantin Belousov 	}
299e1976efdSKonstantin Belousov 	return (0);
300e1976efdSKonstantin Belousov }
301e1976efdSKonstantin Belousov 
302e1976efdSKonstantin Belousov static int
trace_cont(int pid)303e1976efdSKonstantin Belousov trace_cont(int pid)
304e1976efdSKonstantin Belousov {
305e1976efdSKonstantin Belousov 	struct ptrace_lwpinfo lwpinfo;
306e1976efdSKonstantin Belousov 	int status;
307e1976efdSKonstantin Belousov 
308e1976efdSKonstantin Belousov 	if (ptrace(PT_CONTINUE, pid, (caddr_t)1, 0) < 0) {
309e1976efdSKonstantin Belousov 		perror("PT_CONTINUE");
310e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
311e1976efdSKonstantin Belousov 		return (-1);
312e1976efdSKonstantin Belousov 	}
313e1976efdSKonstantin Belousov 
314e1976efdSKonstantin Belousov 	if (waitpid(pid, &status, 0) == -1) {
315e1976efdSKonstantin Belousov 		perror("waitpid");
316e1976efdSKonstantin Belousov 		return (-1);
317e1976efdSKonstantin Belousov 	}
318e1976efdSKonstantin Belousov 	if (WIFEXITED(status) || WIFSIGNALED(status)) {
319e1976efdSKonstantin Belousov 		wait_info(pid, status, NULL);
320e1976efdSKonstantin Belousov 		return (-1);
321e1976efdSKonstantin Belousov 	}
322e1976efdSKonstantin Belousov 	assert(WIFSTOPPED(status));
323e1976efdSKonstantin Belousov 	assert(WSTOPSIG(status) == SIGTRAP);
324e1976efdSKonstantin Belousov 
325e1976efdSKonstantin Belousov 	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
326e1976efdSKonstantin Belousov 		perror("PT_LWPINFO");
327e1976efdSKonstantin Belousov 		ptrace(PT_KILL, pid, NULL, 0);
328e1976efdSKonstantin Belousov 		return (-1);
329e1976efdSKonstantin Belousov 	}
330e1976efdSKonstantin Belousov 	wait_info(pid, status, &lwpinfo);
331e1976efdSKonstantin Belousov 
332e1976efdSKonstantin Belousov 	if ((lwpinfo.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) ==
333e1976efdSKonstantin Belousov 	    (PL_FLAG_EXEC | PL_FLAG_SCX))
334e1976efdSKonstantin Belousov 		get_pathname(pid);
335e1976efdSKonstantin Belousov 
336e1976efdSKonstantin Belousov 	if ((lwpinfo.pl_flags & (PL_FLAG_FORKED | PL_FLAG_SCX)) ==
337e1976efdSKonstantin Belousov 	    (PL_FLAG_FORKED | PL_FLAG_SCX)) {
338e1976efdSKonstantin Belousov 		printf(TRACE "forked child %d\n", lwpinfo.pl_child_pid);
339e1976efdSKonstantin Belousov 		return (lwpinfo.pl_child_pid);
340e1976efdSKonstantin Belousov 	}
341e1976efdSKonstantin Belousov 
342e1976efdSKonstantin Belousov 	return (0);
343e1976efdSKonstantin Belousov }
344e1976efdSKonstantin Belousov 
345e1976efdSKonstantin Belousov static int
trace(pid_t pid)346e1976efdSKonstantin Belousov trace(pid_t pid)
347e1976efdSKonstantin Belousov {
348e1976efdSKonstantin Belousov 
349e1976efdSKonstantin Belousov 	return (trace_syscalls ? trace_sc(pid) : trace_cont(pid));
350e1976efdSKonstantin Belousov }
351e1976efdSKonstantin Belousov 
352e1976efdSKonstantin Belousov 
353e1976efdSKonstantin Belousov int
main(int argc,char * argv[])354e1976efdSKonstantin Belousov main(int argc, char *argv[])
355e1976efdSKonstantin Belousov {
356e1976efdSKonstantin Belousov 	struct ptrace_lwpinfo lwpinfo;
357e1976efdSKonstantin Belousov 	int c, status, use_vfork;
358e1976efdSKonstantin Belousov 	pid_t pid, pid1;
359e1976efdSKonstantin Belousov 
360e1976efdSKonstantin Belousov 	trace_syscalls = 1;
361*6403a140SKonstantin Belousov 	remote_getpid = 0;
362e1976efdSKonstantin Belousov 	use_vfork = 0;
363*6403a140SKonstantin Belousov 	while ((c = getopt(argc, argv, "crsv")) != -1) {
364e1976efdSKonstantin Belousov 		switch (c) {
365e1976efdSKonstantin Belousov 		case 'c':
366e1976efdSKonstantin Belousov 			trace_syscalls = 0;
367e1976efdSKonstantin Belousov 			break;
368*6403a140SKonstantin Belousov 		case 'r':
369*6403a140SKonstantin Belousov 			remote_getpid = 1;
370*6403a140SKonstantin Belousov 			break;
371e1976efdSKonstantin Belousov 		case 's':
372e1976efdSKonstantin Belousov 			trace_syscalls = 1;
373e1976efdSKonstantin Belousov 			break;
374e1976efdSKonstantin Belousov 		case 'v':
375e1976efdSKonstantin Belousov 			use_vfork = 1;
376e1976efdSKonstantin Belousov 			break;
377e1976efdSKonstantin Belousov 		default:
378e1976efdSKonstantin Belousov 		case '?':
379*6403a140SKonstantin Belousov 			fprintf(stderr, "Usage: %s [-c] [-r] [-s] [-v]\n",
380*6403a140SKonstantin Belousov 			    argv[0]);
381e1976efdSKonstantin Belousov 			return (2);
382e1976efdSKonstantin Belousov 		}
383e1976efdSKonstantin Belousov 	}
384e1976efdSKonstantin Belousov 
385e1976efdSKonstantin Belousov 	if ((pid = fork()) < 0) {
386e1976efdSKonstantin Belousov 		perror("fork");
387e1976efdSKonstantin Belousov 		return 1;
388e1976efdSKonstantin Belousov 	}
389e1976efdSKonstantin Belousov 	else if (pid == 0) {
390e1976efdSKonstantin Belousov 		if (ptrace(PT_TRACE_ME, 0, NULL, 0) < 0) {
391e1976efdSKonstantin Belousov 			perror("PT_TRACE_ME");
392e1976efdSKonstantin Belousov 			_exit(1);
393e1976efdSKonstantin Belousov 		}
394e1976efdSKonstantin Belousov 		kill(getpid(), SIGSTOP);
395e1976efdSKonstantin Belousov 		getpid();
396e1976efdSKonstantin Belousov 		if ((pid1 = use_vfork ? vfork() : fork()) < 0) {
397e1976efdSKonstantin Belousov 			perror("fork1");
398e1976efdSKonstantin Belousov 			return (1);
399e1976efdSKonstantin Belousov 		} else if (pid1 == 0) {
400e1976efdSKonstantin Belousov 			printf("Hi from child %d\n", getpid());
401e1976efdSKonstantin Belousov 			execl("/bin/ls", "ls", "/", (char *)NULL);
402e1976efdSKonstantin Belousov 		}
403e1976efdSKonstantin Belousov 	}
404e1976efdSKonstantin Belousov 	else { /* parent */
405e1976efdSKonstantin Belousov 		if (waitpid(pid, &status, 0) == -1) {
406e1976efdSKonstantin Belousov 			perror("waitpid");
407e1976efdSKonstantin Belousov 			return (-1);
408e1976efdSKonstantin Belousov 		}
409e1976efdSKonstantin Belousov 		assert(WIFSTOPPED(status));
410e1976efdSKonstantin Belousov 		assert(WSTOPSIG(status) == SIGSTOP);
411e1976efdSKonstantin Belousov 
412e1976efdSKonstantin Belousov 		if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo,
413e1976efdSKonstantin Belousov 		    sizeof(lwpinfo)) < 0) {
414e1976efdSKonstantin Belousov 			perror("PT_LWPINFO");
415e1976efdSKonstantin Belousov 			ptrace(PT_KILL, pid, NULL, 0);
416e1976efdSKonstantin Belousov 			return (-1);
417e1976efdSKonstantin Belousov 		}
418e1976efdSKonstantin Belousov 		wait_info(pid, status, &lwpinfo);
419e1976efdSKonstantin Belousov 
420e1976efdSKonstantin Belousov 		if (ptrace(PT_FOLLOW_FORK, pid, 0, 1) < 0) {
421e1976efdSKonstantin Belousov 			perror("PT_FOLLOW_FORK");
422e1976efdSKonstantin Belousov 			ptrace(PT_KILL, pid, NULL, 0);
423e1976efdSKonstantin Belousov 			return (2);
424e1976efdSKonstantin Belousov 		}
425e1976efdSKonstantin Belousov 
426e1976efdSKonstantin Belousov 		while ((pid1 = trace(pid)) >= 0) {
427e1976efdSKonstantin Belousov 			if (pid1 != 0) {
428e1976efdSKonstantin Belousov 				printf(TRACE "attached to pid %d\n", pid1);
429e1976efdSKonstantin Belousov #if 0
430e1976efdSKonstantin Belousov 				kill(pid1, SIGCONT);
431e1976efdSKonstantin Belousov #endif
432e1976efdSKonstantin Belousov 				if (waitpid(pid1, &status, 0) == -1) {
433e1976efdSKonstantin Belousov 					perror("waitpid");
434e1976efdSKonstantin Belousov 					return (-1);
435e1976efdSKonstantin Belousov 				}
436e1976efdSKonstantin Belousov 				printf(TRACE "nested loop, pid %d status %s\n",
437e1976efdSKonstantin Belousov 				    pid1, decode_wait_status(status));
438e1976efdSKonstantin Belousov 				assert(WIFSTOPPED(status));
439e1976efdSKonstantin Belousov 				assert(WSTOPSIG(status) == SIGSTOP);
440e1976efdSKonstantin Belousov 				if (ptrace(PT_LWPINFO, pid1, (caddr_t)&lwpinfo,
441e1976efdSKonstantin Belousov 				    sizeof(lwpinfo)) < 0) {
442e1976efdSKonstantin Belousov 					perror("PT_LWPINFO");
443e1976efdSKonstantin Belousov 					ptrace(PT_KILL, pid1, NULL, 0);
444e1976efdSKonstantin Belousov 					return (-1);
445e1976efdSKonstantin Belousov 				}
446e1976efdSKonstantin Belousov 				wait_info(pid1, status, &lwpinfo);
447e1976efdSKonstantin Belousov 
448e1976efdSKonstantin Belousov 				while (trace(pid1) >= 0)
449e1976efdSKonstantin Belousov 					;
450e1976efdSKonstantin Belousov 			}
451e1976efdSKonstantin Belousov 		}
452e1976efdSKonstantin Belousov 
453e1976efdSKonstantin Belousov 		ptrace(PT_CONTINUE, pid, (caddr_t)1, 0);
454e1976efdSKonstantin Belousov 	}
455e1976efdSKonstantin Belousov 	return (0);
456e1976efdSKonstantin Belousov }
457