blob: 1d057fcd6201c869b2ad74016e977af363560de5 [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
307 /* See if they want to run as another user. */
308 if (username != NULL) {
309 struct passwd *pent;
310
311 if (getuid() != 0 || geteuid() != 0) {
312 fprintf(stderr,
313 "%s: you must be root to use the -u option\n",
314 progname);
315 exit(1);
316 }
317 if ((pent = getpwnam(username)) == NULL) {
318 fprintf(stderr, "%s: cannot find user `%s'\n",
319 progname, optarg);
320 exit(1);
321 }
322 run_uid = pent->pw_uid;
323 run_gid = pent->pw_gid;
324 }
325 else {
326 run_uid = getuid();
327 run_gid = getgid();
328 }
329
330#ifndef SVR4
331 setreuid(geteuid(), getuid());
332#endif
333
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000334 /* Check if they want to redirect the output. */
335 if (outfname) {
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000336 long f;
337
Roland McGrath37b9a662003-11-07 02:26:54 +0000338 /* See if they want to pipe the output. */
339 if (outfname[0] == '|' || outfname[0] == '!') {
340 /*
341 * We can't do the <outfname>.PID funny business
342 * when using popen, so prohibit it.
343 */
344 if (followfork > 1) {
345 fprintf(stderr, "\
346%s: piping the output and -ff are mutually exclusive options\n",
347 progname);
348 exit(1);
349 }
350
351 if ((outf = popen(outfname + 1, "w")) == NULL) {
352 fprintf(stderr, "%s: can't popen '%s': %s\n",
353 progname, outfname + 1,
354 strerror(errno));
355 exit(1);
356 }
357 }
358 else if ((outf = fopen(outfname, "w")) == NULL) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000359 fprintf(stderr, "%s: can't fopen '%s': %s\n",
360 progname, outfname, strerror(errno));
361 exit(1);
362 }
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000363
364 if ((f=fcntl(fileno(outf), F_GETFD)) < 0 ) {
365 perror("failed to get flags for outputfile");
366 exit(1);
367 }
368
369 if (fcntl(fileno(outf), F_SETFD, f|FD_CLOEXEC) < 0 ) {
370 perror("failed to set flags for outputfile");
371 exit(1);
372 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000373 }
374
375#ifndef SVR4
376 setreuid(geteuid(), getuid());
377#endif
378
Roland McGrath37b9a662003-11-07 02:26:54 +0000379 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000381 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000382 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000383 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000384 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000385
Roland McGrathee9d4352002-12-18 04:16:10 +0000386 for (c = 0; c < tcbtabsize; c++) {
387 tcp = tcbtab[c];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000388 /* Reinitialize the output since it may have changed. */
389 tcp->outf = outf;
390 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
391 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000392#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000393 if (proc_open(tcp, 1) < 0) {
394 fprintf(stderr, "trouble opening proc file\n");
395 droptcb(tcp);
396 continue;
397 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000398#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000399 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
400 perror("attach: ptrace(PTRACE_ATTACH, ...)");
401 droptcb(tcp);
402 continue;
403 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000404#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000405 if (!qflag)
406 fprintf(stderr,
407 "Process %u attached - interrupt to quit\n",
408 pid);
409 }
410
411 if (optind < argc) {
412 struct stat statbuf;
413 char *filename;
414 char pathname[MAXPATHLEN];
415
416 filename = argv[optind];
417 if (strchr(filename, '/'))
418 strcpy(pathname, filename);
419#ifdef USE_DEBUGGING_EXEC
420 /*
421 * Debuggers customarily check the current directory
422 * first regardless of the path but doing that gives
423 * security geeks a panic attack.
424 */
425 else if (stat(filename, &statbuf) == 0)
426 strcpy(pathname, filename);
427#endif /* USE_DEBUGGING_EXEC */
428 else {
429 char *path;
430 int m, n, len;
431
432 for (path = getenv("PATH"); path && *path; path += m) {
433 if (strchr(path, ':')) {
434 n = strchr(path, ':') - path;
435 m = n + 1;
436 }
437 else
438 m = n = strlen(path);
439 if (n == 0) {
440 getcwd(pathname, MAXPATHLEN);
441 len = strlen(pathname);
442 }
443 else {
444 strncpy(pathname, path, n);
445 len = n;
446 }
447 if (len && pathname[len - 1] != '/')
448 pathname[len++] = '/';
449 strcpy(pathname + len, filename);
Roland McGrathed645162003-06-03 07:18:19 +0000450 if (stat(pathname, &statbuf) == 0 &&
451 /* Accept only regular files
452 with some execute bits set.
453 XXX not perfect, might still fail */
454 S_ISREG(statbuf.st_mode) &&
455 (statbuf.st_mode & 0111))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000456 break;
457 }
458 }
459 if (stat(pathname, &statbuf) < 0) {
460 fprintf(stderr, "%s: %s: command not found\n",
461 progname, filename);
462 exit(1);
463 }
464 switch (pid = fork()) {
465 case -1:
466 perror("strace: fork");
467 cleanup();
468 exit(1);
469 break;
470 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000471#ifdef USE_PROCFS
472 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000473#ifdef MIPS
474 /* Kludge for SGI, see proc_open for details. */
475 sa.sa_handler = foobar;
476 sa.sa_flags = 0;
477 sigemptyset(&sa.sa_mask);
478 sigaction(SIGINT, &sa, NULL);
479#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000480#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000481 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000482#else /* FREEBSD */
483 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000484#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000485#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000486 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000487 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000488
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000489 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
490 perror("strace: ptrace(PTRACE_TRACEME, ...)");
491 return -1;
492 }
493 if (debug)
494 kill(getpid(), SIGSTOP);
495
496 if (username != NULL || geteuid() == 0) {
497 uid_t run_euid = run_uid;
498 gid_t run_egid = run_gid;
499
500 if (statbuf.st_mode & S_ISUID)
501 run_euid = statbuf.st_uid;
502 if (statbuf.st_mode & S_ISGID)
503 run_egid = statbuf.st_gid;
504
505 /*
506 * It is important to set groups before we
507 * lose privileges on setuid.
508 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000509 if (username != NULL) {
510 if (initgroups(username, run_gid) < 0) {
511 perror("initgroups");
512 exit(1);
513 }
514 if (setregid(run_gid, run_egid) < 0) {
515 perror("setregid");
516 exit(1);
517 }
518 if (setreuid(run_uid, run_euid) < 0) {
519 perror("setreuid");
520 exit(1);
521 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000522 }
523 }
524 else
525 setreuid(run_uid, run_uid);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000526#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000527
528 execv(pathname, &argv[optind]);
529 perror("strace: exec");
530 _exit(1);
531 break;
532 }
533 default:
534 if ((tcp = alloctcb(pid)) == NULL) {
535 fprintf(stderr, "tcb table full\n");
536 cleanup();
537 exit(1);
538 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000539#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000540 if (proc_open(tcp, 0) < 0) {
541 fprintf(stderr, "trouble opening proc file\n");
542 cleanup();
543 exit(1);
544 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000545#endif /* USE_PROCFS */
546#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000547 fake_execve(tcp, pathname, &argv[optind], environ);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000548#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000549 break;
550 }
551 }
552 else if (pflag_seen == 0)
553 usage(stderr, 1);
554
555 sigemptyset(&empty_set);
556 sigemptyset(&blocked_set);
557 sa.sa_handler = SIG_IGN;
558 sigemptyset(&sa.sa_mask);
559 sa.sa_flags = 0;
560 sigaction(SIGTTOU, &sa, NULL);
561 sigaction(SIGTTIN, &sa, NULL);
562 if (interactive) {
563 sigaddset(&blocked_set, SIGHUP);
564 sigaddset(&blocked_set, SIGINT);
565 sigaddset(&blocked_set, SIGQUIT);
566 sigaddset(&blocked_set, SIGPIPE);
567 sigaddset(&blocked_set, SIGTERM);
568 sa.sa_handler = interrupt;
569#ifdef SUNOS4
570 /* POSIX signals on sunos4.1 are a little broken. */
571 sa.sa_flags = SA_INTERRUPT;
572#endif /* SUNOS4 */
573 }
574 sigaction(SIGHUP, &sa, NULL);
575 sigaction(SIGINT, &sa, NULL);
576 sigaction(SIGQUIT, &sa, NULL);
577 sigaction(SIGPIPE, &sa, NULL);
578 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000579#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000580 sa.sa_handler = reaper;
581 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000582#else
583 /* Make sure SIGCHLD has the default action so that waitpid
584 definitely works without losing track of children. The user
585 should not have given us a bogus state to inherit, but he might
586 have. Arguably we should detect SIG_IGN here and pass it on
587 to children, but probably noone really needs that. */
588 sa.sa_handler = SIG_DFL;
589 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000590#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000591
592 if (trace() < 0)
593 exit(1);
594 cleanup();
595 exit(0);
596}
597
598void
599newoutf(tcp)
600struct tcb *tcp;
601{
602 char name[MAXPATHLEN];
603 FILE *fp;
604
605 if (outfname && followfork > 1) {
606 sprintf(name, "%s.%u", outfname, tcp->pid);
607#ifndef SVR4
608 setreuid(geteuid(), getuid());
609#endif
610 fp = fopen(name, "w");
611#ifndef SVR4
612 setreuid(geteuid(), getuid());
613#endif
614 if (fp == NULL) {
615 perror("fopen");
616 return;
617 }
618 tcp->outf = fp;
619 }
620 return;
621}
622
623struct tcb *
624alloctcb(pid)
625int pid;
626{
627 int i;
628 struct tcb *tcp;
629
Roland McGrathee9d4352002-12-18 04:16:10 +0000630 for (i = 0; i < tcbtabsize; i++) {
631 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000632 if ((tcp->flags & TCB_INUSE) == 0) {
633 tcp->pid = pid;
634 tcp->parent = NULL;
635 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000636 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000637#ifdef TCB_CLONE_THREAD
638 tcp->nclone_threads = tcp->nclone_detached = 0;
639 tcp->nclone_waiting = 0;
640#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 tcp->flags = TCB_INUSE | TCB_STARTUP;
642 tcp->outf = outf; /* Initialise to current out file */
643 tcp->stime.tv_sec = 0;
644 tcp->stime.tv_usec = 0;
645 tcp->pfd = -1;
646 nprocs++;
647 return tcp;
648 }
649 }
650 return NULL;
651}
652
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000653#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000654int
655proc_open(tcp, attaching)
656struct tcb *tcp;
657int attaching;
658{
659 char proc[32];
660 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000661#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000662 int i;
663 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000664 sigset_t signals;
665 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000666#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000667#ifndef HAVE_POLLABLE_PROCFS
668 static int last_pfd;
669#endif
670
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000671#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000672 /* Open the process pseudo-files in /proc. */
673 sprintf(proc, "/proc/%d/ctl", tcp->pid);
674 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000675 perror("strace: open(\"/proc/...\", ...)");
676 return -1;
677 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000678 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
679 perror("F_GETFD");
680 return -1;
681 }
682 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
683 perror("F_SETFD");
684 return -1;
685 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000686 sprintf(proc, "/proc/%d/status", tcp->pid);
687 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
688 perror("strace: open(\"/proc/...\", ...)");
689 return -1;
690 }
691 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
692 perror("F_GETFD");
693 return -1;
694 }
695 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
696 perror("F_SETFD");
697 return -1;
698 }
699 sprintf(proc, "/proc/%d/as", tcp->pid);
700 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
701 perror("strace: open(\"/proc/...\", ...)");
702 return -1;
703 }
704 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
705 perror("F_GETFD");
706 return -1;
707 }
708 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
709 perror("F_SETFD");
710 return -1;
711 }
712#else
713 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000714#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000715 sprintf(proc, "/proc/%d", tcp->pid);
716 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000717#else /* FREEBSD */
718 sprintf(proc, "/proc/%d/mem", tcp->pid);
719 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
720#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000721 perror("strace: open(\"/proc/...\", ...)");
722 return -1;
723 }
724 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
725 perror("F_GETFD");
726 return -1;
727 }
728 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
729 perror("F_SETFD");
730 return -1;
731 }
732#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000733#ifdef FREEBSD
734 sprintf(proc, "/proc/%d/regs", tcp->pid);
735 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
736 perror("strace: open(\"/proc/.../regs\", ...)");
737 return -1;
738 }
739 if (cflag) {
740 sprintf(proc, "/proc/%d/status", tcp->pid);
741 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
742 perror("strace: open(\"/proc/.../status\", ...)");
743 return -1;
744 }
745 } else
746 tcp->pfd_status = -1;
747#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000748 rebuild_pollv();
749 if (!attaching) {
750 /*
751 * Wait for the child to pause. Because of a race
752 * condition we have to poll for the event.
753 */
754 for (;;) {
755 if (IOCTL_STATUS (tcp) < 0) {
756 perror("strace: PIOCSTATUS");
757 return -1;
758 }
759 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000760 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000761 }
762 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000763#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000764 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000765 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000766 perror("strace: PIOCSTOP");
767 return -1;
768 }
Roland McGrath553a6092002-12-16 20:40:39 +0000769#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000770#ifdef PIOCSET
771 /* Set Run-on-Last-Close. */
772 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000773 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000774 perror("PIOCSET PR_RLC");
775 return -1;
776 }
777 /* Set or Reset Inherit-on-Fork. */
778 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000779 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780 perror("PIOC{SET,RESET} PR_FORK");
781 return -1;
782 }
783#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000784#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000785 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
786 perror("PIOCSRLC");
787 return -1;
788 }
789 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
790 perror("PIOC{S,R}FORK");
791 return -1;
792 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000793#else /* FREEBSD */
794 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
795 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
796 perror("PIOCGFL");
797 return -1;
798 }
799 arg &= ~PF_LINGER;
800 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
801 perror("PIOCSFL");
802 return -1;
803 }
804#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000805#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000806#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000807 /* Enable all syscall entries we care about. */
808 premptyset(&syscalls);
809 for (i = 1; i < MAX_QUALS; ++i) {
810 if (i > (sizeof syscalls) * CHAR_BIT) break;
811 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
812 }
813 praddset (&syscalls, SYS_execve);
814 if (followfork) {
815 praddset (&syscalls, SYS_fork);
816#ifdef SYS_forkall
817 praddset (&syscalls, SYS_forkall);
818#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000819#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000820 praddset (&syscalls, SYS_fork1);
821#endif
822#ifdef SYS_rfork1
823 praddset (&syscalls, SYS_rfork1);
824#endif
825#ifdef SYS_rforkall
826 praddset (&syscalls, SYS_rforkall);
827#endif
828 }
829 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000830 perror("PIOCSENTRY");
831 return -1;
832 }
John Hughes19e49982001-10-19 08:59:12 +0000833 /* Enable the syscall exits. */
834 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000835 perror("PIOSEXIT");
836 return -1;
837 }
John Hughes19e49982001-10-19 08:59:12 +0000838 /* Enable signals we care about. */
839 premptyset(&signals);
840 for (i = 1; i < MAX_QUALS; ++i) {
841 if (i > (sizeof signals) * CHAR_BIT) break;
842 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
843 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000844 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000845 perror("PIOCSTRACE");
846 return -1;
847 }
John Hughes19e49982001-10-19 08:59:12 +0000848 /* Enable faults we care about */
849 premptyset(&faults);
850 for (i = 1; i < MAX_QUALS; ++i) {
851 if (i > (sizeof faults) * CHAR_BIT) break;
852 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
853 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000854 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000855 perror("PIOCSFAULT");
856 return -1;
857 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000858#else /* FREEBSD */
859 /* set events flags. */
860 arg = S_SIG | S_SCE | S_SCX ;
861 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
862 perror("PIOCBIS");
863 return -1;
864 }
865#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000866 if (!attaching) {
867#ifdef MIPS
868 /*
869 * The SGI PRSABORT doesn't work for pause() so
870 * we send it a caught signal to wake it up.
871 */
872 kill(tcp->pid, SIGINT);
873#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000874#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000875 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000876 arg = PRSABORT;
877 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000878 perror("PIOCRUN");
879 return -1;
880 }
Roland McGrath553a6092002-12-16 20:40:39 +0000881#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000882#endif /* !MIPS*/
883#ifdef FREEBSD
884 /* wake up the child if it received the SIGSTOP */
885 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000886#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000887 for (;;) {
888 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000889 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000890 perror("PIOCWSTOP");
891 return -1;
892 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000893 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000894 tcp->flags &= ~TCB_INSYSCALL;
895 get_scno(tcp);
896 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000897 break;
898 }
899 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000900#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000901 arg = 0;
902 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000903#else /* FREEBSD */
904 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +0000905#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000906 perror("PIOCRUN");
907 return -1;
908 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000909#ifdef FREEBSD
910 /* handle the case where we "opened" the child before
911 it did the kill -STOP */
912 if (tcp->status.PR_WHY == PR_SIGNALLED &&
913 tcp->status.PR_WHAT == SIGSTOP)
914 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000915#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000916 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000917#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000918 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000919#else /* FREEBSD */
920 } else {
Roland McGrath553a6092002-12-16 20:40:39 +0000921 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000922 /* We are attaching to an already running process.
923 * Try to figure out the state of the process in syscalls,
924 * to handle the first event well.
925 * This is done by having a look at the "wchan" property of the
926 * process, which tells where it is stopped (if it is). */
927 FILE * status;
928 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +0000929
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000930 sprintf(proc, "/proc/%d/status", tcp->pid);
931 status = fopen(proc, "r");
932 if (status &&
933 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
934 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
935 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
936 strcmp(wchan, "stopevent")) {
937 /* The process is asleep in the middle of a syscall.
938 Fake the syscall entry event */
939 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
940 tcp->status.PR_WHY = PR_SYSENTRY;
941 trace_syscall(tcp);
942 }
943 if (status)
944 fclose(status);
945 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000946 }
947#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000948#ifndef HAVE_POLLABLE_PROCFS
949 if (proc_poll_pipe[0] != -1)
950 proc_poller(tcp->pfd);
951 else if (nprocs > 1) {
952 proc_poll_open();
953 proc_poller(last_pfd);
954 proc_poller(tcp->pfd);
955 }
956 last_pfd = tcp->pfd;
957#endif /* !HAVE_POLLABLE_PROCFS */
958 return 0;
959}
960
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000961#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000963struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000964pid2tcb(pid)
965int pid;
966{
967 int i;
968 struct tcb *tcp;
969
Roland McGrathee9d4352002-12-18 04:16:10 +0000970 for (i = 0; i < tcbtabsize; i++) {
971 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000972 if (pid && tcp->pid != pid)
973 continue;
974 if (tcp->flags & TCB_INUSE)
975 return tcp;
976 }
977 return NULL;
978}
979
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000980#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000981
982static struct tcb *
983pfd2tcb(pfd)
984int pfd;
985{
986 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987
Roland McGrathca16be82003-01-10 19:55:28 +0000988 for (i = 0; i < tcbtabsize; i++) {
989 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000990 if (tcp->pfd != pfd)
991 continue;
992 if (tcp->flags & TCB_INUSE)
993 return tcp;
994 }
995 return NULL;
996}
997
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000998#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000999
1000void
1001droptcb(tcp)
1002struct tcb *tcp;
1003{
1004 if (tcp->pid == 0)
1005 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001006#ifdef TCB_CLONE_THREAD
1007 if (tcp->nclone_threads > 0) {
1008 /* There are other threads left in this process, but this
1009 is the one whose PID represents the whole process.
1010 We need to keep this record around as a zombie until
1011 all the threads die. */
1012 tcp->flags |= TCB_EXITING;
1013 return;
1014 }
1015#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001016 nprocs--;
1017 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001018
Roland McGrathe29341c2003-01-10 20:14:20 +00001019 if (tcp->parent != NULL) {
1020 tcp->parent->nchildren--;
1021#ifdef TCB_CLONE_THREAD
1022 if (tcp->flags & TCB_CLONE_DETACHED)
1023 tcp->parent->nclone_detached--;
1024 if (tcp->flags & TCB_CLONE_THREAD)
1025 tcp->parent->nclone_threads--;
1026#endif
Roland McGrath09623452003-05-23 02:27:13 +00001027#ifdef TCB_CLONE_DETACHED
1028 if (!(tcp->flags & TCB_CLONE_DETACHED))
1029#endif
1030 tcp->parent->nzombies++;
Roland McGrathe29341c2003-01-10 20:14:20 +00001031 tcp->parent = NULL;
1032 }
1033
1034 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001035 if (tcp->pfd != -1) {
1036 close(tcp->pfd);
1037 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001038#ifdef FREEBSD
1039 if (tcp->pfd_reg != -1) {
1040 close(tcp->pfd_reg);
1041 tcp->pfd_reg = -1;
1042 }
1043 if (tcp->pfd_status != -1) {
1044 close(tcp->pfd_status);
1045 tcp->pfd_status = -1;
1046 }
Roland McGrath553a6092002-12-16 20:40:39 +00001047#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001048#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001049 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001050#endif
1051 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001052
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001053 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001054 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001055
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001056 tcp->outf = 0;
1057}
1058
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001059#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001060
1061static int
1062resume(tcp)
1063struct tcb *tcp;
1064{
1065 if (tcp == NULL)
1066 return -1;
1067
1068 if (!(tcp->flags & TCB_SUSPENDED)) {
1069 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1070 return -1;
1071 }
1072 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001073#ifdef TCB_CLONE_THREAD
1074 if (tcp->flags & TCB_CLONE_THREAD)
1075 tcp->parent->nclone_waiting--;
1076#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001077
1078 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1079 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1080 return -1;
1081 }
1082
1083 if (!qflag)
1084 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1085 return 0;
1086}
1087
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001088#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089
1090/* detach traced process; continue with sig */
1091
1092static int
1093detach(tcp, sig)
1094struct tcb *tcp;
1095int sig;
1096{
1097 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001098#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001099 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001100#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101
1102 if (tcp->flags & TCB_BPTSET)
1103 sig = SIGKILL;
1104
1105#ifdef LINUX
1106 /*
1107 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001108 * before detaching. Arghh. We go through hoops
1109 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001110 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001111#if defined(SPARC)
1112#undef PTRACE_DETACH
1113#define PTRACE_DETACH PTRACE_SUNDETACH
1114#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001115 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1116 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001117 }
1118 else if (errno != ESRCH) {
1119 /* Shouldn't happen. */
1120 perror("detach: ptrace(PTRACE_DETACH, ...)");
1121 }
1122 else if (kill(tcp->pid, 0) < 0) {
1123 if (errno != ESRCH)
1124 perror("detach: checking sanity");
1125 }
1126 else if (kill(tcp->pid, SIGSTOP) < 0) {
1127 if (errno != ESRCH)
1128 perror("detach: stopping child");
1129 }
1130 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001132#ifdef __WALL
1133 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1134 if (errno == ECHILD) /* Already gone. */
1135 break;
1136 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001137 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001138 break;
1139 }
1140#endif /* __WALL */
1141 /* No __WALL here. */
1142 if (waitpid(tcp->pid, &status, 0) < 0) {
1143 if (errno != ECHILD) {
1144 perror("detach: waiting");
1145 break;
1146 }
1147#ifdef __WCLONE
1148 /* If no processes, try clones. */
1149 if (wait4(tcp->pid, &status, __WCLONE,
1150 NULL) < 0) {
1151 if (errno != ECHILD)
1152 perror("detach: waiting");
1153 break;
1154 }
1155#endif /* __WCLONE */
1156 }
1157#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001158 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001159#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001160 if (!WIFSTOPPED(status)) {
1161 /* Au revoir, mon ami. */
1162 break;
1163 }
1164 if (WSTOPSIG(status) == SIGSTOP) {
1165 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001166 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001167 if (errno != ESRCH)
1168 perror("detach: ptrace(PTRACE_DETACH, ...)");
1169 /* I died trying. */
1170 }
1171 break;
1172 }
1173 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001174 WSTOPSIG(status) == SIGTRAP ?
1175 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176 if (errno != ESRCH)
1177 perror("detach: ptrace(PTRACE_CONT, ...)");
1178 break;
1179 }
1180 }
1181 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001182#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001183
1184#if defined(SUNOS4)
1185 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1186 if (sig && kill(tcp->pid, sig) < 0)
1187 perror("detach: kill");
1188 sig = 0;
1189 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1190 perror("detach: ptrace(PTRACE_DETACH, ...)");
1191#endif /* SUNOS4 */
1192
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001193#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001194 resumed = 0;
1195
1196 /* XXX This won't always be quite right (but it never was).
1197 A waiter with argument 0 or < -1 is waiting for any pid in
1198 a particular pgrp, which this child might or might not be
1199 in. The waiter will only wake up if it's argument is -1
1200 or if it's waiting for tcp->pid's pgrp. It makes a
1201 difference to wake up a waiter when there might be more
1202 traced children, because it could get a false ECHILD
1203 error. OTOH, if this was the last child in the pgrp, then
1204 it ought to wake up and get ECHILD. We would have to
1205 search the system for all pid's in the pgrp to be sure.
1206
1207 && (t->waitpid == -1 ||
1208 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1209 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1210 */
1211
1212 if (tcp->parent &&
1213 (tcp->parent->flags & TCB_SUSPENDED) &&
1214 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1215 error = resume(tcp->parent);
1216 ++resumed;
1217 }
1218#ifdef TCB_CLONE_THREAD
1219 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1220 /* Some other threads of our parent are waiting too. */
1221 unsigned int i;
1222
1223 /* Resume all the threads that were waiting for this PID. */
1224 for (i = 0; i < tcbtabsize; i++) {
1225 struct tcb *t = tcbtab[i];
1226 if (t->parent == tcp->parent && t != tcp
1227 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1228 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1229 && t->waitpid == tcp->pid) {
1230 error |= resume (t);
1231 ++resumed;
1232 }
1233 }
1234 if (resumed == 0)
1235 /* Noone was waiting for this PID in particular,
1236 so now we might need to resume some wildcarders. */
1237 for (i = 0; i < tcbtabsize; i++) {
1238 struct tcb *t = tcbtab[i];
1239 if (t->parent == tcp->parent && t != tcp
1240 && ((t->flags
1241 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1242 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1243 && t->waitpid <= 0
1244 ) {
1245 error |= resume (t);
1246 break;
1247 }
1248 }
1249 }
1250#endif
1251
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001252#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001253
1254 if (!qflag)
1255 fprintf(stderr, "Process %u detached\n", tcp->pid);
1256
1257 droptcb(tcp);
1258 return error;
1259}
1260
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001261#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001262
1263static void
1264reaper(sig)
1265int sig;
1266{
1267 int pid;
1268 int status;
1269
1270 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1271#if 0
1272 struct tcb *tcp;
1273
1274 tcp = pid2tcb(pid);
1275 if (tcp)
1276 droptcb(tcp);
1277#endif
1278 }
1279}
1280
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001281#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001282
1283static void
1284cleanup()
1285{
1286 int i;
1287 struct tcb *tcp;
1288
Roland McGrathee9d4352002-12-18 04:16:10 +00001289 for (i = 0; i < tcbtabsize; i++) {
1290 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001291 if (!(tcp->flags & TCB_INUSE))
1292 continue;
1293 if (debug)
1294 fprintf(stderr,
1295 "cleanup: looking at pid %u\n", tcp->pid);
1296 if (tcp_last &&
1297 (!outfname || followfork < 2 || tcp_last == tcp)) {
1298 tprintf(" <unfinished ...>\n");
1299 tcp_last = NULL;
1300 }
1301 if (tcp->flags & TCB_ATTACHED)
1302 detach(tcp, 0);
1303 else {
1304 kill(tcp->pid, SIGCONT);
1305 kill(tcp->pid, SIGTERM);
1306 }
1307 }
1308 if (cflag)
1309 call_summary(outf);
1310}
1311
1312static void
1313interrupt(sig)
1314int sig;
1315{
1316 interrupted = 1;
1317}
1318
1319#ifndef HAVE_STRERROR
1320
Roland McGrath6d2b3492002-12-30 00:51:30 +00001321#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001322extern int sys_nerr;
1323extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001324#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001325
1326const char *
1327strerror(errno)
1328int errno;
1329{
1330 static char buf[64];
1331
1332 if (errno < 1 || errno >= sys_nerr) {
1333 sprintf(buf, "Unknown error %d", errno);
1334 return buf;
1335 }
1336 return sys_errlist[errno];
1337}
1338
1339#endif /* HAVE_STERRROR */
1340
1341#ifndef HAVE_STRSIGNAL
1342
Roland McGrath8f474e02003-01-14 07:53:33 +00001343#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001344extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001345#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001346#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1347extern char *_sys_siglist[];
1348#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001349
1350const char *
1351strsignal(sig)
1352int sig;
1353{
1354 static char buf[64];
1355
1356 if (sig < 1 || sig >= NSIG) {
1357 sprintf(buf, "Unknown signal %d", sig);
1358 return buf;
1359 }
1360#ifdef HAVE__SYS_SIGLIST
1361 return _sys_siglist[sig];
1362#else
1363 return sys_siglist[sig];
1364#endif
1365}
1366
1367#endif /* HAVE_STRSIGNAL */
1368
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001369#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001370
1371static void
1372rebuild_pollv()
1373{
1374 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001375
Roland McGrathee9d4352002-12-18 04:16:10 +00001376 if (pollv != NULL)
1377 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001378 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001379 if (pollv == NULL) {
1380 fprintf(stderr, "strace: out of memory for poll vector\n");
1381 exit(1);
1382 }
1383
Roland McGrathca16be82003-01-10 19:55:28 +00001384 for (i = j = 0; i < tcbtabsize; i++) {
1385 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001386 if (!(tcp->flags & TCB_INUSE))
1387 continue;
1388 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001389 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001390 j++;
1391 }
1392 if (j != nprocs) {
1393 fprintf(stderr, "strace: proc miscount\n");
1394 exit(1);
1395 }
1396}
1397
1398#ifndef HAVE_POLLABLE_PROCFS
1399
1400static void
1401proc_poll_open()
1402{
1403 int arg;
1404 int i;
1405
1406 if (pipe(proc_poll_pipe) < 0) {
1407 perror("pipe");
1408 exit(1);
1409 }
1410 for (i = 0; i < 2; i++) {
1411 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1412 perror("F_GETFD");
1413 exit(1);
1414 }
1415 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1416 perror("F_SETFD");
1417 exit(1);
1418 }
1419 }
1420}
1421
1422static int
1423proc_poll(pollv, nfds, timeout)
1424struct pollfd *pollv;
1425int nfds;
1426int timeout;
1427{
1428 int i;
1429 int n;
1430 struct proc_pollfd pollinfo;
1431
1432 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1433 return n;
1434 if (n != sizeof(struct proc_pollfd)) {
1435 fprintf(stderr, "panic: short read: %d\n", n);
1436 exit(1);
1437 }
1438 for (i = 0; i < nprocs; i++) {
1439 if (pollv[i].fd == pollinfo.fd)
1440 pollv[i].revents = pollinfo.revents;
1441 else
1442 pollv[i].revents = 0;
1443 }
1444 poller_pid = pollinfo.pid;
1445 return 1;
1446}
1447
1448static void
1449wakeup_handler(sig)
1450int sig;
1451{
1452}
1453
1454static void
1455proc_poller(pfd)
1456int pfd;
1457{
1458 struct proc_pollfd pollinfo;
1459 struct sigaction sa;
1460 sigset_t blocked_set, empty_set;
1461 int i;
1462 int n;
1463 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001464#ifdef FREEBSD
1465 struct procfs_status pfs;
1466#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001467
1468 switch (fork()) {
1469 case -1:
1470 perror("fork");
1471 _exit(0);
1472 case 0:
1473 break;
1474 default:
1475 return;
1476 }
1477
1478 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1479 sa.sa_flags = 0;
1480 sigemptyset(&sa.sa_mask);
1481 sigaction(SIGHUP, &sa, NULL);
1482 sigaction(SIGINT, &sa, NULL);
1483 sigaction(SIGQUIT, &sa, NULL);
1484 sigaction(SIGPIPE, &sa, NULL);
1485 sigaction(SIGTERM, &sa, NULL);
1486 sa.sa_handler = wakeup_handler;
1487 sigaction(SIGUSR1, &sa, NULL);
1488 sigemptyset(&blocked_set);
1489 sigaddset(&blocked_set, SIGUSR1);
1490 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1491 sigemptyset(&empty_set);
1492
1493 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1494 perror("getrlimit(RLIMIT_NOFILE, ...)");
1495 _exit(0);
1496 }
1497 n = rl.rlim_cur;
1498 for (i = 0; i < n; i++) {
1499 if (i != pfd && i != proc_poll_pipe[1])
1500 close(i);
1501 }
1502
1503 pollinfo.fd = pfd;
1504 pollinfo.pid = getpid();
1505 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001506#ifndef FREEBSD
1507 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1508#else /* FREEBSD */
1509 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1510#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001511 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001512 switch (errno) {
1513 case EINTR:
1514 continue;
1515 case EBADF:
1516 pollinfo.revents = POLLERR;
1517 break;
1518 case ENOENT:
1519 pollinfo.revents = POLLHUP;
1520 break;
1521 default:
1522 perror("proc_poller: PIOCWSTOP");
1523 }
1524 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1525 _exit(0);
1526 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001527 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001528 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1529 sigsuspend(&empty_set);
1530 }
1531}
1532
1533#endif /* !HAVE_POLLABLE_PROCFS */
1534
1535static int
1536choose_pfd()
1537{
1538 int i, j;
1539 struct tcb *tcp;
1540
1541 static int last;
1542
1543 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001544 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001545 /*
1546 * The previous process is ready to run again. We'll
1547 * let it do so if it is currently in a syscall. This
1548 * heuristic improves the readability of the trace.
1549 */
1550 tcp = pfd2tcb(pollv[last].fd);
1551 if (tcp && (tcp->flags & TCB_INSYSCALL))
1552 return pollv[last].fd;
1553 }
1554
1555 for (i = 0; i < nprocs; i++) {
1556 /* Let competing children run round robin. */
1557 j = (i + last + 1) % nprocs;
1558 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1559 tcp = pfd2tcb(pollv[j].fd);
1560 if (!tcp) {
1561 fprintf(stderr, "strace: lost proc\n");
1562 exit(1);
1563 }
1564 droptcb(tcp);
1565 return -1;
1566 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001567 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001568 last = j;
1569 return pollv[j].fd;
1570 }
1571 }
1572 fprintf(stderr, "strace: nothing ready\n");
1573 exit(1);
1574}
1575
1576static int
1577trace()
1578{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001579#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001580 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001581#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001582 struct tcb *tcp;
1583 int pfd;
1584 int what;
1585 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001586 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001587
1588 for (;;) {
1589 if (interactive)
1590 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1591
1592 if (nprocs == 0)
1593 break;
1594
1595 switch (nprocs) {
1596 case 1:
1597#ifndef HAVE_POLLABLE_PROCFS
1598 if (proc_poll_pipe[0] == -1) {
1599#endif
1600 tcp = pid2tcb(0);
1601 if (!tcp)
1602 continue;
1603 pfd = tcp->pfd;
1604 if (pfd == -1)
1605 continue;
1606 break;
1607#ifndef HAVE_POLLABLE_PROCFS
1608 }
1609 /* fall through ... */
1610#endif /* !HAVE_POLLABLE_PROCFS */
1611 default:
1612#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001613#ifdef POLL_HACK
1614 /* On some systems (e.g. UnixWare) we get too much ugly
1615 "unfinished..." stuff when multiple proceses are in
1616 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001617
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001618 if (in_syscall) {
1619 struct pollfd pv;
1620 tcp = in_syscall;
1621 in_syscall = NULL;
1622 pv.fd = tcp->pfd;
1623 pv.events = POLLWANT;
1624 if ((what = poll (&pv, 1, 1)) < 0) {
1625 if (interrupted)
1626 return 0;
1627 continue;
1628 }
1629 else if (what == 1 && pv.revents & POLLWANT) {
1630 goto FOUND;
1631 }
1632 }
1633#endif
1634
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001635 if (poll(pollv, nprocs, INFTIM) < 0) {
1636 if (interrupted)
1637 return 0;
1638 continue;
1639 }
1640#else /* !HAVE_POLLABLE_PROCFS */
1641 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1642 if (interrupted)
1643 return 0;
1644 continue;
1645 }
1646#endif /* !HAVE_POLLABLE_PROCFS */
1647 pfd = choose_pfd();
1648 if (pfd == -1)
1649 continue;
1650 break;
1651 }
1652
1653 /* Look up `pfd' in our table. */
1654 if ((tcp = pfd2tcb(pfd)) == NULL) {
1655 fprintf(stderr, "unknown pfd: %u\n", pfd);
1656 exit(1);
1657 }
John Hughesb6643082002-05-23 11:02:22 +00001658#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001659 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001660#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001661 /* Get the status of the process. */
1662 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001663#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001664 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001665#else /* FREEBSD */
1666 /* Thanks to some scheduling mystery, the first poller
1667 sometimes waits for the already processed end of fork
1668 event. Doing a non blocking poll here solves the problem. */
1669 if (proc_poll_pipe[0] != -1)
1670 ioctl_result = IOCTL_STATUS (tcp);
1671 else
1672 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001673#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001674 ioctl_errno = errno;
1675#ifndef HAVE_POLLABLE_PROCFS
1676 if (proc_poll_pipe[0] != -1) {
1677 if (ioctl_result < 0)
1678 kill(poller_pid, SIGKILL);
1679 else
1680 kill(poller_pid, SIGUSR1);
1681 }
1682#endif /* !HAVE_POLLABLE_PROCFS */
1683 }
1684 if (interrupted)
1685 return 0;
1686
1687 if (interactive)
1688 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1689
1690 if (ioctl_result < 0) {
1691 /* Find out what happened if it failed. */
1692 switch (ioctl_errno) {
1693 case EINTR:
1694 case EBADF:
1695 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001696#ifdef FREEBSD
1697 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001698#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699 case ENOENT:
1700 droptcb(tcp);
1701 continue;
1702 default:
1703 perror("PIOCWSTOP");
1704 exit(1);
1705 }
1706 }
1707
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001708#ifdef FREEBSD
1709 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1710 /* discard first event for a syscall we never entered */
1711 IOCTL (tcp->pfd, PIOCRUN, 0);
1712 continue;
1713 }
Roland McGrath553a6092002-12-16 20:40:39 +00001714#endif
1715
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716 /* clear the just started flag */
1717 tcp->flags &= ~TCB_STARTUP;
1718
1719 /* set current output file */
1720 outf = tcp->outf;
1721
1722 if (cflag) {
1723 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001724#ifdef FREEBSD
1725 char buf[1024];
1726 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001727
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001728 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1729 buf[len] = '\0';
1730 sscanf(buf,
1731 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1732 &stime.tv_sec, &stime.tv_usec);
1733 } else
1734 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001735#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001736 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1737 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001738#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001739 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1740 tcp->stime = stime;
1741 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001742 what = tcp->status.PR_WHAT;
1743 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001744#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001745 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001746 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1747 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001748 if (trace_syscall(tcp) < 0) {
1749 fprintf(stderr, "syscall trouble\n");
1750 exit(1);
1751 }
1752 }
1753 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001754#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001755 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001756#ifdef POLL_HACK
1757 in_syscall = tcp;
1758#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001759 case PR_SYSEXIT:
1760 if (trace_syscall(tcp) < 0) {
1761 fprintf(stderr, "syscall trouble\n");
1762 exit(1);
1763 }
1764 break;
1765 case PR_SIGNALLED:
1766 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1767 printleader(tcp);
1768 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001769 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001770 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001771#ifdef PR_INFO
1772 if (tcp->status.PR_INFO.si_signo == what) {
1773 printleader(tcp);
1774 tprintf(" siginfo=");
1775 printsiginfo(&tcp->status.PR_INFO, 1);
1776 printtrailer(tcp);
1777 }
1778#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001779 }
1780 break;
1781 case PR_FAULTED:
1782 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1783 printleader(tcp);
1784 tprintf("=== FAULT %d ===", what);
1785 printtrailer(tcp);
1786 }
1787 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001788#ifdef FREEBSD
1789 case 0: /* handle case we polled for nothing */
1790 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001791#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001792 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001793 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001794 exit(1);
1795 break;
1796 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001797 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001798#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001799 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001800#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001801 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001802#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001803 perror("PIOCRUN");
1804 exit(1);
1805 }
1806 }
1807 return 0;
1808}
1809
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001810#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001811
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001812#ifdef TCB_GROUP_EXITING
1813/* Handle an exit detach or death signal that is taking all the
1814 related clone threads with it. This is called in three circumstances:
1815 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1816 SIG == 0 Continuing TCP will perform an exit_group syscall.
1817 SIG == other Continuing TCP with SIG will kill the process.
1818*/
1819static int
1820handle_group_exit(struct tcb *tcp, int sig)
1821{
1822 /* We need to locate our records of all the clone threads
1823 related to TCP, either its children or siblings. */
1824 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1825 ? tcp->parent
1826 : tcp->nclone_detached > 0
1827 ? tcp : NULL);
1828
1829 if (sig < 0) {
1830 if (leader != NULL && leader != tcp)
1831 fprintf(stderr,
1832 "PANIC: handle_group_exit: %d leader %d\n",
1833 tcp->pid, leader ? leader->pid : -1);
1834 droptcb(tcp); /* Already died. */
1835 }
1836 else {
1837 if (tcp->flags & TCB_ATTACHED) {
1838 if (leader != NULL && leader != tcp) {
1839 /* We need to detach the leader so that the
1840 process death will be reported to its real
1841 parent. But we kill it first to prevent
1842 it doing anything before we kill the whole
1843 process in a moment. We can use
1844 PTRACE_KILL on a thread that's not already
1845 stopped. Then the value we pass in
1846 PTRACE_DETACH just sets the death
1847 signal reported to the real parent. */
1848 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1849 if (debug)
1850 fprintf(stderr,
1851 " [%d exit %d kills %d]\n",
1852 tcp->pid, sig, leader->pid);
1853 detach(leader, sig);
1854 }
1855 detach(tcp, sig);
1856 }
1857 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1858 perror("strace: ptrace(PTRACE_CONT, ...)");
1859 cleanup();
1860 return -1;
1861 }
1862 else {
1863 if (leader != NULL && leader != tcp)
1864 droptcb(tcp);
1865 /* The leader will report to us as parent now,
1866 and then we'll get to the SIG==-1 case. */
1867 return 0;
1868 }
1869 }
1870
1871 /* Note that TCP and LEADER are no longer valid,
1872 but we can still compare against them. */
1873 if (leader != NULL) {
1874 unsigned int i;
1875 for (i = 0; i < tcbtabsize; i++) {
1876 struct tcb *t = tcbtab[i];
1877 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1878 && t->parent == leader)
1879 droptcb(t);
1880 }
1881 }
1882
1883 return 0;
1884}
1885#endif
1886
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001887static int
1888trace()
1889{
1890 int pid;
1891 int wait_errno;
1892 int status;
1893 struct tcb *tcp;
1894#ifdef LINUX
1895 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001896#ifdef __WALL
1897 static int wait4_options = __WALL;
1898#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001899#endif /* LINUX */
1900
1901 while (nprocs != 0) {
1902 if (interactive)
1903 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1904#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001905#ifdef __WALL
1906 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00001907 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001908 /* this kernel does not support __WALL */
1909 wait4_options &= ~__WALL;
1910 errno = 0;
1911 pid = wait4(-1, &status, wait4_options,
1912 cflag ? &ru : NULL);
1913 }
Roland McGrath5bc05552002-12-17 04:50:47 +00001914 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001915 /* most likely a "cloned" process */
1916 pid = wait4(-1, &status, __WCLONE,
1917 cflag ? &ru : NULL);
1918 if (pid == -1) {
1919 fprintf(stderr, "strace: clone wait4 "
1920 "failed: %s\n", strerror(errno));
1921 }
1922 }
1923#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001924 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001925#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001926#endif /* LINUX */
1927#ifdef SUNOS4
1928 pid = wait(&status);
1929#endif /* SUNOS4 */
1930 wait_errno = errno;
1931 if (interactive)
1932 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1933
1934 if (interrupted)
1935 return 0;
1936
1937 if (pid == -1) {
1938 switch (wait_errno) {
1939 case EINTR:
1940 continue;
1941 case ECHILD:
1942 /*
1943 * We would like to verify this case
1944 * but sometimes a race in Solbourne's
1945 * version of SunOS sometimes reports
1946 * ECHILD before sending us SIGCHILD.
1947 */
1948#if 0
1949 if (nprocs == 0)
1950 return 0;
1951 fprintf(stderr, "strace: proc miscount\n");
1952 exit(1);
1953#endif
1954 return 0;
1955 default:
1956 errno = wait_errno;
1957 perror("strace: wait");
1958 return -1;
1959 }
1960 }
1961 if (debug)
1962 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1963
1964 /* Look up `pid' in our table. */
1965 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001966#ifdef LINUX
1967 if (followfork || followvfork) {
1968 /* This is needed to go with the CLONE_PTRACE
1969 changes in process.c/util.c: we might see
1970 the child's initial trap before we see the
1971 parent return from the clone syscall.
1972 Leave the child suspended until the parent
1973 returns from its system call. Only then
1974 will we have the association of parent and
1975 child so that we know how to do clearbpt
1976 in the child. */
1977 if ((tcp = alloctcb(pid)) == NULL) {
1978 fprintf(stderr, " [tcb table full]\n");
1979 kill(pid, SIGKILL); /* XXX */
1980 return 0;
1981 }
1982 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
1983 newoutf(tcp);
1984 if (!qflag)
1985 fprintf(stderr, "\
1986Process %d attached (waiting for parent)\n",
1987 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001988 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001989 else
1990 /* This can happen if a clone call used
1991 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001992#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001993 {
1994 fprintf(stderr, "unknown pid: %u\n", pid);
1995 if (WIFSTOPPED(status))
1996 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1997 exit(1);
1998 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001999 }
2000 /* set current output file */
2001 outf = tcp->outf;
2002 if (cflag) {
2003#ifdef LINUX
2004 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2005 tcp->stime = ru.ru_stime;
2006#endif /* !LINUX */
2007 }
2008
2009 if (tcp->flags & TCB_SUSPENDED) {
2010 /*
2011 * Apparently, doing any ptrace() call on a stopped
2012 * process, provokes the kernel to report the process
2013 * status again on a subsequent wait(), even if the
2014 * process has not been actually restarted.
2015 * Since we have inspected the arguments of suspended
2016 * processes we end up here testing for this case.
2017 */
2018 continue;
2019 }
2020 if (WIFSIGNALED(status)) {
2021 if (!cflag
2022 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2023 printleader(tcp);
2024 tprintf("+++ killed by %s +++",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002025 signame(WTERMSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002026 printtrailer(tcp);
2027 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002028#ifdef TCB_GROUP_EXITING
2029 handle_group_exit(tcp, -1);
2030#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002031 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002032#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002033 continue;
2034 }
2035 if (WIFEXITED(status)) {
2036 if (debug)
2037 fprintf(stderr, "pid %u exited\n", pid);
2038 if (tcp->flags & TCB_ATTACHED)
2039 fprintf(stderr,
2040 "PANIC: attached pid %u exited\n",
2041 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002042 if (tcp == tcp_last) {
2043 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2044 == TCB_INSYSCALL)
2045 tprintf(" <unfinished ... exit status %d>\n",
2046 WEXITSTATUS(status));
2047 tcp_last = NULL;
2048 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002049#ifdef TCB_GROUP_EXITING
2050 handle_group_exit(tcp, -1);
2051#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002052 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002053#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002054 continue;
2055 }
2056 if (!WIFSTOPPED(status)) {
2057 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2058 droptcb(tcp);
2059 continue;
2060 }
2061 if (debug)
2062 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002063 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002064
2065 if (tcp->flags & TCB_STARTUP) {
2066 /*
2067 * This flag is there to keep us in sync.
2068 * Next time this process stops it should
2069 * really be entering a system call.
2070 */
2071 tcp->flags &= ~TCB_STARTUP;
2072 if (tcp->flags & TCB_ATTACHED) {
2073 /*
2074 * Interestingly, the process may stop
2075 * with STOPSIG equal to some other signal
2076 * than SIGSTOP if we happend to attach
2077 * just before the process takes a signal.
2078 */
2079 if (!WIFSTOPPED(status)) {
2080 fprintf(stderr,
2081 "pid %u not stopped\n", pid);
2082 detach(tcp, WSTOPSIG(status));
2083 continue;
2084 }
2085 }
2086 else {
2087#ifdef SUNOS4
2088 /* A child of us stopped at exec */
2089 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2090 fixvfork(tcp);
2091#endif /* SUNOS4 */
2092 }
2093 if (tcp->flags & TCB_BPTSET) {
2094 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2095 droptcb(tcp);
2096 cleanup();
2097 return -1;
2098 }
2099 }
2100 goto tracing;
2101 }
2102
2103 if (WSTOPSIG(status) != SIGTRAP) {
2104 if (WSTOPSIG(status) == SIGSTOP &&
2105 (tcp->flags & TCB_SIGTRAPPED)) {
2106 /*
2107 * Trapped attempt to block SIGTRAP
2108 * Hope we are back in control now.
2109 */
2110 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2111 if (ptrace(PTRACE_SYSCALL,
2112 pid, (char *) 1, 0) < 0) {
2113 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2114 cleanup();
2115 return -1;
2116 }
2117 continue;
2118 }
2119 if (!cflag
2120 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002121 unsigned long addr = 0, pc = 0;
2122#ifdef PT_GETSIGINFO
2123# define PSR_RI 41
2124 struct siginfo si;
2125 unsigned long psr;
2126
2127 upeek(pid, PT_CR_IPSR, &psr);
2128 upeek(pid, PT_CR_IIP, &pc);
2129
2130 pc += (psr >> PSR_RI) & 0x3;
2131 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2132 addr = (unsigned long) si.si_addr;
2133#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002134 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002135 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002136 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002137 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002138 printtrailer(tcp);
2139 }
2140 if ((tcp->flags & TCB_ATTACHED) &&
2141 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002142#ifdef TCB_GROUP_EXITING
2143 handle_group_exit(tcp, WSTOPSIG(status));
2144#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002145 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002146#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002147 continue;
2148 }
2149 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2150 WSTOPSIG(status)) < 0) {
2151 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2152 cleanup();
2153 return -1;
2154 }
2155 tcp->flags &= ~TCB_SUSPENDED;
2156 continue;
2157 }
2158 if (trace_syscall(tcp) < 0) {
2159 if (tcp->flags & TCB_ATTACHED)
2160 detach(tcp, 0);
2161 else {
2162 ptrace(PTRACE_KILL,
2163 tcp->pid, (char *) 1, SIGTERM);
2164 droptcb(tcp);
2165 }
2166 continue;
2167 }
2168 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002169#ifdef TCB_GROUP_EXITING
2170 if (tcp->flags & TCB_GROUP_EXITING) {
2171 if (handle_group_exit(tcp, 0) < 0)
2172 return -1;
2173 continue;
2174 }
2175#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002176 if (tcp->flags & TCB_ATTACHED)
2177 detach(tcp, 0);
2178 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2179 perror("strace: ptrace(PTRACE_CONT, ...)");
2180 cleanup();
2181 return -1;
2182 }
2183 continue;
2184 }
2185 if (tcp->flags & TCB_SUSPENDED) {
2186 if (!qflag)
2187 fprintf(stderr, "Process %u suspended\n", pid);
2188 continue;
2189 }
2190 tracing:
2191 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2192 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2193 cleanup();
2194 return -1;
2195 }
2196 }
2197 return 0;
2198}
2199
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002200#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002201
2202static int curcol;
2203
2204#ifdef __STDC__
2205#include <stdarg.h>
2206#define VA_START(a, b) va_start(a, b)
2207#else
2208#include <varargs.h>
2209#define VA_START(a, b) va_start(a)
2210#endif
2211
2212void
2213#ifdef __STDC__
2214tprintf(const char *fmt, ...)
2215#else
2216tprintf(fmt, va_alist)
2217char *fmt;
2218va_dcl
2219#endif
2220{
2221 va_list args;
2222
2223 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002224 if (outf) {
2225 int n = vfprintf(outf, fmt, args);
2226 if (n < 0 && outf != stderr)
2227 perror(outfname == NULL
2228 ? "<writing to pipe>" : outfname);
2229 else
2230 curcol += n;
2231 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002232 va_end(args);
2233 return;
2234}
2235
2236void
2237printleader(tcp)
2238struct tcb *tcp;
2239{
2240 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2241 tcp_last->flags |= TCB_REPRINT;
2242 tprintf(" <unfinished ...>\n");
2243 }
2244 curcol = 0;
2245 if ((followfork == 1 || pflag_seen > 1) && outfname)
2246 tprintf("%-5d ", tcp->pid);
2247 else if (nprocs > 1 && !outfname)
2248 tprintf("[pid %5u] ", tcp->pid);
2249 if (tflag) {
2250 char str[sizeof("HH:MM:SS")];
2251 struct timeval tv, dtv;
2252 static struct timeval otv;
2253
2254 gettimeofday(&tv, NULL);
2255 if (rflag) {
2256 if (otv.tv_sec == 0)
2257 otv = tv;
2258 tv_sub(&dtv, &tv, &otv);
2259 tprintf("%6ld.%06ld ",
2260 (long) dtv.tv_sec, (long) dtv.tv_usec);
2261 otv = tv;
2262 }
2263 else if (tflag > 2) {
2264 tprintf("%ld.%06ld ",
2265 (long) tv.tv_sec, (long) tv.tv_usec);
2266 }
2267 else {
2268 time_t local = tv.tv_sec;
2269 strftime(str, sizeof(str), "%T", localtime(&local));
2270 if (tflag > 1)
2271 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2272 else
2273 tprintf("%s ", str);
2274 }
2275 }
2276 if (iflag)
2277 printcall(tcp);
2278}
2279
2280void
2281tabto(col)
2282int col;
2283{
2284 if (curcol < col)
2285 tprintf("%*s", col - curcol, "");
2286}
2287
2288void
2289printtrailer(tcp)
2290struct tcb *tcp;
2291{
2292 tprintf("\n");
2293 tcp_last = NULL;
2294}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002295
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002296#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002297
2298int mp_ioctl (int fd, int cmd, void *arg, int size) {
2299
2300 struct iovec iov[2];
2301 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002302
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002303 iov[0].iov_base = &cmd;
2304 iov[0].iov_len = sizeof cmd;
2305 if (arg) {
2306 ++n;
2307 iov[1].iov_base = arg;
2308 iov[1].iov_len = size;
2309 }
Roland McGrath553a6092002-12-16 20:40:39 +00002310
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002311 return writev (fd, iov, n);
2312}
2313
2314#endif