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