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