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"
25#include "lldb/Utility/Log.h"
27
28#include "llvm/ADT/StringRef.h"
29#include "llvm/BinaryFormat/Minidump.h"
30#include "llvm/Support/ConvertUTF.h"
31#include "llvm/Support/Error.h"
32
34
35#include <cinttypes>
36
37using namespace lldb;
38using namespace lldb_private;
39using namespace llvm::minidump;
40
41void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) {
42 LocationDescriptor loc;
43 loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size);
44 // Stream will begin at the current end of data section
45 loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
46
47 Directory dir;
48 dir.Type = static_cast<llvm::support::little_t<StreamType>>(type);
49 dir.Location = loc;
50
51 m_directories.push_back(dir);
52}
53
54Status MinidumpFileBuilder::AddSystemInfo(const llvm::Triple &target_triple) {
56 AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
57
58 llvm::minidump::ProcessorArchitecture arch;
59 switch (target_triple.getArch()) {
60 case llvm::Triple::ArchType::x86_64:
61 arch = ProcessorArchitecture::AMD64;
62 break;
63 case llvm::Triple::ArchType::x86:
64 arch = ProcessorArchitecture::X86;
65 break;
66 case llvm::Triple::ArchType::arm:
67 arch = ProcessorArchitecture::ARM;
68 break;
69 case llvm::Triple::ArchType::aarch64:
70 arch = ProcessorArchitecture::ARM64;
71 break;
72 case llvm::Triple::ArchType::mips64:
73 case llvm::Triple::ArchType::mips64el:
74 case llvm::Triple::ArchType::mips:
75 case llvm::Triple::ArchType::mipsel:
76 arch = ProcessorArchitecture::MIPS;
77 break;
78 case llvm::Triple::ArchType::ppc64:
79 case llvm::Triple::ArchType::ppc:
80 case llvm::Triple::ArchType::ppc64le:
81 arch = ProcessorArchitecture::PPC;
82 break;
83 default:
84 error.SetErrorStringWithFormat("Architecture %s not supported.",
85 target_triple.getArchName().str().c_str());
86 return error;
87 };
88
89 llvm::support::little_t<OSPlatform> platform_id;
90 switch (target_triple.getOS()) {
91 case llvm::Triple::OSType::Linux:
92 if (target_triple.getEnvironment() ==
93 llvm::Triple::EnvironmentType::Android)
94 platform_id = OSPlatform::Android;
95 else
96 platform_id = OSPlatform::Linux;
97 break;
98 case llvm::Triple::OSType::Win32:
99 platform_id = OSPlatform::Win32NT;
100 break;
101 case llvm::Triple::OSType::MacOSX:
102 platform_id = OSPlatform::MacOSX;
103 break;
104 case llvm::Triple::OSType::IOS:
105 platform_id = OSPlatform::IOS;
106 break;
107 default:
108 error.SetErrorStringWithFormat("OS %s not supported.",
109 target_triple.getOSName().str().c_str());
110 return error;
111 };
112
113 llvm::minidump::SystemInfo sys_info;
114 sys_info.ProcessorArch =
115 static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch);
116 // Global offset to beginning of a csd_string in a data section
117 sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>(
118 GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo));
119 sys_info.PlatformId = platform_id;
120 m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo));
121
122 std::string csd_string;
123
124 error = WriteString(csd_string, &m_data);
125 if (error.Fail()) {
126 error.SetErrorString("Unable to convert the csd string to UTF16.");
127 return error;
128 }
129
130 return error;
131}
132
133Status WriteString(const std::string &to_write,
136 // let the StringRef eat also null termination char
137 llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1);
138 llvm::SmallVector<llvm::UTF16, 128> to_write_utf16;
139
140 bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16);
141 if (!converted) {
142 error.SetErrorStringWithFormat(
143 "Unable to convert the string to UTF16. Failed to convert %s",
144 to_write.c_str());
145 return error;
146 }
147
148 // size of the UTF16 string should be written without the null termination
149 // character that is stored in 2 bytes
150 llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2);
151
152 buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t));
153 buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes());
154
155 return error;
156}
157
158llvm::Expected<uint64_t> getModuleFileSize(Target &target,
159 const ModuleSP &mod) {
160 // JIT module has the same vm and file size.
161 uint64_t SizeOfImage = 0;
162 if (mod->GetObjectFile()->CalculateType() == ObjectFile::Type::eTypeJIT) {
163 for (const auto &section : *mod->GetObjectFile()->GetSectionList()) {
164 SizeOfImage += section->GetByteSize();
165 }
166 return SizeOfImage;
167 }
168
169 SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
170
171 if (!sect_sp) {
172 return llvm::createStringError(std::errc::operation_not_supported,
173 "Couldn't obtain the section information.");
174 }
175 lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target);
176 // Use memory size since zero fill sections, like ".bss", will be smaller on
177 // disk.
178 lldb::addr_t sect_size = sect_sp->GetByteSize();
179 // This will usually be zero, but make sure to calculate the BaseOfImage
180 // offset.
181 const lldb::addr_t base_sect_offset =
182 mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) -
183 sect_addr;
184 SizeOfImage = sect_size - base_sect_offset;
185 lldb::addr_t next_sect_addr = sect_addr + sect_size;
186 Address sect_so_addr;
187 target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
188 lldb::SectionSP next_sect_sp = sect_so_addr.GetSection();
189 while (next_sect_sp &&
190 next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) {
191 sect_size = sect_sp->GetByteSize();
192 SizeOfImage += sect_size;
193 next_sect_addr += sect_size;
194 target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
195 next_sect_sp = sect_so_addr.GetSection();
196 }
197
198 return SizeOfImage;
199}
200
201// ModuleList stream consists of a number of modules, followed by an array
202// of llvm::minidump::Module's structures. Every structure informs about a
203// single module. Additional data of variable length, such as module's names,
204// are stored just after the ModuleList stream. The llvm::minidump::Module
205// structures point to this helper data by global offset.
207 constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module);
209
210 const ModuleList &modules = target.GetImages();
211 llvm::support::ulittle32_t modules_count =
212 static_cast<llvm::support::ulittle32_t>(modules.GetSize());
213
214 // This helps us with getting the correct global offset in minidump
215 // file later, when we will be setting up offsets from the
216 // the llvm::minidump::Module's structures into helper data
217 size_t size_before = GetCurrentDataEndOffset();
218
219 // This is the size of the main part of the ModuleList stream.
220 // It consists of a module number and corresponding number of
221 // structs describing individual modules
222 size_t module_stream_size =
223 sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
224
225 // Adding directory describing this stream.
226 AddDirectory(StreamType::ModuleList, module_stream_size);
227
228 m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t));
229
230 // Temporary storage for the helper data (of variable length)
231 // as these cannot be dumped to m_data before dumping entire
232 // array of module structures.
233 DataBufferHeap helper_data;
234
235 for (size_t i = 0; i < modules_count; ++i) {
236 ModuleSP mod = modules.GetModuleAtIndex(i);
237 std::string module_name = mod->GetSpecificationDescription();
238 auto maybe_mod_size = getModuleFileSize(target, mod);
239 if (!maybe_mod_size) {
240 llvm::Error mod_size_err = maybe_mod_size.takeError();
241 llvm::handleAllErrors(std::move(mod_size_err),
242 [&](const llvm::ErrorInfoBase &E) {
243 error.SetErrorStringWithFormat(
244 "Unable to get the size of module %s: %s.",
245 module_name.c_str(), E.message().c_str());
246 });
247 return error;
248 }
249
250 uint64_t mod_size = std::move(*maybe_mod_size);
251
252 llvm::support::ulittle32_t signature =
253 static_cast<llvm::support::ulittle32_t>(
254 static_cast<uint32_t>(minidump::CvSignature::ElfBuildId));
255 auto uuid = mod->GetUUID().GetBytes();
256
257 VSFixedFileInfo info;
258 info.Signature = static_cast<llvm::support::ulittle32_t>(0u);
259 info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u);
260 info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
261 info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
262 info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
263 info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
264 info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u);
265 info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u);
266 info.FileOS = static_cast<llvm::support::ulittle32_t>(0u);
267 info.FileType = static_cast<llvm::support::ulittle32_t>(0u);
268 info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u);
269 info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u);
270 info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u);
271
272 LocationDescriptor ld;
273 ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u);
274 ld.RVA = static_cast<llvm::support::ulittle32_t>(0u);
275
276 // Setting up LocationDescriptor for uuid string. The global offset into
277 // minidump file is calculated.
278 LocationDescriptor ld_cv;
279 ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>(
280 sizeof(llvm::support::ulittle32_t) + uuid.size());
281 ld_cv.RVA = static_cast<llvm::support::ulittle32_t>(
282 size_before + module_stream_size + helper_data.GetByteSize());
283
284 helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t));
285 helper_data.AppendData(uuid.begin(), uuid.size());
286
287 llvm::minidump::Module m;
288 m.BaseOfImage = static_cast<llvm::support::ulittle64_t>(
289 mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target));
290 m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size);
291 m.Checksum = static_cast<llvm::support::ulittle32_t>(0);
292 m.TimeDateStamp =
293 static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
294 m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>(
295 size_before + module_stream_size + helper_data.GetByteSize());
296 m.VersionInfo = info;
297 m.CvRecord = ld_cv;
298 m.MiscRecord = ld;
299
300 error = WriteString(module_name, &helper_data);
301
302 if (error.Fail())
303 return error;
304
305 m_data.AppendData(&m, sizeof(llvm::minidump::Module));
306 }
307
308 m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
309 return error;
310}
311
313 llvm::StringRef reg_name) {
314 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
315 if (!reg_info)
316 return 0;
318 bool success = reg_ctx->ReadRegister(reg_info, reg_value);
319 if (!success)
320 return 0;
321 return reg_value.GetAsUInt16();
322}
323
325 llvm::StringRef reg_name) {
326 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
327 if (!reg_info)
328 return 0;
330 bool success = reg_ctx->ReadRegister(reg_info, reg_value);
331 if (!success)
332 return 0;
333 return reg_value.GetAsUInt32();
334}
335
337 llvm::StringRef reg_name) {
338 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
339 if (!reg_info)
340 return 0;
342 bool success = reg_ctx->ReadRegister(reg_info, reg_value);
343 if (!success)
344 return 0;
345 return reg_value.GetAsUInt64();
346}
347
348llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx,
349 llvm::StringRef reg_name) {
350 return static_cast<llvm::support::ulittle16_t>(
351 read_register_u16_raw(reg_ctx, reg_name));
352}
353
354llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx,
355 llvm::StringRef reg_name) {
356 return static_cast<llvm::support::ulittle32_t>(
357 read_register_u32_raw(reg_ctx, reg_name));
358}
359
360llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,
361 llvm::StringRef reg_name) {
362 return static_cast<llvm::support::ulittle64_t>(
363 read_register_u64_raw(reg_ctx, reg_name));
364}
365
366void read_register_u128(RegisterContext *reg_ctx, llvm::StringRef reg_name,
367 uint8_t *dst) {
368 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
369 if (reg_info) {
371 if (reg_ctx->ReadRegister(reg_info, reg_value)) {
373 uint32_t bytes_copied = reg_value.GetAsMemoryData(
374 *reg_info, dst, 16, lldb::ByteOrder::eByteOrderLittle, error);
375 if (bytes_copied == 16)
376 return;
377 }
378 }
379 // If anything goes wrong, then zero out the register value.
380 memset(dst, 0, 16);
381}
382
386 thread_context.p1_home = {};
387 thread_context.context_flags = static_cast<uint32_t>(
392 thread_context.rax = read_register_u64(reg_ctx, "rax");
393 thread_context.rbx = read_register_u64(reg_ctx, "rbx");
394 thread_context.rcx = read_register_u64(reg_ctx, "rcx");
395 thread_context.rdx = read_register_u64(reg_ctx, "rdx");
396 thread_context.rdi = read_register_u64(reg_ctx, "rdi");
397 thread_context.rsi = read_register_u64(reg_ctx, "rsi");
398 thread_context.rbp = read_register_u64(reg_ctx, "rbp");
399 thread_context.rsp = read_register_u64(reg_ctx, "rsp");
400 thread_context.r8 = read_register_u64(reg_ctx, "r8");
401 thread_context.r9 = read_register_u64(reg_ctx, "r9");
402 thread_context.r10 = read_register_u64(reg_ctx, "r10");
403 thread_context.r11 = read_register_u64(reg_ctx, "r11");
404 thread_context.r12 = read_register_u64(reg_ctx, "r12");
405 thread_context.r13 = read_register_u64(reg_ctx, "r13");
406 thread_context.r14 = read_register_u64(reg_ctx, "r14");
407 thread_context.r15 = read_register_u64(reg_ctx, "r15");
408 thread_context.rip = read_register_u64(reg_ctx, "rip");
409 thread_context.eflags = read_register_u32(reg_ctx, "rflags");
410 thread_context.cs = read_register_u16(reg_ctx, "cs");
411 thread_context.fs = read_register_u16(reg_ctx, "fs");
412 thread_context.gs = read_register_u16(reg_ctx, "gs");
413 thread_context.ss = read_register_u16(reg_ctx, "ss");
414 thread_context.ds = read_register_u16(reg_ctx, "ds");
415 return thread_context;
416}
417
421 thread_context.context_flags = static_cast<uint32_t>(
422 minidump::RegisterContextMinidump_ARM64::Flags::ARM64_Flag |
423 minidump::RegisterContextMinidump_ARM64::Flags::Integer |
424 minidump::RegisterContextMinidump_ARM64::Flags::FloatingPoint);
425 char reg_name[16];
426 for (uint32_t i = 0; i < 31; ++i) {
427 snprintf(reg_name, sizeof(reg_name), "x%u", i);
428 thread_context.x[i] = read_register_u64(reg_ctx, reg_name);
429 }
430 // Work around a bug in debugserver where "sp" on arm64 doesn't have the alt
431 // name set to "x31"
432 thread_context.x[31] = read_register_u64(reg_ctx, "sp");
433 thread_context.pc = read_register_u64(reg_ctx, "pc");
434 thread_context.cpsr = read_register_u32(reg_ctx, "cpsr");
435 thread_context.fpsr = read_register_u32(reg_ctx, "fpsr");
436 thread_context.fpcr = read_register_u32(reg_ctx, "fpcr");
437 for (uint32_t i = 0; i < 32; ++i) {
438 snprintf(reg_name, sizeof(reg_name), "v%u", i);
439 read_register_u128(reg_ctx, reg_name, &thread_context.v[i * 16]);
440 }
441 return thread_context;
442}
443
445 llvm::Triple::ArchType m_arch;
446 union {
449 };
450
451public:
452 ArchThreadContexts(llvm::Triple::ArchType arch) : m_arch(arch) {}
453
455 switch (m_arch) {
456 case llvm::Triple::ArchType::x86_64:
458 return true;
459 case llvm::Triple::ArchType::aarch64:
460 arm64 = GetThreadContext_ARM64(reg_ctx);
461 return true;
462 default:
463 break;
464 }
465 return false;
466 }
467
468 const void *data() const { return &x86_64; }
469
470 size_t size() const {
471 switch (m_arch) {
472 case llvm::Triple::ArchType::x86_64:
473 return sizeof(x86_64);
474 case llvm::Triple::ArchType::aarch64:
475 return sizeof(arm64);
476 default:
477 break;
478 }
479 return 0;
480 }
481};
482
483// Function returns start and size of the memory region that contains
484// memory location pointed to by the current stack pointer.
485llvm::Expected<std::pair<addr_t, addr_t>>
486findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) {
487 MemoryRegionInfo range_info;
488 Status error = process_sp->GetMemoryRegionInfo(rsp, range_info);
489 // Skip failed memory region requests or any regions with no permissions.
490 if (error.Fail() || range_info.GetLLDBPermissions() == 0)
491 return llvm::createStringError(
492 std::errc::not_supported,
493 "unable to load stack segment of the process");
494
495 // This is a duplicate of the logic in
496 // Process::SaveOffRegionsWithStackPointers but ultimately, we need to only
497 // save up from the start of the stack down to the stack pointer
498 const addr_t range_end = range_info.GetRange().GetRangeEnd();
499 const addr_t red_zone = process_sp->GetABI()->GetRedZoneSize();
500 const addr_t stack_head = rsp - red_zone;
501 if (stack_head > range_info.GetRange().GetRangeEnd()) {
502 range_info.GetRange().SetRangeBase(stack_head);
503 range_info.GetRange().SetByteSize(range_end - stack_head);
504 }
505
506 const addr_t addr = range_info.GetRange().GetRangeBase();
507 const addr_t size = range_info.GetRange().GetByteSize();
508
509 if (size == 0)
510 return llvm::createStringError(std::errc::not_supported,
511 "stack segment of the process is empty");
512
513 return std::make_pair(addr, size);
514}
515
517 constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
518 lldb_private::ThreadList thread_list = process_sp->GetThreadList();
519
520 // size of the entire thread stream consists of:
521 // number of threads and threads array
522 size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) +
523 thread_list.GetSize() * minidump_thread_size;
524 // save for the ability to set up RVA
525 size_t size_before = GetCurrentDataEndOffset();
526
527 AddDirectory(StreamType::ThreadList, thread_stream_size);
528
529 llvm::support::ulittle32_t thread_count =
530 static_cast<llvm::support::ulittle32_t>(thread_list.GetSize());
531 m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));
532
533 DataBufferHeap helper_data;
534
535 const uint32_t num_threads = thread_list.GetSize();
536
537 for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
538 ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
539 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
541
542 if (!reg_ctx_sp) {
543 error.SetErrorString("Unable to get the register context.");
544 return error;
545 }
546 RegisterContext *reg_ctx = reg_ctx_sp.get();
547 Target &target = process_sp->GetTarget();
548 const ArchSpec &arch = target.GetArchitecture();
549 ArchThreadContexts thread_context(arch.GetMachine());
550 if (!thread_context.prepareRegisterContext(reg_ctx)) {
551 error.SetErrorStringWithFormat(
552 "architecture %s not supported.",
553 arch.GetTriple().getArchName().str().c_str());
554 return error;
555 }
556 uint64_t sp = reg_ctx->GetSP();
557 auto expected_address_range = findStackHelper(process_sp, sp);
558
559 if (!expected_address_range) {
560 consumeError(expected_address_range.takeError());
561 error.SetErrorString("Unable to get the stack address.");
562 return error;
563 }
564
565 std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range);
566 uint64_t addr = range.first;
567 uint64_t size = range.second;
568
569 auto data_up = std::make_unique<DataBufferHeap>(size, 0);
570 const size_t stack_bytes_read =
571 process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
572
573 if (error.Fail())
574 return error;
575
576 LocationDescriptor stack_memory;
577 stack_memory.DataSize =
578 static_cast<llvm::support::ulittle32_t>(stack_bytes_read);
579 stack_memory.RVA = static_cast<llvm::support::ulittle32_t>(
580 size_before + thread_stream_size + helper_data.GetByteSize());
581
582 MemoryDescriptor stack;
583 stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr);
584 stack.Memory = stack_memory;
585
586 helper_data.AppendData(data_up->GetBytes(), stack_bytes_read);
587
588 LocationDescriptor thread_context_memory_locator;
589 thread_context_memory_locator.DataSize =
590 static_cast<llvm::support::ulittle32_t>(thread_context.size());
591 thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
592 size_before + thread_stream_size + helper_data.GetByteSize());
593 // Cache thie thread context memory so we can reuse for exceptions.
594 m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator;
595
596 helper_data.AppendData(thread_context.data(), thread_context.size());
597
598 llvm::minidump::Thread t;
599 t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
600 t.SuspendCount = static_cast<llvm::support::ulittle32_t>(
601 (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0);
602 t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0);
603 t.Priority = static_cast<llvm::support::ulittle32_t>(0);
604 t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);
605 t.Stack = stack, t.Context = thread_context_memory_locator;
606
607 m_data.AppendData(&t, sizeof(llvm::minidump::Thread));
608 }
609
610 m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
611 return Status();
612}
613
615 lldb_private::ThreadList thread_list = process_sp->GetThreadList();
616
617 const uint32_t num_threads = thread_list.GetSize();
618 for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
619 ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
620 StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
621 bool add_exception = false;
622 if (stop_info_sp) {
623 switch (stop_info_sp->GetStopReason()) {
626 add_exception = true;
627 break;
628 default:
629 break;
630 }
631 }
632 if (add_exception) {
633 constexpr size_t minidump_exception_size =
634 sizeof(llvm::minidump::ExceptionStream);
635 AddDirectory(StreamType::Exception, minidump_exception_size);
636 StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
637 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
638 Exception exp_record = {};
639 exp_record.ExceptionCode =
640 static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
641 exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0);
642 exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);
643 exp_record.ExceptionAddress = reg_ctx_sp->GetPC();
644 exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0);
645 exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
646 // exp_record.ExceptionInformation;
647
648 ExceptionStream exp_stream;
649 exp_stream.ThreadId =
650 static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
651 exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
652 exp_stream.ExceptionRecord = exp_record;
653 auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID());
654 if (Iter != m_tid_to_reg_ctx.end()) {
655 exp_stream.ThreadContext = Iter->second;
656 } else {
657 exp_stream.ThreadContext.DataSize = 0;
658 exp_stream.ThreadContext.RVA = 0;
659 }
660 m_data.AppendData(&exp_stream, minidump_exception_size);
661 }
662 }
663}
664
667 lldb::SaveCoreStyle core_style) {
670 error = process_sp->CalculateCoreFileSaveRanges(core_style, core_ranges);
671 if (error.Fail()) {
672 error.SetErrorString("Process doesn't support getting memory region info.");
673 return error;
674 }
675
676 DataBufferHeap helper_data;
677 std::vector<MemoryDescriptor> mem_descriptors;
678 for (const auto &core_range : core_ranges) {
679 // Skip empty memory regions.
680 if (core_range.range.empty())
681 continue;
682 const addr_t addr = core_range.range.start();
683 const addr_t size = core_range.range.size();
684 auto data_up = std::make_unique<DataBufferHeap>(size, 0);
685 const size_t bytes_read =
686 process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
687 if (error.Fail()) {
688 Log *log = GetLog(LLDBLog::Object);
689 LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
690 bytes_read, error.AsCString());
691 error.Clear();
692 }
693 if (bytes_read == 0)
694 continue;
695 // We have a good memory region with valid bytes to store.
696 LocationDescriptor memory_dump;
697 memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read);
698 memory_dump.RVA =
699 static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
700 MemoryDescriptor memory_desc;
701 memory_desc.StartOfMemoryRange =
702 static_cast<llvm::support::ulittle64_t>(addr);
703 memory_desc.Memory = memory_dump;
704 mem_descriptors.push_back(memory_desc);
705 m_data.AppendData(data_up->GetBytes(), bytes_read);
706 }
707
708 AddDirectory(StreamType::MemoryList,
709 sizeof(llvm::support::ulittle32_t) +
710 mem_descriptors.size() *
711 sizeof(llvm::minidump::MemoryDescriptor));
712 llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size());
713
714 m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
715 for (auto memory_descriptor : mem_descriptors) {
716 m_data.AppendData(&memory_descriptor,
717 sizeof(llvm::minidump::MemoryDescriptor));
718 }
719
720 return error;
721}
722
724 AddDirectory(StreamType::MiscInfo,
726
728 misc_info.size = static_cast<llvm::support::ulittle32_t>(
730 // Default set flags1 to 0, in case that we will not be able to
731 // get any information
732 misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);
733
735 process_sp->GetProcessInfo(process_info);
736 if (process_info.ProcessIDIsValid()) {
737 // Set flags1 to reflect that PID is filled in
738 misc_info.flags1 =
739 static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>(
741 misc_info.process_id =
742 static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID());
743 }
744
745 m_data.AppendData(&misc_info,
747}
748
749std::unique_ptr<llvm::MemoryBuffer>
750getFileStreamHelper(const std::string &path) {
751 auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);
752 if (!maybe_stream)
753 return nullptr;
754 return std::move(maybe_stream.get());
755}
756
758 const lldb::ProcessSP &process_sp) {
759 std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
760 {StreamType::LinuxCPUInfo, "/proc/cpuinfo"},
761 {StreamType::LinuxLSBRelease, "/etc/lsb-release"},
762 };
763
765 process_sp->GetProcessInfo(process_info);
766 if (process_info.ProcessIDIsValid()) {
767 lldb::pid_t pid = process_info.GetProcessID();
768 std::string pid_str = std::to_string(pid);
769 files_with_stream_types.push_back(
770 {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"});
771 files_with_stream_types.push_back(
772 {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"});
773 files_with_stream_types.push_back(
774 {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"});
775 files_with_stream_types.push_back(
776 {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"});
777 files_with_stream_types.push_back(
778 {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"});
779 files_with_stream_types.push_back(
780 {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"});
781 files_with_stream_types.push_back(
782 {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"});
783 }
784
785 for (const auto &entry : files_with_stream_types) {
786 StreamType stream = entry.first;
787 std::string path = entry.second;
788 auto memory_buffer = getFileStreamHelper(path);
789
790 if (memory_buffer) {
791 size_t size = memory_buffer->getBufferSize();
792 if (size == 0)
793 continue;
794 AddDirectory(stream, size);
795 m_data.AppendData(memory_buffer->getBufferStart(), size);
796 }
797 }
798}
799
801 constexpr size_t header_size = sizeof(llvm::minidump::Header);
802 constexpr size_t directory_size = sizeof(llvm::minidump::Directory);
803
804 // write header
805 llvm::minidump::Header header;
806 header.Signature = static_cast<llvm::support::ulittle32_t>(
807 llvm::minidump::Header::MagicSignature);
808 header.Version = static_cast<llvm::support::ulittle32_t>(
809 llvm::minidump::Header::MagicVersion);
810 header.NumberOfStreams =
811 static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum());
812 header.StreamDirectoryRVA =
813 static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
814 header.Checksum = static_cast<llvm::support::ulittle32_t>(
815 0u), // not used in most of the writers
816 header.TimeDateStamp =
817 static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
818 header.Flags =
819 static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag
820
822 size_t bytes_written;
823
824 bytes_written = header_size;
825 error = core_file->Write(&header, bytes_written);
826 if (error.Fail() || bytes_written != header_size) {
827 if (bytes_written != header_size)
828 error.SetErrorStringWithFormat(
829 "unable to write the header (written %zd/%zd)", bytes_written,
830 header_size);
831 return error;
832 }
833
834 // write data
835 bytes_written = m_data.GetByteSize();
836 error = core_file->Write(m_data.GetBytes(), bytes_written);
837 if (error.Fail() || bytes_written != m_data.GetByteSize()) {
838 if (bytes_written != m_data.GetByteSize())
839 error.SetErrorStringWithFormat(
840 "unable to write the data (written %zd/%" PRIu64 ")", bytes_written,
842 return error;
843 }
844
845 // write directories
846 for (const Directory &dir : m_directories) {
847 bytes_written = directory_size;
848 error = core_file->Write(&dir, bytes_written);
849 if (error.Fail() || bytes_written != directory_size) {
850 if (bytes_written != directory_size)
851 error.SetErrorStringWithFormat(
852 "unable to write the directory (written %zd/%zd)", bytes_written,
853 directory_size);
854 return error;
855 }
856 }
857
858 return error;
859}
860
862 return m_directories.size();
863}
864
866 return sizeof(llvm::minidump::Header) + m_data.GetByteSize();
867}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition: Log.h:366
llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx, llvm::StringRef reg_name)
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)
llvm::Expected< std::pair< addr_t, addr_t > > findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp)
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 Dump(lldb::FileUP &core_file) const
size_t GetCurrentDataEndOffset() const
lldb_private::Status AddModuleList(lldb_private::Target &target)
void AddExceptions(const lldb::ProcessSP &process_sp)
lldb_private::DataBufferHeap m_data
void AddLinuxFileStreams(const lldb::ProcessSP &process_sp)
void AddMiscInfo(const lldb::ProcessSP &process_sp)
size_t GetDirectoriesNum() const
lldb_private::Status AddSystemInfo(const llvm::Triple &target_triple)
lldb_private::Status AddMemoryList(const lldb::ProcessSP &process_sp, lldb::SaveCoreStyle core_style)
std::map< lldb::tid_t, llvm::minidump::LocationDescriptor > m_tid_to_reg_ctx
std::vector< llvm::minidump::Directory > m_directories
lldb_private::Status AddThreadList(const lldb::ProcessSP &process_sp)
void AddDirectory(llvm::minidump::StreamType type, size_t stream_size)
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:450
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition: ArchSpec.cpp:683
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
std::vector< CoreFileMemoryRange > CoreFileMemoryRanges
Definition: Process.h:734
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:44
bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr, uint32_t stop_id=SectionLoadHistory::eStopIDNow)
Definition: Target.cpp:3104
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition: Target.h:981
const ArchSpec & GetArchitecture() const
Definition: Target.h:1023
uint32_t GetSize(bool can_update=true)
Definition: ThreadList.cpp:83
lldb::ThreadSP GetThreadAtIndex(uint32_t idx, bool can_update=true)
Definition: ThreadList.cpp:91
uint8_t * GetBytes()
Get a pointer to the data.
Definition: DataBuffer.h:108
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:331
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::Thread > ThreadSP
Definition: lldb-forward.h:441
std::unique_ptr< lldb_private::File > FileUP
Definition: lldb-forward.h:347
std::shared_ptr< lldb_private::Process > ProcessSP
Definition: lldb-forward.h:384
uint64_t pid_t
Definition: lldb-types.h:83
@ eByteOrderLittle
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
Definition: lldb-forward.h:422
std::shared_ptr< lldb_private::Section > SectionSP
Definition: lldb-forward.h:409
uint64_t addr_t
Definition: lldb-types.h:80
@ eStopReasonException
@ eStopReasonSignal
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
Definition: lldb-forward.h:389
std::shared_ptr< lldb_private::Module > ModuleSP
Definition: lldb-forward.h:368
BaseType GetRangeBase() const
Definition: RangeMap.h:45
SizeType GetByteSize() const
Definition: RangeMap.h:87
void SetRangeBase(BaseType b)
Set the start value for the range, and keep the same size.
Definition: RangeMap.h:48
BaseType GetRangeEnd() const
Definition: RangeMap.h:78
void SetByteSize(SizeType s)
Definition: RangeMap.h:89
Every register is described in detail including its name, alternate name (optional),...
llvm::support::ulittle32_t process_id
Definition: MinidumpTypes.h:79
llvm::support::ulittle32_t flags1
Definition: MinidumpTypes.h:78
llvm::support::ulittle32_t size
Definition: MinidumpTypes.h:76