1 //===-- MinidumpParser.cpp ---------------------------------------*- C++ 2 //-*-===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is distributed under the University of Illinois Open Source 7 // License. See LICENSE.TXT for details. 8 // 9 //===----------------------------------------------------------------------===// 10 11 // Project includes 12 #include "MinidumpParser.h" 13 14 // Other libraries and framework includes 15 // C includes 16 // C++ includes 17 18 using namespace lldb_private; 19 using namespace minidump; 20 21 llvm::Optional<MinidumpParser> 22 MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) { 23 if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader)) { 24 return llvm::None; 25 } 26 27 llvm::ArrayRef<uint8_t> header_data(data_buf_sp->GetBytes(), 28 sizeof(MinidumpHeader)); 29 const MinidumpHeader *header = MinidumpHeader::Parse(header_data); 30 31 if (header == nullptr) { 32 return llvm::None; 33 } 34 35 lldb::offset_t directory_list_offset = header->stream_directory_rva; 36 // check if there is enough data for the parsing of the directory list 37 if ((directory_list_offset + 38 sizeof(MinidumpDirectory) * header->streams_count) > 39 data_buf_sp->GetByteSize()) { 40 return llvm::None; 41 } 42 43 const MinidumpDirectory *directory = nullptr; 44 Error error; 45 llvm::ArrayRef<uint8_t> directory_data( 46 data_buf_sp->GetBytes() + directory_list_offset, 47 sizeof(MinidumpDirectory) * header->streams_count); 48 llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map; 49 50 for (uint32_t i = 0; i < header->streams_count; ++i) { 51 error = consumeObject(directory_data, directory); 52 if (error.Fail()) { 53 return llvm::None; 54 } 55 directory_map[static_cast<const uint32_t>(directory->stream_type)] = 56 directory->location; 57 } 58 59 MinidumpParser parser(data_buf_sp, header, directory_map); 60 return llvm::Optional<MinidumpParser>(parser); 61 } 62 63 MinidumpParser::MinidumpParser( 64 const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header, 65 const llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &directory_map) 66 : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) { 67 } 68 69 lldb::offset_t MinidumpParser::GetByteSize() { 70 return m_data_sp->GetByteSize(); 71 } 72 73 llvm::Optional<llvm::ArrayRef<uint8_t>> 74 MinidumpParser::GetStream(MinidumpStreamType stream_type) { 75 auto iter = m_directory_map.find(static_cast<uint32_t>(stream_type)); 76 if (iter == m_directory_map.end()) 77 return llvm::None; 78 79 // check if there is enough data 80 if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize()) 81 return llvm::None; 82 83 llvm::ArrayRef<uint8_t> arr_ref(m_data_sp->GetBytes() + iter->second.rva, 84 iter->second.data_size); 85 return llvm::Optional<llvm::ArrayRef<uint8_t>>(arr_ref); 86 } 87 88 llvm::Optional<std::vector<const MinidumpThread *>> 89 MinidumpParser::GetThreads() { 90 llvm::Optional<llvm::ArrayRef<uint8_t>> data = 91 GetStream(MinidumpStreamType::ThreadList); 92 93 if (!data) 94 return llvm::None; 95 96 return MinidumpThread::ParseThreadList(data.getValue()); 97 } 98 99 const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() { 100 llvm::Optional<llvm::ArrayRef<uint8_t>> data = 101 GetStream(MinidumpStreamType::SystemInfo); 102 103 if (!data) 104 return nullptr; 105 106 return MinidumpSystemInfo::Parse(data.getValue()); 107 } 108 109 ArchSpec MinidumpParser::GetArchitecture() { 110 ArchSpec arch_spec; 111 arch_spec.GetTriple().setOS(llvm::Triple::OSType::UnknownOS); 112 arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor); 113 arch_spec.GetTriple().setArch(llvm::Triple::ArchType::UnknownArch); 114 115 // TODO should we add the OS type here, or somewhere else ? 116 117 const MinidumpSystemInfo *system_info = GetSystemInfo(); 118 119 if (!system_info) 120 return arch_spec; 121 122 // TODO what to do about big endiand flavors of arm ? 123 // TODO set the arm subarch stuff if the minidump has info about it 124 125 const MinidumpCPUArchitecture arch = 126 static_cast<const MinidumpCPUArchitecture>( 127 static_cast<const uint32_t>(system_info->processor_arch)); 128 switch (arch) { 129 case MinidumpCPUArchitecture::X86: 130 arch_spec.GetTriple().setArch(llvm::Triple::ArchType::x86); 131 break; 132 case MinidumpCPUArchitecture::AMD64: 133 arch_spec.GetTriple().setArch(llvm::Triple::ArchType::x86_64); 134 break; 135 case MinidumpCPUArchitecture::ARM: 136 arch_spec.GetTriple().setArch(llvm::Triple::ArchType::arm); 137 break; 138 case MinidumpCPUArchitecture::ARM64: 139 arch_spec.GetTriple().setArch(llvm::Triple::ArchType::aarch64); 140 break; 141 } 142 143 return arch_spec; 144 } 145 146 const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() { 147 llvm::Optional<llvm::ArrayRef<uint8_t>> data = 148 GetStream(MinidumpStreamType::MiscInfo); 149 150 if (!data) 151 return nullptr; 152 153 return MinidumpMiscInfo::Parse(data.getValue()); 154 } 155