blob: 58cafc737fcbde9a901b7bbafbcba5f62d359b1f [file] [log] [blame]
Dimitar Vlahovski36e21a32016-10-05 18:11:45 +00001//===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===//
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +00002//
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//
Dimitar Vlahovski36e21a32016-10-05 18:11:45 +00008//===----------------------------------------------------------------------===//
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +00009
10// Project includes
11#include "MinidumpParser.h"
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000012#include "NtStructures.h"
13#include "RegisterContextMinidump_x86_32.h"
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000014
15// Other libraries and framework includes
Dimitar Vlahovskib52206d2016-10-19 14:14:18 +000016#include "lldb/Target/MemoryRegionInfo.h"
17
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000018// C includes
19// C++ includes
Dimitar Vlahovskib52206d2016-10-19 14:14:18 +000020#include <map>
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000021
22using namespace lldb_private;
23using namespace minidump;
24
25llvm::Optional<MinidumpParser>
Kate Stoneb9c1b512016-09-06 20:57:50 +000026MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) {
27 if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader)) {
28 return llvm::None;
29 }
30
31 llvm::ArrayRef<uint8_t> header_data(data_buf_sp->GetBytes(),
32 sizeof(MinidumpHeader));
33 const MinidumpHeader *header = MinidumpHeader::Parse(header_data);
34
35 if (header == nullptr) {
36 return llvm::None;
37 }
38
39 lldb::offset_t directory_list_offset = header->stream_directory_rva;
40 // check if there is enough data for the parsing of the directory list
41 if ((directory_list_offset +
42 sizeof(MinidumpDirectory) * header->streams_count) >
43 data_buf_sp->GetByteSize()) {
44 return llvm::None;
45 }
46
47 const MinidumpDirectory *directory = nullptr;
Zachary Turner97206d52017-05-12 04:51:55 +000048 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +000049 llvm::ArrayRef<uint8_t> directory_data(
50 data_buf_sp->GetBytes() + directory_list_offset,
51 sizeof(MinidumpDirectory) * header->streams_count);
52 llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map;
53
54 for (uint32_t i = 0; i < header->streams_count; ++i) {
55 error = consumeObject(directory_data, directory);
56 if (error.Fail()) {
57 return llvm::None;
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000058 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000059 directory_map[static_cast<const uint32_t>(directory->stream_type)] =
60 directory->location;
61 }
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000062
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +000063 return MinidumpParser(data_buf_sp, header, std::move(directory_map));
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000064}
65
Kate Stoneb9c1b512016-09-06 20:57:50 +000066MinidumpParser::MinidumpParser(
67 const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header,
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +000068 llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map)
Kate Stoneb9c1b512016-09-06 20:57:50 +000069 : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) {
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000070}
71
Dimitar Vlahovski4c319072016-09-27 19:05:55 +000072llvm::ArrayRef<uint8_t> MinidumpParser::GetData() {
Dimitar Vlahovski36e21a32016-10-05 18:11:45 +000073 return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(),
74 m_data_sp->GetByteSize());
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000075}
76
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +000077llvm::ArrayRef<uint8_t>
Kate Stoneb9c1b512016-09-06 20:57:50 +000078MinidumpParser::GetStream(MinidumpStreamType stream_type) {
79 auto iter = m_directory_map.find(static_cast<uint32_t>(stream_type));
80 if (iter == m_directory_map.end())
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +000081 return {};
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000082
Kate Stoneb9c1b512016-09-06 20:57:50 +000083 // check if there is enough data
Dimitar Vlahovski36e21a32016-10-05 18:11:45 +000084 if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize())
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +000085 return {};
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000086
Dimitar Vlahovski36e21a32016-10-05 18:11:45 +000087 return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva,
88 iter->second.data_size);
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000089}
90
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +000091llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) {
Dimitar Vlahovski36e21a32016-10-05 18:11:45 +000092 auto arr_ref = m_data_sp->GetData();
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +000093 if (rva > arr_ref.size())
94 return llvm::None;
95 arr_ref = arr_ref.drop_front(rva);
96 return parseMinidumpString(arr_ref);
97}
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +000098
Leonard Mosescu9fecd372018-05-02 20:06:17 +000099UUID MinidumpParser::GetModuleUUID(const MinidumpModule *module) {
100 auto cv_record =
101 GetData().slice(module->CV_record.rva, module->CV_record.data_size);
102
103 // Read the CV record signature
104 const llvm::support::ulittle32_t *signature = nullptr;
105 Status error = consumeObject(cv_record, signature);
106 if (error.Fail())
107 return UUID();
108
109 const CvSignature cv_signature =
110 static_cast<CvSignature>(static_cast<const uint32_t>(*signature));
111
112 if (cv_signature == CvSignature::Pdb70) {
113 // PDB70 record
114 const CvRecordPdb70 *pdb70_uuid = nullptr;
115 Status error = consumeObject(cv_record, pdb70_uuid);
116 if (!error.Fail())
117 return UUID(pdb70_uuid, sizeof(*pdb70_uuid));
118 } else if (cv_signature == CvSignature::ElfBuildId) {
119 // ELF BuildID (found in Breakpad/Crashpad generated minidumps)
120 //
121 // This is variable-length, but usually 20 bytes
122 // as the binutils ld default is a SHA-1 hash.
123 // (We'll handle only 16 and 20 bytes signatures,
124 // matching LLDB support for UUIDs)
125 //
126 if (cv_record.size() == 16 || cv_record.size() == 20)
127 return UUID(cv_record.data(), cv_record.size());
128 }
129
130 return UUID();
131}
132
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000133llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() {
134 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList);
135
136 if (data.size() == 0)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000137 return llvm::None;
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +0000138
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000139 return MinidumpThread::ParseThreadList(data);
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +0000140}
141
Dimitar Vlahovskib52206d2016-10-19 14:14:18 +0000142llvm::ArrayRef<uint8_t>
143MinidumpParser::GetThreadContext(const MinidumpThread &td) {
144 if (td.thread_context.rva + td.thread_context.data_size > GetData().size())
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000145 return {};
Dimitar Vlahovskib52206d2016-10-19 14:14:18 +0000146
147 return GetData().slice(td.thread_context.rva, td.thread_context.data_size);
148}
149
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000150llvm::ArrayRef<uint8_t>
151MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) {
Adrian Prantl05097242018-04-30 16:49:04 +0000152 // On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If
153 // the minidump was captured with a 64-bit debugger, then the CONTEXT we just
154 // grabbed from the mini_dump_thread is the one for the 64-bit "native"
155 // process rather than the 32-bit "guest" process we care about. In this
156 // case, we can get the 32-bit CONTEXT from the TEB (Thread Environment
157 // Block) of the 64-bit process.
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000158 auto teb_mem = GetMemory(td.teb, sizeof(TEB64));
159 if (teb_mem.empty())
160 return {};
161
162 const TEB64 *wow64teb;
Zachary Turner97206d52017-05-12 04:51:55 +0000163 Status error = consumeObject(teb_mem, wow64teb);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000164 if (error.Fail())
165 return {};
166
Adrian Prantl05097242018-04-30 16:49:04 +0000167 // Slot 1 of the thread-local storage in the 64-bit TEB points to a structure
168 // that includes the 32-bit CONTEXT (after a ULONG). See:
169 // https://msdn.microsoft.com/en-us/library/ms681670.aspx
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000170 auto context =
171 GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32));
172 if (context.size() < sizeof(MinidumpContext_x86_32))
173 return {};
174
175 return context;
176 // NOTE: We don't currently use the TEB for anything else. If we
177 // need it in the future, the 32-bit TEB is located according to the address
178 // stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]).
179}
180
Kate Stoneb9c1b512016-09-06 20:57:50 +0000181const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000182 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo);
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +0000183
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000184 if (data.size() == 0)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000185 return nullptr;
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +0000186
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000187 return MinidumpSystemInfo::Parse(data);
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +0000188}
189
Kate Stoneb9c1b512016-09-06 20:57:50 +0000190ArchSpec MinidumpParser::GetArchitecture() {
191 ArchSpec arch_spec;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000192 const MinidumpSystemInfo *system_info = GetSystemInfo();
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +0000193
Kate Stoneb9c1b512016-09-06 20:57:50 +0000194 if (!system_info)
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +0000195 return arch_spec;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000196
197 // TODO what to do about big endiand flavors of arm ?
198 // TODO set the arm subarch stuff if the minidump has info about it
199
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000200 llvm::Triple triple;
201 triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
202
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203 const MinidumpCPUArchitecture arch =
204 static_cast<const MinidumpCPUArchitecture>(
205 static_cast<const uint32_t>(system_info->processor_arch));
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000206
Kate Stoneb9c1b512016-09-06 20:57:50 +0000207 switch (arch) {
208 case MinidumpCPUArchitecture::X86:
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000209 triple.setArch(llvm::Triple::ArchType::x86);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000210 break;
211 case MinidumpCPUArchitecture::AMD64:
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000212 triple.setArch(llvm::Triple::ArchType::x86_64);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000213 break;
214 case MinidumpCPUArchitecture::ARM:
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000215 triple.setArch(llvm::Triple::ArchType::arm);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000216 break;
217 case MinidumpCPUArchitecture::ARM64:
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000218 triple.setArch(llvm::Triple::ArchType::aarch64);
219 break;
220 default:
221 triple.setArch(llvm::Triple::ArchType::UnknownArch);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000222 break;
223 }
224
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000225 const MinidumpOSPlatform os = static_cast<const MinidumpOSPlatform>(
226 static_cast<const uint32_t>(system_info->platform_id));
227
228 // TODO add all of the OSes that Minidump/breakpad distinguishes?
229 switch (os) {
230 case MinidumpOSPlatform::Win32S:
231 case MinidumpOSPlatform::Win32Windows:
232 case MinidumpOSPlatform::Win32NT:
233 case MinidumpOSPlatform::Win32CE:
234 triple.setOS(llvm::Triple::OSType::Win32);
235 break;
236 case MinidumpOSPlatform::Linux:
237 triple.setOS(llvm::Triple::OSType::Linux);
238 break;
239 case MinidumpOSPlatform::MacOSX:
240 triple.setOS(llvm::Triple::OSType::MacOSX);
241 break;
242 case MinidumpOSPlatform::Android:
243 triple.setOS(llvm::Triple::OSType::Linux);
244 triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
245 break;
246 default:
247 triple.setOS(llvm::Triple::OSType::UnknownOS);
248 break;
249 }
250
251 arch_spec.SetTriple(triple);
252
Kate Stoneb9c1b512016-09-06 20:57:50 +0000253 return arch_spec;
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +0000254}
255
Kate Stoneb9c1b512016-09-06 20:57:50 +0000256const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000257 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MiscInfo);
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +0000258
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000259 if (data.size() == 0)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000260 return nullptr;
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +0000261
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000262 return MinidumpMiscInfo::Parse(data);
263}
264
265llvm::Optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {
266 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::LinuxProcStatus);
267
268 if (data.size() == 0)
269 return llvm::None;
270
271 return LinuxProcStatus::Parse(data);
272}
273
274llvm::Optional<lldb::pid_t> MinidumpParser::GetPid() {
275 const MinidumpMiscInfo *misc_info = GetMiscInfo();
276 if (misc_info != nullptr) {
277 return misc_info->GetPid();
278 }
279
280 llvm::Optional<LinuxProcStatus> proc_status = GetLinuxProcStatus();
281 if (proc_status.hasValue()) {
282 return proc_status->GetPid();
283 }
284
285 return llvm::None;
286}
287
288llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() {
289 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ModuleList);
290
291 if (data.size() == 0)
292 return {};
293
294 return MinidumpModule::ParseModuleList(data);
295}
296
Dimitar Vlahovskib52206d2016-10-19 14:14:18 +0000297std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() {
298 llvm::ArrayRef<MinidumpModule> modules = GetModuleList();
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000299 // map module_name -> pair(load_address, pointer to module struct in memory)
Dimitar Vlahovskib52206d2016-10-19 14:14:18 +0000300 llvm::StringMap<std::pair<uint64_t, const MinidumpModule *>> lowest_addr;
301
302 std::vector<const MinidumpModule *> filtered_modules;
303
304 llvm::Optional<std::string> name;
305 std::string module_name;
306
307 for (const auto &module : modules) {
308 name = GetMinidumpString(module.module_name_rva);
309
310 if (!name)
311 continue;
312
313 module_name = name.getValue();
314
315 auto iter = lowest_addr.end();
316 bool exists;
317 std::tie(iter, exists) = lowest_addr.try_emplace(
318 module_name, std::make_pair(module.base_of_image, &module));
319
320 if (exists && module.base_of_image < iter->second.first)
321 iter->second = std::make_pair(module.base_of_image, &module);
322 }
323
324 filtered_modules.reserve(lowest_addr.size());
325 for (const auto &module : lowest_addr) {
326 filtered_modules.push_back(module.second.second);
327 }
328
329 return filtered_modules;
330}
331
Dimitar Vlahovski1d2859e2016-09-13 15:54:38 +0000332const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() {
333 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::Exception);
334
335 if (data.size() == 0)
336 return nullptr;
337
338 return MinidumpExceptionStream::Parse(data);
Dimitar Vlahovski2e50d8e2016-09-01 11:29:53 +0000339}
Dimitar Vlahovskib52206d2016-10-19 14:14:18 +0000340
341llvm::Optional<minidump::Range>
342MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
343 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryList);
344 llvm::ArrayRef<uint8_t> data64 = GetStream(MinidumpStreamType::Memory64List);
345
346 if (data.empty() && data64.empty())
347 return llvm::None;
348
349 if (!data.empty()) {
350 llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list =
351 MinidumpMemoryDescriptor::ParseMemoryList(data);
352
353 if (memory_list.empty())
354 return llvm::None;
355
356 for (const auto &memory_desc : memory_list) {
357 const MinidumpLocationDescriptor &loc_desc = memory_desc.memory;
358 const lldb::addr_t range_start = memory_desc.start_of_memory_range;
359 const size_t range_size = loc_desc.data_size;
360
361 if (loc_desc.rva + loc_desc.data_size > GetData().size())
362 return llvm::None;
363
364 if (range_start <= addr && addr < range_start + range_size) {
365 return minidump::Range(range_start,
366 GetData().slice(loc_desc.rva, range_size));
367 }
368 }
369 }
370
Adrian Prantl05097242018-04-30 16:49:04 +0000371 // Some Minidumps have a Memory64ListStream that captures all the heap memory
372 // (full-memory Minidumps). We can't exactly use the same loop as above,
373 // because the Minidump uses slightly different data structures to describe
374 // those
Dimitar Vlahovskib52206d2016-10-19 14:14:18 +0000375
376 if (!data64.empty()) {
377 llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
378 uint64_t base_rva;
379 std::tie(memory64_list, base_rva) =
380 MinidumpMemoryDescriptor64::ParseMemory64List(data64);
381
382 if (memory64_list.empty())
383 return llvm::None;
384
385 for (const auto &memory_desc64 : memory64_list) {
386 const lldb::addr_t range_start = memory_desc64.start_of_memory_range;
387 const size_t range_size = memory_desc64.data_size;
388
389 if (base_rva + range_size > GetData().size())
390 return llvm::None;
391
392 if (range_start <= addr && addr < range_start + range_size) {
393 return minidump::Range(range_start,
394 GetData().slice(base_rva, range_size));
395 }
396 base_rva += range_size;
397 }
398 }
399
400 return llvm::None;
401}
402
403llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
404 size_t size) {
405 // I don't have a sense of how frequently this is called or how many memory
406 // ranges a Minidump typically has, so I'm not sure if searching for the
407 // appropriate range linearly each time is stupid. Perhaps we should build
408 // an index for faster lookups.
409 llvm::Optional<minidump::Range> range = FindMemoryRange(addr);
410 if (!range)
411 return {};
412
413 // There's at least some overlap between the beginning of the desired range
Adrian Prantl05097242018-04-30 16:49:04 +0000414 // (addr) and the current range. Figure out where the overlap begins and how
415 // much overlap there is.
Dimitar Vlahovskib52206d2016-10-19 14:14:18 +0000416
417 const size_t offset = addr - range->start;
418
419 if (addr < range->start || offset >= range->range_ref.size())
420 return {};
421
422 const size_t overlap = std::min(size, range->range_ref.size() - offset);
423 return range->range_ref.slice(offset, overlap);
424}
425
426llvm::Optional<MemoryRegionInfo>
427MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) {
428 MemoryRegionInfo info;
429 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryInfoList);
430 if (data.empty())
431 return llvm::None;
432
433 std::vector<const MinidumpMemoryInfo *> mem_info_list =
434 MinidumpMemoryInfo::ParseMemoryInfoList(data);
435 if (mem_info_list.empty())
436 return llvm::None;
437
438 const auto yes = MemoryRegionInfo::eYes;
439 const auto no = MemoryRegionInfo::eNo;
440
441 const MinidumpMemoryInfo *next_entry = nullptr;
442 for (const auto &entry : mem_info_list) {
443 const auto head = entry->base_address;
444 const auto tail = head + entry->region_size;
445
446 if (head <= load_addr && load_addr < tail) {
447 info.GetRange().SetRangeBase(
448 (entry->state != uint32_t(MinidumpMemoryInfoState::MemFree))
449 ? head
450 : load_addr);
451 info.GetRange().SetRangeEnd(tail);
452
453 const uint32_t PageNoAccess =
454 static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageNoAccess);
455 info.SetReadable((entry->protect & PageNoAccess) == 0 ? yes : no);
456
457 const uint32_t PageWritable =
458 static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageWritable);
459 info.SetWritable((entry->protect & PageWritable) != 0 ? yes : no);
460
461 const uint32_t PageExecutable = static_cast<uint32_t>(
462 MinidumpMemoryProtectionContants::PageExecutable);
463 info.SetExecutable((entry->protect & PageExecutable) != 0 ? yes : no);
464
465 const uint32_t MemFree =
466 static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree);
467 info.SetMapped((entry->state != MemFree) ? yes : no);
468
469 return info;
470 } else if (head > load_addr &&
471 (next_entry == nullptr || head < next_entry->base_address)) {
472 // In case there is no region containing load_addr keep track of the
473 // nearest region after load_addr so we can return the distance to it.
474 next_entry = entry;
475 }
476 }
477
478 // No containing region found. Create an unmapped region that extends to the
479 // next region or LLDB_INVALID_ADDRESS
480 info.GetRange().SetRangeBase(load_addr);
481 info.GetRange().SetRangeEnd((next_entry != nullptr) ? next_entry->base_address
482 : LLDB_INVALID_ADDRESS);
483 info.SetReadable(no);
484 info.SetWritable(no);
485 info.SetExecutable(no);
486 info.SetMapped(no);
487
488 // Note that the memory info list doesn't seem to contain ranges in kernel
489 // space, so if you're walking a stack that has kernel frames, the stack may
490 // appear truncated.
491 return info;
492}