Minidump parsing
Summary:
This is a 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.
Reviewers: labath, amccarth
Subscribers: tberghammer, danalbert, srhines, lldb-commits, dschuff
Differential Revision: https://reviews.llvm.org/D23545
llvm-svn: 280356
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
new file mode 100644
index 0000000..18b8a3f
--- /dev/null
+++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -0,0 +1,160 @@
+//===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Project includes
+#include "MinidumpParser.h"
+
+// Other libraries and framework includes
+// C includes
+// C++ includes
+
+using namespace lldb_private;
+using namespace minidump;
+
+llvm::Optional<MinidumpParser>
+MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp)
+{
+ if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader))
+ {
+ return llvm::None;
+ }
+
+ llvm::ArrayRef<uint8_t> header_data(data_buf_sp->GetBytes(), sizeof(MinidumpHeader));
+ const MinidumpHeader *header = MinidumpHeader::Parse(header_data);
+
+ if (header == nullptr)
+ {
+ return llvm::None;
+ }
+
+ lldb::offset_t directory_list_offset = header->stream_directory_rva;
+ // check if there is enough data for the parsing of the directory list
+ if ((directory_list_offset + sizeof(MinidumpDirectory) * header->streams_count) > data_buf_sp->GetByteSize())
+ {
+ return llvm::None;
+ }
+
+ const MinidumpDirectory *directory = nullptr;
+ Error error;
+ llvm::ArrayRef<uint8_t> directory_data(data_buf_sp->GetBytes() + directory_list_offset,
+ sizeof(MinidumpDirectory) * header->streams_count);
+ llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map;
+
+ for (uint32_t i = 0; i < header->streams_count; ++i)
+ {
+ error = consumeObject(directory_data, directory);
+ if (error.Fail())
+ {
+ return llvm::None;
+ }
+ directory_map[static_cast<const uint32_t>(directory->stream_type)] = directory->location;
+ }
+
+ MinidumpParser parser(data_buf_sp, header, directory_map);
+ return llvm::Optional<MinidumpParser>(parser);
+}
+
+MinidumpParser::MinidumpParser(const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header,
+ const llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &directory_map)
+ : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map)
+{
+}
+
+lldb::offset_t
+MinidumpParser::GetByteSize()
+{
+ return m_data_sp->GetByteSize();
+}
+
+llvm::Optional<llvm::ArrayRef<uint8_t>>
+MinidumpParser::GetStream(MinidumpStreamType stream_type)
+{
+ auto iter = m_directory_map.find(static_cast<uint32_t>(stream_type));
+ if (iter == m_directory_map.end())
+ return llvm::None;
+
+ // check if there is enough data
+ if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize())
+ return llvm::None;
+
+ llvm::ArrayRef<uint8_t> arr_ref(m_data_sp->GetBytes() + iter->second.rva, iter->second.data_size);
+ return llvm::Optional<llvm::ArrayRef<uint8_t>>(arr_ref);
+}
+
+llvm::Optional<std::vector<const MinidumpThread *>>
+MinidumpParser::GetThreads()
+{
+ llvm::Optional<llvm::ArrayRef<uint8_t>> data = GetStream(MinidumpStreamType::ThreadList);
+
+ if (!data)
+ return llvm::None;
+
+ return MinidumpThread::ParseThreadList(data.getValue());
+}
+
+const MinidumpSystemInfo *
+MinidumpParser::GetSystemInfo()
+{
+ llvm::Optional<llvm::ArrayRef<uint8_t>> data = GetStream(MinidumpStreamType::SystemInfo);
+
+ if (!data)
+ return nullptr;
+
+ return MinidumpSystemInfo::Parse(data.getValue());
+}
+
+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 ?
+
+ const 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
+
+ const MinidumpCPUArchitecture arch =
+ static_cast<const MinidumpCPUArchitecture>(static_cast<const uint32_t>(system_info->processor_arch));
+ switch (arch)
+ {
+ case MinidumpCPUArchitecture::X86:
+ arch_spec.GetTriple().setArch(llvm::Triple::ArchType::x86);
+ break;
+ case MinidumpCPUArchitecture::AMD64:
+ arch_spec.GetTriple().setArch(llvm::Triple::ArchType::x86_64);
+ break;
+ case MinidumpCPUArchitecture::ARM:
+ arch_spec.GetTriple().setArch(llvm::Triple::ArchType::arm);
+ break;
+ case MinidumpCPUArchitecture::ARM64:
+ arch_spec.GetTriple().setArch(llvm::Triple::ArchType::aarch64);
+ break;
+ }
+
+ return arch_spec;
+}
+
+const MinidumpMiscInfo *
+MinidumpParser::GetMiscInfo()
+{
+ llvm::Optional<llvm::ArrayRef<uint8_t>> data = GetStream(MinidumpStreamType::MiscInfo);
+
+ if (!data)
+ return nullptr;
+
+ return MinidumpMiscInfo::Parse(data.getValue());
+}