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/HostProcess.h" 11 #include "lldb/Host/windows/ProcessLauncherWindows.h" 12 #include "lldb/Target/ProcessLaunchInfo.h" 13 14 #include <string> 15 #include <vector> 16 17 using namespace lldb; 18 using namespace lldb_private; 19 20 namespace 21 { 22 void 23 CreateEnvironmentBuffer(const Args &env, std::vector<char> &buffer) 24 { 25 if (env.GetArgumentCount() == 0) 26 return; 27 28 int bytes = 0; 29 for (int i = 0; i < env.GetArgumentCount(); ++i) 30 bytes += strlen(env.GetArgumentAtIndex(i)) + sizeof(char); 31 bytes += sizeof(char); 32 buffer.resize(bytes); 33 char *cur_entry = &buffer[0]; 34 for (int i = 0; i < env.GetArgumentCount(); ++i) 35 { 36 ::strcpy(cur_entry, env.GetArgumentAtIndex(i)); 37 cur_entry += strlen(cur_entry) + sizeof(char); 38 } 39 // Environment buffer is a null terminated list of null terminated 40 // strings, so it is terminated by two null bytes. 41 buffer.back() = 0; 42 } 43 } 44 45 HostProcess 46 ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) 47 { 48 error.Clear(); 49 50 std::string executable; 51 std::string commandLine; 52 std::vector<char> environment; 53 STARTUPINFO startupinfo = {0}; 54 PROCESS_INFORMATION pi = {0}; 55 56 HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO); 57 HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO); 58 HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO); 59 60 startupinfo.cb = sizeof(startupinfo); 61 startupinfo.dwFlags |= STARTF_USESTDHANDLES; 62 startupinfo.hStdError = stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE); 63 startupinfo.hStdInput = stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE); 64 startupinfo.hStdOutput = stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE); 65 66 const char *hide_console_var = getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE"); 67 if (hide_console_var && llvm::StringRef(hide_console_var).equals_lower("true")) 68 { 69 startupinfo.dwFlags |= STARTF_USESHOWWINDOW; 70 startupinfo.wShowWindow = SW_HIDE; 71 } 72 73 DWORD flags = CREATE_NEW_CONSOLE; 74 if (launch_info.GetFlags().Test(eLaunchFlagDebug)) 75 flags |= DEBUG_ONLY_THIS_PROCESS; 76 77 auto &env = const_cast<Args &>(launch_info.GetEnvironmentEntries()); 78 LPVOID env_block = nullptr; 79 ::CreateEnvironmentBuffer(env, environment); 80 if (!environment.empty()) 81 env_block = environment.data(); 82 83 executable = launch_info.GetExecutableFile().GetPath(); 84 launch_info.GetArguments().GetQuotedCommandString(commandLine); 85 BOOL result = ::CreateProcessA(executable.c_str(), const_cast<char *>(commandLine.c_str()), NULL, NULL, TRUE, flags, 86 env_block, launch_info.GetWorkingDirectory().GetCString(), &startupinfo, &pi); 87 if (result) 88 { 89 // Do not call CloseHandle on pi.hProcess, since we want to pass that back through the HostProcess. 90 ::CloseHandle(pi.hThread); 91 } 92 93 if (stdin_handle) 94 ::CloseHandle(stdin_handle); 95 if (stdout_handle) 96 ::CloseHandle(stdout_handle); 97 if (stderr_handle) 98 ::CloseHandle(stderr_handle); 99 100 if (!result) 101 error.SetError(::GetLastError(), eErrorTypeWin32); 102 return HostProcess(pi.hProcess); 103 } 104 105 HANDLE 106 ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd) 107 { 108 const FileAction *action = launch_info.GetFileActionForFD(fd); 109 if (action == nullptr) 110 return NULL; 111 SECURITY_ATTRIBUTES secattr = {0}; 112 secattr.nLength = sizeof(SECURITY_ATTRIBUTES); 113 secattr.bInheritHandle = TRUE; 114 115 const char *path = action->GetPath(); 116 DWORD access = 0; 117 DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; 118 DWORD create = 0; 119 DWORD flags = 0; 120 if (fd == STDIN_FILENO) 121 { 122 access = GENERIC_READ; 123 create = OPEN_EXISTING; 124 flags = FILE_ATTRIBUTE_READONLY; 125 } 126 if (fd == STDOUT_FILENO || fd == STDERR_FILENO) 127 { 128 access = GENERIC_WRITE; 129 create = CREATE_ALWAYS; 130 if (fd == STDERR_FILENO) 131 flags = FILE_FLAG_WRITE_THROUGH; 132 } 133 134 HANDLE result = ::CreateFile(path, access, share, &secattr, create, flags, NULL); 135 return (result == INVALID_HANDLE_VALUE) ? NULL : result; 136 } 137