1 //===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "MinidumpParser.h"
10 #include "NtStructures.h"
11 #include "RegisterContextMinidump_x86_32.h"
12 
13 #include "lldb/Utility/LLDBAssert.h"
14 #include "Plugins/Process/Utility/LinuxProcMaps.h"
15 
16 // C includes
17 // C++ includes
18 #include <algorithm>
19 #include <map>
20 #include <vector>
21 #include <utility>
22 
23 using namespace lldb_private;
24 using namespace minidump;
25 
26 static llvm::Error stringError(llvm::StringRef Err) {
27   return llvm::make_error<llvm::StringError>(Err,
28                                              llvm::inconvertibleErrorCode());
29 }
30 
31 llvm::Expected<MinidumpParser>
32 MinidumpParser::Create(const lldb::DataBufferSP &data_sp) {
33   if (data_sp->GetByteSize() < sizeof(MinidumpHeader))
34     return stringError("Buffer too small.");
35 
36   llvm::ArrayRef<uint8_t> header_data(data_sp->GetBytes(),
37                                       sizeof(MinidumpHeader));
38   const MinidumpHeader *header = MinidumpHeader::Parse(header_data);
39   if (!header)
40     return stringError("invalid minidump: can't parse the header");
41 
42   // A minidump without at least one stream is clearly ill-formed
43   if (header->streams_count == 0)
44     return stringError("invalid minidump: no streams present");
45 
46   struct FileRange {
47     uint32_t offset = 0;
48     uint32_t size = 0;
49 
50     FileRange(uint32_t offset, uint32_t size) : offset(offset), size(size) {}
51     uint32_t end() const { return offset + size; }
52   };
53 
54   const uint32_t file_size = data_sp->GetByteSize();
55 
56   // Build a global minidump file map, checking for:
57   // - overlapping streams/data structures
58   // - truncation (streams pointing past the end of file)
59   std::vector<FileRange> minidump_map;
60 
61   minidump_map.emplace_back(0, sizeof(MinidumpHeader));
62 
63   // Add the directory entries to the file map
64   FileRange directory_range(header->stream_directory_rva,
65                             header->streams_count * sizeof(MinidumpDirectory));
66   if (directory_range.end() > file_size)
67     return stringError("invalid minidump: truncated streams directory");
68   minidump_map.push_back(directory_range);
69 
70   llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map;
71 
72   // Parse stream directory entries
73   llvm::ArrayRef<uint8_t> directory_data(
74       data_sp->GetBytes() + directory_range.offset, directory_range.size);
75   for (uint32_t i = 0; i < header->streams_count; ++i) {
76     const MinidumpDirectory *directory_entry = nullptr;
77     Status error = consumeObject(directory_data, directory_entry);
78     if (error.Fail())
79       return error.ToError();
80     if (directory_entry->stream_type == 0) {
81       // Ignore dummy streams (technically ill-formed, but a number of
82       // existing minidumps seem to contain such streams)
83       if (directory_entry->location.data_size == 0)
84         continue;
85       return stringError("invalid minidump: bad stream type");
86     }
87     // Update the streams map, checking for duplicate stream types
88     if (!directory_map
89              .insert({directory_entry->stream_type, directory_entry->location})
90              .second)
91       return stringError("invalid minidump: duplicate stream type");
92 
93     // Ignore the zero-length streams for layout checks
94     if (directory_entry->location.data_size != 0) {
95       minidump_map.emplace_back(directory_entry->location.rva,
96                                 directory_entry->location.data_size);
97     }
98   }
99 
100   // Sort the file map ranges by start offset
101   llvm::sort(minidump_map.begin(), minidump_map.end(),
102              [](const FileRange &a, const FileRange &b) {
103                return a.offset < b.offset;
104              });
105 
106   // Check for overlapping streams/data structures
107   for (size_t i = 1; i < minidump_map.size(); ++i) {
108     const auto &prev_range = minidump_map[i - 1];
109     if (prev_range.end() > minidump_map[i].offset)
110       return stringError("invalid minidump: overlapping streams");
111   }
112 
113   // Check for streams past the end of file
114   const auto &last_range = minidump_map.back();
115   if (last_range.end() > file_size)
116     return stringError("invalid minidump: truncated stream");
117 
118   return MinidumpParser(std::move(data_sp), std::move(directory_map));
119 }
120 
121 MinidumpParser::MinidumpParser(
122     lldb::DataBufferSP data_sp,
123     llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map)
124     : m_data_sp(std::move(data_sp)), m_directory_map(std::move(directory_map)) {
125 }
126 
127 llvm::ArrayRef<uint8_t> MinidumpParser::GetData() {
128   return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(),
129                                  m_data_sp->GetByteSize());
130 }
131 
132 llvm::ArrayRef<uint8_t>
133 MinidumpParser::GetStream(StreamType stream_type) {
134   auto iter = m_directory_map.find(static_cast<uint32_t>(stream_type));
135   if (iter == m_directory_map.end())
136     return {};
137 
138   // check if there is enough data
139   if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize())
140     return {};
141 
142   return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva,
143                                  iter->second.data_size);
144 }
145 
146 llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) {
147   auto arr_ref = m_data_sp->GetData();
148   if (rva > arr_ref.size())
149     return llvm::None;
150   arr_ref = arr_ref.drop_front(rva);
151   return parseMinidumpString(arr_ref);
152 }
153 
154 UUID MinidumpParser::GetModuleUUID(const MinidumpModule *module) {
155   auto cv_record =
156       GetData().slice(module->CV_record.rva, module->CV_record.data_size);
157 
158   // Read the CV record signature
159   const llvm::support::ulittle32_t *signature = nullptr;
160   Status error = consumeObject(cv_record, signature);
161   if (error.Fail())
162     return UUID();
163 
164   const CvSignature cv_signature =
165       static_cast<CvSignature>(static_cast<uint32_t>(*signature));
166 
167   if (cv_signature == CvSignature::Pdb70) {
168     const CvRecordPdb70 *pdb70_uuid = nullptr;
169     Status error = consumeObject(cv_record, pdb70_uuid);
170     if (error.Fail())
171       return UUID();
172     // If the age field is not zero, then include the entire pdb70_uuid struct
173     if (pdb70_uuid->Age != 0)
174       return UUID::fromData(pdb70_uuid, sizeof(*pdb70_uuid));
175 
176     // Many times UUIDs are all zeroes. This can cause more than one module
177     // to claim it has a valid UUID of all zeroes and causes the files to all
178     // merge into the first module that claims this valid zero UUID.
179     bool all_zeroes = true;
180     for (size_t i = 0; all_zeroes && i < sizeof(pdb70_uuid->Uuid); ++i)
181       all_zeroes = pdb70_uuid->Uuid[i] == 0;
182     if (all_zeroes)
183       return UUID();
184 
185     if (GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) {
186       // Breakpad incorrectly byte swaps the first 32 bit and next 2 16 bit
187       // values in the UUID field. Undo this so we can match things up
188       // with our symbol files
189       uint8_t apple_uuid[16];
190       // Byte swap the first 32 bits
191       apple_uuid[0] = pdb70_uuid->Uuid[3];
192       apple_uuid[1] = pdb70_uuid->Uuid[2];
193       apple_uuid[2] = pdb70_uuid->Uuid[1];
194       apple_uuid[3] = pdb70_uuid->Uuid[0];
195       // Byte swap the next 16 bit value
196       apple_uuid[4] = pdb70_uuid->Uuid[5];
197       apple_uuid[5] = pdb70_uuid->Uuid[4];
198       // Byte swap the next 16 bit value
199       apple_uuid[6] = pdb70_uuid->Uuid[7];
200       apple_uuid[7] = pdb70_uuid->Uuid[6];
201       for (size_t i = 8; i < sizeof(pdb70_uuid->Uuid); ++i)
202         apple_uuid[i] = pdb70_uuid->Uuid[i];
203       return UUID::fromData(apple_uuid, sizeof(apple_uuid));
204     }
205     return UUID::fromData(pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid));
206   } else if (cv_signature == CvSignature::ElfBuildId)
207     return UUID::fromOptionalData(cv_record);
208 
209   return UUID();
210 }
211 
212 llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() {
213   llvm::ArrayRef<uint8_t> data = GetStream(StreamType::ThreadList);
214 
215   if (data.size() == 0)
216     return llvm::None;
217 
218   return MinidumpThread::ParseThreadList(data);
219 }
220 
221 llvm::ArrayRef<uint8_t>
222 MinidumpParser::GetThreadContext(const MinidumpLocationDescriptor &location) {
223   if (location.rva + location.data_size > GetData().size())
224     return {};
225   return GetData().slice(location.rva, location.data_size);
226 }
227 
228 llvm::ArrayRef<uint8_t>
229 MinidumpParser::GetThreadContext(const MinidumpThread &td) {
230   return GetThreadContext(td.thread_context);
231 }
232 
233 llvm::ArrayRef<uint8_t>
234 MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) {
235   // On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If
236   // the minidump was captured with a 64-bit debugger, then the CONTEXT we just
237   // grabbed from the mini_dump_thread is the one for the 64-bit "native"
238   // process rather than the 32-bit "guest" process we care about.  In this
239   // case, we can get the 32-bit CONTEXT from the TEB (Thread Environment
240   // Block) of the 64-bit process.
241   auto teb_mem = GetMemory(td.teb, sizeof(TEB64));
242   if (teb_mem.empty())
243     return {};
244 
245   const TEB64 *wow64teb;
246   Status error = consumeObject(teb_mem, wow64teb);
247   if (error.Fail())
248     return {};
249 
250   // Slot 1 of the thread-local storage in the 64-bit TEB points to a structure
251   // that includes the 32-bit CONTEXT (after a ULONG). See:
252   // https://msdn.microsoft.com/en-us/library/ms681670.aspx
253   auto context =
254       GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32));
255   if (context.size() < sizeof(MinidumpContext_x86_32))
256     return {};
257 
258   return context;
259   // NOTE:  We don't currently use the TEB for anything else.  If we
260   // need it in the future, the 32-bit TEB is located according to the address
261   // stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]).
262 }
263 
264 const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
265   llvm::ArrayRef<uint8_t> data = GetStream(StreamType::SystemInfo);
266 
267   if (data.size() == 0)
268     return nullptr;
269 
270   return MinidumpSystemInfo::Parse(data);
271 }
272 
273 ArchSpec MinidumpParser::GetArchitecture() {
274   if (m_arch.IsValid())
275     return m_arch;
276 
277   // Set the architecture in m_arch
278   const MinidumpSystemInfo *system_info = GetSystemInfo();
279 
280   if (!system_info)
281     return m_arch;
282 
283   // TODO what to do about big endiand flavors of arm ?
284   // TODO set the arm subarch stuff if the minidump has info about it
285 
286   llvm::Triple triple;
287   triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
288 
289   auto arch = static_cast<ProcessorArchitecture>(
290       static_cast<uint32_t>(system_info->processor_arch));
291 
292   switch (arch) {
293   case ProcessorArchitecture::X86:
294     triple.setArch(llvm::Triple::ArchType::x86);
295     break;
296   case ProcessorArchitecture::AMD64:
297     triple.setArch(llvm::Triple::ArchType::x86_64);
298     break;
299   case ProcessorArchitecture::ARM:
300     triple.setArch(llvm::Triple::ArchType::arm);
301     break;
302   case ProcessorArchitecture::ARM64:
303     triple.setArch(llvm::Triple::ArchType::aarch64);
304     break;
305   default:
306     triple.setArch(llvm::Triple::ArchType::UnknownArch);
307     break;
308   }
309 
310   auto os =
311       static_cast<OSPlatform>(static_cast<uint32_t>(system_info->platform_id));
312 
313   // TODO add all of the OSes that Minidump/breakpad distinguishes?
314   switch (os) {
315   case OSPlatform::Win32S:
316   case OSPlatform::Win32Windows:
317   case OSPlatform::Win32NT:
318   case OSPlatform::Win32CE:
319     triple.setOS(llvm::Triple::OSType::Win32);
320     break;
321   case OSPlatform::Linux:
322     triple.setOS(llvm::Triple::OSType::Linux);
323     break;
324   case OSPlatform::MacOSX:
325     triple.setOS(llvm::Triple::OSType::MacOSX);
326     triple.setVendor(llvm::Triple::Apple);
327     break;
328   case OSPlatform::IOS:
329     triple.setOS(llvm::Triple::OSType::IOS);
330     triple.setVendor(llvm::Triple::Apple);
331     break;
332   case OSPlatform::Android:
333     triple.setOS(llvm::Triple::OSType::Linux);
334     triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
335     break;
336   default: {
337     triple.setOS(llvm::Triple::OSType::UnknownOS);
338     std::string csd_version;
339     if (auto s = GetMinidumpString(system_info->csd_version_rva))
340       csd_version = *s;
341     if (csd_version.find("Linux") != std::string::npos)
342       triple.setOS(llvm::Triple::OSType::Linux);
343     break;
344     }
345   }
346   m_arch.SetTriple(triple);
347   return m_arch;
348 }
349 
350 const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
351   llvm::ArrayRef<uint8_t> data = GetStream(StreamType::MiscInfo);
352 
353   if (data.size() == 0)
354     return nullptr;
355 
356   return MinidumpMiscInfo::Parse(data);
357 }
358 
359 llvm::Optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {
360   llvm::ArrayRef<uint8_t> data = GetStream(StreamType::LinuxProcStatus);
361 
362   if (data.size() == 0)
363     return llvm::None;
364 
365   return LinuxProcStatus::Parse(data);
366 }
367 
368 llvm::Optional<lldb::pid_t> MinidumpParser::GetPid() {
369   const MinidumpMiscInfo *misc_info = GetMiscInfo();
370   if (misc_info != nullptr) {
371     return misc_info->GetPid();
372   }
373 
374   llvm::Optional<LinuxProcStatus> proc_status = GetLinuxProcStatus();
375   if (proc_status.hasValue()) {
376     return proc_status->GetPid();
377   }
378 
379   return llvm::None;
380 }
381 
382 llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() {
383   llvm::ArrayRef<uint8_t> data = GetStream(StreamType::ModuleList);
384 
385   if (data.size() == 0)
386     return {};
387 
388   return MinidumpModule::ParseModuleList(data);
389 }
390 
391 std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() {
392   llvm::ArrayRef<MinidumpModule> modules = GetModuleList();
393   // map module_name -> filtered_modules index
394   typedef llvm::StringMap<size_t> MapType;
395   MapType module_name_to_filtered_index;
396 
397   std::vector<const MinidumpModule *> filtered_modules;
398 
399   llvm::Optional<std::string> name;
400   std::string module_name;
401 
402   for (const auto &module : modules) {
403     name = GetMinidumpString(module.module_name_rva);
404 
405     if (!name)
406       continue;
407 
408     module_name = name.getValue();
409 
410     MapType::iterator iter;
411     bool inserted;
412     // See if we have inserted this module aready into filtered_modules. If we
413     // haven't insert an entry into module_name_to_filtered_index with the
414     // index where we will insert it if it isn't in the vector already.
415     std::tie(iter, inserted) = module_name_to_filtered_index.try_emplace(
416         module_name, filtered_modules.size());
417 
418     if (inserted) {
419       // This module has not been seen yet, insert it into filtered_modules at
420       // the index that was inserted into module_name_to_filtered_index using
421       // "filtered_modules.size()" above.
422       filtered_modules.push_back(&module);
423     } else {
424       // This module has been seen. Modules are sometimes mentioned multiple
425       // times when they are mapped discontiguously, so find the module with
426       // the lowest "base_of_image" and use that as the filtered module.
427       auto dup_module = filtered_modules[iter->second];
428       if (module.base_of_image < dup_module->base_of_image)
429         filtered_modules[iter->second] = &module;
430     }
431   }
432   return filtered_modules;
433 }
434 
435 const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() {
436   llvm::ArrayRef<uint8_t> data = GetStream(StreamType::Exception);
437 
438   if (data.size() == 0)
439     return nullptr;
440 
441   return MinidumpExceptionStream::Parse(data);
442 }
443 
444 llvm::Optional<minidump::Range>
445 MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
446   llvm::ArrayRef<uint8_t> data = GetStream(StreamType::MemoryList);
447   llvm::ArrayRef<uint8_t> data64 = GetStream(StreamType::Memory64List);
448 
449   if (data.empty() && data64.empty())
450     return llvm::None;
451 
452   if (!data.empty()) {
453     llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list =
454         MinidumpMemoryDescriptor::ParseMemoryList(data);
455 
456     if (memory_list.empty())
457       return llvm::None;
458 
459     for (const auto &memory_desc : memory_list) {
460       const MinidumpLocationDescriptor &loc_desc = memory_desc.memory;
461       const lldb::addr_t range_start = memory_desc.start_of_memory_range;
462       const size_t range_size = loc_desc.data_size;
463 
464       if (loc_desc.rva + loc_desc.data_size > GetData().size())
465         return llvm::None;
466 
467       if (range_start <= addr && addr < range_start + range_size) {
468         return minidump::Range(range_start,
469                                GetData().slice(loc_desc.rva, range_size));
470       }
471     }
472   }
473 
474   // Some Minidumps have a Memory64ListStream that captures all the heap memory
475   // (full-memory Minidumps).  We can't exactly use the same loop as above,
476   // because the Minidump uses slightly different data structures to describe
477   // those
478 
479   if (!data64.empty()) {
480     llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
481     uint64_t base_rva;
482     std::tie(memory64_list, base_rva) =
483         MinidumpMemoryDescriptor64::ParseMemory64List(data64);
484 
485     if (memory64_list.empty())
486       return llvm::None;
487 
488     for (const auto &memory_desc64 : memory64_list) {
489       const lldb::addr_t range_start = memory_desc64.start_of_memory_range;
490       const size_t range_size = memory_desc64.data_size;
491 
492       if (base_rva + range_size > GetData().size())
493         return llvm::None;
494 
495       if (range_start <= addr && addr < range_start + range_size) {
496         return minidump::Range(range_start,
497                                GetData().slice(base_rva, range_size));
498       }
499       base_rva += range_size;
500     }
501   }
502 
503   return llvm::None;
504 }
505 
506 llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
507                                                   size_t size) {
508   // I don't have a sense of how frequently this is called or how many memory
509   // ranges a Minidump typically has, so I'm not sure if searching for the
510   // appropriate range linearly each time is stupid.  Perhaps we should build
511   // an index for faster lookups.
512   llvm::Optional<minidump::Range> range = FindMemoryRange(addr);
513   if (!range)
514     return {};
515 
516   // There's at least some overlap between the beginning of the desired range
517   // (addr) and the current range.  Figure out where the overlap begins and how
518   // much overlap there is.
519 
520   const size_t offset = addr - range->start;
521 
522   if (addr < range->start || offset >= range->range_ref.size())
523     return {};
524 
525   const size_t overlap = std::min(size, range->range_ref.size() - offset);
526   return range->range_ref.slice(offset, overlap);
527 }
528 
529 static bool
530 CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,
531                                 std::vector<MemoryRegionInfo> &regions) {
532   auto data = parser.GetStream(StreamType::LinuxMaps);
533   if (data.empty())
534     return false;
535   ParseLinuxMapRegions(llvm::toStringRef(data),
536                        [&](const lldb_private::MemoryRegionInfo &region,
537                            const lldb_private::Status &status) -> bool {
538     if (status.Success())
539       regions.push_back(region);
540     return true;
541   });
542   return !regions.empty();
543 }
544 
545 static bool
546 CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,
547                                      std::vector<MemoryRegionInfo> &regions) {
548   auto data = parser.GetStream(StreamType::MemoryInfoList);
549   if (data.empty())
550     return false;
551   auto mem_info_list = MinidumpMemoryInfo::ParseMemoryInfoList(data);
552   if (mem_info_list.empty())
553     return false;
554   constexpr auto yes = MemoryRegionInfo::eYes;
555   constexpr auto no = MemoryRegionInfo::eNo;
556   regions.reserve(mem_info_list.size());
557   for (const auto &entry : mem_info_list) {
558     MemoryRegionInfo region;
559     region.GetRange().SetRangeBase(entry->base_address);
560     region.GetRange().SetByteSize(entry->region_size);
561     region.SetReadable(entry->isReadable() ? yes : no);
562     region.SetWritable(entry->isWritable() ? yes : no);
563     region.SetExecutable(entry->isExecutable() ? yes : no);
564     region.SetMapped(entry->isMapped() ? yes : no);
565     regions.push_back(region);
566   }
567   return !regions.empty();
568 }
569 
570 static bool
571 CreateRegionsCacheFromMemoryList(MinidumpParser &parser,
572                                  std::vector<MemoryRegionInfo> &regions) {
573   auto data = parser.GetStream(StreamType::MemoryList);
574   if (data.empty())
575     return false;
576   auto memory_list = MinidumpMemoryDescriptor::ParseMemoryList(data);
577   if (memory_list.empty())
578     return false;
579   regions.reserve(memory_list.size());
580   for (const auto &memory_desc : memory_list) {
581     if (memory_desc.memory.data_size == 0)
582       continue;
583     MemoryRegionInfo region;
584     region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);
585     region.GetRange().SetByteSize(memory_desc.memory.data_size);
586     region.SetReadable(MemoryRegionInfo::eYes);
587     region.SetMapped(MemoryRegionInfo::eYes);
588     regions.push_back(region);
589   }
590   regions.shrink_to_fit();
591   return !regions.empty();
592 }
593 
594 static bool
595 CreateRegionsCacheFromMemory64List(MinidumpParser &parser,
596                                    std::vector<MemoryRegionInfo> &regions) {
597   llvm::ArrayRef<uint8_t> data =
598       parser.GetStream(StreamType::Memory64List);
599   if (data.empty())
600     return false;
601   llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
602   uint64_t base_rva;
603   std::tie(memory64_list, base_rva) =
604       MinidumpMemoryDescriptor64::ParseMemory64List(data);
605 
606   if (memory64_list.empty())
607     return false;
608 
609   regions.reserve(memory64_list.size());
610   for (const auto &memory_desc : memory64_list) {
611     if (memory_desc.data_size == 0)
612       continue;
613     MemoryRegionInfo region;
614     region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);
615     region.GetRange().SetByteSize(memory_desc.data_size);
616     region.SetReadable(MemoryRegionInfo::eYes);
617     region.SetMapped(MemoryRegionInfo::eYes);
618     regions.push_back(region);
619   }
620   regions.shrink_to_fit();
621   return !regions.empty();
622 }
623 
624 MemoryRegionInfo
625 MinidumpParser::FindMemoryRegion(lldb::addr_t load_addr) const {
626   auto begin = m_regions.begin();
627   auto end = m_regions.end();
628   auto pos = std::lower_bound(begin, end, load_addr);
629   if (pos != end && pos->GetRange().Contains(load_addr))
630     return *pos;
631 
632   MemoryRegionInfo region;
633   if (pos == begin)
634     region.GetRange().SetRangeBase(0);
635   else {
636     auto prev = pos - 1;
637     if (prev->GetRange().Contains(load_addr))
638       return *prev;
639     region.GetRange().SetRangeBase(prev->GetRange().GetRangeEnd());
640   }
641   if (pos == end)
642     region.GetRange().SetRangeEnd(UINT64_MAX);
643   else
644     region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase());
645   region.SetReadable(MemoryRegionInfo::eNo);
646   region.SetWritable(MemoryRegionInfo::eNo);
647   region.SetExecutable(MemoryRegionInfo::eNo);
648   region.SetMapped(MemoryRegionInfo::eNo);
649   return region;
650 }
651 
652 MemoryRegionInfo
653 MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) {
654   if (!m_parsed_regions)
655     GetMemoryRegions();
656   return FindMemoryRegion(load_addr);
657 }
658 
659 const MemoryRegionInfos &MinidumpParser::GetMemoryRegions() {
660   if (!m_parsed_regions) {
661     m_parsed_regions = true;
662     // We haven't cached our memory regions yet we will create the region cache
663     // once. We create the region cache using the best source. We start with
664     // the linux maps since they are the most complete and have names for the
665     // regions. Next we try the MemoryInfoList since it has
666     // read/write/execute/map data, and then fall back to the MemoryList and
667     // Memory64List to just get a list of the memory that is mapped in this
668     // core file
669     if (!CreateRegionsCacheFromLinuxMaps(*this, m_regions))
670       if (!CreateRegionsCacheFromMemoryInfoList(*this, m_regions))
671         if (!CreateRegionsCacheFromMemoryList(*this, m_regions))
672           CreateRegionsCacheFromMemory64List(*this, m_regions);
673     llvm::sort(m_regions.begin(), m_regions.end());
674   }
675   return m_regions;
676 }
677 
678 #define ENUM_TO_CSTR(ST) case (uint32_t)StreamType::ST: return #ST
679 
680 llvm::StringRef
681 MinidumpParser::GetStreamTypeAsString(uint32_t stream_type) {
682   switch (stream_type) {
683     ENUM_TO_CSTR(Unused);
684     ENUM_TO_CSTR(ThreadList);
685     ENUM_TO_CSTR(ModuleList);
686     ENUM_TO_CSTR(MemoryList);
687     ENUM_TO_CSTR(Exception);
688     ENUM_TO_CSTR(SystemInfo);
689     ENUM_TO_CSTR(ThreadExList);
690     ENUM_TO_CSTR(Memory64List);
691     ENUM_TO_CSTR(CommentA);
692     ENUM_TO_CSTR(CommentW);
693     ENUM_TO_CSTR(HandleData);
694     ENUM_TO_CSTR(FunctionTable);
695     ENUM_TO_CSTR(UnloadedModuleList);
696     ENUM_TO_CSTR(MiscInfo);
697     ENUM_TO_CSTR(MemoryInfoList);
698     ENUM_TO_CSTR(ThreadInfoList);
699     ENUM_TO_CSTR(HandleOperationList);
700     ENUM_TO_CSTR(Token);
701     ENUM_TO_CSTR(JavascriptData);
702     ENUM_TO_CSTR(SystemMemoryInfo);
703     ENUM_TO_CSTR(ProcessVMCounters);
704     ENUM_TO_CSTR(BreakpadInfo);
705     ENUM_TO_CSTR(AssertionInfo);
706     ENUM_TO_CSTR(LinuxCPUInfo);
707     ENUM_TO_CSTR(LinuxProcStatus);
708     ENUM_TO_CSTR(LinuxLSBRelease);
709     ENUM_TO_CSTR(LinuxCMDLine);
710     ENUM_TO_CSTR(LinuxEnviron);
711     ENUM_TO_CSTR(LinuxAuxv);
712     ENUM_TO_CSTR(LinuxMaps);
713     ENUM_TO_CSTR(LinuxDSODebug);
714     ENUM_TO_CSTR(LinuxProcStat);
715     ENUM_TO_CSTR(LinuxProcUptime);
716     ENUM_TO_CSTR(LinuxProcFD);
717     ENUM_TO_CSTR(FacebookAppCustomData);
718     ENUM_TO_CSTR(FacebookBuildID);
719     ENUM_TO_CSTR(FacebookAppVersionName);
720     ENUM_TO_CSTR(FacebookJavaStack);
721     ENUM_TO_CSTR(FacebookDalvikInfo);
722     ENUM_TO_CSTR(FacebookUnwindSymbols);
723     ENUM_TO_CSTR(FacebookDumpErrorLog);
724     ENUM_TO_CSTR(FacebookAppStateLog);
725     ENUM_TO_CSTR(FacebookAbortReason);
726     ENUM_TO_CSTR(FacebookThreadName);
727     ENUM_TO_CSTR(FacebookLogcat);
728   }
729   return "unknown stream type";
730 }
731