https://github.com/Jlalond updated https://github.com/llvm/llvm-project/pull/120166
>From d5dfb15e1ae90ade9b25374eefc605cc36685a43 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde <jalalo...@fb.com> Date: Mon, 16 Dec 2024 16:04:01 -0800 Subject: [PATCH 1/4] Make workaround for the Dynamic loader issue --- .../Minidump/MinidumpFileBuilder.cpp | 4 +- .../Process/minidump/MinidumpParser.cpp | 25 ++- .../Plugins/Process/minidump/MinidumpParser.h | 8 +- .../Process/minidump/ProcessMinidump.cpp | 205 +++++++++--------- .../Process/minidump/ProcessMinidump.h | 7 +- llvm/include/llvm/BinaryFormat/Minidump.h | 4 + 6 files changed, 137 insertions(+), 116 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp index bcac5edbc1a793..a4541f8bddf1a2 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp @@ -918,8 +918,8 @@ Status MinidumpFileBuilder::DumpHeader() const { 0u), // not used in most of the writers header.TimeDateStamp = static_cast<llvm::support::ulittle32_t>(std::time(nullptr)); - header.Flags = - static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag + header.Flags = static_cast<llvm::support::ulittle64_t>( + llvm::minidump::Header::LLDB_HEADER_FLAG); Status error; size_t bytes_written; diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp index afc095ddbb2f91..6a328b3b841ed0 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -20,8 +20,8 @@ #include <algorithm> #include <map> #include <optional> -#include <vector> #include <utility> +#include <vector> using namespace lldb_private; using namespace minidump; @@ -45,6 +45,10 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetData() { m_data_sp->GetByteSize()); } +const llvm::minidump::Header *MinidumpParser::GetHeader() const { + return reinterpret_cast<llvm::minidump::Header *>(m_file.get()); +} + llvm::ArrayRef<uint8_t> MinidumpParser::GetStream(StreamType stream_type) { return m_file->getRawStream(stream_type).value_or(llvm::ArrayRef<uint8_t>()); } @@ -70,8 +74,7 @@ UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) { if (GetArchitecture().GetTriple().isOSBinFormatELF()) { if (pdb70_uuid->Age != 0) return UUID(pdb70_uuid, sizeof(*pdb70_uuid)); - return UUID(&pdb70_uuid->Uuid, - sizeof(pdb70_uuid->Uuid)); + return UUID(&pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid)); } return UUID(*pdb70_uuid); } else if (cv_signature == CvSignature::ElfBuildId) @@ -453,10 +456,12 @@ MinidumpParser::FindMemoryRange(lldb::addr_t addr) { if (!GetStream(StreamType::Memory64List).empty()) { llvm::Error err = llvm::Error::success(); - for (const auto &memory_desc : GetMinidumpFile().getMemory64List(err)) { - if (memory_desc.first.StartOfMemoryRange <= addr - && addr < memory_desc.first.StartOfMemoryRange + memory_desc.first.DataSize) { - return minidump::Range(memory_desc.first.StartOfMemoryRange, memory_desc.second); + for (const auto &memory_desc : GetMinidumpFile().getMemory64List(err)) { + if (memory_desc.first.StartOfMemoryRange <= addr && + addr < memory_desc.first.StartOfMemoryRange + + memory_desc.first.DataSize) { + return minidump::Range(memory_desc.first.StartOfMemoryRange, + memory_desc.second); } } @@ -490,7 +495,8 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr, return range->range_ref.slice(offset, overlap); } -llvm::iterator_range<FallibleMemory64Iterator> MinidumpParser::GetMemory64Iterator(llvm::Error &err) { +llvm::iterator_range<FallibleMemory64Iterator> +MinidumpParser::GetMemory64Iterator(llvm::Error &err) { llvm::ErrorAsOutParameter ErrAsOutParam(&err); return m_file->getMemory64List(err); } @@ -602,8 +608,7 @@ std::pair<MemoryRegionInfos, bool> MinidumpParser::BuildMemoryRegions() { case StreamType::ST: \ return #ST -llvm::StringRef -MinidumpParser::GetStreamTypeAsString(StreamType stream_type) { +llvm::StringRef MinidumpParser::GetStreamTypeAsString(StreamType stream_type) { switch (stream_type) { ENUM_TO_CSTR(Unused); ENUM_TO_CSTR(ThreadList); diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/lldb/source/Plugins/Process/minidump/MinidumpParser.h index f0b6e6027c52f0..e13065264668c2 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.h +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.h @@ -47,7 +47,8 @@ struct Range { } }; -using FallibleMemory64Iterator = llvm::object::MinidumpFile::FallibleMemory64Iterator; +using FallibleMemory64Iterator = + llvm::object::MinidumpFile::FallibleMemory64Iterator; using ExceptionStreamsIterator = llvm::object::MinidumpFile::ExceptionStreamsIterator; @@ -56,6 +57,8 @@ class MinidumpParser { static llvm::Expected<MinidumpParser> Create(const lldb::DataBufferSP &data_buf_sp); + const llvm::minidump::Header *GetHeader() const; + llvm::ArrayRef<uint8_t> GetData(); llvm::ArrayRef<uint8_t> GetStream(StreamType stream_type); @@ -96,7 +99,8 @@ class MinidumpParser { /// complete (includes all regions mapped into the process memory). std::pair<MemoryRegionInfos, bool> BuildMemoryRegions(); - llvm::iterator_range<FallibleMemory64Iterator> GetMemory64Iterator(llvm::Error &err); + llvm::iterator_range<FallibleMemory64Iterator> + GetMemory64Iterator(llvm::Error &err); static llvm::StringRef GetStreamTypeAsString(StreamType stream_type); diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index 5b0df72130c161..e03e91887781d8 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -138,7 +138,8 @@ lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, return nullptr; lldbassert(DataPtr->GetByteSize() == header_size); - if (identify_magic(toStringRef(DataPtr->GetData())) != llvm::file_magic::minidump) + if (identify_magic(toStringRef(DataPtr->GetData())) != + llvm::file_magic::minidump) return nullptr; auto AllData = @@ -344,6 +345,23 @@ ArchSpec ProcessMinidump::GetArchitecture() { return ArchSpec(triple); } +bool ProcessMinidump::IsLLDBMinidump() const { + const llvm::minidump::Header *header = m_minidump_parser->GetHeader(); + if (!header) + return false; + return (header->Flags & llvm::minidump::Header::LLDB_HEADER_FLAG) == 0; +} + +DynamicLoader *ProcessMinidump::GetDynamicLoader() { + // This is a workaround for the dynamic loader not playing nice in issue + // #119598. The specific reason we use the dynamic loader is to get the TLS + // info sections, which we can assume are not being written to the minidump + // unless it's an LLDB generate minidump. + if (IsLLDBMinidump()) + return PostMortemProcess::GetDynamicLoader(); + return nullptr; +} + DataExtractor ProcessMinidump::GetAuxvData() { std::optional<llvm::ArrayRef<uint8_t>> auxv = m_minidump_parser->GetStream(StreamType::LinuxAuxv); @@ -487,8 +505,8 @@ void ProcessMinidump::ReadModuleList() { Log *log = GetLog(LLDBLog::DynamicLoader); for (auto module : filtered_modules) { - std::string name = cantFail(m_minidump_parser->GetMinidumpFile().getString( - module->ModuleNameRVA)); + std::string name = cantFail( + m_minidump_parser->GetMinidumpFile().getString(module->ModuleNameRVA)); const uint64_t load_addr = module->BaseOfImage; const uint64_t load_size = module->SizeOfImage; LLDB_LOG(log, "found module: name: {0} {1:x10}-{2:x10} size: {3}", name, @@ -507,8 +525,8 @@ void ProcessMinidump::ReadModuleList() { Status error; // Try and find a module with a full UUID that matches. This function will // add the module to the target if it finds one. - lldb::ModuleSP module_sp = GetTarget().GetOrCreateModule(module_spec, - true /* notify */, &error); + lldb::ModuleSP module_sp = + GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error); if (module_sp) { LLDB_LOG(log, "Full uuid match for {0}.", name); } else { @@ -532,9 +550,8 @@ void ProcessMinidump::ReadModuleList() { // we don't then we will end up setting the load address of a different // ObjectFilePlaceholder and an assertion will fire. auto *objfile = module_sp->GetObjectFile(); - if (objfile && - objfile->GetPluginName() == - ObjectFilePlaceholder::GetPluginNameStatic()) { + if (objfile && objfile->GetPluginName() == + ObjectFilePlaceholder::GetPluginNameStatic()) { if (((ObjectFilePlaceholder *)objfile)->GetBaseImageAddress() != load_addr) module_sp.reset(); @@ -564,8 +581,7 @@ void ProcessMinidump::ReadModuleList() { } bool load_addr_changed = false; - module_sp->SetLoadAddress(GetTarget(), load_addr, false, - load_addr_changed); + module_sp->SetLoadAddress(GetTarget(), load_addr, false, load_addr_changed); } } @@ -593,10 +609,10 @@ JITLoaderList &ProcessMinidump::GetJITLoaders() { return *m_jit_loaders_up; } -#define INIT_BOOL(VAR, LONG, SHORT, DESC) \ - VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true) -#define APPEND_OPT(VAR) \ - m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1) +#define INIT_BOOL(VAR, LONG, SHORT, DESC) \ + VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true) +#define APPEND_OPT(VAR) \ + m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1) class CommandObjectProcessMinidumpDump : public CommandObjectParsed { private: @@ -657,55 +673,50 @@ class CommandObjectProcessMinidumpDump : public CommandObjectParsed { // If no options were set, then dump everything m_dump_all.GetOptionValue().SetCurrentValue(true); } - bool DumpAll() const { - return m_dump_all.GetOptionValue().GetCurrentValue(); - } + bool DumpAll() const { return m_dump_all.GetOptionValue().GetCurrentValue(); } bool DumpDirectory() const { - return DumpAll() || - m_dump_directory.GetOptionValue().GetCurrentValue(); + return DumpAll() || m_dump_directory.GetOptionValue().GetCurrentValue(); } bool DumpLinux() const { return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue(); } bool DumpLinuxCPUInfo() const { return DumpLinux() || - m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue(); + m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue(); } bool DumpLinuxProcStatus() const { return DumpLinux() || - m_dump_linux_proc_status.GetOptionValue().GetCurrentValue(); + m_dump_linux_proc_status.GetOptionValue().GetCurrentValue(); } bool DumpLinuxProcStat() const { return DumpLinux() || - m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue(); + m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue(); } bool DumpLinuxLSBRelease() const { return DumpLinux() || - m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue(); + m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue(); } bool DumpLinuxCMDLine() const { return DumpLinux() || - m_dump_linux_cmdline.GetOptionValue().GetCurrentValue(); + m_dump_linux_cmdline.GetOptionValue().GetCurrentValue(); } bool DumpLinuxEnviron() const { return DumpLinux() || - m_dump_linux_environ.GetOptionValue().GetCurrentValue(); + m_dump_linux_environ.GetOptionValue().GetCurrentValue(); } bool DumpLinuxAuxv() const { - return DumpLinux() || - m_dump_linux_auxv.GetOptionValue().GetCurrentValue(); + return DumpLinux() || m_dump_linux_auxv.GetOptionValue().GetCurrentValue(); } bool DumpLinuxMaps() const { - return DumpLinux() || - m_dump_linux_maps.GetOptionValue().GetCurrentValue(); + return DumpLinux() || m_dump_linux_maps.GetOptionValue().GetCurrentValue(); } bool DumpLinuxProcUptime() const { return DumpLinux() || - m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue(); + m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue(); } bool DumpLinuxProcFD() const { return DumpLinux() || - m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue(); + m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue(); } bool DumpFacebook() const { return DumpAll() || m_fb_all.GetOptionValue().GetCurrentValue(); @@ -743,60 +754,59 @@ class CommandObjectProcessMinidumpDump : public CommandObjectParsed { bool DumpFacebookLogcat() const { return DumpFacebook() || m_fb_logcat.GetOptionValue().GetCurrentValue(); } + public: CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "process plugin dump", - "Dump information from the minidump file.", nullptr), - m_option_group(), - INIT_BOOL(m_dump_all, "all", 'a', - "Dump the everything in the minidump."), - INIT_BOOL(m_dump_directory, "directory", 'd', - "Dump the minidump directory map."), - INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C', - "Dump linux /proc/cpuinfo."), - INIT_BOOL(m_dump_linux_proc_status, "status", 's', - "Dump linux /proc/<pid>/status."), - INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r', - "Dump linux /etc/lsb-release."), - INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c', - "Dump linux /proc/<pid>/cmdline."), - INIT_BOOL(m_dump_linux_environ, "environ", 'e', - "Dump linux /proc/<pid>/environ."), - INIT_BOOL(m_dump_linux_auxv, "auxv", 'x', - "Dump linux /proc/<pid>/auxv."), - INIT_BOOL(m_dump_linux_maps, "maps", 'm', - "Dump linux /proc/<pid>/maps."), - INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S', - "Dump linux /proc/<pid>/stat."), - INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u', - "Dump linux process uptime."), - INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f', - "Dump linux /proc/<pid>/fd."), - INIT_BOOL(m_dump_linux_all, "linux", 'l', - "Dump all linux streams."), - INIT_BOOL(m_fb_app_data, "fb-app-data", 1, - "Dump Facebook application custom data."), - INIT_BOOL(m_fb_build_id, "fb-build-id", 2, - "Dump the Facebook build ID."), - INIT_BOOL(m_fb_version, "fb-version", 3, - "Dump Facebook application version string."), - INIT_BOOL(m_fb_java_stack, "fb-java-stack", 4, - "Dump Facebook java stack."), - INIT_BOOL(m_fb_dalvik, "fb-dalvik-info", 5, - "Dump Facebook Dalvik info."), - INIT_BOOL(m_fb_unwind, "fb-unwind-symbols", 6, - "Dump Facebook unwind symbols."), - INIT_BOOL(m_fb_error_log, "fb-error-log", 7, - "Dump Facebook error log."), - INIT_BOOL(m_fb_app_state, "fb-app-state-log", 8, - "Dump Facebook java stack."), - INIT_BOOL(m_fb_abort, "fb-abort-reason", 9, - "Dump Facebook abort reason."), - INIT_BOOL(m_fb_thread, "fb-thread-name", 10, - "Dump Facebook thread name."), - INIT_BOOL(m_fb_logcat, "fb-logcat", 11, - "Dump Facebook logcat."), - INIT_BOOL(m_fb_all, "facebook", 12, "Dump all Facebook streams.") { + : CommandObjectParsed(interpreter, "process plugin dump", + "Dump information from the minidump file.", + nullptr), + m_option_group(), INIT_BOOL(m_dump_all, "all", 'a', + "Dump the everything in the minidump."), + INIT_BOOL(m_dump_directory, "directory", 'd', + "Dump the minidump directory map."), + INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C', + "Dump linux /proc/cpuinfo."), + INIT_BOOL(m_dump_linux_proc_status, "status", 's', + "Dump linux /proc/<pid>/status."), + INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r', + "Dump linux /etc/lsb-release."), + INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c', + "Dump linux /proc/<pid>/cmdline."), + INIT_BOOL(m_dump_linux_environ, "environ", 'e', + "Dump linux /proc/<pid>/environ."), + INIT_BOOL(m_dump_linux_auxv, "auxv", 'x', + "Dump linux /proc/<pid>/auxv."), + INIT_BOOL(m_dump_linux_maps, "maps", 'm', + "Dump linux /proc/<pid>/maps."), + INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S', + "Dump linux /proc/<pid>/stat."), + INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u', + "Dump linux process uptime."), + INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f', + "Dump linux /proc/<pid>/fd."), + INIT_BOOL(m_dump_linux_all, "linux", 'l', "Dump all linux streams."), + INIT_BOOL(m_fb_app_data, "fb-app-data", 1, + "Dump Facebook application custom data."), + INIT_BOOL(m_fb_build_id, "fb-build-id", 2, + "Dump the Facebook build ID."), + INIT_BOOL(m_fb_version, "fb-version", 3, + "Dump Facebook application version string."), + INIT_BOOL(m_fb_java_stack, "fb-java-stack", 4, + "Dump Facebook java stack."), + INIT_BOOL(m_fb_dalvik, "fb-dalvik-info", 5, + "Dump Facebook Dalvik info."), + INIT_BOOL(m_fb_unwind, "fb-unwind-symbols", 6, + "Dump Facebook unwind symbols."), + INIT_BOOL(m_fb_error_log, "fb-error-log", 7, + "Dump Facebook error log."), + INIT_BOOL(m_fb_app_state, "fb-app-state-log", 8, + "Dump Facebook java stack."), + INIT_BOOL(m_fb_abort, "fb-abort-reason", 9, + "Dump Facebook abort reason."), + INIT_BOOL(m_fb_thread, "fb-thread-name", 10, + "Dump Facebook thread name."), + INIT_BOOL(m_fb_logcat, "fb-logcat", 11, "Dump Facebook logcat."), + INIT_BOOL(m_fb_all, "facebook", 12, "Dump all Facebook streams.") { APPEND_OPT(m_dump_all); APPEND_OPT(m_dump_directory); APPEND_OPT(m_dump_linux_cpuinfo); @@ -899,8 +909,7 @@ class CommandObjectProcessMinidumpDump : public CommandObjectParsed { if (DumpLinuxProcFD()) DumpTextStream(StreamType::LinuxProcFD, "/proc/PID/fd"); if (DumpFacebookAppData()) - DumpTextStream(StreamType::FacebookAppCustomData, - "Facebook App Data"); + DumpTextStream(StreamType::FacebookAppCustomData, "Facebook App Data"); if (DumpFacebookBuildID()) { auto bytes = minidump.GetStream(StreamType::FacebookBuildID); if (bytes.size() >= 4) { @@ -917,26 +926,21 @@ class CommandObjectProcessMinidumpDump : public CommandObjectParsed { DumpTextStream(StreamType::FacebookAppVersionName, "Facebook Version String"); if (DumpFacebookJavaStack()) - DumpTextStream(StreamType::FacebookJavaStack, - "Facebook Java Stack"); + DumpTextStream(StreamType::FacebookJavaStack, "Facebook Java Stack"); if (DumpFacebookDalvikInfo()) - DumpTextStream(StreamType::FacebookDalvikInfo, - "Facebook Dalvik Info"); + DumpTextStream(StreamType::FacebookDalvikInfo, "Facebook Dalvik Info"); if (DumpFacebookUnwindSymbols()) DumpBinaryStream(StreamType::FacebookUnwindSymbols, "Facebook Unwind Symbols Bytes"); if (DumpFacebookErrorLog()) - DumpTextStream(StreamType::FacebookDumpErrorLog, - "Facebook Error Log"); + DumpTextStream(StreamType::FacebookDumpErrorLog, "Facebook Error Log"); if (DumpFacebookAppStateLog()) DumpTextStream(StreamType::FacebookAppStateLog, "Faceook Application State Log"); if (DumpFacebookAbortReason()) - DumpTextStream(StreamType::FacebookAbortReason, - "Facebook Abort Reason"); + DumpTextStream(StreamType::FacebookAbortReason, "Facebook Abort Reason"); if (DumpFacebookThreadName()) - DumpTextStream(StreamType::FacebookThreadName, - "Facebook Thread Name"); + DumpTextStream(StreamType::FacebookThreadName, "Facebook Thread Name"); if (DumpFacebookLogcat()) DumpTextStream(StreamType::FacebookLogcat, "Facebook Logcat"); } @@ -945,11 +949,12 @@ class CommandObjectProcessMinidumpDump : public CommandObjectParsed { class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword { public: CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "process plugin", - "Commands for operating on a ProcessMinidump process.", - "process plugin <subcommand> [<subcommand-options>]") { - LoadSubCommand("dump", - CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter))); + : CommandObjectMultiword( + interpreter, "process plugin", + "Commands for operating on a ProcessMinidump process.", + "process plugin <subcommand> [<subcommand-options>]") { + LoadSubCommand("dump", CommandObjectSP(new CommandObjectProcessMinidumpDump( + interpreter))); } ~CommandObjectMultiwordProcessMinidump() override = default; diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h index 3d235670a33abc..1cc1e8addb15d9 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h @@ -53,6 +53,8 @@ class ProcessMinidump : public PostMortemProcess { Status DoLoadCore() override; + DynamicLoader *GetDynamicLoader() override; + // Returns AUXV structure found in the core file lldb_private::DataExtractor GetAuxvData() override; @@ -74,8 +76,8 @@ class ProcessMinidump : public PostMortemProcess { ArchSpec GetArchitecture(); - Status GetMemoryRegions( - lldb_private::MemoryRegionInfos ®ion_list) override; + Status + GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) override; bool GetProcessInfo(ProcessInstanceInfo &info) override; @@ -113,6 +115,7 @@ class ProcessMinidump : public PostMortemProcess { std::optional<MemoryRegionInfos> m_memory_regions; void BuildMemoryRegions(); + bool IsLLDBMinidump() const; }; } // namespace minidump diff --git a/llvm/include/llvm/BinaryFormat/Minidump.h b/llvm/include/llvm/BinaryFormat/Minidump.h index 03497d4c5fa66f..75762d3196dfcd 100644 --- a/llvm/include/llvm/BinaryFormat/Minidump.h +++ b/llvm/include/llvm/BinaryFormat/Minidump.h @@ -32,6 +32,10 @@ LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); struct Header { static constexpr uint32_t MagicSignature = 0x504d444d; // PMDM static constexpr uint16_t MagicVersion = 0xa793; + // We set all the high bits flag to indicate this is from LLDB. + // We don't want to conflict with anything Microsoft is using the flags for + // and the highest bits are not currently being used. + static const uint32_t LLDB_HEADER_FLAG = 0xF0000000; support::ulittle32_t Signature; // The high 16 bits of version field are implementation specific. The low 16 >From 49bc821677836f3946456f22b9e28c4c0c4c283d Mon Sep 17 00:00:00 2001 From: Jacob Lalonde <jalalo...@fb.com> Date: Fri, 20 Dec 2024 13:14:57 -0800 Subject: [PATCH 2/4] Reset and go with Pavel's plan of a stream section instead of a flag --- .../Minidump/MinidumpFileBuilder.cpp | 24 +- .../ObjectFile/Minidump/MinidumpFileBuilder.h | 1 + .../Process/minidump/MinidumpParser.cpp | 25 +-- .../Plugins/Process/minidump/MinidumpParser.h | 8 +- .../Process/minidump/ProcessMinidump.cpp | 212 ++++++++++-------- .../Process/minidump/ProcessMinidump.h | 7 +- llvm/include/llvm/BinaryFormat/Minidump.h | 5 +- 7 files changed, 157 insertions(+), 125 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp index a4541f8bddf1a2..85ec42349b38d4 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp @@ -58,8 +58,8 @@ Status MinidumpFileBuilder::AddHeaderAndCalculateDirectories() { // First set the offset on the file, and on the bytes saved m_saved_data_size = HEADER_SIZE; // We know we will have at least Misc, SystemInfo, Modules, and ThreadList - // (corresponding memory list for stacks) And an additional memory list for - // non-stacks. + // (corresponding memory list for stacks), an additional memory list for + // non-stacks, and a stream to mark this minidump was generated by LLDB. lldb_private::Target &target = m_process_sp->GetTarget(); m_expected_directories = 6; // Check if OS is linux and reserve directory space for all linux specific @@ -89,8 +89,11 @@ Status MinidumpFileBuilder::AddHeaderAndCalculateDirectories() { "Failed to fill in header and directory " "sections. Written / Expected (%" PRIx64 " / %" PRIx64 ")", new_offset, m_saved_data_size); - return error; + if (error.Fail()) + return error; + + return AddLLDBGeneratedStream(); } Status MinidumpFileBuilder::AddDirectory(StreamType type, @@ -126,6 +129,17 @@ Status MinidumpFileBuilder::AddDirectory(StreamType type, return error; } +Status MinidumpFileBuilder::AddLLDBGeneratedStream() { + Status error; + StreamType type = StreamType::LLDBGenerated; + error = AddDirectory(type, sizeof(StreamType)); + if (error.Fail()) + return error; + + error = AddData(&type, sizeof(StreamType)); + return error; +} + Status MinidumpFileBuilder::AddSystemInfo() { Status error; const llvm::Triple &target_triple = @@ -918,8 +932,8 @@ Status MinidumpFileBuilder::DumpHeader() const { 0u), // not used in most of the writers header.TimeDateStamp = static_cast<llvm::support::ulittle32_t>(std::time(nullptr)); - header.Flags = static_cast<llvm::support::ulittle64_t>( - llvm::minidump::Header::LLDB_HEADER_FLAG); + header.Flags = + static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag Status error; size_t bytes_written; diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h index 58b284608bd535..48293ee1bf5e56 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h +++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h @@ -120,6 +120,7 @@ class MinidumpFileBuilder { void DeleteFile() noexcept; private: + lldb_private::Status AddLLDBGeneratedStream(); // Add data to the end of the buffer, if the buffer exceeds the flush level, // trigger a flush. lldb_private::Status AddData(const void *data, uint64_t size); diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp index 6a328b3b841ed0..afc095ddbb2f91 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -20,8 +20,8 @@ #include <algorithm> #include <map> #include <optional> -#include <utility> #include <vector> +#include <utility> using namespace lldb_private; using namespace minidump; @@ -45,10 +45,6 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetData() { m_data_sp->GetByteSize()); } -const llvm::minidump::Header *MinidumpParser::GetHeader() const { - return reinterpret_cast<llvm::minidump::Header *>(m_file.get()); -} - llvm::ArrayRef<uint8_t> MinidumpParser::GetStream(StreamType stream_type) { return m_file->getRawStream(stream_type).value_or(llvm::ArrayRef<uint8_t>()); } @@ -74,7 +70,8 @@ UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) { if (GetArchitecture().GetTriple().isOSBinFormatELF()) { if (pdb70_uuid->Age != 0) return UUID(pdb70_uuid, sizeof(*pdb70_uuid)); - return UUID(&pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid)); + return UUID(&pdb70_uuid->Uuid, + sizeof(pdb70_uuid->Uuid)); } return UUID(*pdb70_uuid); } else if (cv_signature == CvSignature::ElfBuildId) @@ -456,12 +453,10 @@ MinidumpParser::FindMemoryRange(lldb::addr_t addr) { if (!GetStream(StreamType::Memory64List).empty()) { llvm::Error err = llvm::Error::success(); - for (const auto &memory_desc : GetMinidumpFile().getMemory64List(err)) { - if (memory_desc.first.StartOfMemoryRange <= addr && - addr < memory_desc.first.StartOfMemoryRange + - memory_desc.first.DataSize) { - return minidump::Range(memory_desc.first.StartOfMemoryRange, - memory_desc.second); + for (const auto &memory_desc : GetMinidumpFile().getMemory64List(err)) { + if (memory_desc.first.StartOfMemoryRange <= addr + && addr < memory_desc.first.StartOfMemoryRange + memory_desc.first.DataSize) { + return minidump::Range(memory_desc.first.StartOfMemoryRange, memory_desc.second); } } @@ -495,8 +490,7 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr, return range->range_ref.slice(offset, overlap); } -llvm::iterator_range<FallibleMemory64Iterator> -MinidumpParser::GetMemory64Iterator(llvm::Error &err) { +llvm::iterator_range<FallibleMemory64Iterator> MinidumpParser::GetMemory64Iterator(llvm::Error &err) { llvm::ErrorAsOutParameter ErrAsOutParam(&err); return m_file->getMemory64List(err); } @@ -608,7 +602,8 @@ std::pair<MemoryRegionInfos, bool> MinidumpParser::BuildMemoryRegions() { case StreamType::ST: \ return #ST -llvm::StringRef MinidumpParser::GetStreamTypeAsString(StreamType stream_type) { +llvm::StringRef +MinidumpParser::GetStreamTypeAsString(StreamType stream_type) { switch (stream_type) { ENUM_TO_CSTR(Unused); ENUM_TO_CSTR(ThreadList); diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/lldb/source/Plugins/Process/minidump/MinidumpParser.h index e13065264668c2..f0b6e6027c52f0 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.h +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.h @@ -47,8 +47,7 @@ struct Range { } }; -using FallibleMemory64Iterator = - llvm::object::MinidumpFile::FallibleMemory64Iterator; +using FallibleMemory64Iterator = llvm::object::MinidumpFile::FallibleMemory64Iterator; using ExceptionStreamsIterator = llvm::object::MinidumpFile::ExceptionStreamsIterator; @@ -57,8 +56,6 @@ class MinidumpParser { static llvm::Expected<MinidumpParser> Create(const lldb::DataBufferSP &data_buf_sp); - const llvm::minidump::Header *GetHeader() const; - llvm::ArrayRef<uint8_t> GetData(); llvm::ArrayRef<uint8_t> GetStream(StreamType stream_type); @@ -99,8 +96,7 @@ class MinidumpParser { /// complete (includes all regions mapped into the process memory). std::pair<MemoryRegionInfos, bool> BuildMemoryRegions(); - llvm::iterator_range<FallibleMemory64Iterator> - GetMemory64Iterator(llvm::Error &err); + llvm::iterator_range<FallibleMemory64Iterator> GetMemory64Iterator(llvm::Error &err); static llvm::StringRef GetStreamTypeAsString(StreamType stream_type); diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index e03e91887781d8..c44edd05304b13 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -138,8 +138,7 @@ lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, return nullptr; lldbassert(DataPtr->GetByteSize() == header_size); - if (identify_magic(toStringRef(DataPtr->GetData())) != - llvm::file_magic::minidump) + if (identify_magic(toStringRef(DataPtr->GetData())) != llvm::file_magic::minidump) return nullptr; auto AllData = @@ -345,11 +344,27 @@ ArchSpec ProcessMinidump::GetArchitecture() { return ArchSpec(triple); } -bool ProcessMinidump::IsLLDBMinidump() const { - const llvm::minidump::Header *header = m_minidump_parser->GetHeader(); - if (!header) +bool ProcessMinidump::IsLLDBMinidump() { + // If we've already checked, return the cached value + if (m_is_lldb_generated.has_value()) + return *m_is_lldb_generated; + + // If the minidump doesn't have a LLDBGeneratedStream, it's not an LLDB + // We also check to see if the section was generated correctly, but not + // enforcing an exact size so we can change it in the future without + // impacting older generated Minidumps. + llvm::ArrayRef<uint8_t> lldbStream = + m_minidump_parser->GetStream(StreamType::LLDBGenerated); + if (lldbStream.empty() || lldbStream.size() <= sizeof(StreamType)) { + m_is_lldb_generated = false; return false; - return (header->Flags & llvm::minidump::Header::LLDB_HEADER_FLAG) == 0; + } + + const uint32_t *lldbStreamType = + reinterpret_cast<const uint32_t *>(lldbStream.data()); + + m_is_lldb_generated = *lldbStreamType == (uint32_t)StreamType::LLDBGenerated; + return *m_is_lldb_generated; } DynamicLoader *ProcessMinidump::GetDynamicLoader() { @@ -505,8 +520,8 @@ void ProcessMinidump::ReadModuleList() { Log *log = GetLog(LLDBLog::DynamicLoader); for (auto module : filtered_modules) { - std::string name = cantFail( - m_minidump_parser->GetMinidumpFile().getString(module->ModuleNameRVA)); + std::string name = cantFail(m_minidump_parser->GetMinidumpFile().getString( + module->ModuleNameRVA)); const uint64_t load_addr = module->BaseOfImage; const uint64_t load_size = module->SizeOfImage; LLDB_LOG(log, "found module: name: {0} {1:x10}-{2:x10} size: {3}", name, @@ -525,8 +540,8 @@ void ProcessMinidump::ReadModuleList() { Status error; // Try and find a module with a full UUID that matches. This function will // add the module to the target if it finds one. - lldb::ModuleSP module_sp = - GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error); + lldb::ModuleSP module_sp = GetTarget().GetOrCreateModule(module_spec, + true /* notify */, &error); if (module_sp) { LLDB_LOG(log, "Full uuid match for {0}.", name); } else { @@ -550,8 +565,9 @@ void ProcessMinidump::ReadModuleList() { // we don't then we will end up setting the load address of a different // ObjectFilePlaceholder and an assertion will fire. auto *objfile = module_sp->GetObjectFile(); - if (objfile && objfile->GetPluginName() == - ObjectFilePlaceholder::GetPluginNameStatic()) { + if (objfile && + objfile->GetPluginName() == + ObjectFilePlaceholder::GetPluginNameStatic()) { if (((ObjectFilePlaceholder *)objfile)->GetBaseImageAddress() != load_addr) module_sp.reset(); @@ -581,7 +597,8 @@ void ProcessMinidump::ReadModuleList() { } bool load_addr_changed = false; - module_sp->SetLoadAddress(GetTarget(), load_addr, false, load_addr_changed); + module_sp->SetLoadAddress(GetTarget(), load_addr, false, + load_addr_changed); } } @@ -609,10 +626,10 @@ JITLoaderList &ProcessMinidump::GetJITLoaders() { return *m_jit_loaders_up; } -#define INIT_BOOL(VAR, LONG, SHORT, DESC) \ - VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true) -#define APPEND_OPT(VAR) \ - m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1) +#define INIT_BOOL(VAR, LONG, SHORT, DESC) \ + VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true) +#define APPEND_OPT(VAR) \ + m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1) class CommandObjectProcessMinidumpDump : public CommandObjectParsed { private: @@ -673,50 +690,55 @@ class CommandObjectProcessMinidumpDump : public CommandObjectParsed { // If no options were set, then dump everything m_dump_all.GetOptionValue().SetCurrentValue(true); } - bool DumpAll() const { return m_dump_all.GetOptionValue().GetCurrentValue(); } + bool DumpAll() const { + return m_dump_all.GetOptionValue().GetCurrentValue(); + } bool DumpDirectory() const { - return DumpAll() || m_dump_directory.GetOptionValue().GetCurrentValue(); + return DumpAll() || + m_dump_directory.GetOptionValue().GetCurrentValue(); } bool DumpLinux() const { return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue(); } bool DumpLinuxCPUInfo() const { return DumpLinux() || - m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue(); + m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue(); } bool DumpLinuxProcStatus() const { return DumpLinux() || - m_dump_linux_proc_status.GetOptionValue().GetCurrentValue(); + m_dump_linux_proc_status.GetOptionValue().GetCurrentValue(); } bool DumpLinuxProcStat() const { return DumpLinux() || - m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue(); + m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue(); } bool DumpLinuxLSBRelease() const { return DumpLinux() || - m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue(); + m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue(); } bool DumpLinuxCMDLine() const { return DumpLinux() || - m_dump_linux_cmdline.GetOptionValue().GetCurrentValue(); + m_dump_linux_cmdline.GetOptionValue().GetCurrentValue(); } bool DumpLinuxEnviron() const { return DumpLinux() || - m_dump_linux_environ.GetOptionValue().GetCurrentValue(); + m_dump_linux_environ.GetOptionValue().GetCurrentValue(); } bool DumpLinuxAuxv() const { - return DumpLinux() || m_dump_linux_auxv.GetOptionValue().GetCurrentValue(); + return DumpLinux() || + m_dump_linux_auxv.GetOptionValue().GetCurrentValue(); } bool DumpLinuxMaps() const { - return DumpLinux() || m_dump_linux_maps.GetOptionValue().GetCurrentValue(); + return DumpLinux() || + m_dump_linux_maps.GetOptionValue().GetCurrentValue(); } bool DumpLinuxProcUptime() const { return DumpLinux() || - m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue(); + m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue(); } bool DumpLinuxProcFD() const { return DumpLinux() || - m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue(); + m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue(); } bool DumpFacebook() const { return DumpAll() || m_fb_all.GetOptionValue().GetCurrentValue(); @@ -754,59 +776,60 @@ class CommandObjectProcessMinidumpDump : public CommandObjectParsed { bool DumpFacebookLogcat() const { return DumpFacebook() || m_fb_logcat.GetOptionValue().GetCurrentValue(); } - public: CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "process plugin dump", - "Dump information from the minidump file.", - nullptr), - m_option_group(), INIT_BOOL(m_dump_all, "all", 'a', - "Dump the everything in the minidump."), - INIT_BOOL(m_dump_directory, "directory", 'd', - "Dump the minidump directory map."), - INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C', - "Dump linux /proc/cpuinfo."), - INIT_BOOL(m_dump_linux_proc_status, "status", 's', - "Dump linux /proc/<pid>/status."), - INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r', - "Dump linux /etc/lsb-release."), - INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c', - "Dump linux /proc/<pid>/cmdline."), - INIT_BOOL(m_dump_linux_environ, "environ", 'e', - "Dump linux /proc/<pid>/environ."), - INIT_BOOL(m_dump_linux_auxv, "auxv", 'x', - "Dump linux /proc/<pid>/auxv."), - INIT_BOOL(m_dump_linux_maps, "maps", 'm', - "Dump linux /proc/<pid>/maps."), - INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S', - "Dump linux /proc/<pid>/stat."), - INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u', - "Dump linux process uptime."), - INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f', - "Dump linux /proc/<pid>/fd."), - INIT_BOOL(m_dump_linux_all, "linux", 'l', "Dump all linux streams."), - INIT_BOOL(m_fb_app_data, "fb-app-data", 1, - "Dump Facebook application custom data."), - INIT_BOOL(m_fb_build_id, "fb-build-id", 2, - "Dump the Facebook build ID."), - INIT_BOOL(m_fb_version, "fb-version", 3, - "Dump Facebook application version string."), - INIT_BOOL(m_fb_java_stack, "fb-java-stack", 4, - "Dump Facebook java stack."), - INIT_BOOL(m_fb_dalvik, "fb-dalvik-info", 5, - "Dump Facebook Dalvik info."), - INIT_BOOL(m_fb_unwind, "fb-unwind-symbols", 6, - "Dump Facebook unwind symbols."), - INIT_BOOL(m_fb_error_log, "fb-error-log", 7, - "Dump Facebook error log."), - INIT_BOOL(m_fb_app_state, "fb-app-state-log", 8, - "Dump Facebook java stack."), - INIT_BOOL(m_fb_abort, "fb-abort-reason", 9, - "Dump Facebook abort reason."), - INIT_BOOL(m_fb_thread, "fb-thread-name", 10, - "Dump Facebook thread name."), - INIT_BOOL(m_fb_logcat, "fb-logcat", 11, "Dump Facebook logcat."), - INIT_BOOL(m_fb_all, "facebook", 12, "Dump all Facebook streams.") { + : CommandObjectParsed(interpreter, "process plugin dump", + "Dump information from the minidump file.", nullptr), + m_option_group(), + INIT_BOOL(m_dump_all, "all", 'a', + "Dump the everything in the minidump."), + INIT_BOOL(m_dump_directory, "directory", 'd', + "Dump the minidump directory map."), + INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C', + "Dump linux /proc/cpuinfo."), + INIT_BOOL(m_dump_linux_proc_status, "status", 's', + "Dump linux /proc/<pid>/status."), + INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r', + "Dump linux /etc/lsb-release."), + INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c', + "Dump linux /proc/<pid>/cmdline."), + INIT_BOOL(m_dump_linux_environ, "environ", 'e', + "Dump linux /proc/<pid>/environ."), + INIT_BOOL(m_dump_linux_auxv, "auxv", 'x', + "Dump linux /proc/<pid>/auxv."), + INIT_BOOL(m_dump_linux_maps, "maps", 'm', + "Dump linux /proc/<pid>/maps."), + INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S', + "Dump linux /proc/<pid>/stat."), + INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u', + "Dump linux process uptime."), + INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f', + "Dump linux /proc/<pid>/fd."), + INIT_BOOL(m_dump_linux_all, "linux", 'l', + "Dump all linux streams."), + INIT_BOOL(m_fb_app_data, "fb-app-data", 1, + "Dump Facebook application custom data."), + INIT_BOOL(m_fb_build_id, "fb-build-id", 2, + "Dump the Facebook build ID."), + INIT_BOOL(m_fb_version, "fb-version", 3, + "Dump Facebook application version string."), + INIT_BOOL(m_fb_java_stack, "fb-java-stack", 4, + "Dump Facebook java stack."), + INIT_BOOL(m_fb_dalvik, "fb-dalvik-info", 5, + "Dump Facebook Dalvik info."), + INIT_BOOL(m_fb_unwind, "fb-unwind-symbols", 6, + "Dump Facebook unwind symbols."), + INIT_BOOL(m_fb_error_log, "fb-error-log", 7, + "Dump Facebook error log."), + INIT_BOOL(m_fb_app_state, "fb-app-state-log", 8, + "Dump Facebook java stack."), + INIT_BOOL(m_fb_abort, "fb-abort-reason", 9, + "Dump Facebook abort reason."), + INIT_BOOL(m_fb_thread, "fb-thread-name", 10, + "Dump Facebook thread name."), + INIT_BOOL(m_fb_logcat, "fb-logcat", 11, + "Dump Facebook logcat."), + INIT_BOOL(m_fb_all, "facebook", 12, "Dump all Facebook streams.") { APPEND_OPT(m_dump_all); APPEND_OPT(m_dump_directory); APPEND_OPT(m_dump_linux_cpuinfo); @@ -909,7 +932,8 @@ class CommandObjectProcessMinidumpDump : public CommandObjectParsed { if (DumpLinuxProcFD()) DumpTextStream(StreamType::LinuxProcFD, "/proc/PID/fd"); if (DumpFacebookAppData()) - DumpTextStream(StreamType::FacebookAppCustomData, "Facebook App Data"); + DumpTextStream(StreamType::FacebookAppCustomData, + "Facebook App Data"); if (DumpFacebookBuildID()) { auto bytes = minidump.GetStream(StreamType::FacebookBuildID); if (bytes.size() >= 4) { @@ -926,21 +950,26 @@ class CommandObjectProcessMinidumpDump : public CommandObjectParsed { DumpTextStream(StreamType::FacebookAppVersionName, "Facebook Version String"); if (DumpFacebookJavaStack()) - DumpTextStream(StreamType::FacebookJavaStack, "Facebook Java Stack"); + DumpTextStream(StreamType::FacebookJavaStack, + "Facebook Java Stack"); if (DumpFacebookDalvikInfo()) - DumpTextStream(StreamType::FacebookDalvikInfo, "Facebook Dalvik Info"); + DumpTextStream(StreamType::FacebookDalvikInfo, + "Facebook Dalvik Info"); if (DumpFacebookUnwindSymbols()) DumpBinaryStream(StreamType::FacebookUnwindSymbols, "Facebook Unwind Symbols Bytes"); if (DumpFacebookErrorLog()) - DumpTextStream(StreamType::FacebookDumpErrorLog, "Facebook Error Log"); + DumpTextStream(StreamType::FacebookDumpErrorLog, + "Facebook Error Log"); if (DumpFacebookAppStateLog()) DumpTextStream(StreamType::FacebookAppStateLog, "Faceook Application State Log"); if (DumpFacebookAbortReason()) - DumpTextStream(StreamType::FacebookAbortReason, "Facebook Abort Reason"); + DumpTextStream(StreamType::FacebookAbortReason, + "Facebook Abort Reason"); if (DumpFacebookThreadName()) - DumpTextStream(StreamType::FacebookThreadName, "Facebook Thread Name"); + DumpTextStream(StreamType::FacebookThreadName, + "Facebook Thread Name"); if (DumpFacebookLogcat()) DumpTextStream(StreamType::FacebookLogcat, "Facebook Logcat"); } @@ -949,12 +978,11 @@ class CommandObjectProcessMinidumpDump : public CommandObjectParsed { class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword { public: CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter) - : CommandObjectMultiword( - interpreter, "process plugin", - "Commands for operating on a ProcessMinidump process.", - "process plugin <subcommand> [<subcommand-options>]") { - LoadSubCommand("dump", CommandObjectSP(new CommandObjectProcessMinidumpDump( - interpreter))); + : CommandObjectMultiword(interpreter, "process plugin", + "Commands for operating on a ProcessMinidump process.", + "process plugin <subcommand> [<subcommand-options>]") { + LoadSubCommand("dump", + CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter))); } ~CommandObjectMultiwordProcessMinidump() override = default; diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h index 1cc1e8addb15d9..7525d8aae0f17b 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h @@ -76,8 +76,8 @@ class ProcessMinidump : public PostMortemProcess { ArchSpec GetArchitecture(); - Status - GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) override; + Status GetMemoryRegions( + lldb_private::MemoryRegionInfos ®ion_list) override; bool GetProcessInfo(ProcessInstanceInfo &info) override; @@ -106,6 +106,7 @@ class ProcessMinidump : public PostMortemProcess { JITLoaderList &GetJITLoaders() override; private: + std::optional<bool> m_is_lldb_generated; lldb::DataBufferSP m_core_data; llvm::ArrayRef<minidump::Thread> m_thread_list; std::unordered_map<uint32_t, const minidump::ExceptionStream> @@ -115,7 +116,7 @@ class ProcessMinidump : public PostMortemProcess { std::optional<MemoryRegionInfos> m_memory_regions; void BuildMemoryRegions(); - bool IsLLDBMinidump() const; + bool IsLLDBMinidump(); }; } // namespace minidump diff --git a/llvm/include/llvm/BinaryFormat/Minidump.h b/llvm/include/llvm/BinaryFormat/Minidump.h index 75762d3196dfcd..e587c6d94efaf8 100644 --- a/llvm/include/llvm/BinaryFormat/Minidump.h +++ b/llvm/include/llvm/BinaryFormat/Minidump.h @@ -32,10 +32,6 @@ LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); struct Header { static constexpr uint32_t MagicSignature = 0x504d444d; // PMDM static constexpr uint16_t MagicVersion = 0xa793; - // We set all the high bits flag to indicate this is from LLDB. - // We don't want to conflict with anything Microsoft is using the flags for - // and the highest bits are not currently being used. - static const uint32_t LLDB_HEADER_FLAG = 0xF0000000; support::ulittle32_t Signature; // The high 16 bits of version field are implementation specific. The low 16 @@ -56,6 +52,7 @@ enum class StreamType : uint32_t { #include "llvm/BinaryFormat/MinidumpConstants.def" Unused = 0, LastReserved = 0x0000ffff, + LLDBGenerated = 0x4C4C4442, // ASCII for 'LLDB' }; /// Specifies the location (and size) of various objects in the minidump file. >From 66de1462d63facad0dc1a1eafc1903c8ed934178 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde <jalalo...@fb.com> Date: Fri, 20 Dec 2024 13:31:47 -0800 Subject: [PATCH 3/4] Fix reversed logic, add the new stream type to the parsers ENUM_TO_STR switch. --- .../Process/minidump/MinidumpParser.cpp | 1 + .../Process/minidump/ProcessMinidump.cpp | 20 +++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp index afc095ddbb2f91..e3cb3dc84573c4 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -651,6 +651,7 @@ MinidumpParser::GetStreamTypeAsString(StreamType stream_type) { ENUM_TO_CSTR(FacebookAbortReason); ENUM_TO_CSTR(FacebookThreadName); ENUM_TO_CSTR(FacebookLogcat); + ENUM_TO_CSTR(LLDBGenerated); } return "unknown stream type"; } diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index c44edd05304b13..4c465730b5f1f7 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -344,6 +344,16 @@ ArchSpec ProcessMinidump::GetArchitecture() { return ArchSpec(triple); } +DataExtractor ProcessMinidump::GetAuxvData() { + std::optional<llvm::ArrayRef<uint8_t>> auxv = + m_minidump_parser->GetStream(StreamType::LinuxAuxv); + if (!auxv) + return DataExtractor(); + + return DataExtractor(auxv->data(), auxv->size(), GetByteOrder(), + GetAddressByteSize(), GetAddressByteSize()); +} + bool ProcessMinidump::IsLLDBMinidump() { // If we've already checked, return the cached value if (m_is_lldb_generated.has_value()) @@ -377,16 +387,6 @@ DynamicLoader *ProcessMinidump::GetDynamicLoader() { return nullptr; } -DataExtractor ProcessMinidump::GetAuxvData() { - std::optional<llvm::ArrayRef<uint8_t>> auxv = - m_minidump_parser->GetStream(StreamType::LinuxAuxv); - if (!auxv) - return DataExtractor(); - - return DataExtractor(auxv->data(), auxv->size(), GetByteOrder(), - GetAddressByteSize(), GetAddressByteSize()); -} - void ProcessMinidump::BuildMemoryRegions() { if (m_memory_regions) return; >From 2214e6c2017a1b224d1b35f9d6d39251a9b38e74 Mon Sep 17 00:00:00 2001 From: Jacob Lalonde <jalalo...@fb.com> Date: Mon, 23 Dec 2024 11:11:43 -0800 Subject: [PATCH 4/4] Support empty stream, remove magic bytes --- .../Minidump/MinidumpFileBuilder.cpp | 7 +----- .../Process/minidump/MinidumpParser.cpp | 4 ++++ .../Plugins/Process/minidump/MinidumpParser.h | 1 + .../Process/minidump/ProcessMinidump.cpp | 24 ++++--------------- .../Process/minidump/ProcessMinidump.h | 5 ++-- llvm/include/llvm/BinaryFormat/Minidump.h | 1 - .../llvm/BinaryFormat/MinidumpConstants.def | 4 ++++ 7 files changed, 16 insertions(+), 30 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp index 85ec42349b38d4..a715612328844c 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp @@ -132,12 +132,7 @@ Status MinidumpFileBuilder::AddDirectory(StreamType type, Status MinidumpFileBuilder::AddLLDBGeneratedStream() { Status error; StreamType type = StreamType::LLDBGenerated; - error = AddDirectory(type, sizeof(StreamType)); - if (error.Fail()) - return error; - - error = AddData(&type, sizeof(StreamType)); - return error; + return AddDirectory(type, 0); } Status MinidumpFileBuilder::AddSystemInfo() { diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp index e3cb3dc84573c4..eff099c9eab5e5 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -49,6 +49,10 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetStream(StreamType stream_type) { return m_file->getRawStream(stream_type).value_or(llvm::ArrayRef<uint8_t>()); } +std::optional<llvm::ArrayRef<uint8_t>> MinidumpParser::GetRawStream(StreamType stream_type) { + return m_file->getRawStream(stream_type); +} + UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) { auto cv_record = GetData().slice(module->CvRecord.RVA, module->CvRecord.DataSize); diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/lldb/source/Plugins/Process/minidump/MinidumpParser.h index f0b6e6027c52f0..2c5e6f19ff9a11 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.h +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.h @@ -59,6 +59,7 @@ class MinidumpParser { llvm::ArrayRef<uint8_t> GetData(); llvm::ArrayRef<uint8_t> GetStream(StreamType stream_type); + std::optional<llvm::ArrayRef<uint8_t>> GetRawStream(StreamType stream_type); UUID GetModuleUUID(const minidump::Module *module); diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index 4c465730b5f1f7..08c3bb3f6b66cb 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -355,28 +355,12 @@ DataExtractor ProcessMinidump::GetAuxvData() { } bool ProcessMinidump::IsLLDBMinidump() { - // If we've already checked, return the cached value - if (m_is_lldb_generated.has_value()) - return *m_is_lldb_generated; - - // If the minidump doesn't have a LLDBGeneratedStream, it's not an LLDB - // We also check to see if the section was generated correctly, but not - // enforcing an exact size so we can change it in the future without - // impacting older generated Minidumps. - llvm::ArrayRef<uint8_t> lldbStream = - m_minidump_parser->GetStream(StreamType::LLDBGenerated); - if (lldbStream.empty() || lldbStream.size() <= sizeof(StreamType)) { - m_is_lldb_generated = false; - return false; - } - - const uint32_t *lldbStreamType = - reinterpret_cast<const uint32_t *>(lldbStream.data()); - - m_is_lldb_generated = *lldbStreamType == (uint32_t)StreamType::LLDBGenerated; - return *m_is_lldb_generated; + std::optional<llvm::ArrayRef<uint8_t>> lldb_generated_section = + m_minidump_parser->GetRawStream(StreamType::LLDBGenerated); + return lldb_generated_section.has_value(); } + DynamicLoader *ProcessMinidump::GetDynamicLoader() { // This is a workaround for the dynamic loader not playing nice in issue // #119598. The specific reason we use the dynamic loader is to get the TLS diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h index 7525d8aae0f17b..ad8d0ed7a48329 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h @@ -76,8 +76,8 @@ class ProcessMinidump : public PostMortemProcess { ArchSpec GetArchitecture(); - Status GetMemoryRegions( - lldb_private::MemoryRegionInfos ®ion_list) override; + Status + GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) override; bool GetProcessInfo(ProcessInstanceInfo &info) override; @@ -106,7 +106,6 @@ class ProcessMinidump : public PostMortemProcess { JITLoaderList &GetJITLoaders() override; private: - std::optional<bool> m_is_lldb_generated; lldb::DataBufferSP m_core_data; llvm::ArrayRef<minidump::Thread> m_thread_list; std::unordered_map<uint32_t, const minidump::ExceptionStream> diff --git a/llvm/include/llvm/BinaryFormat/Minidump.h b/llvm/include/llvm/BinaryFormat/Minidump.h index e587c6d94efaf8..03497d4c5fa66f 100644 --- a/llvm/include/llvm/BinaryFormat/Minidump.h +++ b/llvm/include/llvm/BinaryFormat/Minidump.h @@ -52,7 +52,6 @@ enum class StreamType : uint32_t { #include "llvm/BinaryFormat/MinidumpConstants.def" Unused = 0, LastReserved = 0x0000ffff, - LLDBGenerated = 0x4C4C4442, // ASCII for 'LLDB' }; /// Specifies the location (and size) of various objects in the minidump file. diff --git a/llvm/include/llvm/BinaryFormat/MinidumpConstants.def b/llvm/include/llvm/BinaryFormat/MinidumpConstants.def index 5226da3e84126b..722a70ff67a9dc 100644 --- a/llvm/include/llvm/BinaryFormat/MinidumpConstants.def +++ b/llvm/include/llvm/BinaryFormat/MinidumpConstants.def @@ -85,6 +85,10 @@ HANDLE_MDMP_STREAM_TYPE(0xFACECCCC, FacebookAppStateLog) HANDLE_MDMP_STREAM_TYPE(0xFACEDEAD, FacebookAbortReason) HANDLE_MDMP_STREAM_TYPE(0xFACEE000, FacebookThreadName) +// LLDB specific stream types +// Ascii for 'LLDB' +HANDLE_MDMP_STREAM_TYPE(0x4C4C4442, LLDBGenerated) + HANDLE_MDMP_ARCH(0x0000, X86) // PROCESSOR_ARCHITECTURE_INTEL HANDLE_MDMP_ARCH(0x0001, MIPS) // PROCESSOR_ARCHITECTURE_MIPS HANDLE_MDMP_ARCH(0x0002, Alpha) // PROCESSOR_ARCHITECTURE_ALPHA _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits