Coverage Report

Created: 2022-01-18 06:27

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