summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/minidump/MinidumpParser.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:51:52 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:51:52 +0000
commit5f29bb8a675e8f96452b632e7129113f7dec850e (patch)
tree3d3f2a0d3ad10872a4dcaba8ec8d1d20c87ab147 /source/Plugins/Process/minidump/MinidumpParser.cpp
parent88c643b6fec27eec436c8d138fee6346e92337d6 (diff)
Notes
Diffstat (limited to 'source/Plugins/Process/minidump/MinidumpParser.cpp')
-rw-r--r--source/Plugins/Process/minidump/MinidumpParser.cpp435
1 files changed, 167 insertions, 268 deletions
diff --git a/source/Plugins/Process/minidump/MinidumpParser.cpp b/source/Plugins/Process/minidump/MinidumpParser.cpp
index d4053ca70b94..ff015aa54b76 100644
--- a/source/Plugins/Process/minidump/MinidumpParser.cpp
+++ b/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -1,9 +1,8 @@
//===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,8 +10,9 @@
#include "NtStructures.h"
#include "RegisterContextMinidump_x86_32.h"
-#include "lldb/Utility/LLDBAssert.h"
#include "Plugins/Process/Utility/LinuxProcMaps.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
// C includes
// C++ includes
@@ -24,47 +24,33 @@
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;
- }
- return MinidumpParser(data_buf_sp);
+llvm::Expected<MinidumpParser>
+MinidumpParser::Create(const lldb::DataBufferSP &data_sp) {
+ auto ExpectedFile = llvm::object::MinidumpFile::create(
+ llvm::MemoryBufferRef(toStringRef(data_sp->GetData()), "minidump"));
+ if (!ExpectedFile)
+ return ExpectedFile.takeError();
+
+ return MinidumpParser(data_sp, std::move(*ExpectedFile));
}
-MinidumpParser::MinidumpParser(const lldb::DataBufferSP &data_buf_sp)
- : m_data_sp(data_buf_sp) {}
+MinidumpParser::MinidumpParser(lldb::DataBufferSP data_sp,
+ std::unique_ptr<llvm::object::MinidumpFile> file)
+ : m_data_sp(std::move(data_sp)), m_file(std::move(file)) {}
llvm::ArrayRef<uint8_t> MinidumpParser::GetData() {
return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(),
m_data_sp->GetByteSize());
}
-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 {};
-
- // check if there is enough data
- if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize())
- return {};
-
- return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva,
- iter->second.data_size);
-}
-
-llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) {
- auto arr_ref = m_data_sp->GetData();
- if (rva > arr_ref.size())
- return llvm::None;
- arr_ref = arr_ref.drop_front(rva);
- return parseMinidumpString(arr_ref);
+llvm::ArrayRef<uint8_t> MinidumpParser::GetStream(StreamType stream_type) {
+ return m_file->getRawStream(stream_type)
+ .getValueOr(llvm::ArrayRef<uint8_t>());
}
-UUID MinidumpParser::GetModuleUUID(const MinidumpModule *module) {
+UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) {
auto cv_record =
- GetData().slice(module->CV_record.rva, module->CV_record.data_size);
+ GetData().slice(module->CvRecord.RVA, module->CvRecord.DataSize);
// Read the CV record signature
const llvm::support::ulittle32_t *signature = nullptr;
@@ -73,60 +59,68 @@ UUID MinidumpParser::GetModuleUUID(const MinidumpModule *module) {
return UUID();
const CvSignature cv_signature =
- static_cast<CvSignature>(static_cast<const uint32_t>(*signature));
+ static_cast<CvSignature>(static_cast<uint32_t>(*signature));
if (cv_signature == CvSignature::Pdb70) {
- // PDB70 record
const CvRecordPdb70 *pdb70_uuid = nullptr;
Status error = consumeObject(cv_record, pdb70_uuid);
- if (!error.Fail()) {
- auto arch = GetArchitecture();
- // For Apple targets we only need a 16 byte UUID so that we can match
- // the UUID in the Module to actual UUIDs from the built binaries. The
- // "Age" field is zero in breakpad minidump files for Apple targets, so
- // we restrict the UUID to the "Uuid" field so we have a UUID we can use
- // to match.
- if (arch.GetTriple().getVendor() == llvm::Triple::Apple)
- return UUID::fromData(pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid));
- else
- return UUID::fromData(pdb70_uuid, sizeof(*pdb70_uuid));
+ if (error.Fail())
+ return UUID();
+
+ CvRecordPdb70 swapped;
+ if (!GetArchitecture().GetTriple().isOSBinFormatELF()) {
+ // LLDB's UUID class treats the data as a sequence of bytes, but breakpad
+ // interprets it as a sequence of little-endian fields, which it converts
+ // to big-endian when converting to text. Swap the bytes to big endian so
+ // that the string representation comes out right.
+ swapped = *pdb70_uuid;
+ llvm::sys::swapByteOrder(swapped.Uuid.Data1);
+ llvm::sys::swapByteOrder(swapped.Uuid.Data2);
+ llvm::sys::swapByteOrder(swapped.Uuid.Data3);
+ llvm::sys::swapByteOrder(swapped.Age);
+ pdb70_uuid = &swapped;
}
+ if (pdb70_uuid->Age != 0)
+ return UUID::fromOptionalData(pdb70_uuid, sizeof(*pdb70_uuid));
+ return UUID::fromOptionalData(&pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid));
} else if (cv_signature == CvSignature::ElfBuildId)
- return UUID::fromData(cv_record);
+ return UUID::fromOptionalData(cv_record);
return UUID();
}
-llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() {
- llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList);
+llvm::ArrayRef<minidump::Thread> MinidumpParser::GetThreads() {
+ auto ExpectedThreads = GetMinidumpFile().getThreadList();
+ if (ExpectedThreads)
+ return *ExpectedThreads;
- if (data.size() == 0)
- return llvm::None;
-
- return MinidumpThread::ParseThreadList(data);
+ LLDB_LOG_ERROR(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD),
+ ExpectedThreads.takeError(),
+ "Failed to read thread list: {0}");
+ return {};
}
llvm::ArrayRef<uint8_t>
-MinidumpParser::GetThreadContext(const MinidumpLocationDescriptor &location) {
- if (location.rva + location.data_size > GetData().size())
+MinidumpParser::GetThreadContext(const LocationDescriptor &location) {
+ if (location.RVA + location.DataSize > GetData().size())
return {};
- return GetData().slice(location.rva, location.data_size);
+ return GetData().slice(location.RVA, location.DataSize);
}
llvm::ArrayRef<uint8_t>
-MinidumpParser::GetThreadContext(const MinidumpThread &td) {
- return GetThreadContext(td.thread_context);
+MinidumpParser::GetThreadContext(const minidump::Thread &td) {
+ return GetThreadContext(td.Context);
}
llvm::ArrayRef<uint8_t>
-MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) {
+MinidumpParser::GetThreadContextWow64(const minidump::Thread &td) {
// On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If
// the minidump was captured with a 64-bit debugger, then the CONTEXT we just
// grabbed from the mini_dump_thread is the one for the 64-bit "native"
// process rather than the 32-bit "guest" process we care about. In this
// case, we can get the 32-bit CONTEXT from the TEB (Thread Environment
// Block) of the 64-bit process.
- auto teb_mem = GetMemory(td.teb, sizeof(TEB64));
+ auto teb_mem = GetMemory(td.EnvironmentBlock, sizeof(TEB64));
if (teb_mem.empty())
return {};
@@ -149,24 +143,19 @@ MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) {
// stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]).
}
-const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
- llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo);
-
- if (data.size() == 0)
- return nullptr;
-
- return MinidumpSystemInfo::Parse(data);
-}
-
ArchSpec MinidumpParser::GetArchitecture() {
if (m_arch.IsValid())
return m_arch;
// Set the architecture in m_arch
- const MinidumpSystemInfo *system_info = GetSystemInfo();
+ llvm::Expected<const SystemInfo &> system_info = m_file->getSystemInfo();
- if (!system_info)
+ if (!system_info) {
+ LLDB_LOG_ERROR(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS),
+ system_info.takeError(),
+ "Failed to read SystemInfo stream: {0}");
return m_arch;
+ }
// TODO what to do about big endiand flavors of arm ?
// TODO set the arm subarch stuff if the minidump has info about it
@@ -174,21 +163,17 @@ ArchSpec MinidumpParser::GetArchitecture() {
llvm::Triple triple;
triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
- const MinidumpCPUArchitecture arch =
- static_cast<const MinidumpCPUArchitecture>(
- static_cast<const uint32_t>(system_info->processor_arch));
-
- switch (arch) {
- case MinidumpCPUArchitecture::X86:
+ switch (system_info->ProcessorArch) {
+ case ProcessorArchitecture::X86:
triple.setArch(llvm::Triple::ArchType::x86);
break;
- case MinidumpCPUArchitecture::AMD64:
+ case ProcessorArchitecture::AMD64:
triple.setArch(llvm::Triple::ArchType::x86_64);
break;
- case MinidumpCPUArchitecture::ARM:
+ case ProcessorArchitecture::ARM:
triple.setArch(llvm::Triple::ArchType::arm);
break;
- case MinidumpCPUArchitecture::ARM64:
+ case ProcessorArchitecture::ARM64:
triple.setArch(llvm::Triple::ArchType::aarch64);
break;
default:
@@ -196,48 +181,49 @@ ArchSpec MinidumpParser::GetArchitecture() {
break;
}
- const MinidumpOSPlatform os = static_cast<const MinidumpOSPlatform>(
- static_cast<const uint32_t>(system_info->platform_id));
-
// TODO add all of the OSes that Minidump/breakpad distinguishes?
- switch (os) {
- case MinidumpOSPlatform::Win32S:
- case MinidumpOSPlatform::Win32Windows:
- case MinidumpOSPlatform::Win32NT:
- case MinidumpOSPlatform::Win32CE:
+ switch (system_info->PlatformId) {
+ case OSPlatform::Win32S:
+ case OSPlatform::Win32Windows:
+ case OSPlatform::Win32NT:
+ case OSPlatform::Win32CE:
triple.setOS(llvm::Triple::OSType::Win32);
break;
- case MinidumpOSPlatform::Linux:
+ case OSPlatform::Linux:
triple.setOS(llvm::Triple::OSType::Linux);
break;
- case MinidumpOSPlatform::MacOSX:
+ case OSPlatform::MacOSX:
triple.setOS(llvm::Triple::OSType::MacOSX);
triple.setVendor(llvm::Triple::Apple);
break;
- case MinidumpOSPlatform::IOS:
+ case OSPlatform::IOS:
triple.setOS(llvm::Triple::OSType::IOS);
triple.setVendor(llvm::Triple::Apple);
break;
- case MinidumpOSPlatform::Android:
+ case OSPlatform::Android:
triple.setOS(llvm::Triple::OSType::Linux);
triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
break;
default: {
triple.setOS(llvm::Triple::OSType::UnknownOS);
- std::string csd_version;
- if (auto s = GetMinidumpString(system_info->csd_version_rva))
- csd_version = *s;
- if (csd_version.find("Linux") != std::string::npos)
- triple.setOS(llvm::Triple::OSType::Linux);
- break;
+ auto ExpectedCSD = m_file->getString(system_info->CSDVersionRVA);
+ if (!ExpectedCSD) {
+ LLDB_LOG_ERROR(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS),
+ ExpectedCSD.takeError(),
+ "Failed to CSD Version string: {0}");
+ } else {
+ if (ExpectedCSD->find("Linux") != std::string::npos)
+ triple.setOS(llvm::Triple::OSType::Linux);
}
+ break;
+ }
}
m_arch.SetTriple(triple);
return m_arch;
}
const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
- llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MiscInfo);
+ llvm::ArrayRef<uint8_t> data = GetStream(StreamType::MiscInfo);
if (data.size() == 0)
return nullptr;
@@ -246,7 +232,7 @@ const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
}
llvm::Optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {
- llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::LinuxProcStatus);
+ llvm::ArrayRef<uint8_t> data = GetStream(StreamType::LinuxProcStatus);
if (data.size() == 0)
return llvm::None;
@@ -268,41 +254,47 @@ llvm::Optional<lldb::pid_t> MinidumpParser::GetPid() {
return llvm::None;
}
-llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() {
- llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ModuleList);
+llvm::ArrayRef<minidump::Module> MinidumpParser::GetModuleList() {
+ auto ExpectedModules = GetMinidumpFile().getModuleList();
+ if (ExpectedModules)
+ return *ExpectedModules;
- if (data.size() == 0)
- return {};
-
- return MinidumpModule::ParseModuleList(data);
+ LLDB_LOG_ERROR(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_MODULES),
+ ExpectedModules.takeError(),
+ "Failed to read module list: {0}");
+ return {};
}
-std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() {
- llvm::ArrayRef<MinidumpModule> modules = GetModuleList();
+std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() {
+ Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_MODULES);
+ auto ExpectedModules = GetMinidumpFile().getModuleList();
+ if (!ExpectedModules) {
+ LLDB_LOG_ERROR(log, ExpectedModules.takeError(),
+ "Failed to read module list: {0}");
+ return {};
+ }
+
// map module_name -> filtered_modules index
typedef llvm::StringMap<size_t> MapType;
MapType module_name_to_filtered_index;
- std::vector<const MinidumpModule *> filtered_modules;
-
- llvm::Optional<std::string> name;
- std::string module_name;
+ std::vector<const minidump::Module *> filtered_modules;
- for (const auto &module : modules) {
- name = GetMinidumpString(module.module_name_rva);
-
- if (!name)
+ for (const auto &module : *ExpectedModules) {
+ auto ExpectedName = m_file->getString(module.ModuleNameRVA);
+ if (!ExpectedName) {
+ LLDB_LOG_ERROR(log, ExpectedName.takeError(),
+ "Failed to get module name: {0}");
continue;
-
- module_name = name.getValue();
-
+ }
+
MapType::iterator iter;
bool inserted;
// See if we have inserted this module aready into filtered_modules. If we
// haven't insert an entry into module_name_to_filtered_index with the
// index where we will insert it if it isn't in the vector already.
std::tie(iter, inserted) = module_name_to_filtered_index.try_emplace(
- module_name, filtered_modules.size());
+ *ExpectedName, filtered_modules.size());
if (inserted) {
// This module has not been seen yet, insert it into filtered_modules at
@@ -314,7 +306,7 @@ std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() {
// times when they are mapped discontiguously, so find the module with
// the lowest "base_of_image" and use that as the filtered module.
auto dup_module = filtered_modules[iter->second];
- if (module.base_of_image < dup_module->base_of_image)
+ if (module.BaseOfImage < dup_module->BaseOfImage)
filtered_modules[iter->second] = &module;
}
}
@@ -322,7 +314,7 @@ std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() {
}
const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() {
- llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::Exception);
+ llvm::ArrayRef<uint8_t> data = GetStream(StreamType::Exception);
if (data.size() == 0)
return nullptr;
@@ -332,30 +324,30 @@ const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() {
llvm::Optional<minidump::Range>
MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
- llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryList);
- llvm::ArrayRef<uint8_t> data64 = GetStream(MinidumpStreamType::Memory64List);
-
- if (data.empty() && data64.empty())
- return llvm::None;
-
- if (!data.empty()) {
- llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list =
- MinidumpMemoryDescriptor::ParseMemoryList(data);
-
- if (memory_list.empty())
- return llvm::None;
-
- for (const auto &memory_desc : memory_list) {
- const MinidumpLocationDescriptor &loc_desc = memory_desc.memory;
- const lldb::addr_t range_start = memory_desc.start_of_memory_range;
- const size_t range_size = loc_desc.data_size;
-
- if (loc_desc.rva + loc_desc.data_size > GetData().size())
+ llvm::ArrayRef<uint8_t> data64 = GetStream(StreamType::Memory64List);
+ Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_MODULES);
+
+ auto ExpectedMemory = GetMinidumpFile().getMemoryList();
+ if (!ExpectedMemory) {
+ LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),
+ "Failed to read memory list: {0}");
+ } else {
+ for (const auto &memory_desc : *ExpectedMemory) {
+ const LocationDescriptor &loc_desc = memory_desc.Memory;
+ const lldb::addr_t range_start = memory_desc.StartOfMemoryRange;
+ const size_t range_size = loc_desc.DataSize;
+
+ if (loc_desc.RVA + loc_desc.DataSize > GetData().size())
return llvm::None;
if (range_start <= addr && addr < range_start + range_size) {
- return minidump::Range(range_start,
- GetData().slice(loc_desc.rva, range_size));
+ auto ExpectedSlice = GetMinidumpFile().getRawData(loc_desc);
+ if (!ExpectedSlice) {
+ LLDB_LOG_ERROR(log, ExpectedSlice.takeError(),
+ "Failed to get memory slice: {0}");
+ return llvm::None;
+ }
+ return minidump::Range(range_start, *ExpectedSlice);
}
}
}
@@ -418,7 +410,7 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
static bool
CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,
std::vector<MemoryRegionInfo> &regions) {
- auto data = parser.GetStream(MinidumpStreamType::LinuxMaps);
+ auto data = parser.GetStream(StreamType::LinuxMaps);
if (data.empty())
return false;
ParseLinuxMapRegions(llvm::toStringRef(data),
@@ -434,7 +426,7 @@ CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,
static bool
CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,
std::vector<MemoryRegionInfo> &regions) {
- auto data = parser.GetStream(MinidumpStreamType::MemoryInfoList);
+ auto data = parser.GetStream(StreamType::MemoryInfoList);
if (data.empty())
return false;
auto mem_info_list = MinidumpMemoryInfo::ParseMemoryInfoList(data);
@@ -459,19 +451,20 @@ CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,
static bool
CreateRegionsCacheFromMemoryList(MinidumpParser &parser,
std::vector<MemoryRegionInfo> &regions) {
- auto data = parser.GetStream(MinidumpStreamType::MemoryList);
- if (data.empty())
- return false;
- auto memory_list = MinidumpMemoryDescriptor::ParseMemoryList(data);
- if (memory_list.empty())
+ Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_MODULES);
+ auto ExpectedMemory = parser.GetMinidumpFile().getMemoryList();
+ if (!ExpectedMemory) {
+ LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),
+ "Failed to read memory list: {0}");
return false;
- regions.reserve(memory_list.size());
- for (const auto &memory_desc : memory_list) {
- if (memory_desc.memory.data_size == 0)
+ }
+ regions.reserve(ExpectedMemory->size());
+ for (const MemoryDescriptor &memory_desc : *ExpectedMemory) {
+ if (memory_desc.Memory.DataSize == 0)
continue;
MemoryRegionInfo region;
- region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);
- region.GetRange().SetByteSize(memory_desc.memory.data_size);
+ region.GetRange().SetRangeBase(memory_desc.StartOfMemoryRange);
+ region.GetRange().SetByteSize(memory_desc.Memory.DataSize);
region.SetReadable(MemoryRegionInfo::eYes);
region.SetMapped(MemoryRegionInfo::eYes);
regions.push_back(region);
@@ -484,7 +477,7 @@ static bool
CreateRegionsCacheFromMemory64List(MinidumpParser &parser,
std::vector<MemoryRegionInfo> &regions) {
llvm::ArrayRef<uint8_t> data =
- parser.GetStream(MinidumpStreamType::Memory64List);
+ parser.GetStream(StreamType::Memory64List);
if (data.empty())
return false;
llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
@@ -564,120 +557,14 @@ const MemoryRegionInfos &MinidumpParser::GetMemoryRegions() {
return m_regions;
}
-Status MinidumpParser::Initialize() {
- Status error;
-
- lldbassert(m_directory_map.empty());
-
- llvm::ArrayRef<uint8_t> header_data(m_data_sp->GetBytes(),
- sizeof(MinidumpHeader));
- const MinidumpHeader *header = MinidumpHeader::Parse(header_data);
- if (header == nullptr) {
- error.SetErrorString("invalid minidump: can't parse the header");
- return error;
- }
-
- // A minidump without at least one stream is clearly ill-formed
- if (header->streams_count == 0) {
- error.SetErrorString("invalid minidump: no streams present");
- return error;
- }
-
- struct FileRange {
- uint32_t offset = 0;
- uint32_t size = 0;
-
- FileRange(uint32_t offset, uint32_t size) : offset(offset), size(size) {}
- uint32_t end() const { return offset + size; }
- };
-
- const uint32_t file_size = m_data_sp->GetByteSize();
-
- // Build a global minidump file map, checking for:
- // - overlapping streams/data structures
- // - truncation (streams pointing past the end of file)
- std::vector<FileRange> minidump_map;
-
- // Add the minidump header to the file map
- if (sizeof(MinidumpHeader) > file_size) {
- error.SetErrorString("invalid minidump: truncated header");
- return error;
- }
- minidump_map.emplace_back( 0, sizeof(MinidumpHeader) );
-
- // Add the directory entries to the file map
- FileRange directory_range(header->stream_directory_rva,
- header->streams_count *
- sizeof(MinidumpDirectory));
- if (directory_range.end() > file_size) {
- error.SetErrorString("invalid minidump: truncated streams directory");
- return error;
- }
- minidump_map.push_back(directory_range);
-
- // Parse stream directory entries
- llvm::ArrayRef<uint8_t> directory_data(
- m_data_sp->GetBytes() + directory_range.offset, directory_range.size);
- for (uint32_t i = 0; i < header->streams_count; ++i) {
- const MinidumpDirectory *directory_entry = nullptr;
- error = consumeObject(directory_data, directory_entry);
- if (error.Fail())
- return error;
- if (directory_entry->stream_type == 0) {
- // Ignore dummy streams (technically ill-formed, but a number of
- // existing minidumps seem to contain such streams)
- if (directory_entry->location.data_size == 0)
- continue;
- error.SetErrorString("invalid minidump: bad stream type");
- return error;
- }
- // Update the streams map, checking for duplicate stream types
- if (!m_directory_map
- .insert({directory_entry->stream_type, directory_entry->location})
- .second) {
- error.SetErrorString("invalid minidump: duplicate stream type");
- return error;
- }
- // Ignore the zero-length streams for layout checks
- if (directory_entry->location.data_size != 0) {
- minidump_map.emplace_back(directory_entry->location.rva,
- directory_entry->location.data_size);
- }
- }
-
- // Sort the file map ranges by start offset
- llvm::sort(minidump_map.begin(), minidump_map.end(),
- [](const FileRange &a, const FileRange &b) {
- return a.offset < b.offset;
- });
-
- // Check for overlapping streams/data structures
- for (size_t i = 1; i < minidump_map.size(); ++i) {
- const auto &prev_range = minidump_map[i - 1];
- if (prev_range.end() > minidump_map[i].offset) {
- error.SetErrorString("invalid minidump: overlapping streams");
- return error;
- }
- }
-
- // Check for streams past the end of file
- const auto &last_range = minidump_map.back();
- if (last_range.end() > file_size) {
- error.SetErrorString("invalid minidump: truncated stream");
- return error;
- }
-
- return error;
-}
-
-#define ENUM_TO_CSTR(ST) case (uint32_t)MinidumpStreamType::ST: return #ST
+#define ENUM_TO_CSTR(ST) \
+ case StreamType::ST: \
+ return #ST
llvm::StringRef
-MinidumpParser::GetStreamTypeAsString(uint32_t stream_type) {
+MinidumpParser::GetStreamTypeAsString(StreamType stream_type) {
switch (stream_type) {
ENUM_TO_CSTR(Unused);
- ENUM_TO_CSTR(Reserved0);
- ENUM_TO_CSTR(Reserved1);
ENUM_TO_CSTR(ThreadList);
ENUM_TO_CSTR(ModuleList);
ENUM_TO_CSTR(MemoryList);
@@ -698,6 +585,7 @@ MinidumpParser::GetStreamTypeAsString(uint32_t stream_type) {
ENUM_TO_CSTR(JavascriptData);
ENUM_TO_CSTR(SystemMemoryInfo);
ENUM_TO_CSTR(ProcessVMCounters);
+ ENUM_TO_CSTR(LastReserved);
ENUM_TO_CSTR(BreakpadInfo);
ENUM_TO_CSTR(AssertionInfo);
ENUM_TO_CSTR(LinuxCPUInfo);
@@ -711,6 +599,17 @@ MinidumpParser::GetStreamTypeAsString(uint32_t stream_type) {
ENUM_TO_CSTR(LinuxProcStat);
ENUM_TO_CSTR(LinuxProcUptime);
ENUM_TO_CSTR(LinuxProcFD);
+ ENUM_TO_CSTR(FacebookAppCustomData);
+ ENUM_TO_CSTR(FacebookBuildID);
+ ENUM_TO_CSTR(FacebookAppVersionName);
+ ENUM_TO_CSTR(FacebookJavaStack);
+ ENUM_TO_CSTR(FacebookDalvikInfo);
+ ENUM_TO_CSTR(FacebookUnwindSymbols);
+ ENUM_TO_CSTR(FacebookDumpErrorLog);
+ ENUM_TO_CSTR(FacebookAppStateLog);
+ ENUM_TO_CSTR(FacebookAbortReason);
+ ENUM_TO_CSTR(FacebookThreadName);
+ ENUM_TO_CSTR(FacebookLogcat);
}
return "unknown stream type";
}