llvm-project/lldb/source/Host/windows/ProcessLauncherWindows.cpp
Zachary Turner 19e2ea8fb6 Fix TestProcessLaunch for Python 3.
There were a number of problems preventing this from working:

1. The SWIG typemaps for converting Python lists to and from C++
   arrays were not updated for Python 3.  So they were doing things
   like PyString_Check instead of using the PythonString from
   PythonDataObjects.
2. ProcessLauncherWindows was ignoring the environment completely.
   So any test that involved launching an inferior with any kind
   of environment variable would have failed.
3. The test itself was using process.GetSTDOUT(), which isn't
   implemented on Windows.  So this was changed to save the
   value of the environment variable in a local variable and
   have the debugger look at the value of the variable.

llvm-svn: 257669
2016-01-13 21:21:49 +00:00

137 lines
4.5 KiB
C++

//===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Host/HostProcess.h"
#include "lldb/Host/windows/ProcessLauncherWindows.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include <string>
#include <vector>
using namespace lldb;
using namespace lldb_private;
namespace
{
void
CreateEnvironmentBuffer(const Args &env, std::vector<char> &buffer)
{
if (env.GetArgumentCount() == 0)
return;
int bytes = 0;
for (int i = 0; i < env.GetArgumentCount(); ++i)
bytes += strlen(env.GetArgumentAtIndex(i)) + sizeof(char);
bytes += sizeof(char);
buffer.resize(bytes);
char *cur_entry = &buffer[0];
for (int i = 0; i < env.GetArgumentCount(); ++i)
{
::strcpy(cur_entry, env.GetArgumentAtIndex(i));
cur_entry += strlen(cur_entry) + sizeof(char);
}
// Environment buffer is a null terminated list of null terminated
// strings, so it is terminated by two null bytes.
buffer.back() = 0;
}
}
HostProcess
ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error)
{
error.Clear();
std::string executable;
std::string commandLine;
std::vector<char> environment;
STARTUPINFO startupinfo = {0};
PROCESS_INFORMATION pi = {0};
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;
if (launch_info.GetFlags().Test(eLaunchFlagDebug))
flags |= DEBUG_ONLY_THIS_PROCESS;
auto &env = const_cast<Args &>(launch_info.GetEnvironmentEntries());
LPVOID env_block = nullptr;
::CreateEnvironmentBuffer(env, environment);
if (!environment.empty())
env_block = environment.data();
executable = launch_info.GetExecutableFile().GetPath();
launch_info.GetArguments().GetQuotedCommandString(commandLine);
BOOL result = ::CreateProcessA(executable.c_str(), const_cast<char *>(commandLine.c_str()), NULL, NULL, TRUE, flags,
env_block, launch_info.GetWorkingDirectory().GetCString(), &startupinfo, &pi);
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)
error.SetError(::GetLastError(), eErrorTypeWin32);
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 = {0};
secattr.nLength = sizeof(SECURITY_ATTRIBUTES);
secattr.bInheritHandle = TRUE;
const char *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;
}
HANDLE result = ::CreateFile(path, access, share, &secattr, create, flags, NULL);
return (result == INVALID_HANDLE_VALUE) ? NULL : result;
}