blob: ec6bae07df3b83ccf0f9b4c1a2dbabbb3f4e3ea0 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00006 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $Id$
31 */
32
33#include "defs.h"
34
35#include <signal.h>
36#include <errno.h>
37#include <sys/param.h>
38#include <fcntl.h>
39#include <sys/resource.h>
40#include <sys/wait.h>
41#include <sys/stat.h>
42#include <pwd.h>
43#include <grp.h>
44#include <string.h>
45
46#ifdef SVR4
47#include <sys/stropts.h>
48#include <poll.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000049#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000050#include <sys/uio.h>
51#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000052#endif
53
54int debug = 0, followfork = 0, followvfork = 0, interactive = 0;
55int rflag = 0, tflag = 0, dtime = 0, cflag = 0;
56int iflag = 0, xflag = 0, qflag = 0;
57int pflag_seen = 0;
58
59char *username = NULL;
60uid_t run_uid;
61gid_t run_gid;
62
63int acolumn = DEFAULT_ACOLUMN;
64int max_strlen = DEFAULT_STRLEN;
65char *outfname = NULL;
66FILE *outf;
67struct tcb tcbtab[MAX_PROCS];
68int nprocs;
69char *progname;
70extern char version[];
71extern char **environ;
72
73static struct tcb *pid2tcb P((int pid));
74static int trace P((void));
75static void cleanup P((void));
76static void interrupt P((int sig));
77static sigset_t empty_set, blocked_set;
78
79#ifdef HAVE_SIG_ATOMIC_T
80static volatile sig_atomic_t interrupted;
81#else /* !HAVE_SIG_ATOMIC_T */
82#ifdef __STDC__
83static volatile int interrupted;
84#else /* !__STDC__ */
85static int interrupted;
86#endif /* !__STDC__ */
87#endif /* !HAVE_SIG_ATOMIC_T */
88
89#ifdef SVR4
90
91static struct tcb *pfd2tcb P((int pfd));
92static void reaper P((int sig));
93static void rebuild_pollv P((void));
Wichert Akkermane68d61c1999-06-28 13:17:16 +000094struct pollfd pollv[MAX_PROCS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000095
96#ifndef HAVE_POLLABLE_PROCFS
97
98static void proc_poll_open P((void));
99static void proc_poller P((int pfd));
100
101struct proc_pollfd {
102 int fd;
103 int revents;
104 int pid;
105};
106
107static int poller_pid;
108static int proc_poll_pipe[2] = { -1, -1 };
109
110#endif /* !HAVE_POLLABLE_PROCFS */
111
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000112#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000113#define POLLWANT POLLWRNORM
114#else
115#define POLLWANT POLLPRI
116#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000117#endif /* SVR4 */
118
119static void
120usage(ofp, exitval)
121FILE *ofp;
122int exitval;
123{
124 fprintf(ofp, "\
125usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
126 [-p pid] ... [-s strsize] [-u username] [command [arg ...]]\n\
127 or: strace -c [-e expr] ... [-O overhead] [-S sortby] [command [arg ...]]\n\
128-c -- count time, calls, and errors for each syscall and report summary\n\
129-f -- follow forks, -ff -- with output into separate files\n\
130-F -- attempt to follow vforks, -h -- print help message\n\
131-i -- print instruction pointer at time of syscall\n\
132-q -- suppress messages about attaching, detaching, etc.\n\
133-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
134-T -- print time spent in each syscall, -V -- print version\n\
135-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
136-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
137-a column -- alignment COLUMN for printing syscall results (default %d)\n\
138-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
139 options: trace, abbrev, verbose, raw, signal, read, or write\n\
140-o file -- send trace output to FILE instead of stderr\n\
141-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
142-p pid -- trace process with process id PID, may be repeated\n\
143-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
144-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
145-u username -- run command as username handling setuid and/or setgid\n\
146", DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
147 exit(exitval);
148}
149
150#ifdef SVR4
151#ifdef MIPS
152void
153foobar()
154{
155}
156#endif /* MIPS */
157#endif /* SVR4 */
158
159int
160main(argc, argv)
161int argc;
162char *argv[];
163{
164 extern int optind;
165 extern char *optarg;
166 struct tcb *tcp;
167 int c, pid = 0;
168 struct sigaction sa;
169
170 static char buf[BUFSIZ];
171
172 progname = argv[0];
173 outf = stderr;
174 interactive = 1;
175 qualify("trace=all");
176 qualify("abbrev=all");
177 qualify("verbose=all");
178 qualify("signal=all");
179 set_sortby(DEFAULT_SORTBY);
180 set_personality(DEFAULT_PERSONALITY);
181 while ((c = getopt(argc, argv,
182 "+cdfFhiqrtTvVxa:e:o:O:p:s:S:u:")) != EOF) {
183 switch (c) {
184 case 'c':
185 cflag++;
186 dtime++;
187 break;
188 case 'd':
189 debug++;
190 break;
191 case 'f':
192 followfork++;
193 break;
194 case 'F':
195 followvfork++;
196 break;
197 case 'h':
198 usage(stdout, 0);
199 break;
200 case 'i':
201 iflag++;
202 break;
203 case 'q':
204 qflag++;
205 break;
206 case 'r':
207 rflag++;
208 tflag++;
209 break;
210 case 't':
211 tflag++;
212 break;
213 case 'T':
214 dtime++;
215 break;
216 case 'x':
217 xflag++;
218 break;
219 case 'v':
220 qualify("abbrev=none");
221 break;
222 case 'V':
223 printf("%s\n", version);
224 exit(0);
225 break;
226 case 'a':
227 acolumn = atoi(optarg);
228 break;
229 case 'e':
230 qualify(optarg);
231 break;
232 case 'o':
233 outfname = strdup(optarg);
234 break;
235 case 'O':
236 set_overhead(atoi(optarg));
237 break;
238 case 'p':
239 if ((pid = atoi(optarg)) == 0) {
240 fprintf(stderr, "%s: Invalid process id: %s\n",
241 progname, optarg);
242 break;
243 }
244 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000245 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000246 break;
247 }
248 if ((tcp = alloctcb(pid)) == NULL) {
249 fprintf(stderr, "%s: tcb table full, please recompile strace\n",
250 progname);
251 exit(1);
252 }
253 tcp->flags |= TCB_ATTACHED;
254 pflag_seen++;
255 break;
256 case 's':
257 max_strlen = atoi(optarg);
258 break;
259 case 'S':
260 set_sortby(optarg);
261 break;
262 case 'u':
263 username = strdup(optarg);
264 break;
265 default:
266 usage(stderr, 1);
267 break;
268 }
269 }
270
271 /* See if they want to run as another user. */
272 if (username != NULL) {
273 struct passwd *pent;
274
275 if (getuid() != 0 || geteuid() != 0) {
276 fprintf(stderr,
277 "%s: you must be root to use the -u option\n",
278 progname);
279 exit(1);
280 }
281 if ((pent = getpwnam(username)) == NULL) {
282 fprintf(stderr, "%s: cannot find user `%s'\n",
283 progname, optarg);
284 exit(1);
285 }
286 run_uid = pent->pw_uid;
287 run_gid = pent->pw_gid;
288 }
289 else {
290 run_uid = getuid();
291 run_gid = getgid();
292 }
293
294#ifndef SVR4
295 setreuid(geteuid(), getuid());
296#endif
297
298 /* See if they want to pipe the output. */
299 if (outfname && (outfname[0] == '|' || outfname[0] == '!')) {
300 if ((outf = popen(outfname + 1, "w")) == NULL) {
301 fprintf(stderr, "%s: can't popen '%s': %s\n",
302 progname, outfname + 1, strerror(errno));
303 exit(1);
304 }
305 free(outfname);
306 outfname = NULL;
307 }
308
309 /* Check if they want to redirect the output. */
310 if (outfname) {
311 if ((outf = fopen(outfname, "w")) == NULL) {
312 fprintf(stderr, "%s: can't fopen '%s': %s\n",
313 progname, outfname, strerror(errno));
314 exit(1);
315 }
316 }
317
318#ifndef SVR4
319 setreuid(geteuid(), getuid());
320#endif
321
322 if (!outfname) {
323 qflag = 1;
324 setvbuf(outf, buf, _IOLBF, BUFSIZ);
325 }
326 else if (optind < argc)
327 interactive = 0;
328 else
329 qflag = 1;
330
331 for (c = 0, tcp = tcbtab; c < MAX_PROCS; c++, tcp++) {
332 /* Reinitialize the output since it may have changed. */
333 tcp->outf = outf;
334 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
335 continue;
336#ifdef SVR4
337 if (proc_open(tcp, 1) < 0) {
338 fprintf(stderr, "trouble opening proc file\n");
339 droptcb(tcp);
340 continue;
341 }
342#else /* !SVR4 */
343 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
344 perror("attach: ptrace(PTRACE_ATTACH, ...)");
345 droptcb(tcp);
346 continue;
347 }
348#endif /* !SVR4 */
349 if (!qflag)
350 fprintf(stderr,
351 "Process %u attached - interrupt to quit\n",
352 pid);
353 }
354
355 if (optind < argc) {
356 struct stat statbuf;
357 char *filename;
358 char pathname[MAXPATHLEN];
359
360 filename = argv[optind];
361 if (strchr(filename, '/'))
362 strcpy(pathname, filename);
363#ifdef USE_DEBUGGING_EXEC
364 /*
365 * Debuggers customarily check the current directory
366 * first regardless of the path but doing that gives
367 * security geeks a panic attack.
368 */
369 else if (stat(filename, &statbuf) == 0)
370 strcpy(pathname, filename);
371#endif /* USE_DEBUGGING_EXEC */
372 else {
373 char *path;
374 int m, n, len;
375
376 for (path = getenv("PATH"); path && *path; path += m) {
377 if (strchr(path, ':')) {
378 n = strchr(path, ':') - path;
379 m = n + 1;
380 }
381 else
382 m = n = strlen(path);
383 if (n == 0) {
384 getcwd(pathname, MAXPATHLEN);
385 len = strlen(pathname);
386 }
387 else {
388 strncpy(pathname, path, n);
389 len = n;
390 }
391 if (len && pathname[len - 1] != '/')
392 pathname[len++] = '/';
393 strcpy(pathname + len, filename);
394 if (stat(pathname, &statbuf) == 0)
395 break;
396 }
397 }
398 if (stat(pathname, &statbuf) < 0) {
399 fprintf(stderr, "%s: %s: command not found\n",
400 progname, filename);
401 exit(1);
402 }
403 switch (pid = fork()) {
404 case -1:
405 perror("strace: fork");
406 cleanup();
407 exit(1);
408 break;
409 case 0: {
410#ifdef SVR4
Wichert Akkerman789ed351999-06-14 10:45:01 +0000411 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000412#ifdef MIPS
413 /* Kludge for SGI, see proc_open for details. */
414 sa.sa_handler = foobar;
415 sa.sa_flags = 0;
416 sigemptyset(&sa.sa_mask);
417 sigaction(SIGINT, &sa, NULL);
418#endif /* MIPS */
419 pause();
420#else /* !SVR4 */
421 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
422 perror("strace: ptrace(PTRACE_TRACEME, ...)");
423 return -1;
424 }
425 if (debug)
426 kill(getpid(), SIGSTOP);
427
428 if (username != NULL || geteuid() == 0) {
429 uid_t run_euid = run_uid;
430 gid_t run_egid = run_gid;
431
432 if (statbuf.st_mode & S_ISUID)
433 run_euid = statbuf.st_uid;
434 if (statbuf.st_mode & S_ISGID)
435 run_egid = statbuf.st_gid;
436
437 /*
438 * It is important to set groups before we
439 * lose privileges on setuid.
440 */
441 if (username != NULL
442 && initgroups(username, run_gid) < 0) {
443 perror("initgroups");
444 exit(1);
445 }
446 if (setregid(run_gid, run_egid) < 0) {
447 perror("setregid");
448 exit(1);
449 }
450 if (setreuid(run_uid, run_euid) < 0) {
451 perror("setreuid");
452 exit(1);
453 }
454 }
455 else
456 setreuid(run_uid, run_uid);
457#endif /* !SVR4 */
458
459 execv(pathname, &argv[optind]);
460 perror("strace: exec");
461 _exit(1);
462 break;
463 }
464 default:
465 if ((tcp = alloctcb(pid)) == NULL) {
466 fprintf(stderr, "tcb table full\n");
467 cleanup();
468 exit(1);
469 }
470#ifdef SVR4
471 if (proc_open(tcp, 0) < 0) {
472 fprintf(stderr, "trouble opening proc file\n");
473 cleanup();
474 exit(1);
475 }
476#endif /* SVR4 */
477#ifndef SVR4
478 fake_execve(tcp, pathname, &argv[optind], environ);
479#endif
480 break;
481 }
482 }
483 else if (pflag_seen == 0)
484 usage(stderr, 1);
485
486 sigemptyset(&empty_set);
487 sigemptyset(&blocked_set);
488 sa.sa_handler = SIG_IGN;
489 sigemptyset(&sa.sa_mask);
490 sa.sa_flags = 0;
491 sigaction(SIGTTOU, &sa, NULL);
492 sigaction(SIGTTIN, &sa, NULL);
493 if (interactive) {
494 sigaddset(&blocked_set, SIGHUP);
495 sigaddset(&blocked_set, SIGINT);
496 sigaddset(&blocked_set, SIGQUIT);
497 sigaddset(&blocked_set, SIGPIPE);
498 sigaddset(&blocked_set, SIGTERM);
499 sa.sa_handler = interrupt;
500#ifdef SUNOS4
501 /* POSIX signals on sunos4.1 are a little broken. */
502 sa.sa_flags = SA_INTERRUPT;
503#endif /* SUNOS4 */
504 }
505 sigaction(SIGHUP, &sa, NULL);
506 sigaction(SIGINT, &sa, NULL);
507 sigaction(SIGQUIT, &sa, NULL);
508 sigaction(SIGPIPE, &sa, NULL);
509 sigaction(SIGTERM, &sa, NULL);
510#ifdef SVR4
511 sa.sa_handler = reaper;
512 sigaction(SIGCHLD, &sa, NULL);
513#endif /* SVR4 */
514
515 if (trace() < 0)
516 exit(1);
517 cleanup();
518 exit(0);
519}
520
521void
522newoutf(tcp)
523struct tcb *tcp;
524{
525 char name[MAXPATHLEN];
526 FILE *fp;
527
528 if (outfname && followfork > 1) {
529 sprintf(name, "%s.%u", outfname, tcp->pid);
530#ifndef SVR4
531 setreuid(geteuid(), getuid());
532#endif
533 fp = fopen(name, "w");
534#ifndef SVR4
535 setreuid(geteuid(), getuid());
536#endif
537 if (fp == NULL) {
538 perror("fopen");
539 return;
540 }
541 tcp->outf = fp;
542 }
543 return;
544}
545
546struct tcb *
547alloctcb(pid)
548int pid;
549{
550 int i;
551 struct tcb *tcp;
552
553 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
554 if ((tcp->flags & TCB_INUSE) == 0) {
555 tcp->pid = pid;
556 tcp->parent = NULL;
557 tcp->nchildren = 0;
558 tcp->flags = TCB_INUSE | TCB_STARTUP;
559 tcp->outf = outf; /* Initialise to current out file */
560 tcp->stime.tv_sec = 0;
561 tcp->stime.tv_usec = 0;
562 tcp->pfd = -1;
563 nprocs++;
564 return tcp;
565 }
566 }
567 return NULL;
568}
569
570#ifdef SVR4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000571int
572proc_open(tcp, attaching)
573struct tcb *tcp;
574int attaching;
575{
576 char proc[32];
577 long arg;
578 sysset_t sc_enter, sc_exit;
579 sigset_t signals;
580 fltset_t faults;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000581#ifndef HAVE_POLLABLE_PROCFS
582 static int last_pfd;
583#endif
584
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000585#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000586 /* Open the process pseudo-files in /proc. */
587 sprintf(proc, "/proc/%d/ctl", tcp->pid);
588 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000589 perror("strace: open(\"/proc/...\", ...)");
590 return -1;
591 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000592 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
593 perror("F_GETFD");
594 return -1;
595 }
596 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
597 perror("F_SETFD");
598 return -1;
599 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000600 sprintf(proc, "/proc/%d/status", tcp->pid);
601 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
602 perror("strace: open(\"/proc/...\", ...)");
603 return -1;
604 }
605 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
606 perror("F_GETFD");
607 return -1;
608 }
609 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
610 perror("F_SETFD");
611 return -1;
612 }
613 sprintf(proc, "/proc/%d/as", tcp->pid);
614 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
615 perror("strace: open(\"/proc/...\", ...)");
616 return -1;
617 }
618 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
619 perror("F_GETFD");
620 return -1;
621 }
622 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
623 perror("F_SETFD");
624 return -1;
625 }
626#else
627 /* Open the process pseudo-file in /proc. */
628 sprintf(proc, "/proc/%d", tcp->pid);
629 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
630 perror("strace: open(\"/proc/...\", ...)");
631 return -1;
632 }
633 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
634 perror("F_GETFD");
635 return -1;
636 }
637 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
638 perror("F_SETFD");
639 return -1;
640 }
641#endif
642 rebuild_pollv();
643 if (!attaching) {
644 /*
645 * Wait for the child to pause. Because of a race
646 * condition we have to poll for the event.
647 */
648 for (;;) {
649 if (IOCTL_STATUS (tcp) < 0) {
650 perror("strace: PIOCSTATUS");
651 return -1;
652 }
653 if (tcp->status.PR_FLAGS & PR_ASLEEP)
654 break;
655 }
656 }
657 /* Stop the process so that we own the stop. */
658 if (IOCTL(tcp->pfd, PIOCSTOP, NULL) < 0) {
659 perror("strace: PIOCSTOP");
660 return -1;
661 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000662#ifdef PIOCSET
663 /* Set Run-on-Last-Close. */
664 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000665 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000666 perror("PIOCSET PR_RLC");
667 return -1;
668 }
669 /* Set or Reset Inherit-on-Fork. */
670 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000671 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000672 perror("PIOC{SET,RESET} PR_FORK");
673 return -1;
674 }
675#else /* !PIOCSET */
676 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
677 perror("PIOCSRLC");
678 return -1;
679 }
680 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
681 perror("PIOC{S,R}FORK");
682 return -1;
683 }
684#endif /* !PIOCSET */
685 /* Enable all syscall entries. */
686 prfillset(&sc_enter);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000687 if (IOCTL(tcp->pfd, PIOCSENTRY, &sc_enter) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000688 perror("PIOCSENTRY");
689 return -1;
690 }
691 /* Enable all syscall exits. */
692 prfillset(&sc_exit);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000693 if (IOCTL(tcp->pfd, PIOCSEXIT, &sc_exit) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000694 perror("PIOSEXIT");
695 return -1;
696 }
697 /* Enable all signals. */
698 prfillset(&signals);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000699 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000700 perror("PIOCSTRACE");
701 return -1;
702 }
703 /* Enable all faults. */
704 prfillset(&faults);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000705 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000706 perror("PIOCSFAULT");
707 return -1;
708 }
709 if (!attaching) {
710#ifdef MIPS
711 /*
712 * The SGI PRSABORT doesn't work for pause() so
713 * we send it a caught signal to wake it up.
714 */
715 kill(tcp->pid, SIGINT);
716#else /* !MIPS */
717 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000718 arg = PRSABORT;
719 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000720 perror("PIOCRUN");
721 return -1;
722 }
723#endif /* !MIPS */
724 for (;;) {
725 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000726 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000727 perror("PIOCWSTOP");
728 return -1;
729 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000730 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000731#ifdef HAVE_PR_SYSCALL
732 int scno = tcp->status.pr_syscall;
733#else /* !HAVE_PR_SYSCALL */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000734 int scno = tcp->status.PR_WHAT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000735#endif /* !HAVE_PR_SYSCALL */
736 if (scno == SYS_execve)
737 break;
738 }
739 /* Set it running: maybe execve will be next. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000740 arg = 0;
741 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000742 perror("PIOCRUN");
743 return -1;
744 }
745 }
746 }
747#ifndef HAVE_POLLABLE_PROCFS
748 if (proc_poll_pipe[0] != -1)
749 proc_poller(tcp->pfd);
750 else if (nprocs > 1) {
751 proc_poll_open();
752 proc_poller(last_pfd);
753 proc_poller(tcp->pfd);
754 }
755 last_pfd = tcp->pfd;
756#endif /* !HAVE_POLLABLE_PROCFS */
757 return 0;
758}
759
760#endif /* SVR4 */
761
762static struct tcb *
763pid2tcb(pid)
764int pid;
765{
766 int i;
767 struct tcb *tcp;
768
769 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
770 if (pid && tcp->pid != pid)
771 continue;
772 if (tcp->flags & TCB_INUSE)
773 return tcp;
774 }
775 return NULL;
776}
777
778#ifdef SVR4
779
780static struct tcb *
781pfd2tcb(pfd)
782int pfd;
783{
784 int i;
785 struct tcb *tcp;
786
787 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
788 if (tcp->pfd != pfd)
789 continue;
790 if (tcp->flags & TCB_INUSE)
791 return tcp;
792 }
793 return NULL;
794}
795
796#endif /* SVR4 */
797
798void
799droptcb(tcp)
800struct tcb *tcp;
801{
802 if (tcp->pid == 0)
803 return;
804 nprocs--;
805 tcp->pid = 0;
806 tcp->flags = 0;
807 if (tcp->pfd != -1) {
808 close(tcp->pfd);
809 tcp->pfd = -1;
810#ifdef SVR4
811 rebuild_pollv();
812#endif
813 }
814 if (tcp->parent != NULL) {
815 tcp->parent->nchildren--;
816 tcp->parent = NULL;
817 }
818#if 0
819 if (tcp->outf != stderr)
820 fclose(tcp->outf);
821#endif
822 tcp->outf = 0;
823}
824
825#ifndef SVR4
826
827static int
828resume(tcp)
829struct tcb *tcp;
830{
831 if (tcp == NULL)
832 return -1;
833
834 if (!(tcp->flags & TCB_SUSPENDED)) {
835 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
836 return -1;
837 }
838 tcp->flags &= ~TCB_SUSPENDED;
839
840 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
841 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
842 return -1;
843 }
844
845 if (!qflag)
846 fprintf(stderr, "Process %u resumed\n", tcp->pid);
847 return 0;
848}
849
850#endif /* !SVR4 */
851
852/* detach traced process; continue with sig */
853
854static int
855detach(tcp, sig)
856struct tcb *tcp;
857int sig;
858{
859 int error = 0;
860#ifdef LINUX
861 int status;
862#endif
863
864 if (tcp->flags & TCB_BPTSET)
865 sig = SIGKILL;
866
867#ifdef LINUX
868 /*
869 * Linux wrongly insists the child be stopped
870 * before detaching. Arghh. We go through hoops
871 * to make a clean break of things.
872 */
Wichert Akkermandacfb6e1999-06-03 14:21:07 +0000873#if defined(SPARC)
874#undef PTRACE_DETACH
875#define PTRACE_DETACH PTRACE_SUNDETACH
876#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000877 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
878 /* On a clear day, you can see forever. */
879 }
880 else if (errno != ESRCH) {
881 /* Shouldn't happen. */
882 perror("detach: ptrace(PTRACE_DETACH, ...)");
883 }
884 else if (kill(tcp->pid, 0) < 0) {
885 if (errno != ESRCH)
886 perror("detach: checking sanity");
887 }
888 else if (kill(tcp->pid, SIGSTOP) < 0) {
889 if (errno != ESRCH)
890 perror("detach: stopping child");
891 }
892 else {
893 for (;;) {
894 if (waitpid(tcp->pid, &status, 0) < 0) {
895 if (errno != ECHILD)
896 perror("detach: waiting");
897 break;
898 }
899 if (!WIFSTOPPED(status)) {
900 /* Au revoir, mon ami. */
901 break;
902 }
903 if (WSTOPSIG(status) == SIGSTOP) {
904 if ((error = ptrace(PTRACE_DETACH,
905 tcp->pid, (char *) 1, sig)) < 0) {
906 if (errno != ESRCH)
907 perror("detach: ptrace(PTRACE_DETACH, ...)");
908 /* I died trying. */
909 }
910 break;
911 }
912 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
913 WSTOPSIG(status) == SIGTRAP ?
914 0 : WSTOPSIG(status))) < 0) {
915 if (errno != ESRCH)
916 perror("detach: ptrace(PTRACE_CONT, ...)");
917 break;
918 }
919 }
920 }
921#endif /* LINUX */
922
923#if defined(SUNOS4)
924 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
925 if (sig && kill(tcp->pid, sig) < 0)
926 perror("detach: kill");
927 sig = 0;
928 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
929 perror("detach: ptrace(PTRACE_DETACH, ...)");
930#endif /* SUNOS4 */
931
932#ifndef SVR4
933 if (waiting_parent(tcp))
934 error = resume(tcp->parent);
935#endif /* !SVR4 */
936
937 if (!qflag)
938 fprintf(stderr, "Process %u detached\n", tcp->pid);
939
940 droptcb(tcp);
941 return error;
942}
943
944#ifdef SVR4
945
946static void
947reaper(sig)
948int sig;
949{
950 int pid;
951 int status;
952
953 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
954#if 0
955 struct tcb *tcp;
956
957 tcp = pid2tcb(pid);
958 if (tcp)
959 droptcb(tcp);
960#endif
961 }
962}
963
964#endif /* SVR4 */
965
966static void
967cleanup()
968{
969 int i;
970 struct tcb *tcp;
971
972 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
973 if (!(tcp->flags & TCB_INUSE))
974 continue;
975 if (debug)
976 fprintf(stderr,
977 "cleanup: looking at pid %u\n", tcp->pid);
978 if (tcp_last &&
979 (!outfname || followfork < 2 || tcp_last == tcp)) {
980 tprintf(" <unfinished ...>\n");
981 tcp_last = NULL;
982 }
983 if (tcp->flags & TCB_ATTACHED)
984 detach(tcp, 0);
985 else {
986 kill(tcp->pid, SIGCONT);
987 kill(tcp->pid, SIGTERM);
988 }
989 }
990 if (cflag)
991 call_summary(outf);
992}
993
994static void
995interrupt(sig)
996int sig;
997{
998 interrupted = 1;
999}
1000
1001#ifndef HAVE_STRERROR
1002
1003#ifndef SYS_ERRLIST_DECLARED
1004extern int sys_nerr;
1005extern char *sys_errlist[];
1006#endif /* SYS_ERRLIST_DECLARED */
1007
1008const char *
1009strerror(errno)
1010int errno;
1011{
1012 static char buf[64];
1013
1014 if (errno < 1 || errno >= sys_nerr) {
1015 sprintf(buf, "Unknown error %d", errno);
1016 return buf;
1017 }
1018 return sys_errlist[errno];
1019}
1020
1021#endif /* HAVE_STERRROR */
1022
1023#ifndef HAVE_STRSIGNAL
1024
1025#ifndef SYS_SIGLIST_DECLARED
1026#ifdef HAVE__SYS_SIGLIST
1027 extern char *_sys_siglist[];
1028#else
1029 extern char *sys_siglist[];
1030#endif
1031#endif /* SYS_SIGLIST_DECLARED */
1032
1033const char *
1034strsignal(sig)
1035int sig;
1036{
1037 static char buf[64];
1038
1039 if (sig < 1 || sig >= NSIG) {
1040 sprintf(buf, "Unknown signal %d", sig);
1041 return buf;
1042 }
1043#ifdef HAVE__SYS_SIGLIST
1044 return _sys_siglist[sig];
1045#else
1046 return sys_siglist[sig];
1047#endif
1048}
1049
1050#endif /* HAVE_STRSIGNAL */
1051
1052#ifdef SVR4
1053
1054static void
1055rebuild_pollv()
1056{
1057 int i, j;
1058 struct tcb *tcp;
1059
1060 for (i = j = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
1061 if (!(tcp->flags & TCB_INUSE))
1062 continue;
1063 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001064 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001065 j++;
1066 }
1067 if (j != nprocs) {
1068 fprintf(stderr, "strace: proc miscount\n");
1069 exit(1);
1070 }
1071}
1072
1073#ifndef HAVE_POLLABLE_PROCFS
1074
1075static void
1076proc_poll_open()
1077{
1078 int arg;
1079 int i;
1080
1081 if (pipe(proc_poll_pipe) < 0) {
1082 perror("pipe");
1083 exit(1);
1084 }
1085 for (i = 0; i < 2; i++) {
1086 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1087 perror("F_GETFD");
1088 exit(1);
1089 }
1090 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1091 perror("F_SETFD");
1092 exit(1);
1093 }
1094 }
1095}
1096
1097static int
1098proc_poll(pollv, nfds, timeout)
1099struct pollfd *pollv;
1100int nfds;
1101int timeout;
1102{
1103 int i;
1104 int n;
1105 struct proc_pollfd pollinfo;
1106
1107 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1108 return n;
1109 if (n != sizeof(struct proc_pollfd)) {
1110 fprintf(stderr, "panic: short read: %d\n", n);
1111 exit(1);
1112 }
1113 for (i = 0; i < nprocs; i++) {
1114 if (pollv[i].fd == pollinfo.fd)
1115 pollv[i].revents = pollinfo.revents;
1116 else
1117 pollv[i].revents = 0;
1118 }
1119 poller_pid = pollinfo.pid;
1120 return 1;
1121}
1122
1123static void
1124wakeup_handler(sig)
1125int sig;
1126{
1127}
1128
1129static void
1130proc_poller(pfd)
1131int pfd;
1132{
1133 struct proc_pollfd pollinfo;
1134 struct sigaction sa;
1135 sigset_t blocked_set, empty_set;
1136 int i;
1137 int n;
1138 struct rlimit rl;
1139
1140 switch (fork()) {
1141 case -1:
1142 perror("fork");
1143 _exit(0);
1144 case 0:
1145 break;
1146 default:
1147 return;
1148 }
1149
1150 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1151 sa.sa_flags = 0;
1152 sigemptyset(&sa.sa_mask);
1153 sigaction(SIGHUP, &sa, NULL);
1154 sigaction(SIGINT, &sa, NULL);
1155 sigaction(SIGQUIT, &sa, NULL);
1156 sigaction(SIGPIPE, &sa, NULL);
1157 sigaction(SIGTERM, &sa, NULL);
1158 sa.sa_handler = wakeup_handler;
1159 sigaction(SIGUSR1, &sa, NULL);
1160 sigemptyset(&blocked_set);
1161 sigaddset(&blocked_set, SIGUSR1);
1162 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1163 sigemptyset(&empty_set);
1164
1165 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1166 perror("getrlimit(RLIMIT_NOFILE, ...)");
1167 _exit(0);
1168 }
1169 n = rl.rlim_cur;
1170 for (i = 0; i < n; i++) {
1171 if (i != pfd && i != proc_poll_pipe[1])
1172 close(i);
1173 }
1174
1175 pollinfo.fd = pfd;
1176 pollinfo.pid = getpid();
1177 for (;;) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001178 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1179 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001180 switch (errno) {
1181 case EINTR:
1182 continue;
1183 case EBADF:
1184 pollinfo.revents = POLLERR;
1185 break;
1186 case ENOENT:
1187 pollinfo.revents = POLLHUP;
1188 break;
1189 default:
1190 perror("proc_poller: PIOCWSTOP");
1191 }
1192 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1193 _exit(0);
1194 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001195 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001196 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1197 sigsuspend(&empty_set);
1198 }
1199}
1200
1201#endif /* !HAVE_POLLABLE_PROCFS */
1202
1203static int
1204choose_pfd()
1205{
1206 int i, j;
1207 struct tcb *tcp;
1208
1209 static int last;
1210
1211 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001212 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001213 /*
1214 * The previous process is ready to run again. We'll
1215 * let it do so if it is currently in a syscall. This
1216 * heuristic improves the readability of the trace.
1217 */
1218 tcp = pfd2tcb(pollv[last].fd);
1219 if (tcp && (tcp->flags & TCB_INSYSCALL))
1220 return pollv[last].fd;
1221 }
1222
1223 for (i = 0; i < nprocs; i++) {
1224 /* Let competing children run round robin. */
1225 j = (i + last + 1) % nprocs;
1226 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1227 tcp = pfd2tcb(pollv[j].fd);
1228 if (!tcp) {
1229 fprintf(stderr, "strace: lost proc\n");
1230 exit(1);
1231 }
1232 droptcb(tcp);
1233 return -1;
1234 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001235 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001236 last = j;
1237 return pollv[j].fd;
1238 }
1239 }
1240 fprintf(stderr, "strace: nothing ready\n");
1241 exit(1);
1242}
1243
1244static int
1245trace()
1246{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001247#ifdef POLL_HACK
1248 struct tcb *in_syscall;
1249#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001250 struct tcb *tcp;
1251 int pfd;
1252 int what;
1253 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001254 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001255
1256 for (;;) {
1257 if (interactive)
1258 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1259
1260 if (nprocs == 0)
1261 break;
1262
1263 switch (nprocs) {
1264 case 1:
1265#ifndef HAVE_POLLABLE_PROCFS
1266 if (proc_poll_pipe[0] == -1) {
1267#endif
1268 tcp = pid2tcb(0);
1269 if (!tcp)
1270 continue;
1271 pfd = tcp->pfd;
1272 if (pfd == -1)
1273 continue;
1274 break;
1275#ifndef HAVE_POLLABLE_PROCFS
1276 }
1277 /* fall through ... */
1278#endif /* !HAVE_POLLABLE_PROCFS */
1279 default:
1280#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001281#ifdef POLL_HACK
1282 /* On some systems (e.g. UnixWare) we get too much ugly
1283 "unfinished..." stuff when multiple proceses are in
1284 syscalls. Here's a nasty hack */
1285
1286 if (in_syscall) {
1287 struct pollfd pv;
1288 tcp = in_syscall;
1289 in_syscall = NULL;
1290 pv.fd = tcp->pfd;
1291 pv.events = POLLWANT;
1292 if ((what = poll (&pv, 1, 1)) < 0) {
1293 if (interrupted)
1294 return 0;
1295 continue;
1296 }
1297 else if (what == 1 && pv.revents & POLLWANT) {
1298 goto FOUND;
1299 }
1300 }
1301#endif
1302
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001303 if (poll(pollv, nprocs, INFTIM) < 0) {
1304 if (interrupted)
1305 return 0;
1306 continue;
1307 }
1308#else /* !HAVE_POLLABLE_PROCFS */
1309 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1310 if (interrupted)
1311 return 0;
1312 continue;
1313 }
1314#endif /* !HAVE_POLLABLE_PROCFS */
1315 pfd = choose_pfd();
1316 if (pfd == -1)
1317 continue;
1318 break;
1319 }
1320
1321 /* Look up `pfd' in our table. */
1322 if ((tcp = pfd2tcb(pfd)) == NULL) {
1323 fprintf(stderr, "unknown pfd: %u\n", pfd);
1324 exit(1);
1325 }
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001326 FOUND:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001327 /* Get the status of the process. */
1328 if (!interrupted) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001329 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001330 ioctl_errno = errno;
1331#ifndef HAVE_POLLABLE_PROCFS
1332 if (proc_poll_pipe[0] != -1) {
1333 if (ioctl_result < 0)
1334 kill(poller_pid, SIGKILL);
1335 else
1336 kill(poller_pid, SIGUSR1);
1337 }
1338#endif /* !HAVE_POLLABLE_PROCFS */
1339 }
1340 if (interrupted)
1341 return 0;
1342
1343 if (interactive)
1344 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1345
1346 if (ioctl_result < 0) {
1347 /* Find out what happened if it failed. */
1348 switch (ioctl_errno) {
1349 case EINTR:
1350 case EBADF:
1351 continue;
1352 case ENOENT:
1353 droptcb(tcp);
1354 continue;
1355 default:
1356 perror("PIOCWSTOP");
1357 exit(1);
1358 }
1359 }
1360
1361 /* clear the just started flag */
1362 tcp->flags &= ~TCB_STARTUP;
1363
1364 /* set current output file */
1365 outf = tcp->outf;
1366
1367 if (cflag) {
1368 struct timeval stime;
1369
1370 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1371 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
1372 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1373 tcp->stime = stime;
1374 }
1375
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001376 what = tcp->status.PR_WHAT;
1377 switch (tcp->status.PR_WHY) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001378 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001379 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1380 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001381 if (trace_syscall(tcp) < 0) {
1382 fprintf(stderr, "syscall trouble\n");
1383 exit(1);
1384 }
1385 }
1386 break;
1387 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001388#ifdef POLL_HACK
1389 in_syscall = tcp;
1390#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001391 case PR_SYSEXIT:
1392 if (trace_syscall(tcp) < 0) {
1393 fprintf(stderr, "syscall trouble\n");
1394 exit(1);
1395 }
1396 break;
1397 case PR_SIGNALLED:
1398 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1399 printleader(tcp);
1400 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001401 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001402 printtrailer(tcp);
1403 }
1404 break;
1405 case PR_FAULTED:
1406 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1407 printleader(tcp);
1408 tprintf("=== FAULT %d ===", what);
1409 printtrailer(tcp);
1410 }
1411 break;
1412 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001413 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001414 exit(1);
1415 break;
1416 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001417 arg = 0;
1418 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001419 perror("PIOCRUN");
1420 exit(1);
1421 }
1422 }
1423 return 0;
1424}
1425
1426#else /* !SVR4 */
1427
1428static int
1429trace()
1430{
1431 int pid;
1432 int wait_errno;
1433 int status;
1434 struct tcb *tcp;
1435#ifdef LINUX
1436 struct rusage ru;
1437#endif /* LINUX */
1438
1439 while (nprocs != 0) {
1440 if (interactive)
1441 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1442#ifdef LINUX
1443 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
1444#endif /* LINUX */
1445#ifdef SUNOS4
1446 pid = wait(&status);
1447#endif /* SUNOS4 */
1448 wait_errno = errno;
1449 if (interactive)
1450 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1451
1452 if (interrupted)
1453 return 0;
1454
1455 if (pid == -1) {
1456 switch (wait_errno) {
1457 case EINTR:
1458 continue;
1459 case ECHILD:
1460 /*
1461 * We would like to verify this case
1462 * but sometimes a race in Solbourne's
1463 * version of SunOS sometimes reports
1464 * ECHILD before sending us SIGCHILD.
1465 */
1466#if 0
1467 if (nprocs == 0)
1468 return 0;
1469 fprintf(stderr, "strace: proc miscount\n");
1470 exit(1);
1471#endif
1472 return 0;
1473 default:
1474 errno = wait_errno;
1475 perror("strace: wait");
1476 return -1;
1477 }
1478 }
1479 if (debug)
1480 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1481
1482 /* Look up `pid' in our table. */
1483 if ((tcp = pid2tcb(pid)) == NULL) {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001484#if 1 /* XXX davidm */
1485 struct tcb *tcpchild;
1486
1487 if ((tcpchild = alloctcb(pid)) == NULL) {
1488 fprintf(stderr, " [tcb table full]\n");
1489 kill(pid, SIGKILL); /* XXX */
1490 return 0;
1491 }
1492 tcpchild->flags |= TCB_ATTACHED;
1493 newoutf(tcpchild);
1494 tcp->nchildren++;
1495 if (!qflag)
1496 fprintf(stderr, "Process %d attached\n", pid);
1497#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001498 fprintf(stderr, "unknown pid: %u\n", pid);
1499 if (WIFSTOPPED(status))
1500 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1501 exit(1);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001502#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001503 }
1504 /* set current output file */
1505 outf = tcp->outf;
1506 if (cflag) {
1507#ifdef LINUX
1508 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
1509 tcp->stime = ru.ru_stime;
1510#endif /* !LINUX */
1511 }
1512
1513 if (tcp->flags & TCB_SUSPENDED) {
1514 /*
1515 * Apparently, doing any ptrace() call on a stopped
1516 * process, provokes the kernel to report the process
1517 * status again on a subsequent wait(), even if the
1518 * process has not been actually restarted.
1519 * Since we have inspected the arguments of suspended
1520 * processes we end up here testing for this case.
1521 */
1522 continue;
1523 }
1524 if (WIFSIGNALED(status)) {
1525 if (!cflag
1526 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
1527 printleader(tcp);
1528 tprintf("+++ killed by %s +++",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001529 signame(WTERMSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001530 printtrailer(tcp);
1531 }
1532 droptcb(tcp);
1533 continue;
1534 }
1535 if (WIFEXITED(status)) {
1536 if (debug)
1537 fprintf(stderr, "pid %u exited\n", pid);
1538 if (tcp->flags & TCB_ATTACHED)
1539 fprintf(stderr,
1540 "PANIC: attached pid %u exited\n",
1541 pid);
1542 droptcb(tcp);
1543 continue;
1544 }
1545 if (!WIFSTOPPED(status)) {
1546 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
1547 droptcb(tcp);
1548 continue;
1549 }
1550 if (debug)
1551 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001552 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001553
1554 if (tcp->flags & TCB_STARTUP) {
1555 /*
1556 * This flag is there to keep us in sync.
1557 * Next time this process stops it should
1558 * really be entering a system call.
1559 */
1560 tcp->flags &= ~TCB_STARTUP;
1561 if (tcp->flags & TCB_ATTACHED) {
1562 /*
1563 * Interestingly, the process may stop
1564 * with STOPSIG equal to some other signal
1565 * than SIGSTOP if we happend to attach
1566 * just before the process takes a signal.
1567 */
1568 if (!WIFSTOPPED(status)) {
1569 fprintf(stderr,
1570 "pid %u not stopped\n", pid);
1571 detach(tcp, WSTOPSIG(status));
1572 continue;
1573 }
1574 }
1575 else {
1576#ifdef SUNOS4
1577 /* A child of us stopped at exec */
1578 if (WSTOPSIG(status) == SIGTRAP && followvfork)
1579 fixvfork(tcp);
1580#endif /* SUNOS4 */
1581 }
1582 if (tcp->flags & TCB_BPTSET) {
1583 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
1584 droptcb(tcp);
1585 cleanup();
1586 return -1;
1587 }
1588 }
1589 goto tracing;
1590 }
1591
1592 if (WSTOPSIG(status) != SIGTRAP) {
1593 if (WSTOPSIG(status) == SIGSTOP &&
1594 (tcp->flags & TCB_SIGTRAPPED)) {
1595 /*
1596 * Trapped attempt to block SIGTRAP
1597 * Hope we are back in control now.
1598 */
1599 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
1600 if (ptrace(PTRACE_SYSCALL,
1601 pid, (char *) 1, 0) < 0) {
1602 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
1603 cleanup();
1604 return -1;
1605 }
1606 continue;
1607 }
1608 if (!cflag
1609 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
1610 printleader(tcp);
1611 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001612 signame(WSTOPSIG(status)),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001613 strsignal(WSTOPSIG(status)));
1614 printtrailer(tcp);
1615 }
1616 if ((tcp->flags & TCB_ATTACHED) &&
1617 !sigishandled(tcp, WSTOPSIG(status))) {
1618 detach(tcp, WSTOPSIG(status));
1619 continue;
1620 }
1621 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
1622 WSTOPSIG(status)) < 0) {
1623 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
1624 cleanup();
1625 return -1;
1626 }
1627 tcp->flags &= ~TCB_SUSPENDED;
1628 continue;
1629 }
1630 if (trace_syscall(tcp) < 0) {
1631 if (tcp->flags & TCB_ATTACHED)
1632 detach(tcp, 0);
1633 else {
1634 ptrace(PTRACE_KILL,
1635 tcp->pid, (char *) 1, SIGTERM);
1636 droptcb(tcp);
1637 }
1638 continue;
1639 }
1640 if (tcp->flags & TCB_EXITING) {
1641 if (tcp->flags & TCB_ATTACHED)
1642 detach(tcp, 0);
1643 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
1644 perror("strace: ptrace(PTRACE_CONT, ...)");
1645 cleanup();
1646 return -1;
1647 }
1648 continue;
1649 }
1650 if (tcp->flags & TCB_SUSPENDED) {
1651 if (!qflag)
1652 fprintf(stderr, "Process %u suspended\n", pid);
1653 continue;
1654 }
1655 tracing:
1656 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
1657 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
1658 cleanup();
1659 return -1;
1660 }
1661 }
1662 return 0;
1663}
1664
1665#endif /* !SVR4 */
1666
1667static int curcol;
1668
1669#ifdef __STDC__
1670#include <stdarg.h>
1671#define VA_START(a, b) va_start(a, b)
1672#else
1673#include <varargs.h>
1674#define VA_START(a, b) va_start(a)
1675#endif
1676
1677void
1678#ifdef __STDC__
1679tprintf(const char *fmt, ...)
1680#else
1681tprintf(fmt, va_alist)
1682char *fmt;
1683va_dcl
1684#endif
1685{
1686 va_list args;
1687
1688 VA_START(args, fmt);
1689 if (outf)
1690 curcol += vfprintf(outf, fmt, args);
1691 va_end(args);
1692 return;
1693}
1694
1695void
1696printleader(tcp)
1697struct tcb *tcp;
1698{
1699 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
1700 tcp_last->flags |= TCB_REPRINT;
1701 tprintf(" <unfinished ...>\n");
1702 }
1703 curcol = 0;
1704 if ((followfork == 1 || pflag_seen > 1) && outfname)
1705 tprintf("%-5d ", tcp->pid);
1706 else if (nprocs > 1 && !outfname)
1707 tprintf("[pid %5u] ", tcp->pid);
1708 if (tflag) {
1709 char str[sizeof("HH:MM:SS")];
1710 struct timeval tv, dtv;
1711 static struct timeval otv;
1712
1713 gettimeofday(&tv, NULL);
1714 if (rflag) {
1715 if (otv.tv_sec == 0)
1716 otv = tv;
1717 tv_sub(&dtv, &tv, &otv);
1718 tprintf("%6ld.%06ld ",
1719 (long) dtv.tv_sec, (long) dtv.tv_usec);
1720 otv = tv;
1721 }
1722 else if (tflag > 2) {
1723 tprintf("%ld.%06ld ",
1724 (long) tv.tv_sec, (long) tv.tv_usec);
1725 }
1726 else {
1727 time_t local = tv.tv_sec;
1728 strftime(str, sizeof(str), "%T", localtime(&local));
1729 if (tflag > 1)
1730 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
1731 else
1732 tprintf("%s ", str);
1733 }
1734 }
1735 if (iflag)
1736 printcall(tcp);
1737}
1738
1739void
1740tabto(col)
1741int col;
1742{
1743 if (curcol < col)
1744 tprintf("%*s", col - curcol, "");
1745}
1746
1747void
1748printtrailer(tcp)
1749struct tcb *tcp;
1750{
1751 tprintf("\n");
1752 tcp_last = NULL;
1753}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001754
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001755#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001756
1757int mp_ioctl (int fd, int cmd, void *arg, int size) {
1758
1759 struct iovec iov[2];
1760 int n = 1;
1761
1762 iov[0].iov_base = &cmd;
1763 iov[0].iov_len = sizeof cmd;
1764 if (arg) {
1765 ++n;
1766 iov[1].iov_base = arg;
1767 iov[1].iov_len = size;
1768 }
1769
1770 return writev (fd, iov, n);
1771}
1772
1773#endif