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