blob: b91b02682dce091be3946aa83a5f7345813aed59 [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
Roland McGrathe29341c2003-01-10 20:14:20 +0000994 if (tcp->parent != NULL) {
995 tcp->parent->nchildren--;
996#ifdef TCB_CLONE_THREAD
997 if (tcp->flags & TCB_CLONE_DETACHED)
998 tcp->parent->nclone_detached--;
999 if (tcp->flags & TCB_CLONE_THREAD)
1000 tcp->parent->nclone_threads--;
1001#endif
1002 tcp->parent = NULL;
1003 }
1004
1005 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001006 if (tcp->pfd != -1) {
1007 close(tcp->pfd);
1008 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001009#ifdef FREEBSD
1010 if (tcp->pfd_reg != -1) {
1011 close(tcp->pfd_reg);
1012 tcp->pfd_reg = -1;
1013 }
1014 if (tcp->pfd_status != -1) {
1015 close(tcp->pfd_status);
1016 tcp->pfd_status = -1;
1017 }
Roland McGrath553a6092002-12-16 20:40:39 +00001018#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001019#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001020 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001021#endif
1022 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001023
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001024 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001026
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027 tcp->outf = 0;
1028}
1029
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001030#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001031
1032static int
1033resume(tcp)
1034struct tcb *tcp;
1035{
1036 if (tcp == NULL)
1037 return -1;
1038
1039 if (!(tcp->flags & TCB_SUSPENDED)) {
1040 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1041 return -1;
1042 }
1043 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001044#ifdef TCB_CLONE_THREAD
1045 if (tcp->flags & TCB_CLONE_THREAD)
1046 tcp->parent->nclone_waiting--;
1047#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048
1049 if (ptrace(PTRACE_SYSCALL, tcp->pid, (char *) 1, 0) < 0) {
1050 perror("resume: ptrace(PTRACE_SYSCALL, ...)");
1051 return -1;
1052 }
1053
1054 if (!qflag)
1055 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1056 return 0;
1057}
1058
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001059#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001060
1061/* detach traced process; continue with sig */
1062
1063static int
1064detach(tcp, sig)
1065struct tcb *tcp;
1066int sig;
1067{
1068 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001069#ifdef LINUX
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001070 int status, resumed;
Roland McGrathca16be82003-01-10 19:55:28 +00001071#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001072
1073 if (tcp->flags & TCB_BPTSET)
1074 sig = SIGKILL;
1075
1076#ifdef LINUX
1077 /*
1078 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001079 * before detaching. Arghh. We go through hoops
1080 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001081 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001082#if defined(SPARC)
1083#undef PTRACE_DETACH
1084#define PTRACE_DETACH PTRACE_SUNDETACH
1085#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1087 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001088 }
1089 else if (errno != ESRCH) {
1090 /* Shouldn't happen. */
1091 perror("detach: ptrace(PTRACE_DETACH, ...)");
1092 }
1093 else if (kill(tcp->pid, 0) < 0) {
1094 if (errno != ESRCH)
1095 perror("detach: checking sanity");
1096 }
1097 else if (kill(tcp->pid, SIGSTOP) < 0) {
1098 if (errno != ESRCH)
1099 perror("detach: stopping child");
1100 }
1101 else {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001103#ifdef __WALL
1104 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1105 if (errno == ECHILD) /* Already gone. */
1106 break;
1107 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001108 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001109 break;
1110 }
1111#endif /* __WALL */
1112 /* No __WALL here. */
1113 if (waitpid(tcp->pid, &status, 0) < 0) {
1114 if (errno != ECHILD) {
1115 perror("detach: waiting");
1116 break;
1117 }
1118#ifdef __WCLONE
1119 /* If no processes, try clones. */
1120 if (wait4(tcp->pid, &status, __WCLONE,
1121 NULL) < 0) {
1122 if (errno != ECHILD)
1123 perror("detach: waiting");
1124 break;
1125 }
1126#endif /* __WCLONE */
1127 }
1128#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001129 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001130#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 if (!WIFSTOPPED(status)) {
1132 /* Au revoir, mon ami. */
1133 break;
1134 }
1135 if (WSTOPSIG(status) == SIGSTOP) {
1136 if ((error = ptrace(PTRACE_DETACH,
Roland McGrath7bf10472002-12-16 20:42:50 +00001137 tcp->pid, (char *) 1, sig)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138 if (errno != ESRCH)
1139 perror("detach: ptrace(PTRACE_DETACH, ...)");
1140 /* I died trying. */
1141 }
1142 break;
1143 }
1144 if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
Roland McGrath7bf10472002-12-16 20:42:50 +00001145 WSTOPSIG(status) == SIGTRAP ?
1146 0 : WSTOPSIG(status))) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147 if (errno != ESRCH)
1148 perror("detach: ptrace(PTRACE_CONT, ...)");
1149 break;
1150 }
1151 }
1152 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001153#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001154
1155#if defined(SUNOS4)
1156 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1157 if (sig && kill(tcp->pid, sig) < 0)
1158 perror("detach: kill");
1159 sig = 0;
1160 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) < 0)
1161 perror("detach: ptrace(PTRACE_DETACH, ...)");
1162#endif /* SUNOS4 */
1163
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001164#ifndef USE_PROCFS
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001165 resumed = 0;
1166
1167 /* XXX This won't always be quite right (but it never was).
1168 A waiter with argument 0 or < -1 is waiting for any pid in
1169 a particular pgrp, which this child might or might not be
1170 in. The waiter will only wake up if it's argument is -1
1171 or if it's waiting for tcp->pid's pgrp. It makes a
1172 difference to wake up a waiter when there might be more
1173 traced children, because it could get a false ECHILD
1174 error. OTOH, if this was the last child in the pgrp, then
1175 it ought to wake up and get ECHILD. We would have to
1176 search the system for all pid's in the pgrp to be sure.
1177
1178 && (t->waitpid == -1 ||
1179 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1180 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1181 */
1182
1183 if (tcp->parent &&
1184 (tcp->parent->flags & TCB_SUSPENDED) &&
1185 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1186 error = resume(tcp->parent);
1187 ++resumed;
1188 }
1189#ifdef TCB_CLONE_THREAD
1190 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1191 /* Some other threads of our parent are waiting too. */
1192 unsigned int i;
1193
1194 /* Resume all the threads that were waiting for this PID. */
1195 for (i = 0; i < tcbtabsize; i++) {
1196 struct tcb *t = tcbtab[i];
1197 if (t->parent == tcp->parent && t != tcp
1198 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1199 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1200 && t->waitpid == tcp->pid) {
1201 error |= resume (t);
1202 ++resumed;
1203 }
1204 }
1205 if (resumed == 0)
1206 /* Noone was waiting for this PID in particular,
1207 so now we might need to resume some wildcarders. */
1208 for (i = 0; i < tcbtabsize; i++) {
1209 struct tcb *t = tcbtab[i];
1210 if (t->parent == tcp->parent && t != tcp
1211 && ((t->flags
1212 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1213 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1214 && t->waitpid <= 0
1215 ) {
1216 error |= resume (t);
1217 break;
1218 }
1219 }
1220 }
1221#endif
1222
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001223#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224
1225 if (!qflag)
1226 fprintf(stderr, "Process %u detached\n", tcp->pid);
1227
1228 droptcb(tcp);
1229 return error;
1230}
1231
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001232#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001233
1234static void
1235reaper(sig)
1236int sig;
1237{
1238 int pid;
1239 int status;
1240
1241 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1242#if 0
1243 struct tcb *tcp;
1244
1245 tcp = pid2tcb(pid);
1246 if (tcp)
1247 droptcb(tcp);
1248#endif
1249 }
1250}
1251
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001252#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001253
1254static void
1255cleanup()
1256{
1257 int i;
1258 struct tcb *tcp;
1259
Roland McGrathee9d4352002-12-18 04:16:10 +00001260 for (i = 0; i < tcbtabsize; i++) {
1261 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001262 if (!(tcp->flags & TCB_INUSE))
1263 continue;
1264 if (debug)
1265 fprintf(stderr,
1266 "cleanup: looking at pid %u\n", tcp->pid);
1267 if (tcp_last &&
1268 (!outfname || followfork < 2 || tcp_last == tcp)) {
1269 tprintf(" <unfinished ...>\n");
1270 tcp_last = NULL;
1271 }
1272 if (tcp->flags & TCB_ATTACHED)
1273 detach(tcp, 0);
1274 else {
1275 kill(tcp->pid, SIGCONT);
1276 kill(tcp->pid, SIGTERM);
1277 }
1278 }
1279 if (cflag)
1280 call_summary(outf);
1281}
1282
1283static void
1284interrupt(sig)
1285int sig;
1286{
1287 interrupted = 1;
1288}
1289
1290#ifndef HAVE_STRERROR
1291
Roland McGrath6d2b3492002-12-30 00:51:30 +00001292#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001293extern int sys_nerr;
1294extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001295#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001296
1297const char *
1298strerror(errno)
1299int errno;
1300{
1301 static char buf[64];
1302
1303 if (errno < 1 || errno >= sys_nerr) {
1304 sprintf(buf, "Unknown error %d", errno);
1305 return buf;
1306 }
1307 return sys_errlist[errno];
1308}
1309
1310#endif /* HAVE_STERRROR */
1311
1312#ifndef HAVE_STRSIGNAL
1313
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001314#ifdef HAVE__SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001315#if !HAVE_DECL_SYS_SIGLIST
1316extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001317 extern char *_sys_siglist[];
1318#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001319#endif
1320#endif /* SYS_SIGLIST_DECLARED */
1321
1322const char *
1323strsignal(sig)
1324int sig;
1325{
1326 static char buf[64];
1327
1328 if (sig < 1 || sig >= NSIG) {
1329 sprintf(buf, "Unknown signal %d", sig);
1330 return buf;
1331 }
1332#ifdef HAVE__SYS_SIGLIST
1333 return _sys_siglist[sig];
1334#else
1335 return sys_siglist[sig];
1336#endif
1337}
1338
1339#endif /* HAVE_STRSIGNAL */
1340
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001341#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001342
1343static void
1344rebuild_pollv()
1345{
1346 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001347
Roland McGrathee9d4352002-12-18 04:16:10 +00001348 if (pollv != NULL)
1349 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001350 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001351 if (pollv == NULL) {
1352 fprintf(stderr, "strace: out of memory for poll vector\n");
1353 exit(1);
1354 }
1355
Roland McGrathca16be82003-01-10 19:55:28 +00001356 for (i = j = 0; i < tcbtabsize; i++) {
1357 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001358 if (!(tcp->flags & TCB_INUSE))
1359 continue;
1360 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001361 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001362 j++;
1363 }
1364 if (j != nprocs) {
1365 fprintf(stderr, "strace: proc miscount\n");
1366 exit(1);
1367 }
1368}
1369
1370#ifndef HAVE_POLLABLE_PROCFS
1371
1372static void
1373proc_poll_open()
1374{
1375 int arg;
1376 int i;
1377
1378 if (pipe(proc_poll_pipe) < 0) {
1379 perror("pipe");
1380 exit(1);
1381 }
1382 for (i = 0; i < 2; i++) {
1383 if ((arg = fcntl(proc_poll_pipe[i], F_GETFD)) < 0) {
1384 perror("F_GETFD");
1385 exit(1);
1386 }
1387 if (fcntl(proc_poll_pipe[i], F_SETFD, arg|FD_CLOEXEC) < 0) {
1388 perror("F_SETFD");
1389 exit(1);
1390 }
1391 }
1392}
1393
1394static int
1395proc_poll(pollv, nfds, timeout)
1396struct pollfd *pollv;
1397int nfds;
1398int timeout;
1399{
1400 int i;
1401 int n;
1402 struct proc_pollfd pollinfo;
1403
1404 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1405 return n;
1406 if (n != sizeof(struct proc_pollfd)) {
1407 fprintf(stderr, "panic: short read: %d\n", n);
1408 exit(1);
1409 }
1410 for (i = 0; i < nprocs; i++) {
1411 if (pollv[i].fd == pollinfo.fd)
1412 pollv[i].revents = pollinfo.revents;
1413 else
1414 pollv[i].revents = 0;
1415 }
1416 poller_pid = pollinfo.pid;
1417 return 1;
1418}
1419
1420static void
1421wakeup_handler(sig)
1422int sig;
1423{
1424}
1425
1426static void
1427proc_poller(pfd)
1428int pfd;
1429{
1430 struct proc_pollfd pollinfo;
1431 struct sigaction sa;
1432 sigset_t blocked_set, empty_set;
1433 int i;
1434 int n;
1435 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001436#ifdef FREEBSD
1437 struct procfs_status pfs;
1438#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001439
1440 switch (fork()) {
1441 case -1:
1442 perror("fork");
1443 _exit(0);
1444 case 0:
1445 break;
1446 default:
1447 return;
1448 }
1449
1450 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1451 sa.sa_flags = 0;
1452 sigemptyset(&sa.sa_mask);
1453 sigaction(SIGHUP, &sa, NULL);
1454 sigaction(SIGINT, &sa, NULL);
1455 sigaction(SIGQUIT, &sa, NULL);
1456 sigaction(SIGPIPE, &sa, NULL);
1457 sigaction(SIGTERM, &sa, NULL);
1458 sa.sa_handler = wakeup_handler;
1459 sigaction(SIGUSR1, &sa, NULL);
1460 sigemptyset(&blocked_set);
1461 sigaddset(&blocked_set, SIGUSR1);
1462 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1463 sigemptyset(&empty_set);
1464
1465 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1466 perror("getrlimit(RLIMIT_NOFILE, ...)");
1467 _exit(0);
1468 }
1469 n = rl.rlim_cur;
1470 for (i = 0; i < n; i++) {
1471 if (i != pfd && i != proc_poll_pipe[1])
1472 close(i);
1473 }
1474
1475 pollinfo.fd = pfd;
1476 pollinfo.pid = getpid();
1477 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001478#ifndef FREEBSD
1479 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1480#else /* FREEBSD */
1481 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1482#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001483 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001484 switch (errno) {
1485 case EINTR:
1486 continue;
1487 case EBADF:
1488 pollinfo.revents = POLLERR;
1489 break;
1490 case ENOENT:
1491 pollinfo.revents = POLLHUP;
1492 break;
1493 default:
1494 perror("proc_poller: PIOCWSTOP");
1495 }
1496 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1497 _exit(0);
1498 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001499 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001500 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1501 sigsuspend(&empty_set);
1502 }
1503}
1504
1505#endif /* !HAVE_POLLABLE_PROCFS */
1506
1507static int
1508choose_pfd()
1509{
1510 int i, j;
1511 struct tcb *tcp;
1512
1513 static int last;
1514
1515 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001516 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001517 /*
1518 * The previous process is ready to run again. We'll
1519 * let it do so if it is currently in a syscall. This
1520 * heuristic improves the readability of the trace.
1521 */
1522 tcp = pfd2tcb(pollv[last].fd);
1523 if (tcp && (tcp->flags & TCB_INSYSCALL))
1524 return pollv[last].fd;
1525 }
1526
1527 for (i = 0; i < nprocs; i++) {
1528 /* Let competing children run round robin. */
1529 j = (i + last + 1) % nprocs;
1530 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1531 tcp = pfd2tcb(pollv[j].fd);
1532 if (!tcp) {
1533 fprintf(stderr, "strace: lost proc\n");
1534 exit(1);
1535 }
1536 droptcb(tcp);
1537 return -1;
1538 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001539 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001540 last = j;
1541 return pollv[j].fd;
1542 }
1543 }
1544 fprintf(stderr, "strace: nothing ready\n");
1545 exit(1);
1546}
1547
1548static int
1549trace()
1550{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001551#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001552 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001553#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001554 struct tcb *tcp;
1555 int pfd;
1556 int what;
1557 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001558 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001559
1560 for (;;) {
1561 if (interactive)
1562 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1563
1564 if (nprocs == 0)
1565 break;
1566
1567 switch (nprocs) {
1568 case 1:
1569#ifndef HAVE_POLLABLE_PROCFS
1570 if (proc_poll_pipe[0] == -1) {
1571#endif
1572 tcp = pid2tcb(0);
1573 if (!tcp)
1574 continue;
1575 pfd = tcp->pfd;
1576 if (pfd == -1)
1577 continue;
1578 break;
1579#ifndef HAVE_POLLABLE_PROCFS
1580 }
1581 /* fall through ... */
1582#endif /* !HAVE_POLLABLE_PROCFS */
1583 default:
1584#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001585#ifdef POLL_HACK
1586 /* On some systems (e.g. UnixWare) we get too much ugly
1587 "unfinished..." stuff when multiple proceses are in
1588 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001589
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001590 if (in_syscall) {
1591 struct pollfd pv;
1592 tcp = in_syscall;
1593 in_syscall = NULL;
1594 pv.fd = tcp->pfd;
1595 pv.events = POLLWANT;
1596 if ((what = poll (&pv, 1, 1)) < 0) {
1597 if (interrupted)
1598 return 0;
1599 continue;
1600 }
1601 else if (what == 1 && pv.revents & POLLWANT) {
1602 goto FOUND;
1603 }
1604 }
1605#endif
1606
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001607 if (poll(pollv, nprocs, INFTIM) < 0) {
1608 if (interrupted)
1609 return 0;
1610 continue;
1611 }
1612#else /* !HAVE_POLLABLE_PROCFS */
1613 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1614 if (interrupted)
1615 return 0;
1616 continue;
1617 }
1618#endif /* !HAVE_POLLABLE_PROCFS */
1619 pfd = choose_pfd();
1620 if (pfd == -1)
1621 continue;
1622 break;
1623 }
1624
1625 /* Look up `pfd' in our table. */
1626 if ((tcp = pfd2tcb(pfd)) == NULL) {
1627 fprintf(stderr, "unknown pfd: %u\n", pfd);
1628 exit(1);
1629 }
John Hughesb6643082002-05-23 11:02:22 +00001630#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001631 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001632#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001633 /* Get the status of the process. */
1634 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001635#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001636 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001637#else /* FREEBSD */
1638 /* Thanks to some scheduling mystery, the first poller
1639 sometimes waits for the already processed end of fork
1640 event. Doing a non blocking poll here solves the problem. */
1641 if (proc_poll_pipe[0] != -1)
1642 ioctl_result = IOCTL_STATUS (tcp);
1643 else
1644 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001645#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646 ioctl_errno = errno;
1647#ifndef HAVE_POLLABLE_PROCFS
1648 if (proc_poll_pipe[0] != -1) {
1649 if (ioctl_result < 0)
1650 kill(poller_pid, SIGKILL);
1651 else
1652 kill(poller_pid, SIGUSR1);
1653 }
1654#endif /* !HAVE_POLLABLE_PROCFS */
1655 }
1656 if (interrupted)
1657 return 0;
1658
1659 if (interactive)
1660 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1661
1662 if (ioctl_result < 0) {
1663 /* Find out what happened if it failed. */
1664 switch (ioctl_errno) {
1665 case EINTR:
1666 case EBADF:
1667 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001668#ifdef FREEBSD
1669 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00001670#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001671 case ENOENT:
1672 droptcb(tcp);
1673 continue;
1674 default:
1675 perror("PIOCWSTOP");
1676 exit(1);
1677 }
1678 }
1679
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001680#ifdef FREEBSD
1681 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
1682 /* discard first event for a syscall we never entered */
1683 IOCTL (tcp->pfd, PIOCRUN, 0);
1684 continue;
1685 }
Roland McGrath553a6092002-12-16 20:40:39 +00001686#endif
1687
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001688 /* clear the just started flag */
1689 tcp->flags &= ~TCB_STARTUP;
1690
1691 /* set current output file */
1692 outf = tcp->outf;
1693
1694 if (cflag) {
1695 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001696#ifdef FREEBSD
1697 char buf[1024];
1698 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001700 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
1701 buf[len] = '\0';
1702 sscanf(buf,
1703 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
1704 &stime.tv_sec, &stime.tv_usec);
1705 } else
1706 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001707#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001708 stime.tv_sec = tcp->status.pr_stime.tv_sec;
1709 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001710#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001711 tv_sub(&tcp->dtime, &stime, &tcp->stime);
1712 tcp->stime = stime;
1713 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001714 what = tcp->status.PR_WHAT;
1715 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001716#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001717 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001718 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
1719 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001720 if (trace_syscall(tcp) < 0) {
1721 fprintf(stderr, "syscall trouble\n");
1722 exit(1);
1723 }
1724 }
1725 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001726#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001727 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001728#ifdef POLL_HACK
1729 in_syscall = tcp;
1730#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001731 case PR_SYSEXIT:
1732 if (trace_syscall(tcp) < 0) {
1733 fprintf(stderr, "syscall trouble\n");
1734 exit(1);
1735 }
1736 break;
1737 case PR_SIGNALLED:
1738 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
1739 printleader(tcp);
1740 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001741 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001742 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00001743#ifdef PR_INFO
1744 if (tcp->status.PR_INFO.si_signo == what) {
1745 printleader(tcp);
1746 tprintf(" siginfo=");
1747 printsiginfo(&tcp->status.PR_INFO, 1);
1748 printtrailer(tcp);
1749 }
1750#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001751 }
1752 break;
1753 case PR_FAULTED:
1754 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
1755 printleader(tcp);
1756 tprintf("=== FAULT %d ===", what);
1757 printtrailer(tcp);
1758 }
1759 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001760#ifdef FREEBSD
1761 case 0: /* handle case we polled for nothing */
1762 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00001763#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001765 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001766 exit(1);
1767 break;
1768 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001769 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00001770#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001771 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001772#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001773 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001774#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001775 perror("PIOCRUN");
1776 exit(1);
1777 }
1778 }
1779 return 0;
1780}
1781
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001782#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001783
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001784#ifdef TCB_GROUP_EXITING
1785/* Handle an exit detach or death signal that is taking all the
1786 related clone threads with it. This is called in three circumstances:
1787 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
1788 SIG == 0 Continuing TCP will perform an exit_group syscall.
1789 SIG == other Continuing TCP with SIG will kill the process.
1790*/
1791static int
1792handle_group_exit(struct tcb *tcp, int sig)
1793{
1794 /* We need to locate our records of all the clone threads
1795 related to TCP, either its children or siblings. */
1796 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
1797 ? tcp->parent
1798 : tcp->nclone_detached > 0
1799 ? tcp : NULL);
1800
1801 if (sig < 0) {
1802 if (leader != NULL && leader != tcp)
1803 fprintf(stderr,
1804 "PANIC: handle_group_exit: %d leader %d\n",
1805 tcp->pid, leader ? leader->pid : -1);
1806 droptcb(tcp); /* Already died. */
1807 }
1808 else {
1809 if (tcp->flags & TCB_ATTACHED) {
1810 if (leader != NULL && leader != tcp) {
1811 /* We need to detach the leader so that the
1812 process death will be reported to its real
1813 parent. But we kill it first to prevent
1814 it doing anything before we kill the whole
1815 process in a moment. We can use
1816 PTRACE_KILL on a thread that's not already
1817 stopped. Then the value we pass in
1818 PTRACE_DETACH just sets the death
1819 signal reported to the real parent. */
1820 ptrace(PTRACE_KILL, leader->pid, 0, 0);
1821 if (debug)
1822 fprintf(stderr,
1823 " [%d exit %d kills %d]\n",
1824 tcp->pid, sig, leader->pid);
1825 detach(leader, sig);
1826 }
1827 detach(tcp, sig);
1828 }
1829 else if (ptrace(PTRACE_CONT, tcp->pid, (char *) 1, sig) < 0) {
1830 perror("strace: ptrace(PTRACE_CONT, ...)");
1831 cleanup();
1832 return -1;
1833 }
1834 else {
1835 if (leader != NULL && leader != tcp)
1836 droptcb(tcp);
1837 /* The leader will report to us as parent now,
1838 and then we'll get to the SIG==-1 case. */
1839 return 0;
1840 }
1841 }
1842
1843 /* Note that TCP and LEADER are no longer valid,
1844 but we can still compare against them. */
1845 if (leader != NULL) {
1846 unsigned int i;
1847 for (i = 0; i < tcbtabsize; i++) {
1848 struct tcb *t = tcbtab[i];
1849 if (t != tcp && (t->flags & TCB_CLONE_DETACHED)
1850 && t->parent == leader)
1851 droptcb(t);
1852 }
1853 }
1854
1855 return 0;
1856}
1857#endif
1858
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001859static int
1860trace()
1861{
1862 int pid;
1863 int wait_errno;
1864 int status;
1865 struct tcb *tcp;
1866#ifdef LINUX
1867 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001868#ifdef __WALL
1869 static int wait4_options = __WALL;
1870#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001871#endif /* LINUX */
1872
1873 while (nprocs != 0) {
1874 if (interactive)
1875 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1876#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001877#ifdef __WALL
1878 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00001879 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001880 /* this kernel does not support __WALL */
1881 wait4_options &= ~__WALL;
1882 errno = 0;
1883 pid = wait4(-1, &status, wait4_options,
1884 cflag ? &ru : NULL);
1885 }
Roland McGrath5bc05552002-12-17 04:50:47 +00001886 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001887 /* most likely a "cloned" process */
1888 pid = wait4(-1, &status, __WCLONE,
1889 cflag ? &ru : NULL);
1890 if (pid == -1) {
1891 fprintf(stderr, "strace: clone wait4 "
1892 "failed: %s\n", strerror(errno));
1893 }
1894 }
1895#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001896 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00001897#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001898#endif /* LINUX */
1899#ifdef SUNOS4
1900 pid = wait(&status);
1901#endif /* SUNOS4 */
1902 wait_errno = errno;
1903 if (interactive)
1904 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1905
1906 if (interrupted)
1907 return 0;
1908
1909 if (pid == -1) {
1910 switch (wait_errno) {
1911 case EINTR:
1912 continue;
1913 case ECHILD:
1914 /*
1915 * We would like to verify this case
1916 * but sometimes a race in Solbourne's
1917 * version of SunOS sometimes reports
1918 * ECHILD before sending us SIGCHILD.
1919 */
1920#if 0
1921 if (nprocs == 0)
1922 return 0;
1923 fprintf(stderr, "strace: proc miscount\n");
1924 exit(1);
1925#endif
1926 return 0;
1927 default:
1928 errno = wait_errno;
1929 perror("strace: wait");
1930 return -1;
1931 }
1932 }
1933 if (debug)
1934 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
1935
1936 /* Look up `pid' in our table. */
1937 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001938#ifdef LINUX
1939 if (followfork || followvfork) {
1940 /* This is needed to go with the CLONE_PTRACE
1941 changes in process.c/util.c: we might see
1942 the child's initial trap before we see the
1943 parent return from the clone syscall.
1944 Leave the child suspended until the parent
1945 returns from its system call. Only then
1946 will we have the association of parent and
1947 child so that we know how to do clearbpt
1948 in the child. */
1949 if ((tcp = alloctcb(pid)) == NULL) {
1950 fprintf(stderr, " [tcb table full]\n");
1951 kill(pid, SIGKILL); /* XXX */
1952 return 0;
1953 }
1954 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
1955 newoutf(tcp);
1956 if (!qflag)
1957 fprintf(stderr, "\
1958Process %d attached (waiting for parent)\n",
1959 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001960 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001961 else
1962 /* This can happen if a clone call used
1963 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001964#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001965 {
1966 fprintf(stderr, "unknown pid: %u\n", pid);
1967 if (WIFSTOPPED(status))
1968 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
1969 exit(1);
1970 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001971 }
1972 /* set current output file */
1973 outf = tcp->outf;
1974 if (cflag) {
1975#ifdef LINUX
1976 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
1977 tcp->stime = ru.ru_stime;
1978#endif /* !LINUX */
1979 }
1980
1981 if (tcp->flags & TCB_SUSPENDED) {
1982 /*
1983 * Apparently, doing any ptrace() call on a stopped
1984 * process, provokes the kernel to report the process
1985 * status again on a subsequent wait(), even if the
1986 * process has not been actually restarted.
1987 * Since we have inspected the arguments of suspended
1988 * processes we end up here testing for this case.
1989 */
1990 continue;
1991 }
1992 if (WIFSIGNALED(status)) {
1993 if (!cflag
1994 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
1995 printleader(tcp);
1996 tprintf("+++ killed by %s +++",
Nate Sammonsce780fc1999-03-29 23:23:13 +00001997 signame(WTERMSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001998 printtrailer(tcp);
1999 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002000#ifdef TCB_GROUP_EXITING
2001 handle_group_exit(tcp, -1);
2002#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002003 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002004#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002005 continue;
2006 }
2007 if (WIFEXITED(status)) {
2008 if (debug)
2009 fprintf(stderr, "pid %u exited\n", pid);
2010 if (tcp->flags & TCB_ATTACHED)
2011 fprintf(stderr,
2012 "PANIC: attached pid %u exited\n",
2013 pid);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002014#ifdef TCB_GROUP_EXITING
2015 handle_group_exit(tcp, -1);
2016#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002017 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002018#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002019 continue;
2020 }
2021 if (!WIFSTOPPED(status)) {
2022 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2023 droptcb(tcp);
2024 continue;
2025 }
2026 if (debug)
2027 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002028 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002029
2030 if (tcp->flags & TCB_STARTUP) {
2031 /*
2032 * This flag is there to keep us in sync.
2033 * Next time this process stops it should
2034 * really be entering a system call.
2035 */
2036 tcp->flags &= ~TCB_STARTUP;
2037 if (tcp->flags & TCB_ATTACHED) {
2038 /*
2039 * Interestingly, the process may stop
2040 * with STOPSIG equal to some other signal
2041 * than SIGSTOP if we happend to attach
2042 * just before the process takes a signal.
2043 */
2044 if (!WIFSTOPPED(status)) {
2045 fprintf(stderr,
2046 "pid %u not stopped\n", pid);
2047 detach(tcp, WSTOPSIG(status));
2048 continue;
2049 }
2050 }
2051 else {
2052#ifdef SUNOS4
2053 /* A child of us stopped at exec */
2054 if (WSTOPSIG(status) == SIGTRAP && followvfork)
2055 fixvfork(tcp);
2056#endif /* SUNOS4 */
2057 }
2058 if (tcp->flags & TCB_BPTSET) {
2059 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2060 droptcb(tcp);
2061 cleanup();
2062 return -1;
2063 }
2064 }
2065 goto tracing;
2066 }
2067
2068 if (WSTOPSIG(status) != SIGTRAP) {
2069 if (WSTOPSIG(status) == SIGSTOP &&
2070 (tcp->flags & TCB_SIGTRAPPED)) {
2071 /*
2072 * Trapped attempt to block SIGTRAP
2073 * Hope we are back in control now.
2074 */
2075 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
2076 if (ptrace(PTRACE_SYSCALL,
2077 pid, (char *) 1, 0) < 0) {
2078 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2079 cleanup();
2080 return -1;
2081 }
2082 continue;
2083 }
2084 if (!cflag
2085 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002086 unsigned long addr = 0, pc = 0;
2087#ifdef PT_GETSIGINFO
2088# define PSR_RI 41
2089 struct siginfo si;
2090 unsigned long psr;
2091
2092 upeek(pid, PT_CR_IPSR, &psr);
2093 upeek(pid, PT_CR_IIP, &pc);
2094
2095 pc += (psr >> PSR_RI) & 0x3;
2096 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2097 addr = (unsigned long) si.si_addr;
2098#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002099 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002100 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002101 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002102 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002103 printtrailer(tcp);
2104 }
2105 if ((tcp->flags & TCB_ATTACHED) &&
2106 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002107#ifdef TCB_GROUP_EXITING
2108 handle_group_exit(tcp, WSTOPSIG(status));
2109#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002110 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002111#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002112 continue;
2113 }
2114 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1,
2115 WSTOPSIG(status)) < 0) {
2116 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2117 cleanup();
2118 return -1;
2119 }
2120 tcp->flags &= ~TCB_SUSPENDED;
2121 continue;
2122 }
2123 if (trace_syscall(tcp) < 0) {
2124 if (tcp->flags & TCB_ATTACHED)
2125 detach(tcp, 0);
2126 else {
2127 ptrace(PTRACE_KILL,
2128 tcp->pid, (char *) 1, SIGTERM);
2129 droptcb(tcp);
2130 }
2131 continue;
2132 }
2133 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002134#ifdef TCB_GROUP_EXITING
2135 if (tcp->flags & TCB_GROUP_EXITING) {
2136 if (handle_group_exit(tcp, 0) < 0)
2137 return -1;
2138 continue;
2139 }
2140#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002141 if (tcp->flags & TCB_ATTACHED)
2142 detach(tcp, 0);
2143 else if (ptrace(PTRACE_CONT, pid, (char *) 1, 0) < 0) {
2144 perror("strace: ptrace(PTRACE_CONT, ...)");
2145 cleanup();
2146 return -1;
2147 }
2148 continue;
2149 }
2150 if (tcp->flags & TCB_SUSPENDED) {
2151 if (!qflag)
2152 fprintf(stderr, "Process %u suspended\n", pid);
2153 continue;
2154 }
2155 tracing:
2156 if (ptrace(PTRACE_SYSCALL, pid, (char *) 1, 0) < 0) {
2157 perror("trace: ptrace(PTRACE_SYSCALL, ...)");
2158 cleanup();
2159 return -1;
2160 }
2161 }
2162 return 0;
2163}
2164
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002165#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002166
2167static int curcol;
2168
2169#ifdef __STDC__
2170#include <stdarg.h>
2171#define VA_START(a, b) va_start(a, b)
2172#else
2173#include <varargs.h>
2174#define VA_START(a, b) va_start(a)
2175#endif
2176
2177void
2178#ifdef __STDC__
2179tprintf(const char *fmt, ...)
2180#else
2181tprintf(fmt, va_alist)
2182char *fmt;
2183va_dcl
2184#endif
2185{
2186 va_list args;
2187
2188 VA_START(args, fmt);
2189 if (outf)
2190 curcol += vfprintf(outf, fmt, args);
2191 va_end(args);
2192 return;
2193}
2194
2195void
2196printleader(tcp)
2197struct tcb *tcp;
2198{
2199 if (tcp_last && (!outfname || followfork < 2 || tcp_last == tcp)) {
2200 tcp_last->flags |= TCB_REPRINT;
2201 tprintf(" <unfinished ...>\n");
2202 }
2203 curcol = 0;
2204 if ((followfork == 1 || pflag_seen > 1) && outfname)
2205 tprintf("%-5d ", tcp->pid);
2206 else if (nprocs > 1 && !outfname)
2207 tprintf("[pid %5u] ", tcp->pid);
2208 if (tflag) {
2209 char str[sizeof("HH:MM:SS")];
2210 struct timeval tv, dtv;
2211 static struct timeval otv;
2212
2213 gettimeofday(&tv, NULL);
2214 if (rflag) {
2215 if (otv.tv_sec == 0)
2216 otv = tv;
2217 tv_sub(&dtv, &tv, &otv);
2218 tprintf("%6ld.%06ld ",
2219 (long) dtv.tv_sec, (long) dtv.tv_usec);
2220 otv = tv;
2221 }
2222 else if (tflag > 2) {
2223 tprintf("%ld.%06ld ",
2224 (long) tv.tv_sec, (long) tv.tv_usec);
2225 }
2226 else {
2227 time_t local = tv.tv_sec;
2228 strftime(str, sizeof(str), "%T", localtime(&local));
2229 if (tflag > 1)
2230 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2231 else
2232 tprintf("%s ", str);
2233 }
2234 }
2235 if (iflag)
2236 printcall(tcp);
2237}
2238
2239void
2240tabto(col)
2241int col;
2242{
2243 if (curcol < col)
2244 tprintf("%*s", col - curcol, "");
2245}
2246
2247void
2248printtrailer(tcp)
2249struct tcb *tcp;
2250{
2251 tprintf("\n");
2252 tcp_last = NULL;
2253}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002254
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002255#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002256
2257int mp_ioctl (int fd, int cmd, void *arg, int size) {
2258
2259 struct iovec iov[2];
2260 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002261
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002262 iov[0].iov_base = &cmd;
2263 iov[0].iov_len = sizeof cmd;
2264 if (arg) {
2265 ++n;
2266 iov[1].iov_base = arg;
2267 iov[1].iov_len = size;
2268 }
Roland McGrath553a6092002-12-16 20:40:39 +00002269
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002270 return writev (fd, iov, n);
2271}
2272
2273#endif