summaryrefslogtreecommitdiff
path: root/source/Host/windows/Host.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-01-06 20:12:03 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-01-06 20:12:03 +0000
commit9e6d35490a6542f9c97607f93c2ef8ca8e03cbcc (patch)
treedd2a1ddf0476664c2b823409c36cbccd52662ca7 /source/Host/windows/Host.cpp
parent3bd2e91faeb9eeec1aae82c64a3253afff551cfd (diff)
Notes
Diffstat (limited to 'source/Host/windows/Host.cpp')
-rw-r--r--source/Host/windows/Host.cpp326
1 files changed, 326 insertions, 0 deletions
diff --git a/source/Host/windows/Host.cpp b/source/Host/windows/Host.cpp
new file mode 100644
index 0000000000000..2c9a139df256c
--- /dev/null
+++ b/source/Host/windows/Host.cpp
@@ -0,0 +1,326 @@
+//===-- source/Host/windows/Host.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdio.h>
+#include "lldb/Host/windows/windows.h"
+#include "lldb/Host/windows/AutoHandle.h"
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StructuredData.h"
+
+// Windows includes
+#include <TlHelp32.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+ bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple)
+ {
+ // Open the PE File as a binary file, and parse just enough information to determine the
+ // machine type.
+ File imageBinary(
+ executable.GetPath().c_str(),
+ File::eOpenOptionRead,
+ lldb::eFilePermissionsUserRead);
+ imageBinary.SeekFromStart(0x3c);
+ int32_t peOffset = 0;
+ uint32_t peHead = 0;
+ uint16_t machineType = 0;
+ size_t readSize = sizeof(peOffset);
+ imageBinary.Read(&peOffset, readSize);
+ imageBinary.SeekFromStart(peOffset);
+ imageBinary.Read(&peHead, readSize);
+ if (peHead != 0x00004550) // "PE\0\0", little-endian
+ return false; // Error: Can't find PE header
+ readSize = 2;
+ imageBinary.Read(&machineType, readSize);
+ triple.setVendor(llvm::Triple::PC);
+ triple.setOS(llvm::Triple::Win32);
+ triple.setArch(llvm::Triple::UnknownArch);
+ if (machineType == 0x8664)
+ triple.setArch(llvm::Triple::x86_64);
+ else if (machineType == 0x14c)
+ triple.setArch(llvm::Triple::x86);
+
+ return true;
+ }
+
+ 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);
+ DWORD dwSize = buffer.size();
+ if (!::QueryFullProcessImageNameA(handle.get(), 0, &buffer[0], &dwSize))
+ return false;
+ path.assign(&buffer[0]);
+ return true;
+ }
+
+ void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process)
+ {
+ // We may not have permissions to read the path from the process. So start off by
+ // setting the executable file to whatever Toolhelp32 gives us, and then try to
+ // enhance this with more detailed information, but fail gracefully.
+ std::string executable;
+ llvm::Triple triple;
+ triple.setVendor(llvm::Triple::PC);
+ triple.setOS(llvm::Triple::Win32);
+ triple.setArch(llvm::Triple::UnknownArch);
+ if (GetExecutableForProcess(handle, executable))
+ {
+ FileSpec executableFile(executable.c_str(), false);
+ process.SetExecutableFile(executableFile, true);
+ GetTripleForProcess(executableFile, triple);
+ }
+ process.SetArchitecture(ArchSpec(triple));
+
+ // TODO(zturner): Add the ability to get the process user name.
+ }
+}
+
+lldb::DataBufferSP
+Host::GetAuxvData(lldb_private::Process *process)
+{
+ return 0;
+}
+
+lldb::tid_t
+Host::GetCurrentThreadID()
+{
+ return lldb::tid_t(::GetCurrentThreadId());
+}
+
+lldb::thread_t
+Host::GetCurrentThread ()
+{
+ return lldb::thread_t(::GetCurrentThread());
+}
+
+lldb::thread_key_t
+Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback)
+{
+ return TlsAlloc();
+}
+
+void*
+Host::ThreadLocalStorageGet(lldb::thread_key_t key)
+{
+ return ::TlsGetValue (key);
+}
+
+void
+Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value)
+{
+ ::TlsSetValue (key, value);
+}
+
+void
+Host::Kill(lldb::pid_t pid, int signo)
+{
+ TerminateProcess((HANDLE) pid, 1);
+}
+
+
+const char *
+Host::GetSignalAsCString(int signo)
+{
+ return NULL;
+}
+
+FileSpec
+Host::GetModuleFileSpecForHostAddress (const void *host_addr)
+{
+ FileSpec module_filespec;
+
+ HMODULE hmodule = NULL;
+ if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)host_addr, &hmodule))
+ return module_filespec;
+
+ std::vector<char> buffer(MAX_PATH);
+ DWORD chars_copied = 0;
+ do {
+ chars_copied = ::GetModuleFileName(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);
+ return module_filespec;
+}
+
+uint32_t
+Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
+{
+ process_infos.Clear();
+
+ AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
+ if (!snapshot.IsValid())
+ return 0;
+
+ PROCESSENTRY32 pe = {0};
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ if (Process32First(snapshot.get(), &pe))
+ {
+ do
+ {
+ AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr);
+
+ ProcessInstanceInfo process;
+ process.SetExecutableFile(FileSpec(pe.szExeFile, 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));
+ }
+ return process_infos.GetSize();
+}
+
+bool
+Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ process_info.Clear();
+
+ AutoHandle handle(::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid),
+ nullptr);
+ if (!handle.IsValid())
+ return false;
+
+ process_info.SetProcessID(pid);
+ GetProcessExecutableAndTriple(handle, process_info);
+
+ // Need to read the PEB to get parent process and command line arguments.
+ return true;
+}
+
+HostThread
+Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
+{
+ return HostThread();
+}
+
+Error
+Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
+ {
+ FileSpec expand_tool_spec;
+ if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
+ {
+ error.SetErrorString("could not find support executable directory for the lldb-argdumper tool");
+ return error;
+ }
+ expand_tool_spec.AppendPathComponent("lldb-argdumper.exe");
+ if (!expand_tool_spec.Exists())
+ {
+ error.SetErrorString("could not find the lldb-argdumper tool");
+ return error;
+ }
+
+ std::string quoted_cmd_string;
+ launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
+ std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/');
+ StreamString expand_command;
+
+ expand_command.Printf("\"%s\" %s",
+ expand_tool_spec.GetPath().c_str(),
+ quoted_cmd_string.c_str());
+
+ int status;
+ std::string output;
+ RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(), &status, nullptr, &output, 10);
+
+ if (status != 0)
+ {
+ error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", status);
+ return error;
+ }
+
+ auto data_sp = StructuredData::ParseJSON(output);
+ if (!data_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto dict_sp = data_sp->GetAsDictionary();
+ if (!data_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
+ if (!args_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto args_array_sp = args_sp->GetAsArray();
+ if (!args_array_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ launch_info.GetArguments().Clear();
+
+ for (size_t i = 0;
+ i < args_array_sp->GetSize();
+ i++)
+ {
+ auto item_sp = args_array_sp->GetItemAtIndex(i);
+ if (!item_sp)
+ continue;
+ auto str_sp = item_sp->GetAsString();
+ if (!str_sp)
+ continue;
+
+ launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
+ }
+ }
+
+ return error;
+}
+
+size_t
+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();
+ env.Clear();
+ while (*environment_block != '\0')
+ {
+ llvm::StringRef current_var(environment_block);
+ if (current_var[0] != '=')
+ env.AppendString(current_var);
+
+ environment_block += current_var.size()+1;
+ }
+ return env.GetSize();
+}