xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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/ABI.h"
18 #include "lldb/Target/MemoryRegionInfo.h"
19 #include "lldb/Target/Process.h"
20 #include "lldb/Target/RegisterContext.h"
21 #include "lldb/Target/StopInfo.h"
22 #include "lldb/Target/ThreadList.h"
23 #include "lldb/Utility/DataBufferHeap.h"
24 #include "lldb/Utility/DataExtractor.h"
25 #include "lldb/Utility/LLDBLog.h"
26 #include "lldb/Utility/Log.h"
27 #include "lldb/Utility/RangeMap.h"
28 #include "lldb/Utility/RegisterValue.h"
29 
30 #include "llvm/ADT/StringRef.h"
31 #include "llvm/BinaryFormat/Minidump.h"
32 #include "llvm/Support/ConvertUTF.h"
33 #include "llvm/Support/Endian.h"
34 #include "llvm/Support/Error.h"
35 #include "llvm/TargetParser/Triple.h"
36 
37 #include "Plugins/Process/minidump/MinidumpTypes.h"
38 #include "lldb/lldb-enumerations.h"
39 #include "lldb/lldb-forward.h"
40 #include "lldb/lldb-types.h"
41 
42 #include <algorithm>
43 #include <cinttypes>
44 #include <climits>
45 #include <cstddef>
46 #include <cstdint>
47 #include <functional>
48 #include <iostream>
49 #include <set>
50 #include <utility>
51 #include <vector>
52 
53 using namespace lldb;
54 using namespace lldb_private;
55 using namespace llvm::minidump;
56 
AddHeaderAndCalculateDirectories()57 Status MinidumpFileBuilder::AddHeaderAndCalculateDirectories() {
58   // First set the offset on the file, and on the bytes saved
59   m_saved_data_size = HEADER_SIZE;
60   // We know we will have at least Misc, SystemInfo, Modules, and ThreadList
61   // (corresponding memory list for stacks) And an additional memory list for
62   // non-stacks.
63   lldb_private::Target &target = m_process_sp->GetTarget();
64   m_expected_directories = 6;
65   // Check if OS is linux and reserve directory space for all linux specific
66   // breakpad extension directories.
67   if (target.GetArchitecture().GetTriple().getOS() ==
68       llvm::Triple::OSType::Linux)
69     m_expected_directories += 9;
70 
71   // Go through all of the threads and check for exceptions.
72   lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
73   const uint32_t num_threads = thread_list.GetSize();
74   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
75     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
76     StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
77     if (stop_info_sp) {
78       const StopReason &stop_reason = stop_info_sp->GetStopReason();
79       if (stop_reason == StopReason::eStopReasonException ||
80           stop_reason == StopReason::eStopReasonSignal)
81         m_expected_directories++;
82     }
83   }
84 
85   m_saved_data_size +=
86       m_expected_directories * sizeof(llvm::minidump::Directory);
87   Status error;
88   offset_t new_offset = m_core_file->SeekFromStart(m_saved_data_size);
89   if (new_offset != m_saved_data_size)
90     error.SetErrorStringWithFormat("Failed to fill in header and directory "
91                                    "sections. Written / Expected (%" PRIx64
92                                    " / %" PRIx64 ")",
93                                    new_offset, m_saved_data_size);
94 
95   return error;
96 }
97 
AddDirectory(StreamType type,uint64_t stream_size)98 Status MinidumpFileBuilder::AddDirectory(StreamType type,
99                                          uint64_t stream_size) {
100   // We explicitly cast type, an 32b enum, to uint32_t to avoid warnings.
101   Status error;
102   if (GetCurrentDataEndOffset() > UINT32_MAX) {
103     error.SetErrorStringWithFormat("Unable to add directory for stream type "
104                                    "%x, offset is greater then 32 bit limit.",
105                                    (uint32_t)type);
106     return error;
107   }
108 
109   if (m_directories.size() + 1 > m_expected_directories) {
110     error.SetErrorStringWithFormat(
111         "Unable to add directory for stream type %x, exceeded expected number "
112         "of directories %zu.",
113         (uint32_t)type, m_expected_directories);
114     return error;
115   }
116 
117   LocationDescriptor loc;
118   loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size);
119   // Stream will begin at the current end of data section
120   loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
121 
122   Directory dir;
123   dir.Type = static_cast<llvm::support::little_t<StreamType>>(type);
124   dir.Location = loc;
125 
126   m_directories.push_back(dir);
127   return error;
128 }
129 
AddSystemInfo()130 Status MinidumpFileBuilder::AddSystemInfo() {
131   Status error;
132   const llvm::Triple &target_triple =
133       m_process_sp->GetTarget().GetArchitecture().GetTriple();
134   error =
135       AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
136   if (error.Fail())
137     return error;
138 
139   llvm::minidump::ProcessorArchitecture arch;
140   switch (target_triple.getArch()) {
141   case llvm::Triple::ArchType::x86_64:
142     arch = ProcessorArchitecture::AMD64;
143     break;
144   case llvm::Triple::ArchType::x86:
145     arch = ProcessorArchitecture::X86;
146     break;
147   case llvm::Triple::ArchType::arm:
148     arch = ProcessorArchitecture::ARM;
149     break;
150   case llvm::Triple::ArchType::aarch64:
151     arch = ProcessorArchitecture::ARM64;
152     break;
153   case llvm::Triple::ArchType::mips64:
154   case llvm::Triple::ArchType::mips64el:
155   case llvm::Triple::ArchType::mips:
156   case llvm::Triple::ArchType::mipsel:
157     arch = ProcessorArchitecture::MIPS;
158     break;
159   case llvm::Triple::ArchType::ppc64:
160   case llvm::Triple::ArchType::ppc:
161   case llvm::Triple::ArchType::ppc64le:
162     arch = ProcessorArchitecture::PPC;
163     break;
164   default:
165     error.SetErrorStringWithFormat("Architecture %s not supported.",
166                                    target_triple.getArchName().str().c_str());
167     return error;
168   };
169 
170   llvm::support::little_t<OSPlatform> platform_id;
171   switch (target_triple.getOS()) {
172   case llvm::Triple::OSType::Linux:
173     if (target_triple.getEnvironment() ==
174         llvm::Triple::EnvironmentType::Android)
175       platform_id = OSPlatform::Android;
176     else
177       platform_id = OSPlatform::Linux;
178     break;
179   case llvm::Triple::OSType::Win32:
180     platform_id = OSPlatform::Win32NT;
181     break;
182   case llvm::Triple::OSType::MacOSX:
183     platform_id = OSPlatform::MacOSX;
184     break;
185   case llvm::Triple::OSType::IOS:
186     platform_id = OSPlatform::IOS;
187     break;
188   default:
189     error.SetErrorStringWithFormat("OS %s not supported.",
190                                    target_triple.getOSName().str().c_str());
191     return error;
192   };
193 
194   llvm::minidump::SystemInfo sys_info;
195   sys_info.ProcessorArch =
196       static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch);
197   // Global offset to beginning of a csd_string in a data section
198   sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>(
199       GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo));
200   sys_info.PlatformId = platform_id;
201   m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo));
202 
203   std::string csd_string;
204 
205   error = WriteString(csd_string, &m_data);
206   if (error.Fail()) {
207     error.SetErrorString("Unable to convert the csd string to UTF16.");
208     return error;
209   }
210 
211   return error;
212 }
213 
WriteString(const std::string & to_write,lldb_private::DataBufferHeap * buffer)214 Status WriteString(const std::string &to_write,
215                    lldb_private::DataBufferHeap *buffer) {
216   Status error;
217   // let the StringRef eat also null termination char
218   llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1);
219   llvm::SmallVector<llvm::UTF16, 128> to_write_utf16;
220 
221   bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16);
222   if (!converted) {
223     error.SetErrorStringWithFormat(
224         "Unable to convert the string to UTF16. Failed to convert %s",
225         to_write.c_str());
226     return error;
227   }
228 
229   // size of the UTF16 string should be written without the null termination
230   // character that is stored in 2 bytes
231   llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2);
232 
233   buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t));
234   buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes());
235 
236   return error;
237 }
238 
getModuleFileSize(Target & target,const ModuleSP & mod)239 llvm::Expected<uint64_t> getModuleFileSize(Target &target,
240                                            const ModuleSP &mod) {
241   // JIT module has the same vm and file size.
242   uint64_t SizeOfImage = 0;
243   if (mod->GetObjectFile()->CalculateType() == ObjectFile::Type::eTypeJIT) {
244     for (const auto &section : *mod->GetObjectFile()->GetSectionList()) {
245       SizeOfImage += section->GetByteSize();
246     }
247     return SizeOfImage;
248   }
249   SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
250 
251   if (!sect_sp) {
252     return llvm::createStringError(std::errc::operation_not_supported,
253                                    "Couldn't obtain the section information.");
254   }
255   lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target);
256   // Use memory size since zero fill sections, like ".bss", will be smaller on
257   // disk.
258   lldb::addr_t sect_size = sect_sp->GetByteSize();
259   // This will usually be zero, but make sure to calculate the BaseOfImage
260   // offset.
261   const lldb::addr_t base_sect_offset =
262       mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) -
263       sect_addr;
264   SizeOfImage = sect_size - base_sect_offset;
265   lldb::addr_t next_sect_addr = sect_addr + sect_size;
266   Address sect_so_addr;
267   target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
268   lldb::SectionSP next_sect_sp = sect_so_addr.GetSection();
269   while (next_sect_sp &&
270          next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) {
271     sect_size = sect_sp->GetByteSize();
272     SizeOfImage += sect_size;
273     next_sect_addr += sect_size;
274     target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
275     next_sect_sp = sect_so_addr.GetSection();
276   }
277 
278   return SizeOfImage;
279 }
280 
281 // ModuleList stream consists of a number of modules, followed by an array
282 // of llvm::minidump::Module's structures. Every structure informs about a
283 // single module. Additional data of variable length, such as module's names,
284 // are stored just after the ModuleList stream. The llvm::minidump::Module
285 // structures point to this helper data by global offset.
AddModuleList()286 Status MinidumpFileBuilder::AddModuleList() {
287   constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module);
288   Status error;
289 
290   lldb_private::Target &target = m_process_sp->GetTarget();
291   const ModuleList &modules = target.GetImages();
292   llvm::support::ulittle32_t modules_count =
293       static_cast<llvm::support::ulittle32_t>(modules.GetSize());
294 
295   // This helps us with getting the correct global offset in minidump
296   // file later, when we will be setting up offsets from the
297   // the llvm::minidump::Module's structures into helper data
298   size_t size_before = GetCurrentDataEndOffset();
299 
300   // This is the size of the main part of the ModuleList stream.
301   // It consists of a module number and corresponding number of
302   // structs describing individual modules
303   size_t module_stream_size =
304       sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
305 
306   // Adding directory describing this stream.
307   error = AddDirectory(StreamType::ModuleList, module_stream_size);
308   if (error.Fail())
309     return error;
310 
311   m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t));
312 
313   // Temporary storage for the helper data (of variable length)
314   // as these cannot be dumped to m_data before dumping entire
315   // array of module structures.
316   DataBufferHeap helper_data;
317 
318   for (size_t i = 0; i < modules_count; ++i) {
319     ModuleSP mod = modules.GetModuleAtIndex(i);
320     std::string module_name = mod->GetSpecificationDescription();
321     auto maybe_mod_size = getModuleFileSize(target, mod);
322     if (!maybe_mod_size) {
323       llvm::Error mod_size_err = maybe_mod_size.takeError();
324       llvm::handleAllErrors(std::move(mod_size_err),
325                             [&](const llvm::ErrorInfoBase &E) {
326                               error.SetErrorStringWithFormat(
327                                   "Unable to get the size of module %s: %s.",
328                                   module_name.c_str(), E.message().c_str());
329                             });
330       return error;
331     }
332 
333     uint64_t mod_size = std::move(*maybe_mod_size);
334 
335     llvm::support::ulittle32_t signature =
336         static_cast<llvm::support::ulittle32_t>(
337             static_cast<uint32_t>(minidump::CvSignature::ElfBuildId));
338     auto uuid = mod->GetUUID().GetBytes();
339 
340     VSFixedFileInfo info;
341     info.Signature = static_cast<llvm::support::ulittle32_t>(0u);
342     info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u);
343     info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
344     info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
345     info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
346     info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
347     info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u);
348     info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u);
349     info.FileOS = static_cast<llvm::support::ulittle32_t>(0u);
350     info.FileType = static_cast<llvm::support::ulittle32_t>(0u);
351     info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u);
352     info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u);
353     info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u);
354 
355     LocationDescriptor ld;
356     ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u);
357     ld.RVA = static_cast<llvm::support::ulittle32_t>(0u);
358 
359     // Setting up LocationDescriptor for uuid string. The global offset into
360     // minidump file is calculated.
361     LocationDescriptor ld_cv;
362     ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>(
363         sizeof(llvm::support::ulittle32_t) + uuid.size());
364     ld_cv.RVA = static_cast<llvm::support::ulittle32_t>(
365         size_before + module_stream_size + helper_data.GetByteSize());
366 
367     helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t));
368     helper_data.AppendData(uuid.begin(), uuid.size());
369 
370     llvm::minidump::Module m;
371     m.BaseOfImage = static_cast<llvm::support::ulittle64_t>(
372         mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target));
373     m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size);
374     m.Checksum = static_cast<llvm::support::ulittle32_t>(0);
375     m.TimeDateStamp =
376         static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
377     m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>(
378         size_before + module_stream_size + helper_data.GetByteSize());
379     m.VersionInfo = info;
380     m.CvRecord = ld_cv;
381     m.MiscRecord = ld;
382 
383     error = WriteString(module_name, &helper_data);
384 
385     if (error.Fail())
386       return error;
387 
388     m_data.AppendData(&m, sizeof(llvm::minidump::Module));
389   }
390 
391   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
392   return error;
393 }
394 
read_register_u16_raw(RegisterContext * reg_ctx,llvm::StringRef reg_name)395 uint16_t read_register_u16_raw(RegisterContext *reg_ctx,
396                                llvm::StringRef reg_name) {
397   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
398   if (!reg_info)
399     return 0;
400   lldb_private::RegisterValue reg_value;
401   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
402   if (!success)
403     return 0;
404   return reg_value.GetAsUInt16();
405 }
406 
read_register_u32_raw(RegisterContext * reg_ctx,llvm::StringRef reg_name)407 uint32_t read_register_u32_raw(RegisterContext *reg_ctx,
408                                llvm::StringRef reg_name) {
409   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
410   if (!reg_info)
411     return 0;
412   lldb_private::RegisterValue reg_value;
413   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
414   if (!success)
415     return 0;
416   return reg_value.GetAsUInt32();
417 }
418 
read_register_u64_raw(RegisterContext * reg_ctx,llvm::StringRef reg_name)419 uint64_t read_register_u64_raw(RegisterContext *reg_ctx,
420                                llvm::StringRef reg_name) {
421   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
422   if (!reg_info)
423     return 0;
424   lldb_private::RegisterValue reg_value;
425   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
426   if (!success)
427     return 0;
428   return reg_value.GetAsUInt64();
429 }
430 
read_register_u16(RegisterContext * reg_ctx,llvm::StringRef reg_name)431 llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx,
432                                              llvm::StringRef reg_name) {
433   return static_cast<llvm::support::ulittle16_t>(
434       read_register_u16_raw(reg_ctx, reg_name));
435 }
436 
read_register_u32(RegisterContext * reg_ctx,llvm::StringRef reg_name)437 llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx,
438                                              llvm::StringRef reg_name) {
439   return static_cast<llvm::support::ulittle32_t>(
440       read_register_u32_raw(reg_ctx, reg_name));
441 }
442 
read_register_u64(RegisterContext * reg_ctx,llvm::StringRef reg_name)443 llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,
444                                              llvm::StringRef reg_name) {
445   return static_cast<llvm::support::ulittle64_t>(
446       read_register_u64_raw(reg_ctx, reg_name));
447 }
448 
read_register_u128(RegisterContext * reg_ctx,llvm::StringRef reg_name,uint8_t * dst)449 void read_register_u128(RegisterContext *reg_ctx, llvm::StringRef reg_name,
450                         uint8_t *dst) {
451   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
452   if (reg_info) {
453     lldb_private::RegisterValue reg_value;
454     if (reg_ctx->ReadRegister(reg_info, reg_value)) {
455       Status error;
456       uint32_t bytes_copied = reg_value.GetAsMemoryData(
457           *reg_info, dst, 16, lldb::ByteOrder::eByteOrderLittle, error);
458       if (bytes_copied == 16)
459         return;
460     }
461   }
462   // If anything goes wrong, then zero out the register value.
463   memset(dst, 0, 16);
464 }
465 
466 lldb_private::minidump::MinidumpContext_x86_64
GetThreadContext_x86_64(RegisterContext * reg_ctx)467 GetThreadContext_x86_64(RegisterContext *reg_ctx) {
468   lldb_private::minidump::MinidumpContext_x86_64 thread_context = {};
469   thread_context.p1_home = {};
470   thread_context.context_flags = static_cast<uint32_t>(
471       lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag |
472       lldb_private::minidump::MinidumpContext_x86_64_Flags::Control |
473       lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments |
474       lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer);
475   thread_context.rax = read_register_u64(reg_ctx, "rax");
476   thread_context.rbx = read_register_u64(reg_ctx, "rbx");
477   thread_context.rcx = read_register_u64(reg_ctx, "rcx");
478   thread_context.rdx = read_register_u64(reg_ctx, "rdx");
479   thread_context.rdi = read_register_u64(reg_ctx, "rdi");
480   thread_context.rsi = read_register_u64(reg_ctx, "rsi");
481   thread_context.rbp = read_register_u64(reg_ctx, "rbp");
482   thread_context.rsp = read_register_u64(reg_ctx, "rsp");
483   thread_context.r8 = read_register_u64(reg_ctx, "r8");
484   thread_context.r9 = read_register_u64(reg_ctx, "r9");
485   thread_context.r10 = read_register_u64(reg_ctx, "r10");
486   thread_context.r11 = read_register_u64(reg_ctx, "r11");
487   thread_context.r12 = read_register_u64(reg_ctx, "r12");
488   thread_context.r13 = read_register_u64(reg_ctx, "r13");
489   thread_context.r14 = read_register_u64(reg_ctx, "r14");
490   thread_context.r15 = read_register_u64(reg_ctx, "r15");
491   thread_context.rip = read_register_u64(reg_ctx, "rip");
492   thread_context.eflags = read_register_u32(reg_ctx, "rflags");
493   thread_context.cs = read_register_u16(reg_ctx, "cs");
494   thread_context.fs = read_register_u16(reg_ctx, "fs");
495   thread_context.gs = read_register_u16(reg_ctx, "gs");
496   thread_context.ss = read_register_u16(reg_ctx, "ss");
497   thread_context.ds = read_register_u16(reg_ctx, "ds");
498   return thread_context;
499 }
500 
501 minidump::RegisterContextMinidump_ARM64::Context
GetThreadContext_ARM64(RegisterContext * reg_ctx)502 GetThreadContext_ARM64(RegisterContext *reg_ctx) {
503   minidump::RegisterContextMinidump_ARM64::Context thread_context = {};
504   thread_context.context_flags = static_cast<uint32_t>(
505       minidump::RegisterContextMinidump_ARM64::Flags::ARM64_Flag |
506       minidump::RegisterContextMinidump_ARM64::Flags::Integer |
507       minidump::RegisterContextMinidump_ARM64::Flags::FloatingPoint);
508   char reg_name[16];
509   for (uint32_t i = 0; i < 31; ++i) {
510     snprintf(reg_name, sizeof(reg_name), "x%u", i);
511     thread_context.x[i] = read_register_u64(reg_ctx, reg_name);
512   }
513   // Work around a bug in debugserver where "sp" on arm64 doesn't have the alt
514   // name set to "x31"
515   thread_context.x[31] = read_register_u64(reg_ctx, "sp");
516   thread_context.pc = read_register_u64(reg_ctx, "pc");
517   thread_context.cpsr = read_register_u32(reg_ctx, "cpsr");
518   thread_context.fpsr = read_register_u32(reg_ctx, "fpsr");
519   thread_context.fpcr = read_register_u32(reg_ctx, "fpcr");
520   for (uint32_t i = 0; i < 32; ++i) {
521     snprintf(reg_name, sizeof(reg_name), "v%u", i);
522     read_register_u128(reg_ctx, reg_name, &thread_context.v[i * 16]);
523   }
524   return thread_context;
525 }
526 
527 class ArchThreadContexts {
528   llvm::Triple::ArchType m_arch;
529   union {
530     lldb_private::minidump::MinidumpContext_x86_64 x86_64;
531     lldb_private::minidump::RegisterContextMinidump_ARM64::Context arm64;
532   };
533 
534 public:
ArchThreadContexts(llvm::Triple::ArchType arch)535   ArchThreadContexts(llvm::Triple::ArchType arch) : m_arch(arch) {}
536 
prepareRegisterContext(RegisterContext * reg_ctx)537   bool prepareRegisterContext(RegisterContext *reg_ctx) {
538     switch (m_arch) {
539     case llvm::Triple::ArchType::x86_64:
540       x86_64 = GetThreadContext_x86_64(reg_ctx);
541       return true;
542     case llvm::Triple::ArchType::aarch64:
543       arm64 = GetThreadContext_ARM64(reg_ctx);
544       return true;
545     default:
546       break;
547     }
548     return false;
549   }
550 
data() const551   const void *data() const { return &x86_64; }
552 
size() const553   size_t size() const {
554     switch (m_arch) {
555     case llvm::Triple::ArchType::x86_64:
556       return sizeof(x86_64);
557     case llvm::Triple::ArchType::aarch64:
558       return sizeof(arm64);
559     default:
560       break;
561     }
562     return 0;
563   }
564 };
565 
FixThreadStacks()566 Status MinidumpFileBuilder::FixThreadStacks() {
567   Status error;
568   // If we have anything in the heap flush it.
569   FlushBufferToDisk();
570   m_core_file->SeekFromStart(m_thread_list_start);
571   for (auto &pair : m_thread_by_range_end) {
572     // The thread objects will get a new memory descriptor added
573     // When we are emitting the memory list and then we write it here
574     const llvm::minidump::Thread &thread = pair.second;
575     size_t bytes_to_write = sizeof(llvm::minidump::Thread);
576     size_t bytes_written = bytes_to_write;
577     error = m_core_file->Write(&thread, bytes_written);
578     if (error.Fail() || bytes_to_write != bytes_written) {
579       error.SetErrorStringWithFormat(
580           "Wrote incorrect number of bytes to minidump file. (written %zd/%zd)",
581           bytes_written, bytes_to_write);
582       return error;
583     }
584   }
585 
586   return error;
587 }
588 
AddThreadList()589 Status MinidumpFileBuilder::AddThreadList() {
590   constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
591   lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
592 
593   // size of the entire thread stream consists of:
594   // number of threads and threads array
595   size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) +
596                               thread_list.GetSize() * minidump_thread_size;
597   // save for the ability to set up RVA
598   size_t size_before = GetCurrentDataEndOffset();
599   Status error;
600   error = AddDirectory(StreamType::ThreadList, thread_stream_size);
601   if (error.Fail())
602     return error;
603 
604   llvm::support::ulittle32_t thread_count =
605       static_cast<llvm::support::ulittle32_t>(thread_list.GetSize());
606   m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));
607 
608   // Take the offset after the thread count.
609   m_thread_list_start = GetCurrentDataEndOffset();
610   DataBufferHeap helper_data;
611 
612   const uint32_t num_threads = thread_list.GetSize();
613   Log *log = GetLog(LLDBLog::Object);
614   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
615     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
616     RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
617 
618     if (!reg_ctx_sp) {
619       error.SetErrorString("Unable to get the register context.");
620       return error;
621     }
622     RegisterContext *reg_ctx = reg_ctx_sp.get();
623     Target &target = m_process_sp->GetTarget();
624     const ArchSpec &arch = target.GetArchitecture();
625     ArchThreadContexts thread_context(arch.GetMachine());
626     if (!thread_context.prepareRegisterContext(reg_ctx)) {
627       error.SetErrorStringWithFormat(
628           "architecture %s not supported.",
629           arch.GetTriple().getArchName().str().c_str());
630       return error;
631     }
632 
633     uint64_t sp = reg_ctx->GetSP();
634     MemoryRegionInfo sp_region;
635     m_process_sp->GetMemoryRegionInfo(sp, sp_region);
636 
637     // Emit a blank descriptor
638     MemoryDescriptor stack;
639     LocationDescriptor empty_label;
640     empty_label.DataSize = 0;
641     empty_label.RVA = 0;
642     stack.Memory = empty_label;
643     stack.StartOfMemoryRange = 0;
644     LocationDescriptor thread_context_memory_locator;
645     thread_context_memory_locator.DataSize =
646         static_cast<llvm::support::ulittle32_t>(thread_context.size());
647     thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
648         size_before + thread_stream_size + helper_data.GetByteSize());
649     // Cache thie thread context memory so we can reuse for exceptions.
650     m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator;
651 
652     LLDB_LOGF(log, "AddThreadList for thread %d: thread_context %zu bytes",
653               thread_idx, thread_context.size());
654     helper_data.AppendData(thread_context.data(), thread_context.size());
655 
656     llvm::minidump::Thread t;
657     t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
658     t.SuspendCount = static_cast<llvm::support::ulittle32_t>(
659         (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0);
660     t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0);
661     t.Priority = static_cast<llvm::support::ulittle32_t>(0);
662     t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);
663     t.Stack = stack, t.Context = thread_context_memory_locator;
664 
665     // We save off the stack object so we can circle back and clean it up.
666     m_thread_by_range_end[sp_region.GetRange().GetRangeEnd()] = t;
667     m_data.AppendData(&t, sizeof(llvm::minidump::Thread));
668   }
669 
670   LLDB_LOGF(log, "AddThreadList(): total helper_data %" PRIx64 " bytes",
671             helper_data.GetByteSize());
672   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
673   return Status();
674 }
675 
AddExceptions()676 Status MinidumpFileBuilder::AddExceptions() {
677   lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
678   Status error;
679   const uint32_t num_threads = thread_list.GetSize();
680   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
681     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
682     StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
683     bool add_exception = false;
684     if (stop_info_sp) {
685       switch (stop_info_sp->GetStopReason()) {
686       case eStopReasonSignal:
687       case eStopReasonException:
688         add_exception = true;
689         break;
690       default:
691         break;
692       }
693     }
694     if (add_exception) {
695       constexpr size_t minidump_exception_size =
696           sizeof(llvm::minidump::ExceptionStream);
697       error = AddDirectory(StreamType::Exception, minidump_exception_size);
698       if (error.Fail())
699         return error;
700 
701       StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
702       RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
703       Exception exp_record = {};
704       exp_record.ExceptionCode =
705           static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
706       exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0);
707       exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);
708       exp_record.ExceptionAddress = reg_ctx_sp->GetPC();
709       exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0);
710       exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
711       // exp_record.ExceptionInformation;
712 
713       ExceptionStream exp_stream;
714       exp_stream.ThreadId =
715           static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
716       exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
717       exp_stream.ExceptionRecord = exp_record;
718       auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID());
719       if (Iter != m_tid_to_reg_ctx.end()) {
720         exp_stream.ThreadContext = Iter->second;
721       } else {
722         exp_stream.ThreadContext.DataSize = 0;
723         exp_stream.ThreadContext.RVA = 0;
724       }
725       m_data.AppendData(&exp_stream, minidump_exception_size);
726     }
727   }
728 
729   return error;
730 }
731 
AddMiscInfo()732 lldb_private::Status MinidumpFileBuilder::AddMiscInfo() {
733   Status error;
734   error = AddDirectory(StreamType::MiscInfo,
735                        sizeof(lldb_private::minidump::MinidumpMiscInfo));
736   if (error.Fail())
737     return error;
738 
739   lldb_private::minidump::MinidumpMiscInfo misc_info;
740   misc_info.size = static_cast<llvm::support::ulittle32_t>(
741       sizeof(lldb_private::minidump::MinidumpMiscInfo));
742   // Default set flags1 to 0, in case that we will not be able to
743   // get any information
744   misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);
745 
746   lldb_private::ProcessInstanceInfo process_info;
747   m_process_sp->GetProcessInfo(process_info);
748   if (process_info.ProcessIDIsValid()) {
749     // Set flags1 to reflect that PID is filled in
750     misc_info.flags1 =
751         static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>(
752             lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID));
753     misc_info.process_id =
754         static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID());
755   }
756 
757   m_data.AppendData(&misc_info,
758                     sizeof(lldb_private::minidump::MinidumpMiscInfo));
759   return error;
760 }
761 
762 std::unique_ptr<llvm::MemoryBuffer>
getFileStreamHelper(const std::string & path)763 getFileStreamHelper(const std::string &path) {
764   auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);
765   if (!maybe_stream)
766     return nullptr;
767   return std::move(maybe_stream.get());
768 }
769 
AddLinuxFileStreams()770 Status MinidumpFileBuilder::AddLinuxFileStreams() {
771   Status error;
772   // No-op if we are not on linux.
773   if (m_process_sp->GetTarget().GetArchitecture().GetTriple().getOS() !=
774       llvm::Triple::Linux)
775     return error;
776 
777   std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
778       {StreamType::LinuxCPUInfo, "/proc/cpuinfo"},
779       {StreamType::LinuxLSBRelease, "/etc/lsb-release"},
780   };
781 
782   lldb_private::ProcessInstanceInfo process_info;
783   m_process_sp->GetProcessInfo(process_info);
784   if (process_info.ProcessIDIsValid()) {
785     lldb::pid_t pid = process_info.GetProcessID();
786     std::string pid_str = std::to_string(pid);
787     files_with_stream_types.push_back(
788         {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"});
789     files_with_stream_types.push_back(
790         {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"});
791     files_with_stream_types.push_back(
792         {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"});
793     files_with_stream_types.push_back(
794         {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"});
795     files_with_stream_types.push_back(
796         {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"});
797     files_with_stream_types.push_back(
798         {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"});
799     files_with_stream_types.push_back(
800         {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"});
801   }
802 
803   for (const auto &entry : files_with_stream_types) {
804     StreamType stream = entry.first;
805     std::string path = entry.second;
806     auto memory_buffer = getFileStreamHelper(path);
807 
808     if (memory_buffer) {
809       size_t size = memory_buffer->getBufferSize();
810       if (size == 0)
811         continue;
812       error = AddDirectory(stream, size);
813       if (error.Fail())
814         return error;
815       m_data.AppendData(memory_buffer->getBufferStart(), size);
816     }
817   }
818 
819   return error;
820 }
821 
AddMemoryList(SaveCoreStyle core_style)822 Status MinidumpFileBuilder::AddMemoryList(SaveCoreStyle core_style) {
823   Status error;
824 
825   // We first save the thread stacks to ensure they fit in the first UINT32_MAX
826   // bytes of the core file. Thread structures in minidump files can only use
827   // 32 bit memory descriptiors, so we emit them first to ensure the memory is
828   // in accessible with a 32 bit offset.
829   Process::CoreFileMemoryRanges ranges_32;
830   Process::CoreFileMemoryRanges ranges_64;
831   error = m_process_sp->CalculateCoreFileSaveRanges(
832       SaveCoreStyle::eSaveCoreStackOnly, ranges_32);
833   if (error.Fail())
834     return error;
835 
836   // Calculate totalsize including the current offset.
837   uint64_t total_size = GetCurrentDataEndOffset();
838   total_size += ranges_32.size() * sizeof(llvm::minidump::MemoryDescriptor);
839   std::unordered_set<addr_t> stack_start_addresses;
840   for (const auto &core_range : ranges_32) {
841     stack_start_addresses.insert(core_range.range.start());
842     total_size += core_range.range.size();
843   }
844 
845   if (total_size >= UINT32_MAX) {
846     error.SetErrorStringWithFormat("Unable to write minidump. Stack memory "
847                                    "exceeds 32b limit. (Num Stacks %zu)",
848                                    ranges_32.size());
849     return error;
850   }
851 
852   Process::CoreFileMemoryRanges all_core_memory_ranges;
853   if (core_style != SaveCoreStyle::eSaveCoreStackOnly) {
854     error = m_process_sp->CalculateCoreFileSaveRanges(core_style,
855                                                       all_core_memory_ranges);
856     if (error.Fail())
857       return error;
858   }
859 
860   // After saving the stacks, we start packing as much as we can into 32b.
861   // We apply a generous padding here so that the Directory, MemoryList and
862   // Memory64List sections all begin in 32b addressable space.
863   // Then anything overflow extends into 64b addressable space.
864   // All core memeroy ranges will either container nothing on stacks only
865   // or all the memory ranges including stacks
866   if (!all_core_memory_ranges.empty())
867     total_size +=
868         256 + (all_core_memory_ranges.size() - stack_start_addresses.size()) *
869                   sizeof(llvm::minidump::MemoryDescriptor_64);
870 
871   for (const auto &core_range : all_core_memory_ranges) {
872     const addr_t range_size = core_range.range.size();
873     if (stack_start_addresses.count(core_range.range.start()) > 0)
874       // Don't double save stacks.
875       continue;
876 
877     if (total_size + range_size < UINT32_MAX) {
878       ranges_32.push_back(core_range);
879       total_size += range_size;
880     } else {
881       ranges_64.push_back(core_range);
882     }
883   }
884 
885   error = AddMemoryList_32(ranges_32);
886   if (error.Fail())
887     return error;
888 
889   // Add the remaining memory as a 64b range.
890   if (!ranges_64.empty()) {
891     error = AddMemoryList_64(ranges_64);
892     if (error.Fail())
893       return error;
894   }
895 
896   return FixThreadStacks();
897 }
898 
DumpHeader() const899 Status MinidumpFileBuilder::DumpHeader() const {
900   // write header
901   llvm::minidump::Header header;
902   header.Signature = static_cast<llvm::support::ulittle32_t>(
903       llvm::minidump::Header::MagicSignature);
904   header.Version = static_cast<llvm::support::ulittle32_t>(
905       llvm::minidump::Header::MagicVersion);
906   header.NumberOfStreams =
907       static_cast<llvm::support::ulittle32_t>(m_directories.size());
908   // We write the directories right after the header.
909   header.StreamDirectoryRVA =
910       static_cast<llvm::support::ulittle32_t>(HEADER_SIZE);
911   header.Checksum = static_cast<llvm::support::ulittle32_t>(
912       0u), // not used in most of the writers
913       header.TimeDateStamp =
914           static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
915   header.Flags =
916       static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag
917 
918   Status error;
919   size_t bytes_written;
920 
921   m_core_file->SeekFromStart(0);
922   bytes_written = HEADER_SIZE;
923   error = m_core_file->Write(&header, bytes_written);
924   if (error.Fail() || bytes_written != HEADER_SIZE) {
925     if (bytes_written != HEADER_SIZE)
926       error.SetErrorStringWithFormat(
927           "Unable to write the minidump header (written %zd/%zd)",
928           bytes_written, HEADER_SIZE);
929     return error;
930   }
931   return error;
932 }
933 
GetCurrentDataEndOffset() const934 offset_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
935   return m_data.GetByteSize() + m_saved_data_size;
936 }
937 
DumpDirectories() const938 Status MinidumpFileBuilder::DumpDirectories() const {
939   Status error;
940   size_t bytes_written;
941   m_core_file->SeekFromStart(HEADER_SIZE);
942   for (const Directory &dir : m_directories) {
943     bytes_written = DIRECTORY_SIZE;
944     error = m_core_file->Write(&dir, bytes_written);
945     if (error.Fail() || bytes_written != DIRECTORY_SIZE) {
946       if (bytes_written != DIRECTORY_SIZE)
947         error.SetErrorStringWithFormat(
948             "unable to write the directory (written %zd/%zd)", bytes_written,
949             DIRECTORY_SIZE);
950       return error;
951     }
952   }
953 
954   return error;
955 }
956 
957 static uint64_t
GetLargestRangeSize(const Process::CoreFileMemoryRanges & ranges)958 GetLargestRangeSize(const Process::CoreFileMemoryRanges &ranges) {
959   uint64_t max_size = 0;
960   for (const auto &core_range : ranges)
961     max_size = std::max(max_size, core_range.range.size());
962   return max_size;
963 }
964 
965 Status
AddMemoryList_32(Process::CoreFileMemoryRanges & ranges)966 MinidumpFileBuilder::AddMemoryList_32(Process::CoreFileMemoryRanges &ranges) {
967   std::vector<MemoryDescriptor> descriptors;
968   Status error;
969   if (ranges.size() == 0)
970     return error;
971 
972   Log *log = GetLog(LLDBLog::Object);
973   size_t region_index = 0;
974   auto data_up =
975       std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0);
976   for (const auto &core_range : ranges) {
977     // Take the offset before we write.
978     const offset_t offset_for_data = GetCurrentDataEndOffset();
979     const addr_t addr = core_range.range.start();
980     const addr_t size = core_range.range.size();
981     const addr_t end = core_range.range.end();
982 
983     LLDB_LOGF(log,
984               "AddMemoryList %zu/%zu reading memory for region "
985               "(%" PRIx64 " bytes) [%" PRIx64 ", %" PRIx64 ")",
986               region_index, ranges.size(), size, addr, addr + size);
987     ++region_index;
988 
989     const size_t bytes_read =
990         m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
991     if (error.Fail() || bytes_read == 0) {
992       LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
993                 bytes_read, error.AsCString());
994       // Just skip sections with errors or zero bytes in 32b mode
995       continue;
996     } else if (bytes_read != size) {
997       LLDB_LOGF(
998           log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes",
999           addr, size);
1000     }
1001 
1002     MemoryDescriptor descriptor;
1003     descriptor.StartOfMemoryRange =
1004         static_cast<llvm::support::ulittle64_t>(addr);
1005     descriptor.Memory.DataSize =
1006         static_cast<llvm::support::ulittle32_t>(bytes_read);
1007     descriptor.Memory.RVA =
1008         static_cast<llvm::support::ulittle32_t>(offset_for_data);
1009     descriptors.push_back(descriptor);
1010     if (m_thread_by_range_end.count(end) > 0)
1011       m_thread_by_range_end[end].Stack = descriptor;
1012 
1013     // Add the data to the buffer, flush as needed.
1014     error = AddData(data_up->GetBytes(), bytes_read);
1015     if (error.Fail())
1016       return error;
1017   }
1018 
1019   // Add a directory that references this list
1020   // With a size of the number of ranges as a 32 bit num
1021   // And then the size of all the ranges
1022   error = AddDirectory(StreamType::MemoryList,
1023                        sizeof(llvm::support::ulittle32_t) +
1024                            descriptors.size() *
1025                                sizeof(llvm::minidump::MemoryDescriptor));
1026   if (error.Fail())
1027     return error;
1028 
1029   llvm::support::ulittle32_t memory_ranges_num =
1030       static_cast<llvm::support::ulittle32_t>(descriptors.size());
1031   m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
1032   // For 32b we can get away with writing off the descriptors after the data.
1033   // This means no cleanup loop needed.
1034   m_data.AppendData(descriptors.data(),
1035                     descriptors.size() * sizeof(MemoryDescriptor));
1036 
1037   return error;
1038 }
1039 
1040 Status
AddMemoryList_64(Process::CoreFileMemoryRanges & ranges)1041 MinidumpFileBuilder::AddMemoryList_64(Process::CoreFileMemoryRanges &ranges) {
1042   Status error;
1043   if (ranges.empty())
1044     return error;
1045 
1046   error = AddDirectory(StreamType::Memory64List,
1047                        (sizeof(llvm::support::ulittle64_t) * 2) +
1048                            ranges.size() *
1049                                sizeof(llvm::minidump::MemoryDescriptor_64));
1050   if (error.Fail())
1051     return error;
1052 
1053   llvm::support::ulittle64_t memory_ranges_num =
1054       static_cast<llvm::support::ulittle64_t>(ranges.size());
1055   m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle64_t));
1056   // Capture the starting offset for all the descriptors so we can clean them up
1057   // if needed.
1058   offset_t starting_offset =
1059       GetCurrentDataEndOffset() + sizeof(llvm::support::ulittle64_t);
1060   // The base_rva needs to start after the directories, which is right after
1061   // this 8 byte variable.
1062   offset_t base_rva =
1063       starting_offset +
1064       (ranges.size() * sizeof(llvm::minidump::MemoryDescriptor_64));
1065   llvm::support::ulittle64_t memory_ranges_base_rva =
1066       static_cast<llvm::support::ulittle64_t>(base_rva);
1067   m_data.AppendData(&memory_ranges_base_rva,
1068                     sizeof(llvm::support::ulittle64_t));
1069 
1070   bool cleanup_required = false;
1071   std::vector<MemoryDescriptor_64> descriptors;
1072   // Enumerate the ranges and create the memory descriptors so we can append
1073   // them first
1074   for (const auto core_range : ranges) {
1075     // Add the space required to store the memory descriptor
1076     MemoryDescriptor_64 memory_desc;
1077     memory_desc.StartOfMemoryRange =
1078         static_cast<llvm::support::ulittle64_t>(core_range.range.start());
1079     memory_desc.DataSize =
1080         static_cast<llvm::support::ulittle64_t>(core_range.range.size());
1081     descriptors.push_back(memory_desc);
1082     // Now write this memory descriptor to the buffer.
1083     m_data.AppendData(&memory_desc, sizeof(MemoryDescriptor_64));
1084   }
1085 
1086   Log *log = GetLog(LLDBLog::Object);
1087   size_t region_index = 0;
1088   auto data_up =
1089       std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0);
1090   for (const auto &core_range : ranges) {
1091     const addr_t addr = core_range.range.start();
1092     const addr_t size = core_range.range.size();
1093 
1094     LLDB_LOGF(log,
1095               "AddMemoryList_64 %zu/%zu reading memory for region "
1096               "(%" PRIx64 "bytes) "
1097               "[%" PRIx64 ", %" PRIx64 ")",
1098               region_index, ranges.size(), size, addr, addr + size);
1099     ++region_index;
1100 
1101     const size_t bytes_read =
1102         m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
1103     if (error.Fail()) {
1104       LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
1105                 bytes_read, error.AsCString());
1106       error.Clear();
1107       cleanup_required = true;
1108       descriptors[region_index].DataSize = 0;
1109     }
1110     if (bytes_read != size) {
1111       LLDB_LOGF(
1112           log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes",
1113           addr, size);
1114       cleanup_required = true;
1115       descriptors[region_index].DataSize = bytes_read;
1116     }
1117 
1118     // Add the data to the buffer, flush as needed.
1119     error = AddData(data_up->GetBytes(), bytes_read);
1120     if (error.Fail())
1121       return error;
1122   }
1123 
1124   // Early return if there is no cleanup needed.
1125   if (!cleanup_required) {
1126     return error;
1127   } else {
1128     // Flush to disk we can make the fixes in place.
1129     FlushBufferToDisk();
1130     // Fixup the descriptors that were not read correctly.
1131     m_core_file->SeekFromStart(starting_offset);
1132     size_t bytes_written = sizeof(MemoryDescriptor_64) * descriptors.size();
1133     error = m_core_file->Write(descriptors.data(), bytes_written);
1134     if (error.Fail() ||
1135         bytes_written != sizeof(MemoryDescriptor_64) * descriptors.size()) {
1136       error.SetErrorStringWithFormat(
1137           "unable to write the memory descriptors (written %zd/%zd)",
1138           bytes_written, sizeof(MemoryDescriptor_64) * descriptors.size());
1139     }
1140 
1141     return error;
1142   }
1143 }
1144 
AddData(const void * data,uint64_t size)1145 Status MinidumpFileBuilder::AddData(const void *data, uint64_t size) {
1146   // This should also get chunked, because worst case we copy over a big
1147   // object / memory range, say 5gb. In that case, we'd have to allocate 10gb
1148   // 5 gb for the buffer we're copying from, and then 5gb for the buffer we're
1149   // copying to. Which will be short lived and immedaitely go to disk, the goal
1150   // here is to limit the number of bytes we need to host in memory at any given
1151   // time.
1152   m_data.AppendData(data, size);
1153   if (m_data.GetByteSize() > MAX_WRITE_CHUNK_SIZE)
1154     return FlushBufferToDisk();
1155 
1156   return Status();
1157 }
1158 
FlushBufferToDisk()1159 Status MinidumpFileBuilder::FlushBufferToDisk() {
1160   Status error;
1161   // Set the stream to it's end.
1162   m_core_file->SeekFromStart(m_saved_data_size);
1163   addr_t starting_size = m_data.GetByteSize();
1164   addr_t remaining_bytes = starting_size;
1165   offset_t offset = 0;
1166 
1167   while (remaining_bytes > 0) {
1168     size_t bytes_written = remaining_bytes;
1169     // We don't care how many bytes we wrote unless we got an error
1170     // so just decrement the remaining bytes.
1171     error = m_core_file->Write(m_data.GetBytes() + offset, bytes_written);
1172     if (error.Fail()) {
1173       error.SetErrorStringWithFormat(
1174           "Wrote incorrect number of bytes to minidump file. (written %" PRIx64
1175           "/%" PRIx64 ")",
1176           starting_size - remaining_bytes, starting_size);
1177       return error;
1178     }
1179 
1180     offset += bytes_written;
1181     remaining_bytes -= bytes_written;
1182   }
1183 
1184   m_saved_data_size += starting_size;
1185   m_data.Clear();
1186   return error;
1187 }
1188 
DumpFile()1189 Status MinidumpFileBuilder::DumpFile() {
1190   Status error;
1191   // If anything is left unsaved, dump it.
1192   error = FlushBufferToDisk();
1193   if (error.Fail())
1194     return error;
1195 
1196   // Overwrite the header which we filled in earlier.
1197   error = DumpHeader();
1198   if (error.Fail())
1199     return error;
1200 
1201   // Overwrite the space saved for directories
1202   error = DumpDirectories();
1203   if (error.Fail())
1204     return error;
1205 
1206   return error;
1207 }
1208