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

source code of lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp