blob: 083e850c3cdd9a219b66c3ca400340ab391c1162 [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
Wichert Akkerman2ee6e452000-02-18 15:36:12 +000033#include <sys/types.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000034#include "defs.h"
35
36#include <signal.h>
37#include <errno.h>
38#include <sys/param.h>
39#include <fcntl.h>
40#include <sys/resource.h>
41#include <sys/wait.h>
42#include <sys/stat.h>
43#include <pwd.h>
44#include <grp.h>
45#include <string.h>
46
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000047#ifdef USE_PROCFS
48#include <poll.h>
49#endif
50
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000051#ifdef SVR4
52#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000053#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000054#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000055#include <sys/uio.h>
56#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000057#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000058#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000059
60int debug = 0, followfork = 0, followvfork = 0, interactive = 0;
61int rflag = 0, tflag = 0, dtime = 0, cflag = 0;
62int iflag = 0, xflag = 0, qflag = 0;
63int pflag_seen = 0;
64
65char *username = NULL;
66uid_t run_uid;
67gid_t run_gid;
68
69int acolumn = DEFAULT_ACOLUMN;
70int max_strlen = DEFAULT_STRLEN;
71char *outfname = NULL;
72FILE *outf;
73struct tcb tcbtab[MAX_PROCS];
74int nprocs;
75char *progname;
76extern char version[];
77extern char **environ;
78
79static struct tcb *pid2tcb P((int pid));
80static int trace P((void));
81static void cleanup P((void));
82static void interrupt P((int sig));
83static sigset_t empty_set, blocked_set;
84
85#ifdef HAVE_SIG_ATOMIC_T
86static volatile sig_atomic_t interrupted;
87#else /* !HAVE_SIG_ATOMIC_T */
88#ifdef __STDC__
89static volatile int interrupted;
90#else /* !__STDC__ */
91static int interrupted;
92#endif /* !__STDC__ */
93#endif /* !HAVE_SIG_ATOMIC_T */
94
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000095#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000096
97static struct tcb *pfd2tcb P((int pfd));
98static void reaper P((int sig));
99static void rebuild_pollv P((void));
Wichert Akkermane68d61c1999-06-28 13:17:16 +0000100struct pollfd pollv[MAX_PROCS];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000101
102#ifndef HAVE_POLLABLE_PROCFS
103
104static void proc_poll_open P((void));
105static void proc_poller P((int pfd));
106
107struct proc_pollfd {
108 int fd;
109 int revents;
110 int pid;
111};
112
113static int poller_pid;
114static int proc_poll_pipe[2] = { -1, -1 };
115
116#endif /* !HAVE_POLLABLE_PROCFS */
117
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000118#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000119#define POLLWANT POLLWRNORM
120#else
121#define POLLWANT POLLPRI
122#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000123#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000124
125static void
126usage(ofp, exitval)
127FILE *ofp;
128int exitval;
129{
130 fprintf(ofp, "\
131usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
132 [-p pid] ... [-s strsize] [-u username] [command [arg ...]]\n\
133 or: strace -c [-e expr] ... [-O overhead] [-S sortby] [command [arg ...]]\n\
134-c -- count time, calls, and errors for each syscall and report summary\n\
135-f -- follow forks, -ff -- with output into separate files\n\
136-F -- attempt to follow vforks, -h -- print help message\n\
137-i -- print instruction pointer at time of syscall\n\
138-q -- suppress messages about attaching, detaching, etc.\n\
139-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
140-T -- print time spent in each syscall, -V -- print version\n\
141-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
142-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
143-a column -- alignment COLUMN for printing syscall results (default %d)\n\
144-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
145 options: trace, abbrev, verbose, raw, signal, read, or write\n\
146-o file -- send trace output to FILE instead of stderr\n\
147-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
148-p pid -- trace process with process id PID, may be repeated\n\
149-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
150-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
151-u username -- run command as username handling setuid and/or setgid\n\
152", DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
153 exit(exitval);
154}
155
156#ifdef SVR4
157#ifdef MIPS
158void
159foobar()
160{
161}
162#endif /* MIPS */
163#endif /* SVR4 */
164
165int
166main(argc, argv)
167int argc;
168char *argv[];
169{
170 extern int optind;
171 extern char *optarg;
172 struct tcb *tcp;
173 int c, pid = 0;
174 struct sigaction sa;
175
176 static char buf[BUFSIZ];
177
178 progname = argv[0];
179 outf = stderr;
180 interactive = 1;
181 qualify("trace=all");
182 qualify("abbrev=all");
183 qualify("verbose=all");
184 qualify("signal=all");
185 set_sortby(DEFAULT_SORTBY);
186 set_personality(DEFAULT_PERSONALITY);
187 while ((c = getopt(argc, argv,
188 "+cdfFhiqrtTvVxa:e:o:O:p:s:S:u:")) != EOF) {
189 switch (c) {
190 case 'c':
191 cflag++;
192 dtime++;
193 break;
194 case 'd':
195 debug++;
196 break;
197 case 'f':
198 followfork++;
199 break;
200 case 'F':
201 followvfork++;
202 break;
203 case 'h':
204 usage(stdout, 0);
205 break;
206 case 'i':
207 iflag++;
208 break;
209 case 'q':
210 qflag++;
211 break;
212 case 'r':
213 rflag++;
214 tflag++;
215 break;
216 case 't':
217 tflag++;
218 break;
219 case 'T':
220 dtime++;
221 break;
222 case 'x':
223 xflag++;
224 break;
225 case 'v':
226 qualify("abbrev=none");
227 break;
228 case 'V':
229 printf("%s\n", version);
230 exit(0);
231 break;
232 case 'a':
233 acolumn = atoi(optarg);
234 break;
235 case 'e':
236 qualify(optarg);
237 break;
238 case 'o':
239 outfname = strdup(optarg);
240 break;
241 case 'O':
242 set_overhead(atoi(optarg));
243 break;
244 case 'p':
245 if ((pid = atoi(optarg)) == 0) {
246 fprintf(stderr, "%s: Invalid process id: %s\n",
247 progname, optarg);
248 break;
249 }
250 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000251 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000252 break;
253 }
254 if ((tcp = alloctcb(pid)) == NULL) {
255 fprintf(stderr, "%s: tcb table full, please recompile strace\n",
256 progname);
257 exit(1);
258 }
259 tcp->flags |= TCB_ATTACHED;
260 pflag_seen++;
261 break;
262 case 's':
263 max_strlen = atoi(optarg);
264 break;
265 case 'S':
266 set_sortby(optarg);
267 break;
268 case 'u':
269 username = strdup(optarg);
270 break;
271 default:
272 usage(stderr, 1);
273 break;
274 }
275 }
276
277 /* See if they want to run as another user. */
278 if (username != NULL) {
279 struct passwd *pent;
280
281 if (getuid() != 0 || geteuid() != 0) {
282 fprintf(stderr,
283 "%s: you must be root to use the -u option\n",
284 progname);
285 exit(1);
286 }
287 if ((pent = getpwnam(username)) == NULL) {
288 fprintf(stderr, "%s: cannot find user `%s'\n",
289 progname, optarg);
290 exit(1);
291 }
292 run_uid = pent->pw_uid;
293 run_gid = pent->pw_gid;
294 }
295 else {
296 run_uid = getuid();
297 run_gid = getgid();
298 }
299
300#ifndef SVR4
301 setreuid(geteuid(), getuid());
302#endif
303
304 /* See if they want to pipe the output. */
305 if (outfname && (outfname[0] == '|' || outfname[0] == '!')) {
306 if ((outf = popen(outfname + 1, "w")) == NULL) {
307 fprintf(stderr, "%s: can't popen '%s': %s\n",
308 progname, outfname + 1, strerror(errno));
309 exit(1);
310 }
311 free(outfname);
312 outfname = NULL;
313 }
314
315 /* Check if they want to redirect the output. */
316 if (outfname) {
317 if ((outf = fopen(outfname, "w")) == NULL) {
318 fprintf(stderr, "%s: can't fopen '%s': %s\n",
319 progname, outfname, strerror(errno));
320 exit(1);
321 }
322 }
323
324#ifndef SVR4
325 setreuid(geteuid(), getuid());
326#endif
327
328 if (!outfname) {
329 qflag = 1;
330 setvbuf(outf, buf, _IOLBF, BUFSIZ);
331 }
332 else if (optind < argc)
333 interactive = 0;
334 else
335 qflag = 1;
336
337 for (c = 0, tcp = tcbtab; c < MAX_PROCS; c++, tcp++) {
338 /* Reinitialize the output since it may have changed. */
339 tcp->outf = outf;
340 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
341 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000342#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000343 if (proc_open(tcp, 1) < 0) {
344 fprintf(stderr, "trouble opening proc file\n");
345 droptcb(tcp);
346 continue;
347 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000348#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000349 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
350 perror("attach: ptrace(PTRACE_ATTACH, ...)");
351 droptcb(tcp);
352 continue;
353 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000354#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000355 if (!qflag)
356 fprintf(stderr,
357 "Process %u attached - interrupt to quit\n",
358 pid);
359 }
360
361 if (optind < argc) {
362 struct stat statbuf;
363 char *filename;
364 char pathname[MAXPATHLEN];
365
366 filename = argv[optind];
367 if (strchr(filename, '/'))
368 strcpy(pathname, filename);
369#ifdef USE_DEBUGGING_EXEC
370 /*
371 * Debuggers customarily check the current directory
372 * first regardless of the path but doing that gives
373 * security geeks a panic attack.
374 */
375 else if (stat(filename, &statbuf) == 0)
376 strcpy(pathname, filename);
377#endif /* USE_DEBUGGING_EXEC */
378 else {
379 char *path;
380 int m, n, len;
381
382 for (path = getenv("PATH"); path && *path; path += m) {
383 if (strchr(path, ':')) {
384 n = strchr(path, ':') - path;
385 m = n + 1;
386 }
387 else
388 m = n = strlen(path);
389 if (n == 0) {
390 getcwd(pathname, MAXPATHLEN);
391 len = strlen(pathname);
392 }
393 else {
394 strncpy(pathname, path, n);
395 len = n;
396 }
397 if (len && pathname[len - 1] != '/')
398 pathname[len++] = '/';
399 strcpy(pathname + len, filename);
400 if (stat(pathname, &statbuf) == 0)
401 break;
402 }
403 }
404 if (stat(pathname, &statbuf) < 0) {
405 fprintf(stderr, "%s: %s: command not found\n",
406 progname, filename);
407 exit(1);
408 }
409 switch (pid = fork()) {
410 case -1:
411 perror("strace: fork");
412 cleanup();
413 exit(1);
414 break;
415 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000416#ifdef USE_PROCFS
417 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000418#ifdef MIPS
419 /* Kludge for SGI, see proc_open for details. */
420 sa.sa_handler = foobar;
421 sa.sa_flags = 0;
422 sigemptyset(&sa.sa_mask);
423 sigaction(SIGINT, &sa, NULL);
424#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000425#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000426 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000427#else /* FREEBSD */
428 kill(getpid(), SIGSTOP); /* stop HERE */
429#endif /* FREEBSD */
430#else /* !USE_PROCFS */
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000431 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000432 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000433
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000434 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
435 perror("strace: ptrace(PTRACE_TRACEME, ...)");
436 return -1;
437 }
438 if (debug)
439 kill(getpid(), SIGSTOP);
440
441 if (username != NULL || geteuid() == 0) {
442 uid_t run_euid = run_uid;
443 gid_t run_egid = run_gid;
444
445 if (statbuf.st_mode & S_ISUID)
446 run_euid = statbuf.st_uid;
447 if (statbuf.st_mode & S_ISGID)
448 run_egid = statbuf.st_gid;
449
450 /*
451 * It is important to set groups before we
452 * lose privileges on setuid.
453 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000454 if (username != NULL) {
455 if (initgroups(username, run_gid) < 0) {
456 perror("initgroups");
457 exit(1);
458 }
459 if (setregid(run_gid, run_egid) < 0) {
460 perror("setregid");
461 exit(1);
462 }
463 if (setreuid(run_uid, run_euid) < 0) {
464 perror("setreuid");
465 exit(1);
466 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 }
468 }
469 else
470 setreuid(run_uid, run_uid);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000471#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000472
473 execv(pathname, &argv[optind]);
474 perror("strace: exec");
475 _exit(1);
476 break;
477 }
478 default:
479 if ((tcp = alloctcb(pid)) == NULL) {
480 fprintf(stderr, "tcb table full\n");
481 cleanup();
482 exit(1);
483 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000484#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000485 if (proc_open(tcp, 0) < 0) {
486 fprintf(stderr, "trouble opening proc file\n");
487 cleanup();
488 exit(1);
489 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000490#endif /* USE_PROCFS */
491#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000492 fake_execve(tcp, pathname, &argv[optind], environ);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000493#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000494 break;
495 }
496 }
497 else if (pflag_seen == 0)
498 usage(stderr, 1);
499
500 sigemptyset(&empty_set);
501 sigemptyset(&blocked_set);
502 sa.sa_handler = SIG_IGN;
503 sigemptyset(&sa.sa_mask);
504 sa.sa_flags = 0;
505 sigaction(SIGTTOU, &sa, NULL);
506 sigaction(SIGTTIN, &sa, NULL);
507 if (interactive) {
508 sigaddset(&blocked_set, SIGHUP);
509 sigaddset(&blocked_set, SIGINT);
510 sigaddset(&blocked_set, SIGQUIT);
511 sigaddset(&blocked_set, SIGPIPE);
512 sigaddset(&blocked_set, SIGTERM);
513 sa.sa_handler = interrupt;
514#ifdef SUNOS4
515 /* POSIX signals on sunos4.1 are a little broken. */
516 sa.sa_flags = SA_INTERRUPT;
517#endif /* SUNOS4 */
518 }
519 sigaction(SIGHUP, &sa, NULL);
520 sigaction(SIGINT, &sa, NULL);
521 sigaction(SIGQUIT, &sa, NULL);
522 sigaction(SIGPIPE, &sa, NULL);
523 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000524#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000525 sa.sa_handler = reaper;
526 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000527#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000528
529 if (trace() < 0)
530 exit(1);
531 cleanup();
532 exit(0);
533}
534
535void
536newoutf(tcp)
537struct tcb *tcp;
538{
539 char name[MAXPATHLEN];
540 FILE *fp;
541
542 if (outfname && followfork > 1) {
543 sprintf(name, "%s.%u", outfname, tcp->pid);
544#ifndef SVR4
545 setreuid(geteuid(), getuid());
546#endif
547 fp = fopen(name, "w");
548#ifndef SVR4
549 setreuid(geteuid(), getuid());
550#endif
551 if (fp == NULL) {
552 perror("fopen");
553 return;
554 }
555 tcp->outf = fp;
556 }
557 return;
558}
559
560struct tcb *
561alloctcb(pid)
562int pid;
563{
564 int i;
565 struct tcb *tcp;
566
567 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
568 if ((tcp->flags & TCB_INUSE) == 0) {
569 tcp->pid = pid;
570 tcp->parent = NULL;
571 tcp->nchildren = 0;
572 tcp->flags = TCB_INUSE | TCB_STARTUP;
573 tcp->outf = outf; /* Initialise to current out file */
574 tcp->stime.tv_sec = 0;
575 tcp->stime.tv_usec = 0;
576 tcp->pfd = -1;
577 nprocs++;
578 return tcp;
579 }
580 }
581 return NULL;
582}
583
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000584#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000585int
586proc_open(tcp, attaching)
587struct tcb *tcp;
588int attaching;
589{
590 char proc[32];
591 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000592#ifdef SVR4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000593 sysset_t sc_enter, sc_exit;
594 sigset_t signals;
595 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000596#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597#ifndef HAVE_POLLABLE_PROCFS
598 static int last_pfd;
599#endif
600
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000601#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000602 /* Open the process pseudo-files in /proc. */
603 sprintf(proc, "/proc/%d/ctl", tcp->pid);
604 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000605 perror("strace: open(\"/proc/...\", ...)");
606 return -1;
607 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000608 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
609 perror("F_GETFD");
610 return -1;
611 }
612 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
613 perror("F_SETFD");
614 return -1;
615 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000616 sprintf(proc, "/proc/%d/status", tcp->pid);
617 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
618 perror("strace: open(\"/proc/...\", ...)");
619 return -1;
620 }
621 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
622 perror("F_GETFD");
623 return -1;
624 }
625 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
626 perror("F_SETFD");
627 return -1;
628 }
629 sprintf(proc, "/proc/%d/as", tcp->pid);
630 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
631 perror("strace: open(\"/proc/...\", ...)");
632 return -1;
633 }
634 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
635 perror("F_GETFD");
636 return -1;
637 }
638 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
639 perror("F_SETFD");
640 return -1;
641 }
642#else
643 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000644#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000645 sprintf(proc, "/proc/%d", tcp->pid);
646 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000647#else /* FREEBSD */
648 sprintf(proc, "/proc/%d/mem", tcp->pid);
649 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
650#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000651 perror("strace: open(\"/proc/...\", ...)");
652 return -1;
653 }
654 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
655 perror("F_GETFD");
656 return -1;
657 }
658 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
659 perror("F_SETFD");
660 return -1;
661 }
662#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000663#ifdef FREEBSD
664 sprintf(proc, "/proc/%d/regs", tcp->pid);
665 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
666 perror("strace: open(\"/proc/.../regs\", ...)");
667 return -1;
668 }
669 if (cflag) {
670 sprintf(proc, "/proc/%d/status", tcp->pid);
671 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
672 perror("strace: open(\"/proc/.../status\", ...)");
673 return -1;
674 }
675 } else
676 tcp->pfd_status = -1;
677#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000678 rebuild_pollv();
679 if (!attaching) {
680 /*
681 * Wait for the child to pause. Because of a race
682 * condition we have to poll for the event.
683 */
684 for (;;) {
685 if (IOCTL_STATUS (tcp) < 0) {
686 perror("strace: PIOCSTATUS");
687 return -1;
688 }
689 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000690 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000691 }
692 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000693#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000694 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000695 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000696 perror("strace: PIOCSTOP");
697 return -1;
698 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000699#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000700#ifdef PIOCSET
701 /* Set Run-on-Last-Close. */
702 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000703 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000704 perror("PIOCSET PR_RLC");
705 return -1;
706 }
707 /* Set or Reset Inherit-on-Fork. */
708 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000709 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000710 perror("PIOC{SET,RESET} PR_FORK");
711 return -1;
712 }
713#else /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000714#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000715 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
716 perror("PIOCSRLC");
717 return -1;
718 }
719 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
720 perror("PIOC{S,R}FORK");
721 return -1;
722 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000723#else /* FREEBSD */
724 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
725 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
726 perror("PIOCGFL");
727 return -1;
728 }
729 arg &= ~PF_LINGER;
730 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
731 perror("PIOCSFL");
732 return -1;
733 }
734#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000735#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000736#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000737 /* Enable all syscall entries. */
738 prfillset(&sc_enter);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000739 if (IOCTL(tcp->pfd, PIOCSENTRY, &sc_enter) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000740 perror("PIOCSENTRY");
741 return -1;
742 }
743 /* Enable all syscall exits. */
744 prfillset(&sc_exit);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000745 if (IOCTL(tcp->pfd, PIOCSEXIT, &sc_exit) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746 perror("PIOSEXIT");
747 return -1;
748 }
749 /* Enable all signals. */
750 prfillset(&signals);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000751 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000752 perror("PIOCSTRACE");
753 return -1;
754 }
755 /* Enable all faults. */
756 prfillset(&faults);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000757 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000758 perror("PIOCSFAULT");
759 return -1;
760 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000761#else /* FREEBSD */
762 /* set events flags. */
763 arg = S_SIG | S_SCE | S_SCX ;
764 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
765 perror("PIOCBIS");
766 return -1;
767 }
768#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000769 if (!attaching) {
770#ifdef MIPS
771 /*
772 * The SGI PRSABORT doesn't work for pause() so
773 * we send it a caught signal to wake it up.
774 */
775 kill(tcp->pid, SIGINT);
776#else /* !MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000777#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000779 arg = PRSABORT;
780 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000781 perror("PIOCRUN");
782 return -1;
783 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000784#endif
785#endif /* !MIPS*/
786#ifdef FREEBSD
787 /* wake up the child if it received the SIGSTOP */
788 kill(tcp->pid, SIGCONT);
789#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790 for (;;) {
791 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000792 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000793 perror("PIOCWSTOP");
794 return -1;
795 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000796 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000797 tcp->flags &= ~TCB_INSYSCALL;
798 get_scno(tcp);
799 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000800 break;
801 }
802 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000803#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000804 arg = 0;
805 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000806#else /* FREEBSD */
807 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
808#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000809 perror("PIOCRUN");
810 return -1;
811 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000812#ifdef FREEBSD
813 /* handle the case where we "opened" the child before
814 it did the kill -STOP */
815 if (tcp->status.PR_WHY == PR_SIGNALLED &&
816 tcp->status.PR_WHAT == SIGSTOP)
817 kill(tcp->pid, SIGCONT);
818#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000819 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000820#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000821 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000822#else /* FREEBSD */
823 } else {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000824 if (attaching < 2) {
825 /* We are attaching to an already running process.
826 * Try to figure out the state of the process in syscalls,
827 * to handle the first event well.
828 * This is done by having a look at the "wchan" property of the
829 * process, which tells where it is stopped (if it is). */
830 FILE * status;
831 char wchan[20]; /* should be enough */
832
833 sprintf(proc, "/proc/%d/status", tcp->pid);
834 status = fopen(proc, "r");
835 if (status &&
836 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
837 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
838 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
839 strcmp(wchan, "stopevent")) {
840 /* The process is asleep in the middle of a syscall.
841 Fake the syscall entry event */
842 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
843 tcp->status.PR_WHY = PR_SYSENTRY;
844 trace_syscall(tcp);
845 }
846 if (status)
847 fclose(status);
848 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000849 }
850#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000851#ifndef HAVE_POLLABLE_PROCFS
852 if (proc_poll_pipe[0] != -1)
853 proc_poller(tcp->pfd);
854 else if (nprocs > 1) {
855 proc_poll_open();
856 proc_poller(last_pfd);
857 proc_poller(tcp->pfd);
858 }
859 last_pfd = tcp->pfd;
860#endif /* !HAVE_POLLABLE_PROCFS */
861 return 0;
862}
863
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000864#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000865
866static struct tcb *
867pid2tcb(pid)
868int pid;
869{
870 int i;
871 struct tcb *tcp;
872
873 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
874 if (pid && tcp->pid != pid)
875 continue;
876 if (tcp->flags & TCB_INUSE)
877 return tcp;
878 }
879 return NULL;
880}
881
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000882#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883
884static struct tcb *
885pfd2tcb(pfd)
886int pfd;
887{
888 int i;
889 struct tcb *tcp;
890
891 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
892 if (tcp->pfd != pfd)
893 continue;
894 if (tcp->flags & TCB_INUSE)
895 return tcp;
896 }
897 return NULL;
898}
899
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000900#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000901
902void
903droptcb(tcp)
904struct tcb *tcp;
905{
906 if (tcp->pid == 0)
907 return;
908 nprocs--;
909 tcp->pid = 0;
910 tcp->flags = 0;
911 if (tcp->pfd != -1) {
912 close(tcp->pfd);
913 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000914#ifdef FREEBSD
915 if (tcp->pfd_reg != -1) {
916 close(tcp->pfd_reg);
917 tcp->pfd_reg = -1;
918 }
919 if (tcp->pfd_status != -1) {
920 close(tcp->pfd_status);
921 tcp->pfd_status = -1;
922 }
923#endif /* !FREEBSD */
924#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000925 rebuild_pollv();
926#endif
927 }
928 if (tcp->parent != NULL) {
929 tcp->parent->nchildren--;
930 tcp->parent = NULL;
931 }
932#if 0
933 if (tcp->outf != stderr)
934 fclose(tcp->outf);
935#endif
936 tcp->outf = 0;
937}
938
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000939#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000940
941static int
942resume(tcp)
943struct tcb *tcp;
944{
945 if (tcp == NULL)
946 return -1;
947
948 if (!(tcp->flags & TCB_SUSPENDED)) {
949 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
950 return -1;
951 }
952 tcp->flags &= ~TCB_SUSPENDED;
953
954 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
955 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
956 return -1;
957 }
958
959 if (!qflag)
960 fprintf(stderr, "Process %u resumed\n", tcp->pid);
961 return 0;
962}
963
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000964#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000965
966/* detach traced process; continue with sig */
967
968static int
969detach(tcp, sig)
970struct tcb *tcp;
971int sig;
972{
973 int error = 0;
974#ifdef LINUX
975 int status;
976#endif
977
978 if (tcp->flags & TCB_BPTSET)
979 sig = SIGKILL;
980
981#ifdef LINUX
982 /*
983 * Linux wrongly insists the child be stopped
984 * before detaching. Arghh. We go through hoops
985 * to make a clean break of things.
986 */
Wichert Akkermandacfb6e1999-06-03 14:21:07 +0000987#if defined(SPARC)
988#undef PTRACE_DETACH
989#define PTRACE_DETACH PTRACE_SUNDETACH
990#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
992 /* On a clear day, you can see forever. */
993 }
994 else if (errno != ESRCH) {
995 /* Shouldn't happen. */
996 perror("detach: ptrace(PTRACE_DETACH, ...)");
997 }
998 else if (kill(tcp->pid, 0) < 0) {
999 if (errno != ESRCH)
1000 perror("detach: checking sanity");
1001 }
1002 else if (kill(tcp->pid, SIGSTOP) < 0) {
1003 if (errno != ESRCH)
1004 perror("detach: stopping child");
1005 }
1006 else {
1007 for (;;) {
1008 if (waitpid(tcp->pid, &status, 0) < 0) {
1009 if (errno != ECHILD)
1010 perror("detach: waiting");
1011 break;
1012 }
1013 if (!WIFSTOPPED(status)) {
1014 /* Au revoir, mon ami. */
1015 break;
1016 }
1017 if (WSTOPSIG(status) == SIGSTOP) {
1018 if ((error = ptrace(PTRACE_DETACH,
1019 tcp->pid, (char *) 1, sig)) < 0) {
1020 if (errno != ESRCH)
1021 perror("detach: ptrace(PTRACE_DETACH, ...)");
1022 /* I died trying. */
1023 }
1024 break;
1025 }
1026 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
1027 WSTOPSIG(status) == SIGTRAP ?
1028 0 : WSTOPSIG(status))) < 0) {
1029 if (errno != ESRCH)
1030 perror("detach: ptrace(PTRACE_CONT, ...)");
1031 break;
1032 }
1033 }
1034 }
1035#endif /* LINUX */
1036
1037#if defined(SUNOS4)
1038 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1039 if (sig && kill(tcp->pid, sig) < 0)
1040 perror("detach: kill");
1041 sig = 0;
1042 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1043 perror("detach: ptrace(PTRACE_DETACH, ...)");
1044#endif /* SUNOS4 */
1045
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001046#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001047 if (waiting_parent(tcp))
1048 error = resume(tcp->parent);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001049#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001050
1051 if (!qflag)
1052 fprintf(stderr, "Process %u detached\n", tcp->pid);
1053
1054 droptcb(tcp);
1055 return error;
1056}
1057
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001058#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059
1060static void
1061reaper(sig)
1062int sig;
1063{
1064 int pid;
1065 int status;
1066
1067 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1068#if 0
1069 struct tcb *tcp;
1070
1071 tcp = pid2tcb(pid);
1072 if (tcp)
1073 droptcb(tcp);
1074#endif
1075 }
1076}
1077
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001078#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001079
1080static void
1081cleanup()
1082{
1083 int i;
1084 struct tcb *tcp;
1085
1086 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
1087 if (!(tcp->flags & TCB_INUSE))
1088 continue;
1089 if (debug)
1090 fprintf(stderr,
1091 "cleanup: looking at pid %u\n", tcp->pid);
1092 if (tcp_last &&
1093 (!outfname || followfork < 2 || tcp_last == tcp)) {
1094 tprintf(" <unfinished ...>\n");
1095 tcp_last = NULL;
1096 }
1097 if (tcp->flags & TCB_ATTACHED)
1098 detach(tcp, 0);
1099 else {
1100 kill(tcp->pid, SIGCONT);
1101 kill(tcp->pid, SIGTERM);
1102 }
1103 }
1104 if (cflag)
1105 call_summary(outf);
1106}
1107
1108static void
1109interrupt(sig)
1110int sig;
1111{
1112 interrupted = 1;
1113}
1114
1115#ifndef HAVE_STRERROR
1116
1117#ifndef SYS_ERRLIST_DECLARED
1118extern int sys_nerr;
1119extern char *sys_errlist[];
1120#endif /* SYS_ERRLIST_DECLARED */
1121
1122const char *
1123strerror(errno)
1124int errno;
1125{
1126 static char buf[64];
1127
1128 if (errno < 1 || errno >= sys_nerr) {
1129 sprintf(buf, "Unknown error %d", errno);
1130 return buf;
1131 }
1132 return sys_errlist[errno];
1133}
1134
1135#endif /* HAVE_STERRROR */
1136
1137#ifndef HAVE_STRSIGNAL
1138
1139#ifndef SYS_SIGLIST_DECLARED
1140#ifdef HAVE__SYS_SIGLIST
1141 extern char *_sys_siglist[];
1142#else
1143 extern char *sys_siglist[];
1144#endif
1145#endif /* SYS_SIGLIST_DECLARED */
1146
1147const char *
1148strsignal(sig)
1149int sig;
1150{
1151 static char buf[64];
1152
1153 if (sig < 1 || sig >= NSIG) {
1154 sprintf(buf, "Unknown signal %d", sig);
1155 return buf;
1156 }
1157#ifdef HAVE__SYS_SIGLIST
1158 return _sys_siglist[sig];
1159#else
1160 return sys_siglist[sig];
1161#endif
1162}
1163
1164#endif /* HAVE_STRSIGNAL */
1165
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001166#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001167
1168static void
1169rebuild_pollv()
1170{
1171 int i, j;
1172 struct tcb *tcp;
1173
1174 for (i = j = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
1175 if (!(tcp->flags & TCB_INUSE))
1176 continue;
1177 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001178 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 j++;
1180 }
1181 if (j != nprocs) {
1182 fprintf(stderr, "strace: proc miscount\n");
1183 exit(1);
1184 }
1185}
1186
1187#ifndef HAVE_POLLABLE_PROCFS
1188
1189static void
1190proc_poll_open()
1191{
1192 int arg;
1193 int i;
1194
1195 if (pipe(proc_poll_pipe) < 0) {
1196 perror("pipe");
1197 exit(1);
1198 }
1199 for (i = 0; i < 2; i++) {
1200 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1201 perror("F_GETFD");
1202 exit(1);
1203 }
1204 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1205 perror("F_SETFD");
1206 exit(1);
1207 }
1208 }
1209}
1210
1211static int
1212proc_poll(pollv, nfds, timeout)
1213struct pollfd *pollv;
1214int nfds;
1215int timeout;
1216{
1217 int i;
1218 int n;
1219 struct proc_pollfd pollinfo;
1220
1221 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1222 return n;
1223 if (n != sizeof(struct proc_pollfd)) {
1224 fprintf(stderr, "panic: short read: %d\n", n);
1225 exit(1);
1226 }
1227 for (i = 0; i < nprocs; i++) {
1228 if (pollv[i].fd == pollinfo.fd)
1229 pollv[i].revents = pollinfo.revents;
1230 else
1231 pollv[i].revents = 0;
1232 }
1233 poller_pid = pollinfo.pid;
1234 return 1;
1235}
1236
1237static void
1238wakeup_handler(sig)
1239int sig;
1240{
1241}
1242
1243static void
1244proc_poller(pfd)
1245int pfd;
1246{
1247 struct proc_pollfd pollinfo;
1248 struct sigaction sa;
1249 sigset_t blocked_set, empty_set;
1250 int i;
1251 int n;
1252 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001253#ifdef FREEBSD
1254 struct procfs_status pfs;
1255#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001256
1257 switch (fork()) {
1258 case -1:
1259 perror("fork");
1260 _exit(0);
1261 case 0:
1262 break;
1263 default:
1264 return;
1265 }
1266
1267 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1268 sa.sa_flags = 0;
1269 sigemptyset(&sa.sa_mask);
1270 sigaction(SIGHUP, &sa, NULL);
1271 sigaction(SIGINT, &sa, NULL);
1272 sigaction(SIGQUIT, &sa, NULL);
1273 sigaction(SIGPIPE, &sa, NULL);
1274 sigaction(SIGTERM, &sa, NULL);
1275 sa.sa_handler = wakeup_handler;
1276 sigaction(SIGUSR1, &sa, NULL);
1277 sigemptyset(&blocked_set);
1278 sigaddset(&blocked_set, SIGUSR1);
1279 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1280 sigemptyset(&empty_set);
1281
1282 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1283 perror("getrlimit(RLIMIT_NOFILE, ...)");
1284 _exit(0);
1285 }
1286 n = rl.rlim_cur;
1287 for (i = 0; i < n; i++) {
1288 if (i != pfd && i != proc_poll_pipe[1])
1289 close(i);
1290 }
1291
1292 pollinfo.fd = pfd;
1293 pollinfo.pid = getpid();
1294 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001295#ifndef FREEBSD
1296 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1297#else /* FREEBSD */
1298 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1299#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001300 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001301 switch (errno) {
1302 case EINTR:
1303 continue;
1304 case EBADF:
1305 pollinfo.revents = POLLERR;
1306 break;
1307 case ENOENT:
1308 pollinfo.revents = POLLHUP;
1309 break;
1310 default:
1311 perror("proc_poller: PIOCWSTOP");
1312 }
1313 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1314 _exit(0);
1315 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001316 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001317 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1318 sigsuspend(&empty_set);
1319 }
1320}
1321
1322#endif /* !HAVE_POLLABLE_PROCFS */
1323
1324static int
1325choose_pfd()
1326{
1327 int i, j;
1328 struct tcb *tcp;
1329
1330 static int last;
1331
1332 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001333 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001334 /*
1335 * The previous process is ready to run again. We'll
1336 * let it do so if it is currently in a syscall. This
1337 * heuristic improves the readability of the trace.
1338 */
1339 tcp = pfd2tcb(pollv[last].fd);
1340 if (tcp && (tcp->flags & TCB_INSYSCALL))
1341 return pollv[last].fd;
1342 }
1343
1344 for (i = 0; i < nprocs; i++) {
1345 /* Let competing children run round robin. */
1346 j = (i + last + 1) % nprocs;
1347 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1348 tcp = pfd2tcb(pollv[j].fd);
1349 if (!tcp) {
1350 fprintf(stderr, "strace: lost proc\n");
1351 exit(1);
1352 }
1353 droptcb(tcp);
1354 return -1;
1355 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001356 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001357 last = j;
1358 return pollv[j].fd;
1359 }
1360 }
1361 fprintf(stderr, "strace: nothing ready\n");
1362 exit(1);
1363}
1364
1365static int
1366trace()
1367{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001368#ifdef POLL_HACK
1369 struct tcb *in_syscall;
1370#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371 struct tcb *tcp;
1372 int pfd;
1373 int what;
1374 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001375 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376
1377 for (;;) {
1378 if (interactive)
1379 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1380
1381 if (nprocs == 0)
1382 break;
1383
1384 switch (nprocs) {
1385 case 1:
1386#ifndef HAVE_POLLABLE_PROCFS
1387 if (proc_poll_pipe[0] == -1) {
1388#endif
1389 tcp = pid2tcb(0);
1390 if (!tcp)
1391 continue;
1392 pfd = tcp->pfd;
1393 if (pfd == -1)
1394 continue;
1395 break;
1396#ifndef HAVE_POLLABLE_PROCFS
1397 }
1398 /* fall through ... */
1399#endif /* !HAVE_POLLABLE_PROCFS */
1400 default:
1401#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001402#ifdef POLL_HACK
1403 /* On some systems (e.g. UnixWare) we get too much ugly
1404 "unfinished..." stuff when multiple proceses are in
1405 syscalls. Here's a nasty hack */
1406
1407 if (in_syscall) {
1408 struct pollfd pv;
1409 tcp = in_syscall;
1410 in_syscall = NULL;
1411 pv.fd = tcp->pfd;
1412 pv.events = POLLWANT;
1413 if ((what = poll (&pv, 1, 1)) < 0) {
1414 if (interrupted)
1415 return 0;
1416 continue;
1417 }
1418 else if (what == 1 && pv.revents & POLLWANT) {
1419 goto FOUND;
1420 }
1421 }
1422#endif
1423
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001424 if (poll(pollv, nprocs, INFTIM) < 0) {
1425 if (interrupted)
1426 return 0;
1427 continue;
1428 }
1429#else /* !HAVE_POLLABLE_PROCFS */
1430 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1431 if (interrupted)
1432 return 0;
1433 continue;
1434 }
1435#endif /* !HAVE_POLLABLE_PROCFS */
1436 pfd = choose_pfd();
1437 if (pfd == -1)
1438 continue;
1439 break;
1440 }
1441
1442 /* Look up `pfd' in our table. */
1443 if ((tcp = pfd2tcb(pfd)) == NULL) {
1444 fprintf(stderr, "unknown pfd: %u\n", pfd);
1445 exit(1);
1446 }
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001447 FOUND:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001448 /* Get the status of the process. */
1449 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001450#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001451 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001452#else /* FREEBSD */
1453 /* Thanks to some scheduling mystery, the first poller
1454 sometimes waits for the already processed end of fork
1455 event. Doing a non blocking poll here solves the problem. */
1456 if (proc_poll_pipe[0] != -1)
1457 ioctl_result = IOCTL_STATUS (tcp);
1458 else
1459 ioctl_result = IOCTL_WSTOP (tcp);
1460#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001461 ioctl_errno = errno;
1462#ifndef HAVE_POLLABLE_PROCFS
1463 if (proc_poll_pipe[0] != -1) {
1464 if (ioctl_result < 0)
1465 kill(poller_pid, SIGKILL);
1466 else
1467 kill(poller_pid, SIGUSR1);
1468 }
1469#endif /* !HAVE_POLLABLE_PROCFS */
1470 }
1471 if (interrupted)
1472 return 0;
1473
1474 if (interactive)
1475 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1476
1477 if (ioctl_result < 0) {
1478 /* Find out what happened if it failed. */
1479 switch (ioctl_errno) {
1480 case EINTR:
1481 case EBADF:
1482 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001483#ifdef FREEBSD
1484 case ENOTTY:
1485#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001486 case ENOENT:
1487 droptcb(tcp);
1488 continue;
1489 default:
1490 perror("PIOCWSTOP");
1491 exit(1);
1492 }
1493 }
1494
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001495#ifdef FREEBSD
1496 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1497 /* discard first event for a syscall we never entered */
1498 IOCTL (tcp->pfd, PIOCRUN, 0);
1499 continue;
1500 }
1501#endif
1502
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001503 /* clear the just started flag */
1504 tcp->flags &= ~TCB_STARTUP;
1505
1506 /* set current output file */
1507 outf = tcp->outf;
1508
1509 if (cflag) {
1510 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001511#ifdef FREEBSD
1512 char buf[1024];
1513 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001514
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001515 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1516 buf[len] = '\0';
1517 sscanf(buf,
1518 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1519 &stime.tv_sec, &stime.tv_usec);
1520 } else
1521 stime.tv_sec = stime.tv_usec = 0;
1522#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001523 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1524 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001525#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001526 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1527 tcp->stime = stime;
1528 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001529 what = tcp->status.PR_WHAT;
1530 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001531#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001532 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001533 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1534 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001535 if (trace_syscall(tcp) < 0) {
1536 fprintf(stderr, "syscall trouble\n");
1537 exit(1);
1538 }
1539 }
1540 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001541#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001542 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001543#ifdef POLL_HACK
1544 in_syscall = tcp;
1545#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001546 case PR_SYSEXIT:
1547 if (trace_syscall(tcp) < 0) {
1548 fprintf(stderr, "syscall trouble\n");
1549 exit(1);
1550 }
1551 break;
1552 case PR_SIGNALLED:
1553 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1554 printleader(tcp);
1555 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001556 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001557 printtrailer(tcp);
1558 }
1559 break;
1560 case PR_FAULTED:
1561 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1562 printleader(tcp);
1563 tprintf("=== FAULT %d ===", what);
1564 printtrailer(tcp);
1565 }
1566 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001567#ifdef FREEBSD
1568 case 0: /* handle case we polled for nothing */
1569 continue;
1570#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001571 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001572 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001573 exit(1);
1574 break;
1575 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001576 arg = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001577#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001578 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001579#else
1580 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
1581#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001582 perror("PIOCRUN");
1583 exit(1);
1584 }
1585 }
1586 return 0;
1587}
1588
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001589#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001590
1591static int
1592trace()
1593{
1594 int pid;
1595 int wait_errno;
1596 int status;
1597 struct tcb *tcp;
1598#ifdef LINUX
1599 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001600#ifdef __WALL
1601 static int wait4_options = __WALL;
1602#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001603#endif /* LINUX */
1604
1605 while (nprocs != 0) {
1606 if (interactive)
1607 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1608#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001609#ifdef __WALL
1610 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
1611 if ((wait4_options & __WALL) && errno == EINVAL) {
1612 /* this kernel does not support __WALL */
1613 wait4_options &= ~__WALL;
1614 errno = 0;
1615 pid = wait4(-1, &status, wait4_options,
1616 cflag ? &ru : NULL);
1617 }
1618 if (!(wait4_options & __WALL) && errno == ECHILD) {
1619 /* most likely a "cloned" process */
1620 pid = wait4(-1, &status, __WCLONE,
1621 cflag ? &ru : NULL);
1622 if (pid == -1) {
1623 fprintf(stderr, "strace: clone wait4 "
1624 "failed: %s\n", strerror(errno));
1625 }
1626 }
1627#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001629#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001630#endif /* LINUX */
1631#ifdef SUNOS4
1632 pid = wait(&status);
1633#endif /* SUNOS4 */
1634 wait_errno = errno;
1635 if (interactive)
1636 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1637
1638 if (interrupted)
1639 return 0;
1640
1641 if (pid == -1) {
1642 switch (wait_errno) {
1643 case EINTR:
1644 continue;
1645 case ECHILD:
1646 /*
1647 * We would like to verify this case
1648 * but sometimes a race in Solbourne's
1649 * version of SunOS sometimes reports
1650 * ECHILD before sending us SIGCHILD.
1651 */
1652#if 0
1653 if (nprocs == 0)
1654 return 0;
1655 fprintf(stderr, "strace: proc miscount\n");
1656 exit(1);
1657#endif
1658 return 0;
1659 default:
1660 errno = wait_errno;
1661 perror("strace: wait");
1662 return -1;
1663 }
1664 }
1665 if (debug)
1666 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1667
1668 /* Look up `pid' in our table. */
1669 if ((tcp = pid2tcb(pid)) == NULL) {
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001670#if 0 /* XXX davidm */ /* WTA: disabled again */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001671 struct tcb *tcpchild;
1672
1673 if ((tcpchild = alloctcb(pid)) == NULL) {
1674 fprintf(stderr, " [tcb table full]\n");
1675 kill(pid, SIGKILL); /* XXX */
1676 return 0;
1677 }
1678 tcpchild->flags |= TCB_ATTACHED;
1679 newoutf(tcpchild);
1680 tcp->nchildren++;
1681 if (!qflag)
1682 fprintf(stderr, "Process %d attached\n", pid);
1683#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684 fprintf(stderr, "unknown pid: %u\n", pid);
1685 if (WIFSTOPPED(status))
1686 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1687 exit(1);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001688#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001689 }
1690 /* set current output file */
1691 outf = tcp->outf;
1692 if (cflag) {
1693#ifdef LINUX
1694 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
1695 tcp->stime = ru.ru_stime;
1696#endif /* !LINUX */
1697 }
1698
1699 if (tcp->flags & TCB_SUSPENDED) {
1700 /*
1701 * Apparently, doing any ptrace() call on a stopped
1702 * process, provokes the kernel to report the process
1703 * status again on a subsequent wait(), even if the
1704 * process has not been actually restarted.
1705 * Since we have inspected the arguments of suspended
1706 * processes we end up here testing for this case.
1707 */
1708 continue;
1709 }
1710 if (WIFSIGNALED(status)) {
1711 if (!cflag
1712 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
1713 printleader(tcp);
1714 tprintf("+++ killed by %s +++",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001715 signame(WTERMSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716 printtrailer(tcp);
1717 }
1718 droptcb(tcp);
1719 continue;
1720 }
1721 if (WIFEXITED(status)) {
1722 if (debug)
1723 fprintf(stderr, "pid %u exited\n", pid);
1724 if (tcp->flags & TCB_ATTACHED)
1725 fprintf(stderr,
1726 "PANIC: attached pid %u exited\n",
1727 pid);
1728 droptcb(tcp);
1729 continue;
1730 }
1731 if (!WIFSTOPPED(status)) {
1732 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
1733 droptcb(tcp);
1734 continue;
1735 }
1736 if (debug)
1737 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001738 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001739
1740 if (tcp->flags & TCB_STARTUP) {
1741 /*
1742 * This flag is there to keep us in sync.
1743 * Next time this process stops it should
1744 * really be entering a system call.
1745 */
1746 tcp->flags &= ~TCB_STARTUP;
1747 if (tcp->flags & TCB_ATTACHED) {
1748 /*
1749 * Interestingly, the process may stop
1750 * with STOPSIG equal to some other signal
1751 * than SIGSTOP if we happend to attach
1752 * just before the process takes a signal.
1753 */
1754 if (!WIFSTOPPED(status)) {
1755 fprintf(stderr,
1756 "pid %u not stopped\n", pid);
1757 detach(tcp, WSTOPSIG(status));
1758 continue;
1759 }
1760 }
1761 else {
1762#ifdef SUNOS4
1763 /* A child of us stopped at exec */
1764 if (WSTOPSIG(status) == SIGTRAP && followvfork)
1765 fixvfork(tcp);
1766#endif /* SUNOS4 */
1767 }
1768 if (tcp->flags & TCB_BPTSET) {
1769 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
1770 droptcb(tcp);
1771 cleanup();
1772 return -1;
1773 }
1774 }
1775 goto tracing;
1776 }
1777
1778 if (WSTOPSIG(status) != SIGTRAP) {
1779 if (WSTOPSIG(status) == SIGSTOP &&
1780 (tcp->flags & TCB_SIGTRAPPED)) {
1781 /*
1782 * Trapped attempt to block SIGTRAP
1783 * Hope we are back in control now.
1784 */
1785 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
1786 if (ptrace(PTRACE_SYSCALL,
1787 pid, (char *) 1, 0) < 0) {
1788 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
1789 cleanup();
1790 return -1;
1791 }
1792 continue;
1793 }
1794 if (!cflag
1795 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
1796 printleader(tcp);
1797 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001798 signame(WSTOPSIG(status)),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001799 strsignal(WSTOPSIG(status)));
1800 printtrailer(tcp);
1801 }
1802 if ((tcp->flags & TCB_ATTACHED) &&
1803 !sigishandled(tcp, WSTOPSIG(status))) {
1804 detach(tcp, WSTOPSIG(status));
1805 continue;
1806 }
1807 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
1808 WSTOPSIG(status)) < 0) {
1809 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
1810 cleanup();
1811 return -1;
1812 }
1813 tcp->flags &= ~TCB_SUSPENDED;
1814 continue;
1815 }
1816 if (trace_syscall(tcp) < 0) {
1817 if (tcp->flags & TCB_ATTACHED)
1818 detach(tcp, 0);
1819 else {
1820 ptrace(PTRACE_KILL,
1821 tcp->pid, (char *) 1, SIGTERM);
1822 droptcb(tcp);
1823 }
1824 continue;
1825 }
1826 if (tcp->flags & TCB_EXITING) {
1827 if (tcp->flags & TCB_ATTACHED)
1828 detach(tcp, 0);
1829 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
1830 perror("strace: ptrace(PTRACE_CONT, ...)");
1831 cleanup();
1832 return -1;
1833 }
1834 continue;
1835 }
1836 if (tcp->flags & TCB_SUSPENDED) {
1837 if (!qflag)
1838 fprintf(stderr, "Process %u suspended\n", pid);
1839 continue;
1840 }
1841 tracing:
1842 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
1843 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
1844 cleanup();
1845 return -1;
1846 }
1847 }
1848 return 0;
1849}
1850
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001851#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001852
1853static int curcol;
1854
1855#ifdef __STDC__
1856#include <stdarg.h>
1857#define VA_START(a, b) va_start(a, b)
1858#else
1859#include <varargs.h>
1860#define VA_START(a, b) va_start(a)
1861#endif
1862
1863void
1864#ifdef __STDC__
1865tprintf(const char *fmt, ...)
1866#else
1867tprintf(fmt, va_alist)
1868char *fmt;
1869va_dcl
1870#endif
1871{
1872 va_list args;
1873
1874 VA_START(args, fmt);
1875 if (outf)
1876 curcol += vfprintf(outf, fmt, args);
1877 va_end(args);
1878 return;
1879}
1880
1881void
1882printleader(tcp)
1883struct tcb *tcp;
1884{
1885 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
1886 tcp_last->flags |= TCB_REPRINT;
1887 tprintf(" <unfinished ...>\n");
1888 }
1889 curcol = 0;
1890 if ((followfork == 1 || pflag_seen > 1) && outfname)
1891 tprintf("%-5d ", tcp->pid);
1892 else if (nprocs > 1 && !outfname)
1893 tprintf("[pid %5u] ", tcp->pid);
1894 if (tflag) {
1895 char str[sizeof("HH:MM:SS")];
1896 struct timeval tv, dtv;
1897 static struct timeval otv;
1898
1899 gettimeofday(&tv, NULL);
1900 if (rflag) {
1901 if (otv.tv_sec == 0)
1902 otv = tv;
1903 tv_sub(&dtv, &tv, &otv);
1904 tprintf("%6ld.%06ld ",
1905 (long) dtv.tv_sec, (long) dtv.tv_usec);
1906 otv = tv;
1907 }
1908 else if (tflag > 2) {
1909 tprintf("%ld.%06ld ",
1910 (long) tv.tv_sec, (long) tv.tv_usec);
1911 }
1912 else {
1913 time_t local = tv.tv_sec;
1914 strftime(str, sizeof(str), "%T", localtime(&local));
1915 if (tflag > 1)
1916 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
1917 else
1918 tprintf("%s ", str);
1919 }
1920 }
1921 if (iflag)
1922 printcall(tcp);
1923}
1924
1925void
1926tabto(col)
1927int col;
1928{
1929 if (curcol < col)
1930 tprintf("%*s", col - curcol, "");
1931}
1932
1933void
1934printtrailer(tcp)
1935struct tcb *tcp;
1936{
1937 tprintf("\n");
1938 tcp_last = NULL;
1939}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001940
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001941#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001942
1943int mp_ioctl (int fd, int cmd, void *arg, int size) {
1944
1945 struct iovec iov[2];
1946 int n = 1;
1947
1948 iov[0].iov_base = &cmd;
1949 iov[0].iov_len = sizeof cmd;
1950 if (arg) {
1951 ++n;
1952 iov[1].iov_base = arg;
1953 iov[1].iov_len = size;
1954 }
1955
1956 return writev (fd, iov, n);
1957}
1958
1959#endif