New command line option: --trace-children-skip-by-arg, which allows
chase/nochase decisions for child processes to be made on the basis
of their argv[] entries rather than on the name of their executables.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11483 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index e5871c4..d5e762d 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -124,6 +124,9 @@
 "    --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"
+"    --trace-children-skip-by-arg=patt1,patt2,...   same as --trace-children-skip=\n"
+"                              but check the argv[] entries for children, rather\n"
+"                              than the exe name, to make a follow/no-follow decision\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"
@@ -503,7 +506,10 @@
 
       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_STR_CLO (arg, "--trace-children-skip",
+                               VG_(clo_trace_children_skip)) {}
+      else if VG_STR_CLO (arg, "--trace-children-skip-by-arg",
+                               VG_(clo_trace_children_skip_by_arg)) {}
 
       else if VG_BINT_CLO(arg, "--vex-iropt-verbosity",
                        VG_(clo_vex_control).iropt_verbosity, 0, 10) {}
diff --git a/coregrind/m_options.c b/coregrind/m_options.c
index a347c7d..888e2c7 100644
--- a/coregrind/m_options.c
+++ b/coregrind/m_options.c
@@ -57,6 +57,7 @@
 Bool   VG_(clo_demangle)       = True;
 Bool   VG_(clo_trace_children) = False;
 HChar* VG_(clo_trace_children_skip) = NULL;
+HChar* VG_(clo_trace_children_skip_by_arg) = NULL;
 Bool   VG_(clo_child_silent_after_fork) = False;
 Char*  VG_(clo_log_fname_expanded) = NULL;
 Char*  VG_(clo_xml_fname_expanded) = NULL;
@@ -255,9 +256,13 @@
 }
 
 /* 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 )
+   This involves considering --trace-children=,
+   --trace-children-skip=, --trace-children-skip-by-arg=, and the name
+   of the executable.  'child_argv' must not include the name of the
+   executable itself; iow child_argv[0] must be the first arg, if any,
+   for the child. */
+Bool VG_(should_we_trace_this_child) ( HChar* child_exe_name,
+                                       HChar** child_argv )
 {
    // child_exe_name is pulled out of the guest's space.  We
    // should be at least marginally cautious with it, lest it
@@ -265,13 +270,13 @@
    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=.
+   // Otherwise, look for other reasons to say NO.  First,
+   // see if 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;
@@ -294,7 +299,36 @@
             return False;
       }
    }
- 
+
+   // Check if any of the args match any of the patterns specified
+   // by --trace-children-skip-by-arg=. 
+   if (VG_(clo_trace_children_skip_by_arg) && child_argv != NULL) {
+      HChar const* last = VG_(clo_trace_children_skip_by_arg);
+      while (*last) {
+         Int    i;
+         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);
+         for (i = 0; child_argv[i]; i++) {
+            matches = VG_(string_match)(patt, child_argv[i]);
+            if (matches) {
+               VG_(free)(patt);
+               return False;
+            }
+         }
+         VG_(free)(patt);
+      }
+   }
+
    // --trace-children=yes, and this particular executable isn't
    // excluded
    return True;
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 22eae28..2a58ea1 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -2550,8 +2550,29 @@
       return;
    }
 
+   // debug-only printing
+   if (0) {
+      VG_(printf)("ARG1 = %p(%s)\n", (void*)ARG1, (HChar*)ARG1);
+      if (ARG2) {
+         VG_(printf)("ARG2 = ");
+         Int q;
+         HChar** vec = (HChar**)ARG2;
+         for (q = 0; vec[q]; q++)
+            VG_(printf)("%p(%s) ", vec[q], vec[q]);
+         VG_(printf)("\n");
+      } else {
+         VG_(printf)("ARG2 = null\n");
+      }
+   }
+
    // Decide whether or not we want to follow along
-   trace_this_child = VG_(should_we_trace_this_child)( (HChar*)ARG1 );
+   { // Make 'child_argv' be a pointer to the child's arg vector
+     // (skipping the exe name)
+     HChar** child_argv = (HChar**)ARG2;
+     if (child_argv && child_argv[0] == NULL)
+        child_argv = NULL;
+     trace_this_child = VG_(should_we_trace_this_child)( (HChar*)ARG1, child_argv );
+   }
 
    // 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
diff --git a/coregrind/pub_core_options.h b/coregrind/pub_core_options.h
index 06b5701..ecfbd9b 100644
--- a/coregrind/pub_core_options.h
+++ b/coregrind/pub_core_options.h
@@ -70,6 +70,10 @@
 /* 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);
+/* The same as VG_(clo_trace_children), except that these patterns are
+   tested against the arguments for child processes, rather than the
+   executable name. */
+extern HChar* VG_(clo_trace_children_skip_by_arg);
 /* 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
@@ -220,9 +224,13 @@
 extern Bool VG_(clo_dsymutil);
 
 /* 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 );
+   This involves considering --trace-children=,
+   --trace-children-skip=, --trace-children-skip-by-arg=, and the name
+   of the executable.  'child_argv' must not include the name of the
+   executable itself; iow child_argv[0] must be the first arg, if any,
+   for the child. */
+extern Bool VG_(should_we_trace_this_child) ( HChar* child_exe_name,
+                                              HChar** child_argv );
 
 #endif   // __PUB_CORE_OPTIONS_H
 
diff --git a/docs/xml/manual-core.xml b/docs/xml/manual-core.xml
index 59eb787..0fb6c9d 100644
--- a/docs/xml/manual-core.xml
+++ b/docs/xml/manual-core.xml
@@ -663,7 +663,7 @@
 
   <varlistentry id="opt.trace-children-skip" xreflabel="--trace-children-skip">
     <term>
-      <option><![CDATA[--trace-children-skip=patt1,patt2 ]]></option>
+      <option><![CDATA[--trace-children-skip=patt1,patt2,... ]]></option>
     </term>
     <listitem>
       <para>This option only has an effect when 
@@ -687,6 +687,20 @@
     </listitem>
   </varlistentry>
 
+  <varlistentry id="opt.trace-children-skip-by-arg"
+                xreflabel="--trace-children-skip-by-arg">
+    <term>
+      <option><![CDATA[--trace-children-skip-by-arg=patt1,patt2,... ]]></option>
+    </term>
+    <listitem>
+      <para>This is the same as  
+        <option>--trace-children-skip</option>, with one difference:
+        the decision as to whether to trace into a child process is
+        made by examining the arguments to the child process, rather
+        than the name of its executable.</para>
+    </listitem>
+  </varlistentry>
+
   <varlistentry id="opt.child-silent-after-fork"
                 xreflabel="--child-silent-after-fork">
     <term>
diff --git a/none/tests/cmdline1.stdout.exp b/none/tests/cmdline1.stdout.exp
index 9c6d5fe..fadaa59 100644
--- a/none/tests/cmdline1.stdout.exp
+++ b/none/tests/cmdline1.stdout.exp
@@ -12,6 +12,9 @@
     --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
+    --trace-children-skip-by-arg=patt1,patt2,...   same as --trace-children-skip=
+                              but check the argv[] entries for children, rather
+                              than the exe name, to make a follow/no-follow decision
     --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]
diff --git a/none/tests/cmdline2.stdout.exp b/none/tests/cmdline2.stdout.exp
index d27316f..6603e25 100644
--- a/none/tests/cmdline2.stdout.exp
+++ b/none/tests/cmdline2.stdout.exp
@@ -12,6 +12,9 @@
     --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
+    --trace-children-skip-by-arg=patt1,patt2,...   same as --trace-children-skip=
+                              but check the argv[] entries for children, rather
+                              than the exe name, to make a follow/no-follow decision
     --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]