Make ptrace-based launchers able to handle --help, --version etc.
Problem is that --help etc are handled by the tool exe.  But a
ptrace-based launch scheme can't run "no program" if the user just
types "valgrind --help" because the launcher depends on starting the
client first and only then attaching valgrind to it using ptrace.  So
instead provide a dummy do-nothing program to run when no program is
specified.  m_main notices this and acts as if there really had been
no program specified.

This has no effect at all on Linux/ELF program launching.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@6653 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index 578e77d..d725ad4 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -42,7 +42,7 @@
 # Build the launcher (valgrind) for the primary target only.
 #
 bin_PROGRAMS = \
-	valgrind
+	valgrind no_op_client_for_valgrind
 
 if VGO_AIX5
 valgrind_SOURCES = \
@@ -59,6 +59,10 @@
 valgrind_CFLAGS    = $(AM_CFLAGS_PRI)
 valgrind_CCASFLAGS = $(AM_CCASFLAGS_PRI)
 valgrind_LDFLAGS   = $(AM_CFLAGS_PRI)
+
+no_op_client_for_valgrind_SOURCES = no_op_client_for_valgrind.c
+no_op_client_for_valgrind_CPPFLAGS  = $(AM_CPPFLAGS_PRI)
+no_op_client_for_valgrind_CFLAGS    = $(AM_CFLAGS_PRI)
 #
 #----------------------------------------------------------
 
diff --git a/coregrind/launcher-aix5.c b/coregrind/launcher-aix5.c
index eaa2dc7..775e51d 100644
--- a/coregrind/launcher-aix5.c
+++ b/coregrind/launcher-aix5.c
@@ -1329,7 +1329,7 @@
    Child child;
    Int i, loglevel;
    const char *toolname = NULL;
-   const char *clientname = NULL;
+         char *clientname = NULL;
 
    /* First, look in our own /proc/<pid>/sysent file to find
       the syscall numbers for kwrite and _getpid.  These are needed
@@ -1421,6 +1421,44 @@
 
    assert(PAGE_SIZE == 4096); /* stay sane */
 
+   const char* valgrind_lib = VG_LIBDIR;
+
+   /* If there is no program to run, which will be the case if the
+      user just does "valgrind --help", etc, run a dummy do-nothing
+      program so at least the tool can get started and handle the
+      --help/--version etc.  It spots the fact that this is a dummy
+      program and acts like it was started with no program, hence
+      behaving the same as the Linux ports would have. */
+   if (clientname == NULL) {
+      Int j;
+      char** new_argv;
+      const char* noop_exe_name = "no_op_client_for_valgrind";
+      const char* up_n_bindir = "/../../bin";
+      clientname = malloc(strlen(valgrind_lib) + strlen(up_n_bindir)
+                          + 2 + strlen(noop_exe_name));
+      if (clientname == NULL) {
+         fprintf(stderr,"%s: malloc of clientname failed\n", argv[0]);
+         return 1;
+      }
+      sprintf(clientname, "%s%s/%s", valgrind_lib, up_n_bindir, noop_exe_name);
+      /* now we have to add it to the end of argv, which means making
+	 that one word longer.  How tedious. */
+      for (j = 0; argv[j]; j++)
+	;
+      j += 2; 
+      new_argv = calloc(j, sizeof(char*));
+      if (new_argv == NULL) {
+         fprintf(stderr,"%s: malloc of new_argv failed\n", argv[0]);
+         return 1;
+      }
+      for (i = 0; i < j-2; i++)
+	new_argv[i] = argv[i];
+      new_argv[j-2] = clientname;
+      assert(new_argv[j-1] == NULL);
+      argv = new_argv;
+      argc++;
+   }
+
    if (argc < 2 || toolname == NULL || clientname == NULL)
       barf(1, argv[0], "usage: valgrind [args-for-valgrind] prog args"); 
 
@@ -1428,7 +1466,7 @@
       executable. */
    VG_(debugLog)(1, "launcher", "searching for client in $PATH\n");
    if (strchr(clientname, '/') == NULL)
-      clientname = find_client(clientname);
+      clientname = (char*)find_client(clientname);
    VG_(debugLog)(1, "launcher", "found %s\n", clientname);
 
    Int client_exekind = examine_client ( clientname );
@@ -1450,7 +1488,6 @@
    VG_(debugLog)(1, "launcher", "client is an XCOFF%d executable\n", 
                     client_exekind);
 
-   const char* valgrind_lib = VG_LIBDIR;
    const char* platform = child.is64 ? "ppc64-aix5" : "ppc32-aix5";
 
    VG_(debugLog)(1, "launcher", "looking for the tool file\n");
diff --git a/coregrind/m_initimg/initimg-aix5.c b/coregrind/m_initimg/initimg-aix5.c
index 5033be7..cf02dac 100644
--- a/coregrind/m_initimg/initimg-aix5.c
+++ b/coregrind/m_initimg/initimg-aix5.c
@@ -96,6 +96,10 @@
    IIFinaliseImageInfo iifii;
    VG_(memset)( &iifii, 0, sizeof(iifii) );
 
+   /* this can happen, if m_main decides to NULL it out */
+   if (VG_(args_the_exename) == NULL)
+      VG_(err_missing_prog)();
+
    vg_assert( iicii.toolname );
    pltool_len = VG_(strlen)( VG_(libdir) ) 
                 + 1 /*slash*/
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index 84fb4e3..0c8bebc 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -1399,6 +1399,18 @@
          );
    }
 
+#  if defined(VGO_aix5)
+   /* Tolerate ptraced-based launchers.  They can't run 'no program'
+      if the user types "valgrind --help", so they run a do-nothing
+      program $prefix/bin/no_op_client_for_valgrind, and we catch that
+      here and turn it the exe name back into NULL.  Then --help,
+      --version etc work as they should. */
+   if (VG_(args_the_exename) 
+       && VG_(strstr)( VG_(args_the_exename), "/no_op_client_for_valgrind" )) {
+      VG_(args_the_exename) = NULL;
+   }
+#  endif
+
    //--------------------------------------------------------------
    // Extract tool name and whether help has been requested.
    // Note we can't print the help message yet, even if requested,
diff --git a/coregrind/no_op_client_for_valgrind.c b/coregrind/no_op_client_for_valgrind.c
new file mode 100644
index 0000000..5956607
--- /dev/null
+++ b/coregrind/no_op_client_for_valgrind.c
@@ -0,0 +1,16 @@
+
+/* This program doesn't do anything.  So why is it here?  It's a
+   helper for ptraced-based launchers (eg aix5).  They can't run 'no
+   program' if the user types "valgrind --help", so they run this
+   do-nothing program.  m_main notices that and turns the exe name
+   back into NULL.  Then --help, --version etc work as they should. */
+
+#include <stdio.h>
+int main ( void )
+{
+  fprintf(stderr, 
+     "This program (part of Valgrind) does nothing except print\n"
+     "this text.  You should not see this text.  If you do, some\n"
+     "part of valgrind's launch mechanism is not working correctly.\n");
+  return 0;
+}