blob: 8f70d34b15afa68dd91ada3425185f1a2f9c2830 [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) {
371 qflag = 1;
372 setvbuf(outf, buf, _IOLBF, BUFSIZ);
373 }
374 else if (optind < argc)
375 interactive = 0;
376 else
377 qflag = 1;
378
Roland McGrathee9d4352002-12-18 04:16:10 +0000379 for (c = 0; c < tcbtabsize; c++) {
380 tcp = tcbtab[c];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000381 /* Reinitialize the output since it may have changed. */
382 tcp->outf = outf;
383 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
384 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000385#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000386 if (proc_open(tcp, 1) < 0) {
387 fprintf(stderr, "trouble opening proc file\n");
388 droptcb(tcp);
389 continue;
390 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000391#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000392 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
393 perror("attach: ptrace(PTRACE_ATTACH, ...)");
394 droptcb(tcp);
395 continue;
396 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000397#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000398 if (!qflag)
399 fprintf(stderr,
400 "Process %u attached - interrupt to quit\n",
401 pid);
402 }
403
404 if (optind < argc) {
405 struct stat statbuf;
406 char *filename;
407 char pathname[MAXPATHLEN];
408
409 filename = argv[optind];
410 if (strchr(filename, '/'))
411 strcpy(pathname, filename);
412#ifdef USE_DEBUGGING_EXEC
413 /*
414 * Debuggers customarily check the current directory
415 * first regardless of the path but doing that gives
416 * security geeks a panic attack.
417 */
418 else if (stat(filename, &statbuf) == 0)
419 strcpy(pathname, filename);
420#endif /* USE_DEBUGGING_EXEC */
421 else {
422 char *path;
423 int m, n, len;
424
425 for (path = getenv("PATH"); path && *path; path += m) {
426 if (strchr(path, ':')) {
427 n = strchr(path, ':') - path;
428 m = n + 1;
429 }
430 else
431 m = n = strlen(path);
432 if (n == 0) {
433 getcwd(pathname, MAXPATHLEN);
434 len = strlen(pathname);
435 }
436 else {
437 strncpy(pathname, path, n);
438 len = n;
439 }
440 if (len && pathname[len - 1] != '/')
441 pathname[len++] = '/';
442 strcpy(pathname + len, filename);
443 if (stat(pathname, &statbuf) == 0)
444 break;
445 }
446 }
447 if (stat(pathname, &statbuf) < 0) {
448 fprintf(stderr, "%s: %s: command not found\n",
449 progname, filename);
450 exit(1);
451 }
452 switch (pid = fork()) {
453 case -1:
454 perror("strace: fork");
455 cleanup();
456 exit(1);
457 break;
458 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000459#ifdef USE_PROCFS
460 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000461#ifdef MIPS
462 /* Kludge for SGI, see proc_open for details. */
463 sa.sa_handler = foobar;
464 sa.sa_flags = 0;
465 sigemptyset(&sa.sa_mask);
466 sigaction(SIGINT, &sa, NULL);
467#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000468#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000469 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000470#else /* FREEBSD */
471 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000472#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000473#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000474 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000475 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000476
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000477 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
478 perror("strace: ptrace(PTRACE_TRACEME, ...)");
479 return -1;
480 }
481 if (debug)
482 kill(getpid(), SIGSTOP);
483
484 if (username != NULL || geteuid() == 0) {
485 uid_t run_euid = run_uid;
486 gid_t run_egid = run_gid;
487
488 if (statbuf.st_mode & S_ISUID)
489 run_euid = statbuf.st_uid;
490 if (statbuf.st_mode & S_ISGID)
491 run_egid = statbuf.st_gid;
492
493 /*
494 * It is important to set groups before we
495 * lose privileges on setuid.
496 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000497 if (username != NULL) {
498 if (initgroups(username, run_gid) < 0) {
499 perror("initgroups");
500 exit(1);
501 }
502 if (setregid(run_gid, run_egid) < 0) {
503 perror("setregid");
504 exit(1);
505 }
506 if (setreuid(run_uid, run_euid) < 0) {
507 perror("setreuid");
508 exit(1);
509 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000510 }
511 }
512 else
513 setreuid(run_uid, run_uid);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000514#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000515
516 execv(pathname, &argv[optind]);
517 perror("strace: exec");
518 _exit(1);
519 break;
520 }
521 default:
522 if ((tcp = alloctcb(pid)) == NULL) {
523 fprintf(stderr, "tcb table full\n");
524 cleanup();
525 exit(1);
526 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000527#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000528 if (proc_open(tcp, 0) < 0) {
529 fprintf(stderr, "trouble opening proc file\n");
530 cleanup();
531 exit(1);
532 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000533#endif /* USE_PROCFS */
534#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000535 fake_execve(tcp, pathname, &argv[optind], environ);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000536#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000537 break;
538 }
539 }
540 else if (pflag_seen == 0)
541 usage(stderr, 1);
542
543 sigemptyset(&empty_set);
544 sigemptyset(&blocked_set);
545 sa.sa_handler = SIG_IGN;
546 sigemptyset(&sa.sa_mask);
547 sa.sa_flags = 0;
548 sigaction(SIGTTOU, &sa, NULL);
549 sigaction(SIGTTIN, &sa, NULL);
550 if (interactive) {
551 sigaddset(&blocked_set, SIGHUP);
552 sigaddset(&blocked_set, SIGINT);
553 sigaddset(&blocked_set, SIGQUIT);
554 sigaddset(&blocked_set, SIGPIPE);
555 sigaddset(&blocked_set, SIGTERM);
556 sa.sa_handler = interrupt;
557#ifdef SUNOS4
558 /* POSIX signals on sunos4.1 are a little broken. */
559 sa.sa_flags = SA_INTERRUPT;
560#endif /* SUNOS4 */
561 }
562 sigaction(SIGHUP, &sa, NULL);
563 sigaction(SIGINT, &sa, NULL);
564 sigaction(SIGQUIT, &sa, NULL);
565 sigaction(SIGPIPE, &sa, NULL);
566 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000567#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000568 sa.sa_handler = reaper;
569 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000570#else
571 /* Make sure SIGCHLD has the default action so that waitpid
572 definitely works without losing track of children. The user
573 should not have given us a bogus state to inherit, but he might
574 have. Arguably we should detect SIG_IGN here and pass it on
575 to children, but probably noone really needs that. */
576 sa.sa_handler = SIG_DFL;
577 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000578#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000579
580 if (trace() < 0)
581 exit(1);
582 cleanup();
583 exit(0);
584}
585
586void
587newoutf(tcp)
588struct tcb *tcp;
589{
590 char name[MAXPATHLEN];
591 FILE *fp;
592
593 if (outfname && followfork > 1) {
594 sprintf(name, "%s.%u", outfname, tcp->pid);
595#ifndef SVR4
596 setreuid(geteuid(), getuid());
597#endif
598 fp = fopen(name, "w");
599#ifndef SVR4
600 setreuid(geteuid(), getuid());
601#endif
602 if (fp == NULL) {
603 perror("fopen");
604 return;
605 }
606 tcp->outf = fp;
607 }
608 return;
609}
610
611struct tcb *
612alloctcb(pid)
613int pid;
614{
615 int i;
616 struct tcb *tcp;
617
Roland McGrathee9d4352002-12-18 04:16:10 +0000618 for (i = 0; i < tcbtabsize; i++) {
619 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000620 if ((tcp->flags & TCB_INUSE) == 0) {
621 tcp->pid = pid;
622 tcp->parent = NULL;
623 tcp->nchildren = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000624#ifdef TCB_CLONE_THREAD
625 tcp->nclone_threads = tcp->nclone_detached = 0;
626 tcp->nclone_waiting = 0;
627#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000628 tcp->flags = TCB_INUSE | TCB_STARTUP;
629 tcp->outf = outf; /* Initialise to current out file */
630 tcp->stime.tv_sec = 0;
631 tcp->stime.tv_usec = 0;
632 tcp->pfd = -1;
633 nprocs++;
634 return tcp;
635 }
636 }
637 return NULL;
638}
639
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000640#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641int
642proc_open(tcp, attaching)
643struct tcb *tcp;
644int attaching;
645{
646 char proc[32];
647 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000648#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000649 int i;
650 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000651 sigset_t signals;
652 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000653#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000654#ifndef HAVE_POLLABLE_PROCFS
655 static int last_pfd;
656#endif
657
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000658#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000659 /* Open the process pseudo-files in /proc. */
660 sprintf(proc, "/proc/%d/ctl", tcp->pid);
661 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000662 perror("strace: open(\"/proc/...\", ...)");
663 return -1;
664 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000665 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
666 perror("F_GETFD");
667 return -1;
668 }
669 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
670 perror("F_SETFD");
671 return -1;
672 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000673 sprintf(proc, "/proc/%d/status", tcp->pid);
674 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
675 perror("strace: open(\"/proc/...\", ...)");
676 return -1;
677 }
678 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
679 perror("F_GETFD");
680 return -1;
681 }
682 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
683 perror("F_SETFD");
684 return -1;
685 }
686 sprintf(proc, "/proc/%d/as", tcp->pid);
687 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
688 perror("strace: open(\"/proc/...\", ...)");
689 return -1;
690 }
691 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
692 perror("F_GETFD");
693 return -1;
694 }
695 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
696 perror("F_SETFD");
697 return -1;
698 }
699#else
700 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000701#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000702 sprintf(proc, "/proc/%d", tcp->pid);
703 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000704#else /* FREEBSD */
705 sprintf(proc, "/proc/%d/mem", tcp->pid);
706 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
707#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000708 perror("strace: open(\"/proc/...\", ...)");
709 return -1;
710 }
711 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
712 perror("F_GETFD");
713 return -1;
714 }
715 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
716 perror("F_SETFD");
717 return -1;
718 }
719#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000720#ifdef FREEBSD
721 sprintf(proc, "/proc/%d/regs", tcp->pid);
722 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
723 perror("strace: open(\"/proc/.../regs\", ...)");
724 return -1;
725 }
726 if (cflag) {
727 sprintf(proc, "/proc/%d/status", tcp->pid);
728 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
729 perror("strace: open(\"/proc/.../status\", ...)");
730 return -1;
731 }
732 } else
733 tcp->pfd_status = -1;
734#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000735 rebuild_pollv();
736 if (!attaching) {
737 /*
738 * Wait for the child to pause. Because of a race
739 * condition we have to poll for the event.
740 */
741 for (;;) {
742 if (IOCTL_STATUS (tcp) < 0) {
743 perror("strace: PIOCSTATUS");
744 return -1;
745 }
746 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000747 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000748 }
749 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000750#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000751 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000752 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000753 perror("strace: PIOCSTOP");
754 return -1;
755 }
Roland McGrath553a6092002-12-16 20:40:39 +0000756#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757#ifdef PIOCSET
758 /* Set Run-on-Last-Close. */
759 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000760 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000761 perror("PIOCSET PR_RLC");
762 return -1;
763 }
764 /* Set or Reset Inherit-on-Fork. */
765 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000766 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000767 perror("PIOC{SET,RESET} PR_FORK");
768 return -1;
769 }
770#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000771#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000772 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
773 perror("PIOCSRLC");
774 return -1;
775 }
776 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
777 perror("PIOC{S,R}FORK");
778 return -1;
779 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000780#else /* FREEBSD */
781 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
782 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
783 perror("PIOCGFL");
784 return -1;
785 }
786 arg &= ~PF_LINGER;
787 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
788 perror("PIOCSFL");
789 return -1;
790 }
791#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000792#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000793#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000794 /* Enable all syscall entries we care about. */
795 premptyset(&syscalls);
796 for (i = 1; i < MAX_QUALS; ++i) {
797 if (i > (sizeof syscalls) * CHAR_BIT) break;
798 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
799 }
800 praddset (&syscalls, SYS_execve);
801 if (followfork) {
802 praddset (&syscalls, SYS_fork);
803#ifdef SYS_forkall
804 praddset (&syscalls, SYS_forkall);
805#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000806#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000807 praddset (&syscalls, SYS_fork1);
808#endif
809#ifdef SYS_rfork1
810 praddset (&syscalls, SYS_rfork1);
811#endif
812#ifdef SYS_rforkall
813 praddset (&syscalls, SYS_rforkall);
814#endif
815 }
816 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000817 perror("PIOCSENTRY");
818 return -1;
819 }
John Hughes19e49982001-10-19 08:59:12 +0000820 /* Enable the syscall exits. */
821 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000822 perror("PIOSEXIT");
823 return -1;
824 }
John Hughes19e49982001-10-19 08:59:12 +0000825 /* Enable signals we care about. */
826 premptyset(&signals);
827 for (i = 1; i < MAX_QUALS; ++i) {
828 if (i > (sizeof signals) * CHAR_BIT) break;
829 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
830 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000831 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000832 perror("PIOCSTRACE");
833 return -1;
834 }
John Hughes19e49982001-10-19 08:59:12 +0000835 /* Enable faults we care about */
836 premptyset(&faults);
837 for (i = 1; i < MAX_QUALS; ++i) {
838 if (i > (sizeof faults) * CHAR_BIT) break;
839 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
840 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000841 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000842 perror("PIOCSFAULT");
843 return -1;
844 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000845#else /* FREEBSD */
846 /* set events flags. */
847 arg = S_SIG | S_SCE | S_SCX ;
848 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
849 perror("PIOCBIS");
850 return -1;
851 }
852#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000853 if (!attaching) {
854#ifdef MIPS
855 /*
856 * The SGI PRSABORT doesn't work for pause() so
857 * we send it a caught signal to wake it up.
858 */
859 kill(tcp->pid, SIGINT);
860#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000861#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000862 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000863 arg = PRSABORT;
864 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000865 perror("PIOCRUN");
866 return -1;
867 }
Roland McGrath553a6092002-12-16 20:40:39 +0000868#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000869#endif /* !MIPS*/
870#ifdef FREEBSD
871 /* wake up the child if it received the SIGSTOP */
872 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000873#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000874 for (;;) {
875 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000876 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000877 perror("PIOCWSTOP");
878 return -1;
879 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000880 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000881 tcp->flags &= ~TCB_INSYSCALL;
882 get_scno(tcp);
883 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000884 break;
885 }
886 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000887#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000888 arg = 0;
889 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000890#else /* FREEBSD */
891 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +0000892#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000893 perror("PIOCRUN");
894 return -1;
895 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000896#ifdef FREEBSD
897 /* handle the case where we "opened" the child before
898 it did the kill -STOP */
899 if (tcp->status.PR_WHY == PR_SIGNALLED &&
900 tcp->status.PR_WHAT == SIGSTOP)
901 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000902#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000903 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000904#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000905 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000906#else /* FREEBSD */
907 } else {
Roland McGrath553a6092002-12-16 20:40:39 +0000908 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000909 /* We are attaching to an already running process.
910 * Try to figure out the state of the process in syscalls,
911 * to handle the first event well.
912 * This is done by having a look at the "wchan" property of the
913 * process, which tells where it is stopped (if it is). */
914 FILE * status;
915 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +0000916
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000917 sprintf(proc, "/proc/%d/status", tcp->pid);
918 status = fopen(proc, "r");
919 if (status &&
920 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
921 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
922 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
923 strcmp(wchan, "stopevent")) {
924 /* The process is asleep in the middle of a syscall.
925 Fake the syscall entry event */
926 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
927 tcp->status.PR_WHY = PR_SYSENTRY;
928 trace_syscall(tcp);
929 }
930 if (status)
931 fclose(status);
932 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000933 }
934#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000935#ifndef HAVE_POLLABLE_PROCFS
936 if (proc_poll_pipe[0] != -1)
937 proc_poller(tcp->pfd);
938 else if (nprocs > 1) {
939 proc_poll_open();
940 proc_poller(last_pfd);
941 proc_poller(tcp->pfd);
942 }
943 last_pfd = tcp->pfd;
944#endif /* !HAVE_POLLABLE_PROCFS */
945 return 0;
946}
947
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000948#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000949
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000950struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000951pid2tcb(pid)
952int pid;
953{
954 int i;
955 struct tcb *tcp;
956
Roland McGrathee9d4352002-12-18 04:16:10 +0000957 for (i = 0; i < tcbtabsize; i++) {
958 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000959 if (pid && tcp->pid != pid)
960 continue;
961 if (tcp->flags & TCB_INUSE)
962 return tcp;
963 }
964 return NULL;
965}
966
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000967#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000968
969static struct tcb *
970pfd2tcb(pfd)
971int pfd;
972{
973 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974
Roland McGrathca16be82003-01-10 19:55:28 +0000975 for (i = 0; i < tcbtabsize; i++) {
976 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977 if (tcp->pfd != pfd)
978 continue;
979 if (tcp->flags & TCB_INUSE)
980 return tcp;
981 }
982 return NULL;
983}
984
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000985#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986
987void
988droptcb(tcp)
989struct tcb *tcp;
990{
991 if (tcp->pid == 0)
992 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000993#ifdef TCB_CLONE_THREAD
994 if (tcp->nclone_threads > 0) {
995 /* There are other threads left in this process, but this
996 is the one whose PID represents the whole process.
997 We need to keep this record around as a zombie until
998 all the threads die. */
999 tcp->flags |= TCB_EXITING;
1000 return;
1001 }
1002#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001003 nprocs--;
1004 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001005
Roland McGrathe29341c2003-01-10 20:14:20 +00001006 if (tcp->parent != NULL) {
1007 tcp->parent->nchildren--;
1008#ifdef TCB_CLONE_THREAD
1009 if (tcp->flags & TCB_CLONE_DETACHED)
1010 tcp->parent->nclone_detached--;
1011 if (tcp->flags & TCB_CLONE_THREAD)
1012 tcp->parent->nclone_threads--;
1013#endif
1014 tcp->parent = NULL;
1015 }
1016
1017 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001018 if (tcp->pfd != -1) {
1019 close(tcp->pfd);
1020 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001021#ifdef FREEBSD
1022 if (tcp->pfd_reg != -1) {
1023 close(tcp->pfd_reg);
1024 tcp->pfd_reg = -1;
1025 }
1026 if (tcp->pfd_status != -1) {
1027 close(tcp->pfd_status);
1028 tcp->pfd_status = -1;
1029 }
Roland McGrath553a6092002-12-16 20:40:39 +00001030#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001031#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001032 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033#endif
1034 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001035
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001036 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001037 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001038
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001039 tcp->outf = 0;
1040}
1041
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001042#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001043
1044static int
1045resume(tcp)
1046struct tcb *tcp;
1047{
1048 if (tcp == NULL)
1049 return -1;
1050
1051 if (!(tcp->flags & TCB_SUSPENDED)) {
1052 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1053 return -1;
1054 }
1055 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001056#ifdef TCB_CLONE_THREAD
1057 if (tcp->flags & TCB_CLONE_THREAD)
1058 tcp->parent->nclone_waiting--;
1059#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001060
1061 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1062 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1063 return -1;
1064 }
1065
1066 if (!qflag)
1067 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1068 return 0;
1069}
1070
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001071#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001072
1073/* detach traced process; continue with sig */
1074
1075static int
1076detach(tcp, sig)
1077struct tcb *tcp;
1078int sig;
1079{
1080 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001081#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001082 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001083#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001084
1085 if (tcp->flags & TCB_BPTSET)
1086 sig = SIGKILL;
1087
1088#ifdef LINUX
1089 /*
1090 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001091 * before detaching. Arghh. We go through hoops
1092 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001093 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001094#if defined(SPARC)
1095#undef PTRACE_DETACH
1096#define PTRACE_DETACH PTRACE_SUNDETACH
1097#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1099 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001100 }
1101 else if (errno != ESRCH) {
1102 /* Shouldn't happen. */
1103 perror("detach: ptrace(PTRACE_DETACH, ...)");
1104 }
1105 else if (kill(tcp->pid, 0) < 0) {
1106 if (errno != ESRCH)
1107 perror("detach: checking sanity");
1108 }
1109 else if (kill(tcp->pid, SIGSTOP) < 0) {
1110 if (errno != ESRCH)
1111 perror("detach: stopping child");
1112 }
1113 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001115#ifdef __WALL
1116 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1117 if (errno == ECHILD) /* Already gone. */
1118 break;
1119 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001120 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001121 break;
1122 }
1123#endif /* __WALL */
1124 /* No __WALL here. */
1125 if (waitpid(tcp->pid, &status, 0) < 0) {
1126 if (errno != ECHILD) {
1127 perror("detach: waiting");
1128 break;
1129 }
1130#ifdef __WCLONE
1131 /* If no processes, try clones. */
1132 if (wait4(tcp->pid, &status, __WCLONE,
1133 NULL) < 0) {
1134 if (errno != ECHILD)
1135 perror("detach: waiting");
1136 break;
1137 }
1138#endif /* __WCLONE */
1139 }
1140#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001141 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001142#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143 if (!WIFSTOPPED(status)) {
1144 /* Au revoir, mon ami. */
1145 break;
1146 }
1147 if (WSTOPSIG(status) == SIGSTOP) {
1148 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001149 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001150 if (errno != ESRCH)
1151 perror("detach: ptrace(PTRACE_DETACH, ...)");
1152 /* I died trying. */
1153 }
1154 break;
1155 }
1156 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001157 WSTOPSIG(status) == SIGTRAP ?
1158 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159 if (errno != ESRCH)
1160 perror("detach: ptrace(PTRACE_CONT, ...)");
1161 break;
1162 }
1163 }
1164 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001165#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166
1167#if defined(SUNOS4)
1168 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1169 if (sig && kill(tcp->pid, sig) < 0)
1170 perror("detach: kill");
1171 sig = 0;
1172 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1173 perror("detach: ptrace(PTRACE_DETACH, ...)");
1174#endif /* SUNOS4 */
1175
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001176#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001177 resumed = 0;
1178
1179 /* XXX This won't always be quite right (but it never was).
1180 A waiter with argument 0 or < -1 is waiting for any pid in
1181 a particular pgrp, which this child might or might not be
1182 in. The waiter will only wake up if it's argument is -1
1183 or if it's waiting for tcp->pid's pgrp. It makes a
1184 difference to wake up a waiter when there might be more
1185 traced children, because it could get a false ECHILD
1186 error. OTOH, if this was the last child in the pgrp, then
1187 it ought to wake up and get ECHILD. We would have to
1188 search the system for all pid's in the pgrp to be sure.
1189
1190 && (t->waitpid == -1 ||
1191 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1192 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1193 */
1194
1195 if (tcp->parent &&
1196 (tcp->parent->flags & TCB_SUSPENDED) &&
1197 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1198 error = resume(tcp->parent);
1199 ++resumed;
1200 }
1201#ifdef TCB_CLONE_THREAD
1202 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1203 /* Some other threads of our parent are waiting too. */
1204 unsigned int i;
1205
1206 /* Resume all the threads that were waiting for this PID. */
1207 for (i = 0; i < tcbtabsize; i++) {
1208 struct tcb *t = tcbtab[i];
1209 if (t->parent == tcp->parent && t != tcp
1210 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1211 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1212 && t->waitpid == tcp->pid) {
1213 error |= resume (t);
1214 ++resumed;
1215 }
1216 }
1217 if (resumed == 0)
1218 /* Noone was waiting for this PID in particular,
1219 so now we might need to resume some wildcarders. */
1220 for (i = 0; i < tcbtabsize; i++) {
1221 struct tcb *t = tcbtab[i];
1222 if (t->parent == tcp->parent && t != tcp
1223 && ((t->flags
1224 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1225 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1226 && t->waitpid <= 0
1227 ) {
1228 error |= resume (t);
1229 break;
1230 }
1231 }
1232 }
1233#endif
1234
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001235#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001236
1237 if (!qflag)
1238 fprintf(stderr, "Process %u detached\n", tcp->pid);
1239
1240 droptcb(tcp);
1241 return error;
1242}
1243
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001244#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245
1246static void
1247reaper(sig)
1248int sig;
1249{
1250 int pid;
1251 int status;
1252
1253 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1254#if 0
1255 struct tcb *tcp;
1256
1257 tcp = pid2tcb(pid);
1258 if (tcp)
1259 droptcb(tcp);
1260#endif
1261 }
1262}
1263
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001264#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001265
1266static void
1267cleanup()
1268{
1269 int i;
1270 struct tcb *tcp;
1271
Roland McGrathee9d4352002-12-18 04:16:10 +00001272 for (i = 0; i < tcbtabsize; i++) {
1273 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001274 if (!(tcp->flags & TCB_INUSE))
1275 continue;
1276 if (debug)
1277 fprintf(stderr,
1278 "cleanup: looking at pid %u\n", tcp->pid);
1279 if (tcp_last &&
1280 (!outfname || followfork < 2 || tcp_last == tcp)) {
1281 tprintf(" <unfinished ...>\n");
1282 tcp_last = NULL;
1283 }
1284 if (tcp->flags & TCB_ATTACHED)
1285 detach(tcp, 0);
1286 else {
1287 kill(tcp->pid, SIGCONT);
1288 kill(tcp->pid, SIGTERM);
1289 }
1290 }
1291 if (cflag)
1292 call_summary(outf);
1293}
1294
1295static void
1296interrupt(sig)
1297int sig;
1298{
1299 interrupted = 1;
1300}
1301
1302#ifndef HAVE_STRERROR
1303
Roland McGrath6d2b3492002-12-30 00:51:30 +00001304#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001305extern int sys_nerr;
1306extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001307#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001308
1309const char *
1310strerror(errno)
1311int errno;
1312{
1313 static char buf[64];
1314
1315 if (errno < 1 || errno >= sys_nerr) {
1316 sprintf(buf, "Unknown error %d", errno);
1317 return buf;
1318 }
1319 return sys_errlist[errno];
1320}
1321
1322#endif /* HAVE_STERRROR */
1323
1324#ifndef HAVE_STRSIGNAL
1325
Roland McGrath8f474e02003-01-14 07:53:33 +00001326#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001327extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001328#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001329#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1330extern char *_sys_siglist[];
1331#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001332
1333const char *
1334strsignal(sig)
1335int sig;
1336{
1337 static char buf[64];
1338
1339 if (sig < 1 || sig >= NSIG) {
1340 sprintf(buf, "Unknown signal %d", sig);
1341 return buf;
1342 }
1343#ifdef HAVE__SYS_SIGLIST
1344 return _sys_siglist[sig];
1345#else
1346 return sys_siglist[sig];
1347#endif
1348}
1349
1350#endif /* HAVE_STRSIGNAL */
1351
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001352#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001353
1354static void
1355rebuild_pollv()
1356{
1357 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001358
Roland McGrathee9d4352002-12-18 04:16:10 +00001359 if (pollv != NULL)
1360 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001361 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001362 if (pollv == NULL) {
1363 fprintf(stderr, "strace: out of memory for poll vector\n");
1364 exit(1);
1365 }
1366
Roland McGrathca16be82003-01-10 19:55:28 +00001367 for (i = j = 0; i < tcbtabsize; i++) {
1368 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001369 if (!(tcp->flags & TCB_INUSE))
1370 continue;
1371 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001372 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001373 j++;
1374 }
1375 if (j != nprocs) {
1376 fprintf(stderr, "strace: proc miscount\n");
1377 exit(1);
1378 }
1379}
1380
1381#ifndef HAVE_POLLABLE_PROCFS
1382
1383static void
1384proc_poll_open()
1385{
1386 int arg;
1387 int i;
1388
1389 if (pipe(proc_poll_pipe) < 0) {
1390 perror("pipe");
1391 exit(1);
1392 }
1393 for (i = 0; i < 2; i++) {
1394 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1395 perror("F_GETFD");
1396 exit(1);
1397 }
1398 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1399 perror("F_SETFD");
1400 exit(1);
1401 }
1402 }
1403}
1404
1405static int
1406proc_poll(pollv, nfds, timeout)
1407struct pollfd *pollv;
1408int nfds;
1409int timeout;
1410{
1411 int i;
1412 int n;
1413 struct proc_pollfd pollinfo;
1414
1415 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1416 return n;
1417 if (n != sizeof(struct proc_pollfd)) {
1418 fprintf(stderr, "panic: short read: %d\n", n);
1419 exit(1);
1420 }
1421 for (i = 0; i < nprocs; i++) {
1422 if (pollv[i].fd == pollinfo.fd)
1423 pollv[i].revents = pollinfo.revents;
1424 else
1425 pollv[i].revents = 0;
1426 }
1427 poller_pid = pollinfo.pid;
1428 return 1;
1429}
1430
1431static void
1432wakeup_handler(sig)
1433int sig;
1434{
1435}
1436
1437static void
1438proc_poller(pfd)
1439int pfd;
1440{
1441 struct proc_pollfd pollinfo;
1442 struct sigaction sa;
1443 sigset_t blocked_set, empty_set;
1444 int i;
1445 int n;
1446 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001447#ifdef FREEBSD
1448 struct procfs_status pfs;
1449#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001450
1451 switch (fork()) {
1452 case -1:
1453 perror("fork");
1454 _exit(0);
1455 case 0:
1456 break;
1457 default:
1458 return;
1459 }
1460
1461 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1462 sa.sa_flags = 0;
1463 sigemptyset(&sa.sa_mask);
1464 sigaction(SIGHUP, &sa, NULL);
1465 sigaction(SIGINT, &sa, NULL);
1466 sigaction(SIGQUIT, &sa, NULL);
1467 sigaction(SIGPIPE, &sa, NULL);
1468 sigaction(SIGTERM, &sa, NULL);
1469 sa.sa_handler = wakeup_handler;
1470 sigaction(SIGUSR1, &sa, NULL);
1471 sigemptyset(&blocked_set);
1472 sigaddset(&blocked_set, SIGUSR1);
1473 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1474 sigemptyset(&empty_set);
1475
1476 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1477 perror("getrlimit(RLIMIT_NOFILE, ...)");
1478 _exit(0);
1479 }
1480 n = rl.rlim_cur;
1481 for (i = 0; i < n; i++) {
1482 if (i != pfd && i != proc_poll_pipe[1])
1483 close(i);
1484 }
1485
1486 pollinfo.fd = pfd;
1487 pollinfo.pid = getpid();
1488 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001489#ifndef FREEBSD
1490 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1491#else /* FREEBSD */
1492 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1493#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001494 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001495 switch (errno) {
1496 case EINTR:
1497 continue;
1498 case EBADF:
1499 pollinfo.revents = POLLERR;
1500 break;
1501 case ENOENT:
1502 pollinfo.revents = POLLHUP;
1503 break;
1504 default:
1505 perror("proc_poller: PIOCWSTOP");
1506 }
1507 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1508 _exit(0);
1509 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001510 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001511 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1512 sigsuspend(&empty_set);
1513 }
1514}
1515
1516#endif /* !HAVE_POLLABLE_PROCFS */
1517
1518static int
1519choose_pfd()
1520{
1521 int i, j;
1522 struct tcb *tcp;
1523
1524 static int last;
1525
1526 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001527 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001528 /*
1529 * The previous process is ready to run again. We'll
1530 * let it do so if it is currently in a syscall. This
1531 * heuristic improves the readability of the trace.
1532 */
1533 tcp = pfd2tcb(pollv[last].fd);
1534 if (tcp && (tcp->flags & TCB_INSYSCALL))
1535 return pollv[last].fd;
1536 }
1537
1538 for (i = 0; i < nprocs; i++) {
1539 /* Let competing children run round robin. */
1540 j = (i + last + 1) % nprocs;
1541 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1542 tcp = pfd2tcb(pollv[j].fd);
1543 if (!tcp) {
1544 fprintf(stderr, "strace: lost proc\n");
1545 exit(1);
1546 }
1547 droptcb(tcp);
1548 return -1;
1549 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001550 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001551 last = j;
1552 return pollv[j].fd;
1553 }
1554 }
1555 fprintf(stderr, "strace: nothing ready\n");
1556 exit(1);
1557}
1558
1559static int
1560trace()
1561{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001562#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001563 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001564#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001565 struct tcb *tcp;
1566 int pfd;
1567 int what;
1568 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001569 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001570
1571 for (;;) {
1572 if (interactive)
1573 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1574
1575 if (nprocs == 0)
1576 break;
1577
1578 switch (nprocs) {
1579 case 1:
1580#ifndef HAVE_POLLABLE_PROCFS
1581 if (proc_poll_pipe[0] == -1) {
1582#endif
1583 tcp = pid2tcb(0);
1584 if (!tcp)
1585 continue;
1586 pfd = tcp->pfd;
1587 if (pfd == -1)
1588 continue;
1589 break;
1590#ifndef HAVE_POLLABLE_PROCFS
1591 }
1592 /* fall through ... */
1593#endif /* !HAVE_POLLABLE_PROCFS */
1594 default:
1595#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001596#ifdef POLL_HACK
1597 /* On some systems (e.g. UnixWare) we get too much ugly
1598 "unfinished..." stuff when multiple proceses are in
1599 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001600
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001601 if (in_syscall) {
1602 struct pollfd pv;
1603 tcp = in_syscall;
1604 in_syscall = NULL;
1605 pv.fd = tcp->pfd;
1606 pv.events = POLLWANT;
1607 if ((what = poll (&pv, 1, 1)) < 0) {
1608 if (interrupted)
1609 return 0;
1610 continue;
1611 }
1612 else if (what == 1 && pv.revents & POLLWANT) {
1613 goto FOUND;
1614 }
1615 }
1616#endif
1617
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001618 if (poll(pollv, nprocs, INFTIM) < 0) {
1619 if (interrupted)
1620 return 0;
1621 continue;
1622 }
1623#else /* !HAVE_POLLABLE_PROCFS */
1624 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1625 if (interrupted)
1626 return 0;
1627 continue;
1628 }
1629#endif /* !HAVE_POLLABLE_PROCFS */
1630 pfd = choose_pfd();
1631 if (pfd == -1)
1632 continue;
1633 break;
1634 }
1635
1636 /* Look up `pfd' in our table. */
1637 if ((tcp = pfd2tcb(pfd)) == NULL) {
1638 fprintf(stderr, "unknown pfd: %u\n", pfd);
1639 exit(1);
1640 }
John Hughesb6643082002-05-23 11:02:22 +00001641#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001642 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001643#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001644 /* Get the status of the process. */
1645 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001646#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001647 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001648#else /* FREEBSD */
1649 /* Thanks to some scheduling mystery, the first poller
1650 sometimes waits for the already processed end of fork
1651 event. Doing a non blocking poll here solves the problem. */
1652 if (proc_poll_pipe[0] != -1)
1653 ioctl_result = IOCTL_STATUS (tcp);
1654 else
1655 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001656#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657 ioctl_errno = errno;
1658#ifndef HAVE_POLLABLE_PROCFS
1659 if (proc_poll_pipe[0] != -1) {
1660 if (ioctl_result < 0)
1661 kill(poller_pid, SIGKILL);
1662 else
1663 kill(poller_pid, SIGUSR1);
1664 }
1665#endif /* !HAVE_POLLABLE_PROCFS */
1666 }
1667 if (interrupted)
1668 return 0;
1669
1670 if (interactive)
1671 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1672
1673 if (ioctl_result < 0) {
1674 /* Find out what happened if it failed. */
1675 switch (ioctl_errno) {
1676 case EINTR:
1677 case EBADF:
1678 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001679#ifdef FREEBSD
1680 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001681#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001682 case ENOENT:
1683 droptcb(tcp);
1684 continue;
1685 default:
1686 perror("PIOCWSTOP");
1687 exit(1);
1688 }
1689 }
1690
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001691#ifdef FREEBSD
1692 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1693 /* discard first event for a syscall we never entered */
1694 IOCTL (tcp->pfd, PIOCRUN, 0);
1695 continue;
1696 }
Roland McGrath553a6092002-12-16 20:40:39 +00001697#endif
1698
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699 /* clear the just started flag */
1700 tcp->flags &= ~TCB_STARTUP;
1701
1702 /* set current output file */
1703 outf = tcp->outf;
1704
1705 if (cflag) {
1706 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001707#ifdef FREEBSD
1708 char buf[1024];
1709 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001710
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001711 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1712 buf[len] = '\0';
1713 sscanf(buf,
1714 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1715 &stime.tv_sec, &stime.tv_usec);
1716 } else
1717 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001718#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001719 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1720 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001721#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001722 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1723 tcp->stime = stime;
1724 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001725 what = tcp->status.PR_WHAT;
1726 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001727#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001729 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1730 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001731 if (trace_syscall(tcp) < 0) {
1732 fprintf(stderr, "syscall trouble\n");
1733 exit(1);
1734 }
1735 }
1736 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001737#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001738 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001739#ifdef POLL_HACK
1740 in_syscall = tcp;
1741#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001742 case PR_SYSEXIT:
1743 if (trace_syscall(tcp) < 0) {
1744 fprintf(stderr, "syscall trouble\n");
1745 exit(1);
1746 }
1747 break;
1748 case PR_SIGNALLED:
1749 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1750 printleader(tcp);
1751 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001752 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001753 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001754#ifdef PR_INFO
1755 if (tcp->status.PR_INFO.si_signo == what) {
1756 printleader(tcp);
1757 tprintf(" siginfo=");
1758 printsiginfo(&tcp->status.PR_INFO, 1);
1759 printtrailer(tcp);
1760 }
1761#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001762 }
1763 break;
1764 case PR_FAULTED:
1765 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1766 printleader(tcp);
1767 tprintf("=== FAULT %d ===", what);
1768 printtrailer(tcp);
1769 }
1770 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001771#ifdef FREEBSD
1772 case 0: /* handle case we polled for nothing */
1773 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001774#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001775 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001776 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001777 exit(1);
1778 break;
1779 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001780 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001781#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001782 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001783#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001784 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001785#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001786 perror("PIOCRUN");
1787 exit(1);
1788 }
1789 }
1790 return 0;
1791}
1792
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001793#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001794
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001795#ifdef TCB_GROUP_EXITING
1796/* Handle an exit detach or death signal that is taking all the
1797 related clone threads with it. This is called in three circumstances:
1798 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1799 SIG == 0 Continuing TCP will perform an exit_group syscall.
1800 SIG == other Continuing TCP with SIG will kill the process.
1801*/
1802static int
1803handle_group_exit(struct tcb *tcp, int sig)
1804{
1805 /* We need to locate our records of all the clone threads
1806 related to TCP, either its children or siblings. */
1807 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1808 ? tcp->parent
1809 : tcp->nclone_detached > 0
1810 ? tcp : NULL);
1811
1812 if (sig < 0) {
1813 if (leader != NULL && leader != tcp)
1814 fprintf(stderr,
1815 "PANIC: handle_group_exit: %d leader %d\n",
1816 tcp->pid, leader ? leader->pid : -1);
1817 droptcb(tcp); /* Already died. */
1818 }
1819 else {
1820 if (tcp->flags & TCB_ATTACHED) {
1821 if (leader != NULL && leader != tcp) {
1822 /* We need to detach the leader so that the
1823 process death will be reported to its real
1824 parent. But we kill it first to prevent
1825 it doing anything before we kill the whole
1826 process in a moment. We can use
1827 PTRACE_KILL on a thread that's not already
1828 stopped. Then the value we pass in
1829 PTRACE_DETACH just sets the death
1830 signal reported to the real parent. */
1831 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1832 if (debug)
1833 fprintf(stderr,
1834 " [%d exit %d kills %d]\n",
1835 tcp->pid, sig, leader->pid);
1836 detach(leader, sig);
1837 }
1838 detach(tcp, sig);
1839 }
1840 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1841 perror("strace: ptrace(PTRACE_CONT, ...)");
1842 cleanup();
1843 return -1;
1844 }
1845 else {
1846 if (leader != NULL && leader != tcp)
1847 droptcb(tcp);
1848 /* The leader will report to us as parent now,
1849 and then we'll get to the SIG==-1 case. */
1850 return 0;
1851 }
1852 }
1853
1854 /* Note that TCP and LEADER are no longer valid,
1855 but we can still compare against them. */
1856 if (leader != NULL) {
1857 unsigned int i;
1858 for (i = 0; i < tcbtabsize; i++) {
1859 struct tcb *t = tcbtab[i];
1860 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1861 && t->parent == leader)
1862 droptcb(t);
1863 }
1864 }
1865
1866 return 0;
1867}
1868#endif
1869
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001870static int
1871trace()
1872{
1873 int pid;
1874 int wait_errno;
1875 int status;
1876 struct tcb *tcp;
1877#ifdef LINUX
1878 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001879#ifdef __WALL
1880 static int wait4_options = __WALL;
1881#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001882#endif /* LINUX */
1883
1884 while (nprocs != 0) {
1885 if (interactive)
1886 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1887#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001888#ifdef __WALL
1889 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00001890 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001891 /* this kernel does not support __WALL */
1892 wait4_options &= ~__WALL;
1893 errno = 0;
1894 pid = wait4(-1, &status, wait4_options,
1895 cflag ? &ru : NULL);
1896 }
Roland McGrath5bc05552002-12-17 04:50:47 +00001897 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001898 /* most likely a "cloned" process */
1899 pid = wait4(-1, &status, __WCLONE,
1900 cflag ? &ru : NULL);
1901 if (pid == -1) {
1902 fprintf(stderr, "strace: clone wait4 "
1903 "failed: %s\n", strerror(errno));
1904 }
1905 }
1906#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001907 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001908#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001909#endif /* LINUX */
1910#ifdef SUNOS4
1911 pid = wait(&status);
1912#endif /* SUNOS4 */
1913 wait_errno = errno;
1914 if (interactive)
1915 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1916
1917 if (interrupted)
1918 return 0;
1919
1920 if (pid == -1) {
1921 switch (wait_errno) {
1922 case EINTR:
1923 continue;
1924 case ECHILD:
1925 /*
1926 * We would like to verify this case
1927 * but sometimes a race in Solbourne's
1928 * version of SunOS sometimes reports
1929 * ECHILD before sending us SIGCHILD.
1930 */
1931#if 0
1932 if (nprocs == 0)
1933 return 0;
1934 fprintf(stderr, "strace: proc miscount\n");
1935 exit(1);
1936#endif
1937 return 0;
1938 default:
1939 errno = wait_errno;
1940 perror("strace: wait");
1941 return -1;
1942 }
1943 }
1944 if (debug)
1945 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1946
1947 /* Look up `pid' in our table. */
1948 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001949#ifdef LINUX
1950 if (followfork || followvfork) {
1951 /* This is needed to go with the CLONE_PTRACE
1952 changes in process.c/util.c: we might see
1953 the child's initial trap before we see the
1954 parent return from the clone syscall.
1955 Leave the child suspended until the parent
1956 returns from its system call. Only then
1957 will we have the association of parent and
1958 child so that we know how to do clearbpt
1959 in the child. */
1960 if ((tcp = alloctcb(pid)) == NULL) {
1961 fprintf(stderr, " [tcb table full]\n");
1962 kill(pid, SIGKILL); /* XXX */
1963 return 0;
1964 }
1965 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
1966 newoutf(tcp);
1967 if (!qflag)
1968 fprintf(stderr, "\
1969Process %d attached (waiting for parent)\n",
1970 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001971 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001972 else
1973 /* This can happen if a clone call used
1974 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001975#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001976 {
1977 fprintf(stderr, "unknown pid: %u\n", pid);
1978 if (WIFSTOPPED(status))
1979 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1980 exit(1);
1981 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001982 }
1983 /* set current output file */
1984 outf = tcp->outf;
1985 if (cflag) {
1986#ifdef LINUX
1987 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
1988 tcp->stime = ru.ru_stime;
1989#endif /* !LINUX */
1990 }
1991
1992 if (tcp->flags & TCB_SUSPENDED) {
1993 /*
1994 * Apparently, doing any ptrace() call on a stopped
1995 * process, provokes the kernel to report the process
1996 * status again on a subsequent wait(), even if the
1997 * process has not been actually restarted.
1998 * Since we have inspected the arguments of suspended
1999 * processes we end up here testing for this case.
2000 */
2001 continue;
2002 }
2003 if (WIFSIGNALED(status)) {
2004 if (!cflag
2005 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2006 printleader(tcp);
2007 tprintf("+++ killed by %s +++",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002008 signame(WTERMSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002009 printtrailer(tcp);
2010 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002011#ifdef TCB_GROUP_EXITING
2012 handle_group_exit(tcp, -1);
2013#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002014 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002015#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002016 continue;
2017 }
2018 if (WIFEXITED(status)) {
2019 if (debug)
2020 fprintf(stderr, "pid %u exited\n", pid);
2021 if (tcp->flags & TCB_ATTACHED)
2022 fprintf(stderr,
2023 "PANIC: attached pid %u exited\n",
2024 pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002025#ifdef TCB_GROUP_EXITING
2026 handle_group_exit(tcp, -1);
2027#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002028 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002029#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002030 continue;
2031 }
2032 if (!WIFSTOPPED(status)) {
2033 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2034 droptcb(tcp);
2035 continue;
2036 }
2037 if (debug)
2038 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002039 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002040
2041 if (tcp->flags & TCB_STARTUP) {
2042 /*
2043 * This flag is there to keep us in sync.
2044 * Next time this process stops it should
2045 * really be entering a system call.
2046 */
2047 tcp->flags &= ~TCB_STARTUP;
2048 if (tcp->flags & TCB_ATTACHED) {
2049 /*
2050 * Interestingly, the process may stop
2051 * with STOPSIG equal to some other signal
2052 * than SIGSTOP if we happend to attach
2053 * just before the process takes a signal.
2054 */
2055 if (!WIFSTOPPED(status)) {
2056 fprintf(stderr,
2057 "pid %u not stopped\n", pid);
2058 detach(tcp, WSTOPSIG(status));
2059 continue;
2060 }
2061 }
2062 else {
2063#ifdef SUNOS4
2064 /* A child of us stopped at exec */
2065 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2066 fixvfork(tcp);
2067#endif /* SUNOS4 */
2068 }
2069 if (tcp->flags & TCB_BPTSET) {
2070 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2071 droptcb(tcp);
2072 cleanup();
2073 return -1;
2074 }
2075 }
2076 goto tracing;
2077 }
2078
2079 if (WSTOPSIG(status) != SIGTRAP) {
2080 if (WSTOPSIG(status) == SIGSTOP &&
2081 (tcp->flags & TCB_SIGTRAPPED)) {
2082 /*
2083 * Trapped attempt to block SIGTRAP
2084 * Hope we are back in control now.
2085 */
2086 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2087 if (ptrace(PTRACE_SYSCALL,
2088 pid, (char *) 1, 0) < 0) {
2089 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2090 cleanup();
2091 return -1;
2092 }
2093 continue;
2094 }
2095 if (!cflag
2096 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002097 unsigned long addr = 0, pc = 0;
2098#ifdef PT_GETSIGINFO
2099# define PSR_RI 41
2100 struct siginfo si;
2101 unsigned long psr;
2102
2103 upeek(pid, PT_CR_IPSR, &psr);
2104 upeek(pid, PT_CR_IIP, &pc);
2105
2106 pc += (psr >> PSR_RI) & 0x3;
2107 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2108 addr = (unsigned long) si.si_addr;
2109#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002110 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002111 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002112 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002113 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002114 printtrailer(tcp);
2115 }
2116 if ((tcp->flags & TCB_ATTACHED) &&
2117 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002118#ifdef TCB_GROUP_EXITING
2119 handle_group_exit(tcp, WSTOPSIG(status));
2120#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002121 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002122#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002123 continue;
2124 }
2125 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2126 WSTOPSIG(status)) < 0) {
2127 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2128 cleanup();
2129 return -1;
2130 }
2131 tcp->flags &= ~TCB_SUSPENDED;
2132 continue;
2133 }
2134 if (trace_syscall(tcp) < 0) {
2135 if (tcp->flags & TCB_ATTACHED)
2136 detach(tcp, 0);
2137 else {
2138 ptrace(PTRACE_KILL,
2139 tcp->pid, (char *) 1, SIGTERM);
2140 droptcb(tcp);
2141 }
2142 continue;
2143 }
2144 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002145#ifdef TCB_GROUP_EXITING
2146 if (tcp->flags & TCB_GROUP_EXITING) {
2147 if (handle_group_exit(tcp, 0) < 0)
2148 return -1;
2149 continue;
2150 }
2151#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002152 if (tcp->flags & TCB_ATTACHED)
2153 detach(tcp, 0);
2154 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2155 perror("strace: ptrace(PTRACE_CONT, ...)");
2156 cleanup();
2157 return -1;
2158 }
2159 continue;
2160 }
2161 if (tcp->flags & TCB_SUSPENDED) {
2162 if (!qflag)
2163 fprintf(stderr, "Process %u suspended\n", pid);
2164 continue;
2165 }
2166 tracing:
2167 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2168 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2169 cleanup();
2170 return -1;
2171 }
2172 }
2173 return 0;
2174}
2175
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002176#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002177
2178static int curcol;
2179
2180#ifdef __STDC__
2181#include <stdarg.h>
2182#define VA_START(a, b) va_start(a, b)
2183#else
2184#include <varargs.h>
2185#define VA_START(a, b) va_start(a)
2186#endif
2187
2188void
2189#ifdef __STDC__
2190tprintf(const char *fmt, ...)
2191#else
2192tprintf(fmt, va_alist)
2193char *fmt;
2194va_dcl
2195#endif
2196{
2197 va_list args;
2198
2199 VA_START(args, fmt);
2200 if (outf)
2201 curcol += vfprintf(outf, fmt, args);
2202 va_end(args);
2203 return;
2204}
2205
2206void
2207printleader(tcp)
2208struct tcb *tcp;
2209{
2210 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2211 tcp_last->flags |= TCB_REPRINT;
2212 tprintf(" <unfinished ...>\n");
2213 }
2214 curcol = 0;
2215 if ((followfork == 1 || pflag_seen > 1) && outfname)
2216 tprintf("%-5d ", tcp->pid);
2217 else if (nprocs > 1 && !outfname)
2218 tprintf("[pid %5u] ", tcp->pid);
2219 if (tflag) {
2220 char str[sizeof("HH:MM:SS")];
2221 struct timeval tv, dtv;
2222 static struct timeval otv;
2223
2224 gettimeofday(&tv, NULL);
2225 if (rflag) {
2226 if (otv.tv_sec == 0)
2227 otv = tv;
2228 tv_sub(&dtv, &tv, &otv);
2229 tprintf("%6ld.%06ld ",
2230 (long) dtv.tv_sec, (long) dtv.tv_usec);
2231 otv = tv;
2232 }
2233 else if (tflag > 2) {
2234 tprintf("%ld.%06ld ",
2235 (long) tv.tv_sec, (long) tv.tv_usec);
2236 }
2237 else {
2238 time_t local = tv.tv_sec;
2239 strftime(str, sizeof(str), "%T", localtime(&local));
2240 if (tflag > 1)
2241 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2242 else
2243 tprintf("%s ", str);
2244 }
2245 }
2246 if (iflag)
2247 printcall(tcp);
2248}
2249
2250void
2251tabto(col)
2252int col;
2253{
2254 if (curcol < col)
2255 tprintf("%*s", col - curcol, "");
2256}
2257
2258void
2259printtrailer(tcp)
2260struct tcb *tcp;
2261{
2262 tprintf("\n");
2263 tcp_last = NULL;
2264}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002265
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002266#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002267
2268int mp_ioctl (int fd, int cmd, void *arg, int size) {
2269
2270 struct iovec iov[2];
2271 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002272
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002273 iov[0].iov_base = &cmd;
2274 iov[0].iov_len = sizeof cmd;
2275 if (arg) {
2276 ++n;
2277 iov[1].iov_base = arg;
2278 iov[1].iov_len = size;
2279 }
Roland McGrath553a6092002-12-16 20:40:39 +00002280
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002281 return writev (fd, iov, n);
2282}
2283
2284#endif