blob: 41194b7f33a1dc08a1d558409c379621a5456bf5 [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 McGrath09623452003-05-23 02:27:13 +0000624 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000625#ifdef TCB_CLONE_THREAD
626 tcp->nclone_threads = tcp->nclone_detached = 0;
627 tcp->nclone_waiting = 0;
628#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000629 tcp->flags = TCB_INUSE | TCB_STARTUP;
630 tcp->outf = outf; /* Initialise to current out file */
631 tcp->stime.tv_sec = 0;
632 tcp->stime.tv_usec = 0;
633 tcp->pfd = -1;
634 nprocs++;
635 return tcp;
636 }
637 }
638 return NULL;
639}
640
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000641#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000642int
643proc_open(tcp, attaching)
644struct tcb *tcp;
645int attaching;
646{
647 char proc[32];
648 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000649#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000650 int i;
651 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000652 sigset_t signals;
653 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000654#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000655#ifndef HAVE_POLLABLE_PROCFS
656 static int last_pfd;
657#endif
658
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000659#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000660 /* Open the process pseudo-files in /proc. */
661 sprintf(proc, "/proc/%d/ctl", tcp->pid);
662 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000663 perror("strace: open(\"/proc/...\", ...)");
664 return -1;
665 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000666 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
667 perror("F_GETFD");
668 return -1;
669 }
670 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
671 perror("F_SETFD");
672 return -1;
673 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000674 sprintf(proc, "/proc/%d/status", tcp->pid);
675 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
676 perror("strace: open(\"/proc/...\", ...)");
677 return -1;
678 }
679 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
680 perror("F_GETFD");
681 return -1;
682 }
683 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
684 perror("F_SETFD");
685 return -1;
686 }
687 sprintf(proc, "/proc/%d/as", tcp->pid);
688 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
689 perror("strace: open(\"/proc/...\", ...)");
690 return -1;
691 }
692 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
693 perror("F_GETFD");
694 return -1;
695 }
696 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
697 perror("F_SETFD");
698 return -1;
699 }
700#else
701 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000702#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000703 sprintf(proc, "/proc/%d", tcp->pid);
704 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000705#else /* FREEBSD */
706 sprintf(proc, "/proc/%d/mem", tcp->pid);
707 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
708#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000709 perror("strace: open(\"/proc/...\", ...)");
710 return -1;
711 }
712 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
713 perror("F_GETFD");
714 return -1;
715 }
716 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
717 perror("F_SETFD");
718 return -1;
719 }
720#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000721#ifdef FREEBSD
722 sprintf(proc, "/proc/%d/regs", tcp->pid);
723 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
724 perror("strace: open(\"/proc/.../regs\", ...)");
725 return -1;
726 }
727 if (cflag) {
728 sprintf(proc, "/proc/%d/status", tcp->pid);
729 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
730 perror("strace: open(\"/proc/.../status\", ...)");
731 return -1;
732 }
733 } else
734 tcp->pfd_status = -1;
735#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000736 rebuild_pollv();
737 if (!attaching) {
738 /*
739 * Wait for the child to pause. Because of a race
740 * condition we have to poll for the event.
741 */
742 for (;;) {
743 if (IOCTL_STATUS (tcp) < 0) {
744 perror("strace: PIOCSTATUS");
745 return -1;
746 }
747 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000748 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000749 }
750 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000751#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000752 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000753 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000754 perror("strace: PIOCSTOP");
755 return -1;
756 }
Roland McGrath553a6092002-12-16 20:40:39 +0000757#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000758#ifdef PIOCSET
759 /* Set Run-on-Last-Close. */
760 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000761 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000762 perror("PIOCSET PR_RLC");
763 return -1;
764 }
765 /* Set or Reset Inherit-on-Fork. */
766 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000767 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000768 perror("PIOC{SET,RESET} PR_FORK");
769 return -1;
770 }
771#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000772#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000773 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
774 perror("PIOCSRLC");
775 return -1;
776 }
777 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
778 perror("PIOC{S,R}FORK");
779 return -1;
780 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000781#else /* FREEBSD */
782 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
783 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
784 perror("PIOCGFL");
785 return -1;
786 }
787 arg &= ~PF_LINGER;
788 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
789 perror("PIOCSFL");
790 return -1;
791 }
792#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000793#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000794#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000795 /* Enable all syscall entries we care about. */
796 premptyset(&syscalls);
797 for (i = 1; i < MAX_QUALS; ++i) {
798 if (i > (sizeof syscalls) * CHAR_BIT) break;
799 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
800 }
801 praddset (&syscalls, SYS_execve);
802 if (followfork) {
803 praddset (&syscalls, SYS_fork);
804#ifdef SYS_forkall
805 praddset (&syscalls, SYS_forkall);
806#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000807#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000808 praddset (&syscalls, SYS_fork1);
809#endif
810#ifdef SYS_rfork1
811 praddset (&syscalls, SYS_rfork1);
812#endif
813#ifdef SYS_rforkall
814 praddset (&syscalls, SYS_rforkall);
815#endif
816 }
817 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000818 perror("PIOCSENTRY");
819 return -1;
820 }
John Hughes19e49982001-10-19 08:59:12 +0000821 /* Enable the syscall exits. */
822 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000823 perror("PIOSEXIT");
824 return -1;
825 }
John Hughes19e49982001-10-19 08:59:12 +0000826 /* Enable signals we care about. */
827 premptyset(&signals);
828 for (i = 1; i < MAX_QUALS; ++i) {
829 if (i > (sizeof signals) * CHAR_BIT) break;
830 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
831 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000832 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000833 perror("PIOCSTRACE");
834 return -1;
835 }
John Hughes19e49982001-10-19 08:59:12 +0000836 /* Enable faults we care about */
837 premptyset(&faults);
838 for (i = 1; i < MAX_QUALS; ++i) {
839 if (i > (sizeof faults) * CHAR_BIT) break;
840 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
841 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000842 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000843 perror("PIOCSFAULT");
844 return -1;
845 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000846#else /* FREEBSD */
847 /* set events flags. */
848 arg = S_SIG | S_SCE | S_SCX ;
849 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
850 perror("PIOCBIS");
851 return -1;
852 }
853#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000854 if (!attaching) {
855#ifdef MIPS
856 /*
857 * The SGI PRSABORT doesn't work for pause() so
858 * we send it a caught signal to wake it up.
859 */
860 kill(tcp->pid, SIGINT);
861#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000862#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000863 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000864 arg = PRSABORT;
865 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000866 perror("PIOCRUN");
867 return -1;
868 }
Roland McGrath553a6092002-12-16 20:40:39 +0000869#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000870#endif /* !MIPS*/
871#ifdef FREEBSD
872 /* wake up the child if it received the SIGSTOP */
873 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000874#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000875 for (;;) {
876 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000877 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000878 perror("PIOCWSTOP");
879 return -1;
880 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000881 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000882 tcp->flags &= ~TCB_INSYSCALL;
883 get_scno(tcp);
884 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000885 break;
886 }
887 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000888#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000889 arg = 0;
890 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000891#else /* FREEBSD */
892 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +0000893#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 perror("PIOCRUN");
895 return -1;
896 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000897#ifdef FREEBSD
898 /* handle the case where we "opened" the child before
899 it did the kill -STOP */
900 if (tcp->status.PR_WHY == PR_SIGNALLED &&
901 tcp->status.PR_WHAT == SIGSTOP)
902 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000903#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000904 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000905#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000906 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000907#else /* FREEBSD */
908 } else {
Roland McGrath553a6092002-12-16 20:40:39 +0000909 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000910 /* We are attaching to an already running process.
911 * Try to figure out the state of the process in syscalls,
912 * to handle the first event well.
913 * This is done by having a look at the "wchan" property of the
914 * process, which tells where it is stopped (if it is). */
915 FILE * status;
916 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +0000917
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000918 sprintf(proc, "/proc/%d/status", tcp->pid);
919 status = fopen(proc, "r");
920 if (status &&
921 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
922 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
923 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
924 strcmp(wchan, "stopevent")) {
925 /* The process is asleep in the middle of a syscall.
926 Fake the syscall entry event */
927 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
928 tcp->status.PR_WHY = PR_SYSENTRY;
929 trace_syscall(tcp);
930 }
931 if (status)
932 fclose(status);
933 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000934 }
935#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000936#ifndef HAVE_POLLABLE_PROCFS
937 if (proc_poll_pipe[0] != -1)
938 proc_poller(tcp->pfd);
939 else if (nprocs > 1) {
940 proc_poll_open();
941 proc_poller(last_pfd);
942 proc_poller(tcp->pfd);
943 }
944 last_pfd = tcp->pfd;
945#endif /* !HAVE_POLLABLE_PROCFS */
946 return 0;
947}
948
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000949#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000950
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000951struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000952pid2tcb(pid)
953int pid;
954{
955 int i;
956 struct tcb *tcp;
957
Roland McGrathee9d4352002-12-18 04:16:10 +0000958 for (i = 0; i < tcbtabsize; i++) {
959 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000960 if (pid && tcp->pid != pid)
961 continue;
962 if (tcp->flags & TCB_INUSE)
963 return tcp;
964 }
965 return NULL;
966}
967
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000968#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000969
970static struct tcb *
971pfd2tcb(pfd)
972int pfd;
973{
974 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000975
Roland McGrathca16be82003-01-10 19:55:28 +0000976 for (i = 0; i < tcbtabsize; i++) {
977 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000978 if (tcp->pfd != pfd)
979 continue;
980 if (tcp->flags & TCB_INUSE)
981 return tcp;
982 }
983 return NULL;
984}
985
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000986#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987
988void
989droptcb(tcp)
990struct tcb *tcp;
991{
992 if (tcp->pid == 0)
993 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000994#ifdef TCB_CLONE_THREAD
995 if (tcp->nclone_threads > 0) {
996 /* There are other threads left in this process, but this
997 is the one whose PID represents the whole process.
998 We need to keep this record around as a zombie until
999 all the threads die. */
1000 tcp->flags |= TCB_EXITING;
1001 return;
1002 }
1003#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001004 nprocs--;
1005 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001006
Roland McGrathe29341c2003-01-10 20:14:20 +00001007 if (tcp->parent != NULL) {
1008 tcp->parent->nchildren--;
1009#ifdef TCB_CLONE_THREAD
1010 if (tcp->flags & TCB_CLONE_DETACHED)
1011 tcp->parent->nclone_detached--;
1012 if (tcp->flags & TCB_CLONE_THREAD)
1013 tcp->parent->nclone_threads--;
1014#endif
Roland McGrath09623452003-05-23 02:27:13 +00001015#ifdef TCB_CLONE_DETACHED
1016 if (!(tcp->flags & TCB_CLONE_DETACHED))
1017#endif
1018 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001019 tcp->parent = NULL;
1020 }
1021
1022 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023 if (tcp->pfd != -1) {
1024 close(tcp->pfd);
1025 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001026#ifdef FREEBSD
1027 if (tcp->pfd_reg != -1) {
1028 close(tcp->pfd_reg);
1029 tcp->pfd_reg = -1;
1030 }
1031 if (tcp->pfd_status != -1) {
1032 close(tcp->pfd_status);
1033 tcp->pfd_status = -1;
1034 }
Roland McGrath553a6092002-12-16 20:40:39 +00001035#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001036#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001037 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001038#endif
1039 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001040
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001041 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001042 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001043
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 tcp->outf = 0;
1045}
1046
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001047#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048
1049static int
1050resume(tcp)
1051struct tcb *tcp;
1052{
1053 if (tcp == NULL)
1054 return -1;
1055
1056 if (!(tcp->flags & TCB_SUSPENDED)) {
1057 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1058 return -1;
1059 }
1060 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001061#ifdef TCB_CLONE_THREAD
1062 if (tcp->flags & TCB_CLONE_THREAD)
1063 tcp->parent->nclone_waiting--;
1064#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001065
1066 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1067 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1068 return -1;
1069 }
1070
1071 if (!qflag)
1072 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1073 return 0;
1074}
1075
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001076#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001077
1078/* detach traced process; continue with sig */
1079
1080static int
1081detach(tcp, sig)
1082struct tcb *tcp;
1083int sig;
1084{
1085 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001086#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001087 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001088#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089
1090 if (tcp->flags & TCB_BPTSET)
1091 sig = SIGKILL;
1092
1093#ifdef LINUX
1094 /*
1095 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001096 * before detaching. Arghh. We go through hoops
1097 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001099#if defined(SPARC)
1100#undef PTRACE_DETACH
1101#define PTRACE_DETACH PTRACE_SUNDETACH
1102#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001103 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1104 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001105 }
1106 else if (errno != ESRCH) {
1107 /* Shouldn't happen. */
1108 perror("detach: ptrace(PTRACE_DETACH, ...)");
1109 }
1110 else if (kill(tcp->pid, 0) < 0) {
1111 if (errno != ESRCH)
1112 perror("detach: checking sanity");
1113 }
1114 else if (kill(tcp->pid, SIGSTOP) < 0) {
1115 if (errno != ESRCH)
1116 perror("detach: stopping child");
1117 }
1118 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001120#ifdef __WALL
1121 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1122 if (errno == ECHILD) /* Already gone. */
1123 break;
1124 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001125 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001126 break;
1127 }
1128#endif /* __WALL */
1129 /* No __WALL here. */
1130 if (waitpid(tcp->pid, &status, 0) < 0) {
1131 if (errno != ECHILD) {
1132 perror("detach: waiting");
1133 break;
1134 }
1135#ifdef __WCLONE
1136 /* If no processes, try clones. */
1137 if (wait4(tcp->pid, &status, __WCLONE,
1138 NULL) < 0) {
1139 if (errno != ECHILD)
1140 perror("detach: waiting");
1141 break;
1142 }
1143#endif /* __WCLONE */
1144 }
1145#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001146 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001147#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001148 if (!WIFSTOPPED(status)) {
1149 /* Au revoir, mon ami. */
1150 break;
1151 }
1152 if (WSTOPSIG(status) == SIGSTOP) {
1153 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001154 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001155 if (errno != ESRCH)
1156 perror("detach: ptrace(PTRACE_DETACH, ...)");
1157 /* I died trying. */
1158 }
1159 break;
1160 }
1161 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001162 WSTOPSIG(status) == SIGTRAP ?
1163 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001164 if (errno != ESRCH)
1165 perror("detach: ptrace(PTRACE_CONT, ...)");
1166 break;
1167 }
1168 }
1169 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001170#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001171
1172#if defined(SUNOS4)
1173 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1174 if (sig && kill(tcp->pid, sig) < 0)
1175 perror("detach: kill");
1176 sig = 0;
1177 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1178 perror("detach: ptrace(PTRACE_DETACH, ...)");
1179#endif /* SUNOS4 */
1180
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001181#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001182 resumed = 0;
1183
1184 /* XXX This won't always be quite right (but it never was).
1185 A waiter with argument 0 or < -1 is waiting for any pid in
1186 a particular pgrp, which this child might or might not be
1187 in. The waiter will only wake up if it's argument is -1
1188 or if it's waiting for tcp->pid's pgrp. It makes a
1189 difference to wake up a waiter when there might be more
1190 traced children, because it could get a false ECHILD
1191 error. OTOH, if this was the last child in the pgrp, then
1192 it ought to wake up and get ECHILD. We would have to
1193 search the system for all pid's in the pgrp to be sure.
1194
1195 && (t->waitpid == -1 ||
1196 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1197 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1198 */
1199
1200 if (tcp->parent &&
1201 (tcp->parent->flags & TCB_SUSPENDED) &&
1202 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1203 error = resume(tcp->parent);
1204 ++resumed;
1205 }
1206#ifdef TCB_CLONE_THREAD
1207 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1208 /* Some other threads of our parent are waiting too. */
1209 unsigned int i;
1210
1211 /* Resume all the threads that were waiting for this PID. */
1212 for (i = 0; i < tcbtabsize; i++) {
1213 struct tcb *t = tcbtab[i];
1214 if (t->parent == tcp->parent && t != tcp
1215 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1216 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1217 && t->waitpid == tcp->pid) {
1218 error |= resume (t);
1219 ++resumed;
1220 }
1221 }
1222 if (resumed == 0)
1223 /* Noone was waiting for this PID in particular,
1224 so now we might need to resume some wildcarders. */
1225 for (i = 0; i < tcbtabsize; i++) {
1226 struct tcb *t = tcbtab[i];
1227 if (t->parent == tcp->parent && t != tcp
1228 && ((t->flags
1229 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1230 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1231 && t->waitpid <= 0
1232 ) {
1233 error |= resume (t);
1234 break;
1235 }
1236 }
1237 }
1238#endif
1239
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001240#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001241
1242 if (!qflag)
1243 fprintf(stderr, "Process %u detached\n", tcp->pid);
1244
1245 droptcb(tcp);
1246 return error;
1247}
1248
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001249#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001250
1251static void
1252reaper(sig)
1253int sig;
1254{
1255 int pid;
1256 int status;
1257
1258 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1259#if 0
1260 struct tcb *tcp;
1261
1262 tcp = pid2tcb(pid);
1263 if (tcp)
1264 droptcb(tcp);
1265#endif
1266 }
1267}
1268
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001269#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001270
1271static void
1272cleanup()
1273{
1274 int i;
1275 struct tcb *tcp;
1276
Roland McGrathee9d4352002-12-18 04:16:10 +00001277 for (i = 0; i < tcbtabsize; i++) {
1278 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001279 if (!(tcp->flags & TCB_INUSE))
1280 continue;
1281 if (debug)
1282 fprintf(stderr,
1283 "cleanup: looking at pid %u\n", tcp->pid);
1284 if (tcp_last &&
1285 (!outfname || followfork < 2 || tcp_last == tcp)) {
1286 tprintf(" <unfinished ...>\n");
1287 tcp_last = NULL;
1288 }
1289 if (tcp->flags & TCB_ATTACHED)
1290 detach(tcp, 0);
1291 else {
1292 kill(tcp->pid, SIGCONT);
1293 kill(tcp->pid, SIGTERM);
1294 }
1295 }
1296 if (cflag)
1297 call_summary(outf);
1298}
1299
1300static void
1301interrupt(sig)
1302int sig;
1303{
1304 interrupted = 1;
1305}
1306
1307#ifndef HAVE_STRERROR
1308
Roland McGrath6d2b3492002-12-30 00:51:30 +00001309#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001310extern int sys_nerr;
1311extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001312#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001313
1314const char *
1315strerror(errno)
1316int errno;
1317{
1318 static char buf[64];
1319
1320 if (errno < 1 || errno >= sys_nerr) {
1321 sprintf(buf, "Unknown error %d", errno);
1322 return buf;
1323 }
1324 return sys_errlist[errno];
1325}
1326
1327#endif /* HAVE_STERRROR */
1328
1329#ifndef HAVE_STRSIGNAL
1330
Roland McGrath8f474e02003-01-14 07:53:33 +00001331#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001332extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001333#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001334#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1335extern char *_sys_siglist[];
1336#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001337
1338const char *
1339strsignal(sig)
1340int sig;
1341{
1342 static char buf[64];
1343
1344 if (sig < 1 || sig >= NSIG) {
1345 sprintf(buf, "Unknown signal %d", sig);
1346 return buf;
1347 }
1348#ifdef HAVE__SYS_SIGLIST
1349 return _sys_siglist[sig];
1350#else
1351 return sys_siglist[sig];
1352#endif
1353}
1354
1355#endif /* HAVE_STRSIGNAL */
1356
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001357#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001358
1359static void
1360rebuild_pollv()
1361{
1362 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001363
Roland McGrathee9d4352002-12-18 04:16:10 +00001364 if (pollv != NULL)
1365 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001366 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001367 if (pollv == NULL) {
1368 fprintf(stderr, "strace: out of memory for poll vector\n");
1369 exit(1);
1370 }
1371
Roland McGrathca16be82003-01-10 19:55:28 +00001372 for (i = j = 0; i < tcbtabsize; i++) {
1373 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374 if (!(tcp->flags & TCB_INUSE))
1375 continue;
1376 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001377 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001378 j++;
1379 }
1380 if (j != nprocs) {
1381 fprintf(stderr, "strace: proc miscount\n");
1382 exit(1);
1383 }
1384}
1385
1386#ifndef HAVE_POLLABLE_PROCFS
1387
1388static void
1389proc_poll_open()
1390{
1391 int arg;
1392 int i;
1393
1394 if (pipe(proc_poll_pipe) < 0) {
1395 perror("pipe");
1396 exit(1);
1397 }
1398 for (i = 0; i < 2; i++) {
1399 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1400 perror("F_GETFD");
1401 exit(1);
1402 }
1403 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1404 perror("F_SETFD");
1405 exit(1);
1406 }
1407 }
1408}
1409
1410static int
1411proc_poll(pollv, nfds, timeout)
1412struct pollfd *pollv;
1413int nfds;
1414int timeout;
1415{
1416 int i;
1417 int n;
1418 struct proc_pollfd pollinfo;
1419
1420 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1421 return n;
1422 if (n != sizeof(struct proc_pollfd)) {
1423 fprintf(stderr, "panic: short read: %d\n", n);
1424 exit(1);
1425 }
1426 for (i = 0; i < nprocs; i++) {
1427 if (pollv[i].fd == pollinfo.fd)
1428 pollv[i].revents = pollinfo.revents;
1429 else
1430 pollv[i].revents = 0;
1431 }
1432 poller_pid = pollinfo.pid;
1433 return 1;
1434}
1435
1436static void
1437wakeup_handler(sig)
1438int sig;
1439{
1440}
1441
1442static void
1443proc_poller(pfd)
1444int pfd;
1445{
1446 struct proc_pollfd pollinfo;
1447 struct sigaction sa;
1448 sigset_t blocked_set, empty_set;
1449 int i;
1450 int n;
1451 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001452#ifdef FREEBSD
1453 struct procfs_status pfs;
1454#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001455
1456 switch (fork()) {
1457 case -1:
1458 perror("fork");
1459 _exit(0);
1460 case 0:
1461 break;
1462 default:
1463 return;
1464 }
1465
1466 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1467 sa.sa_flags = 0;
1468 sigemptyset(&sa.sa_mask);
1469 sigaction(SIGHUP, &sa, NULL);
1470 sigaction(SIGINT, &sa, NULL);
1471 sigaction(SIGQUIT, &sa, NULL);
1472 sigaction(SIGPIPE, &sa, NULL);
1473 sigaction(SIGTERM, &sa, NULL);
1474 sa.sa_handler = wakeup_handler;
1475 sigaction(SIGUSR1, &sa, NULL);
1476 sigemptyset(&blocked_set);
1477 sigaddset(&blocked_set, SIGUSR1);
1478 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1479 sigemptyset(&empty_set);
1480
1481 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1482 perror("getrlimit(RLIMIT_NOFILE, ...)");
1483 _exit(0);
1484 }
1485 n = rl.rlim_cur;
1486 for (i = 0; i < n; i++) {
1487 if (i != pfd && i != proc_poll_pipe[1])
1488 close(i);
1489 }
1490
1491 pollinfo.fd = pfd;
1492 pollinfo.pid = getpid();
1493 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001494#ifndef FREEBSD
1495 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1496#else /* FREEBSD */
1497 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1498#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001499 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001500 switch (errno) {
1501 case EINTR:
1502 continue;
1503 case EBADF:
1504 pollinfo.revents = POLLERR;
1505 break;
1506 case ENOENT:
1507 pollinfo.revents = POLLHUP;
1508 break;
1509 default:
1510 perror("proc_poller: PIOCWSTOP");
1511 }
1512 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1513 _exit(0);
1514 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001515 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001516 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1517 sigsuspend(&empty_set);
1518 }
1519}
1520
1521#endif /* !HAVE_POLLABLE_PROCFS */
1522
1523static int
1524choose_pfd()
1525{
1526 int i, j;
1527 struct tcb *tcp;
1528
1529 static int last;
1530
1531 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001532 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001533 /*
1534 * The previous process is ready to run again. We'll
1535 * let it do so if it is currently in a syscall. This
1536 * heuristic improves the readability of the trace.
1537 */
1538 tcp = pfd2tcb(pollv[last].fd);
1539 if (tcp && (tcp->flags & TCB_INSYSCALL))
1540 return pollv[last].fd;
1541 }
1542
1543 for (i = 0; i < nprocs; i++) {
1544 /* Let competing children run round robin. */
1545 j = (i + last + 1) % nprocs;
1546 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1547 tcp = pfd2tcb(pollv[j].fd);
1548 if (!tcp) {
1549 fprintf(stderr, "strace: lost proc\n");
1550 exit(1);
1551 }
1552 droptcb(tcp);
1553 return -1;
1554 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001555 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001556 last = j;
1557 return pollv[j].fd;
1558 }
1559 }
1560 fprintf(stderr, "strace: nothing ready\n");
1561 exit(1);
1562}
1563
1564static int
1565trace()
1566{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001567#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001568 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001569#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001570 struct tcb *tcp;
1571 int pfd;
1572 int what;
1573 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001574 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001575
1576 for (;;) {
1577 if (interactive)
1578 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1579
1580 if (nprocs == 0)
1581 break;
1582
1583 switch (nprocs) {
1584 case 1:
1585#ifndef HAVE_POLLABLE_PROCFS
1586 if (proc_poll_pipe[0] == -1) {
1587#endif
1588 tcp = pid2tcb(0);
1589 if (!tcp)
1590 continue;
1591 pfd = tcp->pfd;
1592 if (pfd == -1)
1593 continue;
1594 break;
1595#ifndef HAVE_POLLABLE_PROCFS
1596 }
1597 /* fall through ... */
1598#endif /* !HAVE_POLLABLE_PROCFS */
1599 default:
1600#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001601#ifdef POLL_HACK
1602 /* On some systems (e.g. UnixWare) we get too much ugly
1603 "unfinished..." stuff when multiple proceses are in
1604 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001605
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001606 if (in_syscall) {
1607 struct pollfd pv;
1608 tcp = in_syscall;
1609 in_syscall = NULL;
1610 pv.fd = tcp->pfd;
1611 pv.events = POLLWANT;
1612 if ((what = poll (&pv, 1, 1)) < 0) {
1613 if (interrupted)
1614 return 0;
1615 continue;
1616 }
1617 else if (what == 1 && pv.revents & POLLWANT) {
1618 goto FOUND;
1619 }
1620 }
1621#endif
1622
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 if (poll(pollv, nprocs, INFTIM) < 0) {
1624 if (interrupted)
1625 return 0;
1626 continue;
1627 }
1628#else /* !HAVE_POLLABLE_PROCFS */
1629 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1630 if (interrupted)
1631 return 0;
1632 continue;
1633 }
1634#endif /* !HAVE_POLLABLE_PROCFS */
1635 pfd = choose_pfd();
1636 if (pfd == -1)
1637 continue;
1638 break;
1639 }
1640
1641 /* Look up `pfd' in our table. */
1642 if ((tcp = pfd2tcb(pfd)) == NULL) {
1643 fprintf(stderr, "unknown pfd: %u\n", pfd);
1644 exit(1);
1645 }
John Hughesb6643082002-05-23 11:02:22 +00001646#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001647 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001648#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001649 /* Get the status of the process. */
1650 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001651#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001652 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001653#else /* FREEBSD */
1654 /* Thanks to some scheduling mystery, the first poller
1655 sometimes waits for the already processed end of fork
1656 event. Doing a non blocking poll here solves the problem. */
1657 if (proc_poll_pipe[0] != -1)
1658 ioctl_result = IOCTL_STATUS (tcp);
1659 else
1660 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001661#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001662 ioctl_errno = errno;
1663#ifndef HAVE_POLLABLE_PROCFS
1664 if (proc_poll_pipe[0] != -1) {
1665 if (ioctl_result < 0)
1666 kill(poller_pid, SIGKILL);
1667 else
1668 kill(poller_pid, SIGUSR1);
1669 }
1670#endif /* !HAVE_POLLABLE_PROCFS */
1671 }
1672 if (interrupted)
1673 return 0;
1674
1675 if (interactive)
1676 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1677
1678 if (ioctl_result < 0) {
1679 /* Find out what happened if it failed. */
1680 switch (ioctl_errno) {
1681 case EINTR:
1682 case EBADF:
1683 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001684#ifdef FREEBSD
1685 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001686#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001687 case ENOENT:
1688 droptcb(tcp);
1689 continue;
1690 default:
1691 perror("PIOCWSTOP");
1692 exit(1);
1693 }
1694 }
1695
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001696#ifdef FREEBSD
1697 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1698 /* discard first event for a syscall we never entered */
1699 IOCTL (tcp->pfd, PIOCRUN, 0);
1700 continue;
1701 }
Roland McGrath553a6092002-12-16 20:40:39 +00001702#endif
1703
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001704 /* clear the just started flag */
1705 tcp->flags &= ~TCB_STARTUP;
1706
1707 /* set current output file */
1708 outf = tcp->outf;
1709
1710 if (cflag) {
1711 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001712#ifdef FREEBSD
1713 char buf[1024];
1714 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001716 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1717 buf[len] = '\0';
1718 sscanf(buf,
1719 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1720 &stime.tv_sec, &stime.tv_usec);
1721 } else
1722 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001723#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001724 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1725 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001726#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001727 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1728 tcp->stime = stime;
1729 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001730 what = tcp->status.PR_WHAT;
1731 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001732#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001734 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1735 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001736 if (trace_syscall(tcp) < 0) {
1737 fprintf(stderr, "syscall trouble\n");
1738 exit(1);
1739 }
1740 }
1741 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001742#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001743 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001744#ifdef POLL_HACK
1745 in_syscall = tcp;
1746#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001747 case PR_SYSEXIT:
1748 if (trace_syscall(tcp) < 0) {
1749 fprintf(stderr, "syscall trouble\n");
1750 exit(1);
1751 }
1752 break;
1753 case PR_SIGNALLED:
1754 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1755 printleader(tcp);
1756 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001757 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001758 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001759#ifdef PR_INFO
1760 if (tcp->status.PR_INFO.si_signo == what) {
1761 printleader(tcp);
1762 tprintf(" siginfo=");
1763 printsiginfo(&tcp->status.PR_INFO, 1);
1764 printtrailer(tcp);
1765 }
1766#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001767 }
1768 break;
1769 case PR_FAULTED:
1770 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1771 printleader(tcp);
1772 tprintf("=== FAULT %d ===", what);
1773 printtrailer(tcp);
1774 }
1775 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001776#ifdef FREEBSD
1777 case 0: /* handle case we polled for nothing */
1778 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001779#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001780 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001781 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001782 exit(1);
1783 break;
1784 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001785 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001786#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001787 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001788#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001789 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001790#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001791 perror("PIOCRUN");
1792 exit(1);
1793 }
1794 }
1795 return 0;
1796}
1797
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001798#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001799
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001800#ifdef TCB_GROUP_EXITING
1801/* Handle an exit detach or death signal that is taking all the
1802 related clone threads with it. This is called in three circumstances:
1803 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1804 SIG == 0 Continuing TCP will perform an exit_group syscall.
1805 SIG == other Continuing TCP with SIG will kill the process.
1806*/
1807static int
1808handle_group_exit(struct tcb *tcp, int sig)
1809{
1810 /* We need to locate our records of all the clone threads
1811 related to TCP, either its children or siblings. */
1812 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1813 ? tcp->parent
1814 : tcp->nclone_detached > 0
1815 ? tcp : NULL);
1816
1817 if (sig < 0) {
1818 if (leader != NULL && leader != tcp)
1819 fprintf(stderr,
1820 "PANIC: handle_group_exit: %d leader %d\n",
1821 tcp->pid, leader ? leader->pid : -1);
1822 droptcb(tcp); /* Already died. */
1823 }
1824 else {
1825 if (tcp->flags & TCB_ATTACHED) {
1826 if (leader != NULL && leader != tcp) {
1827 /* We need to detach the leader so that the
1828 process death will be reported to its real
1829 parent. But we kill it first to prevent
1830 it doing anything before we kill the whole
1831 process in a moment. We can use
1832 PTRACE_KILL on a thread that's not already
1833 stopped. Then the value we pass in
1834 PTRACE_DETACH just sets the death
1835 signal reported to the real parent. */
1836 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1837 if (debug)
1838 fprintf(stderr,
1839 " [%d exit %d kills %d]\n",
1840 tcp->pid, sig, leader->pid);
1841 detach(leader, sig);
1842 }
1843 detach(tcp, sig);
1844 }
1845 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1846 perror("strace: ptrace(PTRACE_CONT, ...)");
1847 cleanup();
1848 return -1;
1849 }
1850 else {
1851 if (leader != NULL && leader != tcp)
1852 droptcb(tcp);
1853 /* The leader will report to us as parent now,
1854 and then we'll get to the SIG==-1 case. */
1855 return 0;
1856 }
1857 }
1858
1859 /* Note that TCP and LEADER are no longer valid,
1860 but we can still compare against them. */
1861 if (leader != NULL) {
1862 unsigned int i;
1863 for (i = 0; i < tcbtabsize; i++) {
1864 struct tcb *t = tcbtab[i];
1865 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1866 && t->parent == leader)
1867 droptcb(t);
1868 }
1869 }
1870
1871 return 0;
1872}
1873#endif
1874
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001875static int
1876trace()
1877{
1878 int pid;
1879 int wait_errno;
1880 int status;
1881 struct tcb *tcp;
1882#ifdef LINUX
1883 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001884#ifdef __WALL
1885 static int wait4_options = __WALL;
1886#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001887#endif /* LINUX */
1888
1889 while (nprocs != 0) {
1890 if (interactive)
1891 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1892#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001893#ifdef __WALL
1894 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00001895 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001896 /* this kernel does not support __WALL */
1897 wait4_options &= ~__WALL;
1898 errno = 0;
1899 pid = wait4(-1, &status, wait4_options,
1900 cflag ? &ru : NULL);
1901 }
Roland McGrath5bc05552002-12-17 04:50:47 +00001902 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001903 /* most likely a "cloned" process */
1904 pid = wait4(-1, &status, __WCLONE,
1905 cflag ? &ru : NULL);
1906 if (pid == -1) {
1907 fprintf(stderr, "strace: clone wait4 "
1908 "failed: %s\n", strerror(errno));
1909 }
1910 }
1911#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001912 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001913#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001914#endif /* LINUX */
1915#ifdef SUNOS4
1916 pid = wait(&status);
1917#endif /* SUNOS4 */
1918 wait_errno = errno;
1919 if (interactive)
1920 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1921
1922 if (interrupted)
1923 return 0;
1924
1925 if (pid == -1) {
1926 switch (wait_errno) {
1927 case EINTR:
1928 continue;
1929 case ECHILD:
1930 /*
1931 * We would like to verify this case
1932 * but sometimes a race in Solbourne's
1933 * version of SunOS sometimes reports
1934 * ECHILD before sending us SIGCHILD.
1935 */
1936#if 0
1937 if (nprocs == 0)
1938 return 0;
1939 fprintf(stderr, "strace: proc miscount\n");
1940 exit(1);
1941#endif
1942 return 0;
1943 default:
1944 errno = wait_errno;
1945 perror("strace: wait");
1946 return -1;
1947 }
1948 }
1949 if (debug)
1950 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1951
1952 /* Look up `pid' in our table. */
1953 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001954#ifdef LINUX
1955 if (followfork || followvfork) {
1956 /* This is needed to go with the CLONE_PTRACE
1957 changes in process.c/util.c: we might see
1958 the child's initial trap before we see the
1959 parent return from the clone syscall.
1960 Leave the child suspended until the parent
1961 returns from its system call. Only then
1962 will we have the association of parent and
1963 child so that we know how to do clearbpt
1964 in the child. */
1965 if ((tcp = alloctcb(pid)) == NULL) {
1966 fprintf(stderr, " [tcb table full]\n");
1967 kill(pid, SIGKILL); /* XXX */
1968 return 0;
1969 }
1970 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
1971 newoutf(tcp);
1972 if (!qflag)
1973 fprintf(stderr, "\
1974Process %d attached (waiting for parent)\n",
1975 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001976 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001977 else
1978 /* This can happen if a clone call used
1979 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001980#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001981 {
1982 fprintf(stderr, "unknown pid: %u\n", pid);
1983 if (WIFSTOPPED(status))
1984 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1985 exit(1);
1986 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001987 }
1988 /* set current output file */
1989 outf = tcp->outf;
1990 if (cflag) {
1991#ifdef LINUX
1992 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
1993 tcp->stime = ru.ru_stime;
1994#endif /* !LINUX */
1995 }
1996
1997 if (tcp->flags & TCB_SUSPENDED) {
1998 /*
1999 * Apparently, doing any ptrace() call on a stopped
2000 * process, provokes the kernel to report the process
2001 * status again on a subsequent wait(), even if the
2002 * process has not been actually restarted.
2003 * Since we have inspected the arguments of suspended
2004 * processes we end up here testing for this case.
2005 */
2006 continue;
2007 }
2008 if (WIFSIGNALED(status)) {
2009 if (!cflag
2010 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2011 printleader(tcp);
2012 tprintf("+++ killed by %s +++",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002013 signame(WTERMSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002014 printtrailer(tcp);
2015 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002016#ifdef TCB_GROUP_EXITING
2017 handle_group_exit(tcp, -1);
2018#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002019 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002020#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002021 continue;
2022 }
2023 if (WIFEXITED(status)) {
2024 if (debug)
2025 fprintf(stderr, "pid %u exited\n", pid);
2026 if (tcp->flags & TCB_ATTACHED)
2027 fprintf(stderr,
2028 "PANIC: attached pid %u exited\n",
2029 pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002030#ifdef TCB_GROUP_EXITING
2031 handle_group_exit(tcp, -1);
2032#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002033 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002034#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002035 continue;
2036 }
2037 if (!WIFSTOPPED(status)) {
2038 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2039 droptcb(tcp);
2040 continue;
2041 }
2042 if (debug)
2043 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002044 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002045
2046 if (tcp->flags & TCB_STARTUP) {
2047 /*
2048 * This flag is there to keep us in sync.
2049 * Next time this process stops it should
2050 * really be entering a system call.
2051 */
2052 tcp->flags &= ~TCB_STARTUP;
2053 if (tcp->flags & TCB_ATTACHED) {
2054 /*
2055 * Interestingly, the process may stop
2056 * with STOPSIG equal to some other signal
2057 * than SIGSTOP if we happend to attach
2058 * just before the process takes a signal.
2059 */
2060 if (!WIFSTOPPED(status)) {
2061 fprintf(stderr,
2062 "pid %u not stopped\n", pid);
2063 detach(tcp, WSTOPSIG(status));
2064 continue;
2065 }
2066 }
2067 else {
2068#ifdef SUNOS4
2069 /* A child of us stopped at exec */
2070 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2071 fixvfork(tcp);
2072#endif /* SUNOS4 */
2073 }
2074 if (tcp->flags & TCB_BPTSET) {
2075 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2076 droptcb(tcp);
2077 cleanup();
2078 return -1;
2079 }
2080 }
2081 goto tracing;
2082 }
2083
2084 if (WSTOPSIG(status) != SIGTRAP) {
2085 if (WSTOPSIG(status) == SIGSTOP &&
2086 (tcp->flags & TCB_SIGTRAPPED)) {
2087 /*
2088 * Trapped attempt to block SIGTRAP
2089 * Hope we are back in control now.
2090 */
2091 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2092 if (ptrace(PTRACE_SYSCALL,
2093 pid, (char *) 1, 0) < 0) {
2094 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2095 cleanup();
2096 return -1;
2097 }
2098 continue;
2099 }
2100 if (!cflag
2101 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002102 unsigned long addr = 0, pc = 0;
2103#ifdef PT_GETSIGINFO
2104# define PSR_RI 41
2105 struct siginfo si;
2106 unsigned long psr;
2107
2108 upeek(pid, PT_CR_IPSR, &psr);
2109 upeek(pid, PT_CR_IIP, &pc);
2110
2111 pc += (psr >> PSR_RI) & 0x3;
2112 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2113 addr = (unsigned long) si.si_addr;
2114#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002115 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002116 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002117 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002118 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002119 printtrailer(tcp);
2120 }
2121 if ((tcp->flags & TCB_ATTACHED) &&
2122 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002123#ifdef TCB_GROUP_EXITING
2124 handle_group_exit(tcp, WSTOPSIG(status));
2125#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002126 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002127#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002128 continue;
2129 }
2130 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2131 WSTOPSIG(status)) < 0) {
2132 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2133 cleanup();
2134 return -1;
2135 }
2136 tcp->flags &= ~TCB_SUSPENDED;
2137 continue;
2138 }
2139 if (trace_syscall(tcp) < 0) {
2140 if (tcp->flags & TCB_ATTACHED)
2141 detach(tcp, 0);
2142 else {
2143 ptrace(PTRACE_KILL,
2144 tcp->pid, (char *) 1, SIGTERM);
2145 droptcb(tcp);
2146 }
2147 continue;
2148 }
2149 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002150#ifdef TCB_GROUP_EXITING
2151 if (tcp->flags & TCB_GROUP_EXITING) {
2152 if (handle_group_exit(tcp, 0) < 0)
2153 return -1;
2154 continue;
2155 }
2156#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002157 if (tcp->flags & TCB_ATTACHED)
2158 detach(tcp, 0);
2159 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2160 perror("strace: ptrace(PTRACE_CONT, ...)");
2161 cleanup();
2162 return -1;
2163 }
2164 continue;
2165 }
2166 if (tcp->flags & TCB_SUSPENDED) {
2167 if (!qflag)
2168 fprintf(stderr, "Process %u suspended\n", pid);
2169 continue;
2170 }
2171 tracing:
2172 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2173 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2174 cleanup();
2175 return -1;
2176 }
2177 }
2178 return 0;
2179}
2180
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002181#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002182
2183static int curcol;
2184
2185#ifdef __STDC__
2186#include <stdarg.h>
2187#define VA_START(a, b) va_start(a, b)
2188#else
2189#include <varargs.h>
2190#define VA_START(a, b) va_start(a)
2191#endif
2192
2193void
2194#ifdef __STDC__
2195tprintf(const char *fmt, ...)
2196#else
2197tprintf(fmt, va_alist)
2198char *fmt;
2199va_dcl
2200#endif
2201{
2202 va_list args;
2203
2204 VA_START(args, fmt);
2205 if (outf)
2206 curcol += vfprintf(outf, fmt, args);
2207 va_end(args);
2208 return;
2209}
2210
2211void
2212printleader(tcp)
2213struct tcb *tcp;
2214{
2215 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2216 tcp_last->flags |= TCB_REPRINT;
2217 tprintf(" <unfinished ...>\n");
2218 }
2219 curcol = 0;
2220 if ((followfork == 1 || pflag_seen > 1) && outfname)
2221 tprintf("%-5d ", tcp->pid);
2222 else if (nprocs > 1 && !outfname)
2223 tprintf("[pid %5u] ", tcp->pid);
2224 if (tflag) {
2225 char str[sizeof("HH:MM:SS")];
2226 struct timeval tv, dtv;
2227 static struct timeval otv;
2228
2229 gettimeofday(&tv, NULL);
2230 if (rflag) {
2231 if (otv.tv_sec == 0)
2232 otv = tv;
2233 tv_sub(&dtv, &tv, &otv);
2234 tprintf("%6ld.%06ld ",
2235 (long) dtv.tv_sec, (long) dtv.tv_usec);
2236 otv = tv;
2237 }
2238 else if (tflag > 2) {
2239 tprintf("%ld.%06ld ",
2240 (long) tv.tv_sec, (long) tv.tv_usec);
2241 }
2242 else {
2243 time_t local = tv.tv_sec;
2244 strftime(str, sizeof(str), "%T", localtime(&local));
2245 if (tflag > 1)
2246 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2247 else
2248 tprintf("%s ", str);
2249 }
2250 }
2251 if (iflag)
2252 printcall(tcp);
2253}
2254
2255void
2256tabto(col)
2257int col;
2258{
2259 if (curcol < col)
2260 tprintf("%*s", col - curcol, "");
2261}
2262
2263void
2264printtrailer(tcp)
2265struct tcb *tcp;
2266{
2267 tprintf("\n");
2268 tcp_last = NULL;
2269}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002270
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002271#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002272
2273int mp_ioctl (int fd, int cmd, void *arg, int size) {
2274
2275 struct iovec iov[2];
2276 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002277
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002278 iov[0].iov_base = &cmd;
2279 iov[0].iov_len = sizeof cmd;
2280 if (arg) {
2281 ++n;
2282 iov[1].iov_base = arg;
2283 iov[1].iov_len = size;
2284 }
Roland McGrath553a6092002-12-16 20:40:39 +00002285
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002286 return writev (fd, iov, n);
2287}
2288
2289#endif