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 <cstddef>
45#include <cstdint>
46#include <utility>
47
48using namespace lldb;
49using namespace lldb_private;
50using namespace llvm::minidump;
51
53 // First set the offset on the file, and on the bytes saved
55 // We know we will have at least Misc, SystemInfo, Modules, and ThreadList
56 // (corresponding memory list for stacks), an additional memory list for
57 // non-stacks, and a stream to mark this minidump was generated by LLDB.
58 lldb_private::Target &target = m_process_sp->GetTarget();
60 // Check if OS is linux and reserve directory space for all linux specific
61 // breakpad extension directories.
62 if (target.GetArchitecture().GetTriple().getOS() ==
63 llvm::Triple::OSType::Linux)
65
66 // Go through all of the threads and check for exceptions.
67 std::vector<lldb::ThreadSP> threads =
68 m_process_sp->CalculateCoreFileThreadList(m_save_core_options);
69 for (const ThreadSP &thread_sp : threads) {
70 StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
71 if (stop_info_sp) {
72 const StopReason &stop_reason = stop_info_sp->GetStopReason();
73 if (stop_reason != lldb::eStopReasonInvalid)
75 }
76 }
77
78 // Add a generous buffer of directories, these are quite small
79 // and forks may add new directories upstream LLDB hadn't accounted for
80 // when we started pre-calculating directory size, so this should account for
81 // that
83
85 m_expected_directories * sizeof(llvm::minidump::Directory);
87 offset_t new_offset = m_core_file->SeekFromStart(m_saved_data_size);
88 if (new_offset != m_saved_data_size)
90 "Failed to fill in header and directory "
91 "sections. Written / Expected (%" PRIx64 " / %" PRIx64 ")",
92 new_offset, m_saved_data_size);
93
94 if (error.Fail())
95 return error;
96
98}
99
101 uint64_t stream_size) {
102 // We explicitly cast type, an 32b enum, to uint32_t to avoid warnings.
106 "Unable to add directory for stream type "
107 "%x, offset is greater then 32 bit limit.",
108 (uint32_t)type);
109 return error;
110 }
111
112 if (m_directories.size() + 1 > m_expected_directories) {
114 "Unable to add directory for stream type %x, exceeded expected number "
115 "of directories %zu.",
116 (uint32_t)type, m_expected_directories);
117 return error;
118 }
119
120 LocationDescriptor loc;
121 loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size);
122 // Stream will begin at the current end of data section
123 loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
124
125 Directory dir;
126 dir.Type = static_cast<llvm::support::little_t<StreamType>>(type);
127 dir.Location = loc;
128
129 m_directories.push_back(dir);
130 return error;
131}
132
135 StreamType type = StreamType::LLDBGenerated;
136 return AddDirectory(type, 0);
137}
138
141 const llvm::Triple &target_triple =
142 m_process_sp->GetTarget().GetArchitecture().GetTriple();
143 error =
144 AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
145 if (error.Fail())
146 return error;
147
148 llvm::minidump::ProcessorArchitecture arch;
149 switch (target_triple.getArch()) {
150 case llvm::Triple::ArchType::x86_64:
151 arch = ProcessorArchitecture::AMD64;
152 break;
153 case llvm::Triple::ArchType::x86:
154 arch = ProcessorArchitecture::X86;
155 break;
156 case llvm::Triple::ArchType::arm:
157 arch = ProcessorArchitecture::ARM;
158 break;
159 case llvm::Triple::ArchType::aarch64:
160 arch = ProcessorArchitecture::ARM64;
161 break;
162 case llvm::Triple::ArchType::mips64:
163 case llvm::Triple::ArchType::mips64el:
164 case llvm::Triple::ArchType::mips:
165 case llvm::Triple::ArchType::mipsel:
166 arch = ProcessorArchitecture::MIPS;
167 break;
168 case llvm::Triple::ArchType::ppc64:
169 case llvm::Triple::ArchType::ppc:
170 case llvm::Triple::ArchType::ppc64le:
171 arch = ProcessorArchitecture::PPC;
172 break;
173 default:
175 "Architecture %s not supported.",
176 target_triple.getArchName().str().c_str());
177 return error;
178 };
179
180 llvm::support::little_t<OSPlatform> platform_id;
181 switch (target_triple.getOS()) {
182 case llvm::Triple::OSType::Linux:
183 if (target_triple.getEnvironment() ==
184 llvm::Triple::EnvironmentType::Android)
185 platform_id = OSPlatform::Android;
186 else
187 platform_id = OSPlatform::Linux;
188 break;
189 case llvm::Triple::OSType::Win32:
190 platform_id = OSPlatform::Win32NT;
191 break;
192 case llvm::Triple::OSType::MacOSX:
193 platform_id = OSPlatform::MacOSX;
194 break;
195 case llvm::Triple::OSType::IOS:
196 platform_id = OSPlatform::IOS;
197 break;
198 default:
200 "OS %s not supported.", target_triple.getOSName().str().c_str());
201 return error;
202 };
203
204 llvm::minidump::SystemInfo sys_info{};
205 sys_info.ProcessorArch =
206 static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch);
207 // Global offset to beginning of a csd_string in a data section
208 sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>(
209 GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo));
210 sys_info.PlatformId = platform_id;
211 m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo));
212
213 std::string csd_string;
214
215 error = WriteString(csd_string, &m_data);
216 if (error.Fail()) {
217 error =
218 Status::FromErrorString("Unable to convert the csd string to UTF16.");
219 return error;
220 }
221
222 return error;
223}
224
225Status WriteString(const std::string &to_write,
228 // let the StringRef eat also null termination char
229 llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1);
230 llvm::SmallVector<llvm::UTF16, 128> to_write_utf16;
231
232 bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16);
233 if (!converted) {
235 "Unable to convert the string to UTF16. Failed to convert %s",
236 to_write.c_str());
237 return error;
238 }
239
240 // size of the UTF16 string should be written without the null termination
241 // character that is stored in 2 bytes
242 llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2);
243
244 buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t));
245 buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes());
246
247 return error;
248}
249
250llvm::Expected<uint64_t> getModuleFileSize(Target &target,
251 const ModuleSP &mod) {
252 // JIT module has the same vm and file size.
253 uint64_t SizeOfImage = 0;
254 if (mod->GetObjectFile()->CalculateType() == ObjectFile::Type::eTypeJIT) {
255 for (const auto &section : *mod->GetObjectFile()->GetSectionList()) {
256 SizeOfImage += section->GetByteSize();
257 }
258 return SizeOfImage;
259 }
260 SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
261
262 if (!sect_sp) {
263 return llvm::createStringError(std::errc::operation_not_supported,
264 "Couldn't obtain the section information.");
265 }
266 lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target);
267 // Use memory size since zero fill sections, like ".bss", will be smaller on
268 // disk.
269 lldb::addr_t sect_size = sect_sp->GetByteSize();
270 // This will usually be zero, but make sure to calculate the BaseOfImage
271 // offset.
272 const lldb::addr_t base_sect_offset =
273 mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) -
274 sect_addr;
275 SizeOfImage = sect_size - base_sect_offset;
276 lldb::addr_t next_sect_addr = sect_addr + sect_size;
277 Address sect_so_addr;
278 target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
279 lldb::SectionSP next_sect_sp = sect_so_addr.GetSection();
280 while (next_sect_sp &&
281 next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) {
282 sect_size = sect_sp->GetByteSize();
283 SizeOfImage += sect_size;
284 next_sect_addr += sect_size;
285 target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
286 next_sect_sp = sect_so_addr.GetSection();
287 }
288
289 return SizeOfImage;
290}
291
292// ModuleList stream consists of a number of modules, followed by an array
293// of llvm::minidump::Module's structures. Every structure informs about a
294// single module. Additional data of variable length, such as module's names,
295// are stored just after the ModuleList stream. The llvm::minidump::Module
296// structures point to this helper data by global offset.
298 constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module);
300
301 lldb_private::Target &target = m_process_sp->GetTarget();
302 const ModuleList &modules = target.GetImages();
303 llvm::support::ulittle32_t modules_count =
304 static_cast<llvm::support::ulittle32_t>(modules.GetSize());
305
306 // This helps us with getting the correct global offset in minidump
307 // file later, when we will be setting up offsets from the
308 // the llvm::minidump::Module's structures into helper data
309 size_t size_before = GetCurrentDataEndOffset();
310
311 // Temporary storage for the helper data (of variable length)
312 // as these cannot be dumped to m_data before dumping entire
313 // array of module structures.
314 DataBufferHeap helper_data;
315
316 // Vector to store modules that pass validation.
317 std::vector<std::pair<ModuleSP, uint64_t>> valid_modules;
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 Log *log = GetLog(LLDBLog::Object);
326 llvm::handleAllErrors(
327 std::move(mod_size_err), [&](const llvm::ErrorInfoBase &E) {
328 LLDB_LOGF(log, "Unable to get the size of module %s: %s",
329 module_name.c_str(), E.message().c_str());
330 });
331 continue;
332 }
333 valid_modules.emplace_back(mod, *maybe_mod_size);
334 }
335
336 size_t module_stream_size = sizeof(llvm::support::ulittle32_t) +
337 valid_modules.size() * minidump_module_size;
338
339 error = AddDirectory(StreamType::ModuleList, module_stream_size);
340 if (error.Fail())
341 return error;
342
343 // Setting the header with the number of modules.
344 llvm::support::ulittle32_t count =
345 static_cast<llvm::support::ulittle32_t>(valid_modules.size());
346 m_data.AppendData(&count, sizeof(llvm::support::ulittle32_t));
347
348 for (const auto &valid_module : valid_modules) {
349 ModuleSP mod = valid_module.first;
350 uint64_t module_size = valid_module.second;
351 std::string module_name = mod->GetSpecificationDescription();
352
353 llvm::support::ulittle32_t signature =
354 static_cast<llvm::support::ulittle32_t>(
355 static_cast<uint32_t>(minidump::CvSignature::ElfBuildId));
356 auto uuid = mod->GetUUID().GetBytes();
357
358 VSFixedFileInfo info;
359 info.Signature = static_cast<llvm::support::ulittle32_t>(0u);
360 info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u);
361 info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
362 info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
363 info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
364 info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
365 info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u);
366 info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u);
367 info.FileOS = static_cast<llvm::support::ulittle32_t>(0u);
368 info.FileType = static_cast<llvm::support::ulittle32_t>(0u);
369 info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u);
370 info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u);
371 info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u);
372
373 LocationDescriptor ld;
374 ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u);
375 ld.RVA = static_cast<llvm::support::ulittle32_t>(0u);
376
377 // Setting up LocationDescriptor for uuid string. The global offset into
378 // minidump file is calculated.
379 LocationDescriptor ld_cv;
380 ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>(
381 sizeof(llvm::support::ulittle32_t) + uuid.size());
382 ld_cv.RVA = static_cast<llvm::support::ulittle32_t>(
383 size_before + module_stream_size + helper_data.GetByteSize());
384
385 helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t));
386 helper_data.AppendData(uuid.begin(), uuid.size());
387
388 llvm::minidump::Module m{};
389 m.BaseOfImage = static_cast<llvm::support::ulittle64_t>(
390 mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target));
391 m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(module_size);
392 m.Checksum = static_cast<llvm::support::ulittle32_t>(0);
393 m.TimeDateStamp =
394 static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
395 m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>(
396 size_before + module_stream_size + helper_data.GetByteSize());
397 m.VersionInfo = info;
398 m.CvRecord = ld_cv;
399 m.MiscRecord = ld;
400
401 error = WriteString(module_name, &helper_data);
402
403 if (error.Fail())
404 return error;
405
406 m_data.AppendData(&m, sizeof(llvm::minidump::Module));
407 }
408
409 m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
410 return error;
411}
412
414 llvm::StringRef reg_name) {
415 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
416 if (!reg_info)
417 return 0;
419 bool success = reg_ctx->ReadRegister(reg_info, reg_value);
420 if (!success)
421 return 0;
422 return reg_value.GetAsUInt16();
423}
424
426 llvm::StringRef reg_name) {
427 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
428 if (!reg_info)
429 return 0;
431 bool success = reg_ctx->ReadRegister(reg_info, reg_value);
432 if (!success)
433 return 0;
434 return reg_value.GetAsUInt32();
435}
436
438 llvm::StringRef reg_name) {
439 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
440 if (!reg_info)
441 return 0;
443 bool success = reg_ctx->ReadRegister(reg_info, reg_value);
444 if (!success)
445 return 0;
446 return reg_value.GetAsUInt64();
447}
448
449llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx,
450 llvm::StringRef reg_name) {
451 return static_cast<llvm::support::ulittle16_t>(
452 read_register_u16_raw(reg_ctx, reg_name));
453}
454
455llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx,
456 llvm::StringRef reg_name) {
457 return static_cast<llvm::support::ulittle32_t>(
458 read_register_u32_raw(reg_ctx, reg_name));
459}
460
461llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,
462 llvm::StringRef reg_name) {
463 return static_cast<llvm::support::ulittle64_t>(
464 read_register_u64_raw(reg_ctx, reg_name));
465}
466
467void read_register_u128(RegisterContext *reg_ctx, llvm::StringRef reg_name,
468 uint8_t *dst) {
469 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
470 if (reg_info) {
472 if (reg_ctx->ReadRegister(reg_info, reg_value)) {
474 uint32_t bytes_copied = reg_value.GetAsMemoryData(
475 *reg_info, dst, 16, lldb::ByteOrder::eByteOrderLittle, error);
476 if (bytes_copied == 16)
477 return;
478 }
479 }
480 // If anything goes wrong, then zero out the register value.
481 memset(dst, 0, 16);
482}
483
487 thread_context.p1_home = {};
488 thread_context.context_flags = static_cast<uint32_t>(
494 thread_context.rax = read_register_u64(reg_ctx, "rax");
495 thread_context.rbx = read_register_u64(reg_ctx, "rbx");
496 thread_context.rcx = read_register_u64(reg_ctx, "rcx");
497 thread_context.rdx = read_register_u64(reg_ctx, "rdx");
498 thread_context.rdi = read_register_u64(reg_ctx, "rdi");
499 thread_context.rsi = read_register_u64(reg_ctx, "rsi");
500 thread_context.rbp = read_register_u64(reg_ctx, "rbp");
501 thread_context.rsp = read_register_u64(reg_ctx, "rsp");
502 thread_context.r8 = read_register_u64(reg_ctx, "r8");
503 thread_context.r9 = read_register_u64(reg_ctx, "r9");
504 thread_context.r10 = read_register_u64(reg_ctx, "r10");
505 thread_context.r11 = read_register_u64(reg_ctx, "r11");
506 thread_context.r12 = read_register_u64(reg_ctx, "r12");
507 thread_context.r13 = read_register_u64(reg_ctx, "r13");
508 thread_context.r14 = read_register_u64(reg_ctx, "r14");
509 thread_context.r15 = read_register_u64(reg_ctx, "r15");
510 thread_context.rip = read_register_u64(reg_ctx, "rip");
511 // To make our code agnostic to whatever type the register value identifies
512 // itself as, we read as a u64 and truncate to u32/u16 ourselves.
513 thread_context.eflags = read_register_u64(reg_ctx, "rflags");
514 thread_context.cs = read_register_u64(reg_ctx, "cs");
515 thread_context.fs = read_register_u64(reg_ctx, "fs");
516 thread_context.gs = read_register_u64(reg_ctx, "gs");
517 thread_context.ss = read_register_u64(reg_ctx, "ss");
518 thread_context.ds = read_register_u64(reg_ctx, "ds");
519 thread_context.fs_base = read_register_u64(reg_ctx, "fs_base");
520 thread_context.gs_base = read_register_u64(reg_ctx, "gs_base");
521 return thread_context;
522}
523
527 thread_context.context_flags = static_cast<uint32_t>(
531 char reg_name[16];
532 for (uint32_t i = 0; i < 31; ++i) {
533 snprintf(reg_name, sizeof(reg_name), "x%u", i);
534 thread_context.x[i] = read_register_u64(reg_ctx, reg_name);
535 }
536 // Work around a bug in debugserver where "sp" on arm64 doesn't have the alt
537 // name set to "x31"
538 thread_context.x[31] = read_register_u64(reg_ctx, "sp");
539 thread_context.pc = read_register_u64(reg_ctx, "pc");
540 thread_context.cpsr = read_register_u32(reg_ctx, "cpsr");
541 thread_context.fpsr = read_register_u32(reg_ctx, "fpsr");
542 thread_context.fpcr = read_register_u32(reg_ctx, "fpcr");
543 for (uint32_t i = 0; i < 32; ++i) {
544 snprintf(reg_name, sizeof(reg_name), "v%u", i);
545 read_register_u128(reg_ctx, reg_name, &thread_context.v[i * 16]);
546 }
547 return thread_context;
548}
549
551 llvm::Triple::ArchType m_arch;
552 union {
555 };
556
557public:
558 ArchThreadContexts(llvm::Triple::ArchType arch) : m_arch(arch) {}
559
561 switch (m_arch) {
562 case llvm::Triple::ArchType::x86_64:
564 return true;
565 case llvm::Triple::ArchType::aarch64:
566 arm64 = GetThreadContext_ARM64(reg_ctx);
567 return true;
568 default:
569 break;
570 }
571 return false;
572 }
573
574 const void *data() const { return &x86_64; }
575
576 size_t size() const {
577 switch (m_arch) {
578 case llvm::Triple::ArchType::x86_64:
579 return sizeof(x86_64);
580 case llvm::Triple::ArchType::aarch64:
581 return sizeof(arm64);
582 default:
583 break;
584 }
585 return 0;
586 }
587};
588
591 // If we have anything in the heap flush it.
593 m_core_file->SeekFromStart(m_thread_list_start);
594 for (auto &pair : m_thread_by_range_end) {
595 // The thread objects will get a new memory descriptor added
596 // When we are emitting the memory list and then we write it here
597 const llvm::minidump::Thread &thread = pair.second;
598 size_t bytes_to_write = sizeof(llvm::minidump::Thread);
599 size_t bytes_written = bytes_to_write;
600 error = m_core_file->Write(&thread, bytes_written);
601 if (error.Fail() || bytes_to_write != bytes_written) {
603 "Wrote incorrect number of bytes to minidump file. (written %zd/%zd)",
604 bytes_written, bytes_to_write);
605 return error;
606 }
607 }
608
609 return error;
610}
611
613 constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
614 std::vector<ThreadSP> thread_list =
615 m_process_sp->CalculateCoreFileThreadList(m_save_core_options);
616
617 // size of the entire thread stream consists of:
618 // number of threads and threads array
619 size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) +
620 thread_list.size() * minidump_thread_size;
621 // save for the ability to set up RVA
622 size_t size_before = GetCurrentDataEndOffset();
624 error = AddDirectory(StreamType::ThreadList, thread_stream_size);
625 if (error.Fail())
626 return error;
627
628 llvm::support::ulittle32_t thread_count =
629 static_cast<llvm::support::ulittle32_t>(thread_list.size());
630 m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));
631
632 // Take the offset after the thread count.
634 DataBufferHeap helper_data;
635
636 Log *log = GetLog(LLDBLog::Object);
637 for (const ThreadSP &thread_sp : thread_list) {
638 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
639
640 if (!reg_ctx_sp) {
641 error = Status::FromErrorString("Unable to get the register context.");
642 return error;
643 }
644 RegisterContext *reg_ctx = reg_ctx_sp.get();
645 Target &target = m_process_sp->GetTarget();
646 const ArchSpec &arch = target.GetArchitecture();
647 ArchThreadContexts thread_context(arch.GetMachine());
648 if (!thread_context.prepareRegisterContext(reg_ctx)) {
650 "architecture %s not supported.",
651 arch.GetTriple().getArchName().str().c_str());
652 return error;
653 }
654
655 uint64_t sp = reg_ctx->GetSP();
656 MemoryRegionInfo sp_region;
657 m_process_sp->GetMemoryRegionInfo(sp, sp_region);
658
659 // Emit a blank descriptor
660 MemoryDescriptor stack;
661 LocationDescriptor empty_label;
662 empty_label.DataSize = 0;
663 empty_label.RVA = 0;
664 stack.Memory = empty_label;
665 stack.StartOfMemoryRange = 0;
666 LocationDescriptor thread_context_memory_locator;
667 thread_context_memory_locator.DataSize =
668 static_cast<llvm::support::ulittle32_t>(thread_context.size());
669 thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
670 size_before + thread_stream_size + helper_data.GetByteSize());
671 // Cache thie thread context memory so we can reuse for exceptions.
672 m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator;
673
674 LLDB_LOGF(log, "AddThreadList for thread %d: thread_context %zu bytes",
675 thread_sp->GetIndexID(), thread_context.size());
676 helper_data.AppendData(thread_context.data(), thread_context.size());
677
678 llvm::minidump::Thread t;
679 t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
680 t.SuspendCount = static_cast<llvm::support::ulittle32_t>(
681 (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0);
682 t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0);
683 t.Priority = static_cast<llvm::support::ulittle32_t>(0);
684 t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);
685 t.Stack = stack, t.Context = thread_context_memory_locator;
686
687 // We save off the stack object so we can circle back and clean it up.
688 m_thread_by_range_end[sp_region.GetRange().GetRangeEnd()] = t;
689 m_data.AppendData(&t, sizeof(llvm::minidump::Thread));
690 }
691
692 LLDB_LOGF(log, "AddThreadList(): total helper_data %" PRIx64 " bytes",
693 helper_data.GetByteSize());
694 m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
695 return Status();
696}
697
699 std::vector<ThreadSP> thread_list =
700 m_process_sp->CalculateCoreFileThreadList(m_save_core_options);
702 for (const ThreadSP &thread_sp : thread_list) {
703 StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
704 // If we don't have a stop info, or if it's invalid, skip.
705 if (!stop_info_sp ||
706 stop_info_sp->GetStopReason() == lldb::eStopReasonInvalid)
707 continue;
708
709 constexpr size_t minidump_exception_size =
710 sizeof(llvm::minidump::ExceptionStream);
711 error = AddDirectory(StreamType::Exception, minidump_exception_size);
712 if (error.Fail())
713 return error;
714
715 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
716 Exception exp_record = {};
717 exp_record.ExceptionCode =
718 static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
719 exp_record.ExceptionFlags =
720 static_cast<llvm::support::ulittle32_t>(Exception::LLDB_FLAG);
721 exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);
722 exp_record.ExceptionAddress = reg_ctx_sp->GetPC();
723 exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(1);
724 std::string description = stop_info_sp->GetDescription();
725 // We have 120 bytes to work with and it's unlikely description will
726 // overflow, but we gotta check.
727 memcpy(&exp_record.ExceptionInformation, description.c_str(),
728 std::min(description.size(), Exception::MaxParameterBytes));
729 exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
730 ExceptionStream exp_stream;
731 exp_stream.ThreadId =
732 static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
733 exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
734 exp_stream.ExceptionRecord = exp_record;
735 auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID());
736 if (Iter != m_tid_to_reg_ctx.end()) {
737 exp_stream.ThreadContext = Iter->second;
738 } else {
739 exp_stream.ThreadContext.DataSize = 0;
740 exp_stream.ThreadContext.RVA = 0;
741 }
742 m_data.AppendData(&exp_stream, minidump_exception_size);
743 }
744
745 return error;
746}
747
750 error = AddDirectory(StreamType::MiscInfo,
752 if (error.Fail())
753 return error;
754
756 misc_info.size = static_cast<llvm::support::ulittle32_t>(
758 // Default set flags1 to 0, in case that we will not be able to
759 // get any information
760 misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);
761
763 m_process_sp->GetProcessInfo(process_info);
764 if (process_info.ProcessIDIsValid()) {
765 // Set flags1 to reflect that PID is filled in
766 misc_info.flags1 =
767 static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>(
769 misc_info.process_id =
770 static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID());
771 }
772
773 m_data.AppendData(&misc_info,
775 return error;
776}
777
778std::unique_ptr<llvm::MemoryBuffer>
779getFileStreamHelper(const std::string &path) {
780 auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);
781 if (!maybe_stream)
782 return nullptr;
783 return std::move(maybe_stream.get());
784}
785
788 // No-op if we are not on linux.
789 if (m_process_sp->GetTarget().GetArchitecture().GetTriple().getOS() !=
790 llvm::Triple::Linux)
791 return error;
792
793 std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
794 {StreamType::LinuxCPUInfo, "/proc/cpuinfo"},
795 {StreamType::LinuxLSBRelease, "/etc/lsb-release"},
796 };
797
799 m_process_sp->GetProcessInfo(process_info);
800 if (process_info.ProcessIDIsValid()) {
801 lldb::pid_t pid = process_info.GetProcessID();
802 std::string pid_str = std::to_string(pid);
803 files_with_stream_types.push_back(
804 {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"});
805 files_with_stream_types.push_back(
806 {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"});
807 files_with_stream_types.push_back(
808 {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"});
809 files_with_stream_types.push_back(
810 {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"});
811 files_with_stream_types.push_back(
812 {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"});
813 files_with_stream_types.push_back(
814 {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"});
815 files_with_stream_types.push_back(
816 {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"});
817 }
818
819 for (const auto &entry : files_with_stream_types) {
820 StreamType stream = entry.first;
821 std::string path = entry.second;
822 auto memory_buffer = getFileStreamHelper(path);
823
824 if (memory_buffer) {
825 size_t size = memory_buffer->getBufferSize();
826 if (size == 0)
827 continue;
828 error = AddDirectory(stream, size);
829 if (error.Fail())
830 return error;
831 m_data.AppendData(memory_buffer->getBufferStart(), size);
832 }
833 }
834
835 return error;
836}
837
840
841 // We first save the thread stacks to ensure they fit in the first UINT32_MAX
842 // bytes of the core file. Thread structures in minidump files can only use
843 // 32 bit memory descriptiors, so we emit them first to ensure the memory is
844 // in accessible with a 32 bit offset.
845 std::vector<CoreFileMemoryRange> ranges_32;
846 llvm::Expected<CoreFileMemoryRanges> all_core_memory_ranges_maybe =
847 m_save_core_options.GetMemoryRegionsToSave();
848 if (!all_core_memory_ranges_maybe)
849 return Status::FromError(all_core_memory_ranges_maybe.takeError());
850
851 const CoreFileMemoryRanges &all_core_memory_ranges =
852 *all_core_memory_ranges_maybe;
853
854 lldb_private::Progress progress("Saving Minidump File", "",
855 all_core_memory_ranges.GetSize());
856 std::vector<CoreFileMemoryRange> all_core_memory_vec;
857 // Extract all the data into just a vector of data. So we can mutate this in
858 // place.
859 for (const auto &core_range : all_core_memory_ranges)
860 all_core_memory_vec.push_back(core_range.data);
861
862 // Start by saving all of the stacks and ensuring they fit under the 32b
863 // limit.
864 uint64_t total_size = GetCurrentDataEndOffset();
865 auto iterator = all_core_memory_vec.begin();
866 while (iterator != all_core_memory_vec.end()) {
867 if (m_thread_by_range_end.count(iterator->range.end()) > 0) {
868 // We don't save stacks twice.
869 ranges_32.push_back(*iterator);
870 total_size +=
871 iterator->range.size() + sizeof(llvm::minidump::MemoryDescriptor);
872 iterator = all_core_memory_vec.erase(iterator);
873 } else {
874 iterator++;
875 }
876 }
877
878 // The header has to be in 32b memory, as it needs to be addressable by a 32b
879 // RVA. Everything else can be 64b.
880 total_size += sizeof(llvm::minidump::MemoryListHeader);
881
882 if (total_size >= UINT32_MAX) {
884 "Unable to write minidump. Stack memory "
885 "exceeds 32b limit. (Num Stacks %zu)",
886 ranges_32.size());
887 return error;
888 }
889
890 // Save only the thread stacks to the 32b memory list. Everything else will
891 // get put in Memory64, this simplifies tracking
892 error = AddMemoryList_32(ranges_32, progress);
893 if (error.Fail())
894 return error;
895
896 // Add the remaining memory as a 64b range.
897 if (!all_core_memory_ranges.IsEmpty()) {
898 error = AddMemoryList_64(all_core_memory_vec, progress);
899 if (error.Fail())
900 return error;
901 }
902
903 return FixThreadStacks();
904}
905
907 // write header
908 llvm::minidump::Header header;
909 header.Signature = static_cast<llvm::support::ulittle32_t>(
910 llvm::minidump::Header::MagicSignature);
911 header.Version = static_cast<llvm::support::ulittle32_t>(
912 llvm::minidump::Header::MagicVersion);
913 header.NumberOfStreams =
914 static_cast<llvm::support::ulittle32_t>(m_directories.size());
915 // We write the directories right after the header.
916 header.StreamDirectoryRVA =
917 static_cast<llvm::support::ulittle32_t>(HEADER_SIZE);
918 header.Checksum = static_cast<llvm::support::ulittle32_t>(
919 0u); // not used in most of the writers
920 header.TimeDateStamp =
921 static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
922 header.Flags =
923 static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag
924
926 size_t bytes_written;
927
928 m_core_file->SeekFromStart(0);
929 bytes_written = HEADER_SIZE;
930 error = m_core_file->Write(&header, bytes_written);
931 if (error.Fail() || bytes_written != HEADER_SIZE) {
932 if (bytes_written != HEADER_SIZE)
934 "Unable to write the minidump header (written %zd/%zd)",
935 bytes_written, HEADER_SIZE);
936 return error;
937 }
938 return error;
939}
940
944
947 size_t bytes_written;
948 m_core_file->SeekFromStart(HEADER_SIZE);
949 for (const Directory &dir : m_directories) {
950 bytes_written = DIRECTORY_SIZE;
951 error = m_core_file->Write(&dir, bytes_written);
952 if (error.Fail() || bytes_written != DIRECTORY_SIZE) {
953 if (bytes_written != DIRECTORY_SIZE)
955 "unable to write the directory (written %zd/%zd)", bytes_written,
957 return error;
958 }
959 }
960
961 return error;
962}
963
965 lldb_private::DataBufferHeap &data_buffer,
966 const lldb_private::CoreFileMemoryRange &range, uint64_t &bytes_read) {
967
968 const lldb::addr_t addr = range.range.start();
969 const lldb::addr_t size = range.range.size();
970 Log *log = GetLog(LLDBLog::Object);
971 uint64_t total_bytes_read = 0;
972 Status addDataError;
974 [&](Status &error, lldb::addr_t current_addr, const void *buf,
975 uint64_t bytes_read) -> lldb_private::IterationAction {
976 if (error.Fail() || bytes_read == 0) {
977 LLDB_LOGF(log,
978 "Failed to read memory region at: 0x%" PRIx64
979 ". Bytes read: 0x%" PRIx64 ", error: %s",
980 current_addr, bytes_read, error.AsCString());
981
982 // If we failed in a memory read, we would normally want to skip
983 // this entire region. If we had already written to the minidump
984 // file, we can't easily rewind that state.
985 //
986 // So if we do encounter an error while reading, we return
987 // immediately, any prior bytes read will still be included but
988 // any bytes partially read before the error are ignored.
990 }
991
992 if (current_addr != addr + total_bytes_read) {
993 LLDB_LOGF(log,
994 "Current addr is at unexpected address, 0x%" PRIx64
995 ", expected at 0x%" PRIx64,
996 current_addr, addr + total_bytes_read);
997
998 // Something went wrong and the address is not where it should be
999 // we'll error out of this Minidump generation.
1000 addDataError = Status::FromErrorStringWithFormat(
1001 "Unexpected address encounterd when reading memory in chunks "
1002 "0x%" PRIx64 " expected 0x%" PRIx64,
1003 current_addr, addr + total_bytes_read);
1005 }
1006
1007 // Write to the minidump file with the chunk potentially flushing to
1008 // disk.
1009 // This error will be captured by the outer scope and is considered fatal.
1010 // If we get an error writing to disk we can't easily guarauntee that we
1011 // won't corrupt the minidump.
1012 addDataError = AddData(buf, bytes_read);
1013 if (addDataError.Fail())
1015
1016 total_bytes_read += bytes_read;
1017 // If we have a partial read, report it, but only if the partial read
1018 // didn't finish reading the entire region.
1019 if (bytes_read != data_buffer.GetByteSize() && total_bytes_read != size) {
1020 LLDB_LOGF(log,
1021 "Memory region at: 0x%" PRIx64 " partial read 0x%" PRIx64
1022 " bytes out of 0x%" PRIx64 " bytes.",
1023 current_addr, bytes_read,
1024 data_buffer.GetByteSize() - bytes_read);
1025
1026 // If we've read some bytes, we stop trying to read more and return
1027 // this best effort attempt
1029 }
1030
1031 // No problems, keep going!
1033 };
1034
1035 bytes_read = m_process_sp->ReadMemoryInChunks(
1036 addr, data_buffer.GetBytes(), data_buffer.GetByteSize(), size, callback);
1037 return addDataError;
1038}
1039
1040static uint64_t
1041GetLargestRangeSize(const std::vector<CoreFileMemoryRange> &ranges) {
1042 uint64_t max_size = 0;
1043 for (const auto &core_range : ranges)
1044 max_size = std::max(max_size, core_range.range.size());
1045 return max_size;
1046}
1047
1048Status
1049MinidumpFileBuilder::AddMemoryList_32(std::vector<CoreFileMemoryRange> &ranges,
1050 Progress &progress) {
1051 std::vector<MemoryDescriptor> descriptors;
1052 Status error;
1053 if (ranges.size() == 0)
1054 return error;
1055
1056 Log *log = GetLog(LLDBLog::Object);
1057 size_t region_index = 0;
1058 lldb_private::DataBufferHeap data_buffer(
1059 std::min(GetLargestRangeSize(ranges), MAX_WRITE_CHUNK_SIZE), 0);
1060 for (const auto &core_range : ranges) {
1061 // Take the offset before we write.
1062 const offset_t offset_for_data = GetCurrentDataEndOffset();
1063 const addr_t addr = core_range.range.start();
1064 const addr_t size = core_range.range.size();
1065 const addr_t end = core_range.range.end();
1066
1067 LLDB_LOGF(log,
1068 "AddMemoryList %zu/%zu reading memory for region "
1069 "(0x%" PRIx64 " bytes) [0x%" PRIx64 ", 0x%" PRIx64 ")",
1070 region_index, ranges.size(), size, addr, addr + size);
1071 ++region_index;
1072
1073 progress.Increment(1, "Adding Memory Range " + core_range.Dump());
1074 uint64_t bytes_read = 0;
1075 error = ReadWriteMemoryInChunks(data_buffer, core_range, bytes_read);
1076 if (error.Fail())
1077 return error;
1078
1079 // If we completely failed to read this range
1080 // we can drop the memory range
1081 if (bytes_read == 0)
1082 continue;
1083
1084 MemoryDescriptor descriptor;
1085 descriptor.StartOfMemoryRange =
1086 static_cast<llvm::support::ulittle64_t>(addr);
1087 descriptor.Memory.DataSize =
1088 static_cast<llvm::support::ulittle32_t>(bytes_read);
1089 descriptor.Memory.RVA =
1090 static_cast<llvm::support::ulittle32_t>(offset_for_data);
1091 descriptors.push_back(descriptor);
1092 if (m_thread_by_range_end.count(end) > 0)
1093 m_thread_by_range_end[end].Stack = descriptor;
1094 }
1095
1096 // Add a directory that references this list
1097 // With a size of the number of ranges as a 32 bit num
1098 // And then the size of all the ranges
1099 error = AddDirectory(StreamType::MemoryList,
1100 sizeof(llvm::minidump::MemoryListHeader) +
1101 descriptors.size() *
1102 sizeof(llvm::minidump::MemoryDescriptor));
1103 if (error.Fail())
1104 return error;
1105
1106 llvm::minidump::MemoryListHeader list_header;
1107 llvm::support::ulittle32_t memory_ranges_num =
1108 static_cast<llvm::support::ulittle32_t>(descriptors.size());
1109 list_header.NumberOfMemoryRanges = memory_ranges_num;
1110 m_data.AppendData(&list_header, sizeof(llvm::minidump::MemoryListHeader));
1111 // For 32b we can get away with writing off the descriptors after the data.
1112 // This means no cleanup loop needed.
1113 m_data.AppendData(descriptors.data(),
1114 descriptors.size() * sizeof(MemoryDescriptor));
1115
1116 return error;
1117}
1118
1119Status
1120MinidumpFileBuilder::AddMemoryList_64(std::vector<CoreFileMemoryRange> &ranges,
1121 Progress &progress) {
1122 Status error;
1123 if (ranges.empty())
1124 return error;
1125
1126 error = AddDirectory(StreamType::Memory64List,
1127 (sizeof(llvm::minidump::Memory64ListHeader)) +
1128 ranges.size() *
1129 sizeof(llvm::minidump::MemoryDescriptor_64));
1130 if (error.Fail())
1131 return error;
1132
1133 llvm::minidump::Memory64ListHeader list_header;
1134 llvm::support::ulittle64_t memory_ranges_num =
1135 static_cast<llvm::support::ulittle64_t>(ranges.size());
1136 list_header.NumberOfMemoryRanges = memory_ranges_num;
1137 // Capture the starting offset for all the descriptors so we can clean them up
1138 // if needed.
1139 offset_t starting_offset =
1140 GetCurrentDataEndOffset() + sizeof(llvm::minidump::Memory64ListHeader);
1141 // The base_rva needs to start after the directories, which is right after
1142 // the descriptors + the size of the header.
1143 offset_t base_rva =
1144 starting_offset +
1145 (ranges.size() * sizeof(llvm::minidump::MemoryDescriptor_64));
1146 llvm::support::ulittle64_t memory_ranges_base_rva =
1147 static_cast<llvm::support::ulittle64_t>(base_rva);
1148 list_header.BaseRVA = memory_ranges_base_rva;
1149 m_data.AppendData(&list_header, sizeof(llvm::minidump::Memory64ListHeader));
1150
1151 lldb_private::DataBufferHeap data_buffer(
1152 std::min(GetLargestRangeSize(ranges), MAX_WRITE_CHUNK_SIZE), 0);
1153 bool cleanup_required = false;
1154 std::vector<MemoryDescriptor_64> descriptors;
1155 // Enumerate the ranges and create the memory descriptors so we can append
1156 // them first
1157 for (const auto core_range : ranges) {
1158 // Add the space required to store the memory descriptor
1159 MemoryDescriptor_64 memory_desc;
1160 memory_desc.StartOfMemoryRange =
1161 static_cast<llvm::support::ulittle64_t>(core_range.range.start());
1162 memory_desc.DataSize =
1163 static_cast<llvm::support::ulittle64_t>(core_range.range.size());
1164 descriptors.push_back(memory_desc);
1165 // Now write this memory descriptor to the buffer.
1166 m_data.AppendData(&memory_desc, sizeof(MemoryDescriptor_64));
1167 }
1168
1169 Log *log = GetLog(LLDBLog::Object);
1170 size_t region_index = 0;
1171 for (const auto &core_range : ranges) {
1172 const addr_t addr = core_range.range.start();
1173 const addr_t size = core_range.range.size();
1174
1175 LLDB_LOGF(log,
1176 "AddMemoryList_64 %zu/%zu reading memory for region "
1177 "(%" PRIx64 "bytes) "
1178 "[%" PRIx64 ", %" PRIx64 ")",
1179 region_index, ranges.size(), size, addr, addr + size);
1180
1181 progress.Increment(1, "Adding Memory Range " + core_range.Dump());
1182 uint64_t bytes_read = 0;
1183 error = ReadWriteMemoryInChunks(data_buffer, core_range, bytes_read);
1184 if (error.Fail())
1185 return error;
1186
1187 if (bytes_read == 0) {
1188 cleanup_required = true;
1189 descriptors[region_index].DataSize = 0;
1190 }
1191 if (bytes_read != size) {
1192 cleanup_required = true;
1193 descriptors[region_index].DataSize = bytes_read;
1194 }
1195
1196 ++region_index;
1197 }
1198
1199 // Early return if there is no cleanup needed.
1200 if (!cleanup_required) {
1201 return error;
1202 } else {
1203 // Flush to disk we can make the fixes in place.
1205 // Fixup the descriptors that were not read correctly.
1206 m_core_file->SeekFromStart(starting_offset);
1207 size_t bytes_written = sizeof(MemoryDescriptor_64) * descriptors.size();
1208 error = m_core_file->Write(descriptors.data(), bytes_written);
1209 if (error.Fail() ||
1210 bytes_written != sizeof(MemoryDescriptor_64) * descriptors.size()) {
1212 "unable to write the memory descriptors (written %zd/%zd)",
1213 bytes_written, sizeof(MemoryDescriptor_64) * descriptors.size());
1214 }
1215
1216 return error;
1217 }
1218}
1219
1220Status MinidumpFileBuilder::AddData(const void *data, uint64_t size) {
1221 // Append the data to the buffer, if the buffer spills over, flush it to disk
1222 m_data.AppendData(data, size);
1223 if (m_data.GetByteSize() > MAX_WRITE_CHUNK_SIZE)
1224 return FlushBufferToDisk();
1225
1226 return Status();
1227}
1228
1230 Status error;
1231 // Set the stream to it's end.
1232 m_core_file->SeekFromStart(m_saved_data_size);
1233 addr_t starting_size = m_data.GetByteSize();
1234 addr_t remaining_bytes = starting_size;
1235 offset_t offset = 0;
1236
1237 while (remaining_bytes > 0) {
1238 size_t bytes_written = remaining_bytes;
1239 // We don't care how many bytes we wrote unless we got an error
1240 // so just decrement the remaining bytes.
1241 error = m_core_file->Write(m_data.GetBytes() + offset, bytes_written);
1242 if (error.Fail()) {
1244 "Wrote incorrect number of bytes to minidump file. (written %" PRIx64
1245 "/%" PRIx64 ")",
1246 starting_size - remaining_bytes, starting_size);
1247 return error;
1248 }
1249
1250 offset += bytes_written;
1251 remaining_bytes -= bytes_written;
1252 }
1253
1254 m_saved_data_size += starting_size;
1255 m_data.Clear();
1256 return error;
1257}
1258
1260 Status error;
1261 // If anything is left unsaved, dump it.
1263 if (error.Fail())
1264 return error;
1265
1266 // Overwrite the header which we filled in earlier.
1267 error = DumpHeader();
1268 if (error.Fail())
1269 return error;
1270
1271 // Overwrite the space saved for directories
1273 if (error.Fail())
1274 return error;
1275
1276 return error;
1277}
1278
1280 Log *log = GetLog(LLDBLog::Object);
1281
1282 if (m_core_file) {
1283 Status error = m_core_file->Close();
1284 if (error.Fail())
1285 LLDB_LOGF(log, "Failed to close minidump file: %s", error.AsCString());
1286
1287 m_core_file.reset();
1288 }
1289}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition Log.h:383
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 uint64_t MAX_WRITE_CHUNK_SIZE
static constexpr size_t DIRECTORY_SIZE
lldb_private::DataBufferHeap m_data
lldb_private::Status AddSystemInfo()
lldb_private::Status ReadWriteMemoryInChunks(lldb_private::DataBufferHeap &data_buffer, const lldb_private::CoreFileMemoryRange &range, uint64_t &bytes_read)
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
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:432
An architecture specification class.
Definition ArchSpec.h:32
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition ArchSpec.h:457
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition ArchSpec.cpp:673
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:125
lldb::ModuleSP GetModuleAtIndex(size_t idx) const
Get the module shared pointer for the module at index idx.
size_t GetSize() const
Gets the size of the module list.
@ eTypeJIT
JIT code that has symbols, sections and possibly debug info.
Definition ObjectFile.h:67
bool ProcessIDIsValid() const
Definition ProcessInfo.h:72
lldb::pid_t GetProcessID() const
Definition ProcessInfo.h:68
std::function< IterationAction(lldb_private::Status &error, lldb::addr_t bytes_addr, const void *bytes, lldb::offset_t bytes_size)> ReadMemoryChunkCallback
Definition Process.h:1616
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:62
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 Fail() const
Test for error condition.
Definition Status.cpp:293
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:136
bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr, uint32_t stop_id=SectionLoadHistory::eStopIDNow, bool allow_section_end=false)
Definition Target.cpp:3328
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition Target.h:1140
const ArchSpec & GetArchitecture() const
Definition Target.h:1182
uint8_t * GetBytes()
Get a pointer to the data.
Definition DataBuffer.h:108
#define UINT32_MAX
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
IterationAction
Useful for callbacks whose return type indicates whether to continue iteration or short-circuit.
std::shared_ptr< lldb_private::Thread > ThreadSP
uint64_t offset_t
Definition lldb-types.h:85
@ eStateSuspended
Process or thread is in a suspended state as far as the debugger is concerned while other processes o...
uint64_t pid_t
Definition lldb-types.h:83
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
std::shared_ptr< lldb_private::Section > SectionSP
uint64_t addr_t
Definition lldb-types.h:80
StopReason
Thread stop reasons.
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
std::shared_ptr< lldb_private::Module > ModuleSP
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
llvm::support::ulittle32_t flags1