blob: 9f287f7e7d6a2623819ce5fbc925c240edb922eb [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",
411 pid);
412 }
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];
420 if (strchr(filename, '/'))
421 strcpy(pathname, filename);
422#ifdef USE_DEBUGGING_EXEC
423 /*
424 * Debuggers customarily check the current directory
425 * first regardless of the path but doing that gives
426 * security geeks a panic attack.
427 */
428 else if (stat(filename, &statbuf) == 0)
429 strcpy(pathname, filename);
430#endif /* USE_DEBUGGING_EXEC */
431 else {
432 char *path;
433 int m, n, len;
434
435 for (path = getenv("PATH"); path && *path; path += m) {
436 if (strchr(path, ':')) {
437 n = strchr(path, ':') - path;
438 m = n + 1;
439 }
440 else
441 m = n = strlen(path);
442 if (n == 0) {
443 getcwd(pathname, MAXPATHLEN);
444 len = strlen(pathname);
445 }
446 else {
447 strncpy(pathname, path, n);
448 len = n;
449 }
450 if (len && pathname[len - 1] != '/')
451 pathname[len++] = '/';
452 strcpy(pathname + len, filename);
Roland McGrathed645162003-06-03 07:18:19 +0000453 if (stat(pathname, &statbuf) == 0 &&
454 /* Accept only regular files
455 with some execute bits set.
456 XXX not perfect, might still fail */
457 S_ISREG(statbuf.st_mode) &&
458 (statbuf.st_mode & 0111))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000459 break;
460 }
461 }
462 if (stat(pathname, &statbuf) < 0) {
463 fprintf(stderr, "%s: %s: command not found\n",
464 progname, filename);
465 exit(1);
466 }
467 switch (pid = fork()) {
468 case -1:
469 perror("strace: fork");
470 cleanup();
471 exit(1);
472 break;
473 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000474#ifdef USE_PROCFS
475 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000476#ifdef MIPS
477 /* Kludge for SGI, see proc_open for details. */
478 sa.sa_handler = foobar;
479 sa.sa_flags = 0;
480 sigemptyset(&sa.sa_mask);
481 sigaction(SIGINT, &sa, NULL);
482#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000483#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000484 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000485#else /* FREEBSD */
486 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000487#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000488#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000489 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000490 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000491
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000492 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
493 perror("strace: ptrace(PTRACE_TRACEME, ...)");
494 return -1;
495 }
496 if (debug)
497 kill(getpid(), SIGSTOP);
498
499 if (username != NULL || geteuid() == 0) {
500 uid_t run_euid = run_uid;
501 gid_t run_egid = run_gid;
502
503 if (statbuf.st_mode & S_ISUID)
504 run_euid = statbuf.st_uid;
505 if (statbuf.st_mode & S_ISGID)
506 run_egid = statbuf.st_gid;
507
508 /*
509 * It is important to set groups before we
510 * lose privileges on setuid.
511 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000512 if (username != NULL) {
513 if (initgroups(username, run_gid) < 0) {
514 perror("initgroups");
515 exit(1);
516 }
517 if (setregid(run_gid, run_egid) < 0) {
518 perror("setregid");
519 exit(1);
520 }
521 if (setreuid(run_uid, run_euid) < 0) {
522 perror("setreuid");
523 exit(1);
524 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000525 }
526 }
527 else
528 setreuid(run_uid, run_uid);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000529#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000530
531 execv(pathname, &argv[optind]);
532 perror("strace: exec");
533 _exit(1);
534 break;
535 }
536 default:
537 if ((tcp = alloctcb(pid)) == NULL) {
538 fprintf(stderr, "tcb table full\n");
539 cleanup();
540 exit(1);
541 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000542#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543 if (proc_open(tcp, 0) < 0) {
544 fprintf(stderr, "trouble opening proc file\n");
545 cleanup();
546 exit(1);
547 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000548#endif /* USE_PROCFS */
549#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000550 fake_execve(tcp, pathname, &argv[optind], environ);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000551#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000552 break;
553 }
554 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000555
556 sigemptyset(&empty_set);
557 sigemptyset(&blocked_set);
558 sa.sa_handler = SIG_IGN;
559 sigemptyset(&sa.sa_mask);
560 sa.sa_flags = 0;
561 sigaction(SIGTTOU, &sa, NULL);
562 sigaction(SIGTTIN, &sa, NULL);
563 if (interactive) {
564 sigaddset(&blocked_set, SIGHUP);
565 sigaddset(&blocked_set, SIGINT);
566 sigaddset(&blocked_set, SIGQUIT);
567 sigaddset(&blocked_set, SIGPIPE);
568 sigaddset(&blocked_set, SIGTERM);
569 sa.sa_handler = interrupt;
570#ifdef SUNOS4
571 /* POSIX signals on sunos4.1 are a little broken. */
572 sa.sa_flags = SA_INTERRUPT;
573#endif /* SUNOS4 */
574 }
575 sigaction(SIGHUP, &sa, NULL);
576 sigaction(SIGINT, &sa, NULL);
577 sigaction(SIGQUIT, &sa, NULL);
578 sigaction(SIGPIPE, &sa, NULL);
579 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000580#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000581 sa.sa_handler = reaper;
582 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000583#else
584 /* Make sure SIGCHLD has the default action so that waitpid
585 definitely works without losing track of children. The user
586 should not have given us a bogus state to inherit, but he might
587 have. Arguably we should detect SIG_IGN here and pass it on
588 to children, but probably noone really needs that. */
589 sa.sa_handler = SIG_DFL;
590 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000591#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000592
593 if (trace() < 0)
594 exit(1);
595 cleanup();
596 exit(0);
597}
598
599void
600newoutf(tcp)
601struct tcb *tcp;
602{
603 char name[MAXPATHLEN];
604 FILE *fp;
605
606 if (outfname && followfork > 1) {
607 sprintf(name, "%s.%u", outfname, tcp->pid);
608#ifndef SVR4
609 setreuid(geteuid(), getuid());
610#endif
611 fp = fopen(name, "w");
612#ifndef SVR4
613 setreuid(geteuid(), getuid());
614#endif
615 if (fp == NULL) {
616 perror("fopen");
617 return;
618 }
619 tcp->outf = fp;
620 }
621 return;
622}
623
624struct tcb *
625alloctcb(pid)
626int pid;
627{
628 int i;
629 struct tcb *tcp;
630
Roland McGrathee9d4352002-12-18 04:16:10 +0000631 for (i = 0; i < tcbtabsize; i++) {
632 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000633 if ((tcp->flags & TCB_INUSE) == 0) {
634 tcp->pid = pid;
635 tcp->parent = NULL;
636 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000637 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000638#ifdef TCB_CLONE_THREAD
639 tcp->nclone_threads = tcp->nclone_detached = 0;
640 tcp->nclone_waiting = 0;
641#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000642 tcp->flags = TCB_INUSE | TCB_STARTUP;
643 tcp->outf = outf; /* Initialise to current out file */
644 tcp->stime.tv_sec = 0;
645 tcp->stime.tv_usec = 0;
646 tcp->pfd = -1;
647 nprocs++;
648 return tcp;
649 }
650 }
651 return NULL;
652}
653
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000654#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000655int
656proc_open(tcp, attaching)
657struct tcb *tcp;
658int attaching;
659{
660 char proc[32];
661 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000662#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000663 int i;
664 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000665 sigset_t signals;
666 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000667#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000668#ifndef HAVE_POLLABLE_PROCFS
669 static int last_pfd;
670#endif
671
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000672#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000673 /* Open the process pseudo-files in /proc. */
674 sprintf(proc, "/proc/%d/ctl", tcp->pid);
675 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000676 perror("strace: open(\"/proc/...\", ...)");
677 return -1;
678 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000679 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
680 perror("F_GETFD");
681 return -1;
682 }
683 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
684 perror("F_SETFD");
685 return -1;
686 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000687 sprintf(proc, "/proc/%d/status", tcp->pid);
688 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
689 perror("strace: open(\"/proc/...\", ...)");
690 return -1;
691 }
692 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
693 perror("F_GETFD");
694 return -1;
695 }
696 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
697 perror("F_SETFD");
698 return -1;
699 }
700 sprintf(proc, "/proc/%d/as", tcp->pid);
701 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
702 perror("strace: open(\"/proc/...\", ...)");
703 return -1;
704 }
705 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
706 perror("F_GETFD");
707 return -1;
708 }
709 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
710 perror("F_SETFD");
711 return -1;
712 }
713#else
714 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000715#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000716 sprintf(proc, "/proc/%d", tcp->pid);
717 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000718#else /* FREEBSD */
719 sprintf(proc, "/proc/%d/mem", tcp->pid);
720 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
721#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000722 perror("strace: open(\"/proc/...\", ...)");
723 return -1;
724 }
725 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
726 perror("F_GETFD");
727 return -1;
728 }
729 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
730 perror("F_SETFD");
731 return -1;
732 }
733#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000734#ifdef FREEBSD
735 sprintf(proc, "/proc/%d/regs", tcp->pid);
736 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
737 perror("strace: open(\"/proc/.../regs\", ...)");
738 return -1;
739 }
740 if (cflag) {
741 sprintf(proc, "/proc/%d/status", tcp->pid);
742 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
743 perror("strace: open(\"/proc/.../status\", ...)");
744 return -1;
745 }
746 } else
747 tcp->pfd_status = -1;
748#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000749 rebuild_pollv();
750 if (!attaching) {
751 /*
752 * Wait for the child to pause. Because of a race
753 * condition we have to poll for the event.
754 */
755 for (;;) {
756 if (IOCTL_STATUS (tcp) < 0) {
757 perror("strace: PIOCSTATUS");
758 return -1;
759 }
760 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000761 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000762 }
763 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000764#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000765 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000766 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000767 perror("strace: PIOCSTOP");
768 return -1;
769 }
Roland McGrath553a6092002-12-16 20:40:39 +0000770#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000771#ifdef PIOCSET
772 /* Set Run-on-Last-Close. */
773 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000774 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775 perror("PIOCSET PR_RLC");
776 return -1;
777 }
778 /* Set or Reset Inherit-on-Fork. */
779 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000780 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000781 perror("PIOC{SET,RESET} PR_FORK");
782 return -1;
783 }
784#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000785#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000786 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
787 perror("PIOCSRLC");
788 return -1;
789 }
790 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
791 perror("PIOC{S,R}FORK");
792 return -1;
793 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000794#else /* FREEBSD */
795 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
796 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
797 perror("PIOCGFL");
798 return -1;
799 }
800 arg &= ~PF_LINGER;
801 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
802 perror("PIOCSFL");
803 return -1;
804 }
805#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000806#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000807#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000808 /* Enable all syscall entries we care about. */
809 premptyset(&syscalls);
810 for (i = 1; i < MAX_QUALS; ++i) {
811 if (i > (sizeof syscalls) * CHAR_BIT) break;
812 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
813 }
814 praddset (&syscalls, SYS_execve);
815 if (followfork) {
816 praddset (&syscalls, SYS_fork);
817#ifdef SYS_forkall
818 praddset (&syscalls, SYS_forkall);
819#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000820#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000821 praddset (&syscalls, SYS_fork1);
822#endif
823#ifdef SYS_rfork1
824 praddset (&syscalls, SYS_rfork1);
825#endif
826#ifdef SYS_rforkall
827 praddset (&syscalls, SYS_rforkall);
828#endif
829 }
830 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000831 perror("PIOCSENTRY");
832 return -1;
833 }
John Hughes19e49982001-10-19 08:59:12 +0000834 /* Enable the syscall exits. */
835 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000836 perror("PIOSEXIT");
837 return -1;
838 }
John Hughes19e49982001-10-19 08:59:12 +0000839 /* Enable signals we care about. */
840 premptyset(&signals);
841 for (i = 1; i < MAX_QUALS; ++i) {
842 if (i > (sizeof signals) * CHAR_BIT) break;
843 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
844 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000845 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000846 perror("PIOCSTRACE");
847 return -1;
848 }
John Hughes19e49982001-10-19 08:59:12 +0000849 /* Enable faults we care about */
850 premptyset(&faults);
851 for (i = 1; i < MAX_QUALS; ++i) {
852 if (i > (sizeof faults) * CHAR_BIT) break;
853 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
854 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000855 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000856 perror("PIOCSFAULT");
857 return -1;
858 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000859#else /* FREEBSD */
860 /* set events flags. */
861 arg = S_SIG | S_SCE | S_SCX ;
862 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
863 perror("PIOCBIS");
864 return -1;
865 }
866#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000867 if (!attaching) {
868#ifdef MIPS
869 /*
870 * The SGI PRSABORT doesn't work for pause() so
871 * we send it a caught signal to wake it up.
872 */
873 kill(tcp->pid, SIGINT);
874#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000875#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000876 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000877 arg = PRSABORT;
878 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000879 perror("PIOCRUN");
880 return -1;
881 }
Roland McGrath553a6092002-12-16 20:40:39 +0000882#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000883#endif /* !MIPS*/
884#ifdef FREEBSD
885 /* wake up the child if it received the SIGSTOP */
886 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000887#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000888 for (;;) {
889 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000890 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000891 perror("PIOCWSTOP");
892 return -1;
893 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000894 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000895 tcp->flags &= ~TCB_INSYSCALL;
896 get_scno(tcp);
897 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000898 break;
899 }
900 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000901#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000902 arg = 0;
903 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000904#else /* FREEBSD */
905 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +0000906#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000907 perror("PIOCRUN");
908 return -1;
909 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000910#ifdef FREEBSD
911 /* handle the case where we "opened" the child before
912 it did the kill -STOP */
913 if (tcp->status.PR_WHY == PR_SIGNALLED &&
914 tcp->status.PR_WHAT == SIGSTOP)
915 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000916#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000917 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000918#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000919 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000920#else /* FREEBSD */
921 } else {
Roland McGrath553a6092002-12-16 20:40:39 +0000922 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000923 /* We are attaching to an already running process.
924 * Try to figure out the state of the process in syscalls,
925 * to handle the first event well.
926 * This is done by having a look at the "wchan" property of the
927 * process, which tells where it is stopped (if it is). */
928 FILE * status;
929 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +0000930
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000931 sprintf(proc, "/proc/%d/status", tcp->pid);
932 status = fopen(proc, "r");
933 if (status &&
934 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
935 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
936 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
937 strcmp(wchan, "stopevent")) {
938 /* The process is asleep in the middle of a syscall.
939 Fake the syscall entry event */
940 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
941 tcp->status.PR_WHY = PR_SYSENTRY;
942 trace_syscall(tcp);
943 }
944 if (status)
945 fclose(status);
946 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000947 }
948#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000949#ifndef HAVE_POLLABLE_PROCFS
950 if (proc_poll_pipe[0] != -1)
951 proc_poller(tcp->pfd);
952 else if (nprocs > 1) {
953 proc_poll_open();
954 proc_poller(last_pfd);
955 proc_poller(tcp->pfd);
956 }
957 last_pfd = tcp->pfd;
958#endif /* !HAVE_POLLABLE_PROCFS */
959 return 0;
960}
961
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000962#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000963
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000964struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000965pid2tcb(pid)
966int pid;
967{
968 int i;
969 struct tcb *tcp;
970
Roland McGrathee9d4352002-12-18 04:16:10 +0000971 for (i = 0; i < tcbtabsize; i++) {
972 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000973 if (pid && tcp->pid != pid)
974 continue;
975 if (tcp->flags & TCB_INUSE)
976 return tcp;
977 }
978 return NULL;
979}
980
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000981#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000982
983static struct tcb *
984pfd2tcb(pfd)
985int pfd;
986{
987 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000988
Roland McGrathca16be82003-01-10 19:55:28 +0000989 for (i = 0; i < tcbtabsize; i++) {
990 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 if (tcp->pfd != pfd)
992 continue;
993 if (tcp->flags & TCB_INUSE)
994 return tcp;
995 }
996 return NULL;
997}
998
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000999#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001000
1001void
1002droptcb(tcp)
1003struct tcb *tcp;
1004{
1005 if (tcp->pid == 0)
1006 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001007#ifdef TCB_CLONE_THREAD
1008 if (tcp->nclone_threads > 0) {
1009 /* There are other threads left in this process, but this
1010 is the one whose PID represents the whole process.
1011 We need to keep this record around as a zombie until
1012 all the threads die. */
1013 tcp->flags |= TCB_EXITING;
1014 return;
1015 }
1016#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001017 nprocs--;
1018 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001019
Roland McGrathe29341c2003-01-10 20:14:20 +00001020 if (tcp->parent != NULL) {
1021 tcp->parent->nchildren--;
1022#ifdef TCB_CLONE_THREAD
1023 if (tcp->flags & TCB_CLONE_DETACHED)
1024 tcp->parent->nclone_detached--;
1025 if (tcp->flags & TCB_CLONE_THREAD)
1026 tcp->parent->nclone_threads--;
1027#endif
Roland McGrath09623452003-05-23 02:27:13 +00001028#ifdef TCB_CLONE_DETACHED
1029 if (!(tcp->flags & TCB_CLONE_DETACHED))
1030#endif
1031 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001032 tcp->parent = NULL;
1033 }
1034
1035 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001036 if (tcp->pfd != -1) {
1037 close(tcp->pfd);
1038 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001039#ifdef FREEBSD
1040 if (tcp->pfd_reg != -1) {
1041 close(tcp->pfd_reg);
1042 tcp->pfd_reg = -1;
1043 }
1044 if (tcp->pfd_status != -1) {
1045 close(tcp->pfd_status);
1046 tcp->pfd_status = -1;
1047 }
Roland McGrath553a6092002-12-16 20:40:39 +00001048#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001049#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001050 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001051#endif
1052 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001053
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001054 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001055 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001056
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001057 tcp->outf = 0;
1058}
1059
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001060#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061
1062static int
1063resume(tcp)
1064struct tcb *tcp;
1065{
1066 if (tcp == NULL)
1067 return -1;
1068
1069 if (!(tcp->flags & TCB_SUSPENDED)) {
1070 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1071 return -1;
1072 }
1073 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001074#ifdef TCB_CLONE_THREAD
1075 if (tcp->flags & TCB_CLONE_THREAD)
1076 tcp->parent->nclone_waiting--;
1077#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001078
1079 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1080 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1081 return -1;
1082 }
1083
1084 if (!qflag)
1085 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1086 return 0;
1087}
1088
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001089#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001090
1091/* detach traced process; continue with sig */
1092
1093static int
1094detach(tcp, sig)
1095struct tcb *tcp;
1096int sig;
1097{
1098 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001099#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001100 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001101#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102
1103 if (tcp->flags & TCB_BPTSET)
1104 sig = SIGKILL;
1105
1106#ifdef LINUX
1107 /*
1108 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001109 * before detaching. Arghh. We go through hoops
1110 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001111 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001112#if defined(SPARC)
1113#undef PTRACE_DETACH
1114#define PTRACE_DETACH PTRACE_SUNDETACH
1115#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001116 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1117 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001118 }
1119 else if (errno != ESRCH) {
1120 /* Shouldn't happen. */
1121 perror("detach: ptrace(PTRACE_DETACH, ...)");
1122 }
1123 else if (kill(tcp->pid, 0) < 0) {
1124 if (errno != ESRCH)
1125 perror("detach: checking sanity");
1126 }
1127 else if (kill(tcp->pid, SIGSTOP) < 0) {
1128 if (errno != ESRCH)
1129 perror("detach: stopping child");
1130 }
1131 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001133#ifdef __WALL
1134 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1135 if (errno == ECHILD) /* Already gone. */
1136 break;
1137 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001138 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001139 break;
1140 }
1141#endif /* __WALL */
1142 /* No __WALL here. */
1143 if (waitpid(tcp->pid, &status, 0) < 0) {
1144 if (errno != ECHILD) {
1145 perror("detach: waiting");
1146 break;
1147 }
1148#ifdef __WCLONE
1149 /* If no processes, try clones. */
1150 if (wait4(tcp->pid, &status, __WCLONE,
1151 NULL) < 0) {
1152 if (errno != ECHILD)
1153 perror("detach: waiting");
1154 break;
1155 }
1156#endif /* __WCLONE */
1157 }
1158#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001159 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001160#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001161 if (!WIFSTOPPED(status)) {
1162 /* Au revoir, mon ami. */
1163 break;
1164 }
1165 if (WSTOPSIG(status) == SIGSTOP) {
1166 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001167 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001168 if (errno != ESRCH)
1169 perror("detach: ptrace(PTRACE_DETACH, ...)");
1170 /* I died trying. */
1171 }
1172 break;
1173 }
1174 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001175 WSTOPSIG(status) == SIGTRAP ?
1176 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177 if (errno != ESRCH)
1178 perror("detach: ptrace(PTRACE_CONT, ...)");
1179 break;
1180 }
1181 }
1182 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001183#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184
1185#if defined(SUNOS4)
1186 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1187 if (sig && kill(tcp->pid, sig) < 0)
1188 perror("detach: kill");
1189 sig = 0;
1190 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1191 perror("detach: ptrace(PTRACE_DETACH, ...)");
1192#endif /* SUNOS4 */
1193
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001194#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001195 resumed = 0;
1196
1197 /* XXX This won't always be quite right (but it never was).
1198 A waiter with argument 0 or < -1 is waiting for any pid in
1199 a particular pgrp, which this child might or might not be
1200 in. The waiter will only wake up if it's argument is -1
1201 or if it's waiting for tcp->pid's pgrp. It makes a
1202 difference to wake up a waiter when there might be more
1203 traced children, because it could get a false ECHILD
1204 error. OTOH, if this was the last child in the pgrp, then
1205 it ought to wake up and get ECHILD. We would have to
1206 search the system for all pid's in the pgrp to be sure.
1207
1208 && (t->waitpid == -1 ||
1209 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1210 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1211 */
1212
1213 if (tcp->parent &&
1214 (tcp->parent->flags & TCB_SUSPENDED) &&
1215 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1216 error = resume(tcp->parent);
1217 ++resumed;
1218 }
1219#ifdef TCB_CLONE_THREAD
1220 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1221 /* Some other threads of our parent are waiting too. */
1222 unsigned int i;
1223
1224 /* Resume all the threads that were waiting for this PID. */
1225 for (i = 0; i < tcbtabsize; i++) {
1226 struct tcb *t = tcbtab[i];
1227 if (t->parent == tcp->parent && t != tcp
1228 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1229 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1230 && t->waitpid == tcp->pid) {
1231 error |= resume (t);
1232 ++resumed;
1233 }
1234 }
1235 if (resumed == 0)
1236 /* Noone was waiting for this PID in particular,
1237 so now we might need to resume some wildcarders. */
1238 for (i = 0; i < tcbtabsize; i++) {
1239 struct tcb *t = tcbtab[i];
1240 if (t->parent == tcp->parent && t != tcp
1241 && ((t->flags
1242 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1243 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1244 && t->waitpid <= 0
1245 ) {
1246 error |= resume (t);
1247 break;
1248 }
1249 }
1250 }
1251#endif
1252
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001253#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001254
1255 if (!qflag)
1256 fprintf(stderr, "Process %u detached\n", tcp->pid);
1257
1258 droptcb(tcp);
1259 return error;
1260}
1261
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001262#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001263
1264static void
1265reaper(sig)
1266int sig;
1267{
1268 int pid;
1269 int status;
1270
1271 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1272#if 0
1273 struct tcb *tcp;
1274
1275 tcp = pid2tcb(pid);
1276 if (tcp)
1277 droptcb(tcp);
1278#endif
1279 }
1280}
1281
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001282#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001283
1284static void
1285cleanup()
1286{
1287 int i;
1288 struct tcb *tcp;
1289
Roland McGrathee9d4352002-12-18 04:16:10 +00001290 for (i = 0; i < tcbtabsize; i++) {
1291 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001292 if (!(tcp->flags & TCB_INUSE))
1293 continue;
1294 if (debug)
1295 fprintf(stderr,
1296 "cleanup: looking at pid %u\n", tcp->pid);
1297 if (tcp_last &&
1298 (!outfname || followfork < 2 || tcp_last == tcp)) {
1299 tprintf(" <unfinished ...>\n");
1300 tcp_last = NULL;
1301 }
1302 if (tcp->flags & TCB_ATTACHED)
1303 detach(tcp, 0);
1304 else {
1305 kill(tcp->pid, SIGCONT);
1306 kill(tcp->pid, SIGTERM);
1307 }
1308 }
1309 if (cflag)
1310 call_summary(outf);
1311}
1312
1313static void
1314interrupt(sig)
1315int sig;
1316{
1317 interrupted = 1;
1318}
1319
1320#ifndef HAVE_STRERROR
1321
Roland McGrath6d2b3492002-12-30 00:51:30 +00001322#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001323extern int sys_nerr;
1324extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001325#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001326
1327const char *
1328strerror(errno)
1329int errno;
1330{
1331 static char buf[64];
1332
1333 if (errno < 1 || errno >= sys_nerr) {
1334 sprintf(buf, "Unknown error %d", errno);
1335 return buf;
1336 }
1337 return sys_errlist[errno];
1338}
1339
1340#endif /* HAVE_STERRROR */
1341
1342#ifndef HAVE_STRSIGNAL
1343
Roland McGrath8f474e02003-01-14 07:53:33 +00001344#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001345extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001346#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001347#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1348extern char *_sys_siglist[];
1349#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001350
1351const char *
1352strsignal(sig)
1353int sig;
1354{
1355 static char buf[64];
1356
1357 if (sig < 1 || sig >= NSIG) {
1358 sprintf(buf, "Unknown signal %d", sig);
1359 return buf;
1360 }
1361#ifdef HAVE__SYS_SIGLIST
1362 return _sys_siglist[sig];
1363#else
1364 return sys_siglist[sig];
1365#endif
1366}
1367
1368#endif /* HAVE_STRSIGNAL */
1369
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001370#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371
1372static void
1373rebuild_pollv()
1374{
1375 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376
Roland McGrathee9d4352002-12-18 04:16:10 +00001377 if (pollv != NULL)
1378 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001379 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001380 if (pollv == NULL) {
1381 fprintf(stderr, "strace: out of memory for poll vector\n");
1382 exit(1);
1383 }
1384
Roland McGrathca16be82003-01-10 19:55:28 +00001385 for (i = j = 0; i < tcbtabsize; i++) {
1386 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001387 if (!(tcp->flags & TCB_INUSE))
1388 continue;
1389 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001390 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001391 j++;
1392 }
1393 if (j != nprocs) {
1394 fprintf(stderr, "strace: proc miscount\n");
1395 exit(1);
1396 }
1397}
1398
1399#ifndef HAVE_POLLABLE_PROCFS
1400
1401static void
1402proc_poll_open()
1403{
1404 int arg;
1405 int i;
1406
1407 if (pipe(proc_poll_pipe) < 0) {
1408 perror("pipe");
1409 exit(1);
1410 }
1411 for (i = 0; i < 2; i++) {
1412 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1413 perror("F_GETFD");
1414 exit(1);
1415 }
1416 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1417 perror("F_SETFD");
1418 exit(1);
1419 }
1420 }
1421}
1422
1423static int
1424proc_poll(pollv, nfds, timeout)
1425struct pollfd *pollv;
1426int nfds;
1427int timeout;
1428{
1429 int i;
1430 int n;
1431 struct proc_pollfd pollinfo;
1432
1433 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1434 return n;
1435 if (n != sizeof(struct proc_pollfd)) {
1436 fprintf(stderr, "panic: short read: %d\n", n);
1437 exit(1);
1438 }
1439 for (i = 0; i < nprocs; i++) {
1440 if (pollv[i].fd == pollinfo.fd)
1441 pollv[i].revents = pollinfo.revents;
1442 else
1443 pollv[i].revents = 0;
1444 }
1445 poller_pid = pollinfo.pid;
1446 return 1;
1447}
1448
1449static void
1450wakeup_handler(sig)
1451int sig;
1452{
1453}
1454
1455static void
1456proc_poller(pfd)
1457int pfd;
1458{
1459 struct proc_pollfd pollinfo;
1460 struct sigaction sa;
1461 sigset_t blocked_set, empty_set;
1462 int i;
1463 int n;
1464 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001465#ifdef FREEBSD
1466 struct procfs_status pfs;
1467#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001468
1469 switch (fork()) {
1470 case -1:
1471 perror("fork");
1472 _exit(0);
1473 case 0:
1474 break;
1475 default:
1476 return;
1477 }
1478
1479 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1480 sa.sa_flags = 0;
1481 sigemptyset(&sa.sa_mask);
1482 sigaction(SIGHUP, &sa, NULL);
1483 sigaction(SIGINT, &sa, NULL);
1484 sigaction(SIGQUIT, &sa, NULL);
1485 sigaction(SIGPIPE, &sa, NULL);
1486 sigaction(SIGTERM, &sa, NULL);
1487 sa.sa_handler = wakeup_handler;
1488 sigaction(SIGUSR1, &sa, NULL);
1489 sigemptyset(&blocked_set);
1490 sigaddset(&blocked_set, SIGUSR1);
1491 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1492 sigemptyset(&empty_set);
1493
1494 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1495 perror("getrlimit(RLIMIT_NOFILE, ...)");
1496 _exit(0);
1497 }
1498 n = rl.rlim_cur;
1499 for (i = 0; i < n; i++) {
1500 if (i != pfd && i != proc_poll_pipe[1])
1501 close(i);
1502 }
1503
1504 pollinfo.fd = pfd;
1505 pollinfo.pid = getpid();
1506 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001507#ifndef FREEBSD
1508 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1509#else /* FREEBSD */
1510 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1511#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001512 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001513 switch (errno) {
1514 case EINTR:
1515 continue;
1516 case EBADF:
1517 pollinfo.revents = POLLERR;
1518 break;
1519 case ENOENT:
1520 pollinfo.revents = POLLHUP;
1521 break;
1522 default:
1523 perror("proc_poller: PIOCWSTOP");
1524 }
1525 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1526 _exit(0);
1527 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001528 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001529 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1530 sigsuspend(&empty_set);
1531 }
1532}
1533
1534#endif /* !HAVE_POLLABLE_PROCFS */
1535
1536static int
1537choose_pfd()
1538{
1539 int i, j;
1540 struct tcb *tcp;
1541
1542 static int last;
1543
1544 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001545 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001546 /*
1547 * The previous process is ready to run again. We'll
1548 * let it do so if it is currently in a syscall. This
1549 * heuristic improves the readability of the trace.
1550 */
1551 tcp = pfd2tcb(pollv[last].fd);
1552 if (tcp && (tcp->flags & TCB_INSYSCALL))
1553 return pollv[last].fd;
1554 }
1555
1556 for (i = 0; i < nprocs; i++) {
1557 /* Let competing children run round robin. */
1558 j = (i + last + 1) % nprocs;
1559 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1560 tcp = pfd2tcb(pollv[j].fd);
1561 if (!tcp) {
1562 fprintf(stderr, "strace: lost proc\n");
1563 exit(1);
1564 }
1565 droptcb(tcp);
1566 return -1;
1567 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001568 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001569 last = j;
1570 return pollv[j].fd;
1571 }
1572 }
1573 fprintf(stderr, "strace: nothing ready\n");
1574 exit(1);
1575}
1576
1577static int
1578trace()
1579{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001580#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001581 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001582#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001583 struct tcb *tcp;
1584 int pfd;
1585 int what;
1586 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001587 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001588
1589 for (;;) {
1590 if (interactive)
1591 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1592
1593 if (nprocs == 0)
1594 break;
1595
1596 switch (nprocs) {
1597 case 1:
1598#ifndef HAVE_POLLABLE_PROCFS
1599 if (proc_poll_pipe[0] == -1) {
1600#endif
1601 tcp = pid2tcb(0);
1602 if (!tcp)
1603 continue;
1604 pfd = tcp->pfd;
1605 if (pfd == -1)
1606 continue;
1607 break;
1608#ifndef HAVE_POLLABLE_PROCFS
1609 }
1610 /* fall through ... */
1611#endif /* !HAVE_POLLABLE_PROCFS */
1612 default:
1613#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001614#ifdef POLL_HACK
1615 /* On some systems (e.g. UnixWare) we get too much ugly
1616 "unfinished..." stuff when multiple proceses are in
1617 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001618
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001619 if (in_syscall) {
1620 struct pollfd pv;
1621 tcp = in_syscall;
1622 in_syscall = NULL;
1623 pv.fd = tcp->pfd;
1624 pv.events = POLLWANT;
1625 if ((what = poll (&pv, 1, 1)) < 0) {
1626 if (interrupted)
1627 return 0;
1628 continue;
1629 }
1630 else if (what == 1 && pv.revents & POLLWANT) {
1631 goto FOUND;
1632 }
1633 }
1634#endif
1635
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636 if (poll(pollv, nprocs, INFTIM) < 0) {
1637 if (interrupted)
1638 return 0;
1639 continue;
1640 }
1641#else /* !HAVE_POLLABLE_PROCFS */
1642 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1643 if (interrupted)
1644 return 0;
1645 continue;
1646 }
1647#endif /* !HAVE_POLLABLE_PROCFS */
1648 pfd = choose_pfd();
1649 if (pfd == -1)
1650 continue;
1651 break;
1652 }
1653
1654 /* Look up `pfd' in our table. */
1655 if ((tcp = pfd2tcb(pfd)) == NULL) {
1656 fprintf(stderr, "unknown pfd: %u\n", pfd);
1657 exit(1);
1658 }
John Hughesb6643082002-05-23 11:02:22 +00001659#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001660 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001661#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001662 /* Get the status of the process. */
1663 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001664#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001665 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001666#else /* FREEBSD */
1667 /* Thanks to some scheduling mystery, the first poller
1668 sometimes waits for the already processed end of fork
1669 event. Doing a non blocking poll here solves the problem. */
1670 if (proc_poll_pipe[0] != -1)
1671 ioctl_result = IOCTL_STATUS (tcp);
1672 else
1673 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001674#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675 ioctl_errno = errno;
1676#ifndef HAVE_POLLABLE_PROCFS
1677 if (proc_poll_pipe[0] != -1) {
1678 if (ioctl_result < 0)
1679 kill(poller_pid, SIGKILL);
1680 else
1681 kill(poller_pid, SIGUSR1);
1682 }
1683#endif /* !HAVE_POLLABLE_PROCFS */
1684 }
1685 if (interrupted)
1686 return 0;
1687
1688 if (interactive)
1689 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1690
1691 if (ioctl_result < 0) {
1692 /* Find out what happened if it failed. */
1693 switch (ioctl_errno) {
1694 case EINTR:
1695 case EBADF:
1696 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001697#ifdef FREEBSD
1698 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001699#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001700 case ENOENT:
1701 droptcb(tcp);
1702 continue;
1703 default:
1704 perror("PIOCWSTOP");
1705 exit(1);
1706 }
1707 }
1708
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001709#ifdef FREEBSD
1710 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1711 /* discard first event for a syscall we never entered */
1712 IOCTL (tcp->pfd, PIOCRUN, 0);
1713 continue;
1714 }
Roland McGrath553a6092002-12-16 20:40:39 +00001715#endif
1716
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001717 /* clear the just started flag */
1718 tcp->flags &= ~TCB_STARTUP;
1719
1720 /* set current output file */
1721 outf = tcp->outf;
1722
1723 if (cflag) {
1724 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001725#ifdef FREEBSD
1726 char buf[1024];
1727 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001729 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1730 buf[len] = '\0';
1731 sscanf(buf,
1732 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1733 &stime.tv_sec, &stime.tv_usec);
1734 } else
1735 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001736#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001737 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1738 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001739#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001740 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1741 tcp->stime = stime;
1742 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001743 what = tcp->status.PR_WHAT;
1744 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001745#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001746 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001747 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1748 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001749 if (trace_syscall(tcp) < 0) {
1750 fprintf(stderr, "syscall trouble\n");
1751 exit(1);
1752 }
1753 }
1754 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001755#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001756 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001757#ifdef POLL_HACK
1758 in_syscall = tcp;
1759#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001760 case PR_SYSEXIT:
1761 if (trace_syscall(tcp) < 0) {
1762 fprintf(stderr, "syscall trouble\n");
1763 exit(1);
1764 }
1765 break;
1766 case PR_SIGNALLED:
1767 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1768 printleader(tcp);
1769 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001770 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001771 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001772#ifdef PR_INFO
1773 if (tcp->status.PR_INFO.si_signo == what) {
1774 printleader(tcp);
1775 tprintf(" siginfo=");
1776 printsiginfo(&tcp->status.PR_INFO, 1);
1777 printtrailer(tcp);
1778 }
1779#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001780 }
1781 break;
1782 case PR_FAULTED:
1783 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1784 printleader(tcp);
1785 tprintf("=== FAULT %d ===", what);
1786 printtrailer(tcp);
1787 }
1788 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001789#ifdef FREEBSD
1790 case 0: /* handle case we polled for nothing */
1791 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001792#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001793 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001794 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001795 exit(1);
1796 break;
1797 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001798 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001799#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001800 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001801#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001802 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001803#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001804 perror("PIOCRUN");
1805 exit(1);
1806 }
1807 }
1808 return 0;
1809}
1810
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001811#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001812
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001813#ifdef TCB_GROUP_EXITING
1814/* Handle an exit detach or death signal that is taking all the
1815 related clone threads with it. This is called in three circumstances:
1816 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1817 SIG == 0 Continuing TCP will perform an exit_group syscall.
1818 SIG == other Continuing TCP with SIG will kill the process.
1819*/
1820static int
1821handle_group_exit(struct tcb *tcp, int sig)
1822{
1823 /* We need to locate our records of all the clone threads
1824 related to TCP, either its children or siblings. */
1825 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1826 ? tcp->parent
1827 : tcp->nclone_detached > 0
1828 ? tcp : NULL);
1829
1830 if (sig < 0) {
1831 if (leader != NULL && leader != tcp)
1832 fprintf(stderr,
1833 "PANIC: handle_group_exit: %d leader %d\n",
1834 tcp->pid, leader ? leader->pid : -1);
1835 droptcb(tcp); /* Already died. */
1836 }
1837 else {
1838 if (tcp->flags & TCB_ATTACHED) {
1839 if (leader != NULL && leader != tcp) {
1840 /* We need to detach the leader so that the
1841 process death will be reported to its real
1842 parent. But we kill it first to prevent
1843 it doing anything before we kill the whole
1844 process in a moment. We can use
1845 PTRACE_KILL on a thread that's not already
1846 stopped. Then the value we pass in
1847 PTRACE_DETACH just sets the death
1848 signal reported to the real parent. */
1849 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1850 if (debug)
1851 fprintf(stderr,
1852 " [%d exit %d kills %d]\n",
1853 tcp->pid, sig, leader->pid);
1854 detach(leader, sig);
1855 }
1856 detach(tcp, sig);
1857 }
1858 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1859 perror("strace: ptrace(PTRACE_CONT, ...)");
1860 cleanup();
1861 return -1;
1862 }
1863 else {
1864 if (leader != NULL && leader != tcp)
1865 droptcb(tcp);
1866 /* The leader will report to us as parent now,
1867 and then we'll get to the SIG==-1 case. */
1868 return 0;
1869 }
1870 }
1871
1872 /* Note that TCP and LEADER are no longer valid,
1873 but we can still compare against them. */
1874 if (leader != NULL) {
1875 unsigned int i;
1876 for (i = 0; i < tcbtabsize; i++) {
1877 struct tcb *t = tcbtab[i];
1878 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1879 && t->parent == leader)
1880 droptcb(t);
1881 }
1882 }
1883
1884 return 0;
1885}
1886#endif
1887
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001888static int
1889trace()
1890{
1891 int pid;
1892 int wait_errno;
1893 int status;
1894 struct tcb *tcp;
1895#ifdef LINUX
1896 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001897#ifdef __WALL
1898 static int wait4_options = __WALL;
1899#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001900#endif /* LINUX */
1901
1902 while (nprocs != 0) {
1903 if (interactive)
1904 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1905#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001906#ifdef __WALL
1907 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00001908 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001909 /* this kernel does not support __WALL */
1910 wait4_options &= ~__WALL;
1911 errno = 0;
1912 pid = wait4(-1, &status, wait4_options,
1913 cflag ? &ru : NULL);
1914 }
Roland McGrath5bc05552002-12-17 04:50:47 +00001915 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001916 /* most likely a "cloned" process */
1917 pid = wait4(-1, &status, __WCLONE,
1918 cflag ? &ru : NULL);
1919 if (pid == -1) {
1920 fprintf(stderr, "strace: clone wait4 "
1921 "failed: %s\n", strerror(errno));
1922 }
1923 }
1924#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001925 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001926#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001927#endif /* LINUX */
1928#ifdef SUNOS4
1929 pid = wait(&status);
1930#endif /* SUNOS4 */
1931 wait_errno = errno;
1932 if (interactive)
1933 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1934
1935 if (interrupted)
1936 return 0;
1937
1938 if (pid == -1) {
1939 switch (wait_errno) {
1940 case EINTR:
1941 continue;
1942 case ECHILD:
1943 /*
1944 * We would like to verify this case
1945 * but sometimes a race in Solbourne's
1946 * version of SunOS sometimes reports
1947 * ECHILD before sending us SIGCHILD.
1948 */
1949#if 0
1950 if (nprocs == 0)
1951 return 0;
1952 fprintf(stderr, "strace: proc miscount\n");
1953 exit(1);
1954#endif
1955 return 0;
1956 default:
1957 errno = wait_errno;
1958 perror("strace: wait");
1959 return -1;
1960 }
1961 }
1962 if (debug)
1963 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1964
1965 /* Look up `pid' in our table. */
1966 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001967#ifdef LINUX
1968 if (followfork || followvfork) {
1969 /* This is needed to go with the CLONE_PTRACE
1970 changes in process.c/util.c: we might see
1971 the child's initial trap before we see the
1972 parent return from the clone syscall.
1973 Leave the child suspended until the parent
1974 returns from its system call. Only then
1975 will we have the association of parent and
1976 child so that we know how to do clearbpt
1977 in the child. */
1978 if ((tcp = alloctcb(pid)) == NULL) {
1979 fprintf(stderr, " [tcb table full]\n");
1980 kill(pid, SIGKILL); /* XXX */
1981 return 0;
1982 }
1983 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
1984 newoutf(tcp);
1985 if (!qflag)
1986 fprintf(stderr, "\
1987Process %d attached (waiting for parent)\n",
1988 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001989 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001990 else
1991 /* This can happen if a clone call used
1992 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001993#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001994 {
1995 fprintf(stderr, "unknown pid: %u\n", pid);
1996 if (WIFSTOPPED(status))
1997 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1998 exit(1);
1999 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002000 }
2001 /* set current output file */
2002 outf = tcp->outf;
2003 if (cflag) {
2004#ifdef LINUX
2005 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2006 tcp->stime = ru.ru_stime;
2007#endif /* !LINUX */
2008 }
2009
2010 if (tcp->flags & TCB_SUSPENDED) {
2011 /*
2012 * Apparently, doing any ptrace() call on a stopped
2013 * process, provokes the kernel to report the process
2014 * status again on a subsequent wait(), even if the
2015 * process has not been actually restarted.
2016 * Since we have inspected the arguments of suspended
2017 * processes we end up here testing for this case.
2018 */
2019 continue;
2020 }
2021 if (WIFSIGNALED(status)) {
2022 if (!cflag
2023 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2024 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002025 tprintf("+++ killed by %s %s+++",
2026 signame(WTERMSIG(status)),
2027#ifdef WCOREDUMP
2028 WCOREDUMP(status) ? "(core dumped) " :
2029#endif
2030 "");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002031 printtrailer(tcp);
2032 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002033#ifdef TCB_GROUP_EXITING
2034 handle_group_exit(tcp, -1);
2035#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002036 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002037#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002038 continue;
2039 }
2040 if (WIFEXITED(status)) {
2041 if (debug)
2042 fprintf(stderr, "pid %u exited\n", pid);
2043 if (tcp->flags & TCB_ATTACHED)
2044 fprintf(stderr,
2045 "PANIC: attached pid %u exited\n",
2046 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002047 if (tcp == tcp_last) {
2048 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2049 == TCB_INSYSCALL)
2050 tprintf(" <unfinished ... exit status %d>\n",
2051 WEXITSTATUS(status));
2052 tcp_last = NULL;
2053 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002054#ifdef TCB_GROUP_EXITING
2055 handle_group_exit(tcp, -1);
2056#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002057 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002058#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002059 continue;
2060 }
2061 if (!WIFSTOPPED(status)) {
2062 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2063 droptcb(tcp);
2064 continue;
2065 }
2066 if (debug)
2067 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002068 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002069
2070 if (tcp->flags & TCB_STARTUP) {
2071 /*
2072 * This flag is there to keep us in sync.
2073 * Next time this process stops it should
2074 * really be entering a system call.
2075 */
2076 tcp->flags &= ~TCB_STARTUP;
2077 if (tcp->flags & TCB_ATTACHED) {
2078 /*
2079 * Interestingly, the process may stop
2080 * with STOPSIG equal to some other signal
2081 * than SIGSTOP if we happend to attach
2082 * just before the process takes a signal.
2083 */
2084 if (!WIFSTOPPED(status)) {
2085 fprintf(stderr,
2086 "pid %u not stopped\n", pid);
2087 detach(tcp, WSTOPSIG(status));
2088 continue;
2089 }
2090 }
2091 else {
2092#ifdef SUNOS4
2093 /* A child of us stopped at exec */
2094 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2095 fixvfork(tcp);
2096#endif /* SUNOS4 */
2097 }
2098 if (tcp->flags & TCB_BPTSET) {
2099 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2100 droptcb(tcp);
2101 cleanup();
2102 return -1;
2103 }
2104 }
2105 goto tracing;
2106 }
2107
2108 if (WSTOPSIG(status) != SIGTRAP) {
2109 if (WSTOPSIG(status) == SIGSTOP &&
2110 (tcp->flags & TCB_SIGTRAPPED)) {
2111 /*
2112 * Trapped attempt to block SIGTRAP
2113 * Hope we are back in control now.
2114 */
2115 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2116 if (ptrace(PTRACE_SYSCALL,
2117 pid, (char *) 1, 0) < 0) {
2118 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2119 cleanup();
2120 return -1;
2121 }
2122 continue;
2123 }
2124 if (!cflag
2125 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002126 unsigned long addr = 0, pc = 0;
2127#ifdef PT_GETSIGINFO
2128# define PSR_RI 41
2129 struct siginfo si;
2130 unsigned long psr;
2131
2132 upeek(pid, PT_CR_IPSR, &psr);
2133 upeek(pid, PT_CR_IIP, &pc);
2134
2135 pc += (psr >> PSR_RI) & 0x3;
2136 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2137 addr = (unsigned long) si.si_addr;
2138#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002139 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002140 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002141 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002142 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002143 printtrailer(tcp);
2144 }
2145 if ((tcp->flags & TCB_ATTACHED) &&
2146 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002147#ifdef TCB_GROUP_EXITING
2148 handle_group_exit(tcp, WSTOPSIG(status));
2149#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002150 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002151#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002152 continue;
2153 }
2154 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2155 WSTOPSIG(status)) < 0) {
2156 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2157 cleanup();
2158 return -1;
2159 }
2160 tcp->flags &= ~TCB_SUSPENDED;
2161 continue;
2162 }
2163 if (trace_syscall(tcp) < 0) {
2164 if (tcp->flags & TCB_ATTACHED)
2165 detach(tcp, 0);
2166 else {
2167 ptrace(PTRACE_KILL,
2168 tcp->pid, (char *) 1, SIGTERM);
2169 droptcb(tcp);
2170 }
2171 continue;
2172 }
2173 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002174#ifdef TCB_GROUP_EXITING
2175 if (tcp->flags & TCB_GROUP_EXITING) {
2176 if (handle_group_exit(tcp, 0) < 0)
2177 return -1;
2178 continue;
2179 }
2180#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002181 if (tcp->flags & TCB_ATTACHED)
2182 detach(tcp, 0);
2183 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2184 perror("strace: ptrace(PTRACE_CONT, ...)");
2185 cleanup();
2186 return -1;
2187 }
2188 continue;
2189 }
2190 if (tcp->flags & TCB_SUSPENDED) {
2191 if (!qflag)
2192 fprintf(stderr, "Process %u suspended\n", pid);
2193 continue;
2194 }
2195 tracing:
2196 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2197 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2198 cleanup();
2199 return -1;
2200 }
2201 }
2202 return 0;
2203}
2204
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002205#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002206
2207static int curcol;
2208
2209#ifdef __STDC__
2210#include <stdarg.h>
2211#define VA_START(a, b) va_start(a, b)
2212#else
2213#include <varargs.h>
2214#define VA_START(a, b) va_start(a)
2215#endif
2216
2217void
2218#ifdef __STDC__
2219tprintf(const char *fmt, ...)
2220#else
2221tprintf(fmt, va_alist)
2222char *fmt;
2223va_dcl
2224#endif
2225{
2226 va_list args;
2227
2228 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002229 if (outf) {
2230 int n = vfprintf(outf, fmt, args);
2231 if (n < 0 && outf != stderr)
2232 perror(outfname == NULL
2233 ? "<writing to pipe>" : outfname);
2234 else
2235 curcol += n;
2236 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002237 va_end(args);
2238 return;
2239}
2240
2241void
2242printleader(tcp)
2243struct tcb *tcp;
2244{
2245 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2246 tcp_last->flags |= TCB_REPRINT;
2247 tprintf(" <unfinished ...>\n");
2248 }
2249 curcol = 0;
2250 if ((followfork == 1 || pflag_seen > 1) && outfname)
2251 tprintf("%-5d ", tcp->pid);
2252 else if (nprocs > 1 && !outfname)
2253 tprintf("[pid %5u] ", tcp->pid);
2254 if (tflag) {
2255 char str[sizeof("HH:MM:SS")];
2256 struct timeval tv, dtv;
2257 static struct timeval otv;
2258
2259 gettimeofday(&tv, NULL);
2260 if (rflag) {
2261 if (otv.tv_sec == 0)
2262 otv = tv;
2263 tv_sub(&dtv, &tv, &otv);
2264 tprintf("%6ld.%06ld ",
2265 (long) dtv.tv_sec, (long) dtv.tv_usec);
2266 otv = tv;
2267 }
2268 else if (tflag > 2) {
2269 tprintf("%ld.%06ld ",
2270 (long) tv.tv_sec, (long) tv.tv_usec);
2271 }
2272 else {
2273 time_t local = tv.tv_sec;
2274 strftime(str, sizeof(str), "%T", localtime(&local));
2275 if (tflag > 1)
2276 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2277 else
2278 tprintf("%s ", str);
2279 }
2280 }
2281 if (iflag)
2282 printcall(tcp);
2283}
2284
2285void
2286tabto(col)
2287int col;
2288{
2289 if (curcol < col)
2290 tprintf("%*s", col - curcol, "");
2291}
2292
2293void
2294printtrailer(tcp)
2295struct tcb *tcp;
2296{
2297 tprintf("\n");
2298 tcp_last = NULL;
2299}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002300
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002301#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002302
2303int mp_ioctl (int fd, int cmd, void *arg, int size) {
2304
2305 struct iovec iov[2];
2306 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002307
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002308 iov[0].iov_base = &cmd;
2309 iov[0].iov_len = sizeof cmd;
2310 if (arg) {
2311 ++n;
2312 iov[1].iov_base = arg;
2313 iov[1].iov_len = size;
2314 }
Roland McGrath553a6092002-12-16 20:40:39 +00002315
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002316 return writev (fd, iov, n);
2317}
2318
2319#endif