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