1 //===-- ProcessLauncherWindows.cpp ----------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Host/windows/ProcessLauncherWindows.h"
10 #include "lldb/Host/HostProcess.h"
11 #include "lldb/Host/ProcessLaunchInfo.h"
13 #include "llvm/ADT/SmallVector.h"
14 #include "llvm/Support/ConvertUTF.h"
15 #include "llvm/Support/Program.h"
21 using namespace lldb_private
;
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
) {
30 if (llvm::ConvertUTF8toWide(Environment::compose(KV
), warg
)) {
32 buffer
.end(), reinterpret_cast<const char *>(warg
.c_str()),
33 reinterpret_cast<const char *>(warg
.c_str() + warg
.size() + 1));
36 // One null wchar_t (to end the block) is two null bytes
39 // Insert extra two bytes, just in case the environment was empty.
44 static bool GetFlattenedWindowsCommandString(Args args
, std::wstring
&command
) {
48 std::vector
<llvm::StringRef
> args_ref
;
49 for (auto &entry
: args
.entries())
50 args_ref
.push_back(entry
.ref());
52 llvm::ErrorOr
<std::wstring
> result
=
53 llvm::sys::flattenWindowsCommandLine(args_ref
);
54 if (result
.getError())
62 ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo
&launch_info
,
66 std::string executable
;
67 std::vector
<char> environment
;
68 STARTUPINFO startupinfo
= {};
69 PROCESS_INFORMATION pi
= {};
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
);
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
);
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
;
92 DWORD flags
= CREATE_NEW_CONSOLE
| CREATE_UNICODE_ENVIRONMENT
;
93 if (launch_info
.GetFlags().Test(eLaunchFlagDebug
))
94 flags
|= DEBUG_ONLY_THIS_PROCESS
;
96 if (launch_info
.GetFlags().Test(eLaunchFlagDisableSTDIO
))
97 flags
&= ~CREATE_NEW_CONSOLE
;
99 LPVOID env_block
= nullptr;
100 ::CreateEnvironmentBuffer(launch_info
.GetEnvironment(), environment
);
101 env_block
= environment
.data();
103 executable
= launch_info
.GetExecutableFile().GetPath();
104 std::wstring wcommandLine
;
105 GetFlattenedWindowsCommandString(launch_info
.GetArguments(), wcommandLine
);
107 std::wstring wexecutable
, wworkingDirectory
;
108 llvm::ConvertUTF8toWide(executable
, wexecutable
);
109 llvm::ConvertUTF8toWide(launch_info
.GetWorkingDirectory().GetPath(),
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];
116 BOOL result
= ::CreateProcessW(
117 wexecutable
.c_str(), pwcommandLine
, NULL
, NULL
, TRUE
, flags
, env_block
,
118 wworkingDirectory
.size() == 0 ? NULL
: wworkingDirectory
.c_str(),
122 // Call GetLastError before we make any other system calls.
123 error
= Status(::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.
129 // Do not call CloseHandle on pi.hProcess, since we want to pass that back
130 // through the HostProcess.
131 ::CloseHandle(pi
.hThread
);
135 ::CloseHandle(stdin_handle
);
137 ::CloseHandle(stdout_handle
);
139 ::CloseHandle(stderr_handle
);
142 return HostProcess();
144 return HostProcess(pi
.hProcess
);
148 ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo
&launch_info
,
150 const FileAction
*action
= launch_info
.GetFileActionForFD(fd
);
151 if (action
== nullptr)
153 SECURITY_ATTRIBUTES secattr
= {};
154 secattr
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
155 secattr
.bInheritHandle
= TRUE
;
157 llvm::StringRef path
= action
->GetPath();
159 DWORD share
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
162 if (fd
== STDIN_FILENO
) {
163 access
= GENERIC_READ
;
164 create
= OPEN_EXISTING
;
165 flags
= FILE_ATTRIBUTE_READONLY
;
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
;
175 llvm::ConvertUTF8toWide(path
, wpath
);
176 HANDLE result
= ::CreateFileW(wpath
.c_str(), access
, share
, &secattr
, create
,
178 return (result
== INVALID_HANDLE_VALUE
) ? NULL
: result
;