[Lldb-commits] [lldb] [LLDB] Impove ObjectFileELF's .dynamic parsing and usage. (PR #101237)

Greg Clayton via lldb-commits lldb-commits at lists.llvm.org
Tue Jul 30 15:21:44 PDT 2024


https://github.com/clayborg updated https://github.com/llvm/llvm-project/pull/101237

>From 6ef64acd518afe8bdc42c5042f35c857be96e3b4 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/2] 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 c8475db8ae160..17e18261b4752 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 890db5c274814..becee73f96205 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 844e981b1d890..cb3883019727d 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 d5a639d9beacd..65f78f63a5c7c 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 0000000000000..f4162a4a1d5fc
--- /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 0000000000000..2b1d716597bc5
--- /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 13e457239d7de1bae42736e99745d603ee5d4c14 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/2] 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 becee73f96205..ee891a5182d53 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 cb3883019727d..ae2025ba2cedb 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 f4162a4a1d5fc..9cae6c99c9f76 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;
 }
-



More information about the lldb-commits mailing list