1dda28197Spatrick //===-- ProcessLauncherWindows.cpp ----------------------------------------===// 2061da546Spatrick // 3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6061da546Spatrick // 7061da546Spatrick //===----------------------------------------------------------------------===// 8061da546Spatrick 9061da546Spatrick #include "lldb/Host/windows/ProcessLauncherWindows.h" 10061da546Spatrick #include "lldb/Host/HostProcess.h" 11061da546Spatrick #include "lldb/Host/ProcessLaunchInfo.h" 12061da546Spatrick 13061da546Spatrick #include "llvm/ADT/SmallVector.h" 14061da546Spatrick #include "llvm/Support/ConvertUTF.h" 15061da546Spatrick #include "llvm/Support/Program.h" 16061da546Spatrick 17061da546Spatrick #include <string> 18061da546Spatrick #include <vector> 19061da546Spatrick 20061da546Spatrick using namespace lldb; 21061da546Spatrick using namespace lldb_private; 22061da546Spatrick 23061da546Spatrick namespace { 24061da546Spatrick void CreateEnvironmentBuffer(const Environment &env, 25061da546Spatrick std::vector<char> &buffer) { 26dda28197Spatrick // The buffer is a list of null-terminated UTF-16 strings, followed by an 27dda28197Spatrick // extra L'\0' (two bytes of 0). An empty environment must have one 28dda28197Spatrick // empty string, followed by an extra L'\0'. 29061da546Spatrick for (const auto &KV : env) { 30061da546Spatrick std::wstring warg; 31061da546Spatrick if (llvm::ConvertUTF8toWide(Environment::compose(KV), warg)) { 32061da546Spatrick buffer.insert( 33061da546Spatrick buffer.end(), reinterpret_cast<const char *>(warg.c_str()), 34061da546Spatrick reinterpret_cast<const char *>(warg.c_str() + warg.size() + 1)); 35061da546Spatrick } 36061da546Spatrick } 37061da546Spatrick // One null wchar_t (to end the block) is two null bytes 38061da546Spatrick buffer.push_back(0); 39061da546Spatrick buffer.push_back(0); 40dda28197Spatrick // Insert extra two bytes, just in case the environment was empty. 41dda28197Spatrick buffer.push_back(0); 42dda28197Spatrick buffer.push_back(0); 43061da546Spatrick } 44061da546Spatrick 45*be691f3bSpatrick bool GetFlattenedWindowsCommandString(Args args, std::wstring &command) { 46061da546Spatrick if (args.empty()) 47061da546Spatrick return false; 48061da546Spatrick 49061da546Spatrick std::vector<llvm::StringRef> args_ref; 50061da546Spatrick for (auto &entry : args.entries()) 51061da546Spatrick args_ref.push_back(entry.ref()); 52061da546Spatrick 53*be691f3bSpatrick llvm::ErrorOr<std::wstring> result = 54*be691f3bSpatrick llvm::sys::flattenWindowsCommandLine(args_ref); 55*be691f3bSpatrick if (result.getError()) 56*be691f3bSpatrick return false; 57*be691f3bSpatrick 58*be691f3bSpatrick command = *result; 59061da546Spatrick return true; 60061da546Spatrick } 61061da546Spatrick } // namespace 62061da546Spatrick 63061da546Spatrick HostProcess 64061da546Spatrick ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, 65061da546Spatrick Status &error) { 66061da546Spatrick error.Clear(); 67061da546Spatrick 68061da546Spatrick std::string executable; 69061da546Spatrick std::vector<char> environment; 70061da546Spatrick STARTUPINFO startupinfo = {}; 71061da546Spatrick PROCESS_INFORMATION pi = {}; 72061da546Spatrick 73061da546Spatrick HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO); 74061da546Spatrick HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO); 75061da546Spatrick HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO); 76061da546Spatrick 77061da546Spatrick startupinfo.cb = sizeof(startupinfo); 78061da546Spatrick startupinfo.dwFlags |= STARTF_USESTDHANDLES; 79061da546Spatrick startupinfo.hStdError = 80061da546Spatrick stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE); 81061da546Spatrick startupinfo.hStdInput = 82061da546Spatrick stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE); 83061da546Spatrick startupinfo.hStdOutput = 84061da546Spatrick stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE); 85061da546Spatrick 86061da546Spatrick const char *hide_console_var = 87061da546Spatrick getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE"); 88061da546Spatrick if (hide_console_var && 89*be691f3bSpatrick llvm::StringRef(hide_console_var).equals_insensitive("true")) { 90061da546Spatrick startupinfo.dwFlags |= STARTF_USESHOWWINDOW; 91061da546Spatrick startupinfo.wShowWindow = SW_HIDE; 92061da546Spatrick } 93061da546Spatrick 94061da546Spatrick DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT; 95061da546Spatrick if (launch_info.GetFlags().Test(eLaunchFlagDebug)) 96061da546Spatrick flags |= DEBUG_ONLY_THIS_PROCESS; 97061da546Spatrick 98061da546Spatrick if (launch_info.GetFlags().Test(eLaunchFlagDisableSTDIO)) 99061da546Spatrick flags &= ~CREATE_NEW_CONSOLE; 100061da546Spatrick 101061da546Spatrick LPVOID env_block = nullptr; 102061da546Spatrick ::CreateEnvironmentBuffer(launch_info.GetEnvironment(), environment); 103061da546Spatrick env_block = environment.data(); 104061da546Spatrick 105061da546Spatrick executable = launch_info.GetExecutableFile().GetPath(); 106*be691f3bSpatrick std::wstring wcommandLine; 107*be691f3bSpatrick GetFlattenedWindowsCommandString(launch_info.GetArguments(), wcommandLine); 108061da546Spatrick 109*be691f3bSpatrick std::wstring wexecutable, wworkingDirectory; 110061da546Spatrick llvm::ConvertUTF8toWide(executable, wexecutable); 111061da546Spatrick llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(), 112061da546Spatrick wworkingDirectory); 113061da546Spatrick // If the command line is empty, it's best to pass a null pointer to tell 114061da546Spatrick // CreateProcessW to use the executable name as the command line. If the 115061da546Spatrick // command line is not empty, its contents may be modified by CreateProcessW. 116061da546Spatrick WCHAR *pwcommandLine = wcommandLine.empty() ? nullptr : &wcommandLine[0]; 117061da546Spatrick 118061da546Spatrick BOOL result = ::CreateProcessW( 119061da546Spatrick wexecutable.c_str(), pwcommandLine, NULL, NULL, TRUE, flags, env_block, 120061da546Spatrick wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(), 121061da546Spatrick &startupinfo, &pi); 122061da546Spatrick 123061da546Spatrick if (!result) { 124061da546Spatrick // Call GetLastError before we make any other system calls. 125061da546Spatrick error.SetError(::GetLastError(), eErrorTypeWin32); 126061da546Spatrick // Note that error 50 ("The request is not supported") will occur if you 127061da546Spatrick // try debug a 64-bit inferior from a 32-bit LLDB. 128061da546Spatrick } 129061da546Spatrick 130061da546Spatrick if (result) { 131061da546Spatrick // Do not call CloseHandle on pi.hProcess, since we want to pass that back 132061da546Spatrick // through the HostProcess. 133061da546Spatrick ::CloseHandle(pi.hThread); 134061da546Spatrick } 135061da546Spatrick 136061da546Spatrick if (stdin_handle) 137061da546Spatrick ::CloseHandle(stdin_handle); 138061da546Spatrick if (stdout_handle) 139061da546Spatrick ::CloseHandle(stdout_handle); 140061da546Spatrick if (stderr_handle) 141061da546Spatrick ::CloseHandle(stderr_handle); 142061da546Spatrick 143061da546Spatrick if (!result) 144061da546Spatrick return HostProcess(); 145061da546Spatrick 146061da546Spatrick return HostProcess(pi.hProcess); 147061da546Spatrick } 148061da546Spatrick 149061da546Spatrick HANDLE 150061da546Spatrick ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, 151061da546Spatrick int fd) { 152061da546Spatrick const FileAction *action = launch_info.GetFileActionForFD(fd); 153061da546Spatrick if (action == nullptr) 154061da546Spatrick return NULL; 155061da546Spatrick SECURITY_ATTRIBUTES secattr = {}; 156061da546Spatrick secattr.nLength = sizeof(SECURITY_ATTRIBUTES); 157061da546Spatrick secattr.bInheritHandle = TRUE; 158061da546Spatrick 159061da546Spatrick llvm::StringRef path = action->GetPath(); 160061da546Spatrick DWORD access = 0; 161061da546Spatrick DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; 162061da546Spatrick DWORD create = 0; 163061da546Spatrick DWORD flags = 0; 164061da546Spatrick if (fd == STDIN_FILENO) { 165061da546Spatrick access = GENERIC_READ; 166061da546Spatrick create = OPEN_EXISTING; 167061da546Spatrick flags = FILE_ATTRIBUTE_READONLY; 168061da546Spatrick } 169061da546Spatrick if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { 170061da546Spatrick access = GENERIC_WRITE; 171061da546Spatrick create = CREATE_ALWAYS; 172061da546Spatrick if (fd == STDERR_FILENO) 173061da546Spatrick flags = FILE_FLAG_WRITE_THROUGH; 174061da546Spatrick } 175061da546Spatrick 176061da546Spatrick std::wstring wpath; 177061da546Spatrick llvm::ConvertUTF8toWide(path, wpath); 178061da546Spatrick HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create, 179061da546Spatrick flags, NULL); 180061da546Spatrick return (result == INVALID_HANDLE_VALUE) ? NULL : result; 181061da546Spatrick } 182