blob: 0da34abe5fbc45dd610b4353a273cae898633584 [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;
Roland McGrath138c6a32006-01-12 09:50:49 +0000202 set_sortby(DEFAULT_SORTBY);
203 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000204 qualify("trace=all");
205 qualify("abbrev=all");
206 qualify("verbose=all");
207 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000208 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);
Roland McGrathdccec722005-05-09 07:45:47 +0000288 if (max_strlen < 0) {
289 fprintf(stderr,
290 "%s: invalid -s argument: %s\n",
291 progname, optarg);
292 exit(1);
293 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000294 break;
295 case 'S':
296 set_sortby(optarg);
297 break;
298 case 'u':
299 username = strdup(optarg);
300 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000301 case 'E':
302 if (putenv(optarg) < 0) {
303 fprintf(stderr, "%s: out of memory\n",
304 progname);
305 exit(1);
306 }
307 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000308 default:
309 usage(stderr, 1);
310 break;
311 }
312 }
313
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000314 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000315 usage(stderr, 1);
316
Roland McGrathcb9def62006-04-25 07:48:03 +0000317 if (followfork > 1 && cflag) {
318 fprintf(stderr,
319 "%s: -c and -ff are mutually exclusive options\n",
320 progname);
321 exit(1);
322 }
323
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000324 /* See if they want to run as another user. */
325 if (username != NULL) {
326 struct passwd *pent;
327
328 if (getuid() != 0 || geteuid() != 0) {
329 fprintf(stderr,
330 "%s: you must be root to use the -u option\n",
331 progname);
332 exit(1);
333 }
334 if ((pent = getpwnam(username)) == NULL) {
335 fprintf(stderr, "%s: cannot find user `%s'\n",
336 progname, optarg);
337 exit(1);
338 }
339 run_uid = pent->pw_uid;
340 run_gid = pent->pw_gid;
341 }
342 else {
343 run_uid = getuid();
344 run_gid = getgid();
345 }
346
347#ifndef SVR4
348 setreuid(geteuid(), getuid());
349#endif
350
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000351 /* Check if they want to redirect the output. */
352 if (outfname) {
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000353 long f;
354
Roland McGrath37b9a662003-11-07 02:26:54 +0000355 /* See if they want to pipe the output. */
356 if (outfname[0] == '|' || outfname[0] == '!') {
357 /*
358 * We can't do the <outfname>.PID funny business
359 * when using popen, so prohibit it.
360 */
361 if (followfork > 1) {
362 fprintf(stderr, "\
363%s: piping the output and -ff are mutually exclusive options\n",
364 progname);
365 exit(1);
366 }
367
368 if ((outf = popen(outfname + 1, "w")) == NULL) {
369 fprintf(stderr, "%s: can't popen '%s': %s\n",
370 progname, outfname + 1,
371 strerror(errno));
372 exit(1);
373 }
374 }
375 else if ((outf = fopen(outfname, "w")) == NULL) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000376 fprintf(stderr, "%s: can't fopen '%s': %s\n",
377 progname, outfname, strerror(errno));
378 exit(1);
379 }
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000380
381 if ((f=fcntl(fileno(outf), F_GETFD)) < 0 ) {
382 perror("failed to get flags for outputfile");
383 exit(1);
384 }
385
386 if (fcntl(fileno(outf), F_SETFD, f|FD_CLOEXEC) < 0 ) {
387 perror("failed to set flags for outputfile");
388 exit(1);
389 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000390 }
391
392#ifndef SVR4
393 setreuid(geteuid(), getuid());
394#endif
395
Roland McGrath37b9a662003-11-07 02:26:54 +0000396 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000397 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000398 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000399 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000400 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000401 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000402
Roland McGrathee9d4352002-12-18 04:16:10 +0000403 for (c = 0; c < tcbtabsize; c++) {
404 tcp = tcbtab[c];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000405 /* Reinitialize the output since it may have changed. */
406 tcp->outf = outf;
407 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
408 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000409#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000410 if (proc_open(tcp, 1) < 0) {
411 fprintf(stderr, "trouble opening proc file\n");
412 droptcb(tcp);
413 continue;
414 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000415#else /* !USE_PROCFS */
Roland McGrath70b08532004-04-09 00:25:21 +0000416# ifdef LINUX
417 if (tcp->flags & TCB_CLONE_THREAD)
418 continue;
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000419 if (followfork) {
Roland McGrath70b08532004-04-09 00:25:21 +0000420 char procdir[MAXPATHLEN];
421 DIR *dir;
422 sprintf(procdir, "/proc/%d/task", tcp->pid);
423 dir = opendir(procdir);
424 if (dir != NULL) {
425 unsigned int ntid = 0, nerr = 0;
426 struct dirent *de;
427 int tid;
428 while ((de = readdir(dir)) != NULL) {
429 if (de->d_fileno == 0 ||
430 de->d_name[0] == '.')
431 continue;
432 tid = atoi(de->d_name);
433 if (tid <= 0)
434 continue;
435 ++ntid;
436 if (ptrace(PTRACE_ATTACH, tid,
437 (char *) 1, 0) < 0)
438 ++nerr;
439 else if (tid != tcbtab[c]->pid) {
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000440 if (nprocs == tcbtabsize &&
441 expand_tcbtab())
442 tcp = NULL;
443 else
444 tcp = alloctcb(tid);
Dmitry V. Levin76860f62006-10-11 22:55:25 +0000445 if (tcp == NULL)
Roland McGrath70b08532004-04-09 00:25:21 +0000446 exit(1);
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000447 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK;
Roland McGrath70b08532004-04-09 00:25:21 +0000448 tcbtab[c]->nchildren++;
449 tcbtab[c]->nclone_threads++;
450 tcbtab[c]->nclone_detached++;
451 tcp->parent = tcbtab[c];
452 }
453 }
454 closedir(dir);
455 if (nerr == ntid) {
456 perror("attach: ptrace(PTRACE_ATTACH, ...)");
457 droptcb(tcp);
458 continue;
459 }
460 if (!qflag) {
461 ntid -= nerr;
462 if (ntid > 1)
463 fprintf(stderr, "\
464Process %u attached with %u threads - interrupt to quit\n",
465 tcp->pid, ntid);
466 else
467 fprintf(stderr, "\
468Process %u attached - interrupt to quit\n",
469 tcp->pid);
470 }
471 continue;
472 }
473 }
474# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000475 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
476 perror("attach: ptrace(PTRACE_ATTACH, ...)");
477 droptcb(tcp);
478 continue;
479 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000480#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000481 if (!qflag)
482 fprintf(stderr,
483 "Process %u attached - interrupt to quit\n",
Roland McGrathc3266d52004-02-20 02:23:52 +0000484 tcp->pid);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000485 }
486
Roland McGrathce0d1542003-11-11 21:24:23 +0000487 if (!pflag_seen) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000488 struct stat statbuf;
489 char *filename;
490 char pathname[MAXPATHLEN];
491
492 filename = argv[optind];
Roland McGrathbdb09df2004-03-02 06:50:04 +0000493 if (strchr(filename, '/')) {
494 if (strlen(filename) > sizeof pathname - 1) {
495 errno = ENAMETOOLONG;
496 perror("strace: exec");
497 exit(1);
498 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000499 strcpy(pathname, filename);
Roland McGrathbdb09df2004-03-02 06:50:04 +0000500 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000501#ifdef USE_DEBUGGING_EXEC
502 /*
503 * Debuggers customarily check the current directory
504 * first regardless of the path but doing that gives
505 * security geeks a panic attack.
506 */
507 else if (stat(filename, &statbuf) == 0)
508 strcpy(pathname, filename);
509#endif /* USE_DEBUGGING_EXEC */
510 else {
511 char *path;
512 int m, n, len;
513
514 for (path = getenv("PATH"); path && *path; path += m) {
515 if (strchr(path, ':')) {
516 n = strchr(path, ':') - path;
517 m = n + 1;
518 }
519 else
520 m = n = strlen(path);
521 if (n == 0) {
522 getcwd(pathname, MAXPATHLEN);
523 len = strlen(pathname);
524 }
Roland McGrathbdb09df2004-03-02 06:50:04 +0000525 else if (n > sizeof pathname - 1)
526 continue;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000527 else {
528 strncpy(pathname, path, n);
529 len = n;
530 }
531 if (len && pathname[len - 1] != '/')
532 pathname[len++] = '/';
533 strcpy(pathname + len, filename);
Roland McGrathed645162003-06-03 07:18:19 +0000534 if (stat(pathname, &statbuf) == 0 &&
535 /* Accept only regular files
536 with some execute bits set.
537 XXX not perfect, might still fail */
538 S_ISREG(statbuf.st_mode) &&
539 (statbuf.st_mode & 0111))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000540 break;
541 }
542 }
543 if (stat(pathname, &statbuf) < 0) {
544 fprintf(stderr, "%s: %s: command not found\n",
545 progname, filename);
546 exit(1);
547 }
548 switch (pid = fork()) {
549 case -1:
550 perror("strace: fork");
551 cleanup();
552 exit(1);
553 break;
554 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000555#ifdef USE_PROCFS
556 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000557#ifdef MIPS
558 /* Kludge for SGI, see proc_open for details. */
559 sa.sa_handler = foobar;
560 sa.sa_flags = 0;
561 sigemptyset(&sa.sa_mask);
562 sigaction(SIGINT, &sa, NULL);
563#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000564#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000565 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000566#else /* FREEBSD */
567 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000568#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000569#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000570 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000571 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000572
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000573 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
574 perror("strace: ptrace(PTRACE_TRACEME, ...)");
575 return -1;
576 }
577 if (debug)
578 kill(getpid(), SIGSTOP);
579
580 if (username != NULL || geteuid() == 0) {
581 uid_t run_euid = run_uid;
582 gid_t run_egid = run_gid;
583
584 if (statbuf.st_mode & S_ISUID)
585 run_euid = statbuf.st_uid;
586 if (statbuf.st_mode & S_ISGID)
587 run_egid = statbuf.st_gid;
588
589 /*
590 * It is important to set groups before we
591 * lose privileges on setuid.
592 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000593 if (username != NULL) {
594 if (initgroups(username, run_gid) < 0) {
595 perror("initgroups");
596 exit(1);
597 }
598 if (setregid(run_gid, run_egid) < 0) {
599 perror("setregid");
600 exit(1);
601 }
602 if (setreuid(run_uid, run_euid) < 0) {
603 perror("setreuid");
604 exit(1);
605 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000606 }
607 }
608 else
609 setreuid(run_uid, run_uid);
Roland McGrath15dca8e2005-02-06 01:16:32 +0000610
611 /*
612 * Induce an immediate stop so that the parent
613 * will resume us with PTRACE_SYSCALL and display
614 * this execve call normally.
615 */
616 kill(getpid(), SIGSTOP);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000617#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000618
619 execv(pathname, &argv[optind]);
620 perror("strace: exec");
621 _exit(1);
622 break;
623 }
624 default:
625 if ((tcp = alloctcb(pid)) == NULL) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000626 cleanup();
627 exit(1);
628 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000629#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630 if (proc_open(tcp, 0) < 0) {
631 fprintf(stderr, "trouble opening proc file\n");
632 cleanup();
633 exit(1);
634 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000635#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000636 break;
637 }
638 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000639
640 sigemptyset(&empty_set);
641 sigemptyset(&blocked_set);
642 sa.sa_handler = SIG_IGN;
643 sigemptyset(&sa.sa_mask);
644 sa.sa_flags = 0;
645 sigaction(SIGTTOU, &sa, NULL);
646 sigaction(SIGTTIN, &sa, NULL);
647 if (interactive) {
648 sigaddset(&blocked_set, SIGHUP);
649 sigaddset(&blocked_set, SIGINT);
650 sigaddset(&blocked_set, SIGQUIT);
651 sigaddset(&blocked_set, SIGPIPE);
652 sigaddset(&blocked_set, SIGTERM);
653 sa.sa_handler = interrupt;
654#ifdef SUNOS4
655 /* POSIX signals on sunos4.1 are a little broken. */
656 sa.sa_flags = SA_INTERRUPT;
657#endif /* SUNOS4 */
658 }
659 sigaction(SIGHUP, &sa, NULL);
660 sigaction(SIGINT, &sa, NULL);
661 sigaction(SIGQUIT, &sa, NULL);
662 sigaction(SIGPIPE, &sa, NULL);
663 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000664#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000665 sa.sa_handler = reaper;
666 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000667#else
668 /* Make sure SIGCHLD has the default action so that waitpid
669 definitely works without losing track of children. The user
670 should not have given us a bogus state to inherit, but he might
671 have. Arguably we should detect SIG_IGN here and pass it on
672 to children, but probably noone really needs that. */
673 sa.sa_handler = SIG_DFL;
674 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000675#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000676
677 if (trace() < 0)
678 exit(1);
679 cleanup();
680 exit(0);
681}
682
683void
684newoutf(tcp)
685struct tcb *tcp;
686{
687 char name[MAXPATHLEN];
688 FILE *fp;
689
690 if (outfname && followfork > 1) {
691 sprintf(name, "%s.%u", outfname, tcp->pid);
692#ifndef SVR4
693 setreuid(geteuid(), getuid());
694#endif
695 fp = fopen(name, "w");
696#ifndef SVR4
697 setreuid(geteuid(), getuid());
698#endif
699 if (fp == NULL) {
700 perror("fopen");
701 return;
702 }
703 tcp->outf = fp;
704 }
705 return;
706}
707
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000708int
709expand_tcbtab()
710{
711 /* Allocate some more TCBs and expand the table.
712 We don't want to relocate the TCBs because our
713 callers have pointers and it would be a pain.
714 So tcbtab is a table of pointers. Since we never
715 free the TCBs, we allocate a single chunk of many. */
716 struct tcb **newtab = (struct tcb **)
717 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
718 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
719 sizeof *newtcbs);
720 int i;
721 if (newtab == NULL || newtcbs == NULL) {
722 if (newtab != NULL)
723 free(newtab);
Dmitry V. Levin76860f62006-10-11 22:55:25 +0000724 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
725 progname);
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000726 return 1;
727 }
728 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
729 newtab[i] = &newtcbs[i - tcbtabsize];
730 tcbtabsize *= 2;
731 tcbtab = newtab;
732
733 return 0;
734}
735
736
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000737struct tcb *
738alloctcb(pid)
739int pid;
740{
741 int i;
742 struct tcb *tcp;
743
Roland McGrathee9d4352002-12-18 04:16:10 +0000744 for (i = 0; i < tcbtabsize; i++) {
745 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746 if ((tcp->flags & TCB_INUSE) == 0) {
747 tcp->pid = pid;
748 tcp->parent = NULL;
749 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000750 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000751#ifdef TCB_CLONE_THREAD
752 tcp->nclone_threads = tcp->nclone_detached = 0;
753 tcp->nclone_waiting = 0;
754#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000755 tcp->flags = TCB_INUSE | TCB_STARTUP;
756 tcp->outf = outf; /* Initialise to current out file */
757 tcp->stime.tv_sec = 0;
758 tcp->stime.tv_usec = 0;
759 tcp->pfd = -1;
760 nprocs++;
761 return tcp;
762 }
763 }
Dmitry V. Levin76860f62006-10-11 22:55:25 +0000764 fprintf(stderr, "%s: alloctcb: tcb table full\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000765 return NULL;
766}
767
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000768#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000769int
770proc_open(tcp, attaching)
771struct tcb *tcp;
772int attaching;
773{
774 char proc[32];
775 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000776#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000777 int i;
778 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000779 sigset_t signals;
780 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000781#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000782#ifndef HAVE_POLLABLE_PROCFS
783 static int last_pfd;
784#endif
785
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000786#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000787 /* Open the process pseudo-files in /proc. */
788 sprintf(proc, "/proc/%d/ctl", tcp->pid);
789 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000790 perror("strace: open(\"/proc/...\", ...)");
791 return -1;
792 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000793 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
794 perror("F_GETFD");
795 return -1;
796 }
797 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
798 perror("F_SETFD");
799 return -1;
800 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000801 sprintf(proc, "/proc/%d/status", tcp->pid);
802 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
803 perror("strace: open(\"/proc/...\", ...)");
804 return -1;
805 }
806 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
807 perror("F_GETFD");
808 return -1;
809 }
810 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
811 perror("F_SETFD");
812 return -1;
813 }
814 sprintf(proc, "/proc/%d/as", tcp->pid);
815 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
816 perror("strace: open(\"/proc/...\", ...)");
817 return -1;
818 }
819 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
820 perror("F_GETFD");
821 return -1;
822 }
823 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
824 perror("F_SETFD");
825 return -1;
826 }
827#else
828 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000829#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000830 sprintf(proc, "/proc/%d", tcp->pid);
831 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000832#else /* FREEBSD */
833 sprintf(proc, "/proc/%d/mem", tcp->pid);
834 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
835#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000836 perror("strace: open(\"/proc/...\", ...)");
837 return -1;
838 }
839 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
840 perror("F_GETFD");
841 return -1;
842 }
843 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
844 perror("F_SETFD");
845 return -1;
846 }
847#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000848#ifdef FREEBSD
849 sprintf(proc, "/proc/%d/regs", tcp->pid);
850 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
851 perror("strace: open(\"/proc/.../regs\", ...)");
852 return -1;
853 }
854 if (cflag) {
855 sprintf(proc, "/proc/%d/status", tcp->pid);
856 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
857 perror("strace: open(\"/proc/.../status\", ...)");
858 return -1;
859 }
860 } else
861 tcp->pfd_status = -1;
862#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000863 rebuild_pollv();
864 if (!attaching) {
865 /*
866 * Wait for the child to pause. Because of a race
867 * condition we have to poll for the event.
868 */
869 for (;;) {
870 if (IOCTL_STATUS (tcp) < 0) {
871 perror("strace: PIOCSTATUS");
872 return -1;
873 }
874 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000875 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000876 }
877 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000878#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000879 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000880 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000881 perror("strace: PIOCSTOP");
882 return -1;
883 }
Roland McGrath553a6092002-12-16 20:40:39 +0000884#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000885#ifdef PIOCSET
886 /* Set Run-on-Last-Close. */
887 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000888 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000889 perror("PIOCSET PR_RLC");
890 return -1;
891 }
892 /* Set or Reset Inherit-on-Fork. */
893 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000894 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000895 perror("PIOC{SET,RESET} PR_FORK");
896 return -1;
897 }
898#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000899#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000900 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
901 perror("PIOCSRLC");
902 return -1;
903 }
904 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
905 perror("PIOC{S,R}FORK");
906 return -1;
907 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000908#else /* FREEBSD */
909 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
910 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
911 perror("PIOCGFL");
912 return -1;
913 }
914 arg &= ~PF_LINGER;
915 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
916 perror("PIOCSFL");
917 return -1;
918 }
919#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000920#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000921#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000922 /* Enable all syscall entries we care about. */
923 premptyset(&syscalls);
924 for (i = 1; i < MAX_QUALS; ++i) {
925 if (i > (sizeof syscalls) * CHAR_BIT) break;
926 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
927 }
928 praddset (&syscalls, SYS_execve);
929 if (followfork) {
930 praddset (&syscalls, SYS_fork);
931#ifdef SYS_forkall
932 praddset (&syscalls, SYS_forkall);
933#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000934#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000935 praddset (&syscalls, SYS_fork1);
936#endif
937#ifdef SYS_rfork1
938 praddset (&syscalls, SYS_rfork1);
939#endif
940#ifdef SYS_rforkall
941 praddset (&syscalls, SYS_rforkall);
942#endif
943 }
944 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000945 perror("PIOCSENTRY");
946 return -1;
947 }
John Hughes19e49982001-10-19 08:59:12 +0000948 /* Enable the syscall exits. */
949 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000950 perror("PIOSEXIT");
951 return -1;
952 }
John Hughes19e49982001-10-19 08:59:12 +0000953 /* Enable signals we care about. */
954 premptyset(&signals);
955 for (i = 1; i < MAX_QUALS; ++i) {
956 if (i > (sizeof signals) * CHAR_BIT) break;
957 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
958 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000959 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000960 perror("PIOCSTRACE");
961 return -1;
962 }
John Hughes19e49982001-10-19 08:59:12 +0000963 /* Enable faults we care about */
964 premptyset(&faults);
965 for (i = 1; i < MAX_QUALS; ++i) {
966 if (i > (sizeof faults) * CHAR_BIT) break;
967 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
968 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000969 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000970 perror("PIOCSFAULT");
971 return -1;
972 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000973#else /* FREEBSD */
974 /* set events flags. */
975 arg = S_SIG | S_SCE | S_SCX ;
976 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
977 perror("PIOCBIS");
978 return -1;
979 }
980#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000981 if (!attaching) {
982#ifdef MIPS
983 /*
984 * The SGI PRSABORT doesn't work for pause() so
985 * we send it a caught signal to wake it up.
986 */
987 kill(tcp->pid, SIGINT);
988#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000989#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000990 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000991 arg = PRSABORT;
992 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000993 perror("PIOCRUN");
994 return -1;
995 }
Roland McGrath553a6092002-12-16 20:40:39 +0000996#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000997#endif /* !MIPS*/
998#ifdef FREEBSD
999 /* wake up the child if it received the SIGSTOP */
1000 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001001#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001002 for (;;) {
1003 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001004 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001005 perror("PIOCWSTOP");
1006 return -1;
1007 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001008 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001009 tcp->flags &= ~TCB_INSYSCALL;
1010 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001011 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001012 break;
1013 }
1014 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001015#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001016 arg = 0;
1017 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001018#else /* FREEBSD */
1019 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001020#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001021 perror("PIOCRUN");
1022 return -1;
1023 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001024#ifdef FREEBSD
1025 /* handle the case where we "opened" the child before
1026 it did the kill -STOP */
1027 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1028 tcp->status.PR_WHAT == SIGSTOP)
1029 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001030#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001031 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001032#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001034#else /* FREEBSD */
1035 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001036 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001037 /* We are attaching to an already running process.
1038 * Try to figure out the state of the process in syscalls,
1039 * to handle the first event well.
1040 * This is done by having a look at the "wchan" property of the
1041 * process, which tells where it is stopped (if it is). */
1042 FILE * status;
1043 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001044
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001045 sprintf(proc, "/proc/%d/status", tcp->pid);
1046 status = fopen(proc, "r");
1047 if (status &&
1048 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1049 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1050 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1051 strcmp(wchan, "stopevent")) {
1052 /* The process is asleep in the middle of a syscall.
1053 Fake the syscall entry event */
1054 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1055 tcp->status.PR_WHY = PR_SYSENTRY;
1056 trace_syscall(tcp);
1057 }
1058 if (status)
1059 fclose(status);
1060 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001061 }
1062#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063#ifndef HAVE_POLLABLE_PROCFS
1064 if (proc_poll_pipe[0] != -1)
1065 proc_poller(tcp->pfd);
1066 else if (nprocs > 1) {
1067 proc_poll_open();
1068 proc_poller(last_pfd);
1069 proc_poller(tcp->pfd);
1070 }
1071 last_pfd = tcp->pfd;
1072#endif /* !HAVE_POLLABLE_PROCFS */
1073 return 0;
1074}
1075
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001076#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001077
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001078struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001079pid2tcb(pid)
1080int pid;
1081{
1082 int i;
1083 struct tcb *tcp;
1084
Roland McGrathee9d4352002-12-18 04:16:10 +00001085 for (i = 0; i < tcbtabsize; i++) {
1086 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001087 if (pid && tcp->pid != pid)
1088 continue;
1089 if (tcp->flags & TCB_INUSE)
1090 return tcp;
1091 }
1092 return NULL;
1093}
1094
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001095#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001096
1097static struct tcb *
1098pfd2tcb(pfd)
1099int pfd;
1100{
1101 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102
Roland McGrathca16be82003-01-10 19:55:28 +00001103 for (i = 0; i < tcbtabsize; i++) {
1104 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001105 if (tcp->pfd != pfd)
1106 continue;
1107 if (tcp->flags & TCB_INUSE)
1108 return tcp;
1109 }
1110 return NULL;
1111}
1112
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001113#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114
1115void
1116droptcb(tcp)
1117struct tcb *tcp;
1118{
1119 if (tcp->pid == 0)
1120 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001121#ifdef TCB_CLONE_THREAD
1122 if (tcp->nclone_threads > 0) {
1123 /* There are other threads left in this process, but this
1124 is the one whose PID represents the whole process.
1125 We need to keep this record around as a zombie until
1126 all the threads die. */
1127 tcp->flags |= TCB_EXITING;
1128 return;
1129 }
1130#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 nprocs--;
1132 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001133
Roland McGrathe29341c2003-01-10 20:14:20 +00001134 if (tcp->parent != NULL) {
1135 tcp->parent->nchildren--;
1136#ifdef TCB_CLONE_THREAD
1137 if (tcp->flags & TCB_CLONE_DETACHED)
1138 tcp->parent->nclone_detached--;
1139 if (tcp->flags & TCB_CLONE_THREAD)
1140 tcp->parent->nclone_threads--;
1141#endif
Roland McGrath09623452003-05-23 02:27:13 +00001142#ifdef TCB_CLONE_DETACHED
1143 if (!(tcp->flags & TCB_CLONE_DETACHED))
1144#endif
1145 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001146 tcp->parent = NULL;
1147 }
1148
1149 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001150 if (tcp->pfd != -1) {
1151 close(tcp->pfd);
1152 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001153#ifdef FREEBSD
1154 if (tcp->pfd_reg != -1) {
1155 close(tcp->pfd_reg);
1156 tcp->pfd_reg = -1;
1157 }
1158 if (tcp->pfd_status != -1) {
1159 close(tcp->pfd_status);
1160 tcp->pfd_status = -1;
1161 }
Roland McGrath553a6092002-12-16 20:40:39 +00001162#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001163#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001164 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165#endif
1166 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001167
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001168 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001169 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001170
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001171 tcp->outf = 0;
1172}
1173
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001174#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001175
1176static int
1177resume(tcp)
1178struct tcb *tcp;
1179{
1180 if (tcp == NULL)
1181 return -1;
1182
1183 if (!(tcp->flags & TCB_SUSPENDED)) {
1184 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1185 return -1;
1186 }
1187 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001188#ifdef TCB_CLONE_THREAD
1189 if (tcp->flags & TCB_CLONE_THREAD)
1190 tcp->parent->nclone_waiting--;
1191#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001192
1193 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1194 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1195 return -1;
1196 }
1197
1198 if (!qflag)
1199 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1200 return 0;
1201}
1202
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001203#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001204
1205/* detach traced process; continue with sig */
1206
1207static int
1208detach(tcp, sig)
1209struct tcb *tcp;
1210int sig;
1211{
1212 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001213#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001214 int status, resumed;
Roland McGratha08a97e2005-08-03 11:23:46 +00001215 struct tcb *zombie = NULL;
1216
1217 /* If the group leader is lingering only because of this other
1218 thread now dying, then detach the leader as well. */
1219 if ((tcp->flags & TCB_CLONE_THREAD) &&
1220 tcp->parent->nclone_threads == 1 &&
1221 (tcp->parent->flags & TCB_EXITING))
1222 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001223#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224
1225 if (tcp->flags & TCB_BPTSET)
1226 sig = SIGKILL;
1227
1228#ifdef LINUX
1229 /*
1230 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001231 * before detaching. Arghh. We go through hoops
1232 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001233 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001234#if defined(SPARC)
1235#undef PTRACE_DETACH
1236#define PTRACE_DETACH PTRACE_SUNDETACH
1237#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001238 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1239 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001240 }
1241 else if (errno != ESRCH) {
1242 /* Shouldn't happen. */
1243 perror("detach: ptrace(PTRACE_DETACH, ...)");
1244 }
1245 else if (kill(tcp->pid, 0) < 0) {
1246 if (errno != ESRCH)
1247 perror("detach: checking sanity");
1248 }
1249 else if (kill(tcp->pid, SIGSTOP) < 0) {
1250 if (errno != ESRCH)
1251 perror("detach: stopping child");
1252 }
1253 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001254 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001255#ifdef __WALL
1256 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1257 if (errno == ECHILD) /* Already gone. */
1258 break;
1259 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001260 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001261 break;
1262 }
1263#endif /* __WALL */
1264 /* No __WALL here. */
1265 if (waitpid(tcp->pid, &status, 0) < 0) {
1266 if (errno != ECHILD) {
1267 perror("detach: waiting");
1268 break;
1269 }
1270#ifdef __WCLONE
1271 /* If no processes, try clones. */
1272 if (wait4(tcp->pid, &status, __WCLONE,
1273 NULL) < 0) {
1274 if (errno != ECHILD)
1275 perror("detach: waiting");
1276 break;
1277 }
1278#endif /* __WCLONE */
1279 }
1280#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001281 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001282#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001283 if (!WIFSTOPPED(status)) {
1284 /* Au revoir, mon ami. */
1285 break;
1286 }
1287 if (WSTOPSIG(status) == SIGSTOP) {
1288 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001289 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001290 if (errno != ESRCH)
1291 perror("detach: ptrace(PTRACE_DETACH, ...)");
1292 /* I died trying. */
1293 }
1294 break;
1295 }
1296 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001297 WSTOPSIG(status) == SIGTRAP ?
1298 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001299 if (errno != ESRCH)
1300 perror("detach: ptrace(PTRACE_CONT, ...)");
1301 break;
1302 }
1303 }
1304 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001305#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001306
1307#if defined(SUNOS4)
1308 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1309 if (sig && kill(tcp->pid, sig) < 0)
1310 perror("detach: kill");
1311 sig = 0;
1312 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1313 perror("detach: ptrace(PTRACE_DETACH, ...)");
1314#endif /* SUNOS4 */
1315
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001316#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001317 resumed = 0;
1318
1319 /* XXX This won't always be quite right (but it never was).
1320 A waiter with argument 0 or < -1 is waiting for any pid in
1321 a particular pgrp, which this child might or might not be
1322 in. The waiter will only wake up if it's argument is -1
1323 or if it's waiting for tcp->pid's pgrp. It makes a
1324 difference to wake up a waiter when there might be more
1325 traced children, because it could get a false ECHILD
1326 error. OTOH, if this was the last child in the pgrp, then
1327 it ought to wake up and get ECHILD. We would have to
1328 search the system for all pid's in the pgrp to be sure.
1329
1330 && (t->waitpid == -1 ||
1331 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1332 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1333 */
1334
1335 if (tcp->parent &&
1336 (tcp->parent->flags & TCB_SUSPENDED) &&
1337 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1338 error = resume(tcp->parent);
1339 ++resumed;
1340 }
1341#ifdef TCB_CLONE_THREAD
1342 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1343 /* Some other threads of our parent are waiting too. */
1344 unsigned int i;
1345
1346 /* Resume all the threads that were waiting for this PID. */
1347 for (i = 0; i < tcbtabsize; i++) {
1348 struct tcb *t = tcbtab[i];
1349 if (t->parent == tcp->parent && t != tcp
1350 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1351 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1352 && t->waitpid == tcp->pid) {
1353 error |= resume (t);
1354 ++resumed;
1355 }
1356 }
1357 if (resumed == 0)
1358 /* Noone was waiting for this PID in particular,
1359 so now we might need to resume some wildcarders. */
1360 for (i = 0; i < tcbtabsize; i++) {
1361 struct tcb *t = tcbtab[i];
1362 if (t->parent == tcp->parent && t != tcp
1363 && ((t->flags
1364 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1365 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1366 && t->waitpid <= 0
1367 ) {
1368 error |= resume (t);
1369 break;
1370 }
1371 }
1372 }
1373#endif
1374
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001375#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376
1377 if (!qflag)
1378 fprintf(stderr, "Process %u detached\n", tcp->pid);
1379
1380 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001381
1382#ifdef LINUX
1383 if (zombie != NULL)
1384 error = detach(zombie) || error;
1385#endif
1386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001387 return error;
1388}
1389
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001390#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001391
1392static void
1393reaper(sig)
1394int sig;
1395{
1396 int pid;
1397 int status;
1398
1399 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1400#if 0
1401 struct tcb *tcp;
1402
1403 tcp = pid2tcb(pid);
1404 if (tcp)
1405 droptcb(tcp);
1406#endif
1407 }
1408}
1409
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001410#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001411
1412static void
1413cleanup()
1414{
1415 int i;
1416 struct tcb *tcp;
1417
Roland McGrathee9d4352002-12-18 04:16:10 +00001418 for (i = 0; i < tcbtabsize; i++) {
1419 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001420 if (!(tcp->flags & TCB_INUSE))
1421 continue;
1422 if (debug)
1423 fprintf(stderr,
1424 "cleanup: looking at pid %u\n", tcp->pid);
1425 if (tcp_last &&
1426 (!outfname || followfork < 2 || tcp_last == tcp)) {
1427 tprintf(" <unfinished ...>\n");
1428 tcp_last = NULL;
1429 }
1430 if (tcp->flags & TCB_ATTACHED)
1431 detach(tcp, 0);
1432 else {
1433 kill(tcp->pid, SIGCONT);
1434 kill(tcp->pid, SIGTERM);
1435 }
1436 }
1437 if (cflag)
1438 call_summary(outf);
1439}
1440
1441static void
1442interrupt(sig)
1443int sig;
1444{
1445 interrupted = 1;
1446}
1447
1448#ifndef HAVE_STRERROR
1449
Roland McGrath6d2b3492002-12-30 00:51:30 +00001450#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001451extern int sys_nerr;
1452extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001453#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001454
1455const char *
1456strerror(errno)
1457int errno;
1458{
1459 static char buf[64];
1460
1461 if (errno < 1 || errno >= sys_nerr) {
1462 sprintf(buf, "Unknown error %d", errno);
1463 return buf;
1464 }
1465 return sys_errlist[errno];
1466}
1467
1468#endif /* HAVE_STERRROR */
1469
1470#ifndef HAVE_STRSIGNAL
1471
Roland McGrath8f474e02003-01-14 07:53:33 +00001472#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001473extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001474#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001475#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1476extern char *_sys_siglist[];
1477#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001478
1479const char *
1480strsignal(sig)
1481int sig;
1482{
1483 static char buf[64];
1484
1485 if (sig < 1 || sig >= NSIG) {
1486 sprintf(buf, "Unknown signal %d", sig);
1487 return buf;
1488 }
1489#ifdef HAVE__SYS_SIGLIST
1490 return _sys_siglist[sig];
1491#else
1492 return sys_siglist[sig];
1493#endif
1494}
1495
1496#endif /* HAVE_STRSIGNAL */
1497
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001498#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001499
1500static void
1501rebuild_pollv()
1502{
1503 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001504
Roland McGrathee9d4352002-12-18 04:16:10 +00001505 if (pollv != NULL)
1506 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001507 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001508 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001509 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001510 exit(1);
1511 }
1512
Roland McGrathca16be82003-01-10 19:55:28 +00001513 for (i = j = 0; i < tcbtabsize; i++) {
1514 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001515 if (!(tcp->flags & TCB_INUSE))
1516 continue;
1517 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001518 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001519 j++;
1520 }
1521 if (j != nprocs) {
1522 fprintf(stderr, "strace: proc miscount\n");
1523 exit(1);
1524 }
1525}
1526
1527#ifndef HAVE_POLLABLE_PROCFS
1528
1529static void
1530proc_poll_open()
1531{
1532 int arg;
1533 int i;
1534
1535 if (pipe(proc_poll_pipe) < 0) {
1536 perror("pipe");
1537 exit(1);
1538 }
1539 for (i = 0; i < 2; i++) {
1540 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1541 perror("F_GETFD");
1542 exit(1);
1543 }
1544 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1545 perror("F_SETFD");
1546 exit(1);
1547 }
1548 }
1549}
1550
1551static int
1552proc_poll(pollv, nfds, timeout)
1553struct pollfd *pollv;
1554int nfds;
1555int timeout;
1556{
1557 int i;
1558 int n;
1559 struct proc_pollfd pollinfo;
1560
1561 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1562 return n;
1563 if (n != sizeof(struct proc_pollfd)) {
1564 fprintf(stderr, "panic: short read: %d\n", n);
1565 exit(1);
1566 }
1567 for (i = 0; i < nprocs; i++) {
1568 if (pollv[i].fd == pollinfo.fd)
1569 pollv[i].revents = pollinfo.revents;
1570 else
1571 pollv[i].revents = 0;
1572 }
1573 poller_pid = pollinfo.pid;
1574 return 1;
1575}
1576
1577static void
1578wakeup_handler(sig)
1579int sig;
1580{
1581}
1582
1583static void
1584proc_poller(pfd)
1585int pfd;
1586{
1587 struct proc_pollfd pollinfo;
1588 struct sigaction sa;
1589 sigset_t blocked_set, empty_set;
1590 int i;
1591 int n;
1592 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001593#ifdef FREEBSD
1594 struct procfs_status pfs;
1595#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001596
1597 switch (fork()) {
1598 case -1:
1599 perror("fork");
1600 _exit(0);
1601 case 0:
1602 break;
1603 default:
1604 return;
1605 }
1606
1607 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1608 sa.sa_flags = 0;
1609 sigemptyset(&sa.sa_mask);
1610 sigaction(SIGHUP, &sa, NULL);
1611 sigaction(SIGINT, &sa, NULL);
1612 sigaction(SIGQUIT, &sa, NULL);
1613 sigaction(SIGPIPE, &sa, NULL);
1614 sigaction(SIGTERM, &sa, NULL);
1615 sa.sa_handler = wakeup_handler;
1616 sigaction(SIGUSR1, &sa, NULL);
1617 sigemptyset(&blocked_set);
1618 sigaddset(&blocked_set, SIGUSR1);
1619 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1620 sigemptyset(&empty_set);
1621
1622 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1623 perror("getrlimit(RLIMIT_NOFILE, ...)");
1624 _exit(0);
1625 }
1626 n = rl.rlim_cur;
1627 for (i = 0; i < n; i++) {
1628 if (i != pfd && i != proc_poll_pipe[1])
1629 close(i);
1630 }
1631
1632 pollinfo.fd = pfd;
1633 pollinfo.pid = getpid();
1634 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001635#ifndef FREEBSD
1636 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1637#else /* FREEBSD */
1638 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1639#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001640 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001641 switch (errno) {
1642 case EINTR:
1643 continue;
1644 case EBADF:
1645 pollinfo.revents = POLLERR;
1646 break;
1647 case ENOENT:
1648 pollinfo.revents = POLLHUP;
1649 break;
1650 default:
1651 perror("proc_poller: PIOCWSTOP");
1652 }
1653 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1654 _exit(0);
1655 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001656 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1658 sigsuspend(&empty_set);
1659 }
1660}
1661
1662#endif /* !HAVE_POLLABLE_PROCFS */
1663
1664static int
1665choose_pfd()
1666{
1667 int i, j;
1668 struct tcb *tcp;
1669
1670 static int last;
1671
1672 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001673 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001674 /*
1675 * The previous process is ready to run again. We'll
1676 * let it do so if it is currently in a syscall. This
1677 * heuristic improves the readability of the trace.
1678 */
1679 tcp = pfd2tcb(pollv[last].fd);
1680 if (tcp && (tcp->flags & TCB_INSYSCALL))
1681 return pollv[last].fd;
1682 }
1683
1684 for (i = 0; i < nprocs; i++) {
1685 /* Let competing children run round robin. */
1686 j = (i + last + 1) % nprocs;
1687 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1688 tcp = pfd2tcb(pollv[j].fd);
1689 if (!tcp) {
1690 fprintf(stderr, "strace: lost proc\n");
1691 exit(1);
1692 }
1693 droptcb(tcp);
1694 return -1;
1695 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001696 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001697 last = j;
1698 return pollv[j].fd;
1699 }
1700 }
1701 fprintf(stderr, "strace: nothing ready\n");
1702 exit(1);
1703}
1704
1705static int
1706trace()
1707{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001708#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001709 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001710#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001711 struct tcb *tcp;
1712 int pfd;
1713 int what;
1714 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001715 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716
1717 for (;;) {
1718 if (interactive)
1719 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1720
1721 if (nprocs == 0)
1722 break;
1723
1724 switch (nprocs) {
1725 case 1:
1726#ifndef HAVE_POLLABLE_PROCFS
1727 if (proc_poll_pipe[0] == -1) {
1728#endif
1729 tcp = pid2tcb(0);
1730 if (!tcp)
1731 continue;
1732 pfd = tcp->pfd;
1733 if (pfd == -1)
1734 continue;
1735 break;
1736#ifndef HAVE_POLLABLE_PROCFS
1737 }
1738 /* fall through ... */
1739#endif /* !HAVE_POLLABLE_PROCFS */
1740 default:
1741#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001742#ifdef POLL_HACK
1743 /* On some systems (e.g. UnixWare) we get too much ugly
1744 "unfinished..." stuff when multiple proceses are in
1745 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001746
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001747 if (in_syscall) {
1748 struct pollfd pv;
1749 tcp = in_syscall;
1750 in_syscall = NULL;
1751 pv.fd = tcp->pfd;
1752 pv.events = POLLWANT;
1753 if ((what = poll (&pv, 1, 1)) < 0) {
1754 if (interrupted)
1755 return 0;
1756 continue;
1757 }
1758 else if (what == 1 && pv.revents & POLLWANT) {
1759 goto FOUND;
1760 }
1761 }
1762#endif
1763
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764 if (poll(pollv, nprocs, INFTIM) < 0) {
1765 if (interrupted)
1766 return 0;
1767 continue;
1768 }
1769#else /* !HAVE_POLLABLE_PROCFS */
1770 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1771 if (interrupted)
1772 return 0;
1773 continue;
1774 }
1775#endif /* !HAVE_POLLABLE_PROCFS */
1776 pfd = choose_pfd();
1777 if (pfd == -1)
1778 continue;
1779 break;
1780 }
1781
1782 /* Look up `pfd' in our table. */
1783 if ((tcp = pfd2tcb(pfd)) == NULL) {
1784 fprintf(stderr, "unknown pfd: %u\n", pfd);
1785 exit(1);
1786 }
John Hughesb6643082002-05-23 11:02:22 +00001787#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001788 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001789#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001790 /* Get the status of the process. */
1791 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001792#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001793 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001794#else /* FREEBSD */
1795 /* Thanks to some scheduling mystery, the first poller
1796 sometimes waits for the already processed end of fork
1797 event. Doing a non blocking poll here solves the problem. */
1798 if (proc_poll_pipe[0] != -1)
1799 ioctl_result = IOCTL_STATUS (tcp);
1800 else
1801 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001802#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001803 ioctl_errno = errno;
1804#ifndef HAVE_POLLABLE_PROCFS
1805 if (proc_poll_pipe[0] != -1) {
1806 if (ioctl_result < 0)
1807 kill(poller_pid, SIGKILL);
1808 else
1809 kill(poller_pid, SIGUSR1);
1810 }
1811#endif /* !HAVE_POLLABLE_PROCFS */
1812 }
1813 if (interrupted)
1814 return 0;
1815
1816 if (interactive)
1817 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1818
1819 if (ioctl_result < 0) {
1820 /* Find out what happened if it failed. */
1821 switch (ioctl_errno) {
1822 case EINTR:
1823 case EBADF:
1824 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001825#ifdef FREEBSD
1826 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001827#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001828 case ENOENT:
1829 droptcb(tcp);
1830 continue;
1831 default:
1832 perror("PIOCWSTOP");
1833 exit(1);
1834 }
1835 }
1836
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001837#ifdef FREEBSD
1838 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1839 /* discard first event for a syscall we never entered */
1840 IOCTL (tcp->pfd, PIOCRUN, 0);
1841 continue;
1842 }
Roland McGrath553a6092002-12-16 20:40:39 +00001843#endif
1844
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001845 /* clear the just started flag */
1846 tcp->flags &= ~TCB_STARTUP;
1847
1848 /* set current output file */
1849 outf = tcp->outf;
1850
1851 if (cflag) {
1852 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001853#ifdef FREEBSD
1854 char buf[1024];
1855 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001856
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001857 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1858 buf[len] = '\0';
1859 sscanf(buf,
1860 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1861 &stime.tv_sec, &stime.tv_usec);
1862 } else
1863 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001864#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001865 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1866 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001867#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001868 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1869 tcp->stime = stime;
1870 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001871 what = tcp->status.PR_WHAT;
1872 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001873#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001874 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001875 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1876 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001877 if (trace_syscall(tcp) < 0) {
1878 fprintf(stderr, "syscall trouble\n");
1879 exit(1);
1880 }
1881 }
1882 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001883#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001884 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001885#ifdef POLL_HACK
1886 in_syscall = tcp;
1887#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001888 case PR_SYSEXIT:
1889 if (trace_syscall(tcp) < 0) {
1890 fprintf(stderr, "syscall trouble\n");
1891 exit(1);
1892 }
1893 break;
1894 case PR_SIGNALLED:
1895 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1896 printleader(tcp);
1897 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001898 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001899 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001900#ifdef PR_INFO
1901 if (tcp->status.PR_INFO.si_signo == what) {
1902 printleader(tcp);
1903 tprintf(" siginfo=");
1904 printsiginfo(&tcp->status.PR_INFO, 1);
1905 printtrailer(tcp);
1906 }
1907#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001908 }
1909 break;
1910 case PR_FAULTED:
1911 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1912 printleader(tcp);
1913 tprintf("=== FAULT %d ===", what);
1914 printtrailer(tcp);
1915 }
1916 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001917#ifdef FREEBSD
1918 case 0: /* handle case we polled for nothing */
1919 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001920#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001921 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001922 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001923 exit(1);
1924 break;
1925 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001926 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001927#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001928 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001929#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001930 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001931#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001932 perror("PIOCRUN");
1933 exit(1);
1934 }
1935 }
1936 return 0;
1937}
1938
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001939#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001940
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001941#ifdef TCB_GROUP_EXITING
1942/* Handle an exit detach or death signal that is taking all the
1943 related clone threads with it. This is called in three circumstances:
1944 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1945 SIG == 0 Continuing TCP will perform an exit_group syscall.
1946 SIG == other Continuing TCP with SIG will kill the process.
1947*/
1948static int
1949handle_group_exit(struct tcb *tcp, int sig)
1950{
1951 /* We need to locate our records of all the clone threads
1952 related to TCP, either its children or siblings. */
1953 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1954 ? tcp->parent
1955 : tcp->nclone_detached > 0
1956 ? tcp : NULL);
1957
1958 if (sig < 0) {
Roland McGrath05690952004-10-20 01:00:27 +00001959 if (leader != NULL && leader != tcp &&
1960 !(leader->flags & TCB_GROUP_EXITING))
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001961 fprintf(stderr,
1962 "PANIC: handle_group_exit: %d leader %d\n",
1963 tcp->pid, leader ? leader->pid : -1);
Roland McGratha08a97e2005-08-03 11:23:46 +00001964 detach(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001965 }
1966 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00001967 /* Mark that we are taking the process down. */
1968 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001969 if (tcp->flags & TCB_ATTACHED) {
Roland McGrath00dc13f2004-10-20 02:04:15 +00001970 if (leader != NULL && leader != tcp) {
1971 if (leader->flags & TCB_ATTACHED) {
1972 /* We need to detach the leader so
1973 that the process death will be
1974 reported to its real parent.
1975 But we kill it first to prevent
1976 it doing anything before we kill
1977 the whole process in a moment.
1978 We can use PTRACE_KILL on a
1979 thread that's not already
1980 stopped. Then the value we pass
1981 in PTRACE_DETACH just sets the
1982 death signal reported to the
1983 real parent. */
1984 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1985 if (debug)
1986 fprintf(stderr,
1987 " [%d exit %d kills %d]\n",
1988 tcp->pid, sig, leader->pid);
1989 detach(leader, sig);
1990 }
1991 else
1992 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001993 }
1994 detach(tcp, sig);
1995 }
1996 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1997 perror("strace: ptrace(PTRACE_CONT, ...)");
1998 cleanup();
1999 return -1;
2000 }
2001 else {
Roland McGrath05690952004-10-20 01:00:27 +00002002 if (leader != NULL)
2003 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002004 if (leader != NULL && leader != tcp)
2005 droptcb(tcp);
2006 /* The leader will report to us as parent now,
2007 and then we'll get to the SIG==-1 case. */
2008 return 0;
2009 }
2010 }
2011
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002012 return 0;
2013}
2014#endif
2015
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002016static int
2017trace()
2018{
2019 int pid;
2020 int wait_errno;
2021 int status;
2022 struct tcb *tcp;
2023#ifdef LINUX
2024 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002025#ifdef __WALL
2026 static int wait4_options = __WALL;
2027#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002028#endif /* LINUX */
2029
2030 while (nprocs != 0) {
2031 if (interactive)
2032 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2033#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002034#ifdef __WALL
2035 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002036 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002037 /* this kernel does not support __WALL */
2038 wait4_options &= ~__WALL;
2039 errno = 0;
2040 pid = wait4(-1, &status, wait4_options,
2041 cflag ? &ru : NULL);
2042 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002043 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002044 /* most likely a "cloned" process */
2045 pid = wait4(-1, &status, __WCLONE,
2046 cflag ? &ru : NULL);
2047 if (pid == -1) {
2048 fprintf(stderr, "strace: clone wait4 "
2049 "failed: %s\n", strerror(errno));
2050 }
2051 }
2052#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002053 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002054#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002055#endif /* LINUX */
2056#ifdef SUNOS4
2057 pid = wait(&status);
2058#endif /* SUNOS4 */
2059 wait_errno = errno;
2060 if (interactive)
2061 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2062
2063 if (interrupted)
2064 return 0;
2065
2066 if (pid == -1) {
2067 switch (wait_errno) {
2068 case EINTR:
2069 continue;
2070 case ECHILD:
2071 /*
2072 * We would like to verify this case
2073 * but sometimes a race in Solbourne's
2074 * version of SunOS sometimes reports
2075 * ECHILD before sending us SIGCHILD.
2076 */
2077#if 0
2078 if (nprocs == 0)
2079 return 0;
2080 fprintf(stderr, "strace: proc miscount\n");
2081 exit(1);
2082#endif
2083 return 0;
2084 default:
2085 errno = wait_errno;
2086 perror("strace: wait");
2087 return -1;
2088 }
2089 }
2090 if (debug)
2091 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2092
2093 /* Look up `pid' in our table. */
2094 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002095#ifdef LINUX
2096 if (followfork || followvfork) {
2097 /* This is needed to go with the CLONE_PTRACE
2098 changes in process.c/util.c: we might see
2099 the child's initial trap before we see the
2100 parent return from the clone syscall.
2101 Leave the child suspended until the parent
2102 returns from its system call. Only then
2103 will we have the association of parent and
2104 child so that we know how to do clearbpt
2105 in the child. */
Dmitry V. Levin76860f62006-10-11 22:55:25 +00002106 if (nprocs == tcbtabsize &&
2107 expand_tcbtab())
2108 tcp = NULL;
2109 else
2110 tcp = alloctcb(pid);
2111 if (tcp == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002112 kill(pid, SIGKILL); /* XXX */
2113 return 0;
2114 }
2115 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
2116 newoutf(tcp);
2117 if (!qflag)
2118 fprintf(stderr, "\
2119Process %d attached (waiting for parent)\n",
2120 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002121 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002122 else
2123 /* This can happen if a clone call used
2124 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002125#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002126 {
2127 fprintf(stderr, "unknown pid: %u\n", pid);
2128 if (WIFSTOPPED(status))
2129 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2130 exit(1);
2131 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002132 }
2133 /* set current output file */
2134 outf = tcp->outf;
2135 if (cflag) {
2136#ifdef LINUX
2137 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2138 tcp->stime = ru.ru_stime;
2139#endif /* !LINUX */
2140 }
2141
2142 if (tcp->flags & TCB_SUSPENDED) {
2143 /*
2144 * Apparently, doing any ptrace() call on a stopped
2145 * process, provokes the kernel to report the process
2146 * status again on a subsequent wait(), even if the
2147 * process has not been actually restarted.
2148 * Since we have inspected the arguments of suspended
2149 * processes we end up here testing for this case.
2150 */
2151 continue;
2152 }
2153 if (WIFSIGNALED(status)) {
2154 if (!cflag
2155 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2156 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002157 tprintf("+++ killed by %s %s+++",
2158 signame(WTERMSIG(status)),
2159#ifdef WCOREDUMP
2160 WCOREDUMP(status) ? "(core dumped) " :
2161#endif
2162 "");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002163 printtrailer(tcp);
2164 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002165#ifdef TCB_GROUP_EXITING
2166 handle_group_exit(tcp, -1);
2167#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002168 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002169#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002170 continue;
2171 }
2172 if (WIFEXITED(status)) {
2173 if (debug)
2174 fprintf(stderr, "pid %u exited\n", pid);
Roland McGrath05690952004-10-20 01:00:27 +00002175 if ((tcp->flags & TCB_ATTACHED)
2176#ifdef TCB_GROUP_EXITING
2177 && !(tcp->parent && (tcp->parent->flags &
2178 TCB_GROUP_EXITING))
2179#endif
2180 )
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002181 fprintf(stderr,
2182 "PANIC: attached pid %u exited\n",
2183 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002184 if (tcp == tcp_last) {
2185 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2186 == TCB_INSYSCALL)
2187 tprintf(" <unfinished ... exit status %d>\n",
2188 WEXITSTATUS(status));
2189 tcp_last = NULL;
2190 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002191#ifdef TCB_GROUP_EXITING
2192 handle_group_exit(tcp, -1);
2193#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002194 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002195#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002196 continue;
2197 }
2198 if (!WIFSTOPPED(status)) {
2199 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2200 droptcb(tcp);
2201 continue;
2202 }
2203 if (debug)
2204 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002205 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002206
2207 if (tcp->flags & TCB_STARTUP) {
2208 /*
2209 * This flag is there to keep us in sync.
2210 * Next time this process stops it should
2211 * really be entering a system call.
2212 */
2213 tcp->flags &= ~TCB_STARTUP;
2214 if (tcp->flags & TCB_ATTACHED) {
2215 /*
2216 * Interestingly, the process may stop
2217 * with STOPSIG equal to some other signal
2218 * than SIGSTOP if we happend to attach
2219 * just before the process takes a signal.
2220 */
2221 if (!WIFSTOPPED(status)) {
2222 fprintf(stderr,
2223 "pid %u not stopped\n", pid);
2224 detach(tcp, WSTOPSIG(status));
2225 continue;
2226 }
2227 }
2228 else {
2229#ifdef SUNOS4
2230 /* A child of us stopped at exec */
2231 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2232 fixvfork(tcp);
2233#endif /* SUNOS4 */
2234 }
2235 if (tcp->flags & TCB_BPTSET) {
2236 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2237 droptcb(tcp);
2238 cleanup();
2239 return -1;
2240 }
2241 }
2242 goto tracing;
2243 }
2244
2245 if (WSTOPSIG(status) != SIGTRAP) {
2246 if (WSTOPSIG(status) == SIGSTOP &&
2247 (tcp->flags & TCB_SIGTRAPPED)) {
2248 /*
2249 * Trapped attempt to block SIGTRAP
2250 * Hope we are back in control now.
2251 */
2252 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2253 if (ptrace(PTRACE_SYSCALL,
2254 pid, (char *) 1, 0) < 0) {
2255 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2256 cleanup();
2257 return -1;
2258 }
2259 continue;
2260 }
2261 if (!cflag
2262 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002263 unsigned long addr = 0, pc = 0;
2264#ifdef PT_GETSIGINFO
2265# define PSR_RI 41
2266 struct siginfo si;
2267 unsigned long psr;
2268
2269 upeek(pid, PT_CR_IPSR, &psr);
2270 upeek(pid, PT_CR_IIP, &pc);
2271
2272 pc += (psr >> PSR_RI) & 0x3;
2273 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2274 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002275#elif defined PTRACE_GETSIGINFO
2276 if (WSTOPSIG(status) == SIGSEGV ||
2277 WSTOPSIG(status) == SIGBUS) {
2278 siginfo_t si;
2279 if (ptrace(PTRACE_GETSIGINFO, pid,
2280 0, &si) == 0)
2281 addr = (unsigned long)
2282 si.si_addr;
2283 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002284#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002285 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002286 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002287 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002288 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002289 printtrailer(tcp);
2290 }
Roland McGrath05690952004-10-20 01:00:27 +00002291 if (((tcp->flags & TCB_ATTACHED) ||
2292 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002293 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002294#ifdef TCB_GROUP_EXITING
2295 handle_group_exit(tcp, WSTOPSIG(status));
2296#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002297 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002298#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002299 continue;
2300 }
2301 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2302 WSTOPSIG(status)) < 0) {
2303 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2304 cleanup();
2305 return -1;
2306 }
2307 tcp->flags &= ~TCB_SUSPENDED;
2308 continue;
2309 }
2310 if (trace_syscall(tcp) < 0) {
2311 if (tcp->flags & TCB_ATTACHED)
2312 detach(tcp, 0);
2313 else {
2314 ptrace(PTRACE_KILL,
2315 tcp->pid, (char *) 1, SIGTERM);
2316 droptcb(tcp);
2317 }
2318 continue;
2319 }
2320 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002321#ifdef TCB_GROUP_EXITING
2322 if (tcp->flags & TCB_GROUP_EXITING) {
2323 if (handle_group_exit(tcp, 0) < 0)
2324 return -1;
2325 continue;
2326 }
2327#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002328 if (tcp->flags & TCB_ATTACHED)
2329 detach(tcp, 0);
2330 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2331 perror("strace: ptrace(PTRACE_CONT, ...)");
2332 cleanup();
2333 return -1;
2334 }
2335 continue;
2336 }
2337 if (tcp->flags & TCB_SUSPENDED) {
2338 if (!qflag)
2339 fprintf(stderr, "Process %u suspended\n", pid);
2340 continue;
2341 }
2342 tracing:
2343 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2344 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2345 cleanup();
2346 return -1;
2347 }
2348 }
2349 return 0;
2350}
2351
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002352#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002353
2354static int curcol;
2355
2356#ifdef __STDC__
2357#include <stdarg.h>
2358#define VA_START(a, b) va_start(a, b)
2359#else
2360#include <varargs.h>
2361#define VA_START(a, b) va_start(a)
2362#endif
2363
2364void
2365#ifdef __STDC__
2366tprintf(const char *fmt, ...)
2367#else
2368tprintf(fmt, va_alist)
2369char *fmt;
2370va_dcl
2371#endif
2372{
2373 va_list args;
2374
2375 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002376 if (outf) {
2377 int n = vfprintf(outf, fmt, args);
2378 if (n < 0 && outf != stderr)
2379 perror(outfname == NULL
2380 ? "<writing to pipe>" : outfname);
2381 else
2382 curcol += n;
2383 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002384 va_end(args);
2385 return;
2386}
2387
2388void
2389printleader(tcp)
2390struct tcb *tcp;
2391{
2392 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2393 tcp_last->flags |= TCB_REPRINT;
2394 tprintf(" <unfinished ...>\n");
2395 }
2396 curcol = 0;
2397 if ((followfork == 1 || pflag_seen > 1) && outfname)
2398 tprintf("%-5d ", tcp->pid);
2399 else if (nprocs > 1 && !outfname)
2400 tprintf("[pid %5u] ", tcp->pid);
2401 if (tflag) {
2402 char str[sizeof("HH:MM:SS")];
2403 struct timeval tv, dtv;
2404 static struct timeval otv;
2405
2406 gettimeofday(&tv, NULL);
2407 if (rflag) {
2408 if (otv.tv_sec == 0)
2409 otv = tv;
2410 tv_sub(&dtv, &tv, &otv);
2411 tprintf("%6ld.%06ld ",
2412 (long) dtv.tv_sec, (long) dtv.tv_usec);
2413 otv = tv;
2414 }
2415 else if (tflag > 2) {
2416 tprintf("%ld.%06ld ",
2417 (long) tv.tv_sec, (long) tv.tv_usec);
2418 }
2419 else {
2420 time_t local = tv.tv_sec;
2421 strftime(str, sizeof(str), "%T", localtime(&local));
2422 if (tflag > 1)
2423 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2424 else
2425 tprintf("%s ", str);
2426 }
2427 }
2428 if (iflag)
2429 printcall(tcp);
2430}
2431
2432void
2433tabto(col)
2434int col;
2435{
2436 if (curcol < col)
2437 tprintf("%*s", col - curcol, "");
2438}
2439
2440void
2441printtrailer(tcp)
2442struct tcb *tcp;
2443{
2444 tprintf("\n");
2445 tcp_last = NULL;
2446}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002447
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002448#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002449
2450int mp_ioctl (int fd, int cmd, void *arg, int size) {
2451
2452 struct iovec iov[2];
2453 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002454
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002455 iov[0].iov_base = &cmd;
2456 iov[0].iov_len = sizeof cmd;
2457 if (arg) {
2458 ++n;
2459 iov[1].iov_base = arg;
2460 iov[1].iov_len = size;
2461 }
Roland McGrath553a6092002-12-16 20:40:39 +00002462
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002463 return writev (fd, iov, n);
2464}
2465
2466#endif