]> granicus.if.org Git - strace/blobdiff - strace.c
tests: add a test for -yy option
[strace] / strace.c
index 6e9ea91afb1b73fb7c343b6d6cd5e3da41da0d71..cb9675856fda13360e735e50a2347a83397ffe3f 100644 (file)
--- a/strace.c
+++ b/strace.c
@@ -50,6 +50,10 @@ extern char **environ;
 extern int optind;
 extern char *optarg;
 
+#ifdef USE_LIBUNWIND
+/* if this is true do the stack trace for every system call */
+bool stack_trace_enabled = false;
+#endif
 
 #if defined __NR_tkill
 # define my_tkill(tid, sig) syscall(__NR_tkill, (tid), (sig))
@@ -77,11 +81,12 @@ unsigned int xflag = 0;
 bool need_fork_exec_workarounds = 0;
 bool debug_flag = 0;
 bool Tflag = 0;
+bool iflag = 0;
+bool count_wallclock = 0;
 unsigned int qflag = 0;
 /* Which WSTOPSIG(status) value marks syscall traps? */
 static unsigned int syscall_trap_sig = SIGTRAP;
 static unsigned int tflag = 0;
-static bool iflag = 0;
 static bool rflag = 0;
 static bool print_pid_pfx = 0;
 
@@ -124,7 +129,7 @@ static int post_attach_sigstop = TCB_IGNORE_ONE_SIGSTOP;
 bool not_failing_only = 0;
 
 /* Show path associated with fd arguments */
-bool show_fd_path = 0;
+unsigned int show_fd_path = 0;
 
 static bool detach_on_execve = 0;
 /* Are we "strace PROG" and need to skip detach on first execve? */
@@ -158,7 +163,6 @@ static const char *progname;
 unsigned os_release; /* generated from uname()'s u.release */
 
 static void detach(struct tcb *tcp);
-static int trace(void);
 static void cleanup(void);
 static void interrupt(int sig);
 static sigset_t empty_set, blocked_set;
@@ -201,6 +205,7 @@ usage: strace [-CdffhiqrtttTvVxxy] [-I n] [-e expr]...\n\
               -p pid... / [-D] [-E var=val]... [-u username] PROG [ARGS]\n\
 -c -- count time, calls, and errors for each syscall and report summary\n\
 -C -- like -c but also print regular output\n\
+-w -- summarise syscall latency (default is system time)\n\
 -d -- enable debug output to stderr\n\
 -D -- run tracer process as a detached grandchild, not as parent\n\
 -f -- follow forks, -ff -- with output into separate files\n\
@@ -211,6 +216,7 @@ usage: strace [-CdffhiqrtttTvVxxy] [-I n] [-e expr]...\n\
 -v -- verbose mode: print unabbreviated argv, stat, termios, etc. args\n\
 -x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
 -y -- print paths associated with file descriptor arguments\n\
+-yy -- print ip:port pairs associated with socket file descriptors\n\
 -h -- print help message, -V -- print version\n\
 -a column -- alignment COLUMN for printing syscall results (default %d)\n\
 -b execve -- detach on this syscall\n\
@@ -232,6 +238,10 @@ usage: strace [-CdffhiqrtttTvVxxy] [-I n] [-e expr]...\n\
 -E var -- remove var from the environment for command\n\
 -P path -- trace accesses to path\n\
 "
+#ifdef USE_LIBUNWIND
+"-k obtain stack trace between each syscall (experimental)\n\
+"
+#endif
 /* ancient, no one should use it
 -F -- attempt to follow vforks (deprecated, use -f)\n\
  */
@@ -336,11 +346,11 @@ ptrace_attach_or_seize(int pid)
 {
        int r;
        if (!use_seize)
-               return ptrace(PTRACE_ATTACH, pid, 0, 0);
-       r = ptrace(PTRACE_SEIZE, pid, 0, 0);
+               return ptrace(PTRACE_ATTACH, pid, 0L, 0L);
+       r = ptrace(PTRACE_SEIZE, pid, 0L, (unsigned long)ptrace_setoptions);
        if (r)
                return r;
-       r = ptrace(PTRACE_INTERRUPT, pid, 0, 0);
+       r = ptrace(PTRACE_INTERRUPT, pid, 0L, 0L);
        return r;
 }
 #else
@@ -439,8 +449,12 @@ swap_uid(void)
        }
 }
 
-#if _LFS64_LARGEFILE
-# define fopen_for_output fopen64
+#ifdef _LARGEFILE64_SOURCE
+# ifdef HAVE_FOPEN64
+#  define fopen_for_output fopen64
+# else
+#  define fopen_for_output fopen
+# endif
 # define struct_stat struct stat64
 # define stat_file stat64
 # define struct_dirent struct dirent64
@@ -486,6 +500,7 @@ static FILE *
 strace_popen(const char *command)
 {
        FILE *fp;
+       int pid;
        int fds[2];
 
        swap_uid();
@@ -494,11 +509,11 @@ strace_popen(const char *command)
 
        set_cloexec_flag(fds[1]); /* never fails */
 
-       popen_pid = vfork();
-       if (popen_pid == -1)
+       pid = vfork();
+       if (pid < 0)
                perror_msg_and_die("vfork");
 
-       if (popen_pid == 0) {
+       if (pid == 0) {
                /* child */
                close(fds[1]);
                if (fds[0] != 0) {
@@ -511,6 +526,7 @@ strace_popen(const char *command)
        }
 
        /* parent */
+       popen_pid = pid;
        close(fds[0]);
        swap_uid();
        fp = fdopen(fds[1], "w");
@@ -536,6 +552,10 @@ tprintf(const char *fmt, ...)
        va_end(args);
 }
 
+#ifndef HAVE_FPUTS_UNLOCKED
+# define fputs_unlocked fputs
+#endif
+
 void
 tprints(const char *str)
 {
@@ -623,7 +643,7 @@ printleader(struct tcb *tcp)
                }
        }
        if (iflag)
-               printcall(tcp);
+               print_pc(tcp);
 }
 
 void
@@ -656,7 +676,7 @@ expand_tcbtab(void)
           callers have pointers and it would be a pain.
           So tcbtab is a table of pointers.  Since we never
           free the TCBs, we allocate a single chunk of many.  */
-       int i = tcbtabsize;
+       unsigned int i = tcbtabsize;
        struct tcb *newtcbs = calloc(tcbtabsize, sizeof(newtcbs[0]));
        struct tcb **newtab = realloc(tcbtab, tcbtabsize * 2 * sizeof(tcbtab[0]));
        if (!newtab || !newtcbs)
@@ -670,7 +690,7 @@ expand_tcbtab(void)
 static struct tcb *
 alloctcb(int pid)
 {
-       int i;
+       unsigned int i;
        struct tcb *tcp;
 
        if (nprocs == tcbtabsize)
@@ -678,13 +698,18 @@ alloctcb(int pid)
 
        for (i = 0; i < tcbtabsize; i++) {
                tcp = tcbtab[i];
-               if ((tcp->flags & TCB_INUSE) == 0) {
+               if (!tcp->pid) {
                        memset(tcp, 0, sizeof(*tcp));
                        tcp->pid = pid;
-                       tcp->flags = TCB_INUSE;
 #if SUPPORTED_PERSONALITIES > 1
                        tcp->currpers = current_personality;
 #endif
+
+#ifdef USE_LIBUNWIND
+                       if (stack_trace_enabled)
+                               unwind_tcb_init(tcp);
+#endif
+
                        nprocs++;
                        if (debug_flag)
                                fprintf(stderr, "new tcb for pid %d, active tcbs:%d\n", tcp->pid, nprocs);
@@ -700,6 +725,12 @@ droptcb(struct tcb *tcp)
        if (tcp->pid == 0)
                return;
 
+#ifdef USE_LIBUNWIND
+       if (stack_trace_enabled) {
+               unwind_tcb_fin(tcp);
+       }
+#endif
+
        nprocs--;
        if (debug_flag)
                fprintf(stderr, "dropped tcb for pid %d, %d remain\n", tcp->pid, nprocs);
@@ -807,7 +838,7 @@ detach(struct tcb *tcp)
         * 3. Attach SIGSTOP was already pending (TCB_IGNORE_ONE_SIGSTOP set)
         */
        for (;;) {
-               int sig;
+               unsigned int sig;
                if (waitpid(tcp->pid, &status, __WALL) < 0) {
                        if (errno == EINTR)
                                continue;
@@ -924,7 +955,7 @@ process_opt_p_list(char *opt)
 static void
 startup_attach(void)
 {
-       int tcbi;
+       unsigned int tcbi;
        struct tcb *tcp;
 
        /*
@@ -959,7 +990,7 @@ startup_attach(void)
        for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
                tcp = tcbtab[tcbi];
 
-               if (!(tcp->flags & TCB_INUSE))
+               if (!tcp->pid)
                        continue;
 
                /* Is this a process we should attach to, but not yet attached? */
@@ -1153,7 +1184,7 @@ startup_child(char **argv)
 #endif /* USE_DEBUGGING_EXEC */
        else {
                const char *path;
-               int m, n, len;
+               size_t m, n, len;
 
                for (path = getenv("PATH"); path && *path; path += m) {
                        const char *colon = strchr(path, ':');
@@ -1205,7 +1236,7 @@ startup_child(char **argv)
                prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
 #endif
 
-       strace_child = pid = fork();
+       pid = fork();
        if (pid < 0) {
                perror_msg_and_die("fork");
        }
@@ -1222,6 +1253,7 @@ startup_child(char **argv)
        /* We are the tracer */
 
        if (!daemonized_tracer) {
+               strace_child = pid;
                if (!use_seize) {
                        /* child did PTRACE_TRACEME, nothing to do in parent */
                } else {
@@ -1252,9 +1284,9 @@ startup_child(char **argv)
                }
                tcp = alloctcb(pid);
                if (!NOMMU_SYSTEM)
-                       tcp->flags |= TCB_ATTACHED | TCB_STRACE_CHILD | TCB_STARTUP | post_attach_sigstop;
+                       tcp->flags |= TCB_ATTACHED | TCB_STARTUP | post_attach_sigstop;
                else
-                       tcp->flags |= TCB_ATTACHED | TCB_STRACE_CHILD | TCB_STARTUP;
+                       tcp->flags |= TCB_ATTACHED | TCB_STARTUP;
                newoutf(tcp);
        }
        else {
@@ -1406,12 +1438,13 @@ test_ptrace_setoptions_followfork(void)
  *
  * Use of this option enables correct handling of user-generated SIGTRAPs,
  * and SIGTRAPs generated by special instructions such as int3 on x86:
- * _start:     .globl  _start
- *             int3
- *             movl    $42, %ebx
- *             movl    $1, %eax
- *             int     $0x80
- * (compile with: "gcc -nostartfiles -nostdlib -o int3 int3.S")
+
+# compile with: gcc -nostartfiles -nostdlib -o int3 int3.S
+_start:                .globl  _start
+               int3
+               movl    $42, %ebx
+               movl    $1, %eax
+               int     $0x80
  */
 static int
 test_ptrace_setoptions_for_all(void)
@@ -1603,6 +1636,7 @@ init(int argc, char *argv[])
        struct tcb *tcp;
        int c, i;
        int optF = 0;
+       unsigned int tcbi;
        struct sigaction sa;
 
        progname = argv[0] ? argv[0] : "strace";
@@ -1626,8 +1660,8 @@ init(int argc, char *argv[])
        tcp = calloc(tcbtabsize, sizeof(*tcp));
        if (!tcp)
                die_out_of_memory();
-       for (c = 0; c < tcbtabsize; c++)
-               tcbtab[c] = tcp++;
+       for (tcbi = 0; tcbi < tcbtabsize; tcbi++)
+               tcbtab[tcbi] = tcp++;
 
        shared_log = stderr;
        set_sortby(DEFAULT_SORTBY);
@@ -1640,7 +1674,10 @@ init(int argc, char *argv[])
 #endif
        qualify("signal=all");
        while ((c = getopt(argc, argv,
-               "+b:cCdfFhiqrtTvVxyz"
+               "+b:cCdfFhiqrtTvVwxyz"
+#ifdef USE_LIBUNWIND
+               "k"
+#endif
                "D"
                "a:e:o:O:p:s:S:u:E:P:I:")) != EOF) {
                switch (c) {
@@ -1692,11 +1729,14 @@ init(int argc, char *argv[])
                case 'T':
                        Tflag = 1;
                        break;
+               case 'w':
+                       count_wallclock = 1;
+                       break;
                case 'x':
                        xflag++;
                        break;
                case 'y':
-                       show_fd_path = 1;
+                       show_fd_path++;
                        break;
                case 'v':
                        qualify("abbrev=none");
@@ -1743,6 +1783,11 @@ init(int argc, char *argv[])
                case 'u':
                        username = strdup(optarg);
                        break;
+#ifdef USE_LIBUNWIND
+               case 'k':
+                       stack_trace_enabled = true;
+                       break;
+#endif
                case 'E':
                        if (putenv(optarg) < 0)
                                die_out_of_memory();
@@ -1781,6 +1826,32 @@ init(int argc, char *argv[])
                error_msg_and_die("(-c or -C) and -ff are mutually exclusive");
        }
 
+       if (count_wallclock && !cflag) {
+               error_msg_and_die("-w must be given with (-c or -C)");
+       }
+
+       if (cflag == CFLAG_ONLY_STATS) {
+               if (iflag)
+                       error_msg("-%c has no effect with -c", 'i');
+#ifdef USE_LIBUNWIND
+               if (stack_trace_enabled)
+                       error_msg("-%c has no effect with -c", 'k');
+#endif
+               if (rflag)
+                       error_msg("-%c has no effect with -c", 'r');
+               if (tflag)
+                       error_msg("-%c has no effect with -c", 't');
+               if (Tflag)
+                       error_msg("-%c has no effect with -c", 'T');
+               if (show_fd_path)
+                       error_msg("-%c has no effect with -c", 'y');
+       }
+
+#ifdef USE_LIBUNWIND
+       if (stack_trace_enabled)
+               unwind_init();
+#endif
+
        /* See if they want to run as another user. */
        if (username != NULL) {
                struct passwd *pent;
@@ -1909,14 +1980,14 @@ init(int argc, char *argv[])
 static struct tcb *
 pid2tcb(int pid)
 {
-       int i;
+       unsigned int i;
 
        if (pid <= 0)
                return NULL;
 
        for (i = 0; i < tcbtabsize; i++) {
                struct tcb *tcp = tcbtab[i];
-               if (tcp->pid == pid && (tcp->flags & TCB_INUSE))
+               if (tcp->pid == pid)
                        return tcp;
        }
 
@@ -1926,7 +1997,7 @@ pid2tcb(int pid)
 static void
 cleanup(void)
 {
-       int i;
+       unsigned int i;
        struct tcb *tcp;
        int fatal_sig;
 
@@ -1937,12 +2008,12 @@ cleanup(void)
 
        for (i = 0; i < tcbtabsize; i++) {
                tcp = tcbtab[i];
-               if (!(tcp->flags & TCB_INUSE))
+               if (!tcp->pid)
                        continue;
                if (debug_flag)
                        fprintf(stderr,
                                "cleanup: looking at pid %u\n", tcp->pid);
-               if (tcp->flags & TCB_STRACE_CHILD) {
+               if (tcp->pid == strace_child) {
                        kill(tcp->pid, SIGCONT);
                        kill(tcp->pid, fatal_sig);
                }
@@ -1958,21 +2029,39 @@ interrupt(int sig)
        interrupted = sig;
 }
 
-static int
+static void
 trace(void)
 {
        struct rusage ru;
 
-       while (nprocs != 0) {
+       /* Used to be "while (nprocs != 0)", but in this testcase:
+        *  int main() { _exit(!!fork()); }
+        * under strace -f, parent sometimes (rarely) manages
+        * to exit before we see the first stop of the child,
+        * and we are losing track of it:
+        *  19923 clone(...) = 19924
+        *  19923 exit_group(1)     = ?
+        *  19923 +++ exited with 1 +++
+        * Waiting for ECHILD works better.
+        * (However, if -o|logger is in use, we can't do that.
+        * Can work around that by double-forking the logger,
+        * but that loses the ability to wait for its completion on exit.
+        * Oh well...)
+        */
+       while (1) {
                int pid;
                int wait_errno;
-               int status, sig;
+               int status;
                int stopped;
-               struct tcb *tcp;
+               unsigned int sig;
                unsigned event;
+               struct tcb *tcp;
 
                if (interrupted)
-                       return 0;
+                       return;
+
+               if (popen_pid != 0 && nprocs == 0)
+                       return;
 
                if (interactive)
                        sigprocmask(SIG_SETMASK, &empty_set, NULL);
@@ -1984,16 +2073,17 @@ trace(void)
                if (pid < 0) {
                        if (wait_errno == EINTR)
                                continue;
-                       if (wait_errno == ECHILD)
-                               /* Should not happen since nprocs > 0 */
-                               return 0;
+                       if (nprocs == 0 && wait_errno == ECHILD)
+                               return;
+                       /* If nprocs > 0, ECHILD is not expected,
+                        * treat it as any other error here:
+                        */
                        errno = wait_errno;
-                       perror_msg("wait4(__WALL)");
-                       return -1;
+                       perror_msg_and_die("wait4(__WALL)");
                }
 
                if (pid == popen_pid) {
-                       if (WIFEXITED(status) || WIFSIGNALED(status))
+                       if (!WIFSTOPPED(status))
                                popen_pid = 0;
                        continue;
                }
@@ -2001,7 +2091,7 @@ trace(void)
                event = ((unsigned)status >> 16);
                if (debug_flag) {
                        char buf[sizeof("WIFEXITED,exitcode=%u") + sizeof(int)*3 /*paranoia:*/ + 16];
-                       char evbuf[sizeof(",PTRACE_EVENT_?? (%u)") + sizeof(int)*3 /*paranoia:*/ + 16];
+                       char evbuf[sizeof(",EVENT_VFORK_DONE (%u)") + sizeof(int)*3 /*paranoia:*/ + 16];
                        strcpy(buf, "???");
                        if (WIFSIGNALED(status))
 #ifdef WCOREDUMP
@@ -2017,6 +2107,7 @@ trace(void)
                        if (WIFSTOPPED(status))
                                sprintf(buf, "WIFSTOPPED,sig=%s", signame(WSTOPSIG(status)));
 #ifdef WIFCONTINUED
+                       /* Should never be seen */
                        if (WIFCONTINUED(status))
                                strcpy(buf, "WIFCONTINUED");
 #endif
@@ -2029,24 +2120,32 @@ trace(void)
                                        [PTRACE_EVENT_VFORK_DONE] = "VFORK_DONE",
                                        [PTRACE_EVENT_EXEC]  = "EXEC",
                                        [PTRACE_EVENT_EXIT]  = "EXIT",
+                                       /* [PTRACE_EVENT_STOP (=128)] would make biggish array */
                                };
-                               const char *e;
+                               const char *e = "??";
                                if (event < ARRAY_SIZE(event_names))
                                        e = event_names[event];
-                               else {
-                                       sprintf(buf, "?? (%u)", event);
-                                       e = buf;
-                               }
-                               sprintf(evbuf, ",PTRACE_EVENT_%s", e);
+                               else if (event == PTRACE_EVENT_STOP)
+                                       e = "STOP";
+                               sprintf(evbuf, ",EVENT_%s (%u)", e, event);
                        }
-                       fprintf(stderr, " [wait(0x%04x) = %u] %s%s\n", status, pid, buf, evbuf);
+                       fprintf(stderr, " [wait(0x%06x) = %u] %s%s\n", status, pid, buf, evbuf);
                }
 
                /* Look up 'pid' in our table. */
                tcp = pid2tcb(pid);
 
                if (!tcp) {
+                       if (!WIFSTOPPED(status)) {
+                               /* This can happen if we inherited
+                                * an unknown child. Example:
+                                * (sleep 1 & exec strace sleep 2)
+                                */
+                               error_msg("Exit of unknown pid %u seen", pid);
+                               continue;
+                       }
                        if (followfork) {
+                               /* We assume it's a fork/vfork/clone child */
                                tcp = alloctcb(pid);
                                tcp->flags |= TCB_ATTACHED | TCB_STARTUP | post_attach_sigstop;
                                newoutf(tcp);
@@ -2055,10 +2154,11 @@ trace(void)
                                                pid);
                        } else {
                                /* This can happen if a clone call used
-                                  CLONE_PTRACE itself.  */
-                               if (WIFSTOPPED(status))
-                                       ptrace(PTRACE_CONT, pid, (char *) 0, 0);
-                               error_msg_and_die("Unknown pid: %u", pid);
+                                * CLONE_PTRACE itself.
+                                */
+                               ptrace(PTRACE_CONT, pid, (char *) 0, 0);
+                               error_msg("Stop of unknown pid %u seen, PTRACE_CONTed it", pid);
+                               continue;
                        }
                }
 
@@ -2087,8 +2187,11 @@ trace(void)
 
                        if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, (long) &old_pid) < 0)
                                goto dont_switch_tcbs;
+                       /* Avoid truncation in pid2tcb() param passing */
                        if (old_pid <= 0 || old_pid == pid)
                                goto dont_switch_tcbs;
+                       if ((unsigned long) old_pid > UINT_MAX)
+                               goto dont_switch_tcbs;
                        execve_thread = pid2tcb(old_pid);
                        /* It should be !NULL, but I feel paranoid */
                        if (!execve_thread)
@@ -2188,13 +2291,13 @@ trace(void)
                                if (clearbpt(tcp) < 0) {
                                        /* Pretty fatal */
                                        droptcb(tcp);
-                                       cleanup();
-                                       return -1;
+                                       exit_code = 1;
+                                       return;
                                }
                        }
-                       if (ptrace_setoptions) {
+                       if (!use_seize && ptrace_setoptions) {
                                if (debug_flag)
-                                       fprintf(stderr, "setting opts %x on pid %d\n", ptrace_setoptions, tcp->pid);
+                                       fprintf(stderr, "setting opts 0x%x on pid %d\n", ptrace_setoptions, tcp->pid);
                                if (ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL, ptrace_setoptions) < 0) {
                                        if (errno != ESRCH) {
                                                /* Should never happen, really */
@@ -2256,31 +2359,14 @@ trace(void)
                            && !hide_log_until_execve
                            && (qual_flags[sig] & QUAL_SIGNAL)
                           ) {
-#if defined(PT_CR_IPSR) && defined(PT_CR_IIP)
-                               long pc = 0;
-                               long psr = 0;
-
-                               upeek(tcp, PT_CR_IPSR, &psr);
-                               upeek(tcp, PT_CR_IIP, &pc);
-
-# define PSR_RI        41
-                               pc += (psr >> PSR_RI) & 0x3;
-# define PC_FORMAT_STR " @ %lx"
-# define PC_FORMAT_ARG , pc
-#else
-# define PC_FORMAT_STR ""
-# define PC_FORMAT_ARG /* nothing */
-#endif
                                printleader(tcp);
                                if (!stopped) {
                                        tprintf("--- %s ", signame(sig));
                                        printsiginfo(&si, verbose(tcp));
-                                       tprintf(PC_FORMAT_STR " ---\n"
-                                               PC_FORMAT_ARG);
+                                       tprints(" ---\n");
                                } else
-                                       tprintf("--- stopped by %s" PC_FORMAT_STR " ---\n",
-                                               signame(sig)
-                                               PC_FORMAT_ARG);
+                                       tprintf("--- stopped by %s ---\n",
+                                               signame(sig));
                                line_ended();
                        }
 
@@ -2296,8 +2382,9 @@ trace(void)
                                 * (that is, process really stops. It used to continue to run).
                                 */
                                if (ptrace_restart(PTRACE_LISTEN, tcp, 0) < 0) {
-                                       cleanup();
-                                       return -1;
+                                       /* Note: ptrace_restart emitted error message */
+                                       exit_code = 1;
+                                       return;
                                }
                                continue;
                        }
@@ -2307,7 +2394,7 @@ trace(void)
 
                /* We handled quick cases, we are permitted to interrupt now. */
                if (interrupted)
-                       return 0;
+                       return;
 
                /* This should be syscall entry or exit.
                 * (Or it still can be that pesky post-execve SIGTRAP!)
@@ -2330,11 +2417,11 @@ trace(void)
                sig = 0;
  restart_tracee:
                if (ptrace_restart(PTRACE_SYSCALL, tcp, sig) < 0) {
-                       cleanup();
-                       return -1;
+                       /* Note: ptrace_restart emitted error message */
+                       exit_code = 1;
+                       return;
                }
-       }
-       return 0;
+       } /* while (1) */
 }
 
 int
@@ -2343,8 +2430,7 @@ main(int argc, char *argv[])
        init(argc, argv);
 
        /* Run main tracing loop */
-       if (trace() < 0)
-               return 1;
+       trace();
 
        cleanup();
        fflush(NULL);