blob: 25f45c823187516cdab566ad0de504b1c9dbb031 [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
33#include "defs.h"
34
Roland McGrath795edb12005-02-02 04:44:57 +000035#include <sys/types.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000036#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);
Roland McGrath15dca8e2005-02-06 01:16:32 +0000600
601 /*
602 * Induce an immediate stop so that the parent
603 * will resume us with PTRACE_SYSCALL and display
604 * this execve call normally.
605 */
606 kill(getpid(), SIGSTOP);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000607#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000608
609 execv(pathname, &argv[optind]);
610 perror("strace: exec");
611 _exit(1);
612 break;
613 }
614 default:
615 if ((tcp = alloctcb(pid)) == NULL) {
616 fprintf(stderr, "tcb table full\n");
617 cleanup();
618 exit(1);
619 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000620#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621 if (proc_open(tcp, 0) < 0) {
622 fprintf(stderr, "trouble opening proc file\n");
623 cleanup();
624 exit(1);
625 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000626#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000627 break;
628 }
629 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630
631 sigemptyset(&empty_set);
632 sigemptyset(&blocked_set);
633 sa.sa_handler = SIG_IGN;
634 sigemptyset(&sa.sa_mask);
635 sa.sa_flags = 0;
636 sigaction(SIGTTOU, &sa, NULL);
637 sigaction(SIGTTIN, &sa, NULL);
638 if (interactive) {
639 sigaddset(&blocked_set, SIGHUP);
640 sigaddset(&blocked_set, SIGINT);
641 sigaddset(&blocked_set, SIGQUIT);
642 sigaddset(&blocked_set, SIGPIPE);
643 sigaddset(&blocked_set, SIGTERM);
644 sa.sa_handler = interrupt;
645#ifdef SUNOS4
646 /* POSIX signals on sunos4.1 are a little broken. */
647 sa.sa_flags = SA_INTERRUPT;
648#endif /* SUNOS4 */
649 }
650 sigaction(SIGHUP, &sa, NULL);
651 sigaction(SIGINT, &sa, NULL);
652 sigaction(SIGQUIT, &sa, NULL);
653 sigaction(SIGPIPE, &sa, NULL);
654 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000655#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000656 sa.sa_handler = reaper;
657 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000658#else
659 /* Make sure SIGCHLD has the default action so that waitpid
660 definitely works without losing track of children. The user
661 should not have given us a bogus state to inherit, but he might
662 have. Arguably we should detect SIG_IGN here and pass it on
663 to children, but probably noone really needs that. */
664 sa.sa_handler = SIG_DFL;
665 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000666#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000667
668 if (trace() < 0)
669 exit(1);
670 cleanup();
671 exit(0);
672}
673
674void
675newoutf(tcp)
676struct tcb *tcp;
677{
678 char name[MAXPATHLEN];
679 FILE *fp;
680
681 if (outfname && followfork > 1) {
682 sprintf(name, "%s.%u", outfname, tcp->pid);
683#ifndef SVR4
684 setreuid(geteuid(), getuid());
685#endif
686 fp = fopen(name, "w");
687#ifndef SVR4
688 setreuid(geteuid(), getuid());
689#endif
690 if (fp == NULL) {
691 perror("fopen");
692 return;
693 }
694 tcp->outf = fp;
695 }
696 return;
697}
698
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000699int
700expand_tcbtab()
701{
702 /* Allocate some more TCBs and expand the table.
703 We don't want to relocate the TCBs because our
704 callers have pointers and it would be a pain.
705 So tcbtab is a table of pointers. Since we never
706 free the TCBs, we allocate a single chunk of many. */
707 struct tcb **newtab = (struct tcb **)
708 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
709 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
710 sizeof *newtcbs);
711 int i;
712 if (newtab == NULL || newtcbs == NULL) {
713 if (newtab != NULL)
714 free(newtab);
715 return 1;
716 }
717 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
718 newtab[i] = &newtcbs[i - tcbtabsize];
719 tcbtabsize *= 2;
720 tcbtab = newtab;
721
722 return 0;
723}
724
725
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000726struct tcb *
727alloctcb(pid)
728int pid;
729{
730 int i;
731 struct tcb *tcp;
732
Roland McGrathee9d4352002-12-18 04:16:10 +0000733 for (i = 0; i < tcbtabsize; i++) {
734 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000735 if ((tcp->flags & TCB_INUSE) == 0) {
736 tcp->pid = pid;
737 tcp->parent = NULL;
738 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000739 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000740#ifdef TCB_CLONE_THREAD
741 tcp->nclone_threads = tcp->nclone_detached = 0;
742 tcp->nclone_waiting = 0;
743#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000744 tcp->flags = TCB_INUSE | TCB_STARTUP;
745 tcp->outf = outf; /* Initialise to current out file */
746 tcp->stime.tv_sec = 0;
747 tcp->stime.tv_usec = 0;
748 tcp->pfd = -1;
749 nprocs++;
750 return tcp;
751 }
752 }
753 return NULL;
754}
755
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000756#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757int
758proc_open(tcp, attaching)
759struct tcb *tcp;
760int attaching;
761{
762 char proc[32];
763 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000764#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000765 int i;
766 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000767 sigset_t signals;
768 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000769#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000770#ifndef HAVE_POLLABLE_PROCFS
771 static int last_pfd;
772#endif
773
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000774#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000775 /* Open the process pseudo-files in /proc. */
776 sprintf(proc, "/proc/%d/ctl", tcp->pid);
777 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778 perror("strace: open(\"/proc/...\", ...)");
779 return -1;
780 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000781 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
782 perror("F_GETFD");
783 return -1;
784 }
785 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
786 perror("F_SETFD");
787 return -1;
788 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000789 sprintf(proc, "/proc/%d/status", tcp->pid);
790 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
791 perror("strace: open(\"/proc/...\", ...)");
792 return -1;
793 }
794 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
795 perror("F_GETFD");
796 return -1;
797 }
798 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
799 perror("F_SETFD");
800 return -1;
801 }
802 sprintf(proc, "/proc/%d/as", tcp->pid);
803 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
804 perror("strace: open(\"/proc/...\", ...)");
805 return -1;
806 }
807 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
808 perror("F_GETFD");
809 return -1;
810 }
811 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
812 perror("F_SETFD");
813 return -1;
814 }
815#else
816 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000817#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000818 sprintf(proc, "/proc/%d", tcp->pid);
819 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000820#else /* FREEBSD */
821 sprintf(proc, "/proc/%d/mem", tcp->pid);
822 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
823#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000824 perror("strace: open(\"/proc/...\", ...)");
825 return -1;
826 }
827 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
828 perror("F_GETFD");
829 return -1;
830 }
831 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
832 perror("F_SETFD");
833 return -1;
834 }
835#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000836#ifdef FREEBSD
837 sprintf(proc, "/proc/%d/regs", tcp->pid);
838 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
839 perror("strace: open(\"/proc/.../regs\", ...)");
840 return -1;
841 }
842 if (cflag) {
843 sprintf(proc, "/proc/%d/status", tcp->pid);
844 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
845 perror("strace: open(\"/proc/.../status\", ...)");
846 return -1;
847 }
848 } else
849 tcp->pfd_status = -1;
850#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000851 rebuild_pollv();
852 if (!attaching) {
853 /*
854 * Wait for the child to pause. Because of a race
855 * condition we have to poll for the event.
856 */
857 for (;;) {
858 if (IOCTL_STATUS (tcp) < 0) {
859 perror("strace: PIOCSTATUS");
860 return -1;
861 }
862 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000863 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000864 }
865 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000866#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000867 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000868 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000869 perror("strace: PIOCSTOP");
870 return -1;
871 }
Roland McGrath553a6092002-12-16 20:40:39 +0000872#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000873#ifdef PIOCSET
874 /* Set Run-on-Last-Close. */
875 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000876 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000877 perror("PIOCSET PR_RLC");
878 return -1;
879 }
880 /* Set or Reset Inherit-on-Fork. */
881 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000882 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883 perror("PIOC{SET,RESET} PR_FORK");
884 return -1;
885 }
886#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000887#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000888 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
889 perror("PIOCSRLC");
890 return -1;
891 }
892 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
893 perror("PIOC{S,R}FORK");
894 return -1;
895 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000896#else /* FREEBSD */
897 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
898 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
899 perror("PIOCGFL");
900 return -1;
901 }
902 arg &= ~PF_LINGER;
903 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
904 perror("PIOCSFL");
905 return -1;
906 }
907#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000908#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000909#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000910 /* Enable all syscall entries we care about. */
911 premptyset(&syscalls);
912 for (i = 1; i < MAX_QUALS; ++i) {
913 if (i > (sizeof syscalls) * CHAR_BIT) break;
914 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
915 }
916 praddset (&syscalls, SYS_execve);
917 if (followfork) {
918 praddset (&syscalls, SYS_fork);
919#ifdef SYS_forkall
920 praddset (&syscalls, SYS_forkall);
921#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000922#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000923 praddset (&syscalls, SYS_fork1);
924#endif
925#ifdef SYS_rfork1
926 praddset (&syscalls, SYS_rfork1);
927#endif
928#ifdef SYS_rforkall
929 praddset (&syscalls, SYS_rforkall);
930#endif
931 }
932 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000933 perror("PIOCSENTRY");
934 return -1;
935 }
John Hughes19e49982001-10-19 08:59:12 +0000936 /* Enable the syscall exits. */
937 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000938 perror("PIOSEXIT");
939 return -1;
940 }
John Hughes19e49982001-10-19 08:59:12 +0000941 /* Enable signals we care about. */
942 premptyset(&signals);
943 for (i = 1; i < MAX_QUALS; ++i) {
944 if (i > (sizeof signals) * CHAR_BIT) break;
945 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
946 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000947 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000948 perror("PIOCSTRACE");
949 return -1;
950 }
John Hughes19e49982001-10-19 08:59:12 +0000951 /* Enable faults we care about */
952 premptyset(&faults);
953 for (i = 1; i < MAX_QUALS; ++i) {
954 if (i > (sizeof faults) * CHAR_BIT) break;
955 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
956 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000957 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000958 perror("PIOCSFAULT");
959 return -1;
960 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000961#else /* FREEBSD */
962 /* set events flags. */
963 arg = S_SIG | S_SCE | S_SCX ;
964 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
965 perror("PIOCBIS");
966 return -1;
967 }
968#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000969 if (!attaching) {
970#ifdef MIPS
971 /*
972 * The SGI PRSABORT doesn't work for pause() so
973 * we send it a caught signal to wake it up.
974 */
975 kill(tcp->pid, SIGINT);
976#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000977#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000978 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000979 arg = PRSABORT;
980 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000981 perror("PIOCRUN");
982 return -1;
983 }
Roland McGrath553a6092002-12-16 20:40:39 +0000984#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000985#endif /* !MIPS*/
986#ifdef FREEBSD
987 /* wake up the child if it received the SIGSTOP */
988 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000989#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000990 for (;;) {
991 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000992 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000993 perror("PIOCWSTOP");
994 return -1;
995 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000996 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000997 tcp->flags &= ~TCB_INSYSCALL;
998 get_scno(tcp);
999 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001000 break;
1001 }
1002 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001003#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001004 arg = 0;
1005 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001006#else /* FREEBSD */
1007 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001008#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001009 perror("PIOCRUN");
1010 return -1;
1011 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001012#ifdef FREEBSD
1013 /* handle the case where we "opened" the child before
1014 it did the kill -STOP */
1015 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1016 tcp->status.PR_WHAT == SIGSTOP)
1017 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001018#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001020#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001021 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001022#else /* FREEBSD */
1023 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001024 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001025 /* We are attaching to an already running process.
1026 * Try to figure out the state of the process in syscalls,
1027 * to handle the first event well.
1028 * This is done by having a look at the "wchan" property of the
1029 * process, which tells where it is stopped (if it is). */
1030 FILE * status;
1031 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001032
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001033 sprintf(proc, "/proc/%d/status", tcp->pid);
1034 status = fopen(proc, "r");
1035 if (status &&
1036 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1037 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1038 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1039 strcmp(wchan, "stopevent")) {
1040 /* The process is asleep in the middle of a syscall.
1041 Fake the syscall entry event */
1042 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1043 tcp->status.PR_WHY = PR_SYSENTRY;
1044 trace_syscall(tcp);
1045 }
1046 if (status)
1047 fclose(status);
1048 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001049 }
1050#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001051#ifndef HAVE_POLLABLE_PROCFS
1052 if (proc_poll_pipe[0] != -1)
1053 proc_poller(tcp->pfd);
1054 else if (nprocs > 1) {
1055 proc_poll_open();
1056 proc_poller(last_pfd);
1057 proc_poller(tcp->pfd);
1058 }
1059 last_pfd = tcp->pfd;
1060#endif /* !HAVE_POLLABLE_PROCFS */
1061 return 0;
1062}
1063
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001064#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001065
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001066struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067pid2tcb(pid)
1068int pid;
1069{
1070 int i;
1071 struct tcb *tcp;
1072
Roland McGrathee9d4352002-12-18 04:16:10 +00001073 for (i = 0; i < tcbtabsize; i++) {
1074 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001075 if (pid && tcp->pid != pid)
1076 continue;
1077 if (tcp->flags & TCB_INUSE)
1078 return tcp;
1079 }
1080 return NULL;
1081}
1082
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001083#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001084
1085static struct tcb *
1086pfd2tcb(pfd)
1087int pfd;
1088{
1089 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001090
Roland McGrathca16be82003-01-10 19:55:28 +00001091 for (i = 0; i < tcbtabsize; i++) {
1092 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001093 if (tcp->pfd != pfd)
1094 continue;
1095 if (tcp->flags & TCB_INUSE)
1096 return tcp;
1097 }
1098 return NULL;
1099}
1100
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001101#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102
1103void
1104droptcb(tcp)
1105struct tcb *tcp;
1106{
1107 if (tcp->pid == 0)
1108 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001109#ifdef TCB_CLONE_THREAD
1110 if (tcp->nclone_threads > 0) {
1111 /* There are other threads left in this process, but this
1112 is the one whose PID represents the whole process.
1113 We need to keep this record around as a zombie until
1114 all the threads die. */
1115 tcp->flags |= TCB_EXITING;
1116 return;
1117 }
1118#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119 nprocs--;
1120 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001121
Roland McGrathe29341c2003-01-10 20:14:20 +00001122 if (tcp->parent != NULL) {
1123 tcp->parent->nchildren--;
1124#ifdef TCB_CLONE_THREAD
1125 if (tcp->flags & TCB_CLONE_DETACHED)
1126 tcp->parent->nclone_detached--;
1127 if (tcp->flags & TCB_CLONE_THREAD)
1128 tcp->parent->nclone_threads--;
1129#endif
Roland McGrath09623452003-05-23 02:27:13 +00001130#ifdef TCB_CLONE_DETACHED
1131 if (!(tcp->flags & TCB_CLONE_DETACHED))
1132#endif
1133 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001134 tcp->parent = NULL;
1135 }
1136
1137 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138 if (tcp->pfd != -1) {
1139 close(tcp->pfd);
1140 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001141#ifdef FREEBSD
1142 if (tcp->pfd_reg != -1) {
1143 close(tcp->pfd_reg);
1144 tcp->pfd_reg = -1;
1145 }
1146 if (tcp->pfd_status != -1) {
1147 close(tcp->pfd_status);
1148 tcp->pfd_status = -1;
1149 }
Roland McGrath553a6092002-12-16 20:40:39 +00001150#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001151#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001152 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153#endif
1154 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001155
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001156 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001158
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159 tcp->outf = 0;
1160}
1161
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001162#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001163
1164static int
1165resume(tcp)
1166struct tcb *tcp;
1167{
1168 if (tcp == NULL)
1169 return -1;
1170
1171 if (!(tcp->flags & TCB_SUSPENDED)) {
1172 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1173 return -1;
1174 }
1175 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001176#ifdef TCB_CLONE_THREAD
1177 if (tcp->flags & TCB_CLONE_THREAD)
1178 tcp->parent->nclone_waiting--;
1179#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001180
1181 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1182 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1183 return -1;
1184 }
1185
1186 if (!qflag)
1187 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1188 return 0;
1189}
1190
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001191#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001192
1193/* detach traced process; continue with sig */
1194
1195static int
1196detach(tcp, sig)
1197struct tcb *tcp;
1198int sig;
1199{
1200 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001201#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001202 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001203#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001204
1205 if (tcp->flags & TCB_BPTSET)
1206 sig = SIGKILL;
1207
1208#ifdef LINUX
1209 /*
1210 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001211 * before detaching. Arghh. We go through hoops
1212 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001213 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001214#if defined(SPARC)
1215#undef PTRACE_DETACH
1216#define PTRACE_DETACH PTRACE_SUNDETACH
1217#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001218 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1219 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001220 }
1221 else if (errno != ESRCH) {
1222 /* Shouldn't happen. */
1223 perror("detach: ptrace(PTRACE_DETACH, ...)");
1224 }
1225 else if (kill(tcp->pid, 0) < 0) {
1226 if (errno != ESRCH)
1227 perror("detach: checking sanity");
1228 }
1229 else if (kill(tcp->pid, SIGSTOP) < 0) {
1230 if (errno != ESRCH)
1231 perror("detach: stopping child");
1232 }
1233 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001234 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001235#ifdef __WALL
1236 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1237 if (errno == ECHILD) /* Already gone. */
1238 break;
1239 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001240 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001241 break;
1242 }
1243#endif /* __WALL */
1244 /* No __WALL here. */
1245 if (waitpid(tcp->pid, &status, 0) < 0) {
1246 if (errno != ECHILD) {
1247 perror("detach: waiting");
1248 break;
1249 }
1250#ifdef __WCLONE
1251 /* If no processes, try clones. */
1252 if (wait4(tcp->pid, &status, __WCLONE,
1253 NULL) < 0) {
1254 if (errno != ECHILD)
1255 perror("detach: waiting");
1256 break;
1257 }
1258#endif /* __WCLONE */
1259 }
1260#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001261 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001262#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001263 if (!WIFSTOPPED(status)) {
1264 /* Au revoir, mon ami. */
1265 break;
1266 }
1267 if (WSTOPSIG(status) == SIGSTOP) {
1268 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001269 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001270 if (errno != ESRCH)
1271 perror("detach: ptrace(PTRACE_DETACH, ...)");
1272 /* I died trying. */
1273 }
1274 break;
1275 }
1276 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001277 WSTOPSIG(status) == SIGTRAP ?
1278 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001279 if (errno != ESRCH)
1280 perror("detach: ptrace(PTRACE_CONT, ...)");
1281 break;
1282 }
1283 }
1284 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001285#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286
1287#if defined(SUNOS4)
1288 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1289 if (sig && kill(tcp->pid, sig) < 0)
1290 perror("detach: kill");
1291 sig = 0;
1292 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1293 perror("detach: ptrace(PTRACE_DETACH, ...)");
1294#endif /* SUNOS4 */
1295
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001296#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001297 resumed = 0;
1298
1299 /* XXX This won't always be quite right (but it never was).
1300 A waiter with argument 0 or < -1 is waiting for any pid in
1301 a particular pgrp, which this child might or might not be
1302 in. The waiter will only wake up if it's argument is -1
1303 or if it's waiting for tcp->pid's pgrp. It makes a
1304 difference to wake up a waiter when there might be more
1305 traced children, because it could get a false ECHILD
1306 error. OTOH, if this was the last child in the pgrp, then
1307 it ought to wake up and get ECHILD. We would have to
1308 search the system for all pid's in the pgrp to be sure.
1309
1310 && (t->waitpid == -1 ||
1311 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1312 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1313 */
1314
1315 if (tcp->parent &&
1316 (tcp->parent->flags & TCB_SUSPENDED) &&
1317 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1318 error = resume(tcp->parent);
1319 ++resumed;
1320 }
1321#ifdef TCB_CLONE_THREAD
1322 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1323 /* Some other threads of our parent are waiting too. */
1324 unsigned int i;
1325
1326 /* Resume all the threads that were waiting for this PID. */
1327 for (i = 0; i < tcbtabsize; i++) {
1328 struct tcb *t = tcbtab[i];
1329 if (t->parent == tcp->parent && t != tcp
1330 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1331 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1332 && t->waitpid == tcp->pid) {
1333 error |= resume (t);
1334 ++resumed;
1335 }
1336 }
1337 if (resumed == 0)
1338 /* Noone was waiting for this PID in particular,
1339 so now we might need to resume some wildcarders. */
1340 for (i = 0; i < tcbtabsize; i++) {
1341 struct tcb *t = tcbtab[i];
1342 if (t->parent == tcp->parent && t != tcp
1343 && ((t->flags
1344 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1345 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1346 && t->waitpid <= 0
1347 ) {
1348 error |= resume (t);
1349 break;
1350 }
1351 }
1352 }
1353#endif
1354
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001355#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001356
1357 if (!qflag)
1358 fprintf(stderr, "Process %u detached\n", tcp->pid);
1359
1360 droptcb(tcp);
1361 return error;
1362}
1363
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001364#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001365
1366static void
1367reaper(sig)
1368int sig;
1369{
1370 int pid;
1371 int status;
1372
1373 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1374#if 0
1375 struct tcb *tcp;
1376
1377 tcp = pid2tcb(pid);
1378 if (tcp)
1379 droptcb(tcp);
1380#endif
1381 }
1382}
1383
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001384#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001385
1386static void
1387cleanup()
1388{
1389 int i;
1390 struct tcb *tcp;
1391
Roland McGrathee9d4352002-12-18 04:16:10 +00001392 for (i = 0; i < tcbtabsize; i++) {
1393 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001394 if (!(tcp->flags & TCB_INUSE))
1395 continue;
1396 if (debug)
1397 fprintf(stderr,
1398 "cleanup: looking at pid %u\n", tcp->pid);
1399 if (tcp_last &&
1400 (!outfname || followfork < 2 || tcp_last == tcp)) {
1401 tprintf(" <unfinished ...>\n");
1402 tcp_last = NULL;
1403 }
1404 if (tcp->flags & TCB_ATTACHED)
1405 detach(tcp, 0);
1406 else {
1407 kill(tcp->pid, SIGCONT);
1408 kill(tcp->pid, SIGTERM);
1409 }
1410 }
1411 if (cflag)
1412 call_summary(outf);
1413}
1414
1415static void
1416interrupt(sig)
1417int sig;
1418{
1419 interrupted = 1;
1420}
1421
1422#ifndef HAVE_STRERROR
1423
Roland McGrath6d2b3492002-12-30 00:51:30 +00001424#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001425extern int sys_nerr;
1426extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001427#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001428
1429const char *
1430strerror(errno)
1431int errno;
1432{
1433 static char buf[64];
1434
1435 if (errno < 1 || errno >= sys_nerr) {
1436 sprintf(buf, "Unknown error %d", errno);
1437 return buf;
1438 }
1439 return sys_errlist[errno];
1440}
1441
1442#endif /* HAVE_STERRROR */
1443
1444#ifndef HAVE_STRSIGNAL
1445
Roland McGrath8f474e02003-01-14 07:53:33 +00001446#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001447extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001448#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001449#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1450extern char *_sys_siglist[];
1451#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001452
1453const char *
1454strsignal(sig)
1455int sig;
1456{
1457 static char buf[64];
1458
1459 if (sig < 1 || sig >= NSIG) {
1460 sprintf(buf, "Unknown signal %d", sig);
1461 return buf;
1462 }
1463#ifdef HAVE__SYS_SIGLIST
1464 return _sys_siglist[sig];
1465#else
1466 return sys_siglist[sig];
1467#endif
1468}
1469
1470#endif /* HAVE_STRSIGNAL */
1471
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001472#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001473
1474static void
1475rebuild_pollv()
1476{
1477 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001478
Roland McGrathee9d4352002-12-18 04:16:10 +00001479 if (pollv != NULL)
1480 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001481 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001482 if (pollv == NULL) {
1483 fprintf(stderr, "strace: out of memory for poll vector\n");
1484 exit(1);
1485 }
1486
Roland McGrathca16be82003-01-10 19:55:28 +00001487 for (i = j = 0; i < tcbtabsize; i++) {
1488 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001489 if (!(tcp->flags & TCB_INUSE))
1490 continue;
1491 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001492 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001493 j++;
1494 }
1495 if (j != nprocs) {
1496 fprintf(stderr, "strace: proc miscount\n");
1497 exit(1);
1498 }
1499}
1500
1501#ifndef HAVE_POLLABLE_PROCFS
1502
1503static void
1504proc_poll_open()
1505{
1506 int arg;
1507 int i;
1508
1509 if (pipe(proc_poll_pipe) < 0) {
1510 perror("pipe");
1511 exit(1);
1512 }
1513 for (i = 0; i < 2; i++) {
1514 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1515 perror("F_GETFD");
1516 exit(1);
1517 }
1518 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1519 perror("F_SETFD");
1520 exit(1);
1521 }
1522 }
1523}
1524
1525static int
1526proc_poll(pollv, nfds, timeout)
1527struct pollfd *pollv;
1528int nfds;
1529int timeout;
1530{
1531 int i;
1532 int n;
1533 struct proc_pollfd pollinfo;
1534
1535 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1536 return n;
1537 if (n != sizeof(struct proc_pollfd)) {
1538 fprintf(stderr, "panic: short read: %d\n", n);
1539 exit(1);
1540 }
1541 for (i = 0; i < nprocs; i++) {
1542 if (pollv[i].fd == pollinfo.fd)
1543 pollv[i].revents = pollinfo.revents;
1544 else
1545 pollv[i].revents = 0;
1546 }
1547 poller_pid = pollinfo.pid;
1548 return 1;
1549}
1550
1551static void
1552wakeup_handler(sig)
1553int sig;
1554{
1555}
1556
1557static void
1558proc_poller(pfd)
1559int pfd;
1560{
1561 struct proc_pollfd pollinfo;
1562 struct sigaction sa;
1563 sigset_t blocked_set, empty_set;
1564 int i;
1565 int n;
1566 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001567#ifdef FREEBSD
1568 struct procfs_status pfs;
1569#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001570
1571 switch (fork()) {
1572 case -1:
1573 perror("fork");
1574 _exit(0);
1575 case 0:
1576 break;
1577 default:
1578 return;
1579 }
1580
1581 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1582 sa.sa_flags = 0;
1583 sigemptyset(&sa.sa_mask);
1584 sigaction(SIGHUP, &sa, NULL);
1585 sigaction(SIGINT, &sa, NULL);
1586 sigaction(SIGQUIT, &sa, NULL);
1587 sigaction(SIGPIPE, &sa, NULL);
1588 sigaction(SIGTERM, &sa, NULL);
1589 sa.sa_handler = wakeup_handler;
1590 sigaction(SIGUSR1, &sa, NULL);
1591 sigemptyset(&blocked_set);
1592 sigaddset(&blocked_set, SIGUSR1);
1593 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1594 sigemptyset(&empty_set);
1595
1596 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1597 perror("getrlimit(RLIMIT_NOFILE, ...)");
1598 _exit(0);
1599 }
1600 n = rl.rlim_cur;
1601 for (i = 0; i < n; i++) {
1602 if (i != pfd && i != proc_poll_pipe[1])
1603 close(i);
1604 }
1605
1606 pollinfo.fd = pfd;
1607 pollinfo.pid = getpid();
1608 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001609#ifndef FREEBSD
1610 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1611#else /* FREEBSD */
1612 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1613#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001614 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615 switch (errno) {
1616 case EINTR:
1617 continue;
1618 case EBADF:
1619 pollinfo.revents = POLLERR;
1620 break;
1621 case ENOENT:
1622 pollinfo.revents = POLLHUP;
1623 break;
1624 default:
1625 perror("proc_poller: PIOCWSTOP");
1626 }
1627 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1628 _exit(0);
1629 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001630 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1632 sigsuspend(&empty_set);
1633 }
1634}
1635
1636#endif /* !HAVE_POLLABLE_PROCFS */
1637
1638static int
1639choose_pfd()
1640{
1641 int i, j;
1642 struct tcb *tcp;
1643
1644 static int last;
1645
1646 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001647 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648 /*
1649 * The previous process is ready to run again. We'll
1650 * let it do so if it is currently in a syscall. This
1651 * heuristic improves the readability of the trace.
1652 */
1653 tcp = pfd2tcb(pollv[last].fd);
1654 if (tcp && (tcp->flags & TCB_INSYSCALL))
1655 return pollv[last].fd;
1656 }
1657
1658 for (i = 0; i < nprocs; i++) {
1659 /* Let competing children run round robin. */
1660 j = (i + last + 1) % nprocs;
1661 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1662 tcp = pfd2tcb(pollv[j].fd);
1663 if (!tcp) {
1664 fprintf(stderr, "strace: lost proc\n");
1665 exit(1);
1666 }
1667 droptcb(tcp);
1668 return -1;
1669 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001670 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001671 last = j;
1672 return pollv[j].fd;
1673 }
1674 }
1675 fprintf(stderr, "strace: nothing ready\n");
1676 exit(1);
1677}
1678
1679static int
1680trace()
1681{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001682#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001683 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001684#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685 struct tcb *tcp;
1686 int pfd;
1687 int what;
1688 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001689 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001690
1691 for (;;) {
1692 if (interactive)
1693 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1694
1695 if (nprocs == 0)
1696 break;
1697
1698 switch (nprocs) {
1699 case 1:
1700#ifndef HAVE_POLLABLE_PROCFS
1701 if (proc_poll_pipe[0] == -1) {
1702#endif
1703 tcp = pid2tcb(0);
1704 if (!tcp)
1705 continue;
1706 pfd = tcp->pfd;
1707 if (pfd == -1)
1708 continue;
1709 break;
1710#ifndef HAVE_POLLABLE_PROCFS
1711 }
1712 /* fall through ... */
1713#endif /* !HAVE_POLLABLE_PROCFS */
1714 default:
1715#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001716#ifdef POLL_HACK
1717 /* On some systems (e.g. UnixWare) we get too much ugly
1718 "unfinished..." stuff when multiple proceses are in
1719 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001720
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001721 if (in_syscall) {
1722 struct pollfd pv;
1723 tcp = in_syscall;
1724 in_syscall = NULL;
1725 pv.fd = tcp->pfd;
1726 pv.events = POLLWANT;
1727 if ((what = poll (&pv, 1, 1)) < 0) {
1728 if (interrupted)
1729 return 0;
1730 continue;
1731 }
1732 else if (what == 1 && pv.revents & POLLWANT) {
1733 goto FOUND;
1734 }
1735 }
1736#endif
1737
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001738 if (poll(pollv, nprocs, INFTIM) < 0) {
1739 if (interrupted)
1740 return 0;
1741 continue;
1742 }
1743#else /* !HAVE_POLLABLE_PROCFS */
1744 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1745 if (interrupted)
1746 return 0;
1747 continue;
1748 }
1749#endif /* !HAVE_POLLABLE_PROCFS */
1750 pfd = choose_pfd();
1751 if (pfd == -1)
1752 continue;
1753 break;
1754 }
1755
1756 /* Look up `pfd' in our table. */
1757 if ((tcp = pfd2tcb(pfd)) == NULL) {
1758 fprintf(stderr, "unknown pfd: %u\n", pfd);
1759 exit(1);
1760 }
John Hughesb6643082002-05-23 11:02:22 +00001761#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001762 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001763#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764 /* Get the status of the process. */
1765 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001766#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001767 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001768#else /* FREEBSD */
1769 /* Thanks to some scheduling mystery, the first poller
1770 sometimes waits for the already processed end of fork
1771 event. Doing a non blocking poll here solves the problem. */
1772 if (proc_poll_pipe[0] != -1)
1773 ioctl_result = IOCTL_STATUS (tcp);
1774 else
1775 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001776#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001777 ioctl_errno = errno;
1778#ifndef HAVE_POLLABLE_PROCFS
1779 if (proc_poll_pipe[0] != -1) {
1780 if (ioctl_result < 0)
1781 kill(poller_pid, SIGKILL);
1782 else
1783 kill(poller_pid, SIGUSR1);
1784 }
1785#endif /* !HAVE_POLLABLE_PROCFS */
1786 }
1787 if (interrupted)
1788 return 0;
1789
1790 if (interactive)
1791 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1792
1793 if (ioctl_result < 0) {
1794 /* Find out what happened if it failed. */
1795 switch (ioctl_errno) {
1796 case EINTR:
1797 case EBADF:
1798 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001799#ifdef FREEBSD
1800 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001801#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001802 case ENOENT:
1803 droptcb(tcp);
1804 continue;
1805 default:
1806 perror("PIOCWSTOP");
1807 exit(1);
1808 }
1809 }
1810
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001811#ifdef FREEBSD
1812 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1813 /* discard first event for a syscall we never entered */
1814 IOCTL (tcp->pfd, PIOCRUN, 0);
1815 continue;
1816 }
Roland McGrath553a6092002-12-16 20:40:39 +00001817#endif
1818
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001819 /* clear the just started flag */
1820 tcp->flags &= ~TCB_STARTUP;
1821
1822 /* set current output file */
1823 outf = tcp->outf;
1824
1825 if (cflag) {
1826 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001827#ifdef FREEBSD
1828 char buf[1024];
1829 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001830
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001831 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1832 buf[len] = '\0';
1833 sscanf(buf,
1834 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1835 &stime.tv_sec, &stime.tv_usec);
1836 } else
1837 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001838#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001839 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1840 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001841#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001842 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1843 tcp->stime = stime;
1844 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001845 what = tcp->status.PR_WHAT;
1846 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001847#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001848 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001849 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1850 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001851 if (trace_syscall(tcp) < 0) {
1852 fprintf(stderr, "syscall trouble\n");
1853 exit(1);
1854 }
1855 }
1856 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001857#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001858 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001859#ifdef POLL_HACK
1860 in_syscall = tcp;
1861#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001862 case PR_SYSEXIT:
1863 if (trace_syscall(tcp) < 0) {
1864 fprintf(stderr, "syscall trouble\n");
1865 exit(1);
1866 }
1867 break;
1868 case PR_SIGNALLED:
1869 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1870 printleader(tcp);
1871 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001872 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001873 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001874#ifdef PR_INFO
1875 if (tcp->status.PR_INFO.si_signo == what) {
1876 printleader(tcp);
1877 tprintf(" siginfo=");
1878 printsiginfo(&tcp->status.PR_INFO, 1);
1879 printtrailer(tcp);
1880 }
1881#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001882 }
1883 break;
1884 case PR_FAULTED:
1885 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1886 printleader(tcp);
1887 tprintf("=== FAULT %d ===", what);
1888 printtrailer(tcp);
1889 }
1890 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001891#ifdef FREEBSD
1892 case 0: /* handle case we polled for nothing */
1893 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001894#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001895 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001896 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001897 exit(1);
1898 break;
1899 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001900 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001901#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001902 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001903#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001904 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001905#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001906 perror("PIOCRUN");
1907 exit(1);
1908 }
1909 }
1910 return 0;
1911}
1912
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001913#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001914
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001915#ifdef TCB_GROUP_EXITING
1916/* Handle an exit detach or death signal that is taking all the
1917 related clone threads with it. This is called in three circumstances:
1918 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1919 SIG == 0 Continuing TCP will perform an exit_group syscall.
1920 SIG == other Continuing TCP with SIG will kill the process.
1921*/
1922static int
1923handle_group_exit(struct tcb *tcp, int sig)
1924{
1925 /* We need to locate our records of all the clone threads
1926 related to TCP, either its children or siblings. */
1927 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1928 ? tcp->parent
1929 : tcp->nclone_detached > 0
1930 ? tcp : NULL);
1931
1932 if (sig < 0) {
Roland McGrath05690952004-10-20 01:00:27 +00001933 if (leader != NULL && leader != tcp &&
1934 !(leader->flags & TCB_GROUP_EXITING))
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001935 fprintf(stderr,
1936 "PANIC: handle_group_exit: %d leader %d\n",
1937 tcp->pid, leader ? leader->pid : -1);
1938 droptcb(tcp); /* Already died. */
1939 }
1940 else {
1941 if (tcp->flags & TCB_ATTACHED) {
Roland McGrath00dc13f2004-10-20 02:04:15 +00001942 if (leader != NULL && leader != tcp) {
1943 if (leader->flags & TCB_ATTACHED) {
1944 /* We need to detach the leader so
1945 that the process death will be
1946 reported to its real parent.
1947 But we kill it first to prevent
1948 it doing anything before we kill
1949 the whole process in a moment.
1950 We can use PTRACE_KILL on a
1951 thread that's not already
1952 stopped. Then the value we pass
1953 in PTRACE_DETACH just sets the
1954 death signal reported to the
1955 real parent. */
1956 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1957 if (debug)
1958 fprintf(stderr,
1959 " [%d exit %d kills %d]\n",
1960 tcp->pid, sig, leader->pid);
1961 detach(leader, sig);
1962 }
1963 else
1964 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001965 }
1966 detach(tcp, sig);
1967 }
1968 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1969 perror("strace: ptrace(PTRACE_CONT, ...)");
1970 cleanup();
1971 return -1;
1972 }
1973 else {
Roland McGrath05690952004-10-20 01:00:27 +00001974 if (leader != NULL)
1975 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001976 if (leader != NULL && leader != tcp)
1977 droptcb(tcp);
1978 /* The leader will report to us as parent now,
1979 and then we'll get to the SIG==-1 case. */
1980 return 0;
1981 }
1982 }
1983
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001984 return 0;
1985}
1986#endif
1987
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001988static int
1989trace()
1990{
1991 int pid;
1992 int wait_errno;
1993 int status;
1994 struct tcb *tcp;
1995#ifdef LINUX
1996 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001997#ifdef __WALL
1998 static int wait4_options = __WALL;
1999#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002000#endif /* LINUX */
2001
2002 while (nprocs != 0) {
2003 if (interactive)
2004 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2005#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002006#ifdef __WALL
2007 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002008 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002009 /* this kernel does not support __WALL */
2010 wait4_options &= ~__WALL;
2011 errno = 0;
2012 pid = wait4(-1, &status, wait4_options,
2013 cflag ? &ru : NULL);
2014 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002015 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002016 /* most likely a "cloned" process */
2017 pid = wait4(-1, &status, __WCLONE,
2018 cflag ? &ru : NULL);
2019 if (pid == -1) {
2020 fprintf(stderr, "strace: clone wait4 "
2021 "failed: %s\n", strerror(errno));
2022 }
2023 }
2024#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002025 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002026#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002027#endif /* LINUX */
2028#ifdef SUNOS4
2029 pid = wait(&status);
2030#endif /* SUNOS4 */
2031 wait_errno = errno;
2032 if (interactive)
2033 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2034
2035 if (interrupted)
2036 return 0;
2037
2038 if (pid == -1) {
2039 switch (wait_errno) {
2040 case EINTR:
2041 continue;
2042 case ECHILD:
2043 /*
2044 * We would like to verify this case
2045 * but sometimes a race in Solbourne's
2046 * version of SunOS sometimes reports
2047 * ECHILD before sending us SIGCHILD.
2048 */
2049#if 0
2050 if (nprocs == 0)
2051 return 0;
2052 fprintf(stderr, "strace: proc miscount\n");
2053 exit(1);
2054#endif
2055 return 0;
2056 default:
2057 errno = wait_errno;
2058 perror("strace: wait");
2059 return -1;
2060 }
2061 }
2062 if (debug)
2063 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2064
2065 /* Look up `pid' in our table. */
2066 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002067#ifdef LINUX
2068 if (followfork || followvfork) {
2069 /* This is needed to go with the CLONE_PTRACE
2070 changes in process.c/util.c: we might see
2071 the child's initial trap before we see the
2072 parent return from the clone syscall.
2073 Leave the child suspended until the parent
2074 returns from its system call. Only then
2075 will we have the association of parent and
2076 child so that we know how to do clearbpt
2077 in the child. */
2078 if ((tcp = alloctcb(pid)) == NULL) {
2079 fprintf(stderr, " [tcb table full]\n");
2080 kill(pid, SIGKILL); /* XXX */
2081 return 0;
2082 }
2083 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
2084 newoutf(tcp);
2085 if (!qflag)
2086 fprintf(stderr, "\
2087Process %d attached (waiting for parent)\n",
2088 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002089 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002090 else
2091 /* This can happen if a clone call used
2092 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002093#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002094 {
2095 fprintf(stderr, "unknown pid: %u\n", pid);
2096 if (WIFSTOPPED(status))
2097 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2098 exit(1);
2099 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002100 }
2101 /* set current output file */
2102 outf = tcp->outf;
2103 if (cflag) {
2104#ifdef LINUX
2105 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2106 tcp->stime = ru.ru_stime;
2107#endif /* !LINUX */
2108 }
2109
2110 if (tcp->flags & TCB_SUSPENDED) {
2111 /*
2112 * Apparently, doing any ptrace() call on a stopped
2113 * process, provokes the kernel to report the process
2114 * status again on a subsequent wait(), even if the
2115 * process has not been actually restarted.
2116 * Since we have inspected the arguments of suspended
2117 * processes we end up here testing for this case.
2118 */
2119 continue;
2120 }
2121 if (WIFSIGNALED(status)) {
2122 if (!cflag
2123 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2124 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002125 tprintf("+++ killed by %s %s+++",
2126 signame(WTERMSIG(status)),
2127#ifdef WCOREDUMP
2128 WCOREDUMP(status) ? "(core dumped) " :
2129#endif
2130 "");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002131 printtrailer(tcp);
2132 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002133#ifdef TCB_GROUP_EXITING
2134 handle_group_exit(tcp, -1);
2135#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002136 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002137#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002138 continue;
2139 }
2140 if (WIFEXITED(status)) {
2141 if (debug)
2142 fprintf(stderr, "pid %u exited\n", pid);
Roland McGrath05690952004-10-20 01:00:27 +00002143 if ((tcp->flags & TCB_ATTACHED)
2144#ifdef TCB_GROUP_EXITING
2145 && !(tcp->parent && (tcp->parent->flags &
2146 TCB_GROUP_EXITING))
2147#endif
2148 )
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002149 fprintf(stderr,
2150 "PANIC: attached pid %u exited\n",
2151 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002152 if (tcp == tcp_last) {
2153 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2154 == TCB_INSYSCALL)
2155 tprintf(" <unfinished ... exit status %d>\n",
2156 WEXITSTATUS(status));
2157 tcp_last = NULL;
2158 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002159#ifdef TCB_GROUP_EXITING
2160 handle_group_exit(tcp, -1);
2161#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002162 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002163#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002164 continue;
2165 }
2166 if (!WIFSTOPPED(status)) {
2167 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2168 droptcb(tcp);
2169 continue;
2170 }
2171 if (debug)
2172 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002173 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002174
2175 if (tcp->flags & TCB_STARTUP) {
2176 /*
2177 * This flag is there to keep us in sync.
2178 * Next time this process stops it should
2179 * really be entering a system call.
2180 */
2181 tcp->flags &= ~TCB_STARTUP;
2182 if (tcp->flags & TCB_ATTACHED) {
2183 /*
2184 * Interestingly, the process may stop
2185 * with STOPSIG equal to some other signal
2186 * than SIGSTOP if we happend to attach
2187 * just before the process takes a signal.
2188 */
2189 if (!WIFSTOPPED(status)) {
2190 fprintf(stderr,
2191 "pid %u not stopped\n", pid);
2192 detach(tcp, WSTOPSIG(status));
2193 continue;
2194 }
2195 }
2196 else {
2197#ifdef SUNOS4
2198 /* A child of us stopped at exec */
2199 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2200 fixvfork(tcp);
2201#endif /* SUNOS4 */
2202 }
2203 if (tcp->flags & TCB_BPTSET) {
2204 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2205 droptcb(tcp);
2206 cleanup();
2207 return -1;
2208 }
2209 }
2210 goto tracing;
2211 }
2212
2213 if (WSTOPSIG(status) != SIGTRAP) {
2214 if (WSTOPSIG(status) == SIGSTOP &&
2215 (tcp->flags & TCB_SIGTRAPPED)) {
2216 /*
2217 * Trapped attempt to block SIGTRAP
2218 * Hope we are back in control now.
2219 */
2220 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2221 if (ptrace(PTRACE_SYSCALL,
2222 pid, (char *) 1, 0) < 0) {
2223 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2224 cleanup();
2225 return -1;
2226 }
2227 continue;
2228 }
2229 if (!cflag
2230 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002231 unsigned long addr = 0, pc = 0;
2232#ifdef PT_GETSIGINFO
2233# define PSR_RI 41
2234 struct siginfo si;
2235 unsigned long psr;
2236
2237 upeek(pid, PT_CR_IPSR, &psr);
2238 upeek(pid, PT_CR_IIP, &pc);
2239
2240 pc += (psr >> PSR_RI) & 0x3;
2241 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2242 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002243#elif defined PTRACE_GETSIGINFO
2244 if (WSTOPSIG(status) == SIGSEGV ||
2245 WSTOPSIG(status) == SIGBUS) {
2246 siginfo_t si;
2247 if (ptrace(PTRACE_GETSIGINFO, pid,
2248 0, &si) == 0)
2249 addr = (unsigned long)
2250 si.si_addr;
2251 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002252#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002253 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002254 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002255 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002256 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002257 printtrailer(tcp);
2258 }
Roland McGrath05690952004-10-20 01:00:27 +00002259 if (((tcp->flags & TCB_ATTACHED) ||
2260 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002261 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002262#ifdef TCB_GROUP_EXITING
2263 handle_group_exit(tcp, WSTOPSIG(status));
2264#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002265 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002266#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002267 continue;
2268 }
2269 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2270 WSTOPSIG(status)) < 0) {
2271 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2272 cleanup();
2273 return -1;
2274 }
2275 tcp->flags &= ~TCB_SUSPENDED;
2276 continue;
2277 }
2278 if (trace_syscall(tcp) < 0) {
2279 if (tcp->flags & TCB_ATTACHED)
2280 detach(tcp, 0);
2281 else {
2282 ptrace(PTRACE_KILL,
2283 tcp->pid, (char *) 1, SIGTERM);
2284 droptcb(tcp);
2285 }
2286 continue;
2287 }
2288 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002289#ifdef TCB_GROUP_EXITING
2290 if (tcp->flags & TCB_GROUP_EXITING) {
2291 if (handle_group_exit(tcp, 0) < 0)
2292 return -1;
2293 continue;
2294 }
2295#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002296 if (tcp->flags & TCB_ATTACHED)
2297 detach(tcp, 0);
2298 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2299 perror("strace: ptrace(PTRACE_CONT, ...)");
2300 cleanup();
2301 return -1;
2302 }
2303 continue;
2304 }
2305 if (tcp->flags & TCB_SUSPENDED) {
2306 if (!qflag)
2307 fprintf(stderr, "Process %u suspended\n", pid);
2308 continue;
2309 }
2310 tracing:
2311 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2312 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2313 cleanup();
2314 return -1;
2315 }
2316 }
2317 return 0;
2318}
2319
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002320#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002321
2322static int curcol;
2323
2324#ifdef __STDC__
2325#include <stdarg.h>
2326#define VA_START(a, b) va_start(a, b)
2327#else
2328#include <varargs.h>
2329#define VA_START(a, b) va_start(a)
2330#endif
2331
2332void
2333#ifdef __STDC__
2334tprintf(const char *fmt, ...)
2335#else
2336tprintf(fmt, va_alist)
2337char *fmt;
2338va_dcl
2339#endif
2340{
2341 va_list args;
2342
2343 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002344 if (outf) {
2345 int n = vfprintf(outf, fmt, args);
2346 if (n < 0 && outf != stderr)
2347 perror(outfname == NULL
2348 ? "<writing to pipe>" : outfname);
2349 else
2350 curcol += n;
2351 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002352 va_end(args);
2353 return;
2354}
2355
2356void
2357printleader(tcp)
2358struct tcb *tcp;
2359{
2360 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2361 tcp_last->flags |= TCB_REPRINT;
2362 tprintf(" <unfinished ...>\n");
2363 }
2364 curcol = 0;
2365 if ((followfork == 1 || pflag_seen > 1) && outfname)
2366 tprintf("%-5d ", tcp->pid);
2367 else if (nprocs > 1 && !outfname)
2368 tprintf("[pid %5u] ", tcp->pid);
2369 if (tflag) {
2370 char str[sizeof("HH:MM:SS")];
2371 struct timeval tv, dtv;
2372 static struct timeval otv;
2373
2374 gettimeofday(&tv, NULL);
2375 if (rflag) {
2376 if (otv.tv_sec == 0)
2377 otv = tv;
2378 tv_sub(&dtv, &tv, &otv);
2379 tprintf("%6ld.%06ld ",
2380 (long) dtv.tv_sec, (long) dtv.tv_usec);
2381 otv = tv;
2382 }
2383 else if (tflag > 2) {
2384 tprintf("%ld.%06ld ",
2385 (long) tv.tv_sec, (long) tv.tv_usec);
2386 }
2387 else {
2388 time_t local = tv.tv_sec;
2389 strftime(str, sizeof(str), "%T", localtime(&local));
2390 if (tflag > 1)
2391 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2392 else
2393 tprintf("%s ", str);
2394 }
2395 }
2396 if (iflag)
2397 printcall(tcp);
2398}
2399
2400void
2401tabto(col)
2402int col;
2403{
2404 if (curcol < col)
2405 tprintf("%*s", col - curcol, "");
2406}
2407
2408void
2409printtrailer(tcp)
2410struct tcb *tcp;
2411{
2412 tprintf("\n");
2413 tcp_last = NULL;
2414}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002415
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002416#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002417
2418int mp_ioctl (int fd, int cmd, void *arg, int size) {
2419
2420 struct iovec iov[2];
2421 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002422
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002423 iov[0].iov_base = &cmd;
2424 iov[0].iov_len = sizeof cmd;
2425 if (arg) {
2426 ++n;
2427 iov[1].iov_base = arg;
2428 iov[1].iov_len = size;
2429 }
Roland McGrath553a6092002-12-16 20:40:39 +00002430
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002431 return writev (fd, iov, n);
2432}
2433
2434#endif