xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp (revision 5956d97f4b3204318ceb6aa9c77bd0bc6ea87a41)
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 =
276         static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
277     m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>(
278         size_before + module_stream_size + helper_data.GetByteSize());
279     m.VersionInfo = info;
280     m.CvRecord = ld_cv;
281     m.MiscRecord = ld;
282 
283     error = WriteString(module_name, &helper_data);
284 
285     if (error.Fail())
286       return error;
287 
288     m_data.AppendData(&m, sizeof(llvm::minidump::Module));
289   }
290 
291   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
292   return error;
293 }
294 
295 uint16_t read_register_u16_raw(RegisterContext *reg_ctx,
296                                const std::string &reg_name) {
297   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
298   if (!reg_info)
299     return 0;
300   lldb_private::RegisterValue reg_value;
301   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
302   if (!success)
303     return 0;
304   return reg_value.GetAsUInt16();
305 }
306 
307 uint32_t read_register_u32_raw(RegisterContext *reg_ctx,
308                                const std::string &reg_name) {
309   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
310   if (!reg_info)
311     return 0;
312   lldb_private::RegisterValue reg_value;
313   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
314   if (!success)
315     return 0;
316   return reg_value.GetAsUInt32();
317 }
318 
319 uint64_t read_register_u64_raw(RegisterContext *reg_ctx,
320                                const std::string &reg_name) {
321   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
322   if (!reg_info)
323     return 0;
324   lldb_private::RegisterValue reg_value;
325   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
326   if (!success)
327     return 0;
328   return reg_value.GetAsUInt64();
329 }
330 
331 llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx,
332                                              const std::string &reg_name) {
333   return static_cast<llvm::support::ulittle16_t>(
334       read_register_u16_raw(reg_ctx, reg_name));
335 }
336 
337 llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx,
338                                              const std::string &reg_name) {
339   return static_cast<llvm::support::ulittle32_t>(
340       read_register_u32_raw(reg_ctx, reg_name));
341 }
342 
343 llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,
344                                              const std::string &reg_name) {
345   return static_cast<llvm::support::ulittle64_t>(
346       read_register_u64_raw(reg_ctx, reg_name));
347 }
348 
349 lldb_private::minidump::MinidumpContext_x86_64
350 GetThreadContext_64(RegisterContext *reg_ctx) {
351   lldb_private::minidump::MinidumpContext_x86_64 thread_context;
352   thread_context.context_flags = static_cast<uint32_t>(
353       lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag |
354       lldb_private::minidump::MinidumpContext_x86_64_Flags::Control |
355       lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments |
356       lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer);
357   thread_context.rax = read_register_u64(reg_ctx, "rax");
358   thread_context.rbx = read_register_u64(reg_ctx, "rbx");
359   thread_context.rcx = read_register_u64(reg_ctx, "rcx");
360   thread_context.rdx = read_register_u64(reg_ctx, "rdx");
361   thread_context.rdi = read_register_u64(reg_ctx, "rdi");
362   thread_context.rsi = read_register_u64(reg_ctx, "rsi");
363   thread_context.rbp = read_register_u64(reg_ctx, "rbp");
364   thread_context.rsp = read_register_u64(reg_ctx, "rsp");
365   thread_context.r8 = read_register_u64(reg_ctx, "r8");
366   thread_context.r9 = read_register_u64(reg_ctx, "r9");
367   thread_context.r10 = read_register_u64(reg_ctx, "r10");
368   thread_context.r11 = read_register_u64(reg_ctx, "r11");
369   thread_context.r12 = read_register_u64(reg_ctx, "r12");
370   thread_context.r13 = read_register_u64(reg_ctx, "r13");
371   thread_context.r14 = read_register_u64(reg_ctx, "r14");
372   thread_context.r15 = read_register_u64(reg_ctx, "r15");
373   thread_context.rip = read_register_u64(reg_ctx, "rip");
374   thread_context.eflags = read_register_u32(reg_ctx, "rflags");
375   thread_context.cs = read_register_u16(reg_ctx, "cs");
376   thread_context.fs = read_register_u16(reg_ctx, "fs");
377   thread_context.gs = read_register_u16(reg_ctx, "gs");
378   thread_context.ss = read_register_u16(reg_ctx, "ss");
379   thread_context.ds = read_register_u16(reg_ctx, "ds");
380   return thread_context;
381 }
382 
383 // Function returns start and size of the memory region that contains
384 // memory location pointed to by the current stack pointer.
385 llvm::Expected<std::pair<addr_t, addr_t>>
386 findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) {
387   MemoryRegionInfo range_info;
388   Status error = process_sp->GetMemoryRegionInfo(rsp, range_info);
389   // Skip failed memory region requests or any regions with no permissions.
390   if (error.Fail() || range_info.GetLLDBPermissions() == 0)
391     return llvm::createStringError(
392         std::errc::not_supported,
393         "unable to load stack segment of the process");
394 
395   const addr_t addr = range_info.GetRange().GetRangeBase();
396   const addr_t size = range_info.GetRange().GetByteSize();
397 
398   if (size == 0)
399     return llvm::createStringError(std::errc::not_supported,
400                                    "stack segment of the process is empty");
401 
402   return std::make_pair(addr, size);
403 }
404 
405 Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
406   constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
407   lldb_private::ThreadList thread_list = process_sp->GetThreadList();
408 
409   // size of the entire thread stream consists of:
410   // number of threads and threads array
411   size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) +
412                               thread_list.GetSize() * minidump_thread_size;
413   // save for the ability to set up RVA
414   size_t size_before = GetCurrentDataEndOffset();
415 
416   AddDirectory(StreamType::ThreadList, thread_stream_size);
417 
418   llvm::support::ulittle32_t thread_count =
419       static_cast<llvm::support::ulittle32_t>(thread_list.GetSize());
420   m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));
421 
422   DataBufferHeap helper_data;
423 
424   const uint32_t num_threads = thread_list.GetSize();
425 
426   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
427     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
428     RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
429     Status error;
430 
431     if (!reg_ctx_sp) {
432       error.SetErrorString("Unable to get the register context.");
433       return error;
434     }
435     RegisterContext *reg_ctx = reg_ctx_sp.get();
436     auto thread_context = GetThreadContext_64(reg_ctx);
437     uint64_t rsp = read_register_u64_raw(reg_ctx, "rsp");
438     auto expected_address_range = findStackHelper(process_sp, rsp);
439 
440     if (!expected_address_range) {
441       error.SetErrorString("Unable to get the stack address.");
442       return error;
443     }
444 
445     std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range);
446     uint64_t addr = range.first;
447     uint64_t size = range.second;
448 
449     auto data_up = std::make_unique<DataBufferHeap>(size, 0);
450     const size_t stack_bytes_read =
451         process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
452 
453     if (error.Fail())
454       return error;
455 
456     LocationDescriptor stack_memory;
457     stack_memory.DataSize =
458         static_cast<llvm::support::ulittle32_t>(stack_bytes_read);
459     stack_memory.RVA = static_cast<llvm::support::ulittle32_t>(
460         size_before + thread_stream_size + helper_data.GetByteSize());
461 
462     MemoryDescriptor stack;
463     stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr);
464     stack.Memory = stack_memory;
465 
466     helper_data.AppendData(data_up->GetBytes(), stack_bytes_read);
467 
468     LocationDescriptor thread_context_memory_locator;
469     thread_context_memory_locator.DataSize =
470         static_cast<llvm::support::ulittle32_t>(sizeof(thread_context));
471     thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
472         size_before + thread_stream_size + helper_data.GetByteSize());
473 
474     helper_data.AppendData(
475         &thread_context,
476         sizeof(lldb_private::minidump::MinidumpContext_x86_64));
477 
478     llvm::minidump::Thread t;
479     t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
480     t.SuspendCount = static_cast<llvm::support::ulittle32_t>(
481         (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0);
482     t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0);
483     t.Priority = static_cast<llvm::support::ulittle32_t>(0);
484     t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);
485     t.Stack = stack, t.Context = thread_context_memory_locator;
486 
487     m_data.AppendData(&t, sizeof(llvm::minidump::Thread));
488   }
489 
490   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
491   return Status();
492 }
493 
494 Status MinidumpFileBuilder::AddException(const lldb::ProcessSP &process_sp) {
495   Status error;
496   lldb_private::ThreadList thread_list = process_sp->GetThreadList();
497 
498   const uint32_t num_threads = thread_list.GetSize();
499   uint32_t stop_reason_thread_idx = 0;
500   for (stop_reason_thread_idx = 0; stop_reason_thread_idx < num_threads;
501        ++stop_reason_thread_idx) {
502     ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx));
503     StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
504 
505     if (stop_info_sp && stop_info_sp->IsValid())
506       break;
507   }
508 
509   if (stop_reason_thread_idx == num_threads) {
510     error.SetErrorString("No stop reason thread found.");
511     return error;
512   }
513 
514   constexpr size_t minidump_exception_size =
515       sizeof(llvm::minidump::ExceptionStream);
516   AddDirectory(StreamType::Exception, minidump_exception_size);
517   size_t size_before = GetCurrentDataEndOffset();
518 
519   ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx));
520   RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
521   RegisterContext *reg_ctx = reg_ctx_sp.get();
522   auto thread_context = GetThreadContext_64(reg_ctx);
523   StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
524 
525   DataBufferHeap helper_data;
526 
527   LocationDescriptor thread_context_memory_locator;
528   thread_context_memory_locator.DataSize =
529       static_cast<llvm::support::ulittle32_t>(sizeof(thread_context));
530   thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
531       size_before + minidump_exception_size + helper_data.GetByteSize());
532 
533   helper_data.AppendData(
534       &thread_context, sizeof(lldb_private::minidump::MinidumpContext_x86_64));
535 
536   Exception exp_record;
537   exp_record.ExceptionCode =
538       static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
539   exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0);
540   exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);
541   exp_record.ExceptionAddress = read_register_u64(reg_ctx, "rip");
542   exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0);
543   exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
544   // exp_record.ExceptionInformation;
545 
546   ExceptionStream exp_stream;
547   exp_stream.ThreadId =
548       static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
549   exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
550   exp_stream.ExceptionRecord = exp_record;
551   exp_stream.ThreadContext = thread_context_memory_locator;
552 
553   m_data.AppendData(&exp_stream, minidump_exception_size);
554   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
555   return error;
556 }
557 
558 lldb_private::Status
559 MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp) {
560   Status error;
561 
562   if (error.Fail()) {
563     error.SetErrorString("Process doesn't support getting memory region info.");
564     return error;
565   }
566 
567   // Get interesting addresses
568   std::vector<size_t> interesting_addresses;
569   auto thread_list = process_sp->GetThreadList();
570   for (size_t i = 0; i < thread_list.GetSize(); ++i) {
571     ThreadSP thread_sp(thread_list.GetThreadAtIndex(i));
572     RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
573     RegisterContext *reg_ctx = reg_ctx_sp.get();
574 
575     interesting_addresses.push_back(read_register_u64(reg_ctx, "rsp"));
576     interesting_addresses.push_back(read_register_u64(reg_ctx, "rip"));
577   }
578 
579   DataBufferHeap helper_data;
580   std::vector<MemoryDescriptor> mem_descriptors;
581 
582   std::set<addr_t> visited_region_base_addresses;
583   for (size_t interesting_address : interesting_addresses) {
584     MemoryRegionInfo range_info;
585     error = process_sp->GetMemoryRegionInfo(interesting_address, range_info);
586     // Skip failed memory region requests or any regions with no permissions.
587     if (error.Fail() || range_info.GetLLDBPermissions() == 0)
588       continue;
589     const addr_t addr = range_info.GetRange().GetRangeBase();
590     // Skip any regions we have already saved out.
591     if (visited_region_base_addresses.insert(addr).second == false)
592       continue;
593     const addr_t size = range_info.GetRange().GetByteSize();
594     if (size == 0)
595       continue;
596     auto data_up = std::make_unique<DataBufferHeap>(size, 0);
597     const size_t bytes_read =
598         process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
599     if (bytes_read == 0)
600       continue;
601     // We have a good memory region with valid bytes to store.
602     LocationDescriptor memory_dump;
603     memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read);
604     memory_dump.RVA =
605         static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
606     MemoryDescriptor memory_desc;
607     memory_desc.StartOfMemoryRange =
608         static_cast<llvm::support::ulittle64_t>(addr);
609     memory_desc.Memory = memory_dump;
610     mem_descriptors.push_back(memory_desc);
611     m_data.AppendData(data_up->GetBytes(), bytes_read);
612   }
613 
614   AddDirectory(StreamType::MemoryList,
615                sizeof(llvm::support::ulittle32_t) +
616                    mem_descriptors.size() *
617                        sizeof(llvm::minidump::MemoryDescriptor));
618   llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size());
619 
620   m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
621   for (auto memory_descriptor : mem_descriptors) {
622     m_data.AppendData(&memory_descriptor,
623                       sizeof(llvm::minidump::MemoryDescriptor));
624   }
625 
626   return error;
627 }
628 
629 void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) {
630   AddDirectory(StreamType::MiscInfo,
631                sizeof(lldb_private::minidump::MinidumpMiscInfo));
632 
633   lldb_private::minidump::MinidumpMiscInfo misc_info;
634   misc_info.size = static_cast<llvm::support::ulittle32_t>(
635       sizeof(lldb_private::minidump::MinidumpMiscInfo));
636   // Default set flags1 to 0, in case that we will not be able to
637   // get any information
638   misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);
639 
640   lldb_private::ProcessInstanceInfo process_info;
641   process_sp->GetProcessInfo(process_info);
642   if (process_info.ProcessIDIsValid()) {
643     // Set flags1 to reflect that PID is filled in
644     misc_info.flags1 =
645         static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>(
646             lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID));
647     misc_info.process_id =
648         static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID());
649   }
650 
651   m_data.AppendData(&misc_info,
652                     sizeof(lldb_private::minidump::MinidumpMiscInfo));
653 }
654 
655 std::unique_ptr<llvm::MemoryBuffer>
656 getFileStreamHelper(const std::string &path) {
657   auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);
658   if (!maybe_stream)
659     return nullptr;
660   return std::move(maybe_stream.get());
661 }
662 
663 void MinidumpFileBuilder::AddLinuxFileStreams(
664     const lldb::ProcessSP &process_sp) {
665   std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
666       {StreamType::LinuxCPUInfo, "/proc/cpuinfo"},
667       {StreamType::LinuxLSBRelease, "/etc/lsb-release"},
668   };
669 
670   lldb_private::ProcessInstanceInfo process_info;
671   process_sp->GetProcessInfo(process_info);
672   if (process_info.ProcessIDIsValid()) {
673     lldb::pid_t pid = process_info.GetProcessID();
674     std::string pid_str = std::to_string(pid);
675     files_with_stream_types.push_back(
676         {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"});
677     files_with_stream_types.push_back(
678         {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"});
679     files_with_stream_types.push_back(
680         {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"});
681     files_with_stream_types.push_back(
682         {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"});
683     files_with_stream_types.push_back(
684         {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"});
685     files_with_stream_types.push_back(
686         {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"});
687     files_with_stream_types.push_back(
688         {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"});
689   }
690 
691   for (const auto &entry : files_with_stream_types) {
692     StreamType stream = entry.first;
693     std::string path = entry.second;
694     auto memory_buffer = getFileStreamHelper(path);
695 
696     if (memory_buffer) {
697       size_t size = memory_buffer->getBufferSize();
698       if (size == 0)
699         continue;
700       AddDirectory(stream, size);
701       m_data.AppendData(memory_buffer->getBufferStart(), size);
702     }
703   }
704 }
705 
706 Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
707   constexpr size_t header_size = sizeof(llvm::minidump::Header);
708   constexpr size_t directory_size = sizeof(llvm::minidump::Directory);
709 
710   // write header
711   llvm::minidump::Header header;
712   header.Signature = static_cast<llvm::support::ulittle32_t>(
713       llvm::minidump::Header::MagicSignature);
714   header.Version = static_cast<llvm::support::ulittle32_t>(
715       llvm::minidump::Header::MagicVersion);
716   header.NumberOfStreams =
717       static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum());
718   header.StreamDirectoryRVA =
719       static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
720   header.Checksum = static_cast<llvm::support::ulittle32_t>(
721       0u), // not used in most of the writers
722       header.TimeDateStamp =
723           static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
724   header.Flags =
725       static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag
726 
727   Status error;
728   size_t bytes_written;
729 
730   bytes_written = header_size;
731   error = core_file->Write(&header, bytes_written);
732   if (error.Fail() || bytes_written != header_size) {
733     if (bytes_written != header_size)
734       error.SetErrorStringWithFormat(
735           "unable to write the header (written %zd/%zd)", bytes_written,
736           header_size);
737     return error;
738   }
739 
740   // write data
741   bytes_written = m_data.GetByteSize();
742   error = core_file->Write(m_data.GetBytes(), bytes_written);
743   if (error.Fail() || bytes_written != m_data.GetByteSize()) {
744     if (bytes_written != m_data.GetByteSize())
745       error.SetErrorStringWithFormat(
746           "unable to write the data (written %zd/%" PRIu64 ")", bytes_written,
747           m_data.GetByteSize());
748     return error;
749   }
750 
751   // write directories
752   for (const Directory &dir : m_directories) {
753     bytes_written = directory_size;
754     error = core_file->Write(&dir, bytes_written);
755     if (error.Fail() || bytes_written != directory_size) {
756       if (bytes_written != directory_size)
757         error.SetErrorStringWithFormat(
758             "unable to write the directory (written %zd/%zd)", bytes_written,
759             directory_size);
760       return error;
761     }
762   }
763 
764   return error;
765 }
766 
767 size_t MinidumpFileBuilder::GetDirectoriesNum() const {
768   return m_directories.size();
769 }
770 
771 size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
772   return sizeof(llvm::minidump::Header) + m_data.GetByteSize();
773 }
774