]> granicus.if.org Git - strace/commitdiff
Make threaded execve handling code more reabable and somewhat simpler
authorDenys Vlasenko <vda.linux@googlemail.com>
Thu, 22 Mar 2012 08:35:51 +0000 (09:35 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 22 Mar 2012 08:35:51 +0000 (09:35 +0100)
* strace.c (droptcb): Remove outfname check in "outfname && followfork >= 2" -
with recent changes, followfork >= 2 check guarantees that outfile
was specified, and _is already opened_.
(trace): Move tcb existence check before threaded execve handling.
This allows to remove tcp != NULL checks in threaded execve handling.
Rewrite threaded execve handling code to be less indented,
keeping the same logic.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
strace.c

index 2c792ffa901b32e6eef196186b6bf9308127f5df..1ade018bd8b5c839d4a3fd89de711957a69df439 100644 (file)
--- a/strace.c
+++ b/strace.c
@@ -684,7 +684,7 @@ droptcb(struct tcb *tcp)
                fprintf(stderr, "dropped tcb for pid %d, %d remain\n", tcp->pid, nprocs);
 
        if (tcp->outf) {
-               if (outfname && followfork >= 2) {
+               if (followfork >= 2) {
                        if (tcp->curcol != 0)
                                fprintf(tcp->outf, " <detached ...>\n");
                        fclose(tcp->outf);
@@ -1898,6 +1898,32 @@ trace(void)
                /* Look up 'pid' in our table. */
                tcp = pid2tcb(pid);
 
+               if (!tcp) {
+                       if (followfork) {
+                               /* This is needed to go with the CLONE_PTRACE
+                                  changes in process.c/util.c: we might see
+                                  the child's initial trap before we see the
+                                  parent return from the clone syscall.
+                                  Leave the child suspended until the parent
+                                  returns from its system call.  Only then
+                                  will we have the association of parent and
+                                  child so that we know how to do clearbpt
+                                  in the child.  */
+                               tcp = alloctcb(pid);
+                               tcp->flags |= TCB_ATTACHED | TCB_STARTUP | post_attach_sigstop;
+                               newoutf(tcp);
+                               if (!qflag)
+                                       fprintf(stderr, "Process %d attached\n",
+                                               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);
+                       }
+               }
+
                /* Under Linux, execve changes pid to thread leader's pid,
                 * and we see this changed pid on EVENT_EXEC and later,
                 * execve sysexit. Leader "disappears" without exit
@@ -1913,44 +1939,47 @@ trace(void)
                 * On 2.6 and earlier, it can return garbage.
                 */
                if (event == PTRACE_EVENT_EXEC && os_release >= KERNEL_VERSION(3,0,0)) {
+                       struct tcb *execve_thread;
                        long old_pid = 0;
-                       if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, (long) &old_pid) >= 0
-                        && old_pid > 0
-                        && old_pid != pid
-                       ) {
-                               struct tcb *execve_thread = pid2tcb(old_pid);
-                               if (tcp) {
-                                       outf = tcp->outf;
-                                       curcol = tcp->curcol;
-                                       if (execve_thread) {
-                                               if (execve_thread->curcol != 0) {
-                                                       /*
-                                                        * One case we are here is -ff:
-                                                        * try "strace -oLOG -ff test/threaded_execve"
-                                                        */
-                                                       fprintf(execve_thread->outf, " <pid changed to %d ...>\n", pid);
-                                                       execve_thread->curcol = 0;
-                                               }
-                                               /* swap output FILEs (needed for -ff) */
-                                               tcp->outf = execve_thread->outf;
-                                               tcp->curcol = execve_thread->curcol;
-                                               execve_thread->outf = outf;
-                                               execve_thread->curcol = curcol;
-                                       }
-                                       droptcb(tcp);
-                               }
-                               tcp = execve_thread;
-                               if (tcp) {
-                                       tcp->pid = pid;
-                                       if (cflag != CFLAG_ONLY_STATS) {
-                                               printleader(tcp);
-                                               tprintf("+++ superseded by execve in pid %lu +++\n", old_pid);
-                                               line_ended();
-                                               tcp->flags |= TCB_REPRINT;
-                                       }
-                               }
+
+                       if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, (long) &old_pid) < 0)
+                               goto dont_switch_tcbs;
+                       if (old_pid <= 0 || old_pid == pid)
+                               goto dont_switch_tcbs;
+                       execve_thread = pid2tcb(old_pid);
+                       /* It should be !NULL, but I feel paranoid */
+                       if (!execve_thread)
+                               goto dont_switch_tcbs;
+
+                       outf = tcp->outf;
+                       curcol = tcp->curcol;
+                       if (execve_thread->curcol != 0) {
+                               /*
+                                * One case we are here is -ff:
+                                * try "strace -oLOG -ff test/threaded_execve"
+                                */
+                               fprintf(execve_thread->outf, " <pid changed to %d ...>\n", pid);
+                               execve_thread->curcol = 0;
+                       }
+                       /* Swap output FILEs (needed for -ff) */
+                       tcp->outf = execve_thread->outf;
+                       tcp->curcol = execve_thread->curcol;
+                       /* And their column positions */
+                       execve_thread->outf = outf;
+                       execve_thread->curcol = curcol;
+                       /* Drop leader, but close execve'd thread outfile (if -ff) */
+                       droptcb(tcp);
+                       /* Switch to the thread, reusing leader's outfile and pid */
+                       tcp = execve_thread;
+                       tcp->pid = pid;
+                       if (cflag != CFLAG_ONLY_STATS) {
+                               printleader(tcp);
+                               tprintf("+++ superseded by execve in pid %lu +++\n", old_pid);
+                               line_ended();
+                               tcp->flags |= TCB_REPRINT;
                        }
                }
+ dont_switch_tcbs:
 
                if (event == PTRACE_EVENT_EXEC && detach_on_execve) {
                        if (!skip_startup_execve)
@@ -1959,34 +1988,6 @@ trace(void)
                        skip_startup_execve = 0;
                }
 
-               if (tcp == NULL) {
-                       if (followfork) {
-                               /* This is needed to go with the CLONE_PTRACE
-                                  changes in process.c/util.c: we might see
-                                  the child's initial trap before we see the
-                                  parent return from the clone syscall.
-                                  Leave the child suspended until the parent
-                                  returns from its system call.  Only then
-                                  will we have the association of parent and
-                                  child so that we know how to do clearbpt
-                                  in the child.  */
-                               tcp = alloctcb(pid);
-                               tcp->flags |= TCB_ATTACHED | TCB_STARTUP | post_attach_sigstop;
-                               newoutf(tcp);
-                               if (!qflag)
-                                       fprintf(stderr, "Process %d attached\n",
-                                               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);
-                       }
-               }
-
                /* Set current output file */
                outf = tcp->outf;
                curcol = tcp->curcol;