//===-- 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::Create(const lldb::DataBufferSP &data_buf_sp) { if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader)) { return llvm::None; } llvm::ArrayRef 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 directory_data( data_buf_sp->GetBytes() + directory_list_offset, sizeof(MinidumpDirectory) * header->streams_count); llvm::DenseMap 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(directory->stream_type)] = directory->location; } MinidumpParser parser(data_buf_sp, header, directory_map); return llvm::Optional(parser); } MinidumpParser::MinidumpParser( const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header, const llvm::DenseMap &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> MinidumpParser::GetStream(MinidumpStreamType stream_type) { auto iter = m_directory_map.find(static_cast(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 arr_ref(m_data_sp->GetBytes() + iter->second.rva, iter->second.data_size); return llvm::Optional>(arr_ref); } llvm::Optional> MinidumpParser::GetThreads() { llvm::Optional> data = GetStream(MinidumpStreamType::ThreadList); if (!data) return llvm::None; return MinidumpThread::ParseThreadList(data.getValue()); } const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() { llvm::Optional> 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( static_cast(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> data = GetStream(MinidumpStreamType::MiscInfo); if (!data) return nullptr; return MinidumpMiscInfo::Parse(data.getValue()); }