Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
39644 views
//===-- MinidumpParser.cpp ------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "MinidumpParser.h"9#include "NtStructures.h"10#include "RegisterContextMinidump_x86_32.h"1112#include "Plugins/Process/Utility/LinuxProcMaps.h"13#include "lldb/Utility/LLDBAssert.h"14#include "lldb/Utility/LLDBLog.h"15#include "lldb/Utility/Log.h"1617// C includes18// C++ includes19#include <algorithm>20#include <map>21#include <optional>22#include <vector>23#include <utility>2425using namespace lldb_private;26using namespace minidump;2728llvm::Expected<MinidumpParser>29MinidumpParser::Create(const lldb::DataBufferSP &data_sp) {30auto ExpectedFile = llvm::object::MinidumpFile::create(31llvm::MemoryBufferRef(toStringRef(data_sp->GetData()), "minidump"));32if (!ExpectedFile)33return ExpectedFile.takeError();3435return MinidumpParser(data_sp, std::move(*ExpectedFile));36}3738MinidumpParser::MinidumpParser(lldb::DataBufferSP data_sp,39std::unique_ptr<llvm::object::MinidumpFile> file)40: m_data_sp(std::move(data_sp)), m_file(std::move(file)) {}4142llvm::ArrayRef<uint8_t> MinidumpParser::GetData() {43return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(),44m_data_sp->GetByteSize());45}4647llvm::ArrayRef<uint8_t> MinidumpParser::GetStream(StreamType stream_type) {48return m_file->getRawStream(stream_type).value_or(llvm::ArrayRef<uint8_t>());49}5051UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) {52auto cv_record =53GetData().slice(module->CvRecord.RVA, module->CvRecord.DataSize);5455// Read the CV record signature56const llvm::support::ulittle32_t *signature = nullptr;57Status error = consumeObject(cv_record, signature);58if (error.Fail())59return UUID();6061const CvSignature cv_signature =62static_cast<CvSignature>(static_cast<uint32_t>(*signature));6364if (cv_signature == CvSignature::Pdb70) {65const UUID::CvRecordPdb70 *pdb70_uuid = nullptr;66Status error = consumeObject(cv_record, pdb70_uuid);67if (error.Fail())68return UUID();69if (GetArchitecture().GetTriple().isOSBinFormatELF()) {70if (pdb70_uuid->Age != 0)71return UUID(pdb70_uuid, sizeof(*pdb70_uuid));72return UUID(&pdb70_uuid->Uuid,73sizeof(pdb70_uuid->Uuid));74}75return UUID(*pdb70_uuid);76} else if (cv_signature == CvSignature::ElfBuildId)77return UUID(cv_record);7879return UUID();80}8182llvm::ArrayRef<minidump::Thread> MinidumpParser::GetThreads() {83auto ExpectedThreads = GetMinidumpFile().getThreadList();84if (ExpectedThreads)85return *ExpectedThreads;8687LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), ExpectedThreads.takeError(),88"Failed to read thread list: {0}");89return {};90}9192llvm::ArrayRef<uint8_t>93MinidumpParser::GetThreadContext(const LocationDescriptor &location) {94if (location.RVA + location.DataSize > GetData().size())95return {};96return GetData().slice(location.RVA, location.DataSize);97}9899llvm::ArrayRef<uint8_t>100MinidumpParser::GetThreadContext(const minidump::Thread &td) {101return GetThreadContext(td.Context);102}103104llvm::ArrayRef<uint8_t>105MinidumpParser::GetThreadContextWow64(const minidump::Thread &td) {106// On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If107// the minidump was captured with a 64-bit debugger, then the CONTEXT we just108// grabbed from the mini_dump_thread is the one for the 64-bit "native"109// process rather than the 32-bit "guest" process we care about. In this110// case, we can get the 32-bit CONTEXT from the TEB (Thread Environment111// Block) of the 64-bit process.112auto teb_mem = GetMemory(td.EnvironmentBlock, sizeof(TEB64));113if (teb_mem.empty())114return {};115116const TEB64 *wow64teb;117Status error = consumeObject(teb_mem, wow64teb);118if (error.Fail())119return {};120121// Slot 1 of the thread-local storage in the 64-bit TEB points to a structure122// that includes the 32-bit CONTEXT (after a ULONG). See:123// https://msdn.microsoft.com/en-us/library/ms681670.aspx124auto context =125GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32));126if (context.size() < sizeof(MinidumpContext_x86_32))127return {};128129return context;130// NOTE: We don't currently use the TEB for anything else. If we131// need it in the future, the 32-bit TEB is located according to the address132// stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]).133}134135ArchSpec MinidumpParser::GetArchitecture() {136if (m_arch.IsValid())137return m_arch;138139// Set the architecture in m_arch140llvm::Expected<const SystemInfo &> system_info = m_file->getSystemInfo();141142if (!system_info) {143LLDB_LOG_ERROR(GetLog(LLDBLog::Process), system_info.takeError(),144"Failed to read SystemInfo stream: {0}");145return m_arch;146}147148// TODO what to do about big endiand flavors of arm ?149// TODO set the arm subarch stuff if the minidump has info about it150151llvm::Triple triple;152triple.setVendor(llvm::Triple::VendorType::UnknownVendor);153154switch (system_info->ProcessorArch) {155case ProcessorArchitecture::X86:156triple.setArch(llvm::Triple::ArchType::x86);157break;158case ProcessorArchitecture::AMD64:159triple.setArch(llvm::Triple::ArchType::x86_64);160break;161case ProcessorArchitecture::ARM:162triple.setArch(llvm::Triple::ArchType::arm);163break;164case ProcessorArchitecture::ARM64:165case ProcessorArchitecture::BP_ARM64:166triple.setArch(llvm::Triple::ArchType::aarch64);167break;168default:169triple.setArch(llvm::Triple::ArchType::UnknownArch);170break;171}172173// TODO add all of the OSes that Minidump/breakpad distinguishes?174switch (system_info->PlatformId) {175case OSPlatform::Win32S:176case OSPlatform::Win32Windows:177case OSPlatform::Win32NT:178case OSPlatform::Win32CE:179triple.setOS(llvm::Triple::OSType::Win32);180triple.setVendor(llvm::Triple::VendorType::PC);181break;182case OSPlatform::Linux:183triple.setOS(llvm::Triple::OSType::Linux);184break;185case OSPlatform::MacOSX:186triple.setOS(llvm::Triple::OSType::MacOSX);187triple.setVendor(llvm::Triple::Apple);188break;189case OSPlatform::IOS:190triple.setOS(llvm::Triple::OSType::IOS);191triple.setVendor(llvm::Triple::Apple);192break;193case OSPlatform::Android:194triple.setOS(llvm::Triple::OSType::Linux);195triple.setEnvironment(llvm::Triple::EnvironmentType::Android);196break;197default: {198triple.setOS(llvm::Triple::OSType::UnknownOS);199auto ExpectedCSD = m_file->getString(system_info->CSDVersionRVA);200if (!ExpectedCSD) {201LLDB_LOG_ERROR(GetLog(LLDBLog::Process), ExpectedCSD.takeError(),202"Failed to CSD Version string: {0}");203} else {204if (ExpectedCSD->find("Linux") != std::string::npos)205triple.setOS(llvm::Triple::OSType::Linux);206}207break;208}209}210m_arch.SetTriple(triple);211return m_arch;212}213214const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {215llvm::ArrayRef<uint8_t> data = GetStream(StreamType::MiscInfo);216217if (data.size() == 0)218return nullptr;219220return MinidumpMiscInfo::Parse(data);221}222223std::optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {224llvm::ArrayRef<uint8_t> data = GetStream(StreamType::LinuxProcStatus);225226if (data.size() == 0)227return std::nullopt;228229return LinuxProcStatus::Parse(data);230}231232std::optional<lldb::pid_t> MinidumpParser::GetPid() {233const MinidumpMiscInfo *misc_info = GetMiscInfo();234if (misc_info != nullptr) {235return misc_info->GetPid();236}237238std::optional<LinuxProcStatus> proc_status = GetLinuxProcStatus();239if (proc_status) {240return proc_status->GetPid();241}242243return std::nullopt;244}245246llvm::ArrayRef<minidump::Module> MinidumpParser::GetModuleList() {247auto ExpectedModules = GetMinidumpFile().getModuleList();248if (ExpectedModules)249return *ExpectedModules;250251LLDB_LOG_ERROR(GetLog(LLDBLog::Modules), ExpectedModules.takeError(),252"Failed to read module list: {0}");253return {};254}255256static bool257CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,258std::vector<MemoryRegionInfo> ®ions) {259auto data = parser.GetStream(StreamType::LinuxMaps);260if (data.empty())261return false;262263Log *log = GetLog(LLDBLog::Expressions);264ParseLinuxMapRegions(265llvm::toStringRef(data),266[®ions, &log](llvm::Expected<MemoryRegionInfo> region) -> bool {267if (region)268regions.push_back(*region);269else270LLDB_LOG_ERROR(log, region.takeError(),271"Reading memory region from minidump failed: {0}");272return true;273});274return !regions.empty();275}276277/// Check for the memory regions starting at \a load_addr for a contiguous278/// section that has execute permissions that matches the module path.279///280/// When we load a breakpad generated minidump file, we might have the281/// /proc/<pid>/maps text for a process that details the memory map of the282/// process that the minidump is describing. This checks the sorted memory283/// regions for a section that has execute permissions. A sample maps files284/// might look like:285///286/// 00400000-00401000 r--p 00000000 fd:01 2838574 /tmp/a.out287/// 00401000-00402000 r-xp 00001000 fd:01 2838574 /tmp/a.out288/// 00402000-00403000 r--p 00002000 fd:01 2838574 /tmp/a.out289/// 00403000-00404000 r--p 00002000 fd:01 2838574 /tmp/a.out290/// 00404000-00405000 rw-p 00003000 fd:01 2838574 /tmp/a.out291/// ...292///293/// This function should return true when given 0x00400000 and "/tmp/a.out"294/// is passed in as the path since it has a consecutive memory region for295/// "/tmp/a.out" that has execute permissions at 0x00401000. This will help us296/// differentiate if a file has been memory mapped into a process for reading297/// and breakpad ends up saving a minidump file that has two module entries for298/// a given file: one that is read only for the entire file, and then one that299/// is the real executable that is loaded into memory for execution. For memory300/// mapped files they will typically show up and r--p permissions and a range301/// matcning the entire range of the file on disk:302///303/// 00800000-00805000 r--p 00000000 fd:01 2838574 /tmp/a.out304/// 00805000-00806000 r-xp 00001000 fd:01 1234567 /usr/lib/libc.so305///306/// This function should return false when asked about 0x00800000 with307/// "/tmp/a.out" as the path.308///309/// \param[in] path310/// The path to the module to check for in the memory regions. Only sequential311/// memory regions whose paths match this path will be considered when looking312/// for execute permissions.313///314/// \param[in] regions315/// A sorted list of memory regions obtained from a call to316/// CreateRegionsCacheFromLinuxMaps.317///318/// \param[in] base_of_image319/// The load address of this module from BaseOfImage in the modules list.320///321/// \return322/// True if a contiguous region of memory belonging to the module with a323/// matching path exists that has executable permissions. Returns false if324/// \a regions is empty or if there are no regions with execute permissions325/// that match \a path.326327static bool CheckForLinuxExecutable(ConstString path,328const MemoryRegionInfos ®ions,329lldb::addr_t base_of_image) {330if (regions.empty())331return false;332lldb::addr_t addr = base_of_image;333MemoryRegionInfo region = MinidumpParser::GetMemoryRegionInfo(regions, addr);334while (region.GetName() == path) {335if (region.GetExecutable() == MemoryRegionInfo::eYes)336return true;337addr += region.GetRange().GetByteSize();338region = MinidumpParser::GetMemoryRegionInfo(regions, addr);339}340return false;341}342343std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() {344Log *log = GetLog(LLDBLog::Modules);345auto ExpectedModules = GetMinidumpFile().getModuleList();346if (!ExpectedModules) {347LLDB_LOG_ERROR(log, ExpectedModules.takeError(),348"Failed to read module list: {0}");349return {};350}351352// Create memory regions from the linux maps only. We do this to avoid issues353// with breakpad generated minidumps where if someone has mmap'ed a shared354// library into memory to access its data in the object file, we can get a355// minidump with two mappings for a binary: one whose base image points to a356// memory region that is read + execute and one that is read only.357MemoryRegionInfos linux_regions;358if (CreateRegionsCacheFromLinuxMaps(*this, linux_regions))359llvm::sort(linux_regions);360361// map module_name -> filtered_modules index362typedef llvm::StringMap<size_t> MapType;363MapType module_name_to_filtered_index;364365std::vector<const minidump::Module *> filtered_modules;366367for (const auto &module : *ExpectedModules) {368auto ExpectedName = m_file->getString(module.ModuleNameRVA);369if (!ExpectedName) {370LLDB_LOG_ERROR(log, ExpectedName.takeError(),371"Failed to get module name: {0}");372continue;373}374375MapType::iterator iter;376bool inserted;377// See if we have inserted this module aready into filtered_modules. If we378// haven't insert an entry into module_name_to_filtered_index with the379// index where we will insert it if it isn't in the vector already.380std::tie(iter, inserted) = module_name_to_filtered_index.try_emplace(381*ExpectedName, filtered_modules.size());382383if (inserted) {384// This module has not been seen yet, insert it into filtered_modules at385// the index that was inserted into module_name_to_filtered_index using386// "filtered_modules.size()" above.387filtered_modules.push_back(&module);388} else {389// We have a duplicate module entry. Check the linux regions to see if390// either module is not really a mapped executable. If one but not the391// other is a real mapped executable, prefer the executable one. This392// can happen when a process mmap's in the file for an executable in393// order to read bytes from the executable file. A memory region mapping394// will exist for the mmap'ed version and for the loaded executable, but395// only one will have a consecutive region that is executable in the396// memory regions.397auto dup_module = filtered_modules[iter->second];398ConstString name(*ExpectedName);399bool is_executable =400CheckForLinuxExecutable(name, linux_regions, module.BaseOfImage);401bool dup_is_executable =402CheckForLinuxExecutable(name, linux_regions, dup_module->BaseOfImage);403404if (is_executable != dup_is_executable) {405if (is_executable)406filtered_modules[iter->second] = &module;407continue;408}409// This module has been seen. Modules are sometimes mentioned multiple410// times when they are mapped discontiguously, so find the module with411// the lowest "base_of_image" and use that as the filtered module.412if (module.BaseOfImage < dup_module->BaseOfImage)413filtered_modules[iter->second] = &module;414}415}416return filtered_modules;417}418419const minidump::ExceptionStream *MinidumpParser::GetExceptionStream() {420auto ExpectedStream = GetMinidumpFile().getExceptionStream();421if (ExpectedStream)422return &*ExpectedStream;423424LLDB_LOG_ERROR(GetLog(LLDBLog::Process), ExpectedStream.takeError(),425"Failed to read minidump exception stream: {0}");426return nullptr;427}428429std::optional<minidump::Range>430MinidumpParser::FindMemoryRange(lldb::addr_t addr) {431llvm::ArrayRef<uint8_t> data64 = GetStream(StreamType::Memory64List);432Log *log = GetLog(LLDBLog::Modules);433434auto ExpectedMemory = GetMinidumpFile().getMemoryList();435if (!ExpectedMemory) {436LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),437"Failed to read memory list: {0}");438} else {439for (const auto &memory_desc : *ExpectedMemory) {440const LocationDescriptor &loc_desc = memory_desc.Memory;441const lldb::addr_t range_start = memory_desc.StartOfMemoryRange;442const size_t range_size = loc_desc.DataSize;443444if (loc_desc.RVA + loc_desc.DataSize > GetData().size())445return std::nullopt;446447if (range_start <= addr && addr < range_start + range_size) {448auto ExpectedSlice = GetMinidumpFile().getRawData(loc_desc);449if (!ExpectedSlice) {450LLDB_LOG_ERROR(log, ExpectedSlice.takeError(),451"Failed to get memory slice: {0}");452return std::nullopt;453}454return minidump::Range(range_start, *ExpectedSlice);455}456}457}458459// Some Minidumps have a Memory64ListStream that captures all the heap memory460// (full-memory Minidumps). We can't exactly use the same loop as above,461// because the Minidump uses slightly different data structures to describe462// those463464if (!data64.empty()) {465llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;466uint64_t base_rva;467std::tie(memory64_list, base_rva) =468MinidumpMemoryDescriptor64::ParseMemory64List(data64);469470if (memory64_list.empty())471return std::nullopt;472473for (const auto &memory_desc64 : memory64_list) {474const lldb::addr_t range_start = memory_desc64.start_of_memory_range;475const size_t range_size = memory_desc64.data_size;476477if (base_rva + range_size > GetData().size())478return std::nullopt;479480if (range_start <= addr && addr < range_start + range_size) {481return minidump::Range(range_start,482GetData().slice(base_rva, range_size));483}484base_rva += range_size;485}486}487488return std::nullopt;489}490491llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,492size_t size) {493// I don't have a sense of how frequently this is called or how many memory494// ranges a Minidump typically has, so I'm not sure if searching for the495// appropriate range linearly each time is stupid. Perhaps we should build496// an index for faster lookups.497std::optional<minidump::Range> range = FindMemoryRange(addr);498if (!range)499return {};500501// There's at least some overlap between the beginning of the desired range502// (addr) and the current range. Figure out where the overlap begins and how503// much overlap there is.504505const size_t offset = addr - range->start;506507if (addr < range->start || offset >= range->range_ref.size())508return {};509510const size_t overlap = std::min(size, range->range_ref.size() - offset);511return range->range_ref.slice(offset, overlap);512}513514static bool515CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,516std::vector<MemoryRegionInfo> ®ions) {517Log *log = GetLog(LLDBLog::Modules);518auto ExpectedInfo = parser.GetMinidumpFile().getMemoryInfoList();519if (!ExpectedInfo) {520LLDB_LOG_ERROR(log, ExpectedInfo.takeError(),521"Failed to read memory info list: {0}");522return false;523}524constexpr auto yes = MemoryRegionInfo::eYes;525constexpr auto no = MemoryRegionInfo::eNo;526for (const MemoryInfo &entry : *ExpectedInfo) {527MemoryRegionInfo region;528region.GetRange().SetRangeBase(entry.BaseAddress);529region.GetRange().SetByteSize(entry.RegionSize);530531MemoryProtection prot = entry.Protect;532region.SetReadable(bool(prot & MemoryProtection::NoAccess) ? no : yes);533region.SetWritable(534bool(prot & (MemoryProtection::ReadWrite | MemoryProtection::WriteCopy |535MemoryProtection::ExecuteReadWrite |536MemoryProtection::ExeciteWriteCopy))537? yes538: no);539region.SetExecutable(540bool(prot & (MemoryProtection::Execute | MemoryProtection::ExecuteRead |541MemoryProtection::ExecuteReadWrite |542MemoryProtection::ExeciteWriteCopy))543? yes544: no);545region.SetMapped(entry.State != MemoryState::Free ? yes : no);546regions.push_back(region);547}548return !regions.empty();549}550551static bool552CreateRegionsCacheFromMemoryList(MinidumpParser &parser,553std::vector<MemoryRegionInfo> ®ions) {554Log *log = GetLog(LLDBLog::Modules);555auto ExpectedMemory = parser.GetMinidumpFile().getMemoryList();556if (!ExpectedMemory) {557LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),558"Failed to read memory list: {0}");559return false;560}561regions.reserve(ExpectedMemory->size());562for (const MemoryDescriptor &memory_desc : *ExpectedMemory) {563if (memory_desc.Memory.DataSize == 0)564continue;565MemoryRegionInfo region;566region.GetRange().SetRangeBase(memory_desc.StartOfMemoryRange);567region.GetRange().SetByteSize(memory_desc.Memory.DataSize);568region.SetReadable(MemoryRegionInfo::eYes);569region.SetMapped(MemoryRegionInfo::eYes);570regions.push_back(region);571}572regions.shrink_to_fit();573return !regions.empty();574}575576static bool577CreateRegionsCacheFromMemory64List(MinidumpParser &parser,578std::vector<MemoryRegionInfo> ®ions) {579llvm::ArrayRef<uint8_t> data =580parser.GetStream(StreamType::Memory64List);581if (data.empty())582return false;583llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;584uint64_t base_rva;585std::tie(memory64_list, base_rva) =586MinidumpMemoryDescriptor64::ParseMemory64List(data);587588if (memory64_list.empty())589return false;590591regions.reserve(memory64_list.size());592for (const auto &memory_desc : memory64_list) {593if (memory_desc.data_size == 0)594continue;595MemoryRegionInfo region;596region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);597region.GetRange().SetByteSize(memory_desc.data_size);598region.SetReadable(MemoryRegionInfo::eYes);599region.SetMapped(MemoryRegionInfo::eYes);600regions.push_back(region);601}602regions.shrink_to_fit();603return !regions.empty();604}605606std::pair<MemoryRegionInfos, bool> MinidumpParser::BuildMemoryRegions() {607// We create the region cache using the best source. We start with608// the linux maps since they are the most complete and have names for the609// regions. Next we try the MemoryInfoList since it has610// read/write/execute/map data, and then fall back to the MemoryList and611// Memory64List to just get a list of the memory that is mapped in this612// core file613MemoryRegionInfos result;614const auto &return_sorted = [&](bool is_complete) {615llvm::sort(result);616return std::make_pair(std::move(result), is_complete);617};618if (CreateRegionsCacheFromLinuxMaps(*this, result))619return return_sorted(true);620if (CreateRegionsCacheFromMemoryInfoList(*this, result))621return return_sorted(true);622if (CreateRegionsCacheFromMemoryList(*this, result))623return return_sorted(false);624CreateRegionsCacheFromMemory64List(*this, result);625return return_sorted(false);626}627628#define ENUM_TO_CSTR(ST) \629case StreamType::ST: \630return #ST631632llvm::StringRef633MinidumpParser::GetStreamTypeAsString(StreamType stream_type) {634switch (stream_type) {635ENUM_TO_CSTR(Unused);636ENUM_TO_CSTR(ThreadList);637ENUM_TO_CSTR(ModuleList);638ENUM_TO_CSTR(MemoryList);639ENUM_TO_CSTR(Exception);640ENUM_TO_CSTR(SystemInfo);641ENUM_TO_CSTR(ThreadExList);642ENUM_TO_CSTR(Memory64List);643ENUM_TO_CSTR(CommentA);644ENUM_TO_CSTR(CommentW);645ENUM_TO_CSTR(HandleData);646ENUM_TO_CSTR(FunctionTable);647ENUM_TO_CSTR(UnloadedModuleList);648ENUM_TO_CSTR(MiscInfo);649ENUM_TO_CSTR(MemoryInfoList);650ENUM_TO_CSTR(ThreadInfoList);651ENUM_TO_CSTR(HandleOperationList);652ENUM_TO_CSTR(Token);653ENUM_TO_CSTR(JavascriptData);654ENUM_TO_CSTR(SystemMemoryInfo);655ENUM_TO_CSTR(ProcessVMCounters);656ENUM_TO_CSTR(LastReserved);657ENUM_TO_CSTR(BreakpadInfo);658ENUM_TO_CSTR(AssertionInfo);659ENUM_TO_CSTR(LinuxCPUInfo);660ENUM_TO_CSTR(LinuxProcStatus);661ENUM_TO_CSTR(LinuxLSBRelease);662ENUM_TO_CSTR(LinuxCMDLine);663ENUM_TO_CSTR(LinuxEnviron);664ENUM_TO_CSTR(LinuxAuxv);665ENUM_TO_CSTR(LinuxMaps);666ENUM_TO_CSTR(LinuxDSODebug);667ENUM_TO_CSTR(LinuxProcStat);668ENUM_TO_CSTR(LinuxProcUptime);669ENUM_TO_CSTR(LinuxProcFD);670ENUM_TO_CSTR(FacebookAppCustomData);671ENUM_TO_CSTR(FacebookBuildID);672ENUM_TO_CSTR(FacebookAppVersionName);673ENUM_TO_CSTR(FacebookJavaStack);674ENUM_TO_CSTR(FacebookDalvikInfo);675ENUM_TO_CSTR(FacebookUnwindSymbols);676ENUM_TO_CSTR(FacebookDumpErrorLog);677ENUM_TO_CSTR(FacebookAppStateLog);678ENUM_TO_CSTR(FacebookAbortReason);679ENUM_TO_CSTR(FacebookThreadName);680ENUM_TO_CSTR(FacebookLogcat);681}682return "unknown stream type";683}684685MemoryRegionInfo686MinidumpParser::GetMemoryRegionInfo(const MemoryRegionInfos ®ions,687lldb::addr_t load_addr) {688MemoryRegionInfo region;689auto pos = llvm::upper_bound(regions, load_addr);690if (pos != regions.begin() &&691std::prev(pos)->GetRange().Contains(load_addr)) {692return *std::prev(pos);693}694695if (pos == regions.begin())696region.GetRange().SetRangeBase(0);697else698region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd());699700if (pos == regions.end())701region.GetRange().SetRangeEnd(UINT64_MAX);702else703region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase());704705region.SetReadable(MemoryRegionInfo::eNo);706region.SetWritable(MemoryRegionInfo::eNo);707region.SetExecutable(MemoryRegionInfo::eNo);708region.SetMapped(MemoryRegionInfo::eNo);709return region;710}711712713