File: | tools/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp |
Warning: | line 59, column 47 Called C++ object pointer is null |
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 | ||||
18 | // C includes | |||
19 | // C++ includes | |||
20 | #include <map> | |||
21 | ||||
22 | using namespace lldb_private; | |||
23 | using namespace minidump; | |||
24 | ||||
25 | llvm::Optional<MinidumpParser> | |||
26 | MinidumpParser::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; | |||
48 | Status error; | |||
49 | 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; | |||
58 | } | |||
59 | directory_map[static_cast<const uint32_t>(directory->stream_type)] = | |||
| ||||
60 | directory->location; | |||
61 | } | |||
62 | ||||
63 | return MinidumpParser(data_buf_sp, header, std::move(directory_map)); | |||
64 | } | |||
65 | ||||
66 | MinidumpParser::MinidumpParser( | |||
67 | const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header, | |||
68 | llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map) | |||
69 | : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) { | |||
70 | } | |||
71 | ||||
72 | llvm::ArrayRef<uint8_t> MinidumpParser::GetData() { | |||
73 | return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(), | |||
74 | m_data_sp->GetByteSize()); | |||
75 | } | |||
76 | ||||
77 | llvm::ArrayRef<uint8_t> | |||
78 | MinidumpParser::GetStream(MinidumpStreamType stream_type) { | |||
79 | auto iter = m_directory_map.find(static_cast<uint32_t>(stream_type)); | |||
80 | if (iter == m_directory_map.end()) | |||
81 | return {}; | |||
82 | ||||
83 | // check if there is enough data | |||
84 | if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize()) | |||
85 | return {}; | |||
86 | ||||
87 | return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva, | |||
88 | iter->second.data_size); | |||
89 | } | |||
90 | ||||
91 | llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) { | |||
92 | auto arr_ref = m_data_sp->GetData(); | |||
93 | if (rva > arr_ref.size()) | |||
94 | return llvm::None; | |||
95 | arr_ref = arr_ref.drop_front(rva); | |||
96 | return parseMinidumpString(arr_ref); | |||
97 | } | |||
98 | ||||
99 | llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() { | |||
100 | llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList); | |||
101 | ||||
102 | if (data.size() == 0) | |||
103 | return llvm::None; | |||
104 | ||||
105 | return MinidumpThread::ParseThreadList(data); | |||
106 | } | |||
107 | ||||
108 | llvm::ArrayRef<uint8_t> | |||
109 | MinidumpParser::GetThreadContext(const MinidumpThread &td) { | |||
110 | if (td.thread_context.rva + td.thread_context.data_size > GetData().size()) | |||
111 | return {}; | |||
112 | ||||
113 | return GetData().slice(td.thread_context.rva, td.thread_context.data_size); | |||
114 | } | |||
115 | ||||
116 | llvm::ArrayRef<uint8_t> | |||
117 | MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) { | |||
118 | // On Windows, a 32-bit process can run on a 64-bit machine under | |||
119 | // WOW64. If the minidump was captured with a 64-bit debugger, then | |||
120 | // the CONTEXT we just grabbed from the mini_dump_thread is the one | |||
121 | // for the 64-bit "native" process rather than the 32-bit "guest" | |||
122 | // process we care about. In this case, we can get the 32-bit CONTEXT | |||
123 | // from the TEB (Thread Environment Block) of the 64-bit process. | |||
124 | auto teb_mem = GetMemory(td.teb, sizeof(TEB64)); | |||
125 | if (teb_mem.empty()) | |||
126 | return {}; | |||
127 | ||||
128 | const TEB64 *wow64teb; | |||
129 | Status error = consumeObject(teb_mem, wow64teb); | |||
130 | if (error.Fail()) | |||
131 | return {}; | |||
132 | ||||
133 | // Slot 1 of the thread-local storage in the 64-bit TEB points to a | |||
134 | // structure that includes the 32-bit CONTEXT (after a ULONG). | |||
135 | // See: https://msdn.microsoft.com/en-us/library/ms681670.aspx | |||
136 | auto context = | |||
137 | GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32)); | |||
138 | if (context.size() < sizeof(MinidumpContext_x86_32)) | |||
139 | return {}; | |||
140 | ||||
141 | return context; | |||
142 | // NOTE: We don't currently use the TEB for anything else. If we | |||
143 | // need it in the future, the 32-bit TEB is located according to the address | |||
144 | // stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]). | |||
145 | } | |||
146 | ||||
147 | const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() { | |||
148 | llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo); | |||
149 | ||||
150 | if (data.size() == 0) | |||
151 | return nullptr; | |||
152 | ||||
153 | return MinidumpSystemInfo::Parse(data); | |||
154 | } | |||
155 | ||||
156 | ArchSpec MinidumpParser::GetArchitecture() { | |||
157 | ArchSpec arch_spec; | |||
158 | const MinidumpSystemInfo *system_info = GetSystemInfo(); | |||
159 | ||||
160 | if (!system_info) | |||
161 | return arch_spec; | |||
162 | ||||
163 | // TODO what to do about big endiand flavors of arm ? | |||
164 | // TODO set the arm subarch stuff if the minidump has info about it | |||
165 | ||||
166 | llvm::Triple triple; | |||
167 | triple.setVendor(llvm::Triple::VendorType::UnknownVendor); | |||
168 | ||||
169 | const MinidumpCPUArchitecture arch = | |||
170 | static_cast<const MinidumpCPUArchitecture>( | |||
171 | static_cast<const uint32_t>(system_info->processor_arch)); | |||
172 | ||||
173 | switch (arch) { | |||
174 | case MinidumpCPUArchitecture::X86: | |||
175 | triple.setArch(llvm::Triple::ArchType::x86); | |||
176 | break; | |||
177 | case MinidumpCPUArchitecture::AMD64: | |||
178 | triple.setArch(llvm::Triple::ArchType::x86_64); | |||
179 | break; | |||
180 | case MinidumpCPUArchitecture::ARM: | |||
181 | triple.setArch(llvm::Triple::ArchType::arm); | |||
182 | break; | |||
183 | case MinidumpCPUArchitecture::ARM64: | |||
184 | triple.setArch(llvm::Triple::ArchType::aarch64); | |||
185 | break; | |||
186 | default: | |||
187 | triple.setArch(llvm::Triple::ArchType::UnknownArch); | |||
188 | break; | |||
189 | } | |||
190 | ||||
191 | const MinidumpOSPlatform os = static_cast<const MinidumpOSPlatform>( | |||
192 | static_cast<const uint32_t>(system_info->platform_id)); | |||
193 | ||||
194 | // TODO add all of the OSes that Minidump/breakpad distinguishes? | |||
195 | switch (os) { | |||
196 | case MinidumpOSPlatform::Win32S: | |||
197 | case MinidumpOSPlatform::Win32Windows: | |||
198 | case MinidumpOSPlatform::Win32NT: | |||
199 | case MinidumpOSPlatform::Win32CE: | |||
200 | triple.setOS(llvm::Triple::OSType::Win32); | |||
201 | break; | |||
202 | case MinidumpOSPlatform::Linux: | |||
203 | triple.setOS(llvm::Triple::OSType::Linux); | |||
204 | break; | |||
205 | case MinidumpOSPlatform::MacOSX: | |||
206 | triple.setOS(llvm::Triple::OSType::MacOSX); | |||
207 | break; | |||
208 | case MinidumpOSPlatform::Android: | |||
209 | triple.setOS(llvm::Triple::OSType::Linux); | |||
210 | triple.setEnvironment(llvm::Triple::EnvironmentType::Android); | |||
211 | break; | |||
212 | default: | |||
213 | triple.setOS(llvm::Triple::OSType::UnknownOS); | |||
214 | break; | |||
215 | } | |||
216 | ||||
217 | arch_spec.SetTriple(triple); | |||
218 | ||||
219 | return arch_spec; | |||
220 | } | |||
221 | ||||
222 | const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() { | |||
223 | llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MiscInfo); | |||
224 | ||||
225 | if (data.size() == 0) | |||
226 | return nullptr; | |||
227 | ||||
228 | return MinidumpMiscInfo::Parse(data); | |||
229 | } | |||
230 | ||||
231 | llvm::Optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() { | |||
232 | llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::LinuxProcStatus); | |||
233 | ||||
234 | if (data.size() == 0) | |||
235 | return llvm::None; | |||
236 | ||||
237 | return LinuxProcStatus::Parse(data); | |||
238 | } | |||
239 | ||||
240 | llvm::Optional<lldb::pid_t> MinidumpParser::GetPid() { | |||
241 | const MinidumpMiscInfo *misc_info = GetMiscInfo(); | |||
242 | if (misc_info != nullptr) { | |||
243 | return misc_info->GetPid(); | |||
244 | } | |||
245 | ||||
246 | llvm::Optional<LinuxProcStatus> proc_status = GetLinuxProcStatus(); | |||
247 | if (proc_status.hasValue()) { | |||
248 | return proc_status->GetPid(); | |||
249 | } | |||
250 | ||||
251 | return llvm::None; | |||
252 | } | |||
253 | ||||
254 | llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() { | |||
255 | llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ModuleList); | |||
256 | ||||
257 | if (data.size() == 0) | |||
258 | return {}; | |||
259 | ||||
260 | return MinidumpModule::ParseModuleList(data); | |||
261 | } | |||
262 | ||||
263 | std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() { | |||
264 | llvm::ArrayRef<MinidumpModule> modules = GetModuleList(); | |||
265 | // map module_name -> pair(load_address, pointer to module struct in memory) | |||
266 | llvm::StringMap<std::pair<uint64_t, const MinidumpModule *>> lowest_addr; | |||
267 | ||||
268 | std::vector<const MinidumpModule *> filtered_modules; | |||
269 | ||||
270 | llvm::Optional<std::string> name; | |||
271 | std::string module_name; | |||
272 | ||||
273 | for (const auto &module : modules) { | |||
274 | name = GetMinidumpString(module.module_name_rva); | |||
275 | ||||
276 | if (!name) | |||
277 | continue; | |||
278 | ||||
279 | module_name = name.getValue(); | |||
280 | ||||
281 | auto iter = lowest_addr.end(); | |||
282 | bool exists; | |||
283 | std::tie(iter, exists) = lowest_addr.try_emplace( | |||
284 | module_name, std::make_pair(module.base_of_image, &module)); | |||
285 | ||||
286 | if (exists && module.base_of_image < iter->second.first) | |||
287 | iter->second = std::make_pair(module.base_of_image, &module); | |||
288 | } | |||
289 | ||||
290 | filtered_modules.reserve(lowest_addr.size()); | |||
291 | for (const auto &module : lowest_addr) { | |||
292 | filtered_modules.push_back(module.second.second); | |||
293 | } | |||
294 | ||||
295 | return filtered_modules; | |||
296 | } | |||
297 | ||||
298 | const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() { | |||
299 | llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::Exception); | |||
300 | ||||
301 | if (data.size() == 0) | |||
302 | return nullptr; | |||
303 | ||||
304 | return MinidumpExceptionStream::Parse(data); | |||
305 | } | |||
306 | ||||
307 | llvm::Optional<minidump::Range> | |||
308 | MinidumpParser::FindMemoryRange(lldb::addr_t addr) { | |||
309 | llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryList); | |||
310 | llvm::ArrayRef<uint8_t> data64 = GetStream(MinidumpStreamType::Memory64List); | |||
311 | ||||
312 | if (data.empty() && data64.empty()) | |||
313 | return llvm::None; | |||
314 | ||||
315 | if (!data.empty()) { | |||
316 | llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list = | |||
317 | MinidumpMemoryDescriptor::ParseMemoryList(data); | |||
318 | ||||
319 | if (memory_list.empty()) | |||
320 | return llvm::None; | |||
321 | ||||
322 | for (const auto &memory_desc : memory_list) { | |||
323 | const MinidumpLocationDescriptor &loc_desc = memory_desc.memory; | |||
324 | const lldb::addr_t range_start = memory_desc.start_of_memory_range; | |||
325 | const size_t range_size = loc_desc.data_size; | |||
326 | ||||
327 | if (loc_desc.rva + loc_desc.data_size > GetData().size()) | |||
328 | return llvm::None; | |||
329 | ||||
330 | if (range_start <= addr && addr < range_start + range_size) { | |||
331 | return minidump::Range(range_start, | |||
332 | GetData().slice(loc_desc.rva, range_size)); | |||
333 | } | |||
334 | } | |||
335 | } | |||
336 | ||||
337 | // Some Minidumps have a Memory64ListStream that captures all the heap | |||
338 | // memory (full-memory Minidumps). We can't exactly use the same loop as | |||
339 | // above, because the Minidump uses slightly different data structures to | |||
340 | // describe those | |||
341 | ||||
342 | if (!data64.empty()) { | |||
343 | llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list; | |||
344 | uint64_t base_rva; | |||
345 | std::tie(memory64_list, base_rva) = | |||
346 | MinidumpMemoryDescriptor64::ParseMemory64List(data64); | |||
347 | ||||
348 | if (memory64_list.empty()) | |||
349 | return llvm::None; | |||
350 | ||||
351 | for (const auto &memory_desc64 : memory64_list) { | |||
352 | const lldb::addr_t range_start = memory_desc64.start_of_memory_range; | |||
353 | const size_t range_size = memory_desc64.data_size; | |||
354 | ||||
355 | if (base_rva + range_size > GetData().size()) | |||
356 | return llvm::None; | |||
357 | ||||
358 | if (range_start <= addr && addr < range_start + range_size) { | |||
359 | return minidump::Range(range_start, | |||
360 | GetData().slice(base_rva, range_size)); | |||
361 | } | |||
362 | base_rva += range_size; | |||
363 | } | |||
364 | } | |||
365 | ||||
366 | return llvm::None; | |||
367 | } | |||
368 | ||||
369 | llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr, | |||
370 | size_t size) { | |||
371 | // I don't have a sense of how frequently this is called or how many memory | |||
372 | // ranges a Minidump typically has, so I'm not sure if searching for the | |||
373 | // appropriate range linearly each time is stupid. Perhaps we should build | |||
374 | // an index for faster lookups. | |||
375 | llvm::Optional<minidump::Range> range = FindMemoryRange(addr); | |||
376 | if (!range) | |||
377 | return {}; | |||
378 | ||||
379 | // There's at least some overlap between the beginning of the desired range | |||
380 | // (addr) and the current range. Figure out where the overlap begins and | |||
381 | // how much overlap there is. | |||
382 | ||||
383 | const size_t offset = addr - range->start; | |||
384 | ||||
385 | if (addr < range->start || offset >= range->range_ref.size()) | |||
386 | return {}; | |||
387 | ||||
388 | const size_t overlap = std::min(size, range->range_ref.size() - offset); | |||
389 | return range->range_ref.slice(offset, overlap); | |||
390 | } | |||
391 | ||||
392 | llvm::Optional<MemoryRegionInfo> | |||
393 | MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) { | |||
394 | MemoryRegionInfo info; | |||
395 | llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryInfoList); | |||
396 | if (data.empty()) | |||
397 | return llvm::None; | |||
398 | ||||
399 | std::vector<const MinidumpMemoryInfo *> mem_info_list = | |||
400 | MinidumpMemoryInfo::ParseMemoryInfoList(data); | |||
401 | if (mem_info_list.empty()) | |||
402 | return llvm::None; | |||
403 | ||||
404 | const auto yes = MemoryRegionInfo::eYes; | |||
405 | const auto no = MemoryRegionInfo::eNo; | |||
406 | ||||
407 | const MinidumpMemoryInfo *next_entry = nullptr; | |||
408 | for (const auto &entry : mem_info_list) { | |||
409 | const auto head = entry->base_address; | |||
410 | const auto tail = head + entry->region_size; | |||
411 | ||||
412 | if (head <= load_addr && load_addr < tail) { | |||
413 | info.GetRange().SetRangeBase( | |||
414 | (entry->state != uint32_t(MinidumpMemoryInfoState::MemFree)) | |||
415 | ? head | |||
416 | : load_addr); | |||
417 | info.GetRange().SetRangeEnd(tail); | |||
418 | ||||
419 | const uint32_t PageNoAccess = | |||
420 | static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageNoAccess); | |||
421 | info.SetReadable((entry->protect & PageNoAccess) == 0 ? yes : no); | |||
422 | ||||
423 | const uint32_t PageWritable = | |||
424 | static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageWritable); | |||
425 | info.SetWritable((entry->protect & PageWritable) != 0 ? yes : no); | |||
426 | ||||
427 | const uint32_t PageExecutable = static_cast<uint32_t>( | |||
428 | MinidumpMemoryProtectionContants::PageExecutable); | |||
429 | info.SetExecutable((entry->protect & PageExecutable) != 0 ? yes : no); | |||
430 | ||||
431 | const uint32_t MemFree = | |||
432 | static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree); | |||
433 | info.SetMapped((entry->state != MemFree) ? yes : no); | |||
434 | ||||
435 | return info; | |||
436 | } else if (head > load_addr && | |||
437 | (next_entry == nullptr || head < next_entry->base_address)) { | |||
438 | // In case there is no region containing load_addr keep track of the | |||
439 | // nearest region after load_addr so we can return the distance to it. | |||
440 | next_entry = entry; | |||
441 | } | |||
442 | } | |||
443 | ||||
444 | // No containing region found. Create an unmapped region that extends to the | |||
445 | // next region or LLDB_INVALID_ADDRESS | |||
446 | info.GetRange().SetRangeBase(load_addr); | |||
447 | info.GetRange().SetRangeEnd((next_entry != nullptr) ? next_entry->base_address | |||
448 | : LLDB_INVALID_ADDRESS(18446744073709551615UL)); | |||
449 | info.SetReadable(no); | |||
450 | info.SetWritable(no); | |||
451 | info.SetExecutable(no); | |||
452 | info.SetMapped(no); | |||
453 | ||||
454 | // Note that the memory info list doesn't seem to contain ranges in kernel | |||
455 | // space, so if you're walking a stack that has kernel frames, the stack may | |||
456 | // appear truncated. | |||
457 | return info; | |||
458 | } |
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 | // Reference: |
47 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680394.aspx |
48 | enum class MinidumpStreamType : uint32_t { |
49 | Unused = 0, |
50 | Reserved0 = 1, |
51 | Reserved1 = 2, |
52 | ThreadList = 3, |
53 | ModuleList = 4, |
54 | MemoryList = 5, |
55 | Exception = 6, |
56 | SystemInfo = 7, |
57 | ThreadExList = 8, |
58 | Memory64List = 9, |
59 | CommentA = 10, |
60 | CommentW = 11, |
61 | HandleData = 12, |
62 | FunctionTable = 13, |
63 | UnloadedModuleList = 14, |
64 | MiscInfo = 15, |
65 | MemoryInfoList = 16, |
66 | ThreadInfoList = 17, |
67 | HandleOperationList = 18, |
68 | Token = 19, |
69 | JavascriptData = 20, |
70 | SystemMemoryInfo = 21, |
71 | ProcessVMCounters = 22, |
72 | LastReserved = 0x0000ffff, |
73 | |
74 | /* Breakpad extension types. 0x4767 = "Gg" */ |
75 | BreakpadInfo = 0x47670001, |
76 | AssertionInfo = 0x47670002, |
77 | /* These are additional minidump stream values which are specific to |
78 | * the linux breakpad implementation. */ |
79 | LinuxCPUInfo = 0x47670003, /* /proc/cpuinfo */ |
80 | LinuxProcStatus = 0x47670004, /* /proc/$x/status */ |
81 | LinuxLSBRelease = 0x47670005, /* /etc/lsb-release */ |
82 | LinuxCMDLine = 0x47670006, /* /proc/$x/cmdline */ |
83 | LinuxEnviron = 0x47670007, /* /proc/$x/environ */ |
84 | LinuxAuxv = 0x47670008, /* /proc/$x/auxv */ |
85 | LinuxMaps = 0x47670009, /* /proc/$x/maps */ |
86 | LinuxDSODebug = 0x4767000A |
87 | }; |
88 | |
89 | // for MinidumpSystemInfo.processor_arch |
90 | enum class MinidumpCPUArchitecture : uint16_t { |
91 | X86 = 0, /* PROCESSOR_ARCHITECTURE_INTEL */ |
92 | MIPS = 1, /* PROCESSOR_ARCHITECTURE_MIPS */ |
93 | Alpha = 2, /* PROCESSOR_ARCHITECTURE_ALPHA */ |
94 | PPC = 3, /* PROCESSOR_ARCHITECTURE_PPC */ |
95 | SHX = 4, /* PROCESSOR_ARCHITECTURE_SHX (Super-H) */ |
96 | ARM = 5, /* PROCESSOR_ARCHITECTURE_ARM */ |
97 | IA64 = 6, /* PROCESSOR_ARCHITECTURE_IA64 */ |
98 | Alpha64 = 7, /* PROCESSOR_ARCHITECTURE_ALPHA64 */ |
99 | MSIL = 8, /* PROCESSOR_ARCHITECTURE_MSIL |
100 | * (Microsoft Intermediate Language) */ |
101 | AMD64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */ |
102 | X86Win64 = 10, /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */ |
103 | SPARC = 0x8001, /* Breakpad-defined value for SPARC */ |
104 | PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */ |
105 | ARM64 = 0x8003, /* Breakpad-defined value for ARM64 */ |
106 | MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */ |
107 | Unknown = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */ |
108 | }; |
109 | |
110 | // for MinidumpSystemInfo.platform_id |
111 | enum class MinidumpOSPlatform : uint32_t { |
112 | Win32S = 0, /* VER_PLATFORM_WIN32s (Windows 3.1) */ |
113 | Win32Windows = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */ |
114 | Win32NT = 2, /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */ |
115 | Win32CE = 3, /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH |
116 | * (Windows CE, Windows Mobile, "Handheld") */ |
117 | |
118 | /* The following values are Breakpad-defined. */ |
119 | Unix = 0x8000, /* Generic Unix-ish */ |
120 | MacOSX = 0x8101, /* Mac OS X/Darwin */ |
121 | IOS = 0x8102, /* iOS */ |
122 | Linux = 0x8201, /* Linux */ |
123 | Solaris = 0x8202, /* Solaris */ |
124 | Android = 0x8203, /* Android */ |
125 | PS3 = 0x8204, /* PS3 */ |
126 | NaCl = 0x8205 /* Native Client (NaCl) */ |
127 | }; |
128 | |
129 | // For MinidumpCPUInfo.arm_cpu_info.elf_hwcaps. |
130 | // This matches the Linux kernel definitions from <asm/hwcaps.h> |
131 | enum class MinidumpPCPUInformationARMElfHwCaps : uint32_t { |
132 | SWP = (1 << 0), |
133 | Half = (1 << 1), |
134 | Thumb = (1 << 2), |
135 | _26BIT = (1 << 3), |
136 | FastMult = (1 << 4), |
137 | FPA = (1 << 5), |
138 | VFP = (1 << 6), |
139 | EDSP = (1 << 7), |
140 | Java = (1 << 8), |
141 | IWMMXT = (1 << 9), |
142 | Crunch = (1 << 10), |
143 | ThumbEE = (1 << 11), |
144 | Neon = (1 << 12), |
145 | VFPv3 = (1 << 13), |
146 | VFPv3D16 = (1 << 14), |
147 | TLS = (1 << 15), |
148 | VFPv4 = (1 << 16), |
149 | IDIVA = (1 << 17), |
150 | IDIVT = (1 << 18), |
151 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IDIVT)LLVM_BITMASK_LARGEST_ENUMERATOR = IDIVT |
152 | }; |
153 | |
154 | enum class MinidumpMiscInfoFlags : uint32_t { |
155 | ProcessID = (1 << 0), |
156 | ProcessTimes = (1 << 1), |
157 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ ProcessTimes)LLVM_BITMASK_LARGEST_ENUMERATOR = ProcessTimes |
158 | }; |
159 | |
160 | template <typename T> |
161 | Status consumeObject(llvm::ArrayRef<uint8_t> &Buffer, const T *&Object) { |
162 | Status error; |
163 | if (Buffer.size() < sizeof(T)) { |
164 | error.SetErrorString("Insufficient buffer!"); |
165 | return error; |
166 | } |
167 | |
168 | Object = reinterpret_cast<const T *>(Buffer.data()); |
169 | Buffer = Buffer.drop_front(sizeof(T)); |
170 | return error; |
171 | } |
172 | |
173 | // parse a MinidumpString which is with UTF-16 |
174 | // Reference: |
175 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680395(v=vs.85).aspx |
176 | llvm::Optional<std::string> parseMinidumpString(llvm::ArrayRef<uint8_t> &data); |
177 | |
178 | // Reference: |
179 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680378(v=vs.85).aspx |
180 | struct MinidumpHeader { |
181 | llvm::support::ulittle32_t signature; |
182 | llvm::support::ulittle32_t |
183 | version; // The high 16 bits of version field are implementation specific |
184 | llvm::support::ulittle32_t streams_count; |
185 | llvm::support::ulittle32_t |
186 | stream_directory_rva; // offset of the stream directory |
187 | llvm::support::ulittle32_t checksum; |
188 | llvm::support::ulittle32_t time_date_stamp; // time_t format |
189 | llvm::support::ulittle64_t flags; |
190 | |
191 | static const MinidumpHeader *Parse(llvm::ArrayRef<uint8_t> &data); |
192 | }; |
193 | static_assert(sizeof(MinidumpHeader) == 32, |
194 | "sizeof MinidumpHeader is not correct!"); |
195 | |
196 | // Reference: |
197 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680383.aspx |
198 | struct MinidumpLocationDescriptor { |
199 | llvm::support::ulittle32_t data_size; |
200 | llvm::support::ulittle32_t rva; |
201 | }; |
202 | static_assert(sizeof(MinidumpLocationDescriptor) == 8, |
203 | "sizeof MinidumpLocationDescriptor is not correct!"); |
204 | |
205 | // Reference: |
206 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680384(v=vs.85).aspx |
207 | struct MinidumpMemoryDescriptor { |
208 | llvm::support::ulittle64_t start_of_memory_range; |
209 | MinidumpLocationDescriptor memory; |
210 | |
211 | static llvm::ArrayRef<MinidumpMemoryDescriptor> |
212 | ParseMemoryList(llvm::ArrayRef<uint8_t> &data); |
213 | }; |
214 | static_assert(sizeof(MinidumpMemoryDescriptor) == 16, |
215 | "sizeof MinidumpMemoryDescriptor is not correct!"); |
216 | |
217 | struct MinidumpMemoryDescriptor64 { |
218 | llvm::support::ulittle64_t start_of_memory_range; |
219 | llvm::support::ulittle64_t data_size; |
220 | |
221 | static std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t> |
222 | ParseMemory64List(llvm::ArrayRef<uint8_t> &data); |
223 | }; |
224 | static_assert(sizeof(MinidumpMemoryDescriptor64) == 16, |
225 | "sizeof MinidumpMemoryDescriptor64 is not correct!"); |
226 | |
227 | // Reference: |
228 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680365.aspx |
229 | struct MinidumpDirectory { |
230 | llvm::support::ulittle32_t stream_type; |
231 | MinidumpLocationDescriptor location; |
232 | }; |
233 | static_assert(sizeof(MinidumpDirectory) == 12, |
234 | "sizeof MinidumpDirectory is not correct!"); |
235 | |
236 | // Reference: |
237 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680385(v=vs.85).aspx |
238 | struct MinidumpMemoryInfoListHeader { |
239 | llvm::support::ulittle32_t size_of_header; |
240 | llvm::support::ulittle32_t size_of_entry; |
241 | llvm::support::ulittle64_t num_of_entries; |
242 | }; |
243 | static_assert(sizeof(MinidumpMemoryInfoListHeader) == 16, |
244 | "sizeof MinidumpMemoryInfoListHeader is not correct!"); |
245 | |
246 | // Reference: |
247 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680386(v=vs.85).aspx |
248 | struct MinidumpMemoryInfo { |
249 | llvm::support::ulittle64_t base_address; |
250 | llvm::support::ulittle64_t allocation_base; |
251 | llvm::support::ulittle32_t allocation_protect; |
252 | llvm::support::ulittle32_t alignment1; |
253 | llvm::support::ulittle64_t region_size; |
254 | llvm::support::ulittle32_t state; |
255 | llvm::support::ulittle32_t protect; |
256 | llvm::support::ulittle32_t type; |
257 | llvm::support::ulittle32_t alignment2; |
258 | |
259 | static std::vector<const MinidumpMemoryInfo *> |
260 | ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data); |
261 | }; |
262 | static_assert(sizeof(MinidumpMemoryInfo) == 48, |
263 | "sizeof MinidumpMemoryInfo is not correct!"); |
264 | |
265 | enum class MinidumpMemoryInfoState : uint32_t { |
266 | MemCommit = 0x1000, |
267 | MemFree = 0x10000, |
268 | MemReserve = 0x2000, |
269 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemFree)LLVM_BITMASK_LARGEST_ENUMERATOR = MemFree |
270 | }; |
271 | |
272 | enum class MinidumpMemoryInfoType : uint32_t { |
273 | MemImage = 0x1000000, |
274 | MemMapped = 0x40000, |
275 | MemPrivate = 0x20000, |
276 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemImage)LLVM_BITMASK_LARGEST_ENUMERATOR = MemImage |
277 | }; |
278 | |
279 | // Reference: |
280 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx |
281 | enum class MinidumpMemoryProtectionContants : uint32_t { |
282 | PageExecute = 0x10, |
283 | PageExecuteRead = 0x20, |
284 | PageExecuteReadWrite = 0x40, |
285 | PageExecuteWriteCopy = 0x80, |
286 | PageNoAccess = 0x01, |
287 | PageReadOnly = 0x02, |
288 | PageReadWrite = 0x04, |
289 | PageWriteCopy = 0x08, |
290 | PageTargetsInvalid = 0x40000000, |
291 | PageTargetsNoUpdate = 0x40000000, |
292 | |
293 | PageWritable = PageExecuteReadWrite | PageExecuteWriteCopy | PageReadWrite | |
294 | PageWriteCopy, |
295 | PageExecutable = PageExecute | PageExecuteRead | PageExecuteReadWrite | |
296 | PageExecuteWriteCopy, |
297 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ PageTargetsInvalid)LLVM_BITMASK_LARGEST_ENUMERATOR = PageTargetsInvalid |
298 | }; |
299 | |
300 | // Reference: |
301 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx |
302 | struct MinidumpThread { |
303 | llvm::support::ulittle32_t thread_id; |
304 | llvm::support::ulittle32_t suspend_count; |
305 | llvm::support::ulittle32_t priority_class; |
306 | llvm::support::ulittle32_t priority; |
307 | llvm::support::ulittle64_t teb; |
308 | MinidumpMemoryDescriptor stack; |
309 | MinidumpLocationDescriptor thread_context; |
310 | |
311 | static const MinidumpThread *Parse(llvm::ArrayRef<uint8_t> &data); |
312 | |
313 | static llvm::ArrayRef<MinidumpThread> |
314 | ParseThreadList(llvm::ArrayRef<uint8_t> &data); |
315 | }; |
316 | static_assert(sizeof(MinidumpThread) == 48, |
317 | "sizeof MinidumpThread is not correct!"); |
318 | |
319 | // Reference: |
320 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680396(v=vs.85).aspx |
321 | union MinidumpCPUInfo { |
322 | struct { |
323 | llvm::support::ulittle32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */ |
324 | llvm::support::ulittle32_t version_information; /* cpuid 1: eax */ |
325 | llvm::support::ulittle32_t feature_information; /* cpuid 1: edx */ |
326 | llvm::support::ulittle32_t |
327 | amd_extended_cpu_features; /* cpuid 0x80000001, ebx */ |
328 | } x86_cpu_info; |
329 | struct { |
330 | llvm::support::ulittle32_t cpuid; |
331 | llvm::support::ulittle32_t elf_hwcaps; /* linux specific, 0 otherwise */ |
332 | } arm_cpu_info; |
333 | struct { |
334 | llvm::support::ulittle64_t processor_features[2]; |
335 | } other_cpu_info; |
336 | }; |
337 | static_assert(sizeof(MinidumpCPUInfo) == 24, |
338 | "sizeof MinidumpCPUInfo is not correct!"); |
339 | |
340 | // Reference: |
341 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680396(v=vs.85).aspx |
342 | struct MinidumpSystemInfo { |
343 | llvm::support::ulittle16_t processor_arch; |
344 | llvm::support::ulittle16_t processor_level; |
345 | llvm::support::ulittle16_t processor_revision; |
346 | |
347 | uint8_t number_of_processors; |
348 | uint8_t product_type; |
349 | |
350 | llvm::support::ulittle32_t major_version; |
351 | llvm::support::ulittle32_t minor_version; |
352 | llvm::support::ulittle32_t build_number; |
353 | llvm::support::ulittle32_t platform_id; |
354 | llvm::support::ulittle32_t csd_version_rva; |
355 | |
356 | llvm::support::ulittle16_t suit_mask; |
357 | llvm::support::ulittle16_t reserved2; |
358 | |
359 | MinidumpCPUInfo cpu; |
360 | |
361 | static const MinidumpSystemInfo *Parse(llvm::ArrayRef<uint8_t> &data); |
362 | }; |
363 | static_assert(sizeof(MinidumpSystemInfo) == 56, |
364 | "sizeof MinidumpSystemInfo is not correct!"); |
365 | |
366 | // TODO misc2, misc3 ? |
367 | // Reference: |
368 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680389(v=vs.85).aspx |
369 | struct MinidumpMiscInfo { |
370 | llvm::support::ulittle32_t size; |
371 | // flags1 represents what info in the struct is valid |
372 | llvm::support::ulittle32_t flags1; |
373 | llvm::support::ulittle32_t process_id; |
374 | llvm::support::ulittle32_t process_create_time; |
375 | llvm::support::ulittle32_t process_user_time; |
376 | llvm::support::ulittle32_t process_kernel_time; |
377 | |
378 | static const MinidumpMiscInfo *Parse(llvm::ArrayRef<uint8_t> &data); |
379 | |
380 | llvm::Optional<lldb::pid_t> GetPid() const; |
381 | }; |
382 | static_assert(sizeof(MinidumpMiscInfo) == 24, |
383 | "sizeof MinidumpMiscInfo is not correct!"); |
384 | |
385 | // The /proc/pid/status is saved as an ascii string in the file |
386 | class LinuxProcStatus { |
387 | public: |
388 | llvm::StringRef proc_status; |
389 | lldb::pid_t pid; |
390 | |
391 | static llvm::Optional<LinuxProcStatus> Parse(llvm::ArrayRef<uint8_t> &data); |
392 | |
393 | lldb::pid_t GetPid() const; |
394 | |
395 | private: |
396 | LinuxProcStatus() = default; |
397 | }; |
398 | |
399 | // MinidumpModule stuff |
400 | struct MinidumpVSFixedFileInfo { |
401 | llvm::support::ulittle32_t signature; |
402 | llvm::support::ulittle32_t struct_version; |
403 | llvm::support::ulittle32_t file_version_hi; |
404 | llvm::support::ulittle32_t file_version_lo; |
405 | llvm::support::ulittle32_t product_version_hi; |
406 | llvm::support::ulittle32_t product_version_lo; |
407 | // file_flags_mask - identifies valid bits in fileFlags |
408 | llvm::support::ulittle32_t file_flags_mask; |
409 | llvm::support::ulittle32_t file_flags; |
410 | llvm::support::ulittle32_t file_os; |
411 | llvm::support::ulittle32_t file_type; |
412 | llvm::support::ulittle32_t file_subtype; |
413 | llvm::support::ulittle32_t file_date_hi; |
414 | llvm::support::ulittle32_t file_date_lo; |
415 | }; |
416 | static_assert(sizeof(MinidumpVSFixedFileInfo) == 52, |
417 | "sizeof MinidumpVSFixedFileInfo is not correct!"); |
418 | |
419 | struct MinidumpModule { |
420 | llvm::support::ulittle64_t base_of_image; |
421 | llvm::support::ulittle32_t size_of_image; |
422 | llvm::support::ulittle32_t checksum; |
423 | llvm::support::ulittle32_t time_date_stamp; |
424 | llvm::support::ulittle32_t module_name_rva; |
425 | MinidumpVSFixedFileInfo version_info; |
426 | MinidumpLocationDescriptor CV_record; |
427 | MinidumpLocationDescriptor misc_record; |
428 | llvm::support::ulittle32_t reserved0[2]; |
429 | llvm::support::ulittle32_t reserved1[2]; |
430 | |
431 | static const MinidumpModule *Parse(llvm::ArrayRef<uint8_t> &data); |
432 | |
433 | static llvm::ArrayRef<MinidumpModule> |
434 | ParseModuleList(llvm::ArrayRef<uint8_t> &data); |
435 | }; |
436 | static_assert(sizeof(MinidumpModule) == 108, |
437 | "sizeof MinidumpVSFixedFileInfo is not correct!"); |
438 | |
439 | // Exception stuff |
440 | struct MinidumpException { |
441 | enum : unsigned { |
442 | ExceptonInfoMaxParams = 15, |
443 | DumpRequested = 0xFFFFFFFF, |
444 | }; |
445 | |
446 | llvm::support::ulittle32_t exception_code; |
447 | llvm::support::ulittle32_t exception_flags; |
448 | llvm::support::ulittle64_t exception_record; |
449 | llvm::support::ulittle64_t exception_address; |
450 | llvm::support::ulittle32_t number_parameters; |
451 | llvm::support::ulittle32_t unused_alignment; |
452 | llvm::support::ulittle64_t exception_information[ExceptonInfoMaxParams]; |
453 | }; |
454 | static_assert(sizeof(MinidumpException) == 152, |
455 | "sizeof MinidumpException is not correct!"); |
456 | |
457 | struct MinidumpExceptionStream { |
458 | llvm::support::ulittle32_t thread_id; |
459 | llvm::support::ulittle32_t alignment; |
460 | MinidumpException exception_record; |
461 | MinidumpLocationDescriptor thread_context; |
462 | |
463 | static const MinidumpExceptionStream *Parse(llvm::ArrayRef<uint8_t> &data); |
464 | }; |
465 | static_assert(sizeof(MinidumpExceptionStream) == 168, |
466 | "sizeof MinidumpExceptionStream is not correct!"); |
467 | |
468 | } // namespace minidump |
469 | } // namespace lldb_private |
470 | #endif // liblldb_MinidumpTypes_h_ |