From: Denys Vlasenko Date: Wed, 6 Feb 2013 12:18:42 +0000 (+0100) Subject: Shortcut tests for fork/exec syscalls X-Git-Tag: v4.8~189 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8d4ca0c8cd81329ad730ab52b1e0653c1bbea803;p=strace Shortcut tests for fork/exec syscalls 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 --- diff --git a/defs.h b/defs.h index a45fa62b..2df92d3a 100644 --- 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; diff --git a/strace.c b/strace.c index 3df3fbb5..eac6ba59 100644 --- 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. */ diff --git a/syscall.c b/syscall.c index ec588b12..0eb1fd1c 100644 --- 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; }