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