https://github.com/GeorgeHuyubo updated https://github.com/llvm/llvm-project/pull/92492
>From a9714b155a116e9b1d18434c0485ea2ad35680f3 Mon Sep 17 00:00:00 2001 From: George Hu <huyubo...@gmail.com> Date: Tue, 14 May 2024 16:18:20 -0700 Subject: [PATCH] Read and store gnu build id from loaded core file --- .../Process/elf-core/ProcessElfCore.cpp | 74 ++++++++++++++++++- .../Plugins/Process/elf-core/ProcessElfCore.h | 10 +++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 36812c27a5b6d..0e0937b77f4b4 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -250,6 +250,9 @@ Status ProcessElfCore::DoLoadCore() { } } + // Try to find gnu build id before we load the executable. + UpdateBuildIdForNTFileEntries(); + // Core files are useless without the main executable. See if we can locate // the main executable using data we found in the core file notes. lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); @@ -258,6 +261,7 @@ Status ProcessElfCore::DoLoadCore() { if (!m_nt_file_entries.empty()) { ModuleSpec exe_module_spec; exe_module_spec.GetArchitecture() = arch; + exe_module_spec.GetUUID() = m_nt_file_entries[0].uuid; exe_module_spec.GetFileSpec().SetFile(m_nt_file_entries[0].path, FileSpec::Style::native); if (exe_module_spec.GetFileSpec()) { @@ -271,6 +275,14 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { + for (NT_FILE_Entry &entry : m_nt_file_entries) { + entry.uuid = FindBuidIdInCoreMemory(entry.start); + } + } +} + lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() { if (m_dyld_up.get() == nullptr) m_dyld_up.reset(DynamicLoader::FindPlugin( @@ -573,7 +585,6 @@ llvm::Expected<std::vector<CoreNote>> ProcessElfCore::parseSegment(const DataExtractor &segment) { lldb::offset_t offset = 0; std::vector<CoreNote> result; - while (offset < segment.GetByteSize()) { ELFNote note = ELFNote(); if (!note.Parse(segment, &offset)) @@ -983,6 +994,67 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +UUID ProcessElfCore::FindBuidIdInCoreMemory(lldb::addr_t address) { + UUID invalid_uuid; + const uint32_t addr_size = GetAddressByteSize(); + const size_t elf_header_size = addr_size == 4 ? sizeof(llvm::ELF::Elf32_Ehdr) + : sizeof(llvm::ELF::Elf64_Ehdr); + + // 80 bytes buffer is larger enough for the ELF header or program headers + unsigned char buf[80]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size || !elf::ELFHeader::MagicBytesMatch(buf)) + return invalid_uuid; + assert(sizeof(buf) >= elf_header_size); + DataExtractor elf_header_data(buf, elf_header_size, GetByteOrder(), + addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(elf_header_data, &offset); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { + byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); + if (byte_read != elf_header.e_phentsize) + break; + assert(sizeof(buf) >= elf_header.e_phentsize); + DataExtractor program_header_data(buf, elf_header.e_phentsize, + GetByteOrder(), addr_size); + offset = 0; + elf::ELFProgramHeader program_header; + program_header.Parse(program_header_data, &offset); + if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + + std::vector<uint8_t> note_bytes; + note_bytes.resize(program_header.p_memsz); + + byte_read = ReadMemory(program_header.p_vaddr, note_bytes.data(), + program_header.p_memsz, error); + if (byte_read != program_header.p_memsz) + continue; + assert(sizeof(buf) >= program_header.p_memsz); + DataExtractor segment_data(note_bytes.data(), note_bytes.size(), + GetByteOrder(), addr_size); + auto notes_or_error = parseSegment(segment_data); + if (!notes_or_error) + return invalid_uuid; + for (const CoreNote ¬e : *notes_or_error) { + if (note.info.n_namesz == 4 && + note.info.n_type == llvm::ELF::NT_GNU_BUILD_ID) { + if ("GNU" == note.info.n_name) + return UUID(llvm::ArrayRef<uint8_t>( + note.data.GetDataStart(), note.info.n_descsz /*byte size*/)); + } + } + } + return invalid_uuid; +} + uint32_t ProcessElfCore::GetNumThreadContexts() { if (!m_thread_data_valid) DoLoadCore(); diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h index 2cec635bbacfe..668a7c4846747 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -117,6 +117,10 @@ class ProcessElfCore : public lldb_private::PostMortemProcess { lldb::addr_t end; lldb::addr_t file_ofs; std::string path; + // Add a UUID member for convenient access. The UUID value is not in the + // NT_FILE entries, we will find it in core memory and store it here for + // easy access. + lldb_private::UUID uuid; }; // For ProcessElfCore only @@ -158,6 +162,12 @@ class ProcessElfCore : public lldb_private::PostMortemProcess { // Returns number of thread contexts stored in the core file uint32_t GetNumThreadContexts(); + // Populate gnu uuid for each NT_FILE entry + void UpdateBuildIdForNTFileEntries(); + + // Returns the value of certain type of note of a given start address + lldb_private::UUID FindBuidIdInCoreMemory(lldb::addr_t address); + // Parse a contiguous address range of the process from LOAD segment lldb::addr_t AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits