1172d37d3SZachary Turner //===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===// 2172d37d3SZachary Turner // 3172d37d3SZachary Turner // The LLVM Compiler Infrastructure 4172d37d3SZachary Turner // 5172d37d3SZachary Turner // This file is distributed under the University of Illinois Open Source 6172d37d3SZachary Turner // License. See LICENSE.TXT for details. 7172d37d3SZachary Turner // 8172d37d3SZachary Turner //===----------------------------------------------------------------------===// 9172d37d3SZachary Turner 10172d37d3SZachary Turner #include "lldb/Host/HostProcess.h" 11172d37d3SZachary Turner #include "lldb/Host/windows/ProcessLauncherWindows.h" 12172d37d3SZachary Turner #include "lldb/Target/ProcessLaunchInfo.h" 13172d37d3SZachary Turner 14*190fadcdSZachary Turner #include "llvm/ADT/SmallVector.h" 15*190fadcdSZachary Turner #include "llvm/Support/ConvertUTF.h" 16*190fadcdSZachary Turner 17172d37d3SZachary Turner #include <string> 18172d37d3SZachary Turner #include <vector> 19172d37d3SZachary Turner 20172d37d3SZachary Turner using namespace lldb; 21172d37d3SZachary Turner using namespace lldb_private; 22172d37d3SZachary Turner 2319e2ea8fSZachary Turner namespace 2419e2ea8fSZachary Turner { 2519e2ea8fSZachary Turner void 2619e2ea8fSZachary Turner CreateEnvironmentBuffer(const Args &env, std::vector<char> &buffer) 2719e2ea8fSZachary Turner { 2819e2ea8fSZachary Turner if (env.GetArgumentCount() == 0) 2919e2ea8fSZachary Turner return; 3019e2ea8fSZachary Turner 31*190fadcdSZachary Turner // Environment buffer is a null terminated list of null terminated strings 3219e2ea8fSZachary Turner for (int i = 0; i < env.GetArgumentCount(); ++i) 3319e2ea8fSZachary Turner { 34*190fadcdSZachary Turner std::wstring warg; 35*190fadcdSZachary Turner if (llvm::ConvertUTF8toWide(env.GetArgumentAtIndex(i), warg)) 36*190fadcdSZachary Turner { 37*190fadcdSZachary Turner buffer.insert(buffer.end(), (char *)warg.c_str(), (char *)(warg.c_str() + warg.size() + 1)); 3819e2ea8fSZachary Turner } 39*190fadcdSZachary Turner } 40*190fadcdSZachary Turner // One null wchar_t (to end the block) is two null bytes 41*190fadcdSZachary Turner buffer.push_back(0); 42*190fadcdSZachary Turner buffer.push_back(0); 4319e2ea8fSZachary Turner } 4419e2ea8fSZachary Turner } 4519e2ea8fSZachary Turner 46172d37d3SZachary Turner HostProcess 47172d37d3SZachary Turner ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) 48172d37d3SZachary Turner { 49172d37d3SZachary Turner error.Clear(); 50172d37d3SZachary Turner 51172d37d3SZachary Turner std::string executable; 52172d37d3SZachary Turner std::string commandLine; 53172d37d3SZachary Turner std::vector<char> environment; 54172d37d3SZachary Turner STARTUPINFO startupinfo = {0}; 55172d37d3SZachary Turner PROCESS_INFORMATION pi = {0}; 56172d37d3SZachary Turner 57172d37d3SZachary Turner HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO); 58172d37d3SZachary Turner HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO); 59172d37d3SZachary Turner HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO); 60172d37d3SZachary Turner 61172d37d3SZachary Turner startupinfo.cb = sizeof(startupinfo); 62172d37d3SZachary Turner startupinfo.dwFlags |= STARTF_USESTDHANDLES; 63e1adc7bcSAdrian McCarthy startupinfo.hStdError = stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE); 64e1adc7bcSAdrian McCarthy startupinfo.hStdInput = stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE); 65e1adc7bcSAdrian McCarthy startupinfo.hStdOutput = stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE); 66172d37d3SZachary Turner 67555a7a6aSZachary Turner const char *hide_console_var = getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE"); 68555a7a6aSZachary Turner if (hide_console_var && llvm::StringRef(hide_console_var).equals_lower("true")) 69555a7a6aSZachary Turner { 70555a7a6aSZachary Turner startupinfo.dwFlags |= STARTF_USESHOWWINDOW; 71555a7a6aSZachary Turner startupinfo.wShowWindow = SW_HIDE; 72555a7a6aSZachary Turner } 73555a7a6aSZachary Turner 74*190fadcdSZachary Turner DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT; 75742346a2SZachary Turner if (launch_info.GetFlags().Test(eLaunchFlagDebug)) 76742346a2SZachary Turner flags |= DEBUG_ONLY_THIS_PROCESS; 77742346a2SZachary Turner 7819e2ea8fSZachary Turner auto &env = const_cast<Args &>(launch_info.GetEnvironmentEntries()); 7919e2ea8fSZachary Turner LPVOID env_block = nullptr; 8019e2ea8fSZachary Turner ::CreateEnvironmentBuffer(env, environment); 8119e2ea8fSZachary Turner if (!environment.empty()) 8219e2ea8fSZachary Turner env_block = environment.data(); 8319e2ea8fSZachary Turner 84172d37d3SZachary Turner executable = launch_info.GetExecutableFile().GetPath(); 85172d37d3SZachary Turner launch_info.GetArguments().GetQuotedCommandString(commandLine); 86*190fadcdSZachary Turner 87*190fadcdSZachary Turner std::wstring wexecutable, wcommandLine, wworkingDirectory; 88*190fadcdSZachary Turner llvm::ConvertUTF8toWide(executable, wexecutable); 89*190fadcdSZachary Turner llvm::ConvertUTF8toWide(commandLine, wcommandLine); 90*190fadcdSZachary Turner llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(), wworkingDirectory); 91*190fadcdSZachary Turner 92*190fadcdSZachary Turner wcommandLine.resize(PATH_MAX); // Needs to be over-allocated because CreateProcessW can modify it 93*190fadcdSZachary Turner BOOL result = ::CreateProcessW(wexecutable.c_str(), &wcommandLine[0], NULL, NULL, TRUE, flags, env_block, 94*190fadcdSZachary Turner wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(), &startupinfo, &pi); 95172d37d3SZachary Turner if (result) 96172d37d3SZachary Turner { 97172d37d3SZachary Turner // Do not call CloseHandle on pi.hProcess, since we want to pass that back through the HostProcess. 98172d37d3SZachary Turner ::CloseHandle(pi.hThread); 99172d37d3SZachary Turner } 100172d37d3SZachary Turner 101172d37d3SZachary Turner if (stdin_handle) 102172d37d3SZachary Turner ::CloseHandle(stdin_handle); 103172d37d3SZachary Turner if (stdout_handle) 104172d37d3SZachary Turner ::CloseHandle(stdout_handle); 105172d37d3SZachary Turner if (stderr_handle) 106172d37d3SZachary Turner ::CloseHandle(stderr_handle); 107172d37d3SZachary Turner 108172d37d3SZachary Turner if (!result) 109172d37d3SZachary Turner error.SetError(::GetLastError(), eErrorTypeWin32); 110172d37d3SZachary Turner return HostProcess(pi.hProcess); 111172d37d3SZachary Turner } 112172d37d3SZachary Turner 113172d37d3SZachary Turner HANDLE 114172d37d3SZachary Turner ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd) 115172d37d3SZachary Turner { 116172d37d3SZachary Turner const FileAction *action = launch_info.GetFileActionForFD(fd); 117172d37d3SZachary Turner if (action == nullptr) 118172d37d3SZachary Turner return NULL; 119172d37d3SZachary Turner SECURITY_ATTRIBUTES secattr = {0}; 120172d37d3SZachary Turner secattr.nLength = sizeof(SECURITY_ATTRIBUTES); 121172d37d3SZachary Turner secattr.bInheritHandle = TRUE; 122172d37d3SZachary Turner 123172d37d3SZachary Turner const char *path = action->GetPath(); 124172d37d3SZachary Turner DWORD access = 0; 125022c3c85SZachary Turner DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; 126172d37d3SZachary Turner DWORD create = 0; 127172d37d3SZachary Turner DWORD flags = 0; 128172d37d3SZachary Turner if (fd == STDIN_FILENO) 129172d37d3SZachary Turner { 130172d37d3SZachary Turner access = GENERIC_READ; 131172d37d3SZachary Turner create = OPEN_EXISTING; 132172d37d3SZachary Turner flags = FILE_ATTRIBUTE_READONLY; 133172d37d3SZachary Turner } 134172d37d3SZachary Turner if (fd == STDOUT_FILENO || fd == STDERR_FILENO) 135172d37d3SZachary Turner { 136172d37d3SZachary Turner access = GENERIC_WRITE; 137172d37d3SZachary Turner create = CREATE_ALWAYS; 138172d37d3SZachary Turner if (fd == STDERR_FILENO) 139172d37d3SZachary Turner flags = FILE_FLAG_WRITE_THROUGH; 140172d37d3SZachary Turner } 141172d37d3SZachary Turner 142*190fadcdSZachary Turner std::wstring wpath; 143*190fadcdSZachary Turner llvm::ConvertUTF8toWide(path, wpath); 144*190fadcdSZachary Turner HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create, flags, NULL); 145172d37d3SZachary Turner return (result == INVALID_HANDLE_VALUE) ? NULL : result; 146172d37d3SZachary Turner } 147