24#include "llvm/ADT/StringRef.h"
25#include "llvm/BinaryFormat/Minidump.h"
26#include "llvm/Support/ConvertUTF.h"
27#include "llvm/Support/Error.h"
35using namespace llvm::minidump;
38 LocationDescriptor loc;
39 loc.DataSize =
static_cast<llvm::support::ulittle32_t
>(stream_size);
44 dir.Type =
static_cast<llvm::support::little_t<StreamType>
>(type);
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
>(
115 sys_info.PlatformId = platform_id;
118 std::string csd_string;
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());
210 size_t module_stream_size =
211 sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
214 AddDirectory(StreamType::ModuleList, module_stream_size);
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;
296 const std::string ®_name) {
301 bool success = reg_ctx->
ReadRegister(reg_info, reg_value);
308 const std::string ®_name) {
313 bool success = reg_ctx->
ReadRegister(reg_info, reg_value);
320 const std::string ®_name) {
325 bool success = reg_ctx->
ReadRegister(reg_info, reg_value);
332 const std::string ®_name) {
333 return static_cast<llvm::support::ulittle16_t
>(
338 const std::string ®_name) {
339 return static_cast<llvm::support::ulittle32_t
>(
344 const std::string ®_name) {
345 return static_cast<llvm::support::ulittle64_t
>(
381 return thread_context;
386llvm::Expected<std::pair<addr_t, addr_t>>
392 return llvm::createStringError(
393 std::errc::not_supported,
394 "unable to load stack segment of the process");
400 return llvm::createStringError(std::errc::not_supported,
401 "stack segment of the process is empty");
403 return std::make_pair(addr, size);
407 constexpr size_t minidump_thread_size =
sizeof(llvm::minidump::Thread);
412 size_t thread_stream_size =
sizeof(llvm::support::ulittle32_t) +
413 thread_list.
GetSize() * minidump_thread_size;
417 AddDirectory(StreamType::ThreadList, thread_stream_size);
419 llvm::support::ulittle32_t thread_count =
420 static_cast<llvm::support::ulittle32_t
>(thread_list.
GetSize());
427 for (
uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
429 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
433 error.SetErrorString(
"Unable to get the register context.");
441 if (!expected_address_range) {
442 error.SetErrorString(
"Unable to get the stack address.");
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;
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);
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());
463 MemoryDescriptor stack;
464 stack.StartOfMemoryRange =
static_cast<llvm::support::ulittle64_t
>(addr);
465 stack.Memory = stack_memory;
467 helper_data.
AppendData(data_up->GetBytes(), stack_bytes_read);
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());
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;
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) {
504 StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
506 if (stop_info_sp && stop_info_sp->IsValid())
510 if (stop_reason_thread_idx == num_threads) {
511 error.SetErrorString(
"No stop reason thread found.");
515 constexpr size_t minidump_exception_size =
516 sizeof(llvm::minidump::ExceptionStream);
517 AddDirectory(StreamType::Exception, minidump_exception_size);
521 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
524 StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
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());
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);
543 exp_record.NumberParameters =
static_cast<llvm::support::ulittle32_t
>(0);
544 exp_record.UnusedAlignment =
static_cast<llvm::support::ulittle32_t
>(0);
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;
564 error.SetErrorString(
"Process doesn't support getting memory region info.");
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());
581 std::vector<MemoryDescriptor> mem_descriptors;
583 std::set<addr_t> visited_region_base_addresses;
584 for (
size_t interesting_address : interesting_addresses) {
586 error = process_sp->GetMemoryRegionInfo(interesting_address, range_info);
592 if (visited_region_base_addresses.insert(addr).second ==
false)
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);
603 LocationDescriptor memory_dump;
604 memory_dump.DataSize =
static_cast<llvm::support::ulittle32_t
>(bytes_read);
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);
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());
622 for (
auto memory_descriptor : mem_descriptors) {
624 sizeof(llvm::minidump::MemoryDescriptor));
635 misc_info.
size =
static_cast<llvm::support::ulittle32_t
>(
639 misc_info.
flags1 =
static_cast<llvm::support::ulittle32_t
>(0);
642 process_sp->GetProcessInfo(process_info);
646 static_cast<llvm::support::ulittle32_t
>(
static_cast<uint32_t>(
649 static_cast<llvm::support::ulittle32_t
>(process_info.
GetProcessID());
656std::unique_ptr<llvm::MemoryBuffer>
658 auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);
661 return std::move(maybe_stream.get());
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"},
672 process_sp->GetProcessInfo(process_info);
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"});
692 for (
const auto &entry : files_with_stream_types) {
693 StreamType stream = entry.first;
694 std::string path = entry.second;
698 size_t size = memory_buffer->getBufferSize();
708 constexpr size_t header_size =
sizeof(llvm::minidump::Header);
709 constexpr size_t directory_size =
sizeof(llvm::minidump::Directory);
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 =
719 header.StreamDirectoryRVA =
721 header.Checksum =
static_cast<llvm::support::ulittle32_t
>(
723 header.TimeDateStamp =
724 static_cast<llvm::support::ulittle32_t
>(std::time(
nullptr));
726 static_cast<llvm::support::ulittle64_t
>(0u);
729 size_t bytes_written;
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,
743 error = core_file->Write(
m_data.GetBytes(), bytes_written);
746 error.SetErrorStringWithFormat(
747 "unable to write the data (written %zd/%" PRIu64
")", bytes_written,
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,
static llvm::raw_ostream & error(Stream &strm)
uint64_t read_register_u64_raw(RegisterContext *reg_ctx, const std::string ®_name)
llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx, const std::string ®_name)
Status WriteString(const std::string &to_write, lldb_private::DataBufferHeap *buffer)
uint16_t read_register_u16_raw(RegisterContext *reg_ctx, const std::string ®_name)
llvm::Expected< uint64_t > getModuleFileSize(Target &target, const ModuleSP &mod)
llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx, const std::string ®_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 ®_name)
uint32_t read_register_u32_raw(RegisterContext *reg_ctx, const std::string ®_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.
lldb::SectionSP GetSection() const
Get const accessor for the section.
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)
uint32_t GetLLDBPermissions() const
A collection class for Module objects.
lldb::ModuleSP GetModuleAtIndex(size_t idx) const
Get the module shared pointer for the module at index idx.
size_t GetSize() const
Gets the size of the module list.
bool ProcessIDIsValid() const
lldb::pid_t GetProcessID() const
const RegisterInfo * GetRegisterInfoByName(llvm::StringRef reg_name, uint32_t start_idx=0)
virtual bool ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_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
bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr, uint32_t stop_id=SectionLoadHistory::eStopIDNow)
const ModuleList & GetImages() const
Get accessor for the images for this process.
uint32_t GetSize(bool can_update=true)
lldb::ThreadSP GetThreadAtIndex(uint32_t idx, bool can_update=true)
A class that represents a running process on the host machine.
BaseType GetRangeBase() const
SizeType GetByteSize() const
llvm::support::ulittle16_t fs
llvm::support::ulittle64_t rdx
llvm::support::ulittle16_t cs
llvm::support::ulittle64_t rsp
llvm::support::ulittle16_t ss
llvm::support::ulittle64_t rbx
llvm::support::ulittle16_t ds
llvm::support::ulittle64_t r8
llvm::support::ulittle16_t gs
llvm::support::ulittle64_t rcx
llvm::support::ulittle64_t r10
llvm::support::ulittle64_t r15
llvm::support::ulittle64_t rbp
llvm::support::ulittle64_t r13
llvm::support::ulittle64_t r12
llvm::support::ulittle64_t rsi
llvm::support::ulittle64_t p1_home
llvm::support::ulittle64_t rax
llvm::support::ulittle32_t context_flags
llvm::support::ulittle64_t rdi
llvm::support::ulittle64_t r14
llvm::support::ulittle32_t eflags
llvm::support::ulittle64_t r9
llvm::support::ulittle64_t rip
llvm::support::ulittle64_t r11
llvm::support::ulittle32_t process_id
llvm::support::ulittle32_t flags1
llvm::support::ulittle32_t size