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>
5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
35 #include <sys/types.h>
39 #include <sys/param.h>
41 #include <sys/resource.h>
48 #include <sys/utsname.h>
51 # include <asm/unistd.h>
52 # if defined __NR_tkill
53 # define my_tkill(tid, sig) syscall(__NR_tkill, (tid), (sig))
55 /* kill() may choose arbitrarily the target task of the process group
56 while we later wait on a that specific TID. PID process waits become
57 TID task specific waits for a process under ptrace(2). */
58 # warning "Neither tkill(2) nor tgkill(2) available, risk of strace hangs!"
59 # define my_tkill(tid, sig) kill((tid), (sig))
63 #if defined(IA64) && defined(LINUX)
64 # include <asm/ptrace_offsets.h>
72 #include <sys/stropts.h>
79 extern char **environ;
84 int debug = 0, followfork = 0;
85 unsigned int ptrace_setoptions = 0;
86 /* Which WSTOPSIG(status) value marks syscall traps? */
87 static unsigned int syscall_trap_sig = SIGTRAP;
88 int dtime = 0, xflag = 0, qflag = 0;
89 cflag_t cflag = CFLAG_NONE;
90 static int iflag = 0, pflag_seen = 0, rflag = 0, tflag = 0;
95 INTR_ANYWHERE = 1, /* don't block/ignore any signals */
96 INTR_WHILE_WAIT = 2, /* block fatal signals while decoding syscall. default */
97 INTR_NEVER = 3, /* block fatal signals. default if '-o FILE PROG' */
98 INTR_BLOCK_TSTP_TOO = 4, /* block fatal signals and SIGTSTP (^Z) */
102 /* We play with signal mask only if this mode is active: */
103 #define interactive (opt_intr == INTR_WHILE_WAIT)
106 * daemonized_tracer supports -D option.
107 * With this option, strace forks twice.
108 * Unlike normal case, with -D *grandparent* process exec's,
109 * becoming a traced process. Child exits (this prevents traced process
110 * from having children it doesn't expect to have), and grandchild
111 * attaches to grandparent similarly to strace -p PID.
112 * This allows for more transparent interaction in cases
113 * when process and its parent are communicating via signals,
114 * wait() etc. Without -D, strace process gets lodged in between,
115 * disrupting parent<->child link.
117 static bool daemonized_tracer = 0;
120 static int post_attach_sigstop = TCB_IGNORE_ONE_SIGSTOP;
121 # define use_seize (post_attach_sigstop == 0)
123 # define post_attach_sigstop TCB_IGNORE_ONE_SIGSTOP
127 /* Sometimes we want to print only succeeding syscalls. */
128 int not_failing_only = 0;
130 /* Show path associated with fd arguments */
131 int show_fd_path = 0;
133 /* are we filtering traces based on paths? */
134 int tracing_paths = 0;
136 static int exit_code = 0;
137 static int strace_child = 0;
138 static int strace_tracer_pid = 0;
140 static char *username = NULL;
141 static uid_t run_uid;
142 static gid_t run_gid;
144 int max_strlen = DEFAULT_STRLEN;
145 static int acolumn = DEFAULT_ACOLUMN;
146 static char *acolumn_spaces;
147 static char *outfname = NULL;
149 struct tcb *printing_tcp = NULL;
151 static struct tcb **tcbtab;
152 static unsigned int nprocs, tcbtabsize;
153 static const char *progname;
155 static char *os_release; /* from uname() */
157 static int detach(struct tcb *tcp);
158 static int trace(void);
159 static void cleanup(void);
160 static void interrupt(int sig);
161 static sigset_t empty_set, blocked_set;
163 #ifdef HAVE_SIG_ATOMIC_T
164 static volatile sig_atomic_t interrupted;
166 static volatile int interrupted;
171 static struct tcb *pfd2tcb(int pfd);
172 static void reaper(int sig);
173 static void rebuild_pollv(void);
174 static struct pollfd *pollv;
176 #ifndef HAVE_POLLABLE_PROCFS
178 static void proc_poll_open(void);
179 static void proc_poller(int pfd);
187 static int poller_pid;
188 static int proc_poll_pipe[2] = { -1, -1 };
190 #endif /* !HAVE_POLLABLE_PROCFS */
192 #ifdef HAVE_MP_PROCFS
193 #define POLLWANT POLLWRNORM
195 #define POLLWANT POLLPRI
197 #endif /* USE_PROCFS */
200 usage(FILE *ofp, int exitval)
203 usage: strace [-CdDffhiqrtttTvVxxy] [-I n] [-a column] [-e expr]... [-o file]\n\
204 [-p pid]... [-s strsize] [-u username] [-E var=val]...\n\
205 [-P path] [PROG [ARGS]]]\n\
206 or: strace -c [-D] [-I n] [-e expr]... [-O overhead] [-S sortby] [-E var=val]...\n\
208 -c -- count time, calls, and errors for each syscall and report summary\n\
209 -C -- like -c but also print regular output while processes are running\n\
210 -D -- run tracer process as a detached grandchild, not as parent\n\
211 -f -- follow forks, -ff -- with output into separate files\n\
212 -F -- attempt to follow vforks, -h -- print help message\n\
213 -i -- print instruction pointer at time of syscall\n\
215 1: no signals are blocked\n\
216 2: fatal signals are blocked while decoding syscall (default)\n\
217 3: fatal signals are always blocked (default if '-o FILE PROG')\n\
218 4: fatal signals and SIGTSTP (^Z) are always blocked\n\
219 (useful to make 'strace -o FILE PROG' not stop on ^Z)\n\
220 -q -- suppress messages about attaching, detaching, etc.\n\
221 -r -- print relative timestamp, -t -- absolute timestamp, -tt -- with usecs\n\
222 -T -- print time spent in each syscall, -V -- print version\n\
223 -v -- verbose mode: print unabbreviated argv, stat, termio[s], etc. args\n\
224 -x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
225 -y -- print paths associated with file descriptor arguments\n\
226 -a column -- alignment COLUMN for printing syscall results (default %d)\n\
227 -e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
228 options: trace, abbrev, verbose, raw, signal, read, or write\n\
229 -o file -- send trace output to FILE instead of stderr\n\
230 -O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
231 -p pid -- trace process with process id PID, may be repeated\n\
232 -s strsize -- limit length of print strings to STRSIZE chars (default %d)\n\
233 -S sortby -- sort syscall counts by: time, calls, name, nothing (default %s)\n\
234 -u username -- run command as username handling setuid and/or setgid\n\
235 -E var=val -- put var=val in the environment for command\n\
236 -E var -- remove var from the environment for command\n\
237 -P path -- trace accesses to path\n\
238 " /* this is broken, so don't document it
239 -z -- print only succeeding syscalls\n\
241 , DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
245 static void die(void) __attribute__ ((noreturn));
246 static void die(void)
248 if (strace_tracer_pid == getpid()) {
255 static void verror_msg(int err_no, const char *fmt, va_list p)
261 /* We want to print entire message with single fprintf to ensure
262 * message integrity if stderr is shared with other programs.
263 * Thus we use vasprintf + single fprintf.
266 if (vasprintf(&msg, fmt, p) >= 0) {
268 fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(err_no));
270 fprintf(stderr, "%s: %s\n", progname, msg);
273 /* malloc in vasprintf failed, try it without malloc */
274 fprintf(stderr, "%s: ", progname);
275 vfprintf(stderr, fmt, p);
277 fprintf(stderr, ": %s\n", strerror(err_no));
281 /* We don't switch stderr to buffered, thus fprintf(stderr)
282 * always flushes its output and this is not necessary: */
283 /* fflush(stderr); */
286 void error_msg(const char *fmt, ...)
290 verror_msg(0, fmt, p);
294 void error_msg_and_die(const char *fmt, ...)
298 verror_msg(0, fmt, p);
302 void perror_msg(const char *fmt, ...)
306 verror_msg(errno, fmt, p);
310 void perror_msg_and_die(const char *fmt, ...)
314 verror_msg(errno, fmt, p);
318 void die_out_of_memory(void)
320 static bool recursed = 0;
324 error_msg_and_die("Out of memory");
336 /* Glue for systems without a MMU that cannot provide fork() */
338 # define strace_vforked 0
340 # define strace_vforked 1
341 # define fork() vfork()
346 ptrace_attach_or_seize(int pid)
350 return ptrace(PTRACE_ATTACH, pid, 0, 0);
351 r = ptrace(PTRACE_SEIZE, pid, 0, PTRACE_SEIZE_DEVEL);
354 r = ptrace(PTRACE_INTERRUPT, pid, 0, 0);
358 # define ptrace_attach_or_seize(pid) ptrace(PTRACE_ATTACH, (pid), 0, 0)
362 set_cloexec_flag(int fd)
366 flags = fcntl(fd, F_GETFD);
368 /* Can happen only if fd is bad.
369 * Should never happen: if it does, we have a bug
370 * in the caller. Therefore we just abort
371 * instead of propagating the error.
373 perror_msg_and_die("fcntl(%d, F_GETFD)", fd);
376 newflags = flags | FD_CLOEXEC;
377 if (flags == newflags)
380 fcntl(fd, F_SETFD, newflags); /* never fails */
384 * When strace is setuid executable, we have to swap uids
385 * before and after filesystem and process management operations.
391 int euid = geteuid(), uid = getuid();
393 if (euid != uid && setreuid(euid, uid) < 0) {
394 perror_msg_and_die("setreuid");
400 # define fopen_for_output fopen64
402 # define fopen_for_output fopen
406 strace_fopen(const char *path)
411 fp = fopen_for_output(path, "w");
413 perror_msg_and_die("Can't fopen '%s'", path);
415 set_cloexec_flag(fileno(fp));
419 static int popen_pid = 0;
422 # define _PATH_BSHELL "/bin/sh"
426 * We cannot use standard popen(3) here because we have to distinguish
427 * popen child process from other processes we trace, and standard popen(3)
428 * does not export its child's pid.
431 strace_popen(const char *command)
438 perror_msg_and_die("pipe");
440 set_cloexec_flag(fds[1]); /* never fails */
444 perror_msg_and_die("vfork");
446 if (popen_pid == 0) {
451 perror_msg_and_die("dup2");
454 execl(_PATH_BSHELL, "sh", "-c", command, NULL);
455 perror_msg_and_die("Can't execute '%s'", _PATH_BSHELL);
461 fp = fdopen(fds[1], "w");
468 newoutf(struct tcb *tcp)
470 if (outfname && followfork > 1) {
471 char name[520 + sizeof(int) * 3];
472 sprintf(name, "%.512s.%u", outfname, tcp->pid);
473 tcp->outf = strace_fopen(name);
484 * Block user interruptions as we would leave the traced
485 * process stopped (process state T) if we would terminate in
486 * between PTRACE_ATTACH and wait4() on SIGSTOP.
487 * We rely on cleanup() from this point on.
490 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
492 if (daemonized_tracer) {
495 perror_msg_and_die("fork");
497 if (pid) { /* parent */
499 * Wait for grandchild to attach to straced process
500 * (grandparent). Grandchild SIGKILLs us after it attached.
501 * Grandparent's wait() is unblocked by our death,
502 * it proceeds to exec the straced program.
505 _exit(0); /* paranoia */
508 /* We will be the tracer process. Remember our new pid: */
509 strace_tracer_pid = getpid();
512 for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
515 /* Is this a process we should attach to, but not yet attached? */
516 if ((tcp->flags & (TCB_ATTACHED | TCB_STARTUP)) != TCB_ATTACHED)
519 /* Reinitialize the output since it may have changed */
524 if (proc_open(tcp, 1) < 0) {
525 fprintf(stderr, "trouble opening proc file\n");
529 #else /* !USE_PROCFS */
531 if (followfork && !daemonized_tracer) {
532 char procdir[sizeof("/proc/%d/task") + sizeof(int) * 3];
535 sprintf(procdir, "/proc/%d/task", tcp->pid);
536 dir = opendir(procdir);
538 unsigned int ntid = 0, nerr = 0;
541 while ((de = readdir(dir)) != NULL) {
545 if (de->d_fileno == 0)
547 tid = atoi(de->d_name);
551 if (ptrace_attach_or_seize(tid) < 0) {
554 fprintf(stderr, "attach to pid %d failed\n", tid);
558 fprintf(stderr, "attach to pid %d succeeded\n", tid);
561 cur_tcp = alloctcb(tid);
562 cur_tcp->flags |= TCB_ATTACHED | TCB_STARTUP | post_attach_sigstop;
566 sigprocmask(SIG_SETMASK, &empty_set, NULL);
569 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
573 perror("attach: ptrace(PTRACE_ATTACH, ...)");
578 fprintf(stderr, ntid > 1
579 ? "Process %u attached with %u threads - interrupt to quit\n"
580 : "Process %u attached - interrupt to quit\n",
583 if (!(tcp->flags & TCB_STARTUP)) {
584 /* -p PID, we failed to attach to PID itself
585 * but did attach to some of its sibling threads.
591 } /* if (opendir worked) */
594 if (ptrace_attach_or_seize(tcp->pid) < 0) {
595 perror("attach: ptrace(PTRACE_ATTACH, ...)");
599 tcp->flags |= TCB_STARTUP | post_attach_sigstop;
601 fprintf(stderr, "attach to pid %d (main) succeeded\n", tcp->pid);
603 if (daemonized_tracer) {
605 * It is our grandparent we trace, not a -p PID.
606 * Don't want to just detach on exit, so...
608 tcp->flags &= ~TCB_ATTACHED;
610 * Make parent go away.
611 * Also makes grandparent's wait() unblock.
613 kill(getppid(), SIGKILL);
616 #endif /* !USE_PROCFS */
619 "Process %u attached - interrupt to quit\n",
621 } /* for each tcbtab[] */
625 sigprocmask(SIG_SETMASK, &empty_set, NULL);
629 startup_child(char **argv)
632 const char *filename;
633 char pathname[MAXPATHLEN];
638 if (strchr(filename, '/')) {
639 if (strlen(filename) > sizeof pathname - 1) {
640 errno = ENAMETOOLONG;
641 perror_msg_and_die("exec");
643 strcpy(pathname, filename);
645 #ifdef USE_DEBUGGING_EXEC
647 * Debuggers customarily check the current directory
648 * first regardless of the path but doing that gives
649 * security geeks a panic attack.
651 else if (stat(filename, &statbuf) == 0)
652 strcpy(pathname, filename);
653 #endif /* USE_DEBUGGING_EXEC */
658 for (path = getenv("PATH"); path && *path; path += m) {
659 const char *colon = strchr(path, ':');
665 m = n = strlen(path);
667 if (!getcwd(pathname, MAXPATHLEN))
669 len = strlen(pathname);
671 else if (n > sizeof pathname - 1)
674 strncpy(pathname, path, n);
677 if (len && pathname[len - 1] != '/')
678 pathname[len++] = '/';
679 strcpy(pathname + len, filename);
680 if (stat(pathname, &statbuf) == 0 &&
681 /* Accept only regular files
682 with some execute bits set.
683 XXX not perfect, might still fail */
684 S_ISREG(statbuf.st_mode) &&
685 (statbuf.st_mode & 0111))
689 if (stat(pathname, &statbuf) < 0) {
690 perror_msg_and_die("Can't stat '%s'", filename);
692 strace_child = pid = fork();
694 perror_msg_and_die("fork");
696 if ((pid != 0 && daemonized_tracer) /* -D: parent to become a traced process */
697 || (pid == 0 && !daemonized_tracer) /* not -D: child to become a traced process */
704 /* Kludge for SGI, see proc_open for details. */
705 sa.sa_handler = foobar;
707 sigemptyset(&sa.sa_mask);
708 sigaction(SIGINT, &sa, NULL);
715 #else /* !USE_PROCFS */
716 if (!daemonized_tracer && !use_seize) {
717 if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0) {
718 perror_msg_and_die("ptrace(PTRACE_TRACEME, ...)");
722 if (username != NULL) {
723 uid_t run_euid = run_uid;
724 gid_t run_egid = run_gid;
726 if (statbuf.st_mode & S_ISUID)
727 run_euid = statbuf.st_uid;
728 if (statbuf.st_mode & S_ISGID)
729 run_egid = statbuf.st_gid;
731 * It is important to set groups before we
732 * lose privileges on setuid.
734 if (initgroups(username, run_gid) < 0) {
735 perror_msg_and_die("initgroups");
737 if (setregid(run_gid, run_egid) < 0) {
738 perror_msg_and_die("setregid");
740 if (setreuid(run_uid, run_euid) < 0) {
741 perror_msg_and_die("setreuid");
744 else if (geteuid() != 0)
745 setreuid(run_uid, run_uid);
747 if (!daemonized_tracer) {
749 * Induce a ptrace stop. Tracer (our parent)
750 * will resume us with PTRACE_SYSCALL and display
751 * the immediately following execve syscall.
752 * Can't do this on NOMMU systems, we are after
753 * vfork: parent is blocked, stopping would deadlock.
758 struct sigaction sv_sigchld;
759 sigaction(SIGCHLD, NULL, &sv_sigchld);
761 * Make sure it is not SIG_IGN, otherwise wait
764 signal(SIGCHLD, SIG_DFL);
766 * Wait for grandchild to attach to us.
767 * It kills child after that, and wait() unblocks.
772 sigaction(SIGCHLD, &sv_sigchld, NULL);
774 #endif /* !USE_PROCFS */
776 execv(pathname, argv);
777 perror_msg_and_die("exec");
780 /* We are the tracer */
782 if (!daemonized_tracer) {
784 /* child did PTRACE_TRACEME, nothing to do in parent */
786 if (!strace_vforked) {
787 /* Wait until child stopped itself */
789 while (waitpid(pid, &status, WSTOPPED) < 0) {
792 perror_msg_and_die("waitpid");
794 if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
796 perror_msg_and_die("Unexpected wait status %x", status);
799 /* Else: vforked case, we have no way to sync.
800 * Just attach to it as soon as possible.
801 * This means that we may miss a few first syscalls...
804 if (ptrace_attach_or_seize(pid)) {
806 perror_msg_and_die("Can't attach to %d", pid);
813 tcp->flags |= TCB_STARTUP | post_attach_sigstop;
815 tcp->flags |= TCB_STARTUP;
818 /* With -D, *we* are child here, IOW: different pid. Fetch it: */
819 strace_tracer_pid = getpid();
820 /* The tracee is our parent: */
823 /* We want subsequent startup_attach() to attach to it: */
824 tcp->flags |= TCB_ATTACHED;
827 if (proc_open(tcp, 0) < 0) {
828 perror_msg_and_die("trouble opening proc file");
834 static void kill_save_errno(pid_t pid, int sig)
836 int saved_errno = errno;
838 (void) kill(pid, sig);
843 * Test whether the kernel support PTRACE_O_TRACECLONE et al options.
844 * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
845 * and then see which options are supported by the kernel.
848 test_ptrace_setoptions_followfork(void)
850 int pid, expected_grandchild = 0, found_grandchild = 0;
851 const unsigned int test_options = PTRACE_O_TRACECLONE |
857 perror_msg_and_die("fork");
860 if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0)
861 perror_msg_and_die("%s: PTRACE_TRACEME doesn't work",
865 perror_msg_and_die("fork");
870 int status, tracee_pid;
873 tracee_pid = wait(&status);
874 if (tracee_pid <= 0) {
877 else if (errno == ECHILD)
879 kill_save_errno(pid, SIGKILL);
880 perror_msg_and_die("%s: unexpected wait result %d",
881 __func__, tracee_pid);
883 if (WIFEXITED(status)) {
884 if (WEXITSTATUS(status)) {
885 if (tracee_pid != pid)
886 kill_save_errno(pid, SIGKILL);
887 error_msg_and_die("%s: unexpected exit status %u",
888 __func__, WEXITSTATUS(status));
892 if (WIFSIGNALED(status)) {
893 if (tracee_pid != pid)
894 kill_save_errno(pid, SIGKILL);
895 error_msg_and_die("%s: unexpected signal %u",
896 __func__, WTERMSIG(status));
898 if (!WIFSTOPPED(status)) {
899 if (tracee_pid != pid)
900 kill_save_errno(tracee_pid, SIGKILL);
902 error_msg_and_die("%s: unexpected wait status %x",
905 if (tracee_pid != pid) {
906 found_grandchild = tracee_pid;
907 if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0) {
908 kill_save_errno(tracee_pid, SIGKILL);
909 kill_save_errno(pid, SIGKILL);
910 perror_msg_and_die("PTRACE_CONT doesn't work");
914 switch (WSTOPSIG(status)) {
916 if (ptrace(PTRACE_SETOPTIONS, pid, 0, test_options) < 0
917 && errno != EINVAL && errno != EIO)
918 perror_msg("PTRACE_SETOPTIONS");
921 if (status >> 16 == PTRACE_EVENT_FORK) {
924 if (ptrace(PTRACE_GETEVENTMSG, pid,
925 NULL, (long) &msg) == 0)
926 expected_grandchild = msg;
930 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) {
931 kill_save_errno(pid, SIGKILL);
932 perror_msg_and_die("PTRACE_SYSCALL doesn't work");
935 if (expected_grandchild && expected_grandchild == found_grandchild) {
936 ptrace_setoptions |= test_options;
938 fprintf(stderr, "ptrace_setoptions = %#x\n",
942 error_msg("Test for PTRACE_O_TRACECLONE failed, "
943 "giving up using this feature.");
947 * Test whether the kernel support PTRACE_O_TRACESYSGOOD.
948 * First fork a new child, call ptrace(PTRACE_SETOPTIONS) on it,
949 * and then see whether it will stop with (SIGTRAP | 0x80).
951 * Use of this option enables correct handling of user-generated SIGTRAPs,
952 * and SIGTRAPs generated by special instructions such as int3 on x86:
953 * _start: .globl _start
958 * (compile with: "gcc -nostartfiles -nostdlib -o int3 int3.S")
961 test_ptrace_setoptions_for_all(void)
963 const unsigned int test_options = PTRACE_O_TRACESYSGOOD |
970 perror_msg_and_die("fork");
974 if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0)
975 /* Note: exits with exitcode 1 */
976 perror_msg_and_die("%s: PTRACE_TRACEME doesn't work",
979 _exit(0); /* parent should see entry into this syscall */
983 int status, tracee_pid;
986 tracee_pid = wait(&status);
987 if (tracee_pid <= 0) {
990 kill_save_errno(pid, SIGKILL);
991 perror_msg_and_die("%s: unexpected wait result %d",
992 __func__, tracee_pid);
994 if (WIFEXITED(status)) {
995 if (WEXITSTATUS(status) == 0)
997 error_msg_and_die("%s: unexpected exit status %u",
998 __func__, WEXITSTATUS(status));
1000 if (WIFSIGNALED(status)) {
1001 error_msg_and_die("%s: unexpected signal %u",
1002 __func__, WTERMSIG(status));
1004 if (!WIFSTOPPED(status)) {
1006 error_msg_and_die("%s: unexpected wait status %x",
1009 if (WSTOPSIG(status) == SIGSTOP) {
1011 * We don't check "options aren't accepted" error.
1012 * If it happens, we'll never get (SIGTRAP | 0x80),
1013 * and thus will decide to not use the option.
1014 * IOW: the outcome of the test will be correct.
1016 if (ptrace(PTRACE_SETOPTIONS, pid, 0L, test_options) < 0
1017 && errno != EINVAL && errno != EIO)
1018 perror_msg("PTRACE_SETOPTIONS");
1020 if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
1023 if (ptrace(PTRACE_SYSCALL, pid, 0L, 0L) < 0) {
1024 kill_save_errno(pid, SIGKILL);
1025 perror_msg_and_die("PTRACE_SYSCALL doesn't work");
1030 syscall_trap_sig = (SIGTRAP | 0x80);
1031 ptrace_setoptions |= test_options;
1033 fprintf(stderr, "ptrace_setoptions = %#x\n",
1038 error_msg("Test for PTRACE_O_TRACESYSGOOD failed, "
1039 "giving up using this feature.");
1044 test_ptrace_seize(void)
1050 perror_msg_and_die("fork");
1057 /* PTRACE_SEIZE, unlike ATTACH, doesn't force tracee to trap. After
1058 * attaching tracee continues to run unless a trap condition occurs.
1059 * PTRACE_SEIZE doesn't affect signal or group stop state.
1061 if (ptrace(PTRACE_SEIZE, pid, 0, PTRACE_SEIZE_DEVEL) == 0) {
1062 post_attach_sigstop = 0; /* this sets use_seize to 1 */
1064 fprintf(stderr, "PTRACE_SEIZE doesn't work\n");
1070 int status, tracee_pid;
1073 tracee_pid = waitpid(pid, &status, 0);
1074 if (tracee_pid <= 0) {
1077 perror_msg_and_die("%s: unexpected wait result %d",
1078 __func__, tracee_pid);
1080 if (WIFSIGNALED(status)) {
1083 error_msg_and_die("%s: unexpected wait status %x",
1087 # else /* !USE_SEIZE */
1088 # define test_ptrace_seize() ((void)0)
1093 /* Noinline: don't want main to have struct utsname permanently on stack */
1094 static void __attribute__ ((noinline))
1095 get_os_release(void)
1099 perror_msg_and_die("uname");
1100 os_release = strdup(u.release);
1102 die_out_of_memory();
1106 main(int argc, char *argv[])
1111 struct sigaction sa;
1113 progname = argv[0] ? argv[0] : "strace";
1115 strace_tracer_pid = getpid();
1119 /* Allocate the initial tcbtab. */
1120 tcbtabsize = argc; /* Surely enough for all -p args. */
1121 tcbtab = calloc(tcbtabsize, sizeof(tcbtab[0]));
1123 die_out_of_memory();
1124 tcp = calloc(tcbtabsize, sizeof(*tcp));
1126 die_out_of_memory();
1127 for (c = 0; c < tcbtabsize; c++)
1131 set_sortby(DEFAULT_SORTBY);
1132 set_personality(DEFAULT_PERSONALITY);
1133 qualify("trace=all");
1134 qualify("abbrev=all");
1135 qualify("verbose=all");
1136 qualify("signal=all");
1137 while ((c = getopt(argc, argv,
1142 "a:e:o:O:p:s:S:u:E:P:I:")) != EOF) {
1145 if (cflag == CFLAG_BOTH) {
1146 error_msg_and_die("-c and -C are mutually exclusive options");
1148 cflag = CFLAG_ONLY_STATS;
1151 if (cflag == CFLAG_ONLY_STATS) {
1152 error_msg_and_die("-c and -C are mutually exclusive options");
1161 daemonized_tracer = 1;
1196 qualify("abbrev=none");
1199 printf("%s -- version %s\n", PACKAGE_NAME, VERSION);
1203 not_failing_only = 1;
1206 acolumn = atoi(optarg);
1208 error_msg_and_die("Bad column width '%s'", optarg);
1214 outfname = strdup(optarg);
1217 set_overhead(atoi(optarg));
1222 error_msg("Invalid process id: '%s'", optarg);
1225 if (pid == strace_tracer_pid) {
1226 error_msg("I'm sorry, I can't let you do that, Dave.");
1229 tcp = alloc_tcb(pid, 0);
1230 tcp->flags |= TCB_ATTACHED;
1235 if (pathtrace_select(optarg)) {
1236 error_msg_and_die("Failed to select path '%s'", optarg);
1240 max_strlen = atoi(optarg);
1241 if (max_strlen < 0) {
1242 error_msg_and_die("Invalid -%c argument: '%s'", c, optarg);
1249 username = strdup(optarg);
1252 if (putenv(optarg) < 0)
1253 die_out_of_memory();
1256 opt_intr = atoi(optarg);
1257 if (opt_intr <= 0 || opt_intr >= NUM_INTR_OPTS) {
1258 error_msg_and_die("Invalid -%c argument: '%s'", c, optarg);
1267 /* argc -= optind; - no need, argc is not used below */
1269 acolumn_spaces = malloc(acolumn + 1);
1270 if (!acolumn_spaces)
1271 die_out_of_memory();
1272 memset(acolumn_spaces, ' ', acolumn);
1273 acolumn_spaces[acolumn] = '\0';
1275 /* Must have PROG [ARGS], or -p PID. Not both. */
1276 if (!argv[0] == !pflag_seen)
1279 if (pflag_seen && daemonized_tracer) {
1280 error_msg_and_die("-D and -p are mutually exclusive options");
1286 if (followfork > 1 && cflag) {
1287 error_msg_and_die("(-c or -C) and -ff are mutually exclusive options");
1290 /* See if they want to run as another user. */
1291 if (username != NULL) {
1292 struct passwd *pent;
1294 if (getuid() != 0 || geteuid() != 0) {
1295 error_msg_and_die("You must be root to use the -u option");
1297 pent = getpwnam(username);
1299 error_msg_and_die("Cannot find user '%s'", username);
1301 run_uid = pent->pw_uid;
1302 run_gid = pent->pw_gid;
1311 test_ptrace_setoptions_followfork();
1312 test_ptrace_setoptions_for_all();
1313 test_ptrace_seize();
1316 /* Check if they want to redirect the output. */
1318 /* See if they want to pipe the output. */
1319 if (outfname[0] == '|' || outfname[0] == '!') {
1321 * We can't do the <outfname>.PID funny business
1322 * when using popen, so prohibit it.
1325 error_msg_and_die("Piping the output and -ff are mutually exclusive");
1326 outf = strace_popen(outfname + 1);
1328 else if (followfork <= 1)
1329 outf = strace_fopen(outfname);
1332 if (!outfname || outfname[0] == '|' || outfname[0] == '!') {
1333 char *buf = malloc(BUFSIZ);
1335 die_out_of_memory();
1336 setvbuf(outf, buf, _IOLBF, BUFSIZ);
1338 if (outfname && argv[0]) {
1340 opt_intr = INTR_NEVER;
1344 opt_intr = INTR_WHILE_WAIT;
1346 /* argv[0] -pPID -oFILE Default interactive setting
1347 * yes 0 0 INTR_WHILE_WAIT
1348 * no 1 0 INTR_WHILE_WAIT
1349 * yes 0 1 INTR_NEVER
1350 * no 1 1 INTR_WHILE_WAIT
1353 /* STARTUP_CHILD must be called before the signal handlers get
1354 installed below as they are inherited into the spawned process.
1355 Also we do not need to be protected by them as during interruption
1356 in the STARTUP_CHILD mode we kill the spawned process anyway. */
1358 startup_child(argv);
1360 sigemptyset(&empty_set);
1361 sigemptyset(&blocked_set);
1362 sa.sa_handler = SIG_IGN;
1363 sigemptyset(&sa.sa_mask);
1365 sigaction(SIGTTOU, &sa, NULL); /* SIG_IGN */
1366 sigaction(SIGTTIN, &sa, NULL); /* SIG_IGN */
1367 if (opt_intr != INTR_ANYWHERE) {
1368 if (opt_intr == INTR_BLOCK_TSTP_TOO)
1369 sigaction(SIGTSTP, &sa, NULL); /* SIG_IGN */
1371 * In interactive mode (if no -o OUTFILE, or -p PID is used),
1372 * fatal signals are blocked while syscall stop is processed,
1373 * and acted on in between, when waiting for new syscall stops.
1374 * In non-interactive mode, signals are ignored.
1376 if (opt_intr == INTR_WHILE_WAIT) {
1377 sigaddset(&blocked_set, SIGHUP);
1378 sigaddset(&blocked_set, SIGINT);
1379 sigaddset(&blocked_set, SIGQUIT);
1380 sigaddset(&blocked_set, SIGPIPE);
1381 sigaddset(&blocked_set, SIGTERM);
1382 sa.sa_handler = interrupt;
1384 /* POSIX signals on sunos4.1 are a little broken. */
1385 sa.sa_flags = SA_INTERRUPT;
1388 /* SIG_IGN, or set handler for these */
1389 sigaction(SIGHUP, &sa, NULL);
1390 sigaction(SIGINT, &sa, NULL);
1391 sigaction(SIGQUIT, &sa, NULL);
1392 sigaction(SIGPIPE, &sa, NULL);
1393 sigaction(SIGTERM, &sa, NULL);
1396 sa.sa_handler = reaper;
1397 sigaction(SIGCHLD, &sa, NULL);
1399 /* Make sure SIGCHLD has the default action so that waitpid
1400 definitely works without losing track of children. The user
1401 should not have given us a bogus state to inherit, but he might
1402 have. Arguably we should detect SIG_IGN here and pass it on
1403 to children, but probably noone really needs that. */
1404 sa.sa_handler = SIG_DFL;
1405 sigaction(SIGCHLD, &sa, NULL);
1406 #endif /* USE_PROCFS */
1408 if (pflag_seen || daemonized_tracer)
1416 if (exit_code > 0xff) {
1417 /* Child was killed by a signal, mimic that. */
1419 signal(exit_code, SIG_DFL);
1421 /* Paranoia - what if this signal is not fatal?
1422 Exit with 128 + signo then. */
1431 /* Allocate some more TCBs and expand the table.
1432 We don't want to relocate the TCBs because our
1433 callers have pointers and it would be a pain.
1434 So tcbtab is a table of pointers. Since we never
1435 free the TCBs, we allocate a single chunk of many. */
1437 struct tcb *newtcbs = calloc(tcbtabsize, sizeof(newtcbs[0]));
1438 struct tcb **newtab = realloc(tcbtab, tcbtabsize * 2 * sizeof(tcbtab[0]));
1439 if (!newtab || !newtcbs)
1440 die_out_of_memory();
1443 while (i < tcbtabsize)
1444 tcbtab[i++] = newtcbs++;
1448 alloc_tcb(int pid, int command_options_parsed)
1453 if (nprocs == tcbtabsize)
1456 for (i = 0; i < tcbtabsize; i++) {
1458 if ((tcp->flags & TCB_INUSE) == 0) {
1459 memset(tcp, 0, sizeof(*tcp));
1461 tcp->flags = TCB_INUSE;
1462 tcp->outf = outf; /* Initialise to current out file */
1463 #if SUPPORTED_PERSONALITIES > 1
1464 tcp->currpers = current_personality;
1471 fprintf(stderr, "new tcb for pid %d, active tcbs:%d\n", tcp->pid, nprocs);
1472 if (command_options_parsed)
1477 error_msg_and_die("bug in alloc_tcb");
1482 proc_open(struct tcb *tcp, int attaching)
1492 #ifndef HAVE_POLLABLE_PROCFS
1493 static int last_pfd;
1496 #ifdef HAVE_MP_PROCFS
1497 /* Open the process pseudo-files in /proc. */
1498 sprintf(proc, "/proc/%d/ctl", tcp->pid);
1499 tcp->pfd = open(proc, O_WRONLY|O_EXCL);
1501 perror("strace: open(\"/proc/...\", ...)");
1504 set_cloexec_flag(tcp->pfd);
1505 sprintf(proc, "/proc/%d/status", tcp->pid);
1506 tcp->pfd_stat = open(proc, O_RDONLY|O_EXCL);
1507 if (tcp->pfd_stat < 0) {
1508 perror("strace: open(\"/proc/...\", ...)");
1511 set_cloexec_flag(tcp->pfd_stat);
1512 sprintf(proc, "/proc/%d/as", tcp->pid);
1513 tcp->pfd_as = open(proc, O_RDONLY|O_EXCL);
1514 if (tcp->pfd_as < 0) {
1515 perror("strace: open(\"/proc/...\", ...)");
1518 set_cloexec_flag(tcp->pfd_as);
1520 /* Open the process pseudo-file in /proc. */
1522 sprintf(proc, "/proc/%d", tcp->pid);
1523 tcp->pfd = open(proc, O_RDWR|O_EXCL);
1525 sprintf(proc, "/proc/%d/mem", tcp->pid);
1526 tcp->pfd = open(proc, O_RDWR);
1529 perror("strace: open(\"/proc/...\", ...)");
1532 set_cloexec_flag(tcp->pfd);
1535 sprintf(proc, "/proc/%d/regs", tcp->pid);
1536 tcp->pfd_reg = open(proc, O_RDONLY);
1537 if (tcp->pfd_reg < 0) {
1538 perror("strace: open(\"/proc/.../regs\", ...)");
1542 sprintf(proc, "/proc/%d/status", tcp->pid);
1543 tcp->pfd_status = open(proc, O_RDONLY);
1544 if (tcp->pfd_status < 0) {
1545 perror("strace: open(\"/proc/.../status\", ...)");
1549 tcp->pfd_status = -1;
1550 #endif /* FREEBSD */
1554 * Wait for the child to pause. Because of a race
1555 * condition we have to poll for the event.
1558 if (IOCTL_STATUS(tcp) < 0) {
1559 perror("strace: PIOCSTATUS");
1562 if (tcp->status.PR_FLAGS & PR_ASLEEP)
1567 /* Stop the process so that we own the stop. */
1568 if (IOCTL(tcp->pfd, PIOCSTOP, (char *)NULL) < 0) {
1569 perror("strace: PIOCSTOP");
1574 /* Set Run-on-Last-Close. */
1576 if (IOCTL(tcp->pfd, PIOCSET, &arg) < 0) {
1577 perror("PIOCSET PR_RLC");
1580 /* Set or Reset Inherit-on-Fork. */
1582 if (IOCTL(tcp->pfd, followfork ? PIOCSET : PIOCRESET, &arg) < 0) {
1583 perror("PIOC{SET,RESET} PR_FORK");
1586 #else /* !PIOCSET */
1588 if (ioctl(tcp->pfd, PIOCSRLC) < 0) {
1592 if (ioctl(tcp->pfd, followfork ? PIOCSFORK : PIOCRFORK) < 0) {
1593 perror("PIOC{S,R}FORK");
1597 /* just unset the PF_LINGER flag for the Run-on-Last-Close. */
1598 if (ioctl(tcp->pfd, PIOCGFL, &arg) < 0) {
1603 if (ioctl(tcp->pfd, PIOCSFL, arg) < 0) {
1607 #endif /* FREEBSD */
1608 #endif /* !PIOCSET */
1610 /* Enable all syscall entries we care about. */
1611 premptyset(&syscalls);
1612 for (i = 1; i < MAX_QUALS; ++i) {
1613 if (i > (sizeof syscalls) * CHAR_BIT) break;
1614 if (qual_flags[i] & QUAL_TRACE) praddset(&syscalls, i);
1616 praddset(&syscalls, SYS_execve);
1618 praddset(&syscalls, SYS_fork);
1620 praddset(&syscalls, SYS_forkall);
1623 praddset(&syscalls, SYS_fork1);
1626 praddset(&syscalls, SYS_rfork1);
1629 praddset(&syscalls, SYS_rforkall);
1632 if (IOCTL(tcp->pfd, PIOCSENTRY, &syscalls) < 0) {
1633 perror("PIOCSENTRY");
1636 /* Enable the syscall exits. */
1637 if (IOCTL(tcp->pfd, PIOCSEXIT, &syscalls) < 0) {
1641 /* Enable signals we care about. */
1642 premptyset(&signals);
1643 for (i = 1; i < MAX_QUALS; ++i) {
1644 if (i > (sizeof signals) * CHAR_BIT) break;
1645 if (qual_flags[i] & QUAL_SIGNAL) praddset(&signals, i);
1647 if (IOCTL(tcp->pfd, PIOCSTRACE, &signals) < 0) {
1648 perror("PIOCSTRACE");
1651 /* Enable faults we care about */
1652 premptyset(&faults);
1653 for (i = 1; i < MAX_QUALS; ++i) {
1654 if (i > (sizeof faults) * CHAR_BIT) break;
1655 if (qual_flags[i] & QUAL_FAULT) praddset(&faults, i);
1657 if (IOCTL(tcp->pfd, PIOCSFAULT, &faults) < 0) {
1658 perror("PIOCSFAULT");
1662 /* set events flags. */
1663 arg = S_SIG | S_SCE | S_SCX;
1664 if (ioctl(tcp->pfd, PIOCBIS, arg) < 0) {
1668 #endif /* FREEBSD */
1672 * The SGI PRSABORT doesn't work for pause() so
1673 * we send it a caught signal to wake it up.
1675 kill(tcp->pid, SIGINT);
1678 /* The child is in a pause(), abort it. */
1680 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0) {
1687 /* wake up the child if it received the SIGSTOP */
1688 kill(tcp->pid, SIGCONT);
1691 /* Wait for the child to do something. */
1692 if (IOCTL_WSTOP(tcp) < 0) {
1693 perror("PIOCWSTOP");
1696 if (tcp->status.PR_WHY == PR_SYSENTRY) {
1697 tcp->flags &= ~TCB_INSYSCALL;
1699 if (known_scno(tcp) == SYS_execve)
1702 /* Set it running: maybe execve will be next. */
1705 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0)
1707 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0)
1714 /* handle the case where we "opened" the child before
1715 it did the kill -STOP */
1716 if (tcp->status.PR_WHY == PR_SIGNALLED &&
1717 tcp->status.PR_WHAT == SIGSTOP)
1718 kill(tcp->pid, SIGCONT);
1724 if (attaching < 2) {
1725 /* We are attaching to an already running process.
1726 * Try to figure out the state of the process in syscalls,
1727 * to handle the first event well.
1728 * This is done by having a look at the "wchan" property of the
1729 * process, which tells where it is stopped (if it is). */
1731 char wchan[20]; /* should be enough */
1733 sprintf(proc, "/proc/%d/status", tcp->pid);
1734 status = fopen(proc, "r");
1736 (fscanf(status, "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d"
1737 "%*d,%*d %*d,%*d %19s", wchan) == 1) &&
1738 strcmp(wchan, "nochan") && strcmp(wchan, "spread") &&
1739 strcmp(wchan, "stopevent")) {
1740 /* The process is asleep in the middle of a syscall.
1741 Fake the syscall entry event */
1742 tcp->flags &= ~(TCB_INSYSCALL|TCB_STARTUP);
1743 tcp->status.PR_WHY = PR_SYSENTRY;
1748 } /* otherwise it's a fork being followed */
1750 #endif /* FREEBSD */
1751 #ifndef HAVE_POLLABLE_PROCFS
1752 if (proc_poll_pipe[0] != -1)
1753 proc_poller(tcp->pfd);
1754 else if (nprocs > 1) {
1756 proc_poller(last_pfd);
1757 proc_poller(tcp->pfd);
1759 last_pfd = tcp->pfd;
1760 #endif /* !HAVE_POLLABLE_PROCFS */
1764 #endif /* USE_PROCFS */
1774 for (i = 0; i < tcbtabsize; i++) {
1775 struct tcb *tcp = tcbtab[i];
1776 if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
1786 first_used_tcb(void)
1790 for (i = 0; i < tcbtabsize; i++) {
1792 if (tcp->flags & TCB_INUSE)
1803 for (i = 0; i < tcbtabsize; i++) {
1804 struct tcb *tcp = tcbtab[i];
1805 if (tcp->pfd != pfd)
1807 if (tcp->flags & TCB_INUSE)
1813 #endif /* USE_PROCFS */
1816 droptcb(struct tcb *tcp)
1823 fprintf(stderr, "dropped tcb for pid %d, %d remain\n", tcp->pid, nprocs);
1826 if (tcp->pfd != -1) {
1830 if (tcp->pfd_reg != -1) {
1831 close(tcp->pfd_reg);
1834 if (tcp->pfd_status != -1) {
1835 close(tcp->pfd_status);
1836 tcp->pfd_status = -1;
1839 tcp->flags = 0; /* rebuild_pollv needs it */
1844 if (outfname && followfork > 1 && tcp->outf)
1847 memset(tcp, 0, sizeof(*tcp));
1850 /* detach traced process; continue with sig
1851 Never call DETACH twice on the same process as both unattached and
1852 attached-unstopped processes give the same ESRCH. For unattached process we
1853 would SIGSTOP it and wait for its SIGSTOP notification forever. */
1856 detach(struct tcb *tcp)
1860 int status, catch_sigstop;
1863 if (tcp->flags & TCB_BPTSET)
1868 * Linux wrongly insists the child be stopped
1869 * before detaching. Arghh. We go through hoops
1870 * to make a clean break of things.
1873 #undef PTRACE_DETACH
1874 #define PTRACE_DETACH PTRACE_SUNDETACH
1877 * We attached but possibly didn't see the expected SIGSTOP.
1878 * We must catch exactly one as otherwise the detached process
1879 * would be left stopped (process state T).
1881 catch_sigstop = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP);
1882 error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, 0);
1884 /* On a clear day, you can see forever. */
1886 else if (errno != ESRCH) {
1887 /* Shouldn't happen. */
1888 perror("detach: ptrace(PTRACE_DETACH, ...)");
1890 else if (my_tkill(tcp->pid, 0) < 0) {
1892 perror("detach: checking sanity");
1894 else if (!catch_sigstop && my_tkill(tcp->pid, SIGSTOP) < 0) {
1896 perror("detach: stopping child");
1900 if (catch_sigstop) {
1903 if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
1904 if (errno == ECHILD) /* Already gone. */
1906 if (errno != EINVAL) {
1907 perror("detach: waiting");
1911 /* No __WALL here. */
1912 if (waitpid(tcp->pid, &status, 0) < 0) {
1913 if (errno != ECHILD) {
1914 perror("detach: waiting");
1918 /* If no processes, try clones. */
1919 if (wait4(tcp->pid, &status, __WCLONE,
1921 if (errno != ECHILD)
1922 perror("detach: waiting");
1925 #endif /* __WCLONE */
1930 if (!WIFSTOPPED(status)) {
1931 /* Au revoir, mon ami. */
1934 if (WSTOPSIG(status) == SIGSTOP) {
1935 ptrace_restart(PTRACE_DETACH, tcp, 0);
1938 error = ptrace_restart(PTRACE_CONT, tcp,
1939 WSTOPSIG(status) == syscall_trap_sig ? 0
1940 : WSTOPSIG(status));
1948 /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */
1949 error = ptrace_restart(PTRACE_DETACH, tcp, 0);
1953 fprintf(stderr, "Process %u detached\n", tcp->pid);
1962 static void reaper(int sig)
1967 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
1971 #endif /* USE_PROCFS */
1980 /* 'interrupted' is a volatile object, fetch it only once */
1981 fatal_sig = interrupted;
1983 fatal_sig = SIGTERM;
1985 for (i = 0; i < tcbtabsize; i++) {
1987 if (!(tcp->flags & TCB_INUSE))
1991 "cleanup: looking at pid %u\n", tcp->pid);
1993 (!outfname || followfork < 2 || printing_tcp == tcp)) {
1994 tprints(" <unfinished ...>\n");
1995 printing_tcp = NULL;
1997 if (tcp->flags & TCB_ATTACHED)
2000 kill(tcp->pid, SIGCONT);
2001 kill(tcp->pid, fatal_sig);
2014 #ifndef HAVE_STRERROR
2016 #if !HAVE_DECL_SYS_ERRLIST
2017 extern int sys_nerr;
2018 extern char *sys_errlist[];
2019 #endif /* HAVE_DECL_SYS_ERRLIST */
2022 strerror(int err_no)
2024 static char buf[64];
2026 if (err_no < 1 || err_no >= sys_nerr) {
2027 sprintf(buf, "Unknown error %d", err_no);
2030 return sys_errlist[err_no];
2033 #endif /* HAVE_STERRROR */
2035 #ifndef HAVE_STRSIGNAL
2037 #if defined HAVE_SYS_SIGLIST && !defined HAVE_DECL_SYS_SIGLIST
2038 extern char *sys_siglist[];
2040 #if defined HAVE_SYS__SIGLIST && !defined HAVE_DECL__SYS_SIGLIST
2041 extern char *_sys_siglist[];
2047 static char buf[64];
2049 if (sig < 1 || sig >= NSIG) {
2050 sprintf(buf, "Unknown signal %d", sig);
2053 #ifdef HAVE__SYS_SIGLIST
2054 return _sys_siglist[sig];
2056 return sys_siglist[sig];
2060 #endif /* HAVE_STRSIGNAL */
2070 pollv = malloc(nprocs * sizeof(pollv[0]));
2072 die_out_of_memory();
2074 for (i = j = 0; i < tcbtabsize; i++) {
2075 struct tcb *tcp = tcbtab[i];
2076 if (!(tcp->flags & TCB_INUSE))
2078 pollv[j].fd = tcp->pfd;
2079 pollv[j].events = POLLWANT;
2083 error_msg_and_die("proc miscount");
2087 #ifndef HAVE_POLLABLE_PROCFS
2090 proc_poll_open(void)
2094 if (pipe(proc_poll_pipe) < 0) {
2095 perror_msg_and_die("pipe");
2097 for (i = 0; i < 2; i++) {
2098 set_cloexec_flag(proc_poll_pipe[i]);
2103 proc_poll(struct pollfd *pollv, int nfds, int timeout)
2107 struct proc_pollfd pollinfo;
2109 n = read(proc_poll_pipe[0], &pollinfo, sizeof(pollinfo));
2112 if (n != sizeof(struct proc_pollfd)) {
2113 error_msg_and_die("panic: short read: %d", n);
2115 for (i = 0; i < nprocs; i++) {
2116 if (pollv[i].fd == pollinfo.fd)
2117 pollv[i].revents = pollinfo.revents;
2119 pollv[i].revents = 0;
2121 poller_pid = pollinfo.pid;
2126 wakeup_handler(int sig)
2131 proc_poller(int pfd)
2133 struct proc_pollfd pollinfo;
2134 struct sigaction sa;
2135 sigset_t blocked_set, empty_set;
2140 struct procfs_status pfs;
2141 #endif /* FREEBSD */
2145 perror_msg_and_die("fork");
2152 sa.sa_handler = interactive ? SIG_DFL : SIG_IGN;
2154 sigemptyset(&sa.sa_mask);
2155 sigaction(SIGHUP, &sa, NULL);
2156 sigaction(SIGINT, &sa, NULL);
2157 sigaction(SIGQUIT, &sa, NULL);
2158 sigaction(SIGPIPE, &sa, NULL);
2159 sigaction(SIGTERM, &sa, NULL);
2160 sa.sa_handler = wakeup_handler;
2161 sigaction(SIGUSR1, &sa, NULL);
2162 sigemptyset(&blocked_set);
2163 sigaddset(&blocked_set, SIGUSR1);
2164 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2165 sigemptyset(&empty_set);
2167 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
2168 perror_msg_and_die("getrlimit(RLIMIT_NOFILE, ...)");
2171 for (i = 0; i < n; i++) {
2172 if (i != pfd && i != proc_poll_pipe[1])
2177 pollinfo.pid = getpid();
2180 if (ioctl(pfd, PIOCWSTOP, NULL) < 0)
2182 if (ioctl(pfd, PIOCWSTOP, &pfs) < 0)
2189 pollinfo.revents = POLLERR;
2192 pollinfo.revents = POLLHUP;
2195 perror("proc_poller: PIOCWSTOP");
2197 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2200 pollinfo.revents = POLLWANT;
2201 write(proc_poll_pipe[1], &pollinfo, sizeof(pollinfo));
2202 sigsuspend(&empty_set);
2206 #endif /* !HAVE_POLLABLE_PROCFS */
2216 if (followfork < 2 &&
2217 last < nprocs && (pollv[last].revents & POLLWANT)) {
2219 * The previous process is ready to run again. We'll
2220 * let it do so if it is currently in a syscall. This
2221 * heuristic improves the readability of the trace.
2223 tcp = pfd2tcb(pollv[last].fd);
2224 if (tcp && exiting(tcp))
2225 return pollv[last].fd;
2228 for (i = 0; i < nprocs; i++) {
2229 /* Let competing children run round robin. */
2230 j = (i + last + 1) % nprocs;
2231 if (pollv[j].revents & (POLLHUP | POLLERR)) {
2232 tcp = pfd2tcb(pollv[j].fd);
2234 error_msg_and_die("lost proc");
2239 if (pollv[j].revents & POLLWANT) {
2244 error_msg_and_die("nothing ready");
2251 struct tcb *in_syscall = NULL;
2256 int ioctl_result = 0, ioctl_errno = 0;
2261 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2268 #ifndef HAVE_POLLABLE_PROCFS
2269 if (proc_poll_pipe[0] == -1) {
2271 tcp = first_used_tcb();
2278 #ifndef HAVE_POLLABLE_PROCFS
2280 /* fall through ... */
2281 #endif /* !HAVE_POLLABLE_PROCFS */
2283 #ifdef HAVE_POLLABLE_PROCFS
2285 /* On some systems (e.g. UnixWare) we get too much ugly
2286 "unfinished..." stuff when multiple proceses are in
2287 syscalls. Here's a nasty hack */
2294 pv.events = POLLWANT;
2295 what = poll(&pv, 1, 1);
2301 else if (what == 1 && pv.revents & POLLWANT) {
2307 if (poll(pollv, nprocs, INFTIM) < 0) {
2312 #else /* !HAVE_POLLABLE_PROCFS */
2313 if (proc_poll(pollv, nprocs, INFTIM) < 0) {
2318 #endif /* !HAVE_POLLABLE_PROCFS */
2325 /* Look up `pfd' in our table. */
2328 error_msg_and_die("unknown pfd: %u", pfd);
2333 /* Get the status of the process. */
2336 ioctl_result = IOCTL_WSTOP(tcp);
2338 /* Thanks to some scheduling mystery, the first poller
2339 sometimes waits for the already processed end of fork
2340 event. Doing a non blocking poll here solves the problem. */
2341 if (proc_poll_pipe[0] != -1)
2342 ioctl_result = IOCTL_STATUS(tcp);
2344 ioctl_result = IOCTL_WSTOP(tcp);
2345 #endif /* FREEBSD */
2346 ioctl_errno = errno;
2347 #ifndef HAVE_POLLABLE_PROCFS
2348 if (proc_poll_pipe[0] != -1) {
2349 if (ioctl_result < 0)
2350 kill(poller_pid, SIGKILL);
2352 kill(poller_pid, SIGUSR1);
2354 #endif /* !HAVE_POLLABLE_PROCFS */
2360 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2362 if (ioctl_result < 0) {
2363 /* Find out what happened if it failed. */
2364 switch (ioctl_errno) {
2375 perror_msg_and_die("PIOCWSTOP");
2380 if ((tcp->flags & TCB_STARTUP) && (tcp->status.PR_WHY == PR_SYSEXIT)) {
2381 /* discard first event for a syscall we never entered */
2382 IOCTL(tcp->pfd, PIOCRUN, 0);
2387 /* clear the just started flag */
2388 tcp->flags &= ~TCB_STARTUP;
2390 /* set current output file */
2392 curcol = tcp->curcol;
2395 struct timeval stime;
2400 len = pread(tcp->pfd_status, buf, sizeof(buf) - 1, 0);
2404 "%*s %*d %*d %*d %*d %*d,%*d %*s %*d,%*d %*d,%*d %ld,%ld",
2405 &stime.tv_sec, &stime.tv_usec);
2407 stime.tv_sec = stime.tv_usec = 0;
2408 #else /* !FREEBSD */
2409 stime.tv_sec = tcp->status.pr_stime.tv_sec;
2410 stime.tv_usec = tcp->status.pr_stime.tv_nsec/1000;
2411 #endif /* !FREEBSD */
2412 tv_sub(&tcp->dtime, &stime, &tcp->stime);
2415 what = tcp->status.PR_WHAT;
2416 switch (tcp->status.PR_WHY) {
2419 if (tcp->status.PR_FLAGS & PR_ASLEEP) {
2420 tcp->status.PR_WHY = PR_SYSENTRY;
2421 if (trace_syscall(tcp) < 0) {
2422 error_msg_and_die("syscall trouble");
2426 #endif /* !FREEBSD */
2432 if (trace_syscall(tcp) < 0) {
2433 error_msg_and_die("syscall trouble");
2437 if (cflag != CFLAG_ONLY_STATS
2438 && (qual_flags[what] & QUAL_SIGNAL)) {
2440 tprintf("--- %s (%s) ---\n",
2441 signame(what), strsignal(what));
2442 printing_tcp = NULL;
2444 if (tcp->status.PR_INFO.si_signo == what) {
2446 tprints(" siginfo=");
2447 printsiginfo(&tcp->status.PR_INFO, 1);
2449 printing_tcp = NULL;
2455 if (cflag != CFLAGS_ONLY_STATS
2456 && (qual_flags[what] & QUAL_FAULT)) {
2458 tprintf("=== FAULT %d ===\n", what);
2459 printing_tcp = NULL;
2463 case 0: /* handle case we polled for nothing */
2467 error_msg_and_die("odd stop %d", tcp->status.PR_WHY);
2470 /* Remember current print column before continuing. */
2471 tcp->curcol = curcol;
2474 if (IOCTL(tcp->pfd, PIOCRUN, &arg) < 0)
2476 if (IOCTL(tcp->pfd, PIOCRUN, 0) < 0)
2479 perror_msg_and_die("PIOCRUN");
2485 #else /* !USE_PROCFS */
2492 struct rusage *rup = cflag ? &ru : NULL;
2494 static int wait4_options = __WALL;
2498 while (nprocs != 0) {
2509 sigprocmask(SIG_SETMASK, &empty_set, NULL);
2512 pid = wait4(-1, &status, wait4_options, rup);
2513 if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
2514 /* this kernel does not support __WALL */
2515 wait4_options &= ~__WALL;
2516 pid = wait4(-1, &status, wait4_options, rup);
2518 if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
2519 /* most likely a "cloned" process */
2520 pid = wait4(-1, &status, __WCLONE, rup);
2522 perror_msg("wait4(__WCLONE) failed");
2526 pid = wait4(-1, &status, 0, rup);
2527 # endif /* __WALL */
2530 pid = wait(&status);
2534 sigprocmask(SIG_BLOCK, &blocked_set, NULL);
2537 switch (wait_errno) {
2542 * We would like to verify this case
2543 * but sometimes a race in Solbourne's
2544 * version of SunOS sometimes reports
2545 * ECHILD before sending us SIGCHILD.
2550 perror("strace: wait");
2554 if (pid == popen_pid) {
2555 if (WIFEXITED(status) || WIFSIGNALED(status))
2560 event = ((unsigned)status >> 16);
2562 char buf[sizeof("WIFEXITED,exitcode=%u") + sizeof(int)*3 /*paranoia:*/ + 16];
2565 static const char *const event_names[] = {
2566 [PTRACE_EVENT_CLONE] = "CLONE",
2567 [PTRACE_EVENT_FORK] = "FORK",
2568 [PTRACE_EVENT_VFORK] = "VFORK",
2569 [PTRACE_EVENT_VFORK_DONE] = "VFORK_DONE",
2570 [PTRACE_EVENT_EXEC] = "EXEC",
2571 [PTRACE_EVENT_EXIT] = "EXIT",
2574 if (event < ARRAY_SIZE(event_names))
2575 e = event_names[event];
2577 sprintf(buf, "?? (%u)", event);
2580 fprintf(stderr, " PTRACE_EVENT_%s", e);
2584 if (WIFSIGNALED(status))
2586 sprintf(buf, "WIFSIGNALED,%ssig=%s",
2587 WCOREDUMP(status) ? "core," : "",
2588 signame(WTERMSIG(status)));
2590 sprintf(buf, "WIFSIGNALED,sig=%s",
2591 signame(WTERMSIG(status)));
2593 if (WIFEXITED(status))
2594 sprintf(buf, "WIFEXITED,exitcode=%u", WEXITSTATUS(status));
2595 if (WIFSTOPPED(status))
2596 sprintf(buf, "WIFSTOPPED,sig=%s", signame(WSTOPSIG(status)));
2598 if (WIFCONTINUED(status))
2599 strcpy(buf, "WIFCONTINUED");
2601 fprintf(stderr, " [wait(0x%04x) = %u] %s\n", status, pid, buf);
2604 /* Look up 'pid' in our table. */
2608 /* Under Linux, execve changes pid to thread leader's pid,
2609 * and we see this changed pid on EVENT_EXEC and later,
2610 * execve sysexit. Leader "disappears" without exit
2611 * notification. Let user know that, drop leader's tcb,
2612 * and fix up pid in execve thread's tcb.
2613 * Effectively, execve thread's tcb replaces leader's tcb.
2615 * BTW, leader is 'stuck undead' (doesn't report WIFEXITED
2616 * on exit syscall) in multithreaded programs exactly
2617 * in order to handle this case.
2619 * PTRACE_GETEVENTMSG returns old pid starting from Linux 3.0.
2620 * On 2.6 and earlier, it can return garbage.
2622 if (event == PTRACE_EVENT_EXEC && os_release[0] >= '3') {
2624 if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, (long) &old_pid) >= 0
2628 struct tcb *execve_thread = pid2tcb(old_pid);
2631 curcol = tcp->curcol;
2634 tprints(" <unfinished ...>\n");
2636 tprintf("+++ superseded by execve in pid %lu +++\n", old_pid);
2637 printing_tcp = NULL;
2640 if (execve_thread) {
2641 /* swap output FILEs (needed for -ff) */
2642 tcp->outf = execve_thread->outf;
2643 execve_thread->outf = outf;
2647 tcp = execve_thread;
2650 tcp->flags |= TCB_REPRINT;
2659 /* This is needed to go with the CLONE_PTRACE
2660 changes in process.c/util.c: we might see
2661 the child's initial trap before we see the
2662 parent return from the clone syscall.
2663 Leave the child suspended until the parent
2664 returns from its system call. Only then
2665 will we have the association of parent and
2666 child so that we know how to do clearbpt
2668 tcp = alloctcb(pid);
2669 tcp->flags |= TCB_ATTACHED | TCB_STARTUP | post_attach_sigstop;
2671 fprintf(stderr, "Process %d attached\n",
2675 /* This can happen if a clone call used
2676 CLONE_PTRACE itself. */
2679 if (WIFSTOPPED(status))
2680 ptrace(PTRACE_CONT, pid, (char *) 1, 0);
2681 error_msg_and_die("Unknown pid: %u", pid);
2684 /* set current output file */
2686 curcol = tcp->curcol;
2689 tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
2690 tcp->stime = ru.ru_stime;
2694 if (WIFSIGNALED(status)) {
2695 if (pid == strace_child)
2696 exit_code = 0x100 | WTERMSIG(status);
2697 if (cflag != CFLAG_ONLY_STATS
2698 && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)) {
2701 tprintf("+++ killed by %s %s+++\n",
2702 signame(WTERMSIG(status)),
2703 WCOREDUMP(status) ? "(core dumped) " : "");
2705 tprintf("+++ killed by %s +++\n",
2706 signame(WTERMSIG(status)));
2708 printing_tcp = NULL;
2714 if (WIFEXITED(status)) {
2715 if (pid == strace_child)
2716 exit_code = WEXITSTATUS(status);
2717 if (tcp == printing_tcp) {
2718 tprints(" <unfinished ...>\n");
2719 printing_tcp = NULL;
2721 if (!cflag /* && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL) */ ) {
2723 tprintf("+++ exited with %d +++\n", WEXITSTATUS(status));
2724 printing_tcp = NULL;
2730 if (!WIFSTOPPED(status)) {
2731 fprintf(stderr, "PANIC: pid %u not stopped\n", pid);
2736 /* Is this the very first time we see this tracee stopped? */
2737 if (tcp->flags & TCB_STARTUP) {
2739 fprintf(stderr, "pid %d has TCB_STARTUP, initializing it\n", tcp->pid);
2740 tcp->flags &= ~TCB_STARTUP;
2741 if (tcp->flags & TCB_BPTSET) {
2743 * One example is a breakpoint inherited from
2744 * parent through fork().
2746 if (clearbpt(tcp) < 0) {
2754 if (ptrace_setoptions) {
2756 fprintf(stderr, "setting opts %x on pid %d\n", ptrace_setoptions, tcp->pid);
2757 if (ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL, ptrace_setoptions) < 0) {
2758 if (errno != ESRCH) {
2759 /* Should never happen, really */
2760 perror_msg_and_die("PTRACE_SETOPTIONS");
2767 sig = WSTOPSIG(status);
2772 if (event == PTRACE_EVENT_STOP || event == PTRACE_EVENT_STOP1) {
2774 * PTRACE_INTERRUPT-stop or group-stop.
2775 * PTRACE_INTERRUPT-stop has sig == SIGTRAP here.
2787 goto restart_tracee_with_sig_0;
2790 /* Is this post-attach SIGSTOP?
2791 * Interestingly, the process may stop
2792 * with STOPSIG equal to some other signal
2793 * than SIGSTOP if we happend to attach
2794 * just before the process takes a signal.
2796 if (sig == SIGSTOP && (tcp->flags & TCB_IGNORE_ONE_SIGSTOP)) {
2798 fprintf(stderr, "ignored SIGSTOP on pid %d\n", tcp->pid);
2799 tcp->flags &= ~TCB_IGNORE_ONE_SIGSTOP;
2800 goto restart_tracee_with_sig_0;
2803 if (sig != syscall_trap_sig) {
2806 /* Nonzero (true) if tracee is stopped by signal
2807 * (as opposed to "tracee received signal").
2809 stopped = (ptrace(PTRACE_GETSIGINFO, pid, 0, (long) &si) < 0);
2813 if (cflag != CFLAG_ONLY_STATS
2814 && (qual_flags[sig] & QUAL_SIGNAL)) {
2815 #if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
2819 upeek(tcp, PT_CR_IPSR, &psr);
2820 upeek(tcp, PT_CR_IIP, &pc);
2823 pc += (psr >> PSR_RI) & 0x3;
2824 # define PC_FORMAT_STR " @ %lx"
2825 # define PC_FORMAT_ARG , pc
2827 # define PC_FORMAT_STR ""
2828 # define PC_FORMAT_ARG /* nothing */
2833 printsiginfo(&si, verbose(tcp));
2834 tprintf(" (%s)" PC_FORMAT_STR " ---\n",
2838 tprintf("--- %s by %s" PC_FORMAT_STR " ---\n",
2842 printing_tcp = NULL;
2847 /* It's signal-delivery-stop. Inject the signal */
2848 goto restart_tracee;
2850 /* It's group-stop */
2854 * This ends ptrace-stop, but does *not* end group-stop.
2855 * This makes stopping signals work properly on straced process
2856 * (that is, process really stops. It used to continue to run).
2858 if (ptrace_restart(PTRACE_LISTEN, tcp, 0) < 0) {
2864 /* We don't have PTRACE_LISTEN support... */
2866 goto restart_tracee;
2869 /* We handled quick cases, we are permitted to interrupt now. */
2873 /* This should be syscall entry or exit.
2874 * (Or it still can be that pesky post-execve SIGTRAP!)
2877 if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) {
2878 /* ptrace() failed in trace_syscall() with ESRCH.
2879 * Likely a result of process disappearing mid-flight.
2880 * Observed case: exit_group() terminating
2881 * all processes in thread group.
2883 if (tcp->flags & TCB_ATTACHED) {
2885 /* Do we have dangling line "syscall(param, param"?
2886 * Finish the line then.
2888 printing_tcp->flags |= TCB_REPRINT;
2889 tprints(" <unfinished ...>\n");
2890 printing_tcp = NULL;
2893 /* We assume that ptrace error was caused by process death.
2894 * We used to detach(tcp) here, but since we no longer
2895 * implement "detach before death" policy/hack,
2896 * we can let this process to report its death to us
2897 * normally, via WIFEXITED or WIFSIGNALED wait status.
2900 /* It's our real child (and we also trace it) */
2901 /* my_tkill(pid, SIGKILL); - why? */
2902 /* droptcb(tcp); - why? */
2906 restart_tracee_with_sig_0:
2909 /* Remember current print column before continuing. */
2910 tcp->curcol = curcol;
2911 if (ptrace_restart(PTRACE_SYSCALL, tcp, sig) < 0) {
2919 #endif /* !USE_PROCFS */
2922 tprintf(const char *fmt, ...)
2926 va_start(args, fmt);
2928 int n = vfprintf(outf, fmt, args);
2931 perror(outfname == NULL
2932 ? "<writing to pipe>" : outfname);
2940 tprints(const char *str)
2943 int n = fputs(str, outf);
2945 curcol += strlen(str);
2949 perror(outfname == NULL
2950 ? "<writing to pipe>" : outfname);
2955 printleader(struct tcb *tcp)
2958 if (printing_tcp->ptrace_errno) {
2959 if (printing_tcp->flags & TCB_INSYSCALL) {
2960 tprints(" <unavailable>) ");
2963 tprints("= ? <unavailable>\n");
2964 printing_tcp->ptrace_errno = 0;
2965 } else if (!outfname || followfork < 2 || printing_tcp == tcp) {
2966 printing_tcp->flags |= TCB_REPRINT;
2967 tprints(" <unfinished ...>\n");
2973 if ((followfork == 1 || pflag_seen > 1) && outfname)
2974 tprintf("%-5d ", tcp->pid);
2975 else if (nprocs > 1 && !outfname)
2976 tprintf("[pid %5u] ", tcp->pid);
2978 char str[sizeof("HH:MM:SS")];
2979 struct timeval tv, dtv;
2980 static struct timeval otv;
2982 gettimeofday(&tv, NULL);
2984 if (otv.tv_sec == 0)
2986 tv_sub(&dtv, &tv, &otv);
2987 tprintf("%6ld.%06ld ",
2988 (long) dtv.tv_sec, (long) dtv.tv_usec);
2991 else if (tflag > 2) {
2992 tprintf("%ld.%06ld ",
2993 (long) tv.tv_sec, (long) tv.tv_usec);
2996 time_t local = tv.tv_sec;
2997 strftime(str, sizeof(str), "%T", localtime(&local));
2999 tprintf("%s.%06ld ", str, (long) tv.tv_usec);
3001 tprintf("%s ", str);
3011 if (curcol < acolumn)
3012 tprints(acolumn_spaces + curcol);
3015 #ifdef HAVE_MP_PROCFS
3018 mp_ioctl(int fd, int cmd, void *arg, int size)
3020 struct iovec iov[2];
3023 iov[0].iov_base = &cmd;
3024 iov[0].iov_len = sizeof cmd;
3027 iov[1].iov_base = arg;
3028 iov[1].iov_len = size;
3031 return writev(fd, iov, n);