brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.2 KiB · 58ebb7b Raw
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> &regions) {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      [&regions, &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 &regions,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> &regions) {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> &regions) {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 &regions,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