24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/BinaryFormat/Minidump.h"
26 #include "llvm/Support/ConvertUTF.h"
27 #include "llvm/Support/Error.h"
35 using namespace llvm::minidump;
38 LocationDescriptor loc;
39 loc.DataSize =
static_cast<llvm::support::ulittle32_t
>(stream_size);
41 loc.RVA =
static_cast<llvm::support::ulittle32_t
>(GetCurrentDataEndOffset());
44 dir.Type =
static_cast<llvm::support::little_t<StreamType>
>(type);
47 m_directories.push_back(dir);
52 AddDirectory(StreamType::SystemInfo,
sizeof(llvm::minidump::SystemInfo));
54 llvm::minidump::ProcessorArchitecture arch;
55 switch (target_triple.getArch()) {
56 case llvm::Triple::ArchType::x86_64:
57 arch = ProcessorArchitecture::AMD64;
59 case llvm::Triple::ArchType::x86:
60 arch = ProcessorArchitecture::X86;
62 case llvm::Triple::ArchType::arm:
63 arch = ProcessorArchitecture::ARM;
65 case llvm::Triple::ArchType::aarch64:
66 arch = ProcessorArchitecture::ARM64;
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;
74 case llvm::Triple::ArchType::ppc64:
75 case llvm::Triple::ArchType::ppc:
76 case llvm::Triple::ArchType::ppc64le:
77 arch = ProcessorArchitecture::PPC;
80 error.SetErrorStringWithFormat(
"Architecture %s not supported.",
81 target_triple.getArchName().str().c_str());
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;
92 platform_id = OSPlatform::Linux;
94 case llvm::Triple::OSType::Win32:
95 platform_id = OSPlatform::Win32NT;
97 case llvm::Triple::OSType::MacOSX:
98 platform_id = OSPlatform::MacOSX;
100 case llvm::Triple::OSType::IOS:
101 platform_id = OSPlatform::IOS;
104 error.SetErrorStringWithFormat(
"OS %s not supported.",
105 target_triple.getOSName().str().c_str());
109 llvm::minidump::SystemInfo sys_info;
110 sys_info.ProcessorArch =
111 static_cast<llvm::support::little_t<ProcessorArchitecture>
>(arch);
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));
122 error.SetErrorString(
"Unable to convert the csd string to UTF16.");
133 llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1);
134 llvm::SmallVector<llvm::UTF16, 128> to_write_utf16;
136 bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16);
138 error.SetErrorStringWithFormat(
139 "Unable to convert the string to UTF16. Failed to convert %s",
146 llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2);
148 buffer->
AppendData(&to_write_size,
sizeof(llvm::support::ulittle32_t));
149 buffer->
AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes());
155 const ModuleSP &mod) {
156 SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
157 uint64_t SizeOfImage = 0;
160 return llvm::createStringError(std::errc::operation_not_supported,
161 "Couldn't obtain the section information.");
163 lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target);
170 mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) -
172 SizeOfImage = sect_size - base_sect_offset;
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;
195 constexpr
size_t minidump_module_size =
sizeof(llvm::minidump::Module);
199 llvm::support::ulittle32_t modules_count =
200 static_cast<llvm::support::ulittle32_t
>(modules.
GetSize());
205 size_t size_before = GetCurrentDataEndOffset();
210 size_t module_stream_size =
211 sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
214 AddDirectory(StreamType::ModuleList, module_stream_size);
216 m_data.AppendData(&modules_count,
sizeof(llvm::support::ulittle32_t));
223 for (
size_t i = 0; i < modules_count; ++i) {
225 std::string module_name = mod->GetSpecificationDescription();
227 if (!maybe_mod_size) {
228 error.SetErrorStringWithFormat(
"Unable to get the size of module %s.",
229 module_name.c_str());
233 uint64_t mod_size = std::move(*maybe_mod_size);
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();
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);
255 LocationDescriptor ld;
256 ld.DataSize =
static_cast<llvm::support::ulittle32_t
>(0u);
257 ld.RVA =
static_cast<llvm::support::ulittle32_t
>(0u);
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());
267 helper_data.
AppendData(&signature,
sizeof(llvm::support::ulittle32_t));
268 helper_data.
AppendData(uuid.begin(), uuid.size());
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);
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;
288 m_data.AppendData(&m,
sizeof(llvm::minidump::Module));
291 m_data.AppendData(helper_data.GetBytes(), helper_data.
GetByteSize());
301 bool success = reg_ctx->
ReadRegister(reg_info, reg_value);
313 bool success = reg_ctx->
ReadRegister(reg_info, reg_value);
325 bool success = reg_ctx->
ReadRegister(reg_info, reg_value);
333 return static_cast<llvm::support::ulittle16_t
>(
339 return static_cast<llvm::support::ulittle32_t
>(
345 return static_cast<llvm::support::ulittle64_t
>(
380 return thread_context;
385 llvm::Expected<std::pair<addr_t, addr_t>>
391 return llvm::createStringError(
392 std::errc::not_supported,
393 "unable to load stack segment of the process");
399 return llvm::createStringError(std::errc::not_supported,
400 "stack segment of the process is empty");
402 return std::make_pair(addr, size);
406 constexpr
size_t minidump_thread_size =
sizeof(llvm::minidump::Thread);
411 size_t thread_stream_size =
sizeof(llvm::support::ulittle32_t) +
412 thread_list.
GetSize() * minidump_thread_size;
414 size_t size_before = GetCurrentDataEndOffset();
416 AddDirectory(StreamType::ThreadList, thread_stream_size);
418 llvm::support::ulittle32_t thread_count =
419 static_cast<llvm::support::ulittle32_t
>(thread_list.
GetSize());
420 m_data.AppendData(&thread_count,
sizeof(llvm::support::ulittle32_t));
426 for (
uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
428 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
432 error.SetErrorString(
"Unable to get the register context.");
440 if (!expected_address_range) {
441 error.SetErrorString(
"Unable to get the stack address.");
445 std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range);
446 uint64_t addr = range.first;
447 uint64_t size = range.second;
449 auto data_up = std::make_unique<DataBufferHeap>(size, 0);
450 const size_t stack_bytes_read =
451 process_sp->ReadMemory(addr, data_up->GetBytes(), size,
error);
456 LocationDescriptor stack_memory;
457 stack_memory.DataSize =
458 static_cast<llvm::support::ulittle32_t
>(stack_bytes_read);
459 stack_memory.RVA =
static_cast<llvm::support::ulittle32_t
>(
460 size_before + thread_stream_size + helper_data.
GetByteSize());
462 MemoryDescriptor stack;
463 stack.StartOfMemoryRange =
static_cast<llvm::support::ulittle64_t
>(addr);
464 stack.Memory = stack_memory;
466 helper_data.
AppendData(data_up->GetBytes(), stack_bytes_read);
468 LocationDescriptor thread_context_memory_locator;
469 thread_context_memory_locator.DataSize =
470 static_cast<llvm::support::ulittle32_t
>(
sizeof(thread_context));
471 thread_context_memory_locator.RVA =
static_cast<llvm::support::ulittle32_t
>(
472 size_before + thread_stream_size + helper_data.
GetByteSize());
478 llvm::minidump::Thread t;
479 t.ThreadId =
static_cast<llvm::support::ulittle32_t
>(thread_sp->GetID());
480 t.SuspendCount =
static_cast<llvm::support::ulittle32_t
>(
482 t.PriorityClass =
static_cast<llvm::support::ulittle32_t
>(0);
483 t.Priority =
static_cast<llvm::support::ulittle32_t
>(0);
484 t.EnvironmentBlock =
static_cast<llvm::support::ulittle64_t
>(0);
485 t.Stack = stack, t.Context = thread_context_memory_locator;
487 m_data.AppendData(&t,
sizeof(llvm::minidump::Thread));
490 m_data.AppendData(helper_data.GetBytes(), helper_data.
GetByteSize());
499 uint32_t stop_reason_thread_idx = 0;
500 for (stop_reason_thread_idx = 0; stop_reason_thread_idx < num_threads;
501 ++stop_reason_thread_idx) {
503 StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
505 if (stop_info_sp && stop_info_sp->IsValid())
509 if (stop_reason_thread_idx == num_threads) {
510 error.SetErrorString(
"No stop reason thread found.");
514 constexpr
size_t minidump_exception_size =
515 sizeof(llvm::minidump::ExceptionStream);
516 AddDirectory(StreamType::Exception, minidump_exception_size);
517 size_t size_before = GetCurrentDataEndOffset();
520 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
523 StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
527 LocationDescriptor thread_context_memory_locator;
528 thread_context_memory_locator.DataSize =
529 static_cast<llvm::support::ulittle32_t
>(
sizeof(thread_context));
530 thread_context_memory_locator.RVA =
static_cast<llvm::support::ulittle32_t
>(
531 size_before + minidump_exception_size + helper_data.
GetByteSize());
537 exp_record.ExceptionCode =
538 static_cast<llvm::support::ulittle32_t
>(stop_info_sp->GetValue());
539 exp_record.ExceptionFlags =
static_cast<llvm::support::ulittle32_t
>(0);
540 exp_record.ExceptionRecord =
static_cast<llvm::support::ulittle64_t
>(0);
542 exp_record.NumberParameters =
static_cast<llvm::support::ulittle32_t
>(0);
543 exp_record.UnusedAlignment =
static_cast<llvm::support::ulittle32_t
>(0);
546 ExceptionStream exp_stream;
547 exp_stream.ThreadId =
548 static_cast<llvm::support::ulittle32_t
>(thread_sp->GetID());
549 exp_stream.UnusedAlignment =
static_cast<llvm::support::ulittle32_t
>(0);
550 exp_stream.ExceptionRecord = exp_record;
551 exp_stream.ThreadContext = thread_context_memory_locator;
553 m_data.AppendData(&exp_stream, minidump_exception_size);
554 m_data.AppendData(helper_data.GetBytes(), helper_data.
GetByteSize());
563 error.SetErrorString(
"Process doesn't support getting memory region info.");
568 std::vector<size_t> interesting_addresses;
569 auto thread_list = process_sp->GetThreadList();
570 for (
size_t i = 0; i < thread_list.GetSize(); ++i) {
571 ThreadSP thread_sp(thread_list.GetThreadAtIndex(i));
572 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
580 std::vector<MemoryDescriptor> mem_descriptors;
582 std::set<addr_t> visited_region_base_addresses;
583 for (
size_t interesting_address : interesting_addresses) {
585 error = process_sp->GetMemoryRegionInfo(interesting_address, range_info);
591 if (visited_region_base_addresses.insert(addr).second ==
false)
596 auto data_up = std::make_unique<DataBufferHeap>(size, 0);
597 const size_t bytes_read =
598 process_sp->ReadMemory(addr, data_up->GetBytes(), size,
error);
602 LocationDescriptor memory_dump;
603 memory_dump.DataSize =
static_cast<llvm::support::ulittle32_t
>(bytes_read);
605 static_cast<llvm::support::ulittle32_t
>(GetCurrentDataEndOffset());
606 MemoryDescriptor memory_desc;
607 memory_desc.StartOfMemoryRange =
608 static_cast<llvm::support::ulittle64_t
>(addr);
609 memory_desc.Memory = memory_dump;
610 mem_descriptors.push_back(memory_desc);
611 m_data.AppendData(data_up->GetBytes(), bytes_read);
614 AddDirectory(StreamType::MemoryList,
615 sizeof(llvm::support::ulittle32_t) +
616 mem_descriptors.size() *
617 sizeof(llvm::minidump::MemoryDescriptor));
618 llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size());
620 m_data.AppendData(&memory_ranges_num,
sizeof(llvm::support::ulittle32_t));
621 for (
auto memory_descriptor : mem_descriptors) {
622 m_data.AppendData(&memory_descriptor,
623 sizeof(llvm::minidump::MemoryDescriptor));
630 AddDirectory(StreamType::MiscInfo,
634 misc_info.
size =
static_cast<llvm::support::ulittle32_t
>(
638 misc_info.
flags1 =
static_cast<llvm::support::ulittle32_t
>(0);
641 process_sp->GetProcessInfo(process_info);
645 static_cast<llvm::support::ulittle32_t
>(
static_cast<uint32_t>(
648 static_cast<llvm::support::ulittle32_t
>(process_info.
GetProcessID());
651 m_data.AppendData(&misc_info,
655 std::unique_ptr<llvm::MemoryBuffer>
657 auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);
660 return std::move(maybe_stream.get());
664 const lldb::ProcessSP &process_sp) {
665 std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
666 {StreamType::LinuxCPUInfo,
"/proc/cpuinfo"},
667 {StreamType::LinuxLSBRelease,
"/etc/lsb-release"},
671 process_sp->GetProcessInfo(process_info);
675 files_with_stream_types.push_back(
676 {StreamType::LinuxProcStatus,
"/proc/" + pid_str +
"/status"});
677 files_with_stream_types.push_back(
678 {StreamType::LinuxCMDLine,
"/proc/" + pid_str +
"/cmdline"});
679 files_with_stream_types.push_back(
680 {StreamType::LinuxEnviron,
"/proc/" + pid_str +
"/environ"});
681 files_with_stream_types.push_back(
682 {StreamType::LinuxAuxv,
"/proc/" + pid_str +
"/auxv"});
683 files_with_stream_types.push_back(
684 {StreamType::LinuxMaps,
"/proc/" + pid_str +
"/maps"});
685 files_with_stream_types.push_back(
686 {StreamType::LinuxProcStat,
"/proc/" + pid_str +
"/stat"});
687 files_with_stream_types.push_back(
688 {StreamType::LinuxProcFD,
"/proc/" + pid_str +
"/fd"});
691 for (
const auto &entry : files_with_stream_types) {
692 StreamType stream = entry.first;
697 size_t size = memory_buffer->getBufferSize();
700 AddDirectory(stream, size);
701 m_data.AppendData(memory_buffer->getBufferStart(), size);
707 constexpr
size_t header_size =
sizeof(llvm::minidump::Header);
708 constexpr
size_t directory_size =
sizeof(llvm::minidump::Directory);
711 llvm::minidump::Header header;
712 header.Signature =
static_cast<llvm::support::ulittle32_t
>(
713 llvm::minidump::Header::MagicSignature);
714 header.Version =
static_cast<llvm::support::ulittle32_t
>(
715 llvm::minidump::Header::MagicVersion);
716 header.NumberOfStreams =
717 static_cast<llvm::support::ulittle32_t
>(GetDirectoriesNum());
718 header.StreamDirectoryRVA =
719 static_cast<llvm::support::ulittle32_t
>(GetCurrentDataEndOffset());
720 header.Checksum =
static_cast<llvm::support::ulittle32_t
>(
722 header.TimeDateStamp =
723 static_cast<llvm::support::ulittle32_t
>(std::time(
nullptr));
725 static_cast<llvm::support::ulittle64_t
>(0u);
728 size_t bytes_written;
730 bytes_written = header_size;
731 error = core_file->Write(&header, bytes_written);
732 if (
error.Fail() || bytes_written != header_size) {
733 if (bytes_written != header_size)
734 error.SetErrorStringWithFormat(
735 "unable to write the header (written %zd/%zd)", bytes_written,
741 bytes_written = m_data.GetByteSize();
742 error = core_file->Write(m_data.GetBytes(), bytes_written);
743 if (
error.Fail() || bytes_written != m_data.GetByteSize()) {
744 if (bytes_written != m_data.GetByteSize())
745 error.SetErrorStringWithFormat(
746 "unable to write the data (written %zd/%" PRIu64
")", bytes_written,
747 m_data.GetByteSize());
752 for (
const Directory &dir : m_directories) {
753 bytes_written = directory_size;
754 error = core_file->Write(&dir, bytes_written);
755 if (
error.Fail() || bytes_written != directory_size) {
756 if (bytes_written != directory_size)
757 error.SetErrorStringWithFormat(
758 "unable to write the directory (written %zd/%zd)", bytes_written,
768 return m_directories.size();
772 return sizeof(llvm::minidump::Header) + m_data.GetByteSize();