blob: d13243d6143f0846d7ce6642a30ad3faa48001ff [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00006 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $Id$
31 */
32
33#include "defs.h"
34
Roland McGrath795edb12005-02-02 04:44:57 +000035#include <sys/types.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000036#include <signal.h>
37#include <errno.h>
38#include <sys/param.h>
39#include <fcntl.h>
40#include <sys/resource.h>
41#include <sys/wait.h>
42#include <sys/stat.h>
43#include <pwd.h>
44#include <grp.h>
45#include <string.h>
John Hughes19e49982001-10-19 08:59:12 +000046#include <limits.h>
Roland McGrath70b08532004-04-09 00:25:21 +000047#include <dirent.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000048
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000049#if defined(IA64) && defined(LINUX)
50# include <asm/ptrace_offsets.h>
51#endif
52
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000053#ifdef USE_PROCFS
54#include <poll.h>
55#endif
56
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000057#ifdef SVR4
58#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000059#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000060#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000061#include <sys/uio.h>
62#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000063#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000064#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000065
66int debug = 0, followfork = 0, followvfork = 0, interactive = 0;
67int rflag = 0, tflag = 0, dtime = 0, cflag = 0;
68int iflag = 0, xflag = 0, qflag = 0;
69int pflag_seen = 0;
70
Michal Ludvig17f8fb32002-11-06 13:17:21 +000071/* Sometimes we want to print only succeeding syscalls. */
72int not_failing_only = 0;
73
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000074char *username = NULL;
75uid_t run_uid;
76gid_t run_gid;
77
78int acolumn = DEFAULT_ACOLUMN;
79int max_strlen = DEFAULT_STRLEN;
80char *outfname = NULL;
81FILE *outf;
Roland McGrathee9d4352002-12-18 04:16:10 +000082struct tcb **tcbtab;
83unsigned int nprocs, tcbtabsize;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000084char *progname;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000085extern char **environ;
86
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000087static int trace P((void));
88static void cleanup P((void));
89static void interrupt P((int sig));
90static sigset_t empty_set, blocked_set;
91
92#ifdef HAVE_SIG_ATOMIC_T
93static volatile sig_atomic_t interrupted;
94#else /* !HAVE_SIG_ATOMIC_T */
95#ifdef __STDC__
96static volatile int interrupted;
97#else /* !__STDC__ */
98static int interrupted;
99#endif /* !__STDC__ */
100#endif /* !HAVE_SIG_ATOMIC_T */
101
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000102#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000103
104static struct tcb *pfd2tcb P((int pfd));
105static void reaper P((int sig));
106static void rebuild_pollv P((void));
Roland McGrathee9d4352002-12-18 04:16:10 +0000107static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000108
109#ifndef HAVE_POLLABLE_PROCFS
110
111static void proc_poll_open P((void));
112static void proc_poller P((int pfd));
113
114struct proc_pollfd {
115 int fd;
116 int revents;
117 int pid;
118};
119
120static int poller_pid;
121static int proc_poll_pipe[2] = { -1, -1 };
122
123#endif /* !HAVE_POLLABLE_PROCFS */
124
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000125#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000126#define POLLWANT POLLWRNORM
127#else
128#define POLLWANT POLLPRI
129#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000130#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000131
132static void
133usage(ofp, exitval)
134FILE *ofp;
135int exitval;
136{
137 fprintf(ofp, "\
138usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000139 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
140 [command [arg ...]]\n\
141 or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
142 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000143-c -- count time, calls, and errors for each syscall and report summary\n\
144-f -- follow forks, -ff -- with output into separate files\n\
145-F -- attempt to follow vforks, -h -- print help message\n\
146-i -- print instruction pointer at time of syscall\n\
147-q -- suppress messages about attaching, detaching, etc.\n\
148-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
149-T -- print time spent in each syscall, -V -- print version\n\
150-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
151-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
152-a column -- alignment COLUMN for printing syscall results (default %d)\n\
153-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
154 options: trace, abbrev, verbose, raw, signal, read, or write\n\
155-o file -- send trace output to FILE instead of stderr\n\
156-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
157-p pid -- trace process with process id PID, may be repeated\n\
158-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
159-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
160-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000161-E var=val -- put var=val in the environment for command\n\
162-E var -- remove var from the environment for command\n\
163" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000164-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000165 */
166, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000167 exit(exitval);
168}
169
170#ifdef SVR4
171#ifdef MIPS
172void
173foobar()
174{
175}
176#endif /* MIPS */
177#endif /* SVR4 */
178
179int
180main(argc, argv)
181int argc;
182char *argv[];
183{
184 extern int optind;
185 extern char *optarg;
186 struct tcb *tcp;
187 int c, pid = 0;
188 struct sigaction sa;
189
190 static char buf[BUFSIZ];
191
Roland McGrathee9d4352002-12-18 04:16:10 +0000192 /* Allocate the initial tcbtab. */
193 tcbtabsize = argc; /* Surely enough for all -p args. */
194 tcbtab = (struct tcb **) malloc (tcbtabsize * sizeof tcbtab[0]);
195 tcbtab[0] = (struct tcb *) calloc (tcbtabsize, sizeof *tcbtab[0]);
196 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
197 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
198
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000199 progname = argv[0];
200 outf = stderr;
201 interactive = 1;
202 qualify("trace=all");
203 qualify("abbrev=all");
204 qualify("verbose=all");
205 qualify("signal=all");
206 set_sortby(DEFAULT_SORTBY);
207 set_personality(DEFAULT_PERSONALITY);
208 while ((c = getopt(argc, argv,
Roland McGrathde6e5332003-01-24 04:31:23 +0000209 "+cdfFhiqrtTvVxza:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000210 switch (c) {
211 case 'c':
212 cflag++;
213 dtime++;
214 break;
215 case 'd':
216 debug++;
217 break;
218 case 'f':
219 followfork++;
220 break;
221 case 'F':
222 followvfork++;
223 break;
224 case 'h':
225 usage(stdout, 0);
226 break;
227 case 'i':
228 iflag++;
229 break;
230 case 'q':
231 qflag++;
232 break;
233 case 'r':
234 rflag++;
235 tflag++;
236 break;
237 case 't':
238 tflag++;
239 break;
240 case 'T':
241 dtime++;
242 break;
243 case 'x':
244 xflag++;
245 break;
246 case 'v':
247 qualify("abbrev=none");
248 break;
249 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000250 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000251 exit(0);
252 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000253 case 'z':
254 not_failing_only = 1;
255 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000256 case 'a':
257 acolumn = atoi(optarg);
258 break;
259 case 'e':
260 qualify(optarg);
261 break;
262 case 'o':
263 outfname = strdup(optarg);
264 break;
265 case 'O':
266 set_overhead(atoi(optarg));
267 break;
268 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000269 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000270 fprintf(stderr, "%s: Invalid process id: %s\n",
271 progname, optarg);
272 break;
273 }
274 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000275 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000276 break;
277 }
278 if ((tcp = alloctcb(pid)) == NULL) {
Roland McGrathde6e5332003-01-24 04:31:23 +0000279 fprintf(stderr, "%s: out of memory\n",
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 progname);
281 exit(1);
282 }
283 tcp->flags |= TCB_ATTACHED;
284 pflag_seen++;
285 break;
286 case 's':
287 max_strlen = atoi(optarg);
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 McGrathce0d1542003-11-11 21:24:23 +0000314 if (optind == argc && !pflag_seen)
315 usage(stderr, 1);
316
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000317 /* See if they want to run as another user. */
318 if (username != NULL) {
319 struct passwd *pent;
320
321 if (getuid() != 0 || geteuid() != 0) {
322 fprintf(stderr,
323 "%s: you must be root to use the -u option\n",
324 progname);
325 exit(1);
326 }
327 if ((pent = getpwnam(username)) == NULL) {
328 fprintf(stderr, "%s: cannot find user `%s'\n",
329 progname, optarg);
330 exit(1);
331 }
332 run_uid = pent->pw_uid;
333 run_gid = pent->pw_gid;
334 }
335 else {
336 run_uid = getuid();
337 run_gid = getgid();
338 }
339
340#ifndef SVR4
341 setreuid(geteuid(), getuid());
342#endif
343
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000344 /* Check if they want to redirect the output. */
345 if (outfname) {
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000346 long f;
347
Roland McGrath37b9a662003-11-07 02:26:54 +0000348 /* See if they want to pipe the output. */
349 if (outfname[0] == '|' || outfname[0] == '!') {
350 /*
351 * We can't do the <outfname>.PID funny business
352 * when using popen, so prohibit it.
353 */
354 if (followfork > 1) {
355 fprintf(stderr, "\
356%s: piping the output and -ff are mutually exclusive options\n",
357 progname);
358 exit(1);
359 }
360
361 if ((outf = popen(outfname + 1, "w")) == NULL) {
362 fprintf(stderr, "%s: can't popen '%s': %s\n",
363 progname, outfname + 1,
364 strerror(errno));
365 exit(1);
366 }
367 }
368 else if ((outf = fopen(outfname, "w")) == NULL) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000369 fprintf(stderr, "%s: can't fopen '%s': %s\n",
370 progname, outfname, strerror(errno));
371 exit(1);
372 }
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000373
374 if ((f=fcntl(fileno(outf), F_GETFD)) < 0 ) {
375 perror("failed to get flags for outputfile");
376 exit(1);
377 }
378
379 if (fcntl(fileno(outf), F_SETFD, f|FD_CLOEXEC) < 0 ) {
380 perror("failed to set flags for outputfile");
381 exit(1);
382 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000383 }
384
385#ifndef SVR4
386 setreuid(geteuid(), getuid());
387#endif
388
Roland McGrath37b9a662003-11-07 02:26:54 +0000389 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000390 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000391 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000392 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000393 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000394 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000395
Roland McGrathee9d4352002-12-18 04:16:10 +0000396 for (c = 0; c < tcbtabsize; c++) {
397 tcp = tcbtab[c];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000398 /* Reinitialize the output since it may have changed. */
399 tcp->outf = outf;
400 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
401 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000402#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000403 if (proc_open(tcp, 1) < 0) {
404 fprintf(stderr, "trouble opening proc file\n");
405 droptcb(tcp);
406 continue;
407 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000408#else /* !USE_PROCFS */
Roland McGrath70b08532004-04-09 00:25:21 +0000409# ifdef LINUX
410 if (tcp->flags & TCB_CLONE_THREAD)
411 continue;
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000412 if (followfork) {
Roland McGrath70b08532004-04-09 00:25:21 +0000413 char procdir[MAXPATHLEN];
414 DIR *dir;
415 sprintf(procdir, "/proc/%d/task", tcp->pid);
416 dir = opendir(procdir);
417 if (dir != NULL) {
418 unsigned int ntid = 0, nerr = 0;
419 struct dirent *de;
420 int tid;
421 while ((de = readdir(dir)) != NULL) {
422 if (de->d_fileno == 0 ||
423 de->d_name[0] == '.')
424 continue;
425 tid = atoi(de->d_name);
426 if (tid <= 0)
427 continue;
428 ++ntid;
429 if (ptrace(PTRACE_ATTACH, tid,
430 (char *) 1, 0) < 0)
431 ++nerr;
432 else if (tid != tcbtab[c]->pid) {
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000433 if (nprocs == tcbtabsize &&
434 expand_tcbtab())
435 tcp = NULL;
436 else
437 tcp = alloctcb(tid);
Roland McGrath70b08532004-04-09 00:25:21 +0000438 if (tcp == NULL) {
439 fprintf(stderr, "%s: out of memory\n",
440 progname);
441 exit(1);
442 }
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000443 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK;
Roland McGrath70b08532004-04-09 00:25:21 +0000444 tcbtab[c]->nchildren++;
445 tcbtab[c]->nclone_threads++;
446 tcbtab[c]->nclone_detached++;
447 tcp->parent = tcbtab[c];
448 }
449 }
450 closedir(dir);
451 if (nerr == ntid) {
452 perror("attach: ptrace(PTRACE_ATTACH, ...)");
453 droptcb(tcp);
454 continue;
455 }
456 if (!qflag) {
457 ntid -= nerr;
458 if (ntid > 1)
459 fprintf(stderr, "\
460Process %u attached with %u threads - interrupt to quit\n",
461 tcp->pid, ntid);
462 else
463 fprintf(stderr, "\
464Process %u attached - interrupt to quit\n",
465 tcp->pid);
466 }
467 continue;
468 }
469 }
470# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000471 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
472 perror("attach: ptrace(PTRACE_ATTACH, ...)");
473 droptcb(tcp);
474 continue;
475 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000476#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000477 if (!qflag)
478 fprintf(stderr,
479 "Process %u attached - interrupt to quit\n",
Roland McGrathc3266d52004-02-20 02:23:52 +0000480 tcp->pid);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000481 }
482
Roland McGrathce0d1542003-11-11 21:24:23 +0000483 if (!pflag_seen) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000484 struct stat statbuf;
485 char *filename;
486 char pathname[MAXPATHLEN];
487
488 filename = argv[optind];
Roland McGrathbdb09df2004-03-02 06:50:04 +0000489 if (strchr(filename, '/')) {
490 if (strlen(filename) > sizeof pathname - 1) {
491 errno = ENAMETOOLONG;
492 perror("strace: exec");
493 exit(1);
494 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000495 strcpy(pathname, filename);
Roland McGrathbdb09df2004-03-02 06:50:04 +0000496 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000497#ifdef USE_DEBUGGING_EXEC
498 /*
499 * Debuggers customarily check the current directory
500 * first regardless of the path but doing that gives
501 * security geeks a panic attack.
502 */
503 else if (stat(filename, &statbuf) == 0)
504 strcpy(pathname, filename);
505#endif /* USE_DEBUGGING_EXEC */
506 else {
507 char *path;
508 int m, n, len;
509
510 for (path = getenv("PATH"); path && *path; path += m) {
511 if (strchr(path, ':')) {
512 n = strchr(path, ':') - path;
513 m = n + 1;
514 }
515 else
516 m = n = strlen(path);
517 if (n == 0) {
518 getcwd(pathname, MAXPATHLEN);
519 len = strlen(pathname);
520 }
Roland McGrathbdb09df2004-03-02 06:50:04 +0000521 else if (n > sizeof pathname - 1)
522 continue;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000523 else {
524 strncpy(pathname, path, n);
525 len = n;
526 }
527 if (len && pathname[len - 1] != '/')
528 pathname[len++] = '/';
529 strcpy(pathname + len, filename);
Roland McGrathed645162003-06-03 07:18:19 +0000530 if (stat(pathname, &statbuf) == 0 &&
531 /* Accept only regular files
532 with some execute bits set.
533 XXX not perfect, might still fail */
534 S_ISREG(statbuf.st_mode) &&
535 (statbuf.st_mode & 0111))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000536 break;
537 }
538 }
539 if (stat(pathname, &statbuf) < 0) {
540 fprintf(stderr, "%s: %s: command not found\n",
541 progname, filename);
542 exit(1);
543 }
544 switch (pid = fork()) {
545 case -1:
546 perror("strace: fork");
547 cleanup();
548 exit(1);
549 break;
550 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000551#ifdef USE_PROCFS
552 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000553#ifdef MIPS
554 /* Kludge for SGI, see proc_open for details. */
555 sa.sa_handler = foobar;
556 sa.sa_flags = 0;
557 sigemptyset(&sa.sa_mask);
558 sigaction(SIGINT, &sa, NULL);
559#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000560#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000561 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000562#else /* FREEBSD */
563 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000564#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000565#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000566 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000567 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000568
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000569 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
570 perror("strace: ptrace(PTRACE_TRACEME, ...)");
571 return -1;
572 }
573 if (debug)
574 kill(getpid(), SIGSTOP);
575
576 if (username != NULL || geteuid() == 0) {
577 uid_t run_euid = run_uid;
578 gid_t run_egid = run_gid;
579
580 if (statbuf.st_mode & S_ISUID)
581 run_euid = statbuf.st_uid;
582 if (statbuf.st_mode & S_ISGID)
583 run_egid = statbuf.st_gid;
584
585 /*
586 * It is important to set groups before we
587 * lose privileges on setuid.
588 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000589 if (username != NULL) {
590 if (initgroups(username, run_gid) < 0) {
591 perror("initgroups");
592 exit(1);
593 }
594 if (setregid(run_gid, run_egid) < 0) {
595 perror("setregid");
596 exit(1);
597 }
598 if (setreuid(run_uid, run_euid) < 0) {
599 perror("setreuid");
600 exit(1);
601 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602 }
603 }
604 else
605 setreuid(run_uid, run_uid);
Roland McGrath15dca8e2005-02-06 01:16:32 +0000606
607 /*
608 * Induce an immediate stop so that the parent
609 * will resume us with PTRACE_SYSCALL and display
610 * this execve call normally.
611 */
612 kill(getpid(), SIGSTOP);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000613#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000614
615 execv(pathname, &argv[optind]);
616 perror("strace: exec");
617 _exit(1);
618 break;
619 }
620 default:
621 if ((tcp = alloctcb(pid)) == NULL) {
622 fprintf(stderr, "tcb table full\n");
623 cleanup();
624 exit(1);
625 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000626#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000627 if (proc_open(tcp, 0) < 0) {
628 fprintf(stderr, "trouble opening proc file\n");
629 cleanup();
630 exit(1);
631 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000632#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000633 break;
634 }
635 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000636
637 sigemptyset(&empty_set);
638 sigemptyset(&blocked_set);
639 sa.sa_handler = SIG_IGN;
640 sigemptyset(&sa.sa_mask);
641 sa.sa_flags = 0;
642 sigaction(SIGTTOU, &sa, NULL);
643 sigaction(SIGTTIN, &sa, NULL);
644 if (interactive) {
645 sigaddset(&blocked_set, SIGHUP);
646 sigaddset(&blocked_set, SIGINT);
647 sigaddset(&blocked_set, SIGQUIT);
648 sigaddset(&blocked_set, SIGPIPE);
649 sigaddset(&blocked_set, SIGTERM);
650 sa.sa_handler = interrupt;
651#ifdef SUNOS4
652 /* POSIX signals on sunos4.1 are a little broken. */
653 sa.sa_flags = SA_INTERRUPT;
654#endif /* SUNOS4 */
655 }
656 sigaction(SIGHUP, &sa, NULL);
657 sigaction(SIGINT, &sa, NULL);
658 sigaction(SIGQUIT, &sa, NULL);
659 sigaction(SIGPIPE, &sa, NULL);
660 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000661#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000662 sa.sa_handler = reaper;
663 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000664#else
665 /* Make sure SIGCHLD has the default action so that waitpid
666 definitely works without losing track of children. The user
667 should not have given us a bogus state to inherit, but he might
668 have. Arguably we should detect SIG_IGN here and pass it on
669 to children, but probably noone really needs that. */
670 sa.sa_handler = SIG_DFL;
671 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000672#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000673
674 if (trace() < 0)
675 exit(1);
676 cleanup();
677 exit(0);
678}
679
680void
681newoutf(tcp)
682struct tcb *tcp;
683{
684 char name[MAXPATHLEN];
685 FILE *fp;
686
687 if (outfname && followfork > 1) {
688 sprintf(name, "%s.%u", outfname, tcp->pid);
689#ifndef SVR4
690 setreuid(geteuid(), getuid());
691#endif
692 fp = fopen(name, "w");
693#ifndef SVR4
694 setreuid(geteuid(), getuid());
695#endif
696 if (fp == NULL) {
697 perror("fopen");
698 return;
699 }
700 tcp->outf = fp;
701 }
702 return;
703}
704
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000705int
706expand_tcbtab()
707{
708 /* Allocate some more TCBs and expand the table.
709 We don't want to relocate the TCBs because our
710 callers have pointers and it would be a pain.
711 So tcbtab is a table of pointers. Since we never
712 free the TCBs, we allocate a single chunk of many. */
713 struct tcb **newtab = (struct tcb **)
714 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
715 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
716 sizeof *newtcbs);
717 int i;
718 if (newtab == NULL || newtcbs == NULL) {
719 if (newtab != NULL)
720 free(newtab);
721 return 1;
722 }
723 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
724 newtab[i] = &newtcbs[i - tcbtabsize];
725 tcbtabsize *= 2;
726 tcbtab = newtab;
727
728 return 0;
729}
730
731
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000732struct tcb *
733alloctcb(pid)
734int pid;
735{
736 int i;
737 struct tcb *tcp;
738
Roland McGrathee9d4352002-12-18 04:16:10 +0000739 for (i = 0; i < tcbtabsize; i++) {
740 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000741 if ((tcp->flags & TCB_INUSE) == 0) {
742 tcp->pid = pid;
743 tcp->parent = NULL;
744 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000745 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000746#ifdef TCB_CLONE_THREAD
747 tcp->nclone_threads = tcp->nclone_detached = 0;
748 tcp->nclone_waiting = 0;
749#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000750 tcp->flags = TCB_INUSE | TCB_STARTUP;
751 tcp->outf = outf; /* Initialise to current out file */
752 tcp->stime.tv_sec = 0;
753 tcp->stime.tv_usec = 0;
754 tcp->pfd = -1;
755 nprocs++;
756 return tcp;
757 }
758 }
759 return NULL;
760}
761
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000762#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763int
764proc_open(tcp, attaching)
765struct tcb *tcp;
766int attaching;
767{
768 char proc[32];
769 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000770#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000771 int i;
772 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000773 sigset_t signals;
774 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000775#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776#ifndef HAVE_POLLABLE_PROCFS
777 static int last_pfd;
778#endif
779
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000780#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000781 /* Open the process pseudo-files in /proc. */
782 sprintf(proc, "/proc/%d/ctl", tcp->pid);
783 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000784 perror("strace: open(\"/proc/...\", ...)");
785 return -1;
786 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000787 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
788 perror("F_GETFD");
789 return -1;
790 }
791 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
792 perror("F_SETFD");
793 return -1;
794 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000795 sprintf(proc, "/proc/%d/status", tcp->pid);
796 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
797 perror("strace: open(\"/proc/...\", ...)");
798 return -1;
799 }
800 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
801 perror("F_GETFD");
802 return -1;
803 }
804 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
805 perror("F_SETFD");
806 return -1;
807 }
808 sprintf(proc, "/proc/%d/as", tcp->pid);
809 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
810 perror("strace: open(\"/proc/...\", ...)");
811 return -1;
812 }
813 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
814 perror("F_GETFD");
815 return -1;
816 }
817 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
818 perror("F_SETFD");
819 return -1;
820 }
821#else
822 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000823#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000824 sprintf(proc, "/proc/%d", tcp->pid);
825 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000826#else /* FREEBSD */
827 sprintf(proc, "/proc/%d/mem", tcp->pid);
828 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
829#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000830 perror("strace: open(\"/proc/...\", ...)");
831 return -1;
832 }
833 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
834 perror("F_GETFD");
835 return -1;
836 }
837 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
838 perror("F_SETFD");
839 return -1;
840 }
841#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000842#ifdef FREEBSD
843 sprintf(proc, "/proc/%d/regs", tcp->pid);
844 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
845 perror("strace: open(\"/proc/.../regs\", ...)");
846 return -1;
847 }
848 if (cflag) {
849 sprintf(proc, "/proc/%d/status", tcp->pid);
850 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
851 perror("strace: open(\"/proc/.../status\", ...)");
852 return -1;
853 }
854 } else
855 tcp->pfd_status = -1;
856#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000857 rebuild_pollv();
858 if (!attaching) {
859 /*
860 * Wait for the child to pause. Because of a race
861 * condition we have to poll for the event.
862 */
863 for (;;) {
864 if (IOCTL_STATUS (tcp) < 0) {
865 perror("strace: PIOCSTATUS");
866 return -1;
867 }
868 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000869 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000870 }
871 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000872#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000873 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000874 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000875 perror("strace: PIOCSTOP");
876 return -1;
877 }
Roland McGrath553a6092002-12-16 20:40:39 +0000878#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000879#ifdef PIOCSET
880 /* Set Run-on-Last-Close. */
881 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000882 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883 perror("PIOCSET PR_RLC");
884 return -1;
885 }
886 /* Set or Reset Inherit-on-Fork. */
887 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000888 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000889 perror("PIOC{SET,RESET} PR_FORK");
890 return -1;
891 }
892#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000893#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
895 perror("PIOCSRLC");
896 return -1;
897 }
898 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
899 perror("PIOC{S,R}FORK");
900 return -1;
901 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000902#else /* FREEBSD */
903 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
904 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
905 perror("PIOCGFL");
906 return -1;
907 }
908 arg &= ~PF_LINGER;
909 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
910 perror("PIOCSFL");
911 return -1;
912 }
913#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000914#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000915#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000916 /* Enable all syscall entries we care about. */
917 premptyset(&syscalls);
918 for (i = 1; i < MAX_QUALS; ++i) {
919 if (i > (sizeof syscalls) * CHAR_BIT) break;
920 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
921 }
922 praddset (&syscalls, SYS_execve);
923 if (followfork) {
924 praddset (&syscalls, SYS_fork);
925#ifdef SYS_forkall
926 praddset (&syscalls, SYS_forkall);
927#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000928#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000929 praddset (&syscalls, SYS_fork1);
930#endif
931#ifdef SYS_rfork1
932 praddset (&syscalls, SYS_rfork1);
933#endif
934#ifdef SYS_rforkall
935 praddset (&syscalls, SYS_rforkall);
936#endif
937 }
938 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000939 perror("PIOCSENTRY");
940 return -1;
941 }
John Hughes19e49982001-10-19 08:59:12 +0000942 /* Enable the syscall exits. */
943 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000944 perror("PIOSEXIT");
945 return -1;
946 }
John Hughes19e49982001-10-19 08:59:12 +0000947 /* Enable signals we care about. */
948 premptyset(&signals);
949 for (i = 1; i < MAX_QUALS; ++i) {
950 if (i > (sizeof signals) * CHAR_BIT) break;
951 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
952 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000953 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000954 perror("PIOCSTRACE");
955 return -1;
956 }
John Hughes19e49982001-10-19 08:59:12 +0000957 /* Enable faults we care about */
958 premptyset(&faults);
959 for (i = 1; i < MAX_QUALS; ++i) {
960 if (i > (sizeof faults) * CHAR_BIT) break;
961 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
962 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000963 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000964 perror("PIOCSFAULT");
965 return -1;
966 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000967#else /* FREEBSD */
968 /* set events flags. */
969 arg = S_SIG | S_SCE | S_SCX ;
970 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
971 perror("PIOCBIS");
972 return -1;
973 }
974#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000975 if (!attaching) {
976#ifdef MIPS
977 /*
978 * The SGI PRSABORT doesn't work for pause() so
979 * we send it a caught signal to wake it up.
980 */
981 kill(tcp->pid, SIGINT);
982#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000983#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000984 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000985 arg = PRSABORT;
986 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987 perror("PIOCRUN");
988 return -1;
989 }
Roland McGrath553a6092002-12-16 20:40:39 +0000990#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000991#endif /* !MIPS*/
992#ifdef FREEBSD
993 /* wake up the child if it received the SIGSTOP */
994 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000995#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000996 for (;;) {
997 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000998 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000999 perror("PIOCWSTOP");
1000 return -1;
1001 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001002 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001003 tcp->flags &= ~TCB_INSYSCALL;
1004 get_scno(tcp);
1005 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001006 break;
1007 }
1008 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001009#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001010 arg = 0;
1011 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001012#else /* FREEBSD */
1013 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001014#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001015 perror("PIOCRUN");
1016 return -1;
1017 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001018#ifdef FREEBSD
1019 /* handle the case where we "opened" the child before
1020 it did the kill -STOP */
1021 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1022 tcp->status.PR_WHAT == SIGSTOP)
1023 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001024#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001026#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001028#else /* FREEBSD */
1029 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001030 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001031 /* We are attaching to an already running process.
1032 * Try to figure out the state of the process in syscalls,
1033 * to handle the first event well.
1034 * This is done by having a look at the "wchan" property of the
1035 * process, which tells where it is stopped (if it is). */
1036 FILE * status;
1037 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001038
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001039 sprintf(proc, "/proc/%d/status", tcp->pid);
1040 status = fopen(proc, "r");
1041 if (status &&
1042 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1043 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1044 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1045 strcmp(wchan, "stopevent")) {
1046 /* The process is asleep in the middle of a syscall.
1047 Fake the syscall entry event */
1048 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1049 tcp->status.PR_WHY = PR_SYSENTRY;
1050 trace_syscall(tcp);
1051 }
1052 if (status)
1053 fclose(status);
1054 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001055 }
1056#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001057#ifndef HAVE_POLLABLE_PROCFS
1058 if (proc_poll_pipe[0] != -1)
1059 proc_poller(tcp->pfd);
1060 else if (nprocs > 1) {
1061 proc_poll_open();
1062 proc_poller(last_pfd);
1063 proc_poller(tcp->pfd);
1064 }
1065 last_pfd = tcp->pfd;
1066#endif /* !HAVE_POLLABLE_PROCFS */
1067 return 0;
1068}
1069
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001070#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001072struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073pid2tcb(pid)
1074int pid;
1075{
1076 int i;
1077 struct tcb *tcp;
1078
Roland McGrathee9d4352002-12-18 04:16:10 +00001079 for (i = 0; i < tcbtabsize; i++) {
1080 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001081 if (pid && tcp->pid != pid)
1082 continue;
1083 if (tcp->flags & TCB_INUSE)
1084 return tcp;
1085 }
1086 return NULL;
1087}
1088
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001089#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001090
1091static struct tcb *
1092pfd2tcb(pfd)
1093int pfd;
1094{
1095 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001096
Roland McGrathca16be82003-01-10 19:55:28 +00001097 for (i = 0; i < tcbtabsize; i++) {
1098 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001099 if (tcp->pfd != pfd)
1100 continue;
1101 if (tcp->flags & TCB_INUSE)
1102 return tcp;
1103 }
1104 return NULL;
1105}
1106
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001107#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001108
1109void
1110droptcb(tcp)
1111struct tcb *tcp;
1112{
1113 if (tcp->pid == 0)
1114 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001115#ifdef TCB_CLONE_THREAD
1116 if (tcp->nclone_threads > 0) {
1117 /* There are other threads left in this process, but this
1118 is the one whose PID represents the whole process.
1119 We need to keep this record around as a zombie until
1120 all the threads die. */
1121 tcp->flags |= TCB_EXITING;
1122 return;
1123 }
1124#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 nprocs--;
1126 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001127
Roland McGrathe29341c2003-01-10 20:14:20 +00001128 if (tcp->parent != NULL) {
1129 tcp->parent->nchildren--;
1130#ifdef TCB_CLONE_THREAD
1131 if (tcp->flags & TCB_CLONE_DETACHED)
1132 tcp->parent->nclone_detached--;
1133 if (tcp->flags & TCB_CLONE_THREAD)
1134 tcp->parent->nclone_threads--;
1135#endif
Roland McGrath09623452003-05-23 02:27:13 +00001136#ifdef TCB_CLONE_DETACHED
1137 if (!(tcp->flags & TCB_CLONE_DETACHED))
1138#endif
1139 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001140 tcp->parent = NULL;
1141 }
1142
1143 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001144 if (tcp->pfd != -1) {
1145 close(tcp->pfd);
1146 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001147#ifdef FREEBSD
1148 if (tcp->pfd_reg != -1) {
1149 close(tcp->pfd_reg);
1150 tcp->pfd_reg = -1;
1151 }
1152 if (tcp->pfd_status != -1) {
1153 close(tcp->pfd_status);
1154 tcp->pfd_status = -1;
1155 }
Roland McGrath553a6092002-12-16 20:40:39 +00001156#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001157#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001158 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159#endif
1160 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001161
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001162 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001163 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001164
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165 tcp->outf = 0;
1166}
1167
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001168#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001169
1170static int
1171resume(tcp)
1172struct tcb *tcp;
1173{
1174 if (tcp == NULL)
1175 return -1;
1176
1177 if (!(tcp->flags & TCB_SUSPENDED)) {
1178 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1179 return -1;
1180 }
1181 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001182#ifdef TCB_CLONE_THREAD
1183 if (tcp->flags & TCB_CLONE_THREAD)
1184 tcp->parent->nclone_waiting--;
1185#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001186
1187 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1188 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1189 return -1;
1190 }
1191
1192 if (!qflag)
1193 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1194 return 0;
1195}
1196
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001197#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001198
1199/* detach traced process; continue with sig */
1200
1201static int
1202detach(tcp, sig)
1203struct tcb *tcp;
1204int sig;
1205{
1206 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001207#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001208 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001209#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001210
1211 if (tcp->flags & TCB_BPTSET)
1212 sig = SIGKILL;
1213
1214#ifdef LINUX
1215 /*
1216 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001217 * before detaching. Arghh. We go through hoops
1218 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001219 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001220#if defined(SPARC)
1221#undef PTRACE_DETACH
1222#define PTRACE_DETACH PTRACE_SUNDETACH
1223#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1225 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001226 }
1227 else if (errno != ESRCH) {
1228 /* Shouldn't happen. */
1229 perror("detach: ptrace(PTRACE_DETACH, ...)");
1230 }
1231 else if (kill(tcp->pid, 0) < 0) {
1232 if (errno != ESRCH)
1233 perror("detach: checking sanity");
1234 }
1235 else if (kill(tcp->pid, SIGSTOP) < 0) {
1236 if (errno != ESRCH)
1237 perror("detach: stopping child");
1238 }
1239 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001240 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001241#ifdef __WALL
1242 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1243 if (errno == ECHILD) /* Already gone. */
1244 break;
1245 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001246 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001247 break;
1248 }
1249#endif /* __WALL */
1250 /* No __WALL here. */
1251 if (waitpid(tcp->pid, &status, 0) < 0) {
1252 if (errno != ECHILD) {
1253 perror("detach: waiting");
1254 break;
1255 }
1256#ifdef __WCLONE
1257 /* If no processes, try clones. */
1258 if (wait4(tcp->pid, &status, __WCLONE,
1259 NULL) < 0) {
1260 if (errno != ECHILD)
1261 perror("detach: waiting");
1262 break;
1263 }
1264#endif /* __WCLONE */
1265 }
1266#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001267 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001268#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001269 if (!WIFSTOPPED(status)) {
1270 /* Au revoir, mon ami. */
1271 break;
1272 }
1273 if (WSTOPSIG(status) == SIGSTOP) {
1274 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001275 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001276 if (errno != ESRCH)
1277 perror("detach: ptrace(PTRACE_DETACH, ...)");
1278 /* I died trying. */
1279 }
1280 break;
1281 }
1282 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001283 WSTOPSIG(status) == SIGTRAP ?
1284 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001285 if (errno != ESRCH)
1286 perror("detach: ptrace(PTRACE_CONT, ...)");
1287 break;
1288 }
1289 }
1290 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001291#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001292
1293#if defined(SUNOS4)
1294 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1295 if (sig && kill(tcp->pid, sig) < 0)
1296 perror("detach: kill");
1297 sig = 0;
1298 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1299 perror("detach: ptrace(PTRACE_DETACH, ...)");
1300#endif /* SUNOS4 */
1301
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001302#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001303 resumed = 0;
1304
1305 /* XXX This won't always be quite right (but it never was).
1306 A waiter with argument 0 or < -1 is waiting for any pid in
1307 a particular pgrp, which this child might or might not be
1308 in. The waiter will only wake up if it's argument is -1
1309 or if it's waiting for tcp->pid's pgrp. It makes a
1310 difference to wake up a waiter when there might be more
1311 traced children, because it could get a false ECHILD
1312 error. OTOH, if this was the last child in the pgrp, then
1313 it ought to wake up and get ECHILD. We would have to
1314 search the system for all pid's in the pgrp to be sure.
1315
1316 && (t->waitpid == -1 ||
1317 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1318 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1319 */
1320
1321 if (tcp->parent &&
1322 (tcp->parent->flags & TCB_SUSPENDED) &&
1323 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1324 error = resume(tcp->parent);
1325 ++resumed;
1326 }
1327#ifdef TCB_CLONE_THREAD
1328 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1329 /* Some other threads of our parent are waiting too. */
1330 unsigned int i;
1331
1332 /* Resume all the threads that were waiting for this PID. */
1333 for (i = 0; i < tcbtabsize; i++) {
1334 struct tcb *t = tcbtab[i];
1335 if (t->parent == tcp->parent && t != tcp
1336 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1337 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1338 && t->waitpid == tcp->pid) {
1339 error |= resume (t);
1340 ++resumed;
1341 }
1342 }
1343 if (resumed == 0)
1344 /* Noone was waiting for this PID in particular,
1345 so now we might need to resume some wildcarders. */
1346 for (i = 0; i < tcbtabsize; i++) {
1347 struct tcb *t = tcbtab[i];
1348 if (t->parent == tcp->parent && t != tcp
1349 && ((t->flags
1350 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1351 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1352 && t->waitpid <= 0
1353 ) {
1354 error |= resume (t);
1355 break;
1356 }
1357 }
1358 }
1359#endif
1360
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001361#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001362
1363 if (!qflag)
1364 fprintf(stderr, "Process %u detached\n", tcp->pid);
1365
1366 droptcb(tcp);
1367 return error;
1368}
1369
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001370#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371
1372static void
1373reaper(sig)
1374int sig;
1375{
1376 int pid;
1377 int status;
1378
1379 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1380#if 0
1381 struct tcb *tcp;
1382
1383 tcp = pid2tcb(pid);
1384 if (tcp)
1385 droptcb(tcp);
1386#endif
1387 }
1388}
1389
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001390#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001391
1392static void
1393cleanup()
1394{
1395 int i;
1396 struct tcb *tcp;
1397
Roland McGrathee9d4352002-12-18 04:16:10 +00001398 for (i = 0; i < tcbtabsize; i++) {
1399 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001400 if (!(tcp->flags & TCB_INUSE))
1401 continue;
1402 if (debug)
1403 fprintf(stderr,
1404 "cleanup: looking at pid %u\n", tcp->pid);
1405 if (tcp_last &&
1406 (!outfname || followfork < 2 || tcp_last == tcp)) {
1407 tprintf(" <unfinished ...>\n");
1408 tcp_last = NULL;
1409 }
1410 if (tcp->flags & TCB_ATTACHED)
1411 detach(tcp, 0);
1412 else {
1413 kill(tcp->pid, SIGCONT);
1414 kill(tcp->pid, SIGTERM);
1415 }
1416 }
1417 if (cflag)
1418 call_summary(outf);
1419}
1420
1421static void
1422interrupt(sig)
1423int sig;
1424{
1425 interrupted = 1;
1426}
1427
1428#ifndef HAVE_STRERROR
1429
Roland McGrath6d2b3492002-12-30 00:51:30 +00001430#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001431extern int sys_nerr;
1432extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001433#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001434
1435const char *
1436strerror(errno)
1437int errno;
1438{
1439 static char buf[64];
1440
1441 if (errno < 1 || errno >= sys_nerr) {
1442 sprintf(buf, "Unknown error %d", errno);
1443 return buf;
1444 }
1445 return sys_errlist[errno];
1446}
1447
1448#endif /* HAVE_STERRROR */
1449
1450#ifndef HAVE_STRSIGNAL
1451
Roland McGrath8f474e02003-01-14 07:53:33 +00001452#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001453extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001454#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001455#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1456extern char *_sys_siglist[];
1457#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001458
1459const char *
1460strsignal(sig)
1461int sig;
1462{
1463 static char buf[64];
1464
1465 if (sig < 1 || sig >= NSIG) {
1466 sprintf(buf, "Unknown signal %d", sig);
1467 return buf;
1468 }
1469#ifdef HAVE__SYS_SIGLIST
1470 return _sys_siglist[sig];
1471#else
1472 return sys_siglist[sig];
1473#endif
1474}
1475
1476#endif /* HAVE_STRSIGNAL */
1477
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001478#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001479
1480static void
1481rebuild_pollv()
1482{
1483 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001484
Roland McGrathee9d4352002-12-18 04:16:10 +00001485 if (pollv != NULL)
1486 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001487 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001488 if (pollv == NULL) {
1489 fprintf(stderr, "strace: out of memory for poll vector\n");
1490 exit(1);
1491 }
1492
Roland McGrathca16be82003-01-10 19:55:28 +00001493 for (i = j = 0; i < tcbtabsize; i++) {
1494 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001495 if (!(tcp->flags & TCB_INUSE))
1496 continue;
1497 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001498 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001499 j++;
1500 }
1501 if (j != nprocs) {
1502 fprintf(stderr, "strace: proc miscount\n");
1503 exit(1);
1504 }
1505}
1506
1507#ifndef HAVE_POLLABLE_PROCFS
1508
1509static void
1510proc_poll_open()
1511{
1512 int arg;
1513 int i;
1514
1515 if (pipe(proc_poll_pipe) < 0) {
1516 perror("pipe");
1517 exit(1);
1518 }
1519 for (i = 0; i < 2; i++) {
1520 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1521 perror("F_GETFD");
1522 exit(1);
1523 }
1524 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1525 perror("F_SETFD");
1526 exit(1);
1527 }
1528 }
1529}
1530
1531static int
1532proc_poll(pollv, nfds, timeout)
1533struct pollfd *pollv;
1534int nfds;
1535int timeout;
1536{
1537 int i;
1538 int n;
1539 struct proc_pollfd pollinfo;
1540
1541 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1542 return n;
1543 if (n != sizeof(struct proc_pollfd)) {
1544 fprintf(stderr, "panic: short read: %d\n", n);
1545 exit(1);
1546 }
1547 for (i = 0; i < nprocs; i++) {
1548 if (pollv[i].fd == pollinfo.fd)
1549 pollv[i].revents = pollinfo.revents;
1550 else
1551 pollv[i].revents = 0;
1552 }
1553 poller_pid = pollinfo.pid;
1554 return 1;
1555}
1556
1557static void
1558wakeup_handler(sig)
1559int sig;
1560{
1561}
1562
1563static void
1564proc_poller(pfd)
1565int pfd;
1566{
1567 struct proc_pollfd pollinfo;
1568 struct sigaction sa;
1569 sigset_t blocked_set, empty_set;
1570 int i;
1571 int n;
1572 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001573#ifdef FREEBSD
1574 struct procfs_status pfs;
1575#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001576
1577 switch (fork()) {
1578 case -1:
1579 perror("fork");
1580 _exit(0);
1581 case 0:
1582 break;
1583 default:
1584 return;
1585 }
1586
1587 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1588 sa.sa_flags = 0;
1589 sigemptyset(&sa.sa_mask);
1590 sigaction(SIGHUP, &sa, NULL);
1591 sigaction(SIGINT, &sa, NULL);
1592 sigaction(SIGQUIT, &sa, NULL);
1593 sigaction(SIGPIPE, &sa, NULL);
1594 sigaction(SIGTERM, &sa, NULL);
1595 sa.sa_handler = wakeup_handler;
1596 sigaction(SIGUSR1, &sa, NULL);
1597 sigemptyset(&blocked_set);
1598 sigaddset(&blocked_set, SIGUSR1);
1599 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1600 sigemptyset(&empty_set);
1601
1602 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1603 perror("getrlimit(RLIMIT_NOFILE, ...)");
1604 _exit(0);
1605 }
1606 n = rl.rlim_cur;
1607 for (i = 0; i < n; i++) {
1608 if (i != pfd && i != proc_poll_pipe[1])
1609 close(i);
1610 }
1611
1612 pollinfo.fd = pfd;
1613 pollinfo.pid = getpid();
1614 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001615#ifndef FREEBSD
1616 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1617#else /* FREEBSD */
1618 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1619#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001620 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 switch (errno) {
1622 case EINTR:
1623 continue;
1624 case EBADF:
1625 pollinfo.revents = POLLERR;
1626 break;
1627 case ENOENT:
1628 pollinfo.revents = POLLHUP;
1629 break;
1630 default:
1631 perror("proc_poller: PIOCWSTOP");
1632 }
1633 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1634 _exit(0);
1635 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001636 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001637 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1638 sigsuspend(&empty_set);
1639 }
1640}
1641
1642#endif /* !HAVE_POLLABLE_PROCFS */
1643
1644static int
1645choose_pfd()
1646{
1647 int i, j;
1648 struct tcb *tcp;
1649
1650 static int last;
1651
1652 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001653 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001654 /*
1655 * The previous process is ready to run again. We'll
1656 * let it do so if it is currently in a syscall. This
1657 * heuristic improves the readability of the trace.
1658 */
1659 tcp = pfd2tcb(pollv[last].fd);
1660 if (tcp && (tcp->flags & TCB_INSYSCALL))
1661 return pollv[last].fd;
1662 }
1663
1664 for (i = 0; i < nprocs; i++) {
1665 /* Let competing children run round robin. */
1666 j = (i + last + 1) % nprocs;
1667 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1668 tcp = pfd2tcb(pollv[j].fd);
1669 if (!tcp) {
1670 fprintf(stderr, "strace: lost proc\n");
1671 exit(1);
1672 }
1673 droptcb(tcp);
1674 return -1;
1675 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001676 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001677 last = j;
1678 return pollv[j].fd;
1679 }
1680 }
1681 fprintf(stderr, "strace: nothing ready\n");
1682 exit(1);
1683}
1684
1685static int
1686trace()
1687{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001688#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001689 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001690#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001691 struct tcb *tcp;
1692 int pfd;
1693 int what;
1694 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001695 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001696
1697 for (;;) {
1698 if (interactive)
1699 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1700
1701 if (nprocs == 0)
1702 break;
1703
1704 switch (nprocs) {
1705 case 1:
1706#ifndef HAVE_POLLABLE_PROCFS
1707 if (proc_poll_pipe[0] == -1) {
1708#endif
1709 tcp = pid2tcb(0);
1710 if (!tcp)
1711 continue;
1712 pfd = tcp->pfd;
1713 if (pfd == -1)
1714 continue;
1715 break;
1716#ifndef HAVE_POLLABLE_PROCFS
1717 }
1718 /* fall through ... */
1719#endif /* !HAVE_POLLABLE_PROCFS */
1720 default:
1721#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001722#ifdef POLL_HACK
1723 /* On some systems (e.g. UnixWare) we get too much ugly
1724 "unfinished..." stuff when multiple proceses are in
1725 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001726
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001727 if (in_syscall) {
1728 struct pollfd pv;
1729 tcp = in_syscall;
1730 in_syscall = NULL;
1731 pv.fd = tcp->pfd;
1732 pv.events = POLLWANT;
1733 if ((what = poll (&pv, 1, 1)) < 0) {
1734 if (interrupted)
1735 return 0;
1736 continue;
1737 }
1738 else if (what == 1 && pv.revents & POLLWANT) {
1739 goto FOUND;
1740 }
1741 }
1742#endif
1743
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001744 if (poll(pollv, nprocs, INFTIM) < 0) {
1745 if (interrupted)
1746 return 0;
1747 continue;
1748 }
1749#else /* !HAVE_POLLABLE_PROCFS */
1750 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1751 if (interrupted)
1752 return 0;
1753 continue;
1754 }
1755#endif /* !HAVE_POLLABLE_PROCFS */
1756 pfd = choose_pfd();
1757 if (pfd == -1)
1758 continue;
1759 break;
1760 }
1761
1762 /* Look up `pfd' in our table. */
1763 if ((tcp = pfd2tcb(pfd)) == NULL) {
1764 fprintf(stderr, "unknown pfd: %u\n", pfd);
1765 exit(1);
1766 }
John Hughesb6643082002-05-23 11:02:22 +00001767#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001768 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001769#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001770 /* Get the status of the process. */
1771 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001772#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001773 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001774#else /* FREEBSD */
1775 /* Thanks to some scheduling mystery, the first poller
1776 sometimes waits for the already processed end of fork
1777 event. Doing a non blocking poll here solves the problem. */
1778 if (proc_poll_pipe[0] != -1)
1779 ioctl_result = IOCTL_STATUS (tcp);
1780 else
1781 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001782#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001783 ioctl_errno = errno;
1784#ifndef HAVE_POLLABLE_PROCFS
1785 if (proc_poll_pipe[0] != -1) {
1786 if (ioctl_result < 0)
1787 kill(poller_pid, SIGKILL);
1788 else
1789 kill(poller_pid, SIGUSR1);
1790 }
1791#endif /* !HAVE_POLLABLE_PROCFS */
1792 }
1793 if (interrupted)
1794 return 0;
1795
1796 if (interactive)
1797 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1798
1799 if (ioctl_result < 0) {
1800 /* Find out what happened if it failed. */
1801 switch (ioctl_errno) {
1802 case EINTR:
1803 case EBADF:
1804 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001805#ifdef FREEBSD
1806 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001807#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001808 case ENOENT:
1809 droptcb(tcp);
1810 continue;
1811 default:
1812 perror("PIOCWSTOP");
1813 exit(1);
1814 }
1815 }
1816
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001817#ifdef FREEBSD
1818 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1819 /* discard first event for a syscall we never entered */
1820 IOCTL (tcp->pfd, PIOCRUN, 0);
1821 continue;
1822 }
Roland McGrath553a6092002-12-16 20:40:39 +00001823#endif
1824
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001825 /* clear the just started flag */
1826 tcp->flags &= ~TCB_STARTUP;
1827
1828 /* set current output file */
1829 outf = tcp->outf;
1830
1831 if (cflag) {
1832 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001833#ifdef FREEBSD
1834 char buf[1024];
1835 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001836
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001837 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1838 buf[len] = '\0';
1839 sscanf(buf,
1840 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1841 &stime.tv_sec, &stime.tv_usec);
1842 } else
1843 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001844#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001845 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1846 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001847#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001848 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1849 tcp->stime = stime;
1850 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001851 what = tcp->status.PR_WHAT;
1852 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001853#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001854 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001855 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1856 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001857 if (trace_syscall(tcp) < 0) {
1858 fprintf(stderr, "syscall trouble\n");
1859 exit(1);
1860 }
1861 }
1862 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001863#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001864 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001865#ifdef POLL_HACK
1866 in_syscall = tcp;
1867#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001868 case PR_SYSEXIT:
1869 if (trace_syscall(tcp) < 0) {
1870 fprintf(stderr, "syscall trouble\n");
1871 exit(1);
1872 }
1873 break;
1874 case PR_SIGNALLED:
1875 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1876 printleader(tcp);
1877 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001878 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001879 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001880#ifdef PR_INFO
1881 if (tcp->status.PR_INFO.si_signo == what) {
1882 printleader(tcp);
1883 tprintf(" siginfo=");
1884 printsiginfo(&tcp->status.PR_INFO, 1);
1885 printtrailer(tcp);
1886 }
1887#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001888 }
1889 break;
1890 case PR_FAULTED:
1891 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1892 printleader(tcp);
1893 tprintf("=== FAULT %d ===", what);
1894 printtrailer(tcp);
1895 }
1896 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001897#ifdef FREEBSD
1898 case 0: /* handle case we polled for nothing */
1899 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001900#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001901 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001902 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001903 exit(1);
1904 break;
1905 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001906 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001907#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001908 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001909#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001910 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001911#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001912 perror("PIOCRUN");
1913 exit(1);
1914 }
1915 }
1916 return 0;
1917}
1918
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001919#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001920
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001921#ifdef TCB_GROUP_EXITING
1922/* Handle an exit detach or death signal that is taking all the
1923 related clone threads with it. This is called in three circumstances:
1924 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1925 SIG == 0 Continuing TCP will perform an exit_group syscall.
1926 SIG == other Continuing TCP with SIG will kill the process.
1927*/
1928static int
1929handle_group_exit(struct tcb *tcp, int sig)
1930{
1931 /* We need to locate our records of all the clone threads
1932 related to TCP, either its children or siblings. */
1933 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1934 ? tcp->parent
1935 : tcp->nclone_detached > 0
1936 ? tcp : NULL);
1937
1938 if (sig < 0) {
Roland McGrath05690952004-10-20 01:00:27 +00001939 if (leader != NULL && leader != tcp &&
1940 !(leader->flags & TCB_GROUP_EXITING))
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001941 fprintf(stderr,
1942 "PANIC: handle_group_exit: %d leader %d\n",
1943 tcp->pid, leader ? leader->pid : -1);
1944 droptcb(tcp); /* Already died. */
1945 }
1946 else {
1947 if (tcp->flags & TCB_ATTACHED) {
Roland McGrath00dc13f2004-10-20 02:04:15 +00001948 if (leader != NULL && leader != tcp) {
1949 if (leader->flags & TCB_ATTACHED) {
1950 /* We need to detach the leader so
1951 that the process death will be
1952 reported to its real parent.
1953 But we kill it first to prevent
1954 it doing anything before we kill
1955 the whole process in a moment.
1956 We can use PTRACE_KILL on a
1957 thread that's not already
1958 stopped. Then the value we pass
1959 in PTRACE_DETACH just sets the
1960 death signal reported to the
1961 real parent. */
1962 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1963 if (debug)
1964 fprintf(stderr,
1965 " [%d exit %d kills %d]\n",
1966 tcp->pid, sig, leader->pid);
1967 detach(leader, sig);
1968 }
1969 else
1970 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001971 }
1972 detach(tcp, sig);
1973 }
1974 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1975 perror("strace: ptrace(PTRACE_CONT, ...)");
1976 cleanup();
1977 return -1;
1978 }
1979 else {
Roland McGrath05690952004-10-20 01:00:27 +00001980 if (leader != NULL)
1981 leader->flags |= TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001982 if (leader != NULL && leader != tcp)
1983 droptcb(tcp);
1984 /* The leader will report to us as parent now,
1985 and then we'll get to the SIG==-1 case. */
1986 return 0;
1987 }
1988 }
1989
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001990 return 0;
1991}
1992#endif
1993
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001994static int
1995trace()
1996{
1997 int pid;
1998 int wait_errno;
1999 int status;
2000 struct tcb *tcp;
2001#ifdef LINUX
2002 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002003#ifdef __WALL
2004 static int wait4_options = __WALL;
2005#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002006#endif /* LINUX */
2007
2008 while (nprocs != 0) {
2009 if (interactive)
2010 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2011#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002012#ifdef __WALL
2013 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002014 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002015 /* this kernel does not support __WALL */
2016 wait4_options &= ~__WALL;
2017 errno = 0;
2018 pid = wait4(-1, &status, wait4_options,
2019 cflag ? &ru : NULL);
2020 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002021 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002022 /* most likely a "cloned" process */
2023 pid = wait4(-1, &status, __WCLONE,
2024 cflag ? &ru : NULL);
2025 if (pid == -1) {
2026 fprintf(stderr, "strace: clone wait4 "
2027 "failed: %s\n", strerror(errno));
2028 }
2029 }
2030#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002031 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002032#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002033#endif /* LINUX */
2034#ifdef SUNOS4
2035 pid = wait(&status);
2036#endif /* SUNOS4 */
2037 wait_errno = errno;
2038 if (interactive)
2039 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2040
2041 if (interrupted)
2042 return 0;
2043
2044 if (pid == -1) {
2045 switch (wait_errno) {
2046 case EINTR:
2047 continue;
2048 case ECHILD:
2049 /*
2050 * We would like to verify this case
2051 * but sometimes a race in Solbourne's
2052 * version of SunOS sometimes reports
2053 * ECHILD before sending us SIGCHILD.
2054 */
2055#if 0
2056 if (nprocs == 0)
2057 return 0;
2058 fprintf(stderr, "strace: proc miscount\n");
2059 exit(1);
2060#endif
2061 return 0;
2062 default:
2063 errno = wait_errno;
2064 perror("strace: wait");
2065 return -1;
2066 }
2067 }
2068 if (debug)
2069 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2070
2071 /* Look up `pid' in our table. */
2072 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002073#ifdef LINUX
2074 if (followfork || followvfork) {
2075 /* This is needed to go with the CLONE_PTRACE
2076 changes in process.c/util.c: we might see
2077 the child's initial trap before we see the
2078 parent return from the clone syscall.
2079 Leave the child suspended until the parent
2080 returns from its system call. Only then
2081 will we have the association of parent and
2082 child so that we know how to do clearbpt
2083 in the child. */
2084 if ((tcp = alloctcb(pid)) == NULL) {
2085 fprintf(stderr, " [tcb table full]\n");
2086 kill(pid, SIGKILL); /* XXX */
2087 return 0;
2088 }
2089 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
2090 newoutf(tcp);
2091 if (!qflag)
2092 fprintf(stderr, "\
2093Process %d attached (waiting for parent)\n",
2094 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002095 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002096 else
2097 /* This can happen if a clone call used
2098 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002099#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002100 {
2101 fprintf(stderr, "unknown pid: %u\n", pid);
2102 if (WIFSTOPPED(status))
2103 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2104 exit(1);
2105 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002106 }
2107 /* set current output file */
2108 outf = tcp->outf;
2109 if (cflag) {
2110#ifdef LINUX
2111 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2112 tcp->stime = ru.ru_stime;
2113#endif /* !LINUX */
2114 }
2115
2116 if (tcp->flags & TCB_SUSPENDED) {
2117 /*
2118 * Apparently, doing any ptrace() call on a stopped
2119 * process, provokes the kernel to report the process
2120 * status again on a subsequent wait(), even if the
2121 * process has not been actually restarted.
2122 * Since we have inspected the arguments of suspended
2123 * processes we end up here testing for this case.
2124 */
2125 continue;
2126 }
2127 if (WIFSIGNALED(status)) {
2128 if (!cflag
2129 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2130 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002131 tprintf("+++ killed by %s %s+++",
2132 signame(WTERMSIG(status)),
2133#ifdef WCOREDUMP
2134 WCOREDUMP(status) ? "(core dumped) " :
2135#endif
2136 "");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002137 printtrailer(tcp);
2138 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002139#ifdef TCB_GROUP_EXITING
2140 handle_group_exit(tcp, -1);
2141#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002142 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002143#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002144 continue;
2145 }
2146 if (WIFEXITED(status)) {
2147 if (debug)
2148 fprintf(stderr, "pid %u exited\n", pid);
Roland McGrath05690952004-10-20 01:00:27 +00002149 if ((tcp->flags & TCB_ATTACHED)
2150#ifdef TCB_GROUP_EXITING
2151 && !(tcp->parent && (tcp->parent->flags &
2152 TCB_GROUP_EXITING))
2153#endif
2154 )
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002155 fprintf(stderr,
2156 "PANIC: attached pid %u exited\n",
2157 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002158 if (tcp == tcp_last) {
2159 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2160 == TCB_INSYSCALL)
2161 tprintf(" <unfinished ... exit status %d>\n",
2162 WEXITSTATUS(status));
2163 tcp_last = NULL;
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 (!WIFSTOPPED(status)) {
2173 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2174 droptcb(tcp);
2175 continue;
2176 }
2177 if (debug)
2178 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002179 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002180
2181 if (tcp->flags & TCB_STARTUP) {
2182 /*
2183 * This flag is there to keep us in sync.
2184 * Next time this process stops it should
2185 * really be entering a system call.
2186 */
2187 tcp->flags &= ~TCB_STARTUP;
2188 if (tcp->flags & TCB_ATTACHED) {
2189 /*
2190 * Interestingly, the process may stop
2191 * with STOPSIG equal to some other signal
2192 * than SIGSTOP if we happend to attach
2193 * just before the process takes a signal.
2194 */
2195 if (!WIFSTOPPED(status)) {
2196 fprintf(stderr,
2197 "pid %u not stopped\n", pid);
2198 detach(tcp, WSTOPSIG(status));
2199 continue;
2200 }
2201 }
2202 else {
2203#ifdef SUNOS4
2204 /* A child of us stopped at exec */
2205 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2206 fixvfork(tcp);
2207#endif /* SUNOS4 */
2208 }
2209 if (tcp->flags & TCB_BPTSET) {
2210 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2211 droptcb(tcp);
2212 cleanup();
2213 return -1;
2214 }
2215 }
2216 goto tracing;
2217 }
2218
2219 if (WSTOPSIG(status) != SIGTRAP) {
2220 if (WSTOPSIG(status) == SIGSTOP &&
2221 (tcp->flags & TCB_SIGTRAPPED)) {
2222 /*
2223 * Trapped attempt to block SIGTRAP
2224 * Hope we are back in control now.
2225 */
2226 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2227 if (ptrace(PTRACE_SYSCALL,
2228 pid, (char *) 1, 0) < 0) {
2229 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2230 cleanup();
2231 return -1;
2232 }
2233 continue;
2234 }
2235 if (!cflag
2236 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002237 unsigned long addr = 0, pc = 0;
2238#ifdef PT_GETSIGINFO
2239# define PSR_RI 41
2240 struct siginfo si;
2241 unsigned long psr;
2242
2243 upeek(pid, PT_CR_IPSR, &psr);
2244 upeek(pid, PT_CR_IIP, &pc);
2245
2246 pc += (psr >> PSR_RI) & 0x3;
2247 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2248 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002249#elif defined PTRACE_GETSIGINFO
2250 if (WSTOPSIG(status) == SIGSEGV ||
2251 WSTOPSIG(status) == SIGBUS) {
2252 siginfo_t si;
2253 if (ptrace(PTRACE_GETSIGINFO, pid,
2254 0, &si) == 0)
2255 addr = (unsigned long)
2256 si.si_addr;
2257 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002258#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002259 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002260 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002261 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002262 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002263 printtrailer(tcp);
2264 }
Roland McGrath05690952004-10-20 01:00:27 +00002265 if (((tcp->flags & TCB_ATTACHED) ||
2266 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002267 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002268#ifdef TCB_GROUP_EXITING
2269 handle_group_exit(tcp, WSTOPSIG(status));
2270#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002271 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002272#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002273 continue;
2274 }
2275 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2276 WSTOPSIG(status)) < 0) {
2277 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2278 cleanup();
2279 return -1;
2280 }
2281 tcp->flags &= ~TCB_SUSPENDED;
2282 continue;
2283 }
2284 if (trace_syscall(tcp) < 0) {
2285 if (tcp->flags & TCB_ATTACHED)
2286 detach(tcp, 0);
2287 else {
2288 ptrace(PTRACE_KILL,
2289 tcp->pid, (char *) 1, SIGTERM);
2290 droptcb(tcp);
2291 }
2292 continue;
2293 }
2294 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002295#ifdef TCB_GROUP_EXITING
2296 if (tcp->flags & TCB_GROUP_EXITING) {
2297 if (handle_group_exit(tcp, 0) < 0)
2298 return -1;
2299 continue;
2300 }
2301#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002302 if (tcp->flags & TCB_ATTACHED)
2303 detach(tcp, 0);
2304 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2305 perror("strace: ptrace(PTRACE_CONT, ...)");
2306 cleanup();
2307 return -1;
2308 }
2309 continue;
2310 }
2311 if (tcp->flags & TCB_SUSPENDED) {
2312 if (!qflag)
2313 fprintf(stderr, "Process %u suspended\n", pid);
2314 continue;
2315 }
2316 tracing:
2317 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2318 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2319 cleanup();
2320 return -1;
2321 }
2322 }
2323 return 0;
2324}
2325
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002326#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002327
2328static int curcol;
2329
2330#ifdef __STDC__
2331#include <stdarg.h>
2332#define VA_START(a, b) va_start(a, b)
2333#else
2334#include <varargs.h>
2335#define VA_START(a, b) va_start(a)
2336#endif
2337
2338void
2339#ifdef __STDC__
2340tprintf(const char *fmt, ...)
2341#else
2342tprintf(fmt, va_alist)
2343char *fmt;
2344va_dcl
2345#endif
2346{
2347 va_list args;
2348
2349 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002350 if (outf) {
2351 int n = vfprintf(outf, fmt, args);
2352 if (n < 0 && outf != stderr)
2353 perror(outfname == NULL
2354 ? "<writing to pipe>" : outfname);
2355 else
2356 curcol += n;
2357 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002358 va_end(args);
2359 return;
2360}
2361
2362void
2363printleader(tcp)
2364struct tcb *tcp;
2365{
2366 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2367 tcp_last->flags |= TCB_REPRINT;
2368 tprintf(" <unfinished ...>\n");
2369 }
2370 curcol = 0;
2371 if ((followfork == 1 || pflag_seen > 1) && outfname)
2372 tprintf("%-5d ", tcp->pid);
2373 else if (nprocs > 1 && !outfname)
2374 tprintf("[pid %5u] ", tcp->pid);
2375 if (tflag) {
2376 char str[sizeof("HH:MM:SS")];
2377 struct timeval tv, dtv;
2378 static struct timeval otv;
2379
2380 gettimeofday(&tv, NULL);
2381 if (rflag) {
2382 if (otv.tv_sec == 0)
2383 otv = tv;
2384 tv_sub(&dtv, &tv, &otv);
2385 tprintf("%6ld.%06ld ",
2386 (long) dtv.tv_sec, (long) dtv.tv_usec);
2387 otv = tv;
2388 }
2389 else if (tflag > 2) {
2390 tprintf("%ld.%06ld ",
2391 (long) tv.tv_sec, (long) tv.tv_usec);
2392 }
2393 else {
2394 time_t local = tv.tv_sec;
2395 strftime(str, sizeof(str), "%T", localtime(&local));
2396 if (tflag > 1)
2397 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2398 else
2399 tprintf("%s ", str);
2400 }
2401 }
2402 if (iflag)
2403 printcall(tcp);
2404}
2405
2406void
2407tabto(col)
2408int col;
2409{
2410 if (curcol < col)
2411 tprintf("%*s", col - curcol, "");
2412}
2413
2414void
2415printtrailer(tcp)
2416struct tcb *tcp;
2417{
2418 tprintf("\n");
2419 tcp_last = NULL;
2420}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002421
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002422#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002423
2424int mp_ioctl (int fd, int cmd, void *arg, int size) {
2425
2426 struct iovec iov[2];
2427 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002428
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002429 iov[0].iov_base = &cmd;
2430 iov[0].iov_len = sizeof cmd;
2431 if (arg) {
2432 ++n;
2433 iov[1].iov_base = arg;
2434 iov[1].iov_len = size;
2435 }
Roland McGrath553a6092002-12-16 20:40:39 +00002436
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002437 return writev (fd, iov, n);
2438}
2439
2440#endif