blob: 13459d8772c4a1115171ae2c2e3c4a2d1b0cb6bc [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
33#include "defs.h"
34
Roland McGrath795edb12005-02-02 04:44:57 +000035#include <sys/types.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000036#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>
Roland McGrath70b08532004-04-09 00:25:21 +000047#include <dirent.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000048
Roland McGrath134813a2007-06-02 00:07:33 +000049#ifdef LINUX
50# include <asm/unistd.h>
51# if defined __NR_tgkill
52# define my_tgkill(pid, tid, sig) syscall (__NR_tgkill, (pid), (tid), (sig))
53# elif defined __NR_tkill
54# define my_tgkill(pid, tid, sig) syscall (__NR_tkill, (tid), (sig))
55# else
56 /* kill() may choose arbitrarily the target task of the process group
57 while we later wait on a that specific TID. PID process waits become
58 TID task specific waits for a process under ptrace(2). */
59# warning "Neither tkill(2) nor tgkill(2) available, risk of strace hangs!"
60# define my_tgkill(pid, tid, sig) kill ((tid), (sig))
61# endif
62#endif
63
Wichert Akkerman7b3346b2001-10-09 23:47:38 +000064#if defined(IA64) && defined(LINUX)
65# include <asm/ptrace_offsets.h>
66#endif
67
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +000068#ifdef USE_PROCFS
69#include <poll.h>
70#endif
71
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000072#ifdef SVR4
73#include <sys/stropts.h>
Wichert Akkermanea78f0f1999-11-29 15:34:02 +000074#ifdef HAVE_MP_PROCFS
John Hughes1d08dcf2001-07-10 13:48:44 +000075#ifdef HAVE_SYS_UIO_H
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000076#include <sys/uio.h>
77#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000078#endif
John Hughes1d08dcf2001-07-10 13:48:44 +000079#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000080
Roland McGrath41c48222008-07-18 00:25:10 +000081int debug = 0, followfork = 0;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000082int dtime = 0, cflag = 0, xflag = 0, qflag = 0;
83static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000084
Michal Ludvig17f8fb32002-11-06 13:17:21 +000085/* Sometimes we want to print only succeeding syscalls. */
86int not_failing_only = 0;
87
Dmitry V. Levina6809652008-11-10 17:14:58 +000088static int exit_code = 0;
89static int strace_child = 0;
90
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000091static char *username = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000092uid_t run_uid;
93gid_t run_gid;
94
95int acolumn = DEFAULT_ACOLUMN;
96int max_strlen = DEFAULT_STRLEN;
Dmitry V. Levinb9fe0112006-12-13 16:59:44 +000097static char *outfname = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098FILE *outf;
Roland McGrathee9d4352002-12-18 04:16:10 +000099struct tcb **tcbtab;
100unsigned int nprocs, tcbtabsize;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000101char *progname;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000102extern char **environ;
103
Roland McGrath0a463882007-07-05 18:43:16 +0000104static int detach P((struct tcb *tcp, int sig));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000105static int trace P((void));
106static void cleanup P((void));
107static void interrupt P((int sig));
108static sigset_t empty_set, blocked_set;
109
110#ifdef HAVE_SIG_ATOMIC_T
111static volatile sig_atomic_t interrupted;
112#else /* !HAVE_SIG_ATOMIC_T */
113#ifdef __STDC__
114static volatile int interrupted;
115#else /* !__STDC__ */
116static int interrupted;
117#endif /* !__STDC__ */
118#endif /* !HAVE_SIG_ATOMIC_T */
119
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000120#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000121
122static struct tcb *pfd2tcb P((int pfd));
123static void reaper P((int sig));
124static void rebuild_pollv P((void));
Roland McGrathee9d4352002-12-18 04:16:10 +0000125static struct pollfd *pollv;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126
127#ifndef HAVE_POLLABLE_PROCFS
128
129static void proc_poll_open P((void));
130static void proc_poller P((int pfd));
131
132struct proc_pollfd {
133 int fd;
134 int revents;
135 int pid;
136};
137
138static int poller_pid;
139static int proc_poll_pipe[2] = { -1, -1 };
140
141#endif /* !HAVE_POLLABLE_PROCFS */
142
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000143#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000144#define POLLWANT POLLWRNORM
145#else
146#define POLLWANT POLLPRI
147#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000148#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000149
150static void
151usage(ofp, exitval)
152FILE *ofp;
153int exitval;
154{
155 fprintf(ofp, "\
156usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000157 [-p pid] ... [-s strsize] [-u username] [-E var=val] ...\n\
158 [command [arg ...]]\n\
159 or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...\n\
160 [command [arg ...]]\n\
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000161-c -- count time, calls, and errors for each syscall and report summary\n\
162-f -- follow forks, -ff -- with output into separate files\n\
163-F -- attempt to follow vforks, -h -- print help message\n\
164-i -- print instruction pointer at time of syscall\n\
165-q -- suppress messages about attaching, detaching, etc.\n\
166-r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
167-T -- print time spent in each syscall, -V -- print version\n\
168-v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
169-x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
170-a column -- alignment COLUMN for printing syscall results (default %d)\n\
171-e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
172 options: trace, abbrev, verbose, raw, signal, read, or write\n\
173-o file -- send trace output to FILE instead of stderr\n\
174-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
175-p pid -- trace process with process id PID, may be repeated\n\
176-s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
177-S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
178-u username -- run command as username handling setuid and/or setgid\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000179-E var=val -- put var=val in the environment for command\n\
180-E var -- remove var from the environment for command\n\
181" /* this is broken, so don't document it
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000182-z -- print only succeeding syscalls\n\
Roland McGrathde6e5332003-01-24 04:31:23 +0000183 */
184, DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000185 exit(exitval);
186}
187
188#ifdef SVR4
189#ifdef MIPS
190void
191foobar()
192{
193}
194#endif /* MIPS */
195#endif /* SVR4 */
196
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000197static int
198set_cloexec_flag(int fd)
199{
200 int flags, newflags;
201
202 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
203 {
204 fprintf(stderr, "%s: fcntl F_GETFD: %s\n",
205 progname, strerror(errno));
206 return -1;
207 }
208
209 newflags = flags | FD_CLOEXEC;
210 if (flags == newflags)
211 return 0;
212
213 if (fcntl(fd, F_SETFD, newflags) < 0)
214 {
215 fprintf(stderr, "%s: fcntl F_SETFD: %s\n",
216 progname, strerror(errno));
217 return -1;
218 }
219
220 return 0;
221}
222
223/*
224 * When strace is setuid executable, we have to swap uids
225 * before and after filesystem and process management operations.
226 */
227static void
228swap_uid(void)
229{
230#ifndef SVR4
231 int euid = geteuid(), uid = getuid();
232
233 if (euid != uid && setreuid(euid, uid) < 0)
234 {
235 fprintf(stderr, "%s: setreuid: %s\n",
236 progname, strerror(errno));
237 exit(1);
238 }
239#endif
240}
241
Roland McGrath4bfa6262007-07-05 20:03:16 +0000242#if _LFS64_LARGEFILE
243# define fopen_for_output fopen64
244#else
245# define fopen_for_output fopen
246#endif
247
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000248static FILE *
249strace_fopen(const char *path, const char *mode)
250{
251 FILE *fp;
252
253 swap_uid();
Roland McGrath4bfa6262007-07-05 20:03:16 +0000254 if ((fp = fopen_for_output(path, mode)) == NULL)
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000255 fprintf(stderr, "%s: can't fopen '%s': %s\n",
256 progname, path, strerror(errno));
257 swap_uid();
258 if (fp && set_cloexec_flag(fileno(fp)) < 0)
259 {
260 fclose(fp);
261 fp = NULL;
262 }
263 return fp;
264}
265
266static int popen_pid = -1;
267
268#ifndef _PATH_BSHELL
269# define _PATH_BSHELL "/bin/sh"
270#endif
271
272/*
273 * We cannot use standard popen(3) here because we have to distinguish
274 * popen child process from other processes we trace, and standard popen(3)
275 * does not export its child's pid.
276 */
277static FILE *
278strace_popen(const char *command)
279{
280 int fds[2];
281
282 swap_uid();
283 if (pipe(fds) < 0)
284 {
285 fprintf(stderr, "%s: pipe: %s\n",
286 progname, strerror(errno));
287 swap_uid();
288 return NULL;
289 }
290
291 if (set_cloexec_flag(fds[1]) < 0)
292 {
293 close(fds[0]);
294 close(fds[1]);
295 swap_uid();
296 return NULL;
297 }
298
299 if ((popen_pid = fork()) == -1)
300 {
301 fprintf(stderr, "%s: fork: %s\n",
302 progname, strerror(errno));
303 close(fds[0]);
304 close(fds[1]);
305 swap_uid();
306 return NULL;
307 }
308
309 if (popen_pid)
310 {
311 /* parent */
312 close(fds[0]);
313 swap_uid();
314 return fdopen(fds[1], "w");
315 } else
316 {
317 /* child */
318 close(fds[1]);
319 if (fds[0] && (dup2(fds[0], 0) || close(fds[0])))
320 {
321 fprintf(stderr, "%s: dup2: %s\n",
322 progname, strerror(errno));
323 _exit(1);
324 }
325 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
326 fprintf(stderr, "%s: execl: %s: %s\n",
327 progname, _PATH_BSHELL, strerror(errno));
328 _exit(1);
329 }
330}
331
332static int
333newoutf(struct tcb *tcp)
334{
335 if (outfname && followfork > 1) {
336 char name[MAXPATHLEN];
337 FILE *fp;
338
339 sprintf(name, "%s.%u", outfname, tcp->pid);
340 if ((fp = strace_fopen(name, "w")) == NULL)
341 return -1;
342 tcp->outf = fp;
343 }
344 return 0;
345}
346
Roland McGrath02203312007-06-11 22:06:31 +0000347static void
348startup_attach(void)
349{
350 int tcbi;
351 struct tcb *tcp;
352
353 /*
354 * Block user interruptions as we would leave the traced
355 * process stopped (process state T) if we would terminate in
356 * between PTRACE_ATTACH and wait4 () on SIGSTOP.
357 * We rely on cleanup () from this point on.
358 */
359 if (interactive)
360 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
361
362 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
363 tcp = tcbtab[tcbi];
364 if (!(tcp->flags & TCB_INUSE) || !(tcp->flags & TCB_ATTACHED))
365 continue;
366#ifdef LINUX
367 if (tcp->flags & TCB_CLONE_THREAD)
368 continue;
369#endif
370 /* Reinitialize the output since it may have changed. */
371 tcp->outf = outf;
372 if (newoutf(tcp) < 0)
373 exit(1);
374
375#ifdef USE_PROCFS
376 if (proc_open(tcp, 1) < 0) {
377 fprintf(stderr, "trouble opening proc file\n");
378 droptcb(tcp);
379 continue;
380 }
381#else /* !USE_PROCFS */
382# ifdef LINUX
383 if (followfork) {
384 char procdir[MAXPATHLEN];
385 DIR *dir;
386
387 sprintf(procdir, "/proc/%d/task", tcp->pid);
388 dir = opendir(procdir);
389 if (dir != NULL) {
390 unsigned int ntid = 0, nerr = 0;
391 struct dirent *de;
392 int tid;
393 while ((de = readdir(dir)) != NULL) {
394 if (de->d_fileno == 0 ||
395 de->d_name[0] == '.')
396 continue;
397 tid = atoi(de->d_name);
398 if (tid <= 0)
399 continue;
400 ++ntid;
401 if (ptrace(PTRACE_ATTACH, tid,
402 (char *) 1, 0) < 0)
403 ++nerr;
404 else if (tid != tcbtab[tcbi]->pid) {
405 if (nprocs == tcbtabsize &&
406 expand_tcbtab())
407 tcp = NULL;
408 else
409 tcp = alloctcb(tid);
410 if (tcp == NULL)
411 exit(1);
412 tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK;
413 tcbtab[tcbi]->nchildren++;
414 tcbtab[tcbi]->nclone_threads++;
415 tcbtab[tcbi]->nclone_detached++;
416 tcp->parent = tcbtab[tcbi];
417 }
418 if (interactive) {
419 sigprocmask(SIG_SETMASK, &empty_set, NULL);
420 if (interrupted)
421 return;
422 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
423 }
424 }
425 closedir(dir);
426 if (nerr == ntid) {
427 perror("attach: ptrace(PTRACE_ATTACH, ...)");
428 droptcb(tcp);
429 continue;
430 }
431 if (!qflag) {
432 ntid -= nerr;
433 if (ntid > 1)
434 fprintf(stderr, "\
435Process %u attached with %u threads - interrupt to quit\n",
436 tcp->pid, ntid);
437 else
438 fprintf(stderr, "\
439Process %u attached - interrupt to quit\n",
440 tcp->pid);
441 }
442 continue;
443 }
444 }
445# endif
446 if (ptrace(PTRACE_ATTACH, tcp->pid, (char *) 1, 0) < 0) {
447 perror("attach: ptrace(PTRACE_ATTACH, ...)");
448 droptcb(tcp);
449 continue;
450 }
451 /* INTERRUPTED is going to be checked at the top of TRACE. */
452#endif /* !USE_PROCFS */
453 if (!qflag)
454 fprintf(stderr,
455 "Process %u attached - interrupt to quit\n",
456 tcp->pid);
457 }
458
459 if (interactive)
460 sigprocmask(SIG_SETMASK, &empty_set, NULL);
461}
462
463static void
464startup_child (char **argv)
465{
466 struct stat statbuf;
467 const char *filename;
468 char pathname[MAXPATHLEN];
469 int pid = 0;
470 struct tcb *tcp;
471
472 filename = argv[0];
473 if (strchr(filename, '/')) {
474 if (strlen(filename) > sizeof pathname - 1) {
475 errno = ENAMETOOLONG;
476 perror("strace: exec");
477 exit(1);
478 }
479 strcpy(pathname, filename);
480 }
481#ifdef USE_DEBUGGING_EXEC
482 /*
483 * Debuggers customarily check the current directory
484 * first regardless of the path but doing that gives
485 * security geeks a panic attack.
486 */
487 else if (stat(filename, &statbuf) == 0)
488 strcpy(pathname, filename);
489#endif /* USE_DEBUGGING_EXEC */
490 else {
491 char *path;
492 int m, n, len;
493
494 for (path = getenv("PATH"); path && *path; path += m) {
495 if (strchr(path, ':')) {
496 n = strchr(path, ':') - path;
497 m = n + 1;
498 }
499 else
500 m = n = strlen(path);
501 if (n == 0) {
502 if (!getcwd(pathname, MAXPATHLEN))
503 continue;
504 len = strlen(pathname);
505 }
506 else if (n > sizeof pathname - 1)
507 continue;
508 else {
509 strncpy(pathname, path, n);
510 len = n;
511 }
512 if (len && pathname[len - 1] != '/')
513 pathname[len++] = '/';
514 strcpy(pathname + len, filename);
515 if (stat(pathname, &statbuf) == 0 &&
516 /* Accept only regular files
517 with some execute bits set.
518 XXX not perfect, might still fail */
519 S_ISREG(statbuf.st_mode) &&
520 (statbuf.st_mode & 0111))
521 break;
522 }
523 }
524 if (stat(pathname, &statbuf) < 0) {
525 fprintf(stderr, "%s: %s: command not found\n",
526 progname, filename);
527 exit(1);
528 }
Dmitry V. Levina6809652008-11-10 17:14:58 +0000529 strace_child = pid = fork();
530 switch (pid) {
Roland McGrath02203312007-06-11 22:06:31 +0000531 case -1:
532 perror("strace: fork");
533 cleanup();
534 exit(1);
535 break;
536 case 0: {
537#ifdef USE_PROCFS
538 if (outf != stderr) close (fileno (outf));
539#ifdef MIPS
540 /* Kludge for SGI, see proc_open for details. */
541 sa.sa_handler = foobar;
542 sa.sa_flags = 0;
543 sigemptyset(&sa.sa_mask);
544 sigaction(SIGINT, &sa, NULL);
545#endif /* MIPS */
546#ifndef FREEBSD
547 pause();
548#else /* FREEBSD */
549 kill(getpid(), SIGSTOP); /* stop HERE */
550#endif /* FREEBSD */
551#else /* !USE_PROCFS */
552 if (outf!=stderr)
553 close(fileno (outf));
554
555 if (ptrace(PTRACE_TRACEME, 0, (char *) 1, 0) < 0) {
556 perror("strace: ptrace(PTRACE_TRACEME, ...)");
557 exit(1);
558 }
559 if (debug)
560 kill(getpid(), SIGSTOP);
561
562 if (username != NULL || geteuid() == 0) {
563 uid_t run_euid = run_uid;
564 gid_t run_egid = run_gid;
565
566 if (statbuf.st_mode & S_ISUID)
567 run_euid = statbuf.st_uid;
568 if (statbuf.st_mode & S_ISGID)
569 run_egid = statbuf.st_gid;
570
571 /*
572 * It is important to set groups before we
573 * lose privileges on setuid.
574 */
575 if (username != NULL) {
576 if (initgroups(username, run_gid) < 0) {
577 perror("initgroups");
578 exit(1);
579 }
580 if (setregid(run_gid, run_egid) < 0) {
581 perror("setregid");
582 exit(1);
583 }
584 if (setreuid(run_uid, run_euid) < 0) {
585 perror("setreuid");
586 exit(1);
587 }
588 }
589 }
590 else
591 setreuid(run_uid, run_uid);
592
593 /*
594 * Induce an immediate stop so that the parent
595 * will resume us with PTRACE_SYSCALL and display
596 * this execve call normally.
597 */
598 kill(getpid(), SIGSTOP);
599#endif /* !USE_PROCFS */
600
601 execv(pathname, argv);
602 perror("strace: exec");
603 _exit(1);
604 break;
605 }
606 default:
607 if ((tcp = alloctcb(pid)) == NULL) {
608 cleanup();
609 exit(1);
610 }
611#ifdef USE_PROCFS
612 if (proc_open(tcp, 0) < 0) {
613 fprintf(stderr, "trouble opening proc file\n");
614 cleanup();
615 exit(1);
616 }
617#endif /* USE_PROCFS */
618 break;
619 }
620}
621
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000622int
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000623main(int argc, char *argv[])
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000624{
625 extern int optind;
626 extern char *optarg;
627 struct tcb *tcp;
628 int c, pid = 0;
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000629 int optF = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630 struct sigaction sa;
631
632 static char buf[BUFSIZ];
633
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000634 progname = argv[0] ? argv[0] : "strace";
635
Roland McGrathee9d4352002-12-18 04:16:10 +0000636 /* Allocate the initial tcbtab. */
637 tcbtabsize = argc; /* Surely enough for all -p args. */
Dmitry V. Levin08b623e2007-10-08 21:04:41 +0000638 if ((tcbtab = calloc (tcbtabsize, sizeof tcbtab[0])) == NULL) {
639 fprintf(stderr, "%s: out of memory\n", progname);
640 exit(1);
641 }
642 if ((tcbtab[0] = calloc (tcbtabsize, sizeof tcbtab[0][0])) == NULL) {
643 fprintf(stderr, "%s: out of memory\n", progname);
644 exit(1);
645 }
Roland McGrathee9d4352002-12-18 04:16:10 +0000646 for (tcp = tcbtab[0]; tcp < &tcbtab[0][tcbtabsize]; ++tcp)
647 tcbtab[tcp - tcbtab[0]] = &tcbtab[0][tcp - tcbtab[0]];
648
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000649 outf = stderr;
650 interactive = 1;
Roland McGrath138c6a32006-01-12 09:50:49 +0000651 set_sortby(DEFAULT_SORTBY);
652 set_personality(DEFAULT_PERSONALITY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000653 qualify("trace=all");
654 qualify("abbrev=all");
655 qualify("verbose=all");
656 qualify("signal=all");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000657 while ((c = getopt(argc, argv,
Roland McGrathde6e5332003-01-24 04:31:23 +0000658 "+cdfFhiqrtTvVxza:e:o:O:p:s:S:u:E:")) != EOF) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000659 switch (c) {
660 case 'c':
661 cflag++;
662 dtime++;
663 break;
664 case 'd':
665 debug++;
666 break;
Roland McGrath41c48222008-07-18 00:25:10 +0000667 case 'F':
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000668 optF = 1;
669 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000670 case 'f':
671 followfork++;
672 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000673 case 'h':
674 usage(stdout, 0);
675 break;
676 case 'i':
677 iflag++;
678 break;
679 case 'q':
680 qflag++;
681 break;
682 case 'r':
683 rflag++;
684 tflag++;
685 break;
686 case 't':
687 tflag++;
688 break;
689 case 'T':
690 dtime++;
691 break;
692 case 'x':
693 xflag++;
694 break;
695 case 'v':
696 qualify("abbrev=none");
697 break;
698 case 'V':
Roland McGrath9c9a2532003-02-20 02:56:29 +0000699 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000700 exit(0);
701 break;
Michal Ludvig17f8fb32002-11-06 13:17:21 +0000702 case 'z':
703 not_failing_only = 1;
704 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000705 case 'a':
706 acolumn = atoi(optarg);
707 break;
708 case 'e':
709 qualify(optarg);
710 break;
711 case 'o':
712 outfname = strdup(optarg);
713 break;
714 case 'O':
715 set_overhead(atoi(optarg));
716 break;
717 case 'p':
Roland McGrathde6e5332003-01-24 04:31:23 +0000718 if ((pid = atoi(optarg)) <= 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000719 fprintf(stderr, "%s: Invalid process id: %s\n",
720 progname, optarg);
721 break;
722 }
723 if (pid == getpid()) {
Wichert Akkerman54a47671999-10-17 00:57:34 +0000724 fprintf(stderr, "%s: I'm sorry, I can't let you do that, Dave.\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000725 break;
726 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000727 if ((tcp = alloc_tcb(pid, 0)) == NULL) {
Roland McGrathde6e5332003-01-24 04:31:23 +0000728 fprintf(stderr, "%s: out of memory\n",
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000729 progname);
730 exit(1);
731 }
732 tcp->flags |= TCB_ATTACHED;
733 pflag_seen++;
734 break;
735 case 's':
736 max_strlen = atoi(optarg);
Roland McGrathdccec722005-05-09 07:45:47 +0000737 if (max_strlen < 0) {
738 fprintf(stderr,
739 "%s: invalid -s argument: %s\n",
740 progname, optarg);
741 exit(1);
742 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000743 break;
744 case 'S':
745 set_sortby(optarg);
746 break;
747 case 'u':
748 username = strdup(optarg);
749 break;
Roland McGrathde6e5332003-01-24 04:31:23 +0000750 case 'E':
751 if (putenv(optarg) < 0) {
752 fprintf(stderr, "%s: out of memory\n",
753 progname);
754 exit(1);
755 }
756 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757 default:
758 usage(stderr, 1);
759 break;
760 }
761 }
762
Roland McGrathd0c4c0c2006-04-25 07:39:40 +0000763 if ((optind == argc) == !pflag_seen)
Roland McGrathce0d1542003-11-11 21:24:23 +0000764 usage(stderr, 1);
765
Dmitry V. Levin06350db2008-07-25 15:42:34 +0000766 if (!followfork)
767 followfork = optF;
768
Roland McGrathcb9def62006-04-25 07:48:03 +0000769 if (followfork > 1 && cflag) {
770 fprintf(stderr,
771 "%s: -c and -ff are mutually exclusive options\n",
772 progname);
773 exit(1);
774 }
775
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776 /* See if they want to run as another user. */
777 if (username != NULL) {
778 struct passwd *pent;
779
780 if (getuid() != 0 || geteuid() != 0) {
781 fprintf(stderr,
782 "%s: you must be root to use the -u option\n",
783 progname);
784 exit(1);
785 }
786 if ((pent = getpwnam(username)) == NULL) {
787 fprintf(stderr, "%s: cannot find user `%s'\n",
Roland McGrath09553f82007-07-05 19:31:49 +0000788 progname, username);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789 exit(1);
790 }
791 run_uid = pent->pw_uid;
792 run_gid = pent->pw_gid;
793 }
794 else {
795 run_uid = getuid();
796 run_gid = getgid();
797 }
798
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799 /* Check if they want to redirect the output. */
800 if (outfname) {
Roland McGrath37b9a662003-11-07 02:26:54 +0000801 /* See if they want to pipe the output. */
802 if (outfname[0] == '|' || outfname[0] == '!') {
803 /*
804 * We can't do the <outfname>.PID funny business
805 * when using popen, so prohibit it.
806 */
807 if (followfork > 1) {
808 fprintf(stderr, "\
809%s: piping the output and -ff are mutually exclusive options\n",
810 progname);
811 exit(1);
812 }
813
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000814 if ((outf = strace_popen(outfname + 1)) == NULL)
Roland McGrath37b9a662003-11-07 02:26:54 +0000815 exit(1);
Roland McGrath37b9a662003-11-07 02:26:54 +0000816 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000817 else if (followfork <= 1 &&
818 (outf = strace_fopen(outfname, "w")) == NULL)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000819 exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000820 }
821
Roland McGrath37b9a662003-11-07 02:26:54 +0000822 if (!outfname || outfname[0] == '|' || outfname[0] == '!')
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000823 setvbuf(outf, buf, _IOLBF, BUFSIZ);
Roland McGrath37b9a662003-11-07 02:26:54 +0000824 if (outfname && optind < argc) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000825 interactive = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000826 qflag = 1;
Roland McGrath36931052003-06-03 01:35:20 +0000827 }
Roland McGrath54cc1c82007-11-03 23:34:11 +0000828 /* Valid states here:
829 optind < argc pflag_seen outfname interactive
830 1 0 0 1
831 0 1 0 1
832 1 0 1 0
833 0 1 1 1
834 */
835
836 /* STARTUP_CHILD must be called before the signal handlers get
837 installed below as they are inherited into the spawned process.
838 Also we do not need to be protected by them as during interruption
839 in the STARTUP_CHILD mode we kill the spawned process anyway. */
840 if (!pflag_seen)
841 startup_child(&argv[optind]);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000842
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000843 sigemptyset(&empty_set);
844 sigemptyset(&blocked_set);
845 sa.sa_handler = SIG_IGN;
846 sigemptyset(&sa.sa_mask);
847 sa.sa_flags = 0;
848 sigaction(SIGTTOU, &sa, NULL);
849 sigaction(SIGTTIN, &sa, NULL);
850 if (interactive) {
851 sigaddset(&blocked_set, SIGHUP);
852 sigaddset(&blocked_set, SIGINT);
853 sigaddset(&blocked_set, SIGQUIT);
854 sigaddset(&blocked_set, SIGPIPE);
855 sigaddset(&blocked_set, SIGTERM);
856 sa.sa_handler = interrupt;
857#ifdef SUNOS4
858 /* POSIX signals on sunos4.1 are a little broken. */
859 sa.sa_flags = SA_INTERRUPT;
860#endif /* SUNOS4 */
861 }
862 sigaction(SIGHUP, &sa, NULL);
863 sigaction(SIGINT, &sa, NULL);
864 sigaction(SIGQUIT, &sa, NULL);
865 sigaction(SIGPIPE, &sa, NULL);
866 sigaction(SIGTERM, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000867#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000868 sa.sa_handler = reaper;
869 sigaction(SIGCHLD, &sa, NULL);
Roland McGrath553a6092002-12-16 20:40:39 +0000870#else
871 /* Make sure SIGCHLD has the default action so that waitpid
872 definitely works without losing track of children. The user
873 should not have given us a bogus state to inherit, but he might
874 have. Arguably we should detect SIG_IGN here and pass it on
875 to children, but probably noone really needs that. */
876 sa.sa_handler = SIG_DFL;
877 sigaction(SIGCHLD, &sa, NULL);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000878#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000879
Roland McGrath02203312007-06-11 22:06:31 +0000880 if (pflag_seen)
881 startup_attach();
Roland McGrath02203312007-06-11 22:06:31 +0000882
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883 if (trace() < 0)
884 exit(1);
885 cleanup();
Dmitry V. Levina6809652008-11-10 17:14:58 +0000886 fflush(NULL);
887 if (exit_code > 0xff) {
888 /* Child was killed by a signal, mimic that. */
889 exit_code &= 0xff;
890 signal(exit_code, SIG_DFL);
891 raise(exit_code);
892 /* Paranoia - what if this signal is not fatal?
893 Exit with 128 + signo then. */
894 exit_code += 128;
895 }
896 exit(exit_code);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000897}
898
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000899int
900expand_tcbtab()
901{
902 /* Allocate some more TCBs and expand the table.
903 We don't want to relocate the TCBs because our
904 callers have pointers and it would be a pain.
905 So tcbtab is a table of pointers. Since we never
906 free the TCBs, we allocate a single chunk of many. */
907 struct tcb **newtab = (struct tcb **)
908 realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
909 struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
910 sizeof *newtcbs);
911 int i;
912 if (newtab == NULL || newtcbs == NULL) {
913 if (newtab != NULL)
914 free(newtab);
Dmitry V. Levin76860f62006-10-11 22:55:25 +0000915 fprintf(stderr, "%s: expand_tcbtab: out of memory\n",
916 progname);
Roland McGrath7b54a7a2004-06-04 01:50:45 +0000917 return 1;
918 }
919 for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
920 newtab[i] = &newtcbs[i - tcbtabsize];
921 tcbtabsize *= 2;
922 tcbtab = newtab;
923
924 return 0;
925}
926
927
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000928struct tcb *
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000929alloc_tcb(int pid, int command_options_parsed)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000930{
931 int i;
932 struct tcb *tcp;
933
Roland McGrathee9d4352002-12-18 04:16:10 +0000934 for (i = 0; i < tcbtabsize; i++) {
935 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000936 if ((tcp->flags & TCB_INUSE) == 0) {
937 tcp->pid = pid;
938 tcp->parent = NULL;
939 tcp->nchildren = 0;
Roland McGrath09623452003-05-23 02:27:13 +0000940 tcp->nzombies = 0;
Roland McGrathe85bbfe2003-01-09 06:53:31 +0000941#ifdef TCB_CLONE_THREAD
942 tcp->nclone_threads = tcp->nclone_detached = 0;
943 tcp->nclone_waiting = 0;
944#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000945 tcp->flags = TCB_INUSE | TCB_STARTUP;
946 tcp->outf = outf; /* Initialise to current out file */
947 tcp->stime.tv_sec = 0;
948 tcp->stime.tv_usec = 0;
949 tcp->pfd = -1;
950 nprocs++;
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000951 if (command_options_parsed)
952 newoutf(tcp);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000953 return tcp;
954 }
955 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000956 fprintf(stderr, "%s: alloc_tcb: tcb table full\n", progname);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000957 return NULL;
958}
959
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000960#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000961int
962proc_open(tcp, attaching)
963struct tcb *tcp;
964int attaching;
965{
966 char proc[32];
967 long arg;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000968#ifdef SVR4
John Hughes19e49982001-10-19 08:59:12 +0000969 int i;
970 sysset_t syscalls;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000971 sigset_t signals;
972 fltset_t faults;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000973#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974#ifndef HAVE_POLLABLE_PROCFS
975 static int last_pfd;
976#endif
977
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000978#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000979 /* Open the process pseudo-files in /proc. */
980 sprintf(proc, "/proc/%d/ctl", tcp->pid);
981 if ((tcp->pfd = open(proc, O_WRONLY|O_EXCL)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000982 perror("strace: open(\"/proc/...\", ...)");
983 return -1;
984 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000985 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 return -1;
987 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000988 sprintf(proc, "/proc/%d/status", tcp->pid);
989 if ((tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL)) < 0) {
990 perror("strace: open(\"/proc/...\", ...)");
991 return -1;
992 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +0000993 if (set_cloexec_flag(tcp->pfd_stat) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000994 return -1;
995 }
996 sprintf(proc, "/proc/%d/as", tcp->pid);
997 if ((tcp->pfd_as = open(proc, O_RDONLY|O_EXCL)) < 0) {
998 perror("strace: open(\"/proc/...\", ...)");
999 return -1;
1000 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001001 if (set_cloexec_flag(tcp->pfd_as) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001002 return -1;
1003 }
1004#else
1005 /* Open the process pseudo-file in /proc. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001006#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001007 sprintf(proc, "/proc/%d", tcp->pid);
1008 if ((tcp->pfd = open(proc, O_RDWR|O_EXCL)) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001009#else /* FREEBSD */
1010 sprintf(proc, "/proc/%d/mem", tcp->pid);
1011 if ((tcp->pfd = open(proc, O_RDWR)) < 0) {
1012#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001013 perror("strace: open(\"/proc/...\", ...)");
1014 return -1;
1015 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001016 if (set_cloexec_flag(tcp->pfd) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001017 return -1;
1018 }
1019#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001020#ifdef FREEBSD
1021 sprintf(proc, "/proc/%d/regs", tcp->pid);
1022 if ((tcp->pfd_reg = open(proc, O_RDONLY)) < 0) {
1023 perror("strace: open(\"/proc/.../regs\", ...)");
1024 return -1;
1025 }
1026 if (cflag) {
1027 sprintf(proc, "/proc/%d/status", tcp->pid);
1028 if ((tcp->pfd_status = open(proc, O_RDONLY)) < 0) {
1029 perror("strace: open(\"/proc/.../status\", ...)");
1030 return -1;
1031 }
1032 } else
1033 tcp->pfd_status = -1;
1034#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001035 rebuild_pollv();
1036 if (!attaching) {
1037 /*
1038 * Wait for the child to pause. Because of a race
1039 * condition we have to poll for the event.
1040 */
1041 for (;;) {
1042 if (IOCTL_STATUS (tcp) < 0) {
1043 perror("strace: PIOCSTATUS");
1044 return -1;
1045 }
1046 if (tcp->status.PR_FLAGS & PR_ASLEEP)
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001047 break;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001048 }
1049 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001050#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001051 /* Stop the process so that we own the stop. */
Wichert Akkerman16a03d22000-08-10 02:14:04 +00001052 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001053 perror("strace: PIOCSTOP");
1054 return -1;
1055 }
Roland McGrath553a6092002-12-16 20:40:39 +00001056#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001057#ifdef PIOCSET
1058 /* Set Run-on-Last-Close. */
1059 arg = PR_RLC;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001060 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061 perror("PIOCSET PR_RLC");
1062 return -1;
1063 }
1064 /* Set or Reset Inherit-on-Fork. */
1065 arg = PR_FORK;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001066 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067 perror("PIOC{SET,RESET} PR_FORK");
1068 return -1;
1069 }
1070#else /* !PIOCSET */
Roland McGrath553a6092002-12-16 20:40:39 +00001071#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001072 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1073 perror("PIOCSRLC");
1074 return -1;
1075 }
1076 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1077 perror("PIOC{S,R}FORK");
1078 return -1;
1079 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001080#else /* FREEBSD */
1081 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1082 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1083 perror("PIOCGFL");
1084 return -1;
1085 }
1086 arg &= ~PF_LINGER;
1087 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
1088 perror("PIOCSFL");
1089 return -1;
1090 }
1091#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001092#endif /* !PIOCSET */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001093#ifndef FREEBSD
John Hughes19e49982001-10-19 08:59:12 +00001094 /* Enable all syscall entries we care about. */
1095 premptyset(&syscalls);
1096 for (i = 1; i < MAX_QUALS; ++i) {
1097 if (i > (sizeof syscalls) * CHAR_BIT) break;
1098 if (qual_flags [i] & QUAL_TRACE) praddset (&syscalls, i);
1099 }
1100 praddset (&syscalls, SYS_execve);
1101 if (followfork) {
1102 praddset (&syscalls, SYS_fork);
1103#ifdef SYS_forkall
1104 praddset (&syscalls, SYS_forkall);
1105#endif
Roland McGrath553a6092002-12-16 20:40:39 +00001106#ifdef SYS_fork1
John Hughes19e49982001-10-19 08:59:12 +00001107 praddset (&syscalls, SYS_fork1);
1108#endif
1109#ifdef SYS_rfork1
1110 praddset (&syscalls, SYS_rfork1);
1111#endif
1112#ifdef SYS_rforkall
1113 praddset (&syscalls, SYS_rforkall);
1114#endif
1115 }
1116 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001117 perror("PIOCSENTRY");
1118 return -1;
1119 }
John Hughes19e49982001-10-19 08:59:12 +00001120 /* Enable the syscall exits. */
1121 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 perror("PIOSEXIT");
1123 return -1;
1124 }
John Hughes19e49982001-10-19 08:59:12 +00001125 /* Enable signals we care about. */
1126 premptyset(&signals);
1127 for (i = 1; i < MAX_QUALS; ++i) {
1128 if (i > (sizeof signals) * CHAR_BIT) break;
1129 if (qual_flags [i] & QUAL_SIGNAL) praddset (&signals, i);
1130 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001131 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132 perror("PIOCSTRACE");
1133 return -1;
1134 }
John Hughes19e49982001-10-19 08:59:12 +00001135 /* Enable faults we care about */
1136 premptyset(&faults);
1137 for (i = 1; i < MAX_QUALS; ++i) {
1138 if (i > (sizeof faults) * CHAR_BIT) break;
1139 if (qual_flags [i] & QUAL_FAULT) praddset (&faults, i);
1140 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001141 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001142 perror("PIOCSFAULT");
1143 return -1;
1144 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001145#else /* FREEBSD */
1146 /* set events flags. */
1147 arg = S_SIG | S_SCE | S_SCX ;
1148 if(ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1149 perror("PIOCBIS");
1150 return -1;
1151 }
1152#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153 if (!attaching) {
1154#ifdef MIPS
1155 /*
1156 * The SGI PRSABORT doesn't work for pause() so
1157 * we send it a caught signal to wake it up.
1158 */
1159 kill(tcp->pid, SIGINT);
1160#else /* !MIPS */
Roland McGrath553a6092002-12-16 20:40:39 +00001161#ifdef PRSABORT
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001162 /* The child is in a pause(), abort it. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001163 arg = PRSABORT;
1164 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165 perror("PIOCRUN");
1166 return -1;
1167 }
Roland McGrath553a6092002-12-16 20:40:39 +00001168#endif
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001169#endif /* !MIPS*/
1170#ifdef FREEBSD
1171 /* wake up the child if it received the SIGSTOP */
1172 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001173#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001174 for (;;) {
1175 /* Wait for the child to do something. */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001176 if (IOCTL_WSTOP (tcp) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001177 perror("PIOCWSTOP");
1178 return -1;
1179 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001180 if (tcp->status.PR_WHY == PR_SYSENTRY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001181 tcp->flags &= ~TCB_INSYSCALL;
1182 get_scno(tcp);
Roland McGrath76989d72005-06-07 23:21:31 +00001183 if (known_scno(tcp) == SYS_execve)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001184 break;
1185 }
1186 /* Set it running: maybe execve will be next. */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001187#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001188 arg = 0;
1189 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001190#else /* FREEBSD */
1191 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00001192#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193 perror("PIOCRUN");
1194 return -1;
1195 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001196#ifdef FREEBSD
1197 /* handle the case where we "opened" the child before
1198 it did the kill -STOP */
1199 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1200 tcp->status.PR_WHAT == SIGSTOP)
1201 kill(tcp->pid, SIGCONT);
Roland McGrath553a6092002-12-16 20:40:39 +00001202#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001204#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001205 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001206#else /* FREEBSD */
1207 } else {
Roland McGrath553a6092002-12-16 20:40:39 +00001208 if (attaching < 2) {
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001209 /* We are attaching to an already running process.
1210 * Try to figure out the state of the process in syscalls,
1211 * to handle the first event well.
1212 * This is done by having a look at the "wchan" property of the
1213 * process, which tells where it is stopped (if it is). */
1214 FILE * status;
1215 char wchan[20]; /* should be enough */
Roland McGrath553a6092002-12-16 20:40:39 +00001216
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00001217 sprintf(proc, "/proc/%d/status", tcp->pid);
1218 status = fopen(proc, "r");
1219 if (status &&
1220 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1221 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1222 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1223 strcmp(wchan, "stopevent")) {
1224 /* The process is asleep in the middle of a syscall.
1225 Fake the syscall entry event */
1226 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1227 tcp->status.PR_WHY = PR_SYSENTRY;
1228 trace_syscall(tcp);
1229 }
1230 if (status)
1231 fclose(status);
1232 } /* otherwise it's a fork being followed */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001233 }
1234#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235#ifndef HAVE_POLLABLE_PROCFS
1236 if (proc_poll_pipe[0] != -1)
1237 proc_poller(tcp->pfd);
1238 else if (nprocs > 1) {
1239 proc_poll_open();
1240 proc_poller(last_pfd);
1241 proc_poller(tcp->pfd);
1242 }
1243 last_pfd = tcp->pfd;
1244#endif /* !HAVE_POLLABLE_PROCFS */
1245 return 0;
1246}
1247
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001248#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001249
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001250struct tcb *
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251pid2tcb(pid)
1252int pid;
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 (pid && tcp->pid != pid)
1260 continue;
1261 if (tcp->flags & TCB_INUSE)
1262 return tcp;
1263 }
1264 return NULL;
1265}
1266
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001267#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001268
1269static struct tcb *
1270pfd2tcb(pfd)
1271int pfd;
1272{
1273 int i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001274
Roland McGrathca16be82003-01-10 19:55:28 +00001275 for (i = 0; i < tcbtabsize; i++) {
1276 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001277 if (tcp->pfd != pfd)
1278 continue;
1279 if (tcp->flags & TCB_INUSE)
1280 return tcp;
1281 }
1282 return NULL;
1283}
1284
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001285#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286
1287void
1288droptcb(tcp)
1289struct tcb *tcp;
1290{
1291 if (tcp->pid == 0)
1292 return;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001293#ifdef TCB_CLONE_THREAD
1294 if (tcp->nclone_threads > 0) {
1295 /* There are other threads left in this process, but this
1296 is the one whose PID represents the whole process.
1297 We need to keep this record around as a zombie until
1298 all the threads die. */
1299 tcp->flags |= TCB_EXITING;
1300 return;
1301 }
1302#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001303 nprocs--;
1304 tcp->pid = 0;
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001305
Roland McGrathe29341c2003-01-10 20:14:20 +00001306 if (tcp->parent != NULL) {
1307 tcp->parent->nchildren--;
1308#ifdef TCB_CLONE_THREAD
1309 if (tcp->flags & TCB_CLONE_DETACHED)
1310 tcp->parent->nclone_detached--;
1311 if (tcp->flags & TCB_CLONE_THREAD)
1312 tcp->parent->nclone_threads--;
1313#endif
Roland McGrath09623452003-05-23 02:27:13 +00001314#ifdef TCB_CLONE_DETACHED
1315 if (!(tcp->flags & TCB_CLONE_DETACHED))
1316#endif
1317 tcp->parent->nzombies++;
Roland McGrath276ceb32007-11-13 08:12:12 +00001318#ifdef LINUX
1319 /* Update `tcp->parent->parent->nchildren' and the other fields
1320 like NCLONE_DETACHED, only for zombie group leader that has
1321 already reported and been short-circuited at the top of this
1322 function. The same condition as at the top of DETACH. */
1323 if ((tcp->flags & TCB_CLONE_THREAD) &&
1324 tcp->parent->nclone_threads == 0 &&
1325 (tcp->parent->flags & TCB_EXITING))
1326 droptcb(tcp->parent);
1327#endif
Roland McGrathe29341c2003-01-10 20:14:20 +00001328 tcp->parent = NULL;
1329 }
1330
1331 tcp->flags = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001332 if (tcp->pfd != -1) {
1333 close(tcp->pfd);
1334 tcp->pfd = -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001335#ifdef FREEBSD
1336 if (tcp->pfd_reg != -1) {
1337 close(tcp->pfd_reg);
1338 tcp->pfd_reg = -1;
1339 }
1340 if (tcp->pfd_status != -1) {
1341 close(tcp->pfd_status);
1342 tcp->pfd_status = -1;
1343 }
Roland McGrath553a6092002-12-16 20:40:39 +00001344#endif /* !FREEBSD */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001345#ifdef USE_PROCFS
Roland McGrathe29341c2003-01-10 20:14:20 +00001346 rebuild_pollv(); /* Note, flags needs to be cleared by now. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001347#endif
1348 }
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001349
Wichert Akkerman822f0c92002-04-03 10:55:14 +00001350 if (outfname && followfork > 1 && tcp->outf)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001351 fclose(tcp->outf);
Wichert Akkermaneb8ebda2002-04-01 17:48:02 +00001352
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001353 tcp->outf = 0;
1354}
1355
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001356#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001357
1358static int
1359resume(tcp)
1360struct tcb *tcp;
1361{
1362 if (tcp == NULL)
1363 return -1;
1364
1365 if (!(tcp->flags & TCB_SUSPENDED)) {
1366 fprintf(stderr, "PANIC: pid %u not suspended\n", tcp->pid);
1367 return -1;
1368 }
1369 tcp->flags &= ~TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001370#ifdef TCB_CLONE_THREAD
1371 if (tcp->flags & TCB_CLONE_THREAD)
1372 tcp->parent->nclone_waiting--;
1373#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001375 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001377
1378 if (!qflag)
1379 fprintf(stderr, "Process %u resumed\n", tcp->pid);
1380 return 0;
1381}
1382
Roland McGrath1bfd3102007-08-03 10:02:00 +00001383static int
1384resume_from_tcp (struct tcb *tcp)
1385{
1386 int error = 0;
1387 int resumed = 0;
1388
1389 /* XXX This won't always be quite right (but it never was).
1390 A waiter with argument 0 or < -1 is waiting for any pid in
1391 a particular pgrp, which this child might or might not be
1392 in. The waiter will only wake up if it's argument is -1
1393 or if it's waiting for tcp->pid's pgrp. It makes a
1394 difference to wake up a waiter when there might be more
1395 traced children, because it could get a false ECHILD
1396 error. OTOH, if this was the last child in the pgrp, then
1397 it ought to wake up and get ECHILD. We would have to
1398 search the system for all pid's in the pgrp to be sure.
1399
1400 && (t->waitpid == -1 ||
1401 (t->waitpid == 0 && getpgid (tcp->pid) == getpgid (t->pid))
1402 || (t->waitpid < 0 && t->waitpid == -getpid (t->pid)))
1403 */
1404
1405 if (tcp->parent &&
1406 (tcp->parent->flags & TCB_SUSPENDED) &&
1407 (tcp->parent->waitpid <= 0 || tcp->parent->waitpid == tcp->pid)) {
1408 error = resume(tcp->parent);
1409 ++resumed;
1410 }
1411#ifdef TCB_CLONE_THREAD
1412 if (tcp->parent && tcp->parent->nclone_waiting > 0) {
1413 /* Some other threads of our parent are waiting too. */
1414 unsigned int i;
1415
1416 /* Resume all the threads that were waiting for this PID. */
1417 for (i = 0; i < tcbtabsize; i++) {
1418 struct tcb *t = tcbtab[i];
1419 if (t->parent == tcp->parent && t != tcp
1420 && ((t->flags & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1421 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1422 && t->waitpid == tcp->pid) {
1423 error |= resume (t);
1424 ++resumed;
1425 }
1426 }
1427 if (resumed == 0)
1428 /* Noone was waiting for this PID in particular,
1429 so now we might need to resume some wildcarders. */
1430 for (i = 0; i < tcbtabsize; i++) {
1431 struct tcb *t = tcbtab[i];
1432 if (t->parent == tcp->parent && t != tcp
1433 && ((t->flags
1434 & (TCB_CLONE_THREAD|TCB_SUSPENDED))
1435 == (TCB_CLONE_THREAD|TCB_SUSPENDED))
1436 && t->waitpid <= 0
1437 ) {
1438 error |= resume (t);
1439 break;
1440 }
1441 }
1442 }
1443
1444 return error;
1445}
1446#endif
1447
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001448#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001449
Roland McGrath0a463882007-07-05 18:43:16 +00001450/* detach traced process; continue with sig
1451 Never call DETACH twice on the same process as both unattached and
1452 attached-unstopped processes give the same ESRCH. For unattached process we
1453 would SIGSTOP it and wait for its SIGSTOP notification forever. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001454
1455static int
1456detach(tcp, sig)
1457struct tcb *tcp;
1458int sig;
1459{
1460 int error = 0;
Roland McGrathca16be82003-01-10 19:55:28 +00001461#ifdef LINUX
Roland McGrath1bfd3102007-08-03 10:02:00 +00001462 int status, catch_sigstop;
Roland McGratha08a97e2005-08-03 11:23:46 +00001463 struct tcb *zombie = NULL;
1464
1465 /* If the group leader is lingering only because of this other
1466 thread now dying, then detach the leader as well. */
1467 if ((tcp->flags & TCB_CLONE_THREAD) &&
1468 tcp->parent->nclone_threads == 1 &&
1469 (tcp->parent->flags & TCB_EXITING))
1470 zombie = tcp->parent;
Roland McGrathca16be82003-01-10 19:55:28 +00001471#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001472
1473 if (tcp->flags & TCB_BPTSET)
1474 sig = SIGKILL;
1475
1476#ifdef LINUX
1477 /*
1478 * Linux wrongly insists the child be stopped
Roland McGrath7bf10472002-12-16 20:42:50 +00001479 * before detaching. Arghh. We go through hoops
1480 * to make a clean break of things.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001481 */
Roland McGrath7bf10472002-12-16 20:42:50 +00001482#if defined(SPARC)
1483#undef PTRACE_DETACH
1484#define PTRACE_DETACH PTRACE_SUNDETACH
1485#endif
Roland McGrath02203312007-06-11 22:06:31 +00001486 /*
1487 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
1488 * expected SIGSTOP. We must catch exactly one as otherwise the
1489 * detached process would be left stopped (process state T).
1490 */
1491 catch_sigstop = (tcp->flags & TCB_STARTUP);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001492 if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
1493 /* On a clear day, you can see forever. */
Roland McGrath7bf10472002-12-16 20:42:50 +00001494 }
1495 else if (errno != ESRCH) {
1496 /* Shouldn't happen. */
1497 perror("detach: ptrace(PTRACE_DETACH, ...)");
1498 }
Roland McGrath134813a2007-06-02 00:07:33 +00001499 else if (my_tgkill((tcp->flags & TCB_CLONE_THREAD ? tcp->parent->pid
1500 : tcp->pid),
1501 tcp->pid, 0) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001502 if (errno != ESRCH)
1503 perror("detach: checking sanity");
1504 }
Roland McGrath02203312007-06-11 22:06:31 +00001505 else if (!catch_sigstop && my_tgkill((tcp->flags & TCB_CLONE_THREAD
1506 ? tcp->parent->pid : tcp->pid),
1507 tcp->pid, SIGSTOP) < 0) {
Roland McGrath7bf10472002-12-16 20:42:50 +00001508 if (errno != ESRCH)
1509 perror("detach: stopping child");
1510 }
Roland McGrath02203312007-06-11 22:06:31 +00001511 else
1512 catch_sigstop = 1;
1513 if (catch_sigstop)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001514 for (;;) {
Roland McGrath7508cb42002-12-17 10:48:05 +00001515#ifdef __WALL
1516 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1517 if (errno == ECHILD) /* Already gone. */
1518 break;
1519 if (errno != EINVAL) {
Roland McGrath553a6092002-12-16 20:40:39 +00001520 perror("detach: waiting");
Roland McGrath7508cb42002-12-17 10:48:05 +00001521 break;
1522 }
1523#endif /* __WALL */
1524 /* No __WALL here. */
1525 if (waitpid(tcp->pid, &status, 0) < 0) {
1526 if (errno != ECHILD) {
1527 perror("detach: waiting");
1528 break;
1529 }
1530#ifdef __WCLONE
1531 /* If no processes, try clones. */
1532 if (wait4(tcp->pid, &status, __WCLONE,
1533 NULL) < 0) {
1534 if (errno != ECHILD)
1535 perror("detach: waiting");
1536 break;
1537 }
1538#endif /* __WCLONE */
1539 }
1540#ifdef __WALL
Roland McGrath553a6092002-12-16 20:40:39 +00001541 }
Roland McGrath7508cb42002-12-17 10:48:05 +00001542#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001543 if (!WIFSTOPPED(status)) {
1544 /* Au revoir, mon ami. */
1545 break;
1546 }
1547 if (WSTOPSIG(status) == SIGSTOP) {
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001548 ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001549 break;
1550 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001551 error = ptrace_restart(PTRACE_CONT, tcp,
1552 WSTOPSIG(status) == SIGTRAP ? 0
1553 : WSTOPSIG(status));
1554 if (error < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001555 break;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001556 }
Roland McGrath7bf10472002-12-16 20:42:50 +00001557#endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001558
1559#if defined(SUNOS4)
1560 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1561 if (sig && kill(tcp->pid, sig) < 0)
1562 perror("detach: kill");
1563 sig = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001564 error = ptrace_restart(PTRACE_DETACH, tcp, sig);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001565#endif /* SUNOS4 */
1566
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001567#ifndef USE_PROCFS
Roland McGrath1bfd3102007-08-03 10:02:00 +00001568 error |= resume_from_tcp (tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00001569#endif
1570
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001571 if (!qflag)
1572 fprintf(stderr, "Process %u detached\n", tcp->pid);
1573
1574 droptcb(tcp);
Roland McGratha08a97e2005-08-03 11:23:46 +00001575
1576#ifdef LINUX
Roland McGrath0a463882007-07-05 18:43:16 +00001577 if (zombie != NULL) {
1578 /* TCP no longer exists therefore you must not detach () it. */
1579 droptcb(zombie);
1580 }
Roland McGratha08a97e2005-08-03 11:23:46 +00001581#endif
1582
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001583 return error;
1584}
1585
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001586#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001587
1588static void
1589reaper(sig)
1590int sig;
1591{
1592 int pid;
1593 int status;
1594
1595 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1596#if 0
1597 struct tcb *tcp;
1598
1599 tcp = pid2tcb(pid);
1600 if (tcp)
1601 droptcb(tcp);
1602#endif
1603 }
1604}
1605
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001606#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001607
1608static void
1609cleanup()
1610{
1611 int i;
1612 struct tcb *tcp;
1613
Roland McGrathee9d4352002-12-18 04:16:10 +00001614 for (i = 0; i < tcbtabsize; i++) {
1615 tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001616 if (!(tcp->flags & TCB_INUSE))
1617 continue;
1618 if (debug)
1619 fprintf(stderr,
1620 "cleanup: looking at pid %u\n", tcp->pid);
1621 if (tcp_last &&
1622 (!outfname || followfork < 2 || tcp_last == tcp)) {
1623 tprintf(" <unfinished ...>\n");
1624 tcp_last = NULL;
1625 }
1626 if (tcp->flags & TCB_ATTACHED)
1627 detach(tcp, 0);
1628 else {
1629 kill(tcp->pid, SIGCONT);
1630 kill(tcp->pid, SIGTERM);
1631 }
1632 }
1633 if (cflag)
1634 call_summary(outf);
1635}
1636
1637static void
1638interrupt(sig)
1639int sig;
1640{
1641 interrupted = 1;
1642}
1643
1644#ifndef HAVE_STRERROR
1645
Roland McGrath6d2b3492002-12-30 00:51:30 +00001646#if !HAVE_DECL_SYS_ERRLIST
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647extern int sys_nerr;
1648extern char *sys_errlist[];
Roland McGrath6d2b3492002-12-30 00:51:30 +00001649#endif /* HAVE_DECL_SYS_ERRLIST */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001650
1651const char *
1652strerror(errno)
1653int errno;
1654{
1655 static char buf[64];
1656
1657 if (errno < 1 || errno >= sys_nerr) {
1658 sprintf(buf, "Unknown error %d", errno);
1659 return buf;
1660 }
1661 return sys_errlist[errno];
1662}
1663
1664#endif /* HAVE_STERRROR */
1665
1666#ifndef HAVE_STRSIGNAL
1667
Roland McGrath8f474e02003-01-14 07:53:33 +00001668#if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
Roland McGrath6d2b3492002-12-30 00:51:30 +00001669extern char *sys_siglist[];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670#endif
Roland McGrath8f474e02003-01-14 07:53:33 +00001671#if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
1672extern char *_sys_siglist[];
1673#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001674
1675const char *
1676strsignal(sig)
1677int sig;
1678{
1679 static char buf[64];
1680
1681 if (sig < 1 || sig >= NSIG) {
1682 sprintf(buf, "Unknown signal %d", sig);
1683 return buf;
1684 }
1685#ifdef HAVE__SYS_SIGLIST
1686 return _sys_siglist[sig];
1687#else
1688 return sys_siglist[sig];
1689#endif
1690}
1691
1692#endif /* HAVE_STRSIGNAL */
1693
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001694#ifdef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001695
1696static void
1697rebuild_pollv()
1698{
1699 int i, j;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001700
Roland McGrathee9d4352002-12-18 04:16:10 +00001701 if (pollv != NULL)
1702 free (pollv);
Roland McGrathc012d222003-01-10 20:05:56 +00001703 pollv = (struct pollfd *) malloc(nprocs * sizeof pollv[0]);
Roland McGrathee9d4352002-12-18 04:16:10 +00001704 if (pollv == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001705 fprintf(stderr, "%s: out of memory\n", progname);
Roland McGrathee9d4352002-12-18 04:16:10 +00001706 exit(1);
1707 }
1708
Roland McGrathca16be82003-01-10 19:55:28 +00001709 for (i = j = 0; i < tcbtabsize; i++) {
1710 struct tcb *tcp = tcbtab[i];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001711 if (!(tcp->flags & TCB_INUSE))
1712 continue;
1713 pollv[j].fd = tcp->pfd;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001714 pollv[j].events = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715 j++;
1716 }
1717 if (j != nprocs) {
1718 fprintf(stderr, "strace: proc miscount\n");
1719 exit(1);
1720 }
1721}
1722
1723#ifndef HAVE_POLLABLE_PROCFS
1724
1725static void
1726proc_poll_open()
1727{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 int i;
1729
1730 if (pipe(proc_poll_pipe) < 0) {
1731 perror("pipe");
1732 exit(1);
1733 }
1734 for (i = 0; i < 2; i++) {
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00001735 if (set_cloexec_flag(proc_poll_pipe[i]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001736 exit(1);
1737 }
1738 }
1739}
1740
1741static int
1742proc_poll(pollv, nfds, timeout)
1743struct pollfd *pollv;
1744int nfds;
1745int timeout;
1746{
1747 int i;
1748 int n;
1749 struct proc_pollfd pollinfo;
1750
1751 if ((n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo))) < 0)
1752 return n;
1753 if (n != sizeof(struct proc_pollfd)) {
1754 fprintf(stderr, "panic: short read: %d\n", n);
1755 exit(1);
1756 }
1757 for (i = 0; i < nprocs; i++) {
1758 if (pollv[i].fd == pollinfo.fd)
1759 pollv[i].revents = pollinfo.revents;
1760 else
1761 pollv[i].revents = 0;
1762 }
1763 poller_pid = pollinfo.pid;
1764 return 1;
1765}
1766
1767static void
1768wakeup_handler(sig)
1769int sig;
1770{
1771}
1772
1773static void
1774proc_poller(pfd)
1775int pfd;
1776{
1777 struct proc_pollfd pollinfo;
1778 struct sigaction sa;
1779 sigset_t blocked_set, empty_set;
1780 int i;
1781 int n;
1782 struct rlimit rl;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001783#ifdef FREEBSD
1784 struct procfs_status pfs;
1785#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001786
1787 switch (fork()) {
1788 case -1:
1789 perror("fork");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001790 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001791 case 0:
1792 break;
1793 default:
1794 return;
1795 }
1796
1797 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
1798 sa.sa_flags = 0;
1799 sigemptyset(&sa.sa_mask);
1800 sigaction(SIGHUP, &sa, NULL);
1801 sigaction(SIGINT, &sa, NULL);
1802 sigaction(SIGQUIT, &sa, NULL);
1803 sigaction(SIGPIPE, &sa, NULL);
1804 sigaction(SIGTERM, &sa, NULL);
1805 sa.sa_handler = wakeup_handler;
1806 sigaction(SIGUSR1, &sa, NULL);
1807 sigemptyset(&blocked_set);
1808 sigaddset(&blocked_set, SIGUSR1);
1809 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1810 sigemptyset(&empty_set);
1811
1812 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1813 perror("getrlimit(RLIMIT_NOFILE, ...)");
Dmitry V. Levina6809652008-11-10 17:14:58 +00001814 _exit(1);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001815 }
1816 n = rl.rlim_cur;
1817 for (i = 0; i < n; i++) {
1818 if (i != pfd && i != proc_poll_pipe[1])
1819 close(i);
1820 }
1821
1822 pollinfo.fd = pfd;
1823 pollinfo.pid = getpid();
1824 for (;;) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001825#ifndef FREEBSD
1826 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
1827#else /* FREEBSD */
1828 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
1829#endif /* FREEBSD */
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001830 {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001831 switch (errno) {
1832 case EINTR:
1833 continue;
1834 case EBADF:
1835 pollinfo.revents = POLLERR;
1836 break;
1837 case ENOENT:
1838 pollinfo.revents = POLLHUP;
1839 break;
1840 default:
1841 perror("proc_poller: PIOCWSTOP");
1842 }
1843 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1844 _exit(0);
1845 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001846 pollinfo.revents = POLLWANT;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001847 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
1848 sigsuspend(&empty_set);
1849 }
1850}
1851
1852#endif /* !HAVE_POLLABLE_PROCFS */
1853
1854static int
1855choose_pfd()
1856{
1857 int i, j;
1858 struct tcb *tcp;
1859
1860 static int last;
1861
1862 if (followfork < 2 &&
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001863 last < nprocs && (pollv[last].revents & POLLWANT)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001864 /*
1865 * The previous process is ready to run again. We'll
1866 * let it do so if it is currently in a syscall. This
1867 * heuristic improves the readability of the trace.
1868 */
1869 tcp = pfd2tcb(pollv[last].fd);
1870 if (tcp && (tcp->flags & TCB_INSYSCALL))
1871 return pollv[last].fd;
1872 }
1873
1874 for (i = 0; i < nprocs; i++) {
1875 /* Let competing children run round robin. */
1876 j = (i + last + 1) % nprocs;
1877 if (pollv[j].revents & (POLLHUP | POLLERR)) {
1878 tcp = pfd2tcb(pollv[j].fd);
1879 if (!tcp) {
1880 fprintf(stderr, "strace: lost proc\n");
1881 exit(1);
1882 }
1883 droptcb(tcp);
1884 return -1;
1885 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001886 if (pollv[j].revents & POLLWANT) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001887 last = j;
1888 return pollv[j].fd;
1889 }
1890 }
1891 fprintf(stderr, "strace: nothing ready\n");
1892 exit(1);
1893}
1894
1895static int
1896trace()
1897{
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001898#ifdef POLL_HACK
John Hughesd870b3c2002-05-21 11:24:18 +00001899 struct tcb *in_syscall = NULL;
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001900#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001901 struct tcb *tcp;
1902 int pfd;
1903 int what;
1904 int ioctl_result = 0, ioctl_errno = 0;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001905 long arg;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001906
1907 for (;;) {
1908 if (interactive)
1909 sigprocmask(SIG_SETMASK, &empty_set, NULL);
1910
1911 if (nprocs == 0)
1912 break;
1913
1914 switch (nprocs) {
1915 case 1:
1916#ifndef HAVE_POLLABLE_PROCFS
1917 if (proc_poll_pipe[0] == -1) {
1918#endif
1919 tcp = pid2tcb(0);
1920 if (!tcp)
1921 continue;
1922 pfd = tcp->pfd;
1923 if (pfd == -1)
1924 continue;
1925 break;
1926#ifndef HAVE_POLLABLE_PROCFS
1927 }
1928 /* fall through ... */
1929#endif /* !HAVE_POLLABLE_PROCFS */
1930 default:
1931#ifdef HAVE_POLLABLE_PROCFS
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001932#ifdef POLL_HACK
1933 /* On some systems (e.g. UnixWare) we get too much ugly
1934 "unfinished..." stuff when multiple proceses are in
1935 syscalls. Here's a nasty hack */
Roland McGrath553a6092002-12-16 20:40:39 +00001936
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001937 if (in_syscall) {
1938 struct pollfd pv;
1939 tcp = in_syscall;
1940 in_syscall = NULL;
1941 pv.fd = tcp->pfd;
1942 pv.events = POLLWANT;
1943 if ((what = poll (&pv, 1, 1)) < 0) {
1944 if (interrupted)
1945 return 0;
1946 continue;
1947 }
1948 else if (what == 1 && pv.revents & POLLWANT) {
1949 goto FOUND;
1950 }
1951 }
1952#endif
1953
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001954 if (poll(pollv, nprocs, INFTIM) < 0) {
1955 if (interrupted)
1956 return 0;
1957 continue;
1958 }
1959#else /* !HAVE_POLLABLE_PROCFS */
1960 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
1961 if (interrupted)
1962 return 0;
1963 continue;
1964 }
1965#endif /* !HAVE_POLLABLE_PROCFS */
1966 pfd = choose_pfd();
1967 if (pfd == -1)
1968 continue;
1969 break;
1970 }
1971
1972 /* Look up `pfd' in our table. */
1973 if ((tcp = pfd2tcb(pfd)) == NULL) {
1974 fprintf(stderr, "unknown pfd: %u\n", pfd);
1975 exit(1);
1976 }
John Hughesb6643082002-05-23 11:02:22 +00001977#ifdef POLL_HACK
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00001978 FOUND:
John Hughesb6643082002-05-23 11:02:22 +00001979#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001980 /* Get the status of the process. */
1981 if (!interrupted) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001982#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001983 ioctl_result = IOCTL_WSTOP (tcp);
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001984#else /* FREEBSD */
1985 /* Thanks to some scheduling mystery, the first poller
1986 sometimes waits for the already processed end of fork
1987 event. Doing a non blocking poll here solves the problem. */
1988 if (proc_poll_pipe[0] != -1)
1989 ioctl_result = IOCTL_STATUS (tcp);
1990 else
1991 ioctl_result = IOCTL_WSTOP (tcp);
Roland McGrath553a6092002-12-16 20:40:39 +00001992#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001993 ioctl_errno = errno;
1994#ifndef HAVE_POLLABLE_PROCFS
1995 if (proc_poll_pipe[0] != -1) {
1996 if (ioctl_result < 0)
1997 kill(poller_pid, SIGKILL);
1998 else
1999 kill(poller_pid, SIGUSR1);
2000 }
2001#endif /* !HAVE_POLLABLE_PROCFS */
2002 }
2003 if (interrupted)
2004 return 0;
2005
2006 if (interactive)
2007 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2008
2009 if (ioctl_result < 0) {
2010 /* Find out what happened if it failed. */
2011 switch (ioctl_errno) {
2012 case EINTR:
2013 case EBADF:
2014 continue;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002015#ifdef FREEBSD
2016 case ENOTTY:
Roland McGrath553a6092002-12-16 20:40:39 +00002017#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002018 case ENOENT:
2019 droptcb(tcp);
2020 continue;
2021 default:
2022 perror("PIOCWSTOP");
2023 exit(1);
2024 }
2025 }
2026
Wichert Akkerman2e4ffe52000-09-03 23:57:48 +00002027#ifdef FREEBSD
2028 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2029 /* discard first event for a syscall we never entered */
2030 IOCTL (tcp->pfd, PIOCRUN, 0);
2031 continue;
2032 }
Roland McGrath553a6092002-12-16 20:40:39 +00002033#endif
2034
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002035 /* clear the just started flag */
2036 tcp->flags &= ~TCB_STARTUP;
2037
2038 /* set current output file */
2039 outf = tcp->outf;
2040
2041 if (cflag) {
2042 struct timeval stime;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002043#ifdef FREEBSD
2044 char buf[1024];
2045 int len;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002046
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002047 if ((len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0)) > 0) {
2048 buf[len] = '\0';
2049 sscanf(buf,
2050 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2051 &stime.tv_sec, &stime.tv_usec);
2052 } else
2053 stime.tv_sec = stime.tv_usec = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002054#else /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002055 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2056 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002057#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002058 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2059 tcp->stime = stime;
2060 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002061 what = tcp->status.PR_WHAT;
2062 switch (tcp->status.PR_WHY) {
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002063#ifndef FREEBSD
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002064 case PR_REQUESTED:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002065 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2066 tcp->status.PR_WHY = PR_SYSENTRY;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002067 if (trace_syscall(tcp) < 0) {
2068 fprintf(stderr, "syscall trouble\n");
2069 exit(1);
2070 }
2071 }
2072 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002073#endif /* !FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002074 case PR_SYSENTRY:
Wichert Akkerman9dbf1541999-11-26 13:11:29 +00002075#ifdef POLL_HACK
2076 in_syscall = tcp;
2077#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002078 case PR_SYSEXIT:
2079 if (trace_syscall(tcp) < 0) {
2080 fprintf(stderr, "syscall trouble\n");
2081 exit(1);
2082 }
2083 break;
2084 case PR_SIGNALLED:
2085 if (!cflag && (qual_flags[what] & QUAL_SIGNAL)) {
2086 printleader(tcp);
2087 tprintf("--- %s (%s) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002088 signame(what), strsignal(what));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002089 printtrailer(tcp);
John Hughes58265892001-10-18 15:13:53 +00002090#ifdef PR_INFO
2091 if (tcp->status.PR_INFO.si_signo == what) {
2092 printleader(tcp);
2093 tprintf(" siginfo=");
2094 printsiginfo(&tcp->status.PR_INFO, 1);
2095 printtrailer(tcp);
2096 }
2097#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002098 }
2099 break;
2100 case PR_FAULTED:
2101 if (!cflag && (qual_flags[what] & QUAL_FAULT)) {
2102 printleader(tcp);
2103 tprintf("=== FAULT %d ===", what);
2104 printtrailer(tcp);
2105 }
2106 break;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002107#ifdef FREEBSD
2108 case 0: /* handle case we polled for nothing */
2109 continue;
Roland McGrath553a6092002-12-16 20:40:39 +00002110#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002111 default:
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002112 fprintf(stderr, "odd stop %d\n", tcp->status.PR_WHY);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002113 exit(1);
2114 break;
2115 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002116 arg = 0;
Roland McGrath553a6092002-12-16 20:40:39 +00002117#ifndef FREEBSD
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002118 if (IOCTL (tcp->pfd, PIOCRUN, &arg) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002119#else
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002120 if (IOCTL (tcp->pfd, PIOCRUN, 0) < 0) {
Roland McGrath553a6092002-12-16 20:40:39 +00002121#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002122 perror("PIOCRUN");
2123 exit(1);
2124 }
2125 }
2126 return 0;
2127}
2128
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002129#else /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002130
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002131#ifdef TCB_GROUP_EXITING
2132/* Handle an exit detach or death signal that is taking all the
2133 related clone threads with it. This is called in three circumstances:
2134 SIG == -1 TCP has already died (TCB_ATTACHED is clear, strace is parent).
2135 SIG == 0 Continuing TCP will perform an exit_group syscall.
2136 SIG == other Continuing TCP with SIG will kill the process.
2137*/
2138static int
2139handle_group_exit(struct tcb *tcp, int sig)
2140{
2141 /* We need to locate our records of all the clone threads
2142 related to TCP, either its children or siblings. */
2143 struct tcb *leader = ((tcp->flags & TCB_CLONE_THREAD)
2144 ? tcp->parent
2145 : tcp->nclone_detached > 0
2146 ? tcp : NULL);
2147
2148 if (sig < 0) {
Roland McGrath05690952004-10-20 01:00:27 +00002149 if (leader != NULL && leader != tcp &&
2150 !(leader->flags & TCB_GROUP_EXITING))
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002151 fprintf(stderr,
2152 "PANIC: handle_group_exit: %d leader %d\n",
2153 tcp->pid, leader ? leader->pid : -1);
Roland McGrath0a463882007-07-05 18:43:16 +00002154 /* TCP no longer exists therefore you must not detach () it. */
Roland McGrath1bfd3102007-08-03 10:02:00 +00002155#ifndef USE_PROCFS
2156 resume_from_tcp (tcp);
2157#endif
Roland McGrath0a463882007-07-05 18:43:16 +00002158 droptcb(tcp); /* Already died. */
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002159 }
2160 else {
Roland McGratha08a97e2005-08-03 11:23:46 +00002161 /* Mark that we are taking the process down. */
2162 tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002163 if (tcp->flags & TCB_ATTACHED) {
Roland McGrathd6a32f12007-07-11 08:35:11 +00002164 detach(tcp, sig);
Roland McGrath1bfd3102007-08-03 10:02:00 +00002165 if (leader != NULL && leader != tcp)
2166 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002167 } else {
2168 if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
2169 cleanup();
2170 return -1;
2171 }
2172 if (leader != NULL) {
Roland McGrath05690952004-10-20 01:00:27 +00002173 leader->flags |= TCB_GROUP_EXITING;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002174 if (leader != tcp)
2175 droptcb(tcp);
2176 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002177 /* The leader will report to us as parent now,
2178 and then we'll get to the SIG==-1 case. */
2179 return 0;
2180 }
2181 }
2182
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002183 return 0;
2184}
2185#endif
2186
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002187static int
2188trace()
2189{
2190 int pid;
2191 int wait_errno;
2192 int status;
2193 struct tcb *tcp;
2194#ifdef LINUX
2195 struct rusage ru;
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002196#ifdef __WALL
2197 static int wait4_options = __WALL;
2198#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002199#endif /* LINUX */
2200
2201 while (nprocs != 0) {
Roland McGrath02203312007-06-11 22:06:31 +00002202 if (interrupted)
2203 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002204 if (interactive)
2205 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2206#ifdef LINUX
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002207#ifdef __WALL
2208 pid = wait4(-1, &status, wait4_options, cflag ? &ru : NULL);
Roland McGrath5bc05552002-12-17 04:50:47 +00002209 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002210 /* this kernel does not support __WALL */
2211 wait4_options &= ~__WALL;
2212 errno = 0;
2213 pid = wait4(-1, &status, wait4_options,
2214 cflag ? &ru : NULL);
2215 }
Roland McGrath5bc05552002-12-17 04:50:47 +00002216 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002217 /* most likely a "cloned" process */
2218 pid = wait4(-1, &status, __WCLONE,
2219 cflag ? &ru : NULL);
2220 if (pid == -1) {
2221 fprintf(stderr, "strace: clone wait4 "
2222 "failed: %s\n", strerror(errno));
2223 }
2224 }
2225#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002226 pid = wait4(-1, &status, 0, cflag ? &ru : NULL);
Wichert Akkerman2f1d87e2001-03-28 14:40:14 +00002227#endif /* __WALL */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002228#endif /* LINUX */
2229#ifdef SUNOS4
2230 pid = wait(&status);
2231#endif /* SUNOS4 */
2232 wait_errno = errno;
2233 if (interactive)
2234 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2235
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002236 if (pid == -1) {
2237 switch (wait_errno) {
2238 case EINTR:
2239 continue;
2240 case ECHILD:
2241 /*
2242 * We would like to verify this case
2243 * but sometimes a race in Solbourne's
2244 * version of SunOS sometimes reports
2245 * ECHILD before sending us SIGCHILD.
2246 */
2247#if 0
2248 if (nprocs == 0)
2249 return 0;
2250 fprintf(stderr, "strace: proc miscount\n");
2251 exit(1);
2252#endif
2253 return 0;
2254 default:
2255 errno = wait_errno;
2256 perror("strace: wait");
2257 return -1;
2258 }
2259 }
Dmitry V. Levin10de62b2006-12-13 21:45:31 +00002260 if (pid == popen_pid) {
2261 if (WIFEXITED(status) || WIFSIGNALED(status))
2262 popen_pid = -1;
2263 continue;
2264 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002265 if (debug)
2266 fprintf(stderr, " [wait(%#x) = %u]\n", status, pid);
2267
2268 /* Look up `pid' in our table. */
2269 if ((tcp = pid2tcb(pid)) == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002270#ifdef LINUX
Roland McGrath41c48222008-07-18 00:25:10 +00002271 if (followfork) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002272 /* This is needed to go with the CLONE_PTRACE
2273 changes in process.c/util.c: we might see
2274 the child's initial trap before we see the
2275 parent return from the clone syscall.
2276 Leave the child suspended until the parent
2277 returns from its system call. Only then
2278 will we have the association of parent and
2279 child so that we know how to do clearbpt
2280 in the child. */
Dmitry V. Levin76860f62006-10-11 22:55:25 +00002281 if (nprocs == tcbtabsize &&
2282 expand_tcbtab())
2283 tcp = NULL;
2284 else
2285 tcp = alloctcb(pid);
2286 if (tcp == NULL) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002287 kill(pid, SIGKILL); /* XXX */
2288 return 0;
2289 }
2290 tcp->flags |= TCB_ATTACHED | TCB_SUSPENDED;
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002291 if (!qflag)
2292 fprintf(stderr, "\
2293Process %d attached (waiting for parent)\n",
2294 pid);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002295 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002296 else
2297 /* This can happen if a clone call used
2298 CLONE_PTRACE itself. */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002299#endif
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002300 {
2301 fprintf(stderr, "unknown pid: %u\n", pid);
2302 if (WIFSTOPPED(status))
2303 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2304 exit(1);
2305 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002306 }
2307 /* set current output file */
2308 outf = tcp->outf;
2309 if (cflag) {
2310#ifdef LINUX
2311 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2312 tcp->stime = ru.ru_stime;
2313#endif /* !LINUX */
2314 }
2315
2316 if (tcp->flags & TCB_SUSPENDED) {
2317 /*
2318 * Apparently, doing any ptrace() call on a stopped
2319 * process, provokes the kernel to report the process
2320 * status again on a subsequent wait(), even if the
2321 * process has not been actually restarted.
2322 * Since we have inspected the arguments of suspended
2323 * processes we end up here testing for this case.
2324 */
2325 continue;
2326 }
2327 if (WIFSIGNALED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002328 if (pid == strace_child)
2329 exit_code = 0x100 | WTERMSIG(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002330 if (!cflag
2331 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2332 printleader(tcp);
Roland McGrath2efe8792004-01-13 09:59:45 +00002333 tprintf("+++ killed by %s %s+++",
2334 signame(WTERMSIG(status)),
2335#ifdef WCOREDUMP
2336 WCOREDUMP(status) ? "(core dumped) " :
2337#endif
2338 "");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002339 printtrailer(tcp);
2340 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002341#ifdef TCB_GROUP_EXITING
2342 handle_group_exit(tcp, -1);
2343#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002344 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002345#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002346 continue;
2347 }
2348 if (WIFEXITED(status)) {
Dmitry V. Levina6809652008-11-10 17:14:58 +00002349 if (pid == strace_child)
2350 exit_code = WEXITSTATUS(status);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002351 if (debug)
2352 fprintf(stderr, "pid %u exited\n", pid);
Roland McGrath05690952004-10-20 01:00:27 +00002353 if ((tcp->flags & TCB_ATTACHED)
2354#ifdef TCB_GROUP_EXITING
2355 && !(tcp->parent && (tcp->parent->flags &
2356 TCB_GROUP_EXITING))
Roland McGrath1bfd3102007-08-03 10:02:00 +00002357 && !(tcp->flags & TCB_GROUP_EXITING)
Roland McGrath05690952004-10-20 01:00:27 +00002358#endif
2359 )
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002360 fprintf(stderr,
2361 "PANIC: attached pid %u exited\n",
2362 pid);
Roland McGrath0a396902003-06-10 03:05:53 +00002363 if (tcp == tcp_last) {
2364 if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT))
2365 == TCB_INSYSCALL)
2366 tprintf(" <unfinished ... exit status %d>\n",
2367 WEXITSTATUS(status));
2368 tcp_last = NULL;
2369 }
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002370#ifdef TCB_GROUP_EXITING
2371 handle_group_exit(tcp, -1);
2372#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002373 droptcb(tcp);
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002374#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002375 continue;
2376 }
2377 if (!WIFSTOPPED(status)) {
2378 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2379 droptcb(tcp);
2380 continue;
2381 }
2382 if (debug)
2383 fprintf(stderr, "pid %u stopped, [%s]\n",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002384 pid, signame(WSTOPSIG(status)));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002385
Roland McGrath02203312007-06-11 22:06:31 +00002386 /*
2387 * Interestingly, the process may stop
2388 * with STOPSIG equal to some other signal
2389 * than SIGSTOP if we happend to attach
2390 * just before the process takes a signal.
2391 */
2392 if ((tcp->flags & TCB_STARTUP) && WSTOPSIG(status) == SIGSTOP) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002393 /*
2394 * This flag is there to keep us in sync.
2395 * Next time this process stops it should
2396 * really be entering a system call.
2397 */
2398 tcp->flags &= ~TCB_STARTUP;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002399 if (tcp->flags & TCB_BPTSET) {
Roland McGrath02203312007-06-11 22:06:31 +00002400 /*
2401 * One example is a breakpoint inherited from
2402 * parent through fork ().
2403 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002404 if (clearbpt(tcp) < 0) /* Pretty fatal */ {
2405 droptcb(tcp);
2406 cleanup();
2407 return -1;
2408 }
2409 }
2410 goto tracing;
2411 }
2412
2413 if (WSTOPSIG(status) != SIGTRAP) {
2414 if (WSTOPSIG(status) == SIGSTOP &&
2415 (tcp->flags & TCB_SIGTRAPPED)) {
2416 /*
2417 * Trapped attempt to block SIGTRAP
2418 * Hope we are back in control now.
2419 */
2420 tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002421 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002422 cleanup();
2423 return -1;
2424 }
2425 continue;
2426 }
2427 if (!cflag
2428 && (qual_flags[WSTOPSIG(status)] & QUAL_SIGNAL)) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00002429 unsigned long addr = 0;
2430 long pc = 0;
Dmitry V. Levin96339422006-10-11 23:11:43 +00002431#if defined(PT_CR_IPSR) && defined(PT_CR_IIP) && defined(PT_GETSIGINFO)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002432# define PSR_RI 41
2433 struct siginfo si;
Jan Kratochvil1f942712008-08-06 21:38:52 +00002434 long psr;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002435
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002436 upeek(tcp, PT_CR_IPSR, &psr);
2437 upeek(tcp, PT_CR_IIP, &pc);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002438
2439 pc += (psr >> PSR_RI) & 0x3;
2440 ptrace(PT_GETSIGINFO, pid, 0, (long) &si);
2441 addr = (unsigned long) si.si_addr;
Roland McGrath3a055d72005-03-06 22:24:29 +00002442#elif defined PTRACE_GETSIGINFO
2443 if (WSTOPSIG(status) == SIGSEGV ||
2444 WSTOPSIG(status) == SIGBUS) {
2445 siginfo_t si;
2446 if (ptrace(PTRACE_GETSIGINFO, pid,
2447 0, &si) == 0)
2448 addr = (unsigned long)
2449 si.si_addr;
2450 }
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002451#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002452 printleader(tcp);
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002453 tprintf("--- %s (%s) @ %lx (%lx) ---",
Nate Sammonsce780fc1999-03-29 23:23:13 +00002454 signame(WSTOPSIG(status)),
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00002455 strsignal(WSTOPSIG(status)), pc, addr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002456 printtrailer(tcp);
2457 }
Roland McGrath05690952004-10-20 01:00:27 +00002458 if (((tcp->flags & TCB_ATTACHED) ||
2459 tcp->nclone_threads > 0) &&
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002460 !sigishandled(tcp, WSTOPSIG(status))) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002461#ifdef TCB_GROUP_EXITING
2462 handle_group_exit(tcp, WSTOPSIG(status));
2463#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002464 detach(tcp, WSTOPSIG(status));
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002465#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002466 continue;
2467 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002468 if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002469 cleanup();
2470 return -1;
2471 }
2472 tcp->flags &= ~TCB_SUSPENDED;
2473 continue;
2474 }
Roland McGrath02203312007-06-11 22:06:31 +00002475 /* we handled the STATUS, we are permitted to interrupt now. */
2476 if (interrupted)
2477 return 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002478 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002479 if (tcp->flags & TCB_ATTACHED)
2480 detach(tcp, 0);
2481 else {
2482 ptrace(PTRACE_KILL,
2483 tcp->pid, (char *) 1, SIGTERM);
2484 droptcb(tcp);
2485 }
2486 continue;
2487 }
2488 if (tcp->flags & TCB_EXITING) {
Roland McGrathe85bbfe2003-01-09 06:53:31 +00002489#ifdef TCB_GROUP_EXITING
2490 if (tcp->flags & TCB_GROUP_EXITING) {
2491 if (handle_group_exit(tcp, 0) < 0)
2492 return -1;
2493 continue;
2494 }
2495#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002496 if (tcp->flags & TCB_ATTACHED)
2497 detach(tcp, 0);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002498 else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002499 cleanup();
2500 return -1;
2501 }
2502 continue;
2503 }
2504 if (tcp->flags & TCB_SUSPENDED) {
2505 if (!qflag)
2506 fprintf(stderr, "Process %u suspended\n", pid);
2507 continue;
2508 }
2509 tracing:
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002510 if (ptrace_restart(PTRACE_SYSCALL, tcp, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002511 cleanup();
2512 return -1;
2513 }
2514 }
2515 return 0;
2516}
2517
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002518#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002519
2520static int curcol;
2521
2522#ifdef __STDC__
2523#include <stdarg.h>
2524#define VA_START(a, b) va_start(a, b)
2525#else
2526#include <varargs.h>
2527#define VA_START(a, b) va_start(a)
2528#endif
2529
2530void
2531#ifdef __STDC__
2532tprintf(const char *fmt, ...)
2533#else
2534tprintf(fmt, va_alist)
2535char *fmt;
2536va_dcl
2537#endif
2538{
2539 va_list args;
2540
2541 VA_START(args, fmt);
Roland McGrathb310a0c2003-11-06 23:41:22 +00002542 if (outf) {
2543 int n = vfprintf(outf, fmt, args);
2544 if (n < 0 && outf != stderr)
2545 perror(outfname == NULL
2546 ? "<writing to pipe>" : outfname);
2547 else
2548 curcol += n;
2549 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002550 va_end(args);
2551 return;
2552}
2553
2554void
2555printleader(tcp)
2556struct tcb *tcp;
2557{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00002558 if (tcp_last) {
2559 if (tcp_last->ptrace_errno) {
2560 if (tcp_last->flags & TCB_INSYSCALL) {
2561 tprintf(" <unavailable>)");
2562 tabto(acolumn);
2563 }
2564 tprintf("= ? <unavailable>\n");
2565 tcp_last->ptrace_errno = 0;
2566 } else if (!outfname || followfork < 2 || tcp_last == tcp) {
2567 tcp_last->flags |= TCB_REPRINT;
2568 tprintf(" <unfinished ...>\n");
2569 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002570 }
2571 curcol = 0;
2572 if ((followfork == 1 || pflag_seen > 1) && outfname)
2573 tprintf("%-5d ", tcp->pid);
2574 else if (nprocs > 1 && !outfname)
2575 tprintf("[pid %5u] ", tcp->pid);
2576 if (tflag) {
2577 char str[sizeof("HH:MM:SS")];
2578 struct timeval tv, dtv;
2579 static struct timeval otv;
2580
2581 gettimeofday(&tv, NULL);
2582 if (rflag) {
2583 if (otv.tv_sec == 0)
2584 otv = tv;
2585 tv_sub(&dtv, &tv, &otv);
2586 tprintf("%6ld.%06ld ",
2587 (long) dtv.tv_sec, (long) dtv.tv_usec);
2588 otv = tv;
2589 }
2590 else if (tflag > 2) {
2591 tprintf("%ld.%06ld ",
2592 (long) tv.tv_sec, (long) tv.tv_usec);
2593 }
2594 else {
2595 time_t local = tv.tv_sec;
2596 strftime(str, sizeof(str), "%T", localtime(&local));
2597 if (tflag > 1)
2598 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
2599 else
2600 tprintf("%s ", str);
2601 }
2602 }
2603 if (iflag)
2604 printcall(tcp);
2605}
2606
2607void
2608tabto(col)
2609int col;
2610{
2611 if (curcol < col)
2612 tprintf("%*s", col - curcol, "");
2613}
2614
2615void
2616printtrailer(tcp)
2617struct tcb *tcp;
2618{
2619 tprintf("\n");
2620 tcp_last = NULL;
2621}
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002622
Wichert Akkermanea78f0f1999-11-29 15:34:02 +00002623#ifdef HAVE_MP_PROCFS
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002624
2625int mp_ioctl (int fd, int cmd, void *arg, int size) {
2626
2627 struct iovec iov[2];
2628 int n = 1;
Roland McGrath553a6092002-12-16 20:40:39 +00002629
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002630 iov[0].iov_base = &cmd;
2631 iov[0].iov_len = sizeof cmd;
2632 if (arg) {
2633 ++n;
2634 iov[1].iov_base = arg;
2635 iov[1].iov_len = size;
2636 }
Roland McGrath553a6092002-12-16 20:40:39 +00002637
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00002638 return writev (fd, iov, n);
2639}
2640
2641#endif