Implment "platform process list" for Windows.

This patch implements basic functionality of the "platform process
list" command for Windows.  Currently this has the following
limitations.

* Certain types of filtering are not enabled (e.g. filtering by
  architecture with -a), although most filters work.
* The username of the process is not yet obtained.
* Using -v to list verbose information generates an error.
* The architecture column displays the entire triple, leading to
  misaligned formatting of the printed table.

Reviewed by: Greg Clayton
Differential Revision: http://reviews.llvm.org/D4413

llvm-svn: 212510
This commit is contained in:
Zachary Turner 2014-07-08 04:52:15 +00:00
parent 24f3dee6ca
commit 310035a4f9
3 changed files with 165 additions and 2 deletions

View File

@ -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

View File

@ -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)
{

View File

@ -10,6 +10,7 @@
// C Includes
#include <stdio.h>
#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 <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.
}
}
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
(