[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92078)
via lldb-commits
lldb-commits at lists.llvm.org
Tue May 14 14:23:43 PDT 2024
https://github.com/GeorgeHuyubo updated https://github.com/llvm/llvm-project/pull/92078
>From 6073a22e4da334ac744e1662e8f43abfee4be4f2 Mon Sep 17 00:00:00 2001
From: George Hu <huyubohyb at gmail.com>
Date: Mon, 13 May 2024 17:03:30 -0700
Subject: [PATCH] Read and store gnu build id from loaded core file
---
lldb/include/lldb/Target/Process.h | 50 +++++++++++++++
lldb/source/Commands/CommandObjectMemory.cpp | 61 +------------------
.../Process/elf-core/ProcessElfCore.cpp | 50 +++++++++++++++
.../Plugins/Process/elf-core/ProcessElfCore.h | 11 ++++
lldb/source/Target/Process.cpp | 27 ++++++++
5 files changed, 140 insertions(+), 59 deletions(-)
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index aac0cf51680a9..03ee57a5e79b9 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -406,6 +406,36 @@ class Process : public std::enable_shared_from_this<Process>,
lldb::StateType state);
} Notifications;
+ class ProcessMemoryIterator {
+ public:
+ ProcessMemoryIterator(lldb::ProcessSP process_sp, lldb::addr_t base)
+ : m_process_sp(process_sp), m_base_addr(base) {
+ lldbassert(process_sp.get() != nullptr);
+ }
+
+ bool IsValid() { return m_is_valid; }
+
+ uint8_t operator[](lldb::addr_t offset) {
+ if (!IsValid())
+ return 0;
+
+ uint8_t retval = 0;
+ Status error;
+ if (0 ==
+ m_process_sp->ReadMemory(m_base_addr + offset, &retval, 1, error)) {
+ m_is_valid = false;
+ return 0;
+ }
+
+ return retval;
+ }
+
+ private:
+ lldb::ProcessSP m_process_sp;
+ lldb::addr_t m_base_addr;
+ bool m_is_valid = true;
+ };
+
class ProcessEventData : public EventData {
friend class Process;
@@ -1649,6 +1679,26 @@ class Process : public std::enable_shared_from_this<Process>,
lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error);
+ /// Find a string within a memory region.
+ ///
+ /// This function searches for the string represented by the provided buffer
+ /// within the memory range specified by the low and high addresses. It uses
+ /// a bad character heuristic to optimize the search process.
+ ///
+ /// \param[in] low The starting address of the memory region to be searched.
+ ///
+ /// \param[in] high The ending address of the memory region to be searched.
+ ///
+ /// \param[in] buffer A pointer to the buffer containing the string to be
+ /// searched.
+ ///
+ /// \param[in] buffer_size The size of the buffer in bytes.
+ ///
+ /// \return The address where the string was found or LLDB_INVALID_ADDRESS if
+ /// not found.
+ lldb::addr_t FindInMemory(lldb::addr_t low, lldb::addr_t high, uint8_t *buffer,
+ size_t buffer_size);
+
bool WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
Status &error);
diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp
index b78a0492cca55..1c13484dede64 100644
--- a/lldb/source/Commands/CommandObjectMemory.cpp
+++ b/lldb/source/Commands/CommandObjectMemory.cpp
@@ -977,35 +977,6 @@ class CommandObjectMemoryFind : public CommandObjectParsed {
Options *GetOptions() override { return &m_option_group; }
protected:
- class ProcessMemoryIterator {
- public:
- ProcessMemoryIterator(ProcessSP process_sp, lldb::addr_t base)
- : m_process_sp(process_sp), m_base_addr(base) {
- lldbassert(process_sp.get() != nullptr);
- }
-
- bool IsValid() { return m_is_valid; }
-
- uint8_t operator[](lldb::addr_t offset) {
- if (!IsValid())
- return 0;
-
- uint8_t retval = 0;
- Status error;
- if (0 ==
- m_process_sp->ReadMemory(m_base_addr + offset, &retval, 1, error)) {
- m_is_valid = false;
- return 0;
- }
-
- return retval;
- }
-
- private:
- ProcessSP m_process_sp;
- lldb::addr_t m_base_addr;
- bool m_is_valid = true;
- };
void DoExecute(Args &command, CommandReturnObject &result) override {
// No need to check "process" for validity as eCommandRequiresProcess
// ensures it is valid
@@ -1106,8 +1077,8 @@ class CommandObjectMemoryFind : public CommandObjectParsed {
found_location = low_addr;
bool ever_found = false;
while (count) {
- found_location = FastSearch(found_location, high_addr, buffer.GetBytes(),
- buffer.GetByteSize());
+ found_location = process->FindInMemory(
+ found_location, high_addr, buffer.GetBytes(), buffer.GetByteSize());
if (found_location == LLDB_INVALID_ADDRESS) {
if (!ever_found) {
result.AppendMessage("data not found within the range.\n");
@@ -1144,34 +1115,6 @@ class CommandObjectMemoryFind : public CommandObjectParsed {
result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
}
- lldb::addr_t FastSearch(lldb::addr_t low, lldb::addr_t high, uint8_t *buffer,
- size_t buffer_size) {
- const size_t region_size = high - low;
-
- if (region_size < buffer_size)
- return LLDB_INVALID_ADDRESS;
-
- std::vector<size_t> bad_char_heuristic(256, buffer_size);
- ProcessSP process_sp = m_exe_ctx.GetProcessSP();
- ProcessMemoryIterator iterator(process_sp, low);
-
- for (size_t idx = 0; idx < buffer_size - 1; idx++) {
- decltype(bad_char_heuristic)::size_type bcu_idx = buffer[idx];
- bad_char_heuristic[bcu_idx] = buffer_size - idx - 1;
- }
- for (size_t s = 0; s <= (region_size - buffer_size);) {
- int64_t j = buffer_size - 1;
- while (j >= 0 && buffer[j] == iterator[s + j])
- j--;
- if (j < 0)
- return low + s;
- else
- s += bad_char_heuristic[iterator[s + buffer_size - 1]];
- }
-
- return LLDB_INVALID_ADDRESS;
- }
-
OptionGroupOptions m_option_group;
OptionGroupFindMemory m_memory_options;
OptionGroupMemoryTag m_memory_tag_options;
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 36812c27a5b6d..4ff03eb8ab485 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -6,10 +6,12 @@
//
//===----------------------------------------------------------------------===//
+#include <cstddef>
#include <cstdlib>
#include <memory>
#include <mutex>
+#include <tuple>
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
@@ -210,6 +212,9 @@ Status ProcessElfCore::DoLoadCore() {
}
}
+ // We need to update uuid after address range is populated.
+ UpdateBuildIdForNTFileEntries();
+
if (!ranges_are_sorted) {
m_core_aranges.Sort();
m_core_range_infos.Sort();
@@ -258,6 +263,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 +277,16 @@ 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 = FindBuildId(entry);
+ if (uuid)
+ entry.uuid = uuid.value();
+ }
+ }
+}
+
lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
if (m_dyld_up.get() == nullptr)
m_dyld_up.reset(DynamicLoader::FindPlugin(
@@ -983,6 +999,40 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
}
}
+bool ProcessElfCore::IsElf(const NT_FILE_Entry entry) {
+ size_t size = strlen(llvm::ELF::ElfMagic);
+ uint8_t buf[size];
+ Status error;
+ size_t byte_read = ReadMemory(entry.start, buf, size, error);
+ if (byte_read == size)
+ return memcmp(llvm::ELF::ElfMagic, buf, size) == 0;
+ else
+ return false;
+}
+
+std::optional<UUID> ProcessElfCore::FindBuildId(const NT_FILE_Entry entry) {
+ if (!IsElf(entry))
+ return std::nullopt;
+ // Build ID is stored in the ELF file as a section named ".note.gnu.build-id"
+ uint8_t gnu_build_id_bytes[8] = {0x03, 0x00, 0x00, 0x00,
+ 0x47, 0x4e, 0x55, 0x00};
+ lldb::addr_t gnu_build_id_addr =
+ FindInMemory(entry.start, entry.end, gnu_build_id_bytes, 8);
+ if (gnu_build_id_addr == LLDB_INVALID_ADDRESS)
+ return std::nullopt;
+ uint8_t buf[36];
+ Status error;
+ size_t byte_read = ReadMemory(gnu_build_id_addr - 8, buf, 36, error);
+ // .note.gnu.build-id starts with 04 00 00 00 {id_byte_size} 00 00 00 03 00 00
+ // 00 47 4e 55 00
+ if (byte_read == 36) {
+ if (buf[0] == 0x04) {
+ return UUID(llvm::ArrayRef<uint8_t>(buf + 16, buf[4] /*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..ae827f3df002c 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -117,6 +117,8 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
lldb::addr_t end;
lldb::addr_t file_ofs;
std::string path;
+ lldb_private::UUID
+ uuid; // extracted from .note.gnu.build-id section from core file
};
// For ProcessElfCore only
@@ -158,6 +160,15 @@ 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 UUID of a given NT_FILE entry
+ std::optional<lldb_private::UUID> FindBuildId(const NT_FILE_Entry entry);
+
+ // Returns true if the given NT_FILE entry is an ELF file
+ bool IsElf(const NT_FILE_Entry entry);
+
// Parse a contiguous address range of the process from LOAD segment
lldb::addr_t
AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header);
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 25afade9a8275..4a3f0068a838b 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -3191,6 +3191,33 @@ Status Process::Halt(bool clear_thread_plans, bool use_run_lock) {
return Status();
}
+lldb::addr_t Process::FindInMemory(lldb::addr_t low, lldb::addr_t high,
+ uint8_t *buffer, size_t buffer_size) {
+ const size_t region_size = high - low;
+
+ if (region_size < buffer_size)
+ return LLDB_INVALID_ADDRESS;
+
+ std::vector<size_t> bad_char_heuristic(256, buffer_size);
+ ProcessMemoryIterator iterator(shared_from_this(), low);
+
+ for (size_t idx = 0; idx < buffer_size - 1; idx++) {
+ decltype(bad_char_heuristic)::size_type bcu_idx = buffer[idx];
+ bad_char_heuristic[bcu_idx] = buffer_size - idx - 1;
+ }
+ for (size_t s = 0; s <= (region_size - buffer_size);) {
+ int64_t j = buffer_size - 1;
+ while (j >= 0 && buffer[j] == iterator[s + j])
+ j--;
+ if (j < 0)
+ return low + s;
+ else
+ s += bad_char_heuristic[iterator[s + buffer_size - 1]];
+ }
+
+ return LLDB_INVALID_ADDRESS;
+}
+
Status Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) {
Status error;
More information about the lldb-commits
mailing list