dvlahovski created this revision.
dvlahovski added reviewers: labath, amccarth.
dvlahovski added a subscriber: lldb-commits.
Herald added subscribers: dschuff, srhines, danalbert, tberghammer.

This is a work-in-progress minidump parsing code.
There are still some more structures/data streams that need to be added.
The aim ot this is to be used in the implementation of
a minidump debugging plugin that works on all platforms/architectures.
Currently we have a windows-only plugin that uses the WinAPI to parse
the dump files.
Also added unittests for the current functionality.

https://reviews.llvm.org/D23545

Files:
  cmake/LLDBDependencies.cmake
  source/Plugins/Process/CMakeLists.txt
  source/Plugins/Process/minidump/CMakeLists.txt
  source/Plugins/Process/minidump/MinidumpParser.cpp
  source/Plugins/Process/minidump/MinidumpParser.h
  source/Plugins/Process/minidump/MinidumpTypes.cpp
  source/Plugins/Process/minidump/MinidumpTypes.h
  unittests/Process/CMakeLists.txt
  unittests/Process/minidump/CMakeLists.txt
  unittests/Process/minidump/Inputs/linux-x86_64.dmp
  unittests/Process/minidump/MinidumpParserTest.cpp

Index: unittests/Process/minidump/MinidumpParserTest.cpp
===================================================================
--- /dev/null
+++ unittests/Process/minidump/MinidumpParserTest.cpp
@@ -0,0 +1,86 @@
+//===-- MinidumpTypesTest.cpp -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
+// Workaround for MSVC standard library bug, which fails to include <thread> when
+// exceptions are disabled.
+#include <eh.h>
+#endif
+
+#include "gtest/gtest.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Host/FileSpec.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+#include "Plugins/Process/minidump/MinidumpParser.h"
+#include "Plugins/Process/minidump/MinidumpTypes.h"
+
+extern const char *TestMainArgv0;
+
+using namespace lldb_private;
+using namespace minidump;
+
+class MinidumpParserTest : public testing::Test
+{
+public:
+    void
+    SetUp() override
+    {
+        llvm::StringRef dmp_folder = llvm::sys::path::parent_path(TestMainArgv0);
+        inputs_folder = dmp_folder;
+        llvm::sys::path::append(inputs_folder, "Inputs");
+    }
+
+    void
+    SetUpData(const char *minidump_filename)
+    {
+        llvm::SmallString<128> filename = inputs_folder;
+        llvm::sys::path::append(filename, minidump_filename);
+        FileSpec minidump_file(filename.c_str(), false);
+        lldb::DataBufferSP data_sp(minidump_file.MemoryMapFileContents());
+        DataExtractor data(data_sp, lldb::eByteOrderLittle, 4);
+        ASSERT_GT(data.GetByteSize(), 0UL);
+        parser.SetData(data);
+        ASSERT_TRUE(parser.ParseHeader());
+    }
+
+    llvm::SmallString<128> inputs_folder;
+    MinidumpParser parser;
+};
+
+TEST_F(MinidumpParserTest, GetThreads)
+{
+    SetUpData("linux-x86_64.dmp");
+    llvm::Optional<std::vector<MinidumpThread>> thread_list;
+
+    thread_list = parser.GetThreads();
+    ASSERT_TRUE(thread_list.hasValue());
+    ASSERT_EQ(1UL, thread_list->size());
+
+    MinidumpThread thread = thread_list.getValue()[0];
+    ASSERT_EQ(16001UL, thread.thread_id);
+}
+
+TEST_F(MinidumpParserTest, GetArchitecture)
+{
+    SetUpData("linux-x86_64.dmp");
+    ASSERT_EQ(llvm::Triple::ArchType::x86_64, parser.GetArchitecture().GetTriple().getArch());
+}
+
+TEST_F(MinidumpParserTest, GetMiscInfo)
+{
+    SetUpData("linux-x86_64.dmp");
+    llvm::Optional<MinidumpMiscInfo> misc_info = parser.GetMiscInfo();
+    ASSERT_FALSE(misc_info.hasValue());
+    // linux breakpad generated minidump files don't have misc info stream
+}
Index: unittests/Process/minidump/CMakeLists.txt
===================================================================
--- /dev/null
+++ unittests/Process/minidump/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_lldb_unittest(LLDBMinidumpTests
+  MinidumpParserTest.cpp
+  )
+
+set(test_inputs
+   linux-x86_64.dmp)
+
+add_unittest_inputs(LLDBMinidumpTests "${test_inputs}")
Index: unittests/Process/CMakeLists.txt
===================================================================
--- unittests/Process/CMakeLists.txt
+++ unittests/Process/CMakeLists.txt
@@ -1 +1,2 @@
 add_subdirectory(gdb-remote)
+add_subdirectory(minidump)
Index: source/Plugins/Process/minidump/MinidumpTypes.h
===================================================================
--- /dev/null
+++ source/Plugins/Process/minidump/MinidumpTypes.h
@@ -0,0 +1,275 @@
+//===-- MinidumpTypes.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MinidumpTypes_h_
+#define liblldb_MinidumpTypes_h_
+
+// C includes
+#include <cstring>
+
+// C++ includes
+
+// Other libraries and framework includes
+#include "lldb/Core/DataExtractor.h"
+#include "llvm/ADT/Optional.h"
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms679293(v=vs.85).aspx
+// https://chromium.googlesource.com/breakpad/breakpad/
+
+namespace lldb_private
+{
+
+namespace minidump
+{
+
+// RVA - relative virtual address - basically offset from the beginning of the file
+typedef uint32_t RVA;
+
+#define MINIDUMP_SIGNATURE 0x504d444d // 'PMDM'
+#define MINIDUMP_VERSION 0x0000a793   // 42899
+
+enum MinidumpStreamType
+{
+    MINIDUMP_UNUSED_STREAM = 0,
+    MINIDUMP_RESERVED_STREAM_0 = 1,
+    MINIDUMP_RESERVED_STREAM_1 = 2,
+    MINIDUMP_THREAD_LIST_STREAM = 3,
+    MINIDUMP_MODULE_LIST_STREAM = 4,
+    MINIDUMP_MEMORY_LIST_STREAM = 5,
+    MINIDUMP_EXCEPTION_STREAM = 6,
+    MINIDUMP_SYSTEM_INFO_STREAM = 7,
+    MINIDUMP_THREAD_EX_LIST_STREAM = 8,
+    MINIDUMP_MEMORY_64_LIST_STREAM = 9,
+    MINIDUMP_COMMENT_STREAM_A = 10,
+    MINIDUMP_COMMENT_STREAM_W = 11,
+    MINIDUMP_HANDLE_DATA_STREAM = 12,
+    MINIDUMP_FUNCTION_TABLE_STREAM = 13,
+    MINIDUMP_UNLOADED_MODULE_LIST_STREAM = 14,
+    MINIDUMP_MISC_INFO_STREAM = 15,
+    MINIDUMP_MEMORY_INFO_LIST_STREAM = 16,
+    MINIDUMP_THREAD_INFO_LIST_STREAM = 17,
+    MINIDUMP_HANDLE_OPERATION_LIST_STREAM = 18,
+    MINIDUMP_TOKEN_STREAM = 19,
+    MINIDUMP_JAVASCRIPT_DATA_STREAM = 20,
+    MINIDUMP_SYSTEM_MEMORY_INFO_STREAM = 21,
+    MINIDUMP_PROCESS_VM_COUNTERS_STREAM = 22,
+    MINIDUMP_LAST_RESERVED_STREAM = 0x0000ffff,
+
+    /* Breakpad extension types.  0x4767 = "Gg" */
+    MINIDUMP_BREAKPAD_INFO_STREAM = 0x47670001,
+    MINIDUMP_ASSERTION_INFO_STREAM = 0x47670002,
+    /* These are additional minidump stream values which are specific to
+     * the linux breakpad implementation.   */
+    MINIDUMP_LINUX_CPU_INFO = 0x47670003,    /* /proc/cpuinfo      */
+    MINIDUMP_LINUX_PROC_STATUS = 0x47670004, /* /proc/$x/status    */
+    MINIDUMP_LINUX_LSB_RELEASE = 0x47670005, /* /etc/lsb-release   */
+    MINIDUMP_LINUX_CMD_LINE = 0x47670006,    /* /proc/$x/cmdline   */
+    MINIDUMP_LINUX_ENVIRON = 0x47670007,     /* /proc/$x/environ   */
+    MINIDUMP_LINUX_AUXV = 0x47670008,        /* /proc/$x/auxv      */
+    MINIDUMP_LINUX_MAPS = 0x47670009,        /* /proc/$x/maps      */
+    MINIDUMP_LINUX_DSO_DEBUG = 0x4767000A
+};
+
+// for MinidumpSystemInfo.processor_arch
+enum MinidumpCPUArchitecture
+{
+    MINIDUMP_CPU_ARCHITECTURE_X86 = 0,         /* PROCESSOR_ARCHITECTURE_INTEL */
+    MINIDUMP_CPU_ARCHITECTURE_MIPS = 1,        /* PROCESSOR_ARCHITECTURE_MIPS */
+    MINIDUMP_CPU_ARCHITECTURE_ALPHA = 2,       /* PROCESSOR_ARCHITECTURE_ALPHA */
+    MINIDUMP_CPU_ARCHITECTURE_PPC = 3,         /* PROCESSOR_ARCHITECTURE_PPC */
+    MINIDUMP_CPU_ARCHITECTURE_SHX = 4,         /* PROCESSOR_ARCHITECTURE_SHX (Super-H) */
+    MINIDUMP_CPU_ARCHITECTURE_ARM = 5,         /* PROCESSOR_ARCHITECTURE_ARM */
+    MINIDUMP_CPU_ARCHITECTURE_IA64 = 6,        /* PROCESSOR_ARCHITECTURE_IA64 */
+    MINIDUMP_CPU_ARCHITECTURE_ALPHA64 = 7,     /* PROCESSOR_ARCHITECTURE_ALPHA64 */
+    MINIDUMP_CPU_ARCHITECTURE_MSIL = 8,        /* PROCESSOR_ARCHITECTURE_MSIL
+                                                * (Microsoft Intermediate Language) */
+    MINIDUMP_CPU_ARCHITECTURE_AMD64 = 9,       /* PROCESSOR_ARCHITECTURE_AMD64 */
+    MINIDUMP_CPU_ARCHITECTURE_X86_WIN64 = 10,  /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */
+    MINIDUMP_CPU_ARCHITECTURE_SPARC = 0x8001,  /* Breakpad-defined value for SPARC */
+    MINIDUMP_CPU_ARCHITECTURE_PPC64 = 0x8002,  /* Breakpad-defined value for PPC64 */
+    MINIDUMP_CPU_ARCHITECTURE_ARM64 = 0x8003,  /* Breakpad-defined value for ARM64 */
+    MINIDUMP_CPU_ARCHITECTURE_MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */
+    MINIDUMP_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */
+};
+
+// for MinidumpSystemInfo.platform_id
+enum
+{
+    MINIDUMP_OS_WIN32S = 0,        /* VER_PLATFORM_WIN32s (Windows 3.1) */
+    MINIDUMP_OS_WIN32_WINDOWS = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */
+    MINIDUMP_OS_WIN32_NT = 2,      /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */
+    MINIDUMP_OS_WIN32_CE = 3,      /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH
+                                    * (Windows CE, Windows Mobile, "Handheld") */
+
+    /* The following values are Breakpad-defined. */
+    MINIDUMP_OS_UNIX = 0x8000,     /* Generic Unix-ish */
+    MINIDUMP_OS_MAC_OS_X = 0x8101, /* Mac OS X/Darwin */
+    MINIDUMP_OS_IOS = 0x8102,      /* iOS */
+    MINIDUMP_OS_LINUX = 0x8201,    /* Linux */
+    MINIDUMP_OS_SOLARIS = 0x8202,  /* Solaris */
+    MINIDUMP_OS_ANDROID = 0x8203,  /* Android */
+    MINIDUMP_OS_PS3 = 0x8204,      /* PS3 */
+    MINIDUMP_OS_NACL = 0x8205      /* Native Client (NaCl) */
+} MINIDUMPOSPlatform;
+
+/* For MinidumpCPUInfo.arm_cpu_info.elf_hwcaps.
+ * This matches the Linux kernel definitions from <asm/hwcaps.h> */
+enum MinidumpPCPUInformationARMElfHwCaps
+{
+    MINIDUMP_CPU_ARM_ELF_HWCAP_SWP = (1 << 0),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_HALF = (1 << 1),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_THUMB = (1 << 2),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_26BIT = (1 << 3),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_FAST_MULT = (1 << 4),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_FPA = (1 << 5),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_VFP = (1 << 6),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_EDSP = (1 << 7),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_JAVA = (1 << 8),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_IWMMXT = (1 << 9),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_CRUNCH = (1 << 10),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_THUMBEE = (1 << 11),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_NEON = (1 << 12),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_VFPv3 = (1 << 13),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_VFPv3D16 = (1 << 14),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_TLS = (1 << 15),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_VFPv4 = (1 << 16),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_IDIVA = (1 << 17),
+    MINIDUMP_CPU_ARM_ELF_HWCAP_IDIVT = (1 << 18),
+};
+
+struct MinidumpHeader
+{
+    uint32_t signature;
+    uint32_t version;
+    uint32_t streams_count;
+    RVA stream_directory_rva; // offset of the stream directory
+    uint32_t checksum;
+    uint32_t time_date_stamp; // time_t format
+    uint64_t flags;
+
+    static bool
+    SignatureMatchAndSetByteOrder(DataExtractor &data, lldb::offset_t *offset);
+
+    static llvm::Optional<MinidumpHeader>
+    Parse(const DataExtractor &data, lldb::offset_t *offset);
+};
+const int MINIDUMP_HEADER_SIZE = 3 * 4 + sizeof(RVA) + 2 * 4 + 8;
+static_assert(sizeof(MinidumpHeader) == MINIDUMP_HEADER_SIZE, "sizeof MinidumpHeader is not correct!");
+
+struct MinidumpLocationDescriptor
+{
+    uint32_t data_size;
+    RVA rva;
+};
+const int MINIDUMP_LOCATION_DESCRIPTOR_SIZE = 4 + sizeof(RVA);
+static_assert(sizeof(MinidumpLocationDescriptor) == MINIDUMP_LOCATION_DESCRIPTOR_SIZE,
+              "sizeof MinidumpLocationDescriptor is not correct!");
+
+struct MinidumpMemoryDescriptor
+{
+    uint64_t start_of_memory_range;
+    MinidumpLocationDescriptor memory;
+};
+const int MINIDUMP_MEMORY_DESCRIPTOR_SIZE = 8 + MINIDUMP_LOCATION_DESCRIPTOR_SIZE;
+static_assert(sizeof(MinidumpMemoryDescriptor) == MINIDUMP_MEMORY_DESCRIPTOR_SIZE,
+              "sizeof MinidumpMemoryDescriptor is not correct!");
+
+struct MinidumpDirectory
+{
+    uint32_t stream_type;
+    MinidumpLocationDescriptor location;
+};
+const int MINIDUMP_DIRECTORY_SIZE = 4 + MINIDUMP_LOCATION_DESCRIPTOR_SIZE;
+static_assert(sizeof(MinidumpDirectory) == MINIDUMP_DIRECTORY_SIZE, "sizeof MinidumpDirectory is not correct!");
+
+struct MinidumpThread
+{
+    uint32_t thread_id;
+    uint32_t suspend_count;
+    uint32_t priority_class;
+    uint32_t priority;
+    uint64_t teb;
+    MinidumpMemoryDescriptor stack;
+    MinidumpLocationDescriptor thread_context;
+
+    static llvm::Optional<MinidumpThread>
+    Parse(const DataExtractor &data, lldb::offset_t *offset);
+
+    static llvm::Optional<std::vector<MinidumpThread>>
+    ParseThreadList(const DataExtractor &data, lldb::offset_t *offset);
+};
+const int MINIDUMP_THREAD_SIZE = 4 * 4 + 8 + MINIDUMP_MEMORY_DESCRIPTOR_SIZE + MINIDUMP_LOCATION_DESCRIPTOR_SIZE;
+static_assert(sizeof(MinidumpDirectory) == MINIDUMP_DIRECTORY_SIZE, "sizeof MinidumpDirectory is not correct!");
+
+union MinidumpCPUInfo {
+    struct
+    {
+        uint32_t vendor_id[3];              /* cpuid 0: ebx, edx, ecx */
+        uint32_t version_information;       /* cpuid 1: eax */
+        uint32_t feature_information;       /* cpuid 1: edx */
+        uint32_t amd_extended_cpu_features; /* cpuid 0x80000001, ebx */
+    } x86_cpu_info;
+    struct
+    {
+        uint32_t cpuid;
+        uint32_t elf_hwcaps; /* linux specific, 0 otherwise */
+    } arm_cpu_info;
+    struct
+    {
+        uint64_t processor_features[2];
+    } other_cpu_info;
+};
+const int MINIDUMP_CPU_INFO_SIZE = 6 * 4;
+static_assert(sizeof(MinidumpCPUInfo) == MINIDUMP_CPU_INFO_SIZE, "sizeof MinidumpCPUInfo is not correct!");
+
+struct MinidumpSystemInfo
+{
+    uint16_t processor_arch;
+    uint16_t processor_level;
+    uint16_t processor_revision;
+
+    uint8_t number_of_processors;
+    uint8_t product_type;
+
+    uint32_t major_version;
+    uint32_t minor_version;
+    uint32_t build_number;
+    uint32_t platform_id;
+    RVA csd_version_rva;
+
+    uint16_t suit_mask;
+    uint16_t reserved2;
+
+    MinidumpCPUInfo cpu;
+
+    static llvm::Optional<MinidumpSystemInfo>
+    Parse(const DataExtractor &data, lldb::offset_t *offset);
+};
+const int MINIDUMP_SYSTEM_INFO_SIZE = 3 * 2 + 2 * 1 + 4 * 4 + sizeof(RVA) + 2 * 2 + MINIDUMP_CPU_INFO_SIZE;
+static_assert(sizeof(MinidumpSystemInfo) == MINIDUMP_SYSTEM_INFO_SIZE, "sizeof MinidumpSystemInfo is not correct!");
+
+struct MinidumpMiscInfo
+{
+    uint32_t size;
+    uint32_t flags1;
+    uint32_t process_id;
+    uint32_t process_create_time;
+    uint32_t process_user_time;
+    uint32_t process_kernel_time;
+
+    static llvm::Optional<MinidumpMiscInfo>
+    Parse(const DataExtractor &data, lldb::offset_t *offset);
+};
+const int MINIDUMP_MISC_INFO_SIZE = 6 * 4;
+static_assert(sizeof(MinidumpMiscInfo) == MINIDUMP_MISC_INFO_SIZE, "sizeof MinidumpMiscInfo is not correct!");
+
+} // namespace minidump
+} // namespace lldb_private
+#endif // liblldb_MinidumpTypes_h_
Index: source/Plugins/Process/minidump/MinidumpTypes.cpp
===================================================================
--- /dev/null
+++ source/Plugins/Process/minidump/MinidumpTypes.cpp
@@ -0,0 +1,120 @@
+//===-- MinidumpTypes.cpp ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Log.h"
+
+#include "MinidumpParser.h"
+#include "MinidumpTypes.h"
+
+using namespace lldb_private;
+using namespace minidump;
+
+// MinidumpHeader
+bool
+MinidumpHeader::SignatureMatchAndSetByteOrder(DataExtractor &data, lldb::offset_t *offset)
+{
+    uint32_t signature;
+    // We use the signature also as a byteorder flag
+
+    data.SetByteOrder(lldb::eByteOrderLittle);
+    signature = data.GetU32(offset);
+    if (signature == MINIDUMP_SIGNATURE)
+        return true;
+
+    // the signature might be byte swapped
+    data.SetByteOrder(lldb::eByteOrderBig);
+    *offset -= 4;
+    signature = data.GetU32(offset);
+    if (signature == MINIDUMP_SIGNATURE)
+        return true;
+
+    return false;
+}
+
+llvm::Optional<MinidumpHeader>
+MinidumpHeader::Parse(const DataExtractor &data, lldb::offset_t *offset)
+{
+    MinidumpHeader header;
+    lldb::ByteOrder byteorder = data.GetByteOrder();
+    size_t header_size = sizeof(MinidumpHeader);
+    size_t size = data.ExtractBytes(*offset, header_size, byteorder, &header);
+
+    // The high 16 bits of version field are implementation specific
+    if (size != header_size || (header.version & 0x0000ffff) != MINIDUMP_VERSION)
+        return llvm::None;
+
+    // TODO check for max number of streams ?
+    // TODO more sanity checks ?
+
+    return llvm::Optional<MinidumpHeader>(header);
+}
+
+// MinidumpThread
+llvm::Optional<MinidumpThread>
+MinidumpThread::Parse(const DataExtractor &data, lldb::offset_t *offset)
+{
+    MinidumpThread thread;
+    lldb::ByteOrder byteorder = data.GetByteOrder();
+    size_t thread_size = sizeof(MinidumpThread);
+    size_t size = data.ExtractBytes(*offset, thread_size, byteorder, &thread);
+    if (size != thread_size)
+        return llvm::None;
+
+    *offset += thread_size;
+
+    return llvm::Optional<MinidumpThread>(thread);
+}
+
+llvm::Optional<std::vector<MinidumpThread>>
+MinidumpThread::ParseThreadList(const DataExtractor &data, lldb::offset_t *offset)
+{
+    std::vector<MinidumpThread> thread_list;
+    uint32_t thread_count = data.GetU32(offset);
+    llvm::Optional<MinidumpThread> thread;
+    for (uint32_t i = 0; i < thread_count; ++i)
+    {
+        thread = MinidumpThread::Parse(data, offset);
+        if (thread)
+            thread_list.push_back(MinidumpThread(thread.getValue()));
+    }
+
+    return llvm::Optional<std::vector<MinidumpThread>>(thread_list);
+}
+
+// MinidumpSystemInfo
+llvm::Optional<MinidumpSystemInfo>
+MinidumpSystemInfo::Parse(const DataExtractor &data, lldb::offset_t *offset)
+{
+    MinidumpSystemInfo system_info;
+    lldb::ByteOrder byteorder = data.GetByteOrder();
+    size_t system_info_size = sizeof(MinidumpSystemInfo);
+    size_t size = data.ExtractBytes(*offset, system_info_size, byteorder, &system_info);
+    if (size != system_info_size)
+        return llvm::None;
+
+    *offset += system_info_size;
+
+    return llvm::Optional<MinidumpSystemInfo>(system_info);
+}
+
+// MinidumpMiscInfo
+llvm::Optional<MinidumpMiscInfo>
+MinidumpMiscInfo::Parse(const DataExtractor &data, lldb::offset_t *offset)
+{
+    MinidumpMiscInfo misc_info;
+    lldb::ByteOrder byteorder = data.GetByteOrder();
+    size_t misc_info_size = sizeof(MinidumpMiscInfo);
+    size_t size = data.ExtractBytes(*offset, misc_info_size, byteorder, &misc_info);
+    if (size != misc_info_size)
+        return llvm::None;
+
+    *offset += misc_info_size;
+
+    return llvm::Optional<MinidumpMiscInfo>(misc_info);
+}
Index: source/Plugins/Process/minidump/MinidumpParser.h
===================================================================
--- /dev/null
+++ source/Plugins/Process/minidump/MinidumpParser.h
@@ -0,0 +1,71 @@
+//===-- MinidumpParser.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MinidumpParser_h_
+#define liblldb_MinidumpParser_h_
+
+// C includes
+#include <cstring>
+
+// C++ includes
+#include <unordered_map>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "llvm/ADT/Optional.h"
+
+// Project includes
+#include "MinidumpTypes.h"
+
+namespace lldb_private
+{
+
+namespace minidump
+{
+
+typedef std::unordered_map<int, MinidumpLocationDescriptor> DirectoryMap;
+typedef DirectoryMap::const_iterator DirectoryMapConstIter;
+
+class MinidumpParser
+{
+public:
+    MinidumpParser();
+    MinidumpParser(const DataExtractor &data);
+
+    void
+    SetData(const DataExtractor &data);
+
+    llvm::Optional<DirectoryMapConstIter>
+    GetStream(MinidumpStreamType stream_type);
+
+    bool
+    ParseHeader();
+
+    llvm::Optional<std::vector<MinidumpThread>>
+    GetThreads();
+
+    llvm::Optional<MinidumpSystemInfo>
+    GetSystemInfo();
+
+    ArchSpec
+    GetArchitecture();
+
+    llvm::Optional<MinidumpMiscInfo>
+    GetMiscInfo();
+
+private:
+    DataExtractor m_data;
+    llvm::Optional<MinidumpHeader> m_header;
+    DirectoryMap m_directory_map;
+};
+
+} // namespace minidump
+} // namespace lldb_private
+#endif // liblldb_MinidumpParser_h_
\ No newline at end of file
Index: source/Plugins/Process/minidump/MinidumpParser.cpp
===================================================================
--- /dev/null
+++ source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -0,0 +1,150 @@
+//===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Other libraries and framework includes
+#include "lldb/Core/Log.h"
+
+// Project includes
+#include "MinidumpParser.h"
+
+using namespace lldb_private;
+using namespace minidump;
+
+MinidumpParser::MinidumpParser()
+{
+}
+
+MinidumpParser::MinidumpParser(const DataExtractor &data) : m_data(data)
+{
+}
+
+void
+MinidumpParser::SetData(const DataExtractor &data)
+{
+    m_data = data;
+}
+
+// this method should be called before doing anything else with the parser
+bool
+MinidumpParser::ParseHeader()
+{
+    lldb::ByteOrder byteorder = m_data.GetByteOrder();
+    lldb::offset_t offset = 0;
+    if (!MinidumpHeader::SignatureMatchAndSetByteOrder(m_data, &offset))
+        return false;
+
+    offset = 0;
+    m_header = MinidumpHeader::Parse(m_data, &offset);
+
+    if (!m_header)
+        return false;
+
+    lldb::offset_t directory_list_offset = m_header->stream_directory_rva;
+    MinidumpDirectory directory;
+
+    for (uint32_t i = 0; i < m_header->streams_count; ++i)
+    {
+        m_data.ExtractBytes(directory_list_offset, sizeof(MinidumpDirectory), byteorder, &directory);
+        directory_list_offset += sizeof(MinidumpDirectory);
+        m_directory_map[directory.stream_type] = directory.location;
+    }
+
+    return true;
+}
+
+llvm::Optional<DirectoryMapConstIter>
+MinidumpParser::GetStream(MinidumpStreamType stream_type)
+{
+    DirectoryMapConstIter iter = m_directory_map.find(stream_type);
+    if (iter == m_directory_map.end())
+        return llvm::None;
+
+    return llvm::Optional<DirectoryMapConstIter>(iter);
+}
+
+llvm::Optional<std::vector<MinidumpThread>>
+MinidumpParser::GetThreads()
+{
+    llvm::Optional<std::vector<MinidumpThread>> thread_list;
+    llvm::Optional<DirectoryMapConstIter> iter = GetStream(MINIDUMP_THREAD_LIST_STREAM);
+
+    if (!iter)
+        return thread_list;
+
+    lldb::offset_t offset = (*iter)->second.rva;
+    thread_list = MinidumpThread::ParseThreadList(m_data, &offset);
+
+    return thread_list;
+}
+
+llvm::Optional<MinidumpSystemInfo>
+MinidumpParser::GetSystemInfo()
+{
+    llvm::Optional<MinidumpSystemInfo> system_info;
+    llvm::Optional<DirectoryMapConstIter> iter = GetStream(MINIDUMP_SYSTEM_INFO_STREAM);
+
+    if (!iter)
+        return system_info;
+
+    lldb::offset_t offset = (*iter)->second.rva;
+    system_info = MinidumpSystemInfo::Parse(m_data, &offset);
+
+    return system_info;
+}
+
+ArchSpec
+MinidumpParser::GetArchitecture()
+{
+    ArchSpec arch_spec;
+    arch_spec.GetTriple().setOS(llvm::Triple::OSType::UnknownOS);
+    arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor);
+    arch_spec.GetTriple().setArch(llvm::Triple::ArchType::UnknownArch);
+
+    // TODO should we add the OS type here, or somewhere else ?
+
+    llvm::Optional<MinidumpSystemInfo> system_info = GetSystemInfo();
+
+    if (!system_info)
+        return arch_spec;
+
+    // TODO what to do about big endiand flavors of arm ?
+    // TODO set the arm subarch stuff if the minidump has info about it
+    switch (system_info->processor_arch)
+    {
+        case MINIDUMP_CPU_ARCHITECTURE_X86:
+            arch_spec.GetTriple().setArch(llvm::Triple::ArchType::x86);
+            break;
+        case MINIDUMP_CPU_ARCHITECTURE_AMD64:
+            arch_spec.GetTriple().setArch(llvm::Triple::ArchType::x86_64);
+            break;
+        case MINIDUMP_CPU_ARCHITECTURE_ARM:
+            arch_spec.GetTriple().setArch(llvm::Triple::ArchType::arm);
+            break;
+        case MINIDUMP_CPU_ARCHITECTURE_ARM64:
+            arch_spec.GetTriple().setArch(llvm::Triple::ArchType::aarch64);
+            break;
+    }
+
+    return arch_spec;
+}
+
+llvm::Optional<MinidumpMiscInfo>
+MinidumpParser::GetMiscInfo()
+{
+    llvm::Optional<MinidumpMiscInfo> misc_info;
+    llvm::Optional<DirectoryMapConstIter> iter = GetStream(MINIDUMP_MISC_INFO_STREAM);
+
+    if (!iter)
+        return misc_info;
+
+    lldb::offset_t offset = (*iter)->second.rva;
+    misc_info = MinidumpMiscInfo::Parse(m_data, &offset);
+
+    return misc_info;
+}
Index: source/Plugins/Process/minidump/CMakeLists.txt
===================================================================
--- /dev/null
+++ source/Plugins/Process/minidump/CMakeLists.txt
@@ -0,0 +1,8 @@
+include_directories(../Utility)
+
+add_lldb_library(lldbPluginProcessMinidump
+  MinidumpTypes.cpp
+  MinidumpParser.cpp
+  #ProcessMinidump.cpp
+  #ThreadMinidump.cpp
+  )
Index: source/Plugins/Process/CMakeLists.txt
===================================================================
--- source/Plugins/Process/CMakeLists.txt
+++ source/Plugins/Process/CMakeLists.txt
@@ -17,3 +17,4 @@
 add_subdirectory(Utility)
 add_subdirectory(mach-core)
 add_subdirectory(elf-core)
+add_subdirectory(minidump)
Index: cmake/LLDBDependencies.cmake
===================================================================
--- cmake/LLDBDependencies.cmake
+++ cmake/LLDBDependencies.cmake
@@ -80,6 +80,7 @@
   lldbPluginInstrumentationRuntimeThreadSanitizer
   lldbPluginSystemRuntimeMacOSX
   lldbPluginProcessElfCore
+  lldbPluginProcessMinidump
   lldbPluginJITLoaderGDB
   lldbPluginExpressionParserClang
   lldbPluginExpressionParserGo
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to