LLDB  mainline
ProcessLauncherWindows.cpp
Go to the documentation of this file.
1 //===-- ProcessLauncherWindows.cpp ----------------------------------------===//
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 
10 #include "lldb/Host/HostProcess.h"
12 
13 #include "llvm/ADT/SmallVector.h"
14 #include "llvm/Support/ConvertUTF.h"
15 #include "llvm/Support/Program.h"
16 
17 #include <string>
18 #include <vector>
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 
23 namespace {
24 void CreateEnvironmentBuffer(const Environment &env,
25  std::vector<char> &buffer) {
26  // The buffer is a list of null-terminated UTF-16 strings, followed by an
27  // extra L'\0' (two bytes of 0). An empty environment must have one
28  // empty string, followed by an extra L'\0'.
29  for (const auto &KV : env) {
30  std::wstring warg;
31  if (llvm::ConvertUTF8toWide(Environment::compose(KV), warg)) {
32  buffer.insert(
33  buffer.end(), reinterpret_cast<const char *>(warg.c_str()),
34  reinterpret_cast<const char *>(warg.c_str() + warg.size() + 1));
35  }
36  }
37  // One null wchar_t (to end the block) is two null bytes
38  buffer.push_back(0);
39  buffer.push_back(0);
40  // Insert extra two bytes, just in case the environment was empty.
41  buffer.push_back(0);
42  buffer.push_back(0);
43 }
44 
45 bool GetFlattenedWindowsCommandString(Args args, std::wstring &command) {
46  if (args.empty())
47  return false;
48 
49  std::vector<llvm::StringRef> args_ref;
50  for (auto &entry : args.entries())
51  args_ref.push_back(entry.ref());
52 
53  llvm::ErrorOr<std::wstring> result =
54  llvm::sys::flattenWindowsCommandLine(args_ref);
55  if (result.getError())
56  return false;
57 
58  command = *result;
59  return true;
60 }
61 } // namespace
62 
64 ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
65  Status &error) {
66  error.Clear();
67 
68  std::string executable;
69  std::vector<char> environment;
70  STARTUPINFO startupinfo = {};
71  PROCESS_INFORMATION pi = {};
72 
73  HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO);
74  HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO);
75  HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO);
76 
77  startupinfo.cb = sizeof(startupinfo);
78  startupinfo.dwFlags |= STARTF_USESTDHANDLES;
79  startupinfo.hStdError =
80  stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE);
81  startupinfo.hStdInput =
82  stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE);
83  startupinfo.hStdOutput =
84  stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE);
85 
86  const char *hide_console_var =
87  getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE");
88  if (hide_console_var &&
89  llvm::StringRef(hide_console_var).equals_lower("true")) {
90  startupinfo.dwFlags |= STARTF_USESHOWWINDOW;
91  startupinfo.wShowWindow = SW_HIDE;
92  }
93 
94  DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;
95  if (launch_info.GetFlags().Test(eLaunchFlagDebug))
96  flags |= DEBUG_ONLY_THIS_PROCESS;
97 
98  if (launch_info.GetFlags().Test(eLaunchFlagDisableSTDIO))
99  flags &= ~CREATE_NEW_CONSOLE;
100 
101  LPVOID env_block = nullptr;
102  ::CreateEnvironmentBuffer(launch_info.GetEnvironment(), environment);
103  env_block = environment.data();
104 
105  executable = launch_info.GetExecutableFile().GetPath();
106  std::wstring wcommandLine;
107  GetFlattenedWindowsCommandString(launch_info.GetArguments(), wcommandLine);
108 
109  std::wstring wexecutable, wworkingDirectory;
110  llvm::ConvertUTF8toWide(executable, wexecutable);
111  llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(),
112  wworkingDirectory);
113  // If the command line is empty, it's best to pass a null pointer to tell
114  // CreateProcessW to use the executable name as the command line. If the
115  // command line is not empty, its contents may be modified by CreateProcessW.
116  WCHAR *pwcommandLine = wcommandLine.empty() ? nullptr : &wcommandLine[0];
117 
118  BOOL result = ::CreateProcessW(
119  wexecutable.c_str(), pwcommandLine, NULL, NULL, TRUE, flags, env_block,
120  wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(),
121  &startupinfo, &pi);
122 
123  if (!result) {
124  // Call GetLastError before we make any other system calls.
125  error.SetError(::GetLastError(), eErrorTypeWin32);
126  // Note that error 50 ("The request is not supported") will occur if you
127  // try debug a 64-bit inferior from a 32-bit LLDB.
128  }
129 
130  if (result) {
131  // Do not call CloseHandle on pi.hProcess, since we want to pass that back
132  // through the HostProcess.
133  ::CloseHandle(pi.hThread);
134  }
135 
136  if (stdin_handle)
137  ::CloseHandle(stdin_handle);
138  if (stdout_handle)
139  ::CloseHandle(stdout_handle);
140  if (stderr_handle)
141  ::CloseHandle(stderr_handle);
142 
143  if (!result)
144  return HostProcess();
145 
146  return HostProcess(pi.hProcess);
147 }
148 
149 HANDLE
150 ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info,
151  int fd) {
152  const FileAction *action = launch_info.GetFileActionForFD(fd);
153  if (action == nullptr)
154  return NULL;
155  SECURITY_ATTRIBUTES secattr = {};
156  secattr.nLength = sizeof(SECURITY_ATTRIBUTES);
157  secattr.bInheritHandle = TRUE;
158 
159  llvm::StringRef path = action->GetPath();
160  DWORD access = 0;
161  DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
162  DWORD create = 0;
163  DWORD flags = 0;
164  if (fd == STDIN_FILENO) {
165  access = GENERIC_READ;
166  create = OPEN_EXISTING;
167  flags = FILE_ATTRIBUTE_READONLY;
168  }
169  if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
170  access = GENERIC_WRITE;
171  create = CREATE_ALWAYS;
172  if (fd == STDERR_FILENO)
173  flags = FILE_FLAG_WRITE_THROUGH;
174  }
175 
176  std::wstring wpath;
177  llvm::ConvertUTF8toWide(path, wpath);
178  HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create,
179  flags, NULL);
180  return (result == INVALID_HANDLE_VALUE) ? NULL : result;
181 }
lldb_private::ProcessInfo::GetArguments
Args & GetArguments()
Definition: ProcessInfo.h:75
lldb_private::HostProcess
Definition: HostProcess.h:33
ProcessLaunchInfo.h
HostProcess.h
lldb_private::ProcessLaunchInfo::GetFileActionForFD
const FileAction * GetFileActionForFD(int fd) const
Definition: ProcessLaunchInfo.cpp:117
lldb_private::Flags::Test
bool Test(ValueType bit) const
Test a single flag bit.
Definition: Flags.h:96
lldb_private::ProcessLaunchInfo::GetFlags
Flags & GetFlags()
Definition: ProcessLaunchInfo.h:64
lldb_private::Args
Definition: Args.h:33
lldb_private::FileAction
Definition: FileAction.h:17
lldb::eErrorTypeWin32
@ eErrorTypeWin32
Standard Win32 error codes.
Definition: lldb-enumerations.h:312
lldb_private::FileSpec::GetCString
const char * GetCString(bool denormalize=true) const
Definition: FileSpec.cpp:364
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
lldb_private::ProcessLaunchInfo
Definition: ProcessLaunchInfo.h:31
lldb_private::Args::entries
llvm::ArrayRef< ArgEntry > entries() const
Definition: Args.h:130
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:38
lldb_private::ProcessLaunchInfo::GetWorkingDirectory
const FileSpec & GetWorkingDirectory() const
Definition: ProcessLaunchInfo.cpp:125
lldb_private::FileAction::GetPath
llvm::StringRef GetPath() const
Definition: FileAction.cpp:29
lldb_private::Status
Definition: Status.h:44
ProcessLauncherWindows.h
lldb_private::ProcessInfo::GetEnvironment
Environment & GetEnvironment()
Definition: ProcessInfo.h:87
lldb_private::Environment
Definition: Environment.h:18
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::ProcessInfo::GetExecutableFile
FileSpec & GetExecutableFile()
Definition: ProcessInfo.h:42
lldb_private::Args::empty
bool empty() const
Definition: Args.h:120
lldb_private::FileSpec::GetPath
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:348
lldb
Definition: SBAddress.h:15