blob: a8a1e400acb775f6b39e12e4622cca349cd552f0 [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>
Roland McGrath70b08532004-04-09 00:25:21 +000047#include <dirent.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000048
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000049#if defined(IA64) && defined(LINUX)
50# include <asm/ptrace_offsets.h>
51#endif
52
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000053#ifdef USE_PROCFS
54#include <poll.h>
55#endif
56
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000057#ifdef SVR4
58#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000059#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000060#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000061#include <sys/uio.h>
62#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000063#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000064#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000065
66int debug = 0, followfork = 0, followvfork = 0, interactive = 0;
67int rflag = 0, tflag = 0, dtime = 0, cflag = 0;
68int iflag = 0, xflag = 0, qflag = 0;
69int pflag_seen = 0;
70
Michal Ludvig17f8fb32002-11-06 13:17:21 +000071/* Sometimes we want to print only succeeding syscalls. */
72int not_failing_only = 0;
73
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000074char *username = NULL;
75uid_t run_uid;
76gid_t run_gid;
77
78int acolumn = DEFAULT_ACOLUMN;
79int max_strlen = DEFAULT_STRLEN;
80char *outfname = NULL;
81FILE *outf;
Roland McGrathee9d4352002-12-18 04:16:10 +000082struct tcb **tcbtab;
83unsigned int nprocs, tcbtabsize;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000084char *progname;
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':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000250 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000251 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
Roland McGrathce0d1542003-11-11 21:24:23 +0000308 if (optind == argc && !pflag_seen)
309 usage(stderr, 1);
310
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000311 /* See if they want to run as another user. */
312 if (username != NULL) {
313 struct passwd *pent;
314
315 if (getuid() != 0 || geteuid() != 0) {
316 fprintf(stderr,
317 "%s: you must be root to use the -u option\n",
318 progname);
319 exit(1);
320 }
321 if ((pent = getpwnam(username)) == NULL) {
322 fprintf(stderr, "%s: cannot find user `%s'\n",
323 progname, optarg);
324 exit(1);
325 }
326 run_uid = pent->pw_uid;
327 run_gid = pent->pw_gid;
328 }
329 else {
330 run_uid = getuid();
331 run_gid = getgid();
332 }
333
334#ifndef SVR4
335 setreuid(geteuid(), getuid());
336#endif
337
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000338 /* Check if they want to redirect the output. */
339 if (outfname) {
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000340 long f;
341
Roland McGrath37b9a662003-11-07 02:26:54 +0000342 /* See if they want to pipe the output. */
343 if (outfname[0] == '|' || outfname[0] == '!') {
344 /*
345 * We can't do the <outfname>.PID funny business
346 * when using popen, so prohibit it.
347 */
348 if (followfork > 1) {
349 fprintf(stderr, "\
350%s: piping the output and -ff are mutually exclusive options\n",
351 progname);
352 exit(1);
353 }
354
355 if ((outf = popen(outfname + 1, "w")) == NULL) {
356 fprintf(stderr, "%s: can't popen '%s': %s\n",
357 progname, outfname + 1,
358 strerror(errno));
359 exit(1);
360 }
361 }
362 else if ((outf = fopen(outfname, "w")) == NULL) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000363 fprintf(stderr, "%s: can't fopen '%s': %s\n",
364 progname, outfname, strerror(errno));
365 exit(1);
366 }
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000367
368 if ((f=fcntl(fileno(outf), F_GETFD)) < 0 ) {
369 perror("failed to get flags for outputfile");
370 exit(1);
371 }
372
373 if (fcntl(fileno(outf), F_SETFD, f|FD_CLOEXEC) < 0 ) {
374 perror("failed to set flags for outputfile");
375 exit(1);
376 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000377 }
378
379#ifndef SVR4
380 setreuid(geteuid(), getuid());
381#endif
382
Roland McGrath37b9a662003-11-07 02:26:54 +0000383 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000384 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000385 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000386 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000387 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000388 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000389
Roland McGrathee9d4352002-12-18 04:16:10 +0000390 for (c = 0; c < tcbtabsize; c++) {
391 tcp = tcbtab[c];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000392 /* Reinitialize the output since it may have changed. */
393 tcp->outf = outf;
394 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
395 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000396#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000397 if (proc_open(tcp, 1) < 0) {
398 fprintf(stderr, "trouble opening proc file\n");
399 droptcb(tcp);
400 continue;
401 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000402#else /* !USE_PROCFS */
Roland McGrath70b08532004-04-09 00:25:21 +0000403# ifdef LINUX
404 if (tcp->flags & TCB_CLONE_THREAD)
405 continue;
406 {
407 char procdir[MAXPATHLEN];
408 DIR *dir;
409 sprintf(procdir, "/proc/%d/task", tcp->pid);
410 dir = opendir(procdir);
411 if (dir != NULL) {
412 unsigned int ntid = 0, nerr = 0;
413 struct dirent *de;
414 int tid;
415 while ((de = readdir(dir)) != NULL) {
416 if (de->d_fileno == 0 ||
417 de->d_name[0] == '.')
418 continue;
419 tid = atoi(de->d_name);
420 if (tid <= 0)
421 continue;
422 ++ntid;
423 if (ptrace(PTRACE_ATTACH, tid,
424 (char *) 1, 0) < 0)
425 ++nerr;
426 else if (tid != tcbtab[c]->pid) {
427 tcp = alloctcb(tid);
428 if (tcp == NULL) {
429 fprintf(stderr, "%s: out of memory\n",
430 progname);
431 exit(1);
432 }
433 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED;
434 tcbtab[c]->nchildren++;
435 tcbtab[c]->nclone_threads++;
436 tcbtab[c]->nclone_detached++;
437 tcp->parent = tcbtab[c];
438 }
439 }
440 closedir(dir);
441 if (nerr == ntid) {
442 perror("attach: ptrace(PTRACE_ATTACH, ...)");
443 droptcb(tcp);
444 continue;
445 }
446 if (!qflag) {
447 ntid -= nerr;
448 if (ntid > 1)
449 fprintf(stderr, "\
450Process %u attached with %u threads - interrupt to quit\n",
451 tcp->pid, ntid);
452 else
453 fprintf(stderr, "\
454Process %u attached - interrupt to quit\n",
455 tcp->pid);
456 }
457 continue;
458 }
459 }
460# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000461 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
462 perror("attach: ptrace(PTRACE_ATTACH, ...)");
463 droptcb(tcp);
464 continue;
465 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000466#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 if (!qflag)
468 fprintf(stderr,
469 "Process %u attached - interrupt to quit\n",
Roland McGrathc3266d52004-02-20 02:23:52 +0000470 tcp->pid);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000471 }
472
Roland McGrathce0d1542003-11-11 21:24:23 +0000473 if (!pflag_seen) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000474 struct stat statbuf;
475 char *filename;
476 char pathname[MAXPATHLEN];
477
478 filename = argv[optind];
Roland McGrathbdb09df2004-03-02 06:50:04 +0000479 if (strchr(filename, '/')) {
480 if (strlen(filename) > sizeof pathname - 1) {
481 errno = ENAMETOOLONG;
482 perror("strace: exec");
483 exit(1);
484 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000485 strcpy(pathname, filename);
Roland McGrathbdb09df2004-03-02 06:50:04 +0000486 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000487#ifdef USE_DEBUGGING_EXEC
488 /*
489 * Debuggers customarily check the current directory
490 * first regardless of the path but doing that gives
491 * security geeks a panic attack.
492 */
493 else if (stat(filename, &statbuf) == 0)
494 strcpy(pathname, filename);
495#endif /* USE_DEBUGGING_EXEC */
496 else {
497 char *path;
498 int m, n, len;
499
500 for (path = getenv("PATH"); path && *path; path += m) {
501 if (strchr(path, ':')) {
502 n = strchr(path, ':') - path;
503 m = n + 1;
504 }
505 else
506 m = n = strlen(path);
507 if (n == 0) {
508 getcwd(pathname, MAXPATHLEN);
509 len = strlen(pathname);
510 }
Roland McGrathbdb09df2004-03-02 06:50:04 +0000511 else if (n > sizeof pathname - 1)
512 continue;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000513 else {
514 strncpy(pathname, path, n);
515 len = n;
516 }
517 if (len && pathname[len - 1] != '/')
518 pathname[len++] = '/';
519 strcpy(pathname + len, filename);
Roland McGrathed645162003-06-03 07:18:19 +0000520 if (stat(pathname, &statbuf) == 0 &&
521 /* Accept only regular files
522 with some execute bits set.
523 XXX not perfect, might still fail */
524 S_ISREG(statbuf.st_mode) &&
525 (statbuf.st_mode & 0111))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000526 break;
527 }
528 }
529 if (stat(pathname, &statbuf) < 0) {
530 fprintf(stderr, "%s: %s: command not found\n",
531 progname, filename);
532 exit(1);
533 }
534 switch (pid = fork()) {
535 case -1:
536 perror("strace: fork");
537 cleanup();
538 exit(1);
539 break;
540 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000541#ifdef USE_PROCFS
542 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543#ifdef MIPS
544 /* Kludge for SGI, see proc_open for details. */
545 sa.sa_handler = foobar;
546 sa.sa_flags = 0;
547 sigemptyset(&sa.sa_mask);
548 sigaction(SIGINT, &sa, NULL);
549#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000550#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000551 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000552#else /* FREEBSD */
553 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000554#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000555#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000556 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000557 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000558
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000559 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
560 perror("strace: ptrace(PTRACE_TRACEME, ...)");
561 return -1;
562 }
563 if (debug)
564 kill(getpid(), SIGSTOP);
565
566 if (username != NULL || geteuid() == 0) {
567 uid_t run_euid = run_uid;
568 gid_t run_egid = run_gid;
569
570 if (statbuf.st_mode & S_ISUID)
571 run_euid = statbuf.st_uid;
572 if (statbuf.st_mode & S_ISGID)
573 run_egid = statbuf.st_gid;
574
575 /*
576 * It is important to set groups before we
577 * lose privileges on setuid.
578 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000579 if (username != NULL) {
580 if (initgroups(username, run_gid) < 0) {
581 perror("initgroups");
582 exit(1);
583 }
584 if (setregid(run_gid, run_egid) < 0) {
585 perror("setregid");
586 exit(1);
587 }
588 if (setreuid(run_uid, run_euid) < 0) {
589 perror("setreuid");
590 exit(1);
591 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000592 }
593 }
594 else
595 setreuid(run_uid, run_uid);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000596#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597
598 execv(pathname, &argv[optind]);
599 perror("strace: exec");
600 _exit(1);
601 break;
602 }
603 default:
604 if ((tcp = alloctcb(pid)) == NULL) {
605 fprintf(stderr, "tcb table full\n");
606 cleanup();
607 exit(1);
608 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000609#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000610 if (proc_open(tcp, 0) < 0) {
611 fprintf(stderr, "trouble opening proc file\n");
612 cleanup();
613 exit(1);
614 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000615#endif /* USE_PROCFS */
616#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000617 fake_execve(tcp, pathname, &argv[optind], environ);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000618#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000619 break;
620 }
621 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000622
623 sigemptyset(&empty_set);
624 sigemptyset(&blocked_set);
625 sa.sa_handler = SIG_IGN;
626 sigemptyset(&sa.sa_mask);
627 sa.sa_flags = 0;
628 sigaction(SIGTTOU, &sa, NULL);
629 sigaction(SIGTTIN, &sa, NULL);
630 if (interactive) {
631 sigaddset(&blocked_set, SIGHUP);
632 sigaddset(&blocked_set, SIGINT);
633 sigaddset(&blocked_set, SIGQUIT);
634 sigaddset(&blocked_set, SIGPIPE);
635 sigaddset(&blocked_set, SIGTERM);
636 sa.sa_handler = interrupt;
637#ifdef SUNOS4
638 /* POSIX signals on sunos4.1 are a little broken. */
639 sa.sa_flags = SA_INTERRUPT;
640#endif /* SUNOS4 */
641 }
642 sigaction(SIGHUP, &sa, NULL);
643 sigaction(SIGINT, &sa, NULL);
644 sigaction(SIGQUIT, &sa, NULL);
645 sigaction(SIGPIPE, &sa, NULL);
646 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000647#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000648 sa.sa_handler = reaper;
649 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000650#else
651 /* Make sure SIGCHLD has the default action so that waitpid
652 definitely works without losing track of children. The user
653 should not have given us a bogus state to inherit, but he might
654 have. Arguably we should detect SIG_IGN here and pass it on
655 to children, but probably noone really needs that. */
656 sa.sa_handler = SIG_DFL;
657 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000658#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000659
660 if (trace() < 0)
661 exit(1);
662 cleanup();
663 exit(0);
664}
665
666void
667newoutf(tcp)
668struct tcb *tcp;
669{
670 char name[MAXPATHLEN];
671 FILE *fp;
672
673 if (outfname && followfork > 1) {
674 sprintf(name, "%s.%u", outfname, tcp->pid);
675#ifndef SVR4
676 setreuid(geteuid(), getuid());
677#endif
678 fp = fopen(name, "w");
679#ifndef SVR4
680 setreuid(geteuid(), getuid());
681#endif
682 if (fp == NULL) {
683 perror("fopen");
684 return;
685 }
686 tcp->outf = fp;
687 }
688 return;
689}
690
691struct tcb *
692alloctcb(pid)
693int pid;
694{
695 int i;
696 struct tcb *tcp;
697
Roland McGrathee9d4352002-12-18 04:16:10 +0000698 for (i = 0; i < tcbtabsize; i++) {
699 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000700 if ((tcp->flags & TCB_INUSE) == 0) {
701 tcp->pid = pid;
702 tcp->parent = NULL;
703 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000704 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000705#ifdef TCB_CLONE_THREAD
706 tcp->nclone_threads = tcp->nclone_detached = 0;
707 tcp->nclone_waiting = 0;
708#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000709 tcp->flags = TCB_INUSE | TCB_STARTUP;
710 tcp->outf = outf; /* Initialise to current out file */
711 tcp->stime.tv_sec = 0;
712 tcp->stime.tv_usec = 0;
713 tcp->pfd = -1;
714 nprocs++;
715 return tcp;
716 }
717 }
718 return NULL;
719}
720
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000721#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000722int
723proc_open(tcp, attaching)
724struct tcb *tcp;
725int attaching;
726{
727 char proc[32];
728 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000729#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000730 int i;
731 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000732 sigset_t signals;
733 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000734#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000735#ifndef HAVE_POLLABLE_PROCFS
736 static int last_pfd;
737#endif
738
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000739#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000740 /* Open the process pseudo-files in /proc. */
741 sprintf(proc, "/proc/%d/ctl", tcp->pid);
742 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000743 perror("strace: open(\"/proc/...\", ...)");
744 return -1;
745 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
747 perror("F_GETFD");
748 return -1;
749 }
750 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
751 perror("F_SETFD");
752 return -1;
753 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000754 sprintf(proc, "/proc/%d/status", tcp->pid);
755 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
756 perror("strace: open(\"/proc/...\", ...)");
757 return -1;
758 }
759 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
760 perror("F_GETFD");
761 return -1;
762 }
763 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
764 perror("F_SETFD");
765 return -1;
766 }
767 sprintf(proc, "/proc/%d/as", tcp->pid);
768 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
769 perror("strace: open(\"/proc/...\", ...)");
770 return -1;
771 }
772 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
773 perror("F_GETFD");
774 return -1;
775 }
776 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
777 perror("F_SETFD");
778 return -1;
779 }
780#else
781 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000782#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000783 sprintf(proc, "/proc/%d", tcp->pid);
784 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000785#else /* FREEBSD */
786 sprintf(proc, "/proc/%d/mem", tcp->pid);
787 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
788#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000789 perror("strace: open(\"/proc/...\", ...)");
790 return -1;
791 }
792 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
793 perror("F_GETFD");
794 return -1;
795 }
796 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
797 perror("F_SETFD");
798 return -1;
799 }
800#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000801#ifdef FREEBSD
802 sprintf(proc, "/proc/%d/regs", tcp->pid);
803 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
804 perror("strace: open(\"/proc/.../regs\", ...)");
805 return -1;
806 }
807 if (cflag) {
808 sprintf(proc, "/proc/%d/status", tcp->pid);
809 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
810 perror("strace: open(\"/proc/.../status\", ...)");
811 return -1;
812 }
813 } else
814 tcp->pfd_status = -1;
815#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000816 rebuild_pollv();
817 if (!attaching) {
818 /*
819 * Wait for the child to pause. Because of a race
820 * condition we have to poll for the event.
821 */
822 for (;;) {
823 if (IOCTL_STATUS (tcp) < 0) {
824 perror("strace: PIOCSTATUS");
825 return -1;
826 }
827 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000828 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000829 }
830 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000831#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000832 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000833 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000834 perror("strace: PIOCSTOP");
835 return -1;
836 }
Roland McGrath553a6092002-12-16 20:40:39 +0000837#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000838#ifdef PIOCSET
839 /* Set Run-on-Last-Close. */
840 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000841 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000842 perror("PIOCSET PR_RLC");
843 return -1;
844 }
845 /* Set or Reset Inherit-on-Fork. */
846 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000847 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000848 perror("PIOC{SET,RESET} PR_FORK");
849 return -1;
850 }
851#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000852#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000853 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
854 perror("PIOCSRLC");
855 return -1;
856 }
857 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
858 perror("PIOC{S,R}FORK");
859 return -1;
860 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000861#else /* FREEBSD */
862 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
863 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
864 perror("PIOCGFL");
865 return -1;
866 }
867 arg &= ~PF_LINGER;
868 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
869 perror("PIOCSFL");
870 return -1;
871 }
872#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000873#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000874#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000875 /* Enable all syscall entries we care about. */
876 premptyset(&syscalls);
877 for (i = 1; i < MAX_QUALS; ++i) {
878 if (i > (sizeof syscalls) * CHAR_BIT) break;
879 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
880 }
881 praddset (&syscalls, SYS_execve);
882 if (followfork) {
883 praddset (&syscalls, SYS_fork);
884#ifdef SYS_forkall
885 praddset (&syscalls, SYS_forkall);
886#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000887#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000888 praddset (&syscalls, SYS_fork1);
889#endif
890#ifdef SYS_rfork1
891 praddset (&syscalls, SYS_rfork1);
892#endif
893#ifdef SYS_rforkall
894 praddset (&syscalls, SYS_rforkall);
895#endif
896 }
897 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000898 perror("PIOCSENTRY");
899 return -1;
900 }
John Hughes19e49982001-10-19 08:59:12 +0000901 /* Enable the syscall exits. */
902 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000903 perror("PIOSEXIT");
904 return -1;
905 }
John Hughes19e49982001-10-19 08:59:12 +0000906 /* Enable signals we care about. */
907 premptyset(&signals);
908 for (i = 1; i < MAX_QUALS; ++i) {
909 if (i > (sizeof signals) * CHAR_BIT) break;
910 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
911 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000912 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000913 perror("PIOCSTRACE");
914 return -1;
915 }
John Hughes19e49982001-10-19 08:59:12 +0000916 /* Enable faults we care about */
917 premptyset(&faults);
918 for (i = 1; i < MAX_QUALS; ++i) {
919 if (i > (sizeof faults) * CHAR_BIT) break;
920 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
921 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000922 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000923 perror("PIOCSFAULT");
924 return -1;
925 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000926#else /* FREEBSD */
927 /* set events flags. */
928 arg = S_SIG | S_SCE | S_SCX ;
929 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
930 perror("PIOCBIS");
931 return -1;
932 }
933#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000934 if (!attaching) {
935#ifdef MIPS
936 /*
937 * The SGI PRSABORT doesn't work for pause() so
938 * we send it a caught signal to wake it up.
939 */
940 kill(tcp->pid, SIGINT);
941#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000942#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000943 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000944 arg = PRSABORT;
945 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000946 perror("PIOCRUN");
947 return -1;
948 }
Roland McGrath553a6092002-12-16 20:40:39 +0000949#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000950#endif /* !MIPS*/
951#ifdef FREEBSD
952 /* wake up the child if it received the SIGSTOP */
953 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000954#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000955 for (;;) {
956 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000957 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000958 perror("PIOCWSTOP");
959 return -1;
960 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000961 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000962 tcp->flags &= ~TCB_INSYSCALL;
963 get_scno(tcp);
964 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000965 break;
966 }
967 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000968#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000969 arg = 0;
970 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000971#else /* FREEBSD */
972 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +0000973#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974 perror("PIOCRUN");
975 return -1;
976 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000977#ifdef FREEBSD
978 /* handle the case where we "opened" the child before
979 it did the kill -STOP */
980 if (tcp->status.PR_WHY == PR_SIGNALLED &&
981 tcp->status.PR_WHAT == SIGSTOP)
982 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000983#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000984 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000985#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000987#else /* FREEBSD */
988 } else {
Roland McGrath553a6092002-12-16 20:40:39 +0000989 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000990 /* We are attaching to an already running process.
991 * Try to figure out the state of the process in syscalls,
992 * to handle the first event well.
993 * This is done by having a look at the "wchan" property of the
994 * process, which tells where it is stopped (if it is). */
995 FILE * status;
996 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +0000997
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000998 sprintf(proc, "/proc/%d/status", tcp->pid);
999 status = fopen(proc, "r");
1000 if (status &&
1001 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1002 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1003 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1004 strcmp(wchan, "stopevent")) {
1005 /* The process is asleep in the middle of a syscall.
1006 Fake the syscall entry event */
1007 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1008 tcp->status.PR_WHY = PR_SYSENTRY;
1009 trace_syscall(tcp);
1010 }
1011 if (status)
1012 fclose(status);
1013 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001014 }
1015#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001016#ifndef HAVE_POLLABLE_PROCFS
1017 if (proc_poll_pipe[0] != -1)
1018 proc_poller(tcp->pfd);
1019 else if (nprocs > 1) {
1020 proc_poll_open();
1021 proc_poller(last_pfd);
1022 proc_poller(tcp->pfd);
1023 }
1024 last_pfd = tcp->pfd;
1025#endif /* !HAVE_POLLABLE_PROCFS */
1026 return 0;
1027}
1028
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001029#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001030
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001031struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001032pid2tcb(pid)
1033int pid;
1034{
1035 int i;
1036 struct tcb *tcp;
1037
Roland McGrathee9d4352002-12-18 04:16:10 +00001038 for (i = 0; i < tcbtabsize; i++) {
1039 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001040 if (pid && tcp->pid != pid)
1041 continue;
1042 if (tcp->flags & TCB_INUSE)
1043 return tcp;
1044 }
1045 return NULL;
1046}
1047
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001048#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001049
1050static struct tcb *
1051pfd2tcb(pfd)
1052int pfd;
1053{
1054 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001055
Roland McGrathca16be82003-01-10 19:55:28 +00001056 for (i = 0; i < tcbtabsize; i++) {
1057 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001058 if (tcp->pfd != pfd)
1059 continue;
1060 if (tcp->flags & TCB_INUSE)
1061 return tcp;
1062 }
1063 return NULL;
1064}
1065
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001066#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067
1068void
1069droptcb(tcp)
1070struct tcb *tcp;
1071{
1072 if (tcp->pid == 0)
1073 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001074#ifdef TCB_CLONE_THREAD
1075 if (tcp->nclone_threads > 0) {
1076 /* There are other threads left in this process, but this
1077 is the one whose PID represents the whole process.
1078 We need to keep this record around as a zombie until
1079 all the threads die. */
1080 tcp->flags |= TCB_EXITING;
1081 return;
1082 }
1083#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001084 nprocs--;
1085 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001086
Roland McGrathe29341c2003-01-10 20:14:20 +00001087 if (tcp->parent != NULL) {
1088 tcp->parent->nchildren--;
1089#ifdef TCB_CLONE_THREAD
1090 if (tcp->flags & TCB_CLONE_DETACHED)
1091 tcp->parent->nclone_detached--;
1092 if (tcp->flags & TCB_CLONE_THREAD)
1093 tcp->parent->nclone_threads--;
1094#endif
Roland McGrath09623452003-05-23 02:27:13 +00001095#ifdef TCB_CLONE_DETACHED
1096 if (!(tcp->flags & TCB_CLONE_DETACHED))
1097#endif
1098 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001099 tcp->parent = NULL;
1100 }
1101
1102 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001103 if (tcp->pfd != -1) {
1104 close(tcp->pfd);
1105 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001106#ifdef FREEBSD
1107 if (tcp->pfd_reg != -1) {
1108 close(tcp->pfd_reg);
1109 tcp->pfd_reg = -1;
1110 }
1111 if (tcp->pfd_status != -1) {
1112 close(tcp->pfd_status);
1113 tcp->pfd_status = -1;
1114 }
Roland McGrath553a6092002-12-16 20:40:39 +00001115#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001116#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001117 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118#endif
1119 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001120
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001121 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001123
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001124 tcp->outf = 0;
1125}
1126
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001127#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001128
1129static int
1130resume(tcp)
1131struct tcb *tcp;
1132{
1133 if (tcp == NULL)
1134 return -1;
1135
1136 if (!(tcp->flags & TCB_SUSPENDED)) {
1137 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1138 return -1;
1139 }
1140 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001141#ifdef TCB_CLONE_THREAD
1142 if (tcp->flags & TCB_CLONE_THREAD)
1143 tcp->parent->nclone_waiting--;
1144#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145
1146 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1147 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1148 return -1;
1149 }
1150
1151 if (!qflag)
1152 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1153 return 0;
1154}
1155
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001156#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157
1158/* detach traced process; continue with sig */
1159
1160static int
1161detach(tcp, sig)
1162struct tcb *tcp;
1163int sig;
1164{
1165 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001166#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001167 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001168#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001169
1170 if (tcp->flags & TCB_BPTSET)
1171 sig = SIGKILL;
1172
1173#ifdef LINUX
1174 /*
1175 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001176 * before detaching. Arghh. We go through hoops
1177 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001178 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001179#if defined(SPARC)
1180#undef PTRACE_DETACH
1181#define PTRACE_DETACH PTRACE_SUNDETACH
1182#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001183 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1184 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001185 }
1186 else if (errno != ESRCH) {
1187 /* Shouldn't happen. */
1188 perror("detach: ptrace(PTRACE_DETACH, ...)");
1189 }
1190 else if (kill(tcp->pid, 0) < 0) {
1191 if (errno != ESRCH)
1192 perror("detach: checking sanity");
1193 }
1194 else if (kill(tcp->pid, SIGSTOP) < 0) {
1195 if (errno != ESRCH)
1196 perror("detach: stopping child");
1197 }
1198 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001199 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001200#ifdef __WALL
1201 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1202 if (errno == ECHILD) /* Already gone. */
1203 break;
1204 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001205 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001206 break;
1207 }
1208#endif /* __WALL */
1209 /* No __WALL here. */
1210 if (waitpid(tcp->pid, &status, 0) < 0) {
1211 if (errno != ECHILD) {
1212 perror("detach: waiting");
1213 break;
1214 }
1215#ifdef __WCLONE
1216 /* If no processes, try clones. */
1217 if (wait4(tcp->pid, &status, __WCLONE,
1218 NULL) < 0) {
1219 if (errno != ECHILD)
1220 perror("detach: waiting");
1221 break;
1222 }
1223#endif /* __WCLONE */
1224 }
1225#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001226 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001227#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001228 if (!WIFSTOPPED(status)) {
1229 /* Au revoir, mon ami. */
1230 break;
1231 }
1232 if (WSTOPSIG(status) == SIGSTOP) {
1233 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001234 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235 if (errno != ESRCH)
1236 perror("detach: ptrace(PTRACE_DETACH, ...)");
1237 /* I died trying. */
1238 }
1239 break;
1240 }
1241 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001242 WSTOPSIG(status) == SIGTRAP ?
1243 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001244 if (errno != ESRCH)
1245 perror("detach: ptrace(PTRACE_CONT, ...)");
1246 break;
1247 }
1248 }
1249 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001250#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251
1252#if defined(SUNOS4)
1253 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1254 if (sig && kill(tcp->pid, sig) < 0)
1255 perror("detach: kill");
1256 sig = 0;
1257 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1258 perror("detach: ptrace(PTRACE_DETACH, ...)");
1259#endif /* SUNOS4 */
1260
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001261#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001262 resumed = 0;
1263
1264 /* XXX This won't always be quite right (but it never was).
1265 A waiter with argument 0 or < -1 is waiting for any pid in
1266 a particular pgrp, which this child might or might not be
1267 in. The waiter will only wake up if it's argument is -1
1268 or if it's waiting for tcp->pid's pgrp. It makes a
1269 difference to wake up a waiter when there might be more
1270 traced children, because it could get a false ECHILD
1271 error. OTOH, if this was the last child in the pgrp, then
1272 it ought to wake up and get ECHILD. We would have to
1273 search the system for all pid's in the pgrp to be sure.
1274
1275 && (t->waitpid == -1 ||
1276 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1277 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1278 */
1279
1280 if (tcp->parent &&
1281 (tcp->parent->flags & TCB_SUSPENDED) &&
1282 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1283 error = resume(tcp->parent);
1284 ++resumed;
1285 }
1286#ifdef TCB_CLONE_THREAD
1287 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1288 /* Some other threads of our parent are waiting too. */
1289 unsigned int i;
1290
1291 /* Resume all the threads that were waiting for this PID. */
1292 for (i = 0; i < tcbtabsize; i++) {
1293 struct tcb *t = tcbtab[i];
1294 if (t->parent == tcp->parent && t != tcp
1295 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1296 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1297 && t->waitpid == tcp->pid) {
1298 error |= resume (t);
1299 ++resumed;
1300 }
1301 }
1302 if (resumed == 0)
1303 /* Noone was waiting for this PID in particular,
1304 so now we might need to resume some wildcarders. */
1305 for (i = 0; i < tcbtabsize; i++) {
1306 struct tcb *t = tcbtab[i];
1307 if (t->parent == tcp->parent && t != tcp
1308 && ((t->flags
1309 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1310 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1311 && t->waitpid <= 0
1312 ) {
1313 error |= resume (t);
1314 break;
1315 }
1316 }
1317 }
1318#endif
1319
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001320#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001321
1322 if (!qflag)
1323 fprintf(stderr, "Process %u detached\n", tcp->pid);
1324
1325 droptcb(tcp);
1326 return error;
1327}
1328
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001329#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001330
1331static void
1332reaper(sig)
1333int sig;
1334{
1335 int pid;
1336 int status;
1337
1338 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1339#if 0
1340 struct tcb *tcp;
1341
1342 tcp = pid2tcb(pid);
1343 if (tcp)
1344 droptcb(tcp);
1345#endif
1346 }
1347}
1348
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001349#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001350
1351static void
1352cleanup()
1353{
1354 int i;
1355 struct tcb *tcp;
1356
Roland McGrathee9d4352002-12-18 04:16:10 +00001357 for (i = 0; i < tcbtabsize; i++) {
1358 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001359 if (!(tcp->flags & TCB_INUSE))
1360 continue;
1361 if (debug)
1362 fprintf(stderr,
1363 "cleanup: looking at pid %u\n", tcp->pid);
1364 if (tcp_last &&
1365 (!outfname || followfork < 2 || tcp_last == tcp)) {
1366 tprintf(" <unfinished ...>\n");
1367 tcp_last = NULL;
1368 }
1369 if (tcp->flags & TCB_ATTACHED)
1370 detach(tcp, 0);
1371 else {
1372 kill(tcp->pid, SIGCONT);
1373 kill(tcp->pid, SIGTERM);
1374 }
1375 }
1376 if (cflag)
1377 call_summary(outf);
1378}
1379
1380static void
1381interrupt(sig)
1382int sig;
1383{
1384 interrupted = 1;
1385}
1386
1387#ifndef HAVE_STRERROR
1388
Roland McGrath6d2b3492002-12-30 00:51:30 +00001389#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001390extern int sys_nerr;
1391extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001392#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001393
1394const char *
1395strerror(errno)
1396int errno;
1397{
1398 static char buf[64];
1399
1400 if (errno < 1 || errno >= sys_nerr) {
1401 sprintf(buf, "Unknown error %d", errno);
1402 return buf;
1403 }
1404 return sys_errlist[errno];
1405}
1406
1407#endif /* HAVE_STERRROR */
1408
1409#ifndef HAVE_STRSIGNAL
1410
Roland McGrath8f474e02003-01-14 07:53:33 +00001411#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001412extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001413#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001414#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1415extern char *_sys_siglist[];
1416#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001417
1418const char *
1419strsignal(sig)
1420int sig;
1421{
1422 static char buf[64];
1423
1424 if (sig < 1 || sig >= NSIG) {
1425 sprintf(buf, "Unknown signal %d", sig);
1426 return buf;
1427 }
1428#ifdef HAVE__SYS_SIGLIST
1429 return _sys_siglist[sig];
1430#else
1431 return sys_siglist[sig];
1432#endif
1433}
1434
1435#endif /* HAVE_STRSIGNAL */
1436
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001437#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001438
1439static void
1440rebuild_pollv()
1441{
1442 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001443
Roland McGrathee9d4352002-12-18 04:16:10 +00001444 if (pollv != NULL)
1445 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001446 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001447 if (pollv == NULL) {
1448 fprintf(stderr, "strace: out of memory for poll vector\n");
1449 exit(1);
1450 }
1451
Roland McGrathca16be82003-01-10 19:55:28 +00001452 for (i = j = 0; i < tcbtabsize; i++) {
1453 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001454 if (!(tcp->flags & TCB_INUSE))
1455 continue;
1456 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001457 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001458 j++;
1459 }
1460 if (j != nprocs) {
1461 fprintf(stderr, "strace: proc miscount\n");
1462 exit(1);
1463 }
1464}
1465
1466#ifndef HAVE_POLLABLE_PROCFS
1467
1468static void
1469proc_poll_open()
1470{
1471 int arg;
1472 int i;
1473
1474 if (pipe(proc_poll_pipe) < 0) {
1475 perror("pipe");
1476 exit(1);
1477 }
1478 for (i = 0; i < 2; i++) {
1479 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1480 perror("F_GETFD");
1481 exit(1);
1482 }
1483 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1484 perror("F_SETFD");
1485 exit(1);
1486 }
1487 }
1488}
1489
1490static int
1491proc_poll(pollv, nfds, timeout)
1492struct pollfd *pollv;
1493int nfds;
1494int timeout;
1495{
1496 int i;
1497 int n;
1498 struct proc_pollfd pollinfo;
1499
1500 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1501 return n;
1502 if (n != sizeof(struct proc_pollfd)) {
1503 fprintf(stderr, "panic: short read: %d\n", n);
1504 exit(1);
1505 }
1506 for (i = 0; i < nprocs; i++) {
1507 if (pollv[i].fd == pollinfo.fd)
1508 pollv[i].revents = pollinfo.revents;
1509 else
1510 pollv[i].revents = 0;
1511 }
1512 poller_pid = pollinfo.pid;
1513 return 1;
1514}
1515
1516static void
1517wakeup_handler(sig)
1518int sig;
1519{
1520}
1521
1522static void
1523proc_poller(pfd)
1524int pfd;
1525{
1526 struct proc_pollfd pollinfo;
1527 struct sigaction sa;
1528 sigset_t blocked_set, empty_set;
1529 int i;
1530 int n;
1531 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001532#ifdef FREEBSD
1533 struct procfs_status pfs;
1534#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001535
1536 switch (fork()) {
1537 case -1:
1538 perror("fork");
1539 _exit(0);
1540 case 0:
1541 break;
1542 default:
1543 return;
1544 }
1545
1546 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1547 sa.sa_flags = 0;
1548 sigemptyset(&sa.sa_mask);
1549 sigaction(SIGHUP, &sa, NULL);
1550 sigaction(SIGINT, &sa, NULL);
1551 sigaction(SIGQUIT, &sa, NULL);
1552 sigaction(SIGPIPE, &sa, NULL);
1553 sigaction(SIGTERM, &sa, NULL);
1554 sa.sa_handler = wakeup_handler;
1555 sigaction(SIGUSR1, &sa, NULL);
1556 sigemptyset(&blocked_set);
1557 sigaddset(&blocked_set, SIGUSR1);
1558 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1559 sigemptyset(&empty_set);
1560
1561 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1562 perror("getrlimit(RLIMIT_NOFILE, ...)");
1563 _exit(0);
1564 }
1565 n = rl.rlim_cur;
1566 for (i = 0; i < n; i++) {
1567 if (i != pfd && i != proc_poll_pipe[1])
1568 close(i);
1569 }
1570
1571 pollinfo.fd = pfd;
1572 pollinfo.pid = getpid();
1573 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001574#ifndef FREEBSD
1575 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1576#else /* FREEBSD */
1577 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1578#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001579 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001580 switch (errno) {
1581 case EINTR:
1582 continue;
1583 case EBADF:
1584 pollinfo.revents = POLLERR;
1585 break;
1586 case ENOENT:
1587 pollinfo.revents = POLLHUP;
1588 break;
1589 default:
1590 perror("proc_poller: PIOCWSTOP");
1591 }
1592 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1593 _exit(0);
1594 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001595 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001596 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1597 sigsuspend(&empty_set);
1598 }
1599}
1600
1601#endif /* !HAVE_POLLABLE_PROCFS */
1602
1603static int
1604choose_pfd()
1605{
1606 int i, j;
1607 struct tcb *tcp;
1608
1609 static int last;
1610
1611 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001612 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001613 /*
1614 * The previous process is ready to run again. We'll
1615 * let it do so if it is currently in a syscall. This
1616 * heuristic improves the readability of the trace.
1617 */
1618 tcp = pfd2tcb(pollv[last].fd);
1619 if (tcp && (tcp->flags & TCB_INSYSCALL))
1620 return pollv[last].fd;
1621 }
1622
1623 for (i = 0; i < nprocs; i++) {
1624 /* Let competing children run round robin. */
1625 j = (i + last + 1) % nprocs;
1626 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1627 tcp = pfd2tcb(pollv[j].fd);
1628 if (!tcp) {
1629 fprintf(stderr, "strace: lost proc\n");
1630 exit(1);
1631 }
1632 droptcb(tcp);
1633 return -1;
1634 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001635 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636 last = j;
1637 return pollv[j].fd;
1638 }
1639 }
1640 fprintf(stderr, "strace: nothing ready\n");
1641 exit(1);
1642}
1643
1644static int
1645trace()
1646{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001647#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001648 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001649#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001650 struct tcb *tcp;
1651 int pfd;
1652 int what;
1653 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001654 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001655
1656 for (;;) {
1657 if (interactive)
1658 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1659
1660 if (nprocs == 0)
1661 break;
1662
1663 switch (nprocs) {
1664 case 1:
1665#ifndef HAVE_POLLABLE_PROCFS
1666 if (proc_poll_pipe[0] == -1) {
1667#endif
1668 tcp = pid2tcb(0);
1669 if (!tcp)
1670 continue;
1671 pfd = tcp->pfd;
1672 if (pfd == -1)
1673 continue;
1674 break;
1675#ifndef HAVE_POLLABLE_PROCFS
1676 }
1677 /* fall through ... */
1678#endif /* !HAVE_POLLABLE_PROCFS */
1679 default:
1680#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001681#ifdef POLL_HACK
1682 /* On some systems (e.g. UnixWare) we get too much ugly
1683 "unfinished..." stuff when multiple proceses are in
1684 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001685
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001686 if (in_syscall) {
1687 struct pollfd pv;
1688 tcp = in_syscall;
1689 in_syscall = NULL;
1690 pv.fd = tcp->pfd;
1691 pv.events = POLLWANT;
1692 if ((what = poll (&pv, 1, 1)) < 0) {
1693 if (interrupted)
1694 return 0;
1695 continue;
1696 }
1697 else if (what == 1 && pv.revents & POLLWANT) {
1698 goto FOUND;
1699 }
1700 }
1701#endif
1702
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001703 if (poll(pollv, nprocs, INFTIM) < 0) {
1704 if (interrupted)
1705 return 0;
1706 continue;
1707 }
1708#else /* !HAVE_POLLABLE_PROCFS */
1709 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1710 if (interrupted)
1711 return 0;
1712 continue;
1713 }
1714#endif /* !HAVE_POLLABLE_PROCFS */
1715 pfd = choose_pfd();
1716 if (pfd == -1)
1717 continue;
1718 break;
1719 }
1720
1721 /* Look up `pfd' in our table. */
1722 if ((tcp = pfd2tcb(pfd)) == NULL) {
1723 fprintf(stderr, "unknown pfd: %u\n", pfd);
1724 exit(1);
1725 }
John Hughesb6643082002-05-23 11:02:22 +00001726#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001727 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001728#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001729 /* Get the status of the process. */
1730 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001731#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001732 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001733#else /* FREEBSD */
1734 /* Thanks to some scheduling mystery, the first poller
1735 sometimes waits for the already processed end of fork
1736 event. Doing a non blocking poll here solves the problem. */
1737 if (proc_poll_pipe[0] != -1)
1738 ioctl_result = IOCTL_STATUS (tcp);
1739 else
1740 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001741#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001742 ioctl_errno = errno;
1743#ifndef HAVE_POLLABLE_PROCFS
1744 if (proc_poll_pipe[0] != -1) {
1745 if (ioctl_result < 0)
1746 kill(poller_pid, SIGKILL);
1747 else
1748 kill(poller_pid, SIGUSR1);
1749 }
1750#endif /* !HAVE_POLLABLE_PROCFS */
1751 }
1752 if (interrupted)
1753 return 0;
1754
1755 if (interactive)
1756 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1757
1758 if (ioctl_result < 0) {
1759 /* Find out what happened if it failed. */
1760 switch (ioctl_errno) {
1761 case EINTR:
1762 case EBADF:
1763 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001764#ifdef FREEBSD
1765 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001766#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001767 case ENOENT:
1768 droptcb(tcp);
1769 continue;
1770 default:
1771 perror("PIOCWSTOP");
1772 exit(1);
1773 }
1774 }
1775
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001776#ifdef FREEBSD
1777 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1778 /* discard first event for a syscall we never entered */
1779 IOCTL (tcp->pfd, PIOCRUN, 0);
1780 continue;
1781 }
Roland McGrath553a6092002-12-16 20:40:39 +00001782#endif
1783
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001784 /* clear the just started flag */
1785 tcp->flags &= ~TCB_STARTUP;
1786
1787 /* set current output file */
1788 outf = tcp->outf;
1789
1790 if (cflag) {
1791 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001792#ifdef FREEBSD
1793 char buf[1024];
1794 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001795
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001796 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1797 buf[len] = '\0';
1798 sscanf(buf,
1799 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1800 &stime.tv_sec, &stime.tv_usec);
1801 } else
1802 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001803#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001804 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1805 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001806#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001807 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1808 tcp->stime = stime;
1809 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001810 what = tcp->status.PR_WHAT;
1811 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001812#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001813 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001814 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1815 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001816 if (trace_syscall(tcp) < 0) {
1817 fprintf(stderr, "syscall trouble\n");
1818 exit(1);
1819 }
1820 }
1821 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001822#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001823 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001824#ifdef POLL_HACK
1825 in_syscall = tcp;
1826#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001827 case PR_SYSEXIT:
1828 if (trace_syscall(tcp) < 0) {
1829 fprintf(stderr, "syscall trouble\n");
1830 exit(1);
1831 }
1832 break;
1833 case PR_SIGNALLED:
1834 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1835 printleader(tcp);
1836 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001837 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001838 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001839#ifdef PR_INFO
1840 if (tcp->status.PR_INFO.si_signo == what) {
1841 printleader(tcp);
1842 tprintf(" siginfo=");
1843 printsiginfo(&tcp->status.PR_INFO, 1);
1844 printtrailer(tcp);
1845 }
1846#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001847 }
1848 break;
1849 case PR_FAULTED:
1850 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1851 printleader(tcp);
1852 tprintf("=== FAULT %d ===", what);
1853 printtrailer(tcp);
1854 }
1855 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001856#ifdef FREEBSD
1857 case 0: /* handle case we polled for nothing */
1858 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001859#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001860 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001861 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001862 exit(1);
1863 break;
1864 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001865 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001866#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001867 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001868#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001869 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001870#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001871 perror("PIOCRUN");
1872 exit(1);
1873 }
1874 }
1875 return 0;
1876}
1877
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001878#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001879
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001880#ifdef TCB_GROUP_EXITING
1881/* Handle an exit detach or death signal that is taking all the
1882 related clone threads with it. This is called in three circumstances:
1883 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1884 SIG == 0 Continuing TCP will perform an exit_group syscall.
1885 SIG == other Continuing TCP with SIG will kill the process.
1886*/
1887static int
1888handle_group_exit(struct tcb *tcp, int sig)
1889{
1890 /* We need to locate our records of all the clone threads
1891 related to TCP, either its children or siblings. */
1892 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1893 ? tcp->parent
1894 : tcp->nclone_detached > 0
1895 ? tcp : NULL);
1896
1897 if (sig < 0) {
1898 if (leader != NULL && leader != tcp)
1899 fprintf(stderr,
1900 "PANIC: handle_group_exit: %d leader %d\n",
1901 tcp->pid, leader ? leader->pid : -1);
1902 droptcb(tcp); /* Already died. */
1903 }
1904 else {
1905 if (tcp->flags & TCB_ATTACHED) {
1906 if (leader != NULL && leader != tcp) {
1907 /* We need to detach the leader so that the
1908 process death will be reported to its real
1909 parent. But we kill it first to prevent
1910 it doing anything before we kill the whole
1911 process in a moment. We can use
1912 PTRACE_KILL on a thread that's not already
1913 stopped. Then the value we pass in
1914 PTRACE_DETACH just sets the death
1915 signal reported to the real parent. */
1916 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1917 if (debug)
1918 fprintf(stderr,
1919 " [%d exit %d kills %d]\n",
1920 tcp->pid, sig, leader->pid);
1921 detach(leader, sig);
1922 }
1923 detach(tcp, sig);
1924 }
1925 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1926 perror("strace: ptrace(PTRACE_CONT, ...)");
1927 cleanup();
1928 return -1;
1929 }
1930 else {
1931 if (leader != NULL && leader != tcp)
1932 droptcb(tcp);
1933 /* The leader will report to us as parent now,
1934 and then we'll get to the SIG==-1 case. */
1935 return 0;
1936 }
1937 }
1938
1939 /* Note that TCP and LEADER are no longer valid,
1940 but we can still compare against them. */
1941 if (leader != NULL) {
1942 unsigned int i;
1943 for (i = 0; i < tcbtabsize; i++) {
1944 struct tcb *t = tcbtab[i];
1945 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1946 && t->parent == leader)
1947 droptcb(t);
1948 }
1949 }
1950
1951 return 0;
1952}
1953#endif
1954
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001955static int
1956trace()
1957{
1958 int pid;
1959 int wait_errno;
1960 int status;
1961 struct tcb *tcp;
1962#ifdef LINUX
1963 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001964#ifdef __WALL
1965 static int wait4_options = __WALL;
1966#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001967#endif /* LINUX */
1968
1969 while (nprocs != 0) {
1970 if (interactive)
1971 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1972#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001973#ifdef __WALL
1974 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00001975 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001976 /* this kernel does not support __WALL */
1977 wait4_options &= ~__WALL;
1978 errno = 0;
1979 pid = wait4(-1, &status, wait4_options,
1980 cflag ? &ru : NULL);
1981 }
Roland McGrath5bc05552002-12-17 04:50:47 +00001982 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001983 /* most likely a "cloned" process */
1984 pid = wait4(-1, &status, __WCLONE,
1985 cflag ? &ru : NULL);
1986 if (pid == -1) {
1987 fprintf(stderr, "strace: clone wait4 "
1988 "failed: %s\n", strerror(errno));
1989 }
1990 }
1991#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001992 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001993#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001994#endif /* LINUX */
1995#ifdef SUNOS4
1996 pid = wait(&status);
1997#endif /* SUNOS4 */
1998 wait_errno = errno;
1999 if (interactive)
2000 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2001
2002 if (interrupted)
2003 return 0;
2004
2005 if (pid == -1) {
2006 switch (wait_errno) {
2007 case EINTR:
2008 continue;
2009 case ECHILD:
2010 /*
2011 * We would like to verify this case
2012 * but sometimes a race in Solbourne's
2013 * version of SunOS sometimes reports
2014 * ECHILD before sending us SIGCHILD.
2015 */
2016#if 0
2017 if (nprocs == 0)
2018 return 0;
2019 fprintf(stderr, "strace: proc miscount\n");
2020 exit(1);
2021#endif
2022 return 0;
2023 default:
2024 errno = wait_errno;
2025 perror("strace: wait");
2026 return -1;
2027 }
2028 }
2029 if (debug)
2030 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2031
2032 /* Look up `pid' in our table. */
2033 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002034#ifdef LINUX
2035 if (followfork || followvfork) {
2036 /* This is needed to go with the CLONE_PTRACE
2037 changes in process.c/util.c: we might see
2038 the child's initial trap before we see the
2039 parent return from the clone syscall.
2040 Leave the child suspended until the parent
2041 returns from its system call. Only then
2042 will we have the association of parent and
2043 child so that we know how to do clearbpt
2044 in the child. */
2045 if ((tcp = alloctcb(pid)) == NULL) {
2046 fprintf(stderr, " [tcb table full]\n");
2047 kill(pid, SIGKILL); /* XXX */
2048 return 0;
2049 }
2050 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
2051 newoutf(tcp);
2052 if (!qflag)
2053 fprintf(stderr, "\
2054Process %d attached (waiting for parent)\n",
2055 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002056 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002057 else
2058 /* This can happen if a clone call used
2059 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002060#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002061 {
2062 fprintf(stderr, "unknown pid: %u\n", pid);
2063 if (WIFSTOPPED(status))
2064 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2065 exit(1);
2066 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002067 }
2068 /* set current output file */
2069 outf = tcp->outf;
2070 if (cflag) {
2071#ifdef LINUX
2072 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2073 tcp->stime = ru.ru_stime;
2074#endif /* !LINUX */
2075 }
2076
2077 if (tcp->flags & TCB_SUSPENDED) {
2078 /*
2079 * Apparently, doing any ptrace() call on a stopped
2080 * process, provokes the kernel to report the process
2081 * status again on a subsequent wait(), even if the
2082 * process has not been actually restarted.
2083 * Since we have inspected the arguments of suspended
2084 * processes we end up here testing for this case.
2085 */
2086 continue;
2087 }
2088 if (WIFSIGNALED(status)) {
2089 if (!cflag
2090 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2091 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002092 tprintf("+++ killed by %s %s+++",
2093 signame(WTERMSIG(status)),
2094#ifdef WCOREDUMP
2095 WCOREDUMP(status) ? "(core dumped) " :
2096#endif
2097 "");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002098 printtrailer(tcp);
2099 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002100#ifdef TCB_GROUP_EXITING
2101 handle_group_exit(tcp, -1);
2102#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002103 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002104#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002105 continue;
2106 }
2107 if (WIFEXITED(status)) {
2108 if (debug)
2109 fprintf(stderr, "pid %u exited\n", pid);
2110 if (tcp->flags & TCB_ATTACHED)
2111 fprintf(stderr,
2112 "PANIC: attached pid %u exited\n",
2113 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002114 if (tcp == tcp_last) {
2115 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2116 == TCB_INSYSCALL)
2117 tprintf(" <unfinished ... exit status %d>\n",
2118 WEXITSTATUS(status));
2119 tcp_last = NULL;
2120 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002121#ifdef TCB_GROUP_EXITING
2122 handle_group_exit(tcp, -1);
2123#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002124 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002125#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002126 continue;
2127 }
2128 if (!WIFSTOPPED(status)) {
2129 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2130 droptcb(tcp);
2131 continue;
2132 }
2133 if (debug)
2134 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002135 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002136
2137 if (tcp->flags & TCB_STARTUP) {
2138 /*
2139 * This flag is there to keep us in sync.
2140 * Next time this process stops it should
2141 * really be entering a system call.
2142 */
2143 tcp->flags &= ~TCB_STARTUP;
2144 if (tcp->flags & TCB_ATTACHED) {
2145 /*
2146 * Interestingly, the process may stop
2147 * with STOPSIG equal to some other signal
2148 * than SIGSTOP if we happend to attach
2149 * just before the process takes a signal.
2150 */
2151 if (!WIFSTOPPED(status)) {
2152 fprintf(stderr,
2153 "pid %u not stopped\n", pid);
2154 detach(tcp, WSTOPSIG(status));
2155 continue;
2156 }
2157 }
2158 else {
2159#ifdef SUNOS4
2160 /* A child of us stopped at exec */
2161 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2162 fixvfork(tcp);
2163#endif /* SUNOS4 */
2164 }
2165 if (tcp->flags & TCB_BPTSET) {
2166 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2167 droptcb(tcp);
2168 cleanup();
2169 return -1;
2170 }
2171 }
2172 goto tracing;
2173 }
2174
2175 if (WSTOPSIG(status) != SIGTRAP) {
2176 if (WSTOPSIG(status) == SIGSTOP &&
2177 (tcp->flags & TCB_SIGTRAPPED)) {
2178 /*
2179 * Trapped attempt to block SIGTRAP
2180 * Hope we are back in control now.
2181 */
2182 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2183 if (ptrace(PTRACE_SYSCALL,
2184 pid, (char *) 1, 0) < 0) {
2185 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2186 cleanup();
2187 return -1;
2188 }
2189 continue;
2190 }
2191 if (!cflag
2192 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002193 unsigned long addr = 0, pc = 0;
2194#ifdef PT_GETSIGINFO
2195# define PSR_RI 41
2196 struct siginfo si;
2197 unsigned long psr;
2198
2199 upeek(pid, PT_CR_IPSR, &psr);
2200 upeek(pid, PT_CR_IIP, &pc);
2201
2202 pc += (psr >> PSR_RI) & 0x3;
2203 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2204 addr = (unsigned long) si.si_addr;
2205#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002206 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002207 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002208 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002209 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002210 printtrailer(tcp);
2211 }
2212 if ((tcp->flags & TCB_ATTACHED) &&
2213 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002214#ifdef TCB_GROUP_EXITING
2215 handle_group_exit(tcp, WSTOPSIG(status));
2216#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002217 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002218#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002219 continue;
2220 }
2221 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2222 WSTOPSIG(status)) < 0) {
2223 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2224 cleanup();
2225 return -1;
2226 }
2227 tcp->flags &= ~TCB_SUSPENDED;
2228 continue;
2229 }
2230 if (trace_syscall(tcp) < 0) {
2231 if (tcp->flags & TCB_ATTACHED)
2232 detach(tcp, 0);
2233 else {
2234 ptrace(PTRACE_KILL,
2235 tcp->pid, (char *) 1, SIGTERM);
2236 droptcb(tcp);
2237 }
2238 continue;
2239 }
2240 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002241#ifdef TCB_GROUP_EXITING
2242 if (tcp->flags & TCB_GROUP_EXITING) {
2243 if (handle_group_exit(tcp, 0) < 0)
2244 return -1;
2245 continue;
2246 }
2247#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002248 if (tcp->flags & TCB_ATTACHED)
2249 detach(tcp, 0);
2250 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2251 perror("strace: ptrace(PTRACE_CONT, ...)");
2252 cleanup();
2253 return -1;
2254 }
2255 continue;
2256 }
2257 if (tcp->flags & TCB_SUSPENDED) {
2258 if (!qflag)
2259 fprintf(stderr, "Process %u suspended\n", pid);
2260 continue;
2261 }
2262 tracing:
2263 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2264 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2265 cleanup();
2266 return -1;
2267 }
2268 }
2269 return 0;
2270}
2271
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002272#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002273
2274static int curcol;
2275
2276#ifdef __STDC__
2277#include <stdarg.h>
2278#define VA_START(a, b) va_start(a, b)
2279#else
2280#include <varargs.h>
2281#define VA_START(a, b) va_start(a)
2282#endif
2283
2284void
2285#ifdef __STDC__
2286tprintf(const char *fmt, ...)
2287#else
2288tprintf(fmt, va_alist)
2289char *fmt;
2290va_dcl
2291#endif
2292{
2293 va_list args;
2294
2295 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002296 if (outf) {
2297 int n = vfprintf(outf, fmt, args);
2298 if (n < 0 && outf != stderr)
2299 perror(outfname == NULL
2300 ? "<writing to pipe>" : outfname);
2301 else
2302 curcol += n;
2303 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002304 va_end(args);
2305 return;
2306}
2307
2308void
2309printleader(tcp)
2310struct tcb *tcp;
2311{
2312 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2313 tcp_last->flags |= TCB_REPRINT;
2314 tprintf(" <unfinished ...>\n");
2315 }
2316 curcol = 0;
2317 if ((followfork == 1 || pflag_seen > 1) && outfname)
2318 tprintf("%-5d ", tcp->pid);
2319 else if (nprocs > 1 && !outfname)
2320 tprintf("[pid %5u] ", tcp->pid);
2321 if (tflag) {
2322 char str[sizeof("HH:MM:SS")];
2323 struct timeval tv, dtv;
2324 static struct timeval otv;
2325
2326 gettimeofday(&tv, NULL);
2327 if (rflag) {
2328 if (otv.tv_sec == 0)
2329 otv = tv;
2330 tv_sub(&dtv, &tv, &otv);
2331 tprintf("%6ld.%06ld ",
2332 (long) dtv.tv_sec, (long) dtv.tv_usec);
2333 otv = tv;
2334 }
2335 else if (tflag > 2) {
2336 tprintf("%ld.%06ld ",
2337 (long) tv.tv_sec, (long) tv.tv_usec);
2338 }
2339 else {
2340 time_t local = tv.tv_sec;
2341 strftime(str, sizeof(str), "%T", localtime(&local));
2342 if (tflag > 1)
2343 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2344 else
2345 tprintf("%s ", str);
2346 }
2347 }
2348 if (iflag)
2349 printcall(tcp);
2350}
2351
2352void
2353tabto(col)
2354int col;
2355{
2356 if (curcol < col)
2357 tprintf("%*s", col - curcol, "");
2358}
2359
2360void
2361printtrailer(tcp)
2362struct tcb *tcp;
2363{
2364 tprintf("\n");
2365 tcp_last = NULL;
2366}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002367
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002368#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002369
2370int mp_ioctl (int fd, int cmd, void *arg, int size) {
2371
2372 struct iovec iov[2];
2373 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002374
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002375 iov[0].iov_base = &cmd;
2376 iov[0].iov_len = sizeof cmd;
2377 if (arg) {
2378 ++n;
2379 iov[1].iov_base = arg;
2380 iov[1].iov_len = size;
2381 }
Roland McGrath553a6092002-12-16 20:40:39 +00002382
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002383 return writev (fd, iov, n);
2384}
2385
2386#endif