714 lines · cpp
1//===-- MinidumpParser.cpp ------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "MinidumpParser.h"10#include "NtStructures.h"11#include "RegisterContextMinidump_x86_32.h"12 13#include "Plugins/Process/Utility/LinuxProcMaps.h"14#include "lldb/Utility/LLDBAssert.h"15#include "lldb/Utility/LLDBLog.h"16#include "lldb/Utility/Log.h"17 18// C includes19// C++ includes20#include <algorithm>21#include <map>22#include <optional>23#include <utility>24#include <vector>25 26using namespace lldb_private;27using namespace minidump;28 29llvm::Expected<MinidumpParser>30MinidumpParser::Create(const lldb::DataBufferSP &data_sp) {31 auto ExpectedFile = llvm::object::MinidumpFile::create(32 llvm::MemoryBufferRef(toStringRef(data_sp->GetData()), "minidump"));33 if (!ExpectedFile)34 return ExpectedFile.takeError();35 36 return MinidumpParser(data_sp, std::move(*ExpectedFile));37}38 39MinidumpParser::MinidumpParser(lldb::DataBufferSP data_sp,40 std::unique_ptr<llvm::object::MinidumpFile> file)41 : m_data_sp(std::move(data_sp)), m_file(std::move(file)) {}42 43llvm::ArrayRef<uint8_t> MinidumpParser::GetData() {44 return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(),45 m_data_sp->GetByteSize());46}47 48llvm::ArrayRef<uint8_t> MinidumpParser::GetStream(StreamType stream_type) {49 return m_file->getRawStream(stream_type).value_or(llvm::ArrayRef<uint8_t>());50}51 52std::optional<llvm::ArrayRef<uint8_t>>53MinidumpParser::GetRawStream(StreamType stream_type) {54 return m_file->getRawStream(stream_type);55}56 57UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) {58 auto cv_record =59 GetData().slice(module->CvRecord.RVA, module->CvRecord.DataSize);60 61 // Read the CV record signature62 const llvm::support::ulittle32_t *signature = nullptr;63 Status error = consumeObject(cv_record, signature);64 if (error.Fail())65 return UUID();66 67 const CvSignature cv_signature =68 static_cast<CvSignature>(static_cast<uint32_t>(*signature));69 70 if (cv_signature == CvSignature::Pdb70) {71 const UUID::CvRecordPdb70 *pdb70_uuid = nullptr;72 Status error = consumeObject(cv_record, pdb70_uuid);73 if (error.Fail())74 return UUID();75 if (GetArchitecture().GetTriple().isOSBinFormatELF()) {76 if (pdb70_uuid->Age != 0)77 return UUID(pdb70_uuid, sizeof(*pdb70_uuid));78 return UUID(&pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid));79 }80 return UUID(*pdb70_uuid);81 } else if (cv_signature == CvSignature::ElfBuildId)82 return UUID(cv_record);83 84 return UUID();85}86 87llvm::ArrayRef<minidump::Thread> MinidumpParser::GetThreads() {88 auto ExpectedThreads = GetMinidumpFile().getThreadList();89 if (ExpectedThreads)90 return *ExpectedThreads;91 92 LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), ExpectedThreads.takeError(),93 "Failed to read thread list: {0}");94 return {};95}96 97llvm::ArrayRef<uint8_t>98MinidumpParser::GetThreadContext(const LocationDescriptor &location) {99 if (location.RVA + location.DataSize > GetData().size())100 return {};101 return GetData().slice(location.RVA, location.DataSize);102}103 104llvm::ArrayRef<uint8_t>105MinidumpParser::GetThreadContext(const minidump::Thread &td) {106 return GetThreadContext(td.Context);107}108 109llvm::ArrayRef<uint8_t>110MinidumpParser::GetThreadContextWow64(const minidump::Thread &td) {111 Log *log = GetLog(LLDBLog::Process);112 // On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If113 // the minidump was captured with a 64-bit debugger, then the CONTEXT we just114 // grabbed from the mini_dump_thread is the one for the 64-bit "native"115 // process rather than the 32-bit "guest" process we care about. In this116 // case, we can get the 32-bit CONTEXT from the TEB (Thread Environment117 // Block) of the 64-bit process.118 auto teb_mem_maybe = GetMemory(td.EnvironmentBlock, sizeof(TEB64));119 if (!teb_mem_maybe) {120 LLDB_LOG_ERROR(log, teb_mem_maybe.takeError(),121 "Failed to read Thread Environment Block: {0}");122 return {};123 }124 125 auto teb_mem = *teb_mem_maybe;126 if (teb_mem.empty())127 return {};128 129 const TEB64 *wow64teb;130 Status error = consumeObject(teb_mem, wow64teb);131 if (error.Fail())132 return {};133 134 // Slot 1 of the thread-local storage in the 64-bit TEB points to a structure135 // that includes the 32-bit CONTEXT (after a ULONG). See:136 // https://msdn.microsoft.com/en-us/library/ms681670.aspx137 auto context_maybe =138 GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32));139 if (!context_maybe) {140 LLDB_LOG_ERROR(log, context_maybe.takeError(),141 "Failed to read WOW Thread Context: {0}");142 return {};143 }144 145 auto context = *context_maybe;146 147 if (context.size() < sizeof(MinidumpContext_x86_32))148 return {};149 150 return context;151 // NOTE: We don't currently use the TEB for anything else. If we152 // need it in the future, the 32-bit TEB is located according to the address153 // stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]).154}155 156ArchSpec MinidumpParser::GetArchitecture() {157 if (m_arch.IsValid())158 return m_arch;159 160 // Set the architecture in m_arch161 llvm::Expected<const SystemInfo &> system_info = m_file->getSystemInfo();162 163 if (!system_info) {164 LLDB_LOG_ERROR(GetLog(LLDBLog::Process), system_info.takeError(),165 "Failed to read SystemInfo stream: {0}");166 return m_arch;167 }168 169 // TODO what to do about big endiand flavors of arm ?170 // TODO set the arm subarch stuff if the minidump has info about it171 172 llvm::Triple triple;173 triple.setVendor(llvm::Triple::VendorType::UnknownVendor);174 175 switch (system_info->ProcessorArch) {176 case ProcessorArchitecture::X86:177 triple.setArch(llvm::Triple::ArchType::x86);178 break;179 case ProcessorArchitecture::AMD64:180 triple.setArch(llvm::Triple::ArchType::x86_64);181 break;182 case ProcessorArchitecture::ARM:183 triple.setArch(llvm::Triple::ArchType::arm);184 break;185 case ProcessorArchitecture::ARM64:186 case ProcessorArchitecture::BP_ARM64:187 triple.setArch(llvm::Triple::ArchType::aarch64);188 break;189 default:190 triple.setArch(llvm::Triple::ArchType::UnknownArch);191 break;192 }193 194 // TODO add all of the OSes that Minidump/breakpad distinguishes?195 switch (system_info->PlatformId) {196 case OSPlatform::Win32S:197 case OSPlatform::Win32Windows:198 case OSPlatform::Win32NT:199 case OSPlatform::Win32CE:200 triple.setOS(llvm::Triple::OSType::Win32);201 triple.setVendor(llvm::Triple::VendorType::PC);202 break;203 case OSPlatform::Linux:204 triple.setOS(llvm::Triple::OSType::Linux);205 break;206 case OSPlatform::MacOSX:207 triple.setOS(llvm::Triple::OSType::MacOSX);208 triple.setVendor(llvm::Triple::Apple);209 break;210 case OSPlatform::IOS:211 triple.setOS(llvm::Triple::OSType::IOS);212 triple.setVendor(llvm::Triple::Apple);213 break;214 case OSPlatform::Android:215 triple.setOS(llvm::Triple::OSType::Linux);216 triple.setEnvironment(llvm::Triple::EnvironmentType::Android);217 break;218 default: {219 triple.setOS(llvm::Triple::OSType::UnknownOS);220 auto ExpectedCSD = m_file->getString(system_info->CSDVersionRVA);221 if (!ExpectedCSD) {222 LLDB_LOG_ERROR(GetLog(LLDBLog::Process), ExpectedCSD.takeError(),223 "Failed to CSD Version string: {0}");224 } else {225 if (ExpectedCSD->find("Linux") != std::string::npos)226 triple.setOS(llvm::Triple::OSType::Linux);227 }228 break;229 }230 }231 m_arch.SetTriple(triple);232 return m_arch;233}234 235const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {236 llvm::ArrayRef<uint8_t> data = GetStream(StreamType::MiscInfo);237 238 if (data.size() == 0)239 return nullptr;240 241 return MinidumpMiscInfo::Parse(data);242}243 244std::optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {245 llvm::ArrayRef<uint8_t> data = GetStream(StreamType::LinuxProcStatus);246 247 if (data.size() == 0)248 return std::nullopt;249 250 return LinuxProcStatus::Parse(data);251}252 253std::optional<lldb::pid_t> MinidumpParser::GetPid() {254 const MinidumpMiscInfo *misc_info = GetMiscInfo();255 if (misc_info != nullptr) {256 return misc_info->GetPid();257 }258 259 std::optional<LinuxProcStatus> proc_status = GetLinuxProcStatus();260 if (proc_status) {261 return proc_status->GetPid();262 }263 264 return std::nullopt;265}266 267llvm::ArrayRef<minidump::Module> MinidumpParser::GetModuleList() {268 auto ExpectedModules = GetMinidumpFile().getModuleList();269 if (ExpectedModules)270 return *ExpectedModules;271 272 LLDB_LOG_ERROR(GetLog(LLDBLog::Modules), ExpectedModules.takeError(),273 "Failed to read module list: {0}");274 return {};275}276 277static bool278CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,279 std::vector<MemoryRegionInfo> ®ions) {280 auto data = parser.GetStream(StreamType::LinuxMaps);281 if (data.empty())282 return false;283 284 Log *log = GetLog(LLDBLog::Expressions);285 ParseLinuxMapRegions(286 llvm::toStringRef(data),287 [®ions, &log](llvm::Expected<MemoryRegionInfo> region) -> bool {288 if (region)289 regions.push_back(*region);290 else291 LLDB_LOG_ERROR(log, region.takeError(),292 "Reading memory region from minidump failed: {0}");293 return true;294 });295 return !regions.empty();296}297 298/// Check for the memory regions starting at \a load_addr for a contiguous299/// section that has execute permissions that matches the module path.300///301/// When we load a breakpad generated minidump file, we might have the302/// /proc/<pid>/maps text for a process that details the memory map of the303/// process that the minidump is describing. This checks the sorted memory304/// regions for a section that has execute permissions. A sample maps files305/// might look like:306///307/// 00400000-00401000 r--p 00000000 fd:01 2838574 /tmp/a.out308/// 00401000-00402000 r-xp 00001000 fd:01 2838574 /tmp/a.out309/// 00402000-00403000 r--p 00002000 fd:01 2838574 /tmp/a.out310/// 00403000-00404000 r--p 00002000 fd:01 2838574 /tmp/a.out311/// 00404000-00405000 rw-p 00003000 fd:01 2838574 /tmp/a.out312/// ...313///314/// This function should return true when given 0x00400000 and "/tmp/a.out"315/// is passed in as the path since it has a consecutive memory region for316/// "/tmp/a.out" that has execute permissions at 0x00401000. This will help us317/// differentiate if a file has been memory mapped into a process for reading318/// and breakpad ends up saving a minidump file that has two module entries for319/// a given file: one that is read only for the entire file, and then one that320/// is the real executable that is loaded into memory for execution. For memory321/// mapped files they will typically show up and r--p permissions and a range322/// matcning the entire range of the file on disk:323///324/// 00800000-00805000 r--p 00000000 fd:01 2838574 /tmp/a.out325/// 00805000-00806000 r-xp 00001000 fd:01 1234567 /usr/lib/libc.so326///327/// This function should return false when asked about 0x00800000 with328/// "/tmp/a.out" as the path.329///330/// \param[in] path331/// The path to the module to check for in the memory regions. Only sequential332/// memory regions whose paths match this path will be considered when looking333/// for execute permissions.334///335/// \param[in] regions336/// A sorted list of memory regions obtained from a call to337/// CreateRegionsCacheFromLinuxMaps.338///339/// \param[in] base_of_image340/// The load address of this module from BaseOfImage in the modules list.341///342/// \return343/// True if a contiguous region of memory belonging to the module with a344/// matching path exists that has executable permissions. Returns false if345/// \a regions is empty or if there are no regions with execute permissions346/// that match \a path.347 348static bool CheckForLinuxExecutable(ConstString path,349 const MemoryRegionInfos ®ions,350 lldb::addr_t base_of_image) {351 if (regions.empty())352 return false;353 lldb::addr_t addr = base_of_image;354 MemoryRegionInfo region = MinidumpParser::GetMemoryRegionInfo(regions, addr);355 while (region.GetName() == path) {356 if (region.GetExecutable() == MemoryRegionInfo::eYes)357 return true;358 addr += region.GetRange().GetByteSize();359 region = MinidumpParser::GetMemoryRegionInfo(regions, addr);360 }361 return false;362}363 364std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() {365 Log *log = GetLog(LLDBLog::Modules);366 auto ExpectedModules = GetMinidumpFile().getModuleList();367 if (!ExpectedModules) {368 LLDB_LOG_ERROR(log, ExpectedModules.takeError(),369 "Failed to read module list: {0}");370 return {};371 }372 373 // Create memory regions from the linux maps only. We do this to avoid issues374 // with breakpad generated minidumps where if someone has mmap'ed a shared375 // library into memory to access its data in the object file, we can get a376 // minidump with two mappings for a binary: one whose base image points to a377 // memory region that is read + execute and one that is read only.378 MemoryRegionInfos linux_regions;379 if (CreateRegionsCacheFromLinuxMaps(*this, linux_regions))380 llvm::sort(linux_regions);381 382 // map module_name -> filtered_modules index383 typedef llvm::StringMap<size_t> MapType;384 MapType module_name_to_filtered_index;385 386 std::vector<const minidump::Module *> filtered_modules;387 388 for (const auto &module : *ExpectedModules) {389 auto ExpectedName = m_file->getString(module.ModuleNameRVA);390 if (!ExpectedName) {391 LLDB_LOG_ERROR(log, ExpectedName.takeError(),392 "Failed to get module name: {0}");393 continue;394 }395 396 MapType::iterator iter;397 bool inserted;398 // See if we have inserted this module aready into filtered_modules. If we399 // haven't insert an entry into module_name_to_filtered_index with the400 // index where we will insert it if it isn't in the vector already.401 std::tie(iter, inserted) = module_name_to_filtered_index.try_emplace(402 *ExpectedName, filtered_modules.size());403 404 if (inserted) {405 // This module has not been seen yet, insert it into filtered_modules at406 // the index that was inserted into module_name_to_filtered_index using407 // "filtered_modules.size()" above.408 filtered_modules.push_back(&module);409 } else {410 // We have a duplicate module entry. Check the linux regions to see if411 // either module is not really a mapped executable. If one but not the412 // other is a real mapped executable, prefer the executable one. This413 // can happen when a process mmap's in the file for an executable in414 // order to read bytes from the executable file. A memory region mapping415 // will exist for the mmap'ed version and for the loaded executable, but416 // only one will have a consecutive region that is executable in the417 // memory regions.418 auto dup_module = filtered_modules[iter->second];419 ConstString name(*ExpectedName);420 bool is_executable =421 CheckForLinuxExecutable(name, linux_regions, module.BaseOfImage);422 bool dup_is_executable =423 CheckForLinuxExecutable(name, linux_regions, dup_module->BaseOfImage);424 425 if (is_executable != dup_is_executable) {426 if (is_executable)427 filtered_modules[iter->second] = &module;428 continue;429 }430 // This module has been seen. Modules are sometimes mentioned multiple431 // times when they are mapped discontiguously, so find the module with432 // the lowest "base_of_image" and use that as the filtered module.433 if (module.BaseOfImage < dup_module->BaseOfImage)434 filtered_modules[iter->second] = &module;435 }436 }437 return filtered_modules;438}439 440llvm::iterator_range<ExceptionStreamsIterator>441MinidumpParser::GetExceptionStreams() {442 return GetMinidumpFile().getExceptionStreams();443}444 445std::optional<minidump::Range>446MinidumpParser::FindMemoryRange(lldb::addr_t addr) {447 if (m_memory_ranges.IsEmpty())448 PopulateMemoryRanges();449 450 const MemoryRangeVector::Entry *entry =451 m_memory_ranges.FindEntryThatContains(addr);452 if (!entry)453 return std::nullopt;454 455 return entry->data;456}457 458void MinidumpParser::PopulateMemoryRanges() {459 Log *log = GetLog(LLDBLog::Modules);460 auto ExpectedMemory = GetMinidumpFile().getMemoryList();461 if (ExpectedMemory) {462 for (const auto &memory_desc : *ExpectedMemory) {463 const LocationDescriptor &loc_desc = memory_desc.Memory;464 const lldb::addr_t range_start = memory_desc.StartOfMemoryRange;465 const size_t range_size = loc_desc.DataSize;466 auto ExpectedSlice = GetMinidumpFile().getRawData(loc_desc);467 if (!ExpectedSlice) {468 LLDB_LOG_ERROR(log, ExpectedSlice.takeError(),469 "Failed to get memory slice: {0}");470 continue;471 }472 m_memory_ranges.Append(MemoryRangeVector::Entry(473 range_start, range_size,474 minidump::Range(range_start, *ExpectedSlice)));475 }476 } else {477 LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),478 "Failed to read memory list: {0}");479 }480 481 if (!GetStream(StreamType::Memory64List).empty()) {482 llvm::Error err = llvm::Error::success();483 for (const auto &memory_desc : GetMinidumpFile().getMemory64List(err)) {484 m_memory_ranges.Append(MemoryRangeVector::Entry(485 memory_desc.first.StartOfMemoryRange, memory_desc.first.DataSize,486 minidump::Range(memory_desc.first.StartOfMemoryRange,487 memory_desc.second)));488 }489 490 if (err)491 LLDB_LOG_ERROR(log, std::move(err), "Failed to read memory64 list: {0}");492 }493 494 m_memory_ranges.Sort();495}496 497llvm::Expected<llvm::ArrayRef<uint8_t>>498MinidumpParser::GetMemory(lldb::addr_t addr, size_t size) {499 std::optional<minidump::Range> range = FindMemoryRange(addr);500 if (!range)501 return llvm::createStringError(502 llvm::inconvertibleErrorCode(),503 "No memory range found for address (0x%" PRIx64 ")", addr);504 505 // There's at least some overlap between the beginning of the desired range506 // (addr) and the current range. Figure out where the overlap begins and507 // how much overlap there is.508 509 const size_t offset = addr - range->start;510 511 if (addr < range->start || offset >= range->range_ref.size())512 return llvm::createStringError(513 llvm::inconvertibleErrorCode(),514 "Address (0x%" PRIx64 ") is not in range [0x%" PRIx64 " - 0x%" PRIx64515 ")",516 addr, range->start, range->start + range->range_ref.size());517 518 const size_t overlap = std::min(size, range->range_ref.size() - offset);519 return range->range_ref.slice(offset, overlap);520}521 522llvm::iterator_range<FallibleMemory64Iterator>523MinidumpParser::GetMemory64Iterator(llvm::Error &err) {524 llvm::ErrorAsOutParameter ErrAsOutParam(&err);525 return m_file->getMemory64List(err);526}527 528static bool529CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,530 std::vector<MemoryRegionInfo> ®ions) {531 Log *log = GetLog(LLDBLog::Modules);532 auto ExpectedInfo = parser.GetMinidumpFile().getMemoryInfoList();533 if (!ExpectedInfo) {534 LLDB_LOG_ERROR(log, ExpectedInfo.takeError(),535 "Failed to read memory info list: {0}");536 return false;537 }538 constexpr auto yes = MemoryRegionInfo::eYes;539 constexpr auto no = MemoryRegionInfo::eNo;540 for (const MemoryInfo &entry : *ExpectedInfo) {541 MemoryRegionInfo region;542 region.GetRange().SetRangeBase(entry.BaseAddress);543 region.GetRange().SetByteSize(entry.RegionSize);544 545 MemoryProtection prot = entry.Protect;546 region.SetReadable(bool(prot & MemoryProtection::NoAccess) ? no : yes);547 region.SetWritable(548 bool(prot & (MemoryProtection::ReadWrite | MemoryProtection::WriteCopy |549 MemoryProtection::ExecuteReadWrite |550 MemoryProtection::ExeciteWriteCopy))551 ? yes552 : no);553 region.SetExecutable(554 bool(prot & (MemoryProtection::Execute | MemoryProtection::ExecuteRead |555 MemoryProtection::ExecuteReadWrite |556 MemoryProtection::ExeciteWriteCopy))557 ? yes558 : no);559 region.SetMapped(entry.State != MemoryState::Free ? yes : no);560 regions.push_back(region);561 }562 return !regions.empty();563}564 565static bool566CreateRegionsCacheFromMemoryList(MinidumpParser &parser,567 std::vector<MemoryRegionInfo> ®ions) {568 Log *log = GetLog(LLDBLog::Modules);569 // Cache the expected memory32 into an optional570 // because it is possible to just have a memory64 list571 auto ExpectedMemory = parser.GetMinidumpFile().getMemoryList();572 if (!ExpectedMemory) {573 LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),574 "Failed to read memory list: {0}");575 } else {576 for (const MemoryDescriptor &memory_desc : *ExpectedMemory) {577 if (memory_desc.Memory.DataSize == 0)578 continue;579 MemoryRegionInfo region;580 region.GetRange().SetRangeBase(memory_desc.StartOfMemoryRange);581 region.GetRange().SetByteSize(memory_desc.Memory.DataSize);582 region.SetReadable(MemoryRegionInfo::eYes);583 region.SetMapped(MemoryRegionInfo::eYes);584 regions.push_back(region);585 }586 }587 588 if (!parser.GetStream(StreamType::Memory64List).empty()) {589 llvm::Error err = llvm::Error::success();590 for (const auto &memory_desc : parser.GetMemory64Iterator(err)) {591 if (memory_desc.first.DataSize == 0)592 continue;593 MemoryRegionInfo region;594 region.GetRange().SetRangeBase(memory_desc.first.StartOfMemoryRange);595 region.GetRange().SetByteSize(memory_desc.first.DataSize);596 region.SetReadable(MemoryRegionInfo::eYes);597 region.SetMapped(MemoryRegionInfo::eYes);598 regions.push_back(region);599 }600 601 if (err) {602 LLDB_LOG_ERROR(log, std::move(err), "Failed to read memory64 list: {0}");603 return false;604 }605 }606 607 regions.shrink_to_fit();608 return !regions.empty();609}610 611std::pair<MemoryRegionInfos, bool> MinidumpParser::BuildMemoryRegions() {612 // We create the region cache using the best source. We start with613 // the linux maps since they are the most complete and have names for the614 // regions. Next we try the MemoryInfoList since it has615 // read/write/execute/map data, and then fall back to the MemoryList and616 // Memory64List to just get a list of the memory that is mapped in this617 // core file618 MemoryRegionInfos result;619 const auto &return_sorted = [&](bool is_complete) {620 llvm::sort(result);621 return std::make_pair(std::move(result), is_complete);622 };623 if (CreateRegionsCacheFromLinuxMaps(*this, result))624 return return_sorted(true);625 if (CreateRegionsCacheFromMemoryInfoList(*this, result))626 return return_sorted(true);627 CreateRegionsCacheFromMemoryList(*this, result);628 return return_sorted(false);629}630 631#define ENUM_TO_CSTR(ST) \632 case StreamType::ST: \633 return #ST634 635llvm::StringRef MinidumpParser::GetStreamTypeAsString(StreamType stream_type) {636 switch (stream_type) {637 ENUM_TO_CSTR(Unused);638 ENUM_TO_CSTR(ThreadList);639 ENUM_TO_CSTR(ModuleList);640 ENUM_TO_CSTR(MemoryList);641 ENUM_TO_CSTR(Exception);642 ENUM_TO_CSTR(SystemInfo);643 ENUM_TO_CSTR(ThreadExList);644 ENUM_TO_CSTR(Memory64List);645 ENUM_TO_CSTR(CommentA);646 ENUM_TO_CSTR(CommentW);647 ENUM_TO_CSTR(HandleData);648 ENUM_TO_CSTR(FunctionTable);649 ENUM_TO_CSTR(UnloadedModuleList);650 ENUM_TO_CSTR(MiscInfo);651 ENUM_TO_CSTR(MemoryInfoList);652 ENUM_TO_CSTR(ThreadInfoList);653 ENUM_TO_CSTR(HandleOperationList);654 ENUM_TO_CSTR(Token);655 ENUM_TO_CSTR(JavascriptData);656 ENUM_TO_CSTR(SystemMemoryInfo);657 ENUM_TO_CSTR(ProcessVMCounters);658 ENUM_TO_CSTR(LastReserved);659 ENUM_TO_CSTR(BreakpadInfo);660 ENUM_TO_CSTR(AssertionInfo);661 ENUM_TO_CSTR(LinuxCPUInfo);662 ENUM_TO_CSTR(LinuxProcStatus);663 ENUM_TO_CSTR(LinuxLSBRelease);664 ENUM_TO_CSTR(LinuxCMDLine);665 ENUM_TO_CSTR(LinuxEnviron);666 ENUM_TO_CSTR(LinuxAuxv);667 ENUM_TO_CSTR(LinuxMaps);668 ENUM_TO_CSTR(LinuxDSODebug);669 ENUM_TO_CSTR(LinuxProcStat);670 ENUM_TO_CSTR(LinuxProcUptime);671 ENUM_TO_CSTR(LinuxProcFD);672 ENUM_TO_CSTR(FacebookAppCustomData);673 ENUM_TO_CSTR(FacebookBuildID);674 ENUM_TO_CSTR(FacebookAppVersionName);675 ENUM_TO_CSTR(FacebookJavaStack);676 ENUM_TO_CSTR(FacebookDalvikInfo);677 ENUM_TO_CSTR(FacebookUnwindSymbols);678 ENUM_TO_CSTR(FacebookDumpErrorLog);679 ENUM_TO_CSTR(FacebookAppStateLog);680 ENUM_TO_CSTR(FacebookAbortReason);681 ENUM_TO_CSTR(FacebookThreadName);682 ENUM_TO_CSTR(FacebookLogcat);683 ENUM_TO_CSTR(LLDBGenerated);684 }685 return "unknown stream type";686}687 688MemoryRegionInfo689MinidumpParser::GetMemoryRegionInfo(const MemoryRegionInfos ®ions,690 lldb::addr_t load_addr) {691 MemoryRegionInfo region;692 auto pos = llvm::upper_bound(regions, load_addr);693 if (pos != regions.begin() &&694 std::prev(pos)->GetRange().Contains(load_addr)) {695 return *std::prev(pos);696 }697 698 if (pos == regions.begin())699 region.GetRange().SetRangeBase(0);700 else701 region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd());702 703 if (pos == regions.end())704 region.GetRange().SetRangeEnd(UINT64_MAX);705 else706 region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase());707 708 region.SetReadable(MemoryRegionInfo::eNo);709 region.SetWritable(MemoryRegionInfo::eNo);710 region.SetExecutable(MemoryRegionInfo::eNo);711 region.SetMapped(MemoryRegionInfo::eNo);712 return region;713}714