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