blob: 5fc640d33f48e4291a0cd6de84235939aaec0ba7 [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;
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000406 if (followfork) {
Roland McGrath70b08532004-04-09 00:25:21 +0000407 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) {
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000427 if (nprocs == tcbtabsize &&
428 expand_tcbtab())
429 tcp = NULL;
430 else
431 tcp = alloctcb(tid);
Roland McGrath70b08532004-04-09 00:25:21 +0000432 if (tcp == NULL) {
433 fprintf(stderr, "%s: out of memory\n",
434 progname);
435 exit(1);
436 }
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000437 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK;
Roland McGrath70b08532004-04-09 00:25:21 +0000438 tcbtab[c]->nchildren++;
439 tcbtab[c]->nclone_threads++;
440 tcbtab[c]->nclone_detached++;
441 tcp->parent = tcbtab[c];
442 }
443 }
444 closedir(dir);
445 if (nerr == ntid) {
446 perror("attach: ptrace(PTRACE_ATTACH, ...)");
447 droptcb(tcp);
448 continue;
449 }
450 if (!qflag) {
451 ntid -= nerr;
452 if (ntid > 1)
453 fprintf(stderr, "\
454Process %u attached with %u threads - interrupt to quit\n",
455 tcp->pid, ntid);
456 else
457 fprintf(stderr, "\
458Process %u attached - interrupt to quit\n",
459 tcp->pid);
460 }
461 continue;
462 }
463 }
464# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000465 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
466 perror("attach: ptrace(PTRACE_ATTACH, ...)");
467 droptcb(tcp);
468 continue;
469 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000470#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000471 if (!qflag)
472 fprintf(stderr,
473 "Process %u attached - interrupt to quit\n",
Roland McGrathc3266d52004-02-20 02:23:52 +0000474 tcp->pid);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000475 }
476
Roland McGrathce0d1542003-11-11 21:24:23 +0000477 if (!pflag_seen) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000478 struct stat statbuf;
479 char *filename;
480 char pathname[MAXPATHLEN];
481
482 filename = argv[optind];
Roland McGrathbdb09df2004-03-02 06:50:04 +0000483 if (strchr(filename, '/')) {
484 if (strlen(filename) > sizeof pathname - 1) {
485 errno = ENAMETOOLONG;
486 perror("strace: exec");
487 exit(1);
488 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000489 strcpy(pathname, filename);
Roland McGrathbdb09df2004-03-02 06:50:04 +0000490 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000491#ifdef USE_DEBUGGING_EXEC
492 /*
493 * Debuggers customarily check the current directory
494 * first regardless of the path but doing that gives
495 * security geeks a panic attack.
496 */
497 else if (stat(filename, &statbuf) == 0)
498 strcpy(pathname, filename);
499#endif /* USE_DEBUGGING_EXEC */
500 else {
501 char *path;
502 int m, n, len;
503
504 for (path = getenv("PATH"); path && *path; path += m) {
505 if (strchr(path, ':')) {
506 n = strchr(path, ':') - path;
507 m = n + 1;
508 }
509 else
510 m = n = strlen(path);
511 if (n == 0) {
512 getcwd(pathname, MAXPATHLEN);
513 len = strlen(pathname);
514 }
Roland McGrathbdb09df2004-03-02 06:50:04 +0000515 else if (n > sizeof pathname - 1)
516 continue;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000517 else {
518 strncpy(pathname, path, n);
519 len = n;
520 }
521 if (len && pathname[len - 1] != '/')
522 pathname[len++] = '/';
523 strcpy(pathname + len, filename);
Roland McGrathed645162003-06-03 07:18:19 +0000524 if (stat(pathname, &statbuf) == 0 &&
525 /* Accept only regular files
526 with some execute bits set.
527 XXX not perfect, might still fail */
528 S_ISREG(statbuf.st_mode) &&
529 (statbuf.st_mode & 0111))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000530 break;
531 }
532 }
533 if (stat(pathname, &statbuf) < 0) {
534 fprintf(stderr, "%s: %s: command not found\n",
535 progname, filename);
536 exit(1);
537 }
538 switch (pid = fork()) {
539 case -1:
540 perror("strace: fork");
541 cleanup();
542 exit(1);
543 break;
544 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000545#ifdef USE_PROCFS
546 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000547#ifdef MIPS
548 /* Kludge for SGI, see proc_open for details. */
549 sa.sa_handler = foobar;
550 sa.sa_flags = 0;
551 sigemptyset(&sa.sa_mask);
552 sigaction(SIGINT, &sa, NULL);
553#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000554#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000555 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000556#else /* FREEBSD */
557 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000558#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000559#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000560 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000561 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000562
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000563 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
564 perror("strace: ptrace(PTRACE_TRACEME, ...)");
565 return -1;
566 }
567 if (debug)
568 kill(getpid(), SIGSTOP);
569
570 if (username != NULL || geteuid() == 0) {
571 uid_t run_euid = run_uid;
572 gid_t run_egid = run_gid;
573
574 if (statbuf.st_mode & S_ISUID)
575 run_euid = statbuf.st_uid;
576 if (statbuf.st_mode & S_ISGID)
577 run_egid = statbuf.st_gid;
578
579 /*
580 * It is important to set groups before we
581 * lose privileges on setuid.
582 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000583 if (username != NULL) {
584 if (initgroups(username, run_gid) < 0) {
585 perror("initgroups");
586 exit(1);
587 }
588 if (setregid(run_gid, run_egid) < 0) {
589 perror("setregid");
590 exit(1);
591 }
592 if (setreuid(run_uid, run_euid) < 0) {
593 perror("setreuid");
594 exit(1);
595 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000596 }
597 }
598 else
599 setreuid(run_uid, run_uid);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000600#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000601
602 execv(pathname, &argv[optind]);
603 perror("strace: exec");
604 _exit(1);
605 break;
606 }
607 default:
608 if ((tcp = alloctcb(pid)) == NULL) {
609 fprintf(stderr, "tcb table full\n");
610 cleanup();
611 exit(1);
612 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000613#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000614 if (proc_open(tcp, 0) < 0) {
615 fprintf(stderr, "trouble opening proc file\n");
616 cleanup();
617 exit(1);
618 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000619#endif /* USE_PROCFS */
620#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621 fake_execve(tcp, pathname, &argv[optind], environ);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000622#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000623 break;
624 }
625 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000626
627 sigemptyset(&empty_set);
628 sigemptyset(&blocked_set);
629 sa.sa_handler = SIG_IGN;
630 sigemptyset(&sa.sa_mask);
631 sa.sa_flags = 0;
632 sigaction(SIGTTOU, &sa, NULL);
633 sigaction(SIGTTIN, &sa, NULL);
634 if (interactive) {
635 sigaddset(&blocked_set, SIGHUP);
636 sigaddset(&blocked_set, SIGINT);
637 sigaddset(&blocked_set, SIGQUIT);
638 sigaddset(&blocked_set, SIGPIPE);
639 sigaddset(&blocked_set, SIGTERM);
640 sa.sa_handler = interrupt;
641#ifdef SUNOS4
642 /* POSIX signals on sunos4.1 are a little broken. */
643 sa.sa_flags = SA_INTERRUPT;
644#endif /* SUNOS4 */
645 }
646 sigaction(SIGHUP, &sa, NULL);
647 sigaction(SIGINT, &sa, NULL);
648 sigaction(SIGQUIT, &sa, NULL);
649 sigaction(SIGPIPE, &sa, NULL);
650 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000651#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000652 sa.sa_handler = reaper;
653 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000654#else
655 /* Make sure SIGCHLD has the default action so that waitpid
656 definitely works without losing track of children. The user
657 should not have given us a bogus state to inherit, but he might
658 have. Arguably we should detect SIG_IGN here and pass it on
659 to children, but probably noone really needs that. */
660 sa.sa_handler = SIG_DFL;
661 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000662#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000663
664 if (trace() < 0)
665 exit(1);
666 cleanup();
667 exit(0);
668}
669
670void
671newoutf(tcp)
672struct tcb *tcp;
673{
674 char name[MAXPATHLEN];
675 FILE *fp;
676
677 if (outfname && followfork > 1) {
678 sprintf(name, "%s.%u", outfname, tcp->pid);
679#ifndef SVR4
680 setreuid(geteuid(), getuid());
681#endif
682 fp = fopen(name, "w");
683#ifndef SVR4
684 setreuid(geteuid(), getuid());
685#endif
686 if (fp == NULL) {
687 perror("fopen");
688 return;
689 }
690 tcp->outf = fp;
691 }
692 return;
693}
694
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000695int
696expand_tcbtab()
697{
698 /* Allocate some more TCBs and expand the table.
699 We don't want to relocate the TCBs because our
700 callers have pointers and it would be a pain.
701 So tcbtab is a table of pointers. Since we never
702 free the TCBs, we allocate a single chunk of many. */
703 struct tcb **newtab = (struct tcb **)
704 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
705 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
706 sizeof *newtcbs);
707 int i;
708 if (newtab == NULL || newtcbs == NULL) {
709 if (newtab != NULL)
710 free(newtab);
711 return 1;
712 }
713 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
714 newtab[i] = &newtcbs[i - tcbtabsize];
715 tcbtabsize *= 2;
716 tcbtab = newtab;
717
718 return 0;
719}
720
721
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000722struct tcb *
723alloctcb(pid)
724int pid;
725{
726 int i;
727 struct tcb *tcp;
728
Roland McGrathee9d4352002-12-18 04:16:10 +0000729 for (i = 0; i < tcbtabsize; i++) {
730 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000731 if ((tcp->flags & TCB_INUSE) == 0) {
732 tcp->pid = pid;
733 tcp->parent = NULL;
734 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000735 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000736#ifdef TCB_CLONE_THREAD
737 tcp->nclone_threads = tcp->nclone_detached = 0;
738 tcp->nclone_waiting = 0;
739#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000740 tcp->flags = TCB_INUSE | TCB_STARTUP;
741 tcp->outf = outf; /* Initialise to current out file */
742 tcp->stime.tv_sec = 0;
743 tcp->stime.tv_usec = 0;
744 tcp->pfd = -1;
745 nprocs++;
746 return tcp;
747 }
748 }
749 return NULL;
750}
751
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000752#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000753int
754proc_open(tcp, attaching)
755struct tcb *tcp;
756int attaching;
757{
758 char proc[32];
759 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000760#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000761 int i;
762 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763 sigset_t signals;
764 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000765#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000766#ifndef HAVE_POLLABLE_PROCFS
767 static int last_pfd;
768#endif
769
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000770#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000771 /* Open the process pseudo-files in /proc. */
772 sprintf(proc, "/proc/%d/ctl", tcp->pid);
773 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000774 perror("strace: open(\"/proc/...\", ...)");
775 return -1;
776 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000777 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
778 perror("F_GETFD");
779 return -1;
780 }
781 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
782 perror("F_SETFD");
783 return -1;
784 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000785 sprintf(proc, "/proc/%d/status", tcp->pid);
786 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
787 perror("strace: open(\"/proc/...\", ...)");
788 return -1;
789 }
790 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
791 perror("F_GETFD");
792 return -1;
793 }
794 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
795 perror("F_SETFD");
796 return -1;
797 }
798 sprintf(proc, "/proc/%d/as", tcp->pid);
799 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
800 perror("strace: open(\"/proc/...\", ...)");
801 return -1;
802 }
803 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
804 perror("F_GETFD");
805 return -1;
806 }
807 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
808 perror("F_SETFD");
809 return -1;
810 }
811#else
812 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000813#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000814 sprintf(proc, "/proc/%d", tcp->pid);
815 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000816#else /* FREEBSD */
817 sprintf(proc, "/proc/%d/mem", tcp->pid);
818 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
819#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000820 perror("strace: open(\"/proc/...\", ...)");
821 return -1;
822 }
823 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
824 perror("F_GETFD");
825 return -1;
826 }
827 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
828 perror("F_SETFD");
829 return -1;
830 }
831#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000832#ifdef FREEBSD
833 sprintf(proc, "/proc/%d/regs", tcp->pid);
834 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
835 perror("strace: open(\"/proc/.../regs\", ...)");
836 return -1;
837 }
838 if (cflag) {
839 sprintf(proc, "/proc/%d/status", tcp->pid);
840 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
841 perror("strace: open(\"/proc/.../status\", ...)");
842 return -1;
843 }
844 } else
845 tcp->pfd_status = -1;
846#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000847 rebuild_pollv();
848 if (!attaching) {
849 /*
850 * Wait for the child to pause. Because of a race
851 * condition we have to poll for the event.
852 */
853 for (;;) {
854 if (IOCTL_STATUS (tcp) < 0) {
855 perror("strace: PIOCSTATUS");
856 return -1;
857 }
858 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000859 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000860 }
861 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000862#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000863 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000864 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000865 perror("strace: PIOCSTOP");
866 return -1;
867 }
Roland McGrath553a6092002-12-16 20:40:39 +0000868#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000869#ifdef PIOCSET
870 /* Set Run-on-Last-Close. */
871 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000872 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000873 perror("PIOCSET PR_RLC");
874 return -1;
875 }
876 /* Set or Reset Inherit-on-Fork. */
877 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000878 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000879 perror("PIOC{SET,RESET} PR_FORK");
880 return -1;
881 }
882#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000883#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000884 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
885 perror("PIOCSRLC");
886 return -1;
887 }
888 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
889 perror("PIOC{S,R}FORK");
890 return -1;
891 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000892#else /* FREEBSD */
893 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
894 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
895 perror("PIOCGFL");
896 return -1;
897 }
898 arg &= ~PF_LINGER;
899 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
900 perror("PIOCSFL");
901 return -1;
902 }
903#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000904#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000905#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000906 /* Enable all syscall entries we care about. */
907 premptyset(&syscalls);
908 for (i = 1; i < MAX_QUALS; ++i) {
909 if (i > (sizeof syscalls) * CHAR_BIT) break;
910 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
911 }
912 praddset (&syscalls, SYS_execve);
913 if (followfork) {
914 praddset (&syscalls, SYS_fork);
915#ifdef SYS_forkall
916 praddset (&syscalls, SYS_forkall);
917#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000918#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000919 praddset (&syscalls, SYS_fork1);
920#endif
921#ifdef SYS_rfork1
922 praddset (&syscalls, SYS_rfork1);
923#endif
924#ifdef SYS_rforkall
925 praddset (&syscalls, SYS_rforkall);
926#endif
927 }
928 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000929 perror("PIOCSENTRY");
930 return -1;
931 }
John Hughes19e49982001-10-19 08:59:12 +0000932 /* Enable the syscall exits. */
933 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000934 perror("PIOSEXIT");
935 return -1;
936 }
John Hughes19e49982001-10-19 08:59:12 +0000937 /* Enable signals we care about. */
938 premptyset(&signals);
939 for (i = 1; i < MAX_QUALS; ++i) {
940 if (i > (sizeof signals) * CHAR_BIT) break;
941 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
942 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000943 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000944 perror("PIOCSTRACE");
945 return -1;
946 }
John Hughes19e49982001-10-19 08:59:12 +0000947 /* Enable faults we care about */
948 premptyset(&faults);
949 for (i = 1; i < MAX_QUALS; ++i) {
950 if (i > (sizeof faults) * CHAR_BIT) break;
951 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
952 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000953 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000954 perror("PIOCSFAULT");
955 return -1;
956 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000957#else /* FREEBSD */
958 /* set events flags. */
959 arg = S_SIG | S_SCE | S_SCX ;
960 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
961 perror("PIOCBIS");
962 return -1;
963 }
964#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000965 if (!attaching) {
966#ifdef MIPS
967 /*
968 * The SGI PRSABORT doesn't work for pause() so
969 * we send it a caught signal to wake it up.
970 */
971 kill(tcp->pid, SIGINT);
972#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000973#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000975 arg = PRSABORT;
976 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977 perror("PIOCRUN");
978 return -1;
979 }
Roland McGrath553a6092002-12-16 20:40:39 +0000980#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000981#endif /* !MIPS*/
982#ifdef FREEBSD
983 /* wake up the child if it received the SIGSTOP */
984 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000985#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 for (;;) {
987 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000988 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000989 perror("PIOCWSTOP");
990 return -1;
991 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000992 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000993 tcp->flags &= ~TCB_INSYSCALL;
994 get_scno(tcp);
995 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000996 break;
997 }
998 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000999#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001000 arg = 0;
1001 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001002#else /* FREEBSD */
1003 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001004#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001005 perror("PIOCRUN");
1006 return -1;
1007 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001008#ifdef FREEBSD
1009 /* handle the case where we "opened" the child before
1010 it did the kill -STOP */
1011 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1012 tcp->status.PR_WHAT == SIGSTOP)
1013 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001014#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001015 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001016#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001017 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001018#else /* FREEBSD */
1019 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001020 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001021 /* We are attaching to an already running process.
1022 * Try to figure out the state of the process in syscalls,
1023 * to handle the first event well.
1024 * This is done by having a look at the "wchan" property of the
1025 * process, which tells where it is stopped (if it is). */
1026 FILE * status;
1027 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001028
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001029 sprintf(proc, "/proc/%d/status", tcp->pid);
1030 status = fopen(proc, "r");
1031 if (status &&
1032 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1033 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1034 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1035 strcmp(wchan, "stopevent")) {
1036 /* The process is asleep in the middle of a syscall.
1037 Fake the syscall entry event */
1038 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1039 tcp->status.PR_WHY = PR_SYSENTRY;
1040 trace_syscall(tcp);
1041 }
1042 if (status)
1043 fclose(status);
1044 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001045 }
1046#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001047#ifndef HAVE_POLLABLE_PROCFS
1048 if (proc_poll_pipe[0] != -1)
1049 proc_poller(tcp->pfd);
1050 else if (nprocs > 1) {
1051 proc_poll_open();
1052 proc_poller(last_pfd);
1053 proc_poller(tcp->pfd);
1054 }
1055 last_pfd = tcp->pfd;
1056#endif /* !HAVE_POLLABLE_PROCFS */
1057 return 0;
1058}
1059
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001060#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001062struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063pid2tcb(pid)
1064int pid;
1065{
1066 int i;
1067 struct tcb *tcp;
1068
Roland McGrathee9d4352002-12-18 04:16:10 +00001069 for (i = 0; i < tcbtabsize; i++) {
1070 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071 if (pid && tcp->pid != pid)
1072 continue;
1073 if (tcp->flags & TCB_INUSE)
1074 return tcp;
1075 }
1076 return NULL;
1077}
1078
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001079#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001080
1081static struct tcb *
1082pfd2tcb(pfd)
1083int pfd;
1084{
1085 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086
Roland McGrathca16be82003-01-10 19:55:28 +00001087 for (i = 0; i < tcbtabsize; i++) {
1088 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089 if (tcp->pfd != pfd)
1090 continue;
1091 if (tcp->flags & TCB_INUSE)
1092 return tcp;
1093 }
1094 return NULL;
1095}
1096
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001097#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098
1099void
1100droptcb(tcp)
1101struct tcb *tcp;
1102{
1103 if (tcp->pid == 0)
1104 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001105#ifdef TCB_CLONE_THREAD
1106 if (tcp->nclone_threads > 0) {
1107 /* There are other threads left in this process, but this
1108 is the one whose PID represents the whole process.
1109 We need to keep this record around as a zombie until
1110 all the threads die. */
1111 tcp->flags |= TCB_EXITING;
1112 return;
1113 }
1114#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001115 nprocs--;
1116 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001117
Roland McGrathe29341c2003-01-10 20:14:20 +00001118 if (tcp->parent != NULL) {
1119 tcp->parent->nchildren--;
1120#ifdef TCB_CLONE_THREAD
1121 if (tcp->flags & TCB_CLONE_DETACHED)
1122 tcp->parent->nclone_detached--;
1123 if (tcp->flags & TCB_CLONE_THREAD)
1124 tcp->parent->nclone_threads--;
1125#endif
Roland McGrath09623452003-05-23 02:27:13 +00001126#ifdef TCB_CLONE_DETACHED
1127 if (!(tcp->flags & TCB_CLONE_DETACHED))
1128#endif
1129 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001130 tcp->parent = NULL;
1131 }
1132
1133 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001134 if (tcp->pfd != -1) {
1135 close(tcp->pfd);
1136 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001137#ifdef FREEBSD
1138 if (tcp->pfd_reg != -1) {
1139 close(tcp->pfd_reg);
1140 tcp->pfd_reg = -1;
1141 }
1142 if (tcp->pfd_status != -1) {
1143 close(tcp->pfd_status);
1144 tcp->pfd_status = -1;
1145 }
Roland McGrath553a6092002-12-16 20:40:39 +00001146#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001147#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001148 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001149#endif
1150 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001151
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001152 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001154
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001155 tcp->outf = 0;
1156}
1157
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001158#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159
1160static int
1161resume(tcp)
1162struct tcb *tcp;
1163{
1164 if (tcp == NULL)
1165 return -1;
1166
1167 if (!(tcp->flags & TCB_SUSPENDED)) {
1168 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1169 return -1;
1170 }
1171 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001172#ifdef TCB_CLONE_THREAD
1173 if (tcp->flags & TCB_CLONE_THREAD)
1174 tcp->parent->nclone_waiting--;
1175#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176
1177 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1178 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1179 return -1;
1180 }
1181
1182 if (!qflag)
1183 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1184 return 0;
1185}
1186
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001187#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001188
1189/* detach traced process; continue with sig */
1190
1191static int
1192detach(tcp, sig)
1193struct tcb *tcp;
1194int sig;
1195{
1196 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001197#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001198 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001199#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001200
1201 if (tcp->flags & TCB_BPTSET)
1202 sig = SIGKILL;
1203
1204#ifdef LINUX
1205 /*
1206 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001207 * before detaching. Arghh. We go through hoops
1208 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001209 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001210#if defined(SPARC)
1211#undef PTRACE_DETACH
1212#define PTRACE_DETACH PTRACE_SUNDETACH
1213#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001214 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1215 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001216 }
1217 else if (errno != ESRCH) {
1218 /* Shouldn't happen. */
1219 perror("detach: ptrace(PTRACE_DETACH, ...)");
1220 }
1221 else if (kill(tcp->pid, 0) < 0) {
1222 if (errno != ESRCH)
1223 perror("detach: checking sanity");
1224 }
1225 else if (kill(tcp->pid, SIGSTOP) < 0) {
1226 if (errno != ESRCH)
1227 perror("detach: stopping child");
1228 }
1229 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001230 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001231#ifdef __WALL
1232 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1233 if (errno == ECHILD) /* Already gone. */
1234 break;
1235 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001236 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001237 break;
1238 }
1239#endif /* __WALL */
1240 /* No __WALL here. */
1241 if (waitpid(tcp->pid, &status, 0) < 0) {
1242 if (errno != ECHILD) {
1243 perror("detach: waiting");
1244 break;
1245 }
1246#ifdef __WCLONE
1247 /* If no processes, try clones. */
1248 if (wait4(tcp->pid, &status, __WCLONE,
1249 NULL) < 0) {
1250 if (errno != ECHILD)
1251 perror("detach: waiting");
1252 break;
1253 }
1254#endif /* __WCLONE */
1255 }
1256#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001257 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001258#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001259 if (!WIFSTOPPED(status)) {
1260 /* Au revoir, mon ami. */
1261 break;
1262 }
1263 if (WSTOPSIG(status) == SIGSTOP) {
1264 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001265 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001266 if (errno != ESRCH)
1267 perror("detach: ptrace(PTRACE_DETACH, ...)");
1268 /* I died trying. */
1269 }
1270 break;
1271 }
1272 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001273 WSTOPSIG(status) == SIGTRAP ?
1274 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001275 if (errno != ESRCH)
1276 perror("detach: ptrace(PTRACE_CONT, ...)");
1277 break;
1278 }
1279 }
1280 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001281#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001282
1283#if defined(SUNOS4)
1284 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1285 if (sig && kill(tcp->pid, sig) < 0)
1286 perror("detach: kill");
1287 sig = 0;
1288 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1289 perror("detach: ptrace(PTRACE_DETACH, ...)");
1290#endif /* SUNOS4 */
1291
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001292#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001293 resumed = 0;
1294
1295 /* XXX This won't always be quite right (but it never was).
1296 A waiter with argument 0 or < -1 is waiting for any pid in
1297 a particular pgrp, which this child might or might not be
1298 in. The waiter will only wake up if it's argument is -1
1299 or if it's waiting for tcp->pid's pgrp. It makes a
1300 difference to wake up a waiter when there might be more
1301 traced children, because it could get a false ECHILD
1302 error. OTOH, if this was the last child in the pgrp, then
1303 it ought to wake up and get ECHILD. We would have to
1304 search the system for all pid's in the pgrp to be sure.
1305
1306 && (t->waitpid == -1 ||
1307 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1308 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1309 */
1310
1311 if (tcp->parent &&
1312 (tcp->parent->flags & TCB_SUSPENDED) &&
1313 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1314 error = resume(tcp->parent);
1315 ++resumed;
1316 }
1317#ifdef TCB_CLONE_THREAD
1318 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1319 /* Some other threads of our parent are waiting too. */
1320 unsigned int i;
1321
1322 /* Resume all the threads that were waiting for this PID. */
1323 for (i = 0; i < tcbtabsize; i++) {
1324 struct tcb *t = tcbtab[i];
1325 if (t->parent == tcp->parent && t != tcp
1326 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1327 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1328 && t->waitpid == tcp->pid) {
1329 error |= resume (t);
1330 ++resumed;
1331 }
1332 }
1333 if (resumed == 0)
1334 /* Noone was waiting for this PID in particular,
1335 so now we might need to resume some wildcarders. */
1336 for (i = 0; i < tcbtabsize; i++) {
1337 struct tcb *t = tcbtab[i];
1338 if (t->parent == tcp->parent && t != tcp
1339 && ((t->flags
1340 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1341 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1342 && t->waitpid <= 0
1343 ) {
1344 error |= resume (t);
1345 break;
1346 }
1347 }
1348 }
1349#endif
1350
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001351#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001352
1353 if (!qflag)
1354 fprintf(stderr, "Process %u detached\n", tcp->pid);
1355
1356 droptcb(tcp);
1357 return error;
1358}
1359
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001360#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001361
1362static void
1363reaper(sig)
1364int sig;
1365{
1366 int pid;
1367 int status;
1368
1369 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1370#if 0
1371 struct tcb *tcp;
1372
1373 tcp = pid2tcb(pid);
1374 if (tcp)
1375 droptcb(tcp);
1376#endif
1377 }
1378}
1379
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001380#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001381
1382static void
1383cleanup()
1384{
1385 int i;
1386 struct tcb *tcp;
1387
Roland McGrathee9d4352002-12-18 04:16:10 +00001388 for (i = 0; i < tcbtabsize; i++) {
1389 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001390 if (!(tcp->flags & TCB_INUSE))
1391 continue;
1392 if (debug)
1393 fprintf(stderr,
1394 "cleanup: looking at pid %u\n", tcp->pid);
1395 if (tcp_last &&
1396 (!outfname || followfork < 2 || tcp_last == tcp)) {
1397 tprintf(" <unfinished ...>\n");
1398 tcp_last = NULL;
1399 }
1400 if (tcp->flags & TCB_ATTACHED)
1401 detach(tcp, 0);
1402 else {
1403 kill(tcp->pid, SIGCONT);
1404 kill(tcp->pid, SIGTERM);
1405 }
1406 }
1407 if (cflag)
1408 call_summary(outf);
1409}
1410
1411static void
1412interrupt(sig)
1413int sig;
1414{
1415 interrupted = 1;
1416}
1417
1418#ifndef HAVE_STRERROR
1419
Roland McGrath6d2b3492002-12-30 00:51:30 +00001420#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001421extern int sys_nerr;
1422extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001423#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001424
1425const char *
1426strerror(errno)
1427int errno;
1428{
1429 static char buf[64];
1430
1431 if (errno < 1 || errno >= sys_nerr) {
1432 sprintf(buf, "Unknown error %d", errno);
1433 return buf;
1434 }
1435 return sys_errlist[errno];
1436}
1437
1438#endif /* HAVE_STERRROR */
1439
1440#ifndef HAVE_STRSIGNAL
1441
Roland McGrath8f474e02003-01-14 07:53:33 +00001442#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001443extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001444#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001445#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1446extern char *_sys_siglist[];
1447#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001448
1449const char *
1450strsignal(sig)
1451int sig;
1452{
1453 static char buf[64];
1454
1455 if (sig < 1 || sig >= NSIG) {
1456 sprintf(buf, "Unknown signal %d", sig);
1457 return buf;
1458 }
1459#ifdef HAVE__SYS_SIGLIST
1460 return _sys_siglist[sig];
1461#else
1462 return sys_siglist[sig];
1463#endif
1464}
1465
1466#endif /* HAVE_STRSIGNAL */
1467
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001468#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001469
1470static void
1471rebuild_pollv()
1472{
1473 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001474
Roland McGrathee9d4352002-12-18 04:16:10 +00001475 if (pollv != NULL)
1476 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001477 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001478 if (pollv == NULL) {
1479 fprintf(stderr, "strace: out of memory for poll vector\n");
1480 exit(1);
1481 }
1482
Roland McGrathca16be82003-01-10 19:55:28 +00001483 for (i = j = 0; i < tcbtabsize; i++) {
1484 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001485 if (!(tcp->flags & TCB_INUSE))
1486 continue;
1487 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001488 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001489 j++;
1490 }
1491 if (j != nprocs) {
1492 fprintf(stderr, "strace: proc miscount\n");
1493 exit(1);
1494 }
1495}
1496
1497#ifndef HAVE_POLLABLE_PROCFS
1498
1499static void
1500proc_poll_open()
1501{
1502 int arg;
1503 int i;
1504
1505 if (pipe(proc_poll_pipe) < 0) {
1506 perror("pipe");
1507 exit(1);
1508 }
1509 for (i = 0; i < 2; i++) {
1510 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1511 perror("F_GETFD");
1512 exit(1);
1513 }
1514 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1515 perror("F_SETFD");
1516 exit(1);
1517 }
1518 }
1519}
1520
1521static int
1522proc_poll(pollv, nfds, timeout)
1523struct pollfd *pollv;
1524int nfds;
1525int timeout;
1526{
1527 int i;
1528 int n;
1529 struct proc_pollfd pollinfo;
1530
1531 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1532 return n;
1533 if (n != sizeof(struct proc_pollfd)) {
1534 fprintf(stderr, "panic: short read: %d\n", n);
1535 exit(1);
1536 }
1537 for (i = 0; i < nprocs; i++) {
1538 if (pollv[i].fd == pollinfo.fd)
1539 pollv[i].revents = pollinfo.revents;
1540 else
1541 pollv[i].revents = 0;
1542 }
1543 poller_pid = pollinfo.pid;
1544 return 1;
1545}
1546
1547static void
1548wakeup_handler(sig)
1549int sig;
1550{
1551}
1552
1553static void
1554proc_poller(pfd)
1555int pfd;
1556{
1557 struct proc_pollfd pollinfo;
1558 struct sigaction sa;
1559 sigset_t blocked_set, empty_set;
1560 int i;
1561 int n;
1562 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001563#ifdef FREEBSD
1564 struct procfs_status pfs;
1565#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001566
1567 switch (fork()) {
1568 case -1:
1569 perror("fork");
1570 _exit(0);
1571 case 0:
1572 break;
1573 default:
1574 return;
1575 }
1576
1577 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1578 sa.sa_flags = 0;
1579 sigemptyset(&sa.sa_mask);
1580 sigaction(SIGHUP, &sa, NULL);
1581 sigaction(SIGINT, &sa, NULL);
1582 sigaction(SIGQUIT, &sa, NULL);
1583 sigaction(SIGPIPE, &sa, NULL);
1584 sigaction(SIGTERM, &sa, NULL);
1585 sa.sa_handler = wakeup_handler;
1586 sigaction(SIGUSR1, &sa, NULL);
1587 sigemptyset(&blocked_set);
1588 sigaddset(&blocked_set, SIGUSR1);
1589 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1590 sigemptyset(&empty_set);
1591
1592 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1593 perror("getrlimit(RLIMIT_NOFILE, ...)");
1594 _exit(0);
1595 }
1596 n = rl.rlim_cur;
1597 for (i = 0; i < n; i++) {
1598 if (i != pfd && i != proc_poll_pipe[1])
1599 close(i);
1600 }
1601
1602 pollinfo.fd = pfd;
1603 pollinfo.pid = getpid();
1604 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001605#ifndef FREEBSD
1606 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1607#else /* FREEBSD */
1608 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1609#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001610 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001611 switch (errno) {
1612 case EINTR:
1613 continue;
1614 case EBADF:
1615 pollinfo.revents = POLLERR;
1616 break;
1617 case ENOENT:
1618 pollinfo.revents = POLLHUP;
1619 break;
1620 default:
1621 perror("proc_poller: PIOCWSTOP");
1622 }
1623 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1624 _exit(0);
1625 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001626 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001627 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1628 sigsuspend(&empty_set);
1629 }
1630}
1631
1632#endif /* !HAVE_POLLABLE_PROCFS */
1633
1634static int
1635choose_pfd()
1636{
1637 int i, j;
1638 struct tcb *tcp;
1639
1640 static int last;
1641
1642 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001643 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001644 /*
1645 * The previous process is ready to run again. We'll
1646 * let it do so if it is currently in a syscall. This
1647 * heuristic improves the readability of the trace.
1648 */
1649 tcp = pfd2tcb(pollv[last].fd);
1650 if (tcp && (tcp->flags & TCB_INSYSCALL))
1651 return pollv[last].fd;
1652 }
1653
1654 for (i = 0; i < nprocs; i++) {
1655 /* Let competing children run round robin. */
1656 j = (i + last + 1) % nprocs;
1657 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1658 tcp = pfd2tcb(pollv[j].fd);
1659 if (!tcp) {
1660 fprintf(stderr, "strace: lost proc\n");
1661 exit(1);
1662 }
1663 droptcb(tcp);
1664 return -1;
1665 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001666 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001667 last = j;
1668 return pollv[j].fd;
1669 }
1670 }
1671 fprintf(stderr, "strace: nothing ready\n");
1672 exit(1);
1673}
1674
1675static int
1676trace()
1677{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001678#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001679 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001680#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001681 struct tcb *tcp;
1682 int pfd;
1683 int what;
1684 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001685 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001686
1687 for (;;) {
1688 if (interactive)
1689 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1690
1691 if (nprocs == 0)
1692 break;
1693
1694 switch (nprocs) {
1695 case 1:
1696#ifndef HAVE_POLLABLE_PROCFS
1697 if (proc_poll_pipe[0] == -1) {
1698#endif
1699 tcp = pid2tcb(0);
1700 if (!tcp)
1701 continue;
1702 pfd = tcp->pfd;
1703 if (pfd == -1)
1704 continue;
1705 break;
1706#ifndef HAVE_POLLABLE_PROCFS
1707 }
1708 /* fall through ... */
1709#endif /* !HAVE_POLLABLE_PROCFS */
1710 default:
1711#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001712#ifdef POLL_HACK
1713 /* On some systems (e.g. UnixWare) we get too much ugly
1714 "unfinished..." stuff when multiple proceses are in
1715 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001716
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001717 if (in_syscall) {
1718 struct pollfd pv;
1719 tcp = in_syscall;
1720 in_syscall = NULL;
1721 pv.fd = tcp->pfd;
1722 pv.events = POLLWANT;
1723 if ((what = poll (&pv, 1, 1)) < 0) {
1724 if (interrupted)
1725 return 0;
1726 continue;
1727 }
1728 else if (what == 1 && pv.revents & POLLWANT) {
1729 goto FOUND;
1730 }
1731 }
1732#endif
1733
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001734 if (poll(pollv, nprocs, INFTIM) < 0) {
1735 if (interrupted)
1736 return 0;
1737 continue;
1738 }
1739#else /* !HAVE_POLLABLE_PROCFS */
1740 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1741 if (interrupted)
1742 return 0;
1743 continue;
1744 }
1745#endif /* !HAVE_POLLABLE_PROCFS */
1746 pfd = choose_pfd();
1747 if (pfd == -1)
1748 continue;
1749 break;
1750 }
1751
1752 /* Look up `pfd' in our table. */
1753 if ((tcp = pfd2tcb(pfd)) == NULL) {
1754 fprintf(stderr, "unknown pfd: %u\n", pfd);
1755 exit(1);
1756 }
John Hughesb6643082002-05-23 11:02:22 +00001757#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001758 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001759#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001760 /* Get the status of the process. */
1761 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001762#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001763 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001764#else /* FREEBSD */
1765 /* Thanks to some scheduling mystery, the first poller
1766 sometimes waits for the already processed end of fork
1767 event. Doing a non blocking poll here solves the problem. */
1768 if (proc_poll_pipe[0] != -1)
1769 ioctl_result = IOCTL_STATUS (tcp);
1770 else
1771 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001772#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001773 ioctl_errno = errno;
1774#ifndef HAVE_POLLABLE_PROCFS
1775 if (proc_poll_pipe[0] != -1) {
1776 if (ioctl_result < 0)
1777 kill(poller_pid, SIGKILL);
1778 else
1779 kill(poller_pid, SIGUSR1);
1780 }
1781#endif /* !HAVE_POLLABLE_PROCFS */
1782 }
1783 if (interrupted)
1784 return 0;
1785
1786 if (interactive)
1787 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1788
1789 if (ioctl_result < 0) {
1790 /* Find out what happened if it failed. */
1791 switch (ioctl_errno) {
1792 case EINTR:
1793 case EBADF:
1794 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001795#ifdef FREEBSD
1796 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001797#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001798 case ENOENT:
1799 droptcb(tcp);
1800 continue;
1801 default:
1802 perror("PIOCWSTOP");
1803 exit(1);
1804 }
1805 }
1806
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001807#ifdef FREEBSD
1808 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1809 /* discard first event for a syscall we never entered */
1810 IOCTL (tcp->pfd, PIOCRUN, 0);
1811 continue;
1812 }
Roland McGrath553a6092002-12-16 20:40:39 +00001813#endif
1814
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001815 /* clear the just started flag */
1816 tcp->flags &= ~TCB_STARTUP;
1817
1818 /* set current output file */
1819 outf = tcp->outf;
1820
1821 if (cflag) {
1822 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001823#ifdef FREEBSD
1824 char buf[1024];
1825 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001826
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001827 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1828 buf[len] = '\0';
1829 sscanf(buf,
1830 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1831 &stime.tv_sec, &stime.tv_usec);
1832 } else
1833 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001834#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001835 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1836 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001837#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001838 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1839 tcp->stime = stime;
1840 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001841 what = tcp->status.PR_WHAT;
1842 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001843#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001844 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001845 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1846 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001847 if (trace_syscall(tcp) < 0) {
1848 fprintf(stderr, "syscall trouble\n");
1849 exit(1);
1850 }
1851 }
1852 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001853#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001854 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001855#ifdef POLL_HACK
1856 in_syscall = tcp;
1857#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001858 case PR_SYSEXIT:
1859 if (trace_syscall(tcp) < 0) {
1860 fprintf(stderr, "syscall trouble\n");
1861 exit(1);
1862 }
1863 break;
1864 case PR_SIGNALLED:
1865 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1866 printleader(tcp);
1867 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001868 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001869 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001870#ifdef PR_INFO
1871 if (tcp->status.PR_INFO.si_signo == what) {
1872 printleader(tcp);
1873 tprintf(" siginfo=");
1874 printsiginfo(&tcp->status.PR_INFO, 1);
1875 printtrailer(tcp);
1876 }
1877#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001878 }
1879 break;
1880 case PR_FAULTED:
1881 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1882 printleader(tcp);
1883 tprintf("=== FAULT %d ===", what);
1884 printtrailer(tcp);
1885 }
1886 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001887#ifdef FREEBSD
1888 case 0: /* handle case we polled for nothing */
1889 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001890#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001891 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001892 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001893 exit(1);
1894 break;
1895 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001896 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001897#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001898 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001899#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001900 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001901#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001902 perror("PIOCRUN");
1903 exit(1);
1904 }
1905 }
1906 return 0;
1907}
1908
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001909#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001910
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001911#ifdef TCB_GROUP_EXITING
1912/* Handle an exit detach or death signal that is taking all the
1913 related clone threads with it. This is called in three circumstances:
1914 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1915 SIG == 0 Continuing TCP will perform an exit_group syscall.
1916 SIG == other Continuing TCP with SIG will kill the process.
1917*/
1918static int
1919handle_group_exit(struct tcb *tcp, int sig)
1920{
1921 /* We need to locate our records of all the clone threads
1922 related to TCP, either its children or siblings. */
1923 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1924 ? tcp->parent
1925 : tcp->nclone_detached > 0
1926 ? tcp : NULL);
1927
1928 if (sig < 0) {
1929 if (leader != NULL && leader != tcp)
1930 fprintf(stderr,
1931 "PANIC: handle_group_exit: %d leader %d\n",
1932 tcp->pid, leader ? leader->pid : -1);
1933 droptcb(tcp); /* Already died. */
1934 }
1935 else {
1936 if (tcp->flags & TCB_ATTACHED) {
1937 if (leader != NULL && leader != tcp) {
1938 /* We need to detach the leader so that the
1939 process death will be reported to its real
1940 parent. But we kill it first to prevent
1941 it doing anything before we kill the whole
1942 process in a moment. We can use
1943 PTRACE_KILL on a thread that's not already
1944 stopped. Then the value we pass in
1945 PTRACE_DETACH just sets the death
1946 signal reported to the real parent. */
1947 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1948 if (debug)
1949 fprintf(stderr,
1950 " [%d exit %d kills %d]\n",
1951 tcp->pid, sig, leader->pid);
1952 detach(leader, sig);
1953 }
1954 detach(tcp, sig);
1955 }
1956 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1957 perror("strace: ptrace(PTRACE_CONT, ...)");
1958 cleanup();
1959 return -1;
1960 }
1961 else {
1962 if (leader != NULL && leader != tcp)
1963 droptcb(tcp);
1964 /* The leader will report to us as parent now,
1965 and then we'll get to the SIG==-1 case. */
1966 return 0;
1967 }
1968 }
1969
1970 /* Note that TCP and LEADER are no longer valid,
1971 but we can still compare against them. */
1972 if (leader != NULL) {
1973 unsigned int i;
1974 for (i = 0; i < tcbtabsize; i++) {
1975 struct tcb *t = tcbtab[i];
1976 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1977 && t->parent == leader)
1978 droptcb(t);
1979 }
1980 }
1981
1982 return 0;
1983}
1984#endif
1985
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001986static int
1987trace()
1988{
1989 int pid;
1990 int wait_errno;
1991 int status;
1992 struct tcb *tcp;
1993#ifdef LINUX
1994 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001995#ifdef __WALL
1996 static int wait4_options = __WALL;
1997#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001998#endif /* LINUX */
1999
2000 while (nprocs != 0) {
2001 if (interactive)
2002 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2003#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002004#ifdef __WALL
2005 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002006 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002007 /* this kernel does not support __WALL */
2008 wait4_options &= ~__WALL;
2009 errno = 0;
2010 pid = wait4(-1, &status, wait4_options,
2011 cflag ? &ru : NULL);
2012 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002013 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002014 /* most likely a "cloned" process */
2015 pid = wait4(-1, &status, __WCLONE,
2016 cflag ? &ru : NULL);
2017 if (pid == -1) {
2018 fprintf(stderr, "strace: clone wait4 "
2019 "failed: %s\n", strerror(errno));
2020 }
2021 }
2022#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002023 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002024#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002025#endif /* LINUX */
2026#ifdef SUNOS4
2027 pid = wait(&status);
2028#endif /* SUNOS4 */
2029 wait_errno = errno;
2030 if (interactive)
2031 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2032
2033 if (interrupted)
2034 return 0;
2035
2036 if (pid == -1) {
2037 switch (wait_errno) {
2038 case EINTR:
2039 continue;
2040 case ECHILD:
2041 /*
2042 * We would like to verify this case
2043 * but sometimes a race in Solbourne's
2044 * version of SunOS sometimes reports
2045 * ECHILD before sending us SIGCHILD.
2046 */
2047#if 0
2048 if (nprocs == 0)
2049 return 0;
2050 fprintf(stderr, "strace: proc miscount\n");
2051 exit(1);
2052#endif
2053 return 0;
2054 default:
2055 errno = wait_errno;
2056 perror("strace: wait");
2057 return -1;
2058 }
2059 }
2060 if (debug)
2061 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2062
2063 /* Look up `pid' in our table. */
2064 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002065#ifdef LINUX
2066 if (followfork || followvfork) {
2067 /* This is needed to go with the CLONE_PTRACE
2068 changes in process.c/util.c: we might see
2069 the child's initial trap before we see the
2070 parent return from the clone syscall.
2071 Leave the child suspended until the parent
2072 returns from its system call. Only then
2073 will we have the association of parent and
2074 child so that we know how to do clearbpt
2075 in the child. */
2076 if ((tcp = alloctcb(pid)) == NULL) {
2077 fprintf(stderr, " [tcb table full]\n");
2078 kill(pid, SIGKILL); /* XXX */
2079 return 0;
2080 }
2081 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
2082 newoutf(tcp);
2083 if (!qflag)
2084 fprintf(stderr, "\
2085Process %d attached (waiting for parent)\n",
2086 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002087 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002088 else
2089 /* This can happen if a clone call used
2090 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002091#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002092 {
2093 fprintf(stderr, "unknown pid: %u\n", pid);
2094 if (WIFSTOPPED(status))
2095 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2096 exit(1);
2097 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002098 }
2099 /* set current output file */
2100 outf = tcp->outf;
2101 if (cflag) {
2102#ifdef LINUX
2103 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2104 tcp->stime = ru.ru_stime;
2105#endif /* !LINUX */
2106 }
2107
2108 if (tcp->flags & TCB_SUSPENDED) {
2109 /*
2110 * Apparently, doing any ptrace() call on a stopped
2111 * process, provokes the kernel to report the process
2112 * status again on a subsequent wait(), even if the
2113 * process has not been actually restarted.
2114 * Since we have inspected the arguments of suspended
2115 * processes we end up here testing for this case.
2116 */
2117 continue;
2118 }
2119 if (WIFSIGNALED(status)) {
2120 if (!cflag
2121 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2122 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002123 tprintf("+++ killed by %s %s+++",
2124 signame(WTERMSIG(status)),
2125#ifdef WCOREDUMP
2126 WCOREDUMP(status) ? "(core dumped) " :
2127#endif
2128 "");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002129 printtrailer(tcp);
2130 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002131#ifdef TCB_GROUP_EXITING
2132 handle_group_exit(tcp, -1);
2133#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002134 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002135#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002136 continue;
2137 }
2138 if (WIFEXITED(status)) {
2139 if (debug)
2140 fprintf(stderr, "pid %u exited\n", pid);
2141 if (tcp->flags & TCB_ATTACHED)
2142 fprintf(stderr,
2143 "PANIC: attached pid %u exited\n",
2144 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002145 if (tcp == tcp_last) {
2146 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2147 == TCB_INSYSCALL)
2148 tprintf(" <unfinished ... exit status %d>\n",
2149 WEXITSTATUS(status));
2150 tcp_last = NULL;
2151 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002152#ifdef TCB_GROUP_EXITING
2153 handle_group_exit(tcp, -1);
2154#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002155 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002156#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002157 continue;
2158 }
2159 if (!WIFSTOPPED(status)) {
2160 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2161 droptcb(tcp);
2162 continue;
2163 }
2164 if (debug)
2165 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002166 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002167
2168 if (tcp->flags & TCB_STARTUP) {
2169 /*
2170 * This flag is there to keep us in sync.
2171 * Next time this process stops it should
2172 * really be entering a system call.
2173 */
2174 tcp->flags &= ~TCB_STARTUP;
2175 if (tcp->flags & TCB_ATTACHED) {
2176 /*
2177 * Interestingly, the process may stop
2178 * with STOPSIG equal to some other signal
2179 * than SIGSTOP if we happend to attach
2180 * just before the process takes a signal.
2181 */
2182 if (!WIFSTOPPED(status)) {
2183 fprintf(stderr,
2184 "pid %u not stopped\n", pid);
2185 detach(tcp, WSTOPSIG(status));
2186 continue;
2187 }
2188 }
2189 else {
2190#ifdef SUNOS4
2191 /* A child of us stopped at exec */
2192 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2193 fixvfork(tcp);
2194#endif /* SUNOS4 */
2195 }
2196 if (tcp->flags & TCB_BPTSET) {
2197 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2198 droptcb(tcp);
2199 cleanup();
2200 return -1;
2201 }
2202 }
2203 goto tracing;
2204 }
2205
2206 if (WSTOPSIG(status) != SIGTRAP) {
2207 if (WSTOPSIG(status) == SIGSTOP &&
2208 (tcp->flags & TCB_SIGTRAPPED)) {
2209 /*
2210 * Trapped attempt to block SIGTRAP
2211 * Hope we are back in control now.
2212 */
2213 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2214 if (ptrace(PTRACE_SYSCALL,
2215 pid, (char *) 1, 0) < 0) {
2216 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2217 cleanup();
2218 return -1;
2219 }
2220 continue;
2221 }
2222 if (!cflag
2223 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002224 unsigned long addr = 0, pc = 0;
2225#ifdef PT_GETSIGINFO
2226# define PSR_RI 41
2227 struct siginfo si;
2228 unsigned long psr;
2229
2230 upeek(pid, PT_CR_IPSR, &psr);
2231 upeek(pid, PT_CR_IIP, &pc);
2232
2233 pc += (psr >> PSR_RI) & 0x3;
2234 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2235 addr = (unsigned long) si.si_addr;
2236#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002237 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002238 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002239 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002240 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002241 printtrailer(tcp);
2242 }
2243 if ((tcp->flags & TCB_ATTACHED) &&
2244 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002245#ifdef TCB_GROUP_EXITING
2246 handle_group_exit(tcp, WSTOPSIG(status));
2247#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002248 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002249#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002250 continue;
2251 }
2252 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2253 WSTOPSIG(status)) < 0) {
2254 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2255 cleanup();
2256 return -1;
2257 }
2258 tcp->flags &= ~TCB_SUSPENDED;
2259 continue;
2260 }
2261 if (trace_syscall(tcp) < 0) {
2262 if (tcp->flags & TCB_ATTACHED)
2263 detach(tcp, 0);
2264 else {
2265 ptrace(PTRACE_KILL,
2266 tcp->pid, (char *) 1, SIGTERM);
2267 droptcb(tcp);
2268 }
2269 continue;
2270 }
2271 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002272#ifdef TCB_GROUP_EXITING
2273 if (tcp->flags & TCB_GROUP_EXITING) {
2274 if (handle_group_exit(tcp, 0) < 0)
2275 return -1;
2276 continue;
2277 }
2278#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002279 if (tcp->flags & TCB_ATTACHED)
2280 detach(tcp, 0);
2281 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2282 perror("strace: ptrace(PTRACE_CONT, ...)");
2283 cleanup();
2284 return -1;
2285 }
2286 continue;
2287 }
2288 if (tcp->flags & TCB_SUSPENDED) {
2289 if (!qflag)
2290 fprintf(stderr, "Process %u suspended\n", pid);
2291 continue;
2292 }
2293 tracing:
2294 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2295 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2296 cleanup();
2297 return -1;
2298 }
2299 }
2300 return 0;
2301}
2302
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002303#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002304
2305static int curcol;
2306
2307#ifdef __STDC__
2308#include <stdarg.h>
2309#define VA_START(a, b) va_start(a, b)
2310#else
2311#include <varargs.h>
2312#define VA_START(a, b) va_start(a)
2313#endif
2314
2315void
2316#ifdef __STDC__
2317tprintf(const char *fmt, ...)
2318#else
2319tprintf(fmt, va_alist)
2320char *fmt;
2321va_dcl
2322#endif
2323{
2324 va_list args;
2325
2326 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002327 if (outf) {
2328 int n = vfprintf(outf, fmt, args);
2329 if (n < 0 && outf != stderr)
2330 perror(outfname == NULL
2331 ? "<writing to pipe>" : outfname);
2332 else
2333 curcol += n;
2334 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002335 va_end(args);
2336 return;
2337}
2338
2339void
2340printleader(tcp)
2341struct tcb *tcp;
2342{
2343 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2344 tcp_last->flags |= TCB_REPRINT;
2345 tprintf(" <unfinished ...>\n");
2346 }
2347 curcol = 0;
2348 if ((followfork == 1 || pflag_seen > 1) && outfname)
2349 tprintf("%-5d ", tcp->pid);
2350 else if (nprocs > 1 && !outfname)
2351 tprintf("[pid %5u] ", tcp->pid);
2352 if (tflag) {
2353 char str[sizeof("HH:MM:SS")];
2354 struct timeval tv, dtv;
2355 static struct timeval otv;
2356
2357 gettimeofday(&tv, NULL);
2358 if (rflag) {
2359 if (otv.tv_sec == 0)
2360 otv = tv;
2361 tv_sub(&dtv, &tv, &otv);
2362 tprintf("%6ld.%06ld ",
2363 (long) dtv.tv_sec, (long) dtv.tv_usec);
2364 otv = tv;
2365 }
2366 else if (tflag > 2) {
2367 tprintf("%ld.%06ld ",
2368 (long) tv.tv_sec, (long) tv.tv_usec);
2369 }
2370 else {
2371 time_t local = tv.tv_sec;
2372 strftime(str, sizeof(str), "%T", localtime(&local));
2373 if (tflag > 1)
2374 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2375 else
2376 tprintf("%s ", str);
2377 }
2378 }
2379 if (iflag)
2380 printcall(tcp);
2381}
2382
2383void
2384tabto(col)
2385int col;
2386{
2387 if (curcol < col)
2388 tprintf("%*s", col - curcol, "");
2389}
2390
2391void
2392printtrailer(tcp)
2393struct tcb *tcp;
2394{
2395 tprintf("\n");
2396 tcp_last = NULL;
2397}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002398
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002399#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002400
2401int mp_ioctl (int fd, int cmd, void *arg, int size) {
2402
2403 struct iovec iov[2];
2404 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002405
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002406 iov[0].iov_base = &cmd;
2407 iov[0].iov_len = sizeof cmd;
2408 if (arg) {
2409 ++n;
2410 iov[1].iov_base = arg;
2411 iov[1].iov_len = size;
2412 }
Roland McGrath553a6092002-12-16 20:40:39 +00002413
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002414 return writev (fd, iov, n);
2415}
2416
2417#endif