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/windows/ProcessLauncherWindows.h" 11 #include "lldb/Host/HostProcess.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 void CreateEnvironmentBuffer(const Environment &env, 25 std::vector<char> &buffer) { 26 if (env.size() == 0) 27 return; 28 29 // Environment buffer is a null terminated list of null terminated strings 30 for (const auto &KV : env) { 31 std::wstring warg; 32 if (llvm::ConvertUTF8toWide(Environment::compose(KV), warg)) { 33 buffer.insert(buffer.end(), (char *)warg.c_str(), 34 (char *)(warg.c_str() + warg.size() + 1)); 35 } 36 } 37 // One null wchar_t (to end the block) is two null bytes 38 buffer.push_back(0); 39 buffer.push_back(0); 40 } 41 } 42 43 HostProcess 44 ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, 45 Status &error) { 46 error.Clear(); 47 48 std::string executable; 49 std::string commandLine; 50 std::vector<char> environment; 51 STARTUPINFO startupinfo = {}; 52 PROCESS_INFORMATION pi = {}; 53 54 HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO); 55 HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO); 56 HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO); 57 58 startupinfo.cb = sizeof(startupinfo); 59 startupinfo.dwFlags |= STARTF_USESTDHANDLES; 60 startupinfo.hStdError = 61 stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE); 62 startupinfo.hStdInput = 63 stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE); 64 startupinfo.hStdOutput = 65 stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE); 66 67 const char *hide_console_var = 68 getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE"); 69 if (hide_console_var && 70 llvm::StringRef(hide_console_var).equals_lower("true")) { 71 startupinfo.dwFlags |= STARTF_USESHOWWINDOW; 72 startupinfo.wShowWindow = SW_HIDE; 73 } 74 75 DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT; 76 if (launch_info.GetFlags().Test(eLaunchFlagDebug)) 77 flags |= DEBUG_ONLY_THIS_PROCESS; 78 79 if (launch_info.GetFlags().Test(eLaunchFlagDisableSTDIO)) 80 flags &= ~CREATE_NEW_CONSOLE; 81 82 LPVOID env_block = nullptr; 83 ::CreateEnvironmentBuffer(launch_info.GetEnvironment(), environment); 84 if (!environment.empty()) 85 env_block = environment.data(); 86 87 executable = launch_info.GetExecutableFile().GetPath(); 88 launch_info.GetArguments().GetQuotedCommandString(commandLine); 89 90 std::wstring wexecutable, wcommandLine, wworkingDirectory; 91 llvm::ConvertUTF8toWide(executable, wexecutable); 92 llvm::ConvertUTF8toWide(commandLine, wcommandLine); 93 llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(), 94 wworkingDirectory); 95 96 wcommandLine.resize(PATH_MAX); // Needs to be over-allocated because 97 // CreateProcessW can modify it 98 BOOL result = ::CreateProcessW( 99 wexecutable.c_str(), &wcommandLine[0], NULL, NULL, TRUE, flags, env_block, 100 wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(), 101 &startupinfo, &pi); 102 103 if (!result) { 104 // Call GetLastError before we make any other system calls. 105 error.SetError(::GetLastError(), eErrorTypeWin32); 106 } 107 108 if (result) { 109 // Do not call CloseHandle on pi.hProcess, since we want to pass that back 110 // through the HostProcess. 111 ::CloseHandle(pi.hThread); 112 } 113 114 if (stdin_handle) 115 ::CloseHandle(stdin_handle); 116 if (stdout_handle) 117 ::CloseHandle(stdout_handle); 118 if (stderr_handle) 119 ::CloseHandle(stderr_handle); 120 121 if (!result) 122 return HostProcess(); 123 124 return HostProcess(pi.hProcess); 125 } 126 127 HANDLE 128 ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, 129 int fd) { 130 const FileAction *action = launch_info.GetFileActionForFD(fd); 131 if (action == nullptr) 132 return NULL; 133 SECURITY_ATTRIBUTES secattr = {}; 134 secattr.nLength = sizeof(SECURITY_ATTRIBUTES); 135 secattr.bInheritHandle = TRUE; 136 137 llvm::StringRef path = action->GetPath(); 138 DWORD access = 0; 139 DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; 140 DWORD create = 0; 141 DWORD flags = 0; 142 if (fd == STDIN_FILENO) { 143 access = GENERIC_READ; 144 create = OPEN_EXISTING; 145 flags = FILE_ATTRIBUTE_READONLY; 146 } 147 if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { 148 access = GENERIC_WRITE; 149 create = CREATE_ALWAYS; 150 if (fd == STDERR_FILENO) 151 flags = FILE_FLAG_WRITE_THROUGH; 152 } 153 154 std::wstring wpath; 155 llvm::ConvertUTF8toWide(path, wpath); 156 HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create, 157 flags, NULL); 158 return (result == INVALID_HANDLE_VALUE) ? NULL : result; 159 } 160