Get rid of VG_(getcwd) and replace it with a pair of functions,
VG_(record_startup_wd) which records the working directory at startup,
and VG_(get_startup_wd) which later tells you what value was recorded.
This works because all uses of VG_(getcwd) serve only to record the
directory at process start anyway.  The motivation is that AIX does
not support sys_getcwd directly, so it's easier for the launcher to
ship in the required value using an environment variable.  On Linux
sys_getcwd is used as before.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@6764 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c
index 7901a01..345a6cb 100644
--- a/cachegrind/cg_main.c
+++ b/cachegrind/cg_main.c
@@ -1754,7 +1754,7 @@
    }
 
    /* Get working directory */
-   tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
+   tl_assert( VG_(get_startup_wd)(base_dir, VKI_PATH_MAX) );
 
    /* Do we have a --log-file-qualifier= to consider? */
    if (VG_(clo_log_file_qualifier)) {
diff --git a/callgrind/dump.c b/callgrind/dump.c
index 7172533..a46a180 100644
--- a/callgrind/dump.c
+++ b/callgrind/dump.c
@@ -1689,7 +1689,7 @@
           until it succeeds. */
        while (NULL == base_directory) {
            base_directory = CLG_MALLOC(size);
-           if (!VG_(getcwd)(base_directory, size)) {
+           if (!VG_(get_startup_wd)(base_directory, size)) {
                VG_(free)(base_directory);
                base_directory = 0;
                size *= 2;
diff --git a/coregrind/launcher-aix5.c b/coregrind/launcher-aix5.c
index e7f2115..4b47534 100644
--- a/coregrind/launcher-aix5.c
+++ b/coregrind/launcher-aix5.c
@@ -1526,6 +1526,29 @@
       return 1;
    }
 
+   /* Find out what the current working directory is, and stuff it into the
+      environment so that the child can find it. */
+   char wd_buf[4096];
+   memset(wd_buf, 0, sizeof(wd_buf));
+   if (getcwd(wd_buf, sizeof(wd_buf)-1) == NULL) {
+      fprintf(stderr,"%s: getcwd(..) failed\n", argv[0]);
+      return 1;
+   }
+   assert(wd_buf[ sizeof(wd_buf)-1 ] == 0);
+   char* set_cwd = calloc(1, 100+sizeof(wd_buf));   
+   if (set_cwd == NULL) {
+      fprintf(stderr,"%s: calloc of set_cwd failed\n", argv[0]);
+      return 1;
+   }
+   sprintf(set_cwd, "VALGRIND_STARTUP_PWD_%d_XYZZY=%s", getpid(), wd_buf);
+   VG_(debugLog)(1, "launcher", "doing putenv(\"%s\")\n", set_cwd);
+   putenv_err = putenv(set_cwd);
+   if (putenv_err) {
+      fprintf(stderr,"%s: putenv(\"VALGRIND_STARTUP_PWD_...\") failed\n", 
+                     argv[0]);
+      return 1;
+   }
+
    /* Also, cook up the fully qualified name of this executable.  The
       following is a kludge, but I don't see how to really get the
       fully qualified name on AIX. */
diff --git a/coregrind/m_commandline.c b/coregrind/m_commandline.c
index 3c3d95e..19ad82a 100644
--- a/coregrind/m_commandline.c
+++ b/coregrind/m_commandline.c
@@ -210,7 +210,7 @@
       // contents will be applied twice. (bug #142488)
       if (home) {
          HChar cwd[VKI_PATH_MAX+1];
-         Bool  cwd_ok = VG_(getcwd)(cwd, VKI_PATH_MAX);
+         Bool  cwd_ok = VG_(get_startup_wd)(cwd, VKI_PATH_MAX);
          f2_clo = ( (cwd_ok && VG_STREQ(home, cwd))
                        ? NULL : read_dot_valgrindrc(".") );
       }
diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c
index 2038ee4..f04fbde 100644
--- a/coregrind/m_libcfile.c
+++ b/coregrind/m_libcfile.c
@@ -217,27 +217,73 @@
    return res.isError ? (-1) : 0;
 }
 
-Bool VG_(getcwd) ( Char* buf, SizeT size )
+/* The working directory at startup.  AIX doesn't provide an easy
+   system call to do getcwd, but fortunately we don't need arbitrary
+   getcwd support.  All that is really needed is to note the cwd at
+   process startup.  Hence VG_(record_startup_wd) notes it (in a
+   platform dependent way) and VG_(get_startup_wd) produces the noted
+   value.  Hence: */
+static HChar startup_wd[VKI_PATH_MAX];
+static Bool  startup_wd_acquired = False;
+
+/* Record the process' working directory at startup.  Is intended to
+   be called exactly once, at startup, before the working directory
+   changes.  Return True for success, False for failure, so that the
+   caller can bomb out suitably without creating module cycles if
+   there is a problem. */
+Bool VG_(record_startup_wd) ( void )
 {
+   const Int szB = sizeof(startup_wd);
+   vg_assert(!startup_wd_acquired);
+   vg_assert(szB >= 512 && szB <= 16384/*let's say*/); /* stay sane */
+   VG_(memset)(startup_wd, 0, szB);
 #  if defined(VGO_linux)
-   SysRes res;
-   vg_assert(buf != NULL);
-   res = VG_(do_syscall2)(__NR_getcwd, (UWord)buf, size);
-   return res.isError ? False : True;
+   /* Simple: just ask the kernel */
+   { SysRes res
+        = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1);
+     vg_assert(startup_wd[szB-1] == 0);
+     if (res.isError) {
+        return False;
+     } else {
+        startup_wd_acquired = True;
+        return True;
+     }
+   }
 #  elif defined(VGO_aix5)
-   static Int complaints = 3;
-   if (complaints-- > 0)
-      VG_(debugLog)(0, "libcfile",
-                       "Warning: AIX5: m_libcfile.c: kludged 'getcwd'\n");
-   if (size < 2) return False;
-   buf[0] = '.';
-   buf[1] = 0;
-   return True;
+   /* We can't ask the kernel, so instead rely on launcher-aix5.c to
+      tell us the startup path.  Note the env var is keyed to the
+      parent's PID, not ours, since our parent is the launcher
+      process. */
+   { Char  envvar[100];
+     Char* wd = NULL;
+     VG_(memset)(envvar, 0, sizeof(envvar));
+     VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY", 
+                          (Int)VG_(getppid)());
+     wd = VG_(getenv)( envvar );
+     if (wd == NULL || (1+VG_(strlen)(wd) >= szB))
+        return False;
+     VG_(strncpy_safely)(startup_wd, wd, szB);
+     vg_assert(startup_wd[szB-1] == 0);
+     startup_wd_acquired = True;
+     return True;
+   }
 #  else
 #    error Unknown OS
 #  endif
 }
 
+/* Copy the previously acquired startup_wd into buf[0 .. size-1],
+   or return False if buf isn't big enough. */
+Bool VG_(get_startup_wd) ( Char* buf, SizeT size )
+{
+   vg_assert(startup_wd_acquired);
+   vg_assert(startup_wd[ sizeof(startup_wd)-1 ] == 0);
+   if (1+VG_(strlen)(startup_wd) >= size)
+      return False;
+   VG_(strncpy_safely)(buf, startup_wd, size);
+   return True;
+}
+
 Int VG_(readlink) (Char* path, Char* buf, UInt bufsiz)
 {
    SysRes res;
diff --git a/coregrind/m_libcproc.c b/coregrind/m_libcproc.c
index 1dc748e..3b9cf93 100644
--- a/coregrind/m_libcproc.c
+++ b/coregrind/m_libcproc.c
@@ -47,7 +47,7 @@
 
 /* As deduced from sp_at_startup, the client's argc, argv[] and
    envp[] as extracted from the client's stack at startup-time. */
-Char** VG_(client_envp);
+Char** VG_(client_envp) = NULL;
 
 /* Path to library directory */
 const Char *VG_(libdir) = VG_LIBDIR;
@@ -57,6 +57,7 @@
 Char *VG_(getenv)(Char *varname)
 {
    Int i, n;
+   vg_assert( VG_(client_envp) );
    n = VG_(strlen)(varname);
    for (i = 0; VG_(client_envp)[i] != NULL; i++) {
       Char* s = VG_(client_envp)[i];
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index 80a6ebd..319753d 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -1377,6 +1377,22 @@
      );
    }
 
+   //--------------------------------------------------------------
+   // Record the working directory at startup
+   //   p: none (Linux), getenv and sys_getpid work (AIX)
+   VG_(debugLog)(1, "main", "Getting the working directory at startup\n");
+   { Bool ok = VG_(record_startup_wd)();
+     if (!ok) 
+        VG_(err_config_error)( "Can't establish current working "
+                               "directory at startup");
+   }
+   { Char buf[VKI_PATH_MAX+1];
+     Bool ok = VG_(get_startup_wd)( buf, sizeof(buf) );
+     vg_assert(ok);
+     buf[VKI_PATH_MAX] = 0;
+     VG_(debugLog)(1, "main", "... %s\n", buf );
+   }
+
    //============================================================
    // Command line argument handling order:
    // * If --help/--help-debug are present, show usage message 
diff --git a/coregrind/pub_core_libcfile.h b/coregrind/pub_core_libcfile.h
index f859777..83a426f 100644
--- a/coregrind/pub_core_libcfile.h
+++ b/coregrind/pub_core_libcfile.h
@@ -81,6 +81,14 @@
    written is guaranteed not to exceed 64+strlen(part_of_name). */
 extern Int VG_(mkstemp) ( HChar* part_of_name, /*OUT*/HChar* fullname );
 
+/* Record the process' working directory at startup.  Is intended to
+   be called exactly once, at startup, before the working directory
+   changes.  Return True for success, False for failure, so that the
+   caller can bomb out suitably without creating module cycles if
+   there is a problem.  The saved value can later be acquired by
+   calling VG_(get_startup_wd) (in pub_tool_libcfile.h). */
+extern Bool VG_(record_startup_wd) ( void );
+
 #endif   // __PUB_CORE_LIBCFILE_H
 
 /*--------------------------------------------------------------------*/
diff --git a/include/pub_tool_libcfile.h b/include/pub_tool_libcfile.h
index 7d394cb..d51b361 100644
--- a/include/pub_tool_libcfile.h
+++ b/include/pub_tool_libcfile.h
@@ -56,6 +56,10 @@
 extern Int    VG_(readlink)( Char* path, Char* buf, UInt bufsize );
 extern Int    VG_(getdents)( UInt fd, struct vki_dirent *dirp, UInt count );
 
+/* Copy the working directory at startup into buf[0 .. size-1], or return
+   False if buf is too small. */
+extern Bool VG_(get_startup_wd) ( Char* buf, SizeT size );
+
 #endif   // __PUB_TOOL_LIBCFILE_H
 
 /*--------------------------------------------------------------------*/
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 6fa430b..55c4828 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -1758,7 +1758,7 @@
    // Dummy node at top of the context structure.
    alloc_xpt = new_XPt(0, NULL, /*is_bottom*/False);
 
-   tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
+   tl_assert( VG_(get_startup_wd)(base_dir, VKI_PATH_MAX) );
 }
 
 VG_DETERMINE_INTERFACE_VERSION(ms_pre_clo_init)