blob: 02d1e6e8b9cca7d3d85a70af5864dd111fb2402f [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>
John Hughes19e49982001-10-19 08:59:12 +000046#include <limits.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000047
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000048#if defined(IA64) && defined(LINUX)
49# include <asm/ptrace_offsets.h>
50#endif
51
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000052#ifdef USE_PROCFS
53#include <poll.h>
54#endif
55
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000056#ifdef SVR4
57#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000058#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000059#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000060#include <sys/uio.h>
61#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000062#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000063#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000064
65int debug = 0, followfork = 0, followvfork = 0, interactive = 0;
66int rflag = 0, tflag = 0, dtime = 0, cflag = 0;
67int iflag = 0, xflag = 0, qflag = 0;
68int pflag_seen = 0;
69
Michal Ludvig17f8fb32002-11-06 13:17:21 +000070/* Sometimes we want to print only succeeding syscalls. */
71int not_failing_only = 0;
72
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000073char *username = NULL;
74uid_t run_uid;
75gid_t run_gid;
76
77int acolumn = DEFAULT_ACOLUMN;
78int max_strlen = DEFAULT_STRLEN;
79char *outfname = NULL;
80FILE *outf;
Roland McGrathee9d4352002-12-18 04:16:10 +000081struct tcb **tcbtab;
82unsigned int nprocs, tcbtabsize;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000083char *progname;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000084extern char **environ;
85
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000086static int trace P((void));
87static void cleanup P((void));
88static void interrupt P((int sig));
89static sigset_t empty_set, blocked_set;
90
91#ifdef HAVE_SIG_ATOMIC_T
92static volatile sig_atomic_t interrupted;
93#else /* !HAVE_SIG_ATOMIC_T */
94#ifdef __STDC__
95static volatile int interrupted;
96#else /* !__STDC__ */
97static int interrupted;
98#endif /* !__STDC__ */
99#endif /* !HAVE_SIG_ATOMIC_T */
100
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000101#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000102
103static struct tcb *pfd2tcb P((int pfd));
104static void reaper P((int sig));
105static void rebuild_pollv P((void));
Roland McGrathee9d4352002-12-18 04:16:10 +0000106static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107
108#ifndef HAVE_POLLABLE_PROCFS
109
110static void proc_poll_open P((void));
111static void proc_poller P((int pfd));
112
113struct proc_pollfd {
114 int fd;
115 int revents;
116 int pid;
117};
118
119static int poller_pid;
120static int proc_poll_pipe[2] = { -1, -1 };
121
122#endif /* !HAVE_POLLABLE_PROCFS */
123
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000124#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000125#define POLLWANT POLLWRNORM
126#else
127#define POLLWANT POLLPRI
128#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000129#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000130
131static void
132usage(ofp, exitval)
133FILE *ofp;
134int exitval;
135{
136 fprintf(ofp, "\
137usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000138 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
139 [command [arg ...]]\n\
140 or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
141 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000142-c -- count time, calls, and errors for each syscall and report summary\n\
143-f -- follow forks, -ff -- with output into separate files\n\
144-F -- attempt to follow vforks, -h -- print help message\n\
145-i -- print instruction pointer at time of syscall\n\
146-q -- suppress messages about attaching, detaching, etc.\n\
147-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
148-T -- print time spent in each syscall, -V -- print version\n\
149-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
150-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
151-a column -- alignment COLUMN for printing syscall results (default %d)\n\
152-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
153 options: trace, abbrev, verbose, raw, signal, read, or write\n\
154-o file -- send trace output to FILE instead of stderr\n\
155-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
156-p pid -- trace process with process id PID, may be repeated\n\
157-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
158-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
159-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000160-E var=val -- put var=val in the environment for command\n\
161-E var -- remove var from the environment for command\n\
162" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000163-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000164 */
165, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000166 exit(exitval);
167}
168
169#ifdef SVR4
170#ifdef MIPS
171void
172foobar()
173{
174}
175#endif /* MIPS */
176#endif /* SVR4 */
177
178int
179main(argc, argv)
180int argc;
181char *argv[];
182{
183 extern int optind;
184 extern char *optarg;
185 struct tcb *tcp;
186 int c, pid = 0;
187 struct sigaction sa;
188
189 static char buf[BUFSIZ];
190
Roland McGrathee9d4352002-12-18 04:16:10 +0000191 /* Allocate the initial tcbtab. */
192 tcbtabsize = argc; /* Surely enough for all -p args. */
193 tcbtab = (struct tcb **) malloc (tcbtabsize * sizeof tcbtab[0]);
194 tcbtab[0] = (struct tcb *) calloc (tcbtabsize, sizeof *tcbtab[0]);
195 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
196 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
197
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000198 progname = argv[0];
199 outf = stderr;
200 interactive = 1;
201 qualify("trace=all");
202 qualify("abbrev=all");
203 qualify("verbose=all");
204 qualify("signal=all");
205 set_sortby(DEFAULT_SORTBY);
206 set_personality(DEFAULT_PERSONALITY);
207 while ((c = getopt(argc, argv,
Roland McGrathde6e5332003-01-24 04:31:23 +0000208 "+cdfFhiqrtTvVxza:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000209 switch (c) {
210 case 'c':
211 cflag++;
212 dtime++;
213 break;
214 case 'd':
215 debug++;
216 break;
217 case 'f':
218 followfork++;
219 break;
220 case 'F':
221 followvfork++;
222 break;
223 case 'h':
224 usage(stdout, 0);
225 break;
226 case 'i':
227 iflag++;
228 break;
229 case 'q':
230 qflag++;
231 break;
232 case 'r':
233 rflag++;
234 tflag++;
235 break;
236 case 't':
237 tflag++;
238 break;
239 case 'T':
240 dtime++;
241 break;
242 case 'x':
243 xflag++;
244 break;
245 case 'v':
246 qualify("abbrev=none");
247 break;
248 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000249 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000250 exit(0);
251 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000252 case 'z':
253 not_failing_only = 1;
254 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000255 case 'a':
256 acolumn = atoi(optarg);
257 break;
258 case 'e':
259 qualify(optarg);
260 break;
261 case 'o':
262 outfname = strdup(optarg);
263 break;
264 case 'O':
265 set_overhead(atoi(optarg));
266 break;
267 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000268 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000269 fprintf(stderr, "%s: Invalid process id: %s\n",
270 progname, optarg);
271 break;
272 }
273 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000274 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000275 break;
276 }
277 if ((tcp = alloctcb(pid)) == NULL) {
Roland McGrathde6e5332003-01-24 04:31:23 +0000278 fprintf(stderr, "%s: out of memory\n",
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000279 progname);
280 exit(1);
281 }
282 tcp->flags |= TCB_ATTACHED;
283 pflag_seen++;
284 break;
285 case 's':
286 max_strlen = atoi(optarg);
287 break;
288 case 'S':
289 set_sortby(optarg);
290 break;
291 case 'u':
292 username = strdup(optarg);
293 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000294 case 'E':
295 if (putenv(optarg) < 0) {
296 fprintf(stderr, "%s: out of memory\n",
297 progname);
298 exit(1);
299 }
300 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000301 default:
302 usage(stderr, 1);
303 break;
304 }
305 }
306
307 /* See if they want to run as another user. */
308 if (username != NULL) {
309 struct passwd *pent;
310
311 if (getuid() != 0 || geteuid() != 0) {
312 fprintf(stderr,
313 "%s: you must be root to use the -u option\n",
314 progname);
315 exit(1);
316 }
317 if ((pent = getpwnam(username)) == NULL) {
318 fprintf(stderr, "%s: cannot find user `%s'\n",
319 progname, optarg);
320 exit(1);
321 }
322 run_uid = pent->pw_uid;
323 run_gid = pent->pw_gid;
324 }
325 else {
326 run_uid = getuid();
327 run_gid = getgid();
328 }
329
330#ifndef SVR4
331 setreuid(geteuid(), getuid());
332#endif
333
334 /* See if they want to pipe the output. */
335 if (outfname && (outfname[0] == '|' || outfname[0] == '!')) {
336 if ((outf = popen(outfname + 1, "w")) == NULL) {
337 fprintf(stderr, "%s: can't popen '%s': %s\n",
338 progname, outfname + 1, strerror(errno));
339 exit(1);
340 }
341 free(outfname);
342 outfname = NULL;
343 }
344
345 /* Check if they want to redirect the output. */
346 if (outfname) {
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000347 long f;
348
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000349 if ((outf = fopen(outfname, "w")) == NULL) {
350 fprintf(stderr, "%s: can't fopen '%s': %s\n",
351 progname, outfname, strerror(errno));
352 exit(1);
353 }
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000354
355 if ((f=fcntl(fileno(outf), F_GETFD)) < 0 ) {
356 perror("failed to get flags for outputfile");
357 exit(1);
358 }
359
360 if (fcntl(fileno(outf), F_SETFD, f|FD_CLOEXEC) < 0 ) {
361 perror("failed to set flags for outputfile");
362 exit(1);
363 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000364 }
365
366#ifndef SVR4
367 setreuid(geteuid(), getuid());
368#endif
369
370 if (!outfname) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000371 setvbuf(outf, buf, _IOLBF, BUFSIZ);
372 }
Roland McGrath36931052003-06-03 01:35:20 +0000373 else if (optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000374 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000375 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000376 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000377
Roland McGrathee9d4352002-12-18 04:16:10 +0000378 for (c = 0; c < tcbtabsize; c++) {
379 tcp = tcbtab[c];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380 /* Reinitialize the output since it may have changed. */
381 tcp->outf = outf;
382 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
383 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000384#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000385 if (proc_open(tcp, 1) < 0) {
386 fprintf(stderr, "trouble opening proc file\n");
387 droptcb(tcp);
388 continue;
389 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000390#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000391 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
392 perror("attach: ptrace(PTRACE_ATTACH, ...)");
393 droptcb(tcp);
394 continue;
395 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000396#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000397 if (!qflag)
398 fprintf(stderr,
399 "Process %u attached - interrupt to quit\n",
400 pid);
401 }
402
403 if (optind < argc) {
404 struct stat statbuf;
405 char *filename;
406 char pathname[MAXPATHLEN];
407
408 filename = argv[optind];
409 if (strchr(filename, '/'))
410 strcpy(pathname, filename);
411#ifdef USE_DEBUGGING_EXEC
412 /*
413 * Debuggers customarily check the current directory
414 * first regardless of the path but doing that gives
415 * security geeks a panic attack.
416 */
417 else if (stat(filename, &statbuf) == 0)
418 strcpy(pathname, filename);
419#endif /* USE_DEBUGGING_EXEC */
420 else {
421 char *path;
422 int m, n, len;
423
424 for (path = getenv("PATH"); path && *path; path += m) {
425 if (strchr(path, ':')) {
426 n = strchr(path, ':') - path;
427 m = n + 1;
428 }
429 else
430 m = n = strlen(path);
431 if (n == 0) {
432 getcwd(pathname, MAXPATHLEN);
433 len = strlen(pathname);
434 }
435 else {
436 strncpy(pathname, path, n);
437 len = n;
438 }
439 if (len && pathname[len - 1] != '/')
440 pathname[len++] = '/';
441 strcpy(pathname + len, filename);
Roland McGrathed645162003-06-03 07:18:19 +0000442 if (stat(pathname, &statbuf) == 0 &&
443 /* Accept only regular files
444 with some execute bits set.
445 XXX not perfect, might still fail */
446 S_ISREG(statbuf.st_mode) &&
447 (statbuf.st_mode & 0111))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000448 break;
449 }
450 }
451 if (stat(pathname, &statbuf) < 0) {
452 fprintf(stderr, "%s: %s: command not found\n",
453 progname, filename);
454 exit(1);
455 }
456 switch (pid = fork()) {
457 case -1:
458 perror("strace: fork");
459 cleanup();
460 exit(1);
461 break;
462 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000463#ifdef USE_PROCFS
464 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000465#ifdef MIPS
466 /* Kludge for SGI, see proc_open for details. */
467 sa.sa_handler = foobar;
468 sa.sa_flags = 0;
469 sigemptyset(&sa.sa_mask);
470 sigaction(SIGINT, &sa, NULL);
471#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000472#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000473 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000474#else /* FREEBSD */
475 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000476#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000477#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000478 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000479 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000480
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000481 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
482 perror("strace: ptrace(PTRACE_TRACEME, ...)");
483 return -1;
484 }
485 if (debug)
486 kill(getpid(), SIGSTOP);
487
488 if (username != NULL || geteuid() == 0) {
489 uid_t run_euid = run_uid;
490 gid_t run_egid = run_gid;
491
492 if (statbuf.st_mode & S_ISUID)
493 run_euid = statbuf.st_uid;
494 if (statbuf.st_mode & S_ISGID)
495 run_egid = statbuf.st_gid;
496
497 /*
498 * It is important to set groups before we
499 * lose privileges on setuid.
500 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000501 if (username != NULL) {
502 if (initgroups(username, run_gid) < 0) {
503 perror("initgroups");
504 exit(1);
505 }
506 if (setregid(run_gid, run_egid) < 0) {
507 perror("setregid");
508 exit(1);
509 }
510 if (setreuid(run_uid, run_euid) < 0) {
511 perror("setreuid");
512 exit(1);
513 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000514 }
515 }
516 else
517 setreuid(run_uid, run_uid);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000518#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000519
520 execv(pathname, &argv[optind]);
521 perror("strace: exec");
522 _exit(1);
523 break;
524 }
525 default:
526 if ((tcp = alloctcb(pid)) == NULL) {
527 fprintf(stderr, "tcb table full\n");
528 cleanup();
529 exit(1);
530 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000531#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000532 if (proc_open(tcp, 0) < 0) {
533 fprintf(stderr, "trouble opening proc file\n");
534 cleanup();
535 exit(1);
536 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000537#endif /* USE_PROCFS */
538#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539 fake_execve(tcp, pathname, &argv[optind], environ);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000540#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000541 break;
542 }
543 }
544 else if (pflag_seen == 0)
545 usage(stderr, 1);
546
547 sigemptyset(&empty_set);
548 sigemptyset(&blocked_set);
549 sa.sa_handler = SIG_IGN;
550 sigemptyset(&sa.sa_mask);
551 sa.sa_flags = 0;
552 sigaction(SIGTTOU, &sa, NULL);
553 sigaction(SIGTTIN, &sa, NULL);
554 if (interactive) {
555 sigaddset(&blocked_set, SIGHUP);
556 sigaddset(&blocked_set, SIGINT);
557 sigaddset(&blocked_set, SIGQUIT);
558 sigaddset(&blocked_set, SIGPIPE);
559 sigaddset(&blocked_set, SIGTERM);
560 sa.sa_handler = interrupt;
561#ifdef SUNOS4
562 /* POSIX signals on sunos4.1 are a little broken. */
563 sa.sa_flags = SA_INTERRUPT;
564#endif /* SUNOS4 */
565 }
566 sigaction(SIGHUP, &sa, NULL);
567 sigaction(SIGINT, &sa, NULL);
568 sigaction(SIGQUIT, &sa, NULL);
569 sigaction(SIGPIPE, &sa, NULL);
570 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000571#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000572 sa.sa_handler = reaper;
573 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000574#else
575 /* Make sure SIGCHLD has the default action so that waitpid
576 definitely works without losing track of children. The user
577 should not have given us a bogus state to inherit, but he might
578 have. Arguably we should detect SIG_IGN here and pass it on
579 to children, but probably noone really needs that. */
580 sa.sa_handler = SIG_DFL;
581 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000582#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583
584 if (trace() < 0)
585 exit(1);
586 cleanup();
587 exit(0);
588}
589
590void
591newoutf(tcp)
592struct tcb *tcp;
593{
594 char name[MAXPATHLEN];
595 FILE *fp;
596
597 if (outfname && followfork > 1) {
598 sprintf(name, "%s.%u", outfname, tcp->pid);
599#ifndef SVR4
600 setreuid(geteuid(), getuid());
601#endif
602 fp = fopen(name, "w");
603#ifndef SVR4
604 setreuid(geteuid(), getuid());
605#endif
606 if (fp == NULL) {
607 perror("fopen");
608 return;
609 }
610 tcp->outf = fp;
611 }
612 return;
613}
614
615struct tcb *
616alloctcb(pid)
617int pid;
618{
619 int i;
620 struct tcb *tcp;
621
Roland McGrathee9d4352002-12-18 04:16:10 +0000622 for (i = 0; i < tcbtabsize; i++) {
623 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000624 if ((tcp->flags & TCB_INUSE) == 0) {
625 tcp->pid = pid;
626 tcp->parent = NULL;
627 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000628 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000629#ifdef TCB_CLONE_THREAD
630 tcp->nclone_threads = tcp->nclone_detached = 0;
631 tcp->nclone_waiting = 0;
632#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000633 tcp->flags = TCB_INUSE | TCB_STARTUP;
634 tcp->outf = outf; /* Initialise to current out file */
635 tcp->stime.tv_sec = 0;
636 tcp->stime.tv_usec = 0;
637 tcp->pfd = -1;
638 nprocs++;
639 return tcp;
640 }
641 }
642 return NULL;
643}
644
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000645#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000646int
647proc_open(tcp, attaching)
648struct tcb *tcp;
649int attaching;
650{
651 char proc[32];
652 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000653#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000654 int i;
655 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000656 sigset_t signals;
657 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000658#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000659#ifndef HAVE_POLLABLE_PROCFS
660 static int last_pfd;
661#endif
662
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000663#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000664 /* Open the process pseudo-files in /proc. */
665 sprintf(proc, "/proc/%d/ctl", tcp->pid);
666 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000667 perror("strace: open(\"/proc/...\", ...)");
668 return -1;
669 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000670 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
671 perror("F_GETFD");
672 return -1;
673 }
674 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
675 perror("F_SETFD");
676 return -1;
677 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000678 sprintf(proc, "/proc/%d/status", tcp->pid);
679 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
680 perror("strace: open(\"/proc/...\", ...)");
681 return -1;
682 }
683 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
684 perror("F_GETFD");
685 return -1;
686 }
687 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
688 perror("F_SETFD");
689 return -1;
690 }
691 sprintf(proc, "/proc/%d/as", tcp->pid);
692 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
693 perror("strace: open(\"/proc/...\", ...)");
694 return -1;
695 }
696 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
697 perror("F_GETFD");
698 return -1;
699 }
700 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
701 perror("F_SETFD");
702 return -1;
703 }
704#else
705 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000706#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000707 sprintf(proc, "/proc/%d", tcp->pid);
708 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000709#else /* FREEBSD */
710 sprintf(proc, "/proc/%d/mem", tcp->pid);
711 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
712#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000713 perror("strace: open(\"/proc/...\", ...)");
714 return -1;
715 }
716 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
717 perror("F_GETFD");
718 return -1;
719 }
720 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
721 perror("F_SETFD");
722 return -1;
723 }
724#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000725#ifdef FREEBSD
726 sprintf(proc, "/proc/%d/regs", tcp->pid);
727 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
728 perror("strace: open(\"/proc/.../regs\", ...)");
729 return -1;
730 }
731 if (cflag) {
732 sprintf(proc, "/proc/%d/status", tcp->pid);
733 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
734 perror("strace: open(\"/proc/.../status\", ...)");
735 return -1;
736 }
737 } else
738 tcp->pfd_status = -1;
739#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000740 rebuild_pollv();
741 if (!attaching) {
742 /*
743 * Wait for the child to pause. Because of a race
744 * condition we have to poll for the event.
745 */
746 for (;;) {
747 if (IOCTL_STATUS (tcp) < 0) {
748 perror("strace: PIOCSTATUS");
749 return -1;
750 }
751 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000752 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000753 }
754 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000755#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000756 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000757 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000758 perror("strace: PIOCSTOP");
759 return -1;
760 }
Roland McGrath553a6092002-12-16 20:40:39 +0000761#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000762#ifdef PIOCSET
763 /* Set Run-on-Last-Close. */
764 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000765 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000766 perror("PIOCSET PR_RLC");
767 return -1;
768 }
769 /* Set or Reset Inherit-on-Fork. */
770 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000771 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000772 perror("PIOC{SET,RESET} PR_FORK");
773 return -1;
774 }
775#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000776#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000777 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
778 perror("PIOCSRLC");
779 return -1;
780 }
781 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
782 perror("PIOC{S,R}FORK");
783 return -1;
784 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000785#else /* FREEBSD */
786 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
787 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
788 perror("PIOCGFL");
789 return -1;
790 }
791 arg &= ~PF_LINGER;
792 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
793 perror("PIOCSFL");
794 return -1;
795 }
796#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000797#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000798#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000799 /* Enable all syscall entries we care about. */
800 premptyset(&syscalls);
801 for (i = 1; i < MAX_QUALS; ++i) {
802 if (i > (sizeof syscalls) * CHAR_BIT) break;
803 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
804 }
805 praddset (&syscalls, SYS_execve);
806 if (followfork) {
807 praddset (&syscalls, SYS_fork);
808#ifdef SYS_forkall
809 praddset (&syscalls, SYS_forkall);
810#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000811#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000812 praddset (&syscalls, SYS_fork1);
813#endif
814#ifdef SYS_rfork1
815 praddset (&syscalls, SYS_rfork1);
816#endif
817#ifdef SYS_rforkall
818 praddset (&syscalls, SYS_rforkall);
819#endif
820 }
821 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000822 perror("PIOCSENTRY");
823 return -1;
824 }
John Hughes19e49982001-10-19 08:59:12 +0000825 /* Enable the syscall exits. */
826 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000827 perror("PIOSEXIT");
828 return -1;
829 }
John Hughes19e49982001-10-19 08:59:12 +0000830 /* Enable signals we care about. */
831 premptyset(&signals);
832 for (i = 1; i < MAX_QUALS; ++i) {
833 if (i > (sizeof signals) * CHAR_BIT) break;
834 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
835 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000836 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000837 perror("PIOCSTRACE");
838 return -1;
839 }
John Hughes19e49982001-10-19 08:59:12 +0000840 /* Enable faults we care about */
841 premptyset(&faults);
842 for (i = 1; i < MAX_QUALS; ++i) {
843 if (i > (sizeof faults) * CHAR_BIT) break;
844 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
845 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000846 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000847 perror("PIOCSFAULT");
848 return -1;
849 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000850#else /* FREEBSD */
851 /* set events flags. */
852 arg = S_SIG | S_SCE | S_SCX ;
853 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
854 perror("PIOCBIS");
855 return -1;
856 }
857#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000858 if (!attaching) {
859#ifdef MIPS
860 /*
861 * The SGI PRSABORT doesn't work for pause() so
862 * we send it a caught signal to wake it up.
863 */
864 kill(tcp->pid, SIGINT);
865#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000866#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000867 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000868 arg = PRSABORT;
869 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000870 perror("PIOCRUN");
871 return -1;
872 }
Roland McGrath553a6092002-12-16 20:40:39 +0000873#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000874#endif /* !MIPS*/
875#ifdef FREEBSD
876 /* wake up the child if it received the SIGSTOP */
877 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000878#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000879 for (;;) {
880 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000881 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000882 perror("PIOCWSTOP");
883 return -1;
884 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000885 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000886 tcp->flags &= ~TCB_INSYSCALL;
887 get_scno(tcp);
888 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000889 break;
890 }
891 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000892#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000893 arg = 0;
894 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000895#else /* FREEBSD */
896 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +0000897#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000898 perror("PIOCRUN");
899 return -1;
900 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000901#ifdef FREEBSD
902 /* handle the case where we "opened" the child before
903 it did the kill -STOP */
904 if (tcp->status.PR_WHY == PR_SIGNALLED &&
905 tcp->status.PR_WHAT == SIGSTOP)
906 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000907#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000908 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000909#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000910 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000911#else /* FREEBSD */
912 } else {
Roland McGrath553a6092002-12-16 20:40:39 +0000913 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000914 /* We are attaching to an already running process.
915 * Try to figure out the state of the process in syscalls,
916 * to handle the first event well.
917 * This is done by having a look at the "wchan" property of the
918 * process, which tells where it is stopped (if it is). */
919 FILE * status;
920 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +0000921
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000922 sprintf(proc, "/proc/%d/status", tcp->pid);
923 status = fopen(proc, "r");
924 if (status &&
925 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
926 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
927 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
928 strcmp(wchan, "stopevent")) {
929 /* The process is asleep in the middle of a syscall.
930 Fake the syscall entry event */
931 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
932 tcp->status.PR_WHY = PR_SYSENTRY;
933 trace_syscall(tcp);
934 }
935 if (status)
936 fclose(status);
937 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000938 }
939#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000940#ifndef HAVE_POLLABLE_PROCFS
941 if (proc_poll_pipe[0] != -1)
942 proc_poller(tcp->pfd);
943 else if (nprocs > 1) {
944 proc_poll_open();
945 proc_poller(last_pfd);
946 proc_poller(tcp->pfd);
947 }
948 last_pfd = tcp->pfd;
949#endif /* !HAVE_POLLABLE_PROCFS */
950 return 0;
951}
952
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000953#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000954
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000955struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000956pid2tcb(pid)
957int pid;
958{
959 int i;
960 struct tcb *tcp;
961
Roland McGrathee9d4352002-12-18 04:16:10 +0000962 for (i = 0; i < tcbtabsize; i++) {
963 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000964 if (pid && tcp->pid != pid)
965 continue;
966 if (tcp->flags & TCB_INUSE)
967 return tcp;
968 }
969 return NULL;
970}
971
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000972#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000973
974static struct tcb *
975pfd2tcb(pfd)
976int pfd;
977{
978 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000979
Roland McGrathca16be82003-01-10 19:55:28 +0000980 for (i = 0; i < tcbtabsize; i++) {
981 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000982 if (tcp->pfd != pfd)
983 continue;
984 if (tcp->flags & TCB_INUSE)
985 return tcp;
986 }
987 return NULL;
988}
989
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000990#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991
992void
993droptcb(tcp)
994struct tcb *tcp;
995{
996 if (tcp->pid == 0)
997 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000998#ifdef TCB_CLONE_THREAD
999 if (tcp->nclone_threads > 0) {
1000 /* There are other threads left in this process, but this
1001 is the one whose PID represents the whole process.
1002 We need to keep this record around as a zombie until
1003 all the threads die. */
1004 tcp->flags |= TCB_EXITING;
1005 return;
1006 }
1007#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001008 nprocs--;
1009 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001010
Roland McGrathe29341c2003-01-10 20:14:20 +00001011 if (tcp->parent != NULL) {
1012 tcp->parent->nchildren--;
1013#ifdef TCB_CLONE_THREAD
1014 if (tcp->flags & TCB_CLONE_DETACHED)
1015 tcp->parent->nclone_detached--;
1016 if (tcp->flags & TCB_CLONE_THREAD)
1017 tcp->parent->nclone_threads--;
1018#endif
Roland McGrath09623452003-05-23 02:27:13 +00001019#ifdef TCB_CLONE_DETACHED
1020 if (!(tcp->flags & TCB_CLONE_DETACHED))
1021#endif
1022 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001023 tcp->parent = NULL;
1024 }
1025
1026 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027 if (tcp->pfd != -1) {
1028 close(tcp->pfd);
1029 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001030#ifdef FREEBSD
1031 if (tcp->pfd_reg != -1) {
1032 close(tcp->pfd_reg);
1033 tcp->pfd_reg = -1;
1034 }
1035 if (tcp->pfd_status != -1) {
1036 close(tcp->pfd_status);
1037 tcp->pfd_status = -1;
1038 }
Roland McGrath553a6092002-12-16 20:40:39 +00001039#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001040#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001041 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001042#endif
1043 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001044
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001045 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001046 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001047
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048 tcp->outf = 0;
1049}
1050
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001051#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001052
1053static int
1054resume(tcp)
1055struct tcb *tcp;
1056{
1057 if (tcp == NULL)
1058 return -1;
1059
1060 if (!(tcp->flags & TCB_SUSPENDED)) {
1061 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1062 return -1;
1063 }
1064 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001065#ifdef TCB_CLONE_THREAD
1066 if (tcp->flags & TCB_CLONE_THREAD)
1067 tcp->parent->nclone_waiting--;
1068#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001069
1070 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1071 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1072 return -1;
1073 }
1074
1075 if (!qflag)
1076 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1077 return 0;
1078}
1079
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001080#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001081
1082/* detach traced process; continue with sig */
1083
1084static int
1085detach(tcp, sig)
1086struct tcb *tcp;
1087int sig;
1088{
1089 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001090#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001091 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001092#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001093
1094 if (tcp->flags & TCB_BPTSET)
1095 sig = SIGKILL;
1096
1097#ifdef LINUX
1098 /*
1099 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001100 * before detaching. Arghh. We go through hoops
1101 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001103#if defined(SPARC)
1104#undef PTRACE_DETACH
1105#define PTRACE_DETACH PTRACE_SUNDETACH
1106#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001107 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1108 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001109 }
1110 else if (errno != ESRCH) {
1111 /* Shouldn't happen. */
1112 perror("detach: ptrace(PTRACE_DETACH, ...)");
1113 }
1114 else if (kill(tcp->pid, 0) < 0) {
1115 if (errno != ESRCH)
1116 perror("detach: checking sanity");
1117 }
1118 else if (kill(tcp->pid, SIGSTOP) < 0) {
1119 if (errno != ESRCH)
1120 perror("detach: stopping child");
1121 }
1122 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001123 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001124#ifdef __WALL
1125 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1126 if (errno == ECHILD) /* Already gone. */
1127 break;
1128 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001129 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001130 break;
1131 }
1132#endif /* __WALL */
1133 /* No __WALL here. */
1134 if (waitpid(tcp->pid, &status, 0) < 0) {
1135 if (errno != ECHILD) {
1136 perror("detach: waiting");
1137 break;
1138 }
1139#ifdef __WCLONE
1140 /* If no processes, try clones. */
1141 if (wait4(tcp->pid, &status, __WCLONE,
1142 NULL) < 0) {
1143 if (errno != ECHILD)
1144 perror("detach: waiting");
1145 break;
1146 }
1147#endif /* __WCLONE */
1148 }
1149#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001150 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001151#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001152 if (!WIFSTOPPED(status)) {
1153 /* Au revoir, mon ami. */
1154 break;
1155 }
1156 if (WSTOPSIG(status) == SIGSTOP) {
1157 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001158 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159 if (errno != ESRCH)
1160 perror("detach: ptrace(PTRACE_DETACH, ...)");
1161 /* I died trying. */
1162 }
1163 break;
1164 }
1165 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001166 WSTOPSIG(status) == SIGTRAP ?
1167 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001168 if (errno != ESRCH)
1169 perror("detach: ptrace(PTRACE_CONT, ...)");
1170 break;
1171 }
1172 }
1173 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001174#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001175
1176#if defined(SUNOS4)
1177 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1178 if (sig && kill(tcp->pid, sig) < 0)
1179 perror("detach: kill");
1180 sig = 0;
1181 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1182 perror("detach: ptrace(PTRACE_DETACH, ...)");
1183#endif /* SUNOS4 */
1184
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001185#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001186 resumed = 0;
1187
1188 /* XXX This won't always be quite right (but it never was).
1189 A waiter with argument 0 or < -1 is waiting for any pid in
1190 a particular pgrp, which this child might or might not be
1191 in. The waiter will only wake up if it's argument is -1
1192 or if it's waiting for tcp->pid's pgrp. It makes a
1193 difference to wake up a waiter when there might be more
1194 traced children, because it could get a false ECHILD
1195 error. OTOH, if this was the last child in the pgrp, then
1196 it ought to wake up and get ECHILD. We would have to
1197 search the system for all pid's in the pgrp to be sure.
1198
1199 && (t->waitpid == -1 ||
1200 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1201 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1202 */
1203
1204 if (tcp->parent &&
1205 (tcp->parent->flags & TCB_SUSPENDED) &&
1206 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1207 error = resume(tcp->parent);
1208 ++resumed;
1209 }
1210#ifdef TCB_CLONE_THREAD
1211 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1212 /* Some other threads of our parent are waiting too. */
1213 unsigned int i;
1214
1215 /* Resume all the threads that were waiting for this PID. */
1216 for (i = 0; i < tcbtabsize; i++) {
1217 struct tcb *t = tcbtab[i];
1218 if (t->parent == tcp->parent && t != tcp
1219 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1220 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1221 && t->waitpid == tcp->pid) {
1222 error |= resume (t);
1223 ++resumed;
1224 }
1225 }
1226 if (resumed == 0)
1227 /* Noone was waiting for this PID in particular,
1228 so now we might need to resume some wildcarders. */
1229 for (i = 0; i < tcbtabsize; i++) {
1230 struct tcb *t = tcbtab[i];
1231 if (t->parent == tcp->parent && t != tcp
1232 && ((t->flags
1233 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1234 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1235 && t->waitpid <= 0
1236 ) {
1237 error |= resume (t);
1238 break;
1239 }
1240 }
1241 }
1242#endif
1243
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001244#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245
1246 if (!qflag)
1247 fprintf(stderr, "Process %u detached\n", tcp->pid);
1248
1249 droptcb(tcp);
1250 return error;
1251}
1252
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001253#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001254
1255static void
1256reaper(sig)
1257int sig;
1258{
1259 int pid;
1260 int status;
1261
1262 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1263#if 0
1264 struct tcb *tcp;
1265
1266 tcp = pid2tcb(pid);
1267 if (tcp)
1268 droptcb(tcp);
1269#endif
1270 }
1271}
1272
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001273#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001274
1275static void
1276cleanup()
1277{
1278 int i;
1279 struct tcb *tcp;
1280
Roland McGrathee9d4352002-12-18 04:16:10 +00001281 for (i = 0; i < tcbtabsize; i++) {
1282 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001283 if (!(tcp->flags & TCB_INUSE))
1284 continue;
1285 if (debug)
1286 fprintf(stderr,
1287 "cleanup: looking at pid %u\n", tcp->pid);
1288 if (tcp_last &&
1289 (!outfname || followfork < 2 || tcp_last == tcp)) {
1290 tprintf(" <unfinished ...>\n");
1291 tcp_last = NULL;
1292 }
1293 if (tcp->flags & TCB_ATTACHED)
1294 detach(tcp, 0);
1295 else {
1296 kill(tcp->pid, SIGCONT);
1297 kill(tcp->pid, SIGTERM);
1298 }
1299 }
1300 if (cflag)
1301 call_summary(outf);
1302}
1303
1304static void
1305interrupt(sig)
1306int sig;
1307{
1308 interrupted = 1;
1309}
1310
1311#ifndef HAVE_STRERROR
1312
Roland McGrath6d2b3492002-12-30 00:51:30 +00001313#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001314extern int sys_nerr;
1315extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001316#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001317
1318const char *
1319strerror(errno)
1320int errno;
1321{
1322 static char buf[64];
1323
1324 if (errno < 1 || errno >= sys_nerr) {
1325 sprintf(buf, "Unknown error %d", errno);
1326 return buf;
1327 }
1328 return sys_errlist[errno];
1329}
1330
1331#endif /* HAVE_STERRROR */
1332
1333#ifndef HAVE_STRSIGNAL
1334
Roland McGrath8f474e02003-01-14 07:53:33 +00001335#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001336extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001337#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001338#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1339extern char *_sys_siglist[];
1340#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001341
1342const char *
1343strsignal(sig)
1344int sig;
1345{
1346 static char buf[64];
1347
1348 if (sig < 1 || sig >= NSIG) {
1349 sprintf(buf, "Unknown signal %d", sig);
1350 return buf;
1351 }
1352#ifdef HAVE__SYS_SIGLIST
1353 return _sys_siglist[sig];
1354#else
1355 return sys_siglist[sig];
1356#endif
1357}
1358
1359#endif /* HAVE_STRSIGNAL */
1360
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001361#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001362
1363static void
1364rebuild_pollv()
1365{
1366 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001367
Roland McGrathee9d4352002-12-18 04:16:10 +00001368 if (pollv != NULL)
1369 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001370 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001371 if (pollv == NULL) {
1372 fprintf(stderr, "strace: out of memory for poll vector\n");
1373 exit(1);
1374 }
1375
Roland McGrathca16be82003-01-10 19:55:28 +00001376 for (i = j = 0; i < tcbtabsize; i++) {
1377 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001378 if (!(tcp->flags & TCB_INUSE))
1379 continue;
1380 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001381 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001382 j++;
1383 }
1384 if (j != nprocs) {
1385 fprintf(stderr, "strace: proc miscount\n");
1386 exit(1);
1387 }
1388}
1389
1390#ifndef HAVE_POLLABLE_PROCFS
1391
1392static void
1393proc_poll_open()
1394{
1395 int arg;
1396 int i;
1397
1398 if (pipe(proc_poll_pipe) < 0) {
1399 perror("pipe");
1400 exit(1);
1401 }
1402 for (i = 0; i < 2; i++) {
1403 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1404 perror("F_GETFD");
1405 exit(1);
1406 }
1407 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1408 perror("F_SETFD");
1409 exit(1);
1410 }
1411 }
1412}
1413
1414static int
1415proc_poll(pollv, nfds, timeout)
1416struct pollfd *pollv;
1417int nfds;
1418int timeout;
1419{
1420 int i;
1421 int n;
1422 struct proc_pollfd pollinfo;
1423
1424 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1425 return n;
1426 if (n != sizeof(struct proc_pollfd)) {
1427 fprintf(stderr, "panic: short read: %d\n", n);
1428 exit(1);
1429 }
1430 for (i = 0; i < nprocs; i++) {
1431 if (pollv[i].fd == pollinfo.fd)
1432 pollv[i].revents = pollinfo.revents;
1433 else
1434 pollv[i].revents = 0;
1435 }
1436 poller_pid = pollinfo.pid;
1437 return 1;
1438}
1439
1440static void
1441wakeup_handler(sig)
1442int sig;
1443{
1444}
1445
1446static void
1447proc_poller(pfd)
1448int pfd;
1449{
1450 struct proc_pollfd pollinfo;
1451 struct sigaction sa;
1452 sigset_t blocked_set, empty_set;
1453 int i;
1454 int n;
1455 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001456#ifdef FREEBSD
1457 struct procfs_status pfs;
1458#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001459
1460 switch (fork()) {
1461 case -1:
1462 perror("fork");
1463 _exit(0);
1464 case 0:
1465 break;
1466 default:
1467 return;
1468 }
1469
1470 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1471 sa.sa_flags = 0;
1472 sigemptyset(&sa.sa_mask);
1473 sigaction(SIGHUP, &sa, NULL);
1474 sigaction(SIGINT, &sa, NULL);
1475 sigaction(SIGQUIT, &sa, NULL);
1476 sigaction(SIGPIPE, &sa, NULL);
1477 sigaction(SIGTERM, &sa, NULL);
1478 sa.sa_handler = wakeup_handler;
1479 sigaction(SIGUSR1, &sa, NULL);
1480 sigemptyset(&blocked_set);
1481 sigaddset(&blocked_set, SIGUSR1);
1482 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1483 sigemptyset(&empty_set);
1484
1485 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1486 perror("getrlimit(RLIMIT_NOFILE, ...)");
1487 _exit(0);
1488 }
1489 n = rl.rlim_cur;
1490 for (i = 0; i < n; i++) {
1491 if (i != pfd && i != proc_poll_pipe[1])
1492 close(i);
1493 }
1494
1495 pollinfo.fd = pfd;
1496 pollinfo.pid = getpid();
1497 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001498#ifndef FREEBSD
1499 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1500#else /* FREEBSD */
1501 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1502#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001503 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001504 switch (errno) {
1505 case EINTR:
1506 continue;
1507 case EBADF:
1508 pollinfo.revents = POLLERR;
1509 break;
1510 case ENOENT:
1511 pollinfo.revents = POLLHUP;
1512 break;
1513 default:
1514 perror("proc_poller: PIOCWSTOP");
1515 }
1516 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1517 _exit(0);
1518 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001519 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001520 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1521 sigsuspend(&empty_set);
1522 }
1523}
1524
1525#endif /* !HAVE_POLLABLE_PROCFS */
1526
1527static int
1528choose_pfd()
1529{
1530 int i, j;
1531 struct tcb *tcp;
1532
1533 static int last;
1534
1535 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001536 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001537 /*
1538 * The previous process is ready to run again. We'll
1539 * let it do so if it is currently in a syscall. This
1540 * heuristic improves the readability of the trace.
1541 */
1542 tcp = pfd2tcb(pollv[last].fd);
1543 if (tcp && (tcp->flags & TCB_INSYSCALL))
1544 return pollv[last].fd;
1545 }
1546
1547 for (i = 0; i < nprocs; i++) {
1548 /* Let competing children run round robin. */
1549 j = (i + last + 1) % nprocs;
1550 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1551 tcp = pfd2tcb(pollv[j].fd);
1552 if (!tcp) {
1553 fprintf(stderr, "strace: lost proc\n");
1554 exit(1);
1555 }
1556 droptcb(tcp);
1557 return -1;
1558 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001559 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001560 last = j;
1561 return pollv[j].fd;
1562 }
1563 }
1564 fprintf(stderr, "strace: nothing ready\n");
1565 exit(1);
1566}
1567
1568static int
1569trace()
1570{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001571#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001572 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001573#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001574 struct tcb *tcp;
1575 int pfd;
1576 int what;
1577 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001578 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001579
1580 for (;;) {
1581 if (interactive)
1582 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1583
1584 if (nprocs == 0)
1585 break;
1586
1587 switch (nprocs) {
1588 case 1:
1589#ifndef HAVE_POLLABLE_PROCFS
1590 if (proc_poll_pipe[0] == -1) {
1591#endif
1592 tcp = pid2tcb(0);
1593 if (!tcp)
1594 continue;
1595 pfd = tcp->pfd;
1596 if (pfd == -1)
1597 continue;
1598 break;
1599#ifndef HAVE_POLLABLE_PROCFS
1600 }
1601 /* fall through ... */
1602#endif /* !HAVE_POLLABLE_PROCFS */
1603 default:
1604#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001605#ifdef POLL_HACK
1606 /* On some systems (e.g. UnixWare) we get too much ugly
1607 "unfinished..." stuff when multiple proceses are in
1608 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001609
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001610 if (in_syscall) {
1611 struct pollfd pv;
1612 tcp = in_syscall;
1613 in_syscall = NULL;
1614 pv.fd = tcp->pfd;
1615 pv.events = POLLWANT;
1616 if ((what = poll (&pv, 1, 1)) < 0) {
1617 if (interrupted)
1618 return 0;
1619 continue;
1620 }
1621 else if (what == 1 && pv.revents & POLLWANT) {
1622 goto FOUND;
1623 }
1624 }
1625#endif
1626
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001627 if (poll(pollv, nprocs, INFTIM) < 0) {
1628 if (interrupted)
1629 return 0;
1630 continue;
1631 }
1632#else /* !HAVE_POLLABLE_PROCFS */
1633 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1634 if (interrupted)
1635 return 0;
1636 continue;
1637 }
1638#endif /* !HAVE_POLLABLE_PROCFS */
1639 pfd = choose_pfd();
1640 if (pfd == -1)
1641 continue;
1642 break;
1643 }
1644
1645 /* Look up `pfd' in our table. */
1646 if ((tcp = pfd2tcb(pfd)) == NULL) {
1647 fprintf(stderr, "unknown pfd: %u\n", pfd);
1648 exit(1);
1649 }
John Hughesb6643082002-05-23 11:02:22 +00001650#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001651 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001652#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653 /* Get the status of the process. */
1654 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001655#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001656 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001657#else /* FREEBSD */
1658 /* Thanks to some scheduling mystery, the first poller
1659 sometimes waits for the already processed end of fork
1660 event. Doing a non blocking poll here solves the problem. */
1661 if (proc_poll_pipe[0] != -1)
1662 ioctl_result = IOCTL_STATUS (tcp);
1663 else
1664 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001665#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666 ioctl_errno = errno;
1667#ifndef HAVE_POLLABLE_PROCFS
1668 if (proc_poll_pipe[0] != -1) {
1669 if (ioctl_result < 0)
1670 kill(poller_pid, SIGKILL);
1671 else
1672 kill(poller_pid, SIGUSR1);
1673 }
1674#endif /* !HAVE_POLLABLE_PROCFS */
1675 }
1676 if (interrupted)
1677 return 0;
1678
1679 if (interactive)
1680 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1681
1682 if (ioctl_result < 0) {
1683 /* Find out what happened if it failed. */
1684 switch (ioctl_errno) {
1685 case EINTR:
1686 case EBADF:
1687 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001688#ifdef FREEBSD
1689 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001690#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001691 case ENOENT:
1692 droptcb(tcp);
1693 continue;
1694 default:
1695 perror("PIOCWSTOP");
1696 exit(1);
1697 }
1698 }
1699
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001700#ifdef FREEBSD
1701 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1702 /* discard first event for a syscall we never entered */
1703 IOCTL (tcp->pfd, PIOCRUN, 0);
1704 continue;
1705 }
Roland McGrath553a6092002-12-16 20:40:39 +00001706#endif
1707
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001708 /* clear the just started flag */
1709 tcp->flags &= ~TCB_STARTUP;
1710
1711 /* set current output file */
1712 outf = tcp->outf;
1713
1714 if (cflag) {
1715 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001716#ifdef FREEBSD
1717 char buf[1024];
1718 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001719
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001720 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1721 buf[len] = '\0';
1722 sscanf(buf,
1723 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1724 &stime.tv_sec, &stime.tv_usec);
1725 } else
1726 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001727#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1729 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001730#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001731 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1732 tcp->stime = stime;
1733 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001734 what = tcp->status.PR_WHAT;
1735 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001736#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001737 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001738 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1739 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001740 if (trace_syscall(tcp) < 0) {
1741 fprintf(stderr, "syscall trouble\n");
1742 exit(1);
1743 }
1744 }
1745 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001746#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001747 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001748#ifdef POLL_HACK
1749 in_syscall = tcp;
1750#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001751 case PR_SYSEXIT:
1752 if (trace_syscall(tcp) < 0) {
1753 fprintf(stderr, "syscall trouble\n");
1754 exit(1);
1755 }
1756 break;
1757 case PR_SIGNALLED:
1758 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1759 printleader(tcp);
1760 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001761 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001762 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001763#ifdef PR_INFO
1764 if (tcp->status.PR_INFO.si_signo == what) {
1765 printleader(tcp);
1766 tprintf(" siginfo=");
1767 printsiginfo(&tcp->status.PR_INFO, 1);
1768 printtrailer(tcp);
1769 }
1770#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001771 }
1772 break;
1773 case PR_FAULTED:
1774 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1775 printleader(tcp);
1776 tprintf("=== FAULT %d ===", what);
1777 printtrailer(tcp);
1778 }
1779 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001780#ifdef FREEBSD
1781 case 0: /* handle case we polled for nothing */
1782 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001783#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001784 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001785 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001786 exit(1);
1787 break;
1788 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001789 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001790#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001791 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001792#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001793 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001794#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001795 perror("PIOCRUN");
1796 exit(1);
1797 }
1798 }
1799 return 0;
1800}
1801
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001802#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001803
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001804#ifdef TCB_GROUP_EXITING
1805/* Handle an exit detach or death signal that is taking all the
1806 related clone threads with it. This is called in three circumstances:
1807 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1808 SIG == 0 Continuing TCP will perform an exit_group syscall.
1809 SIG == other Continuing TCP with SIG will kill the process.
1810*/
1811static int
1812handle_group_exit(struct tcb *tcp, int sig)
1813{
1814 /* We need to locate our records of all the clone threads
1815 related to TCP, either its children or siblings. */
1816 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1817 ? tcp->parent
1818 : tcp->nclone_detached > 0
1819 ? tcp : NULL);
1820
1821 if (sig < 0) {
1822 if (leader != NULL && leader != tcp)
1823 fprintf(stderr,
1824 "PANIC: handle_group_exit: %d leader %d\n",
1825 tcp->pid, leader ? leader->pid : -1);
1826 droptcb(tcp); /* Already died. */
1827 }
1828 else {
1829 if (tcp->flags & TCB_ATTACHED) {
1830 if (leader != NULL && leader != tcp) {
1831 /* We need to detach the leader so that the
1832 process death will be reported to its real
1833 parent. But we kill it first to prevent
1834 it doing anything before we kill the whole
1835 process in a moment. We can use
1836 PTRACE_KILL on a thread that's not already
1837 stopped. Then the value we pass in
1838 PTRACE_DETACH just sets the death
1839 signal reported to the real parent. */
1840 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1841 if (debug)
1842 fprintf(stderr,
1843 " [%d exit %d kills %d]\n",
1844 tcp->pid, sig, leader->pid);
1845 detach(leader, sig);
1846 }
1847 detach(tcp, sig);
1848 }
1849 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1850 perror("strace: ptrace(PTRACE_CONT, ...)");
1851 cleanup();
1852 return -1;
1853 }
1854 else {
1855 if (leader != NULL && leader != tcp)
1856 droptcb(tcp);
1857 /* The leader will report to us as parent now,
1858 and then we'll get to the SIG==-1 case. */
1859 return 0;
1860 }
1861 }
1862
1863 /* Note that TCP and LEADER are no longer valid,
1864 but we can still compare against them. */
1865 if (leader != NULL) {
1866 unsigned int i;
1867 for (i = 0; i < tcbtabsize; i++) {
1868 struct tcb *t = tcbtab[i];
1869 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1870 && t->parent == leader)
1871 droptcb(t);
1872 }
1873 }
1874
1875 return 0;
1876}
1877#endif
1878
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001879static int
1880trace()
1881{
1882 int pid;
1883 int wait_errno;
1884 int status;
1885 struct tcb *tcp;
1886#ifdef LINUX
1887 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001888#ifdef __WALL
1889 static int wait4_options = __WALL;
1890#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001891#endif /* LINUX */
1892
1893 while (nprocs != 0) {
1894 if (interactive)
1895 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1896#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001897#ifdef __WALL
1898 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00001899 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001900 /* this kernel does not support __WALL */
1901 wait4_options &= ~__WALL;
1902 errno = 0;
1903 pid = wait4(-1, &status, wait4_options,
1904 cflag ? &ru : NULL);
1905 }
Roland McGrath5bc05552002-12-17 04:50:47 +00001906 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001907 /* most likely a "cloned" process */
1908 pid = wait4(-1, &status, __WCLONE,
1909 cflag ? &ru : NULL);
1910 if (pid == -1) {
1911 fprintf(stderr, "strace: clone wait4 "
1912 "failed: %s\n", strerror(errno));
1913 }
1914 }
1915#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001916 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001917#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001918#endif /* LINUX */
1919#ifdef SUNOS4
1920 pid = wait(&status);
1921#endif /* SUNOS4 */
1922 wait_errno = errno;
1923 if (interactive)
1924 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1925
1926 if (interrupted)
1927 return 0;
1928
1929 if (pid == -1) {
1930 switch (wait_errno) {
1931 case EINTR:
1932 continue;
1933 case ECHILD:
1934 /*
1935 * We would like to verify this case
1936 * but sometimes a race in Solbourne's
1937 * version of SunOS sometimes reports
1938 * ECHILD before sending us SIGCHILD.
1939 */
1940#if 0
1941 if (nprocs == 0)
1942 return 0;
1943 fprintf(stderr, "strace: proc miscount\n");
1944 exit(1);
1945#endif
1946 return 0;
1947 default:
1948 errno = wait_errno;
1949 perror("strace: wait");
1950 return -1;
1951 }
1952 }
1953 if (debug)
1954 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1955
1956 /* Look up `pid' in our table. */
1957 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001958#ifdef LINUX
1959 if (followfork || followvfork) {
1960 /* This is needed to go with the CLONE_PTRACE
1961 changes in process.c/util.c: we might see
1962 the child's initial trap before we see the
1963 parent return from the clone syscall.
1964 Leave the child suspended until the parent
1965 returns from its system call. Only then
1966 will we have the association of parent and
1967 child so that we know how to do clearbpt
1968 in the child. */
1969 if ((tcp = alloctcb(pid)) == NULL) {
1970 fprintf(stderr, " [tcb table full]\n");
1971 kill(pid, SIGKILL); /* XXX */
1972 return 0;
1973 }
1974 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
1975 newoutf(tcp);
1976 if (!qflag)
1977 fprintf(stderr, "\
1978Process %d attached (waiting for parent)\n",
1979 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001980 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001981 else
1982 /* This can happen if a clone call used
1983 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001984#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001985 {
1986 fprintf(stderr, "unknown pid: %u\n", pid);
1987 if (WIFSTOPPED(status))
1988 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1989 exit(1);
1990 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001991 }
1992 /* set current output file */
1993 outf = tcp->outf;
1994 if (cflag) {
1995#ifdef LINUX
1996 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
1997 tcp->stime = ru.ru_stime;
1998#endif /* !LINUX */
1999 }
2000
2001 if (tcp->flags & TCB_SUSPENDED) {
2002 /*
2003 * Apparently, doing any ptrace() call on a stopped
2004 * process, provokes the kernel to report the process
2005 * status again on a subsequent wait(), even if the
2006 * process has not been actually restarted.
2007 * Since we have inspected the arguments of suspended
2008 * processes we end up here testing for this case.
2009 */
2010 continue;
2011 }
2012 if (WIFSIGNALED(status)) {
2013 if (!cflag
2014 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2015 printleader(tcp);
2016 tprintf("+++ killed by %s +++",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002017 signame(WTERMSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002018 printtrailer(tcp);
2019 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002020#ifdef TCB_GROUP_EXITING
2021 handle_group_exit(tcp, -1);
2022#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002023 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002024#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002025 continue;
2026 }
2027 if (WIFEXITED(status)) {
2028 if (debug)
2029 fprintf(stderr, "pid %u exited\n", pid);
2030 if (tcp->flags & TCB_ATTACHED)
2031 fprintf(stderr,
2032 "PANIC: attached pid %u exited\n",
2033 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002034 if (tcp == tcp_last) {
2035 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2036 == TCB_INSYSCALL)
2037 tprintf(" <unfinished ... exit status %d>\n",
2038 WEXITSTATUS(status));
2039 tcp_last = NULL;
2040 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002041#ifdef TCB_GROUP_EXITING
2042 handle_group_exit(tcp, -1);
2043#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002044 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002045#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002046 continue;
2047 }
2048 if (!WIFSTOPPED(status)) {
2049 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2050 droptcb(tcp);
2051 continue;
2052 }
2053 if (debug)
2054 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002055 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002056
2057 if (tcp->flags & TCB_STARTUP) {
2058 /*
2059 * This flag is there to keep us in sync.
2060 * Next time this process stops it should
2061 * really be entering a system call.
2062 */
2063 tcp->flags &= ~TCB_STARTUP;
2064 if (tcp->flags & TCB_ATTACHED) {
2065 /*
2066 * Interestingly, the process may stop
2067 * with STOPSIG equal to some other signal
2068 * than SIGSTOP if we happend to attach
2069 * just before the process takes a signal.
2070 */
2071 if (!WIFSTOPPED(status)) {
2072 fprintf(stderr,
2073 "pid %u not stopped\n", pid);
2074 detach(tcp, WSTOPSIG(status));
2075 continue;
2076 }
2077 }
2078 else {
2079#ifdef SUNOS4
2080 /* A child of us stopped at exec */
2081 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2082 fixvfork(tcp);
2083#endif /* SUNOS4 */
2084 }
2085 if (tcp->flags & TCB_BPTSET) {
2086 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2087 droptcb(tcp);
2088 cleanup();
2089 return -1;
2090 }
2091 }
2092 goto tracing;
2093 }
2094
2095 if (WSTOPSIG(status) != SIGTRAP) {
2096 if (WSTOPSIG(status) == SIGSTOP &&
2097 (tcp->flags & TCB_SIGTRAPPED)) {
2098 /*
2099 * Trapped attempt to block SIGTRAP
2100 * Hope we are back in control now.
2101 */
2102 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2103 if (ptrace(PTRACE_SYSCALL,
2104 pid, (char *) 1, 0) < 0) {
2105 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2106 cleanup();
2107 return -1;
2108 }
2109 continue;
2110 }
2111 if (!cflag
2112 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002113 unsigned long addr = 0, pc = 0;
2114#ifdef PT_GETSIGINFO
2115# define PSR_RI 41
2116 struct siginfo si;
2117 unsigned long psr;
2118
2119 upeek(pid, PT_CR_IPSR, &psr);
2120 upeek(pid, PT_CR_IIP, &pc);
2121
2122 pc += (psr >> PSR_RI) & 0x3;
2123 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2124 addr = (unsigned long) si.si_addr;
2125#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002126 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002127 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002128 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002129 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002130 printtrailer(tcp);
2131 }
2132 if ((tcp->flags & TCB_ATTACHED) &&
2133 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002134#ifdef TCB_GROUP_EXITING
2135 handle_group_exit(tcp, WSTOPSIG(status));
2136#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002137 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002138#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002139 continue;
2140 }
2141 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2142 WSTOPSIG(status)) < 0) {
2143 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2144 cleanup();
2145 return -1;
2146 }
2147 tcp->flags &= ~TCB_SUSPENDED;
2148 continue;
2149 }
2150 if (trace_syscall(tcp) < 0) {
2151 if (tcp->flags & TCB_ATTACHED)
2152 detach(tcp, 0);
2153 else {
2154 ptrace(PTRACE_KILL,
2155 tcp->pid, (char *) 1, SIGTERM);
2156 droptcb(tcp);
2157 }
2158 continue;
2159 }
2160 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002161#ifdef TCB_GROUP_EXITING
2162 if (tcp->flags & TCB_GROUP_EXITING) {
2163 if (handle_group_exit(tcp, 0) < 0)
2164 return -1;
2165 continue;
2166 }
2167#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002168 if (tcp->flags & TCB_ATTACHED)
2169 detach(tcp, 0);
2170 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2171 perror("strace: ptrace(PTRACE_CONT, ...)");
2172 cleanup();
2173 return -1;
2174 }
2175 continue;
2176 }
2177 if (tcp->flags & TCB_SUSPENDED) {
2178 if (!qflag)
2179 fprintf(stderr, "Process %u suspended\n", pid);
2180 continue;
2181 }
2182 tracing:
2183 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2184 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2185 cleanup();
2186 return -1;
2187 }
2188 }
2189 return 0;
2190}
2191
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002192#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002193
2194static int curcol;
2195
2196#ifdef __STDC__
2197#include <stdarg.h>
2198#define VA_START(a, b) va_start(a, b)
2199#else
2200#include <varargs.h>
2201#define VA_START(a, b) va_start(a)
2202#endif
2203
2204void
2205#ifdef __STDC__
2206tprintf(const char *fmt, ...)
2207#else
2208tprintf(fmt, va_alist)
2209char *fmt;
2210va_dcl
2211#endif
2212{
2213 va_list args;
2214
2215 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002216 if (outf) {
2217 int n = vfprintf(outf, fmt, args);
2218 if (n < 0 && outf != stderr)
2219 perror(outfname == NULL
2220 ? "<writing to pipe>" : outfname);
2221 else
2222 curcol += n;
2223 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002224 va_end(args);
2225 return;
2226}
2227
2228void
2229printleader(tcp)
2230struct tcb *tcp;
2231{
2232 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2233 tcp_last->flags |= TCB_REPRINT;
2234 tprintf(" <unfinished ...>\n");
2235 }
2236 curcol = 0;
2237 if ((followfork == 1 || pflag_seen > 1) && outfname)
2238 tprintf("%-5d ", tcp->pid);
2239 else if (nprocs > 1 && !outfname)
2240 tprintf("[pid %5u] ", tcp->pid);
2241 if (tflag) {
2242 char str[sizeof("HH:MM:SS")];
2243 struct timeval tv, dtv;
2244 static struct timeval otv;
2245
2246 gettimeofday(&tv, NULL);
2247 if (rflag) {
2248 if (otv.tv_sec == 0)
2249 otv = tv;
2250 tv_sub(&dtv, &tv, &otv);
2251 tprintf("%6ld.%06ld ",
2252 (long) dtv.tv_sec, (long) dtv.tv_usec);
2253 otv = tv;
2254 }
2255 else if (tflag > 2) {
2256 tprintf("%ld.%06ld ",
2257 (long) tv.tv_sec, (long) tv.tv_usec);
2258 }
2259 else {
2260 time_t local = tv.tv_sec;
2261 strftime(str, sizeof(str), "%T", localtime(&local));
2262 if (tflag > 1)
2263 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2264 else
2265 tprintf("%s ", str);
2266 }
2267 }
2268 if (iflag)
2269 printcall(tcp);
2270}
2271
2272void
2273tabto(col)
2274int col;
2275{
2276 if (curcol < col)
2277 tprintf("%*s", col - curcol, "");
2278}
2279
2280void
2281printtrailer(tcp)
2282struct tcb *tcp;
2283{
2284 tprintf("\n");
2285 tcp_last = NULL;
2286}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002287
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002288#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002289
2290int mp_ioctl (int fd, int cmd, void *arg, int size) {
2291
2292 struct iovec iov[2];
2293 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002294
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002295 iov[0].iov_base = &cmd;
2296 iov[0].iov_len = sizeof cmd;
2297 if (arg) {
2298 ++n;
2299 iov[1].iov_base = arg;
2300 iov[1].iov_len = size;
2301 }
Roland McGrath553a6092002-12-16 20:40:39 +00002302
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002303 return writev (fd, iov, n);
2304}
2305
2306#endif