diff --git a/lldb/include/lldb/Host/windows/AutoHandle.h b/lldb/include/lldb/Host/windows/AutoHandle.h new file mode 100644 index 000000000000..04411c47d9e2 --- /dev/null +++ b/lldb/include/lldb/Host/windows/AutoHandle.h @@ -0,0 +1,40 @@ +//===-- AutoHandle.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_lldb_Host_windows_AutoHandle_h_ +#define LLDB_lldb_Host_windows_AutoHandle_h_ + +namespace lldb_private { + +class AutoHandle { +public: + AutoHandle(HANDLE handle, HANDLE invalid_value = INVALID_HANDLE_VALUE) + : m_handle(handle) + , m_invalid_value(invalid_value) + { + } + + ~AutoHandle() + { + if (m_handle != m_invalid_value) + ::CloseHandle(m_handle); + } + + bool IsValid() const { return m_handle != m_invalid_value; } + + HANDLE get() const { return m_handle; } +private: + HANDLE m_handle; + HANDLE m_invalid_value; +}; + +} + +#endif + diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 6b551d968006..2daa29caeb1e 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -1443,7 +1443,8 @@ Host::GetOSKernelDescription (std::string &s) } #endif -#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined(__linux__) +#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) \ + && !defined(__linux__) && !defined(_WIN32) uint32_t Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) { diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp index 28b4b08d88f1..e2197caf0246 100644 --- a/lldb/source/Host/windows/Host.cpp +++ b/lldb/source/Host/windows/Host.cpp @@ -10,6 +10,7 @@ // C Includes #include #include "lldb/Host/windows/windows.h" +#include "lldb/Host/windows/AutoHandle.h" // C++ Includes // Other libraries and framework includes @@ -21,10 +22,80 @@ #include "lldb/Host/Host.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataExtractor.h" +#include "lldb/Core/StreamFile.h" + +// Windows includes +#include 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 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. + } +} + bool Host::GetOSVersion(uint32_t &major, uint32_t &minor, @@ -210,33 +281,84 @@ Host::GetUserName (uint32_t uid, std::string &user_name) const char * Host::GetGroupName (uint32_t gid, std::string &group_name) { + llvm_unreachable("Windows does not support group name"); return NULL; } uint32_t Host::GetUserID () { - return 0; + llvm_unreachable("Windows does not support uid"); } uint32_t Host::GetGroupID () { + llvm_unreachable("Windows does not support gid"); return 0; } uint32_t Host::GetEffectiveUserID () { + llvm_unreachable("Windows does not support euid"); return 0; } uint32_t Host::GetEffectiveGroupID () { + llvm_unreachable("Windows does not support egid"); return 0; } +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; +} + lldb::thread_t Host::StartMonitoringChildProcess (