1 //===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // Project includes 11 #include "MinidumpParser.h" 12 13 // Other libraries and framework includes 14 // C includes 15 // C++ includes 16 17 using namespace lldb_private; 18 using namespace minidump; 19 20 llvm::Optional<MinidumpParser> 21 MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) { 22 if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader)) { 23 return llvm::None; 24 } 25 26 llvm::ArrayRef<uint8_t> header_data(data_buf_sp->GetBytes(), 27 sizeof(MinidumpHeader)); 28 const MinidumpHeader *header = MinidumpHeader::Parse(header_data); 29 30 if (header == nullptr) { 31 return llvm::None; 32 } 33 34 lldb::offset_t directory_list_offset = header->stream_directory_rva; 35 // check if there is enough data for the parsing of the directory list 36 if ((directory_list_offset + 37 sizeof(MinidumpDirectory) * header->streams_count) > 38 data_buf_sp->GetByteSize()) { 39 return llvm::None; 40 } 41 42 const MinidumpDirectory *directory = nullptr; 43 Error error; 44 llvm::ArrayRef<uint8_t> directory_data( 45 data_buf_sp->GetBytes() + directory_list_offset, 46 sizeof(MinidumpDirectory) * header->streams_count); 47 llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map; 48 49 for (uint32_t i = 0; i < header->streams_count; ++i) { 50 error = consumeObject(directory_data, directory); 51 if (error.Fail()) { 52 return llvm::None; 53 } 54 directory_map[static_cast<const uint32_t>(directory->stream_type)] = 55 directory->location; 56 } 57 58 return MinidumpParser(data_buf_sp, header, std::move(directory_map)); 59 } 60 61 MinidumpParser::MinidumpParser( 62 const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header, 63 llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map) 64 : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) { 65 } 66 67 llvm::ArrayRef<uint8_t> MinidumpParser::GetData() { 68 return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(), 69 m_data_sp->GetByteSize()); 70 } 71 72 llvm::ArrayRef<uint8_t> 73 MinidumpParser::GetStream(MinidumpStreamType stream_type) { 74 auto iter = m_directory_map.find(static_cast<uint32_t>(stream_type)); 75 if (iter == m_directory_map.end()) 76 return {}; 77 78 // check if there is enough data 79 if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize()) 80 return {}; 81 82 return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva, 83 iter->second.data_size); 84 } 85 86 llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) { 87 auto arr_ref = m_data_sp->GetData(); 88 if (rva > arr_ref.size()) 89 return llvm::None; 90 arr_ref = arr_ref.drop_front(rva); 91 return parseMinidumpString(arr_ref); 92 } 93 94 llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() { 95 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList); 96 97 if (data.size() == 0) 98 return llvm::None; 99 100 return MinidumpThread::ParseThreadList(data); 101 } 102 103 const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() { 104 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo); 105 106 if (data.size() == 0) 107 return nullptr; 108 109 return MinidumpSystemInfo::Parse(data); 110 } 111 112 ArchSpec MinidumpParser::GetArchitecture() { 113 ArchSpec arch_spec; 114 const MinidumpSystemInfo *system_info = GetSystemInfo(); 115 116 if (!system_info) 117 return arch_spec; 118 119 // TODO what to do about big endiand flavors of arm ? 120 // TODO set the arm subarch stuff if the minidump has info about it 121 122 llvm::Triple triple; 123 triple.setVendor(llvm::Triple::VendorType::UnknownVendor); 124 125 const MinidumpCPUArchitecture arch = 126 static_cast<const MinidumpCPUArchitecture>( 127 static_cast<const uint32_t>(system_info->processor_arch)); 128 129 switch (arch) { 130 case MinidumpCPUArchitecture::X86: 131 triple.setArch(llvm::Triple::ArchType::x86); 132 break; 133 case MinidumpCPUArchitecture::AMD64: 134 triple.setArch(llvm::Triple::ArchType::x86_64); 135 break; 136 case MinidumpCPUArchitecture::ARM: 137 triple.setArch(llvm::Triple::ArchType::arm); 138 break; 139 case MinidumpCPUArchitecture::ARM64: 140 triple.setArch(llvm::Triple::ArchType::aarch64); 141 break; 142 default: 143 triple.setArch(llvm::Triple::ArchType::UnknownArch); 144 break; 145 } 146 147 const MinidumpOSPlatform os = static_cast<const MinidumpOSPlatform>( 148 static_cast<const uint32_t>(system_info->platform_id)); 149 150 // TODO add all of the OSes that Minidump/breakpad distinguishes? 151 switch (os) { 152 case MinidumpOSPlatform::Win32S: 153 case MinidumpOSPlatform::Win32Windows: 154 case MinidumpOSPlatform::Win32NT: 155 case MinidumpOSPlatform::Win32CE: 156 triple.setOS(llvm::Triple::OSType::Win32); 157 break; 158 case MinidumpOSPlatform::Linux: 159 triple.setOS(llvm::Triple::OSType::Linux); 160 break; 161 case MinidumpOSPlatform::MacOSX: 162 triple.setOS(llvm::Triple::OSType::MacOSX); 163 break; 164 case MinidumpOSPlatform::Android: 165 triple.setOS(llvm::Triple::OSType::Linux); 166 triple.setEnvironment(llvm::Triple::EnvironmentType::Android); 167 break; 168 default: 169 triple.setOS(llvm::Triple::OSType::UnknownOS); 170 break; 171 } 172 173 arch_spec.SetTriple(triple); 174 175 return arch_spec; 176 } 177 178 const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() { 179 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MiscInfo); 180 181 if (data.size() == 0) 182 return nullptr; 183 184 return MinidumpMiscInfo::Parse(data); 185 } 186 187 llvm::Optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() { 188 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::LinuxProcStatus); 189 190 if (data.size() == 0) 191 return llvm::None; 192 193 return LinuxProcStatus::Parse(data); 194 } 195 196 llvm::Optional<lldb::pid_t> MinidumpParser::GetPid() { 197 const MinidumpMiscInfo *misc_info = GetMiscInfo(); 198 if (misc_info != nullptr) { 199 return misc_info->GetPid(); 200 } 201 202 llvm::Optional<LinuxProcStatus> proc_status = GetLinuxProcStatus(); 203 if (proc_status.hasValue()) { 204 return proc_status->GetPid(); 205 } 206 207 return llvm::None; 208 } 209 210 llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() { 211 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ModuleList); 212 213 if (data.size() == 0) 214 return {}; 215 216 return MinidumpModule::ParseModuleList(data); 217 } 218 219 const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() { 220 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::Exception); 221 222 if (data.size() == 0) 223 return nullptr; 224 225 return MinidumpExceptionStream::Parse(data); 226 } 227