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