summaryrefslogtreecommitdiff
path: root/source/Host/windows
diff options
context:
space:
mode:
Diffstat (limited to 'source/Host/windows')
-rw-r--r--source/Host/windows/ConnectionGenericFileWindows.cpp11
-rw-r--r--source/Host/windows/FileSystem.cpp120
-rw-r--r--source/Host/windows/Host.cpp48
-rw-r--r--source/Host/windows/HostInfoWindows.cpp52
-rw-r--r--source/Host/windows/HostProcessWindows.cpp21
-rw-r--r--source/Host/windows/PipeWindows.cpp10
-rw-r--r--source/Host/windows/ProcessLauncherWindows.cpp49
-rw-r--r--source/Host/windows/Windows.cpp157
8 files changed, 348 insertions, 120 deletions
diff --git a/source/Host/windows/ConnectionGenericFileWindows.cpp b/source/Host/windows/ConnectionGenericFileWindows.cpp
index eebf3d4f633c8..9743ed48b8efd 100644
--- a/source/Host/windows/ConnectionGenericFileWindows.cpp
+++ b/source/Host/windows/ConnectionGenericFileWindows.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ConvertUTF.h"
using namespace lldb;
using namespace lldb_private;
@@ -138,7 +139,15 @@ ConnectionGenericFile::Connect(const char *s, Error *error_ptr)
// Open the file for overlapped access. If it does not exist, create it. We open it overlapped
// so that we can issue asynchronous reads and then use WaitForMultipleObjects to allow the read
// to be interrupted by an event object.
- m_file = ::CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL);
+ std::wstring wpath;
+ if (!llvm::ConvertUTF8toWide(path, wpath))
+ {
+ if (error_ptr)
+ error_ptr->SetError(1, eErrorTypeGeneric);
+ return eConnectionStatusError;
+ }
+ m_file = ::CreateFileW(wpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS,
+ FILE_FLAG_OVERLAPPED, NULL);
if (m_file == INVALID_HANDLE_VALUE)
{
if (error_ptr)
diff --git a/source/Host/windows/FileSystem.cpp b/source/Host/windows/FileSystem.cpp
index 2cca12b92711b..3e881f5d9b2be 100644
--- a/source/Host/windows/FileSystem.cpp
+++ b/source/Host/windows/FileSystem.cpp
@@ -15,6 +15,8 @@
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/windows/AutoHandle.h"
+
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/FileSystem.h"
using namespace lldb_private;
@@ -22,6 +24,8 @@ using namespace lldb_private;
const char *
FileSystem::DEV_NULL = "nul";
+const char *FileSystem::PATH_CONVERSION_ERROR = "Error converting path between UTF-8 and native encoding";
+
FileSpec::PathSyntax
FileSystem::GetNativePathSyntax()
{
@@ -47,25 +51,32 @@ Error
FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse)
{
Error error;
+ std::wstring path_buffer;
+ if (!llvm::ConvertUTF8toWide(file_spec.GetPath(), path_buffer))
+ {
+ error.SetErrorString(PATH_CONVERSION_ERROR);
+ return error;
+ }
if (!recurse)
{
- BOOL result = ::RemoveDirectory(file_spec.GetCString());
+ BOOL result = ::RemoveDirectoryW(path_buffer.c_str());
if (!result)
error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
}
else
{
// SHFileOperation() accepts a list of paths, and so must be double-null-terminated to
- // indicate the end of the list.
- std::string path_buffer{file_spec.GetPath()};
+ // indicate the end of the list. The first null terminator is there only in the backing
+ // store but not the actual vector contents, and so we need to push twice.
+ path_buffer.push_back(0);
path_buffer.push_back(0);
- SHFILEOPSTRUCT shfos = {0};
+ SHFILEOPSTRUCTW shfos = {0};
shfos.wFunc = FO_DELETE;
- shfos.pFrom = path_buffer.c_str();
+ shfos.pFrom = (LPCWSTR)path_buffer.data();
shfos.fFlags = FOF_NO_UI;
- int result = ::SHFileOperation(&shfos);
+ int result = ::SHFileOperationW(&shfos);
// TODO(zturner): Correctly handle the intricacies of SHFileOperation return values.
if (result != 0)
error.SetErrorStringWithFormat("SHFileOperation failed");
@@ -121,7 +132,10 @@ Error
FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst)
{
Error error;
- if (!::CreateHardLink(src.GetCString(), dst.GetCString(), nullptr))
+ std::wstring wsrc, wdst;
+ if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || !llvm::ConvertUTF8toWide(dst.GetCString(), wdst))
+ error.SetErrorString(PATH_CONVERSION_ERROR);
+ else if (!::CreateHardLinkW(wsrc.c_str(), wdst.c_str(), nullptr))
error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
return error;
}
@@ -129,13 +143,12 @@ FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst)
int
FileSystem::GetHardlinkCount(const FileSpec &file_spec)
{
- HANDLE file_handle = ::CreateFile(file_spec.GetCString(),
- FILE_READ_ATTRIBUTES,
- FILE_SHARE_READ,
- nullptr,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- nullptr);
+ std::wstring path;
+ if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path))
+ return -1;
+
+ HANDLE file_handle = ::CreateFileW(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, nullptr);
if (file_handle == INVALID_HANDLE_VALUE)
return -1;
@@ -152,7 +165,12 @@ Error
FileSystem::Symlink(const FileSpec &src, const FileSpec &dst)
{
Error error;
- DWORD attrib = ::GetFileAttributes(dst.GetCString());
+ std::wstring wsrc, wdst;
+ if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || !llvm::ConvertUTF8toWide(dst.GetCString(), wdst))
+ error.SetErrorString(PATH_CONVERSION_ERROR);
+ if (error.Fail())
+ return error;
+ DWORD attrib = ::GetFileAttributesW(wdst.c_str());
if (attrib == INVALID_FILE_ATTRIBUTES)
{
error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
@@ -160,7 +178,7 @@ FileSystem::Symlink(const FileSpec &src, const FileSpec &dst)
}
bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY);
DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
- BOOL result = ::CreateSymbolicLink(src.GetCString(), dst.GetCString(), flag);
+ BOOL result = ::CreateSymbolicLinkW(wsrc.c_str(), wdst.c_str(), flag);
if (!result)
error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
return error;
@@ -170,7 +188,13 @@ Error
FileSystem::Unlink(const FileSpec &file_spec)
{
Error error;
- BOOL result = ::DeleteFile(file_spec.GetCString());
+ std::wstring path;
+ if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path))
+ {
+ error.SetErrorString(PATH_CONVERSION_ERROR);
+ return error;
+ }
+ BOOL result = ::DeleteFileW(path.c_str());
if (!result)
error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
return error;
@@ -180,23 +204,31 @@ Error
FileSystem::Readlink(const FileSpec &src, FileSpec &dst)
{
Error error;
- HANDLE h = ::CreateFile(src.GetCString(), GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT, NULL);
+ std::wstring wsrc;
+ if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc))
+ {
+ error.SetErrorString(PATH_CONVERSION_ERROR);
+ return error;
+ }
+
+ HANDLE h = ::CreateFileW(wsrc.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (h == INVALID_HANDLE_VALUE)
{
error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
return error;
}
- char buf[PATH_MAX];
+ std::vector<wchar_t> buf(PATH_MAX + 1);
// Subtract 1 from the path length since this function does not add a null terminator.
- DWORD result = ::GetFinalPathNameByHandle(h, buf, sizeof(buf) - 1,
- FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+ DWORD result = ::GetFinalPathNameByHandleW(h, buf.data(), buf.size() - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+ std::string path;
if (result == 0)
error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
+ else if (!llvm::convertWideToUTF8(buf.data(), path))
+ error.SetErrorString(PATH_CONVERSION_ERROR);
else
- dst.SetFile(buf, false);
+ dst.SetFile(path, false);
::CloseHandle(h);
return error;
@@ -219,3 +251,43 @@ FileSystem::IsLocal(const FileSpec &spec)
return false;
}
+
+FILE *
+FileSystem::Fopen(const char *path, const char *mode)
+{
+ std::wstring wpath, wmode;
+ if (!llvm::ConvertUTF8toWide(path, wpath))
+ return nullptr;
+ if (!llvm::ConvertUTF8toWide(mode, wmode))
+ return nullptr;
+ FILE *file;
+ if (_wfopen_s(&file, wpath.c_str(), wmode.c_str()) != 0)
+ return nullptr;
+ return file;
+}
+
+int
+FileSystem::Stat(const char *path, struct stat *stats)
+{
+ std::wstring wpath;
+ if (!llvm::ConvertUTF8toWide(path, wpath))
+ {
+ errno = EINVAL;
+ return -EINVAL;
+ }
+ int stat_result;
+#ifdef _USE_32BIT_TIME_T
+ struct _stat32 file_stats;
+ stat_result = ::_wstat32(wpath.c_str(), &file_stats);
+#else
+ struct _stat64i32 file_stats;
+ stat_result = ::_wstat64i32(wpath.c_str(), &file_stats);
+#endif
+ if (stat_result == 0)
+ {
+ static_assert(sizeof(struct stat) == sizeof(file_stats),
+ "stat and _stat32/_stat64i32 must have the same layout");
+ *stats = *reinterpret_cast<struct stat *>(&file_stats);
+ }
+ return stat_result;
+}
diff --git a/source/Host/windows/Host.cpp b/source/Host/windows/Host.cpp
index 2c9a139df256c..1b4eeb8d4f606 100644
--- a/source/Host/windows/Host.cpp
+++ b/source/Host/windows/Host.cpp
@@ -26,6 +26,8 @@
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StructuredData.h"
+#include "llvm/Support/ConvertUTF.h"
+
// Windows includes
#include <TlHelp32.h>
@@ -68,12 +70,11 @@ namespace
bool GetExecutableForProcess(const AutoHandle &handle, std::string &path)
{
// Get the process image path. MAX_PATH isn't long enough, paths can actually be up to 32KB.
- std::vector<char> buffer(32768);
+ std::vector<wchar_t> buffer(PATH_MAX);
DWORD dwSize = buffer.size();
- if (!::QueryFullProcessImageNameA(handle.get(), 0, &buffer[0], &dwSize))
+ if (!::QueryFullProcessImageNameW(handle.get(), 0, &buffer[0], &dwSize))
return false;
- path.assign(&buffer[0]);
- return true;
+ return llvm::convertWideToUTF8(buffer.data(), path);
}
void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process)
@@ -156,15 +157,17 @@ Host::GetModuleFileSpecForHostAddress (const void *host_addr)
if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)host_addr, &hmodule))
return module_filespec;
- std::vector<char> buffer(MAX_PATH);
+ std::vector<wchar_t> buffer(PATH_MAX);
DWORD chars_copied = 0;
do {
- chars_copied = ::GetModuleFileName(hmodule, &buffer[0], buffer.size());
+ chars_copied = ::GetModuleFileNameW(hmodule, &buffer[0], buffer.size());
if (chars_copied == buffer.size() && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
buffer.resize(buffer.size() * 2);
} while (chars_copied >= buffer.size());
-
- module_filespec.SetFile(&buffer[0], false);
+ std::string path;
+ if (!llvm::convertWideToUTF8(buffer.data(), path))
+ return module_filespec;
+ module_filespec.SetFile(path, false);
return module_filespec;
}
@@ -177,23 +180,25 @@ Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstance
if (!snapshot.IsValid())
return 0;
- PROCESSENTRY32 pe = {0};
- pe.dwSize = sizeof(PROCESSENTRY32);
- if (Process32First(snapshot.get(), &pe))
+ PROCESSENTRY32W pe = {0};
+ pe.dwSize = sizeof(PROCESSENTRY32W);
+ if (Process32FirstW(snapshot.get(), &pe))
{
do
{
AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr);
ProcessInstanceInfo process;
- process.SetExecutableFile(FileSpec(pe.szExeFile, false), true);
+ std::string exeFile;
+ llvm::convertWideToUTF8(pe.szExeFile, exeFile);
+ process.SetExecutableFile(FileSpec(exeFile, false), true);
process.SetProcessID(pe.th32ProcessID);
process.SetParentProcessID(pe.th32ParentProcessID);
GetProcessExecutableAndTriple(handle, process);
if (match_info.MatchAllProcesses() || match_info.Matches(process))
process_infos.Append(process);
- } while (Process32Next(snapshot.get(), &pe));
+ } while (Process32NextW(snapshot.get(), &pe));
}
return process_infos.GetSize();
}
@@ -216,7 +221,8 @@ Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
}
HostThread
-Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
+Host::StartMonitoringChildProcess(const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid,
+ bool monitor_signals)
{
return HostThread();
}
@@ -312,15 +318,21 @@ Host::GetEnvironment(StringList &env)
{
// The environment block on Windows is a contiguous buffer of NULL terminated strings,
// where the end of the environment block is indicated by two consecutive NULLs.
- LPCH environment_block = ::GetEnvironmentStrings();
+ LPWCH environment_block = ::GetEnvironmentStringsW();
env.Clear();
- while (*environment_block != '\0')
+ while (*environment_block != L'\0')
{
- llvm::StringRef current_var(environment_block);
+ std::string current_var;
+ auto current_var_size = wcslen(environment_block) + 1;
+ if (!llvm::convertWideToUTF8(environment_block, current_var))
+ {
+ environment_block += current_var_size;
+ continue;
+ }
if (current_var[0] != '=')
env.AppendString(current_var);
- environment_block += current_var.size()+1;
+ environment_block += current_var_size;
}
return env.GetSize();
}
diff --git a/source/Host/windows/HostInfoWindows.cpp b/source/Host/windows/HostInfoWindows.cpp
index 6dce71d9172ad..6b2190294081f 100644
--- a/source/Host/windows/HostInfoWindows.cpp
+++ b/source/Host/windows/HostInfoWindows.cpp
@@ -9,18 +9,35 @@
#include "lldb/Host/windows/windows.h"
+#include <objbase.h>
+
#include <mutex> // std::once
#include "lldb/Host/windows/HostInfoWindows.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
using namespace lldb_private;
FileSpec HostInfoWindows::m_program_filespec;
+void
+HostInfoWindows::Initialize()
+{
+ ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+ HostInfoBase::Initialize();
+}
+
+void
+HostInfoWindows::Terminate()
+{
+ HostInfoBase::Terminate();
+ ::CoUninitialize();
+}
+
size_t
HostInfoWindows::GetPageSize()
{
@@ -76,23 +93,24 @@ HostInfoWindows::GetOSKernelDescription(std::string &s)
bool
HostInfoWindows::GetHostname(std::string &s)
{
- char buffer[MAX_COMPUTERNAME_LENGTH + 1];
+ wchar_t buffer[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
- if (!::GetComputerName(buffer, &dwSize))
+ if (!::GetComputerNameW(buffer, &dwSize))
return false;
- s.assign(buffer, buffer + dwSize);
- return true;
+ return llvm::convertWideToUTF8(buffer, s);
}
FileSpec
HostInfoWindows::GetProgramFileSpec()
{
static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
- char buffer[PATH_MAX];
- ::GetModuleFileName(NULL, buffer, sizeof(buffer));
- m_program_filespec.SetFile(buffer, false);
+ std::call_once(g_once_flag, []() {
+ std::vector<wchar_t> buffer(PATH_MAX);
+ ::GetModuleFileNameW(NULL, buffer.data(), buffer.size());
+ std::string path;
+ llvm::convertWideToUTF8(buffer.data(), path);
+ m_program_filespec.SetFile(path, false);
});
return m_program_filespec;
}
@@ -100,7 +118,9 @@ HostInfoWindows::GetProgramFileSpec()
FileSpec
HostInfoWindows::GetDefaultShell()
{
- return FileSpec(::getenv("ComSpec"), false);
+ std::string shell;
+ GetEnvironmentVar("ComSpec", shell);
+ return FileSpec(shell, false);
}
bool
@@ -116,3 +136,15 @@ HostInfoWindows::ComputePythonDirectory(FileSpec &file_spec)
file_spec.GetDirectory().SetString(path.c_str());
return true;
}
+
+bool
+HostInfoWindows::GetEnvironmentVar(const std::string &var_name, std::string &var)
+{
+ std::wstring wvar_name;
+ if (!llvm::ConvertUTF8toWide(var_name, wvar_name))
+ return false;
+
+ if (const wchar_t *wvar = _wgetenv(wvar_name.c_str()))
+ return llvm::convertWideToUTF8(wvar, var);
+ return false;
+}
diff --git a/source/Host/windows/HostProcessWindows.cpp b/source/Host/windows/HostProcessWindows.cpp
index 0f81c18d34afb..2878171cbe773 100644
--- a/source/Host/windows/HostProcessWindows.cpp
+++ b/source/Host/windows/HostProcessWindows.cpp
@@ -14,6 +14,7 @@
#include "lldb/Host/windows/HostProcessWindows.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/ConvertUTF.h"
#include <Psapi.h>
@@ -23,8 +24,7 @@ namespace
{
struct MonitorInfo
{
- HostProcess::MonitorCallback callback;
- void *baton;
+ Host::MonitorChildProcessCallback callback;
HANDLE process_handle;
};
}
@@ -70,9 +70,15 @@ Error HostProcessWindows::GetMainModule(FileSpec &file_spec) const
if (m_process == nullptr)
error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32);
- char path[MAX_PATH] = { 0 };
- if (::GetProcessImageFileName(m_process, path, llvm::array_lengthof(path)))
- file_spec.SetFile(path, false);
+ std::vector<wchar_t> wpath(PATH_MAX);
+ if (::GetProcessImageFileNameW(m_process, wpath.data(), wpath.size()))
+ {
+ std::string path;
+ if (llvm::convertWideToUTF8(wpath.data(), path))
+ file_spec.SetFile(path, false);
+ else
+ error.SetErrorString("Error converting path to UTF-8");
+ }
else
error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
@@ -97,12 +103,11 @@ bool HostProcessWindows::IsRunning() const
}
HostThread
-HostProcessWindows::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals)
+HostProcessWindows::StartMonitoring(const Host::MonitorChildProcessCallback &callback, bool monitor_signals)
{
HostThread monitor_thread;
MonitorInfo *info = new MonitorInfo;
info->callback = callback;
- info->baton = callback_baton;
// Since the life of this HostProcessWindows instance and the life of the process may be different, duplicate the handle so that
// the monitor thread can have ownership over its own copy of the handle.
@@ -122,7 +127,7 @@ HostProcessWindows::MonitorThread(void *thread_arg)
{
::WaitForSingleObject(info->process_handle, INFINITE);
::GetExitCodeProcess(info->process_handle, &exit_code);
- info->callback(info->baton, ::GetProcessId(info->process_handle), true, 0, exit_code);
+ info->callback(::GetProcessId(info->process_handle), true, 0, exit_code);
::CloseHandle(info->process_handle);
delete (info);
}
diff --git a/source/Host/windows/PipeWindows.cpp b/source/Host/windows/PipeWindows.cpp
index d4afd6e749436..6ed8d0e83f3ca 100644
--- a/source/Host/windows/PipeWindows.cpp
+++ b/source/Host/windows/PipeWindows.cpp
@@ -73,8 +73,8 @@ PipeWindows::CreateNew(llvm::StringRef name, bool child_process_inherit)
// Always open for overlapped i/o. We implement blocking manually in Read and Write.
DWORD read_mode = FILE_FLAG_OVERLAPPED;
- m_read =
- ::CreateNamedPipe(pipe_path.c_str(), PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, 1024, 120 * 1000, NULL);
+ m_read = ::CreateNamedPipeA(pipe_path.c_str(), PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024,
+ 1024, 120 * 1000, NULL);
if (INVALID_HANDLE_VALUE == m_read)
return Error(::GetLastError(), eErrorTypeWin32);
m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);
@@ -153,7 +153,8 @@ PipeWindows::OpenNamedPipe(llvm::StringRef name, bool child_process_inherit, boo
if (is_read)
{
- m_read = ::CreateFile(pipe_path.c_str(), GENERIC_READ, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+ m_read =
+ ::CreateFileA(pipe_path.c_str(), GENERIC_READ, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (INVALID_HANDLE_VALUE == m_read)
return Error(::GetLastError(), eErrorTypeWin32);
@@ -164,7 +165,8 @@ PipeWindows::OpenNamedPipe(llvm::StringRef name, bool child_process_inherit, boo
}
else
{
- m_write = ::CreateFile(pipe_path.c_str(), GENERIC_WRITE, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+ m_write =
+ ::CreateFileA(pipe_path.c_str(), GENERIC_WRITE, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (INVALID_HANDLE_VALUE == m_write)
return Error(::GetLastError(), eErrorTypeWin32);
diff --git a/source/Host/windows/ProcessLauncherWindows.cpp b/source/Host/windows/ProcessLauncherWindows.cpp
index 355dd40544f9a..caf0fc71e1212 100644
--- a/source/Host/windows/ProcessLauncherWindows.cpp
+++ b/source/Host/windows/ProcessLauncherWindows.cpp
@@ -11,12 +11,38 @@
#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)
{
@@ -45,14 +71,27 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Erro
startupinfo.wShowWindow = SW_HIDE;
}
- DWORD flags = CREATE_NEW_CONSOLE;
+ 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);
- BOOL result = ::CreateProcessA(executable.c_str(), const_cast<char *>(commandLine.c_str()), NULL, NULL, TRUE, flags, NULL,
- launch_info.GetWorkingDirectory().GetCString(), &startupinfo, &pi);
+
+ 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.
@@ -100,6 +139,8 @@ ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, int
flags = FILE_FLAG_WRITE_THROUGH;
}
- HANDLE result = ::CreateFile(path, access, share, &secattr, create, flags, NULL);
+ 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;
}
diff --git a/source/Host/windows/Windows.cpp b/source/Host/windows/Windows.cpp
index 71bff7a9d2e2f..2aebb10bcdd92 100644
--- a/source/Host/windows/Windows.cpp
+++ b/source/Host/windows/Windows.cpp
@@ -12,6 +12,9 @@
#include "lldb/Host/windows/windows.h"
#include "lldb/Host/windows/win32.h"
+#include "llvm/Support/ConvertUTF.h"
+
+#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
@@ -27,6 +30,29 @@ extern "C"
int _chdir(const char *path);
}
+namespace
+{
+bool
+utf8ToWide(const char *utf8, wchar_t *buf, size_t bufSize)
+{
+ const UTF8 *sourceStart = reinterpret_cast<const UTF8 *>(utf8);
+ size_t sourceLen = strlen(utf8) + 1 /* convert null too */;
+ UTF16 *target = reinterpret_cast<UTF16 *>(buf);
+ ConversionFlags flags = strictConversion;
+ return ConvertUTF8toUTF16(&sourceStart, sourceStart + sourceLen, &target, target + bufSize, flags) == conversionOK;
+}
+
+bool
+wideToUtf8(const wchar_t *wide, char *buf, size_t bufSize)
+{
+ const UTF16 *sourceStart = reinterpret_cast<const UTF16 *>(wide);
+ size_t sourceLen = wcslen(wide) + 1 /* convert null too */;
+ UTF8 *target = reinterpret_cast<UTF8 *>(buf);
+ ConversionFlags flags = strictConversion;
+ return ConvertUTF16toUTF8(&sourceStart, sourceStart + sourceLen, &target, target + bufSize, flags) == conversionOK;
+}
+}
+
int vasprintf(char **ret, const char *fmt, va_list ap)
{
char *buf;
@@ -75,81 +101,90 @@ char* strcasestr(const char *s, const char* find)
char* realpath(const char * name, char * resolved)
{
- char *retname = NULL; /* we will return this, if we fail */
+ char *retname = NULL;
/* SUSv3 says we must set `errno = EINVAL', and return NULL,
* if `name' is passed as a NULL pointer.
*/
-
if (name == NULL)
+ {
errno = EINVAL;
+ return NULL;
+ }
/* Otherwise, `name' must refer to a readable filesystem object,
* if we are going to resolve its absolute path name.
*/
-
- else if (access(name, 4) == 0)
+ wchar_t wideNameBuffer[PATH_MAX];
+ wchar_t *wideName = wideNameBuffer;
+ if (!utf8ToWide(name, wideName, PATH_MAX))
{
- /* If `name' didn't point to an existing entity,
- * then we don't get to here; we simply fall past this block,
- * returning NULL, with `errno' appropriately set by `access'.
- *
- * When we _do_ get to here, then we can use `_fullpath' to
- * resolve the full path for `name' into `resolved', but first,
- * check that we have a suitable buffer, in which to return it.
- */
+ errno = EINVAL;
+ return NULL;
+ }
- if ((retname = resolved) == NULL)
- {
- /* Caller didn't give us a buffer, so we'll exercise the
- * option granted by SUSv3, and allocate one.
- *
- * `_fullpath' would do this for us, but it uses `malloc', and
- * Microsoft's implementation doesn't set `errno' on failure.
- * If we don't do this explicitly ourselves, then we will not
- * know if `_fullpath' fails on `malloc' failure, or for some
- * other reason, and we want to set `errno = ENOMEM' for the
- * `malloc' failure case.
- */
-
- retname = (char*) malloc(_MAX_PATH);
- }
+ if (_waccess(wideName, 4) != 0)
+ return NULL;
+
+ /* If `name' didn't point to an existing entity,
+ * then we don't get to here; we simply fall past this block,
+ * returning NULL, with `errno' appropriately set by `access'.
+ *
+ * When we _do_ get to here, then we can use `_fullpath' to
+ * resolve the full path for `name' into `resolved', but first,
+ * check that we have a suitable buffer, in which to return it.
+ */
- /* By now, we should have a valid buffer.
- * If we don't, then we know that `malloc' failed,
- * so we can set `errno = ENOMEM' appropriately.
+ if ((retname = resolved) == NULL)
+ {
+ /* Caller didn't give us a buffer, so we'll exercise the
+ * option granted by SUSv3, and allocate one.
+ *
+ * `_fullpath' would do this for us, but it uses `malloc', and
+ * Microsoft's implementation doesn't set `errno' on failure.
+ * If we don't do this explicitly ourselves, then we will not
+ * know if `_fullpath' fails on `malloc' failure, or for some
+ * other reason, and we want to set `errno = ENOMEM' for the
+ * `malloc' failure case.
*/
+ retname = (char *)malloc(PATH_MAX);
if (retname == NULL)
+ {
errno = ENOMEM;
+ return NULL;
+ }
+ }
- /* Otherwise, when we do have a valid buffer,
- * `_fullpath' should only fail if the path name is too long.
- */
+ /* Otherwise, when we do have a valid buffer,
+ * `_fullpath' should only fail if the path name is too long.
+ */
- else if ((retname = _fullpath(retname, name, _MAX_PATH)) == NULL)
- errno = ENAMETOOLONG;
+ wchar_t wideFullPathBuffer[PATH_MAX];
+ wchar_t *wideFullPath;
+ if ((wideFullPath = _wfullpath(wideFullPathBuffer, wideName, PATH_MAX)) == NULL)
+ {
+ errno = ENAMETOOLONG;
+ return NULL;
}
- /* By the time we get to here,
- * `retname' either points to the required resolved path name,
- * or it is NULL, with `errno' set appropriately, either of which
- * is our required return condition.
- */
+ // Do a LongPath<->ShortPath roundtrip so that case is resolved by OS
+ // FIXME: Check for failure
+ size_t initialLength = wcslen(wideFullPath);
+ GetShortPathNameW(wideFullPath, wideNameBuffer, PATH_MAX);
+ GetLongPathNameW(wideNameBuffer, wideFullPathBuffer, initialLength + 1);
- if (retname != NULL)
+ // Convert back to UTF-8
+ if (!wideToUtf8(wideFullPathBuffer, retname, PATH_MAX))
{
- // Do a LongPath<->ShortPath roundtrip so that case is resolved by OS
- int initialLength = strlen(retname);
- TCHAR buffer[MAX_PATH];
- GetShortPathName(retname, buffer, MAX_PATH);
- GetLongPathName(buffer, retname, initialLength + 1);
-
- // Force drive to be upper case
- if (retname[1] == ':')
- retname[0] = toupper(retname[0]);
+ errno = EINVAL;
+ return NULL;
}
+ // Force drive to be upper case
+ if (retname[1] == ':')
+ retname[0] = toupper(retname[0]);
+
return retname;
}
@@ -167,7 +202,27 @@ char* basename(char *path)
// use _getcwd() instead of GetCurrentDirectory() because it updates errno
char* getcwd(char* path, int max)
{
- return _getcwd(path, max);
+ assert(path == NULL || max <= PATH_MAX);
+ wchar_t wpath[PATH_MAX];
+ if (wchar_t *wresult = _wgetcwd(wpath, PATH_MAX))
+ {
+ // Caller is allowed to pass in NULL for `path`.
+ // In that case, we're supposed to allocate a
+ // buffer on the caller's behalf.
+ if (path == NULL)
+ {
+ max = UNI_MAX_UTF8_BYTES_PER_CODE_POINT * wcslen(wresult) + 1;
+ path = (char *)malloc(max);
+ if (path == NULL)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+ if (wideToUtf8(wresult, path, max))
+ return path;
+ }
+ return NULL;
}
// use _chdir() instead of SetCurrentDirectory() because it updates errno