From: Denys Vlasenko Date: Thu, 22 Mar 2012 08:35:51 +0000 (+0100) Subject: Make threaded execve handling code more reabable and somewhat simpler X-Git-Tag: v4.7~43 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8511f2a1f02a31f66eab86bf95dee1636fb39076;p=strace Make threaded execve handling code more reabable and somewhat simpler * 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 --- diff --git a/strace.c b/strace.c index 2c792ffa..1ade018b 100644 --- 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, " \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, " \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, " \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;