1*061da546Spatrick //===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===// 2*061da546Spatrick // 3*061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5*061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*061da546Spatrick // 7*061da546Spatrick //===----------------------------------------------------------------------===// 8*061da546Spatrick 9*061da546Spatrick #include "lldb/Host/windows/ProcessLauncherWindows.h" 10*061da546Spatrick #include "lldb/Host/HostProcess.h" 11*061da546Spatrick #include "lldb/Host/ProcessLaunchInfo.h" 12*061da546Spatrick 13*061da546Spatrick #include "llvm/ADT/SmallVector.h" 14*061da546Spatrick #include "llvm/Support/ConvertUTF.h" 15*061da546Spatrick #include "llvm/Support/Program.h" 16*061da546Spatrick 17*061da546Spatrick #include <string> 18*061da546Spatrick #include <vector> 19*061da546Spatrick 20*061da546Spatrick using namespace lldb; 21*061da546Spatrick using namespace lldb_private; 22*061da546Spatrick 23*061da546Spatrick namespace { 24*061da546Spatrick void CreateEnvironmentBuffer(const Environment &env, 25*061da546Spatrick std::vector<char> &buffer) { 26*061da546Spatrick if (env.size() == 0) 27*061da546Spatrick return; 28*061da546Spatrick 29*061da546Spatrick // Environment buffer is a null terminated list of null terminated strings 30*061da546Spatrick for (const auto &KV : env) { 31*061da546Spatrick std::wstring warg; 32*061da546Spatrick if (llvm::ConvertUTF8toWide(Environment::compose(KV), warg)) { 33*061da546Spatrick buffer.insert( 34*061da546Spatrick buffer.end(), reinterpret_cast<const char *>(warg.c_str()), 35*061da546Spatrick reinterpret_cast<const char *>(warg.c_str() + warg.size() + 1)); 36*061da546Spatrick } 37*061da546Spatrick } 38*061da546Spatrick // One null wchar_t (to end the block) is two null bytes 39*061da546Spatrick buffer.push_back(0); 40*061da546Spatrick buffer.push_back(0); 41*061da546Spatrick } 42*061da546Spatrick 43*061da546Spatrick bool GetFlattenedWindowsCommandString(Args args, std::string &command) { 44*061da546Spatrick if (args.empty()) 45*061da546Spatrick return false; 46*061da546Spatrick 47*061da546Spatrick std::vector<llvm::StringRef> args_ref; 48*061da546Spatrick for (auto &entry : args.entries()) 49*061da546Spatrick args_ref.push_back(entry.ref()); 50*061da546Spatrick 51*061da546Spatrick command = llvm::sys::flattenWindowsCommandLine(args_ref); 52*061da546Spatrick return true; 53*061da546Spatrick } 54*061da546Spatrick } // namespace 55*061da546Spatrick 56*061da546Spatrick HostProcess 57*061da546Spatrick ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, 58*061da546Spatrick Status &error) { 59*061da546Spatrick error.Clear(); 60*061da546Spatrick 61*061da546Spatrick std::string executable; 62*061da546Spatrick std::string commandLine; 63*061da546Spatrick std::vector<char> environment; 64*061da546Spatrick STARTUPINFO startupinfo = {}; 65*061da546Spatrick PROCESS_INFORMATION pi = {}; 66*061da546Spatrick 67*061da546Spatrick HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO); 68*061da546Spatrick HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO); 69*061da546Spatrick HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO); 70*061da546Spatrick 71*061da546Spatrick startupinfo.cb = sizeof(startupinfo); 72*061da546Spatrick startupinfo.dwFlags |= STARTF_USESTDHANDLES; 73*061da546Spatrick startupinfo.hStdError = 74*061da546Spatrick stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE); 75*061da546Spatrick startupinfo.hStdInput = 76*061da546Spatrick stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE); 77*061da546Spatrick startupinfo.hStdOutput = 78*061da546Spatrick stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE); 79*061da546Spatrick 80*061da546Spatrick const char *hide_console_var = 81*061da546Spatrick getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE"); 82*061da546Spatrick if (hide_console_var && 83*061da546Spatrick llvm::StringRef(hide_console_var).equals_lower("true")) { 84*061da546Spatrick startupinfo.dwFlags |= STARTF_USESHOWWINDOW; 85*061da546Spatrick startupinfo.wShowWindow = SW_HIDE; 86*061da546Spatrick } 87*061da546Spatrick 88*061da546Spatrick DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT; 89*061da546Spatrick if (launch_info.GetFlags().Test(eLaunchFlagDebug)) 90*061da546Spatrick flags |= DEBUG_ONLY_THIS_PROCESS; 91*061da546Spatrick 92*061da546Spatrick if (launch_info.GetFlags().Test(eLaunchFlagDisableSTDIO)) 93*061da546Spatrick flags &= ~CREATE_NEW_CONSOLE; 94*061da546Spatrick 95*061da546Spatrick LPVOID env_block = nullptr; 96*061da546Spatrick ::CreateEnvironmentBuffer(launch_info.GetEnvironment(), environment); 97*061da546Spatrick if (!environment.empty()) 98*061da546Spatrick env_block = environment.data(); 99*061da546Spatrick 100*061da546Spatrick executable = launch_info.GetExecutableFile().GetPath(); 101*061da546Spatrick GetFlattenedWindowsCommandString(launch_info.GetArguments(), commandLine); 102*061da546Spatrick 103*061da546Spatrick std::wstring wexecutable, wcommandLine, wworkingDirectory; 104*061da546Spatrick llvm::ConvertUTF8toWide(executable, wexecutable); 105*061da546Spatrick llvm::ConvertUTF8toWide(commandLine, wcommandLine); 106*061da546Spatrick llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(), 107*061da546Spatrick wworkingDirectory); 108*061da546Spatrick // If the command line is empty, it's best to pass a null pointer to tell 109*061da546Spatrick // CreateProcessW to use the executable name as the command line. If the 110*061da546Spatrick // command line is not empty, its contents may be modified by CreateProcessW. 111*061da546Spatrick WCHAR *pwcommandLine = wcommandLine.empty() ? nullptr : &wcommandLine[0]; 112*061da546Spatrick 113*061da546Spatrick BOOL result = ::CreateProcessW( 114*061da546Spatrick wexecutable.c_str(), pwcommandLine, NULL, NULL, TRUE, flags, env_block, 115*061da546Spatrick wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(), 116*061da546Spatrick &startupinfo, &pi); 117*061da546Spatrick 118*061da546Spatrick if (!result) { 119*061da546Spatrick // Call GetLastError before we make any other system calls. 120*061da546Spatrick error.SetError(::GetLastError(), eErrorTypeWin32); 121*061da546Spatrick // Note that error 50 ("The request is not supported") will occur if you 122*061da546Spatrick // try debug a 64-bit inferior from a 32-bit LLDB. 123*061da546Spatrick } 124*061da546Spatrick 125*061da546Spatrick if (result) { 126*061da546Spatrick // Do not call CloseHandle on pi.hProcess, since we want to pass that back 127*061da546Spatrick // through the HostProcess. 128*061da546Spatrick ::CloseHandle(pi.hThread); 129*061da546Spatrick } 130*061da546Spatrick 131*061da546Spatrick if (stdin_handle) 132*061da546Spatrick ::CloseHandle(stdin_handle); 133*061da546Spatrick if (stdout_handle) 134*061da546Spatrick ::CloseHandle(stdout_handle); 135*061da546Spatrick if (stderr_handle) 136*061da546Spatrick ::CloseHandle(stderr_handle); 137*061da546Spatrick 138*061da546Spatrick if (!result) 139*061da546Spatrick return HostProcess(); 140*061da546Spatrick 141*061da546Spatrick return HostProcess(pi.hProcess); 142*061da546Spatrick } 143*061da546Spatrick 144*061da546Spatrick HANDLE 145*061da546Spatrick ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, 146*061da546Spatrick int fd) { 147*061da546Spatrick const FileAction *action = launch_info.GetFileActionForFD(fd); 148*061da546Spatrick if (action == nullptr) 149*061da546Spatrick return NULL; 150*061da546Spatrick SECURITY_ATTRIBUTES secattr = {}; 151*061da546Spatrick secattr.nLength = sizeof(SECURITY_ATTRIBUTES); 152*061da546Spatrick secattr.bInheritHandle = TRUE; 153*061da546Spatrick 154*061da546Spatrick llvm::StringRef path = action->GetPath(); 155*061da546Spatrick DWORD access = 0; 156*061da546Spatrick DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; 157*061da546Spatrick DWORD create = 0; 158*061da546Spatrick DWORD flags = 0; 159*061da546Spatrick if (fd == STDIN_FILENO) { 160*061da546Spatrick access = GENERIC_READ; 161*061da546Spatrick create = OPEN_EXISTING; 162*061da546Spatrick flags = FILE_ATTRIBUTE_READONLY; 163*061da546Spatrick } 164*061da546Spatrick if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { 165*061da546Spatrick access = GENERIC_WRITE; 166*061da546Spatrick create = CREATE_ALWAYS; 167*061da546Spatrick if (fd == STDERR_FILENO) 168*061da546Spatrick flags = FILE_FLAG_WRITE_THROUGH; 169*061da546Spatrick } 170*061da546Spatrick 171*061da546Spatrick std::wstring wpath; 172*061da546Spatrick llvm::ConvertUTF8toWide(path, wpath); 173*061da546Spatrick HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create, 174*061da546Spatrick flags, NULL); 175*061da546Spatrick return (result == INVALID_HANDLE_VALUE) ? NULL : result; 176*061da546Spatrick } 177