blob: 6171245495fcaef0edfd099334feedc77aed24fc [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;
Roland McGrathfd3e0422002-12-30 09:33:22 +000084extern const char version[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000085extern char **environ;
86
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000087static int trace P((void));
88static void cleanup P((void));
89static void interrupt P((int sig));
90static sigset_t empty_set, blocked_set;
91
92#ifdef HAVE_SIG_ATOMIC_T
93static volatile sig_atomic_t interrupted;
94#else /* !HAVE_SIG_ATOMIC_T */
95#ifdef __STDC__
96static volatile int interrupted;
97#else /* !__STDC__ */
98static int interrupted;
99#endif /* !__STDC__ */
100#endif /* !HAVE_SIG_ATOMIC_T */
101
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000102#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000103
104static struct tcb *pfd2tcb P((int pfd));
105static void reaper P((int sig));
106static void rebuild_pollv P((void));
Roland McGrathee9d4352002-12-18 04:16:10 +0000107static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000108
109#ifndef HAVE_POLLABLE_PROCFS
110
111static void proc_poll_open P((void));
112static void proc_poller P((int pfd));
113
114struct proc_pollfd {
115 int fd;
116 int revents;
117 int pid;
118};
119
120static int poller_pid;
121static int proc_poll_pipe[2] = { -1, -1 };
122
123#endif /* !HAVE_POLLABLE_PROCFS */
124
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000125#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000126#define POLLWANT POLLWRNORM
127#else
128#define POLLWANT POLLPRI
129#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000130#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000131
132static void
133usage(ofp, exitval)
134FILE *ofp;
135int exitval;
136{
137 fprintf(ofp, "\
138usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000139 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
140 [command [arg ...]]\n\
141 or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
142 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000143-c -- count time, calls, and errors for each syscall and report summary\n\
144-f -- follow forks, -ff -- with output into separate files\n\
145-F -- attempt to follow vforks, -h -- print help message\n\
146-i -- print instruction pointer at time of syscall\n\
147-q -- suppress messages about attaching, detaching, etc.\n\
148-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
149-T -- print time spent in each syscall, -V -- print version\n\
150-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
151-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
152-a column -- alignment COLUMN for printing syscall results (default %d)\n\
153-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
154 options: trace, abbrev, verbose, raw, signal, read, or write\n\
155-o file -- send trace output to FILE instead of stderr\n\
156-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
157-p pid -- trace process with process id PID, may be repeated\n\
158-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
159-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
160-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000161-E var=val -- put var=val in the environment for command\n\
162-E var -- remove var from the environment for command\n\
163" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000164-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000165 */
166, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167 exit(exitval);
168}
169
170#ifdef SVR4
171#ifdef MIPS
172void
173foobar()
174{
175}
176#endif /* MIPS */
177#endif /* SVR4 */
178
179int
180main(argc, argv)
181int argc;
182char *argv[];
183{
184 extern int optind;
185 extern char *optarg;
186 struct tcb *tcp;
187 int c, pid = 0;
188 struct sigaction sa;
189
190 static char buf[BUFSIZ];
191
Roland McGrathee9d4352002-12-18 04:16:10 +0000192 /* Allocate the initial tcbtab. */
193 tcbtabsize = argc; /* Surely enough for all -p args. */
194 tcbtab = (struct tcb **) malloc (tcbtabsize * sizeof tcbtab[0]);
195 tcbtab[0] = (struct tcb *) calloc (tcbtabsize, sizeof *tcbtab[0]);
196 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
197 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
198
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199 progname = argv[0];
200 outf = stderr;
201 interactive = 1;
202 qualify("trace=all");
203 qualify("abbrev=all");
204 qualify("verbose=all");
205 qualify("signal=all");
206 set_sortby(DEFAULT_SORTBY);
207 set_personality(DEFAULT_PERSONALITY);
208 while ((c = getopt(argc, argv,
Roland McGrathde6e5332003-01-24 04:31:23 +0000209 "+cdfFhiqrtTvVxza:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000210 switch (c) {
211 case 'c':
212 cflag++;
213 dtime++;
214 break;
215 case 'd':
216 debug++;
217 break;
218 case 'f':
219 followfork++;
220 break;
221 case 'F':
222 followvfork++;
223 break;
224 case 'h':
225 usage(stdout, 0);
226 break;
227 case 'i':
228 iflag++;
229 break;
230 case 'q':
231 qflag++;
232 break;
233 case 'r':
234 rflag++;
235 tflag++;
236 break;
237 case 't':
238 tflag++;
239 break;
240 case 'T':
241 dtime++;
242 break;
243 case 'x':
244 xflag++;
245 break;
246 case 'v':
247 qualify("abbrev=none");
248 break;
249 case 'V':
250 printf("%s\n", version);
251 exit(0);
252 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000253 case 'z':
254 not_failing_only = 1;
255 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000256 case 'a':
257 acolumn = atoi(optarg);
258 break;
259 case 'e':
260 qualify(optarg);
261 break;
262 case 'o':
263 outfname = strdup(optarg);
264 break;
265 case 'O':
266 set_overhead(atoi(optarg));
267 break;
268 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000269 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000270 fprintf(stderr, "%s: Invalid process id: %s\n",
271 progname, optarg);
272 break;
273 }
274 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000275 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000276 break;
277 }
278 if ((tcp = alloctcb(pid)) == NULL) {
Roland McGrathde6e5332003-01-24 04:31:23 +0000279 fprintf(stderr, "%s: out of memory\n",
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 progname);
281 exit(1);
282 }
283 tcp->flags |= TCB_ATTACHED;
284 pflag_seen++;
285 break;
286 case 's':
287 max_strlen = atoi(optarg);
288 break;
289 case 'S':
290 set_sortby(optarg);
291 break;
292 case 'u':
293 username = strdup(optarg);
294 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000295 case 'E':
296 if (putenv(optarg) < 0) {
297 fprintf(stderr, "%s: out of memory\n",
298 progname);
299 exit(1);
300 }
301 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000302 default:
303 usage(stderr, 1);
304 break;
305 }
306 }
307
308 /* See if they want to run as another user. */
309 if (username != NULL) {
310 struct passwd *pent;
311
312 if (getuid() != 0 || geteuid() != 0) {
313 fprintf(stderr,
314 "%s: you must be root to use the -u option\n",
315 progname);
316 exit(1);
317 }
318 if ((pent = getpwnam(username)) == NULL) {
319 fprintf(stderr, "%s: cannot find user `%s'\n",
320 progname, optarg);
321 exit(1);
322 }
323 run_uid = pent->pw_uid;
324 run_gid = pent->pw_gid;
325 }
326 else {
327 run_uid = getuid();
328 run_gid = getgid();
329 }
330
331#ifndef SVR4
332 setreuid(geteuid(), getuid());
333#endif
334
335 /* See if they want to pipe the output. */
336 if (outfname && (outfname[0] == '|' || outfname[0] == '!')) {
337 if ((outf = popen(outfname + 1, "w")) == NULL) {
338 fprintf(stderr, "%s: can't popen '%s': %s\n",
339 progname, outfname + 1, strerror(errno));
340 exit(1);
341 }
342 free(outfname);
343 outfname = NULL;
344 }
345
346 /* Check if they want to redirect the output. */
347 if (outfname) {
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000348 long f;
349
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000350 if ((outf = fopen(outfname, "w")) == NULL) {
351 fprintf(stderr, "%s: can't fopen '%s': %s\n",
352 progname, outfname, strerror(errno));
353 exit(1);
354 }
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000355
356 if ((f=fcntl(fileno(outf), F_GETFD)) < 0 ) {
357 perror("failed to get flags for outputfile");
358 exit(1);
359 }
360
361 if (fcntl(fileno(outf), F_SETFD, f|FD_CLOEXEC) < 0 ) {
362 perror("failed to set flags for outputfile");
363 exit(1);
364 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000365 }
366
367#ifndef SVR4
368 setreuid(geteuid(), getuid());
369#endif
370
371 if (!outfname) {
372 qflag = 1;
373 setvbuf(outf, buf, _IOLBF, BUFSIZ);
374 }
375 else if (optind < argc)
376 interactive = 0;
377 else
378 qflag = 1;
379
Roland McGrathee9d4352002-12-18 04:16:10 +0000380 for (c = 0; c < tcbtabsize; c++) {
381 tcp = tcbtab[c];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000382 /* Reinitialize the output since it may have changed. */
383 tcp->outf = outf;
384 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
385 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000386#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000387 if (proc_open(tcp, 1) < 0) {
388 fprintf(stderr, "trouble opening proc file\n");
389 droptcb(tcp);
390 continue;
391 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000392#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000393 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
394 perror("attach: ptrace(PTRACE_ATTACH, ...)");
395 droptcb(tcp);
396 continue;
397 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000398#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000399 if (!qflag)
400 fprintf(stderr,
401 "Process %u attached - interrupt to quit\n",
402 pid);
403 }
404
405 if (optind < argc) {
406 struct stat statbuf;
407 char *filename;
408 char pathname[MAXPATHLEN];
409
410 filename = argv[optind];
411 if (strchr(filename, '/'))
412 strcpy(pathname, filename);
413#ifdef USE_DEBUGGING_EXEC
414 /*
415 * Debuggers customarily check the current directory
416 * first regardless of the path but doing that gives
417 * security geeks a panic attack.
418 */
419 else if (stat(filename, &statbuf) == 0)
420 strcpy(pathname, filename);
421#endif /* USE_DEBUGGING_EXEC */
422 else {
423 char *path;
424 int m, n, len;
425
426 for (path = getenv("PATH"); path && *path; path += m) {
427 if (strchr(path, ':')) {
428 n = strchr(path, ':') - path;
429 m = n + 1;
430 }
431 else
432 m = n = strlen(path);
433 if (n == 0) {
434 getcwd(pathname, MAXPATHLEN);
435 len = strlen(pathname);
436 }
437 else {
438 strncpy(pathname, path, n);
439 len = n;
440 }
441 if (len && pathname[len - 1] != '/')
442 pathname[len++] = '/';
443 strcpy(pathname + len, filename);
444 if (stat(pathname, &statbuf) == 0)
445 break;
446 }
447 }
448 if (stat(pathname, &statbuf) < 0) {
449 fprintf(stderr, "%s: %s: command not found\n",
450 progname, filename);
451 exit(1);
452 }
453 switch (pid = fork()) {
454 case -1:
455 perror("strace: fork");
456 cleanup();
457 exit(1);
458 break;
459 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000460#ifdef USE_PROCFS
461 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000462#ifdef MIPS
463 /* Kludge for SGI, see proc_open for details. */
464 sa.sa_handler = foobar;
465 sa.sa_flags = 0;
466 sigemptyset(&sa.sa_mask);
467 sigaction(SIGINT, &sa, NULL);
468#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000469#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000470 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000471#else /* FREEBSD */
472 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000473#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000474#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000475 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000476 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000477
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000478 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
479 perror("strace: ptrace(PTRACE_TRACEME, ...)");
480 return -1;
481 }
482 if (debug)
483 kill(getpid(), SIGSTOP);
484
485 if (username != NULL || geteuid() == 0) {
486 uid_t run_euid = run_uid;
487 gid_t run_egid = run_gid;
488
489 if (statbuf.st_mode & S_ISUID)
490 run_euid = statbuf.st_uid;
491 if (statbuf.st_mode & S_ISGID)
492 run_egid = statbuf.st_gid;
493
494 /*
495 * It is important to set groups before we
496 * lose privileges on setuid.
497 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000498 if (username != NULL) {
499 if (initgroups(username, run_gid) < 0) {
500 perror("initgroups");
501 exit(1);
502 }
503 if (setregid(run_gid, run_egid) < 0) {
504 perror("setregid");
505 exit(1);
506 }
507 if (setreuid(run_uid, run_euid) < 0) {
508 perror("setreuid");
509 exit(1);
510 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000511 }
512 }
513 else
514 setreuid(run_uid, run_uid);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000515#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000516
517 execv(pathname, &argv[optind]);
518 perror("strace: exec");
519 _exit(1);
520 break;
521 }
522 default:
523 if ((tcp = alloctcb(pid)) == NULL) {
524 fprintf(stderr, "tcb table full\n");
525 cleanup();
526 exit(1);
527 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000528#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000529 if (proc_open(tcp, 0) < 0) {
530 fprintf(stderr, "trouble opening proc file\n");
531 cleanup();
532 exit(1);
533 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000534#endif /* USE_PROCFS */
535#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000536 fake_execve(tcp, pathname, &argv[optind], environ);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000537#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538 break;
539 }
540 }
541 else if (pflag_seen == 0)
542 usage(stderr, 1);
543
544 sigemptyset(&empty_set);
545 sigemptyset(&blocked_set);
546 sa.sa_handler = SIG_IGN;
547 sigemptyset(&sa.sa_mask);
548 sa.sa_flags = 0;
549 sigaction(SIGTTOU, &sa, NULL);
550 sigaction(SIGTTIN, &sa, NULL);
551 if (interactive) {
552 sigaddset(&blocked_set, SIGHUP);
553 sigaddset(&blocked_set, SIGINT);
554 sigaddset(&blocked_set, SIGQUIT);
555 sigaddset(&blocked_set, SIGPIPE);
556 sigaddset(&blocked_set, SIGTERM);
557 sa.sa_handler = interrupt;
558#ifdef SUNOS4
559 /* POSIX signals on sunos4.1 are a little broken. */
560 sa.sa_flags = SA_INTERRUPT;
561#endif /* SUNOS4 */
562 }
563 sigaction(SIGHUP, &sa, NULL);
564 sigaction(SIGINT, &sa, NULL);
565 sigaction(SIGQUIT, &sa, NULL);
566 sigaction(SIGPIPE, &sa, NULL);
567 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000568#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000569 sa.sa_handler = reaper;
570 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000571#else
572 /* Make sure SIGCHLD has the default action so that waitpid
573 definitely works without losing track of children. The user
574 should not have given us a bogus state to inherit, but he might
575 have. Arguably we should detect SIG_IGN here and pass it on
576 to children, but probably noone really needs that. */
577 sa.sa_handler = SIG_DFL;
578 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000579#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000580
581 if (trace() < 0)
582 exit(1);
583 cleanup();
584 exit(0);
585}
586
587void
588newoutf(tcp)
589struct tcb *tcp;
590{
591 char name[MAXPATHLEN];
592 FILE *fp;
593
594 if (outfname && followfork > 1) {
595 sprintf(name, "%s.%u", outfname, tcp->pid);
596#ifndef SVR4
597 setreuid(geteuid(), getuid());
598#endif
599 fp = fopen(name, "w");
600#ifndef SVR4
601 setreuid(geteuid(), getuid());
602#endif
603 if (fp == NULL) {
604 perror("fopen");
605 return;
606 }
607 tcp->outf = fp;
608 }
609 return;
610}
611
612struct tcb *
613alloctcb(pid)
614int pid;
615{
616 int i;
617 struct tcb *tcp;
618
Roland McGrathee9d4352002-12-18 04:16:10 +0000619 for (i = 0; i < tcbtabsize; i++) {
620 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621 if ((tcp->flags & TCB_INUSE) == 0) {
622 tcp->pid = pid;
623 tcp->parent = NULL;
624 tcp->nchildren = 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
1015 tcp->parent = NULL;
1016 }
1017
1018 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019 if (tcp->pfd != -1) {
1020 close(tcp->pfd);
1021 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001022#ifdef FREEBSD
1023 if (tcp->pfd_reg != -1) {
1024 close(tcp->pfd_reg);
1025 tcp->pfd_reg = -1;
1026 }
1027 if (tcp->pfd_status != -1) {
1028 close(tcp->pfd_status);
1029 tcp->pfd_status = -1;
1030 }
Roland McGrath553a6092002-12-16 20:40:39 +00001031#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001032#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001033 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001034#endif
1035 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001036
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001037 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001038 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001039
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001040 tcp->outf = 0;
1041}
1042
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001043#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044
1045static int
1046resume(tcp)
1047struct tcb *tcp;
1048{
1049 if (tcp == NULL)
1050 return -1;
1051
1052 if (!(tcp->flags & TCB_SUSPENDED)) {
1053 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1054 return -1;
1055 }
1056 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001057#ifdef TCB_CLONE_THREAD
1058 if (tcp->flags & TCB_CLONE_THREAD)
1059 tcp->parent->nclone_waiting--;
1060#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061
1062 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1063 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1064 return -1;
1065 }
1066
1067 if (!qflag)
1068 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1069 return 0;
1070}
1071
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001072#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073
1074/* detach traced process; continue with sig */
1075
1076static int
1077detach(tcp, sig)
1078struct tcb *tcp;
1079int sig;
1080{
1081 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001082#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001083 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001084#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085
1086 if (tcp->flags & TCB_BPTSET)
1087 sig = SIGKILL;
1088
1089#ifdef LINUX
1090 /*
1091 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001092 * before detaching. Arghh. We go through hoops
1093 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001094 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001095#if defined(SPARC)
1096#undef PTRACE_DETACH
1097#define PTRACE_DETACH PTRACE_SUNDETACH
1098#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001099 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1100 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001101 }
1102 else if (errno != ESRCH) {
1103 /* Shouldn't happen. */
1104 perror("detach: ptrace(PTRACE_DETACH, ...)");
1105 }
1106 else if (kill(tcp->pid, 0) < 0) {
1107 if (errno != ESRCH)
1108 perror("detach: checking sanity");
1109 }
1110 else if (kill(tcp->pid, SIGSTOP) < 0) {
1111 if (errno != ESRCH)
1112 perror("detach: stopping child");
1113 }
1114 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001115 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001116#ifdef __WALL
1117 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1118 if (errno == ECHILD) /* Already gone. */
1119 break;
1120 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001121 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001122 break;
1123 }
1124#endif /* __WALL */
1125 /* No __WALL here. */
1126 if (waitpid(tcp->pid, &status, 0) < 0) {
1127 if (errno != ECHILD) {
1128 perror("detach: waiting");
1129 break;
1130 }
1131#ifdef __WCLONE
1132 /* If no processes, try clones. */
1133 if (wait4(tcp->pid, &status, __WCLONE,
1134 NULL) < 0) {
1135 if (errno != ECHILD)
1136 perror("detach: waiting");
1137 break;
1138 }
1139#endif /* __WCLONE */
1140 }
1141#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001142 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001143#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001144 if (!WIFSTOPPED(status)) {
1145 /* Au revoir, mon ami. */
1146 break;
1147 }
1148 if (WSTOPSIG(status) == SIGSTOP) {
1149 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001150 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151 if (errno != ESRCH)
1152 perror("detach: ptrace(PTRACE_DETACH, ...)");
1153 /* I died trying. */
1154 }
1155 break;
1156 }
1157 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001158 WSTOPSIG(status) == SIGTRAP ?
1159 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001160 if (errno != ESRCH)
1161 perror("detach: ptrace(PTRACE_CONT, ...)");
1162 break;
1163 }
1164 }
1165 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001166#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001167
1168#if defined(SUNOS4)
1169 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1170 if (sig && kill(tcp->pid, sig) < 0)
1171 perror("detach: kill");
1172 sig = 0;
1173 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1174 perror("detach: ptrace(PTRACE_DETACH, ...)");
1175#endif /* SUNOS4 */
1176
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001177#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001178 resumed = 0;
1179
1180 /* XXX This won't always be quite right (but it never was).
1181 A waiter with argument 0 or < -1 is waiting for any pid in
1182 a particular pgrp, which this child might or might not be
1183 in. The waiter will only wake up if it's argument is -1
1184 or if it's waiting for tcp->pid's pgrp. It makes a
1185 difference to wake up a waiter when there might be more
1186 traced children, because it could get a false ECHILD
1187 error. OTOH, if this was the last child in the pgrp, then
1188 it ought to wake up and get ECHILD. We would have to
1189 search the system for all pid's in the pgrp to be sure.
1190
1191 && (t->waitpid == -1 ||
1192 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1193 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1194 */
1195
1196 if (tcp->parent &&
1197 (tcp->parent->flags & TCB_SUSPENDED) &&
1198 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1199 error = resume(tcp->parent);
1200 ++resumed;
1201 }
1202#ifdef TCB_CLONE_THREAD
1203 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1204 /* Some other threads of our parent are waiting too. */
1205 unsigned int i;
1206
1207 /* Resume all the threads that were waiting for this PID. */
1208 for (i = 0; i < tcbtabsize; i++) {
1209 struct tcb *t = tcbtab[i];
1210 if (t->parent == tcp->parent && t != tcp
1211 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1212 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1213 && t->waitpid == tcp->pid) {
1214 error |= resume (t);
1215 ++resumed;
1216 }
1217 }
1218 if (resumed == 0)
1219 /* Noone was waiting for this PID in particular,
1220 so now we might need to resume some wildcarders. */
1221 for (i = 0; i < tcbtabsize; i++) {
1222 struct tcb *t = tcbtab[i];
1223 if (t->parent == tcp->parent && t != tcp
1224 && ((t->flags
1225 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1226 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1227 && t->waitpid <= 0
1228 ) {
1229 error |= resume (t);
1230 break;
1231 }
1232 }
1233 }
1234#endif
1235
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001236#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001237
1238 if (!qflag)
1239 fprintf(stderr, "Process %u detached\n", tcp->pid);
1240
1241 droptcb(tcp);
1242 return error;
1243}
1244
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001245#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001246
1247static void
1248reaper(sig)
1249int sig;
1250{
1251 int pid;
1252 int status;
1253
1254 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1255#if 0
1256 struct tcb *tcp;
1257
1258 tcp = pid2tcb(pid);
1259 if (tcp)
1260 droptcb(tcp);
1261#endif
1262 }
1263}
1264
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001265#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266
1267static void
1268cleanup()
1269{
1270 int i;
1271 struct tcb *tcp;
1272
Roland McGrathee9d4352002-12-18 04:16:10 +00001273 for (i = 0; i < tcbtabsize; i++) {
1274 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001275 if (!(tcp->flags & TCB_INUSE))
1276 continue;
1277 if (debug)
1278 fprintf(stderr,
1279 "cleanup: looking at pid %u\n", tcp->pid);
1280 if (tcp_last &&
1281 (!outfname || followfork < 2 || tcp_last == tcp)) {
1282 tprintf(" <unfinished ...>\n");
1283 tcp_last = NULL;
1284 }
1285 if (tcp->flags & TCB_ATTACHED)
1286 detach(tcp, 0);
1287 else {
1288 kill(tcp->pid, SIGCONT);
1289 kill(tcp->pid, SIGTERM);
1290 }
1291 }
1292 if (cflag)
1293 call_summary(outf);
1294}
1295
1296static void
1297interrupt(sig)
1298int sig;
1299{
1300 interrupted = 1;
1301}
1302
1303#ifndef HAVE_STRERROR
1304
Roland McGrath6d2b3492002-12-30 00:51:30 +00001305#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001306extern int sys_nerr;
1307extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001308#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001309
1310const char *
1311strerror(errno)
1312int errno;
1313{
1314 static char buf[64];
1315
1316 if (errno < 1 || errno >= sys_nerr) {
1317 sprintf(buf, "Unknown error %d", errno);
1318 return buf;
1319 }
1320 return sys_errlist[errno];
1321}
1322
1323#endif /* HAVE_STERRROR */
1324
1325#ifndef HAVE_STRSIGNAL
1326
Roland McGrath8f474e02003-01-14 07:53:33 +00001327#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001328extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001329#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001330#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1331extern char *_sys_siglist[];
1332#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001333
1334const char *
1335strsignal(sig)
1336int sig;
1337{
1338 static char buf[64];
1339
1340 if (sig < 1 || sig >= NSIG) {
1341 sprintf(buf, "Unknown signal %d", sig);
1342 return buf;
1343 }
1344#ifdef HAVE__SYS_SIGLIST
1345 return _sys_siglist[sig];
1346#else
1347 return sys_siglist[sig];
1348#endif
1349}
1350
1351#endif /* HAVE_STRSIGNAL */
1352
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001353#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001354
1355static void
1356rebuild_pollv()
1357{
1358 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001359
Roland McGrathee9d4352002-12-18 04:16:10 +00001360 if (pollv != NULL)
1361 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001362 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001363 if (pollv == NULL) {
1364 fprintf(stderr, "strace: out of memory for poll vector\n");
1365 exit(1);
1366 }
1367
Roland McGrathca16be82003-01-10 19:55:28 +00001368 for (i = j = 0; i < tcbtabsize; i++) {
1369 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001370 if (!(tcp->flags & TCB_INUSE))
1371 continue;
1372 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001373 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374 j++;
1375 }
1376 if (j != nprocs) {
1377 fprintf(stderr, "strace: proc miscount\n");
1378 exit(1);
1379 }
1380}
1381
1382#ifndef HAVE_POLLABLE_PROCFS
1383
1384static void
1385proc_poll_open()
1386{
1387 int arg;
1388 int i;
1389
1390 if (pipe(proc_poll_pipe) < 0) {
1391 perror("pipe");
1392 exit(1);
1393 }
1394 for (i = 0; i < 2; i++) {
1395 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1396 perror("F_GETFD");
1397 exit(1);
1398 }
1399 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1400 perror("F_SETFD");
1401 exit(1);
1402 }
1403 }
1404}
1405
1406static int
1407proc_poll(pollv, nfds, timeout)
1408struct pollfd *pollv;
1409int nfds;
1410int timeout;
1411{
1412 int i;
1413 int n;
1414 struct proc_pollfd pollinfo;
1415
1416 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1417 return n;
1418 if (n != sizeof(struct proc_pollfd)) {
1419 fprintf(stderr, "panic: short read: %d\n", n);
1420 exit(1);
1421 }
1422 for (i = 0; i < nprocs; i++) {
1423 if (pollv[i].fd == pollinfo.fd)
1424 pollv[i].revents = pollinfo.revents;
1425 else
1426 pollv[i].revents = 0;
1427 }
1428 poller_pid = pollinfo.pid;
1429 return 1;
1430}
1431
1432static void
1433wakeup_handler(sig)
1434int sig;
1435{
1436}
1437
1438static void
1439proc_poller(pfd)
1440int pfd;
1441{
1442 struct proc_pollfd pollinfo;
1443 struct sigaction sa;
1444 sigset_t blocked_set, empty_set;
1445 int i;
1446 int n;
1447 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001448#ifdef FREEBSD
1449 struct procfs_status pfs;
1450#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001451
1452 switch (fork()) {
1453 case -1:
1454 perror("fork");
1455 _exit(0);
1456 case 0:
1457 break;
1458 default:
1459 return;
1460 }
1461
1462 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1463 sa.sa_flags = 0;
1464 sigemptyset(&sa.sa_mask);
1465 sigaction(SIGHUP, &sa, NULL);
1466 sigaction(SIGINT, &sa, NULL);
1467 sigaction(SIGQUIT, &sa, NULL);
1468 sigaction(SIGPIPE, &sa, NULL);
1469 sigaction(SIGTERM, &sa, NULL);
1470 sa.sa_handler = wakeup_handler;
1471 sigaction(SIGUSR1, &sa, NULL);
1472 sigemptyset(&blocked_set);
1473 sigaddset(&blocked_set, SIGUSR1);
1474 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1475 sigemptyset(&empty_set);
1476
1477 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1478 perror("getrlimit(RLIMIT_NOFILE, ...)");
1479 _exit(0);
1480 }
1481 n = rl.rlim_cur;
1482 for (i = 0; i < n; i++) {
1483 if (i != pfd && i != proc_poll_pipe[1])
1484 close(i);
1485 }
1486
1487 pollinfo.fd = pfd;
1488 pollinfo.pid = getpid();
1489 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001490#ifndef FREEBSD
1491 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1492#else /* FREEBSD */
1493 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1494#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001495 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001496 switch (errno) {
1497 case EINTR:
1498 continue;
1499 case EBADF:
1500 pollinfo.revents = POLLERR;
1501 break;
1502 case ENOENT:
1503 pollinfo.revents = POLLHUP;
1504 break;
1505 default:
1506 perror("proc_poller: PIOCWSTOP");
1507 }
1508 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1509 _exit(0);
1510 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001511 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001512 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1513 sigsuspend(&empty_set);
1514 }
1515}
1516
1517#endif /* !HAVE_POLLABLE_PROCFS */
1518
1519static int
1520choose_pfd()
1521{
1522 int i, j;
1523 struct tcb *tcp;
1524
1525 static int last;
1526
1527 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001528 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001529 /*
1530 * The previous process is ready to run again. We'll
1531 * let it do so if it is currently in a syscall. This
1532 * heuristic improves the readability of the trace.
1533 */
1534 tcp = pfd2tcb(pollv[last].fd);
1535 if (tcp && (tcp->flags & TCB_INSYSCALL))
1536 return pollv[last].fd;
1537 }
1538
1539 for (i = 0; i < nprocs; i++) {
1540 /* Let competing children run round robin. */
1541 j = (i + last + 1) % nprocs;
1542 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1543 tcp = pfd2tcb(pollv[j].fd);
1544 if (!tcp) {
1545 fprintf(stderr, "strace: lost proc\n");
1546 exit(1);
1547 }
1548 droptcb(tcp);
1549 return -1;
1550 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001551 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001552 last = j;
1553 return pollv[j].fd;
1554 }
1555 }
1556 fprintf(stderr, "strace: nothing ready\n");
1557 exit(1);
1558}
1559
1560static int
1561trace()
1562{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001563#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001564 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001565#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001566 struct tcb *tcp;
1567 int pfd;
1568 int what;
1569 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001570 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001571
1572 for (;;) {
1573 if (interactive)
1574 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1575
1576 if (nprocs == 0)
1577 break;
1578
1579 switch (nprocs) {
1580 case 1:
1581#ifndef HAVE_POLLABLE_PROCFS
1582 if (proc_poll_pipe[0] == -1) {
1583#endif
1584 tcp = pid2tcb(0);
1585 if (!tcp)
1586 continue;
1587 pfd = tcp->pfd;
1588 if (pfd == -1)
1589 continue;
1590 break;
1591#ifndef HAVE_POLLABLE_PROCFS
1592 }
1593 /* fall through ... */
1594#endif /* !HAVE_POLLABLE_PROCFS */
1595 default:
1596#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001597#ifdef POLL_HACK
1598 /* On some systems (e.g. UnixWare) we get too much ugly
1599 "unfinished..." stuff when multiple proceses are in
1600 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001601
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001602 if (in_syscall) {
1603 struct pollfd pv;
1604 tcp = in_syscall;
1605 in_syscall = NULL;
1606 pv.fd = tcp->pfd;
1607 pv.events = POLLWANT;
1608 if ((what = poll (&pv, 1, 1)) < 0) {
1609 if (interrupted)
1610 return 0;
1611 continue;
1612 }
1613 else if (what == 1 && pv.revents & POLLWANT) {
1614 goto FOUND;
1615 }
1616 }
1617#endif
1618
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001619 if (poll(pollv, nprocs, INFTIM) < 0) {
1620 if (interrupted)
1621 return 0;
1622 continue;
1623 }
1624#else /* !HAVE_POLLABLE_PROCFS */
1625 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1626 if (interrupted)
1627 return 0;
1628 continue;
1629 }
1630#endif /* !HAVE_POLLABLE_PROCFS */
1631 pfd = choose_pfd();
1632 if (pfd == -1)
1633 continue;
1634 break;
1635 }
1636
1637 /* Look up `pfd' in our table. */
1638 if ((tcp = pfd2tcb(pfd)) == NULL) {
1639 fprintf(stderr, "unknown pfd: %u\n", pfd);
1640 exit(1);
1641 }
John Hughesb6643082002-05-23 11:02:22 +00001642#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001643 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001644#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645 /* Get the status of the process. */
1646 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001647#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001648 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001649#else /* FREEBSD */
1650 /* Thanks to some scheduling mystery, the first poller
1651 sometimes waits for the already processed end of fork
1652 event. Doing a non blocking poll here solves the problem. */
1653 if (proc_poll_pipe[0] != -1)
1654 ioctl_result = IOCTL_STATUS (tcp);
1655 else
1656 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001657#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001658 ioctl_errno = errno;
1659#ifndef HAVE_POLLABLE_PROCFS
1660 if (proc_poll_pipe[0] != -1) {
1661 if (ioctl_result < 0)
1662 kill(poller_pid, SIGKILL);
1663 else
1664 kill(poller_pid, SIGUSR1);
1665 }
1666#endif /* !HAVE_POLLABLE_PROCFS */
1667 }
1668 if (interrupted)
1669 return 0;
1670
1671 if (interactive)
1672 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1673
1674 if (ioctl_result < 0) {
1675 /* Find out what happened if it failed. */
1676 switch (ioctl_errno) {
1677 case EINTR:
1678 case EBADF:
1679 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001680#ifdef FREEBSD
1681 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001682#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001683 case ENOENT:
1684 droptcb(tcp);
1685 continue;
1686 default:
1687 perror("PIOCWSTOP");
1688 exit(1);
1689 }
1690 }
1691
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001692#ifdef FREEBSD
1693 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1694 /* discard first event for a syscall we never entered */
1695 IOCTL (tcp->pfd, PIOCRUN, 0);
1696 continue;
1697 }
Roland McGrath553a6092002-12-16 20:40:39 +00001698#endif
1699
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001700 /* clear the just started flag */
1701 tcp->flags &= ~TCB_STARTUP;
1702
1703 /* set current output file */
1704 outf = tcp->outf;
1705
1706 if (cflag) {
1707 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001708#ifdef FREEBSD
1709 char buf[1024];
1710 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001711
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001712 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1713 buf[len] = '\0';
1714 sscanf(buf,
1715 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1716 &stime.tv_sec, &stime.tv_usec);
1717 } else
1718 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001719#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001720 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1721 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001722#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001723 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1724 tcp->stime = stime;
1725 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001726 what = tcp->status.PR_WHAT;
1727 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001728#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001729 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001730 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1731 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001732 if (trace_syscall(tcp) < 0) {
1733 fprintf(stderr, "syscall trouble\n");
1734 exit(1);
1735 }
1736 }
1737 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001738#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001739 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001740#ifdef POLL_HACK
1741 in_syscall = tcp;
1742#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001743 case PR_SYSEXIT:
1744 if (trace_syscall(tcp) < 0) {
1745 fprintf(stderr, "syscall trouble\n");
1746 exit(1);
1747 }
1748 break;
1749 case PR_SIGNALLED:
1750 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1751 printleader(tcp);
1752 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001753 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001754 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001755#ifdef PR_INFO
1756 if (tcp->status.PR_INFO.si_signo == what) {
1757 printleader(tcp);
1758 tprintf(" siginfo=");
1759 printsiginfo(&tcp->status.PR_INFO, 1);
1760 printtrailer(tcp);
1761 }
1762#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763 }
1764 break;
1765 case PR_FAULTED:
1766 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1767 printleader(tcp);
1768 tprintf("=== FAULT %d ===", what);
1769 printtrailer(tcp);
1770 }
1771 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001772#ifdef FREEBSD
1773 case 0: /* handle case we polled for nothing */
1774 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001775#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001776 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001777 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001778 exit(1);
1779 break;
1780 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001781 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001782#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001783 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001784#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001785 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001786#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001787 perror("PIOCRUN");
1788 exit(1);
1789 }
1790 }
1791 return 0;
1792}
1793
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001794#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001795
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001796#ifdef TCB_GROUP_EXITING
1797/* Handle an exit detach or death signal that is taking all the
1798 related clone threads with it. This is called in three circumstances:
1799 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1800 SIG == 0 Continuing TCP will perform an exit_group syscall.
1801 SIG == other Continuing TCP with SIG will kill the process.
1802*/
1803static int
1804handle_group_exit(struct tcb *tcp, int sig)
1805{
1806 /* We need to locate our records of all the clone threads
1807 related to TCP, either its children or siblings. */
1808 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1809 ? tcp->parent
1810 : tcp->nclone_detached > 0
1811 ? tcp : NULL);
1812
1813 if (sig < 0) {
1814 if (leader != NULL && leader != tcp)
1815 fprintf(stderr,
1816 "PANIC: handle_group_exit: %d leader %d\n",
1817 tcp->pid, leader ? leader->pid : -1);
1818 droptcb(tcp); /* Already died. */
1819 }
1820 else {
1821 if (tcp->flags & TCB_ATTACHED) {
1822 if (leader != NULL && leader != tcp) {
1823 /* We need to detach the leader so that the
1824 process death will be reported to its real
1825 parent. But we kill it first to prevent
1826 it doing anything before we kill the whole
1827 process in a moment. We can use
1828 PTRACE_KILL on a thread that's not already
1829 stopped. Then the value we pass in
1830 PTRACE_DETACH just sets the death
1831 signal reported to the real parent. */
1832 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1833 if (debug)
1834 fprintf(stderr,
1835 " [%d exit %d kills %d]\n",
1836 tcp->pid, sig, leader->pid);
1837 detach(leader, sig);
1838 }
1839 detach(tcp, sig);
1840 }
1841 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1842 perror("strace: ptrace(PTRACE_CONT, ...)");
1843 cleanup();
1844 return -1;
1845 }
1846 else {
1847 if (leader != NULL && leader != tcp)
1848 droptcb(tcp);
1849 /* The leader will report to us as parent now,
1850 and then we'll get to the SIG==-1 case. */
1851 return 0;
1852 }
1853 }
1854
1855 /* Note that TCP and LEADER are no longer valid,
1856 but we can still compare against them. */
1857 if (leader != NULL) {
1858 unsigned int i;
1859 for (i = 0; i < tcbtabsize; i++) {
1860 struct tcb *t = tcbtab[i];
1861 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1862 && t->parent == leader)
1863 droptcb(t);
1864 }
1865 }
1866
1867 return 0;
1868}
1869#endif
1870
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001871static int
1872trace()
1873{
1874 int pid;
1875 int wait_errno;
1876 int status;
1877 struct tcb *tcp;
1878#ifdef LINUX
1879 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001880#ifdef __WALL
1881 static int wait4_options = __WALL;
1882#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001883#endif /* LINUX */
1884
1885 while (nprocs != 0) {
1886 if (interactive)
1887 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1888#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001889#ifdef __WALL
1890 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00001891 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001892 /* this kernel does not support __WALL */
1893 wait4_options &= ~__WALL;
1894 errno = 0;
1895 pid = wait4(-1, &status, wait4_options,
1896 cflag ? &ru : NULL);
1897 }
Roland McGrath5bc05552002-12-17 04:50:47 +00001898 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001899 /* most likely a "cloned" process */
1900 pid = wait4(-1, &status, __WCLONE,
1901 cflag ? &ru : NULL);
1902 if (pid == -1) {
1903 fprintf(stderr, "strace: clone wait4 "
1904 "failed: %s\n", strerror(errno));
1905 }
1906 }
1907#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001908 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001909#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001910#endif /* LINUX */
1911#ifdef SUNOS4
1912 pid = wait(&status);
1913#endif /* SUNOS4 */
1914 wait_errno = errno;
1915 if (interactive)
1916 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1917
1918 if (interrupted)
1919 return 0;
1920
1921 if (pid == -1) {
1922 switch (wait_errno) {
1923 case EINTR:
1924 continue;
1925 case ECHILD:
1926 /*
1927 * We would like to verify this case
1928 * but sometimes a race in Solbourne's
1929 * version of SunOS sometimes reports
1930 * ECHILD before sending us SIGCHILD.
1931 */
1932#if 0
1933 if (nprocs == 0)
1934 return 0;
1935 fprintf(stderr, "strace: proc miscount\n");
1936 exit(1);
1937#endif
1938 return 0;
1939 default:
1940 errno = wait_errno;
1941 perror("strace: wait");
1942 return -1;
1943 }
1944 }
1945 if (debug)
1946 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1947
1948 /* Look up `pid' in our table. */
1949 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001950#ifdef LINUX
1951 if (followfork || followvfork) {
1952 /* This is needed to go with the CLONE_PTRACE
1953 changes in process.c/util.c: we might see
1954 the child's initial trap before we see the
1955 parent return from the clone syscall.
1956 Leave the child suspended until the parent
1957 returns from its system call. Only then
1958 will we have the association of parent and
1959 child so that we know how to do clearbpt
1960 in the child. */
1961 if ((tcp = alloctcb(pid)) == NULL) {
1962 fprintf(stderr, " [tcb table full]\n");
1963 kill(pid, SIGKILL); /* XXX */
1964 return 0;
1965 }
1966 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
1967 newoutf(tcp);
1968 if (!qflag)
1969 fprintf(stderr, "\
1970Process %d attached (waiting for parent)\n",
1971 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001972 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001973 else
1974 /* This can happen if a clone call used
1975 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001976#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001977 {
1978 fprintf(stderr, "unknown pid: %u\n", pid);
1979 if (WIFSTOPPED(status))
1980 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1981 exit(1);
1982 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001983 }
1984 /* set current output file */
1985 outf = tcp->outf;
1986 if (cflag) {
1987#ifdef LINUX
1988 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
1989 tcp->stime = ru.ru_stime;
1990#endif /* !LINUX */
1991 }
1992
1993 if (tcp->flags & TCB_SUSPENDED) {
1994 /*
1995 * Apparently, doing any ptrace() call on a stopped
1996 * process, provokes the kernel to report the process
1997 * status again on a subsequent wait(), even if the
1998 * process has not been actually restarted.
1999 * Since we have inspected the arguments of suspended
2000 * processes we end up here testing for this case.
2001 */
2002 continue;
2003 }
2004 if (WIFSIGNALED(status)) {
2005 if (!cflag
2006 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2007 printleader(tcp);
2008 tprintf("+++ killed by %s +++",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002009 signame(WTERMSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002010 printtrailer(tcp);
2011 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002012#ifdef TCB_GROUP_EXITING
2013 handle_group_exit(tcp, -1);
2014#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002015 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002016#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002017 continue;
2018 }
2019 if (WIFEXITED(status)) {
2020 if (debug)
2021 fprintf(stderr, "pid %u exited\n", pid);
2022 if (tcp->flags & TCB_ATTACHED)
2023 fprintf(stderr,
2024 "PANIC: attached pid %u exited\n",
2025 pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002026#ifdef TCB_GROUP_EXITING
2027 handle_group_exit(tcp, -1);
2028#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002029 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002030#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002031 continue;
2032 }
2033 if (!WIFSTOPPED(status)) {
2034 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2035 droptcb(tcp);
2036 continue;
2037 }
2038 if (debug)
2039 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002040 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002041
2042 if (tcp->flags & TCB_STARTUP) {
2043 /*
2044 * This flag is there to keep us in sync.
2045 * Next time this process stops it should
2046 * really be entering a system call.
2047 */
2048 tcp->flags &= ~TCB_STARTUP;
2049 if (tcp->flags & TCB_ATTACHED) {
2050 /*
2051 * Interestingly, the process may stop
2052 * with STOPSIG equal to some other signal
2053 * than SIGSTOP if we happend to attach
2054 * just before the process takes a signal.
2055 */
2056 if (!WIFSTOPPED(status)) {
2057 fprintf(stderr,
2058 "pid %u not stopped\n", pid);
2059 detach(tcp, WSTOPSIG(status));
2060 continue;
2061 }
2062 }
2063 else {
2064#ifdef SUNOS4
2065 /* A child of us stopped at exec */
2066 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2067 fixvfork(tcp);
2068#endif /* SUNOS4 */
2069 }
2070 if (tcp->flags & TCB_BPTSET) {
2071 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2072 droptcb(tcp);
2073 cleanup();
2074 return -1;
2075 }
2076 }
2077 goto tracing;
2078 }
2079
2080 if (WSTOPSIG(status) != SIGTRAP) {
2081 if (WSTOPSIG(status) == SIGSTOP &&
2082 (tcp->flags & TCB_SIGTRAPPED)) {
2083 /*
2084 * Trapped attempt to block SIGTRAP
2085 * Hope we are back in control now.
2086 */
2087 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2088 if (ptrace(PTRACE_SYSCALL,
2089 pid, (char *) 1, 0) < 0) {
2090 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2091 cleanup();
2092 return -1;
2093 }
2094 continue;
2095 }
2096 if (!cflag
2097 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002098 unsigned long addr = 0, pc = 0;
2099#ifdef PT_GETSIGINFO
2100# define PSR_RI 41
2101 struct siginfo si;
2102 unsigned long psr;
2103
2104 upeek(pid, PT_CR_IPSR, &psr);
2105 upeek(pid, PT_CR_IIP, &pc);
2106
2107 pc += (psr >> PSR_RI) & 0x3;
2108 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2109 addr = (unsigned long) si.si_addr;
2110#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002111 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002112 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002113 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002114 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002115 printtrailer(tcp);
2116 }
2117 if ((tcp->flags & TCB_ATTACHED) &&
2118 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002119#ifdef TCB_GROUP_EXITING
2120 handle_group_exit(tcp, WSTOPSIG(status));
2121#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002122 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002123#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002124 continue;
2125 }
2126 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2127 WSTOPSIG(status)) < 0) {
2128 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2129 cleanup();
2130 return -1;
2131 }
2132 tcp->flags &= ~TCB_SUSPENDED;
2133 continue;
2134 }
2135 if (trace_syscall(tcp) < 0) {
2136 if (tcp->flags & TCB_ATTACHED)
2137 detach(tcp, 0);
2138 else {
2139 ptrace(PTRACE_KILL,
2140 tcp->pid, (char *) 1, SIGTERM);
2141 droptcb(tcp);
2142 }
2143 continue;
2144 }
2145 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002146#ifdef TCB_GROUP_EXITING
2147 if (tcp->flags & TCB_GROUP_EXITING) {
2148 if (handle_group_exit(tcp, 0) < 0)
2149 return -1;
2150 continue;
2151 }
2152#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002153 if (tcp->flags & TCB_ATTACHED)
2154 detach(tcp, 0);
2155 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2156 perror("strace: ptrace(PTRACE_CONT, ...)");
2157 cleanup();
2158 return -1;
2159 }
2160 continue;
2161 }
2162 if (tcp->flags & TCB_SUSPENDED) {
2163 if (!qflag)
2164 fprintf(stderr, "Process %u suspended\n", pid);
2165 continue;
2166 }
2167 tracing:
2168 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2169 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2170 cleanup();
2171 return -1;
2172 }
2173 }
2174 return 0;
2175}
2176
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002177#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002178
2179static int curcol;
2180
2181#ifdef __STDC__
2182#include <stdarg.h>
2183#define VA_START(a, b) va_start(a, b)
2184#else
2185#include <varargs.h>
2186#define VA_START(a, b) va_start(a)
2187#endif
2188
2189void
2190#ifdef __STDC__
2191tprintf(const char *fmt, ...)
2192#else
2193tprintf(fmt, va_alist)
2194char *fmt;
2195va_dcl
2196#endif
2197{
2198 va_list args;
2199
2200 VA_START(args, fmt);
2201 if (outf)
2202 curcol += vfprintf(outf, fmt, args);
2203 va_end(args);
2204 return;
2205}
2206
2207void
2208printleader(tcp)
2209struct tcb *tcp;
2210{
2211 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2212 tcp_last->flags |= TCB_REPRINT;
2213 tprintf(" <unfinished ...>\n");
2214 }
2215 curcol = 0;
2216 if ((followfork == 1 || pflag_seen > 1) && outfname)
2217 tprintf("%-5d ", tcp->pid);
2218 else if (nprocs > 1 && !outfname)
2219 tprintf("[pid %5u] ", tcp->pid);
2220 if (tflag) {
2221 char str[sizeof("HH:MM:SS")];
2222 struct timeval tv, dtv;
2223 static struct timeval otv;
2224
2225 gettimeofday(&tv, NULL);
2226 if (rflag) {
2227 if (otv.tv_sec == 0)
2228 otv = tv;
2229 tv_sub(&dtv, &tv, &otv);
2230 tprintf("%6ld.%06ld ",
2231 (long) dtv.tv_sec, (long) dtv.tv_usec);
2232 otv = tv;
2233 }
2234 else if (tflag > 2) {
2235 tprintf("%ld.%06ld ",
2236 (long) tv.tv_sec, (long) tv.tv_usec);
2237 }
2238 else {
2239 time_t local = tv.tv_sec;
2240 strftime(str, sizeof(str), "%T", localtime(&local));
2241 if (tflag > 1)
2242 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2243 else
2244 tprintf("%s ", str);
2245 }
2246 }
2247 if (iflag)
2248 printcall(tcp);
2249}
2250
2251void
2252tabto(col)
2253int col;
2254{
2255 if (curcol < col)
2256 tprintf("%*s", col - curcol, "");
2257}
2258
2259void
2260printtrailer(tcp)
2261struct tcb *tcp;
2262{
2263 tprintf("\n");
2264 tcp_last = NULL;
2265}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002266
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002267#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002268
2269int mp_ioctl (int fd, int cmd, void *arg, int size) {
2270
2271 struct iovec iov[2];
2272 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002273
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002274 iov[0].iov_base = &cmd;
2275 iov[0].iov_len = sizeof cmd;
2276 if (arg) {
2277 ++n;
2278 iov[1].iov_base = arg;
2279 iov[1].iov_len = size;
2280 }
Roland McGrath553a6092002-12-16 20:40:39 +00002281
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002282 return writev (fd, iov, n);
2283}
2284
2285#endif