blob: 8f0f7dcf4f23153be53e30a04045c8ed8c782117 [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;
962 struct tcb *tcp;
963
Roland McGrathee9d4352002-12-18 04:16:10 +0000964 for (i = 0, tcp = tcbtab; i < tcbtabsize; i++, tcp++) {
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 McGrathe85bbfe2003-01-09 06:53:31 +00001068 int status, resumed;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001069
1070 if (tcp->flags & TCB_BPTSET)
1071 sig = SIGKILL;
1072
1073#ifdef LINUX
1074 /*
1075 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001076 * before detaching. Arghh. We go through hoops
1077 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001078 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001079#if defined(SPARC)
1080#undef PTRACE_DETACH
1081#define PTRACE_DETACH PTRACE_SUNDETACH
1082#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1084 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001085 }
1086 else if (errno != ESRCH) {
1087 /* Shouldn't happen. */
1088 perror("detach: ptrace(PTRACE_DETACH, ...)");
1089 }
1090 else if (kill(tcp->pid, 0) < 0) {
1091 if (errno != ESRCH)
1092 perror("detach: checking sanity");
1093 }
1094 else if (kill(tcp->pid, SIGSTOP) < 0) {
1095 if (errno != ESRCH)
1096 perror("detach: stopping child");
1097 }
1098 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001099 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001100#ifdef __WALL
1101 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1102 if (errno == ECHILD) /* Already gone. */
1103 break;
1104 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001105 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001106 break;
1107 }
1108#endif /* __WALL */
1109 /* No __WALL here. */
1110 if (waitpid(tcp->pid, &status, 0) < 0) {
1111 if (errno != ECHILD) {
1112 perror("detach: waiting");
1113 break;
1114 }
1115#ifdef __WCLONE
1116 /* If no processes, try clones. */
1117 if (wait4(tcp->pid, &status, __WCLONE,
1118 NULL) < 0) {
1119 if (errno != ECHILD)
1120 perror("detach: waiting");
1121 break;
1122 }
1123#endif /* __WCLONE */
1124 }
1125#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001126 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001127#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001128 if (!WIFSTOPPED(status)) {
1129 /* Au revoir, mon ami. */
1130 break;
1131 }
1132 if (WSTOPSIG(status) == SIGSTOP) {
1133 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001134 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135 if (errno != ESRCH)
1136 perror("detach: ptrace(PTRACE_DETACH, ...)");
1137 /* I died trying. */
1138 }
1139 break;
1140 }
1141 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001142 WSTOPSIG(status) == SIGTRAP ?
1143 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001144 if (errno != ESRCH)
1145 perror("detach: ptrace(PTRACE_CONT, ...)");
1146 break;
1147 }
1148 }
1149 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001150#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151
1152#if defined(SUNOS4)
1153 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1154 if (sig && kill(tcp->pid, sig) < 0)
1155 perror("detach: kill");
1156 sig = 0;
1157 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1158 perror("detach: ptrace(PTRACE_DETACH, ...)");
1159#endif /* SUNOS4 */
1160
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001161#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001162 resumed = 0;
1163
1164 /* XXX This won't always be quite right (but it never was).
1165 A waiter with argument 0 or < -1 is waiting for any pid in
1166 a particular pgrp, which this child might or might not be
1167 in. The waiter will only wake up if it's argument is -1
1168 or if it's waiting for tcp->pid's pgrp. It makes a
1169 difference to wake up a waiter when there might be more
1170 traced children, because it could get a false ECHILD
1171 error. OTOH, if this was the last child in the pgrp, then
1172 it ought to wake up and get ECHILD. We would have to
1173 search the system for all pid's in the pgrp to be sure.
1174
1175 && (t->waitpid == -1 ||
1176 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1177 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1178 */
1179
1180 if (tcp->parent &&
1181 (tcp->parent->flags & TCB_SUSPENDED) &&
1182 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1183 error = resume(tcp->parent);
1184 ++resumed;
1185 }
1186#ifdef TCB_CLONE_THREAD
1187 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1188 /* Some other threads of our parent are waiting too. */
1189 unsigned int i;
1190
1191 /* Resume all the threads that were waiting for this PID. */
1192 for (i = 0; i < tcbtabsize; i++) {
1193 struct tcb *t = tcbtab[i];
1194 if (t->parent == tcp->parent && t != tcp
1195 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1196 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1197 && t->waitpid == tcp->pid) {
1198 error |= resume (t);
1199 ++resumed;
1200 }
1201 }
1202 if (resumed == 0)
1203 /* Noone was waiting for this PID in particular,
1204 so now we might need to resume some wildcarders. */
1205 for (i = 0; i < tcbtabsize; i++) {
1206 struct tcb *t = tcbtab[i];
1207 if (t->parent == tcp->parent && t != tcp
1208 && ((t->flags
1209 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1210 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1211 && t->waitpid <= 0
1212 ) {
1213 error |= resume (t);
1214 break;
1215 }
1216 }
1217 }
1218#endif
1219
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001220#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001221
1222 if (!qflag)
1223 fprintf(stderr, "Process %u detached\n", tcp->pid);
1224
1225 droptcb(tcp);
1226 return error;
1227}
1228
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001229#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001230
1231static void
1232reaper(sig)
1233int sig;
1234{
1235 int pid;
1236 int status;
1237
1238 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1239#if 0
1240 struct tcb *tcp;
1241
1242 tcp = pid2tcb(pid);
1243 if (tcp)
1244 droptcb(tcp);
1245#endif
1246 }
1247}
1248
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001249#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001250
1251static void
1252cleanup()
1253{
1254 int i;
1255 struct tcb *tcp;
1256
Roland McGrathee9d4352002-12-18 04:16:10 +00001257 for (i = 0; i < tcbtabsize; i++) {
1258 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001259 if (!(tcp->flags & TCB_INUSE))
1260 continue;
1261 if (debug)
1262 fprintf(stderr,
1263 "cleanup: looking at pid %u\n", tcp->pid);
1264 if (tcp_last &&
1265 (!outfname || followfork < 2 || tcp_last == tcp)) {
1266 tprintf(" <unfinished ...>\n");
1267 tcp_last = NULL;
1268 }
1269 if (tcp->flags & TCB_ATTACHED)
1270 detach(tcp, 0);
1271 else {
1272 kill(tcp->pid, SIGCONT);
1273 kill(tcp->pid, SIGTERM);
1274 }
1275 }
1276 if (cflag)
1277 call_summary(outf);
1278}
1279
1280static void
1281interrupt(sig)
1282int sig;
1283{
1284 interrupted = 1;
1285}
1286
1287#ifndef HAVE_STRERROR
1288
Roland McGrath6d2b3492002-12-30 00:51:30 +00001289#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001290extern int sys_nerr;
1291extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001292#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293
1294const char *
1295strerror(errno)
1296int errno;
1297{
1298 static char buf[64];
1299
1300 if (errno < 1 || errno >= sys_nerr) {
1301 sprintf(buf, "Unknown error %d", errno);
1302 return buf;
1303 }
1304 return sys_errlist[errno];
1305}
1306
1307#endif /* HAVE_STERRROR */
1308
1309#ifndef HAVE_STRSIGNAL
1310
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001311#ifdef HAVE__SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001312#if !HAVE_DECL_SYS_SIGLIST
1313extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001314 extern char *_sys_siglist[];
1315#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001316#endif
1317#endif /* SYS_SIGLIST_DECLARED */
1318
1319const char *
1320strsignal(sig)
1321int sig;
1322{
1323 static char buf[64];
1324
1325 if (sig < 1 || sig >= NSIG) {
1326 sprintf(buf, "Unknown signal %d", sig);
1327 return buf;
1328 }
1329#ifdef HAVE__SYS_SIGLIST
1330 return _sys_siglist[sig];
1331#else
1332 return sys_siglist[sig];
1333#endif
1334}
1335
1336#endif /* HAVE_STRSIGNAL */
1337
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001338#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001339
1340static void
1341rebuild_pollv()
1342{
1343 int i, j;
1344 struct tcb *tcp;
1345
Roland McGrathee9d4352002-12-18 04:16:10 +00001346 if (pollv != NULL)
1347 free (pollv);
1348 pollv = (struct poll *) malloc(nprocs * sizeof pollv[0]);
1349 if (pollv == NULL) {
1350 fprintf(stderr, "strace: out of memory for poll vector\n");
1351 exit(1);
1352 }
1353
1354 for (i = j = 0, tcp = tcbtab; i < tcbtabsize; i++, tcp++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001355 if (!(tcp->flags & TCB_INUSE))
1356 continue;
1357 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001358 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001359 j++;
1360 }
1361 if (j != nprocs) {
1362 fprintf(stderr, "strace: proc miscount\n");
1363 exit(1);
1364 }
1365}
1366
1367#ifndef HAVE_POLLABLE_PROCFS
1368
1369static void
1370proc_poll_open()
1371{
1372 int arg;
1373 int i;
1374
1375 if (pipe(proc_poll_pipe) < 0) {
1376 perror("pipe");
1377 exit(1);
1378 }
1379 for (i = 0; i < 2; i++) {
1380 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1381 perror("F_GETFD");
1382 exit(1);
1383 }
1384 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1385 perror("F_SETFD");
1386 exit(1);
1387 }
1388 }
1389}
1390
1391static int
1392proc_poll(pollv, nfds, timeout)
1393struct pollfd *pollv;
1394int nfds;
1395int timeout;
1396{
1397 int i;
1398 int n;
1399 struct proc_pollfd pollinfo;
1400
1401 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1402 return n;
1403 if (n != sizeof(struct proc_pollfd)) {
1404 fprintf(stderr, "panic: short read: %d\n", n);
1405 exit(1);
1406 }
1407 for (i = 0; i < nprocs; i++) {
1408 if (pollv[i].fd == pollinfo.fd)
1409 pollv[i].revents = pollinfo.revents;
1410 else
1411 pollv[i].revents = 0;
1412 }
1413 poller_pid = pollinfo.pid;
1414 return 1;
1415}
1416
1417static void
1418wakeup_handler(sig)
1419int sig;
1420{
1421}
1422
1423static void
1424proc_poller(pfd)
1425int pfd;
1426{
1427 struct proc_pollfd pollinfo;
1428 struct sigaction sa;
1429 sigset_t blocked_set, empty_set;
1430 int i;
1431 int n;
1432 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001433#ifdef FREEBSD
1434 struct procfs_status pfs;
1435#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001436
1437 switch (fork()) {
1438 case -1:
1439 perror("fork");
1440 _exit(0);
1441 case 0:
1442 break;
1443 default:
1444 return;
1445 }
1446
1447 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1448 sa.sa_flags = 0;
1449 sigemptyset(&sa.sa_mask);
1450 sigaction(SIGHUP, &sa, NULL);
1451 sigaction(SIGINT, &sa, NULL);
1452 sigaction(SIGQUIT, &sa, NULL);
1453 sigaction(SIGPIPE, &sa, NULL);
1454 sigaction(SIGTERM, &sa, NULL);
1455 sa.sa_handler = wakeup_handler;
1456 sigaction(SIGUSR1, &sa, NULL);
1457 sigemptyset(&blocked_set);
1458 sigaddset(&blocked_set, SIGUSR1);
1459 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1460 sigemptyset(&empty_set);
1461
1462 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1463 perror("getrlimit(RLIMIT_NOFILE, ...)");
1464 _exit(0);
1465 }
1466 n = rl.rlim_cur;
1467 for (i = 0; i < n; i++) {
1468 if (i != pfd && i != proc_poll_pipe[1])
1469 close(i);
1470 }
1471
1472 pollinfo.fd = pfd;
1473 pollinfo.pid = getpid();
1474 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001475#ifndef FREEBSD
1476 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1477#else /* FREEBSD */
1478 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1479#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001480 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001481 switch (errno) {
1482 case EINTR:
1483 continue;
1484 case EBADF:
1485 pollinfo.revents = POLLERR;
1486 break;
1487 case ENOENT:
1488 pollinfo.revents = POLLHUP;
1489 break;
1490 default:
1491 perror("proc_poller: PIOCWSTOP");
1492 }
1493 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1494 _exit(0);
1495 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001496 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001497 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1498 sigsuspend(&empty_set);
1499 }
1500}
1501
1502#endif /* !HAVE_POLLABLE_PROCFS */
1503
1504static int
1505choose_pfd()
1506{
1507 int i, j;
1508 struct tcb *tcp;
1509
1510 static int last;
1511
1512 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001513 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001514 /*
1515 * The previous process is ready to run again. We'll
1516 * let it do so if it is currently in a syscall. This
1517 * heuristic improves the readability of the trace.
1518 */
1519 tcp = pfd2tcb(pollv[last].fd);
1520 if (tcp && (tcp->flags & TCB_INSYSCALL))
1521 return pollv[last].fd;
1522 }
1523
1524 for (i = 0; i < nprocs; i++) {
1525 /* Let competing children run round robin. */
1526 j = (i + last + 1) % nprocs;
1527 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1528 tcp = pfd2tcb(pollv[j].fd);
1529 if (!tcp) {
1530 fprintf(stderr, "strace: lost proc\n");
1531 exit(1);
1532 }
1533 droptcb(tcp);
1534 return -1;
1535 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001536 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001537 last = j;
1538 return pollv[j].fd;
1539 }
1540 }
1541 fprintf(stderr, "strace: nothing ready\n");
1542 exit(1);
1543}
1544
1545static int
1546trace()
1547{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001548#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001549 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001550#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001551 struct tcb *tcp;
1552 int pfd;
1553 int what;
1554 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001555 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001556
1557 for (;;) {
1558 if (interactive)
1559 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1560
1561 if (nprocs == 0)
1562 break;
1563
1564 switch (nprocs) {
1565 case 1:
1566#ifndef HAVE_POLLABLE_PROCFS
1567 if (proc_poll_pipe[0] == -1) {
1568#endif
1569 tcp = pid2tcb(0);
1570 if (!tcp)
1571 continue;
1572 pfd = tcp->pfd;
1573 if (pfd == -1)
1574 continue;
1575 break;
1576#ifndef HAVE_POLLABLE_PROCFS
1577 }
1578 /* fall through ... */
1579#endif /* !HAVE_POLLABLE_PROCFS */
1580 default:
1581#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001582#ifdef POLL_HACK
1583 /* On some systems (e.g. UnixWare) we get too much ugly
1584 "unfinished..." stuff when multiple proceses are in
1585 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001586
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001587 if (in_syscall) {
1588 struct pollfd pv;
1589 tcp = in_syscall;
1590 in_syscall = NULL;
1591 pv.fd = tcp->pfd;
1592 pv.events = POLLWANT;
1593 if ((what = poll (&pv, 1, 1)) < 0) {
1594 if (interrupted)
1595 return 0;
1596 continue;
1597 }
1598 else if (what == 1 && pv.revents & POLLWANT) {
1599 goto FOUND;
1600 }
1601 }
1602#endif
1603
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001604 if (poll(pollv, nprocs, INFTIM) < 0) {
1605 if (interrupted)
1606 return 0;
1607 continue;
1608 }
1609#else /* !HAVE_POLLABLE_PROCFS */
1610 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1611 if (interrupted)
1612 return 0;
1613 continue;
1614 }
1615#endif /* !HAVE_POLLABLE_PROCFS */
1616 pfd = choose_pfd();
1617 if (pfd == -1)
1618 continue;
1619 break;
1620 }
1621
1622 /* Look up `pfd' in our table. */
1623 if ((tcp = pfd2tcb(pfd)) == NULL) {
1624 fprintf(stderr, "unknown pfd: %u\n", pfd);
1625 exit(1);
1626 }
John Hughesb6643082002-05-23 11:02:22 +00001627#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001628 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001629#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001630 /* Get the status of the process. */
1631 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001632#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001633 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001634#else /* FREEBSD */
1635 /* Thanks to some scheduling mystery, the first poller
1636 sometimes waits for the already processed end of fork
1637 event. Doing a non blocking poll here solves the problem. */
1638 if (proc_poll_pipe[0] != -1)
1639 ioctl_result = IOCTL_STATUS (tcp);
1640 else
1641 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001642#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643 ioctl_errno = errno;
1644#ifndef HAVE_POLLABLE_PROCFS
1645 if (proc_poll_pipe[0] != -1) {
1646 if (ioctl_result < 0)
1647 kill(poller_pid, SIGKILL);
1648 else
1649 kill(poller_pid, SIGUSR1);
1650 }
1651#endif /* !HAVE_POLLABLE_PROCFS */
1652 }
1653 if (interrupted)
1654 return 0;
1655
1656 if (interactive)
1657 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1658
1659 if (ioctl_result < 0) {
1660 /* Find out what happened if it failed. */
1661 switch (ioctl_errno) {
1662 case EINTR:
1663 case EBADF:
1664 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001665#ifdef FREEBSD
1666 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001667#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001668 case ENOENT:
1669 droptcb(tcp);
1670 continue;
1671 default:
1672 perror("PIOCWSTOP");
1673 exit(1);
1674 }
1675 }
1676
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001677#ifdef FREEBSD
1678 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1679 /* discard first event for a syscall we never entered */
1680 IOCTL (tcp->pfd, PIOCRUN, 0);
1681 continue;
1682 }
Roland McGrath553a6092002-12-16 20:40:39 +00001683#endif
1684
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685 /* clear the just started flag */
1686 tcp->flags &= ~TCB_STARTUP;
1687
1688 /* set current output file */
1689 outf = tcp->outf;
1690
1691 if (cflag) {
1692 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001693#ifdef FREEBSD
1694 char buf[1024];
1695 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001696
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001697 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1698 buf[len] = '\0';
1699 sscanf(buf,
1700 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1701 &stime.tv_sec, &stime.tv_usec);
1702 } else
1703 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001704#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001705 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1706 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001707#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001708 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1709 tcp->stime = stime;
1710 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001711 what = tcp->status.PR_WHAT;
1712 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001713#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001715 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1716 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001717 if (trace_syscall(tcp) < 0) {
1718 fprintf(stderr, "syscall trouble\n");
1719 exit(1);
1720 }
1721 }
1722 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001723#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001724 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001725#ifdef POLL_HACK
1726 in_syscall = tcp;
1727#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 case PR_SYSEXIT:
1729 if (trace_syscall(tcp) < 0) {
1730 fprintf(stderr, "syscall trouble\n");
1731 exit(1);
1732 }
1733 break;
1734 case PR_SIGNALLED:
1735 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1736 printleader(tcp);
1737 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001738 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001739 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001740#ifdef PR_INFO
1741 if (tcp->status.PR_INFO.si_signo == what) {
1742 printleader(tcp);
1743 tprintf(" siginfo=");
1744 printsiginfo(&tcp->status.PR_INFO, 1);
1745 printtrailer(tcp);
1746 }
1747#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001748 }
1749 break;
1750 case PR_FAULTED:
1751 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1752 printleader(tcp);
1753 tprintf("=== FAULT %d ===", what);
1754 printtrailer(tcp);
1755 }
1756 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001757#ifdef FREEBSD
1758 case 0: /* handle case we polled for nothing */
1759 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001760#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001761 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001762 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763 exit(1);
1764 break;
1765 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001766 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001767#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001768 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001769#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001770 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001771#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001772 perror("PIOCRUN");
1773 exit(1);
1774 }
1775 }
1776 return 0;
1777}
1778
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001779#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001780
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001781#ifdef TCB_GROUP_EXITING
1782/* Handle an exit detach or death signal that is taking all the
1783 related clone threads with it. This is called in three circumstances:
1784 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1785 SIG == 0 Continuing TCP will perform an exit_group syscall.
1786 SIG == other Continuing TCP with SIG will kill the process.
1787*/
1788static int
1789handle_group_exit(struct tcb *tcp, int sig)
1790{
1791 /* We need to locate our records of all the clone threads
1792 related to TCP, either its children or siblings. */
1793 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1794 ? tcp->parent
1795 : tcp->nclone_detached > 0
1796 ? tcp : NULL);
1797
1798 if (sig < 0) {
1799 if (leader != NULL && leader != tcp)
1800 fprintf(stderr,
1801 "PANIC: handle_group_exit: %d leader %d\n",
1802 tcp->pid, leader ? leader->pid : -1);
1803 droptcb(tcp); /* Already died. */
1804 }
1805 else {
1806 if (tcp->flags & TCB_ATTACHED) {
1807 if (leader != NULL && leader != tcp) {
1808 /* We need to detach the leader so that the
1809 process death will be reported to its real
1810 parent. But we kill it first to prevent
1811 it doing anything before we kill the whole
1812 process in a moment. We can use
1813 PTRACE_KILL on a thread that's not already
1814 stopped. Then the value we pass in
1815 PTRACE_DETACH just sets the death
1816 signal reported to the real parent. */
1817 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1818 if (debug)
1819 fprintf(stderr,
1820 " [%d exit %d kills %d]\n",
1821 tcp->pid, sig, leader->pid);
1822 detach(leader, sig);
1823 }
1824 detach(tcp, sig);
1825 }
1826 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1827 perror("strace: ptrace(PTRACE_CONT, ...)");
1828 cleanup();
1829 return -1;
1830 }
1831 else {
1832 if (leader != NULL && leader != tcp)
1833 droptcb(tcp);
1834 /* The leader will report to us as parent now,
1835 and then we'll get to the SIG==-1 case. */
1836 return 0;
1837 }
1838 }
1839
1840 /* Note that TCP and LEADER are no longer valid,
1841 but we can still compare against them. */
1842 if (leader != NULL) {
1843 unsigned int i;
1844 for (i = 0; i < tcbtabsize; i++) {
1845 struct tcb *t = tcbtab[i];
1846 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1847 && t->parent == leader)
1848 droptcb(t);
1849 }
1850 }
1851
1852 return 0;
1853}
1854#endif
1855
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001856static int
1857trace()
1858{
1859 int pid;
1860 int wait_errno;
1861 int status;
1862 struct tcb *tcp;
1863#ifdef LINUX
1864 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001865#ifdef __WALL
1866 static int wait4_options = __WALL;
1867#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001868#endif /* LINUX */
1869
1870 while (nprocs != 0) {
1871 if (interactive)
1872 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1873#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001874#ifdef __WALL
1875 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00001876 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001877 /* this kernel does not support __WALL */
1878 wait4_options &= ~__WALL;
1879 errno = 0;
1880 pid = wait4(-1, &status, wait4_options,
1881 cflag ? &ru : NULL);
1882 }
Roland McGrath5bc05552002-12-17 04:50:47 +00001883 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001884 /* most likely a "cloned" process */
1885 pid = wait4(-1, &status, __WCLONE,
1886 cflag ? &ru : NULL);
1887 if (pid == -1) {
1888 fprintf(stderr, "strace: clone wait4 "
1889 "failed: %s\n", strerror(errno));
1890 }
1891 }
1892#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001893 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001894#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001895#endif /* LINUX */
1896#ifdef SUNOS4
1897 pid = wait(&status);
1898#endif /* SUNOS4 */
1899 wait_errno = errno;
1900 if (interactive)
1901 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1902
1903 if (interrupted)
1904 return 0;
1905
1906 if (pid == -1) {
1907 switch (wait_errno) {
1908 case EINTR:
1909 continue;
1910 case ECHILD:
1911 /*
1912 * We would like to verify this case
1913 * but sometimes a race in Solbourne's
1914 * version of SunOS sometimes reports
1915 * ECHILD before sending us SIGCHILD.
1916 */
1917#if 0
1918 if (nprocs == 0)
1919 return 0;
1920 fprintf(stderr, "strace: proc miscount\n");
1921 exit(1);
1922#endif
1923 return 0;
1924 default:
1925 errno = wait_errno;
1926 perror("strace: wait");
1927 return -1;
1928 }
1929 }
1930 if (debug)
1931 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1932
1933 /* Look up `pid' in our table. */
1934 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001935#ifdef LINUX
1936 if (followfork || followvfork) {
1937 /* This is needed to go with the CLONE_PTRACE
1938 changes in process.c/util.c: we might see
1939 the child's initial trap before we see the
1940 parent return from the clone syscall.
1941 Leave the child suspended until the parent
1942 returns from its system call. Only then
1943 will we have the association of parent and
1944 child so that we know how to do clearbpt
1945 in the child. */
1946 if ((tcp = alloctcb(pid)) == NULL) {
1947 fprintf(stderr, " [tcb table full]\n");
1948 kill(pid, SIGKILL); /* XXX */
1949 return 0;
1950 }
1951 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
1952 newoutf(tcp);
1953 if (!qflag)
1954 fprintf(stderr, "\
1955Process %d attached (waiting for parent)\n",
1956 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001957 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001958 else
1959 /* This can happen if a clone call used
1960 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001961#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001962 {
1963 fprintf(stderr, "unknown pid: %u\n", pid);
1964 if (WIFSTOPPED(status))
1965 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1966 exit(1);
1967 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001968 }
1969 /* set current output file */
1970 outf = tcp->outf;
1971 if (cflag) {
1972#ifdef LINUX
1973 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
1974 tcp->stime = ru.ru_stime;
1975#endif /* !LINUX */
1976 }
1977
1978 if (tcp->flags & TCB_SUSPENDED) {
1979 /*
1980 * Apparently, doing any ptrace() call on a stopped
1981 * process, provokes the kernel to report the process
1982 * status again on a subsequent wait(), even if the
1983 * process has not been actually restarted.
1984 * Since we have inspected the arguments of suspended
1985 * processes we end up here testing for this case.
1986 */
1987 continue;
1988 }
1989 if (WIFSIGNALED(status)) {
1990 if (!cflag
1991 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
1992 printleader(tcp);
1993 tprintf("+++ killed by %s +++",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001994 signame(WTERMSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001995 printtrailer(tcp);
1996 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001997#ifdef TCB_GROUP_EXITING
1998 handle_group_exit(tcp, -1);
1999#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002000 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002001#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002002 continue;
2003 }
2004 if (WIFEXITED(status)) {
2005 if (debug)
2006 fprintf(stderr, "pid %u exited\n", pid);
2007 if (tcp->flags & TCB_ATTACHED)
2008 fprintf(stderr,
2009 "PANIC: attached pid %u exited\n",
2010 pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002011#ifdef TCB_GROUP_EXITING
2012 handle_group_exit(tcp, -1);
2013#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002014 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002015#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002016 continue;
2017 }
2018 if (!WIFSTOPPED(status)) {
2019 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2020 droptcb(tcp);
2021 continue;
2022 }
2023 if (debug)
2024 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002025 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002026
2027 if (tcp->flags & TCB_STARTUP) {
2028 /*
2029 * This flag is there to keep us in sync.
2030 * Next time this process stops it should
2031 * really be entering a system call.
2032 */
2033 tcp->flags &= ~TCB_STARTUP;
2034 if (tcp->flags & TCB_ATTACHED) {
2035 /*
2036 * Interestingly, the process may stop
2037 * with STOPSIG equal to some other signal
2038 * than SIGSTOP if we happend to attach
2039 * just before the process takes a signal.
2040 */
2041 if (!WIFSTOPPED(status)) {
2042 fprintf(stderr,
2043 "pid %u not stopped\n", pid);
2044 detach(tcp, WSTOPSIG(status));
2045 continue;
2046 }
2047 }
2048 else {
2049#ifdef SUNOS4
2050 /* A child of us stopped at exec */
2051 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2052 fixvfork(tcp);
2053#endif /* SUNOS4 */
2054 }
2055 if (tcp->flags & TCB_BPTSET) {
2056 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2057 droptcb(tcp);
2058 cleanup();
2059 return -1;
2060 }
2061 }
2062 goto tracing;
2063 }
2064
2065 if (WSTOPSIG(status) != SIGTRAP) {
2066 if (WSTOPSIG(status) == SIGSTOP &&
2067 (tcp->flags & TCB_SIGTRAPPED)) {
2068 /*
2069 * Trapped attempt to block SIGTRAP
2070 * Hope we are back in control now.
2071 */
2072 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2073 if (ptrace(PTRACE_SYSCALL,
2074 pid, (char *) 1, 0) < 0) {
2075 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2076 cleanup();
2077 return -1;
2078 }
2079 continue;
2080 }
2081 if (!cflag
2082 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002083 unsigned long addr = 0, pc = 0;
2084#ifdef PT_GETSIGINFO
2085# define PSR_RI 41
2086 struct siginfo si;
2087 unsigned long psr;
2088
2089 upeek(pid, PT_CR_IPSR, &psr);
2090 upeek(pid, PT_CR_IIP, &pc);
2091
2092 pc += (psr >> PSR_RI) & 0x3;
2093 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2094 addr = (unsigned long) si.si_addr;
2095#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002096 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002097 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002098 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002099 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002100 printtrailer(tcp);
2101 }
2102 if ((tcp->flags & TCB_ATTACHED) &&
2103 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002104#ifdef TCB_GROUP_EXITING
2105 handle_group_exit(tcp, WSTOPSIG(status));
2106#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002107 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002108#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002109 continue;
2110 }
2111 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2112 WSTOPSIG(status)) < 0) {
2113 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2114 cleanup();
2115 return -1;
2116 }
2117 tcp->flags &= ~TCB_SUSPENDED;
2118 continue;
2119 }
2120 if (trace_syscall(tcp) < 0) {
2121 if (tcp->flags & TCB_ATTACHED)
2122 detach(tcp, 0);
2123 else {
2124 ptrace(PTRACE_KILL,
2125 tcp->pid, (char *) 1, SIGTERM);
2126 droptcb(tcp);
2127 }
2128 continue;
2129 }
2130 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002131#ifdef TCB_GROUP_EXITING
2132 if (tcp->flags & TCB_GROUP_EXITING) {
2133 if (handle_group_exit(tcp, 0) < 0)
2134 return -1;
2135 continue;
2136 }
2137#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002138 if (tcp->flags & TCB_ATTACHED)
2139 detach(tcp, 0);
2140 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2141 perror("strace: ptrace(PTRACE_CONT, ...)");
2142 cleanup();
2143 return -1;
2144 }
2145 continue;
2146 }
2147 if (tcp->flags & TCB_SUSPENDED) {
2148 if (!qflag)
2149 fprintf(stderr, "Process %u suspended\n", pid);
2150 continue;
2151 }
2152 tracing:
2153 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2154 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2155 cleanup();
2156 return -1;
2157 }
2158 }
2159 return 0;
2160}
2161
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002162#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002163
2164static int curcol;
2165
2166#ifdef __STDC__
2167#include <stdarg.h>
2168#define VA_START(a, b) va_start(a, b)
2169#else
2170#include <varargs.h>
2171#define VA_START(a, b) va_start(a)
2172#endif
2173
2174void
2175#ifdef __STDC__
2176tprintf(const char *fmt, ...)
2177#else
2178tprintf(fmt, va_alist)
2179char *fmt;
2180va_dcl
2181#endif
2182{
2183 va_list args;
2184
2185 VA_START(args, fmt);
2186 if (outf)
2187 curcol += vfprintf(outf, fmt, args);
2188 va_end(args);
2189 return;
2190}
2191
2192void
2193printleader(tcp)
2194struct tcb *tcp;
2195{
2196 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2197 tcp_last->flags |= TCB_REPRINT;
2198 tprintf(" <unfinished ...>\n");
2199 }
2200 curcol = 0;
2201 if ((followfork == 1 || pflag_seen > 1) && outfname)
2202 tprintf("%-5d ", tcp->pid);
2203 else if (nprocs > 1 && !outfname)
2204 tprintf("[pid %5u] ", tcp->pid);
2205 if (tflag) {
2206 char str[sizeof("HH:MM:SS")];
2207 struct timeval tv, dtv;
2208 static struct timeval otv;
2209
2210 gettimeofday(&tv, NULL);
2211 if (rflag) {
2212 if (otv.tv_sec == 0)
2213 otv = tv;
2214 tv_sub(&dtv, &tv, &otv);
2215 tprintf("%6ld.%06ld ",
2216 (long) dtv.tv_sec, (long) dtv.tv_usec);
2217 otv = tv;
2218 }
2219 else if (tflag > 2) {
2220 tprintf("%ld.%06ld ",
2221 (long) tv.tv_sec, (long) tv.tv_usec);
2222 }
2223 else {
2224 time_t local = tv.tv_sec;
2225 strftime(str, sizeof(str), "%T", localtime(&local));
2226 if (tflag > 1)
2227 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2228 else
2229 tprintf("%s ", str);
2230 }
2231 }
2232 if (iflag)
2233 printcall(tcp);
2234}
2235
2236void
2237tabto(col)
2238int col;
2239{
2240 if (curcol < col)
2241 tprintf("%*s", col - curcol, "");
2242}
2243
2244void
2245printtrailer(tcp)
2246struct tcb *tcp;
2247{
2248 tprintf("\n");
2249 tcp_last = NULL;
2250}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002251
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002252#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002253
2254int mp_ioctl (int fd, int cmd, void *arg, int size) {
2255
2256 struct iovec iov[2];
2257 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002258
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002259 iov[0].iov_base = &cmd;
2260 iov[0].iov_len = sizeof cmd;
2261 if (arg) {
2262 ++n;
2263 iov[1].iov_base = arg;
2264 iov[1].iov_len = size;
2265 }
Roland McGrath553a6092002-12-16 20:40:39 +00002266
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002267 return writev (fd, iov, n);
2268}
2269
2270#endif