LLDB mainline
MinidumpParser.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "MinidumpParser.h"
10#include "NtStructures.h"
12
16#include "lldb/Utility/Log.h"
17
18// C includes
19// C++ includes
20#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>
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
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 signature
62 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) {
112 // On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If
113 // the minidump was captured with a 64-bit debugger, then the CONTEXT we just
114 // 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 this
116 // case, we can get the 32-bit CONTEXT from the TEB (Thread Environment
117 // 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 structure
135 // that includes the 32-bit CONTEXT (after a ULONG). See:
136 // https://msdn.microsoft.com/en-us/library/ms681670.aspx
137 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 we
152 // need it in the future, the 32-bit TEB is located according to the address
153 // stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]).
154}
155
157 if (m_arch.IsValid())
158 return m_arch;
159
160 // Set the architecture in m_arch
161 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 it
171
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
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 bool
279 std::vector<MemoryRegionInfo> &regions) {
280 auto data = parser.GetStream(StreamType::LinuxMaps);
281 if (data.empty())
282 return false;
283
286 llvm::toStringRef(data),
287 [&regions, &log](llvm::Expected<MemoryRegionInfo> region) -> bool {
288 if (region)
289 regions.push_back(*region);
290 else
291 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 contiguous
299/// section that has execute permissions that matches the module path.
300///
301/// When we load a breakpad generated minidump file, we might have the
302/// /proc/<pid>/maps text for a process that details the memory map of the
303/// process that the minidump is describing. This checks the sorted memory
304/// regions for a section that has execute permissions. A sample maps files
305/// might look like:
306///
307/// 00400000-00401000 r--p 00000000 fd:01 2838574 /tmp/a.out
308/// 00401000-00402000 r-xp 00001000 fd:01 2838574 /tmp/a.out
309/// 00402000-00403000 r--p 00002000 fd:01 2838574 /tmp/a.out
310/// 00403000-00404000 r--p 00002000 fd:01 2838574 /tmp/a.out
311/// 00404000-00405000 rw-p 00003000 fd:01 2838574 /tmp/a.out
312/// ...
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 for
316/// "/tmp/a.out" that has execute permissions at 0x00401000. This will help us
317/// differentiate if a file has been memory mapped into a process for reading
318/// and breakpad ends up saving a minidump file that has two module entries for
319/// a given file: one that is read only for the entire file, and then one that
320/// is the real executable that is loaded into memory for execution. For memory
321/// mapped files they will typically show up and r--p permissions and a range
322/// matcning the entire range of the file on disk:
323///
324/// 00800000-00805000 r--p 00000000 fd:01 2838574 /tmp/a.out
325/// 00805000-00806000 r-xp 00001000 fd:01 1234567 /usr/lib/libc.so
326///
327/// This function should return false when asked about 0x00800000 with
328/// "/tmp/a.out" as the path.
329///
330/// \param[in] path
331/// The path to the module to check for in the memory regions. Only sequential
332/// memory regions whose paths match this path will be considered when looking
333/// for execute permissions.
334///
335/// \param[in] regions
336/// A sorted list of memory regions obtained from a call to
337/// CreateRegionsCacheFromLinuxMaps.
338///
339/// \param[in] base_of_image
340/// The load address of this module from BaseOfImage in the modules list.
341///
342/// \return
343/// True if a contiguous region of memory belonging to the module with a
344/// matching path exists that has executable permissions. Returns false if
345/// \a regions is empty or if there are no regions with execute permissions
346/// that match \a path.
347
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;
355 while (region.GetName() == path) {
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() {
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 issues
374 // with breakpad generated minidumps where if someone has mmap'ed a shared
375 // library into memory to access its data in the object file, we can get a
376 // minidump with two mappings for a binary: one whose base image points to a
377 // 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 index
383 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 we
399 // haven't insert an entry into module_name_to_filtered_index with the
400 // 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 at
406 // the index that was inserted into module_name_to_filtered_index using
407 // "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 if
411 // either module is not really a mapped executable. If one but not the
412 // other is a real mapped executable, prefer the executable one. This
413 // can happen when a process mmap's in the file for an executable in
414 // order to read bytes from the executable file. A memory region mapping
415 // will exist for the mmap'ed version and for the loaded executable, but
416 // only one will have a consecutive region that is executable in the
417 // 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 multiple
431 // times when they are mapped discontiguously, so find the module with
432 // 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>
442 return GetMinidumpFile().getExceptionStreams();
443}
444
445std::optional<minidump::Range>
447 if (m_memory_ranges.IsEmpty())
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
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 }
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)) {
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>>
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 range
506 // (addr) and the current range. Figure out where the overlap begins and
507 // 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%" PRIx64
515 ")",
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>
524 llvm::ErrorAsOutParameter ErrAsOutParam(&err);
525 return m_file->getMemory64List(err);
526}
527
528static bool
530 std::vector<MemoryRegionInfo> &regions) {
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 ? yes
552 : no);
553 region.SetExecutable(
554 bool(prot & (MemoryProtection::Execute | MemoryProtection::ExecuteRead |
555 MemoryProtection::ExecuteReadWrite |
556 MemoryProtection::ExeciteWriteCopy))
557 ? yes
558 : no);
559 region.SetMapped(entry.State != MemoryState::Free ? yes : no);
560 regions.push_back(region);
561 }
562 return !regions.empty();
563}
564
565static bool
567 std::vector<MemoryRegionInfo> &regions) {
569 // Cache the expected memory32 into an optional
570 // because it is possible to just have a memory64 list
571 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);
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);
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 with
613 // the linux maps since they are the most complete and have names for the
614 // regions. Next we try the MemoryInfoList since it has
615 // read/write/execute/map data, and then fall back to the MemoryList and
616 // Memory64List to just get a list of the memory that is mapped in this
617 // core file
618 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);
628 return return_sorted(false);
629}
630
631#define ENUM_TO_CSTR(ST) \
632 case StreamType::ST: \
633 return #ST
634
635llvm::StringRef MinidumpParser::GetStreamTypeAsString(StreamType stream_type) {
636 switch (stream_type) {
637 ENUM_TO_CSTR(Unused);
640 ENUM_TO_CSTR(MemoryList);
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);
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
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 else
701 region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd());
702
703 if (pos == regions.end())
705 else
706 region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase());
707
712 return region;
713}
static llvm::raw_ostream & error(Stream &strm)
#define ENUM_TO_CSTR(eee)
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:392
static bool CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser, std::vector< MemoryRegionInfo > &regions)
static bool CheckForLinuxExecutable(ConstString path, const MemoryRegionInfos &regions, lldb::addr_t base_of_image)
Check for the memory regions starting at load_addr for a contiguous section that has execute permissi...
static bool CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser, std::vector< MemoryRegionInfo > &regions)
static bool CreateRegionsCacheFromMemoryList(MinidumpParser &parser, std::vector< MemoryRegionInfo > &regions)
An architecture specification class.
Definition ArchSpec.h:31
A uniqued constant string class.
Definition ConstString.h:40
void SetMapped(OptionalBool val)
void SetReadable(OptionalBool val)
void SetExecutable(OptionalBool val)
void SetWritable(OptionalBool val)
OptionalBool GetExecutable() const
A collection class for Module objects.
Definition ModuleList.h:104
RangeData< lldb::addr_t, lldb::addr_t, minidump::Range > Entry
Definition RangeMap.h:462
An error handling class.
Definition Status.h:118
Represents UUID's of various sizes.
Definition UUID.h:27
static std::optional< LinuxProcStatus > Parse(llvm::ArrayRef< uint8_t > &data)
MinidumpParser(lldb::DataBufferSP data_sp, std::unique_ptr< llvm::object::MinidumpFile > file)
std::pair< MemoryRegionInfos, bool > BuildMemoryRegions()
Returns a list of memory regions and a flag indicating whether the list is complete (includes all reg...
llvm::ArrayRef< minidump::Module > GetModuleList()
llvm::object::MinidumpFile & GetMinidumpFile()
llvm::ArrayRef< uint8_t > GetData()
static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos &regions, lldb::addr_t load_addr)
llvm::ArrayRef< uint8_t > GetStream(StreamType stream_type)
std::optional< lldb::pid_t > GetPid()
std::optional< llvm::ArrayRef< uint8_t > > GetRawStream(StreamType stream_type)
llvm::iterator_range< ExceptionStreamsIterator > GetExceptionStreams()
std::optional< Range > FindMemoryRange(lldb::addr_t addr)
static llvm::Expected< MinidumpParser > Create(const lldb::DataBufferSP &data_buf_sp)
std::unique_ptr< llvm::object::MinidumpFile > m_file
std::vector< const minidump::Module * > GetFilteredModuleList()
llvm::iterator_range< FallibleMemory64Iterator > GetMemory64Iterator(llvm::Error &err)
std::optional< LinuxProcStatus > GetLinuxProcStatus()
llvm::ArrayRef< uint8_t > GetThreadContext(const LocationDescriptor &location)
llvm::ArrayRef< uint8_t > GetThreadContextWow64(const minidump::Thread &td)
UUID GetModuleUUID(const minidump::Module *module)
static llvm::StringRef GetStreamTypeAsString(StreamType stream_type)
llvm::ArrayRef< minidump::Thread > GetThreads()
llvm::Expected< llvm::ArrayRef< uint8_t > > GetMemory(lldb::addr_t addr, size_t size)
const MinidumpMiscInfo * GetMiscInfo()
#define UINT64_MAX
Status consumeObject(llvm::ArrayRef< uint8_t > &Buffer, const T *&Object)
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:332
void ParseLinuxMapRegions(llvm::StringRef linux_map, LinuxMapCallback const &callback)
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
uint64_t addr_t
Definition lldb-types.h:80
void SetRangeEnd(BaseType end)
Definition RangeMap.h:80
SizeType GetByteSize() const
Definition RangeMap.h:87
void SetRangeBase(BaseType b)
Set the start value for the range, and keep the same size.
Definition RangeMap.h:48
void SetByteSize(SizeType s)
Definition RangeMap.h:89
struct lldb_private::UUID::CvRecordPdb70::@031031370151201011001273071037042037235035311007 Uuid
llvm::support::ulittle32_t Age
Definition UUID.h:47
static const MinidumpMiscInfo * Parse(llvm::ArrayRef< uint8_t > &data)
std::optional< lldb::pid_t > GetPid() const
llvm::support::ulittle64_t tls_slots[64]