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