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