1 //===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // Project includes
11 #include "MinidumpParser.h"
12 #include "NtStructures.h"
13 #include "RegisterContextMinidump_x86_32.h"
14 
15 // Other libraries and framework includes
16 #include "lldb/Target/MemoryRegionInfo.h"
17 #include "lldb/Utility/LLDBAssert.h"
18 
19 // C includes
20 // C++ includes
21 #include <algorithm>
22 #include <map>
23 #include <vector>
24 
25 using namespace lldb_private;
26 using namespace minidump;
27 
28 llvm::Optional<MinidumpParser>
29 MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) {
30   if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader)) {
31     return llvm::None;
32   }
33   return MinidumpParser(data_buf_sp);
34 }
35 
36 MinidumpParser::MinidumpParser(const lldb::DataBufferSP &data_buf_sp)
37     : m_data_sp(data_buf_sp) {}
38 
39 llvm::ArrayRef<uint8_t> MinidumpParser::GetData() {
40   return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(),
41                                  m_data_sp->GetByteSize());
42 }
43 
44 llvm::ArrayRef<uint8_t>
45 MinidumpParser::GetStream(MinidumpStreamType stream_type) {
46   auto iter = m_directory_map.find(static_cast<uint32_t>(stream_type));
47   if (iter == m_directory_map.end())
48     return {};
49 
50   // check if there is enough data
51   if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize())
52     return {};
53 
54   return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva,
55                                  iter->second.data_size);
56 }
57 
58 llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) {
59   auto arr_ref = m_data_sp->GetData();
60   if (rva > arr_ref.size())
61     return llvm::None;
62   arr_ref = arr_ref.drop_front(rva);
63   return parseMinidumpString(arr_ref);
64 }
65 
66 UUID MinidumpParser::GetModuleUUID(const MinidumpModule *module) {
67   auto cv_record =
68       GetData().slice(module->CV_record.rva, module->CV_record.data_size);
69 
70   // Read the CV record signature
71   const llvm::support::ulittle32_t *signature = nullptr;
72   Status error = consumeObject(cv_record, signature);
73   if (error.Fail())
74     return UUID();
75 
76   const CvSignature cv_signature =
77       static_cast<CvSignature>(static_cast<const uint32_t>(*signature));
78 
79   if (cv_signature == CvSignature::Pdb70) {
80     // PDB70 record
81     const CvRecordPdb70 *pdb70_uuid = nullptr;
82     Status error = consumeObject(cv_record, pdb70_uuid);
83     if (!error.Fail()) {
84       auto arch = GetArchitecture();
85       // For Apple targets we only need a 16 byte UUID so that we can match
86       // the UUID in the Module to actual UUIDs from the built binaries. The
87       // "Age" field is zero in breakpad minidump files for Apple targets, so
88       // we restrict the UUID to the "Uuid" field so we have a UUID we can use
89       // to match.
90       if (arch.GetTriple().getVendor() == llvm::Triple::Apple)
91         return UUID::fromData(pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid));
92       else
93         return UUID::fromData(pdb70_uuid, sizeof(*pdb70_uuid));
94     }
95   } else if (cv_signature == CvSignature::ElfBuildId)
96     return UUID::fromData(cv_record);
97 
98   return UUID();
99 }
100 
101 llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() {
102   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList);
103 
104   if (data.size() == 0)
105     return llvm::None;
106 
107   return MinidumpThread::ParseThreadList(data);
108 }
109 
110 llvm::ArrayRef<uint8_t>
111 MinidumpParser::GetThreadContext(const MinidumpThread &td) {
112   if (td.thread_context.rva + td.thread_context.data_size > GetData().size())
113     return {};
114 
115   return GetData().slice(td.thread_context.rva, td.thread_context.data_size);
116 }
117 
118 llvm::ArrayRef<uint8_t>
119 MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) {
120   // On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If
121   // the minidump was captured with a 64-bit debugger, then the CONTEXT we just
122   // grabbed from the mini_dump_thread is the one for the 64-bit "native"
123   // process rather than the 32-bit "guest" process we care about.  In this
124   // case, we can get the 32-bit CONTEXT from the TEB (Thread Environment
125   // Block) of the 64-bit process.
126   auto teb_mem = GetMemory(td.teb, sizeof(TEB64));
127   if (teb_mem.empty())
128     return {};
129 
130   const TEB64 *wow64teb;
131   Status error = consumeObject(teb_mem, wow64teb);
132   if (error.Fail())
133     return {};
134 
135   // Slot 1 of the thread-local storage in the 64-bit TEB points to a structure
136   // that includes the 32-bit CONTEXT (after a ULONG). See:
137   // https://msdn.microsoft.com/en-us/library/ms681670.aspx
138   auto context =
139       GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32));
140   if (context.size() < sizeof(MinidumpContext_x86_32))
141     return {};
142 
143   return context;
144   // NOTE:  We don't currently use the TEB for anything else.  If we
145   // need it in the future, the 32-bit TEB is located according to the address
146   // stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]).
147 }
148 
149 const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
150   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo);
151 
152   if (data.size() == 0)
153     return nullptr;
154 
155   return MinidumpSystemInfo::Parse(data);
156 }
157 
158 ArchSpec MinidumpParser::GetArchitecture() {
159   if (m_arch.IsValid())
160     return m_arch;
161 
162   // Set the architecture in m_arch
163   const MinidumpSystemInfo *system_info = GetSystemInfo();
164 
165   if (!system_info)
166     return m_arch;
167 
168   // TODO what to do about big endiand flavors of arm ?
169   // TODO set the arm subarch stuff if the minidump has info about it
170 
171   llvm::Triple triple;
172   triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
173 
174   const MinidumpCPUArchitecture arch =
175       static_cast<const MinidumpCPUArchitecture>(
176           static_cast<const uint32_t>(system_info->processor_arch));
177 
178   switch (arch) {
179   case MinidumpCPUArchitecture::X86:
180     triple.setArch(llvm::Triple::ArchType::x86);
181     break;
182   case MinidumpCPUArchitecture::AMD64:
183     triple.setArch(llvm::Triple::ArchType::x86_64);
184     break;
185   case MinidumpCPUArchitecture::ARM:
186     triple.setArch(llvm::Triple::ArchType::arm);
187     break;
188   case MinidumpCPUArchitecture::ARM64:
189     triple.setArch(llvm::Triple::ArchType::aarch64);
190     break;
191   default:
192     triple.setArch(llvm::Triple::ArchType::UnknownArch);
193     break;
194   }
195 
196   const MinidumpOSPlatform os = static_cast<const MinidumpOSPlatform>(
197       static_cast<const uint32_t>(system_info->platform_id));
198 
199   // TODO add all of the OSes that Minidump/breakpad distinguishes?
200   switch (os) {
201   case MinidumpOSPlatform::Win32S:
202   case MinidumpOSPlatform::Win32Windows:
203   case MinidumpOSPlatform::Win32NT:
204   case MinidumpOSPlatform::Win32CE:
205     triple.setOS(llvm::Triple::OSType::Win32);
206     break;
207   case MinidumpOSPlatform::Linux:
208     triple.setOS(llvm::Triple::OSType::Linux);
209     break;
210   case MinidumpOSPlatform::MacOSX:
211     triple.setOS(llvm::Triple::OSType::MacOSX);
212     triple.setVendor(llvm::Triple::Apple);
213     break;
214   case MinidumpOSPlatform::IOS:
215     triple.setOS(llvm::Triple::OSType::IOS);
216     triple.setVendor(llvm::Triple::Apple);
217     break;
218   case MinidumpOSPlatform::Android:
219     triple.setOS(llvm::Triple::OSType::Linux);
220     triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
221     break;
222   default: {
223     triple.setOS(llvm::Triple::OSType::UnknownOS);
224     std::string csd_version;
225     if (auto s = GetMinidumpString(system_info->csd_version_rva))
226       csd_version = *s;
227     if (csd_version.find("Linux") != std::string::npos)
228       triple.setOS(llvm::Triple::OSType::Linux);
229     break;
230     }
231   }
232   m_arch.SetTriple(triple);
233   return m_arch;
234 }
235 
236 const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
237   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MiscInfo);
238 
239   if (data.size() == 0)
240     return nullptr;
241 
242   return MinidumpMiscInfo::Parse(data);
243 }
244 
245 llvm::Optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {
246   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::LinuxProcStatus);
247 
248   if (data.size() == 0)
249     return llvm::None;
250 
251   return LinuxProcStatus::Parse(data);
252 }
253 
254 llvm::Optional<lldb::pid_t> MinidumpParser::GetPid() {
255   const MinidumpMiscInfo *misc_info = GetMiscInfo();
256   if (misc_info != nullptr) {
257     return misc_info->GetPid();
258   }
259 
260   llvm::Optional<LinuxProcStatus> proc_status = GetLinuxProcStatus();
261   if (proc_status.hasValue()) {
262     return proc_status->GetPid();
263   }
264 
265   return llvm::None;
266 }
267 
268 llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() {
269   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ModuleList);
270 
271   if (data.size() == 0)
272     return {};
273 
274   return MinidumpModule::ParseModuleList(data);
275 }
276 
277 std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() {
278   llvm::ArrayRef<MinidumpModule> modules = GetModuleList();
279   // map module_name -> pair(load_address, pointer to module struct in memory)
280   llvm::StringMap<std::pair<uint64_t, const MinidumpModule *>> lowest_addr;
281 
282   std::vector<const MinidumpModule *> filtered_modules;
283 
284   llvm::Optional<std::string> name;
285   std::string module_name;
286 
287   for (const auto &module : modules) {
288     name = GetMinidumpString(module.module_name_rva);
289 
290     if (!name)
291       continue;
292 
293     module_name = name.getValue();
294 
295     auto iter = lowest_addr.end();
296     bool exists;
297     std::tie(iter, exists) = lowest_addr.try_emplace(
298         module_name, std::make_pair(module.base_of_image, &module));
299 
300     if (exists && module.base_of_image < iter->second.first)
301       iter->second = std::make_pair(module.base_of_image, &module);
302   }
303 
304   filtered_modules.reserve(lowest_addr.size());
305   for (const auto &module : lowest_addr) {
306     filtered_modules.push_back(module.second.second);
307   }
308 
309   return filtered_modules;
310 }
311 
312 const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() {
313   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::Exception);
314 
315   if (data.size() == 0)
316     return nullptr;
317 
318   return MinidumpExceptionStream::Parse(data);
319 }
320 
321 llvm::Optional<minidump::Range>
322 MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
323   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryList);
324   llvm::ArrayRef<uint8_t> data64 = GetStream(MinidumpStreamType::Memory64List);
325 
326   if (data.empty() && data64.empty())
327     return llvm::None;
328 
329   if (!data.empty()) {
330     llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list =
331         MinidumpMemoryDescriptor::ParseMemoryList(data);
332 
333     if (memory_list.empty())
334       return llvm::None;
335 
336     for (const auto &memory_desc : memory_list) {
337       const MinidumpLocationDescriptor &loc_desc = memory_desc.memory;
338       const lldb::addr_t range_start = memory_desc.start_of_memory_range;
339       const size_t range_size = loc_desc.data_size;
340 
341       if (loc_desc.rva + loc_desc.data_size > GetData().size())
342         return llvm::None;
343 
344       if (range_start <= addr && addr < range_start + range_size) {
345         return minidump::Range(range_start,
346                                GetData().slice(loc_desc.rva, range_size));
347       }
348     }
349   }
350 
351   // Some Minidumps have a Memory64ListStream that captures all the heap memory
352   // (full-memory Minidumps).  We can't exactly use the same loop as above,
353   // because the Minidump uses slightly different data structures to describe
354   // those
355 
356   if (!data64.empty()) {
357     llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
358     uint64_t base_rva;
359     std::tie(memory64_list, base_rva) =
360         MinidumpMemoryDescriptor64::ParseMemory64List(data64);
361 
362     if (memory64_list.empty())
363       return llvm::None;
364 
365     for (const auto &memory_desc64 : memory64_list) {
366       const lldb::addr_t range_start = memory_desc64.start_of_memory_range;
367       const size_t range_size = memory_desc64.data_size;
368 
369       if (base_rva + range_size > GetData().size())
370         return llvm::None;
371 
372       if (range_start <= addr && addr < range_start + range_size) {
373         return minidump::Range(range_start,
374                                GetData().slice(base_rva, range_size));
375       }
376       base_rva += range_size;
377     }
378   }
379 
380   return llvm::None;
381 }
382 
383 llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
384                                                   size_t size) {
385   // I don't have a sense of how frequently this is called or how many memory
386   // ranges a Minidump typically has, so I'm not sure if searching for the
387   // appropriate range linearly each time is stupid.  Perhaps we should build
388   // an index for faster lookups.
389   llvm::Optional<minidump::Range> range = FindMemoryRange(addr);
390   if (!range)
391     return {};
392 
393   // There's at least some overlap between the beginning of the desired range
394   // (addr) and the current range.  Figure out where the overlap begins and how
395   // much overlap there is.
396 
397   const size_t offset = addr - range->start;
398 
399   if (addr < range->start || offset >= range->range_ref.size())
400     return {};
401 
402   const size_t overlap = std::min(size, range->range_ref.size() - offset);
403   return range->range_ref.slice(offset, overlap);
404 }
405 
406 llvm::Optional<MemoryRegionInfo>
407 MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) {
408   MemoryRegionInfo info;
409   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryInfoList);
410   if (data.empty())
411     return llvm::None;
412 
413   std::vector<const MinidumpMemoryInfo *> mem_info_list =
414       MinidumpMemoryInfo::ParseMemoryInfoList(data);
415   if (mem_info_list.empty())
416     return llvm::None;
417 
418   const auto yes = MemoryRegionInfo::eYes;
419   const auto no = MemoryRegionInfo::eNo;
420 
421   const MinidumpMemoryInfo *next_entry = nullptr;
422   for (const auto &entry : mem_info_list) {
423     const auto head = entry->base_address;
424     const auto tail = head + entry->region_size;
425 
426     if (head <= load_addr && load_addr < tail) {
427       info.GetRange().SetRangeBase(
428           (entry->state != uint32_t(MinidumpMemoryInfoState::MemFree))
429               ? head
430               : load_addr);
431       info.GetRange().SetRangeEnd(tail);
432 
433       const uint32_t PageNoAccess =
434           static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageNoAccess);
435       info.SetReadable((entry->protect & PageNoAccess) == 0 ? yes : no);
436 
437       const uint32_t PageWritable =
438           static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageWritable);
439       info.SetWritable((entry->protect & PageWritable) != 0 ? yes : no);
440 
441       const uint32_t PageExecutable = static_cast<uint32_t>(
442           MinidumpMemoryProtectionContants::PageExecutable);
443       info.SetExecutable((entry->protect & PageExecutable) != 0 ? yes : no);
444 
445       const uint32_t MemFree =
446           static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree);
447       info.SetMapped((entry->state != MemFree) ? yes : no);
448 
449       return info;
450     } else if (head > load_addr &&
451                (next_entry == nullptr || head < next_entry->base_address)) {
452       // In case there is no region containing load_addr keep track of the
453       // nearest region after load_addr so we can return the distance to it.
454       next_entry = entry;
455     }
456   }
457 
458   // No containing region found. Create an unmapped region that extends to the
459   // next region or LLDB_INVALID_ADDRESS
460   info.GetRange().SetRangeBase(load_addr);
461   info.GetRange().SetRangeEnd((next_entry != nullptr) ? next_entry->base_address
462                                                       : LLDB_INVALID_ADDRESS);
463   info.SetReadable(no);
464   info.SetWritable(no);
465   info.SetExecutable(no);
466   info.SetMapped(no);
467 
468   // Note that the memory info list doesn't seem to contain ranges in kernel
469   // space, so if you're walking a stack that has kernel frames, the stack may
470   // appear truncated.
471   return info;
472 }
473 
474 Status MinidumpParser::Initialize() {
475   Status error;
476 
477   lldbassert(m_directory_map.empty());
478 
479   llvm::ArrayRef<uint8_t> header_data(m_data_sp->GetBytes(),
480                                       sizeof(MinidumpHeader));
481   const MinidumpHeader *header = MinidumpHeader::Parse(header_data);
482   if (header == nullptr) {
483     error.SetErrorString("invalid minidump: can't parse the header");
484     return error;
485   }
486 
487   // A minidump without at least one stream is clearly ill-formed
488   if (header->streams_count == 0) {
489     error.SetErrorString("invalid minidump: no streams present");
490     return error;
491   }
492 
493   struct FileRange {
494     uint32_t offset = 0;
495     uint32_t size = 0;
496 
497     FileRange(uint32_t offset, uint32_t size) : offset(offset), size(size) {}
498     uint32_t end() const { return offset + size; }
499   };
500 
501   const uint32_t file_size = m_data_sp->GetByteSize();
502 
503   // Build a global minidump file map, checking for:
504   // - overlapping streams/data structures
505   // - truncation (streams pointing past the end of file)
506   std::vector<FileRange> minidump_map;
507 
508   // Add the minidump header to the file map
509   if (sizeof(MinidumpHeader) > file_size) {
510     error.SetErrorString("invalid minidump: truncated header");
511     return error;
512   }
513   minidump_map.emplace_back( 0, sizeof(MinidumpHeader) );
514 
515   // Add the directory entries to the file map
516   FileRange directory_range(header->stream_directory_rva,
517                             header->streams_count *
518                                 sizeof(MinidumpDirectory));
519   if (directory_range.end() > file_size) {
520     error.SetErrorString("invalid minidump: truncated streams directory");
521     return error;
522   }
523   minidump_map.push_back(directory_range);
524 
525   // Parse stream directory entries
526   llvm::ArrayRef<uint8_t> directory_data(
527       m_data_sp->GetBytes() + directory_range.offset, directory_range.size);
528   for (uint32_t i = 0; i < header->streams_count; ++i) {
529     const MinidumpDirectory *directory_entry = nullptr;
530     error = consumeObject(directory_data, directory_entry);
531     if (error.Fail())
532       return error;
533     if (directory_entry->stream_type == 0) {
534       // Ignore dummy streams (technically ill-formed, but a number of
535       // existing minidumps seem to contain such streams)
536       if (directory_entry->location.data_size == 0)
537         continue;
538       error.SetErrorString("invalid minidump: bad stream type");
539       return error;
540     }
541     // Update the streams map, checking for duplicate stream types
542     if (!m_directory_map
543              .insert({directory_entry->stream_type, directory_entry->location})
544              .second) {
545       error.SetErrorString("invalid minidump: duplicate stream type");
546       return error;
547     }
548     // Ignore the zero-length streams for layout checks
549     if (directory_entry->location.data_size != 0) {
550       minidump_map.emplace_back(directory_entry->location.rva,
551                                 directory_entry->location.data_size);
552     }
553   }
554 
555   // Sort the file map ranges by start offset
556   std::sort(minidump_map.begin(), minidump_map.end(),
557             [](const FileRange &a, const FileRange &b) {
558               return a.offset < b.offset;
559             });
560 
561   // Check for overlapping streams/data structures
562   for (size_t i = 1; i < minidump_map.size(); ++i) {
563     const auto &prev_range = minidump_map[i - 1];
564     if (prev_range.end() > minidump_map[i].offset) {
565       error.SetErrorString("invalid minidump: overlapping streams");
566       return error;
567     }
568   }
569 
570   // Check for streams past the end of file
571   const auto &last_range = minidump_map.back();
572   if (last_range.end() > file_size) {
573     error.SetErrorString("invalid minidump: truncated stream");
574     return error;
575   }
576 
577   return error;
578 }
579