]> granicus.if.org Git - strace/blobdiff - strace.c
io: change size types from unsigned long to kernel_ureg_t
[strace] / strace.c
index fd5f23b946b2fe0a8624dd015567b19d563df929..4659ddbd2ad516482a7c7c4639688b2bafbeaa3e 100644 (file)
--- a/strace.c
+++ b/strace.c
@@ -80,7 +80,8 @@ const unsigned int syscall_trap_sig = SIGTRAP | 0x80;
 
 cflag_t cflag = CFLAG_NONE;
 unsigned int followfork = 0;
-unsigned int ptrace_setoptions = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC;
+unsigned int ptrace_setoptions = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC
+                                | PTRACE_O_TRACEEXIT;
 unsigned int xflag = 0;
 bool debug_flag = 0;
 bool Tflag = 0;
@@ -133,10 +134,6 @@ bool not_failing_only = 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? */
-static bool skip_one_b_execve = 0;
-/* Are we "strace PROG" and need to hide everything until execve? */
-bool hide_log_until_execve = 0;
 
 static int exit_code;
 static int strace_child = 0;
@@ -389,24 +386,31 @@ ptrace_attach_or_seize(int pid)
  * Otherwise prints error message and returns -1.
  */
 static int
-ptrace_restart(int op, struct tcb *tcp, int sig)
+ptrace_restart(const unsigned int op, struct tcb *const tcp, unsigned int sig)
 {
        int err;
        const char *msg;
 
        errno = 0;
-       ptrace(op, tcp->pid, (void *) 0, (long) sig);
+       ptrace(op, tcp->pid, 0L, (unsigned long) sig);
        err = errno;
        if (!err)
                return 0;
 
-       msg = "SYSCALL";
-       if (op == PTRACE_CONT)
-               msg = "CONT";
-       if (op == PTRACE_DETACH)
-               msg = "DETACH";
-       if (op == PTRACE_LISTEN)
-               msg = "LISTEN";
+       switch (op) {
+               case PTRACE_CONT:
+                       msg = "CONT";
+                       break;
+               case PTRACE_DETACH:
+                       msg = "DETACH";
+                       break;
+               case PTRACE_LISTEN:
+                       msg = "LISTEN";
+                       break;
+               default:
+                       msg = "SYSCALL";
+       }
+
        /*
         * Why curcol != 0? Otherwise sometimes we get this:
         *
@@ -423,7 +427,7 @@ ptrace_restart(int op, struct tcb *tcp, int sig)
        if (err == ESRCH)
                return 0;
        errno = err;
-       perror_msg("ptrace(PTRACE_%s,pid:%d,sig:%d)", msg, tcp->pid, sig);
+       perror_msg("ptrace(PTRACE_%s,pid:%d,sig:%u)", msg, tcp->pid, sig);
        return -1;
 }
 
@@ -1418,17 +1422,17 @@ startup_child(char **argv)
                                kill(pid, SIGCONT);
                }
                tcp = alloctcb(pid);
-               if (!NOMMU_SYSTEM)
-                       tcp->flags |= TCB_ATTACHED | TCB_STARTUP | post_attach_sigstop;
-               else
-                       tcp->flags |= TCB_ATTACHED | TCB_STARTUP;
+               tcp->flags |= TCB_ATTACHED | TCB_STARTUP
+                           | TCB_SKIP_DETACH_ON_FIRST_EXEC
+                           | (NOMMU_SYSTEM ? 0 : (TCB_HIDE_LOG | post_attach_sigstop));
                newoutf(tcp);
        }
        else {
                /* With -D, we are *child* here, the tracee is our parent. */
                strace_child = strace_tracer_pid;
                strace_tracer_pid = getpid();
-               alloctcb(strace_child);
+               tcp = alloctcb(strace_child);
+               tcp->flags |= TCB_SKIP_DETACH_ON_FIRST_EXEC | TCB_HIDE_LOG;
                /* attaching will be done later, by startup_attach */
                /* note: we don't do newoutf(tcp) here either! */
 
@@ -1642,7 +1646,7 @@ init(int argc, char *argv[])
                        break;
                case 'r':
                        rflag = 1;
-                       /* fall through to tflag++ */
+                       break;
                case 't':
                        tflag++;
                        break;
@@ -1765,9 +1769,21 @@ init(int argc, char *argv[])
                        error_msg("-%c has no effect with -c", 'y');
        }
 
+       if (rflag) {
+               if (tflag > 1)
+                       error_msg("-tt has no effect with -r");
+               tflag = 1;
+       }
+
 #ifdef USE_LIBUNWIND
-       if (stack_trace_enabled)
+       if (stack_trace_enabled) {
+               unsigned int tcbi;
+
                unwind_init();
+               for (tcbi = 0; tcbi < tcbtabsize; ++tcbi) {
+                       unwind_tcb_init(tcbtab[tcbi]);
+               }
+       }
 #endif
 
        /* See if they want to run as another user. */
@@ -1831,8 +1847,7 @@ init(int argc, char *argv[])
        }
 
        if (!outfname || outfname[0] == '|' || outfname[0] == '!') {
-               char *buf = xmalloc(BUFSIZ);
-               setvbuf(shared_log, buf, _IOLBF, BUFSIZ);
+               setvbuf(shared_log, NULL, _IOLBF, 0);
        }
        if (outfname && argv[0]) {
                if (!opt_intr)
@@ -1859,9 +1874,6 @@ init(int argc, char *argv[])
         * in the startup_child() mode we kill the spawned process anyway.
         */
        if (argv[0]) {
-               if (!NOMMU_SYSTEM || daemonized_tracer)
-                       hide_log_until_execve = 1;
-               skip_one_b_execve = 1;
                startup_child(argv);
        }
 
@@ -2044,7 +2056,7 @@ maybe_switch_tcbs(struct tcb *tcp, const int pid)
        struct tcb *execve_thread;
        long old_pid = 0;
 
-       if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, (long) &old_pid) < 0)
+       if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &old_pid) < 0)
                return tcp;
        /* Avoid truncation in pid2tcb() param passing */
        if (old_pid <= 0 || old_pid == pid)
@@ -2095,8 +2107,7 @@ print_signalled(struct tcb *tcp, const int pid, int status)
        }
 
        if (cflag != CFLAG_ONLY_STATS
-        && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL)
-       ) {
+           && is_number_in_set(WTERMSIG(status), &signal_set)) {
                printleader(tcp);
 #ifdef WCOREDUMP
                tprintf("+++ killed by %s %s+++\n",
@@ -2130,9 +2141,8 @@ static void
 print_stopped(struct tcb *tcp, const siginfo_t *si, const unsigned int sig)
 {
        if (cflag != CFLAG_ONLY_STATS
-           && !hide_log_until_execve
-           && (qual_flags[sig] & QUAL_SIGNAL)
-          ) {
+           && !hide_log(tcp)
+           && is_number_in_set(sig, &signal_set)) {
                printleader(tcp);
                if (si) {
                        tprintf("--- %s ", signame(sig));
@@ -2165,6 +2175,43 @@ startup_tcb(struct tcb *tcp)
        }
 }
 
+static void
+print_event_exit(struct tcb *tcp)
+{
+       if (entering(tcp) || filtered(tcp) || hide_log(tcp)
+           || cflag == CFLAG_ONLY_STATS) {
+               return;
+       }
+
+       if (followfork < 2 && printing_tcp && printing_tcp != tcp
+           && printing_tcp->curcol != 0) {
+               current_tcp = printing_tcp;
+               tprints(" <unfinished ...>\n");
+               fflush(printing_tcp->outf);
+               printing_tcp->curcol = 0;
+               current_tcp = tcp;
+       }
+
+       if ((followfork < 2 && printing_tcp != tcp)
+           || (tcp->flags & TCB_REPRINT)) {
+               tcp->flags &= ~TCB_REPRINT;
+               printleader(tcp);
+               tprintf("<... %s resumed>", tcp->s_ent->sys_name);
+       }
+
+       if (!(tcp->sys_func_rval & RVAL_DECODED)) {
+               /*
+                * The decoder has probably decided to print something
+                * on exiting syscall which is not going to happen.
+                */
+               tprints(" <unfinished ...>");
+       }
+       tprints(") ");
+       tabto();
+       tprints("= ?\n");
+       line_ended();
+}
+
 /* Returns true iff the main trace loop has to continue. */
 static bool
 trace(void)
@@ -2266,11 +2313,14 @@ trace(void)
                if (os_release >= KERNEL_VERSION(3,0,0))
                        tcp = maybe_switch_tcbs(tcp, pid);
 
-               if (detach_on_execve && !skip_one_b_execve) {
-                       detach(tcp); /* do "-b execve" thingy */
-                       return true;
+               if (detach_on_execve) {
+                       if (tcp->flags & TCB_SKIP_DETACH_ON_FIRST_EXEC) {
+                               tcp->flags &= ~TCB_SKIP_DETACH_ON_FIRST_EXEC;
+                       } else {
+                               detach(tcp); /* do "-b execve" thingy */
+                               return true;
+                       }
                }
-               skip_one_b_execve = 0;
        }
 
        /* Set current output file */
@@ -2312,10 +2362,14 @@ trace(void)
 
        sig = WSTOPSIG(status);
 
-       if (event != 0) {
-               /* Ptrace event */
+       switch (event) {
+               case 0:
+                       break;
+               case PTRACE_EVENT_EXIT:
+                       print_event_exit(tcp);
+                       goto restart_tracee_with_sig_0;
 #if USE_SEIZE
-               if (event == PTRACE_EVENT_STOP) {
+               case PTRACE_EVENT_STOP:
                        /*
                         * PTRACE_INTERRUPT-stop or group-stop.
                         * PTRACE_INTERRUPT-stop has sig == SIGTRAP here.
@@ -2328,9 +2382,10 @@ trace(void)
                                        stopped = true;
                                        goto show_stopsig;
                        }
-               }
+                       /* fall through */
 #endif
-               goto restart_tracee_with_sig_0;
+               default:
+                       goto restart_tracee_with_sig_0;
        }
 
        /*
@@ -2356,7 +2411,7 @@ trace(void)
                 * TODO: shouldn't we check for errno == EINVAL too?
                 * We can get ESRCH instead, you know...
                 */
-               stopped = ptrace(PTRACE_GETSIGINFO, pid, 0, (long) &si) < 0;
+               stopped = ptrace(PTRACE_GETSIGINFO, pid, 0, &si) < 0;
 #if USE_SEIZE
 show_stopsig:
 #endif