blob: 1d5f2ccf27c0a9b187e17d1b051ee6c75e19ee25 [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;
Roland McGrathfd3e0422002-12-30 09:33:22 +000084extern const char version[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000085extern char **environ;
86
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000087static int trace P((void));
88static void cleanup P((void));
89static void interrupt P((int sig));
90static sigset_t empty_set, blocked_set;
91
92#ifdef HAVE_SIG_ATOMIC_T
93static volatile sig_atomic_t interrupted;
94#else /* !HAVE_SIG_ATOMIC_T */
95#ifdef __STDC__
96static volatile int interrupted;
97#else /* !__STDC__ */
98static int interrupted;
99#endif /* !__STDC__ */
100#endif /* !HAVE_SIG_ATOMIC_T */
101
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000102#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000103
104static struct tcb *pfd2tcb P((int pfd));
105static void reaper P((int sig));
106static void rebuild_pollv P((void));
Roland McGrathee9d4352002-12-18 04:16:10 +0000107static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000108
109#ifndef HAVE_POLLABLE_PROCFS
110
111static void proc_poll_open P((void));
112static void proc_poller P((int pfd));
113
114struct proc_pollfd {
115 int fd;
116 int revents;
117 int pid;
118};
119
120static int poller_pid;
121static int proc_poll_pipe[2] = { -1, -1 };
122
123#endif /* !HAVE_POLLABLE_PROCFS */
124
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000125#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000126#define POLLWANT POLLWRNORM
127#else
128#define POLLWANT POLLPRI
129#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000130#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000131
132static void
133usage(ofp, exitval)
134FILE *ofp;
135int exitval;
136{
137 fprintf(ofp, "\
138usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
139 [-p pid] ... [-s strsize] [-u username] [command [arg ...]]\n\
140 or: strace -c [-e expr] ... [-O overhead] [-S sortby] [command [arg ...]]\n\
141-c -- count time, calls, and errors for each syscall and report summary\n\
142-f -- follow forks, -ff -- with output into separate files\n\
143-F -- attempt to follow vforks, -h -- print help message\n\
144-i -- print instruction pointer at time of syscall\n\
145-q -- suppress messages about attaching, detaching, etc.\n\
146-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
147-T -- print time spent in each syscall, -V -- print version\n\
148-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
149-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
150-a column -- alignment COLUMN for printing syscall results (default %d)\n\
151-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
152 options: trace, abbrev, verbose, raw, signal, read, or write\n\
153-o file -- send trace output to FILE instead of stderr\n\
154-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
155-p pid -- trace process with process id PID, may be repeated\n\
156-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
157-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
158-u username -- run command as username handling setuid and/or setgid\n\
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000159-z -- print only succeeding syscalls\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000160", DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
161 exit(exitval);
162}
163
164#ifdef SVR4
165#ifdef MIPS
166void
167foobar()
168{
169}
170#endif /* MIPS */
171#endif /* SVR4 */
172
173int
174main(argc, argv)
175int argc;
176char *argv[];
177{
178 extern int optind;
179 extern char *optarg;
180 struct tcb *tcp;
181 int c, pid = 0;
182 struct sigaction sa;
183
184 static char buf[BUFSIZ];
185
Roland McGrathee9d4352002-12-18 04:16:10 +0000186 /* Allocate the initial tcbtab. */
187 tcbtabsize = argc; /* Surely enough for all -p args. */
188 tcbtab = (struct tcb **) malloc (tcbtabsize * sizeof tcbtab[0]);
189 tcbtab[0] = (struct tcb *) calloc (tcbtabsize, sizeof *tcbtab[0]);
190 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
191 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
192
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000193 progname = argv[0];
194 outf = stderr;
195 interactive = 1;
196 qualify("trace=all");
197 qualify("abbrev=all");
198 qualify("verbose=all");
199 qualify("signal=all");
200 set_sortby(DEFAULT_SORTBY);
201 set_personality(DEFAULT_PERSONALITY);
202 while ((c = getopt(argc, argv,
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000203 "+cdfFhiqrtTvVxza:e:o:O:p:s:S:u:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000204 switch (c) {
205 case 'c':
206 cflag++;
207 dtime++;
208 break;
209 case 'd':
210 debug++;
211 break;
212 case 'f':
213 followfork++;
214 break;
215 case 'F':
216 followvfork++;
217 break;
218 case 'h':
219 usage(stdout, 0);
220 break;
221 case 'i':
222 iflag++;
223 break;
224 case 'q':
225 qflag++;
226 break;
227 case 'r':
228 rflag++;
229 tflag++;
230 break;
231 case 't':
232 tflag++;
233 break;
234 case 'T':
235 dtime++;
236 break;
237 case 'x':
238 xflag++;
239 break;
240 case 'v':
241 qualify("abbrev=none");
242 break;
243 case 'V':
244 printf("%s\n", version);
245 exit(0);
246 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000247 case 'z':
248 not_failing_only = 1;
249 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000250 case 'a':
251 acolumn = atoi(optarg);
252 break;
253 case 'e':
254 qualify(optarg);
255 break;
256 case 'o':
257 outfname = strdup(optarg);
258 break;
259 case 'O':
260 set_overhead(atoi(optarg));
261 break;
262 case 'p':
263 if ((pid = atoi(optarg)) == 0) {
264 fprintf(stderr, "%s: Invalid process id: %s\n",
265 progname, optarg);
266 break;
267 }
268 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000269 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000270 break;
271 }
272 if ((tcp = alloctcb(pid)) == NULL) {
273 fprintf(stderr, "%s: tcb table full, please recompile strace\n",
274 progname);
275 exit(1);
276 }
277 tcp->flags |= TCB_ATTACHED;
278 pflag_seen++;
279 break;
280 case 's':
281 max_strlen = atoi(optarg);
282 break;
283 case 'S':
284 set_sortby(optarg);
285 break;
286 case 'u':
287 username = strdup(optarg);
288 break;
289 default:
290 usage(stderr, 1);
291 break;
292 }
293 }
294
295 /* See if they want to run as another user. */
296 if (username != NULL) {
297 struct passwd *pent;
298
299 if (getuid() != 0 || geteuid() != 0) {
300 fprintf(stderr,
301 "%s: you must be root to use the -u option\n",
302 progname);
303 exit(1);
304 }
305 if ((pent = getpwnam(username)) == NULL) {
306 fprintf(stderr, "%s: cannot find user `%s'\n",
307 progname, optarg);
308 exit(1);
309 }
310 run_uid = pent->pw_uid;
311 run_gid = pent->pw_gid;
312 }
313 else {
314 run_uid = getuid();
315 run_gid = getgid();
316 }
317
318#ifndef SVR4
319 setreuid(geteuid(), getuid());
320#endif
321
322 /* See if they want to pipe the output. */
323 if (outfname && (outfname[0] == '|' || outfname[0] == '!')) {
324 if ((outf = popen(outfname + 1, "w")) == NULL) {
325 fprintf(stderr, "%s: can't popen '%s': %s\n",
326 progname, outfname + 1, strerror(errno));
327 exit(1);
328 }
329 free(outfname);
330 outfname = NULL;
331 }
332
333 /* Check if they want to redirect the output. */
334 if (outfname) {
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000335 long f;
336
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000337 if ((outf = fopen(outfname, "w")) == NULL) {
338 fprintf(stderr, "%s: can't fopen '%s': %s\n",
339 progname, outfname, strerror(errno));
340 exit(1);
341 }
Wichert Akkerman54b4f792001-08-03 11:43:35 +0000342
343 if ((f=fcntl(fileno(outf), F_GETFD)) < 0 ) {
344 perror("failed to get flags for outputfile");
345 exit(1);
346 }
347
348 if (fcntl(fileno(outf), F_SETFD, f|FD_CLOEXEC) < 0 ) {
349 perror("failed to set flags for outputfile");
350 exit(1);
351 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000352 }
353
354#ifndef SVR4
355 setreuid(geteuid(), getuid());
356#endif
357
358 if (!outfname) {
359 qflag = 1;
360 setvbuf(outf, buf, _IOLBF, BUFSIZ);
361 }
362 else if (optind < argc)
363 interactive = 0;
364 else
365 qflag = 1;
366
Roland McGrathee9d4352002-12-18 04:16:10 +0000367 for (c = 0; c < tcbtabsize; c++) {
368 tcp = tcbtab[c];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000369 /* Reinitialize the output since it may have changed. */
370 tcp->outf = outf;
371 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
372 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000373#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000374 if (proc_open(tcp, 1) < 0) {
375 fprintf(stderr, "trouble opening proc file\n");
376 droptcb(tcp);
377 continue;
378 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000379#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
381 perror("attach: ptrace(PTRACE_ATTACH, ...)");
382 droptcb(tcp);
383 continue;
384 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000385#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000386 if (!qflag)
387 fprintf(stderr,
388 "Process %u attached - interrupt to quit\n",
389 pid);
390 }
391
392 if (optind < argc) {
393 struct stat statbuf;
394 char *filename;
395 char pathname[MAXPATHLEN];
396
397 filename = argv[optind];
398 if (strchr(filename, '/'))
399 strcpy(pathname, filename);
400#ifdef USE_DEBUGGING_EXEC
401 /*
402 * Debuggers customarily check the current directory
403 * first regardless of the path but doing that gives
404 * security geeks a panic attack.
405 */
406 else if (stat(filename, &statbuf) == 0)
407 strcpy(pathname, filename);
408#endif /* USE_DEBUGGING_EXEC */
409 else {
410 char *path;
411 int m, n, len;
412
413 for (path = getenv("PATH"); path && *path; path += m) {
414 if (strchr(path, ':')) {
415 n = strchr(path, ':') - path;
416 m = n + 1;
417 }
418 else
419 m = n = strlen(path);
420 if (n == 0) {
421 getcwd(pathname, MAXPATHLEN);
422 len = strlen(pathname);
423 }
424 else {
425 strncpy(pathname, path, n);
426 len = n;
427 }
428 if (len && pathname[len - 1] != '/')
429 pathname[len++] = '/';
430 strcpy(pathname + len, filename);
431 if (stat(pathname, &statbuf) == 0)
432 break;
433 }
434 }
435 if (stat(pathname, &statbuf) < 0) {
436 fprintf(stderr, "%s: %s: command not found\n",
437 progname, filename);
438 exit(1);
439 }
440 switch (pid = fork()) {
441 case -1:
442 perror("strace: fork");
443 cleanup();
444 exit(1);
445 break;
446 case 0: {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000447#ifdef USE_PROCFS
448 if (outf != stderr) close (fileno (outf));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000449#ifdef MIPS
450 /* Kludge for SGI, see proc_open for details. */
451 sa.sa_handler = foobar;
452 sa.sa_flags = 0;
453 sigemptyset(&sa.sa_mask);
454 sigaction(SIGINT, &sa, NULL);
455#endif /* MIPS */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000456#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000457 pause();
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000458#else /* FREEBSD */
459 kill(getpid(), SIGSTOP); /* stop HERE */
Roland McGrath553a6092002-12-16 20:40:39 +0000460#endif /* FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000461#else /* !USE_PROCFS */
Roland McGrath553a6092002-12-16 20:40:39 +0000462 if (outf!=stderr)
Wichert Akkerman7987cdf2000-07-05 16:05:39 +0000463 close(fileno (outf));
Wichert Akkermanbd4125c2000-06-27 17:28:06 +0000464
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000465 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
466 perror("strace: ptrace(PTRACE_TRACEME, ...)");
467 return -1;
468 }
469 if (debug)
470 kill(getpid(), SIGSTOP);
471
472 if (username != NULL || geteuid() == 0) {
473 uid_t run_euid = run_uid;
474 gid_t run_egid = run_gid;
475
476 if (statbuf.st_mode & S_ISUID)
477 run_euid = statbuf.st_uid;
478 if (statbuf.st_mode & S_ISGID)
479 run_egid = statbuf.st_gid;
480
481 /*
482 * It is important to set groups before we
483 * lose privileges on setuid.
484 */
Wichert Akkerman5ae21ea2000-05-01 01:53:59 +0000485 if (username != NULL) {
486 if (initgroups(username, run_gid) < 0) {
487 perror("initgroups");
488 exit(1);
489 }
490 if (setregid(run_gid, run_egid) < 0) {
491 perror("setregid");
492 exit(1);
493 }
494 if (setreuid(run_uid, run_euid) < 0) {
495 perror("setreuid");
496 exit(1);
497 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000498 }
499 }
500 else
501 setreuid(run_uid, run_uid);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000502#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000503
504 execv(pathname, &argv[optind]);
505 perror("strace: exec");
506 _exit(1);
507 break;
508 }
509 default:
510 if ((tcp = alloctcb(pid)) == NULL) {
511 fprintf(stderr, "tcb table full\n");
512 cleanup();
513 exit(1);
514 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000515#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000516 if (proc_open(tcp, 0) < 0) {
517 fprintf(stderr, "trouble opening proc file\n");
518 cleanup();
519 exit(1);
520 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000521#endif /* USE_PROCFS */
522#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000523 fake_execve(tcp, pathname, &argv[optind], environ);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000524#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000525 break;
526 }
527 }
528 else if (pflag_seen == 0)
529 usage(stderr, 1);
530
531 sigemptyset(&empty_set);
532 sigemptyset(&blocked_set);
533 sa.sa_handler = SIG_IGN;
534 sigemptyset(&sa.sa_mask);
535 sa.sa_flags = 0;
536 sigaction(SIGTTOU, &sa, NULL);
537 sigaction(SIGTTIN, &sa, NULL);
538 if (interactive) {
539 sigaddset(&blocked_set, SIGHUP);
540 sigaddset(&blocked_set, SIGINT);
541 sigaddset(&blocked_set, SIGQUIT);
542 sigaddset(&blocked_set, SIGPIPE);
543 sigaddset(&blocked_set, SIGTERM);
544 sa.sa_handler = interrupt;
545#ifdef SUNOS4
546 /* POSIX signals on sunos4.1 are a little broken. */
547 sa.sa_flags = SA_INTERRUPT;
548#endif /* SUNOS4 */
549 }
550 sigaction(SIGHUP, &sa, NULL);
551 sigaction(SIGINT, &sa, NULL);
552 sigaction(SIGQUIT, &sa, NULL);
553 sigaction(SIGPIPE, &sa, NULL);
554 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000555#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000556 sa.sa_handler = reaper;
557 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000558#else
559 /* Make sure SIGCHLD has the default action so that waitpid
560 definitely works without losing track of children. The user
561 should not have given us a bogus state to inherit, but he might
562 have. Arguably we should detect SIG_IGN here and pass it on
563 to children, but probably noone really needs that. */
564 sa.sa_handler = SIG_DFL;
565 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000566#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000567
568 if (trace() < 0)
569 exit(1);
570 cleanup();
571 exit(0);
572}
573
574void
575newoutf(tcp)
576struct tcb *tcp;
577{
578 char name[MAXPATHLEN];
579 FILE *fp;
580
581 if (outfname && followfork > 1) {
582 sprintf(name, "%s.%u", outfname, tcp->pid);
583#ifndef SVR4
584 setreuid(geteuid(), getuid());
585#endif
586 fp = fopen(name, "w");
587#ifndef SVR4
588 setreuid(geteuid(), getuid());
589#endif
590 if (fp == NULL) {
591 perror("fopen");
592 return;
593 }
594 tcp->outf = fp;
595 }
596 return;
597}
598
599struct tcb *
600alloctcb(pid)
601int pid;
602{
603 int i;
604 struct tcb *tcp;
605
Roland McGrathee9d4352002-12-18 04:16:10 +0000606 for (i = 0; i < tcbtabsize; i++) {
607 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000608 if ((tcp->flags & TCB_INUSE) == 0) {
609 tcp->pid = pid;
610 tcp->parent = NULL;
611 tcp->nchildren = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000612#ifdef TCB_CLONE_THREAD
613 tcp->nclone_threads = tcp->nclone_detached = 0;
614 tcp->nclone_waiting = 0;
615#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000616 tcp->flags = TCB_INUSE | TCB_STARTUP;
617 tcp->outf = outf; /* Initialise to current out file */
618 tcp->stime.tv_sec = 0;
619 tcp->stime.tv_usec = 0;
620 tcp->pfd = -1;
621 nprocs++;
622 return tcp;
623 }
624 }
625 return NULL;
626}
627
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000628#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000629int
630proc_open(tcp, attaching)
631struct tcb *tcp;
632int attaching;
633{
634 char proc[32];
635 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000636#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000637 int i;
638 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000639 sigset_t signals;
640 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000641#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000642#ifndef HAVE_POLLABLE_PROCFS
643 static int last_pfd;
644#endif
645
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000646#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000647 /* Open the process pseudo-files in /proc. */
648 sprintf(proc, "/proc/%d/ctl", tcp->pid);
649 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000650 perror("strace: open(\"/proc/...\", ...)");
651 return -1;
652 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000653 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
654 perror("F_GETFD");
655 return -1;
656 }
657 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
658 perror("F_SETFD");
659 return -1;
660 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000661 sprintf(proc, "/proc/%d/status", tcp->pid);
662 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
663 perror("strace: open(\"/proc/...\", ...)");
664 return -1;
665 }
666 if ((arg = fcntl(tcp->pfd_stat, F_GETFD)) < 0) {
667 perror("F_GETFD");
668 return -1;
669 }
670 if (fcntl(tcp->pfd_stat, F_SETFD, arg|FD_CLOEXEC) < 0) {
671 perror("F_SETFD");
672 return -1;
673 }
674 sprintf(proc, "/proc/%d/as", tcp->pid);
675 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
676 perror("strace: open(\"/proc/...\", ...)");
677 return -1;
678 }
679 if ((arg = fcntl(tcp->pfd_as, F_GETFD)) < 0) {
680 perror("F_GETFD");
681 return -1;
682 }
683 if (fcntl(tcp->pfd_as, F_SETFD, arg|FD_CLOEXEC) < 0) {
684 perror("F_SETFD");
685 return -1;
686 }
687#else
688 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000689#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000690 sprintf(proc, "/proc/%d", tcp->pid);
691 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000692#else /* FREEBSD */
693 sprintf(proc, "/proc/%d/mem", tcp->pid);
694 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
695#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000696 perror("strace: open(\"/proc/...\", ...)");
697 return -1;
698 }
699 if ((arg = fcntl(tcp->pfd, F_GETFD)) < 0) {
700 perror("F_GETFD");
701 return -1;
702 }
703 if (fcntl(tcp->pfd, F_SETFD, arg|FD_CLOEXEC) < 0) {
704 perror("F_SETFD");
705 return -1;
706 }
707#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000708#ifdef FREEBSD
709 sprintf(proc, "/proc/%d/regs", tcp->pid);
710 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
711 perror("strace: open(\"/proc/.../regs\", ...)");
712 return -1;
713 }
714 if (cflag) {
715 sprintf(proc, "/proc/%d/status", tcp->pid);
716 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
717 perror("strace: open(\"/proc/.../status\", ...)");
718 return -1;
719 }
720 } else
721 tcp->pfd_status = -1;
722#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000723 rebuild_pollv();
724 if (!attaching) {
725 /*
726 * Wait for the child to pause. Because of a race
727 * condition we have to poll for the event.
728 */
729 for (;;) {
730 if (IOCTL_STATUS (tcp) < 0) {
731 perror("strace: PIOCSTATUS");
732 return -1;
733 }
734 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000735 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000736 }
737 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000738#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000739 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +0000740 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000741 perror("strace: PIOCSTOP");
742 return -1;
743 }
Roland McGrath553a6092002-12-16 20:40:39 +0000744#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000745#ifdef PIOCSET
746 /* Set Run-on-Last-Close. */
747 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000748 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000749 perror("PIOCSET PR_RLC");
750 return -1;
751 }
752 /* Set or Reset Inherit-on-Fork. */
753 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000754 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000755 perror("PIOC{SET,RESET} PR_FORK");
756 return -1;
757 }
758#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +0000759#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000760 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
761 perror("PIOCSRLC");
762 return -1;
763 }
764 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
765 perror("PIOC{S,R}FORK");
766 return -1;
767 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000768#else /* FREEBSD */
769 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
770 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
771 perror("PIOCGFL");
772 return -1;
773 }
774 arg &= ~PF_LINGER;
775 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
776 perror("PIOCSFL");
777 return -1;
778 }
779#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000781#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +0000782 /* Enable all syscall entries we care about. */
783 premptyset(&syscalls);
784 for (i = 1; i < MAX_QUALS; ++i) {
785 if (i > (sizeof syscalls) * CHAR_BIT) break;
786 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
787 }
788 praddset (&syscalls, SYS_execve);
789 if (followfork) {
790 praddset (&syscalls, SYS_fork);
791#ifdef SYS_forkall
792 praddset (&syscalls, SYS_forkall);
793#endif
Roland McGrath553a6092002-12-16 20:40:39 +0000794#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +0000795 praddset (&syscalls, SYS_fork1);
796#endif
797#ifdef SYS_rfork1
798 praddset (&syscalls, SYS_rfork1);
799#endif
800#ifdef SYS_rforkall
801 praddset (&syscalls, SYS_rforkall);
802#endif
803 }
804 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000805 perror("PIOCSENTRY");
806 return -1;
807 }
John Hughes19e49982001-10-19 08:59:12 +0000808 /* Enable the syscall exits. */
809 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000810 perror("PIOSEXIT");
811 return -1;
812 }
John Hughes19e49982001-10-19 08:59:12 +0000813 /* Enable signals we care about. */
814 premptyset(&signals);
815 for (i = 1; i < MAX_QUALS; ++i) {
816 if (i > (sizeof signals) * CHAR_BIT) break;
817 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
818 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000819 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000820 perror("PIOCSTRACE");
821 return -1;
822 }
John Hughes19e49982001-10-19 08:59:12 +0000823 /* Enable faults we care about */
824 premptyset(&faults);
825 for (i = 1; i < MAX_QUALS; ++i) {
826 if (i > (sizeof faults) * CHAR_BIT) break;
827 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
828 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000829 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000830 perror("PIOCSFAULT");
831 return -1;
832 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000833#else /* FREEBSD */
834 /* set events flags. */
835 arg = S_SIG | S_SCE | S_SCX ;
836 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
837 perror("PIOCBIS");
838 return -1;
839 }
840#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000841 if (!attaching) {
842#ifdef MIPS
843 /*
844 * The SGI PRSABORT doesn't work for pause() so
845 * we send it a caught signal to wake it up.
846 */
847 kill(tcp->pid, SIGINT);
848#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +0000849#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000850 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000851 arg = PRSABORT;
852 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000853 perror("PIOCRUN");
854 return -1;
855 }
Roland McGrath553a6092002-12-16 20:40:39 +0000856#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000857#endif /* !MIPS*/
858#ifdef FREEBSD
859 /* wake up the child if it received the SIGSTOP */
860 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000861#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000862 for (;;) {
863 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000864 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000865 perror("PIOCWSTOP");
866 return -1;
867 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000868 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000869 tcp->flags &= ~TCB_INSYSCALL;
870 get_scno(tcp);
871 if (tcp->scno == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000872 break;
873 }
874 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000875#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000876 arg = 0;
877 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000878#else /* FREEBSD */
879 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +0000880#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000881 perror("PIOCRUN");
882 return -1;
883 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000884#ifdef FREEBSD
885 /* handle the case where we "opened" the child before
886 it did the kill -STOP */
887 if (tcp->status.PR_WHY == PR_SIGNALLED &&
888 tcp->status.PR_WHAT == SIGSTOP)
889 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +0000890#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000891 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000892#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000893 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000894#else /* FREEBSD */
895 } else {
Roland McGrath553a6092002-12-16 20:40:39 +0000896 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000897 /* We are attaching to an already running process.
898 * Try to figure out the state of the process in syscalls,
899 * to handle the first event well.
900 * This is done by having a look at the "wchan" property of the
901 * process, which tells where it is stopped (if it is). */
902 FILE * status;
903 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +0000904
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +0000905 sprintf(proc, "/proc/%d/status", tcp->pid);
906 status = fopen(proc, "r");
907 if (status &&
908 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
909 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
910 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
911 strcmp(wchan, "stopevent")) {
912 /* The process is asleep in the middle of a syscall.
913 Fake the syscall entry event */
914 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
915 tcp->status.PR_WHY = PR_SYSENTRY;
916 trace_syscall(tcp);
917 }
918 if (status)
919 fclose(status);
920 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000921 }
922#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000923#ifndef HAVE_POLLABLE_PROCFS
924 if (proc_poll_pipe[0] != -1)
925 proc_poller(tcp->pfd);
926 else if (nprocs > 1) {
927 proc_poll_open();
928 proc_poller(last_pfd);
929 proc_poller(tcp->pfd);
930 }
931 last_pfd = tcp->pfd;
932#endif /* !HAVE_POLLABLE_PROCFS */
933 return 0;
934}
935
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000936#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000937
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000938struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000939pid2tcb(pid)
940int pid;
941{
942 int i;
943 struct tcb *tcp;
944
Roland McGrathee9d4352002-12-18 04:16:10 +0000945 for (i = 0; i < tcbtabsize; i++) {
946 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000947 if (pid && tcp->pid != pid)
948 continue;
949 if (tcp->flags & TCB_INUSE)
950 return tcp;
951 }
952 return NULL;
953}
954
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000955#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000956
957static struct tcb *
958pfd2tcb(pfd)
959int pfd;
960{
961 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962
Roland McGrathca16be82003-01-10 19:55:28 +0000963 for (i = 0; i < tcbtabsize; i++) {
964 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000965 if (tcp->pfd != pfd)
966 continue;
967 if (tcp->flags & TCB_INUSE)
968 return tcp;
969 }
970 return NULL;
971}
972
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000973#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974
975void
976droptcb(tcp)
977struct tcb *tcp;
978{
979 if (tcp->pid == 0)
980 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000981#ifdef TCB_CLONE_THREAD
982 if (tcp->nclone_threads > 0) {
983 /* There are other threads left in this process, but this
984 is the one whose PID represents the whole process.
985 We need to keep this record around as a zombie until
986 all the threads die. */
987 tcp->flags |= TCB_EXITING;
988 return;
989 }
990#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 nprocs--;
992 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +0000993
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000994 if (tcp->pfd != -1) {
995 close(tcp->pfd);
996 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000997#ifdef FREEBSD
998 if (tcp->pfd_reg != -1) {
999 close(tcp->pfd_reg);
1000 tcp->pfd_reg = -1;
1001 }
1002 if (tcp->pfd_status != -1) {
1003 close(tcp->pfd_status);
1004 tcp->pfd_status = -1;
1005 }
Roland McGrath553a6092002-12-16 20:40:39 +00001006#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001007#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001008 rebuild_pollv();
1009#endif
1010 }
1011 if (tcp->parent != NULL) {
1012 tcp->parent->nchildren--;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001013#ifdef TCB_CLONE_THREAD
1014 if (tcp->flags & TCB_CLONE_DETACHED)
1015 tcp->parent->nclone_detached--;
1016 if (tcp->flags & TCB_CLONE_THREAD)
1017 tcp->parent->nclone_threads--;
1018#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019 tcp->parent = NULL;
1020 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001021
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001022 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001024
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025 tcp->outf = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001026 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027}
1028
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001029#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001030
1031static int
1032resume(tcp)
1033struct tcb *tcp;
1034{
1035 if (tcp == NULL)
1036 return -1;
1037
1038 if (!(tcp->flags & TCB_SUSPENDED)) {
1039 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1040 return -1;
1041 }
1042 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001043#ifdef TCB_CLONE_THREAD
1044 if (tcp->flags & TCB_CLONE_THREAD)
1045 tcp->parent->nclone_waiting--;
1046#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001047
1048 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1049 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1050 return -1;
1051 }
1052
1053 if (!qflag)
1054 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1055 return 0;
1056}
1057
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001058#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059
1060/* detach traced process; continue with sig */
1061
1062static int
1063detach(tcp, sig)
1064struct tcb *tcp;
1065int sig;
1066{
1067 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001068#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001069 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001070#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071
1072 if (tcp->flags & TCB_BPTSET)
1073 sig = SIGKILL;
1074
1075#ifdef LINUX
1076 /*
1077 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001078 * before detaching. Arghh. We go through hoops
1079 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001080 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001081#if defined(SPARC)
1082#undef PTRACE_DETACH
1083#define PTRACE_DETACH PTRACE_SUNDETACH
1084#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1086 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001087 }
1088 else if (errno != ESRCH) {
1089 /* Shouldn't happen. */
1090 perror("detach: ptrace(PTRACE_DETACH, ...)");
1091 }
1092 else if (kill(tcp->pid, 0) < 0) {
1093 if (errno != ESRCH)
1094 perror("detach: checking sanity");
1095 }
1096 else if (kill(tcp->pid, SIGSTOP) < 0) {
1097 if (errno != ESRCH)
1098 perror("detach: stopping child");
1099 }
1100 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001102#ifdef __WALL
1103 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1104 if (errno == ECHILD) /* Already gone. */
1105 break;
1106 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001107 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001108 break;
1109 }
1110#endif /* __WALL */
1111 /* No __WALL here. */
1112 if (waitpid(tcp->pid, &status, 0) < 0) {
1113 if (errno != ECHILD) {
1114 perror("detach: waiting");
1115 break;
1116 }
1117#ifdef __WCLONE
1118 /* If no processes, try clones. */
1119 if (wait4(tcp->pid, &status, __WCLONE,
1120 NULL) < 0) {
1121 if (errno != ECHILD)
1122 perror("detach: waiting");
1123 break;
1124 }
1125#endif /* __WCLONE */
1126 }
1127#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001128 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001129#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001130 if (!WIFSTOPPED(status)) {
1131 /* Au revoir, mon ami. */
1132 break;
1133 }
1134 if (WSTOPSIG(status) == SIGSTOP) {
1135 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001136 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137 if (errno != ESRCH)
1138 perror("detach: ptrace(PTRACE_DETACH, ...)");
1139 /* I died trying. */
1140 }
1141 break;
1142 }
1143 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001144 WSTOPSIG(status) == SIGTRAP ?
1145 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001146 if (errno != ESRCH)
1147 perror("detach: ptrace(PTRACE_CONT, ...)");
1148 break;
1149 }
1150 }
1151 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001152#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153
1154#if defined(SUNOS4)
1155 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1156 if (sig && kill(tcp->pid, sig) < 0)
1157 perror("detach: kill");
1158 sig = 0;
1159 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1160 perror("detach: ptrace(PTRACE_DETACH, ...)");
1161#endif /* SUNOS4 */
1162
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001163#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001164 resumed = 0;
1165
1166 /* XXX This won't always be quite right (but it never was).
1167 A waiter with argument 0 or < -1 is waiting for any pid in
1168 a particular pgrp, which this child might or might not be
1169 in. The waiter will only wake up if it's argument is -1
1170 or if it's waiting for tcp->pid's pgrp. It makes a
1171 difference to wake up a waiter when there might be more
1172 traced children, because it could get a false ECHILD
1173 error. OTOH, if this was the last child in the pgrp, then
1174 it ought to wake up and get ECHILD. We would have to
1175 search the system for all pid's in the pgrp to be sure.
1176
1177 && (t->waitpid == -1 ||
1178 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1179 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1180 */
1181
1182 if (tcp->parent &&
1183 (tcp->parent->flags & TCB_SUSPENDED) &&
1184 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1185 error = resume(tcp->parent);
1186 ++resumed;
1187 }
1188#ifdef TCB_CLONE_THREAD
1189 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1190 /* Some other threads of our parent are waiting too. */
1191 unsigned int i;
1192
1193 /* Resume all the threads that were waiting for this PID. */
1194 for (i = 0; i < tcbtabsize; i++) {
1195 struct tcb *t = tcbtab[i];
1196 if (t->parent == tcp->parent && t != tcp
1197 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1198 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1199 && t->waitpid == tcp->pid) {
1200 error |= resume (t);
1201 ++resumed;
1202 }
1203 }
1204 if (resumed == 0)
1205 /* Noone was waiting for this PID in particular,
1206 so now we might need to resume some wildcarders. */
1207 for (i = 0; i < tcbtabsize; i++) {
1208 struct tcb *t = tcbtab[i];
1209 if (t->parent == tcp->parent && t != tcp
1210 && ((t->flags
1211 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1212 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1213 && t->waitpid <= 0
1214 ) {
1215 error |= resume (t);
1216 break;
1217 }
1218 }
1219 }
1220#endif
1221
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001222#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001223
1224 if (!qflag)
1225 fprintf(stderr, "Process %u detached\n", tcp->pid);
1226
1227 droptcb(tcp);
1228 return error;
1229}
1230
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001231#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001232
1233static void
1234reaper(sig)
1235int sig;
1236{
1237 int pid;
1238 int status;
1239
1240 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1241#if 0
1242 struct tcb *tcp;
1243
1244 tcp = pid2tcb(pid);
1245 if (tcp)
1246 droptcb(tcp);
1247#endif
1248 }
1249}
1250
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001251#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001252
1253static void
1254cleanup()
1255{
1256 int i;
1257 struct tcb *tcp;
1258
Roland McGrathee9d4352002-12-18 04:16:10 +00001259 for (i = 0; i < tcbtabsize; i++) {
1260 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001261 if (!(tcp->flags & TCB_INUSE))
1262 continue;
1263 if (debug)
1264 fprintf(stderr,
1265 "cleanup: looking at pid %u\n", tcp->pid);
1266 if (tcp_last &&
1267 (!outfname || followfork < 2 || tcp_last == tcp)) {
1268 tprintf(" <unfinished ...>\n");
1269 tcp_last = NULL;
1270 }
1271 if (tcp->flags & TCB_ATTACHED)
1272 detach(tcp, 0);
1273 else {
1274 kill(tcp->pid, SIGCONT);
1275 kill(tcp->pid, SIGTERM);
1276 }
1277 }
1278 if (cflag)
1279 call_summary(outf);
1280}
1281
1282static void
1283interrupt(sig)
1284int sig;
1285{
1286 interrupted = 1;
1287}
1288
1289#ifndef HAVE_STRERROR
1290
Roland McGrath6d2b3492002-12-30 00:51:30 +00001291#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001292extern int sys_nerr;
1293extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001294#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001295
1296const char *
1297strerror(errno)
1298int errno;
1299{
1300 static char buf[64];
1301
1302 if (errno < 1 || errno >= sys_nerr) {
1303 sprintf(buf, "Unknown error %d", errno);
1304 return buf;
1305 }
1306 return sys_errlist[errno];
1307}
1308
1309#endif /* HAVE_STERRROR */
1310
1311#ifndef HAVE_STRSIGNAL
1312
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001313#ifdef HAVE__SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001314#if !HAVE_DECL_SYS_SIGLIST
1315extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316 extern char *_sys_siglist[];
1317#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001318#endif
1319#endif /* SYS_SIGLIST_DECLARED */
1320
1321const char *
1322strsignal(sig)
1323int sig;
1324{
1325 static char buf[64];
1326
1327 if (sig < 1 || sig >= NSIG) {
1328 sprintf(buf, "Unknown signal %d", sig);
1329 return buf;
1330 }
1331#ifdef HAVE__SYS_SIGLIST
1332 return _sys_siglist[sig];
1333#else
1334 return sys_siglist[sig];
1335#endif
1336}
1337
1338#endif /* HAVE_STRSIGNAL */
1339
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001340#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001341
1342static void
1343rebuild_pollv()
1344{
1345 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001346
Roland McGrathee9d4352002-12-18 04:16:10 +00001347 if (pollv != NULL)
1348 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001349 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001350 if (pollv == NULL) {
1351 fprintf(stderr, "strace: out of memory for poll vector\n");
1352 exit(1);
1353 }
1354
Roland McGrathca16be82003-01-10 19:55:28 +00001355 for (i = j = 0; i < tcbtabsize; i++) {
1356 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001357 if (!(tcp->flags & TCB_INUSE))
1358 continue;
1359 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001360 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001361 j++;
1362 }
1363 if (j != nprocs) {
1364 fprintf(stderr, "strace: proc miscount\n");
1365 exit(1);
1366 }
1367}
1368
1369#ifndef HAVE_POLLABLE_PROCFS
1370
1371static void
1372proc_poll_open()
1373{
1374 int arg;
1375 int i;
1376
1377 if (pipe(proc_poll_pipe) < 0) {
1378 perror("pipe");
1379 exit(1);
1380 }
1381 for (i = 0; i < 2; i++) {
1382 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1383 perror("F_GETFD");
1384 exit(1);
1385 }
1386 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1387 perror("F_SETFD");
1388 exit(1);
1389 }
1390 }
1391}
1392
1393static int
1394proc_poll(pollv, nfds, timeout)
1395struct pollfd *pollv;
1396int nfds;
1397int timeout;
1398{
1399 int i;
1400 int n;
1401 struct proc_pollfd pollinfo;
1402
1403 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1404 return n;
1405 if (n != sizeof(struct proc_pollfd)) {
1406 fprintf(stderr, "panic: short read: %d\n", n);
1407 exit(1);
1408 }
1409 for (i = 0; i < nprocs; i++) {
1410 if (pollv[i].fd == pollinfo.fd)
1411 pollv[i].revents = pollinfo.revents;
1412 else
1413 pollv[i].revents = 0;
1414 }
1415 poller_pid = pollinfo.pid;
1416 return 1;
1417}
1418
1419static void
1420wakeup_handler(sig)
1421int sig;
1422{
1423}
1424
1425static void
1426proc_poller(pfd)
1427int pfd;
1428{
1429 struct proc_pollfd pollinfo;
1430 struct sigaction sa;
1431 sigset_t blocked_set, empty_set;
1432 int i;
1433 int n;
1434 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001435#ifdef FREEBSD
1436 struct procfs_status pfs;
1437#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001438
1439 switch (fork()) {
1440 case -1:
1441 perror("fork");
1442 _exit(0);
1443 case 0:
1444 break;
1445 default:
1446 return;
1447 }
1448
1449 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1450 sa.sa_flags = 0;
1451 sigemptyset(&sa.sa_mask);
1452 sigaction(SIGHUP, &sa, NULL);
1453 sigaction(SIGINT, &sa, NULL);
1454 sigaction(SIGQUIT, &sa, NULL);
1455 sigaction(SIGPIPE, &sa, NULL);
1456 sigaction(SIGTERM, &sa, NULL);
1457 sa.sa_handler = wakeup_handler;
1458 sigaction(SIGUSR1, &sa, NULL);
1459 sigemptyset(&blocked_set);
1460 sigaddset(&blocked_set, SIGUSR1);
1461 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1462 sigemptyset(&empty_set);
1463
1464 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1465 perror("getrlimit(RLIMIT_NOFILE, ...)");
1466 _exit(0);
1467 }
1468 n = rl.rlim_cur;
1469 for (i = 0; i < n; i++) {
1470 if (i != pfd && i != proc_poll_pipe[1])
1471 close(i);
1472 }
1473
1474 pollinfo.fd = pfd;
1475 pollinfo.pid = getpid();
1476 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001477#ifndef FREEBSD
1478 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1479#else /* FREEBSD */
1480 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1481#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001482 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001483 switch (errno) {
1484 case EINTR:
1485 continue;
1486 case EBADF:
1487 pollinfo.revents = POLLERR;
1488 break;
1489 case ENOENT:
1490 pollinfo.revents = POLLHUP;
1491 break;
1492 default:
1493 perror("proc_poller: PIOCWSTOP");
1494 }
1495 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1496 _exit(0);
1497 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001498 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001499 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1500 sigsuspend(&empty_set);
1501 }
1502}
1503
1504#endif /* !HAVE_POLLABLE_PROCFS */
1505
1506static int
1507choose_pfd()
1508{
1509 int i, j;
1510 struct tcb *tcp;
1511
1512 static int last;
1513
1514 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001515 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001516 /*
1517 * The previous process is ready to run again. We'll
1518 * let it do so if it is currently in a syscall. This
1519 * heuristic improves the readability of the trace.
1520 */
1521 tcp = pfd2tcb(pollv[last].fd);
1522 if (tcp && (tcp->flags & TCB_INSYSCALL))
1523 return pollv[last].fd;
1524 }
1525
1526 for (i = 0; i < nprocs; i++) {
1527 /* Let competing children run round robin. */
1528 j = (i + last + 1) % nprocs;
1529 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1530 tcp = pfd2tcb(pollv[j].fd);
1531 if (!tcp) {
1532 fprintf(stderr, "strace: lost proc\n");
1533 exit(1);
1534 }
1535 droptcb(tcp);
1536 return -1;
1537 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001538 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001539 last = j;
1540 return pollv[j].fd;
1541 }
1542 }
1543 fprintf(stderr, "strace: nothing ready\n");
1544 exit(1);
1545}
1546
1547static int
1548trace()
1549{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001550#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001551 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001552#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001553 struct tcb *tcp;
1554 int pfd;
1555 int what;
1556 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001557 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001558
1559 for (;;) {
1560 if (interactive)
1561 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1562
1563 if (nprocs == 0)
1564 break;
1565
1566 switch (nprocs) {
1567 case 1:
1568#ifndef HAVE_POLLABLE_PROCFS
1569 if (proc_poll_pipe[0] == -1) {
1570#endif
1571 tcp = pid2tcb(0);
1572 if (!tcp)
1573 continue;
1574 pfd = tcp->pfd;
1575 if (pfd == -1)
1576 continue;
1577 break;
1578#ifndef HAVE_POLLABLE_PROCFS
1579 }
1580 /* fall through ... */
1581#endif /* !HAVE_POLLABLE_PROCFS */
1582 default:
1583#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001584#ifdef POLL_HACK
1585 /* On some systems (e.g. UnixWare) we get too much ugly
1586 "unfinished..." stuff when multiple proceses are in
1587 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001588
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001589 if (in_syscall) {
1590 struct pollfd pv;
1591 tcp = in_syscall;
1592 in_syscall = NULL;
1593 pv.fd = tcp->pfd;
1594 pv.events = POLLWANT;
1595 if ((what = poll (&pv, 1, 1)) < 0) {
1596 if (interrupted)
1597 return 0;
1598 continue;
1599 }
1600 else if (what == 1 && pv.revents & POLLWANT) {
1601 goto FOUND;
1602 }
1603 }
1604#endif
1605
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001606 if (poll(pollv, nprocs, INFTIM) < 0) {
1607 if (interrupted)
1608 return 0;
1609 continue;
1610 }
1611#else /* !HAVE_POLLABLE_PROCFS */
1612 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1613 if (interrupted)
1614 return 0;
1615 continue;
1616 }
1617#endif /* !HAVE_POLLABLE_PROCFS */
1618 pfd = choose_pfd();
1619 if (pfd == -1)
1620 continue;
1621 break;
1622 }
1623
1624 /* Look up `pfd' in our table. */
1625 if ((tcp = pfd2tcb(pfd)) == NULL) {
1626 fprintf(stderr, "unknown pfd: %u\n", pfd);
1627 exit(1);
1628 }
John Hughesb6643082002-05-23 11:02:22 +00001629#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001630 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001631#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632 /* Get the status of the process. */
1633 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001634#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001635 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001636#else /* FREEBSD */
1637 /* Thanks to some scheduling mystery, the first poller
1638 sometimes waits for the already processed end of fork
1639 event. Doing a non blocking poll here solves the problem. */
1640 if (proc_poll_pipe[0] != -1)
1641 ioctl_result = IOCTL_STATUS (tcp);
1642 else
1643 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001644#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645 ioctl_errno = errno;
1646#ifndef HAVE_POLLABLE_PROCFS
1647 if (proc_poll_pipe[0] != -1) {
1648 if (ioctl_result < 0)
1649 kill(poller_pid, SIGKILL);
1650 else
1651 kill(poller_pid, SIGUSR1);
1652 }
1653#endif /* !HAVE_POLLABLE_PROCFS */
1654 }
1655 if (interrupted)
1656 return 0;
1657
1658 if (interactive)
1659 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1660
1661 if (ioctl_result < 0) {
1662 /* Find out what happened if it failed. */
1663 switch (ioctl_errno) {
1664 case EINTR:
1665 case EBADF:
1666 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001667#ifdef FREEBSD
1668 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001669#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670 case ENOENT:
1671 droptcb(tcp);
1672 continue;
1673 default:
1674 perror("PIOCWSTOP");
1675 exit(1);
1676 }
1677 }
1678
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001679#ifdef FREEBSD
1680 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1681 /* discard first event for a syscall we never entered */
1682 IOCTL (tcp->pfd, PIOCRUN, 0);
1683 continue;
1684 }
Roland McGrath553a6092002-12-16 20:40:39 +00001685#endif
1686
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001687 /* clear the just started flag */
1688 tcp->flags &= ~TCB_STARTUP;
1689
1690 /* set current output file */
1691 outf = tcp->outf;
1692
1693 if (cflag) {
1694 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001695#ifdef FREEBSD
1696 char buf[1024];
1697 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001699 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1700 buf[len] = '\0';
1701 sscanf(buf,
1702 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1703 &stime.tv_sec, &stime.tv_usec);
1704 } else
1705 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001706#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001707 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1708 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001709#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001710 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1711 tcp->stime = stime;
1712 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001713 what = tcp->status.PR_WHAT;
1714 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001715#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001717 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1718 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001719 if (trace_syscall(tcp) < 0) {
1720 fprintf(stderr, "syscall trouble\n");
1721 exit(1);
1722 }
1723 }
1724 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001725#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001726 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001727#ifdef POLL_HACK
1728 in_syscall = tcp;
1729#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001730 case PR_SYSEXIT:
1731 if (trace_syscall(tcp) < 0) {
1732 fprintf(stderr, "syscall trouble\n");
1733 exit(1);
1734 }
1735 break;
1736 case PR_SIGNALLED:
1737 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1738 printleader(tcp);
1739 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001740 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001741 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001742#ifdef PR_INFO
1743 if (tcp->status.PR_INFO.si_signo == what) {
1744 printleader(tcp);
1745 tprintf(" siginfo=");
1746 printsiginfo(&tcp->status.PR_INFO, 1);
1747 printtrailer(tcp);
1748 }
1749#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001750 }
1751 break;
1752 case PR_FAULTED:
1753 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1754 printleader(tcp);
1755 tprintf("=== FAULT %d ===", what);
1756 printtrailer(tcp);
1757 }
1758 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001759#ifdef FREEBSD
1760 case 0: /* handle case we polled for nothing */
1761 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001762#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001764 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001765 exit(1);
1766 break;
1767 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001768 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001769#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001770 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001771#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001772 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001773#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001774 perror("PIOCRUN");
1775 exit(1);
1776 }
1777 }
1778 return 0;
1779}
1780
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001781#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001782
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001783#ifdef TCB_GROUP_EXITING
1784/* Handle an exit detach or death signal that is taking all the
1785 related clone threads with it. This is called in three circumstances:
1786 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1787 SIG == 0 Continuing TCP will perform an exit_group syscall.
1788 SIG == other Continuing TCP with SIG will kill the process.
1789*/
1790static int
1791handle_group_exit(struct tcb *tcp, int sig)
1792{
1793 /* We need to locate our records of all the clone threads
1794 related to TCP, either its children or siblings. */
1795 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1796 ? tcp->parent
1797 : tcp->nclone_detached > 0
1798 ? tcp : NULL);
1799
1800 if (sig < 0) {
1801 if (leader != NULL && leader != tcp)
1802 fprintf(stderr,
1803 "PANIC: handle_group_exit: %d leader %d\n",
1804 tcp->pid, leader ? leader->pid : -1);
1805 droptcb(tcp); /* Already died. */
1806 }
1807 else {
1808 if (tcp->flags & TCB_ATTACHED) {
1809 if (leader != NULL && leader != tcp) {
1810 /* We need to detach the leader so that the
1811 process death will be reported to its real
1812 parent. But we kill it first to prevent
1813 it doing anything before we kill the whole
1814 process in a moment. We can use
1815 PTRACE_KILL on a thread that's not already
1816 stopped. Then the value we pass in
1817 PTRACE_DETACH just sets the death
1818 signal reported to the real parent. */
1819 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1820 if (debug)
1821 fprintf(stderr,
1822 " [%d exit %d kills %d]\n",
1823 tcp->pid, sig, leader->pid);
1824 detach(leader, sig);
1825 }
1826 detach(tcp, sig);
1827 }
1828 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1829 perror("strace: ptrace(PTRACE_CONT, ...)");
1830 cleanup();
1831 return -1;
1832 }
1833 else {
1834 if (leader != NULL && leader != tcp)
1835 droptcb(tcp);
1836 /* The leader will report to us as parent now,
1837 and then we'll get to the SIG==-1 case. */
1838 return 0;
1839 }
1840 }
1841
1842 /* Note that TCP and LEADER are no longer valid,
1843 but we can still compare against them. */
1844 if (leader != NULL) {
1845 unsigned int i;
1846 for (i = 0; i < tcbtabsize; i++) {
1847 struct tcb *t = tcbtab[i];
1848 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1849 && t->parent == leader)
1850 droptcb(t);
1851 }
1852 }
1853
1854 return 0;
1855}
1856#endif
1857
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001858static int
1859trace()
1860{
1861 int pid;
1862 int wait_errno;
1863 int status;
1864 struct tcb *tcp;
1865#ifdef LINUX
1866 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001867#ifdef __WALL
1868 static int wait4_options = __WALL;
1869#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001870#endif /* LINUX */
1871
1872 while (nprocs != 0) {
1873 if (interactive)
1874 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1875#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001876#ifdef __WALL
1877 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00001878 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001879 /* this kernel does not support __WALL */
1880 wait4_options &= ~__WALL;
1881 errno = 0;
1882 pid = wait4(-1, &status, wait4_options,
1883 cflag ? &ru : NULL);
1884 }
Roland McGrath5bc05552002-12-17 04:50:47 +00001885 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001886 /* most likely a "cloned" process */
1887 pid = wait4(-1, &status, __WCLONE,
1888 cflag ? &ru : NULL);
1889 if (pid == -1) {
1890 fprintf(stderr, "strace: clone wait4 "
1891 "failed: %s\n", strerror(errno));
1892 }
1893 }
1894#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001895 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001896#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001897#endif /* LINUX */
1898#ifdef SUNOS4
1899 pid = wait(&status);
1900#endif /* SUNOS4 */
1901 wait_errno = errno;
1902 if (interactive)
1903 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1904
1905 if (interrupted)
1906 return 0;
1907
1908 if (pid == -1) {
1909 switch (wait_errno) {
1910 case EINTR:
1911 continue;
1912 case ECHILD:
1913 /*
1914 * We would like to verify this case
1915 * but sometimes a race in Solbourne's
1916 * version of SunOS sometimes reports
1917 * ECHILD before sending us SIGCHILD.
1918 */
1919#if 0
1920 if (nprocs == 0)
1921 return 0;
1922 fprintf(stderr, "strace: proc miscount\n");
1923 exit(1);
1924#endif
1925 return 0;
1926 default:
1927 errno = wait_errno;
1928 perror("strace: wait");
1929 return -1;
1930 }
1931 }
1932 if (debug)
1933 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1934
1935 /* Look up `pid' in our table. */
1936 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001937#ifdef LINUX
1938 if (followfork || followvfork) {
1939 /* This is needed to go with the CLONE_PTRACE
1940 changes in process.c/util.c: we might see
1941 the child's initial trap before we see the
1942 parent return from the clone syscall.
1943 Leave the child suspended until the parent
1944 returns from its system call. Only then
1945 will we have the association of parent and
1946 child so that we know how to do clearbpt
1947 in the child. */
1948 if ((tcp = alloctcb(pid)) == NULL) {
1949 fprintf(stderr, " [tcb table full]\n");
1950 kill(pid, SIGKILL); /* XXX */
1951 return 0;
1952 }
1953 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
1954 newoutf(tcp);
1955 if (!qflag)
1956 fprintf(stderr, "\
1957Process %d attached (waiting for parent)\n",
1958 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001959 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001960 else
1961 /* This can happen if a clone call used
1962 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001963#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001964 {
1965 fprintf(stderr, "unknown pid: %u\n", pid);
1966 if (WIFSTOPPED(status))
1967 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1968 exit(1);
1969 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001970 }
1971 /* set current output file */
1972 outf = tcp->outf;
1973 if (cflag) {
1974#ifdef LINUX
1975 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
1976 tcp->stime = ru.ru_stime;
1977#endif /* !LINUX */
1978 }
1979
1980 if (tcp->flags & TCB_SUSPENDED) {
1981 /*
1982 * Apparently, doing any ptrace() call on a stopped
1983 * process, provokes the kernel to report the process
1984 * status again on a subsequent wait(), even if the
1985 * process has not been actually restarted.
1986 * Since we have inspected the arguments of suspended
1987 * processes we end up here testing for this case.
1988 */
1989 continue;
1990 }
1991 if (WIFSIGNALED(status)) {
1992 if (!cflag
1993 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
1994 printleader(tcp);
1995 tprintf("+++ killed by %s +++",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001996 signame(WTERMSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001997 printtrailer(tcp);
1998 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001999#ifdef TCB_GROUP_EXITING
2000 handle_group_exit(tcp, -1);
2001#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002002 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002003#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002004 continue;
2005 }
2006 if (WIFEXITED(status)) {
2007 if (debug)
2008 fprintf(stderr, "pid %u exited\n", pid);
2009 if (tcp->flags & TCB_ATTACHED)
2010 fprintf(stderr,
2011 "PANIC: attached pid %u exited\n",
2012 pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002013#ifdef TCB_GROUP_EXITING
2014 handle_group_exit(tcp, -1);
2015#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002016 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002017#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002018 continue;
2019 }
2020 if (!WIFSTOPPED(status)) {
2021 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2022 droptcb(tcp);
2023 continue;
2024 }
2025 if (debug)
2026 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002027 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002028
2029 if (tcp->flags & TCB_STARTUP) {
2030 /*
2031 * This flag is there to keep us in sync.
2032 * Next time this process stops it should
2033 * really be entering a system call.
2034 */
2035 tcp->flags &= ~TCB_STARTUP;
2036 if (tcp->flags & TCB_ATTACHED) {
2037 /*
2038 * Interestingly, the process may stop
2039 * with STOPSIG equal to some other signal
2040 * than SIGSTOP if we happend to attach
2041 * just before the process takes a signal.
2042 */
2043 if (!WIFSTOPPED(status)) {
2044 fprintf(stderr,
2045 "pid %u not stopped\n", pid);
2046 detach(tcp, WSTOPSIG(status));
2047 continue;
2048 }
2049 }
2050 else {
2051#ifdef SUNOS4
2052 /* A child of us stopped at exec */
2053 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2054 fixvfork(tcp);
2055#endif /* SUNOS4 */
2056 }
2057 if (tcp->flags & TCB_BPTSET) {
2058 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2059 droptcb(tcp);
2060 cleanup();
2061 return -1;
2062 }
2063 }
2064 goto tracing;
2065 }
2066
2067 if (WSTOPSIG(status) != SIGTRAP) {
2068 if (WSTOPSIG(status) == SIGSTOP &&
2069 (tcp->flags & TCB_SIGTRAPPED)) {
2070 /*
2071 * Trapped attempt to block SIGTRAP
2072 * Hope we are back in control now.
2073 */
2074 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2075 if (ptrace(PTRACE_SYSCALL,
2076 pid, (char *) 1, 0) < 0) {
2077 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2078 cleanup();
2079 return -1;
2080 }
2081 continue;
2082 }
2083 if (!cflag
2084 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002085 unsigned long addr = 0, pc = 0;
2086#ifdef PT_GETSIGINFO
2087# define PSR_RI 41
2088 struct siginfo si;
2089 unsigned long psr;
2090
2091 upeek(pid, PT_CR_IPSR, &psr);
2092 upeek(pid, PT_CR_IIP, &pc);
2093
2094 pc += (psr >> PSR_RI) & 0x3;
2095 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2096 addr = (unsigned long) si.si_addr;
2097#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002098 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002099 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002100 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002101 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002102 printtrailer(tcp);
2103 }
2104 if ((tcp->flags & TCB_ATTACHED) &&
2105 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002106#ifdef TCB_GROUP_EXITING
2107 handle_group_exit(tcp, WSTOPSIG(status));
2108#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002109 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002110#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002111 continue;
2112 }
2113 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2114 WSTOPSIG(status)) < 0) {
2115 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2116 cleanup();
2117 return -1;
2118 }
2119 tcp->flags &= ~TCB_SUSPENDED;
2120 continue;
2121 }
2122 if (trace_syscall(tcp) < 0) {
2123 if (tcp->flags & TCB_ATTACHED)
2124 detach(tcp, 0);
2125 else {
2126 ptrace(PTRACE_KILL,
2127 tcp->pid, (char *) 1, SIGTERM);
2128 droptcb(tcp);
2129 }
2130 continue;
2131 }
2132 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002133#ifdef TCB_GROUP_EXITING
2134 if (tcp->flags & TCB_GROUP_EXITING) {
2135 if (handle_group_exit(tcp, 0) < 0)
2136 return -1;
2137 continue;
2138 }
2139#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002140 if (tcp->flags & TCB_ATTACHED)
2141 detach(tcp, 0);
2142 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2143 perror("strace: ptrace(PTRACE_CONT, ...)");
2144 cleanup();
2145 return -1;
2146 }
2147 continue;
2148 }
2149 if (tcp->flags & TCB_SUSPENDED) {
2150 if (!qflag)
2151 fprintf(stderr, "Process %u suspended\n", pid);
2152 continue;
2153 }
2154 tracing:
2155 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2156 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2157 cleanup();
2158 return -1;
2159 }
2160 }
2161 return 0;
2162}
2163
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002164#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002165
2166static int curcol;
2167
2168#ifdef __STDC__
2169#include <stdarg.h>
2170#define VA_START(a, b) va_start(a, b)
2171#else
2172#include <varargs.h>
2173#define VA_START(a, b) va_start(a)
2174#endif
2175
2176void
2177#ifdef __STDC__
2178tprintf(const char *fmt, ...)
2179#else
2180tprintf(fmt, va_alist)
2181char *fmt;
2182va_dcl
2183#endif
2184{
2185 va_list args;
2186
2187 VA_START(args, fmt);
2188 if (outf)
2189 curcol += vfprintf(outf, fmt, args);
2190 va_end(args);
2191 return;
2192}
2193
2194void
2195printleader(tcp)
2196struct tcb *tcp;
2197{
2198 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2199 tcp_last->flags |= TCB_REPRINT;
2200 tprintf(" <unfinished ...>\n");
2201 }
2202 curcol = 0;
2203 if ((followfork == 1 || pflag_seen > 1) && outfname)
2204 tprintf("%-5d ", tcp->pid);
2205 else if (nprocs > 1 && !outfname)
2206 tprintf("[pid %5u] ", tcp->pid);
2207 if (tflag) {
2208 char str[sizeof("HH:MM:SS")];
2209 struct timeval tv, dtv;
2210 static struct timeval otv;
2211
2212 gettimeofday(&tv, NULL);
2213 if (rflag) {
2214 if (otv.tv_sec == 0)
2215 otv = tv;
2216 tv_sub(&dtv, &tv, &otv);
2217 tprintf("%6ld.%06ld ",
2218 (long) dtv.tv_sec, (long) dtv.tv_usec);
2219 otv = tv;
2220 }
2221 else if (tflag > 2) {
2222 tprintf("%ld.%06ld ",
2223 (long) tv.tv_sec, (long) tv.tv_usec);
2224 }
2225 else {
2226 time_t local = tv.tv_sec;
2227 strftime(str, sizeof(str), "%T", localtime(&local));
2228 if (tflag > 1)
2229 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2230 else
2231 tprintf("%s ", str);
2232 }
2233 }
2234 if (iflag)
2235 printcall(tcp);
2236}
2237
2238void
2239tabto(col)
2240int col;
2241{
2242 if (curcol < col)
2243 tprintf("%*s", col - curcol, "");
2244}
2245
2246void
2247printtrailer(tcp)
2248struct tcb *tcp;
2249{
2250 tprintf("\n");
2251 tcp_last = NULL;
2252}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002253
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002254#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002255
2256int mp_ioctl (int fd, int cmd, void *arg, int size) {
2257
2258 struct iovec iov[2];
2259 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002260
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002261 iov[0].iov_base = &cmd;
2262 iov[0].iov_len = sizeof cmd;
2263 if (arg) {
2264 ++n;
2265 iov[1].iov_base = arg;
2266 iov[1].iov_len = size;
2267 }
Roland McGrath553a6092002-12-16 20:40:39 +00002268
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002269 return writev (fd, iov, n);
2270}
2271
2272#endif