blob: dd3e935651cc9759c6ccedf228e187cfbe69e802 [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) {
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000317 long f;
318
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000319 if ((outf = fopen(outfname, "w")) == NULL) {
320 fprintf(stderr, "%s: can't fopen '%s': %s\n",
321 progname, outfname, strerror(errno));
322 exit(1);
323 }
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000324
325 if ((f=fcntl(fileno(outf), F_GETFD)) < 0 ) {
326 perror("failed to get flags for outputfile");
327 exit(1);
328 }
329
330 if (fcntl(fileno(outf), F_SETFD, f|FD_CLOEXEC) < 0 ) {
331 perror("failed to set flags for outputfile");
332 exit(1);
333 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000334 }
335
336#ifndef SVR4
337 setreuid(geteuid(), getuid());
338#endif
339
340 if (!outfname) {
341 qflag = 1;
342 setvbuf(outf, buf, _IOLBF, BUFSIZ);
343 }
344 else if (optind < argc)
345 interactive = 0;
346 else
347 qflag = 1;
348
349 for (c = 0, tcp = tcbtab; c < MAX_PROCS; c++, tcp++) {
350 /* Reinitialize the output since it may have changed. */
351 tcp->outf = outf;
352 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
353 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000354#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000355 if (proc_open(tcp, 1) < 0) {
356 fprintf(stderr, "trouble opening proc file\n");
357 droptcb(tcp);
358 continue;
359 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000360#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000361 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
362 perror("attach: ptrace(PTRACE_ATTACH, ...)");
363 droptcb(tcp);
364 continue;
365 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000366#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000367 if (!qflag)
368 fprintf(stderr,
369 "Process %u attached - interrupt to quit\n",
370 pid);
371 }
372
373 if (optind < argc) {
374 struct stat statbuf;
375 char *filename;
376 char pathname[MAXPATHLEN];
377
378 filename = argv[optind];
379 if (strchr(filename, '/'))
380 strcpy(pathname, filename);
381#ifdef USE_DEBUGGING_EXEC
382 /*
383 * Debuggers customarily check the current directory
384 * first regardless of the path but doing that gives
385 * security geeks a panic attack.
386 */
387 else if (stat(filename, &statbuf) == 0)
388 strcpy(pathname, filename);
389#endif /* USE_DEBUGGING_EXEC */
390 else {
391 char *path;
392 int m, n, len;
393
394 for (path = getenv("PATH"); path && *path; path += m) {
395 if (strchr(path, ':')) {
396 n = strchr(path, ':') - path;
397 m = n + 1;
398 }
399 else
400 m = n = strlen(path);
401 if (n == 0) {
402 getcwd(pathname, MAXPATHLEN);
403 len = strlen(pathname);
404 }
405 else {
406 strncpy(pathname, path, n);
407 len = n;
408 }
409 if (len && pathname[len - 1] != '/')
410 pathname[len++] = '/';
411 strcpy(pathname + len, filename);
412 if (stat(pathname, &statbuf) == 0)
413 break;
414 }
415 }
416 if (stat(pathname, &statbuf) < 0) {
417 fprintf(stderr, "%s: %s: command not found\n",
418 progname, filename);
419 exit(1);
420 }
421 switch (pid = fork()) {
422 case -1:
423 perror("strace: fork");
424 cleanup();
425 exit(1);
426 break;
427 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000428#ifdef USE_PROCFS
429 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000430#ifdef MIPS
431 /* Kludge for SGI, see proc_open for details. */
432 sa.sa_handler = foobar;
433 sa.sa_flags = 0;
434 sigemptyset(&sa.sa_mask);
435 sigaction(SIGINT, &sa, NULL);
436#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000437#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000439#else /* FREEBSD */
440 kill(getpid(), SIGSTOP); /* stop HERE */
441#endif /* FREEBSD */
442#else /* !USE_PROCFS */
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000443 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000444 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000445
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000446 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
447 perror("strace: ptrace(PTRACE_TRACEME, ...)");
448 return -1;
449 }
450 if (debug)
451 kill(getpid(), SIGSTOP);
452
453 if (username != NULL || geteuid() == 0) {
454 uid_t run_euid = run_uid;
455 gid_t run_egid = run_gid;
456
457 if (statbuf.st_mode & S_ISUID)
458 run_euid = statbuf.st_uid;
459 if (statbuf.st_mode & S_ISGID)
460 run_egid = statbuf.st_gid;
461
462 /*
463 * It is important to set groups before we
464 * lose privileges on setuid.
465 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000466 if (username != NULL) {
467 if (initgroups(username, run_gid) < 0) {
468 perror("initgroups");
469 exit(1);
470 }
471 if (setregid(run_gid, run_egid) < 0) {
472 perror("setregid");
473 exit(1);
474 }
475 if (setreuid(run_uid, run_euid) < 0) {
476 perror("setreuid");
477 exit(1);
478 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000479 }
480 }
481 else
482 setreuid(run_uid, run_uid);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000483#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000484
485 execv(pathname, &argv[optind]);
486 perror("strace: exec");
487 _exit(1);
488 break;
489 }
490 default:
491 if ((tcp = alloctcb(pid)) == NULL) {
492 fprintf(stderr, "tcb table full\n");
493 cleanup();
494 exit(1);
495 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000496#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000497 if (proc_open(tcp, 0) < 0) {
498 fprintf(stderr, "trouble opening proc file\n");
499 cleanup();
500 exit(1);
501 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000502#endif /* USE_PROCFS */
503#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000504 fake_execve(tcp, pathname, &argv[optind], environ);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000505#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000506 break;
507 }
508 }
509 else if (pflag_seen == 0)
510 usage(stderr, 1);
511
512 sigemptyset(&empty_set);
513 sigemptyset(&blocked_set);
514 sa.sa_handler = SIG_IGN;
515 sigemptyset(&sa.sa_mask);
516 sa.sa_flags = 0;
517 sigaction(SIGTTOU, &sa, NULL);
518 sigaction(SIGTTIN, &sa, NULL);
519 if (interactive) {
520 sigaddset(&blocked_set, SIGHUP);
521 sigaddset(&blocked_set, SIGINT);
522 sigaddset(&blocked_set, SIGQUIT);
523 sigaddset(&blocked_set, SIGPIPE);
524 sigaddset(&blocked_set, SIGTERM);
525 sa.sa_handler = interrupt;
526#ifdef SUNOS4
527 /* POSIX signals on sunos4.1 are a little broken. */
528 sa.sa_flags = SA_INTERRUPT;
529#endif /* SUNOS4 */
530 }
531 sigaction(SIGHUP, &sa, NULL);
532 sigaction(SIGINT, &sa, NULL);
533 sigaction(SIGQUIT, &sa, NULL);
534 sigaction(SIGPIPE, &sa, NULL);
535 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000536#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000537 sa.sa_handler = reaper;
538 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000539#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000540
541 if (trace() < 0)
542 exit(1);
543 cleanup();
544 exit(0);
545}
546
547void
548newoutf(tcp)
549struct tcb *tcp;
550{
551 char name[MAXPATHLEN];
552 FILE *fp;
553
554 if (outfname && followfork > 1) {
555 sprintf(name, "%s.%u", outfname, tcp->pid);
556#ifndef SVR4
557 setreuid(geteuid(), getuid());
558#endif
559 fp = fopen(name, "w");
560#ifndef SVR4
561 setreuid(geteuid(), getuid());
562#endif
563 if (fp == NULL) {
564 perror("fopen");
565 return;
566 }
567 tcp->outf = fp;
568 }
569 return;
570}
571
572struct tcb *
573alloctcb(pid)
574int pid;
575{
576 int i;
577 struct tcb *tcp;
578
579 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
580 if ((tcp->flags & TCB_INUSE) == 0) {
581 tcp->pid = pid;
582 tcp->parent = NULL;
583 tcp->nchildren = 0;
584 tcp->flags = TCB_INUSE | TCB_STARTUP;
585 tcp->outf = outf; /* Initialise to current out file */
586 tcp->stime.tv_sec = 0;
587 tcp->stime.tv_usec = 0;
588 tcp->pfd = -1;
589 nprocs++;
590 return tcp;
591 }
592 }
593 return NULL;
594}
595
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000596#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597int
598proc_open(tcp, attaching)
599struct tcb *tcp;
600int attaching;
601{
602 char proc[32];
603 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000604#ifdef SVR4
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000605 sysset_t sc_enter, sc_exit;
606 sigset_t signals;
607 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000608#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000609#ifndef HAVE_POLLABLE_PROCFS
610 static int last_pfd;
611#endif
612
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000613#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000614 /* Open the process pseudo-files in /proc. */
615 sprintf(proc, "/proc/%d/ctl", tcp->pid);
616 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000617 perror("strace: open(\"/proc/...\", ...)");
618 return -1;
619 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000620 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
621 perror("F_GETFD");
622 return -1;
623 }
624 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
625 perror("F_SETFD");
626 return -1;
627 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000628 sprintf(proc, "/proc/%d/status", tcp->pid);
629 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
630 perror("strace: open(\"/proc/...\", ...)");
631 return -1;
632 }
633 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
634 perror("F_GETFD");
635 return -1;
636 }
637 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
638 perror("F_SETFD");
639 return -1;
640 }
641 sprintf(proc, "/proc/%d/as", tcp->pid);
642 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
643 perror("strace: open(\"/proc/...\", ...)");
644 return -1;
645 }
646 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
647 perror("F_GETFD");
648 return -1;
649 }
650 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
651 perror("F_SETFD");
652 return -1;
653 }
654#else
655 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000656#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000657 sprintf(proc, "/proc/%d", tcp->pid);
658 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000659#else /* FREEBSD */
660 sprintf(proc, "/proc/%d/mem", tcp->pid);
661 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
662#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000663 perror("strace: open(\"/proc/...\", ...)");
664 return -1;
665 }
666 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
667 perror("F_GETFD");
668 return -1;
669 }
670 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
671 perror("F_SETFD");
672 return -1;
673 }
674#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000675#ifdef FREEBSD
676 sprintf(proc, "/proc/%d/regs", tcp->pid);
677 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
678 perror("strace: open(\"/proc/.../regs\", ...)");
679 return -1;
680 }
681 if (cflag) {
682 sprintf(proc, "/proc/%d/status", tcp->pid);
683 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
684 perror("strace: open(\"/proc/.../status\", ...)");
685 return -1;
686 }
687 } else
688 tcp->pfd_status = -1;
689#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000690 rebuild_pollv();
691 if (!attaching) {
692 /*
693 * Wait for the child to pause. Because of a race
694 * condition we have to poll for the event.
695 */
696 for (;;) {
697 if (IOCTL_STATUS (tcp) < 0) {
698 perror("strace: PIOCSTATUS");
699 return -1;
700 }
701 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000702 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000703 }
704 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000705#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000706 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000707 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000708 perror("strace: PIOCSTOP");
709 return -1;
710 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000711#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712#ifdef PIOCSET
713 /* Set Run-on-Last-Close. */
714 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000715 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000716 perror("PIOCSET PR_RLC");
717 return -1;
718 }
719 /* Set or Reset Inherit-on-Fork. */
720 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000721 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000722 perror("PIOC{SET,RESET} PR_FORK");
723 return -1;
724 }
725#else /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000726#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000727 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
728 perror("PIOCSRLC");
729 return -1;
730 }
731 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
732 perror("PIOC{S,R}FORK");
733 return -1;
734 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000735#else /* FREEBSD */
736 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
737 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
738 perror("PIOCGFL");
739 return -1;
740 }
741 arg &= ~PF_LINGER;
742 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
743 perror("PIOCSFL");
744 return -1;
745 }
746#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000747#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000748#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000749 /* Enable all syscall entries. */
750 prfillset(&sc_enter);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000751 if (IOCTL(tcp->pfd, PIOCSENTRY, &sc_enter) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000752 perror("PIOCSENTRY");
753 return -1;
754 }
755 /* Enable all syscall exits. */
756 prfillset(&sc_exit);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000757 if (IOCTL(tcp->pfd, PIOCSEXIT, &sc_exit) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000758 perror("PIOSEXIT");
759 return -1;
760 }
761 /* Enable all signals. */
762 prfillset(&signals);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000763 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000764 perror("PIOCSTRACE");
765 return -1;
766 }
767 /* Enable all faults. */
768 prfillset(&faults);
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000769 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000770 perror("PIOCSFAULT");
771 return -1;
772 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000773#else /* FREEBSD */
774 /* set events flags. */
775 arg = S_SIG | S_SCE | S_SCX ;
776 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
777 perror("PIOCBIS");
778 return -1;
779 }
780#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000781 if (!attaching) {
782#ifdef MIPS
783 /*
784 * The SGI PRSABORT doesn't work for pause() so
785 * we send it a caught signal to wake it up.
786 */
787 kill(tcp->pid, SIGINT);
788#else /* !MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000789#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000791 arg = PRSABORT;
792 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000793 perror("PIOCRUN");
794 return -1;
795 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000796#endif
797#endif /* !MIPS*/
798#ifdef FREEBSD
799 /* wake up the child if it received the SIGSTOP */
800 kill(tcp->pid, SIGCONT);
801#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000802 for (;;) {
803 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000804 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000805 perror("PIOCWSTOP");
806 return -1;
807 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000808 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000809 tcp->flags &= ~TCB_INSYSCALL;
810 get_scno(tcp);
811 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000812 break;
813 }
814 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000815#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000816 arg = 0;
817 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000818#else /* FREEBSD */
819 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
820#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000821 perror("PIOCRUN");
822 return -1;
823 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000824#ifdef FREEBSD
825 /* handle the case where we "opened" the child before
826 it did the kill -STOP */
827 if (tcp->status.PR_WHY == PR_SIGNALLED &&
828 tcp->status.PR_WHAT == SIGSTOP)
829 kill(tcp->pid, SIGCONT);
830#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000831 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000832#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000833 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000834#else /* FREEBSD */
835 } else {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000836 if (attaching < 2) {
837 /* We are attaching to an already running process.
838 * Try to figure out the state of the process in syscalls,
839 * to handle the first event well.
840 * This is done by having a look at the "wchan" property of the
841 * process, which tells where it is stopped (if it is). */
842 FILE * status;
843 char wchan[20]; /* should be enough */
844
845 sprintf(proc, "/proc/%d/status", tcp->pid);
846 status = fopen(proc, "r");
847 if (status &&
848 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
849 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
850 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
851 strcmp(wchan, "stopevent")) {
852 /* The process is asleep in the middle of a syscall.
853 Fake the syscall entry event */
854 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
855 tcp->status.PR_WHY = PR_SYSENTRY;
856 trace_syscall(tcp);
857 }
858 if (status)
859 fclose(status);
860 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000861 }
862#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000863#ifndef HAVE_POLLABLE_PROCFS
864 if (proc_poll_pipe[0] != -1)
865 proc_poller(tcp->pfd);
866 else if (nprocs > 1) {
867 proc_poll_open();
868 proc_poller(last_pfd);
869 proc_poller(tcp->pfd);
870 }
871 last_pfd = tcp->pfd;
872#endif /* !HAVE_POLLABLE_PROCFS */
873 return 0;
874}
875
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000876#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000877
878static struct tcb *
879pid2tcb(pid)
880int pid;
881{
882 int i;
883 struct tcb *tcp;
884
885 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
886 if (pid && tcp->pid != pid)
887 continue;
888 if (tcp->flags & TCB_INUSE)
889 return tcp;
890 }
891 return NULL;
892}
893
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000894#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000895
896static struct tcb *
897pfd2tcb(pfd)
898int pfd;
899{
900 int i;
901 struct tcb *tcp;
902
903 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
904 if (tcp->pfd != pfd)
905 continue;
906 if (tcp->flags & TCB_INUSE)
907 return tcp;
908 }
909 return NULL;
910}
911
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000912#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000913
914void
915droptcb(tcp)
916struct tcb *tcp;
917{
918 if (tcp->pid == 0)
919 return;
920 nprocs--;
921 tcp->pid = 0;
922 tcp->flags = 0;
923 if (tcp->pfd != -1) {
924 close(tcp->pfd);
925 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000926#ifdef FREEBSD
927 if (tcp->pfd_reg != -1) {
928 close(tcp->pfd_reg);
929 tcp->pfd_reg = -1;
930 }
931 if (tcp->pfd_status != -1) {
932 close(tcp->pfd_status);
933 tcp->pfd_status = -1;
934 }
935#endif /* !FREEBSD */
936#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000937 rebuild_pollv();
938#endif
939 }
940 if (tcp->parent != NULL) {
941 tcp->parent->nchildren--;
942 tcp->parent = NULL;
943 }
944#if 0
945 if (tcp->outf != stderr)
946 fclose(tcp->outf);
947#endif
948 tcp->outf = 0;
949}
950
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000951#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000952
953static int
954resume(tcp)
955struct tcb *tcp;
956{
957 if (tcp == NULL)
958 return -1;
959
960 if (!(tcp->flags & TCB_SUSPENDED)) {
961 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
962 return -1;
963 }
964 tcp->flags &= ~TCB_SUSPENDED;
965
966 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
967 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
968 return -1;
969 }
970
971 if (!qflag)
972 fprintf(stderr, "Process %u resumed\n", tcp->pid);
973 return 0;
974}
975
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000976#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977
978/* detach traced process; continue with sig */
979
980static int
981detach(tcp, sig)
982struct tcb *tcp;
983int sig;
984{
985 int error = 0;
986#ifdef LINUX
987 int status;
988#endif
989
990 if (tcp->flags & TCB_BPTSET)
991 sig = SIGKILL;
992
993#ifdef LINUX
994 /*
995 * Linux wrongly insists the child be stopped
996 * before detaching. Arghh. We go through hoops
997 * to make a clean break of things.
998 */
Wichert Akkermandacfb6e1999-06-03 14:21:07 +0000999#if defined(SPARC)
1000#undef PTRACE_DETACH
1001#define PTRACE_DETACH PTRACE_SUNDETACH
1002#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001003 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1004 /* On a clear day, you can see forever. */
1005 }
1006 else if (errno != ESRCH) {
1007 /* Shouldn't happen. */
1008 perror("detach: ptrace(PTRACE_DETACH, ...)");
1009 }
1010 else if (kill(tcp->pid, 0) < 0) {
1011 if (errno != ESRCH)
1012 perror("detach: checking sanity");
1013 }
1014 else if (kill(tcp->pid, SIGSTOP) < 0) {
1015 if (errno != ESRCH)
1016 perror("detach: stopping child");
1017 }
1018 else {
1019 for (;;) {
1020 if (waitpid(tcp->pid, &status, 0) < 0) {
1021 if (errno != ECHILD)
1022 perror("detach: waiting");
1023 break;
1024 }
1025 if (!WIFSTOPPED(status)) {
1026 /* Au revoir, mon ami. */
1027 break;
1028 }
1029 if (WSTOPSIG(status) == SIGSTOP) {
1030 if ((error = ptrace(PTRACE_DETACH,
1031 tcp->pid, (char *) 1, sig)) < 0) {
1032 if (errno != ESRCH)
1033 perror("detach: ptrace(PTRACE_DETACH, ...)");
1034 /* I died trying. */
1035 }
1036 break;
1037 }
1038 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
1039 WSTOPSIG(status) == SIGTRAP ?
1040 0 : WSTOPSIG(status))) < 0) {
1041 if (errno != ESRCH)
1042 perror("detach: ptrace(PTRACE_CONT, ...)");
1043 break;
1044 }
1045 }
1046 }
1047#endif /* LINUX */
1048
1049#if defined(SUNOS4)
1050 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1051 if (sig && kill(tcp->pid, sig) < 0)
1052 perror("detach: kill");
1053 sig = 0;
1054 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1055 perror("detach: ptrace(PTRACE_DETACH, ...)");
1056#endif /* SUNOS4 */
1057
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001058#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059 if (waiting_parent(tcp))
1060 error = resume(tcp->parent);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001061#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001062
1063 if (!qflag)
1064 fprintf(stderr, "Process %u detached\n", tcp->pid);
1065
1066 droptcb(tcp);
1067 return error;
1068}
1069
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001070#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071
1072static void
1073reaper(sig)
1074int sig;
1075{
1076 int pid;
1077 int status;
1078
1079 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1080#if 0
1081 struct tcb *tcp;
1082
1083 tcp = pid2tcb(pid);
1084 if (tcp)
1085 droptcb(tcp);
1086#endif
1087 }
1088}
1089
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001090#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001091
1092static void
1093cleanup()
1094{
1095 int i;
1096 struct tcb *tcp;
1097
1098 for (i = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
1099 if (!(tcp->flags & TCB_INUSE))
1100 continue;
1101 if (debug)
1102 fprintf(stderr,
1103 "cleanup: looking at pid %u\n", tcp->pid);
1104 if (tcp_last &&
1105 (!outfname || followfork < 2 || tcp_last == tcp)) {
1106 tprintf(" <unfinished ...>\n");
1107 tcp_last = NULL;
1108 }
1109 if (tcp->flags & TCB_ATTACHED)
1110 detach(tcp, 0);
1111 else {
1112 kill(tcp->pid, SIGCONT);
1113 kill(tcp->pid, SIGTERM);
1114 }
1115 }
1116 if (cflag)
1117 call_summary(outf);
1118}
1119
1120static void
1121interrupt(sig)
1122int sig;
1123{
1124 interrupted = 1;
1125}
1126
1127#ifndef HAVE_STRERROR
1128
1129#ifndef SYS_ERRLIST_DECLARED
1130extern int sys_nerr;
1131extern char *sys_errlist[];
1132#endif /* SYS_ERRLIST_DECLARED */
1133
1134const char *
1135strerror(errno)
1136int errno;
1137{
1138 static char buf[64];
1139
1140 if (errno < 1 || errno >= sys_nerr) {
1141 sprintf(buf, "Unknown error %d", errno);
1142 return buf;
1143 }
1144 return sys_errlist[errno];
1145}
1146
1147#endif /* HAVE_STERRROR */
1148
1149#ifndef HAVE_STRSIGNAL
1150
1151#ifndef SYS_SIGLIST_DECLARED
1152#ifdef HAVE__SYS_SIGLIST
1153 extern char *_sys_siglist[];
1154#else
1155 extern char *sys_siglist[];
1156#endif
1157#endif /* SYS_SIGLIST_DECLARED */
1158
1159const char *
1160strsignal(sig)
1161int sig;
1162{
1163 static char buf[64];
1164
1165 if (sig < 1 || sig >= NSIG) {
1166 sprintf(buf, "Unknown signal %d", sig);
1167 return buf;
1168 }
1169#ifdef HAVE__SYS_SIGLIST
1170 return _sys_siglist[sig];
1171#else
1172 return sys_siglist[sig];
1173#endif
1174}
1175
1176#endif /* HAVE_STRSIGNAL */
1177
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001178#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179
1180static void
1181rebuild_pollv()
1182{
1183 int i, j;
1184 struct tcb *tcp;
1185
1186 for (i = j = 0, tcp = tcbtab; i < MAX_PROCS; i++, tcp++) {
1187 if (!(tcp->flags & TCB_INUSE))
1188 continue;
1189 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001190 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191 j++;
1192 }
1193 if (j != nprocs) {
1194 fprintf(stderr, "strace: proc miscount\n");
1195 exit(1);
1196 }
1197}
1198
1199#ifndef HAVE_POLLABLE_PROCFS
1200
1201static void
1202proc_poll_open()
1203{
1204 int arg;
1205 int i;
1206
1207 if (pipe(proc_poll_pipe) < 0) {
1208 perror("pipe");
1209 exit(1);
1210 }
1211 for (i = 0; i < 2; i++) {
1212 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1213 perror("F_GETFD");
1214 exit(1);
1215 }
1216 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1217 perror("F_SETFD");
1218 exit(1);
1219 }
1220 }
1221}
1222
1223static int
1224proc_poll(pollv, nfds, timeout)
1225struct pollfd *pollv;
1226int nfds;
1227int timeout;
1228{
1229 int i;
1230 int n;
1231 struct proc_pollfd pollinfo;
1232
1233 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1234 return n;
1235 if (n != sizeof(struct proc_pollfd)) {
1236 fprintf(stderr, "panic: short read: %d\n", n);
1237 exit(1);
1238 }
1239 for (i = 0; i < nprocs; i++) {
1240 if (pollv[i].fd == pollinfo.fd)
1241 pollv[i].revents = pollinfo.revents;
1242 else
1243 pollv[i].revents = 0;
1244 }
1245 poller_pid = pollinfo.pid;
1246 return 1;
1247}
1248
1249static void
1250wakeup_handler(sig)
1251int sig;
1252{
1253}
1254
1255static void
1256proc_poller(pfd)
1257int pfd;
1258{
1259 struct proc_pollfd pollinfo;
1260 struct sigaction sa;
1261 sigset_t blocked_set, empty_set;
1262 int i;
1263 int n;
1264 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001265#ifdef FREEBSD
1266 struct procfs_status pfs;
1267#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001268
1269 switch (fork()) {
1270 case -1:
1271 perror("fork");
1272 _exit(0);
1273 case 0:
1274 break;
1275 default:
1276 return;
1277 }
1278
1279 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1280 sa.sa_flags = 0;
1281 sigemptyset(&sa.sa_mask);
1282 sigaction(SIGHUP, &sa, NULL);
1283 sigaction(SIGINT, &sa, NULL);
1284 sigaction(SIGQUIT, &sa, NULL);
1285 sigaction(SIGPIPE, &sa, NULL);
1286 sigaction(SIGTERM, &sa, NULL);
1287 sa.sa_handler = wakeup_handler;
1288 sigaction(SIGUSR1, &sa, NULL);
1289 sigemptyset(&blocked_set);
1290 sigaddset(&blocked_set, SIGUSR1);
1291 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1292 sigemptyset(&empty_set);
1293
1294 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1295 perror("getrlimit(RLIMIT_NOFILE, ...)");
1296 _exit(0);
1297 }
1298 n = rl.rlim_cur;
1299 for (i = 0; i < n; i++) {
1300 if (i != pfd && i != proc_poll_pipe[1])
1301 close(i);
1302 }
1303
1304 pollinfo.fd = pfd;
1305 pollinfo.pid = getpid();
1306 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001307#ifndef FREEBSD
1308 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1309#else /* FREEBSD */
1310 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1311#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001312 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001313 switch (errno) {
1314 case EINTR:
1315 continue;
1316 case EBADF:
1317 pollinfo.revents = POLLERR;
1318 break;
1319 case ENOENT:
1320 pollinfo.revents = POLLHUP;
1321 break;
1322 default:
1323 perror("proc_poller: PIOCWSTOP");
1324 }
1325 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1326 _exit(0);
1327 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001328 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1330 sigsuspend(&empty_set);
1331 }
1332}
1333
1334#endif /* !HAVE_POLLABLE_PROCFS */
1335
1336static int
1337choose_pfd()
1338{
1339 int i, j;
1340 struct tcb *tcp;
1341
1342 static int last;
1343
1344 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001345 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001346 /*
1347 * The previous process is ready to run again. We'll
1348 * let it do so if it is currently in a syscall. This
1349 * heuristic improves the readability of the trace.
1350 */
1351 tcp = pfd2tcb(pollv[last].fd);
1352 if (tcp && (tcp->flags & TCB_INSYSCALL))
1353 return pollv[last].fd;
1354 }
1355
1356 for (i = 0; i < nprocs; i++) {
1357 /* Let competing children run round robin. */
1358 j = (i + last + 1) % nprocs;
1359 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1360 tcp = pfd2tcb(pollv[j].fd);
1361 if (!tcp) {
1362 fprintf(stderr, "strace: lost proc\n");
1363 exit(1);
1364 }
1365 droptcb(tcp);
1366 return -1;
1367 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001368 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001369 last = j;
1370 return pollv[j].fd;
1371 }
1372 }
1373 fprintf(stderr, "strace: nothing ready\n");
1374 exit(1);
1375}
1376
1377static int
1378trace()
1379{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001380#ifdef POLL_HACK
1381 struct tcb *in_syscall;
1382#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001383 struct tcb *tcp;
1384 int pfd;
1385 int what;
1386 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001387 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001388
1389 for (;;) {
1390 if (interactive)
1391 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1392
1393 if (nprocs == 0)
1394 break;
1395
1396 switch (nprocs) {
1397 case 1:
1398#ifndef HAVE_POLLABLE_PROCFS
1399 if (proc_poll_pipe[0] == -1) {
1400#endif
1401 tcp = pid2tcb(0);
1402 if (!tcp)
1403 continue;
1404 pfd = tcp->pfd;
1405 if (pfd == -1)
1406 continue;
1407 break;
1408#ifndef HAVE_POLLABLE_PROCFS
1409 }
1410 /* fall through ... */
1411#endif /* !HAVE_POLLABLE_PROCFS */
1412 default:
1413#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001414#ifdef POLL_HACK
1415 /* On some systems (e.g. UnixWare) we get too much ugly
1416 "unfinished..." stuff when multiple proceses are in
1417 syscalls. Here's a nasty hack */
1418
1419 if (in_syscall) {
1420 struct pollfd pv;
1421 tcp = in_syscall;
1422 in_syscall = NULL;
1423 pv.fd = tcp->pfd;
1424 pv.events = POLLWANT;
1425 if ((what = poll (&pv, 1, 1)) < 0) {
1426 if (interrupted)
1427 return 0;
1428 continue;
1429 }
1430 else if (what == 1 && pv.revents & POLLWANT) {
1431 goto FOUND;
1432 }
1433 }
1434#endif
1435
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001436 if (poll(pollv, nprocs, INFTIM) < 0) {
1437 if (interrupted)
1438 return 0;
1439 continue;
1440 }
1441#else /* !HAVE_POLLABLE_PROCFS */
1442 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1443 if (interrupted)
1444 return 0;
1445 continue;
1446 }
1447#endif /* !HAVE_POLLABLE_PROCFS */
1448 pfd = choose_pfd();
1449 if (pfd == -1)
1450 continue;
1451 break;
1452 }
1453
1454 /* Look up `pfd' in our table. */
1455 if ((tcp = pfd2tcb(pfd)) == NULL) {
1456 fprintf(stderr, "unknown pfd: %u\n", pfd);
1457 exit(1);
1458 }
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001459 FOUND:
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001460 /* Get the status of the process. */
1461 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001462#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001463 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001464#else /* FREEBSD */
1465 /* Thanks to some scheduling mystery, the first poller
1466 sometimes waits for the already processed end of fork
1467 event. Doing a non blocking poll here solves the problem. */
1468 if (proc_poll_pipe[0] != -1)
1469 ioctl_result = IOCTL_STATUS (tcp);
1470 else
1471 ioctl_result = IOCTL_WSTOP (tcp);
1472#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001473 ioctl_errno = errno;
1474#ifndef HAVE_POLLABLE_PROCFS
1475 if (proc_poll_pipe[0] != -1) {
1476 if (ioctl_result < 0)
1477 kill(poller_pid, SIGKILL);
1478 else
1479 kill(poller_pid, SIGUSR1);
1480 }
1481#endif /* !HAVE_POLLABLE_PROCFS */
1482 }
1483 if (interrupted)
1484 return 0;
1485
1486 if (interactive)
1487 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1488
1489 if (ioctl_result < 0) {
1490 /* Find out what happened if it failed. */
1491 switch (ioctl_errno) {
1492 case EINTR:
1493 case EBADF:
1494 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001495#ifdef FREEBSD
1496 case ENOTTY:
1497#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001498 case ENOENT:
1499 droptcb(tcp);
1500 continue;
1501 default:
1502 perror("PIOCWSTOP");
1503 exit(1);
1504 }
1505 }
1506
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001507#ifdef FREEBSD
1508 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1509 /* discard first event for a syscall we never entered */
1510 IOCTL (tcp->pfd, PIOCRUN, 0);
1511 continue;
1512 }
1513#endif
1514
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001515 /* clear the just started flag */
1516 tcp->flags &= ~TCB_STARTUP;
1517
1518 /* set current output file */
1519 outf = tcp->outf;
1520
1521 if (cflag) {
1522 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001523#ifdef FREEBSD
1524 char buf[1024];
1525 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001526
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001527 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1528 buf[len] = '\0';
1529 sscanf(buf,
1530 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1531 &stime.tv_sec, &stime.tv_usec);
1532 } else
1533 stime.tv_sec = stime.tv_usec = 0;
1534#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001535 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1536 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001537#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001538 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1539 tcp->stime = stime;
1540 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001541 what = tcp->status.PR_WHAT;
1542 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001543#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001544 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001545 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1546 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001547 if (trace_syscall(tcp) < 0) {
1548 fprintf(stderr, "syscall trouble\n");
1549 exit(1);
1550 }
1551 }
1552 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001553#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001554 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001555#ifdef POLL_HACK
1556 in_syscall = tcp;
1557#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001558 case PR_SYSEXIT:
1559 if (trace_syscall(tcp) < 0) {
1560 fprintf(stderr, "syscall trouble\n");
1561 exit(1);
1562 }
1563 break;
1564 case PR_SIGNALLED:
1565 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1566 printleader(tcp);
1567 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001568 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001569 printtrailer(tcp);
1570 }
1571 break;
1572 case PR_FAULTED:
1573 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1574 printleader(tcp);
1575 tprintf("=== FAULT %d ===", what);
1576 printtrailer(tcp);
1577 }
1578 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001579#ifdef FREEBSD
1580 case 0: /* handle case we polled for nothing */
1581 continue;
1582#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001583 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001584 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001585 exit(1);
1586 break;
1587 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001588 arg = 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001589#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001590 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001591#else
1592 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
1593#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001594 perror("PIOCRUN");
1595 exit(1);
1596 }
1597 }
1598 return 0;
1599}
1600
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001601#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602
1603static int
1604trace()
1605{
1606 int pid;
1607 int wait_errno;
1608 int status;
1609 struct tcb *tcp;
1610#ifdef LINUX
1611 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001612#ifdef __WALL
1613 static int wait4_options = __WALL;
1614#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615#endif /* LINUX */
1616
1617 while (nprocs != 0) {
1618 if (interactive)
1619 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1620#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001621#ifdef __WALL
1622 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
1623 if ((wait4_options & __WALL) && errno == EINVAL) {
1624 /* this kernel does not support __WALL */
1625 wait4_options &= ~__WALL;
1626 errno = 0;
1627 pid = wait4(-1, &status, wait4_options,
1628 cflag ? &ru : NULL);
1629 }
1630 if (!(wait4_options & __WALL) && errno == ECHILD) {
1631 /* most likely a "cloned" process */
1632 pid = wait4(-1, &status, __WCLONE,
1633 cflag ? &ru : NULL);
1634 if (pid == -1) {
1635 fprintf(stderr, "strace: clone wait4 "
1636 "failed: %s\n", strerror(errno));
1637 }
1638 }
1639#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001640 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001641#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642#endif /* LINUX */
1643#ifdef SUNOS4
1644 pid = wait(&status);
1645#endif /* SUNOS4 */
1646 wait_errno = errno;
1647 if (interactive)
1648 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1649
1650 if (interrupted)
1651 return 0;
1652
1653 if (pid == -1) {
1654 switch (wait_errno) {
1655 case EINTR:
1656 continue;
1657 case ECHILD:
1658 /*
1659 * We would like to verify this case
1660 * but sometimes a race in Solbourne's
1661 * version of SunOS sometimes reports
1662 * ECHILD before sending us SIGCHILD.
1663 */
1664#if 0
1665 if (nprocs == 0)
1666 return 0;
1667 fprintf(stderr, "strace: proc miscount\n");
1668 exit(1);
1669#endif
1670 return 0;
1671 default:
1672 errno = wait_errno;
1673 perror("strace: wait");
1674 return -1;
1675 }
1676 }
1677 if (debug)
1678 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1679
1680 /* Look up `pid' in our table. */
1681 if ((tcp = pid2tcb(pid)) == NULL) {
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001682#if 0 /* XXX davidm */ /* WTA: disabled again */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001683 struct tcb *tcpchild;
1684
1685 if ((tcpchild = alloctcb(pid)) == NULL) {
1686 fprintf(stderr, " [tcb table full]\n");
1687 kill(pid, SIGKILL); /* XXX */
1688 return 0;
1689 }
1690 tcpchild->flags |= TCB_ATTACHED;
1691 newoutf(tcpchild);
1692 tcp->nchildren++;
1693 if (!qflag)
1694 fprintf(stderr, "Process %d attached\n", pid);
1695#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001696 fprintf(stderr, "unknown pid: %u\n", pid);
1697 if (WIFSTOPPED(status))
1698 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1699 exit(1);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001700#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001701 }
1702 /* set current output file */
1703 outf = tcp->outf;
1704 if (cflag) {
1705#ifdef LINUX
1706 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
1707 tcp->stime = ru.ru_stime;
1708#endif /* !LINUX */
1709 }
1710
1711 if (tcp->flags & TCB_SUSPENDED) {
1712 /*
1713 * Apparently, doing any ptrace() call on a stopped
1714 * process, provokes the kernel to report the process
1715 * status again on a subsequent wait(), even if the
1716 * process has not been actually restarted.
1717 * Since we have inspected the arguments of suspended
1718 * processes we end up here testing for this case.
1719 */
1720 continue;
1721 }
1722 if (WIFSIGNALED(status)) {
1723 if (!cflag
1724 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
1725 printleader(tcp);
1726 tprintf("+++ killed by %s +++",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001727 signame(WTERMSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 printtrailer(tcp);
1729 }
1730 droptcb(tcp);
1731 continue;
1732 }
1733 if (WIFEXITED(status)) {
1734 if (debug)
1735 fprintf(stderr, "pid %u exited\n", pid);
1736 if (tcp->flags & TCB_ATTACHED)
1737 fprintf(stderr,
1738 "PANIC: attached pid %u exited\n",
1739 pid);
1740 droptcb(tcp);
1741 continue;
1742 }
1743 if (!WIFSTOPPED(status)) {
1744 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
1745 droptcb(tcp);
1746 continue;
1747 }
1748 if (debug)
1749 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001750 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001751
1752 if (tcp->flags & TCB_STARTUP) {
1753 /*
1754 * This flag is there to keep us in sync.
1755 * Next time this process stops it should
1756 * really be entering a system call.
1757 */
1758 tcp->flags &= ~TCB_STARTUP;
1759 if (tcp->flags & TCB_ATTACHED) {
1760 /*
1761 * Interestingly, the process may stop
1762 * with STOPSIG equal to some other signal
1763 * than SIGSTOP if we happend to attach
1764 * just before the process takes a signal.
1765 */
1766 if (!WIFSTOPPED(status)) {
1767 fprintf(stderr,
1768 "pid %u not stopped\n", pid);
1769 detach(tcp, WSTOPSIG(status));
1770 continue;
1771 }
1772 }
1773 else {
1774#ifdef SUNOS4
1775 /* A child of us stopped at exec */
1776 if (WSTOPSIG(status) == SIGTRAP && followvfork)
1777 fixvfork(tcp);
1778#endif /* SUNOS4 */
1779 }
1780 if (tcp->flags & TCB_BPTSET) {
1781 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
1782 droptcb(tcp);
1783 cleanup();
1784 return -1;
1785 }
1786 }
1787 goto tracing;
1788 }
1789
1790 if (WSTOPSIG(status) != SIGTRAP) {
1791 if (WSTOPSIG(status) == SIGSTOP &&
1792 (tcp->flags & TCB_SIGTRAPPED)) {
1793 /*
1794 * Trapped attempt to block SIGTRAP
1795 * Hope we are back in control now.
1796 */
1797 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
1798 if (ptrace(PTRACE_SYSCALL,
1799 pid, (char *) 1, 0) < 0) {
1800 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
1801 cleanup();
1802 return -1;
1803 }
1804 continue;
1805 }
1806 if (!cflag
1807 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
1808 printleader(tcp);
1809 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001810 signame(WSTOPSIG(status)),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001811 strsignal(WSTOPSIG(status)));
1812 printtrailer(tcp);
1813 }
1814 if ((tcp->flags & TCB_ATTACHED) &&
1815 !sigishandled(tcp, WSTOPSIG(status))) {
1816 detach(tcp, WSTOPSIG(status));
1817 continue;
1818 }
1819 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
1820 WSTOPSIG(status)) < 0) {
1821 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
1822 cleanup();
1823 return -1;
1824 }
1825 tcp->flags &= ~TCB_SUSPENDED;
1826 continue;
1827 }
1828 if (trace_syscall(tcp) < 0) {
1829 if (tcp->flags & TCB_ATTACHED)
1830 detach(tcp, 0);
1831 else {
1832 ptrace(PTRACE_KILL,
1833 tcp->pid, (char *) 1, SIGTERM);
1834 droptcb(tcp);
1835 }
1836 continue;
1837 }
1838 if (tcp->flags & TCB_EXITING) {
1839 if (tcp->flags & TCB_ATTACHED)
1840 detach(tcp, 0);
1841 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
1842 perror("strace: ptrace(PTRACE_CONT, ...)");
1843 cleanup();
1844 return -1;
1845 }
1846 continue;
1847 }
1848 if (tcp->flags & TCB_SUSPENDED) {
1849 if (!qflag)
1850 fprintf(stderr, "Process %u suspended\n", pid);
1851 continue;
1852 }
1853 tracing:
1854 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
1855 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
1856 cleanup();
1857 return -1;
1858 }
1859 }
1860 return 0;
1861}
1862
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001863#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001864
1865static int curcol;
1866
1867#ifdef __STDC__
1868#include <stdarg.h>
1869#define VA_START(a, b) va_start(a, b)
1870#else
1871#include <varargs.h>
1872#define VA_START(a, b) va_start(a)
1873#endif
1874
1875void
1876#ifdef __STDC__
1877tprintf(const char *fmt, ...)
1878#else
1879tprintf(fmt, va_alist)
1880char *fmt;
1881va_dcl
1882#endif
1883{
1884 va_list args;
1885
1886 VA_START(args, fmt);
1887 if (outf)
1888 curcol += vfprintf(outf, fmt, args);
1889 va_end(args);
1890 return;
1891}
1892
1893void
1894printleader(tcp)
1895struct tcb *tcp;
1896{
1897 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
1898 tcp_last->flags |= TCB_REPRINT;
1899 tprintf(" <unfinished ...>\n");
1900 }
1901 curcol = 0;
1902 if ((followfork == 1 || pflag_seen > 1) && outfname)
1903 tprintf("%-5d ", tcp->pid);
1904 else if (nprocs > 1 && !outfname)
1905 tprintf("[pid %5u] ", tcp->pid);
1906 if (tflag) {
1907 char str[sizeof("HH:MM:SS")];
1908 struct timeval tv, dtv;
1909 static struct timeval otv;
1910
1911 gettimeofday(&tv, NULL);
1912 if (rflag) {
1913 if (otv.tv_sec == 0)
1914 otv = tv;
1915 tv_sub(&dtv, &tv, &otv);
1916 tprintf("%6ld.%06ld ",
1917 (long) dtv.tv_sec, (long) dtv.tv_usec);
1918 otv = tv;
1919 }
1920 else if (tflag > 2) {
1921 tprintf("%ld.%06ld ",
1922 (long) tv.tv_sec, (long) tv.tv_usec);
1923 }
1924 else {
1925 time_t local = tv.tv_sec;
1926 strftime(str, sizeof(str), "%T", localtime(&local));
1927 if (tflag > 1)
1928 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
1929 else
1930 tprintf("%s ", str);
1931 }
1932 }
1933 if (iflag)
1934 printcall(tcp);
1935}
1936
1937void
1938tabto(col)
1939int col;
1940{
1941 if (curcol < col)
1942 tprintf("%*s", col - curcol, "");
1943}
1944
1945void
1946printtrailer(tcp)
1947struct tcb *tcp;
1948{
1949 tprintf("\n");
1950 tcp_last = NULL;
1951}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001952
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00001953#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001954
1955int mp_ioctl (int fd, int cmd, void *arg, int size) {
1956
1957 struct iovec iov[2];
1958 int n = 1;
1959
1960 iov[0].iov_base = &cmd;
1961 iov[0].iov_len = sizeof cmd;
1962 if (arg) {
1963 ++n;
1964 iov[1].iov_base = arg;
1965 iov[1].iov_len = size;
1966 }
1967
1968 return writev (fd, iov, n);
1969}
1970
1971#endif