[Lldb-commits] [lldb] [LLDB] Impove ObjectFileELF's .dynamic parsing and usage. (PR #101237)
Greg Clayton via lldb-commits
lldb-commits at lists.llvm.org
Thu Aug 8 11:01:41 PDT 2024
https://github.com/clayborg updated https://github.com/llvm/llvm-project/pull/101237
>From f0cd3ef613b2da145b14a3d79d6810cc19e9b198 Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Tue, 30 Jul 2024 13:37:44 -0700
Subject: [PATCH 1/8] Impove ObjectFileELF's .dynamic parsing and usage.
This patch improves the ability of a ObjectFileELF instance to read the .dynamic section. It adds the ability to read the .dynamic section from a ELF file that is read from memory, cleans up the usage of the .dynamic entries so that ObjectFileELF::ParseDynamicSymbols() is the only code that parses .dynamic entries, teaches that function the read and store the string values for each .dynamic entry, and dumps the .dynamic entries in the output of "image dump objfile". It also cleans up the code that gets the dynamic string table and the .dynamic data from the ELF file.
---
lldb/include/lldb/Target/Process.h | 2 +-
.../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 356 +++++++++++++-----
.../Plugins/ObjectFile/ELF/ObjectFileELF.h | 38 +-
lldb/source/Target/Process.cpp | 15 +
.../ObjectFile/ELF/Inputs/memory-elf.cpp | 6 +
.../test/Shell/ObjectFile/ELF/elf-memory.test | 58 +++
6 files changed, 378 insertions(+), 97 deletions(-)
create mode 100644 lldb/test/Shell/ObjectFile/ELF/Inputs/memory-elf.cpp
create mode 100644 lldb/test/Shell/ObjectFile/ELF/elf-memory.test
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index c8475db8ae1609..17e18261b4752d 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1952,7 +1952,7 @@ class Process : public std::enable_shared_from_this<Process>,
lldb::ModuleSP ReadModuleFromMemory(const FileSpec &file_spec,
lldb::addr_t header_addr,
- size_t size_to_read = 512);
+ size_t size_to_read = 0);
/// Attempt to get the attributes for a region of memory in the process.
///
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 890db5c2748146..becee73f962058 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -873,33 +873,29 @@ Address ObjectFileELF::GetImageInfoAddress(Target *target) {
if (!section_list)
return Address();
- // Find the SHT_DYNAMIC (.dynamic) section.
- SectionSP dynsym_section_sp(
- section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true));
- if (!dynsym_section_sp)
- return Address();
- assert(dynsym_section_sp->GetObjectFile() == this);
-
- user_id_t dynsym_id = dynsym_section_sp->GetID();
- const ELFSectionHeaderInfo *dynsym_hdr = GetSectionHeaderByIndex(dynsym_id);
- if (!dynsym_hdr)
- return Address();
-
for (size_t i = 0; i < m_dynamic_symbols.size(); ++i) {
- ELFDynamic &symbol = m_dynamic_symbols[i];
+ const ELFDynamic &symbol = m_dynamic_symbols[i].symbol;
if (symbol.d_tag == DT_DEBUG) {
// Compute the offset as the number of previous entries plus the size of
// d_tag.
- addr_t offset = i * dynsym_hdr->sh_entsize + GetAddressByteSize();
- return Address(dynsym_section_sp, offset);
+ addr_t offset = (i * 2 + 1) * GetAddressByteSize();
+ addr_t file_addr = m_dynamic_base_addr + offset;
+ Address addr;
+ if (addr.ResolveAddressUsingFileSections(file_addr, GetSectionList()))
+ return addr;
}
// MIPS executables uses DT_MIPS_RLD_MAP_REL to support PIE. DT_MIPS_RLD_MAP
// exists in non-PIE.
else if ((symbol.d_tag == DT_MIPS_RLD_MAP ||
symbol.d_tag == DT_MIPS_RLD_MAP_REL) &&
target) {
- addr_t offset = i * dynsym_hdr->sh_entsize + GetAddressByteSize();
+ SectionSP dynsym_section_sp(section_list->FindSectionByType(
+ eSectionTypeELFDynamicLinkInfo, true));
+ if (!dynsym_section_sp)
+ return Address();
+
+ addr_t offset = (i * 2 + 1) * GetAddressByteSize();
addr_t dyn_base = dynsym_section_sp->GetLoadBaseAddress(target);
if (dyn_base == LLDB_INVALID_ADDRESS)
return Address();
@@ -970,62 +966,23 @@ Address ObjectFileELF::GetBaseAddress() {
return LLDB_INVALID_ADDRESS;
}
-// ParseDependentModules
size_t ObjectFileELF::ParseDependentModules() {
if (m_filespec_up)
return m_filespec_up->GetSize();
m_filespec_up = std::make_unique<FileSpecList>();
- if (!ParseSectionHeaders())
- return 0;
-
- SectionList *section_list = GetSectionList();
- if (!section_list)
- return 0;
-
- // Find the SHT_DYNAMIC section.
- Section *dynsym =
- section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true)
- .get();
- if (!dynsym)
- return 0;
- assert(dynsym->GetObjectFile() == this);
-
- const ELFSectionHeaderInfo *header = GetSectionHeaderByIndex(dynsym->GetID());
- if (!header)
- return 0;
- // sh_link: section header index of string table used by entries in the
- // section.
- Section *dynstr = section_list->FindSectionByID(header->sh_link).get();
- if (!dynstr)
- return 0;
-
- DataExtractor dynsym_data;
- DataExtractor dynstr_data;
- if (ReadSectionData(dynsym, dynsym_data) &&
- ReadSectionData(dynstr, dynstr_data)) {
- ELFDynamic symbol;
- const lldb::offset_t section_size = dynsym_data.GetByteSize();
- lldb::offset_t offset = 0;
-
- // The only type of entries we are concerned with are tagged DT_NEEDED,
- // yielding the name of a required library.
- while (offset < section_size) {
- if (!symbol.Parse(dynsym_data, &offset))
- break;
-
- if (symbol.d_tag != DT_NEEDED)
+ if (ParseDynamicSymbols()) {
+ for (const auto &entry : m_dynamic_symbols) {
+ if (entry.symbol.d_tag != DT_NEEDED)
continue;
-
- uint32_t str_index = static_cast<uint32_t>(symbol.d_val);
- const char *lib_name = dynstr_data.PeekCStr(str_index);
- FileSpec file_spec(lib_name);
- FileSystem::Instance().Resolve(file_spec);
- m_filespec_up->Append(file_spec);
+ if (!entry.name.empty()) {
+ FileSpec file_spec(entry.name);
+ FileSystem::Instance().Resolve(file_spec);
+ m_filespec_up->Append(file_spec);
+ }
}
}
-
return m_filespec_up->GetSize();
}
@@ -2472,48 +2429,47 @@ size_t ObjectFileELF::ParseDynamicSymbols() {
if (m_dynamic_symbols.size())
return m_dynamic_symbols.size();
- SectionList *section_list = GetSectionList();
- if (!section_list)
+ std::optional<DataExtractor> dynamic_data = GetDynamicData();
+ if (!dynamic_data)
return 0;
- // Find the SHT_DYNAMIC section.
- Section *dynsym =
- section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true)
- .get();
- if (!dynsym)
- return 0;
- assert(dynsym->GetObjectFile() == this);
-
- ELFDynamic symbol;
- DataExtractor dynsym_data;
- if (ReadSectionData(dynsym, dynsym_data)) {
- const lldb::offset_t section_size = dynsym_data.GetByteSize();
- lldb::offset_t cursor = 0;
-
- while (cursor < section_size) {
- if (!symbol.Parse(dynsym_data, &cursor))
+ ELFDynamicWithName e;
+ lldb::offset_t cursor = 0;
+ while (e.symbol.Parse(*dynamic_data, &cursor)) {
+ m_dynamic_symbols.push_back(e);
+ if (e.symbol.d_tag == DT_NULL)
+ break;
+ }
+ if (std::optional<DataExtractor> dynstr_data = GetDynstrData()) {
+ for (ELFDynamicWithName &entry : m_dynamic_symbols) {
+ switch (entry.symbol.d_tag) {
+ case DT_NEEDED:
+ case DT_SONAME:
+ case DT_RPATH:
+ case DT_RUNPATH:
+ case DT_AUXILIARY:
+ case DT_FILTER: {
+ lldb::offset_t cursor = entry.symbol.d_val;
+ const char *name = dynstr_data->GetCStr(&cursor);
+ if (name)
+ entry.name = name;
break;
-
- m_dynamic_symbols.push_back(symbol);
+ }
+ default:
+ break;
+ }
}
}
-
return m_dynamic_symbols.size();
}
const ELFDynamic *ObjectFileELF::FindDynamicSymbol(unsigned tag) {
if (!ParseDynamicSymbols())
return nullptr;
-
- DynamicSymbolCollIter I = m_dynamic_symbols.begin();
- DynamicSymbolCollIter E = m_dynamic_symbols.end();
- for (; I != E; ++I) {
- ELFDynamic *symbol = &*I;
-
- if (symbol->d_tag == tag)
- return symbol;
+ for (const auto &entry : m_dynamic_symbols) {
+ if (entry.symbol.d_tag == tag)
+ return &entry.symbol;
}
-
return nullptr;
}
@@ -3230,7 +3186,10 @@ void ObjectFileELF::Dump(Stream *s) {
ArchSpec header_arch = GetArchitecture();
*s << ", file = '" << m_file
- << "', arch = " << header_arch.GetArchitectureName() << "\n";
+ << "', arch = " << header_arch.GetArchitectureName();
+ if (m_memory_addr != LLDB_INVALID_ADDRESS)
+ s->Printf(", addr = %#16.16" PRIx64, m_memory_addr);
+ s->EOL();
DumpELFHeader(s, m_header);
s->EOL();
@@ -3248,6 +3207,8 @@ void ObjectFileELF::Dump(Stream *s) {
s->EOL();
DumpDependentModules(s);
s->EOL();
+ DumpELFDynamic(s);
+ s->EOL();
}
// DumpELFHeader
@@ -3492,6 +3453,111 @@ void ObjectFileELF::DumpDependentModules(lldb_private::Stream *s) {
}
}
+std::string static getDynamicTagAsString(uint16_t Arch, uint64_t Type) {
+#define DYNAMIC_STRINGIFY_ENUM(tag, value) \
+ case value: \
+ return #tag;
+
+#define DYNAMIC_TAG(n, v)
+ switch (Arch) {
+ case llvm::ELF::EM_AARCH64:
+ switch (Type) {
+#define AARCH64_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef AARCH64_DYNAMIC_TAG
+ }
+ break;
+
+ case llvm::ELF::EM_HEXAGON:
+ switch (Type) {
+#define HEXAGON_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef HEXAGON_DYNAMIC_TAG
+ }
+ break;
+
+ case llvm::ELF::EM_MIPS:
+ switch (Type) {
+#define MIPS_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef MIPS_DYNAMIC_TAG
+ }
+ break;
+
+ case llvm::ELF::EM_PPC:
+ switch (Type) {
+#define PPC_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef PPC_DYNAMIC_TAG
+ }
+ break;
+
+ case llvm::ELF::EM_PPC64:
+ switch (Type) {
+#define PPC64_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef PPC64_DYNAMIC_TAG
+ }
+ break;
+
+ case llvm::ELF::EM_RISCV:
+ switch (Type) {
+#define RISCV_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef RISCV_DYNAMIC_TAG
+ }
+ break;
+ }
+#undef DYNAMIC_TAG
+ switch (Type) {
+// Now handle all dynamic tags except the architecture specific ones
+#define AARCH64_DYNAMIC_TAG(name, value)
+#define MIPS_DYNAMIC_TAG(name, value)
+#define HEXAGON_DYNAMIC_TAG(name, value)
+#define PPC_DYNAMIC_TAG(name, value)
+#define PPC64_DYNAMIC_TAG(name, value)
+#define RISCV_DYNAMIC_TAG(name, value)
+// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc.
+#define DYNAMIC_TAG_MARKER(name, value)
+#define DYNAMIC_TAG(name, value) \
+ case value: \
+ return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef DYNAMIC_TAG
+#undef AARCH64_DYNAMIC_TAG
+#undef MIPS_DYNAMIC_TAG
+#undef HEXAGON_DYNAMIC_TAG
+#undef PPC_DYNAMIC_TAG
+#undef PPC64_DYNAMIC_TAG
+#undef RISCV_DYNAMIC_TAG
+#undef DYNAMIC_TAG_MARKER
+#undef DYNAMIC_STRINGIFY_ENUM
+ default:
+ return "<unknown:>0x" + llvm::utohexstr(Type, true);
+ }
+}
+
+void ObjectFileELF::DumpELFDynamic(lldb_private::Stream *s) {
+ ParseDynamicSymbols();
+ if (m_dynamic_symbols.empty())
+ return;
+
+ s->PutCString(".dynamic:\n");
+ s->PutCString("IDX d_tag d_val/d_ptr\n");
+ s->PutCString("==== ---------------- ------------------\n");
+ uint32_t idx = 0;
+ for (const auto &entry : m_dynamic_symbols) {
+ s->Printf("[%2u] ", idx++);
+ s->Printf(
+ "%-16s 0x%16.16" PRIx64,
+ getDynamicTagAsString(m_header.e_machine, entry.symbol.d_tag).c_str(),
+ entry.symbol.d_ptr);
+ if (!entry.name.empty())
+ s->Printf(" \"%s\"", entry.name.c_str());
+ s->EOL();
+ }
+}
+
ArchSpec ObjectFileELF::GetArchitecture() {
if (!ParseHeader())
return ArchSpec();
@@ -3664,7 +3730,27 @@ llvm::ArrayRef<ELFProgramHeader> ObjectFileELF::ProgramHeaders() {
}
DataExtractor ObjectFileELF::GetSegmentData(const ELFProgramHeader &H) {
- return DataExtractor(m_data, H.p_offset, H.p_filesz);
+ // Try and read the program header from our cached m_data which can come from
+ // the file on disk being mmap'ed or from the initial part of the ELF file we
+ // read from memory and cached.
+ DataExtractor data = DataExtractor(m_data, H.p_offset, H.p_filesz);
+ if (data.GetByteSize() == H.p_filesz)
+ return data;
+ if (IsInMemory()) {
+ // We have a ELF file in process memory, read the program header data from
+ // the process.
+ ProcessSP process_sp(m_process_wp.lock());
+ if (process_sp) {
+ const lldb::offset_t base_file_addr = GetBaseAddress().GetFileAddress();
+ // const addr_t data_addr = m_memory_addr + H.p_offset; // Not correct for
+ // some files
+ const addr_t data_addr = H.p_vaddr - base_file_addr + m_memory_addr;
+ DataBufferSP data_sp = ReadMemory(process_sp, data_addr, H.p_memsz);
+ if (data_sp)
+ return DataExtractor(data_sp, GetByteOrder(), GetAddressByteSize());
+ }
+ }
+ return DataExtractor();
}
bool ObjectFileELF::AnySegmentHasPhysicalAddress() {
@@ -3704,3 +3790,83 @@ ObjectFileELF::MapFileDataWritable(const FileSpec &file, uint64_t Size,
return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size,
Offset);
}
+
+std::optional<DataExtractor> ObjectFileELF::GetDynstrData() {
+
+ SectionList *section_list = GetSectionList();
+ if (section_list) {
+ // Find the SHT_DYNAMIC section.
+ Section *dynamic =
+ section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true)
+ .get();
+ if (dynamic) {
+ assert(dynamic->GetObjectFile() == this);
+ const ELFSectionHeaderInfo *header =
+ GetSectionHeaderByIndex(dynamic->GetID());
+ if (header) {
+ // sh_link: section header index of string table used by entries in
+ // the section.
+ Section *dynstr = section_list->FindSectionByID(header->sh_link).get();
+ DataExtractor data;
+ if (dynstr && ReadSectionData(dynstr, data))
+ return data;
+ }
+ }
+ }
+
+ // Every ELF file which represents an executable or shared library has
+ // mandatory .dynamic entries. Two of these values are DT_STRTAB and DT_STRSZ
+ // and represent the dynamic symbol tables's string table. These are needed
+ // by the dynamic loader and we can read them from a process' address space.
+ //
+ // When loading and ELF file from memory, only the program headers end up
+ // being mapped into memory, and we can find these values in the PT_DYNAMIC
+ // segment.
+ if (!IsInMemory())
+ return std::nullopt;
+ ProcessSP process_sp(m_process_wp.lock());
+ if (!process_sp)
+ return std::nullopt;
+
+ const ELFDynamic *strtab = FindDynamicSymbol(DT_STRTAB);
+ const ELFDynamic *strsz = FindDynamicSymbol(DT_STRSZ);
+ if (strtab == nullptr || strsz == nullptr)
+ return std::nullopt;
+
+ DataBufferSP data_sp = ReadMemory(process_sp, strtab->d_ptr, strsz->d_val);
+ if (!data_sp)
+ return std::nullopt;
+ return DataExtractor(data_sp, GetByteOrder(), GetAddressByteSize());
+}
+
+std::optional<lldb_private::DataExtractor> ObjectFileELF::GetDynamicData() {
+ DataExtractor data;
+ // The PT_DYNAMIC program header describes where the .dynamic section is and
+ // doesn't require parsing section headers. The PT_DYNAMIC is required by
+ // executables and shared libraries so it will always be available.
+ for (const ELFProgramHeader &H : ProgramHeaders()) {
+ if (H.p_type == llvm::ELF::PT_DYNAMIC) {
+ data = GetSegmentData(H);
+ if (data.GetByteSize() > 0) {
+ m_dynamic_base_addr = H.p_vaddr;
+ return data;
+ }
+ }
+ }
+ // Fall back to using section headers.
+ SectionList *section_list = GetSectionList();
+ if (section_list) {
+ // Find the SHT_DYNAMIC section.
+ Section *dynamic =
+ section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true)
+ .get();
+ if (dynamic) {
+ assert(dynamic->GetObjectFile() == this);
+ if (ReadSectionData(dynamic, data)) {
+ m_dynamic_base_addr = dynamic->GetFileAddress();
+ return data;
+ }
+ }
+ }
+ return std::nullopt;
+}
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index 844e981b1d890a..cb3883019727d0 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -183,7 +183,11 @@ class ObjectFileELF : public lldb_private::ObjectFile {
typedef SectionHeaderColl::iterator SectionHeaderCollIter;
typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter;
- typedef std::vector<elf::ELFDynamic> DynamicSymbolColl;
+ struct ELFDynamicWithName {
+ elf::ELFDynamic symbol;
+ std::string name;
+ };
+ typedef std::vector<ELFDynamicWithName> DynamicSymbolColl;
typedef DynamicSymbolColl::iterator DynamicSymbolCollIter;
typedef DynamicSymbolColl::const_iterator DynamicSymbolCollConstIter;
@@ -213,6 +217,10 @@ class ObjectFileELF : public lldb_private::ObjectFile {
/// Collection of section headers.
SectionHeaderColl m_section_headers;
+ /// The file address of the .dynamic section. This can be found in the p_vaddr
+ /// of the PT_DYNAMIC program header.
+ lldb::addr_t m_dynamic_base_addr = LLDB_INVALID_ADDRESS;
+
/// Collection of symbols from the dynamic table.
DynamicSymbolColl m_dynamic_symbols;
@@ -384,6 +392,9 @@ class ObjectFileELF : public lldb_private::ObjectFile {
/// ELF dependent module dump routine.
void DumpDependentModules(lldb_private::Stream *s);
+ /// ELF dump the .dynamic section
+ void DumpELFDynamic(lldb_private::Stream *s);
+
const elf::ELFDynamic *FindDynamicSymbol(unsigned tag);
unsigned PLTRelocationType();
@@ -402,6 +413,31 @@ class ObjectFileELF : public lldb_private::ObjectFile {
/// .gnu_debugdata section or \c nullptr if an error occured or if there's no
/// section with that name.
std::shared_ptr<ObjectFileELF> GetGnuDebugDataObjectFile();
+
+ /// Get the bytes that represent the .dynamic section.
+ ///
+ /// This function will fetch the data for the .dynamic section in an ELF file.
+ /// If the ELF file is loaded from a file on disk, it will use the PT_DYNAMIC
+ /// program header to extract the data and fall back to using the section
+ /// headers. If the ELF file is loaded from memory, it will use the PT_DYNAMIC
+ /// program header to get the information.
+ ///
+ /// \return The bytes that represent the string table data or \c std::nullopt
+ /// if an error occured.
+ std::optional<lldb_private::DataExtractor> GetDynamicData();
+
+ /// Get the bytes that represent the dynamic string table data.
+ ///
+ /// This function will fetch the data for the string table in an ELF file. If
+ /// the ELF file is loaded from a file on disk, it will use the section
+ /// headers to extract the data. If the ELF file is loaded from memory, it
+ /// will use .dynamic entries to read the information.
+ ///
+ /// \return The bytes that represent the string table data or \c std::nullopt
+ /// if an error occured.
+ std::optional<lldb_private::DataExtractor> GetDynstrData();
+
+
};
#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index d5a639d9beacd9..65f78f63a5c7c6 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -2550,6 +2550,21 @@ ModuleSP Process::ReadModuleFromMemory(const FileSpec &file_spec,
}
ModuleSP module_sp(new Module(file_spec, ArchSpec()));
if (module_sp) {
+ if (size_to_read == 0) {
+ // Default to 8192 in case we can't find a memory region.
+ size_to_read = 0x2000;
+ MemoryRegionInfo range_info;
+ Status error(GetMemoryRegionInfo(header_addr, range_info));
+ if (error.Success()) {
+ // We found a memory region, set the range of bytes ro read to read to
+ // the end of the memory region. This should be enough to contain the
+ // file header and important bits.
+ const auto &range = range_info.GetRange();
+ addr_t end = range.GetRangeBase() + range.GetByteSize();
+ if (end > header_addr)
+ size_to_read = end - header_addr;
+ }
+ }
Status error;
std::unique_ptr<Progress> progress_up;
// Reading an ObjectFile from a local corefile is very fast,
diff --git a/lldb/test/Shell/ObjectFile/ELF/Inputs/memory-elf.cpp b/lldb/test/Shell/ObjectFile/ELF/Inputs/memory-elf.cpp
new file mode 100644
index 00000000000000..f4162a4a1d5fc7
--- /dev/null
+++ b/lldb/test/Shell/ObjectFile/ELF/Inputs/memory-elf.cpp
@@ -0,0 +1,6 @@
+#include <stdio.h>
+int main() {
+ printf("Hello World\n"); // Use something from libc.so
+ return 0;
+}
+
diff --git a/lldb/test/Shell/ObjectFile/ELF/elf-memory.test b/lldb/test/Shell/ObjectFile/ELF/elf-memory.test
new file mode 100644
index 00000000000000..2b1d716597bc59
--- /dev/null
+++ b/lldb/test/Shell/ObjectFile/ELF/elf-memory.test
@@ -0,0 +1,58 @@
+// REQUIRES: system-linux, native
+
+// This test verifies that loading and ELF file from memory works and the new
+// features that were added when loading from memory work like:
+// - Loading the .dynamic section from the PT_DYNAMIC since ELF files loaded
+// from memory don't have the section headers available.
+// - Loading the symbol table from the DT_SYMTAB dynamic entries.
+// This test will make a simple executable that:
+// - links against libc
+// - runs and stops at a breakpoint
+// -
+
+// RUN: %clang_host %p/Inputs/memory-elf.cpp -g -O0 -o %t
+
+// RUN: %lldb %t -b \
+// RUN: -o "b main" \
+// RUN: -o "run" \
+// RUN: -o "script real_module = lldb.target.module[0]" \
+// RUN: -o "script base_addr = real_module.GetObjectFileHeaderAddress().GetLoadAddress(lldb.target)" \
+// RUN: -o "script mem_module = lldb.SBModule(lldb.process, base_addr)" \
+// RUN: -o "script target2 = lldb.debugger.CreateTarget('')" \
+// RUN: -o "script target2.AddModule(mem_module)" \
+// RUN: -o "target select 1" \
+// RUN: -o "image dump objfile" \
+// RUN: | FileCheck %s --check-prefix=MAIN --dump-input=always
+// MAIN: (lldb) image dump objfile
+// MAIN: Dumping headers for 1 module(s).
+// MAIN: ObjectFileELF, file = '', arch = {{.*, addr = 0x[0-9a-f]+}}
+// MAIN: ELF Header
+
+// Make sure we find the program headers and see a PT_DYNAMIC entry.
+// MAIN: Program Headers
+// MAIN: ] PT_DYNAMIC
+
+// Make sure we see some sections created from the program headers
+// MAIN: SectID
+// MAIN: PT_LOAD[0]
+
+// Test we find some symbols in the symbol table
+// MAIN: Symtab, num_symbols =
+
+// Ensure we find some dependent modules as won't find these if we aren't able
+// to load the .dynamic section from the PT_DYNAMIC program header.
+// MAIN: Dependent Modules:
+
+// Check for the .dynamic dump and ensure we find all dynamic entries that are
+// required to be there and needed to get the .dynstr section and the symbol
+// table, and the DT_DEBUG entry to find the list of shared libraries.
+// MAIN: .dynamic:
+// Make sure we found the .dynstr section by checking for valid strings after NEEDED
+// MAIN-DAG: NEEDED {{0x[0-9a-f]+ ".*libc.*"}}
+// MAIN-DAG: STRTAB {{0x[0-9a-f]+}}
+// MAIN-DAG: SYMTAB {{0x[0-9a-f]+}}
+// MAIN-DAG: STRSZ {{0x[0-9a-f]+}}
+// MAIN-DAG: SYMENT {{0x[0-9a-f]+}}
+// MAIN-DAG: DEBUG {{0x[0-9a-f]+}}
+// MAIN: NULL {{0x[0-9a-f]+}}
+
>From 7eeecd2c82b8599ec5d07414b734c3e5b76a3ce4 Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Tue, 30 Jul 2024 15:21:05 -0700
Subject: [PATCH 2/8] Ran git-clang-format to fix clang format issues.
---
lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 6 +++---
lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h | 2 --
lldb/test/Shell/ObjectFile/ELF/Inputs/memory-elf.cpp | 1 -
3 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index becee73f962058..ee891a5182d535 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -3208,7 +3208,7 @@ void ObjectFileELF::Dump(Stream *s) {
DumpDependentModules(s);
s->EOL();
DumpELFDynamic(s);
- s->EOL();
+ s->EOL();
}
// DumpELFHeader
@@ -3797,8 +3797,8 @@ std::optional<DataExtractor> ObjectFileELF::GetDynstrData() {
if (section_list) {
// Find the SHT_DYNAMIC section.
Section *dynamic =
- section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true)
- .get();
+ section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true)
+ .get();
if (dynamic) {
assert(dynamic->GetObjectFile() == this);
const ELFSectionHeaderInfo *header =
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index cb3883019727d0..ae2025ba2cedbf 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -436,8 +436,6 @@ class ObjectFileELF : public lldb_private::ObjectFile {
/// \return The bytes that represent the string table data or \c std::nullopt
/// if an error occured.
std::optional<lldb_private::DataExtractor> GetDynstrData();
-
-
};
#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H
diff --git a/lldb/test/Shell/ObjectFile/ELF/Inputs/memory-elf.cpp b/lldb/test/Shell/ObjectFile/ELF/Inputs/memory-elf.cpp
index f4162a4a1d5fc7..9cae6c99c9f761 100644
--- a/lldb/test/Shell/ObjectFile/ELF/Inputs/memory-elf.cpp
+++ b/lldb/test/Shell/ObjectFile/ELF/Inputs/memory-elf.cpp
@@ -3,4 +3,3 @@ int main() {
printf("Hello World\n"); // Use something from libc.so
return 0;
}
-
>From 8b72ff54ed1a6224c5235bcd42267280e7367cde Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Thu, 1 Aug 2024 14:19:50 -0700
Subject: [PATCH 3/8] Respond to user feedback.
---
.../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 59 +++++++++----------
.../test/Shell/ObjectFile/ELF/elf-memory.test | 6 +-
2 files changed, 29 insertions(+), 36 deletions(-)
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index ee891a5182d535..d26215a9ce3f22 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -2452,7 +2452,7 @@ size_t ObjectFileELF::ParseDynamicSymbols() {
lldb::offset_t cursor = entry.symbol.d_val;
const char *name = dynstr_data->GetCStr(&cursor);
if (name)
- entry.name = name;
+ entry.name = std::string(name);
break;
}
default:
@@ -3739,14 +3739,11 @@ DataExtractor ObjectFileELF::GetSegmentData(const ELFProgramHeader &H) {
if (IsInMemory()) {
// We have a ELF file in process memory, read the program header data from
// the process.
- ProcessSP process_sp(m_process_wp.lock());
- if (process_sp) {
+ if (ProcessSP process_sp = m_process_wp.lock()) {
const lldb::offset_t base_file_addr = GetBaseAddress().GetFileAddress();
- // const addr_t data_addr = m_memory_addr + H.p_offset; // Not correct for
- // some files
- const addr_t data_addr = H.p_vaddr - base_file_addr + m_memory_addr;
- DataBufferSP data_sp = ReadMemory(process_sp, data_addr, H.p_memsz);
- if (data_sp)
+ const addr_t load_bias = m_memory_addr - base_file_addr;
+ const addr_t data_addr = H.p_vaddr + load_bias;
+ if (DataBufferSP data_sp = ReadMemory(process_sp, data_addr, H.p_memsz))
return DataExtractor(data_sp, GetByteOrder(), GetAddressByteSize());
}
}
@@ -3792,24 +3789,23 @@ ObjectFileELF::MapFileDataWritable(const FileSpec &file, uint64_t Size,
}
std::optional<DataExtractor> ObjectFileELF::GetDynstrData() {
-
- SectionList *section_list = GetSectionList();
- if (section_list) {
+ if (SectionList *section_list = GetSectionList()) {
// Find the SHT_DYNAMIC section.
- Section *dynamic =
- section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true)
- .get();
- if (dynamic) {
+ if (Section *dynamic =
+ section_list
+ ->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true)
+ .get()) {
assert(dynamic->GetObjectFile() == this);
- const ELFSectionHeaderInfo *header =
- GetSectionHeaderByIndex(dynamic->GetID());
- if (header) {
+ if (const ELFSectionHeaderInfo *header =
+ GetSectionHeaderByIndex(dynamic->GetID())) {
// sh_link: section header index of string table used by entries in
// the section.
- Section *dynstr = section_list->FindSectionByID(header->sh_link).get();
- DataExtractor data;
- if (dynstr && ReadSectionData(dynstr, data))
- return data;
+ if (Section *dynstr =
+ section_list->FindSectionByID(header->sh_link).get()) {
+ DataExtractor data;
+ if (ReadSectionData(dynstr, data))
+ return data;
+ }
}
}
}
@@ -3833,10 +3829,10 @@ std::optional<DataExtractor> ObjectFileELF::GetDynstrData() {
if (strtab == nullptr || strsz == nullptr)
return std::nullopt;
- DataBufferSP data_sp = ReadMemory(process_sp, strtab->d_ptr, strsz->d_val);
- if (!data_sp)
- return std::nullopt;
- return DataExtractor(data_sp, GetByteOrder(), GetAddressByteSize());
+ if (DataBufferSP data_sp =
+ ReadMemory(process_sp, strtab->d_ptr, strsz->d_val))
+ return DataExtractor(data_sp, GetByteOrder(), GetAddressByteSize());
+ return std::nullopt;
}
std::optional<lldb_private::DataExtractor> ObjectFileELF::GetDynamicData() {
@@ -3854,13 +3850,12 @@ std::optional<lldb_private::DataExtractor> ObjectFileELF::GetDynamicData() {
}
}
// Fall back to using section headers.
- SectionList *section_list = GetSectionList();
- if (section_list) {
+ if (SectionList *section_list = GetSectionList()) {
// Find the SHT_DYNAMIC section.
- Section *dynamic =
- section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true)
- .get();
- if (dynamic) {
+ if (Section *dynamic =
+ section_list
+ ->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true)
+ .get()) {
assert(dynamic->GetObjectFile() == this);
if (ReadSectionData(dynamic, data)) {
m_dynamic_base_addr = dynamic->GetFileAddress();
diff --git a/lldb/test/Shell/ObjectFile/ELF/elf-memory.test b/lldb/test/Shell/ObjectFile/ELF/elf-memory.test
index 2b1d716597bc59..37deda4a26d6b5 100644
--- a/lldb/test/Shell/ObjectFile/ELF/elf-memory.test
+++ b/lldb/test/Shell/ObjectFile/ELF/elf-memory.test
@@ -2,13 +2,12 @@
// This test verifies that loading and ELF file from memory works and the new
// features that were added when loading from memory work like:
-// - Loading the .dynamic section from the PT_DYNAMIC since ELF files loaded
+// - Loading the .dynamic section from the PT_DYNAMIC since ELF files loaded
// from memory don't have the section headers available.
// - Loading the symbol table from the DT_SYMTAB dynamic entries.
// This test will make a simple executable that:
// - links against libc
// - runs and stops at a breakpoint
-// -
// RUN: %clang_host %p/Inputs/memory-elf.cpp -g -O0 -o %t
@@ -44,7 +43,7 @@
// MAIN: Dependent Modules:
// Check for the .dynamic dump and ensure we find all dynamic entries that are
-// required to be there and needed to get the .dynstr section and the symbol
+// required to be there and needed to get the .dynstr section and the symbol
// table, and the DT_DEBUG entry to find the list of shared libraries.
// MAIN: .dynamic:
// Make sure we found the .dynstr section by checking for valid strings after NEEDED
@@ -55,4 +54,3 @@
// MAIN-DAG: SYMENT {{0x[0-9a-f]+}}
// MAIN-DAG: DEBUG {{0x[0-9a-f]+}}
// MAIN: NULL {{0x[0-9a-f]+}}
-
>From b412cf2ca21d5cf40486ea55946a7aea43ee9607 Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Thu, 1 Aug 2024 16:23:18 -0700
Subject: [PATCH 4/8] Fix comment.
---
lldb/test/Shell/ObjectFile/ELF/elf-memory.test | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/test/Shell/ObjectFile/ELF/elf-memory.test b/lldb/test/Shell/ObjectFile/ELF/elf-memory.test
index 37deda4a26d6b5..253b233b991102 100644
--- a/lldb/test/Shell/ObjectFile/ELF/elf-memory.test
+++ b/lldb/test/Shell/ObjectFile/ELF/elf-memory.test
@@ -1,6 +1,6 @@
// REQUIRES: system-linux, native
-// This test verifies that loading and ELF file from memory works and the new
+// This test verifies that loading an ELF file from memory works and the new
// features that were added when loading from memory work like:
// - Loading the .dynamic section from the PT_DYNAMIC since ELF files loaded
// from memory don't have the section headers available.
>From 4f1a6af5b6f56f33a5382b76335e306f7638e294 Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Mon, 5 Aug 2024 17:08:45 -0700
Subject: [PATCH 5/8] Respond to user feedback.
- remove changes the Process.h and Process.cpp
- Modify ObjectFileELF::CreateMemoryInstance(...) to read at least enough bytes to get the program headers.
- Modify ObjectFileELF::GetImageInfoAddress(...) to re-use the resolved address of the current dynanamic entry.
- Change ObjectFileELF::GetDynstrData(...) to use DT_STRTAB and DT_STRSZ even on ELF files with no section headers
- Add a new test to test .dynamic is found and parsed for files without section headers and not loading from memory.
- Update existing test comments to reflect what the test is doing.
---
lldb/include/lldb/Symbol/ObjectFile.h | 6 +-
lldb/include/lldb/Target/Process.h | 2 +-
.../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 118 +++++++++++-------
lldb/source/Symbol/ObjectFile.cpp | 7 +-
lldb/source/Target/Process.cpp | 15 ---
.../ObjectFile/ELF/elf-dynamic-no-shdrs.test | 49 ++++++++
.../test/Shell/ObjectFile/ELF/elf-memory.test | 7 +-
7 files changed, 131 insertions(+), 73 deletions(-)
create mode 100644 lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.test
diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h
index 8592323322e383..2ef1b8a407b5e6 100644
--- a/lldb/include/lldb/Symbol/ObjectFile.h
+++ b/lldb/include/lldb/Symbol/ObjectFile.h
@@ -656,8 +656,10 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
// When an object file is in memory, subclasses should try and lock the
// process weak pointer. If the process weak pointer produces a valid
// ProcessSP, then subclasses can call this function to read memory.
- static lldb::DataBufferSP ReadMemory(const lldb::ProcessSP &process_sp,
- lldb::addr_t addr, size_t byte_size);
+ static lldb::WritableDataBufferSP ReadMemory(
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t addr,
+ size_t byte_size);
// This function returns raw file contents. Do not use it if you want
// transparent decompression of section contents.
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 17e18261b4752d..c8475db8ae1609 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1952,7 +1952,7 @@ class Process : public std::enable_shared_from_this<Process>,
lldb::ModuleSP ReadModuleFromMemory(const FileSpec &file_spec,
lldb::addr_t header_addr,
- size_t size_to_read = 0);
+ size_t size_to_read = 512);
/// Attempt to get the attributes for a region of memory in the process.
///
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index d26215a9ce3f22..34ce1f2f9f1218 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -419,19 +419,35 @@ ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp,
ObjectFile *ObjectFileELF::CreateMemoryInstance(
const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp,
const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {
- if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT)) {
- const uint8_t *magic = data_sp->GetBytes();
- if (ELFHeader::MagicBytesMatch(magic)) {
- unsigned address_size = ELFHeader::AddressSizeInBytes(magic);
- if (address_size == 4 || address_size == 8) {
- std::unique_ptr<ObjectFileELF> objfile_up(
- new ObjectFileELF(module_sp, data_sp, process_sp, header_addr));
- ArchSpec spec = objfile_up->GetArchitecture();
- if (spec && objfile_up->SetModulesArchitecture(spec))
- return objfile_up.release();
- }
- }
- }
+ if (!data_sp || data_sp->GetByteSize() < (llvm::ELF::EI_NIDENT))
+ return nullptr;
+ const uint8_t *magic = data_sp->GetBytes();
+ if (!ELFHeader::MagicBytesMatch(magic))
+ return nullptr;
+ // Read the ELF header first so we can figure out how many bytes we need
+ // to read to get as least the ELF header + program headers.
+ DataExtractor data;
+ data.SetData(data_sp);
+ elf::ELFHeader hdr;
+ lldb::offset_t offset = 0;
+ if (!hdr.Parse(data, &offset))
+ return nullptr;
+
+ // Make sure the address size is set correctly in the ELF header.
+ if (!hdr.Is32Bit() && !hdr.Is64Bit())
+ return nullptr;
+ // Figure out where the program headers end and read enough bytes to get the
+ // program headers in their entirety.
+ lldb::offset_t end_phdrs = hdr.e_phoff + (hdr.e_phentsize * hdr.e_phnum);
+ if (end_phdrs > data_sp->GetByteSize())
+ data_sp = ReadMemory(process_sp, header_addr, end_phdrs);
+
+ std::unique_ptr<ObjectFileELF> objfile_up(
+ new ObjectFileELF(module_sp, data_sp, process_sp, header_addr));
+ ArchSpec spec = objfile_up->GetArchitecture();
+ if (spec && objfile_up->SetModulesArchitecture(spec))
+ return objfile_up.release();
+
return nullptr;
}
@@ -876,35 +892,35 @@ Address ObjectFileELF::GetImageInfoAddress(Target *target) {
for (size_t i = 0; i < m_dynamic_symbols.size(); ++i) {
const ELFDynamic &symbol = m_dynamic_symbols[i].symbol;
- if (symbol.d_tag == DT_DEBUG) {
- // Compute the offset as the number of previous entries plus the size of
- // d_tag.
- addr_t offset = (i * 2 + 1) * GetAddressByteSize();
- addr_t file_addr = m_dynamic_base_addr + offset;
- Address addr;
- if (addr.ResolveAddressUsingFileSections(file_addr, GetSectionList()))
- return addr;
- }
+ if (symbol.d_tag != DT_DEBUG &&
+ symbol.d_tag != DT_MIPS_RLD_MAP &&
+ symbol.d_tag != DT_MIPS_RLD_MAP_REL)
+ continue;
+
+ // Compute the offset as the number of previous entries plus the size of
+ // d_tag.
+ const addr_t offset = (i * 2 + 1) * GetAddressByteSize();
+ const addr_t d_file_addr = m_dynamic_base_addr + offset;
+ Address d_addr;
+ if (d_addr.ResolveAddressUsingFileSections(d_file_addr, GetSectionList()))
+ return Address();
+ if (symbol.d_tag == DT_DEBUG)
+ return d_addr;
+
// MIPS executables uses DT_MIPS_RLD_MAP_REL to support PIE. DT_MIPS_RLD_MAP
// exists in non-PIE.
- else if ((symbol.d_tag == DT_MIPS_RLD_MAP ||
- symbol.d_tag == DT_MIPS_RLD_MAP_REL) &&
- target) {
- SectionSP dynsym_section_sp(section_list->FindSectionByType(
- eSectionTypeELFDynamicLinkInfo, true));
- if (!dynsym_section_sp)
- return Address();
-
- addr_t offset = (i * 2 + 1) * GetAddressByteSize();
- addr_t dyn_base = dynsym_section_sp->GetLoadBaseAddress(target);
- if (dyn_base == LLDB_INVALID_ADDRESS)
+ if ((symbol.d_tag == DT_MIPS_RLD_MAP ||
+ symbol.d_tag == DT_MIPS_RLD_MAP_REL) &&
+ target) {
+ const addr_t d_load_addr = d_addr.GetLoadAddress(target);
+ if (d_load_addr == LLDB_INVALID_ADDRESS)
return Address();
Status error;
if (symbol.d_tag == DT_MIPS_RLD_MAP) {
// DT_MIPS_RLD_MAP tag stores an absolute address of the debug pointer.
Address addr;
- if (target->ReadPointerFromMemory(dyn_base + offset, error, addr, true))
+ if (target->ReadPointerFromMemory(d_load_addr, error, addr, true))
return addr;
}
if (symbol.d_tag == DT_MIPS_RLD_MAP_REL) {
@@ -912,18 +928,17 @@ Address ObjectFileELF::GetImageInfoAddress(Target *target) {
// relative to the address of the tag.
uint64_t rel_offset;
rel_offset = target->ReadUnsignedIntegerFromMemory(
- dyn_base + offset, GetAddressByteSize(), UINT64_MAX, error, true);
+ d_load_addr, GetAddressByteSize(), UINT64_MAX, error, true);
if (error.Success() && rel_offset != UINT64_MAX) {
Address addr;
addr_t debug_ptr_address =
- dyn_base + (offset - GetAddressByteSize()) + rel_offset;
+ d_load_addr - GetAddressByteSize() + rel_offset;
addr.SetOffset(debug_ptr_address);
return addr;
}
}
}
}
-
return Address();
}
@@ -3802,9 +3817,9 @@ std::optional<DataExtractor> ObjectFileELF::GetDynstrData() {
// the section.
if (Section *dynstr =
section_list->FindSectionByID(header->sh_link).get()) {
- DataExtractor data;
+ DataExtractor data;
if (ReadSectionData(dynstr, data))
- return data;
+ return data;
}
}
}
@@ -3818,20 +3833,27 @@ std::optional<DataExtractor> ObjectFileELF::GetDynstrData() {
// When loading and ELF file from memory, only the program headers end up
// being mapped into memory, and we can find these values in the PT_DYNAMIC
// segment.
- if (!IsInMemory())
- return std::nullopt;
- ProcessSP process_sp(m_process_wp.lock());
- if (!process_sp)
- return std::nullopt;
-
const ELFDynamic *strtab = FindDynamicSymbol(DT_STRTAB);
const ELFDynamic *strsz = FindDynamicSymbol(DT_STRSZ);
if (strtab == nullptr || strsz == nullptr)
return std::nullopt;
- if (DataBufferSP data_sp =
- ReadMemory(process_sp, strtab->d_ptr, strsz->d_val))
- return DataExtractor(data_sp, GetByteOrder(), GetAddressByteSize());
+ if (ProcessSP process_sp = m_process_wp.lock()) {
+ if (DataBufferSP data_sp =
+ ReadMemory(process_sp, strtab->d_ptr, strsz->d_val))
+ return DataExtractor(data_sp, GetByteOrder(), GetAddressByteSize());
+ } else {
+ // We have an ELF file with no section headers or we didn't find the
+ // .dynamic section. Try and find the .dynstr section.
+ Address addr;
+ if (addr.ResolveAddressUsingFileSections(strtab->d_ptr, GetSectionList())) {
+ DataExtractor data;
+ addr.GetSection()->GetSectionData(data);
+ return DataExtractor(data,
+ strtab->d_ptr - addr.GetSection()->GetFileOffset(),
+ strsz->d_val);
+ }
+ }
return std::nullopt;
}
diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp
index 2608a9c5fb79a2..0e4f0a931a7cdb 100644
--- a/lldb/source/Symbol/ObjectFile.cpp
+++ b/lldb/source/Symbol/ObjectFile.cpp
@@ -454,9 +454,10 @@ AddressClass ObjectFile::GetAddressClass(addr_t file_addr) {
return AddressClass::eUnknown;
}
-DataBufferSP ObjectFile::ReadMemory(const ProcessSP &process_sp,
- lldb::addr_t addr, size_t byte_size) {
- DataBufferSP data_sp;
+WritableDataBufferSP ObjectFile::ReadMemory(const ProcessSP &process_sp,
+ lldb::addr_t addr,
+ size_t byte_size) {
+ WritableDataBufferSP data_sp;
if (process_sp) {
std::unique_ptr<DataBufferHeap> data_up(new DataBufferHeap(byte_size, 0));
Status error;
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 65f78f63a5c7c6..d5a639d9beacd9 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -2550,21 +2550,6 @@ ModuleSP Process::ReadModuleFromMemory(const FileSpec &file_spec,
}
ModuleSP module_sp(new Module(file_spec, ArchSpec()));
if (module_sp) {
- if (size_to_read == 0) {
- // Default to 8192 in case we can't find a memory region.
- size_to_read = 0x2000;
- MemoryRegionInfo range_info;
- Status error(GetMemoryRegionInfo(header_addr, range_info));
- if (error.Success()) {
- // We found a memory region, set the range of bytes ro read to read to
- // the end of the memory region. This should be enough to contain the
- // file header and important bits.
- const auto &range = range_info.GetRange();
- addr_t end = range.GetRangeBase() + range.GetByteSize();
- if (end > header_addr)
- size_to_read = end - header_addr;
- }
- }
Status error;
std::unique_ptr<Progress> progress_up;
// Reading an ObjectFile from a local corefile is very fast,
diff --git a/lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.test b/lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.test
new file mode 100644
index 00000000000000..65b7163417cf92
--- /dev/null
+++ b/lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.test
@@ -0,0 +1,49 @@
+// REQUIRES: system-linux, native
+
+// This test verifies that loading an ELF file that has no section headers can
+// find the contents on the .dynamic section and the strings associated with
+// the .dynamic seciton.
+// - Loading the .dynamic section from the PT_DYNAMIC
+// This test will make a simple executable that links against libc.so and we
+// verify that we can find the DT_NEEDED entry with the shared library found
+// in the .dynamic dump from "image dump objfile"
+
+// RUN: %clang_host %p/Inputs/memory-elf.cpp -g -O0 -o %t
+// RUN: llvm-strip --strip-sections %t
+
+// RUN: %lldb -b \
+// RUN: -o "target create -d '%t'" \
+// RUN: -o "image dump objfile" \
+// RUN: | FileCheck %s --check-prefix=MAIN --dump-input=always
+// MAIN: (lldb) image dump objfile
+// MAIN: Dumping headers for 1 module(s).
+// MAIN: ObjectFileELF, file =
+// MAIN: ELF Header
+// Make sure there are no section headers
+// MAIN: e_shnum = 0x00000000
+
+// Make sure we find the program headers and see a PT_DYNAMIC entry.
+// MAIN: Program Headers
+// MAIN: ] PT_DYNAMIC
+
+// Make sure we see some sections created from the program headers
+// MAIN: SectID
+// MAIN: PT_LOAD[0]
+
+// Ensure we find some dependent modules as won't find these if we aren't able
+// to load the .dynamic section from the PT_DYNAMIC program header.
+// MAIN: Dependent Modules:
+
+// Check for the .dynamic dump and ensure we find all dynamic entries that are
+// required to be there and needed to get the .dynstr section and the symbol
+// table, and the DT_DEBUG entry to find the list of shared libraries.
+// MAIN: .dynamic:
+// Make sure we found the .dynstr section by checking for valid strings after NEEDED
+// MAIN-DAG: NEEDED {{0x[0-9a-f]+ ".*libc.*"}}
+// MAIN-DAG: STRTAB {{0x[0-9a-f]+}}
+// MAIN-DAG: SYMTAB {{0x[0-9a-f]+}}
+// MAIN-DAG: STRSZ {{0x[0-9a-f]+}}
+// MAIN-DAG: SYMENT {{0x[0-9a-f]+}}
+// MAIN-DAG: DEBUG {{0x[0-9a-f]+}}
+// MAIN: NULL {{0x[0-9a-f]+}}
+
diff --git a/lldb/test/Shell/ObjectFile/ELF/elf-memory.test b/lldb/test/Shell/ObjectFile/ELF/elf-memory.test
index 253b233b991102..0b1c01486a4b43 100644
--- a/lldb/test/Shell/ObjectFile/ELF/elf-memory.test
+++ b/lldb/test/Shell/ObjectFile/ELF/elf-memory.test
@@ -4,10 +4,12 @@
// features that were added when loading from memory work like:
// - Loading the .dynamic section from the PT_DYNAMIC since ELF files loaded
// from memory don't have the section headers available.
-// - Loading the symbol table from the DT_SYMTAB dynamic entries.
// This test will make a simple executable that:
// - links against libc
// - runs and stops at a breakpoint
+// - create a memory ELF file
+// - verify that "image dump objfile" will dump the dynamic section of the
+// memory elf file and find the .dynamic string table.
// RUN: %clang_host %p/Inputs/memory-elf.cpp -g -O0 -o %t
@@ -35,9 +37,6 @@
// MAIN: SectID
// MAIN: PT_LOAD[0]
-// Test we find some symbols in the symbol table
-// MAIN: Symtab, num_symbols =
-
// Ensure we find some dependent modules as won't find these if we aren't able
// to load the .dynamic section from the PT_DYNAMIC program header.
// MAIN: Dependent Modules:
>From d398f14a1fe60257304959a380b0f1eed94f910f Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Mon, 5 Aug 2024 17:15:37 -0700
Subject: [PATCH 6/8] Update comments to reflect the current approach to the
GetDynamicData() and GetDynstrData() functions.
---
lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index ae2025ba2cedbf..aba3a5bfcbf5b6 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -417,10 +417,9 @@ class ObjectFileELF : public lldb_private::ObjectFile {
/// Get the bytes that represent the .dynamic section.
///
/// This function will fetch the data for the .dynamic section in an ELF file.
- /// If the ELF file is loaded from a file on disk, it will use the PT_DYNAMIC
- /// program header to extract the data and fall back to using the section
- /// headers. If the ELF file is loaded from memory, it will use the PT_DYNAMIC
- /// program header to get the information.
+ /// The PT_DYNAMIC program header will be used to extract the data and this
+ /// function will fall back to using the section headers if PT_DYNAMIC isn't
+ /// found.
///
/// \return The bytes that represent the string table data or \c std::nullopt
/// if an error occured.
@@ -430,8 +429,8 @@ class ObjectFileELF : public lldb_private::ObjectFile {
///
/// This function will fetch the data for the string table in an ELF file. If
/// the ELF file is loaded from a file on disk, it will use the section
- /// headers to extract the data. If the ELF file is loaded from memory, it
- /// will use .dynamic entries to read the information.
+ /// headers to extract the data and fall back to using the DT_STRTAB and
+ /// DT_STRSZ .dynamic entries.
///
/// \return The bytes that represent the string table data or \c std::nullopt
/// if an error occured.
>From 878fa9e09988fe946dbcb4515a4b6c4fac7d5cc6 Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Wed, 7 Aug 2024 11:37:18 -0700
Subject: [PATCH 7/8] Address user feedback.
- Fix indentation
- Call addr.GetSection()->GetFileAddress()
- Switch test to yaml
---
.../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 8 +-
.../ObjectFile/ELF/elf-dynamic-no-shdrs.test | 49 ----------
.../ObjectFile/ELF/elf-dynamic-no-shdrs.yaml | 90 +++++++++++++++++++
3 files changed, 94 insertions(+), 53 deletions(-)
delete mode 100644 lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.test
create mode 100644 lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.yaml
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 34ce1f2f9f1218..8f07e023d0c0a1 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -3817,9 +3817,9 @@ std::optional<DataExtractor> ObjectFileELF::GetDynstrData() {
// the section.
if (Section *dynstr =
section_list->FindSectionByID(header->sh_link).get()) {
- DataExtractor data;
+ DataExtractor data;
if (ReadSectionData(dynstr, data))
- return data;
+ return data;
}
}
}
@@ -3850,8 +3850,8 @@ std::optional<DataExtractor> ObjectFileELF::GetDynstrData() {
DataExtractor data;
addr.GetSection()->GetSectionData(data);
return DataExtractor(data,
- strtab->d_ptr - addr.GetSection()->GetFileOffset(),
- strsz->d_val);
+ strtab->d_ptr - addr.GetSection()->GetFileAddress(),
+ strsz->d_val);
}
}
return std::nullopt;
diff --git a/lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.test b/lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.test
deleted file mode 100644
index 65b7163417cf92..00000000000000
--- a/lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.test
+++ /dev/null
@@ -1,49 +0,0 @@
-// REQUIRES: system-linux, native
-
-// This test verifies that loading an ELF file that has no section headers can
-// find the contents on the .dynamic section and the strings associated with
-// the .dynamic seciton.
-// - Loading the .dynamic section from the PT_DYNAMIC
-// This test will make a simple executable that links against libc.so and we
-// verify that we can find the DT_NEEDED entry with the shared library found
-// in the .dynamic dump from "image dump objfile"
-
-// RUN: %clang_host %p/Inputs/memory-elf.cpp -g -O0 -o %t
-// RUN: llvm-strip --strip-sections %t
-
-// RUN: %lldb -b \
-// RUN: -o "target create -d '%t'" \
-// RUN: -o "image dump objfile" \
-// RUN: | FileCheck %s --check-prefix=MAIN --dump-input=always
-// MAIN: (lldb) image dump objfile
-// MAIN: Dumping headers for 1 module(s).
-// MAIN: ObjectFileELF, file =
-// MAIN: ELF Header
-// Make sure there are no section headers
-// MAIN: e_shnum = 0x00000000
-
-// Make sure we find the program headers and see a PT_DYNAMIC entry.
-// MAIN: Program Headers
-// MAIN: ] PT_DYNAMIC
-
-// Make sure we see some sections created from the program headers
-// MAIN: SectID
-// MAIN: PT_LOAD[0]
-
-// Ensure we find some dependent modules as won't find these if we aren't able
-// to load the .dynamic section from the PT_DYNAMIC program header.
-// MAIN: Dependent Modules:
-
-// Check for the .dynamic dump and ensure we find all dynamic entries that are
-// required to be there and needed to get the .dynstr section and the symbol
-// table, and the DT_DEBUG entry to find the list of shared libraries.
-// MAIN: .dynamic:
-// Make sure we found the .dynstr section by checking for valid strings after NEEDED
-// MAIN-DAG: NEEDED {{0x[0-9a-f]+ ".*libc.*"}}
-// MAIN-DAG: STRTAB {{0x[0-9a-f]+}}
-// MAIN-DAG: SYMTAB {{0x[0-9a-f]+}}
-// MAIN-DAG: STRSZ {{0x[0-9a-f]+}}
-// MAIN-DAG: SYMENT {{0x[0-9a-f]+}}
-// MAIN-DAG: DEBUG {{0x[0-9a-f]+}}
-// MAIN: NULL {{0x[0-9a-f]+}}
-
diff --git a/lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.yaml b/lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.yaml
new file mode 100644
index 00000000000000..bc34e16e0b6ad2
--- /dev/null
+++ b/lldb/test/Shell/ObjectFile/ELF/elf-dynamic-no-shdrs.yaml
@@ -0,0 +1,90 @@
+## This test verifies that loading an ELF file that has no section headers can
+## find the contents on the .dynamic section and the strings associated with
+## the .dynamic seciton.
+## - Loading the .dynamic section from the PT_DYNAMIC
+## This test will make a simple executable that links against libc.so and we
+## verify that we can find the DT_NEEDED entry with the shared library found
+## in the .dynamic dump from "image dump objfile"
+
+# RUN: yaml2obj %s -o %t
+
+# RUN: %lldb -b \
+# RUN: -o "target create -d '%t'" \
+# RUN: -o "image dump objfile" \
+# RUN: | FileCheck %s --dump-input=always
+# CHECK: (lldb) image dump objfile
+# CHECK: Dumping headers for 1 module(s).
+# CHECK: ObjectFileELF, file =
+# CHECK: ELF Header
+# Make sure there are no section headers
+# CHECK: e_shnum = 0x00000000
+
+# Make sure we find the program headers and see a PT_DYNAMIC entry.
+# CHECK: Program Headers
+# CHECK: IDX p_type p_offset p_vaddr p_paddr p_filesz p_memsz p_flags p_align
+# CHECK: ==== --------------- -------- -------- -------- -------- -------- ------------------------- --------
+# CHECK: [ 0] PT_LOAD 000000b0 00000000 00000000 00000170 00000170 00000000 ( ) 00000001
+# CHECK: [ 1] PT_DYNAMIC 000001b0 00000100 00000100 00000070 00000070 00000000 ( ) 00000008
+
+# CHECK: Dependent Modules:
+# CHECK: ccc
+# CHECK: aaa
+# CHECK: bbb
+
+# Make sure we see some sections created from the program headers
+# MAIN: SectID
+# MAIN: PT_LOAD[0]
+
+# CHECK: .dynamic:
+# CHECK: IDX d_tag d_val/d_ptr
+# CHECK: ==== ---------------- ------------------
+# CHECK: [ 0] STRTAB 0x0000000000000000
+# CHECK: [ 1] NEEDED 0x0000000000000009 "ccc"
+# CHECK: [ 2] NEEDED 0x0000000000000001 "aaa"
+# CHECK: [ 3] NEEDED 0x0000000000000005 "bbb"
+# CHECK: [ 4] STRSZ 0x0000000000000100
+# CHECK: [ 5] DEBUG 0x00000000deadbeef
+# CHECK: [ 6] NULL 0x0000000000000000
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Type: SectionHeaderTable
+ NoHeaders: true
+ - Name: .dynstr
+ Type: SHT_STRTAB
+ Flags: [ SHF_ALLOC ]
+ Content: '00616161006262620063636300' ## 0,a,a,a,0,b,b,b,0,c,c,c,0
+ Size: 0x100
+ - Name: .dynamic
+ Type: SHT_DYNAMIC
+ Address: 0x100
+ Entries:
+ - Tag: DT_STRTAB
+ Value: 0x0000000000000000
+ - Tag: DT_NEEDED
+ Value: 9
+ - Tag: DT_NEEDED
+ Value: 1
+ - Tag: DT_NEEDED
+ Value: 5
+ - Tag: DT_STRSZ
+ Value: 0x100
+ - Tag: DT_DEBUG
+ Value: 0xdeadbeef
+ - Tag: DT_NULL
+ Value: 0x0
+ProgramHeaders:
+ - Type: PT_LOAD
+ VAddr: 0x0
+ FirstSec: .dynstr
+ LastSec: .dynamic
+ - Type: PT_DYNAMIC
+ FirstSec: .dynamic
+ LastSec: .dynamic
+ VAddr: 0x100
+ Align: 0x8
>From cdba992e19b6b7c955d3e28bf675d10874fe6294 Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Thu, 8 Aug 2024 11:01:07 -0700
Subject: [PATCH 8/8] run clang-format.
---
lldb/include/lldb/Symbol/ObjectFile.h | 7 +++----
lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 5 ++---
lldb/source/Symbol/ObjectFile.cpp | 2 +-
3 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h
index 2ef1b8a407b5e6..d89314d44bf671 100644
--- a/lldb/include/lldb/Symbol/ObjectFile.h
+++ b/lldb/include/lldb/Symbol/ObjectFile.h
@@ -656,10 +656,9 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
// When an object file is in memory, subclasses should try and lock the
// process weak pointer. If the process weak pointer produces a valid
// ProcessSP, then subclasses can call this function to read memory.
- static lldb::WritableDataBufferSP ReadMemory(
- const lldb::ProcessSP &process_sp,
- lldb::addr_t addr,
- size_t byte_size);
+ static lldb::WritableDataBufferSP
+ ReadMemory(const lldb::ProcessSP &process_sp, lldb::addr_t addr,
+ size_t byte_size);
// This function returns raw file contents. Do not use it if you want
// transparent decompression of section contents.
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 8f07e023d0c0a1..414ac6112d5797 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -892,8 +892,7 @@ Address ObjectFileELF::GetImageInfoAddress(Target *target) {
for (size_t i = 0; i < m_dynamic_symbols.size(); ++i) {
const ELFDynamic &symbol = m_dynamic_symbols[i].symbol;
- if (symbol.d_tag != DT_DEBUG &&
- symbol.d_tag != DT_MIPS_RLD_MAP &&
+ if (symbol.d_tag != DT_DEBUG && symbol.d_tag != DT_MIPS_RLD_MAP &&
symbol.d_tag != DT_MIPS_RLD_MAP_REL)
continue;
@@ -911,7 +910,7 @@ Address ObjectFileELF::GetImageInfoAddress(Target *target) {
// exists in non-PIE.
if ((symbol.d_tag == DT_MIPS_RLD_MAP ||
symbol.d_tag == DT_MIPS_RLD_MAP_REL) &&
- target) {
+ target) {
const addr_t d_load_addr = d_addr.GetLoadAddress(target);
if (d_load_addr == LLDB_INVALID_ADDRESS)
return Address();
diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp
index 0e4f0a931a7cdb..35317d209de1f9 100644
--- a/lldb/source/Symbol/ObjectFile.cpp
+++ b/lldb/source/Symbol/ObjectFile.cpp
@@ -455,7 +455,7 @@ AddressClass ObjectFile::GetAddressClass(addr_t file_addr) {
}
WritableDataBufferSP ObjectFile::ReadMemory(const ProcessSP &process_sp,
- lldb::addr_t addr,
+ lldb::addr_t addr,
size_t byte_size) {
WritableDataBufferSP data_sp;
if (process_sp) {
More information about the lldb-commits
mailing list