]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
New flag: --trace-children-skip=patt1,patt2,etc
authorJulian Seward <jseward@acm.org>
Thu, 5 Nov 2009 08:55:13 +0000 (08:55 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 5 Nov 2009 08:55:13 +0000 (08:55 +0000)
Specifies a comma-separated list of executable-names
(with "*" and "?" wildcards allowed) that should not be traced into
even when --trace-children=yes.  Modified version of a patch
from Bill Hoffman.  Fixes #148932.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10927

coregrind/m_main.c
coregrind/m_options.c
coregrind/m_syswrap/syswrap-aix5.c
coregrind/m_syswrap/syswrap-darwin.c
coregrind/m_syswrap/syswrap-generic.c
coregrind/pub_core_options.h
docs/xml/manual-core.xml
none/tests/cmdline1.stdout.exp
none/tests/cmdline2.stdout.exp

index 190569c86b4f014e6d9f4f0452c5cd13fb998bdb..b959c153614b4db7b1c7df8351e3a66a2d55d7a5 100644 (file)
@@ -121,6 +121,8 @@ static void usage_NORETURN ( Bool debug_help )
 "    -q --quiet                run silently; only print error msgs\n"
 "    -v --verbose              be more verbose -- show misc extra info\n"
 "    --trace-children=no|yes   Valgrind-ise child processes (follow execve)? [no]\n"
+"    --trace-children-skip=patt1,patt2,...    specifies a list of executables\n"
+"                              that --trace-children=yes should not trace into\n"
 "    --child-silent-after-fork=no|yes omit child output between fork & exec? [no]\n"
 "    --track-fds=no|yes        track open file descriptors? [no]\n"
 "    --time-stamp=no|yes       add timestamps to log messages? [no]\n"
@@ -490,6 +492,8 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd,
 
       else if VG_BOOL_CLO(arg, "--dsymutil",        VG_(clo_dsymutil)) {}
 
+      else if VG_STR_CLO (arg, "--trace-children-skip",   VG_(clo_trace_children_skip)) {}
+
       else if VG_BINT_CLO(arg, "--vex-iropt-verbosity",
                        VG_(clo_vex_control).iropt_verbosity, 0, 10) {}
       else if VG_BINT_CLO(arg, "--vex-iropt-level",
index 3582818194ed5b66c6a373c0186a46f922e2b986..3d91fd9c595b746cf6a7fc6726cfd454bfc368de 100644 (file)
@@ -38,6 +38,7 @@
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"
 #include "pub_core_mallocfree.h"
+#include "pub_core_seqmatch.h"     // VG_(string_match)
 
 // See pub_{core,tool}_options.h for explanations of all these.
 
@@ -56,6 +57,7 @@ Bool   VG_(clo_xml)            = False;
 HChar* VG_(clo_xml_user_comment) = NULL;
 Bool   VG_(clo_demangle)       = True;
 Bool   VG_(clo_trace_children) = False;
+HChar* VG_(clo_trace_children_skip) = NULL;
 Bool   VG_(clo_child_silent_after_fork) = False;
 Char*  VG_(clo_log_fname_expanded) = NULL;
 Char*  VG_(clo_xml_fname_expanded) = NULL;
@@ -264,6 +266,69 @@ Char* VG_(expand_file_name)(Char* option_name, Char* format)
   }
 }
 
+/*====================================================================*/
+/*=== --trace-children= support                                    ===*/
+/*====================================================================*/
+
+static HChar const* consume_commas ( HChar const* c ) {
+   while (*c && *c == ',') {
+      ++c;
+   }
+   return c;
+}
+
+static HChar const* consume_field ( HChar const* c ) {
+   while (*c && *c != ',') {
+      ++c;
+   }
+   return c;
+}
+
+/* Should we trace into this child executable (across execve etc) ?
+   This involves considering --trace-children=, --trace-children-skip=
+   and the name of the executable. */
+Bool VG_(should_we_trace_this_child) ( HChar* child_exe_name )
+{
+   // child_exe_name is pulled out of the guest's space.  We
+   // should be at least marginally cautious with it, lest it
+   // explode or burst into flames unexpectedly.
+   if (child_exe_name == NULL || VG_(strlen)(child_exe_name) == 0)
+      return VG_(clo_trace_children);  // we know narfink
+
+   // the main logic
+   // If --trace-children=no, the answer is simply NO.
+   if (! VG_(clo_trace_children))
+      return False;
+
+   // otherwise, return True, unless the exe name matches any of the
+   // patterns specified by --trace-children-skip=.
+   if (VG_(clo_trace_children_skip)) {
+      HChar const* last = VG_(clo_trace_children_skip);
+      HChar const* name = (HChar const*)child_exe_name;
+      while (*last) {
+         Bool   matches;
+         HChar* patt;
+         HChar const* first = consume_commas(last);
+         last = consume_field(first);
+         if (first == last)
+            break;
+         vg_assert(last > first);
+         /* copy the candidate string into a temporary malloc'd block
+            so we can use VG_(string_match) on it. */
+         patt = VG_(calloc)("m_options.swttc.1", last - first + 1, 1);
+         VG_(memcpy)(patt, first, last - first);
+         vg_assert(patt[last-first] == 0);
+         matches = VG_(string_match)(patt, name);
+         VG_(free)(patt);
+         if (matches)
+            return False;
+      }
+   }
+   // --trace-children=yes, and this particular executable isn't
+   // excluded
+   return True;
+}
 
 
 /*--------------------------------------------------------------------*/
index 6108ccee5b306957c96a12810f9c647af52c64f1..e8280347ce4fc4a3503129c6a4def4afd9e9acf2 100644 (file)
@@ -798,7 +798,8 @@ static void pre_argv_envp(Addr a, ThreadId tid, Char* s1, Char* s2)
       a += sizeof(char*);
    }
 }
-static SysRes simple_pre_exec_check(const HChar* exe_name)
+static SysRes simple_pre_exec_check ( const HChar* exe_name,
+                                      Bool trace_this_child )
 {
    Int fd, ret;
    SysRes res;
@@ -815,7 +816,7 @@ static SysRes simple_pre_exec_check(const HChar* exe_name)
    // Check we have execute permissions.  We allow setuid executables
    // to be run only in the case when we are not simulating them, that
    // is, they to be run natively.
-   setuid_allowed = VG_(clo_trace_children)  ? False  : True;
+   setuid_allowed = trace_this_child  ? False  : True;
    ret = VG_(check_executable)(NULL/*&is_setuid*/,
                                (HChar*)exe_name, setuid_allowed);
    if (0 != ret) {
@@ -833,6 +834,7 @@ PRE(sys_execve)
    ThreadState* tst;
    Int          i, j, tot_args;
    SysRes       res;
+   Bool         trace_this_child;
 
    PRINT("sys_execve ( %#lx(%s), %#lx, %#lx )", ARG1, (Char*)ARG1, ARG2, ARG3);
    PRE_REG_READ3(vki_off_t, "execve",
@@ -862,10 +864,16 @@ PRE(sys_execve)
    //   SET_STATUS_Failure( VKI_EFAULT );
    //   return;
    //}
+   if (ARG1 == 0 /* obviously bogus */) {
+      SET_STATUS_Failure( VKI_EFAULT );
+   }
+
+   // Decide whether or not we want to follow along
+   trace_this_child = VG_(should_we_trace_this_child)( (HChar*)ARG1 );
 
    // Do the important checks:  it is a file, is executable, permissions are
    // ok, etc.
-   res = simple_pre_exec_check((const HChar*)ARG1);
+   res = simple_pre_exec_check( (const HChar*)ARG1, trace_this_child );
    if (res.isError) {
       SET_STATUS_Failure( res.err );
       return;
@@ -874,7 +882,7 @@ PRE(sys_execve)
    /* If we're tracing the child, and the launcher name looks bogus
       (possibly because launcher.c couldn't figure it out, see
       comments therein) then we have no option but to fail. */
-   if (VG_(clo_trace_children) 
+   if (trace_this_child 
        && (VG_(name_of_launcher) == NULL
            || VG_(name_of_launcher)[0] != '/')) {
       SET_STATUS_Failure( VKI_ECHILD ); /* "No child processes" */
@@ -892,7 +900,7 @@ PRE(sys_execve)
 
    // Set up the child's exe path.
    //
-   if (VG_(clo_trace_children)) {
+   if (trace_this_child) {
 
       // We want to exec the launcher.  Get its pre-remembered path.
       path = VG_(name_of_launcher);
@@ -930,7 +938,7 @@ PRE(sys_execve)
       VG_(env_remove_valgrind_env_stuff)( envp );
    }
 
-   if (VG_(clo_trace_children)) {
+   if (trace_this_child) {
       // Set VALGRIND_LIB in ARG3 (the environment)
       VG_(env_setenv)( &envp, VALGRIND_LIB, VG_(libdir));
    }
@@ -943,7 +951,7 @@ PRE(sys_execve)
    // except that the first VG_(args_for_valgrind_noexecpass) args
    // are omitted.
    //
-   if (!VG_(clo_trace_children)) {
+   if (!trace_this_child) {
       argv = (Char**)ARG2;
    } else {
       vg_assert( VG_(args_for_valgrind_noexecpass) >= 0 );
index 86c974f9ae22c306a57d1dc6662a6c9b0286d644..8c927dc112cb1e43c6c28b5b52cfc780ba555b4e 100644 (file)
@@ -2556,7 +2556,8 @@ static void pre_argv_envp(Addr a, ThreadId tid, Char* s1, Char* s2)
       a += sizeof(char*);
    }
 }
-static SysRes simple_pre_exec_check(const HChar* exe_name)
+static SysRes simple_pre_exec_check ( const HChar* exe_name,
+                                      Bool trace_this_child )
 {
    Int fd, ret;
    SysRes res;
@@ -2573,7 +2574,7 @@ static SysRes simple_pre_exec_check(const HChar* exe_name)
    // Check we have execute permissions.  We allow setuid executables
    // to be run only in the case when we are not simulating them, that
    // is, they to be run natively.
-   setuid_allowed = VG_(clo_trace_children)  ? False  : True;
+   setuid_allowed = trace_this_child  ? False  : True;
    ret = VG_(check_executable)(NULL/*&is_setuid*/,
                                (HChar*)exe_name, setuid_allowed);
    if (0 != ret) {
@@ -2590,6 +2591,7 @@ PRE(posix_spawn)
    Char*        launcher_basename = NULL;
    Int          i, j, tot_args;
    SysRes       res;
+   Bool         trace_this_child;
 
    /* args: pid_t* pid
             char*  path
@@ -2622,15 +2624,19 @@ PRE(posix_spawn)
       syswrap-generic.c. */
 
    /* Check that the name at least begins in client-accessible storage. */
-   if (!VG_(am_is_valid_for_client)( ARG2, 1, VKI_PROT_READ )) {
+   if (ARG2 == 0 /* obviously bogus */
+       || !VG_(am_is_valid_for_client)( ARG2, 1, VKI_PROT_READ )) {
       SET_STATUS_Failure( VKI_EFAULT );
       return;
    }
 
+   // Decide whether or not we want to follow along
+   trace_this_child = VG_(should_we_trace_this_child)( (HChar*)ARG2 );
+
    // Do the important checks:  it is a file, is executable, permissions are
    // ok, etc.  We allow setuid executables to run only in the case when
    // we are not simulating them, that is, they to be run natively.
-   res = simple_pre_exec_check((const HChar*)ARG2);
+   res = simple_pre_exec_check( (const HChar*)ARG2, trace_this_child );
    if (sr_isError(res)) {
       SET_STATUS_Failure( sr_Err(res) );
       return;
@@ -2639,7 +2645,7 @@ PRE(posix_spawn)
    /* If we're tracing the child, and the launcher name looks bogus
       (possibly because launcher.c couldn't figure it out, see
       comments therein) then we have no option but to fail. */
-   if (VG_(clo_trace_children)
+   if (trace_this_child
        && (VG_(name_of_launcher) == NULL
            || VG_(name_of_launcher)[0] != '/')) {
       SET_STATUS_Failure( VKI_ECHILD ); /* "No child processes" */
@@ -2651,7 +2657,7 @@ PRE(posix_spawn)
 
    // Set up the child's exe path.
    //
-   if (VG_(clo_trace_children)) {
+   if (trace_this_child) {
 
       // We want to exec the launcher.  Get its pre-remembered path.
       path = VG_(name_of_launcher);
@@ -2685,7 +2691,7 @@ PRE(posix_spawn)
       VG_(env_remove_valgrind_env_stuff)( envp );
    }
 
-   if (VG_(clo_trace_children)) {
+   if (trace_this_child) {
       // Set VALGRIND_LIB in ARG5 (the environment)
       VG_(env_setenv)( &envp, VALGRIND_LIB, VG_(libdir));
    }
@@ -2698,7 +2704,7 @@ PRE(posix_spawn)
    // except that the first VG_(args_for_valgrind_noexecpass) args
    // are omitted.
    //
-   if (!VG_(clo_trace_children)) {
+   if (!trace_this_child) {
       argv = (Char**)ARG4;
    } else {
       vg_assert( VG_(args_for_valgrind) );
index 5f66535600af1cff40aafb6d3a6c125469b574b8..63f8994a35eb75c18039034393455d2cacdeb6de 100644 (file)
@@ -2488,7 +2488,7 @@ PRE(sys_execve)
    ThreadState* tst;
    Int          i, j, tot_args;
    SysRes       res;
-   Bool         setuid_allowed;
+   Bool         setuid_allowed, trace_this_child;
 
    PRINT("sys_execve ( %#lx(%s), %#lx, %#lx )", ARG1, (char*)ARG1, ARG2, ARG3);
    PRE_REG_READ3(vki_off_t, "execve",
@@ -2510,15 +2510,19 @@ PRE(sys_execve)
       doing it. */
 
    /* Check that the name at least begins in client-accessible storage. */
-   if (!VG_(am_is_valid_for_client)( ARG1, 1, VKI_PROT_READ )) {
+   if (ARG1 == 0 /* obviously bogus */
+       || !VG_(am_is_valid_for_client)( ARG1, 1, VKI_PROT_READ )) {
       SET_STATUS_Failure( VKI_EFAULT );
       return;
    }
 
+   // Decide whether or not we want to follow along
+   trace_this_child = VG_(should_we_trace_this_child)( (HChar*)ARG1 );
+
    // Do the important checks:  it is a file, is executable, permissions are
    // ok, etc.  We allow setuid executables to run only in the case when
    // we are not simulating them, that is, they to be run natively.
-   setuid_allowed = VG_(clo_trace_children)  ? False  : True;
+   setuid_allowed = trace_this_child  ? False  : True;
    res = VG_(pre_exec_check)((const Char*)ARG1, NULL, setuid_allowed);
    if (sr_isError(res)) {
       SET_STATUS_Failure( sr_Err(res) );
@@ -2528,7 +2532,7 @@ PRE(sys_execve)
    /* If we're tracing the child, and the launcher name looks bogus
       (possibly because launcher.c couldn't figure it out, see
       comments therein) then we have no option but to fail. */
-   if (VG_(clo_trace_children) 
+   if (trace_this_child 
        && (VG_(name_of_launcher) == NULL
            || VG_(name_of_launcher)[0] != '/')) {
       SET_STATUS_Failure( VKI_ECHILD ); /* "No child processes" */
@@ -2546,7 +2550,7 @@ PRE(sys_execve)
 
    // Set up the child's exe path.
    //
-   if (VG_(clo_trace_children)) {
+   if (trace_this_child) {
 
       // We want to exec the launcher.  Get its pre-remembered path.
       path = VG_(name_of_launcher);
@@ -2584,7 +2588,7 @@ PRE(sys_execve)
       VG_(env_remove_valgrind_env_stuff)( envp );
    }
 
-   if (VG_(clo_trace_children)) {
+   if (trace_this_child) {
       // Set VALGRIND_LIB in ARG3 (the environment)
       VG_(env_setenv)( &envp, VALGRIND_LIB, VG_(libdir));
    }
@@ -2597,7 +2601,7 @@ PRE(sys_execve)
    // except that the first VG_(args_for_valgrind_noexecpass) args
    // are omitted.
    //
-   if (!VG_(clo_trace_children)) {
+   if (!trace_this_child) {
       argv = (Char**)ARG2;
    } else {
       vg_assert( VG_(args_for_valgrind) );
index 37242b5af0f5aa101be9a36d81cb9d71e96d6c61..e7b6abe06cb47bfcdf6930170904f4a560fc3484 100644 (file)
@@ -61,6 +61,9 @@ extern Int   VG_(clo_sanity_level);
 extern Bool  VG_(clo_demangle);
 /* Simulate child processes? default: NO */
 extern Bool  VG_(clo_trace_children);
+/* String containing comma-separated patterns for executable names
+   that should not be traced into even when --trace-children=yes */
+extern HChar* VG_(clo_trace_children_skip);
 /* After a fork, the child's output can become confusingly
    intermingled with the parent's output.  This is especially
    problematic when VG_(clo_xml) is True.  Setting
@@ -182,6 +185,10 @@ extern void VG_(err_missing_prog) ( void );
 __attribute__((noreturn))
 extern void VG_(err_config_error) ( Char* msg );
 
+/* Should we trace into this child executable (across execve etc) ?
+   This involves considering --trace-children=, --trace-children-skip=
+   and the name of the executable. */
+extern Bool VG_(should_we_trace_this_child) ( HChar* child_exe_name );
 
 #endif   // __PUB_CORE_OPTIONS_H
 
index 924c75e46fa60851ab183164e8b385c1e30defbe..24ab6aeea3a97247bcfc4151e65679eeaa02145f 100644 (file)
@@ -660,6 +660,32 @@ in most cases.  We group the available options by rough categories.</para>
     </listitem>
   </varlistentry>
 
+  <varlistentry id="opt.trace-children-skip" xreflabel="--trace-children-skip">
+    <term>
+      <option><![CDATA[--trace-children-skip=patt1,patt2 ]]></option>
+    </term>
+    <listitem>
+      <para>This option only has an effect when 
+        <option>--trace-children=yes</option> is specified.  It allows
+        for some children to be skipped.  The option takes a comma
+        separated list of patterns for the names of child executables
+        that Valgrind should not trace into.  Patterns may include the
+        metacharacters <computeroutput>?</computeroutput>
+        and <computeroutput>*</computeroutput>, which have the usual
+        meaning.</para>
+      <para>
+        This can be useful for pruning uninteresting branches from a
+        tree of processes being run on Valgrind.  But you should be
+        careful when using it.  When Valgrind skips tracing into an
+        executable, it doesn't just skip tracing that executable, it
+        also skips tracing any of that executable's child processes.
+        In other words, the flag doesn't merely cause tracing to stop
+        at the specified executables -- it skips tracing of entire
+        process subtrees rooted at any of the specified
+        executables.</para>
+    </listitem>
+  </varlistentry>
+
   <varlistentry id="opt.child-silent-after-fork"
                 xreflabel="--child-silent-after-fork">
     <term>
index 2deb6bd5892e99ba474111320b1e1942d53da35d..903f72fbcacef033122f2fbcbf57409ae8b42b8e 100644 (file)
@@ -10,6 +10,8 @@ usage: valgrind [options] prog-and-args
     -q --quiet                run silently; only print error msgs
     -v --verbose              be more verbose -- show misc extra info
     --trace-children=no|yes   Valgrind-ise child processes (follow execve)? [no]
+    --trace-children-skip=patt1,patt2,...    specifies a list of executables
+                              that --trace-children=yes should not trace into
     --child-silent-after-fork=no|yes omit child output between fork & exec? [no]
     --track-fds=no|yes        track open file descriptors? [no]
     --time-stamp=no|yes       add timestamps to log messages? [no]
index 01df9ad01012af20611a1759c900a3eba4cd2ccc..14c192b0d571523e4af72180a5138e5d69d10029 100644 (file)
@@ -10,6 +10,8 @@ usage: valgrind [options] prog-and-args
     -q --quiet                run silently; only print error msgs
     -v --verbose              be more verbose -- show misc extra info
     --trace-children=no|yes   Valgrind-ise child processes (follow execve)? [no]
+    --trace-children-skip=patt1,patt2,...    specifies a list of executables
+                              that --trace-children=yes should not trace into
     --child-silent-after-fork=no|yes omit child output between fork & exec? [no]
     --track-fds=no|yes        track open file descriptors? [no]
     --time-stamp=no|yes       add timestamps to log messages? [no]