]> granicus.if.org Git - strace/commitdiff
Shortcut tests for fork/exec syscalls
authorDenys Vlasenko <vda.linux@googlemail.com>
Wed, 6 Feb 2013 12:18:42 +0000 (13:18 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 6 Feb 2013 12:18:42 +0000 (13:18 +0100)
This change should speed up strace by a tiny bit.

More importantly, it makes it much more clear that
fork and exec fixups are not necessary for any reasonably
recent kernels. IOW: syscall_fixup_for_fork_exec() and its callees
are all dead code.

* defs.h: Declare new need_fork_exec_workarounds flag variable.
* strace.c: Define need_fork_exec_workarounds flag variable.
(test_ptrace_setoptions_followfork): Return 0/1 as success/fail indicator.
(test_ptrace_setoptions_for_all): Likewise.
(init): Set need_fork_exec_workarounds to TRUE if needed.
* syscall.c: Rename internal_syscall() to syscall_fixup_for_fork_exec().
(trace_syscall_entering): Call syscall_fixup_for_fork_exec() only if
need_fork_exec_workarounds == TRUE.
(trace_syscall_exiting): Likewise.

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

diff --git a/defs.h b/defs.h
index a45fa62b728a75f5be054dad0d4b1365ffc3c822..2df92d3ad69b25f474e88832eb747eab76d06d53 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -518,6 +518,7 @@ extern bool qflag;
 extern bool not_failing_only;
 extern bool show_fd_path;
 extern bool tracing_paths;
+extern bool need_fork_exec_workarounds;
 extern unsigned int xflag;
 extern unsigned int followfork;
 extern unsigned int ptrace_setoptions;
index 3df3fbb51c06281ae9965a514e9f414ae221d42e..eac6ba59ba07540f96840428496ecc4ee9f7db3a 100644 (file)
--- a/strace.c
+++ b/strace.c
@@ -65,6 +65,7 @@ cflag_t cflag = CFLAG_NONE;
 unsigned int followfork = 0;
 unsigned int ptrace_setoptions = 0;
 unsigned int xflag = 0;
+bool need_fork_exec_workarounds = 0;
 bool debug_flag = 0;
 bool Tflag = 0;
 bool qflag = 0;
@@ -1165,7 +1166,7 @@ startup_child(char **argv)
  * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
  * and then see which options are supported by the kernel.
  */
-static void
+static int
 test_ptrace_setoptions_followfork(void)
 {
        int pid, expected_grandchild = 0, found_grandchild = 0;
@@ -1258,10 +1259,11 @@ test_ptrace_setoptions_followfork(void)
                if (debug_flag)
                        fprintf(stderr, "ptrace_setoptions = %#x\n",
                                ptrace_setoptions);
-               return;
+               return 0;
        }
        error_msg("Test for PTRACE_O_TRACECLONE failed, "
                  "giving up using this feature.");
+       return 1;
 }
 
 /*
@@ -1278,7 +1280,7 @@ test_ptrace_setoptions_followfork(void)
  *             int     $0x80
  * (compile with: "gcc -nostartfiles -nostdlib -o int3 int3.S")
  */
-static void
+static int
 test_ptrace_setoptions_for_all(void)
 {
        const unsigned int test_options = PTRACE_O_TRACESYSGOOD |
@@ -1287,8 +1289,9 @@ test_ptrace_setoptions_for_all(void)
        int it_worked = 0;
 
        /* this fork test doesn't work on no-mmu systems */
+       /* FIXME: isn't it better to assume we *succeed*? */
        if (strace_vforked)
-               return;
+               return 1;
 
        pid = fork();
        if (pid < 0)
@@ -1357,11 +1360,12 @@ test_ptrace_setoptions_for_all(void)
                if (debug_flag)
                        fprintf(stderr, "ptrace_setoptions = %#x\n",
                                ptrace_setoptions);
-               return;
+               return 0;
        }
 
        error_msg("Test for PTRACE_O_TRACESYSGOOD failed, "
                  "giving up using this feature.");
+       return 1;
 }
 
 #ifdef USE_SEIZE
@@ -1654,9 +1658,14 @@ init(int argc, char *argv[])
                run_gid = getgid();
        }
 
+       /*
+        * On any reasonably recent Linux kernel (circa about 2.5.46)
+        * need_fork_exec_workarounds should stay 0 after these tests:
+        */
+       /*need_fork_exec_workarounds = 0; - already is */
        if (followfork)
-               test_ptrace_setoptions_followfork();
-       test_ptrace_setoptions_for_all();
+               need_fork_exec_workarounds = test_ptrace_setoptions_followfork();
+       need_fork_exec_workarounds |= test_ptrace_setoptions_for_all();
        test_ptrace_seize();
 
        /* Check if they want to redirect the output. */
index ec588b12105b5a8d590d6d186199c59aad8af1fa..0eb1fd1c628d0e3210d4713478e67b0191ee1423 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -1482,7 +1482,7 @@ internal_exec(struct tcb *tcp)
 #endif
 
 static void
-internal_syscall(struct tcb *tcp)
+syscall_fixup_for_fork_exec(struct tcb *tcp)
 {
        /*
         * We must always trace a few critical system calls in order to
@@ -1782,7 +1782,8 @@ trace_syscall_entering(struct tcb *tcp)
        }
 #endif /* SYS_socket_subcall || SYS_ipc_subcall */
 
-       internal_syscall(tcp);
+       if (need_fork_exec_workarounds)
+               syscall_fixup_for_fork_exec(tcp);
 
        if ((SCNO_IN_RANGE(tcp->scno) &&
             !(qual_flags[tcp->scno] & QUAL_TRACE)) ||
@@ -2206,7 +2207,8 @@ trace_syscall_exiting(struct tcb *tcp)
                syscall_fixup_on_sysexit(tcp); /* never fails */
                res = get_error(tcp); /* returns 1 or -1 */
                if (res == 1) {
-                       internal_syscall(tcp);
+                       if (need_fork_exec_workarounds)
+                               syscall_fixup_for_fork_exec(tcp);
                        if (filtered(tcp)) {
                                goto ret;
                        }