Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
39644 views
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"
11
#include "RegisterContextMinidump_x86_32.h"
12
13
#include "Plugins/Process/Utility/LinuxProcMaps.h"
14
#include "lldb/Utility/LLDBAssert.h"
15
#include "lldb/Utility/LLDBLog.h"
16
#include "lldb/Utility/Log.h"
17
18
// C includes
19
// C++ includes
20
#include <algorithm>
21
#include <map>
22
#include <optional>
23
#include <vector>
24
#include <utility>
25
26
using namespace lldb_private;
27
using namespace minidump;
28
29
llvm::Expected<MinidumpParser>
30
MinidumpParser::Create(const lldb::DataBufferSP &data_sp) {
31
auto ExpectedFile = llvm::object::MinidumpFile::create(
32
llvm::MemoryBufferRef(toStringRef(data_sp->GetData()), "minidump"));
33
if (!ExpectedFile)
34
return ExpectedFile.takeError();
35
36
return MinidumpParser(data_sp, std::move(*ExpectedFile));
37
}
38
39
MinidumpParser::MinidumpParser(lldb::DataBufferSP data_sp,
40
std::unique_ptr<llvm::object::MinidumpFile> file)
41
: m_data_sp(std::move(data_sp)), m_file(std::move(file)) {}
42
43
llvm::ArrayRef<uint8_t> MinidumpParser::GetData() {
44
return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(),
45
m_data_sp->GetByteSize());
46
}
47
48
llvm::ArrayRef<uint8_t> MinidumpParser::GetStream(StreamType stream_type) {
49
return m_file->getRawStream(stream_type).value_or(llvm::ArrayRef<uint8_t>());
50
}
51
52
UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) {
53
auto cv_record =
54
GetData().slice(module->CvRecord.RVA, module->CvRecord.DataSize);
55
56
// Read the CV record signature
57
const llvm::support::ulittle32_t *signature = nullptr;
58
Status error = consumeObject(cv_record, signature);
59
if (error.Fail())
60
return UUID();
61
62
const CvSignature cv_signature =
63
static_cast<CvSignature>(static_cast<uint32_t>(*signature));
64
65
if (cv_signature == CvSignature::Pdb70) {
66
const UUID::CvRecordPdb70 *pdb70_uuid = nullptr;
67
Status error = consumeObject(cv_record, pdb70_uuid);
68
if (error.Fail())
69
return UUID();
70
if (GetArchitecture().GetTriple().isOSBinFormatELF()) {
71
if (pdb70_uuid->Age != 0)
72
return UUID(pdb70_uuid, sizeof(*pdb70_uuid));
73
return UUID(&pdb70_uuid->Uuid,
74
sizeof(pdb70_uuid->Uuid));
75
}
76
return UUID(*pdb70_uuid);
77
} else if (cv_signature == CvSignature::ElfBuildId)
78
return UUID(cv_record);
79
80
return UUID();
81
}
82
83
llvm::ArrayRef<minidump::Thread> MinidumpParser::GetThreads() {
84
auto ExpectedThreads = GetMinidumpFile().getThreadList();
85
if (ExpectedThreads)
86
return *ExpectedThreads;
87
88
LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), ExpectedThreads.takeError(),
89
"Failed to read thread list: {0}");
90
return {};
91
}
92
93
llvm::ArrayRef<uint8_t>
94
MinidumpParser::GetThreadContext(const LocationDescriptor &location) {
95
if (location.RVA + location.DataSize > GetData().size())
96
return {};
97
return GetData().slice(location.RVA, location.DataSize);
98
}
99
100
llvm::ArrayRef<uint8_t>
101
MinidumpParser::GetThreadContext(const minidump::Thread &td) {
102
return GetThreadContext(td.Context);
103
}
104
105
llvm::ArrayRef<uint8_t>
106
MinidumpParser::GetThreadContextWow64(const minidump::Thread &td) {
107
// On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If
108
// the minidump was captured with a 64-bit debugger, then the CONTEXT we just
109
// grabbed from the mini_dump_thread is the one for the 64-bit "native"
110
// process rather than the 32-bit "guest" process we care about. In this
111
// case, we can get the 32-bit CONTEXT from the TEB (Thread Environment
112
// Block) of the 64-bit process.
113
auto teb_mem = GetMemory(td.EnvironmentBlock, sizeof(TEB64));
114
if (teb_mem.empty())
115
return {};
116
117
const TEB64 *wow64teb;
118
Status error = consumeObject(teb_mem, wow64teb);
119
if (error.Fail())
120
return {};
121
122
// Slot 1 of the thread-local storage in the 64-bit TEB points to a structure
123
// that includes the 32-bit CONTEXT (after a ULONG). See:
124
// https://msdn.microsoft.com/en-us/library/ms681670.aspx
125
auto context =
126
GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32));
127
if (context.size() < sizeof(MinidumpContext_x86_32))
128
return {};
129
130
return context;
131
// NOTE: We don't currently use the TEB for anything else. If we
132
// need it in the future, the 32-bit TEB is located according to the address
133
// stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]).
134
}
135
136
ArchSpec MinidumpParser::GetArchitecture() {
137
if (m_arch.IsValid())
138
return m_arch;
139
140
// Set the architecture in m_arch
141
llvm::Expected<const SystemInfo &> system_info = m_file->getSystemInfo();
142
143
if (!system_info) {
144
LLDB_LOG_ERROR(GetLog(LLDBLog::Process), system_info.takeError(),
145
"Failed to read SystemInfo stream: {0}");
146
return m_arch;
147
}
148
149
// TODO what to do about big endiand flavors of arm ?
150
// TODO set the arm subarch stuff if the minidump has info about it
151
152
llvm::Triple triple;
153
triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
154
155
switch (system_info->ProcessorArch) {
156
case ProcessorArchitecture::X86:
157
triple.setArch(llvm::Triple::ArchType::x86);
158
break;
159
case ProcessorArchitecture::AMD64:
160
triple.setArch(llvm::Triple::ArchType::x86_64);
161
break;
162
case ProcessorArchitecture::ARM:
163
triple.setArch(llvm::Triple::ArchType::arm);
164
break;
165
case ProcessorArchitecture::ARM64:
166
case ProcessorArchitecture::BP_ARM64:
167
triple.setArch(llvm::Triple::ArchType::aarch64);
168
break;
169
default:
170
triple.setArch(llvm::Triple::ArchType::UnknownArch);
171
break;
172
}
173
174
// TODO add all of the OSes that Minidump/breakpad distinguishes?
175
switch (system_info->PlatformId) {
176
case OSPlatform::Win32S:
177
case OSPlatform::Win32Windows:
178
case OSPlatform::Win32NT:
179
case OSPlatform::Win32CE:
180
triple.setOS(llvm::Triple::OSType::Win32);
181
triple.setVendor(llvm::Triple::VendorType::PC);
182
break;
183
case OSPlatform::Linux:
184
triple.setOS(llvm::Triple::OSType::Linux);
185
break;
186
case OSPlatform::MacOSX:
187
triple.setOS(llvm::Triple::OSType::MacOSX);
188
triple.setVendor(llvm::Triple::Apple);
189
break;
190
case OSPlatform::IOS:
191
triple.setOS(llvm::Triple::OSType::IOS);
192
triple.setVendor(llvm::Triple::Apple);
193
break;
194
case OSPlatform::Android:
195
triple.setOS(llvm::Triple::OSType::Linux);
196
triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
197
break;
198
default: {
199
triple.setOS(llvm::Triple::OSType::UnknownOS);
200
auto ExpectedCSD = m_file->getString(system_info->CSDVersionRVA);
201
if (!ExpectedCSD) {
202
LLDB_LOG_ERROR(GetLog(LLDBLog::Process), ExpectedCSD.takeError(),
203
"Failed to CSD Version string: {0}");
204
} else {
205
if (ExpectedCSD->find("Linux") != std::string::npos)
206
triple.setOS(llvm::Triple::OSType::Linux);
207
}
208
break;
209
}
210
}
211
m_arch.SetTriple(triple);
212
return m_arch;
213
}
214
215
const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
216
llvm::ArrayRef<uint8_t> data = GetStream(StreamType::MiscInfo);
217
218
if (data.size() == 0)
219
return nullptr;
220
221
return MinidumpMiscInfo::Parse(data);
222
}
223
224
std::optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {
225
llvm::ArrayRef<uint8_t> data = GetStream(StreamType::LinuxProcStatus);
226
227
if (data.size() == 0)
228
return std::nullopt;
229
230
return LinuxProcStatus::Parse(data);
231
}
232
233
std::optional<lldb::pid_t> MinidumpParser::GetPid() {
234
const MinidumpMiscInfo *misc_info = GetMiscInfo();
235
if (misc_info != nullptr) {
236
return misc_info->GetPid();
237
}
238
239
std::optional<LinuxProcStatus> proc_status = GetLinuxProcStatus();
240
if (proc_status) {
241
return proc_status->GetPid();
242
}
243
244
return std::nullopt;
245
}
246
247
llvm::ArrayRef<minidump::Module> MinidumpParser::GetModuleList() {
248
auto ExpectedModules = GetMinidumpFile().getModuleList();
249
if (ExpectedModules)
250
return *ExpectedModules;
251
252
LLDB_LOG_ERROR(GetLog(LLDBLog::Modules), ExpectedModules.takeError(),
253
"Failed to read module list: {0}");
254
return {};
255
}
256
257
static bool
258
CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,
259
std::vector<MemoryRegionInfo> &regions) {
260
auto data = parser.GetStream(StreamType::LinuxMaps);
261
if (data.empty())
262
return false;
263
264
Log *log = GetLog(LLDBLog::Expressions);
265
ParseLinuxMapRegions(
266
llvm::toStringRef(data),
267
[&regions, &log](llvm::Expected<MemoryRegionInfo> region) -> bool {
268
if (region)
269
regions.push_back(*region);
270
else
271
LLDB_LOG_ERROR(log, region.takeError(),
272
"Reading memory region from minidump failed: {0}");
273
return true;
274
});
275
return !regions.empty();
276
}
277
278
/// Check for the memory regions starting at \a load_addr for a contiguous
279
/// section that has execute permissions that matches the module path.
280
///
281
/// When we load a breakpad generated minidump file, we might have the
282
/// /proc/<pid>/maps text for a process that details the memory map of the
283
/// process that the minidump is describing. This checks the sorted memory
284
/// regions for a section that has execute permissions. A sample maps files
285
/// might look like:
286
///
287
/// 00400000-00401000 r--p 00000000 fd:01 2838574 /tmp/a.out
288
/// 00401000-00402000 r-xp 00001000 fd:01 2838574 /tmp/a.out
289
/// 00402000-00403000 r--p 00002000 fd:01 2838574 /tmp/a.out
290
/// 00403000-00404000 r--p 00002000 fd:01 2838574 /tmp/a.out
291
/// 00404000-00405000 rw-p 00003000 fd:01 2838574 /tmp/a.out
292
/// ...
293
///
294
/// This function should return true when given 0x00400000 and "/tmp/a.out"
295
/// is passed in as the path since it has a consecutive memory region for
296
/// "/tmp/a.out" that has execute permissions at 0x00401000. This will help us
297
/// differentiate if a file has been memory mapped into a process for reading
298
/// and breakpad ends up saving a minidump file that has two module entries for
299
/// a given file: one that is read only for the entire file, and then one that
300
/// is the real executable that is loaded into memory for execution. For memory
301
/// mapped files they will typically show up and r--p permissions and a range
302
/// matcning the entire range of the file on disk:
303
///
304
/// 00800000-00805000 r--p 00000000 fd:01 2838574 /tmp/a.out
305
/// 00805000-00806000 r-xp 00001000 fd:01 1234567 /usr/lib/libc.so
306
///
307
/// This function should return false when asked about 0x00800000 with
308
/// "/tmp/a.out" as the path.
309
///
310
/// \param[in] path
311
/// The path to the module to check for in the memory regions. Only sequential
312
/// memory regions whose paths match this path will be considered when looking
313
/// for execute permissions.
314
///
315
/// \param[in] regions
316
/// A sorted list of memory regions obtained from a call to
317
/// CreateRegionsCacheFromLinuxMaps.
318
///
319
/// \param[in] base_of_image
320
/// The load address of this module from BaseOfImage in the modules list.
321
///
322
/// \return
323
/// True if a contiguous region of memory belonging to the module with a
324
/// matching path exists that has executable permissions. Returns false if
325
/// \a regions is empty or if there are no regions with execute permissions
326
/// that match \a path.
327
328
static bool CheckForLinuxExecutable(ConstString path,
329
const MemoryRegionInfos &regions,
330
lldb::addr_t base_of_image) {
331
if (regions.empty())
332
return false;
333
lldb::addr_t addr = base_of_image;
334
MemoryRegionInfo region = MinidumpParser::GetMemoryRegionInfo(regions, addr);
335
while (region.GetName() == path) {
336
if (region.GetExecutable() == MemoryRegionInfo::eYes)
337
return true;
338
addr += region.GetRange().GetByteSize();
339
region = MinidumpParser::GetMemoryRegionInfo(regions, addr);
340
}
341
return false;
342
}
343
344
std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() {
345
Log *log = GetLog(LLDBLog::Modules);
346
auto ExpectedModules = GetMinidumpFile().getModuleList();
347
if (!ExpectedModules) {
348
LLDB_LOG_ERROR(log, ExpectedModules.takeError(),
349
"Failed to read module list: {0}");
350
return {};
351
}
352
353
// Create memory regions from the linux maps only. We do this to avoid issues
354
// with breakpad generated minidumps where if someone has mmap'ed a shared
355
// library into memory to access its data in the object file, we can get a
356
// minidump with two mappings for a binary: one whose base image points to a
357
// memory region that is read + execute and one that is read only.
358
MemoryRegionInfos linux_regions;
359
if (CreateRegionsCacheFromLinuxMaps(*this, linux_regions))
360
llvm::sort(linux_regions);
361
362
// map module_name -> filtered_modules index
363
typedef llvm::StringMap<size_t> MapType;
364
MapType module_name_to_filtered_index;
365
366
std::vector<const minidump::Module *> filtered_modules;
367
368
for (const auto &module : *ExpectedModules) {
369
auto ExpectedName = m_file->getString(module.ModuleNameRVA);
370
if (!ExpectedName) {
371
LLDB_LOG_ERROR(log, ExpectedName.takeError(),
372
"Failed to get module name: {0}");
373
continue;
374
}
375
376
MapType::iterator iter;
377
bool inserted;
378
// See if we have inserted this module aready into filtered_modules. If we
379
// haven't insert an entry into module_name_to_filtered_index with the
380
// index where we will insert it if it isn't in the vector already.
381
std::tie(iter, inserted) = module_name_to_filtered_index.try_emplace(
382
*ExpectedName, filtered_modules.size());
383
384
if (inserted) {
385
// This module has not been seen yet, insert it into filtered_modules at
386
// the index that was inserted into module_name_to_filtered_index using
387
// "filtered_modules.size()" above.
388
filtered_modules.push_back(&module);
389
} else {
390
// We have a duplicate module entry. Check the linux regions to see if
391
// either module is not really a mapped executable. If one but not the
392
// other is a real mapped executable, prefer the executable one. This
393
// can happen when a process mmap's in the file for an executable in
394
// order to read bytes from the executable file. A memory region mapping
395
// will exist for the mmap'ed version and for the loaded executable, but
396
// only one will have a consecutive region that is executable in the
397
// memory regions.
398
auto dup_module = filtered_modules[iter->second];
399
ConstString name(*ExpectedName);
400
bool is_executable =
401
CheckForLinuxExecutable(name, linux_regions, module.BaseOfImage);
402
bool dup_is_executable =
403
CheckForLinuxExecutable(name, linux_regions, dup_module->BaseOfImage);
404
405
if (is_executable != dup_is_executable) {
406
if (is_executable)
407
filtered_modules[iter->second] = &module;
408
continue;
409
}
410
// This module has been seen. Modules are sometimes mentioned multiple
411
// times when they are mapped discontiguously, so find the module with
412
// the lowest "base_of_image" and use that as the filtered module.
413
if (module.BaseOfImage < dup_module->BaseOfImage)
414
filtered_modules[iter->second] = &module;
415
}
416
}
417
return filtered_modules;
418
}
419
420
const minidump::ExceptionStream *MinidumpParser::GetExceptionStream() {
421
auto ExpectedStream = GetMinidumpFile().getExceptionStream();
422
if (ExpectedStream)
423
return &*ExpectedStream;
424
425
LLDB_LOG_ERROR(GetLog(LLDBLog::Process), ExpectedStream.takeError(),
426
"Failed to read minidump exception stream: {0}");
427
return nullptr;
428
}
429
430
std::optional<minidump::Range>
431
MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
432
llvm::ArrayRef<uint8_t> data64 = GetStream(StreamType::Memory64List);
433
Log *log = GetLog(LLDBLog::Modules);
434
435
auto ExpectedMemory = GetMinidumpFile().getMemoryList();
436
if (!ExpectedMemory) {
437
LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),
438
"Failed to read memory list: {0}");
439
} else {
440
for (const auto &memory_desc : *ExpectedMemory) {
441
const LocationDescriptor &loc_desc = memory_desc.Memory;
442
const lldb::addr_t range_start = memory_desc.StartOfMemoryRange;
443
const size_t range_size = loc_desc.DataSize;
444
445
if (loc_desc.RVA + loc_desc.DataSize > GetData().size())
446
return std::nullopt;
447
448
if (range_start <= addr && addr < range_start + range_size) {
449
auto ExpectedSlice = GetMinidumpFile().getRawData(loc_desc);
450
if (!ExpectedSlice) {
451
LLDB_LOG_ERROR(log, ExpectedSlice.takeError(),
452
"Failed to get memory slice: {0}");
453
return std::nullopt;
454
}
455
return minidump::Range(range_start, *ExpectedSlice);
456
}
457
}
458
}
459
460
// Some Minidumps have a Memory64ListStream that captures all the heap memory
461
// (full-memory Minidumps). We can't exactly use the same loop as above,
462
// because the Minidump uses slightly different data structures to describe
463
// those
464
465
if (!data64.empty()) {
466
llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
467
uint64_t base_rva;
468
std::tie(memory64_list, base_rva) =
469
MinidumpMemoryDescriptor64::ParseMemory64List(data64);
470
471
if (memory64_list.empty())
472
return std::nullopt;
473
474
for (const auto &memory_desc64 : memory64_list) {
475
const lldb::addr_t range_start = memory_desc64.start_of_memory_range;
476
const size_t range_size = memory_desc64.data_size;
477
478
if (base_rva + range_size > GetData().size())
479
return std::nullopt;
480
481
if (range_start <= addr && addr < range_start + range_size) {
482
return minidump::Range(range_start,
483
GetData().slice(base_rva, range_size));
484
}
485
base_rva += range_size;
486
}
487
}
488
489
return std::nullopt;
490
}
491
492
llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
493
size_t size) {
494
// I don't have a sense of how frequently this is called or how many memory
495
// ranges a Minidump typically has, so I'm not sure if searching for the
496
// appropriate range linearly each time is stupid. Perhaps we should build
497
// an index for faster lookups.
498
std::optional<minidump::Range> range = FindMemoryRange(addr);
499
if (!range)
500
return {};
501
502
// There's at least some overlap between the beginning of the desired range
503
// (addr) and the current range. Figure out where the overlap begins and how
504
// much overlap there is.
505
506
const size_t offset = addr - range->start;
507
508
if (addr < range->start || offset >= range->range_ref.size())
509
return {};
510
511
const size_t overlap = std::min(size, range->range_ref.size() - offset);
512
return range->range_ref.slice(offset, overlap);
513
}
514
515
static bool
516
CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,
517
std::vector<MemoryRegionInfo> &regions) {
518
Log *log = GetLog(LLDBLog::Modules);
519
auto ExpectedInfo = parser.GetMinidumpFile().getMemoryInfoList();
520
if (!ExpectedInfo) {
521
LLDB_LOG_ERROR(log, ExpectedInfo.takeError(),
522
"Failed to read memory info list: {0}");
523
return false;
524
}
525
constexpr auto yes = MemoryRegionInfo::eYes;
526
constexpr auto no = MemoryRegionInfo::eNo;
527
for (const MemoryInfo &entry : *ExpectedInfo) {
528
MemoryRegionInfo region;
529
region.GetRange().SetRangeBase(entry.BaseAddress);
530
region.GetRange().SetByteSize(entry.RegionSize);
531
532
MemoryProtection prot = entry.Protect;
533
region.SetReadable(bool(prot & MemoryProtection::NoAccess) ? no : yes);
534
region.SetWritable(
535
bool(prot & (MemoryProtection::ReadWrite | MemoryProtection::WriteCopy |
536
MemoryProtection::ExecuteReadWrite |
537
MemoryProtection::ExeciteWriteCopy))
538
? yes
539
: no);
540
region.SetExecutable(
541
bool(prot & (MemoryProtection::Execute | MemoryProtection::ExecuteRead |
542
MemoryProtection::ExecuteReadWrite |
543
MemoryProtection::ExeciteWriteCopy))
544
? yes
545
: no);
546
region.SetMapped(entry.State != MemoryState::Free ? yes : no);
547
regions.push_back(region);
548
}
549
return !regions.empty();
550
}
551
552
static bool
553
CreateRegionsCacheFromMemoryList(MinidumpParser &parser,
554
std::vector<MemoryRegionInfo> &regions) {
555
Log *log = GetLog(LLDBLog::Modules);
556
auto ExpectedMemory = parser.GetMinidumpFile().getMemoryList();
557
if (!ExpectedMemory) {
558
LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),
559
"Failed to read memory list: {0}");
560
return false;
561
}
562
regions.reserve(ExpectedMemory->size());
563
for (const MemoryDescriptor &memory_desc : *ExpectedMemory) {
564
if (memory_desc.Memory.DataSize == 0)
565
continue;
566
MemoryRegionInfo region;
567
region.GetRange().SetRangeBase(memory_desc.StartOfMemoryRange);
568
region.GetRange().SetByteSize(memory_desc.Memory.DataSize);
569
region.SetReadable(MemoryRegionInfo::eYes);
570
region.SetMapped(MemoryRegionInfo::eYes);
571
regions.push_back(region);
572
}
573
regions.shrink_to_fit();
574
return !regions.empty();
575
}
576
577
static bool
578
CreateRegionsCacheFromMemory64List(MinidumpParser &parser,
579
std::vector<MemoryRegionInfo> &regions) {
580
llvm::ArrayRef<uint8_t> data =
581
parser.GetStream(StreamType::Memory64List);
582
if (data.empty())
583
return false;
584
llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
585
uint64_t base_rva;
586
std::tie(memory64_list, base_rva) =
587
MinidumpMemoryDescriptor64::ParseMemory64List(data);
588
589
if (memory64_list.empty())
590
return false;
591
592
regions.reserve(memory64_list.size());
593
for (const auto &memory_desc : memory64_list) {
594
if (memory_desc.data_size == 0)
595
continue;
596
MemoryRegionInfo region;
597
region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);
598
region.GetRange().SetByteSize(memory_desc.data_size);
599
region.SetReadable(MemoryRegionInfo::eYes);
600
region.SetMapped(MemoryRegionInfo::eYes);
601
regions.push_back(region);
602
}
603
regions.shrink_to_fit();
604
return !regions.empty();
605
}
606
607
std::pair<MemoryRegionInfos, bool> MinidumpParser::BuildMemoryRegions() {
608
// We create the region cache using the best source. We start with
609
// the linux maps since they are the most complete and have names for the
610
// regions. Next we try the MemoryInfoList since it has
611
// read/write/execute/map data, and then fall back to the MemoryList and
612
// Memory64List to just get a list of the memory that is mapped in this
613
// core file
614
MemoryRegionInfos result;
615
const auto &return_sorted = [&](bool is_complete) {
616
llvm::sort(result);
617
return std::make_pair(std::move(result), is_complete);
618
};
619
if (CreateRegionsCacheFromLinuxMaps(*this, result))
620
return return_sorted(true);
621
if (CreateRegionsCacheFromMemoryInfoList(*this, result))
622
return return_sorted(true);
623
if (CreateRegionsCacheFromMemoryList(*this, result))
624
return return_sorted(false);
625
CreateRegionsCacheFromMemory64List(*this, result);
626
return return_sorted(false);
627
}
628
629
#define ENUM_TO_CSTR(ST) \
630
case StreamType::ST: \
631
return #ST
632
633
llvm::StringRef
634
MinidumpParser::GetStreamTypeAsString(StreamType stream_type) {
635
switch (stream_type) {
636
ENUM_TO_CSTR(Unused);
637
ENUM_TO_CSTR(ThreadList);
638
ENUM_TO_CSTR(ModuleList);
639
ENUM_TO_CSTR(MemoryList);
640
ENUM_TO_CSTR(Exception);
641
ENUM_TO_CSTR(SystemInfo);
642
ENUM_TO_CSTR(ThreadExList);
643
ENUM_TO_CSTR(Memory64List);
644
ENUM_TO_CSTR(CommentA);
645
ENUM_TO_CSTR(CommentW);
646
ENUM_TO_CSTR(HandleData);
647
ENUM_TO_CSTR(FunctionTable);
648
ENUM_TO_CSTR(UnloadedModuleList);
649
ENUM_TO_CSTR(MiscInfo);
650
ENUM_TO_CSTR(MemoryInfoList);
651
ENUM_TO_CSTR(ThreadInfoList);
652
ENUM_TO_CSTR(HandleOperationList);
653
ENUM_TO_CSTR(Token);
654
ENUM_TO_CSTR(JavascriptData);
655
ENUM_TO_CSTR(SystemMemoryInfo);
656
ENUM_TO_CSTR(ProcessVMCounters);
657
ENUM_TO_CSTR(LastReserved);
658
ENUM_TO_CSTR(BreakpadInfo);
659
ENUM_TO_CSTR(AssertionInfo);
660
ENUM_TO_CSTR(LinuxCPUInfo);
661
ENUM_TO_CSTR(LinuxProcStatus);
662
ENUM_TO_CSTR(LinuxLSBRelease);
663
ENUM_TO_CSTR(LinuxCMDLine);
664
ENUM_TO_CSTR(LinuxEnviron);
665
ENUM_TO_CSTR(LinuxAuxv);
666
ENUM_TO_CSTR(LinuxMaps);
667
ENUM_TO_CSTR(LinuxDSODebug);
668
ENUM_TO_CSTR(LinuxProcStat);
669
ENUM_TO_CSTR(LinuxProcUptime);
670
ENUM_TO_CSTR(LinuxProcFD);
671
ENUM_TO_CSTR(FacebookAppCustomData);
672
ENUM_TO_CSTR(FacebookBuildID);
673
ENUM_TO_CSTR(FacebookAppVersionName);
674
ENUM_TO_CSTR(FacebookJavaStack);
675
ENUM_TO_CSTR(FacebookDalvikInfo);
676
ENUM_TO_CSTR(FacebookUnwindSymbols);
677
ENUM_TO_CSTR(FacebookDumpErrorLog);
678
ENUM_TO_CSTR(FacebookAppStateLog);
679
ENUM_TO_CSTR(FacebookAbortReason);
680
ENUM_TO_CSTR(FacebookThreadName);
681
ENUM_TO_CSTR(FacebookLogcat);
682
}
683
return "unknown stream type";
684
}
685
686
MemoryRegionInfo
687
MinidumpParser::GetMemoryRegionInfo(const MemoryRegionInfos &regions,
688
lldb::addr_t load_addr) {
689
MemoryRegionInfo region;
690
auto pos = llvm::upper_bound(regions, load_addr);
691
if (pos != regions.begin() &&
692
std::prev(pos)->GetRange().Contains(load_addr)) {
693
return *std::prev(pos);
694
}
695
696
if (pos == regions.begin())
697
region.GetRange().SetRangeBase(0);
698
else
699
region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd());
700
701
if (pos == regions.end())
702
region.GetRange().SetRangeEnd(UINT64_MAX);
703
else
704
region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase());
705
706
region.SetReadable(MemoryRegionInfo::eNo);
707
region.SetWritable(MemoryRegionInfo::eNo);
708
region.SetExecutable(MemoryRegionInfo::eNo);
709
region.SetMapped(MemoryRegionInfo::eNo);
710
return region;
711
}
712
713