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