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