Implement -w flag to process launch (allow launching inferior process in different working directory) on Linux/FreeBSD
- fixes test case TestProcessLaunch



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@171854 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
index e37a660..e88d792 100644
--- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -627,14 +627,16 @@
                                        char const **envp,
                                        const char *stdin_path,
                                        const char *stdout_path,
-                                       const char *stderr_path)
+                                       const char *stderr_path,
+                                       const char *working_dir)
     : OperationArgs(monitor),
       m_module(module),
       m_argv(argv),
       m_envp(envp),
       m_stdin_path(stdin_path),
       m_stdout_path(stdout_path),
-      m_stderr_path(stderr_path) { }
+      m_stderr_path(stderr_path),
+      m_working_dir(working_dir) { }
 
 ProcessMonitor::LaunchArgs::~LaunchArgs()
 { }
@@ -665,6 +667,7 @@
                                const char *stdin_path,
                                const char *stdout_path,
                                const char *stderr_path,
+                               const char *working_dir,
                                lldb_private::Error &error)
     : m_process(static_cast<ProcessFreeBSD *>(process)),
       m_operation_thread(LLDB_INVALID_HOST_THREAD),
@@ -678,7 +681,7 @@
     std::auto_ptr<LaunchArgs> args;
 
     args.reset(new LaunchArgs(this, module, argv, envp,
-                              stdin_path, stdout_path, stderr_path));
+                              stdin_path, stdout_path, stderr_path, working_dir));
     
 
     // Server/client descriptors.
@@ -839,6 +842,7 @@
     const char *stdin_path = args->m_stdin_path;
     const char *stdout_path = args->m_stdout_path;
     const char *stderr_path = args->m_stderr_path;
+    const char *working_dir = args->m_working_dir;
     lldb::pid_t pid;
 
     lldb::ThreadSP inferior;
@@ -853,6 +857,7 @@
         eDupStdinFailed,
         eDupStdoutFailed,
         eDupStderrFailed,
+        eChdirFailed,
         eExecFailed
     };
 
@@ -887,6 +892,11 @@
             if (!DupDescriptor(stderr_path, STDERR_FILENO, O_WRONLY | O_CREAT))
                 exit(eDupStderrFailed);
 
+        // Change working directory
+        if (working_dir != NULL && working_dir[0])
+          if (0 != ::chdir(working_dir))
+              exit(eChdirFailed);
+
         // Execute.  We should never return.
         execve(argv[0],
                const_cast<char *const *>(argv),
@@ -920,6 +930,9 @@
             case eDupStderrFailed: 
                 args->m_error.SetErrorString("Child open stderr failed.");
                 break;
+            case eChdirFailed:
+                args->m_error.SetErrorString("Child failed to set working directory.");
+                break;
             case eExecFailed: 
                 args->m_error.SetErrorString("Child exec failed.");
                 break;
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
index 4193c77..1485f2b 100644
--- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
@@ -54,6 +54,7 @@
                    const char *stdin_path,
                    const char *stdout_path,
                    const char *stderr_path,
+                   const char *working_dir,
                    lldb_private::Error &error);
 
     ProcessMonitor(ProcessPOSIX *process,
@@ -210,7 +211,8 @@
                    char const **envp,
                    const char *stdin_path,
                    const char *stdout_path,
-                   const char *stderr_path);
+                   const char *stderr_path,
+                   const char *working_dir);
 
         ~LaunchArgs();
 
@@ -220,6 +222,7 @@
         const char *m_stdin_path;       // Redirect stdin or NULL.
         const char *m_stdout_path;      // Redirect stdout or NULL.
         const char *m_stderr_path;      // Redirect stderr or NULL.
+        const char *m_working_dir;      // Working directory or NULL.
     };
 
     void
diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp
index 50beddc..b71f0f9 100644
--- a/source/Plugins/Process/Linux/ProcessMonitor.cpp
+++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp
@@ -780,14 +780,16 @@
                                        char const **envp,
                                        const char *stdin_path,
                                        const char *stdout_path,
-                                       const char *stderr_path)
+                                       const char *stderr_path,
+                                       const char *working_dir)
     : OperationArgs(monitor),
       m_module(module),
       m_argv(argv),
       m_envp(envp),
       m_stdin_path(stdin_path),
       m_stdout_path(stdout_path),
-      m_stderr_path(stderr_path) { }
+      m_stderr_path(stderr_path),
+      m_working_dir(working_dir) { }
 
 ProcessMonitor::LaunchArgs::~LaunchArgs()
 { }
@@ -818,6 +820,7 @@
                                const char *stdin_path,
                                const char *stdout_path,
                                const char *stderr_path,
+                               const char *working_dir,
                                lldb_private::Error &error)
     : m_process(static_cast<ProcessLinux *>(process)),
       m_operation_thread(LLDB_INVALID_HOST_THREAD),
@@ -830,7 +833,7 @@
     std::auto_ptr<LaunchArgs> args;
 
     args.reset(new LaunchArgs(this, module, argv, envp,
-                              stdin_path, stdout_path, stderr_path));
+                              stdin_path, stdout_path, stderr_path, working_dir));
 
     // Server/client descriptors.
     if (!EnableIPC())
@@ -976,6 +979,7 @@
     const char *stdin_path = args->m_stdin_path;
     const char *stdout_path = args->m_stdout_path;
     const char *stderr_path = args->m_stderr_path;
+    const char *working_dir = args->m_working_dir;
 
     lldb_utility::PseudoTerminal terminal;
     const size_t err_len = 1024;
@@ -1010,6 +1014,7 @@
         eDupStdinFailed,
         eDupStdoutFailed,
         eDupStderrFailed,
+        eChdirFailed,
         eExecFailed
     };
 
@@ -1042,6 +1047,11 @@
             if (!DupDescriptor(stderr_path, STDERR_FILENO, O_WRONLY | O_CREAT))
                 exit(eDupStderrFailed);
 
+        // Change working directory
+        if (working_dir != NULL && working_dir[0])
+          if (0 != ::chdir(working_dir))
+              exit(eChdirFailed);
+
         // Execute.  We should never return.
         execve(argv[0],
                const_cast<char *const *>(argv),
@@ -1075,6 +1085,9 @@
             case eDupStderrFailed:
                 args->m_error.SetErrorString("Child open stderr failed.");
                 break;
+            case eChdirFailed:
+                args->m_error.SetErrorString("Child failed to set working directory.");
+                break;
             case eExecFailed:
                 args->m_error.SetErrorString("Child exec failed.");
                 break;
diff --git a/source/Plugins/Process/Linux/ProcessMonitor.h b/source/Plugins/Process/Linux/ProcessMonitor.h
index b154a6d..4fefae2 100644
--- a/source/Plugins/Process/Linux/ProcessMonitor.h
+++ b/source/Plugins/Process/Linux/ProcessMonitor.h
@@ -56,6 +56,7 @@
                    const char *stdin_path,
                    const char *stdout_path,
                    const char *stderr_path,
+                   const char *working_dir,
                    lldb_private::Error &error);
 
     ProcessMonitor(ProcessPOSIX *process,
@@ -200,7 +201,8 @@
                    char const **envp,
                    const char *stdin_path,
                    const char *stdout_path,
-                   const char *stderr_path);
+                   const char *stderr_path,
+                   const char *working_dir);
 
         ~LaunchArgs();
 
@@ -210,6 +212,7 @@
         const char *m_stdin_path;       // Redirect stdin or NULL.
         const char *m_stdout_path;      // Redirect stdout or NULL.
         const char *m_stderr_path;      // Redirect stderr or NULL.
+        const char *m_working_dir;      // Working directory or NULL.
     };
 
     void
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
index f6b9270..a694865 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -17,6 +17,7 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/State.h"
+#include "lldb/Host/FileSpec.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Target/DynamicLoader.h"
@@ -162,6 +163,16 @@
     Error error;
     assert(m_monitor == NULL);
 
+    const char* working_dir = launch_info.GetWorkingDirectory();
+    if (working_dir) {
+      FileSpec WorkingDir(working_dir, true);
+      if (!WorkingDir || WorkingDir.GetFileType() != FileSpec::eFileTypeDirectory)
+      {
+          error.SetErrorStringWithFormat("No such file or directory: %s", working_dir);
+          return error;
+      }
+    }
+
     SetPrivateState(eStateLaunching);
 
     const lldb_private::ProcessLaunchInfo::FileAction *file_action;
@@ -170,7 +181,7 @@
     const char *stdin_path = NULL;
     const char *stdout_path = NULL;
     const char *stderr_path = NULL;
-    
+
     file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
     stdin_path = GetFilePath(file_action, stdin_path);
 
@@ -187,6 +198,7 @@
                                     stdin_path, 
                                     stdout_path, 
                                     stderr_path,
+                                    working_dir,
                                     error);
 
     m_module = module;