1 //===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Host/HostProcess.h" 11 #include "lldb/Host/windows/ProcessLauncherWindows.h" 12 #include "lldb/Target/ProcessLaunchInfo.h" 13 14 #include "llvm/ADT/SmallVector.h" 15 #include "llvm/Support/ConvertUTF.h" 16 17 #include <string> 18 #include <vector> 19 20 using namespace lldb; 21 using namespace lldb_private; 22 23 namespace 24 { 25 void 26 CreateEnvironmentBuffer(const Args &env, std::vector<char> &buffer) 27 { 28 if (env.GetArgumentCount() == 0) 29 return; 30 31 // Environment buffer is a null terminated list of null terminated strings 32 for (int i = 0; i < env.GetArgumentCount(); ++i) 33 { 34 std::wstring warg; 35 if (llvm::ConvertUTF8toWide(env.GetArgumentAtIndex(i), warg)) 36 { 37 buffer.insert(buffer.end(), (char *)warg.c_str(), (char *)(warg.c_str() + warg.size() + 1)); 38 } 39 } 40 // One null wchar_t (to end the block) is two null bytes 41 buffer.push_back(0); 42 buffer.push_back(0); 43 } 44 } 45 46 HostProcess 47 ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) 48 { 49 error.Clear(); 50 51 std::string executable; 52 std::string commandLine; 53 std::vector<char> environment; 54 STARTUPINFO startupinfo = {0}; 55 PROCESS_INFORMATION pi = {0}; 56 57 HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO); 58 HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO); 59 HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO); 60 61 startupinfo.cb = sizeof(startupinfo); 62 startupinfo.dwFlags |= STARTF_USESTDHANDLES; 63 startupinfo.hStdError = stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE); 64 startupinfo.hStdInput = stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE); 65 startupinfo.hStdOutput = stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE); 66 67 const char *hide_console_var = getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE"); 68 if (hide_console_var && llvm::StringRef(hide_console_var).equals_lower("true")) 69 { 70 startupinfo.dwFlags |= STARTF_USESHOWWINDOW; 71 startupinfo.wShowWindow = SW_HIDE; 72 } 73 74 DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT; 75 if (launch_info.GetFlags().Test(eLaunchFlagDebug)) 76 flags |= DEBUG_ONLY_THIS_PROCESS; 77 78 auto &env = const_cast<Args &>(launch_info.GetEnvironmentEntries()); 79 LPVOID env_block = nullptr; 80 ::CreateEnvironmentBuffer(env, environment); 81 if (!environment.empty()) 82 env_block = environment.data(); 83 84 executable = launch_info.GetExecutableFile().GetPath(); 85 launch_info.GetArguments().GetQuotedCommandString(commandLine); 86 87 std::wstring wexecutable, wcommandLine, wworkingDirectory; 88 llvm::ConvertUTF8toWide(executable, wexecutable); 89 llvm::ConvertUTF8toWide(commandLine, wcommandLine); 90 llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(), wworkingDirectory); 91 92 wcommandLine.resize(PATH_MAX); // Needs to be over-allocated because CreateProcessW can modify it 93 BOOL result = ::CreateProcessW(wexecutable.c_str(), &wcommandLine[0], NULL, NULL, TRUE, flags, env_block, 94 wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(), &startupinfo, &pi); 95 if (result) 96 { 97 // Do not call CloseHandle on pi.hProcess, since we want to pass that back through the HostProcess. 98 ::CloseHandle(pi.hThread); 99 } 100 101 if (stdin_handle) 102 ::CloseHandle(stdin_handle); 103 if (stdout_handle) 104 ::CloseHandle(stdout_handle); 105 if (stderr_handle) 106 ::CloseHandle(stderr_handle); 107 108 if (!result) 109 error.SetError(::GetLastError(), eErrorTypeWin32); 110 return HostProcess(pi.hProcess); 111 } 112 113 HANDLE 114 ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd) 115 { 116 const FileAction *action = launch_info.GetFileActionForFD(fd); 117 if (action == nullptr) 118 return NULL; 119 SECURITY_ATTRIBUTES secattr = {0}; 120 secattr.nLength = sizeof(SECURITY_ATTRIBUTES); 121 secattr.bInheritHandle = TRUE; 122 123 const char *path = action->GetPath(); 124 DWORD access = 0; 125 DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; 126 DWORD create = 0; 127 DWORD flags = 0; 128 if (fd == STDIN_FILENO) 129 { 130 access = GENERIC_READ; 131 create = OPEN_EXISTING; 132 flags = FILE_ATTRIBUTE_READONLY; 133 } 134 if (fd == STDOUT_FILENO || fd == STDERR_FILENO) 135 { 136 access = GENERIC_WRITE; 137 create = CREATE_ALWAYS; 138 if (fd == STDERR_FILENO) 139 flags = FILE_FLAG_WRITE_THROUGH; 140 } 141 142 std::wstring wpath; 143 llvm::ConvertUTF8toWide(path, wpath); 144 HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create, flags, NULL); 145 return (result == INVALID_HANDLE_VALUE) ? NULL : result; 146 } 147