
Summary: These classes describe the details of the process we are about to launch, and so they are naturally used by the launching code in the Host module. Previously they were present in Target because that is the most important (but by far not the only) user of the launching code. Since the launching code has other customers, must of which do not care about Targets, it makes sense to move these classes to the Host layer, next to the launching code. This move reduces the number of times that Target is included from host to 8 (it used to be 14). Reviewers: zturner, clayborg, jingham, davide, teemperor Subscribers: emaste, mgorny, lldb-commits Differential Revision: https://reviews.llvm.org/D56602 llvm-svn: 353047
159 lines
5.1 KiB
C++
159 lines
5.1 KiB
C++
//===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Host/windows/ProcessLauncherWindows.h"
|
|
#include "lldb/Host/HostProcess.h"
|
|
#include "lldb/Host/ProcessLaunchInfo.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/Support/ConvertUTF.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
namespace {
|
|
void CreateEnvironmentBuffer(const Environment &env,
|
|
std::vector<char> &buffer) {
|
|
if (env.size() == 0)
|
|
return;
|
|
|
|
// Environment buffer is a null terminated list of null terminated strings
|
|
for (const auto &KV : env) {
|
|
std::wstring warg;
|
|
if (llvm::ConvertUTF8toWide(Environment::compose(KV), warg)) {
|
|
buffer.insert(buffer.end(), (char *)warg.c_str(),
|
|
(char *)(warg.c_str() + warg.size() + 1));
|
|
}
|
|
}
|
|
// One null wchar_t (to end the block) is two null bytes
|
|
buffer.push_back(0);
|
|
buffer.push_back(0);
|
|
}
|
|
}
|
|
|
|
HostProcess
|
|
ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
|
|
Status &error) {
|
|
error.Clear();
|
|
|
|
std::string executable;
|
|
std::string commandLine;
|
|
std::vector<char> environment;
|
|
STARTUPINFO startupinfo = {};
|
|
PROCESS_INFORMATION pi = {};
|
|
|
|
HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO);
|
|
HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO);
|
|
HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO);
|
|
|
|
startupinfo.cb = sizeof(startupinfo);
|
|
startupinfo.dwFlags |= STARTF_USESTDHANDLES;
|
|
startupinfo.hStdError =
|
|
stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE);
|
|
startupinfo.hStdInput =
|
|
stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE);
|
|
startupinfo.hStdOutput =
|
|
stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
const char *hide_console_var =
|
|
getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE");
|
|
if (hide_console_var &&
|
|
llvm::StringRef(hide_console_var).equals_lower("true")) {
|
|
startupinfo.dwFlags |= STARTF_USESHOWWINDOW;
|
|
startupinfo.wShowWindow = SW_HIDE;
|
|
}
|
|
|
|
DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;
|
|
if (launch_info.GetFlags().Test(eLaunchFlagDebug))
|
|
flags |= DEBUG_ONLY_THIS_PROCESS;
|
|
|
|
if (launch_info.GetFlags().Test(eLaunchFlagDisableSTDIO))
|
|
flags &= ~CREATE_NEW_CONSOLE;
|
|
|
|
LPVOID env_block = nullptr;
|
|
::CreateEnvironmentBuffer(launch_info.GetEnvironment(), environment);
|
|
if (!environment.empty())
|
|
env_block = environment.data();
|
|
|
|
executable = launch_info.GetExecutableFile().GetPath();
|
|
launch_info.GetArguments().GetQuotedCommandString(commandLine);
|
|
|
|
std::wstring wexecutable, wcommandLine, wworkingDirectory;
|
|
llvm::ConvertUTF8toWide(executable, wexecutable);
|
|
llvm::ConvertUTF8toWide(commandLine, wcommandLine);
|
|
llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(),
|
|
wworkingDirectory);
|
|
|
|
wcommandLine.resize(PATH_MAX); // Needs to be over-allocated because
|
|
// CreateProcessW can modify it
|
|
BOOL result = ::CreateProcessW(
|
|
wexecutable.c_str(), &wcommandLine[0], NULL, NULL, TRUE, flags, env_block,
|
|
wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(),
|
|
&startupinfo, &pi);
|
|
|
|
if (!result) {
|
|
// Call GetLastError before we make any other system calls.
|
|
error.SetError(::GetLastError(), eErrorTypeWin32);
|
|
}
|
|
|
|
if (result) {
|
|
// Do not call CloseHandle on pi.hProcess, since we want to pass that back
|
|
// through the HostProcess.
|
|
::CloseHandle(pi.hThread);
|
|
}
|
|
|
|
if (stdin_handle)
|
|
::CloseHandle(stdin_handle);
|
|
if (stdout_handle)
|
|
::CloseHandle(stdout_handle);
|
|
if (stderr_handle)
|
|
::CloseHandle(stderr_handle);
|
|
|
|
if (!result)
|
|
return HostProcess();
|
|
|
|
return HostProcess(pi.hProcess);
|
|
}
|
|
|
|
HANDLE
|
|
ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info,
|
|
int fd) {
|
|
const FileAction *action = launch_info.GetFileActionForFD(fd);
|
|
if (action == nullptr)
|
|
return NULL;
|
|
SECURITY_ATTRIBUTES secattr = {};
|
|
secattr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
secattr.bInheritHandle = TRUE;
|
|
|
|
llvm::StringRef path = action->GetPath();
|
|
DWORD access = 0;
|
|
DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
|
DWORD create = 0;
|
|
DWORD flags = 0;
|
|
if (fd == STDIN_FILENO) {
|
|
access = GENERIC_READ;
|
|
create = OPEN_EXISTING;
|
|
flags = FILE_ATTRIBUTE_READONLY;
|
|
}
|
|
if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
|
|
access = GENERIC_WRITE;
|
|
create = CREATE_ALWAYS;
|
|
if (fd == STDERR_FILENO)
|
|
flags = FILE_FLAG_WRITE_THROUGH;
|
|
}
|
|
|
|
std::wstring wpath;
|
|
llvm::ConvertUTF8toWide(path, wpath);
|
|
HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create,
|
|
flags, NULL);
|
|
return (result == INVALID_HANDLE_VALUE) ? NULL : result;
|
|
}
|