Refactor many file functions to use FileSpec over strings.

Summary:
This should solve the issue of sending denormalized paths over gdb-remote
if we stick to GetPath(false) in GDBRemoteCommunicationClient, and let the
server handle any denormalization.

Reviewers: ovyalov, zturner, vharron, clayborg

Reviewed By: clayborg

Subscribers: tberghammer, emaste, lldb-commits

Differential Revision: http://reviews.llvm.org/D9728

llvm-svn: 238604
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 3e92788..0a1ec3f 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -1325,7 +1325,7 @@
     const char *arg = NULL;
     const Args &launch_args = launch_info.GetArguments();
     if (exe_file)
-        exe_path = exe_file.GetPath();
+        exe_path = exe_file.GetPath(false);
     else
     {
         arg = launch_args.GetArgumentAtIndex(0);
@@ -2221,13 +2221,14 @@
 }
 
 int
-GDBRemoteCommunicationClient::SetSTDIN (char const *path)
+GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec)
 {
-    if (path && path[0])
+    if (file_spec)
     {
+        std::string path{file_spec.GetPath(false)};
         StreamString packet;
         packet.PutCString("QSetSTDIN:");
-        packet.PutBytesAsRawHex8(path, strlen(path));
+        packet.PutCStringAsRawHex8(path.c_str());
 
         StringExtractorGDBRemote response;
         if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
@@ -2243,14 +2244,15 @@
 }
 
 int
-GDBRemoteCommunicationClient::SetSTDOUT (char const *path)
+GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec)
 {
-    if (path && path[0])
+    if (file_spec)
     {
+        std::string path{file_spec.GetPath(false)};
         StreamString packet;
         packet.PutCString("QSetSTDOUT:");
-        packet.PutBytesAsRawHex8(path, strlen(path));
-        
+        packet.PutCStringAsRawHex8(path.c_str());
+
         StringExtractorGDBRemote response;
         if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
         {
@@ -2265,14 +2267,15 @@
 }
 
 int
-GDBRemoteCommunicationClient::SetSTDERR (char const *path)
+GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec)
 {
-    if (path && path[0])
+    if (file_spec)
     {
+        std::string path{file_spec.GetPath(false)};
         StreamString packet;
         packet.PutCString("QSetSTDERR:");
-        packet.PutBytesAsRawHex8(path, strlen(path));
-        
+        packet.PutCStringAsRawHex8(path.c_str());
+
         StringExtractorGDBRemote response;
         if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
         {
@@ -2287,7 +2290,7 @@
 }
 
 bool
-GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd)
+GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir)
 {
     StringExtractorGDBRemote response;
     if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success)
@@ -2296,21 +2299,24 @@
             return false;
         if (response.IsErrorResponse())
             return false;
-        response.GetHexByteString (cwd);
+        std::string cwd;
+        response.GetHexByteString(cwd);
+        working_dir.SetFile(cwd, false);
         return !cwd.empty();
     }
     return false;
 }
 
 int
-GDBRemoteCommunicationClient::SetWorkingDir (char const *path)
+GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir)
 {
-    if (path && path[0])
+    if (working_dir)
     {
+        std::string path{working_dir.GetPath(false)};
         StreamString packet;
         packet.PutCString("QSetWorkingDir:");
-        packet.PutBytesAsRawHex8(path, strlen(path));
-        
+        packet.PutCStringAsRawHex8(path.c_str());
+
         StringExtractorGDBRemote response;
         if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
         {
@@ -3262,22 +3268,23 @@
 }
 
 lldb_private::Error
-GDBRemoteCommunicationClient::RunShellCommand (const char *command,           // Shouldn't be NULL
-                                               const char *working_dir,       // Pass NULL to use the current working directory
-                                               int *status_ptr,               // Pass NULL if you don't want the process exit status
-                                               int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
-                                               std::string *command_output,   // Pass NULL if you don't want the command output
-                                               uint32_t timeout_sec)          // Timeout in seconds to wait for shell program to finish
+GDBRemoteCommunicationClient::RunShellCommand(const char *command,           // Shouldn't be NULL
+                                              const FileSpec &working_dir,   // Pass empty FileSpec to use the current working directory
+                                              int *status_ptr,               // Pass NULL if you don't want the process exit status
+                                              int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
+                                              std::string *command_output,   // Pass NULL if you don't want the command output
+                                              uint32_t timeout_sec)          // Timeout in seconds to wait for shell program to finish
 {
     lldb_private::StreamString stream;
     stream.PutCString("qPlatform_shell:");
     stream.PutBytesAsRawHex8(command, strlen(command));
     stream.PutChar(',');
     stream.PutHex32(timeout_sec);
-    if (working_dir && *working_dir)
+    if (working_dir)
     {
+        std::string path{working_dir.GetPath(false)};
         stream.PutChar(',');
-        stream.PutBytesAsRawHex8(working_dir, strlen(working_dir));
+        stream.PutCStringAsRawHex8(path.c_str());
     }
     const char *packet = stream.GetData();
     int packet_len = stream.GetSize();
@@ -3310,14 +3317,15 @@
 }
 
 Error
-GDBRemoteCommunicationClient::MakeDirectory (const char *path,
-                                             uint32_t file_permissions)
+GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec,
+                                            uint32_t file_permissions)
 {
+    std::string path{file_spec.GetPath(false)};
     lldb_private::StreamString stream;
     stream.PutCString("qPlatform_mkdir:");
     stream.PutHex32(file_permissions);
     stream.PutChar(',');
-    stream.PutBytesAsRawHex8(path, strlen(path));
+    stream.PutCStringAsRawHex8(path.c_str());
     const char *packet = stream.GetData();
     int packet_len = stream.GetSize();
     StringExtractorGDBRemote response;
@@ -3332,14 +3340,15 @@
 }
 
 Error
-GDBRemoteCommunicationClient::SetFilePermissions (const char *path,
-                                                  uint32_t file_permissions)
+GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec,
+                                                 uint32_t file_permissions)
 {
+    std::string path{file_spec.GetPath(false)};
     lldb_private::StreamString stream;
     stream.PutCString("qPlatform_chmod:");
     stream.PutHex32(file_permissions);
     stream.PutChar(',');
-    stream.PutBytesAsRawHex8(path, strlen(path));
+    stream.PutCStringAsRawHex8(path.c_str());
     const char *packet = stream.GetData();
     int packet_len = stream.GetSize();
     StringExtractorGDBRemote response;
@@ -3382,9 +3391,9 @@
                                         mode_t mode,
                                         Error &error)
 {
+    std::string path(file_spec.GetPath(false));
     lldb_private::StreamString stream;
     stream.PutCString("vFile:open:");
-    std::string path (file_spec.GetPath(false));
     if (path.empty())
         return UINT64_MAX;
     stream.PutCStringAsRawHex8(path.c_str());
@@ -3422,9 +3431,9 @@
 lldb::user_id_t
 GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec)
 {
+    std::string path(file_spec.GetPath(false));
     lldb_private::StreamString stream;
     stream.PutCString("vFile:size:");
-    std::string path (file_spec.GetPath());
     stream.PutCStringAsRawHex8(path.c_str());
     const char* packet = stream.GetData();
     int packet_len = stream.GetSize();
@@ -3440,12 +3449,14 @@
 }
 
 Error
-GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &file_permissions)
+GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec,
+                                                 uint32_t &file_permissions)
 {
+    std::string path{file_spec.GetPath(false)};
     Error error;
     lldb_private::StreamString stream;
     stream.PutCString("vFile:mode:");
-    stream.PutCStringAsRawHex8(path);
+    stream.PutCStringAsRawHex8(path.c_str());
     const char* packet = stream.GetData();
     int packet_len = stream.GetSize();
     StringExtractorGDBRemote response;
@@ -3564,16 +3575,18 @@
 }
 
 Error
-GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst)
+GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, const FileSpec &dst)
 {
+    std::string src_path{src.GetPath(false)},
+                dst_path{dst.GetPath(false)};
     Error error;
     lldb_private::StreamGDBRemote stream;
     stream.PutCString("vFile:symlink:");
     // the unix symlink() command reverses its parameters where the dst if first,
     // so we follow suit here
-    stream.PutCStringAsRawHex8(dst);
+    stream.PutCStringAsRawHex8(dst_path.c_str());
     stream.PutChar(',');
-    stream.PutCStringAsRawHex8(src);
+    stream.PutCStringAsRawHex8(src_path.c_str());
     const char* packet = stream.GetData();
     int packet_len = stream.GetSize();
     StringExtractorGDBRemote response;
@@ -3607,14 +3620,15 @@
 }
 
 Error
-GDBRemoteCommunicationClient::Unlink (const char *path)
+GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec)
 {
+    std::string path{file_spec.GetPath(false)};
     Error error;
     lldb_private::StreamGDBRemote stream;
     stream.PutCString("vFile:unlink:");
     // the unix symlink() command reverses its parameters where the dst if first,
     // so we follow suit here
-    stream.PutCStringAsRawHex8(path);
+    stream.PutCStringAsRawHex8(path.c_str());
     const char* packet = stream.GetData();
     int packet_len = stream.GetSize();
     StringExtractorGDBRemote response;
@@ -3651,9 +3665,9 @@
 bool
 GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec)
 {
+    std::string path(file_spec.GetPath(false));
     lldb_private::StreamString stream;
     stream.PutCString("vFile:exists:");
-    std::string path (file_spec.GetPath());
     stream.PutCStringAsRawHex8(path.c_str());
     const char* packet = stream.GetData();
     int packet_len = stream.GetSize();
@@ -3675,9 +3689,9 @@
                                             uint64_t &high,
                                             uint64_t &low)
 {
+    std::string path(file_spec.GetPath(false));
     lldb_private::StreamString stream;
     stream.PutCString("vFile:MD5:");
-    std::string path (file_spec.GetPath());
     stream.PutCStringAsRawHex8(path.c_str());
     const char* packet = stream.GetData();
     int packet_len = stream.GetSize();
@@ -3874,7 +3888,7 @@
     packet.PutCStringAsRawHex8(module_path.c_str());
     packet.PutCString(";");
     const auto& triple = arch_spec.GetTriple().getTriple();
-    packet.PutBytesAsRawHex8(triple.c_str(), triple.size());
+    packet.PutCStringAsRawHex8(triple.c_str());
 
     StringExtractorGDBRemote response;
     if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) != PacketResult::Success)
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 23b5d38..726bc57 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -205,11 +205,11 @@
     ///     Zero if the for success, or an error code for failure.
     //------------------------------------------------------------------
     int
-    SetSTDIN (char const *path);
+    SetSTDIN(const FileSpec &file_spec);
     int
-    SetSTDOUT (char const *path);
+    SetSTDOUT(const FileSpec &file_spec);
     int
-    SetSTDERR (char const *path);
+    SetSTDERR(const FileSpec &file_spec);
 
     //------------------------------------------------------------------
     /// Sets the disable ASLR flag to \a enable for a process that will 
@@ -243,27 +243,27 @@
     /// implements the platform, it will change the current working
     /// directory for the platform process.
     ///
-    /// @param[in] path
+    /// @param[in] working_dir
     ///     The path to a directory to use when launching our process
     ///
     /// @return
     ///     Zero if the for success, or an error code for failure.
     //------------------------------------------------------------------
     int
-    SetWorkingDir (char const *path);
+    SetWorkingDir(const FileSpec &working_dir);
 
     //------------------------------------------------------------------
     /// Gets the current working directory of a remote platform GDB
     /// server.
     ///
-    /// @param[out] cwd
+    /// @param[out] working_dir
     ///     The current working directory on the remote platform.
     ///
     /// @return
     ///     Boolean for success
     //------------------------------------------------------------------
     bool
-    GetWorkingDir (std::string &cwd);
+    GetWorkingDir(FileSpec &working_dir);
 
     lldb::addr_t
     AllocateMemory (size_t size, uint32_t permissions);
@@ -466,10 +466,10 @@
     GetFileSize (const FileSpec& file_spec);
     
     Error
-    GetFilePermissions(const char *path, uint32_t &file_permissions);
+    GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions);
 
     Error
-    SetFilePermissions(const char *path, uint32_t file_permissions);
+    SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions);
 
     uint64_t
     ReadFile (lldb::user_id_t fd,
@@ -486,26 +486,26 @@
                Error &error);
     
     Error
-    CreateSymlink (const char *src,
-                   const char *dst);
+    CreateSymlink(const FileSpec &src,
+                  const FileSpec &dst);
     
     Error
-    Unlink (const char *path);
+    Unlink(const FileSpec &file_spec);
 
     Error
-    MakeDirectory (const char *path, uint32_t mode);
-    
+    MakeDirectory(const FileSpec &file_spec, uint32_t mode);
+
     bool
     GetFileExists (const FileSpec& file_spec);
     
     Error
-    RunShellCommand (const char *command,           // Shouldn't be NULL
-                     const char *working_dir,       // Pass NULL to use the current working directory
-                     int *status_ptr,               // Pass NULL if you don't want the process exit status
-                     int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
-                     std::string *command_output,   // Pass NULL if you don't want the command output
-                     uint32_t timeout_sec);         // Timeout in seconds to wait for shell program to finish
-    
+    RunShellCommand(const char *command,           // Shouldn't be NULL
+                    const FileSpec &working_dir,   // Pass empty FileSpec to use the current working directory
+                    int *status_ptr,               // Pass NULL if you don't want the process exit status
+                    int *signo_ptr,                // Pass NULL if you don't want the signal that caused the process to exit
+                    std::string *command_output,   // Pass NULL if you don't want the command output
+                    uint32_t timeout_sec);         // Timeout in seconds to wait for shell program to finish
+
     bool
     CalculateMD5 (const FileSpec& file_spec, uint64_t &high, uint64_t &low);
     
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index c61d9f4..18e8118 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -584,8 +584,8 @@
             {
                 mode_t mode = packet.GetHexMaxU32(false, 0600);
                 Error error;
-                const FileSpec path_spec(path.c_str(), true);
-                int fd = ::open (path_spec.GetPath().c_str(), flags, mode);
+                const FileSpec path_spec{path, true};
+                int fd = ::open(path_spec.GetCString(), flags, mode);
                 const int save_errno = fd == -1 ? errno : 0;
                 StreamString response;
                 response.PutChar('F');
@@ -734,7 +734,7 @@
     if (!path.empty())
     {
         Error error;
-        const uint32_t mode = File::GetPermissions(path.c_str(), error);
+        const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error);
         StreamString response;
         response.Printf("F%u", mode);
         if (mode == 0 || error.Fail())
@@ -773,7 +773,7 @@
     packet.GetHexByteStringTerminatedBy(dst, ',');
     packet.GetChar(); // Skip ',' char
     packet.GetHexByteString(src);
-    Error error = FileSystem::Symlink(src.c_str(), dst.c_str());
+    Error error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false});
     StreamString response;
     response.Printf("F%u,%u", error.GetError(), error.GetError());
     return SendPacketNoLock(response.GetData(), response.GetSize());
@@ -785,7 +785,7 @@
     packet.SetFilePos(::strlen("vFile:unlink:"));
     std::string path;
     packet.GetHexByteString(path);
-    Error error = FileSystem::Unlink(path.c_str());
+    Error error = FileSystem::Unlink(FileSpec{path, true});
     StreamString response;
     response.Printf("F%u,%u", error.GetError(), error.GetError());
     return SendPacketNoLock(response.GetData(), response.GetSize());
@@ -810,7 +810,7 @@
             int status, signo;
             std::string output;
             Error err = Host::RunShellCommand(path.c_str(),
-                                              working_dir.empty() ? NULL : working_dir.c_str(),
+                                              FileSpec{working_dir, true},
                                               &status, &signo, &output, timeout);
             StreamGDBRemote response;
             if (err.Fail())
@@ -875,8 +875,8 @@
     {
         std::string path;
         packet.GetHexByteString(path);
-        Error error = FileSystem::MakeDirectory(path.c_str(), mode);
-        
+        Error error = FileSystem::MakeDirectory(FileSpec{path, false}, mode);
+
         StreamGDBRemote response;
         response.Printf("F%u", error.GetError());
 
@@ -895,7 +895,7 @@
     {
         std::string path;
         packet.GetHexByteString(path);
-        Error error = FileSystem::SetFilePermissions(path.c_str(), mode);
+        Error error = FileSystem::SetFilePermissions(FileSpec{path, true}, mode);
 
         StreamGDBRemote response;
         response.Printf("F%u", error.GetError());
@@ -968,7 +968,7 @@
     packet.GetHexByteString(path);
     const bool read = false;
     const bool write = true;
-    if (file_action.Open(STDIN_FILENO, path.c_str(), read, write))
+    if (file_action.Open(STDIN_FILENO, FileSpec{path, false}, read, write))
     {
         m_process_launch_info.AppendFileAction(file_action);
         return SendOKResponse ();
@@ -985,7 +985,7 @@
     packet.GetHexByteString(path);
     const bool read = true;
     const bool write = false;
-    if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write))
+    if (file_action.Open(STDOUT_FILENO, FileSpec{path, false}, read, write))
     {
         m_process_launch_info.AppendFileAction(file_action);
         return SendOKResponse ();
@@ -1002,7 +1002,7 @@
     packet.GetHexByteString(path);
     const bool read = true;
     const bool write = false;
-    if (file_action.Open(STDERR_FILENO, path.c_str(), read, write))
+    if (file_action.Open(STDERR_FILENO, FileSpec{path, false}, read, write))
     {
         m_process_launch_info.AppendFileAction(file_action);
         return SendOKResponse ();
@@ -1217,7 +1217,7 @@
     response.PutChar(';');
 
     response.PutCString("file_path:");
-    response.PutCStringAsRawHex8(module_path_spec.GetPath().c_str());
+    response.PutCStringAsRawHex8(module_path_spec.GetCString());
     response.PutChar(';');
     response.PutCString("file_offset:");
     response.PutHex64(file_offset);
@@ -1241,7 +1241,7 @@
                      proc_info.GetEffectiveUserID(),
                      proc_info.GetEffectiveGroupID());
     response.PutCString ("name:");
-    response.PutCStringAsRawHex8(proc_info.GetExecutableFile().GetPath().c_str());
+    response.PutCStringAsRawHex8(proc_info.GetExecutableFile().GetCString());
     response.PutChar(';');
     const ArchSpec &proc_arch = proc_info.GetArchitecture();
     if (proc_arch.IsValid())
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 5ffd1e9..8b31dbe 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -950,18 +950,18 @@
     packet.SetFilePos (::strlen ("QSetWorkingDir:"));
     std::string path;
     packet.GetHexByteString (path);
-    m_process_launch_info.SwapWorkingDirectory (path);
+    m_process_launch_info.SetWorkingDirectory(FileSpec{path, true});
     return SendOKResponse ();
 }
 
 GDBRemoteCommunication::PacketResult
 GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
 {
-    const char *working_dir = m_process_launch_info.GetWorkingDirectory();
-    if (working_dir && working_dir[0])
+    FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()};
+    if (working_dir)
     {
         StreamString response;
-        response.PutBytesAsRawHex8(working_dir, strlen(working_dir));
+        response.PutCStringAsRawHex8(working_dir.GetCString());
         return SendPacketNoLock(response.GetData(), response.GetSize());
     }
 
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 3c825c7..7100163 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -878,45 +878,45 @@
         log->Printf ("ProcessGDBRemote::%s() entered", __FUNCTION__);
 
     uint32_t launch_flags = launch_info.GetFlags().Get();
-    const char *stdin_path = NULL;
-    const char *stdout_path = NULL;
-    const char *stderr_path = NULL;
-    const char *working_dir = launch_info.GetWorkingDirectory();
+    FileSpec stdin_file_spec{};
+    FileSpec stdout_file_spec{};
+    FileSpec stderr_file_spec{};
+    FileSpec working_dir = launch_info.GetWorkingDirectory();
 
     const FileAction *file_action;
     file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
     if (file_action)
     {
         if (file_action->GetAction() == FileAction::eFileActionOpen)
-            stdin_path = file_action->GetPath();
+            stdin_file_spec = file_action->GetFileSpec();
     }
     file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
     if (file_action)
     {
         if (file_action->GetAction() == FileAction::eFileActionOpen)
-            stdout_path = file_action->GetPath();
+            stdout_file_spec = file_action->GetFileSpec();
     }
     file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
     if (file_action)
     {
         if (file_action->GetAction() == FileAction::eFileActionOpen)
-            stderr_path = file_action->GetPath();
+            stderr_file_spec = file_action->GetFileSpec();
     }
 
     if (log)
     {
-        if (stdin_path || stdout_path || stderr_path)
+        if (stdin_file_spec || stdout_file_spec || stderr_file_spec)
             log->Printf ("ProcessGDBRemote::%s provided with STDIO paths via launch_info: stdin=%s, stdout=%s, stderr=%s",
                          __FUNCTION__,
-                         stdin_path ? stdin_path : "<null>",
-                         stdout_path ? stdout_path : "<null>",
-                         stderr_path ? stderr_path : "<null>");
+                          stdin_file_spec ?  stdin_file_spec.GetCString() : "<null>",
+                         stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
+                         stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
         else
             log->Printf ("ProcessGDBRemote::%s no STDIO paths given via launch_info", __FUNCTION__);
     }
 
     const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
-    if (stdin_path || disable_stdio)
+    if (stdin_file_spec || disable_stdio)
     {
         // the inferior will be reading stdin from the specified file
         // or stdio is completely disabled
@@ -949,12 +949,12 @@
             if (disable_stdio)
             {
                 // set to /dev/null unless redirected to a file above
-                if (!stdin_path)
-                    stdin_path = "/dev/null";
-                if (!stdout_path)
-                    stdout_path = "/dev/null";
-                if (!stderr_path)
-                    stderr_path = "/dev/null";
+                if (!stdin_file_spec)
+                    stdin_file_spec.SetFile("/dev/null", false);
+                if (!stdout_file_spec)
+                    stdout_file_spec.SetFile("/dev/null", false);
+                if (!stderr_file_spec)
+                    stderr_file_spec.SetFile("/dev/null", false);
             }
             else if (platform_sp && platform_sp->IsHost())
             {
@@ -962,42 +962,41 @@
                 // a pseudo terminal to instead of relying on the 'O' packets for stdio
                 // since 'O' packets can really slow down debugging if the inferior
                 // does a lot of output.
-                const char *slave_name = NULL;
-                if (stdin_path == NULL || stdout_path == NULL || stderr_path == NULL)
+                if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&
+                        pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, NULL, 0))
                 {
-                    if (pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, NULL, 0))
-                        slave_name = pty.GetSlaveName (NULL, 0);
+                    FileSpec slave_name{pty.GetSlaveName(NULL, 0), false};
+
+                    if (!stdin_file_spec)
+                        stdin_file_spec = slave_name;
+
+                    if (!stdout_file_spec)
+                        stdout_file_spec = slave_name;
+
+                    if (!stderr_file_spec)
+                        stderr_file_spec = slave_name;
                 }
-                if (stdin_path == NULL) 
-                    stdin_path = slave_name;
-
-                if (stdout_path == NULL)
-                    stdout_path = slave_name;
-
-                if (stderr_path == NULL)
-                    stderr_path = slave_name;
-
                 if (log)
                     log->Printf ("ProcessGDBRemote::%s adjusted STDIO paths for local platform (IsHost() is true) using slave: stdin=%s, stdout=%s, stderr=%s",
                                  __FUNCTION__,
-                                 stdin_path ? stdin_path : "<null>",
-                                 stdout_path ? stdout_path : "<null>",
-                                 stderr_path ? stderr_path : "<null>");
+                                  stdin_file_spec ?  stdin_file_spec.GetCString() : "<null>",
+                                 stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
+                                 stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
             }
 
             if (log)
                 log->Printf ("ProcessGDBRemote::%s final STDIO paths after all adjustments: stdin=%s, stdout=%s, stderr=%s",
                              __FUNCTION__,
-                             stdin_path ? stdin_path : "<null>",
-                             stdout_path ? stdout_path : "<null>",
-                             stderr_path ? stderr_path : "<null>");
+                              stdin_file_spec ?  stdin_file_spec.GetCString() : "<null>",
+                             stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
+                             stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
 
-            if (stdin_path)
-                m_gdb_comm.SetSTDIN (stdin_path);
-            if (stdout_path)
-                m_gdb_comm.SetSTDOUT (stdout_path);
-            if (stderr_path)
-                m_gdb_comm.SetSTDERR (stderr_path);
+            if (stdin_file_spec)
+                m_gdb_comm.SetSTDIN(stdin_file_spec);
+            if (stdout_file_spec)
+                m_gdb_comm.SetSTDOUT(stdout_file_spec);
+            if (stderr_file_spec)
+                m_gdb_comm.SetSTDERR(stderr_file_spec);
 
             m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR);
             m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError);
@@ -1008,7 +1007,7 @@
             if (launch_event_data != NULL && *launch_event_data != '\0')
                 m_gdb_comm.SendLaunchEventDataPacket (launch_event_data);
             
-            if (working_dir && working_dir[0])
+            if (working_dir)
             {
                 m_gdb_comm.SetWorkingDir (working_dir);
             }