|  | //===-- 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()); | 
|  | } |