LLDB mainline
MinidumpFileBuilder.cpp
Go to the documentation of this file.
1//===-- MinidumpFileBuilder.cpp -------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
13
14#include "lldb/Core/Module.h"
16#include "lldb/Core/Section.h"
17#include "lldb/Target/ABI.h"
19#include "lldb/Target/Process.h"
26#include "lldb/Utility/Log.h"
29
30#include "llvm/ADT/StringRef.h"
31#include "llvm/BinaryFormat/Minidump.h"
32#include "llvm/Support/ConvertUTF.h"
33#include "llvm/Support/Endian.h"
34#include "llvm/Support/Error.h"
35#include "llvm/TargetParser/Triple.h"
36
39#include "lldb/lldb-forward.h"
40#include "lldb/lldb-types.h"
41
42#include <algorithm>
43#include <cinttypes>
44#include <climits>
45#include <cstddef>
46#include <cstdint>
47#include <functional>
48#include <iostream>
49#include <set>
50#include <utility>
51#include <vector>
52
53using namespace lldb;
54using namespace lldb_private;
55using namespace llvm::minidump;
56
58 // First set the offset on the file, and on the bytes saved
60 // We know we will have at least Misc, SystemInfo, Modules, and ThreadList
61 // (corresponding memory list for stacks) And an additional memory list for
62 // non-stacks.
63 lldb_private::Target &target = m_process_sp->GetTarget();
65 // Check if OS is linux and reserve directory space for all linux specific
66 // breakpad extension directories.
67 if (target.GetArchitecture().GetTriple().getOS() ==
68 llvm::Triple::OSType::Linux)
70
71 // Go through all of the threads and check for exceptions.
72 std::vector<lldb::ThreadSP> threads =
73 m_process_sp->CalculateCoreFileThreadList(m_save_core_options);
74 for (const ThreadSP &thread_sp : threads) {
75 StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
76 if (stop_info_sp) {
77 const StopReason &stop_reason = stop_info_sp->GetStopReason();
78 if (stop_reason != lldb::eStopReasonInvalid)
80 }
81 }
82
84 m_expected_directories * sizeof(llvm::minidump::Directory);
86 offset_t new_offset = m_core_file->SeekFromStart(m_saved_data_size);
87 if (new_offset != m_saved_data_size)
89 "Failed to fill in header and directory "
90 "sections. Written / Expected (%" PRIx64 " / %" PRIx64 ")",
91 new_offset, m_saved_data_size);
92
93 return error;
94}
95
97 uint64_t stream_size) {
98 // We explicitly cast type, an 32b enum, to uint32_t to avoid warnings.
102 "Unable to add directory for stream type "
103 "%x, offset is greater then 32 bit limit.",
104 (uint32_t)type);
105 return error;
106 }
107
108 if (m_directories.size() + 1 > m_expected_directories) {
110 "Unable to add directory for stream type %x, exceeded expected number "
111 "of directories %zu.",
112 (uint32_t)type, m_expected_directories);
113 return error;
114 }
115
116 LocationDescriptor loc;
117 loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size);
118 // Stream will begin at the current end of data section
119 loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
120
121 Directory dir;
122 dir.Type = static_cast<llvm::support::little_t<StreamType>>(type);
123 dir.Location = loc;
124
125 m_directories.push_back(dir);
126 return error;
127}
128
131 const llvm::Triple &target_triple =
132 m_process_sp->GetTarget().GetArchitecture().GetTriple();
133 error =
134 AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
135 if (error.Fail())
136 return error;
137
138 llvm::minidump::ProcessorArchitecture arch;
139 switch (target_triple.getArch()) {
140 case llvm::Triple::ArchType::x86_64:
141 arch = ProcessorArchitecture::AMD64;
142 break;
143 case llvm::Triple::ArchType::x86:
144 arch = ProcessorArchitecture::X86;
145 break;
146 case llvm::Triple::ArchType::arm:
147 arch = ProcessorArchitecture::ARM;
148 break;
149 case llvm::Triple::ArchType::aarch64:
150 arch = ProcessorArchitecture::ARM64;
151 break;
152 case llvm::Triple::ArchType::mips64:
153 case llvm::Triple::ArchType::mips64el:
154 case llvm::Triple::ArchType::mips:
155 case llvm::Triple::ArchType::mipsel:
156 arch = ProcessorArchitecture::MIPS;
157 break;
158 case llvm::Triple::ArchType::ppc64:
159 case llvm::Triple::ArchType::ppc:
160 case llvm::Triple::ArchType::ppc64le:
161 arch = ProcessorArchitecture::PPC;
162 break;
163 default:
165 "Architecture %s not supported.",
166 target_triple.getArchName().str().c_str());
167 return error;
168 };
169
170 llvm::support::little_t<OSPlatform> platform_id;
171 switch (target_triple.getOS()) {
172 case llvm::Triple::OSType::Linux:
173 if (target_triple.getEnvironment() ==
174 llvm::Triple::EnvironmentType::Android)
175 platform_id = OSPlatform::Android;
176 else
177 platform_id = OSPlatform::Linux;
178 break;
179 case llvm::Triple::OSType::Win32:
180 platform_id = OSPlatform::Win32NT;
181 break;
182 case llvm::Triple::OSType::MacOSX:
183 platform_id = OSPlatform::MacOSX;
184 break;
185 case llvm::Triple::OSType::IOS:
186 platform_id = OSPlatform::IOS;
187 break;
188 default:
190 "OS %s not supported.", target_triple.getOSName().str().c_str());
191 return error;
192 };
193
194 llvm::minidump::SystemInfo sys_info;
195 sys_info.ProcessorArch =
196 static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch);
197 // Global offset to beginning of a csd_string in a data section
198 sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>(
199 GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo));
200 sys_info.PlatformId = platform_id;
201 m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo));
202
203 std::string csd_string;
204
205 error = WriteString(csd_string, &m_data);
206 if (error.Fail()) {
207 error =
208 Status::FromErrorString("Unable to convert the csd string to UTF16.");
209 return error;
210 }
211
212 return error;
213}
214
215Status WriteString(const std::string &to_write,
218 // let the StringRef eat also null termination char
219 llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1);
220 llvm::SmallVector<llvm::UTF16, 128> to_write_utf16;
221
222 bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16);
223 if (!converted) {
225 "Unable to convert the string to UTF16. Failed to convert %s",
226 to_write.c_str());
227 return error;
228 }
229
230 // size of the UTF16 string should be written without the null termination
231 // character that is stored in 2 bytes
232 llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2);
233
234 buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t));
235 buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes());
236
237 return error;
238}
239
240llvm::Expected<uint64_t> getModuleFileSize(Target &target,
241 const ModuleSP &mod) {
242 // JIT module has the same vm and file size.
243 uint64_t SizeOfImage = 0;
244 if (mod->GetObjectFile()->CalculateType() == ObjectFile::Type::eTypeJIT) {
245 for (const auto &section : *mod->GetObjectFile()->GetSectionList()) {
246 SizeOfImage += section->GetByteSize();
247 }
248 return SizeOfImage;
249 }
250 SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
251
252 if (!sect_sp) {
253 return llvm::createStringError(std::errc::operation_not_supported,
254 "Couldn't obtain the section information.");
255 }
256 lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target);
257 // Use memory size since zero fill sections, like ".bss", will be smaller on
258 // disk.
259 lldb::addr_t sect_size = sect_sp->GetByteSize();
260 // This will usually be zero, but make sure to calculate the BaseOfImage
261 // offset.
262 const lldb::addr_t base_sect_offset =
263 mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) -
264 sect_addr;
265 SizeOfImage = sect_size - base_sect_offset;
266 lldb::addr_t next_sect_addr = sect_addr + sect_size;
267 Address sect_so_addr;
268 target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
269 lldb::SectionSP next_sect_sp = sect_so_addr.GetSection();
270 while (next_sect_sp &&
271 next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) {
272 sect_size = sect_sp->GetByteSize();
273 SizeOfImage += sect_size;
274 next_sect_addr += sect_size;
275 target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
276 next_sect_sp = sect_so_addr.GetSection();
277 }
278
279 return SizeOfImage;
280}
281
282// ModuleList stream consists of a number of modules, followed by an array
283// of llvm::minidump::Module's structures. Every structure informs about a
284// single module. Additional data of variable length, such as module's names,
285// are stored just after the ModuleList stream. The llvm::minidump::Module
286// structures point to this helper data by global offset.
288 constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module);
290
291 lldb_private::Target &target = m_process_sp->GetTarget();
292 const ModuleList &modules = target.GetImages();
293 llvm::support::ulittle32_t modules_count =
294 static_cast<llvm::support::ulittle32_t>(modules.GetSize());
295
296 // This helps us with getting the correct global offset in minidump
297 // file later, when we will be setting up offsets from the
298 // the llvm::minidump::Module's structures into helper data
299 size_t size_before = GetCurrentDataEndOffset();
300
301 // This is the size of the main part of the ModuleList stream.
302 // It consists of a module number and corresponding number of
303 // structs describing individual modules
304 size_t module_stream_size =
305 sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
306
307 // Adding directory describing this stream.
308 error = AddDirectory(StreamType::ModuleList, module_stream_size);
309 if (error.Fail())
310 return error;
311
312 m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t));
313
314 // Temporary storage for the helper data (of variable length)
315 // as these cannot be dumped to m_data before dumping entire
316 // array of module structures.
317 DataBufferHeap helper_data;
318
319 for (size_t i = 0; i < modules_count; ++i) {
320 ModuleSP mod = modules.GetModuleAtIndex(i);
321 std::string module_name = mod->GetSpecificationDescription();
322 auto maybe_mod_size = getModuleFileSize(target, mod);
323 if (!maybe_mod_size) {
324 llvm::Error mod_size_err = maybe_mod_size.takeError();
325 llvm::handleAllErrors(std::move(mod_size_err),
326 [&](const llvm::ErrorInfoBase &E) {
328 "Unable to get the size of module %s: %s.",
329 module_name.c_str(), E.message().c_str());
330 });
331 return error;
332 }
333
334 uint64_t mod_size = std::move(*maybe_mod_size);
335
336 llvm::support::ulittle32_t signature =
337 static_cast<llvm::support::ulittle32_t>(
338 static_cast<uint32_t>(minidump::CvSignature::ElfBuildId));
339 auto uuid = mod->GetUUID().GetBytes();
340
341 VSFixedFileInfo info;
342 info.Signature = static_cast<llvm::support::ulittle32_t>(0u);
343 info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u);
344 info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
345 info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
346 info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
347 info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
348 info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u);
349 info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u);
350 info.FileOS = static_cast<llvm::support::ulittle32_t>(0u);
351 info.FileType = static_cast<llvm::support::ulittle32_t>(0u);
352 info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u);
353 info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u);
354 info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u);
355
356 LocationDescriptor ld;
357 ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u);
358 ld.RVA = static_cast<llvm::support::ulittle32_t>(0u);
359
360 // Setting up LocationDescriptor for uuid string. The global offset into
361 // minidump file is calculated.
362 LocationDescriptor ld_cv;
363 ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>(
364 sizeof(llvm::support::ulittle32_t) + uuid.size());
365 ld_cv.RVA = static_cast<llvm::support::ulittle32_t>(
366 size_before + module_stream_size + helper_data.GetByteSize());
367
368 helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t));
369 helper_data.AppendData(uuid.begin(), uuid.size());
370
371 llvm::minidump::Module m;
372 m.BaseOfImage = static_cast<llvm::support::ulittle64_t>(
373 mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target));
374 m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size);
375 m.Checksum = static_cast<llvm::support::ulittle32_t>(0);
376 m.TimeDateStamp =
377 static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
378 m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>(
379 size_before + module_stream_size + helper_data.GetByteSize());
380 m.VersionInfo = info;
381 m.CvRecord = ld_cv;
382 m.MiscRecord = ld;
383
384 error = WriteString(module_name, &helper_data);
385
386 if (error.Fail())
387 return error;
388
389 m_data.AppendData(&m, sizeof(llvm::minidump::Module));
390 }
391
392 m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
393 return error;
394}
395
397 llvm::StringRef reg_name) {
398 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
399 if (!reg_info)
400 return 0;
402 bool success = reg_ctx->ReadRegister(reg_info, reg_value);
403 if (!success)
404 return 0;
405 return reg_value.GetAsUInt16();
406}
407
409 llvm::StringRef reg_name) {
410 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
411 if (!reg_info)
412 return 0;
414 bool success = reg_ctx->ReadRegister(reg_info, reg_value);
415 if (!success)
416 return 0;
417 return reg_value.GetAsUInt32();
418}
419
421 llvm::StringRef reg_name) {
422 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
423 if (!reg_info)
424 return 0;
426 bool success = reg_ctx->ReadRegister(reg_info, reg_value);
427 if (!success)
428 return 0;
429 return reg_value.GetAsUInt64();
430}
431
432llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx,
433 llvm::StringRef reg_name) {
434 return static_cast<llvm::support::ulittle16_t>(
435 read_register_u16_raw(reg_ctx, reg_name));
436}
437
438llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx,
439 llvm::StringRef reg_name) {
440 return static_cast<llvm::support::ulittle32_t>(
441 read_register_u32_raw(reg_ctx, reg_name));
442}
443
444llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,
445 llvm::StringRef reg_name) {
446 return static_cast<llvm::support::ulittle64_t>(
447 read_register_u64_raw(reg_ctx, reg_name));
448}
449
450void read_register_u128(RegisterContext *reg_ctx, llvm::StringRef reg_name,
451 uint8_t *dst) {
452 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
453 if (reg_info) {
455 if (reg_ctx->ReadRegister(reg_info, reg_value)) {
457 uint32_t bytes_copied = reg_value.GetAsMemoryData(
458 *reg_info, dst, 16, lldb::ByteOrder::eByteOrderLittle, error);
459 if (bytes_copied == 16)
460 return;
461 }
462 }
463 // If anything goes wrong, then zero out the register value.
464 memset(dst, 0, 16);
465}
466
470 thread_context.p1_home = {};
471 thread_context.context_flags = static_cast<uint32_t>(
477 thread_context.rax = read_register_u64(reg_ctx, "rax");
478 thread_context.rbx = read_register_u64(reg_ctx, "rbx");
479 thread_context.rcx = read_register_u64(reg_ctx, "rcx");
480 thread_context.rdx = read_register_u64(reg_ctx, "rdx");
481 thread_context.rdi = read_register_u64(reg_ctx, "rdi");
482 thread_context.rsi = read_register_u64(reg_ctx, "rsi");
483 thread_context.rbp = read_register_u64(reg_ctx, "rbp");
484 thread_context.rsp = read_register_u64(reg_ctx, "rsp");
485 thread_context.r8 = read_register_u64(reg_ctx, "r8");
486 thread_context.r9 = read_register_u64(reg_ctx, "r9");
487 thread_context.r10 = read_register_u64(reg_ctx, "r10");
488 thread_context.r11 = read_register_u64(reg_ctx, "r11");
489 thread_context.r12 = read_register_u64(reg_ctx, "r12");
490 thread_context.r13 = read_register_u64(reg_ctx, "r13");
491 thread_context.r14 = read_register_u64(reg_ctx, "r14");
492 thread_context.r15 = read_register_u64(reg_ctx, "r15");
493 thread_context.rip = read_register_u64(reg_ctx, "rip");
494 // To make our code agnostic to whatever type the register value identifies
495 // itself as, we read as a u64 and truncate to u32/u16 ourselves.
496 thread_context.eflags = read_register_u64(reg_ctx, "rflags");
497 thread_context.cs = read_register_u64(reg_ctx, "cs");
498 thread_context.fs = read_register_u64(reg_ctx, "fs");
499 thread_context.gs = read_register_u64(reg_ctx, "gs");
500 thread_context.ss = read_register_u64(reg_ctx, "ss");
501 thread_context.ds = read_register_u64(reg_ctx, "ds");
502 thread_context.fs_base = read_register_u64(reg_ctx, "fs_base");
503 thread_context.gs_base = read_register_u64(reg_ctx, "gs_base");
504 return thread_context;
505}
506
510 thread_context.context_flags = static_cast<uint32_t>(
511 minidump::RegisterContextMinidump_ARM64::Flags::ARM64_Flag |
512 minidump::RegisterContextMinidump_ARM64::Flags::Integer |
513 minidump::RegisterContextMinidump_ARM64::Flags::FloatingPoint);
514 char reg_name[16];
515 for (uint32_t i = 0; i < 31; ++i) {
516 snprintf(reg_name, sizeof(reg_name), "x%u", i);
517 thread_context.x[i] = read_register_u64(reg_ctx, reg_name);
518 }
519 // Work around a bug in debugserver where "sp" on arm64 doesn't have the alt
520 // name set to "x31"
521 thread_context.x[31] = read_register_u64(reg_ctx, "sp");
522 thread_context.pc = read_register_u64(reg_ctx, "pc");
523 thread_context.cpsr = read_register_u32(reg_ctx, "cpsr");
524 thread_context.fpsr = read_register_u32(reg_ctx, "fpsr");
525 thread_context.fpcr = read_register_u32(reg_ctx, "fpcr");
526 for (uint32_t i = 0; i < 32; ++i) {
527 snprintf(reg_name, sizeof(reg_name), "v%u", i);
528 read_register_u128(reg_ctx, reg_name, &thread_context.v[i * 16]);
529 }
530 return thread_context;
531}
532
534 llvm::Triple::ArchType m_arch;
535 union {
538 };
539
540public:
541 ArchThreadContexts(llvm::Triple::ArchType arch) : m_arch(arch) {}
542
544 switch (m_arch) {
545 case llvm::Triple::ArchType::x86_64:
547 return true;
548 case llvm::Triple::ArchType::aarch64:
549 arm64 = GetThreadContext_ARM64(reg_ctx);
550 return true;
551 default:
552 break;
553 }
554 return false;
555 }
556
557 const void *data() const { return &x86_64; }
558
559 size_t size() const {
560 switch (m_arch) {
561 case llvm::Triple::ArchType::x86_64:
562 return sizeof(x86_64);
563 case llvm::Triple::ArchType::aarch64:
564 return sizeof(arm64);
565 default:
566 break;
567 }
568 return 0;
569 }
570};
571
574 // If we have anything in the heap flush it.
576 m_core_file->SeekFromStart(m_thread_list_start);
577 for (auto &pair : m_thread_by_range_end) {
578 // The thread objects will get a new memory descriptor added
579 // When we are emitting the memory list and then we write it here
580 const llvm::minidump::Thread &thread = pair.second;
581 size_t bytes_to_write = sizeof(llvm::minidump::Thread);
582 size_t bytes_written = bytes_to_write;
583 error = m_core_file->Write(&thread, bytes_written);
584 if (error.Fail() || bytes_to_write != bytes_written) {
586 "Wrote incorrect number of bytes to minidump file. (written %zd/%zd)",
587 bytes_written, bytes_to_write);
588 return error;
589 }
590 }
591
592 return error;
593}
594
596 constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
597 std::vector<ThreadSP> thread_list =
598 m_process_sp->CalculateCoreFileThreadList(m_save_core_options);
599
600 // size of the entire thread stream consists of:
601 // number of threads and threads array
602 size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) +
603 thread_list.size() * minidump_thread_size;
604 // save for the ability to set up RVA
605 size_t size_before = GetCurrentDataEndOffset();
607 error = AddDirectory(StreamType::ThreadList, thread_stream_size);
608 if (error.Fail())
609 return error;
610
611 llvm::support::ulittle32_t thread_count =
612 static_cast<llvm::support::ulittle32_t>(thread_list.size());
613 m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));
614
615 // Take the offset after the thread count.
617 DataBufferHeap helper_data;
618
619 Log *log = GetLog(LLDBLog::Object);
620 for (const ThreadSP &thread_sp : thread_list) {
621 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
622
623 if (!reg_ctx_sp) {
624 error = Status::FromErrorString("Unable to get the register context.");
625 return error;
626 }
627 RegisterContext *reg_ctx = reg_ctx_sp.get();
628 Target &target = m_process_sp->GetTarget();
629 const ArchSpec &arch = target.GetArchitecture();
630 ArchThreadContexts thread_context(arch.GetMachine());
631 if (!thread_context.prepareRegisterContext(reg_ctx)) {
633 "architecture %s not supported.",
634 arch.GetTriple().getArchName().str().c_str());
635 return error;
636 }
637
638 uint64_t sp = reg_ctx->GetSP();
639 MemoryRegionInfo sp_region;
640 m_process_sp->GetMemoryRegionInfo(sp, sp_region);
641
642 // Emit a blank descriptor
643 MemoryDescriptor stack;
644 LocationDescriptor empty_label;
645 empty_label.DataSize = 0;
646 empty_label.RVA = 0;
647 stack.Memory = empty_label;
648 stack.StartOfMemoryRange = 0;
649 LocationDescriptor thread_context_memory_locator;
650 thread_context_memory_locator.DataSize =
651 static_cast<llvm::support::ulittle32_t>(thread_context.size());
652 thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
653 size_before + thread_stream_size + helper_data.GetByteSize());
654 // Cache thie thread context memory so we can reuse for exceptions.
655 m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator;
656
657 LLDB_LOGF(log, "AddThreadList for thread %d: thread_context %zu bytes",
658 thread_sp->GetIndexID(), thread_context.size());
659 helper_data.AppendData(thread_context.data(), thread_context.size());
660
661 llvm::minidump::Thread t;
662 t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
663 t.SuspendCount = static_cast<llvm::support::ulittle32_t>(
664 (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0);
665 t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0);
666 t.Priority = static_cast<llvm::support::ulittle32_t>(0);
667 t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);
668 t.Stack = stack, t.Context = thread_context_memory_locator;
669
670 // We save off the stack object so we can circle back and clean it up.
671 m_thread_by_range_end[sp_region.GetRange().GetRangeEnd()] = t;
672 m_data.AppendData(&t, sizeof(llvm::minidump::Thread));
673 }
674
675 LLDB_LOGF(log, "AddThreadList(): total helper_data %" PRIx64 " bytes",
676 helper_data.GetByteSize());
677 m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
678 return Status();
679}
680
682 std::vector<ThreadSP> thread_list =
683 m_process_sp->CalculateCoreFileThreadList(m_save_core_options);
685 for (const ThreadSP &thread_sp : thread_list) {
686 StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
687 // If we don't have a stop info, or if it's invalid, skip.
688 if (!stop_info_sp ||
689 stop_info_sp->GetStopReason() == lldb::eStopReasonInvalid)
690 continue;
691
692 constexpr size_t minidump_exception_size =
693 sizeof(llvm::minidump::ExceptionStream);
694 error = AddDirectory(StreamType::Exception, minidump_exception_size);
695 if (error.Fail())
696 return error;
697
698 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
699 Exception exp_record = {};
700 exp_record.ExceptionCode =
701 static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
702 exp_record.ExceptionFlags =
703 static_cast<llvm::support::ulittle32_t>(Exception::LLDB_FLAG);
704 exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);
705 exp_record.ExceptionAddress = reg_ctx_sp->GetPC();
706 exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(1);
707 std::string description = stop_info_sp->GetDescription();
708 // We have 120 bytes to work with and it's unlikely description will
709 // overflow, but we gotta check.
710 memcpy(&exp_record.ExceptionInformation, description.c_str(),
711 std::max(description.size(), Exception::MaxParameterBytes));
712 exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
713 ExceptionStream exp_stream;
714 exp_stream.ThreadId =
715 static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
716 exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
717 exp_stream.ExceptionRecord = exp_record;
718 auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID());
719 if (Iter != m_tid_to_reg_ctx.end()) {
720 exp_stream.ThreadContext = Iter->second;
721 } else {
722 exp_stream.ThreadContext.DataSize = 0;
723 exp_stream.ThreadContext.RVA = 0;
724 }
725 m_data.AppendData(&exp_stream, minidump_exception_size);
726 }
727
728 return error;
729}
730
733 error = AddDirectory(StreamType::MiscInfo,
735 if (error.Fail())
736 return error;
737
739 misc_info.size = static_cast<llvm::support::ulittle32_t>(
741 // Default set flags1 to 0, in case that we will not be able to
742 // get any information
743 misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);
744
746 m_process_sp->GetProcessInfo(process_info);
747 if (process_info.ProcessIDIsValid()) {
748 // Set flags1 to reflect that PID is filled in
749 misc_info.flags1 =
750 static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>(
752 misc_info.process_id =
753 static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID());
754 }
755
756 m_data.AppendData(&misc_info,
758 return error;
759}
760
761std::unique_ptr<llvm::MemoryBuffer>
762getFileStreamHelper(const std::string &path) {
763 auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);
764 if (!maybe_stream)
765 return nullptr;
766 return std::move(maybe_stream.get());
767}
768
771 // No-op if we are not on linux.
772 if (m_process_sp->GetTarget().GetArchitecture().GetTriple().getOS() !=
773 llvm::Triple::Linux)
774 return error;
775
776 std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
777 {StreamType::LinuxCPUInfo, "/proc/cpuinfo"},
778 {StreamType::LinuxLSBRelease, "/etc/lsb-release"},
779 };
780
782 m_process_sp->GetProcessInfo(process_info);
783 if (process_info.ProcessIDIsValid()) {
784 lldb::pid_t pid = process_info.GetProcessID();
785 std::string pid_str = std::to_string(pid);
786 files_with_stream_types.push_back(
787 {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"});
788 files_with_stream_types.push_back(
789 {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"});
790 files_with_stream_types.push_back(
791 {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"});
792 files_with_stream_types.push_back(
793 {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"});
794 files_with_stream_types.push_back(
795 {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"});
796 files_with_stream_types.push_back(
797 {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"});
798 files_with_stream_types.push_back(
799 {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"});
800 }
801
802 for (const auto &entry : files_with_stream_types) {
803 StreamType stream = entry.first;
804 std::string path = entry.second;
805 auto memory_buffer = getFileStreamHelper(path);
806
807 if (memory_buffer) {
808 size_t size = memory_buffer->getBufferSize();
809 if (size == 0)
810 continue;
811 error = AddDirectory(stream, size);
812 if (error.Fail())
813 return error;
814 m_data.AppendData(memory_buffer->getBufferStart(), size);
815 }
816 }
817
818 return error;
819}
820
823
824 // We first save the thread stacks to ensure they fit in the first UINT32_MAX
825 // bytes of the core file. Thread structures in minidump files can only use
826 // 32 bit memory descriptiors, so we emit them first to ensure the memory is
827 // in accessible with a 32 bit offset.
828 std::vector<CoreFileMemoryRange> ranges_32;
829 std::vector<CoreFileMemoryRange> ranges_64;
830 CoreFileMemoryRanges all_core_memory_ranges;
831 error = m_process_sp->CalculateCoreFileSaveRanges(m_save_core_options,
832 all_core_memory_ranges);
833
834 if (error.Fail())
835 return error;
836
837 lldb_private::Progress progress("Saving Minidump File", "",
838 all_core_memory_ranges.GetSize());
839 std::vector<CoreFileMemoryRange> all_core_memory_vec;
840 // Extract all the data into just a vector of data. So we can mutate this in
841 // place.
842 for (const auto &core_range : all_core_memory_ranges)
843 all_core_memory_vec.push_back(core_range.data);
844
845 // Start by saving all of the stacks and ensuring they fit under the 32b
846 // limit.
847 uint64_t total_size = GetCurrentDataEndOffset();
848 auto iterator = all_core_memory_vec.begin();
849 while (iterator != all_core_memory_vec.end()) {
850 if (m_thread_by_range_end.count(iterator->range.end()) > 0) {
851 // We don't save stacks twice.
852 ranges_32.push_back(*iterator);
853 total_size +=
854 iterator->range.size() + sizeof(llvm::minidump::MemoryDescriptor);
855 iterator = all_core_memory_vec.erase(iterator);
856 } else {
857 iterator++;
858 }
859 }
860
861 if (total_size >= UINT32_MAX) {
863 "Unable to write minidump. Stack memory "
864 "exceeds 32b limit. (Num Stacks %zu)",
865 ranges_32.size());
866 return error;
867 }
868
869 // After saving the stacks, we start packing as much as we can into 32b.
870 // We apply a generous padding here so that the Directory, MemoryList and
871 // Memory64List sections all begin in 32b addressable space.
872 // Then anything overflow extends into 64b addressable space.
873 // All core memeroy ranges will either container nothing on stacks only
874 // or all the memory ranges including stacks
875 if (!all_core_memory_vec.empty())
876 total_size += 256 + (all_core_memory_vec.size() *
877 sizeof(llvm::minidump::MemoryDescriptor_64));
878
879 for (const auto &core_range : all_core_memory_vec) {
880 const addr_t range_size = core_range.range.size();
881 // We don't need to check for stacks here because we already removed them
882 // from all_core_memory_ranges.
883 if (total_size + range_size < UINT32_MAX) {
884 ranges_32.push_back(core_range);
885 total_size += range_size;
886 } else {
887 ranges_64.push_back(core_range);
888 }
889 }
890
891 error = AddMemoryList_32(ranges_32, progress);
892 if (error.Fail())
893 return error;
894
895 // Add the remaining memory as a 64b range.
896 if (!ranges_64.empty()) {
897 error = AddMemoryList_64(ranges_64, progress);
898 if (error.Fail())
899 return error;
900 }
901
902 return FixThreadStacks();
903}
904
906 // write header
907 llvm::minidump::Header header;
908 header.Signature = static_cast<llvm::support::ulittle32_t>(
909 llvm::minidump::Header::MagicSignature);
910 header.Version = static_cast<llvm::support::ulittle32_t>(
911 llvm::minidump::Header::MagicVersion);
912 header.NumberOfStreams =
913 static_cast<llvm::support::ulittle32_t>(m_directories.size());
914 // We write the directories right after the header.
915 header.StreamDirectoryRVA =
916 static_cast<llvm::support::ulittle32_t>(HEADER_SIZE);
917 header.Checksum = static_cast<llvm::support::ulittle32_t>(
918 0u), // not used in most of the writers
919 header.TimeDateStamp =
920 static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
921 header.Flags =
922 static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag
923
925 size_t bytes_written;
926
927 m_core_file->SeekFromStart(0);
928 bytes_written = HEADER_SIZE;
929 error = m_core_file->Write(&header, bytes_written);
930 if (error.Fail() || bytes_written != HEADER_SIZE) {
931 if (bytes_written != HEADER_SIZE)
933 "Unable to write the minidump header (written %zd/%zd)",
934 bytes_written, HEADER_SIZE);
935 return error;
936 }
937 return error;
938}
939
942}
943
946 size_t bytes_written;
947 m_core_file->SeekFromStart(HEADER_SIZE);
948 for (const Directory &dir : m_directories) {
949 bytes_written = DIRECTORY_SIZE;
950 error = m_core_file->Write(&dir, bytes_written);
951 if (error.Fail() || bytes_written != DIRECTORY_SIZE) {
952 if (bytes_written != DIRECTORY_SIZE)
954 "unable to write the directory (written %zd/%zd)", bytes_written,
956 return error;
957 }
958 }
959
960 return error;
961}
962
963static uint64_t
964GetLargestRangeSize(const std::vector<CoreFileMemoryRange> &ranges) {
965 uint64_t max_size = 0;
966 for (const auto &core_range : ranges)
967 max_size = std::max(max_size, core_range.range.size());
968 return max_size;
969}
970
971Status
972MinidumpFileBuilder::AddMemoryList_32(std::vector<CoreFileMemoryRange> &ranges,
973 Progress &progress) {
974 std::vector<MemoryDescriptor> descriptors;
976 if (ranges.size() == 0)
977 return error;
978
979 Log *log = GetLog(LLDBLog::Object);
980 size_t region_index = 0;
981 auto data_up =
982 std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0);
983 for (const auto &core_range : ranges) {
984 // Take the offset before we write.
985 const offset_t offset_for_data = GetCurrentDataEndOffset();
986 const addr_t addr = core_range.range.start();
987 const addr_t size = core_range.range.size();
988 const addr_t end = core_range.range.end();
989
990 LLDB_LOGF(log,
991 "AddMemoryList %zu/%zu reading memory for region "
992 "(%" PRIx64 " bytes) [%" PRIx64 ", %" PRIx64 ")",
993 region_index, ranges.size(), size, addr, addr + size);
994 ++region_index;
995
996 progress.Increment(1, "Adding Memory Range " + core_range.Dump());
997 const size_t bytes_read =
998 m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
999 if (error.Fail() || bytes_read == 0) {
1000 LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
1001 bytes_read, error.AsCString());
1002 // Just skip sections with errors or zero bytes in 32b mode
1003 continue;
1004 } else if (bytes_read != size) {
1005 LLDB_LOGF(
1006 log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes",
1007 addr, size);
1008 }
1009
1010 MemoryDescriptor descriptor;
1011 descriptor.StartOfMemoryRange =
1012 static_cast<llvm::support::ulittle64_t>(addr);
1013 descriptor.Memory.DataSize =
1014 static_cast<llvm::support::ulittle32_t>(bytes_read);
1015 descriptor.Memory.RVA =
1016 static_cast<llvm::support::ulittle32_t>(offset_for_data);
1017 descriptors.push_back(descriptor);
1018 if (m_thread_by_range_end.count(end) > 0)
1019 m_thread_by_range_end[end].Stack = descriptor;
1020
1021 // Add the data to the buffer, flush as needed.
1022 error = AddData(data_up->GetBytes(), bytes_read);
1023 if (error.Fail())
1024 return error;
1025 }
1026
1027 // Add a directory that references this list
1028 // With a size of the number of ranges as a 32 bit num
1029 // And then the size of all the ranges
1030 error = AddDirectory(StreamType::MemoryList,
1031 sizeof(llvm::minidump::MemoryListHeader) +
1032 descriptors.size() *
1033 sizeof(llvm::minidump::MemoryDescriptor));
1034 if (error.Fail())
1035 return error;
1036
1037 llvm::minidump::MemoryListHeader list_header;
1038 llvm::support::ulittle32_t memory_ranges_num =
1039 static_cast<llvm::support::ulittle32_t>(descriptors.size());
1040 list_header.NumberOfMemoryRanges = memory_ranges_num;
1041 m_data.AppendData(&list_header, sizeof(llvm::minidump::MemoryListHeader));
1042 // For 32b we can get away with writing off the descriptors after the data.
1043 // This means no cleanup loop needed.
1044 m_data.AppendData(descriptors.data(),
1045 descriptors.size() * sizeof(MemoryDescriptor));
1046
1047 return error;
1048}
1049
1050Status
1051MinidumpFileBuilder::AddMemoryList_64(std::vector<CoreFileMemoryRange> &ranges,
1052 Progress &progress) {
1053 Status error;
1054 if (ranges.empty())
1055 return error;
1056
1057 error = AddDirectory(StreamType::Memory64List,
1058 (sizeof(llvm::support::ulittle64_t) * 2) +
1059 ranges.size() *
1060 sizeof(llvm::minidump::MemoryDescriptor_64));
1061 if (error.Fail())
1062 return error;
1063
1064 llvm::minidump::Memory64ListHeader list_header;
1065 llvm::support::ulittle64_t memory_ranges_num =
1066 static_cast<llvm::support::ulittle64_t>(ranges.size());
1067 list_header.NumberOfMemoryRanges = memory_ranges_num;
1068 // Capture the starting offset for all the descriptors so we can clean them up
1069 // if needed.
1070 offset_t starting_offset =
1071 GetCurrentDataEndOffset() + sizeof(llvm::support::ulittle64_t);
1072 // The base_rva needs to start after the directories, which is right after
1073 // this 8 byte variable.
1074 offset_t base_rva =
1075 starting_offset +
1076 (ranges.size() * sizeof(llvm::minidump::MemoryDescriptor_64));
1077 llvm::support::ulittle64_t memory_ranges_base_rva =
1078 static_cast<llvm::support::ulittle64_t>(base_rva);
1079 list_header.BaseRVA = memory_ranges_base_rva;
1080 m_data.AppendData(&list_header, sizeof(llvm::minidump::Memory64ListHeader));
1081
1082 bool cleanup_required = false;
1083 std::vector<MemoryDescriptor_64> descriptors;
1084 // Enumerate the ranges and create the memory descriptors so we can append
1085 // them first
1086 for (const auto core_range : ranges) {
1087 // Add the space required to store the memory descriptor
1088 MemoryDescriptor_64 memory_desc;
1089 memory_desc.StartOfMemoryRange =
1090 static_cast<llvm::support::ulittle64_t>(core_range.range.start());
1091 memory_desc.DataSize =
1092 static_cast<llvm::support::ulittle64_t>(core_range.range.size());
1093 descriptors.push_back(memory_desc);
1094 // Now write this memory descriptor to the buffer.
1095 m_data.AppendData(&memory_desc, sizeof(MemoryDescriptor_64));
1096 }
1097
1098 Log *log = GetLog(LLDBLog::Object);
1099 size_t region_index = 0;
1100 auto data_up =
1101 std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0);
1102 for (const auto &core_range : ranges) {
1103 const addr_t addr = core_range.range.start();
1104 const addr_t size = core_range.range.size();
1105
1106 LLDB_LOGF(log,
1107 "AddMemoryList_64 %zu/%zu reading memory for region "
1108 "(%" PRIx64 "bytes) "
1109 "[%" PRIx64 ", %" PRIx64 ")",
1110 region_index, ranges.size(), size, addr, addr + size);
1111 ++region_index;
1112
1113 progress.Increment(1, "Adding Memory Range " + core_range.Dump());
1114 const size_t bytes_read =
1115 m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
1116 if (error.Fail()) {
1117 LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
1118 bytes_read, error.AsCString());
1119 error.Clear();
1120 cleanup_required = true;
1121 descriptors[region_index].DataSize = 0;
1122 }
1123 if (bytes_read != size) {
1124 LLDB_LOGF(
1125 log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes",
1126 addr, size);
1127 cleanup_required = true;
1128 descriptors[region_index].DataSize = bytes_read;
1129 }
1130
1131 // Add the data to the buffer, flush as needed.
1132 error = AddData(data_up->GetBytes(), bytes_read);
1133 if (error.Fail())
1134 return error;
1135 }
1136
1137 // Early return if there is no cleanup needed.
1138 if (!cleanup_required) {
1139 return error;
1140 } else {
1141 // Flush to disk we can make the fixes in place.
1143 // Fixup the descriptors that were not read correctly.
1144 m_core_file->SeekFromStart(starting_offset);
1145 size_t bytes_written = sizeof(MemoryDescriptor_64) * descriptors.size();
1146 error = m_core_file->Write(descriptors.data(), bytes_written);
1147 if (error.Fail() ||
1148 bytes_written != sizeof(MemoryDescriptor_64) * descriptors.size()) {
1150 "unable to write the memory descriptors (written %zd/%zd)",
1151 bytes_written, sizeof(MemoryDescriptor_64) * descriptors.size());
1152 }
1153
1154 return error;
1155 }
1156}
1157
1158Status MinidumpFileBuilder::AddData(const void *data, uint64_t size) {
1159 // This should also get chunked, because worst case we copy over a big
1160 // object / memory range, say 5gb. In that case, we'd have to allocate 10gb
1161 // 5 gb for the buffer we're copying from, and then 5gb for the buffer we're
1162 // copying to. Which will be short lived and immedaitely go to disk, the goal
1163 // here is to limit the number of bytes we need to host in memory at any given
1164 // time.
1165 m_data.AppendData(data, size);
1167 return FlushBufferToDisk();
1168
1169 return Status();
1170}
1171
1173 Status error;
1174 // Set the stream to it's end.
1175 m_core_file->SeekFromStart(m_saved_data_size);
1176 addr_t starting_size = m_data.GetByteSize();
1177 addr_t remaining_bytes = starting_size;
1178 offset_t offset = 0;
1179
1180 while (remaining_bytes > 0) {
1181 size_t bytes_written = remaining_bytes;
1182 // We don't care how many bytes we wrote unless we got an error
1183 // so just decrement the remaining bytes.
1184 error = m_core_file->Write(m_data.GetBytes() + offset, bytes_written);
1185 if (error.Fail()) {
1187 "Wrote incorrect number of bytes to minidump file. (written %" PRIx64
1188 "/%" PRIx64 ")",
1189 starting_size - remaining_bytes, starting_size);
1190 return error;
1191 }
1192
1193 offset += bytes_written;
1194 remaining_bytes -= bytes_written;
1195 }
1196
1197 m_saved_data_size += starting_size;
1198 m_data.Clear();
1199 return error;
1200}
1201
1203 Status error;
1204 // If anything is left unsaved, dump it.
1206 if (error.Fail())
1207 return error;
1208
1209 // Overwrite the header which we filled in earlier.
1210 error = DumpHeader();
1211 if (error.Fail())
1212 return error;
1213
1214 // Overwrite the space saved for directories
1216 if (error.Fail())
1217 return error;
1218
1219 return error;
1220}
1221
1223 Log *log = GetLog(LLDBLog::Object);
1224
1225 if (m_core_file) {
1226 Status error = m_core_file->Close();
1227 if (error.Fail())
1228 LLDB_LOGF(log, "Failed to close minidump file: %s", error.AsCString());
1229
1230 m_core_file.reset();
1231 }
1232}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition: Log.h:376
llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx, llvm::StringRef reg_name)
static uint64_t GetLargestRangeSize(const std::vector< CoreFileMemoryRange > &ranges)
uint64_t read_register_u64_raw(RegisterContext *reg_ctx, llvm::StringRef reg_name)
Status WriteString(const std::string &to_write, lldb_private::DataBufferHeap *buffer)
lldb_private::minidump::MinidumpContext_x86_64 GetThreadContext_x86_64(RegisterContext *reg_ctx)
llvm::Expected< uint64_t > getModuleFileSize(Target &target, const ModuleSP &mod)
uint16_t read_register_u16_raw(RegisterContext *reg_ctx, llvm::StringRef reg_name)
llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx, llvm::StringRef reg_name)
void read_register_u128(RegisterContext *reg_ctx, llvm::StringRef reg_name, uint8_t *dst)
std::unique_ptr< llvm::MemoryBuffer > getFileStreamHelper(const std::string &path)
llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx, llvm::StringRef reg_name)
minidump::RegisterContextMinidump_ARM64::Context GetThreadContext_ARM64(RegisterContext *reg_ctx)
uint32_t read_register_u32_raw(RegisterContext *reg_ctx, llvm::StringRef reg_name)
Structure holding data neccessary for minidump file creation.
lldb_private::Status WriteString(const std::string &to_write, lldb_private::DataBufferHeap *buffer)
const void * data() const
llvm::Triple::ArchType m_arch
lldb_private::minidump::MinidumpContext_x86_64 x86_64
lldb_private::minidump::RegisterContextMinidump_ARM64::Context arm64
bool prepareRegisterContext(RegisterContext *reg_ctx)
ArchThreadContexts(llvm::Triple::ArchType arch)
lldb_private::Status AddExceptions()
std::unordered_map< lldb::tid_t, llvm::minidump::LocationDescriptor > m_tid_to_reg_ctx
lldb_private::Status AddThreadList()
lldb_private::Status AddHeaderAndCalculateDirectories()
static constexpr size_t DIRECTORY_SIZE
lldb_private::DataBufferHeap m_data
lldb_private::Status AddSystemInfo()
lldb_private::Status AddMemoryList()
std::unordered_map< lldb::addr_t, llvm::minidump::Thread > m_thread_by_range_end
lldb_private::Status AddData(const void *data, uint64_t size)
lldb_private::Status DumpFile()
lldb_private::SaveCoreOptions m_save_core_options
lldb_private::Status FlushBufferToDisk()
lldb::offset_t m_thread_list_start
static constexpr size_t MAX_WRITE_CHUNK_SIZE
lldb_private::Status AddDirectory(llvm::minidump::StreamType type, uint64_t stream_size)
lldb_private::Status FixThreadStacks()
lldb::ProcessSP m_process_sp
static constexpr size_t HEADER_SIZE
lldb::offset_t GetCurrentDataEndOffset() const
lldb_private::Status AddMemoryList_32(std::vector< lldb_private::CoreFileMemoryRange > &ranges, lldb_private::Progress &progress)
std::vector< llvm::minidump::Directory > m_directories
lldb_private::Status DumpDirectories() const
lldb_private::Status AddLinuxFileStreams()
lldb_private::Status AddModuleList()
lldb_private::Status AddMiscInfo()
lldb_private::Status DumpHeader() const
lldb_private::Status AddMemoryList_64(std::vector< lldb_private::CoreFileMemoryRange > &ranges, lldb_private::Progress &progress)
A section + offset based address class.
Definition: Address.h:62
lldb::SectionSP GetSection() const
Get const accessor for the section.
Definition: Address.h:439
An architecture specification class.
Definition: ArchSpec.h:31
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:461
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition: ArchSpec.cpp:701
A subclass of DataBuffer that stores a data buffer on the heap.
lldb::offset_t GetByteSize() const override
Get the number of bytes in the data buffer.
void AppendData(const void *src, uint64_t src_len)
A collection class for Module objects.
Definition: ModuleList.h:103
lldb::ModuleSP GetModuleAtIndex(size_t idx) const
Get the module shared pointer for the module at index idx.
Definition: ModuleList.cpp:429
size_t GetSize() const
Gets the size of the module list.
Definition: ModuleList.cpp:638
bool ProcessIDIsValid() const
Definition: ProcessInfo.h:72
lldb::pid_t GetProcessID() const
Definition: ProcessInfo.h:68
A Progress indicator helper class.
Definition: Progress.h:60
void Increment(uint64_t amount=1, std::optional< std::string > updated_detail={})
Increment the progress and send a notification to the installed callback.
Definition: Progress.cpp:68
uint64_t GetSP(uint64_t fail_value=LLDB_INVALID_ADDRESS)
const RegisterInfo * GetRegisterInfoByName(llvm::StringRef reg_name, uint32_t start_idx=0)
virtual bool ReadRegister(const RegisterInfo *reg_info, RegisterValue &reg_value)=0
uint16_t GetAsUInt16(uint16_t fail_value=UINT16_MAX, bool *success_ptr=nullptr) const
uint32_t GetAsMemoryData(const RegisterInfo &reg_info, void *dst, uint32_t dst_len, lldb::ByteOrder dst_byte_order, Status &error) const
uint64_t GetAsUInt64(uint64_t fail_value=UINT64_MAX, bool *success_ptr=nullptr) const
uint32_t GetAsUInt32(uint32_t fail_value=UINT32_MAX, bool *success_ptr=nullptr) const
An error handling class.
Definition: Status.h:115
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition: Status.cpp:106
static Status FromErrorString(const char *str)
Definition: Status.h:138
bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr, uint32_t stop_id=SectionLoadHistory::eStopIDNow)
Definition: Target.cpp:3219
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition: Target.h:997
const ArchSpec & GetArchitecture() const
Definition: Target.h:1039
uint8_t * GetBytes()
Get a pointer to the data.
Definition: DataBuffer.h:108
#define UINT32_MAX
Definition: lldb-defines.h:19
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:332
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::Thread > ThreadSP
Definition: lldb-forward.h:450
uint64_t offset_t
Definition: lldb-types.h:85
uint64_t pid_t
Definition: lldb-types.h:83
@ eByteOrderLittle
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
Definition: lldb-forward.h:431
std::shared_ptr< lldb_private::Section > SectionSP
Definition: lldb-forward.h:418
uint64_t addr_t
Definition: lldb-types.h:80
StopReason
Thread stop reasons.
@ eStopReasonInvalid
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
Definition: lldb-forward.h:394
std::shared_ptr< lldb_private::Module > ModuleSP
Definition: lldb-forward.h:373
BaseType GetRangeEnd() const
Definition: RangeMap.h:78
Every register is described in detail including its name, alternate name (optional),...
llvm::support::ulittle32_t process_id
Definition: MinidumpTypes.h:73
llvm::support::ulittle32_t flags1
Definition: MinidumpTypes.h:72
llvm::support::ulittle32_t size
Definition: MinidumpTypes.h:70