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