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