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