Coverage Report

Created: 2023-11-11 10:31

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