Win32 API calls that are Unicode aware require wide character strings, but LLDB uses UTF8 everywhere. This patch does conversions wherever necessary when passing strings into and out of Win32 API calls. Patch by Cameron Differential Revision: http://reviews.llvm.org/D17107 Reviewed By: zturner, amccarth llvm-svn: 264074
147 lines
5.0 KiB
C++
147 lines
5.0 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 "llvm/ADT/SmallVector.h"
|
|
#include "llvm/Support/ConvertUTF.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;
|
|
|
|
// Environment buffer is a null terminated list of null terminated strings
|
|
for (int i = 0; i < env.GetArgumentCount(); ++i)
|
|
{
|
|
std::wstring warg;
|
|
if (llvm::ConvertUTF8toWide(env.GetArgumentAtIndex(i), 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, 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 | CREATE_UNICODE_ENVIRONMENT;
|
|
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);
|
|
|
|
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)
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
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;
|
|
}
|