xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp (revision aa1a8ff2d6dbc51ef058f46f3db5a8bb77967145)
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 
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 
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 
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 
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.
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 
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 
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 
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 
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 
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 
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 
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
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
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:
436   ArchThreadContexts(llvm::Triple::ArchType arch) : m_arch(arch) {}
437 
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 
452   const void *data() const { return &x86_64; }
453 
454   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>>
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 
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 
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
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 
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>
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 
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 
767 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 
828 size_t MinidumpFileBuilder::GetDirectoriesNum() const {
829   return m_directories.size();
830 }
831 
832 size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
833   return sizeof(llvm::minidump::Header) + m_data.GetByteSize();
834 }
835