blob: 1553fb59aff577323db030ed32a38faff45562d2 [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);
Roland McGrath70b08532004-04-09 00:25:21 +0000445 if (tcp == NULL) {
446 fprintf(stderr, "%s: out of memory\n",
447 progname);
448 exit(1);
449 }
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000450 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK;
Roland McGrath70b08532004-04-09 00:25:21 +0000451 tcbtab[c]->nchildren++;
452 tcbtab[c]->nclone_threads++;
453 tcbtab[c]->nclone_detached++;
454 tcp->parent = tcbtab[c];
455 }
456 }
457 closedir(dir);
458 if (nerr == ntid) {
459 perror("attach: ptrace(PTRACE_ATTACH, ...)");
460 droptcb(tcp);
461 continue;
462 }
463 if (!qflag) {
464 ntid -= nerr;
465 if (ntid > 1)
466 fprintf(stderr, "\
467Process %u attached with %u threads - interrupt to quit\n",
468 tcp->pid, ntid);
469 else
470 fprintf(stderr, "\
471Process %u attached - interrupt to quit\n",
472 tcp->pid);
473 }
474 continue;
475 }
476 }
477# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000478 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
479 perror("attach: ptrace(PTRACE_ATTACH, ...)");
480 droptcb(tcp);
481 continue;
482 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000483#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000484 if (!qflag)
485 fprintf(stderr,
486 "Process %u attached - interrupt to quit\n",
Roland McGrathc3266d52004-02-20 02:23:52 +0000487 tcp->pid);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000488 }
489
Roland McGrathce0d1542003-11-11 21:24:23 +0000490 if (!pflag_seen) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000491 struct stat statbuf;
492 char *filename;
493 char pathname[MAXPATHLEN];
494
495 filename = argv[optind];
Roland McGrathbdb09df2004-03-02 06:50:04 +0000496 if (strchr(filename, '/')) {
497 if (strlen(filename) > sizeof pathname - 1) {
498 errno = ENAMETOOLONG;
499 perror("strace: exec");
500 exit(1);
501 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000502 strcpy(pathname, filename);
Roland McGrathbdb09df2004-03-02 06:50:04 +0000503 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000504#ifdef USE_DEBUGGING_EXEC
505 /*
506 * Debuggers customarily check the current directory
507 * first regardless of the path but doing that gives
508 * security geeks a panic attack.
509 */
510 else if (stat(filename, &statbuf) == 0)
511 strcpy(pathname, filename);
512#endif /* USE_DEBUGGING_EXEC */
513 else {
514 char *path;
515 int m, n, len;
516
517 for (path = getenv("PATH"); path && *path; path += m) {
518 if (strchr(path, ':')) {
519 n = strchr(path, ':') - path;
520 m = n + 1;
521 }
522 else
523 m = n = strlen(path);
524 if (n == 0) {
525 getcwd(pathname, MAXPATHLEN);
526 len = strlen(pathname);
527 }
Roland McGrathbdb09df2004-03-02 06:50:04 +0000528 else if (n > sizeof pathname - 1)
529 continue;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000530 else {
531 strncpy(pathname, path, n);
532 len = n;
533 }
534 if (len && pathname[len - 1] != '/')
535 pathname[len++] = '/';
536 strcpy(pathname + len, filename);
Roland McGrathed645162003-06-03 07:18:19 +0000537 if (stat(pathname, &statbuf) == 0 &&
538 /* Accept only regular files
539 with some execute bits set.
540 XXX not perfect, might still fail */
541 S_ISREG(statbuf.st_mode) &&
542 (statbuf.st_mode & 0111))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543 break;
544 }
545 }
546 if (stat(pathname, &statbuf) < 0) {
547 fprintf(stderr, "%s: %s: command not found\n",
548 progname, filename);
549 exit(1);
550 }
551 switch (pid = fork()) {
552 case -1:
553 perror("strace: fork");
554 cleanup();
555 exit(1);
556 break;
557 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000558#ifdef USE_PROCFS
559 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560#ifdef MIPS
561 /* Kludge for SGI, see proc_open for details. */
562 sa.sa_handler = foobar;
563 sa.sa_flags = 0;
564 sigemptyset(&sa.sa_mask);
565 sigaction(SIGINT, &sa, NULL);
566#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000567#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000568 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000569#else /* FREEBSD */
570 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000571#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000572#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000573 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000574 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000575
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
577 perror("strace: ptrace(PTRACE_TRACEME, ...)");
578 return -1;
579 }
580 if (debug)
581 kill(getpid(), SIGSTOP);
582
583 if (username != NULL || geteuid() == 0) {
584 uid_t run_euid = run_uid;
585 gid_t run_egid = run_gid;
586
587 if (statbuf.st_mode & S_ISUID)
588 run_euid = statbuf.st_uid;
589 if (statbuf.st_mode & S_ISGID)
590 run_egid = statbuf.st_gid;
591
592 /*
593 * It is important to set groups before we
594 * lose privileges on setuid.
595 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000596 if (username != NULL) {
597 if (initgroups(username, run_gid) < 0) {
598 perror("initgroups");
599 exit(1);
600 }
601 if (setregid(run_gid, run_egid) < 0) {
602 perror("setregid");
603 exit(1);
604 }
605 if (setreuid(run_uid, run_euid) < 0) {
606 perror("setreuid");
607 exit(1);
608 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000609 }
610 }
611 else
612 setreuid(run_uid, run_uid);
Roland McGrath15dca8e2005-02-06 01:16:32 +0000613
614 /*
615 * Induce an immediate stop so that the parent
616 * will resume us with PTRACE_SYSCALL and display
617 * this execve call normally.
618 */
619 kill(getpid(), SIGSTOP);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000620#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621
622 execv(pathname, &argv[optind]);
623 perror("strace: exec");
624 _exit(1);
625 break;
626 }
627 default:
628 if ((tcp = alloctcb(pid)) == NULL) {
629 fprintf(stderr, "tcb table full\n");
630 cleanup();
631 exit(1);
632 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000633#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000634 if (proc_open(tcp, 0) < 0) {
635 fprintf(stderr, "trouble opening proc file\n");
636 cleanup();
637 exit(1);
638 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000639#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000640 break;
641 }
642 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000643
644 sigemptyset(&empty_set);
645 sigemptyset(&blocked_set);
646 sa.sa_handler = SIG_IGN;
647 sigemptyset(&sa.sa_mask);
648 sa.sa_flags = 0;
649 sigaction(SIGTTOU, &sa, NULL);
650 sigaction(SIGTTIN, &sa, NULL);
651 if (interactive) {
652 sigaddset(&blocked_set, SIGHUP);
653 sigaddset(&blocked_set, SIGINT);
654 sigaddset(&blocked_set, SIGQUIT);
655 sigaddset(&blocked_set, SIGPIPE);
656 sigaddset(&blocked_set, SIGTERM);
657 sa.sa_handler = interrupt;
658#ifdef SUNOS4
659 /* POSIX signals on sunos4.1 are a little broken. */
660 sa.sa_flags = SA_INTERRUPT;
661#endif /* SUNOS4 */
662 }
663 sigaction(SIGHUP, &sa, NULL);
664 sigaction(SIGINT, &sa, NULL);
665 sigaction(SIGQUIT, &sa, NULL);
666 sigaction(SIGPIPE, &sa, NULL);
667 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000668#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000669 sa.sa_handler = reaper;
670 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000671#else
672 /* Make sure SIGCHLD has the default action so that waitpid
673 definitely works without losing track of children. The user
674 should not have given us a bogus state to inherit, but he might
675 have. Arguably we should detect SIG_IGN here and pass it on
676 to children, but probably noone really needs that. */
677 sa.sa_handler = SIG_DFL;
678 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000679#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000680
681 if (trace() < 0)
682 exit(1);
683 cleanup();
684 exit(0);
685}
686
687void
688newoutf(tcp)
689struct tcb *tcp;
690{
691 char name[MAXPATHLEN];
692 FILE *fp;
693
694 if (outfname && followfork > 1) {
695 sprintf(name, "%s.%u", outfname, tcp->pid);
696#ifndef SVR4
697 setreuid(geteuid(), getuid());
698#endif
699 fp = fopen(name, "w");
700#ifndef SVR4
701 setreuid(geteuid(), getuid());
702#endif
703 if (fp == NULL) {
704 perror("fopen");
705 return;
706 }
707 tcp->outf = fp;
708 }
709 return;
710}
711
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000712int
713expand_tcbtab()
714{
715 /* Allocate some more TCBs and expand the table.
716 We don't want to relocate the TCBs because our
717 callers have pointers and it would be a pain.
718 So tcbtab is a table of pointers. Since we never
719 free the TCBs, we allocate a single chunk of many. */
720 struct tcb **newtab = (struct tcb **)
721 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
722 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
723 sizeof *newtcbs);
724 int i;
725 if (newtab == NULL || newtcbs == NULL) {
726 if (newtab != NULL)
727 free(newtab);
728 return 1;
729 }
730 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
731 newtab[i] = &newtcbs[i - tcbtabsize];
732 tcbtabsize *= 2;
733 tcbtab = newtab;
734
735 return 0;
736}
737
738
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000739struct tcb *
740alloctcb(pid)
741int pid;
742{
743 int i;
744 struct tcb *tcp;
745
Roland McGrathee9d4352002-12-18 04:16:10 +0000746 for (i = 0; i < tcbtabsize; i++) {
747 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000748 if ((tcp->flags & TCB_INUSE) == 0) {
749 tcp->pid = pid;
750 tcp->parent = NULL;
751 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000752 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000753#ifdef TCB_CLONE_THREAD
754 tcp->nclone_threads = tcp->nclone_detached = 0;
755 tcp->nclone_waiting = 0;
756#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757 tcp->flags = TCB_INUSE | TCB_STARTUP;
758 tcp->outf = outf; /* Initialise to current out file */
759 tcp->stime.tv_sec = 0;
760 tcp->stime.tv_usec = 0;
761 tcp->pfd = -1;
762 nprocs++;
763 return tcp;
764 }
765 }
766 return NULL;
767}
768
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000769#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000770int
771proc_open(tcp, attaching)
772struct tcb *tcp;
773int attaching;
774{
775 char proc[32];
776 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000777#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000778 int i;
779 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780 sigset_t signals;
781 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000782#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000783#ifndef HAVE_POLLABLE_PROCFS
784 static int last_pfd;
785#endif
786
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000787#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000788 /* Open the process pseudo-files in /proc. */
789 sprintf(proc, "/proc/%d/ctl", tcp->pid);
790 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000791 perror("strace: open(\"/proc/...\", ...)");
792 return -1;
793 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
795 perror("F_GETFD");
796 return -1;
797 }
798 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
799 perror("F_SETFD");
800 return -1;
801 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000802 sprintf(proc, "/proc/%d/status", tcp->pid);
803 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
804 perror("strace: open(\"/proc/...\", ...)");
805 return -1;
806 }
807 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
808 perror("F_GETFD");
809 return -1;
810 }
811 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
812 perror("F_SETFD");
813 return -1;
814 }
815 sprintf(proc, "/proc/%d/as", tcp->pid);
816 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
817 perror("strace: open(\"/proc/...\", ...)");
818 return -1;
819 }
820 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
821 perror("F_GETFD");
822 return -1;
823 }
824 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
825 perror("F_SETFD");
826 return -1;
827 }
828#else
829 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000830#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000831 sprintf(proc, "/proc/%d", tcp->pid);
832 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000833#else /* FREEBSD */
834 sprintf(proc, "/proc/%d/mem", tcp->pid);
835 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
836#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000837 perror("strace: open(\"/proc/...\", ...)");
838 return -1;
839 }
840 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
841 perror("F_GETFD");
842 return -1;
843 }
844 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
845 perror("F_SETFD");
846 return -1;
847 }
848#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000849#ifdef FREEBSD
850 sprintf(proc, "/proc/%d/regs", tcp->pid);
851 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
852 perror("strace: open(\"/proc/.../regs\", ...)");
853 return -1;
854 }
855 if (cflag) {
856 sprintf(proc, "/proc/%d/status", tcp->pid);
857 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
858 perror("strace: open(\"/proc/.../status\", ...)");
859 return -1;
860 }
861 } else
862 tcp->pfd_status = -1;
863#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000864 rebuild_pollv();
865 if (!attaching) {
866 /*
867 * Wait for the child to pause. Because of a race
868 * condition we have to poll for the event.
869 */
870 for (;;) {
871 if (IOCTL_STATUS (tcp) < 0) {
872 perror("strace: PIOCSTATUS");
873 return -1;
874 }
875 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000876 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000877 }
878 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000879#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000880 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000881 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000882 perror("strace: PIOCSTOP");
883 return -1;
884 }
Roland McGrath553a6092002-12-16 20:40:39 +0000885#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000886#ifdef PIOCSET
887 /* Set Run-on-Last-Close. */
888 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000889 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000890 perror("PIOCSET PR_RLC");
891 return -1;
892 }
893 /* Set or Reset Inherit-on-Fork. */
894 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000895 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000896 perror("PIOC{SET,RESET} PR_FORK");
897 return -1;
898 }
899#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000900#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000901 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
902 perror("PIOCSRLC");
903 return -1;
904 }
905 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
906 perror("PIOC{S,R}FORK");
907 return -1;
908 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000909#else /* FREEBSD */
910 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
911 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
912 perror("PIOCGFL");
913 return -1;
914 }
915 arg &= ~PF_LINGER;
916 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
917 perror("PIOCSFL");
918 return -1;
919 }
920#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000921#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000922#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000923 /* Enable all syscall entries we care about. */
924 premptyset(&syscalls);
925 for (i = 1; i < MAX_QUALS; ++i) {
926 if (i > (sizeof syscalls) * CHAR_BIT) break;
927 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
928 }
929 praddset (&syscalls, SYS_execve);
930 if (followfork) {
931 praddset (&syscalls, SYS_fork);
932#ifdef SYS_forkall
933 praddset (&syscalls, SYS_forkall);
934#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000935#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000936 praddset (&syscalls, SYS_fork1);
937#endif
938#ifdef SYS_rfork1
939 praddset (&syscalls, SYS_rfork1);
940#endif
941#ifdef SYS_rforkall
942 praddset (&syscalls, SYS_rforkall);
943#endif
944 }
945 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000946 perror("PIOCSENTRY");
947 return -1;
948 }
John Hughes19e49982001-10-19 08:59:12 +0000949 /* Enable the syscall exits. */
950 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000951 perror("PIOSEXIT");
952 return -1;
953 }
John Hughes19e49982001-10-19 08:59:12 +0000954 /* Enable signals we care about. */
955 premptyset(&signals);
956 for (i = 1; i < MAX_QUALS; ++i) {
957 if (i > (sizeof signals) * CHAR_BIT) break;
958 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
959 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000960 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000961 perror("PIOCSTRACE");
962 return -1;
963 }
John Hughes19e49982001-10-19 08:59:12 +0000964 /* Enable faults we care about */
965 premptyset(&faults);
966 for (i = 1; i < MAX_QUALS; ++i) {
967 if (i > (sizeof faults) * CHAR_BIT) break;
968 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
969 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000970 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000971 perror("PIOCSFAULT");
972 return -1;
973 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000974#else /* FREEBSD */
975 /* set events flags. */
976 arg = S_SIG | S_SCE | S_SCX ;
977 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
978 perror("PIOCBIS");
979 return -1;
980 }
981#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000982 if (!attaching) {
983#ifdef MIPS
984 /*
985 * The SGI PRSABORT doesn't work for pause() so
986 * we send it a caught signal to wake it up.
987 */
988 kill(tcp->pid, SIGINT);
989#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000990#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000992 arg = PRSABORT;
993 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000994 perror("PIOCRUN");
995 return -1;
996 }
Roland McGrath553a6092002-12-16 20:40:39 +0000997#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000998#endif /* !MIPS*/
999#ifdef FREEBSD
1000 /* wake up the child if it received the SIGSTOP */
1001 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001002#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001003 for (;;) {
1004 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001005 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001006 perror("PIOCWSTOP");
1007 return -1;
1008 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001009 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001010 tcp->flags &= ~TCB_INSYSCALL;
1011 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001012 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001013 break;
1014 }
1015 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001016#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001017 arg = 0;
1018 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001019#else /* FREEBSD */
1020 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001021#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001022 perror("PIOCRUN");
1023 return -1;
1024 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001025#ifdef FREEBSD
1026 /* handle the case where we "opened" the child before
1027 it did the kill -STOP */
1028 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1029 tcp->status.PR_WHAT == SIGSTOP)
1030 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001031#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001032 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001033#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001034 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001035#else /* FREEBSD */
1036 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001037 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001038 /* We are attaching to an already running process.
1039 * Try to figure out the state of the process in syscalls,
1040 * to handle the first event well.
1041 * This is done by having a look at the "wchan" property of the
1042 * process, which tells where it is stopped (if it is). */
1043 FILE * status;
1044 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001045
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001046 sprintf(proc, "/proc/%d/status", tcp->pid);
1047 status = fopen(proc, "r");
1048 if (status &&
1049 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1050 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1051 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1052 strcmp(wchan, "stopevent")) {
1053 /* The process is asleep in the middle of a syscall.
1054 Fake the syscall entry event */
1055 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1056 tcp->status.PR_WHY = PR_SYSENTRY;
1057 trace_syscall(tcp);
1058 }
1059 if (status)
1060 fclose(status);
1061 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001062 }
1063#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001064#ifndef HAVE_POLLABLE_PROCFS
1065 if (proc_poll_pipe[0] != -1)
1066 proc_poller(tcp->pfd);
1067 else if (nprocs > 1) {
1068 proc_poll_open();
1069 proc_poller(last_pfd);
1070 proc_poller(tcp->pfd);
1071 }
1072 last_pfd = tcp->pfd;
1073#endif /* !HAVE_POLLABLE_PROCFS */
1074 return 0;
1075}
1076
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001077#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001078
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001079struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001080pid2tcb(pid)
1081int pid;
1082{
1083 int i;
1084 struct tcb *tcp;
1085
Roland McGrathee9d4352002-12-18 04:16:10 +00001086 for (i = 0; i < tcbtabsize; i++) {
1087 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001088 if (pid && tcp->pid != pid)
1089 continue;
1090 if (tcp->flags & TCB_INUSE)
1091 return tcp;
1092 }
1093 return NULL;
1094}
1095
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001096#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001097
1098static struct tcb *
1099pfd2tcb(pfd)
1100int pfd;
1101{
1102 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001103
Roland McGrathca16be82003-01-10 19:55:28 +00001104 for (i = 0; i < tcbtabsize; i++) {
1105 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001106 if (tcp->pfd != pfd)
1107 continue;
1108 if (tcp->flags & TCB_INUSE)
1109 return tcp;
1110 }
1111 return NULL;
1112}
1113
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001114#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001115
1116void
1117droptcb(tcp)
1118struct tcb *tcp;
1119{
1120 if (tcp->pid == 0)
1121 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001122#ifdef TCB_CLONE_THREAD
1123 if (tcp->nclone_threads > 0) {
1124 /* There are other threads left in this process, but this
1125 is the one whose PID represents the whole process.
1126 We need to keep this record around as a zombie until
1127 all the threads die. */
1128 tcp->flags |= TCB_EXITING;
1129 return;
1130 }
1131#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132 nprocs--;
1133 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001134
Roland McGrathe29341c2003-01-10 20:14:20 +00001135 if (tcp->parent != NULL) {
1136 tcp->parent->nchildren--;
1137#ifdef TCB_CLONE_THREAD
1138 if (tcp->flags & TCB_CLONE_DETACHED)
1139 tcp->parent->nclone_detached--;
1140 if (tcp->flags & TCB_CLONE_THREAD)
1141 tcp->parent->nclone_threads--;
1142#endif
Roland McGrath09623452003-05-23 02:27:13 +00001143#ifdef TCB_CLONE_DETACHED
1144 if (!(tcp->flags & TCB_CLONE_DETACHED))
1145#endif
1146 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001147 tcp->parent = NULL;
1148 }
1149
1150 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151 if (tcp->pfd != -1) {
1152 close(tcp->pfd);
1153 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001154#ifdef FREEBSD
1155 if (tcp->pfd_reg != -1) {
1156 close(tcp->pfd_reg);
1157 tcp->pfd_reg = -1;
1158 }
1159 if (tcp->pfd_status != -1) {
1160 close(tcp->pfd_status);
1161 tcp->pfd_status = -1;
1162 }
Roland McGrath553a6092002-12-16 20:40:39 +00001163#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001164#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001165 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166#endif
1167 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001168
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001169 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001170 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001171
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172 tcp->outf = 0;
1173}
1174
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001175#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176
1177static int
1178resume(tcp)
1179struct tcb *tcp;
1180{
1181 if (tcp == NULL)
1182 return -1;
1183
1184 if (!(tcp->flags & TCB_SUSPENDED)) {
1185 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1186 return -1;
1187 }
1188 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001189#ifdef TCB_CLONE_THREAD
1190 if (tcp->flags & TCB_CLONE_THREAD)
1191 tcp->parent->nclone_waiting--;
1192#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193
1194 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1195 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1196 return -1;
1197 }
1198
1199 if (!qflag)
1200 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1201 return 0;
1202}
1203
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001204#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001205
1206/* detach traced process; continue with sig */
1207
1208static int
1209detach(tcp, sig)
1210struct tcb *tcp;
1211int sig;
1212{
1213 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001214#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001215 int status, resumed;
Roland McGratha08a97e2005-08-03 11:23:46 +00001216 struct tcb *zombie = NULL;
1217
1218 /* If the group leader is lingering only because of this other
1219 thread now dying, then detach the leader as well. */
1220 if ((tcp->flags & TCB_CLONE_THREAD) &&
1221 tcp->parent->nclone_threads == 1 &&
1222 (tcp->parent->flags & TCB_EXITING))
1223 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001224#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001225
1226 if (tcp->flags & TCB_BPTSET)
1227 sig = SIGKILL;
1228
1229#ifdef LINUX
1230 /*
1231 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001232 * before detaching. Arghh. We go through hoops
1233 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001234 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001235#if defined(SPARC)
1236#undef PTRACE_DETACH
1237#define PTRACE_DETACH PTRACE_SUNDETACH
1238#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001239 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1240 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001241 }
1242 else if (errno != ESRCH) {
1243 /* Shouldn't happen. */
1244 perror("detach: ptrace(PTRACE_DETACH, ...)");
1245 }
1246 else if (kill(tcp->pid, 0) < 0) {
1247 if (errno != ESRCH)
1248 perror("detach: checking sanity");
1249 }
1250 else if (kill(tcp->pid, SIGSTOP) < 0) {
1251 if (errno != ESRCH)
1252 perror("detach: stopping child");
1253 }
1254 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001255 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001256#ifdef __WALL
1257 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1258 if (errno == ECHILD) /* Already gone. */
1259 break;
1260 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001261 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001262 break;
1263 }
1264#endif /* __WALL */
1265 /* No __WALL here. */
1266 if (waitpid(tcp->pid, &status, 0) < 0) {
1267 if (errno != ECHILD) {
1268 perror("detach: waiting");
1269 break;
1270 }
1271#ifdef __WCLONE
1272 /* If no processes, try clones. */
1273 if (wait4(tcp->pid, &status, __WCLONE,
1274 NULL) < 0) {
1275 if (errno != ECHILD)
1276 perror("detach: waiting");
1277 break;
1278 }
1279#endif /* __WCLONE */
1280 }
1281#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001282 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001283#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001284 if (!WIFSTOPPED(status)) {
1285 /* Au revoir, mon ami. */
1286 break;
1287 }
1288 if (WSTOPSIG(status) == SIGSTOP) {
1289 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001290 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291 if (errno != ESRCH)
1292 perror("detach: ptrace(PTRACE_DETACH, ...)");
1293 /* I died trying. */
1294 }
1295 break;
1296 }
1297 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001298 WSTOPSIG(status) == SIGTRAP ?
1299 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300 if (errno != ESRCH)
1301 perror("detach: ptrace(PTRACE_CONT, ...)");
1302 break;
1303 }
1304 }
1305 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001306#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001307
1308#if defined(SUNOS4)
1309 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1310 if (sig && kill(tcp->pid, sig) < 0)
1311 perror("detach: kill");
1312 sig = 0;
1313 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1314 perror("detach: ptrace(PTRACE_DETACH, ...)");
1315#endif /* SUNOS4 */
1316
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001317#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001318 resumed = 0;
1319
1320 /* XXX This won't always be quite right (but it never was).
1321 A waiter with argument 0 or < -1 is waiting for any pid in
1322 a particular pgrp, which this child might or might not be
1323 in. The waiter will only wake up if it's argument is -1
1324 or if it's waiting for tcp->pid's pgrp. It makes a
1325 difference to wake up a waiter when there might be more
1326 traced children, because it could get a false ECHILD
1327 error. OTOH, if this was the last child in the pgrp, then
1328 it ought to wake up and get ECHILD. We would have to
1329 search the system for all pid's in the pgrp to be sure.
1330
1331 && (t->waitpid == -1 ||
1332 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1333 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1334 */
1335
1336 if (tcp->parent &&
1337 (tcp->parent->flags & TCB_SUSPENDED) &&
1338 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1339 error = resume(tcp->parent);
1340 ++resumed;
1341 }
1342#ifdef TCB_CLONE_THREAD
1343 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1344 /* Some other threads of our parent are waiting too. */
1345 unsigned int i;
1346
1347 /* Resume all the threads that were waiting for this PID. */
1348 for (i = 0; i < tcbtabsize; i++) {
1349 struct tcb *t = tcbtab[i];
1350 if (t->parent == tcp->parent && t != tcp
1351 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1352 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1353 && t->waitpid == tcp->pid) {
1354 error |= resume (t);
1355 ++resumed;
1356 }
1357 }
1358 if (resumed == 0)
1359 /* Noone was waiting for this PID in particular,
1360 so now we might need to resume some wildcarders. */
1361 for (i = 0; i < tcbtabsize; i++) {
1362 struct tcb *t = tcbtab[i];
1363 if (t->parent == tcp->parent && t != tcp
1364 && ((t->flags
1365 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1366 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1367 && t->waitpid <= 0
1368 ) {
1369 error |= resume (t);
1370 break;
1371 }
1372 }
1373 }
1374#endif
1375
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001376#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001377
1378 if (!qflag)
1379 fprintf(stderr, "Process %u detached\n", tcp->pid);
1380
1381 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001382
1383#ifdef LINUX
1384 if (zombie != NULL)
1385 error = detach(zombie) || error;
1386#endif
1387
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001388 return error;
1389}
1390
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001391#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001392
1393static void
1394reaper(sig)
1395int sig;
1396{
1397 int pid;
1398 int status;
1399
1400 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1401#if 0
1402 struct tcb *tcp;
1403
1404 tcp = pid2tcb(pid);
1405 if (tcp)
1406 droptcb(tcp);
1407#endif
1408 }
1409}
1410
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001411#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001412
1413static void
1414cleanup()
1415{
1416 int i;
1417 struct tcb *tcp;
1418
Roland McGrathee9d4352002-12-18 04:16:10 +00001419 for (i = 0; i < tcbtabsize; i++) {
1420 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001421 if (!(tcp->flags & TCB_INUSE))
1422 continue;
1423 if (debug)
1424 fprintf(stderr,
1425 "cleanup: looking at pid %u\n", tcp->pid);
1426 if (tcp_last &&
1427 (!outfname || followfork < 2 || tcp_last == tcp)) {
1428 tprintf(" <unfinished ...>\n");
1429 tcp_last = NULL;
1430 }
1431 if (tcp->flags & TCB_ATTACHED)
1432 detach(tcp, 0);
1433 else {
1434 kill(tcp->pid, SIGCONT);
1435 kill(tcp->pid, SIGTERM);
1436 }
1437 }
1438 if (cflag)
1439 call_summary(outf);
1440}
1441
1442static void
1443interrupt(sig)
1444int sig;
1445{
1446 interrupted = 1;
1447}
1448
1449#ifndef HAVE_STRERROR
1450
Roland McGrath6d2b3492002-12-30 00:51:30 +00001451#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001452extern int sys_nerr;
1453extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001454#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001455
1456const char *
1457strerror(errno)
1458int errno;
1459{
1460 static char buf[64];
1461
1462 if (errno < 1 || errno >= sys_nerr) {
1463 sprintf(buf, "Unknown error %d", errno);
1464 return buf;
1465 }
1466 return sys_errlist[errno];
1467}
1468
1469#endif /* HAVE_STERRROR */
1470
1471#ifndef HAVE_STRSIGNAL
1472
Roland McGrath8f474e02003-01-14 07:53:33 +00001473#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001474extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001475#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001476#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1477extern char *_sys_siglist[];
1478#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001479
1480const char *
1481strsignal(sig)
1482int sig;
1483{
1484 static char buf[64];
1485
1486 if (sig < 1 || sig >= NSIG) {
1487 sprintf(buf, "Unknown signal %d", sig);
1488 return buf;
1489 }
1490#ifdef HAVE__SYS_SIGLIST
1491 return _sys_siglist[sig];
1492#else
1493 return sys_siglist[sig];
1494#endif
1495}
1496
1497#endif /* HAVE_STRSIGNAL */
1498
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001499#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001500
1501static void
1502rebuild_pollv()
1503{
1504 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001505
Roland McGrathee9d4352002-12-18 04:16:10 +00001506 if (pollv != NULL)
1507 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001508 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001509 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001510 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001511 exit(1);
1512 }
1513
Roland McGrathca16be82003-01-10 19:55:28 +00001514 for (i = j = 0; i < tcbtabsize; i++) {
1515 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001516 if (!(tcp->flags & TCB_INUSE))
1517 continue;
1518 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001519 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001520 j++;
1521 }
1522 if (j != nprocs) {
1523 fprintf(stderr, "strace: proc miscount\n");
1524 exit(1);
1525 }
1526}
1527
1528#ifndef HAVE_POLLABLE_PROCFS
1529
1530static void
1531proc_poll_open()
1532{
1533 int arg;
1534 int i;
1535
1536 if (pipe(proc_poll_pipe) < 0) {
1537 perror("pipe");
1538 exit(1);
1539 }
1540 for (i = 0; i < 2; i++) {
1541 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1542 perror("F_GETFD");
1543 exit(1);
1544 }
1545 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1546 perror("F_SETFD");
1547 exit(1);
1548 }
1549 }
1550}
1551
1552static int
1553proc_poll(pollv, nfds, timeout)
1554struct pollfd *pollv;
1555int nfds;
1556int timeout;
1557{
1558 int i;
1559 int n;
1560 struct proc_pollfd pollinfo;
1561
1562 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1563 return n;
1564 if (n != sizeof(struct proc_pollfd)) {
1565 fprintf(stderr, "panic: short read: %d\n", n);
1566 exit(1);
1567 }
1568 for (i = 0; i < nprocs; i++) {
1569 if (pollv[i].fd == pollinfo.fd)
1570 pollv[i].revents = pollinfo.revents;
1571 else
1572 pollv[i].revents = 0;
1573 }
1574 poller_pid = pollinfo.pid;
1575 return 1;
1576}
1577
1578static void
1579wakeup_handler(sig)
1580int sig;
1581{
1582}
1583
1584static void
1585proc_poller(pfd)
1586int pfd;
1587{
1588 struct proc_pollfd pollinfo;
1589 struct sigaction sa;
1590 sigset_t blocked_set, empty_set;
1591 int i;
1592 int n;
1593 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001594#ifdef FREEBSD
1595 struct procfs_status pfs;
1596#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001597
1598 switch (fork()) {
1599 case -1:
1600 perror("fork");
1601 _exit(0);
1602 case 0:
1603 break;
1604 default:
1605 return;
1606 }
1607
1608 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1609 sa.sa_flags = 0;
1610 sigemptyset(&sa.sa_mask);
1611 sigaction(SIGHUP, &sa, NULL);
1612 sigaction(SIGINT, &sa, NULL);
1613 sigaction(SIGQUIT, &sa, NULL);
1614 sigaction(SIGPIPE, &sa, NULL);
1615 sigaction(SIGTERM, &sa, NULL);
1616 sa.sa_handler = wakeup_handler;
1617 sigaction(SIGUSR1, &sa, NULL);
1618 sigemptyset(&blocked_set);
1619 sigaddset(&blocked_set, SIGUSR1);
1620 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1621 sigemptyset(&empty_set);
1622
1623 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1624 perror("getrlimit(RLIMIT_NOFILE, ...)");
1625 _exit(0);
1626 }
1627 n = rl.rlim_cur;
1628 for (i = 0; i < n; i++) {
1629 if (i != pfd && i != proc_poll_pipe[1])
1630 close(i);
1631 }
1632
1633 pollinfo.fd = pfd;
1634 pollinfo.pid = getpid();
1635 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001636#ifndef FREEBSD
1637 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1638#else /* FREEBSD */
1639 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1640#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001641 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642 switch (errno) {
1643 case EINTR:
1644 continue;
1645 case EBADF:
1646 pollinfo.revents = POLLERR;
1647 break;
1648 case ENOENT:
1649 pollinfo.revents = POLLHUP;
1650 break;
1651 default:
1652 perror("proc_poller: PIOCWSTOP");
1653 }
1654 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1655 _exit(0);
1656 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001657 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001658 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1659 sigsuspend(&empty_set);
1660 }
1661}
1662
1663#endif /* !HAVE_POLLABLE_PROCFS */
1664
1665static int
1666choose_pfd()
1667{
1668 int i, j;
1669 struct tcb *tcp;
1670
1671 static int last;
1672
1673 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001674 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675 /*
1676 * The previous process is ready to run again. We'll
1677 * let it do so if it is currently in a syscall. This
1678 * heuristic improves the readability of the trace.
1679 */
1680 tcp = pfd2tcb(pollv[last].fd);
1681 if (tcp && (tcp->flags & TCB_INSYSCALL))
1682 return pollv[last].fd;
1683 }
1684
1685 for (i = 0; i < nprocs; i++) {
1686 /* Let competing children run round robin. */
1687 j = (i + last + 1) % nprocs;
1688 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1689 tcp = pfd2tcb(pollv[j].fd);
1690 if (!tcp) {
1691 fprintf(stderr, "strace: lost proc\n");
1692 exit(1);
1693 }
1694 droptcb(tcp);
1695 return -1;
1696 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001697 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698 last = j;
1699 return pollv[j].fd;
1700 }
1701 }
1702 fprintf(stderr, "strace: nothing ready\n");
1703 exit(1);
1704}
1705
1706static int
1707trace()
1708{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001709#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001710 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001711#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712 struct tcb *tcp;
1713 int pfd;
1714 int what;
1715 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001716 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001717
1718 for (;;) {
1719 if (interactive)
1720 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1721
1722 if (nprocs == 0)
1723 break;
1724
1725 switch (nprocs) {
1726 case 1:
1727#ifndef HAVE_POLLABLE_PROCFS
1728 if (proc_poll_pipe[0] == -1) {
1729#endif
1730 tcp = pid2tcb(0);
1731 if (!tcp)
1732 continue;
1733 pfd = tcp->pfd;
1734 if (pfd == -1)
1735 continue;
1736 break;
1737#ifndef HAVE_POLLABLE_PROCFS
1738 }
1739 /* fall through ... */
1740#endif /* !HAVE_POLLABLE_PROCFS */
1741 default:
1742#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001743#ifdef POLL_HACK
1744 /* On some systems (e.g. UnixWare) we get too much ugly
1745 "unfinished..." stuff when multiple proceses are in
1746 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001747
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001748 if (in_syscall) {
1749 struct pollfd pv;
1750 tcp = in_syscall;
1751 in_syscall = NULL;
1752 pv.fd = tcp->pfd;
1753 pv.events = POLLWANT;
1754 if ((what = poll (&pv, 1, 1)) < 0) {
1755 if (interrupted)
1756 return 0;
1757 continue;
1758 }
1759 else if (what == 1 && pv.revents & POLLWANT) {
1760 goto FOUND;
1761 }
1762 }
1763#endif
1764
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001765 if (poll(pollv, nprocs, INFTIM) < 0) {
1766 if (interrupted)
1767 return 0;
1768 continue;
1769 }
1770#else /* !HAVE_POLLABLE_PROCFS */
1771 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1772 if (interrupted)
1773 return 0;
1774 continue;
1775 }
1776#endif /* !HAVE_POLLABLE_PROCFS */
1777 pfd = choose_pfd();
1778 if (pfd == -1)
1779 continue;
1780 break;
1781 }
1782
1783 /* Look up `pfd' in our table. */
1784 if ((tcp = pfd2tcb(pfd)) == NULL) {
1785 fprintf(stderr, "unknown pfd: %u\n", pfd);
1786 exit(1);
1787 }
John Hughesb6643082002-05-23 11:02:22 +00001788#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001789 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001790#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001791 /* Get the status of the process. */
1792 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001793#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001794 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001795#else /* FREEBSD */
1796 /* Thanks to some scheduling mystery, the first poller
1797 sometimes waits for the already processed end of fork
1798 event. Doing a non blocking poll here solves the problem. */
1799 if (proc_poll_pipe[0] != -1)
1800 ioctl_result = IOCTL_STATUS (tcp);
1801 else
1802 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001803#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001804 ioctl_errno = errno;
1805#ifndef HAVE_POLLABLE_PROCFS
1806 if (proc_poll_pipe[0] != -1) {
1807 if (ioctl_result < 0)
1808 kill(poller_pid, SIGKILL);
1809 else
1810 kill(poller_pid, SIGUSR1);
1811 }
1812#endif /* !HAVE_POLLABLE_PROCFS */
1813 }
1814 if (interrupted)
1815 return 0;
1816
1817 if (interactive)
1818 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1819
1820 if (ioctl_result < 0) {
1821 /* Find out what happened if it failed. */
1822 switch (ioctl_errno) {
1823 case EINTR:
1824 case EBADF:
1825 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001826#ifdef FREEBSD
1827 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001828#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001829 case ENOENT:
1830 droptcb(tcp);
1831 continue;
1832 default:
1833 perror("PIOCWSTOP");
1834 exit(1);
1835 }
1836 }
1837
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001838#ifdef FREEBSD
1839 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1840 /* discard first event for a syscall we never entered */
1841 IOCTL (tcp->pfd, PIOCRUN, 0);
1842 continue;
1843 }
Roland McGrath553a6092002-12-16 20:40:39 +00001844#endif
1845
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001846 /* clear the just started flag */
1847 tcp->flags &= ~TCB_STARTUP;
1848
1849 /* set current output file */
1850 outf = tcp->outf;
1851
1852 if (cflag) {
1853 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001854#ifdef FREEBSD
1855 char buf[1024];
1856 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001857
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001858 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1859 buf[len] = '\0';
1860 sscanf(buf,
1861 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1862 &stime.tv_sec, &stime.tv_usec);
1863 } else
1864 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001865#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001866 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1867 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001868#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001869 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1870 tcp->stime = stime;
1871 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001872 what = tcp->status.PR_WHAT;
1873 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001874#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001875 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001876 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1877 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001878 if (trace_syscall(tcp) < 0) {
1879 fprintf(stderr, "syscall trouble\n");
1880 exit(1);
1881 }
1882 }
1883 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001884#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001885 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001886#ifdef POLL_HACK
1887 in_syscall = tcp;
1888#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001889 case PR_SYSEXIT:
1890 if (trace_syscall(tcp) < 0) {
1891 fprintf(stderr, "syscall trouble\n");
1892 exit(1);
1893 }
1894 break;
1895 case PR_SIGNALLED:
1896 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1897 printleader(tcp);
1898 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001899 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001900 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001901#ifdef PR_INFO
1902 if (tcp->status.PR_INFO.si_signo == what) {
1903 printleader(tcp);
1904 tprintf(" siginfo=");
1905 printsiginfo(&tcp->status.PR_INFO, 1);
1906 printtrailer(tcp);
1907 }
1908#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001909 }
1910 break;
1911 case PR_FAULTED:
1912 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1913 printleader(tcp);
1914 tprintf("=== FAULT %d ===", what);
1915 printtrailer(tcp);
1916 }
1917 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001918#ifdef FREEBSD
1919 case 0: /* handle case we polled for nothing */
1920 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001921#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001922 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001923 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001924 exit(1);
1925 break;
1926 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001927 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001928#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001929 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001930#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001931 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001932#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001933 perror("PIOCRUN");
1934 exit(1);
1935 }
1936 }
1937 return 0;
1938}
1939
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001940#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001941
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001942#ifdef TCB_GROUP_EXITING
1943/* Handle an exit detach or death signal that is taking all the
1944 related clone threads with it. This is called in three circumstances:
1945 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1946 SIG == 0 Continuing TCP will perform an exit_group syscall.
1947 SIG == other Continuing TCP with SIG will kill the process.
1948*/
1949static int
1950handle_group_exit(struct tcb *tcp, int sig)
1951{
1952 /* We need to locate our records of all the clone threads
1953 related to TCP, either its children or siblings. */
1954 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1955 ? tcp->parent
1956 : tcp->nclone_detached > 0
1957 ? tcp : NULL);
1958
1959 if (sig < 0) {
Roland McGrath05690952004-10-20 01:00:27 +00001960 if (leader != NULL && leader != tcp &&
1961 !(leader->flags & TCB_GROUP_EXITING))
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001962 fprintf(stderr,
1963 "PANIC: handle_group_exit: %d leader %d\n",
1964 tcp->pid, leader ? leader->pid : -1);
Roland McGratha08a97e2005-08-03 11:23:46 +00001965 detach(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001966 }
1967 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00001968 /* Mark that we are taking the process down. */
1969 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001970 if (tcp->flags & TCB_ATTACHED) {
Roland McGrath00dc13f2004-10-20 02:04:15 +00001971 if (leader != NULL && leader != tcp) {
1972 if (leader->flags & TCB_ATTACHED) {
1973 /* We need to detach the leader so
1974 that the process death will be
1975 reported to its real parent.
1976 But we kill it first to prevent
1977 it doing anything before we kill
1978 the whole process in a moment.
1979 We can use PTRACE_KILL on a
1980 thread that's not already
1981 stopped. Then the value we pass
1982 in PTRACE_DETACH just sets the
1983 death signal reported to the
1984 real parent. */
1985 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1986 if (debug)
1987 fprintf(stderr,
1988 " [%d exit %d kills %d]\n",
1989 tcp->pid, sig, leader->pid);
1990 detach(leader, sig);
1991 }
1992 else
1993 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001994 }
1995 detach(tcp, sig);
1996 }
1997 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1998 perror("strace: ptrace(PTRACE_CONT, ...)");
1999 cleanup();
2000 return -1;
2001 }
2002 else {
Roland McGrath05690952004-10-20 01:00:27 +00002003 if (leader != NULL)
2004 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002005 if (leader != NULL && leader != tcp)
2006 droptcb(tcp);
2007 /* The leader will report to us as parent now,
2008 and then we'll get to the SIG==-1 case. */
2009 return 0;
2010 }
2011 }
2012
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002013 return 0;
2014}
2015#endif
2016
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002017static int
2018trace()
2019{
2020 int pid;
2021 int wait_errno;
2022 int status;
2023 struct tcb *tcp;
2024#ifdef LINUX
2025 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002026#ifdef __WALL
2027 static int wait4_options = __WALL;
2028#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002029#endif /* LINUX */
2030
2031 while (nprocs != 0) {
2032 if (interactive)
2033 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2034#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002035#ifdef __WALL
2036 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002037 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002038 /* this kernel does not support __WALL */
2039 wait4_options &= ~__WALL;
2040 errno = 0;
2041 pid = wait4(-1, &status, wait4_options,
2042 cflag ? &ru : NULL);
2043 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002044 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002045 /* most likely a "cloned" process */
2046 pid = wait4(-1, &status, __WCLONE,
2047 cflag ? &ru : NULL);
2048 if (pid == -1) {
2049 fprintf(stderr, "strace: clone wait4 "
2050 "failed: %s\n", strerror(errno));
2051 }
2052 }
2053#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002054 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002055#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002056#endif /* LINUX */
2057#ifdef SUNOS4
2058 pid = wait(&status);
2059#endif /* SUNOS4 */
2060 wait_errno = errno;
2061 if (interactive)
2062 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2063
2064 if (interrupted)
2065 return 0;
2066
2067 if (pid == -1) {
2068 switch (wait_errno) {
2069 case EINTR:
2070 continue;
2071 case ECHILD:
2072 /*
2073 * We would like to verify this case
2074 * but sometimes a race in Solbourne's
2075 * version of SunOS sometimes reports
2076 * ECHILD before sending us SIGCHILD.
2077 */
2078#if 0
2079 if (nprocs == 0)
2080 return 0;
2081 fprintf(stderr, "strace: proc miscount\n");
2082 exit(1);
2083#endif
2084 return 0;
2085 default:
2086 errno = wait_errno;
2087 perror("strace: wait");
2088 return -1;
2089 }
2090 }
2091 if (debug)
2092 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2093
2094 /* Look up `pid' in our table. */
2095 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002096#ifdef LINUX
2097 if (followfork || followvfork) {
2098 /* This is needed to go with the CLONE_PTRACE
2099 changes in process.c/util.c: we might see
2100 the child's initial trap before we see the
2101 parent return from the clone syscall.
2102 Leave the child suspended until the parent
2103 returns from its system call. Only then
2104 will we have the association of parent and
2105 child so that we know how to do clearbpt
2106 in the child. */
2107 if ((tcp = alloctcb(pid)) == NULL) {
2108 fprintf(stderr, " [tcb table full]\n");
2109 kill(pid, SIGKILL); /* XXX */
2110 return 0;
2111 }
2112 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
2113 newoutf(tcp);
2114 if (!qflag)
2115 fprintf(stderr, "\
2116Process %d attached (waiting for parent)\n",
2117 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002118 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002119 else
2120 /* This can happen if a clone call used
2121 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002122#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002123 {
2124 fprintf(stderr, "unknown pid: %u\n", pid);
2125 if (WIFSTOPPED(status))
2126 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2127 exit(1);
2128 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002129 }
2130 /* set current output file */
2131 outf = tcp->outf;
2132 if (cflag) {
2133#ifdef LINUX
2134 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2135 tcp->stime = ru.ru_stime;
2136#endif /* !LINUX */
2137 }
2138
2139 if (tcp->flags & TCB_SUSPENDED) {
2140 /*
2141 * Apparently, doing any ptrace() call on a stopped
2142 * process, provokes the kernel to report the process
2143 * status again on a subsequent wait(), even if the
2144 * process has not been actually restarted.
2145 * Since we have inspected the arguments of suspended
2146 * processes we end up here testing for this case.
2147 */
2148 continue;
2149 }
2150 if (WIFSIGNALED(status)) {
2151 if (!cflag
2152 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2153 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002154 tprintf("+++ killed by %s %s+++",
2155 signame(WTERMSIG(status)),
2156#ifdef WCOREDUMP
2157 WCOREDUMP(status) ? "(core dumped) " :
2158#endif
2159 "");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002160 printtrailer(tcp);
2161 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002162#ifdef TCB_GROUP_EXITING
2163 handle_group_exit(tcp, -1);
2164#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002165 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002166#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002167 continue;
2168 }
2169 if (WIFEXITED(status)) {
2170 if (debug)
2171 fprintf(stderr, "pid %u exited\n", pid);
Roland McGrath05690952004-10-20 01:00:27 +00002172 if ((tcp->flags & TCB_ATTACHED)
2173#ifdef TCB_GROUP_EXITING
2174 && !(tcp->parent && (tcp->parent->flags &
2175 TCB_GROUP_EXITING))
2176#endif
2177 )
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002178 fprintf(stderr,
2179 "PANIC: attached pid %u exited\n",
2180 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002181 if (tcp == tcp_last) {
2182 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2183 == TCB_INSYSCALL)
2184 tprintf(" <unfinished ... exit status %d>\n",
2185 WEXITSTATUS(status));
2186 tcp_last = NULL;
2187 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002188#ifdef TCB_GROUP_EXITING
2189 handle_group_exit(tcp, -1);
2190#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002191 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002192#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002193 continue;
2194 }
2195 if (!WIFSTOPPED(status)) {
2196 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2197 droptcb(tcp);
2198 continue;
2199 }
2200 if (debug)
2201 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002202 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002203
2204 if (tcp->flags & TCB_STARTUP) {
2205 /*
2206 * This flag is there to keep us in sync.
2207 * Next time this process stops it should
2208 * really be entering a system call.
2209 */
2210 tcp->flags &= ~TCB_STARTUP;
2211 if (tcp->flags & TCB_ATTACHED) {
2212 /*
2213 * Interestingly, the process may stop
2214 * with STOPSIG equal to some other signal
2215 * than SIGSTOP if we happend to attach
2216 * just before the process takes a signal.
2217 */
2218 if (!WIFSTOPPED(status)) {
2219 fprintf(stderr,
2220 "pid %u not stopped\n", pid);
2221 detach(tcp, WSTOPSIG(status));
2222 continue;
2223 }
2224 }
2225 else {
2226#ifdef SUNOS4
2227 /* A child of us stopped at exec */
2228 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2229 fixvfork(tcp);
2230#endif /* SUNOS4 */
2231 }
2232 if (tcp->flags & TCB_BPTSET) {
2233 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2234 droptcb(tcp);
2235 cleanup();
2236 return -1;
2237 }
2238 }
2239 goto tracing;
2240 }
2241
2242 if (WSTOPSIG(status) != SIGTRAP) {
2243 if (WSTOPSIG(status) == SIGSTOP &&
2244 (tcp->flags & TCB_SIGTRAPPED)) {
2245 /*
2246 * Trapped attempt to block SIGTRAP
2247 * Hope we are back in control now.
2248 */
2249 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2250 if (ptrace(PTRACE_SYSCALL,
2251 pid, (char *) 1, 0) < 0) {
2252 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2253 cleanup();
2254 return -1;
2255 }
2256 continue;
2257 }
2258 if (!cflag
2259 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002260 unsigned long addr = 0, pc = 0;
2261#ifdef PT_GETSIGINFO
2262# define PSR_RI 41
2263 struct siginfo si;
2264 unsigned long psr;
2265
2266 upeek(pid, PT_CR_IPSR, &psr);
2267 upeek(pid, PT_CR_IIP, &pc);
2268
2269 pc += (psr >> PSR_RI) & 0x3;
2270 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2271 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002272#elif defined PTRACE_GETSIGINFO
2273 if (WSTOPSIG(status) == SIGSEGV ||
2274 WSTOPSIG(status) == SIGBUS) {
2275 siginfo_t si;
2276 if (ptrace(PTRACE_GETSIGINFO, pid,
2277 0, &si) == 0)
2278 addr = (unsigned long)
2279 si.si_addr;
2280 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002281#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002282 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002283 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002284 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002285 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002286 printtrailer(tcp);
2287 }
Roland McGrath05690952004-10-20 01:00:27 +00002288 if (((tcp->flags & TCB_ATTACHED) ||
2289 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002290 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002291#ifdef TCB_GROUP_EXITING
2292 handle_group_exit(tcp, WSTOPSIG(status));
2293#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002294 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002295#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002296 continue;
2297 }
2298 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2299 WSTOPSIG(status)) < 0) {
2300 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2301 cleanup();
2302 return -1;
2303 }
2304 tcp->flags &= ~TCB_SUSPENDED;
2305 continue;
2306 }
2307 if (trace_syscall(tcp) < 0) {
2308 if (tcp->flags & TCB_ATTACHED)
2309 detach(tcp, 0);
2310 else {
2311 ptrace(PTRACE_KILL,
2312 tcp->pid, (char *) 1, SIGTERM);
2313 droptcb(tcp);
2314 }
2315 continue;
2316 }
2317 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002318#ifdef TCB_GROUP_EXITING
2319 if (tcp->flags & TCB_GROUP_EXITING) {
2320 if (handle_group_exit(tcp, 0) < 0)
2321 return -1;
2322 continue;
2323 }
2324#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002325 if (tcp->flags & TCB_ATTACHED)
2326 detach(tcp, 0);
2327 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2328 perror("strace: ptrace(PTRACE_CONT, ...)");
2329 cleanup();
2330 return -1;
2331 }
2332 continue;
2333 }
2334 if (tcp->flags & TCB_SUSPENDED) {
2335 if (!qflag)
2336 fprintf(stderr, "Process %u suspended\n", pid);
2337 continue;
2338 }
2339 tracing:
2340 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2341 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2342 cleanup();
2343 return -1;
2344 }
2345 }
2346 return 0;
2347}
2348
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002349#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002350
2351static int curcol;
2352
2353#ifdef __STDC__
2354#include <stdarg.h>
2355#define VA_START(a, b) va_start(a, b)
2356#else
2357#include <varargs.h>
2358#define VA_START(a, b) va_start(a)
2359#endif
2360
2361void
2362#ifdef __STDC__
2363tprintf(const char *fmt, ...)
2364#else
2365tprintf(fmt, va_alist)
2366char *fmt;
2367va_dcl
2368#endif
2369{
2370 va_list args;
2371
2372 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002373 if (outf) {
2374 int n = vfprintf(outf, fmt, args);
2375 if (n < 0 && outf != stderr)
2376 perror(outfname == NULL
2377 ? "<writing to pipe>" : outfname);
2378 else
2379 curcol += n;
2380 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002381 va_end(args);
2382 return;
2383}
2384
2385void
2386printleader(tcp)
2387struct tcb *tcp;
2388{
2389 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2390 tcp_last->flags |= TCB_REPRINT;
2391 tprintf(" <unfinished ...>\n");
2392 }
2393 curcol = 0;
2394 if ((followfork == 1 || pflag_seen > 1) && outfname)
2395 tprintf("%-5d ", tcp->pid);
2396 else if (nprocs > 1 && !outfname)
2397 tprintf("[pid %5u] ", tcp->pid);
2398 if (tflag) {
2399 char str[sizeof("HH:MM:SS")];
2400 struct timeval tv, dtv;
2401 static struct timeval otv;
2402
2403 gettimeofday(&tv, NULL);
2404 if (rflag) {
2405 if (otv.tv_sec == 0)
2406 otv = tv;
2407 tv_sub(&dtv, &tv, &otv);
2408 tprintf("%6ld.%06ld ",
2409 (long) dtv.tv_sec, (long) dtv.tv_usec);
2410 otv = tv;
2411 }
2412 else if (tflag > 2) {
2413 tprintf("%ld.%06ld ",
2414 (long) tv.tv_sec, (long) tv.tv_usec);
2415 }
2416 else {
2417 time_t local = tv.tv_sec;
2418 strftime(str, sizeof(str), "%T", localtime(&local));
2419 if (tflag > 1)
2420 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2421 else
2422 tprintf("%s ", str);
2423 }
2424 }
2425 if (iflag)
2426 printcall(tcp);
2427}
2428
2429void
2430tabto(col)
2431int col;
2432{
2433 if (curcol < col)
2434 tprintf("%*s", col - curcol, "");
2435}
2436
2437void
2438printtrailer(tcp)
2439struct tcb *tcp;
2440{
2441 tprintf("\n");
2442 tcp_last = NULL;
2443}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002444
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002445#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002446
2447int mp_ioctl (int fd, int cmd, void *arg, int size) {
2448
2449 struct iovec iov[2];
2450 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002451
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002452 iov[0].iov_base = &cmd;
2453 iov[0].iov_len = sizeof cmd;
2454 if (arg) {
2455 ++n;
2456 iov[1].iov_base = arg;
2457 iov[1].iov_len = size;
2458 }
Roland McGrath553a6092002-12-16 20:40:39 +00002459
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002460 return writev (fd, iov, n);
2461}
2462
2463#endif