[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
via lldb-commits
lldb-commits at lists.llvm.org
Wed May 22 09:40:46 PDT 2024
https://github.com/GeorgeHuyubo updated https://github.com/llvm/llvm-project/pull/92492
>From 4e4ca8edc4116cba0925cca8229bd5b1cb002b21 Mon Sep 17 00:00:00 2001
From: George Hu <huyubohyb at 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 | 87 ++++++++++++++++++-
.../Plugins/Process/elf-core/ProcessElfCore.h | 14 ++-
2 files changed, 97 insertions(+), 4 deletions(-)
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 36812c27a5b6d..3a126220fabf0 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -6,11 +6,14 @@
//
//===----------------------------------------------------------------------===//
+#include <cstddef>
#include <cstdlib>
#include <memory>
#include <mutex>
+#include <tuple>
+#include "Plugins/ObjectFile/ELF/ELFHeader.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
@@ -33,6 +36,7 @@
#include "Plugins/Process/elf-core/RegisterUtilities.h"
#include "ProcessElfCore.h"
#include "ThreadElfCore.h"
+#include "lldb/lldb-types.h"
using namespace lldb_private;
namespace ELF = llvm::ELF;
@@ -250,6 +254,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 +265,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 +279,17 @@ Status ProcessElfCore::DoLoadCore() {
return error;
}
+void ProcessElfCore::UpdateBuildIdForNTFileEntries() {
+ if (!m_nt_file_entries.empty()) {
+ for (NT_FILE_Entry &entry : m_nt_file_entries) {
+ std::optional<UUID> uuid =
+ FindNoteInCoreMemory(entry.start, llvm::ELF::NT_GNU_BUILD_ID);
+ if (uuid)
+ entry.uuid = uuid.value();
+ }
+ }
+}
+
lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
if (m_dyld_up.get() == nullptr)
m_dyld_up.reset(DynamicLoader::FindPlugin(
@@ -570,11 +589,13 @@ static void ParseOpenBSDProcInfo(ThreadData &thread_data,
}
llvm::Expected<std::vector<CoreNote>>
-ProcessElfCore::parseSegment(const DataExtractor &segment) {
+ProcessElfCore::parseSegment(const DataExtractor &segment,
+ unsigned long segment_size) {
lldb::offset_t offset = 0;
std::vector<CoreNote> result;
-
- while (offset < segment.GetByteSize()) {
+ unsigned long note_size =
+ segment_size == 0 ? segment.GetByteSize() : segment_size;
+ while (offset < note_size) {
ELFNote note = ELFNote();
if (!note.Parse(segment, &offset))
return llvm::make_error<llvm::StringError>(
@@ -983,6 +1004,66 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
}
}
+bool ProcessElfCore::IsElf(lldb::addr_t address) {
+ uint8_t buf[4];
+ Status error;
+ size_t byte_read = ReadMemory(address, buf, 4, error);
+ if (byte_read != 4)
+ return false;
+ return elf::ELFHeader::MagicBytesMatch(buf);
+}
+
+std::optional<UUID> ProcessElfCore::FindNoteInCoreMemory(lldb::addr_t address,
+ uint32_t type) {
+ if (!IsElf(address))
+ return std::nullopt;
+ 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);
+
+ unsigned char buf[4096];
+ Status error;
+ size_t byte_read = ReadMemory(address, buf, elf_header_size, error);
+ if (byte_read != elf_header_size)
+ return std::nullopt;
+ DataExtractor data(buf, 4096, GetByteOrder(), addr_size);
+ lldb::offset_t offset = 0;
+
+ elf::ELFHeader elf_header;
+ elf_header.Parse(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;
+ offset = 0;
+ elf::ELFProgramHeader program_header;
+ program_header.Parse(data, &offset);
+ if (program_header.p_type != llvm::ELF::PT_NOTE)
+ continue;
+
+ byte_read =
+ ReadMemory(program_header.p_vaddr, buf, program_header.p_memsz, error);
+ if (byte_read != program_header.p_memsz)
+ continue;
+
+ auto notes_or_error = parseSegment(data, program_header.p_memsz);
+ if (!notes_or_error)
+ return std::nullopt;
+ for (const CoreNote ¬e : *notes_or_error) {
+ if (note.info.n_namesz == 4 && note.info.n_type == type) {
+ if ("GNU" == note.info.n_name)
+ return UUID(llvm::ArrayRef<uint8_t>(
+ note.data.GetDataStart(), note.info.n_descsz /*byte size*/));
+ }
+ }
+ }
+ return std::nullopt;
+}
+
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..84ae75cea02f9 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -117,6 +117,7 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
lldb::addr_t end;
lldb::addr_t file_ofs;
std::string path;
+ lldb_private::UUID uuid; //.note.gnu.build-id
};
// For ProcessElfCore only
@@ -158,6 +159,16 @@ 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
+ std::optional<lldb_private::UUID> FindNoteInCoreMemory(lldb::addr_t address,
+ uint32_t type);
+
+ // Returns true if the given address is a start of ELF file
+ bool IsElf(lldb::addr_t address);
+
// Parse a contiguous address range of the process from LOAD segment
lldb::addr_t
AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header);
@@ -167,7 +178,8 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
AddAddressRangeFromMemoryTagSegment(const elf::ELFProgramHeader &header);
llvm::Expected<std::vector<lldb_private::CoreNote>>
- parseSegment(const lldb_private::DataExtractor &segment);
+ parseSegment(const lldb_private::DataExtractor &segment,
+ unsigned long segment_size = 0);
llvm::Error parseFreeBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
llvm::Error parseNetBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
llvm::Error parseOpenBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
More information about the lldb-commits
mailing list