File: | tools/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp |
Warning: | line 139, column 17 Called C++ object pointer is uninitialized |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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(18446744073709551615UL)); | |||
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())lldb_private::lldb_assert(static_cast<bool>(m_directory_map .empty()), "m_directory_map.empty()", __FUNCTION__, "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp" , 477); | |||
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 | } |
1 | //===-- MinidumpTypes.h -----------------------------------------*- 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 | #ifndef liblldb_MinidumpTypes_h_ |
11 | #define liblldb_MinidumpTypes_h_ |
12 | |
13 | // Project includes |
14 | |
15 | // Other libraries and framework includes |
16 | #include "lldb/Utility/Status.h" |
17 | |
18 | #include "llvm/ADT/ArrayRef.h" |
19 | #include "llvm/ADT/BitmaskEnum.h" |
20 | #include "llvm/ADT/Optional.h" |
21 | #include "llvm/ADT/SmallVector.h" |
22 | #include "llvm/ADT/StringRef.h" |
23 | #include "llvm/Support/ConvertUTF.h" |
24 | #include "llvm/Support/Endian.h" |
25 | |
26 | // C includes |
27 | // C++ includes |
28 | |
29 | // Reference: |
30 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms679293(v=vs.85).aspx |
31 | // https://chromium.googlesource.com/breakpad/breakpad/ |
32 | |
33 | namespace lldb_private { |
34 | |
35 | namespace minidump { |
36 | |
37 | LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()using ::llvm::BitmaskEnumDetail::operator~; using ::llvm::BitmaskEnumDetail ::operator|; using ::llvm::BitmaskEnumDetail::operator&; using ::llvm::BitmaskEnumDetail::operator^; using ::llvm::BitmaskEnumDetail ::operator|=; using ::llvm::BitmaskEnumDetail::operator&= ; using ::llvm::BitmaskEnumDetail::operator^=; |
38 | |
39 | enum class MinidumpHeaderConstants : uint32_t { |
40 | Signature = 0x504d444d, // 'PMDM' |
41 | Version = 0x0000a793, // 42899 |
42 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Signature)LLVM_BITMASK_LARGEST_ENUMERATOR = Signature |
43 | |
44 | }; |
45 | |
46 | enum class CvSignature : uint32_t { |
47 | Pdb70 = 0x53445352, // RSDS |
48 | ElfBuildId = 0x4270454c, // BpEL (Breakpad/Crashpad minidumps) |
49 | }; |
50 | |
51 | // Reference: |
52 | // https://crashpad.chromium.org/doxygen/structcrashpad_1_1CodeViewRecordPDB70.html |
53 | struct CvRecordPdb70 { |
54 | uint8_t Uuid[16]; |
55 | llvm::support::ulittle32_t Age; |
56 | // char PDBFileName[]; |
57 | }; |
58 | static_assert(sizeof(CvRecordPdb70) == 20, |
59 | "sizeof CvRecordPdb70 is not correct!"); |
60 | |
61 | // Reference: |
62 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680394.aspx |
63 | enum class MinidumpStreamType : uint32_t { |
64 | Unused = 0, |
65 | Reserved0 = 1, |
66 | Reserved1 = 2, |
67 | ThreadList = 3, |
68 | ModuleList = 4, |
69 | MemoryList = 5, |
70 | Exception = 6, |
71 | SystemInfo = 7, |
72 | ThreadExList = 8, |
73 | Memory64List = 9, |
74 | CommentA = 10, |
75 | CommentW = 11, |
76 | HandleData = 12, |
77 | FunctionTable = 13, |
78 | UnloadedModuleList = 14, |
79 | MiscInfo = 15, |
80 | MemoryInfoList = 16, |
81 | ThreadInfoList = 17, |
82 | HandleOperationList = 18, |
83 | Token = 19, |
84 | JavascriptData = 20, |
85 | SystemMemoryInfo = 21, |
86 | ProcessVMCounters = 22, |
87 | LastReserved = 0x0000ffff, |
88 | |
89 | /* Breakpad extension types. 0x4767 = "Gg" */ |
90 | BreakpadInfo = 0x47670001, |
91 | AssertionInfo = 0x47670002, |
92 | /* These are additional minidump stream values which are specific to |
93 | * the linux breakpad implementation. */ |
94 | LinuxCPUInfo = 0x47670003, /* /proc/cpuinfo */ |
95 | LinuxProcStatus = 0x47670004, /* /proc/$x/status */ |
96 | LinuxLSBRelease = 0x47670005, /* /etc/lsb-release */ |
97 | LinuxCMDLine = 0x47670006, /* /proc/$x/cmdline */ |
98 | LinuxEnviron = 0x47670007, /* /proc/$x/environ */ |
99 | LinuxAuxv = 0x47670008, /* /proc/$x/auxv */ |
100 | LinuxMaps = 0x47670009, /* /proc/$x/maps */ |
101 | LinuxDSODebug = 0x4767000A |
102 | }; |
103 | |
104 | // for MinidumpSystemInfo.processor_arch |
105 | enum class MinidumpCPUArchitecture : uint16_t { |
106 | X86 = 0, /* PROCESSOR_ARCHITECTURE_INTEL */ |
107 | MIPS = 1, /* PROCESSOR_ARCHITECTURE_MIPS */ |
108 | Alpha = 2, /* PROCESSOR_ARCHITECTURE_ALPHA */ |
109 | PPC = 3, /* PROCESSOR_ARCHITECTURE_PPC */ |
110 | SHX = 4, /* PROCESSOR_ARCHITECTURE_SHX (Super-H) */ |
111 | ARM = 5, /* PROCESSOR_ARCHITECTURE_ARM */ |
112 | IA64 = 6, /* PROCESSOR_ARCHITECTURE_IA64 */ |
113 | Alpha64 = 7, /* PROCESSOR_ARCHITECTURE_ALPHA64 */ |
114 | MSIL = 8, /* PROCESSOR_ARCHITECTURE_MSIL |
115 | * (Microsoft Intermediate Language) */ |
116 | AMD64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */ |
117 | X86Win64 = 10, /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */ |
118 | SPARC = 0x8001, /* Breakpad-defined value for SPARC */ |
119 | PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */ |
120 | ARM64 = 0x8003, /* Breakpad-defined value for ARM64 */ |
121 | MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */ |
122 | Unknown = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */ |
123 | }; |
124 | |
125 | // for MinidumpSystemInfo.platform_id |
126 | enum class MinidumpOSPlatform : uint32_t { |
127 | Win32S = 0, /* VER_PLATFORM_WIN32s (Windows 3.1) */ |
128 | Win32Windows = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */ |
129 | Win32NT = 2, /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */ |
130 | Win32CE = 3, /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH |
131 | * (Windows CE, Windows Mobile, "Handheld") */ |
132 | |
133 | /* The following values are Breakpad-defined. */ |
134 | Unix = 0x8000, /* Generic Unix-ish */ |
135 | MacOSX = 0x8101, /* Mac OS X/Darwin */ |
136 | IOS = 0x8102, /* iOS */ |
137 | Linux = 0x8201, /* Linux */ |
138 | Solaris = 0x8202, /* Solaris */ |
139 | Android = 0x8203, /* Android */ |
140 | PS3 = 0x8204, /* PS3 */ |
141 | NaCl = 0x8205 /* Native Client (NaCl) */ |
142 | }; |
143 | |
144 | // For MinidumpCPUInfo.arm_cpu_info.elf_hwcaps. |
145 | // This matches the Linux kernel definitions from <asm/hwcaps.h> |
146 | enum class MinidumpPCPUInformationARMElfHwCaps : uint32_t { |
147 | SWP = (1 << 0), |
148 | Half = (1 << 1), |
149 | Thumb = (1 << 2), |
150 | _26BIT = (1 << 3), |
151 | FastMult = (1 << 4), |
152 | FPA = (1 << 5), |
153 | VFP = (1 << 6), |
154 | EDSP = (1 << 7), |
155 | Java = (1 << 8), |
156 | IWMMXT = (1 << 9), |
157 | Crunch = (1 << 10), |
158 | ThumbEE = (1 << 11), |
159 | Neon = (1 << 12), |
160 | VFPv3 = (1 << 13), |
161 | VFPv3D16 = (1 << 14), |
162 | TLS = (1 << 15), |
163 | VFPv4 = (1 << 16), |
164 | IDIVA = (1 << 17), |
165 | IDIVT = (1 << 18), |
166 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IDIVT)LLVM_BITMASK_LARGEST_ENUMERATOR = IDIVT |
167 | }; |
168 | |
169 | enum class MinidumpMiscInfoFlags : uint32_t { |
170 | ProcessID = (1 << 0), |
171 | ProcessTimes = (1 << 1), |
172 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ ProcessTimes)LLVM_BITMASK_LARGEST_ENUMERATOR = ProcessTimes |
173 | }; |
174 | |
175 | template <typename T> |
176 | Status consumeObject(llvm::ArrayRef<uint8_t> &Buffer, const T *&Object) { |
177 | Status error; |
178 | if (Buffer.size() < sizeof(T)) { |
179 | error.SetErrorString("Insufficient buffer!"); |
180 | return error; |
181 | } |
182 | |
183 | Object = reinterpret_cast<const T *>(Buffer.data()); |
184 | Buffer = Buffer.drop_front(sizeof(T)); |
185 | return error; |
186 | } |
187 | |
188 | // parse a MinidumpString which is with UTF-16 |
189 | // Reference: |
190 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680395(v=vs.85).aspx |
191 | llvm::Optional<std::string> parseMinidumpString(llvm::ArrayRef<uint8_t> &data); |
192 | |
193 | // Reference: |
194 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680378(v=vs.85).aspx |
195 | struct MinidumpHeader { |
196 | llvm::support::ulittle32_t signature; |
197 | llvm::support::ulittle32_t |
198 | version; // The high 16 bits of version field are implementation specific |
199 | llvm::support::ulittle32_t streams_count; |
200 | llvm::support::ulittle32_t |
201 | stream_directory_rva; // offset of the stream directory |
202 | llvm::support::ulittle32_t checksum; |
203 | llvm::support::ulittle32_t time_date_stamp; // time_t format |
204 | llvm::support::ulittle64_t flags; |
205 | |
206 | static const MinidumpHeader *Parse(llvm::ArrayRef<uint8_t> &data); |
207 | }; |
208 | static_assert(sizeof(MinidumpHeader) == 32, |
209 | "sizeof MinidumpHeader is not correct!"); |
210 | |
211 | // Reference: |
212 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680383.aspx |
213 | struct MinidumpLocationDescriptor { |
214 | llvm::support::ulittle32_t data_size; |
215 | llvm::support::ulittle32_t rva; |
216 | }; |
217 | static_assert(sizeof(MinidumpLocationDescriptor) == 8, |
218 | "sizeof MinidumpLocationDescriptor is not correct!"); |
219 | |
220 | // Reference: |
221 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680384(v=vs.85).aspx |
222 | struct MinidumpMemoryDescriptor { |
223 | llvm::support::ulittle64_t start_of_memory_range; |
224 | MinidumpLocationDescriptor memory; |
225 | |
226 | static llvm::ArrayRef<MinidumpMemoryDescriptor> |
227 | ParseMemoryList(llvm::ArrayRef<uint8_t> &data); |
228 | }; |
229 | static_assert(sizeof(MinidumpMemoryDescriptor) == 16, |
230 | "sizeof MinidumpMemoryDescriptor is not correct!"); |
231 | |
232 | struct MinidumpMemoryDescriptor64 { |
233 | llvm::support::ulittle64_t start_of_memory_range; |
234 | llvm::support::ulittle64_t data_size; |
235 | |
236 | static std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t> |
237 | ParseMemory64List(llvm::ArrayRef<uint8_t> &data); |
238 | }; |
239 | static_assert(sizeof(MinidumpMemoryDescriptor64) == 16, |
240 | "sizeof MinidumpMemoryDescriptor64 is not correct!"); |
241 | |
242 | // Reference: |
243 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680365.aspx |
244 | struct MinidumpDirectory { |
245 | llvm::support::ulittle32_t stream_type; |
246 | MinidumpLocationDescriptor location; |
247 | }; |
248 | static_assert(sizeof(MinidumpDirectory) == 12, |
249 | "sizeof MinidumpDirectory is not correct!"); |
250 | |
251 | // Reference: |
252 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680385(v=vs.85).aspx |
253 | struct MinidumpMemoryInfoListHeader { |
254 | llvm::support::ulittle32_t size_of_header; |
255 | llvm::support::ulittle32_t size_of_entry; |
256 | llvm::support::ulittle64_t num_of_entries; |
257 | }; |
258 | static_assert(sizeof(MinidumpMemoryInfoListHeader) == 16, |
259 | "sizeof MinidumpMemoryInfoListHeader is not correct!"); |
260 | |
261 | // Reference: |
262 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680386(v=vs.85).aspx |
263 | struct MinidumpMemoryInfo { |
264 | llvm::support::ulittle64_t base_address; |
265 | llvm::support::ulittle64_t allocation_base; |
266 | llvm::support::ulittle32_t allocation_protect; |
267 | llvm::support::ulittle32_t alignment1; |
268 | llvm::support::ulittle64_t region_size; |
269 | llvm::support::ulittle32_t state; |
270 | llvm::support::ulittle32_t protect; |
271 | llvm::support::ulittle32_t type; |
272 | llvm::support::ulittle32_t alignment2; |
273 | |
274 | static std::vector<const MinidumpMemoryInfo *> |
275 | ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data); |
276 | }; |
277 | static_assert(sizeof(MinidumpMemoryInfo) == 48, |
278 | "sizeof MinidumpMemoryInfo is not correct!"); |
279 | |
280 | enum class MinidumpMemoryInfoState : uint32_t { |
281 | MemCommit = 0x1000, |
282 | MemFree = 0x10000, |
283 | MemReserve = 0x2000, |
284 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemFree)LLVM_BITMASK_LARGEST_ENUMERATOR = MemFree |
285 | }; |
286 | |
287 | enum class MinidumpMemoryInfoType : uint32_t { |
288 | MemImage = 0x1000000, |
289 | MemMapped = 0x40000, |
290 | MemPrivate = 0x20000, |
291 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemImage)LLVM_BITMASK_LARGEST_ENUMERATOR = MemImage |
292 | }; |
293 | |
294 | // Reference: |
295 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx |
296 | enum class MinidumpMemoryProtectionContants : uint32_t { |
297 | PageExecute = 0x10, |
298 | PageExecuteRead = 0x20, |
299 | PageExecuteReadWrite = 0x40, |
300 | PageExecuteWriteCopy = 0x80, |
301 | PageNoAccess = 0x01, |
302 | PageReadOnly = 0x02, |
303 | PageReadWrite = 0x04, |
304 | PageWriteCopy = 0x08, |
305 | PageTargetsInvalid = 0x40000000, |
306 | PageTargetsNoUpdate = 0x40000000, |
307 | |
308 | PageWritable = PageExecuteReadWrite | PageExecuteWriteCopy | PageReadWrite | |
309 | PageWriteCopy, |
310 | PageExecutable = PageExecute | PageExecuteRead | PageExecuteReadWrite | |
311 | PageExecuteWriteCopy, |
312 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ PageTargetsInvalid)LLVM_BITMASK_LARGEST_ENUMERATOR = PageTargetsInvalid |
313 | }; |
314 | |
315 | // Reference: |
316 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx |
317 | struct MinidumpThread { |
318 | llvm::support::ulittle32_t thread_id; |
319 | llvm::support::ulittle32_t suspend_count; |
320 | llvm::support::ulittle32_t priority_class; |
321 | llvm::support::ulittle32_t priority; |
322 | llvm::support::ulittle64_t teb; |
323 | MinidumpMemoryDescriptor stack; |
324 | MinidumpLocationDescriptor thread_context; |
325 | |
326 | static const MinidumpThread *Parse(llvm::ArrayRef<uint8_t> &data); |
327 | |
328 | static llvm::ArrayRef<MinidumpThread> |
329 | ParseThreadList(llvm::ArrayRef<uint8_t> &data); |
330 | }; |
331 | static_assert(sizeof(MinidumpThread) == 48, |
332 | "sizeof MinidumpThread is not correct!"); |
333 | |
334 | // Reference: |
335 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680396(v=vs.85).aspx |
336 | union MinidumpCPUInfo { |
337 | struct { |
338 | llvm::support::ulittle32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */ |
339 | llvm::support::ulittle32_t version_information; /* cpuid 1: eax */ |
340 | llvm::support::ulittle32_t feature_information; /* cpuid 1: edx */ |
341 | llvm::support::ulittle32_t |
342 | amd_extended_cpu_features; /* cpuid 0x80000001, ebx */ |
343 | } x86_cpu_info; |
344 | struct { |
345 | llvm::support::ulittle32_t cpuid; |
346 | llvm::support::ulittle32_t elf_hwcaps; /* linux specific, 0 otherwise */ |
347 | } arm_cpu_info; |
348 | struct { |
349 | llvm::support::ulittle64_t processor_features[2]; |
350 | } other_cpu_info; |
351 | }; |
352 | static_assert(sizeof(MinidumpCPUInfo) == 24, |
353 | "sizeof MinidumpCPUInfo is not correct!"); |
354 | |
355 | // Reference: |
356 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680396(v=vs.85).aspx |
357 | struct MinidumpSystemInfo { |
358 | llvm::support::ulittle16_t processor_arch; |
359 | llvm::support::ulittle16_t processor_level; |
360 | llvm::support::ulittle16_t processor_revision; |
361 | |
362 | uint8_t number_of_processors; |
363 | uint8_t product_type; |
364 | |
365 | llvm::support::ulittle32_t major_version; |
366 | llvm::support::ulittle32_t minor_version; |
367 | llvm::support::ulittle32_t build_number; |
368 | llvm::support::ulittle32_t platform_id; |
369 | llvm::support::ulittle32_t csd_version_rva; |
370 | |
371 | llvm::support::ulittle16_t suit_mask; |
372 | llvm::support::ulittle16_t reserved2; |
373 | |
374 | MinidumpCPUInfo cpu; |
375 | |
376 | static const MinidumpSystemInfo *Parse(llvm::ArrayRef<uint8_t> &data); |
377 | }; |
378 | static_assert(sizeof(MinidumpSystemInfo) == 56, |
379 | "sizeof MinidumpSystemInfo is not correct!"); |
380 | |
381 | // TODO misc2, misc3 ? |
382 | // Reference: |
383 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680389(v=vs.85).aspx |
384 | struct MinidumpMiscInfo { |
385 | llvm::support::ulittle32_t size; |
386 | // flags1 represents what info in the struct is valid |
387 | llvm::support::ulittle32_t flags1; |
388 | llvm::support::ulittle32_t process_id; |
389 | llvm::support::ulittle32_t process_create_time; |
390 | llvm::support::ulittle32_t process_user_time; |
391 | llvm::support::ulittle32_t process_kernel_time; |
392 | |
393 | static const MinidumpMiscInfo *Parse(llvm::ArrayRef<uint8_t> &data); |
394 | |
395 | llvm::Optional<lldb::pid_t> GetPid() const; |
396 | }; |
397 | static_assert(sizeof(MinidumpMiscInfo) == 24, |
398 | "sizeof MinidumpMiscInfo is not correct!"); |
399 | |
400 | // The /proc/pid/status is saved as an ascii string in the file |
401 | class LinuxProcStatus { |
402 | public: |
403 | llvm::StringRef proc_status; |
404 | lldb::pid_t pid; |
405 | |
406 | static llvm::Optional<LinuxProcStatus> Parse(llvm::ArrayRef<uint8_t> &data); |
407 | |
408 | lldb::pid_t GetPid() const; |
409 | |
410 | private: |
411 | LinuxProcStatus() = default; |
412 | }; |
413 | |
414 | // MinidumpModule stuff |
415 | struct MinidumpVSFixedFileInfo { |
416 | llvm::support::ulittle32_t signature; |
417 | llvm::support::ulittle32_t struct_version; |
418 | llvm::support::ulittle32_t file_version_hi; |
419 | llvm::support::ulittle32_t file_version_lo; |
420 | llvm::support::ulittle32_t product_version_hi; |
421 | llvm::support::ulittle32_t product_version_lo; |
422 | // file_flags_mask - identifies valid bits in fileFlags |
423 | llvm::support::ulittle32_t file_flags_mask; |
424 | llvm::support::ulittle32_t file_flags; |
425 | llvm::support::ulittle32_t file_os; |
426 | llvm::support::ulittle32_t file_type; |
427 | llvm::support::ulittle32_t file_subtype; |
428 | llvm::support::ulittle32_t file_date_hi; |
429 | llvm::support::ulittle32_t file_date_lo; |
430 | }; |
431 | static_assert(sizeof(MinidumpVSFixedFileInfo) == 52, |
432 | "sizeof MinidumpVSFixedFileInfo is not correct!"); |
433 | |
434 | struct MinidumpModule { |
435 | llvm::support::ulittle64_t base_of_image; |
436 | llvm::support::ulittle32_t size_of_image; |
437 | llvm::support::ulittle32_t checksum; |
438 | llvm::support::ulittle32_t time_date_stamp; |
439 | llvm::support::ulittle32_t module_name_rva; |
440 | MinidumpVSFixedFileInfo version_info; |
441 | MinidumpLocationDescriptor CV_record; |
442 | MinidumpLocationDescriptor misc_record; |
443 | llvm::support::ulittle32_t reserved0[2]; |
444 | llvm::support::ulittle32_t reserved1[2]; |
445 | |
446 | static const MinidumpModule *Parse(llvm::ArrayRef<uint8_t> &data); |
447 | |
448 | static llvm::ArrayRef<MinidumpModule> |
449 | ParseModuleList(llvm::ArrayRef<uint8_t> &data); |
450 | }; |
451 | static_assert(sizeof(MinidumpModule) == 108, |
452 | "sizeof MinidumpVSFixedFileInfo is not correct!"); |
453 | |
454 | // Exception stuff |
455 | struct MinidumpException { |
456 | enum : unsigned { |
457 | ExceptonInfoMaxParams = 15, |
458 | DumpRequested = 0xFFFFFFFF, |
459 | }; |
460 | |
461 | llvm::support::ulittle32_t exception_code; |
462 | llvm::support::ulittle32_t exception_flags; |
463 | llvm::support::ulittle64_t exception_record; |
464 | llvm::support::ulittle64_t exception_address; |
465 | llvm::support::ulittle32_t number_parameters; |
466 | llvm::support::ulittle32_t unused_alignment; |
467 | llvm::support::ulittle64_t exception_information[ExceptonInfoMaxParams]; |
468 | }; |
469 | static_assert(sizeof(MinidumpException) == 152, |
470 | "sizeof MinidumpException is not correct!"); |
471 | |
472 | struct MinidumpExceptionStream { |
473 | llvm::support::ulittle32_t thread_id; |
474 | llvm::support::ulittle32_t alignment; |
475 | MinidumpException exception_record; |
476 | MinidumpLocationDescriptor thread_context; |
477 | |
478 | static const MinidumpExceptionStream *Parse(llvm::ArrayRef<uint8_t> &data); |
479 | }; |
480 | static_assert(sizeof(MinidumpExceptionStream) == 168, |
481 | "sizeof MinidumpExceptionStream is not correct!"); |
482 | |
483 | } // namespace minidump |
484 | } // namespace lldb_private |
485 | #endif // liblldb_MinidumpTypes_h_ |