blob: 23d72c8d81bb65bc7cb6b92162fc2e75cd58ffc4 [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
Wichert Akkerman2ee6e452000-02-18 15:36:12 +000033#include <sys/types.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000034#include "defs.h"
35
36#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>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000047
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000048#if defined(IA64) && defined(LINUX)
49# include <asm/ptrace_offsets.h>
50#endif
51
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000052#ifdef USE_PROCFS
53#include <poll.h>
54#endif
55
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000056#ifdef SVR4
57#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000058#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000059#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000060#include <sys/uio.h>
61#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000062#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000063#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000064
65int debug = 0, followfork = 0, followvfork = 0, interactive = 0;
66int rflag = 0, tflag = 0, dtime = 0, cflag = 0;
67int iflag = 0, xflag = 0, qflag = 0;
68int pflag_seen = 0;
69
Michal Ludvig17f8fb32002-11-06 13:17:21 +000070/* Sometimes we want to print only succeeding syscalls. */
71int not_failing_only = 0;
72
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000073char *username = NULL;
74uid_t run_uid;
75gid_t run_gid;
76
77int acolumn = DEFAULT_ACOLUMN;
78int max_strlen = DEFAULT_STRLEN;
79char *outfname = NULL;
80FILE *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;
201 qualify("trace=all");
202 qualify("abbrev=all");
203 qualify("verbose=all");
204 qualify("signal=all");
205 set_sortby(DEFAULT_SORTBY);
206 set_personality(DEFAULT_PERSONALITY);
207 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);
287 break;
288 case 'S':
289 set_sortby(optarg);
290 break;
291 case 'u':
292 username = strdup(optarg);
293 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000294 case 'E':
295 if (putenv(optarg) < 0) {
296 fprintf(stderr, "%s: out of memory\n",
297 progname);
298 exit(1);
299 }
300 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000301 default:
302 usage(stderr, 1);
303 break;
304 }
305 }
306
Roland McGrathce0d1542003-11-11 21:24:23 +0000307 if (optind == argc && !pflag_seen)
308 usage(stderr, 1);
309
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000310 /* See if they want to run as another user. */
311 if (username != NULL) {
312 struct passwd *pent;
313
314 if (getuid() != 0 || geteuid() != 0) {
315 fprintf(stderr,
316 "%s: you must be root to use the -u option\n",
317 progname);
318 exit(1);
319 }
320 if ((pent = getpwnam(username)) == NULL) {
321 fprintf(stderr, "%s: cannot find user `%s'\n",
322 progname, optarg);
323 exit(1);
324 }
325 run_uid = pent->pw_uid;
326 run_gid = pent->pw_gid;
327 }
328 else {
329 run_uid = getuid();
330 run_gid = getgid();
331 }
332
333#ifndef SVR4
334 setreuid(geteuid(), getuid());
335#endif
336
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000337 /* Check if they want to redirect the output. */
338 if (outfname) {
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000339 long f;
340
Roland McGrath37b9a662003-11-07 02:26:54 +0000341 /* See if they want to pipe the output. */
342 if (outfname[0] == '|' || outfname[0] == '!') {
343 /*
344 * We can't do the <outfname>.PID funny business
345 * when using popen, so prohibit it.
346 */
347 if (followfork > 1) {
348 fprintf(stderr, "\
349%s: piping the output and -ff are mutually exclusive options\n",
350 progname);
351 exit(1);
352 }
353
354 if ((outf = popen(outfname + 1, "w")) == NULL) {
355 fprintf(stderr, "%s: can't popen '%s': %s\n",
356 progname, outfname + 1,
357 strerror(errno));
358 exit(1);
359 }
360 }
361 else if ((outf = fopen(outfname, "w")) == NULL) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000362 fprintf(stderr, "%s: can't fopen '%s': %s\n",
363 progname, outfname, strerror(errno));
364 exit(1);
365 }
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000366
367 if ((f=fcntl(fileno(outf), F_GETFD)) < 0 ) {
368 perror("failed to get flags for outputfile");
369 exit(1);
370 }
371
372 if (fcntl(fileno(outf), F_SETFD, f|FD_CLOEXEC) < 0 ) {
373 perror("failed to set flags for outputfile");
374 exit(1);
375 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000376 }
377
378#ifndef SVR4
379 setreuid(geteuid(), getuid());
380#endif
381
Roland McGrath37b9a662003-11-07 02:26:54 +0000382 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000383 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000384 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000385 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000386 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000387 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000388
Roland McGrathee9d4352002-12-18 04:16:10 +0000389 for (c = 0; c < tcbtabsize; c++) {
390 tcp = tcbtab[c];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000391 /* Reinitialize the output since it may have changed. */
392 tcp->outf = outf;
393 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
394 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000395#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000396 if (proc_open(tcp, 1) < 0) {
397 fprintf(stderr, "trouble opening proc file\n");
398 droptcb(tcp);
399 continue;
400 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000401#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000402 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
403 perror("attach: ptrace(PTRACE_ATTACH, ...)");
404 droptcb(tcp);
405 continue;
406 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000407#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000408 if (!qflag)
409 fprintf(stderr,
410 "Process %u attached - interrupt to quit\n",
Roland McGrathc3266d52004-02-20 02:23:52 +0000411 tcp->pid);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000412 }
413
Roland McGrathce0d1542003-11-11 21:24:23 +0000414 if (!pflag_seen) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000415 struct stat statbuf;
416 char *filename;
417 char pathname[MAXPATHLEN];
418
419 filename = argv[optind];
Roland McGrathbdb09df2004-03-02 06:50:04 +0000420 if (strchr(filename, '/')) {
421 if (strlen(filename) > sizeof pathname - 1) {
422 errno = ENAMETOOLONG;
423 perror("strace: exec");
424 exit(1);
425 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000426 strcpy(pathname, filename);
Roland McGrathbdb09df2004-03-02 06:50:04 +0000427 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000428#ifdef USE_DEBUGGING_EXEC
429 /*
430 * Debuggers customarily check the current directory
431 * first regardless of the path but doing that gives
432 * security geeks a panic attack.
433 */
434 else if (stat(filename, &statbuf) == 0)
435 strcpy(pathname, filename);
436#endif /* USE_DEBUGGING_EXEC */
437 else {
438 char *path;
439 int m, n, len;
440
441 for (path = getenv("PATH"); path && *path; path += m) {
442 if (strchr(path, ':')) {
443 n = strchr(path, ':') - path;
444 m = n + 1;
445 }
446 else
447 m = n = strlen(path);
448 if (n == 0) {
449 getcwd(pathname, MAXPATHLEN);
450 len = strlen(pathname);
451 }
Roland McGrathbdb09df2004-03-02 06:50:04 +0000452 else if (n > sizeof pathname - 1)
453 continue;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000454 else {
455 strncpy(pathname, path, n);
456 len = n;
457 }
458 if (len && pathname[len - 1] != '/')
459 pathname[len++] = '/';
460 strcpy(pathname + len, filename);
Roland McGrathed645162003-06-03 07:18:19 +0000461 if (stat(pathname, &statbuf) == 0 &&
462 /* Accept only regular files
463 with some execute bits set.
464 XXX not perfect, might still fail */
465 S_ISREG(statbuf.st_mode) &&
466 (statbuf.st_mode & 0111))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 break;
468 }
469 }
470 if (stat(pathname, &statbuf) < 0) {
471 fprintf(stderr, "%s: %s: command not found\n",
472 progname, filename);
473 exit(1);
474 }
475 switch (pid = fork()) {
476 case -1:
477 perror("strace: fork");
478 cleanup();
479 exit(1);
480 break;
481 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000482#ifdef USE_PROCFS
483 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000484#ifdef MIPS
485 /* Kludge for SGI, see proc_open for details. */
486 sa.sa_handler = foobar;
487 sa.sa_flags = 0;
488 sigemptyset(&sa.sa_mask);
489 sigaction(SIGINT, &sa, NULL);
490#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000491#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000492 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000493#else /* FREEBSD */
494 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000495#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000496#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000497 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000498 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000499
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000500 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
501 perror("strace: ptrace(PTRACE_TRACEME, ...)");
502 return -1;
503 }
504 if (debug)
505 kill(getpid(), SIGSTOP);
506
507 if (username != NULL || geteuid() == 0) {
508 uid_t run_euid = run_uid;
509 gid_t run_egid = run_gid;
510
511 if (statbuf.st_mode & S_ISUID)
512 run_euid = statbuf.st_uid;
513 if (statbuf.st_mode & S_ISGID)
514 run_egid = statbuf.st_gid;
515
516 /*
517 * It is important to set groups before we
518 * lose privileges on setuid.
519 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000520 if (username != NULL) {
521 if (initgroups(username, run_gid) < 0) {
522 perror("initgroups");
523 exit(1);
524 }
525 if (setregid(run_gid, run_egid) < 0) {
526 perror("setregid");
527 exit(1);
528 }
529 if (setreuid(run_uid, run_euid) < 0) {
530 perror("setreuid");
531 exit(1);
532 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000533 }
534 }
535 else
536 setreuid(run_uid, run_uid);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000537#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538
539 execv(pathname, &argv[optind]);
540 perror("strace: exec");
541 _exit(1);
542 break;
543 }
544 default:
545 if ((tcp = alloctcb(pid)) == NULL) {
546 fprintf(stderr, "tcb table full\n");
547 cleanup();
548 exit(1);
549 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000550#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000551 if (proc_open(tcp, 0) < 0) {
552 fprintf(stderr, "trouble opening proc file\n");
553 cleanup();
554 exit(1);
555 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000556#endif /* USE_PROCFS */
557#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000558 fake_execve(tcp, pathname, &argv[optind], environ);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000559#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560 break;
561 }
562 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000563
564 sigemptyset(&empty_set);
565 sigemptyset(&blocked_set);
566 sa.sa_handler = SIG_IGN;
567 sigemptyset(&sa.sa_mask);
568 sa.sa_flags = 0;
569 sigaction(SIGTTOU, &sa, NULL);
570 sigaction(SIGTTIN, &sa, NULL);
571 if (interactive) {
572 sigaddset(&blocked_set, SIGHUP);
573 sigaddset(&blocked_set, SIGINT);
574 sigaddset(&blocked_set, SIGQUIT);
575 sigaddset(&blocked_set, SIGPIPE);
576 sigaddset(&blocked_set, SIGTERM);
577 sa.sa_handler = interrupt;
578#ifdef SUNOS4
579 /* POSIX signals on sunos4.1 are a little broken. */
580 sa.sa_flags = SA_INTERRUPT;
581#endif /* SUNOS4 */
582 }
583 sigaction(SIGHUP, &sa, NULL);
584 sigaction(SIGINT, &sa, NULL);
585 sigaction(SIGQUIT, &sa, NULL);
586 sigaction(SIGPIPE, &sa, NULL);
587 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000588#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000589 sa.sa_handler = reaper;
590 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000591#else
592 /* Make sure SIGCHLD has the default action so that waitpid
593 definitely works without losing track of children. The user
594 should not have given us a bogus state to inherit, but he might
595 have. Arguably we should detect SIG_IGN here and pass it on
596 to children, but probably noone really needs that. */
597 sa.sa_handler = SIG_DFL;
598 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000599#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000600
601 if (trace() < 0)
602 exit(1);
603 cleanup();
604 exit(0);
605}
606
607void
608newoutf(tcp)
609struct tcb *tcp;
610{
611 char name[MAXPATHLEN];
612 FILE *fp;
613
614 if (outfname && followfork > 1) {
615 sprintf(name, "%s.%u", outfname, tcp->pid);
616#ifndef SVR4
617 setreuid(geteuid(), getuid());
618#endif
619 fp = fopen(name, "w");
620#ifndef SVR4
621 setreuid(geteuid(), getuid());
622#endif
623 if (fp == NULL) {
624 perror("fopen");
625 return;
626 }
627 tcp->outf = fp;
628 }
629 return;
630}
631
632struct tcb *
633alloctcb(pid)
634int pid;
635{
636 int i;
637 struct tcb *tcp;
638
Roland McGrathee9d4352002-12-18 04:16:10 +0000639 for (i = 0; i < tcbtabsize; i++) {
640 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 if ((tcp->flags & TCB_INUSE) == 0) {
642 tcp->pid = pid;
643 tcp->parent = NULL;
644 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000645 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000646#ifdef TCB_CLONE_THREAD
647 tcp->nclone_threads = tcp->nclone_detached = 0;
648 tcp->nclone_waiting = 0;
649#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000650 tcp->flags = TCB_INUSE | TCB_STARTUP;
651 tcp->outf = outf; /* Initialise to current out file */
652 tcp->stime.tv_sec = 0;
653 tcp->stime.tv_usec = 0;
654 tcp->pfd = -1;
655 nprocs++;
656 return tcp;
657 }
658 }
659 return NULL;
660}
661
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000662#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000663int
664proc_open(tcp, attaching)
665struct tcb *tcp;
666int attaching;
667{
668 char proc[32];
669 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000670#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000671 int i;
672 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000673 sigset_t signals;
674 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000675#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000676#ifndef HAVE_POLLABLE_PROCFS
677 static int last_pfd;
678#endif
679
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000680#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000681 /* Open the process pseudo-files in /proc. */
682 sprintf(proc, "/proc/%d/ctl", tcp->pid);
683 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000684 perror("strace: open(\"/proc/...\", ...)");
685 return -1;
686 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000687 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
688 perror("F_GETFD");
689 return -1;
690 }
691 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
692 perror("F_SETFD");
693 return -1;
694 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000695 sprintf(proc, "/proc/%d/status", tcp->pid);
696 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
697 perror("strace: open(\"/proc/...\", ...)");
698 return -1;
699 }
700 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
701 perror("F_GETFD");
702 return -1;
703 }
704 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
705 perror("F_SETFD");
706 return -1;
707 }
708 sprintf(proc, "/proc/%d/as", tcp->pid);
709 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
710 perror("strace: open(\"/proc/...\", ...)");
711 return -1;
712 }
713 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
714 perror("F_GETFD");
715 return -1;
716 }
717 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
718 perror("F_SETFD");
719 return -1;
720 }
721#else
722 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000723#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000724 sprintf(proc, "/proc/%d", tcp->pid);
725 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000726#else /* FREEBSD */
727 sprintf(proc, "/proc/%d/mem", tcp->pid);
728 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
729#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000730 perror("strace: open(\"/proc/...\", ...)");
731 return -1;
732 }
733 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
734 perror("F_GETFD");
735 return -1;
736 }
737 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
738 perror("F_SETFD");
739 return -1;
740 }
741#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000742#ifdef FREEBSD
743 sprintf(proc, "/proc/%d/regs", tcp->pid);
744 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
745 perror("strace: open(\"/proc/.../regs\", ...)");
746 return -1;
747 }
748 if (cflag) {
749 sprintf(proc, "/proc/%d/status", tcp->pid);
750 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
751 perror("strace: open(\"/proc/.../status\", ...)");
752 return -1;
753 }
754 } else
755 tcp->pfd_status = -1;
756#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000757 rebuild_pollv();
758 if (!attaching) {
759 /*
760 * Wait for the child to pause. Because of a race
761 * condition we have to poll for the event.
762 */
763 for (;;) {
764 if (IOCTL_STATUS (tcp) < 0) {
765 perror("strace: PIOCSTATUS");
766 return -1;
767 }
768 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000769 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000770 }
771 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000772#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000773 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000774 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000775 perror("strace: PIOCSTOP");
776 return -1;
777 }
Roland McGrath553a6092002-12-16 20:40:39 +0000778#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000779#ifdef PIOCSET
780 /* Set Run-on-Last-Close. */
781 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000782 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000783 perror("PIOCSET PR_RLC");
784 return -1;
785 }
786 /* Set or Reset Inherit-on-Fork. */
787 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000788 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789 perror("PIOC{SET,RESET} PR_FORK");
790 return -1;
791 }
792#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000793#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
795 perror("PIOCSRLC");
796 return -1;
797 }
798 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
799 perror("PIOC{S,R}FORK");
800 return -1;
801 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000802#else /* FREEBSD */
803 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
804 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
805 perror("PIOCGFL");
806 return -1;
807 }
808 arg &= ~PF_LINGER;
809 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
810 perror("PIOCSFL");
811 return -1;
812 }
813#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000814#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000815#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000816 /* Enable all syscall entries we care about. */
817 premptyset(&syscalls);
818 for (i = 1; i < MAX_QUALS; ++i) {
819 if (i > (sizeof syscalls) * CHAR_BIT) break;
820 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
821 }
822 praddset (&syscalls, SYS_execve);
823 if (followfork) {
824 praddset (&syscalls, SYS_fork);
825#ifdef SYS_forkall
826 praddset (&syscalls, SYS_forkall);
827#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000828#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000829 praddset (&syscalls, SYS_fork1);
830#endif
831#ifdef SYS_rfork1
832 praddset (&syscalls, SYS_rfork1);
833#endif
834#ifdef SYS_rforkall
835 praddset (&syscalls, SYS_rforkall);
836#endif
837 }
838 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000839 perror("PIOCSENTRY");
840 return -1;
841 }
John Hughes19e49982001-10-19 08:59:12 +0000842 /* Enable the syscall exits. */
843 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000844 perror("PIOSEXIT");
845 return -1;
846 }
John Hughes19e49982001-10-19 08:59:12 +0000847 /* Enable signals we care about. */
848 premptyset(&signals);
849 for (i = 1; i < MAX_QUALS; ++i) {
850 if (i > (sizeof signals) * CHAR_BIT) break;
851 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
852 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000853 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000854 perror("PIOCSTRACE");
855 return -1;
856 }
John Hughes19e49982001-10-19 08:59:12 +0000857 /* Enable faults we care about */
858 premptyset(&faults);
859 for (i = 1; i < MAX_QUALS; ++i) {
860 if (i > (sizeof faults) * CHAR_BIT) break;
861 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
862 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000863 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000864 perror("PIOCSFAULT");
865 return -1;
866 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000867#else /* FREEBSD */
868 /* set events flags. */
869 arg = S_SIG | S_SCE | S_SCX ;
870 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
871 perror("PIOCBIS");
872 return -1;
873 }
874#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000875 if (!attaching) {
876#ifdef MIPS
877 /*
878 * The SGI PRSABORT doesn't work for pause() so
879 * we send it a caught signal to wake it up.
880 */
881 kill(tcp->pid, SIGINT);
882#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000883#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000884 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000885 arg = PRSABORT;
886 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000887 perror("PIOCRUN");
888 return -1;
889 }
Roland McGrath553a6092002-12-16 20:40:39 +0000890#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000891#endif /* !MIPS*/
892#ifdef FREEBSD
893 /* wake up the child if it received the SIGSTOP */
894 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000895#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000896 for (;;) {
897 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000898 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000899 perror("PIOCWSTOP");
900 return -1;
901 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000902 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000903 tcp->flags &= ~TCB_INSYSCALL;
904 get_scno(tcp);
905 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000906 break;
907 }
908 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000909#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000910 arg = 0;
911 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000912#else /* FREEBSD */
913 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +0000914#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000915 perror("PIOCRUN");
916 return -1;
917 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000918#ifdef FREEBSD
919 /* handle the case where we "opened" the child before
920 it did the kill -STOP */
921 if (tcp->status.PR_WHY == PR_SIGNALLED &&
922 tcp->status.PR_WHAT == SIGSTOP)
923 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000924#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000925 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000926#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000927 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000928#else /* FREEBSD */
929 } else {
Roland McGrath553a6092002-12-16 20:40:39 +0000930 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000931 /* We are attaching to an already running process.
932 * Try to figure out the state of the process in syscalls,
933 * to handle the first event well.
934 * This is done by having a look at the "wchan" property of the
935 * process, which tells where it is stopped (if it is). */
936 FILE * status;
937 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +0000938
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000939 sprintf(proc, "/proc/%d/status", tcp->pid);
940 status = fopen(proc, "r");
941 if (status &&
942 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
943 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
944 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
945 strcmp(wchan, "stopevent")) {
946 /* The process is asleep in the middle of a syscall.
947 Fake the syscall entry event */
948 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
949 tcp->status.PR_WHY = PR_SYSENTRY;
950 trace_syscall(tcp);
951 }
952 if (status)
953 fclose(status);
954 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000955 }
956#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000957#ifndef HAVE_POLLABLE_PROCFS
958 if (proc_poll_pipe[0] != -1)
959 proc_poller(tcp->pfd);
960 else if (nprocs > 1) {
961 proc_poll_open();
962 proc_poller(last_pfd);
963 proc_poller(tcp->pfd);
964 }
965 last_pfd = tcp->pfd;
966#endif /* !HAVE_POLLABLE_PROCFS */
967 return 0;
968}
969
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000970#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000971
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000972struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000973pid2tcb(pid)
974int pid;
975{
976 int i;
977 struct tcb *tcp;
978
Roland McGrathee9d4352002-12-18 04:16:10 +0000979 for (i = 0; i < tcbtabsize; i++) {
980 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000981 if (pid && tcp->pid != pid)
982 continue;
983 if (tcp->flags & TCB_INUSE)
984 return tcp;
985 }
986 return NULL;
987}
988
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000989#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000990
991static struct tcb *
992pfd2tcb(pfd)
993int pfd;
994{
995 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000996
Roland McGrathca16be82003-01-10 19:55:28 +0000997 for (i = 0; i < tcbtabsize; i++) {
998 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000999 if (tcp->pfd != pfd)
1000 continue;
1001 if (tcp->flags & TCB_INUSE)
1002 return tcp;
1003 }
1004 return NULL;
1005}
1006
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001007#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001008
1009void
1010droptcb(tcp)
1011struct tcb *tcp;
1012{
1013 if (tcp->pid == 0)
1014 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001015#ifdef TCB_CLONE_THREAD
1016 if (tcp->nclone_threads > 0) {
1017 /* There are other threads left in this process, but this
1018 is the one whose PID represents the whole process.
1019 We need to keep this record around as a zombie until
1020 all the threads die. */
1021 tcp->flags |= TCB_EXITING;
1022 return;
1023 }
1024#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025 nprocs--;
1026 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001027
Roland McGrathe29341c2003-01-10 20:14:20 +00001028 if (tcp->parent != NULL) {
1029 tcp->parent->nchildren--;
1030#ifdef TCB_CLONE_THREAD
1031 if (tcp->flags & TCB_CLONE_DETACHED)
1032 tcp->parent->nclone_detached--;
1033 if (tcp->flags & TCB_CLONE_THREAD)
1034 tcp->parent->nclone_threads--;
1035#endif
Roland McGrath09623452003-05-23 02:27:13 +00001036#ifdef TCB_CLONE_DETACHED
1037 if (!(tcp->flags & TCB_CLONE_DETACHED))
1038#endif
1039 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001040 tcp->parent = NULL;
1041 }
1042
1043 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 if (tcp->pfd != -1) {
1045 close(tcp->pfd);
1046 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001047#ifdef FREEBSD
1048 if (tcp->pfd_reg != -1) {
1049 close(tcp->pfd_reg);
1050 tcp->pfd_reg = -1;
1051 }
1052 if (tcp->pfd_status != -1) {
1053 close(tcp->pfd_status);
1054 tcp->pfd_status = -1;
1055 }
Roland McGrath553a6092002-12-16 20:40:39 +00001056#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001057#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001058 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059#endif
1060 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001061
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001062 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001064
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001065 tcp->outf = 0;
1066}
1067
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001068#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001069
1070static int
1071resume(tcp)
1072struct tcb *tcp;
1073{
1074 if (tcp == NULL)
1075 return -1;
1076
1077 if (!(tcp->flags & TCB_SUSPENDED)) {
1078 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1079 return -1;
1080 }
1081 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001082#ifdef TCB_CLONE_THREAD
1083 if (tcp->flags & TCB_CLONE_THREAD)
1084 tcp->parent->nclone_waiting--;
1085#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086
1087 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1088 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1089 return -1;
1090 }
1091
1092 if (!qflag)
1093 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1094 return 0;
1095}
1096
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001097#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098
1099/* detach traced process; continue with sig */
1100
1101static int
1102detach(tcp, sig)
1103struct tcb *tcp;
1104int sig;
1105{
1106 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001107#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001108 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001109#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001110
1111 if (tcp->flags & TCB_BPTSET)
1112 sig = SIGKILL;
1113
1114#ifdef LINUX
1115 /*
1116 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001117 * before detaching. Arghh. We go through hoops
1118 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001120#if defined(SPARC)
1121#undef PTRACE_DETACH
1122#define PTRACE_DETACH PTRACE_SUNDETACH
1123#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001124 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1125 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001126 }
1127 else if (errno != ESRCH) {
1128 /* Shouldn't happen. */
1129 perror("detach: ptrace(PTRACE_DETACH, ...)");
1130 }
1131 else if (kill(tcp->pid, 0) < 0) {
1132 if (errno != ESRCH)
1133 perror("detach: checking sanity");
1134 }
1135 else if (kill(tcp->pid, SIGSTOP) < 0) {
1136 if (errno != ESRCH)
1137 perror("detach: stopping child");
1138 }
1139 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001140 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001141#ifdef __WALL
1142 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1143 if (errno == ECHILD) /* Already gone. */
1144 break;
1145 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001146 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001147 break;
1148 }
1149#endif /* __WALL */
1150 /* No __WALL here. */
1151 if (waitpid(tcp->pid, &status, 0) < 0) {
1152 if (errno != ECHILD) {
1153 perror("detach: waiting");
1154 break;
1155 }
1156#ifdef __WCLONE
1157 /* If no processes, try clones. */
1158 if (wait4(tcp->pid, &status, __WCLONE,
1159 NULL) < 0) {
1160 if (errno != ECHILD)
1161 perror("detach: waiting");
1162 break;
1163 }
1164#endif /* __WCLONE */
1165 }
1166#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001167 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001168#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001169 if (!WIFSTOPPED(status)) {
1170 /* Au revoir, mon ami. */
1171 break;
1172 }
1173 if (WSTOPSIG(status) == SIGSTOP) {
1174 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001175 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176 if (errno != ESRCH)
1177 perror("detach: ptrace(PTRACE_DETACH, ...)");
1178 /* I died trying. */
1179 }
1180 break;
1181 }
1182 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001183 WSTOPSIG(status) == SIGTRAP ?
1184 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185 if (errno != ESRCH)
1186 perror("detach: ptrace(PTRACE_CONT, ...)");
1187 break;
1188 }
1189 }
1190 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001191#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001192
1193#if defined(SUNOS4)
1194 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1195 if (sig && kill(tcp->pid, sig) < 0)
1196 perror("detach: kill");
1197 sig = 0;
1198 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1199 perror("detach: ptrace(PTRACE_DETACH, ...)");
1200#endif /* SUNOS4 */
1201
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001202#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001203 resumed = 0;
1204
1205 /* XXX This won't always be quite right (but it never was).
1206 A waiter with argument 0 or < -1 is waiting for any pid in
1207 a particular pgrp, which this child might or might not be
1208 in. The waiter will only wake up if it's argument is -1
1209 or if it's waiting for tcp->pid's pgrp. It makes a
1210 difference to wake up a waiter when there might be more
1211 traced children, because it could get a false ECHILD
1212 error. OTOH, if this was the last child in the pgrp, then
1213 it ought to wake up and get ECHILD. We would have to
1214 search the system for all pid's in the pgrp to be sure.
1215
1216 && (t->waitpid == -1 ||
1217 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1218 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1219 */
1220
1221 if (tcp->parent &&
1222 (tcp->parent->flags & TCB_SUSPENDED) &&
1223 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1224 error = resume(tcp->parent);
1225 ++resumed;
1226 }
1227#ifdef TCB_CLONE_THREAD
1228 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1229 /* Some other threads of our parent are waiting too. */
1230 unsigned int i;
1231
1232 /* Resume all the threads that were waiting for this PID. */
1233 for (i = 0; i < tcbtabsize; i++) {
1234 struct tcb *t = tcbtab[i];
1235 if (t->parent == tcp->parent && t != tcp
1236 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1237 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1238 && t->waitpid == tcp->pid) {
1239 error |= resume (t);
1240 ++resumed;
1241 }
1242 }
1243 if (resumed == 0)
1244 /* Noone was waiting for this PID in particular,
1245 so now we might need to resume some wildcarders. */
1246 for (i = 0; i < tcbtabsize; i++) {
1247 struct tcb *t = tcbtab[i];
1248 if (t->parent == tcp->parent && t != tcp
1249 && ((t->flags
1250 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1251 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1252 && t->waitpid <= 0
1253 ) {
1254 error |= resume (t);
1255 break;
1256 }
1257 }
1258 }
1259#endif
1260
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001261#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001262
1263 if (!qflag)
1264 fprintf(stderr, "Process %u detached\n", tcp->pid);
1265
1266 droptcb(tcp);
1267 return error;
1268}
1269
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001270#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001271
1272static void
1273reaper(sig)
1274int sig;
1275{
1276 int pid;
1277 int status;
1278
1279 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1280#if 0
1281 struct tcb *tcp;
1282
1283 tcp = pid2tcb(pid);
1284 if (tcp)
1285 droptcb(tcp);
1286#endif
1287 }
1288}
1289
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001290#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291
1292static void
1293cleanup()
1294{
1295 int i;
1296 struct tcb *tcp;
1297
Roland McGrathee9d4352002-12-18 04:16:10 +00001298 for (i = 0; i < tcbtabsize; i++) {
1299 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300 if (!(tcp->flags & TCB_INUSE))
1301 continue;
1302 if (debug)
1303 fprintf(stderr,
1304 "cleanup: looking at pid %u\n", tcp->pid);
1305 if (tcp_last &&
1306 (!outfname || followfork < 2 || tcp_last == tcp)) {
1307 tprintf(" <unfinished ...>\n");
1308 tcp_last = NULL;
1309 }
1310 if (tcp->flags & TCB_ATTACHED)
1311 detach(tcp, 0);
1312 else {
1313 kill(tcp->pid, SIGCONT);
1314 kill(tcp->pid, SIGTERM);
1315 }
1316 }
1317 if (cflag)
1318 call_summary(outf);
1319}
1320
1321static void
1322interrupt(sig)
1323int sig;
1324{
1325 interrupted = 1;
1326}
1327
1328#ifndef HAVE_STRERROR
1329
Roland McGrath6d2b3492002-12-30 00:51:30 +00001330#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001331extern int sys_nerr;
1332extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001333#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001334
1335const char *
1336strerror(errno)
1337int errno;
1338{
1339 static char buf[64];
1340
1341 if (errno < 1 || errno >= sys_nerr) {
1342 sprintf(buf, "Unknown error %d", errno);
1343 return buf;
1344 }
1345 return sys_errlist[errno];
1346}
1347
1348#endif /* HAVE_STERRROR */
1349
1350#ifndef HAVE_STRSIGNAL
1351
Roland McGrath8f474e02003-01-14 07:53:33 +00001352#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001353extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001354#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001355#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1356extern char *_sys_siglist[];
1357#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001358
1359const char *
1360strsignal(sig)
1361int sig;
1362{
1363 static char buf[64];
1364
1365 if (sig < 1 || sig >= NSIG) {
1366 sprintf(buf, "Unknown signal %d", sig);
1367 return buf;
1368 }
1369#ifdef HAVE__SYS_SIGLIST
1370 return _sys_siglist[sig];
1371#else
1372 return sys_siglist[sig];
1373#endif
1374}
1375
1376#endif /* HAVE_STRSIGNAL */
1377
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001378#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001379
1380static void
1381rebuild_pollv()
1382{
1383 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001384
Roland McGrathee9d4352002-12-18 04:16:10 +00001385 if (pollv != NULL)
1386 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001387 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001388 if (pollv == NULL) {
1389 fprintf(stderr, "strace: out of memory for poll vector\n");
1390 exit(1);
1391 }
1392
Roland McGrathca16be82003-01-10 19:55:28 +00001393 for (i = j = 0; i < tcbtabsize; i++) {
1394 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001395 if (!(tcp->flags & TCB_INUSE))
1396 continue;
1397 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001398 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001399 j++;
1400 }
1401 if (j != nprocs) {
1402 fprintf(stderr, "strace: proc miscount\n");
1403 exit(1);
1404 }
1405}
1406
1407#ifndef HAVE_POLLABLE_PROCFS
1408
1409static void
1410proc_poll_open()
1411{
1412 int arg;
1413 int i;
1414
1415 if (pipe(proc_poll_pipe) < 0) {
1416 perror("pipe");
1417 exit(1);
1418 }
1419 for (i = 0; i < 2; i++) {
1420 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1421 perror("F_GETFD");
1422 exit(1);
1423 }
1424 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1425 perror("F_SETFD");
1426 exit(1);
1427 }
1428 }
1429}
1430
1431static int
1432proc_poll(pollv, nfds, timeout)
1433struct pollfd *pollv;
1434int nfds;
1435int timeout;
1436{
1437 int i;
1438 int n;
1439 struct proc_pollfd pollinfo;
1440
1441 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1442 return n;
1443 if (n != sizeof(struct proc_pollfd)) {
1444 fprintf(stderr, "panic: short read: %d\n", n);
1445 exit(1);
1446 }
1447 for (i = 0; i < nprocs; i++) {
1448 if (pollv[i].fd == pollinfo.fd)
1449 pollv[i].revents = pollinfo.revents;
1450 else
1451 pollv[i].revents = 0;
1452 }
1453 poller_pid = pollinfo.pid;
1454 return 1;
1455}
1456
1457static void
1458wakeup_handler(sig)
1459int sig;
1460{
1461}
1462
1463static void
1464proc_poller(pfd)
1465int pfd;
1466{
1467 struct proc_pollfd pollinfo;
1468 struct sigaction sa;
1469 sigset_t blocked_set, empty_set;
1470 int i;
1471 int n;
1472 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001473#ifdef FREEBSD
1474 struct procfs_status pfs;
1475#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001476
1477 switch (fork()) {
1478 case -1:
1479 perror("fork");
1480 _exit(0);
1481 case 0:
1482 break;
1483 default:
1484 return;
1485 }
1486
1487 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1488 sa.sa_flags = 0;
1489 sigemptyset(&sa.sa_mask);
1490 sigaction(SIGHUP, &sa, NULL);
1491 sigaction(SIGINT, &sa, NULL);
1492 sigaction(SIGQUIT, &sa, NULL);
1493 sigaction(SIGPIPE, &sa, NULL);
1494 sigaction(SIGTERM, &sa, NULL);
1495 sa.sa_handler = wakeup_handler;
1496 sigaction(SIGUSR1, &sa, NULL);
1497 sigemptyset(&blocked_set);
1498 sigaddset(&blocked_set, SIGUSR1);
1499 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1500 sigemptyset(&empty_set);
1501
1502 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1503 perror("getrlimit(RLIMIT_NOFILE, ...)");
1504 _exit(0);
1505 }
1506 n = rl.rlim_cur;
1507 for (i = 0; i < n; i++) {
1508 if (i != pfd && i != proc_poll_pipe[1])
1509 close(i);
1510 }
1511
1512 pollinfo.fd = pfd;
1513 pollinfo.pid = getpid();
1514 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001515#ifndef FREEBSD
1516 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1517#else /* FREEBSD */
1518 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1519#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001520 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001521 switch (errno) {
1522 case EINTR:
1523 continue;
1524 case EBADF:
1525 pollinfo.revents = POLLERR;
1526 break;
1527 case ENOENT:
1528 pollinfo.revents = POLLHUP;
1529 break;
1530 default:
1531 perror("proc_poller: PIOCWSTOP");
1532 }
1533 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1534 _exit(0);
1535 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001536 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001537 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1538 sigsuspend(&empty_set);
1539 }
1540}
1541
1542#endif /* !HAVE_POLLABLE_PROCFS */
1543
1544static int
1545choose_pfd()
1546{
1547 int i, j;
1548 struct tcb *tcp;
1549
1550 static int last;
1551
1552 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001553 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001554 /*
1555 * The previous process is ready to run again. We'll
1556 * let it do so if it is currently in a syscall. This
1557 * heuristic improves the readability of the trace.
1558 */
1559 tcp = pfd2tcb(pollv[last].fd);
1560 if (tcp && (tcp->flags & TCB_INSYSCALL))
1561 return pollv[last].fd;
1562 }
1563
1564 for (i = 0; i < nprocs; i++) {
1565 /* Let competing children run round robin. */
1566 j = (i + last + 1) % nprocs;
1567 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1568 tcp = pfd2tcb(pollv[j].fd);
1569 if (!tcp) {
1570 fprintf(stderr, "strace: lost proc\n");
1571 exit(1);
1572 }
1573 droptcb(tcp);
1574 return -1;
1575 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001576 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001577 last = j;
1578 return pollv[j].fd;
1579 }
1580 }
1581 fprintf(stderr, "strace: nothing ready\n");
1582 exit(1);
1583}
1584
1585static int
1586trace()
1587{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001588#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001589 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001590#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001591 struct tcb *tcp;
1592 int pfd;
1593 int what;
1594 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001595 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001596
1597 for (;;) {
1598 if (interactive)
1599 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1600
1601 if (nprocs == 0)
1602 break;
1603
1604 switch (nprocs) {
1605 case 1:
1606#ifndef HAVE_POLLABLE_PROCFS
1607 if (proc_poll_pipe[0] == -1) {
1608#endif
1609 tcp = pid2tcb(0);
1610 if (!tcp)
1611 continue;
1612 pfd = tcp->pfd;
1613 if (pfd == -1)
1614 continue;
1615 break;
1616#ifndef HAVE_POLLABLE_PROCFS
1617 }
1618 /* fall through ... */
1619#endif /* !HAVE_POLLABLE_PROCFS */
1620 default:
1621#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001622#ifdef POLL_HACK
1623 /* On some systems (e.g. UnixWare) we get too much ugly
1624 "unfinished..." stuff when multiple proceses are in
1625 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001626
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001627 if (in_syscall) {
1628 struct pollfd pv;
1629 tcp = in_syscall;
1630 in_syscall = NULL;
1631 pv.fd = tcp->pfd;
1632 pv.events = POLLWANT;
1633 if ((what = poll (&pv, 1, 1)) < 0) {
1634 if (interrupted)
1635 return 0;
1636 continue;
1637 }
1638 else if (what == 1 && pv.revents & POLLWANT) {
1639 goto FOUND;
1640 }
1641 }
1642#endif
1643
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001644 if (poll(pollv, nprocs, INFTIM) < 0) {
1645 if (interrupted)
1646 return 0;
1647 continue;
1648 }
1649#else /* !HAVE_POLLABLE_PROCFS */
1650 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1651 if (interrupted)
1652 return 0;
1653 continue;
1654 }
1655#endif /* !HAVE_POLLABLE_PROCFS */
1656 pfd = choose_pfd();
1657 if (pfd == -1)
1658 continue;
1659 break;
1660 }
1661
1662 /* Look up `pfd' in our table. */
1663 if ((tcp = pfd2tcb(pfd)) == NULL) {
1664 fprintf(stderr, "unknown pfd: %u\n", pfd);
1665 exit(1);
1666 }
John Hughesb6643082002-05-23 11:02:22 +00001667#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001668 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001669#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670 /* Get the status of the process. */
1671 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001672#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001673 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001674#else /* FREEBSD */
1675 /* Thanks to some scheduling mystery, the first poller
1676 sometimes waits for the already processed end of fork
1677 event. Doing a non blocking poll here solves the problem. */
1678 if (proc_poll_pipe[0] != -1)
1679 ioctl_result = IOCTL_STATUS (tcp);
1680 else
1681 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001682#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001683 ioctl_errno = errno;
1684#ifndef HAVE_POLLABLE_PROCFS
1685 if (proc_poll_pipe[0] != -1) {
1686 if (ioctl_result < 0)
1687 kill(poller_pid, SIGKILL);
1688 else
1689 kill(poller_pid, SIGUSR1);
1690 }
1691#endif /* !HAVE_POLLABLE_PROCFS */
1692 }
1693 if (interrupted)
1694 return 0;
1695
1696 if (interactive)
1697 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1698
1699 if (ioctl_result < 0) {
1700 /* Find out what happened if it failed. */
1701 switch (ioctl_errno) {
1702 case EINTR:
1703 case EBADF:
1704 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001705#ifdef FREEBSD
1706 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001707#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001708 case ENOENT:
1709 droptcb(tcp);
1710 continue;
1711 default:
1712 perror("PIOCWSTOP");
1713 exit(1);
1714 }
1715 }
1716
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001717#ifdef FREEBSD
1718 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1719 /* discard first event for a syscall we never entered */
1720 IOCTL (tcp->pfd, PIOCRUN, 0);
1721 continue;
1722 }
Roland McGrath553a6092002-12-16 20:40:39 +00001723#endif
1724
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001725 /* clear the just started flag */
1726 tcp->flags &= ~TCB_STARTUP;
1727
1728 /* set current output file */
1729 outf = tcp->outf;
1730
1731 if (cflag) {
1732 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001733#ifdef FREEBSD
1734 char buf[1024];
1735 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001736
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001737 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1738 buf[len] = '\0';
1739 sscanf(buf,
1740 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1741 &stime.tv_sec, &stime.tv_usec);
1742 } else
1743 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001744#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001745 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1746 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001747#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001748 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1749 tcp->stime = stime;
1750 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001751 what = tcp->status.PR_WHAT;
1752 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001753#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001754 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001755 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1756 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001757 if (trace_syscall(tcp) < 0) {
1758 fprintf(stderr, "syscall trouble\n");
1759 exit(1);
1760 }
1761 }
1762 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001763#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001765#ifdef POLL_HACK
1766 in_syscall = tcp;
1767#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001768 case PR_SYSEXIT:
1769 if (trace_syscall(tcp) < 0) {
1770 fprintf(stderr, "syscall trouble\n");
1771 exit(1);
1772 }
1773 break;
1774 case PR_SIGNALLED:
1775 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1776 printleader(tcp);
1777 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001778 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001779 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001780#ifdef PR_INFO
1781 if (tcp->status.PR_INFO.si_signo == what) {
1782 printleader(tcp);
1783 tprintf(" siginfo=");
1784 printsiginfo(&tcp->status.PR_INFO, 1);
1785 printtrailer(tcp);
1786 }
1787#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001788 }
1789 break;
1790 case PR_FAULTED:
1791 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1792 printleader(tcp);
1793 tprintf("=== FAULT %d ===", what);
1794 printtrailer(tcp);
1795 }
1796 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001797#ifdef FREEBSD
1798 case 0: /* handle case we polled for nothing */
1799 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001800#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001801 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001802 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001803 exit(1);
1804 break;
1805 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001806 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001807#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001808 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001809#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001810 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001811#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001812 perror("PIOCRUN");
1813 exit(1);
1814 }
1815 }
1816 return 0;
1817}
1818
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001819#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001820
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001821#ifdef TCB_GROUP_EXITING
1822/* Handle an exit detach or death signal that is taking all the
1823 related clone threads with it. This is called in three circumstances:
1824 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1825 SIG == 0 Continuing TCP will perform an exit_group syscall.
1826 SIG == other Continuing TCP with SIG will kill the process.
1827*/
1828static int
1829handle_group_exit(struct tcb *tcp, int sig)
1830{
1831 /* We need to locate our records of all the clone threads
1832 related to TCP, either its children or siblings. */
1833 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1834 ? tcp->parent
1835 : tcp->nclone_detached > 0
1836 ? tcp : NULL);
1837
1838 if (sig < 0) {
1839 if (leader != NULL && leader != tcp)
1840 fprintf(stderr,
1841 "PANIC: handle_group_exit: %d leader %d\n",
1842 tcp->pid, leader ? leader->pid : -1);
1843 droptcb(tcp); /* Already died. */
1844 }
1845 else {
1846 if (tcp->flags & TCB_ATTACHED) {
1847 if (leader != NULL && leader != tcp) {
1848 /* We need to detach the leader so that the
1849 process death will be reported to its real
1850 parent. But we kill it first to prevent
1851 it doing anything before we kill the whole
1852 process in a moment. We can use
1853 PTRACE_KILL on a thread that's not already
1854 stopped. Then the value we pass in
1855 PTRACE_DETACH just sets the death
1856 signal reported to the real parent. */
1857 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1858 if (debug)
1859 fprintf(stderr,
1860 " [%d exit %d kills %d]\n",
1861 tcp->pid, sig, leader->pid);
1862 detach(leader, sig);
1863 }
1864 detach(tcp, sig);
1865 }
1866 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1867 perror("strace: ptrace(PTRACE_CONT, ...)");
1868 cleanup();
1869 return -1;
1870 }
1871 else {
1872 if (leader != NULL && leader != tcp)
1873 droptcb(tcp);
1874 /* The leader will report to us as parent now,
1875 and then we'll get to the SIG==-1 case. */
1876 return 0;
1877 }
1878 }
1879
1880 /* Note that TCP and LEADER are no longer valid,
1881 but we can still compare against them. */
1882 if (leader != NULL) {
1883 unsigned int i;
1884 for (i = 0; i < tcbtabsize; i++) {
1885 struct tcb *t = tcbtab[i];
1886 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1887 && t->parent == leader)
1888 droptcb(t);
1889 }
1890 }
1891
1892 return 0;
1893}
1894#endif
1895
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001896static int
1897trace()
1898{
1899 int pid;
1900 int wait_errno;
1901 int status;
1902 struct tcb *tcp;
1903#ifdef LINUX
1904 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001905#ifdef __WALL
1906 static int wait4_options = __WALL;
1907#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001908#endif /* LINUX */
1909
1910 while (nprocs != 0) {
1911 if (interactive)
1912 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1913#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001914#ifdef __WALL
1915 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00001916 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001917 /* this kernel does not support __WALL */
1918 wait4_options &= ~__WALL;
1919 errno = 0;
1920 pid = wait4(-1, &status, wait4_options,
1921 cflag ? &ru : NULL);
1922 }
Roland McGrath5bc05552002-12-17 04:50:47 +00001923 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001924 /* most likely a "cloned" process */
1925 pid = wait4(-1, &status, __WCLONE,
1926 cflag ? &ru : NULL);
1927 if (pid == -1) {
1928 fprintf(stderr, "strace: clone wait4 "
1929 "failed: %s\n", strerror(errno));
1930 }
1931 }
1932#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001933 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001934#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001935#endif /* LINUX */
1936#ifdef SUNOS4
1937 pid = wait(&status);
1938#endif /* SUNOS4 */
1939 wait_errno = errno;
1940 if (interactive)
1941 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1942
1943 if (interrupted)
1944 return 0;
1945
1946 if (pid == -1) {
1947 switch (wait_errno) {
1948 case EINTR:
1949 continue;
1950 case ECHILD:
1951 /*
1952 * We would like to verify this case
1953 * but sometimes a race in Solbourne's
1954 * version of SunOS sometimes reports
1955 * ECHILD before sending us SIGCHILD.
1956 */
1957#if 0
1958 if (nprocs == 0)
1959 return 0;
1960 fprintf(stderr, "strace: proc miscount\n");
1961 exit(1);
1962#endif
1963 return 0;
1964 default:
1965 errno = wait_errno;
1966 perror("strace: wait");
1967 return -1;
1968 }
1969 }
1970 if (debug)
1971 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1972
1973 /* Look up `pid' in our table. */
1974 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001975#ifdef LINUX
1976 if (followfork || followvfork) {
1977 /* This is needed to go with the CLONE_PTRACE
1978 changes in process.c/util.c: we might see
1979 the child's initial trap before we see the
1980 parent return from the clone syscall.
1981 Leave the child suspended until the parent
1982 returns from its system call. Only then
1983 will we have the association of parent and
1984 child so that we know how to do clearbpt
1985 in the child. */
1986 if ((tcp = alloctcb(pid)) == NULL) {
1987 fprintf(stderr, " [tcb table full]\n");
1988 kill(pid, SIGKILL); /* XXX */
1989 return 0;
1990 }
1991 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
1992 newoutf(tcp);
1993 if (!qflag)
1994 fprintf(stderr, "\
1995Process %d attached (waiting for parent)\n",
1996 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001997 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001998 else
1999 /* This can happen if a clone call used
2000 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002001#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002002 {
2003 fprintf(stderr, "unknown pid: %u\n", pid);
2004 if (WIFSTOPPED(status))
2005 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2006 exit(1);
2007 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002008 }
2009 /* set current output file */
2010 outf = tcp->outf;
2011 if (cflag) {
2012#ifdef LINUX
2013 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2014 tcp->stime = ru.ru_stime;
2015#endif /* !LINUX */
2016 }
2017
2018 if (tcp->flags & TCB_SUSPENDED) {
2019 /*
2020 * Apparently, doing any ptrace() call on a stopped
2021 * process, provokes the kernel to report the process
2022 * status again on a subsequent wait(), even if the
2023 * process has not been actually restarted.
2024 * Since we have inspected the arguments of suspended
2025 * processes we end up here testing for this case.
2026 */
2027 continue;
2028 }
2029 if (WIFSIGNALED(status)) {
2030 if (!cflag
2031 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2032 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002033 tprintf("+++ killed by %s %s+++",
2034 signame(WTERMSIG(status)),
2035#ifdef WCOREDUMP
2036 WCOREDUMP(status) ? "(core dumped) " :
2037#endif
2038 "");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002039 printtrailer(tcp);
2040 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002041#ifdef TCB_GROUP_EXITING
2042 handle_group_exit(tcp, -1);
2043#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002044 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002045#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002046 continue;
2047 }
2048 if (WIFEXITED(status)) {
2049 if (debug)
2050 fprintf(stderr, "pid %u exited\n", pid);
2051 if (tcp->flags & TCB_ATTACHED)
2052 fprintf(stderr,
2053 "PANIC: attached pid %u exited\n",
2054 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002055 if (tcp == tcp_last) {
2056 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2057 == TCB_INSYSCALL)
2058 tprintf(" <unfinished ... exit status %d>\n",
2059 WEXITSTATUS(status));
2060 tcp_last = NULL;
2061 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002062#ifdef TCB_GROUP_EXITING
2063 handle_group_exit(tcp, -1);
2064#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002065 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002066#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002067 continue;
2068 }
2069 if (!WIFSTOPPED(status)) {
2070 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2071 droptcb(tcp);
2072 continue;
2073 }
2074 if (debug)
2075 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002076 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002077
2078 if (tcp->flags & TCB_STARTUP) {
2079 /*
2080 * This flag is there to keep us in sync.
2081 * Next time this process stops it should
2082 * really be entering a system call.
2083 */
2084 tcp->flags &= ~TCB_STARTUP;
2085 if (tcp->flags & TCB_ATTACHED) {
2086 /*
2087 * Interestingly, the process may stop
2088 * with STOPSIG equal to some other signal
2089 * than SIGSTOP if we happend to attach
2090 * just before the process takes a signal.
2091 */
2092 if (!WIFSTOPPED(status)) {
2093 fprintf(stderr,
2094 "pid %u not stopped\n", pid);
2095 detach(tcp, WSTOPSIG(status));
2096 continue;
2097 }
2098 }
2099 else {
2100#ifdef SUNOS4
2101 /* A child of us stopped at exec */
2102 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2103 fixvfork(tcp);
2104#endif /* SUNOS4 */
2105 }
2106 if (tcp->flags & TCB_BPTSET) {
2107 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2108 droptcb(tcp);
2109 cleanup();
2110 return -1;
2111 }
2112 }
2113 goto tracing;
2114 }
2115
2116 if (WSTOPSIG(status) != SIGTRAP) {
2117 if (WSTOPSIG(status) == SIGSTOP &&
2118 (tcp->flags & TCB_SIGTRAPPED)) {
2119 /*
2120 * Trapped attempt to block SIGTRAP
2121 * Hope we are back in control now.
2122 */
2123 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2124 if (ptrace(PTRACE_SYSCALL,
2125 pid, (char *) 1, 0) < 0) {
2126 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2127 cleanup();
2128 return -1;
2129 }
2130 continue;
2131 }
2132 if (!cflag
2133 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002134 unsigned long addr = 0, pc = 0;
2135#ifdef PT_GETSIGINFO
2136# define PSR_RI 41
2137 struct siginfo si;
2138 unsigned long psr;
2139
2140 upeek(pid, PT_CR_IPSR, &psr);
2141 upeek(pid, PT_CR_IIP, &pc);
2142
2143 pc += (psr >> PSR_RI) & 0x3;
2144 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2145 addr = (unsigned long) si.si_addr;
2146#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002147 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002148 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002149 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002150 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002151 printtrailer(tcp);
2152 }
2153 if ((tcp->flags & TCB_ATTACHED) &&
2154 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002155#ifdef TCB_GROUP_EXITING
2156 handle_group_exit(tcp, WSTOPSIG(status));
2157#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002158 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002159#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002160 continue;
2161 }
2162 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2163 WSTOPSIG(status)) < 0) {
2164 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2165 cleanup();
2166 return -1;
2167 }
2168 tcp->flags &= ~TCB_SUSPENDED;
2169 continue;
2170 }
2171 if (trace_syscall(tcp) < 0) {
2172 if (tcp->flags & TCB_ATTACHED)
2173 detach(tcp, 0);
2174 else {
2175 ptrace(PTRACE_KILL,
2176 tcp->pid, (char *) 1, SIGTERM);
2177 droptcb(tcp);
2178 }
2179 continue;
2180 }
2181 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002182#ifdef TCB_GROUP_EXITING
2183 if (tcp->flags & TCB_GROUP_EXITING) {
2184 if (handle_group_exit(tcp, 0) < 0)
2185 return -1;
2186 continue;
2187 }
2188#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002189 if (tcp->flags & TCB_ATTACHED)
2190 detach(tcp, 0);
2191 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2192 perror("strace: ptrace(PTRACE_CONT, ...)");
2193 cleanup();
2194 return -1;
2195 }
2196 continue;
2197 }
2198 if (tcp->flags & TCB_SUSPENDED) {
2199 if (!qflag)
2200 fprintf(stderr, "Process %u suspended\n", pid);
2201 continue;
2202 }
2203 tracing:
2204 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2205 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2206 cleanup();
2207 return -1;
2208 }
2209 }
2210 return 0;
2211}
2212
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002213#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002214
2215static int curcol;
2216
2217#ifdef __STDC__
2218#include <stdarg.h>
2219#define VA_START(a, b) va_start(a, b)
2220#else
2221#include <varargs.h>
2222#define VA_START(a, b) va_start(a)
2223#endif
2224
2225void
2226#ifdef __STDC__
2227tprintf(const char *fmt, ...)
2228#else
2229tprintf(fmt, va_alist)
2230char *fmt;
2231va_dcl
2232#endif
2233{
2234 va_list args;
2235
2236 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002237 if (outf) {
2238 int n = vfprintf(outf, fmt, args);
2239 if (n < 0 && outf != stderr)
2240 perror(outfname == NULL
2241 ? "<writing to pipe>" : outfname);
2242 else
2243 curcol += n;
2244 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002245 va_end(args);
2246 return;
2247}
2248
2249void
2250printleader(tcp)
2251struct tcb *tcp;
2252{
2253 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2254 tcp_last->flags |= TCB_REPRINT;
2255 tprintf(" <unfinished ...>\n");
2256 }
2257 curcol = 0;
2258 if ((followfork == 1 || pflag_seen > 1) && outfname)
2259 tprintf("%-5d ", tcp->pid);
2260 else if (nprocs > 1 && !outfname)
2261 tprintf("[pid %5u] ", tcp->pid);
2262 if (tflag) {
2263 char str[sizeof("HH:MM:SS")];
2264 struct timeval tv, dtv;
2265 static struct timeval otv;
2266
2267 gettimeofday(&tv, NULL);
2268 if (rflag) {
2269 if (otv.tv_sec == 0)
2270 otv = tv;
2271 tv_sub(&dtv, &tv, &otv);
2272 tprintf("%6ld.%06ld ",
2273 (long) dtv.tv_sec, (long) dtv.tv_usec);
2274 otv = tv;
2275 }
2276 else if (tflag > 2) {
2277 tprintf("%ld.%06ld ",
2278 (long) tv.tv_sec, (long) tv.tv_usec);
2279 }
2280 else {
2281 time_t local = tv.tv_sec;
2282 strftime(str, sizeof(str), "%T", localtime(&local));
2283 if (tflag > 1)
2284 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2285 else
2286 tprintf("%s ", str);
2287 }
2288 }
2289 if (iflag)
2290 printcall(tcp);
2291}
2292
2293void
2294tabto(col)
2295int col;
2296{
2297 if (curcol < col)
2298 tprintf("%*s", col - curcol, "");
2299}
2300
2301void
2302printtrailer(tcp)
2303struct tcb *tcp;
2304{
2305 tprintf("\n");
2306 tcp_last = NULL;
2307}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002308
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002309#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002310
2311int mp_ioctl (int fd, int cmd, void *arg, int size) {
2312
2313 struct iovec iov[2];
2314 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002315
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002316 iov[0].iov_base = &cmd;
2317 iov[0].iov_len = sizeof cmd;
2318 if (arg) {
2319 ++n;
2320 iov[1].iov_base = arg;
2321 iov[1].iov_len = size;
2322 }
Roland McGrath553a6092002-12-16 20:40:39 +00002323
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002324 return writev (fd, iov, n);
2325}
2326
2327#endif