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(MinidumpStreamType 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<const uint32_t>(*signature));
166 
167   if (cv_signature == CvSignature::Pdb70) {
168     // PDB70 record
169     const CvRecordPdb70 *pdb70_uuid = nullptr;
170     Status error = consumeObject(cv_record, pdb70_uuid);
171     if (!error.Fail()) {
172       auto arch = GetArchitecture();
173       // For Apple targets we only need a 16 byte UUID so that we can match
174       // the UUID in the Module to actual UUIDs from the built binaries. The
175       // "Age" field is zero in breakpad minidump files for Apple targets, so
176       // we restrict the UUID to the "Uuid" field so we have a UUID we can use
177       // to match.
178       if (arch.GetTriple().getVendor() == llvm::Triple::Apple)
179         return UUID::fromData(pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid));
180       else
181         return UUID::fromData(pdb70_uuid, sizeof(*pdb70_uuid));
182     }
183   } else if (cv_signature == CvSignature::ElfBuildId)
184     return UUID::fromData(cv_record);
185 
186   return UUID();
187 }
188 
189 llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() {
190   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList);
191 
192   if (data.size() == 0)
193     return llvm::None;
194 
195   return MinidumpThread::ParseThreadList(data);
196 }
197 
198 llvm::ArrayRef<uint8_t>
199 MinidumpParser::GetThreadContext(const MinidumpLocationDescriptor &location) {
200   if (location.rva + location.data_size > GetData().size())
201     return {};
202   return GetData().slice(location.rva, location.data_size);
203 }
204 
205 llvm::ArrayRef<uint8_t>
206 MinidumpParser::GetThreadContext(const MinidumpThread &td) {
207   return GetThreadContext(td.thread_context);
208 }
209 
210 llvm::ArrayRef<uint8_t>
211 MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) {
212   // On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If
213   // the minidump was captured with a 64-bit debugger, then the CONTEXT we just
214   // grabbed from the mini_dump_thread is the one for the 64-bit "native"
215   // process rather than the 32-bit "guest" process we care about.  In this
216   // case, we can get the 32-bit CONTEXT from the TEB (Thread Environment
217   // Block) of the 64-bit process.
218   auto teb_mem = GetMemory(td.teb, sizeof(TEB64));
219   if (teb_mem.empty())
220     return {};
221 
222   const TEB64 *wow64teb;
223   Status error = consumeObject(teb_mem, wow64teb);
224   if (error.Fail())
225     return {};
226 
227   // Slot 1 of the thread-local storage in the 64-bit TEB points to a structure
228   // that includes the 32-bit CONTEXT (after a ULONG). See:
229   // https://msdn.microsoft.com/en-us/library/ms681670.aspx
230   auto context =
231       GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32));
232   if (context.size() < sizeof(MinidumpContext_x86_32))
233     return {};
234 
235   return context;
236   // NOTE:  We don't currently use the TEB for anything else.  If we
237   // need it in the future, the 32-bit TEB is located according to the address
238   // stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]).
239 }
240 
241 const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
242   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo);
243 
244   if (data.size() == 0)
245     return nullptr;
246 
247   return MinidumpSystemInfo::Parse(data);
248 }
249 
250 ArchSpec MinidumpParser::GetArchitecture() {
251   if (m_arch.IsValid())
252     return m_arch;
253 
254   // Set the architecture in m_arch
255   const MinidumpSystemInfo *system_info = GetSystemInfo();
256 
257   if (!system_info)
258     return m_arch;
259 
260   // TODO what to do about big endiand flavors of arm ?
261   // TODO set the arm subarch stuff if the minidump has info about it
262 
263   llvm::Triple triple;
264   triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
265 
266   const MinidumpCPUArchitecture arch =
267       static_cast<const MinidumpCPUArchitecture>(
268           static_cast<const uint32_t>(system_info->processor_arch));
269 
270   switch (arch) {
271   case MinidumpCPUArchitecture::X86:
272     triple.setArch(llvm::Triple::ArchType::x86);
273     break;
274   case MinidumpCPUArchitecture::AMD64:
275     triple.setArch(llvm::Triple::ArchType::x86_64);
276     break;
277   case MinidumpCPUArchitecture::ARM:
278     triple.setArch(llvm::Triple::ArchType::arm);
279     break;
280   case MinidumpCPUArchitecture::ARM64:
281     triple.setArch(llvm::Triple::ArchType::aarch64);
282     break;
283   default:
284     triple.setArch(llvm::Triple::ArchType::UnknownArch);
285     break;
286   }
287 
288   const MinidumpOSPlatform os = static_cast<const MinidumpOSPlatform>(
289       static_cast<const uint32_t>(system_info->platform_id));
290 
291   // TODO add all of the OSes that Minidump/breakpad distinguishes?
292   switch (os) {
293   case MinidumpOSPlatform::Win32S:
294   case MinidumpOSPlatform::Win32Windows:
295   case MinidumpOSPlatform::Win32NT:
296   case MinidumpOSPlatform::Win32CE:
297     triple.setOS(llvm::Triple::OSType::Win32);
298     break;
299   case MinidumpOSPlatform::Linux:
300     triple.setOS(llvm::Triple::OSType::Linux);
301     break;
302   case MinidumpOSPlatform::MacOSX:
303     triple.setOS(llvm::Triple::OSType::MacOSX);
304     triple.setVendor(llvm::Triple::Apple);
305     break;
306   case MinidumpOSPlatform::IOS:
307     triple.setOS(llvm::Triple::OSType::IOS);
308     triple.setVendor(llvm::Triple::Apple);
309     break;
310   case MinidumpOSPlatform::Android:
311     triple.setOS(llvm::Triple::OSType::Linux);
312     triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
313     break;
314   default: {
315     triple.setOS(llvm::Triple::OSType::UnknownOS);
316     std::string csd_version;
317     if (auto s = GetMinidumpString(system_info->csd_version_rva))
318       csd_version = *s;
319     if (csd_version.find("Linux") != std::string::npos)
320       triple.setOS(llvm::Triple::OSType::Linux);
321     break;
322     }
323   }
324   m_arch.SetTriple(triple);
325   return m_arch;
326 }
327 
328 const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
329   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MiscInfo);
330 
331   if (data.size() == 0)
332     return nullptr;
333 
334   return MinidumpMiscInfo::Parse(data);
335 }
336 
337 llvm::Optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {
338   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::LinuxProcStatus);
339 
340   if (data.size() == 0)
341     return llvm::None;
342 
343   return LinuxProcStatus::Parse(data);
344 }
345 
346 llvm::Optional<lldb::pid_t> MinidumpParser::GetPid() {
347   const MinidumpMiscInfo *misc_info = GetMiscInfo();
348   if (misc_info != nullptr) {
349     return misc_info->GetPid();
350   }
351 
352   llvm::Optional<LinuxProcStatus> proc_status = GetLinuxProcStatus();
353   if (proc_status.hasValue()) {
354     return proc_status->GetPid();
355   }
356 
357   return llvm::None;
358 }
359 
360 llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() {
361   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ModuleList);
362 
363   if (data.size() == 0)
364     return {};
365 
366   return MinidumpModule::ParseModuleList(data);
367 }
368 
369 std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() {
370   llvm::ArrayRef<MinidumpModule> modules = GetModuleList();
371   // map module_name -> filtered_modules index
372   typedef llvm::StringMap<size_t> MapType;
373   MapType module_name_to_filtered_index;
374 
375   std::vector<const MinidumpModule *> filtered_modules;
376 
377   llvm::Optional<std::string> name;
378   std::string module_name;
379 
380   for (const auto &module : modules) {
381     name = GetMinidumpString(module.module_name_rva);
382 
383     if (!name)
384       continue;
385 
386     module_name = name.getValue();
387 
388     MapType::iterator iter;
389     bool inserted;
390     // See if we have inserted this module aready into filtered_modules. If we
391     // haven't insert an entry into module_name_to_filtered_index with the
392     // index where we will insert it if it isn't in the vector already.
393     std::tie(iter, inserted) = module_name_to_filtered_index.try_emplace(
394         module_name, filtered_modules.size());
395 
396     if (inserted) {
397       // This module has not been seen yet, insert it into filtered_modules at
398       // the index that was inserted into module_name_to_filtered_index using
399       // "filtered_modules.size()" above.
400       filtered_modules.push_back(&module);
401     } else {
402       // This module has been seen. Modules are sometimes mentioned multiple
403       // times when they are mapped discontiguously, so find the module with
404       // the lowest "base_of_image" and use that as the filtered module.
405       auto dup_module = filtered_modules[iter->second];
406       if (module.base_of_image < dup_module->base_of_image)
407         filtered_modules[iter->second] = &module;
408     }
409   }
410   return filtered_modules;
411 }
412 
413 const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() {
414   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::Exception);
415 
416   if (data.size() == 0)
417     return nullptr;
418 
419   return MinidumpExceptionStream::Parse(data);
420 }
421 
422 llvm::Optional<minidump::Range>
423 MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
424   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryList);
425   llvm::ArrayRef<uint8_t> data64 = GetStream(MinidumpStreamType::Memory64List);
426 
427   if (data.empty() && data64.empty())
428     return llvm::None;
429 
430   if (!data.empty()) {
431     llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list =
432         MinidumpMemoryDescriptor::ParseMemoryList(data);
433 
434     if (memory_list.empty())
435       return llvm::None;
436 
437     for (const auto &memory_desc : memory_list) {
438       const MinidumpLocationDescriptor &loc_desc = memory_desc.memory;
439       const lldb::addr_t range_start = memory_desc.start_of_memory_range;
440       const size_t range_size = loc_desc.data_size;
441 
442       if (loc_desc.rva + loc_desc.data_size > GetData().size())
443         return llvm::None;
444 
445       if (range_start <= addr && addr < range_start + range_size) {
446         return minidump::Range(range_start,
447                                GetData().slice(loc_desc.rva, range_size));
448       }
449     }
450   }
451 
452   // Some Minidumps have a Memory64ListStream that captures all the heap memory
453   // (full-memory Minidumps).  We can't exactly use the same loop as above,
454   // because the Minidump uses slightly different data structures to describe
455   // those
456 
457   if (!data64.empty()) {
458     llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
459     uint64_t base_rva;
460     std::tie(memory64_list, base_rva) =
461         MinidumpMemoryDescriptor64::ParseMemory64List(data64);
462 
463     if (memory64_list.empty())
464       return llvm::None;
465 
466     for (const auto &memory_desc64 : memory64_list) {
467       const lldb::addr_t range_start = memory_desc64.start_of_memory_range;
468       const size_t range_size = memory_desc64.data_size;
469 
470       if (base_rva + range_size > GetData().size())
471         return llvm::None;
472 
473       if (range_start <= addr && addr < range_start + range_size) {
474         return minidump::Range(range_start,
475                                GetData().slice(base_rva, range_size));
476       }
477       base_rva += range_size;
478     }
479   }
480 
481   return llvm::None;
482 }
483 
484 llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
485                                                   size_t size) {
486   // I don't have a sense of how frequently this is called or how many memory
487   // ranges a Minidump typically has, so I'm not sure if searching for the
488   // appropriate range linearly each time is stupid.  Perhaps we should build
489   // an index for faster lookups.
490   llvm::Optional<minidump::Range> range = FindMemoryRange(addr);
491   if (!range)
492     return {};
493 
494   // There's at least some overlap between the beginning of the desired range
495   // (addr) and the current range.  Figure out where the overlap begins and how
496   // much overlap there is.
497 
498   const size_t offset = addr - range->start;
499 
500   if (addr < range->start || offset >= range->range_ref.size())
501     return {};
502 
503   const size_t overlap = std::min(size, range->range_ref.size() - offset);
504   return range->range_ref.slice(offset, overlap);
505 }
506 
507 static bool
508 CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,
509                                 std::vector<MemoryRegionInfo> &regions) {
510   auto data = parser.GetStream(MinidumpStreamType::LinuxMaps);
511   if (data.empty())
512     return false;
513   ParseLinuxMapRegions(llvm::toStringRef(data),
514                        [&](const lldb_private::MemoryRegionInfo &region,
515                            const lldb_private::Status &status) -> bool {
516     if (status.Success())
517       regions.push_back(region);
518     return true;
519   });
520   return !regions.empty();
521 }
522 
523 static bool
524 CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,
525                                      std::vector<MemoryRegionInfo> &regions) {
526   auto data = parser.GetStream(MinidumpStreamType::MemoryInfoList);
527   if (data.empty())
528     return false;
529   auto mem_info_list = MinidumpMemoryInfo::ParseMemoryInfoList(data);
530   if (mem_info_list.empty())
531     return false;
532   constexpr auto yes = MemoryRegionInfo::eYes;
533   constexpr auto no = MemoryRegionInfo::eNo;
534   regions.reserve(mem_info_list.size());
535   for (const auto &entry : mem_info_list) {
536     MemoryRegionInfo region;
537     region.GetRange().SetRangeBase(entry->base_address);
538     region.GetRange().SetByteSize(entry->region_size);
539     region.SetReadable(entry->isReadable() ? yes : no);
540     region.SetWritable(entry->isWritable() ? yes : no);
541     region.SetExecutable(entry->isExecutable() ? yes : no);
542     region.SetMapped(entry->isMapped() ? yes : no);
543     regions.push_back(region);
544   }
545   return !regions.empty();
546 }
547 
548 static bool
549 CreateRegionsCacheFromMemoryList(MinidumpParser &parser,
550                                  std::vector<MemoryRegionInfo> &regions) {
551   auto data = parser.GetStream(MinidumpStreamType::MemoryList);
552   if (data.empty())
553     return false;
554   auto memory_list = MinidumpMemoryDescriptor::ParseMemoryList(data);
555   if (memory_list.empty())
556     return false;
557   regions.reserve(memory_list.size());
558   for (const auto &memory_desc : memory_list) {
559     if (memory_desc.memory.data_size == 0)
560       continue;
561     MemoryRegionInfo region;
562     region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);
563     region.GetRange().SetByteSize(memory_desc.memory.data_size);
564     region.SetReadable(MemoryRegionInfo::eYes);
565     region.SetMapped(MemoryRegionInfo::eYes);
566     regions.push_back(region);
567   }
568   regions.shrink_to_fit();
569   return !regions.empty();
570 }
571 
572 static bool
573 CreateRegionsCacheFromMemory64List(MinidumpParser &parser,
574                                    std::vector<MemoryRegionInfo> &regions) {
575   llvm::ArrayRef<uint8_t> data =
576       parser.GetStream(MinidumpStreamType::Memory64List);
577   if (data.empty())
578     return false;
579   llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
580   uint64_t base_rva;
581   std::tie(memory64_list, base_rva) =
582       MinidumpMemoryDescriptor64::ParseMemory64List(data);
583 
584   if (memory64_list.empty())
585     return false;
586 
587   regions.reserve(memory64_list.size());
588   for (const auto &memory_desc : memory64_list) {
589     if (memory_desc.data_size == 0)
590       continue;
591     MemoryRegionInfo region;
592     region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);
593     region.GetRange().SetByteSize(memory_desc.data_size);
594     region.SetReadable(MemoryRegionInfo::eYes);
595     region.SetMapped(MemoryRegionInfo::eYes);
596     regions.push_back(region);
597   }
598   regions.shrink_to_fit();
599   return !regions.empty();
600 }
601 
602 MemoryRegionInfo
603 MinidumpParser::FindMemoryRegion(lldb::addr_t load_addr) const {
604   auto begin = m_regions.begin();
605   auto end = m_regions.end();
606   auto pos = std::lower_bound(begin, end, load_addr);
607   if (pos != end && pos->GetRange().Contains(load_addr))
608     return *pos;
609 
610   MemoryRegionInfo region;
611   if (pos == begin)
612     region.GetRange().SetRangeBase(0);
613   else {
614     auto prev = pos - 1;
615     if (prev->GetRange().Contains(load_addr))
616       return *prev;
617     region.GetRange().SetRangeBase(prev->GetRange().GetRangeEnd());
618   }
619   if (pos == end)
620     region.GetRange().SetRangeEnd(UINT64_MAX);
621   else
622     region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase());
623   region.SetReadable(MemoryRegionInfo::eNo);
624   region.SetWritable(MemoryRegionInfo::eNo);
625   region.SetExecutable(MemoryRegionInfo::eNo);
626   region.SetMapped(MemoryRegionInfo::eNo);
627   return region;
628 }
629 
630 MemoryRegionInfo
631 MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) {
632   if (!m_parsed_regions)
633     GetMemoryRegions();
634   return FindMemoryRegion(load_addr);
635 }
636 
637 const MemoryRegionInfos &MinidumpParser::GetMemoryRegions() {
638   if (!m_parsed_regions) {
639     m_parsed_regions = true;
640     // We haven't cached our memory regions yet we will create the region cache
641     // once. We create the region cache using the best source. We start with
642     // the linux maps since they are the most complete and have names for the
643     // regions. Next we try the MemoryInfoList since it has
644     // read/write/execute/map data, and then fall back to the MemoryList and
645     // Memory64List to just get a list of the memory that is mapped in this
646     // core file
647     if (!CreateRegionsCacheFromLinuxMaps(*this, m_regions))
648       if (!CreateRegionsCacheFromMemoryInfoList(*this, m_regions))
649         if (!CreateRegionsCacheFromMemoryList(*this, m_regions))
650           CreateRegionsCacheFromMemory64List(*this, m_regions);
651     llvm::sort(m_regions.begin(), m_regions.end());
652   }
653   return m_regions;
654 }
655 
656 #define ENUM_TO_CSTR(ST) case (uint32_t)MinidumpStreamType::ST: return #ST
657 
658 llvm::StringRef
659 MinidumpParser::GetStreamTypeAsString(uint32_t stream_type) {
660   switch (stream_type) {
661     ENUM_TO_CSTR(Unused);
662     ENUM_TO_CSTR(Reserved0);
663     ENUM_TO_CSTR(Reserved1);
664     ENUM_TO_CSTR(ThreadList);
665     ENUM_TO_CSTR(ModuleList);
666     ENUM_TO_CSTR(MemoryList);
667     ENUM_TO_CSTR(Exception);
668     ENUM_TO_CSTR(SystemInfo);
669     ENUM_TO_CSTR(ThreadExList);
670     ENUM_TO_CSTR(Memory64List);
671     ENUM_TO_CSTR(CommentA);
672     ENUM_TO_CSTR(CommentW);
673     ENUM_TO_CSTR(HandleData);
674     ENUM_TO_CSTR(FunctionTable);
675     ENUM_TO_CSTR(UnloadedModuleList);
676     ENUM_TO_CSTR(MiscInfo);
677     ENUM_TO_CSTR(MemoryInfoList);
678     ENUM_TO_CSTR(ThreadInfoList);
679     ENUM_TO_CSTR(HandleOperationList);
680     ENUM_TO_CSTR(Token);
681     ENUM_TO_CSTR(JavascriptData);
682     ENUM_TO_CSTR(SystemMemoryInfo);
683     ENUM_TO_CSTR(ProcessVMCounters);
684     ENUM_TO_CSTR(BreakpadInfo);
685     ENUM_TO_CSTR(AssertionInfo);
686     ENUM_TO_CSTR(LinuxCPUInfo);
687     ENUM_TO_CSTR(LinuxProcStatus);
688     ENUM_TO_CSTR(LinuxLSBRelease);
689     ENUM_TO_CSTR(LinuxCMDLine);
690     ENUM_TO_CSTR(LinuxEnviron);
691     ENUM_TO_CSTR(LinuxAuxv);
692     ENUM_TO_CSTR(LinuxMaps);
693     ENUM_TO_CSTR(LinuxDSODebug);
694     ENUM_TO_CSTR(LinuxProcStat);
695     ENUM_TO_CSTR(LinuxProcUptime);
696     ENUM_TO_CSTR(LinuxProcFD);
697     ENUM_TO_CSTR(FacebookAppCustomData);
698     ENUM_TO_CSTR(FacebookBuildID);
699     ENUM_TO_CSTR(FacebookAppVersionName);
700     ENUM_TO_CSTR(FacebookJavaStack);
701     ENUM_TO_CSTR(FacebookDalvikInfo);
702     ENUM_TO_CSTR(FacebookUnwindSymbols);
703     ENUM_TO_CSTR(FacebookDumpErrorLog);
704     ENUM_TO_CSTR(FacebookAppStateLog);
705     ENUM_TO_CSTR(FacebookAbortReason);
706     ENUM_TO_CSTR(FacebookThreadName);
707     ENUM_TO_CSTR(FacebookLogcat);
708   }
709   return "unknown stream type";
710 }
711