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
diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp
index 28b4b08..e2197ca 100644
--- a/lldb/source/Host/windows/Host.cpp
+++ b/lldb/source/Host/windows/Host.cpp
@@ -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 @@
 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
 (