https://github.com/aokblast updated 
https://github.com/llvm/llvm-project/pull/208905

>From 9c2bb1a439fcf2c880ad7b6cfcfa3f0668610a4a Mon Sep 17 00:00:00 2001
From: ShengYi Hung <[email protected]>
Date: Sat, 11 Jul 2026 19:26:47 +0800
Subject: [PATCH 1/2] [LLDB] Support Auxiliary library in ELF format

An ELF filter library (DT_FILTER) or auxiliary filter (DT_AUXILIARY)
delegates symbol resolution to its filtee: the dynamic linker looks up
each symbol in the filtee first, falling back to the filter library's
own definition. Filter library may export placeholder smyolbs whose
addresses are not the actual function entry points.

To support this, we teach ObjectFileELF to parse the filtee and model
placeholder function definition in filter libraries as ReExported,
reusing the existing re-export machinery.

Notice that in ELF, we don't record the per-symbol target ReExported
library like Macho. Instead, it is a suggestion list from the libraries
that exposes this symbol. As a result, we need to pass the library
Module to read the suggestion list to correctly parse the file in
Resolver.
---
 lldb/include/lldb/Symbol/Symbol.h             | 12 ++++-
 .../Plugins/ObjectFile/ELF/ObjectFileELF.cpp  | 31 +++++++++++
 .../Plugins/ObjectFile/ELF/ObjectFileELF.h    |  2 +
 lldb/source/Symbol/Symbol.cpp                 | 53 +++++++++++++++----
 4 files changed, 87 insertions(+), 11 deletions(-)

diff --git a/lldb/include/lldb/Symbol/Symbol.h 
b/lldb/include/lldb/Symbol/Symbol.h
index 47323b8ba5e56..26f6155f6fa75 100644
--- a/lldb/include/lldb/Symbol/Symbol.h
+++ b/lldb/include/lldb/Symbol/Symbol.h
@@ -162,7 +162,17 @@ class Symbol : public SymbolContextScope {
 
   bool SetReExportedSymbolSharedLibrary(const FileSpec &fspec);
 
-  Symbol *ResolveReExportedSymbol(Target &target) const;
+  /// Find the symbol this re-exported symbol resolves to.
+  ///
+  /// The library recorded on the symbol is searched first. If
+  /// \p containing_module_sp is provided, the libraries re-exported by that
+  /// module (ObjectFile::GetReExportedLibraries()) are then searched in
+  /// order. This matches the DT_FILTER / DT_AUXILIARY behavior in ELF, where
+  /// a filter library may reference multiple filtees and the dynamic linker
+  /// searches them in the order they appear in the dynamic section.
+  Symbol *ResolveReExportedSymbol(
+      Target &target,
+      const lldb::ModuleSP &containing_module_sp = lldb::ModuleSP()) const;
 
   uint32_t GetSiblingIndex() const;
 
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp 
b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 58accbeaf2d92..14092fc494cf7 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -1052,6 +1052,22 @@ Address ObjectFileELF::GetBaseAddress() {
   return Address();
 }
 
+FileSpecList ObjectFileELF::GetReExportedLibraries() {
+  FileSpecList filtees;
+  if (!ParseDynamicSymbols())
+    return filtees;
+  // Multiple DT_FILTER / DT_AUXILIARY entries are permitted; the dynamic
+  // linker searches the filtees in the order the entries appear in the
+  // dynamic section, so preserve that order here.
+  for (const auto &entry : m_dynamic_symbols) {
+    if (entry.symbol.d_tag != DT_FILTER && entry.symbol.d_tag != DT_AUXILIARY)
+      continue;
+    if (!entry.name.empty())
+      filtees.EmplaceBack(entry.name);
+  }
+  return filtees;
+}
+
 size_t ObjectFileELF::ParseDependentModules() {
   if (m_filespec_up)
     return m_filespec_up->GetSize();
@@ -2336,6 +2352,11 @@ ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t 
start_id,
   SectionList *module_section_list =
       module_sp ? module_sp->GetSectionList() : nullptr;
 
+  // This is modeled after the DT_AUXILIARY and DT_FILTER mechanisms in ELF,
+  // where the actual symbols are defined in another library, while the 
compiler
+  // generates stubs in the original library.
+  const FileSpecList filtees = GetReExportedLibraries();
+
   // We might have debug information in a separate object, in which case
   // we need to map the sections from that object to the sections in the
   // main object during symbol lookup.  If we had to compare the sections
@@ -2662,6 +2683,16 @@ ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t 
start_id,
         flags);                         // Symbol flags.
     if (symbol.getBinding() == STB_WEAK)
       dc_symbol.SetIsWeak(true);
+    // Zero-sized exported function in a filter library: a placeholder the
+    // dynamic linker resolves through the filtees (see
+    // GetReExportedLibraries()).  The re-exported name must not carry the
+    // @VERSION suffix, since it is looked up in the filtee by name.
+    if (filtees.GetSize() > 0 && symbol.getType() == STT_FUNC &&
+        symbol.st_size == 0 && symbol.getBinding() != STB_LOCAL &&
+        symbol_section_sp) {
+      dc_symbol.SetReExportedSymbolName(ConstString(symbol_bare));
+      
dc_symbol.SetReExportedSymbolSharedLibrary(filtees.GetFileSpecAtIndex(0));
+    }
     symtab->AddSymbol(dc_symbol);
   }
 
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h 
b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index aa94e625f64e1..d3a785848e86d 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -128,6 +128,8 @@ class ObjectFileELF : public lldb_private::ObjectFile {
 
   uint32_t GetDependentModules(lldb_private::FileSpecList &files) override;
 
+  lldb_private::FileSpecList GetReExportedLibraries() override;
+
   lldb_private::Address
   GetImageInfoAddress(lldb_private::Target *target) override;
 
diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp
index 78d1fd2e569c3..f51f896dbf7d7 100644
--- a/lldb/source/Symbol/Symbol.cpp
+++ b/lldb/source/Symbol/Symbol.cpp
@@ -456,8 +456,15 @@ Symbol *Symbol::ResolveReExportedSymbolInModuleSpec(
     module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny,
                                           sc_list);
     for (const SymbolContext &sc : sc_list) {
-      if (sc.symbol->IsExternal())
-        return sc.symbol;
+      if (!sc.symbol->IsExternal())
+        continue;
+      // Don't return a symbol that itself only re-exports the definition
+      // (e.g. an ELF filter library's placeholder): the real definition is
+      // found by following the module-level re-exports below, which also
+      // guards against cycles.
+      if (sc.symbol->GetType() == eSymbolTypeReExported)
+        continue;
+      return sc.symbol;
     }
     // If we didn't find the symbol in this module, it may be because this
     // module re-exports some whole other library.  We have to search those as
@@ -480,17 +487,43 @@ Symbol *Symbol::ResolveReExportedSymbolInModuleSpec(
   return nullptr;
 }
 
-Symbol *Symbol::ResolveReExportedSymbol(Target &target) const {
+Symbol *Symbol::ResolveReExportedSymbol(
+    Target &target, const lldb::ModuleSP &containing_module_sp) const {
   ConstString reexport_name(GetReExportedSymbolName());
-  if (reexport_name) {
-    ModuleSpec module_spec;
-    ModuleList seen_modules;
-    module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary();
-    if (module_spec.GetFileSpec()) {
-      return ResolveReExportedSymbolInModuleSpec(target, reexport_name,
-                                                 module_spec, seen_modules);
+  if (!reexport_name)
+    return nullptr;
+
+  ModuleList seen_modules;
+
+  // Search the library recorded on the symbol itself first.
+  ModuleSpec module_spec;
+  module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary();
+  if (module_spec.GetFileSpec()) {
+    if (Symbol *result = ResolveReExportedSymbolInModuleSpec(
+            target, reexport_name, module_spec, seen_modules))
+      return result;
+  }
+
+  // The recorded library is only the first candidate: the module defining
+  // this symbol may re-export several libraries which must be searched in
+  // the order they are declared (e.g. an ELF filter library with multiple
+  // DT_FILTER / DT_AUXILIARY entries).  seen_modules is shared with the
+  // search above so no library is searched twice.
+  if (containing_module_sp) {
+    if (ObjectFile *object_file = containing_module_sp->GetObjectFile()) {
+      FileSpecList reexported_libraries = 
object_file->GetReExportedLibraries();
+      const size_t count = reexported_libraries.GetSize();
+      for (size_t idx = 0; idx < count; ++idx) {
+        ModuleSpec reexported_module_spec;
+        reexported_module_spec.GetFileSpec() =
+            reexported_libraries.GetFileSpecAtIndex(idx);
+        if (Symbol *result = ResolveReExportedSymbolInModuleSpec(
+                target, reexport_name, reexported_module_spec, seen_modules))
+          return result;
+      }
     }
   }
+
   return nullptr;
 }
 

>From 0f6e6fdb3d46732c4bd87229b2a944db5bdef91e Mon Sep 17 00:00:00 2001
From: ShengYi Hung <[email protected]>
Date: Sat, 11 Jul 2026 20:13:48 +0800
Subject: [PATCH 2/2] Add unit tests for ELF filter-library symbol handling.

* ObjectFileELFTest.FilterLibraryPlaceholderSymbols: a yaml2obj ELF
  filter library with two DT_AUXILIARY entries checks that
  GetReExportedLibraries() returns the filtees in dynamic-section
  order, that zero-sized exported functions become re-exported symbols
  recording the first filtee and the unversioned name (@VERSION suffix
  stripped), and that nonzero-sized and local definitions are left
  alone.

* ReExportedSymbolTest.ResolveThroughFilteesInOrder: a target holding
  a filter library and two filtee modules checks that
  Symbol::ResolveReExportedSymbol finds a definition in the first
  filtee via the library recorded on the symbol, continues to the next
  filtee in declaration order for symbols the first filtee lacks, and
  that without the containing module only the recorded library is
  searched.

Co-Authored-By: Claude Fable 5 <[email protected]>
---
 .../ObjectFile/ELF/TestObjectFileELF.cpp      | 121 ++++++++
 lldb/unittests/Target/CMakeLists.txt          |   1 +
 .../unittests/Target/ReExportedSymbolTest.cpp | 269 ++++++++++++++++++
 3 files changed, 391 insertions(+)
 create mode 100644 lldb/unittests/Target/ReExportedSymbolTest.cpp

diff --git a/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp 
b/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp
index 63c8c9e6fd79d..5b9ac8b1e941d 100644
--- a/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp
+++ b/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp
@@ -16,6 +16,7 @@
 #include "lldb/Core/Section.h"
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/Symtab.h"
 #include "lldb/Utility/DataBufferHeap.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/Support/Compression.h"
@@ -556,3 +557,123 @@ TEST_F(ObjectFileELFTest, 
SkipsLocalMappingAndDotLSymbols) {
       ConstString("global_obj"), eSymbolTypeAny);
   ASSERT_NE(nullptr, global_obj);
 }
+
+// An ELF filter library (DT_FILTER / DT_AUXILIARY) delegates symbol
+// resolution to its filtees.  Its zero-sized exported function definitions
+// are placeholders whose addresses are meaningless (e.g. FreeBSD >= 15's
+// libc.so.7 exports a zero-sized "mmap" whose address points into an
+// unrelated function; the real definition lives in the libsys.so.7 filtee).
+// Check that the filtees are reported in dynamic-section order and that
+// placeholders are turned into re-exported symbols.
+TEST_F(ObjectFileELFTest, FilterLibraryPlaceholderSymbols) {
+  auto ExpectedFile = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x10
+    Content:         C3C3C3C3
+# .dynstr content: "\0libaux1.so\0libaux2.so\0"
+#   offset 0x1: "libaux1.so"
+#   offset 0xC: "libaux2.so"
+  - Name:            .dynstr
+    Type:            SHT_STRTAB
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x2000
+    AddressAlign:    0x1
+    Content:         "006C6962617578312E736F006C6962617578322E736F00"
+  - Name:            .dynamic
+    Type:            SHT_DYNAMIC
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x3000
+    AddressAlign:    0x8
+    Link:            .dynstr
+    Entries:
+      - Tag:             DT_AUXILIARY
+        Value:           0x1
+      - Tag:             DT_AUXILIARY
+        Value:           0xC
+      - Tag:             DT_NULL
+        Value:           0x0
+Symbols:
+  - Name:            local_helper
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1002
+    Binding:         STB_LOCAL
+  - Name:            mmap
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1000
+    Binding:         STB_GLOBAL
+  - Name:            "open@@FBSD_1.0"
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1001
+    Binding:         STB_WEAK
+  - Name:            printf
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1000
+    Size:            0x4
+    Binding:         STB_GLOBAL
+...
+  )");
+  ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
+  auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
+  ObjectFile *object_file = module_sp->GetObjectFile();
+  ASSERT_NE(nullptr, object_file);
+
+  // The filtees must come back in dynamic-section order.
+  FileSpecList filtees = object_file->GetReExportedLibraries();
+  ASSERT_EQ(2u, filtees.GetSize());
+  EXPECT_EQ(ConstString("libaux1.so"),
+            filtees.GetFileSpecAtIndex(0).GetFilename());
+  EXPECT_EQ(ConstString("libaux2.so"),
+            filtees.GetFileSpecAtIndex(1).GetFilename());
+
+  // A zero-sized exported function becomes a re-export recording the first
+  // filtee.
+  const Symbol *placeholder = module_sp->FindFirstSymbolWithNameAndType(
+      ConstString("mmap"), eSymbolTypeReExported);
+  ASSERT_NE(nullptr, placeholder);
+  EXPECT_EQ(ConstString("mmap"), placeholder->GetReExportedSymbolName());
+  EXPECT_EQ(ConstString("libaux1.so"),
+            ConstString(
+                
placeholder->GetReExportedSymbolSharedLibrary().GetFilename()));
+
+  // The re-exported name must not carry the @VERSION suffix.  Find the
+  // symbol by iterating rather than by name: whether a versioned symbol can
+  // be looked up by its stripped base name is a property of the symtab name
+  // indexes, not of the re-export marking under test here.
+  Symtab *symtab = module_sp->GetSymtab();
+  ASSERT_NE(nullptr, symtab);
+  const Symbol *versioned = nullptr;
+  for (size_t i = 0, e = symtab->GetNumSymbols(); i != e; ++i) {
+    Symbol *candidate = symtab->SymbolAtIndex(i);
+    if (candidate->GetType() == eSymbolTypeReExported &&
+        candidate->GetName().GetStringRef().starts_with("open"))
+      versioned = candidate;
+  }
+  ASSERT_NE(nullptr, versioned);
+  EXPECT_EQ(ConstString("open"), versioned->GetReExportedSymbolName());
+
+  // A function the filter genuinely defines (nonzero size) keeps its
+  // definition, matching the dynamic linker's DT_AUXILIARY fallback.
+  const Symbol *real = module_sp->FindFirstSymbolWithNameAndType(
+      ConstString("printf"), eSymbolTypeCode);
+  ASSERT_NE(nullptr, real);
+
+  // Local zero-sized functions are not exported and must not be marked.
+  const Symbol *local = module_sp->FindFirstSymbolWithNameAndType(
+      ConstString("local_helper"), eSymbolTypeAny);
+  ASSERT_NE(nullptr, local);
+  EXPECT_NE(eSymbolTypeReExported, local->GetType());
+}
diff --git a/lldb/unittests/Target/CMakeLists.txt 
b/lldb/unittests/Target/CMakeLists.txt
index bf08a8f015ba0..665278ba3317f 100644
--- a/lldb/unittests/Target/CMakeLists.txt
+++ b/lldb/unittests/Target/CMakeLists.txt
@@ -10,6 +10,7 @@ add_lldb_unittest(TargetTests
   ModuleCacheTest.cpp
   PathMappingListTest.cpp
   RegisterFlagsTest.cpp
+  ReExportedSymbolTest.cpp
   RemoteAwarePlatformTest.cpp
   ScratchTypeSystemTest.cpp
   StackFrameRecognizerTest.cpp
diff --git a/lldb/unittests/Target/ReExportedSymbolTest.cpp 
b/lldb/unittests/Target/ReExportedSymbolTest.cpp
new file mode 100644
index 0000000000000..bd5512b2d0e34
--- /dev/null
+++ b/lldb/unittests/Target/ReExportedSymbolTest.cpp
@@ -0,0 +1,269 @@
+//===-- ReExportedSymbolTest.cpp 
------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/Platform/Linux/PlatformLinux.h"
+#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/TestUtilities.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+namespace {
+class ReExportedSymbolTest : public testing::Test {
+  SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab,
+                platform_linux::PlatformLinux>
+      subsystems;
+};
+} // namespace
+
+// An ELF filter library naming two auxiliary filtees.  Its zero-sized
+// exported functions "foo" and "bar" are placeholders that ObjectFileELF
+// models as re-exported symbols (the dynamic linker resolves them through
+// the filtees).  "bar" is defined by the first filtee, "foo" only by the
+// second, so resolving "foo" exercises the ordered search across filtees.
+//
+// .dynstr content: "\0libaux1.so\0libaux2.so\0"
+//   offset 0x1: "libaux1.so"
+//   offset 0xC: "libaux2.so"
+static const char *k_filter_yaml = R"(
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x10
+    Content:         C3C3C3C3
+  - Name:            .dynstr
+    Type:            SHT_STRTAB
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x2000
+    AddressAlign:    0x1
+    Content:         "006C6962617578312E736F006C6962617578322E736F00"
+  - Name:            .dynamic
+    Type:            SHT_DYNAMIC
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x3000
+    AddressAlign:    0x8
+    Link:            .dynstr
+    Entries:
+      - Tag:             DT_AUXILIARY
+        Value:           0x1
+      - Tag:             DT_AUXILIARY
+        Value:           0xC
+      - Tag:             DT_NULL
+        Value:           0x0
+Symbols:
+  - Name:            foo
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1000
+    Binding:         STB_GLOBAL
+  - Name:            bar
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1001
+    Binding:         STB_GLOBAL
+  # A real (nonzero-sized) function the filter defines itself.  Besides being
+  # realistic -- a filter library like libc.so.7 is full of real functions --
+  # it gives the object file a code symbol so that SymbolFileSymtab claims the
+  # module (a module whose only symbols are re-export placeholders has no
+  # abilities and would get no symbol table).
+  - Name:            filter_local
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1002
+    Size:            0x2
+    Binding:         STB_GLOBAL
+...
+)";
+
+static const char *k_aux1_yaml = R"(
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x10
+    Content:         C3C3C3C3
+Symbols:
+  - Name:            bar
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1000
+    Size:            0x4
+    Binding:         STB_GLOBAL
+...
+)";
+
+static const char *k_aux2_yaml = R"(
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x10
+    Content:         C3C3C3C3
+Symbols:
+  - Name:            foo
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1000
+    Size:            0x4
+    Binding:         STB_GLOBAL
+...
+)";
+
+// Creates a module from \p file's in-memory buffer, gives it the name the
+// filter's dynamic section refers to, and appends it to the target's image
+// list.
+static ModuleSP AddModule(Target &target, TestFile &file, const char *name) {
+  ModuleSP module_sp = std::make_shared<Module>(file.moduleSpec());
+
+  // The module is built from a buffer with no backing file.  Parse everything
+  // that depends on that buffer *now*, while the module still has no file:
+  //  - GetReExportedLibraries() populates the dynamic-symbol cache, so that
+  //    when the symbol table is parsed below the filter placeholders are seen
+  //    and marked as re-exports.
+  //  - GetSymtab() parses and caches the symbol table (and its symbol file).
+  // Renaming afterwards would otherwise make these look for the symbols in the
+  // now-nonexistent file.  The name is required so re-export resolution can
+  // find the module in the target by the file spec recorded in the filter.
+  if (ObjectFile *of = module_sp->GetObjectFile())
+    of->GetReExportedLibraries();
+  module_sp->GetSymtab();
+  module_sp->SetFileSpecAndObjectName(FileSpec(name), ConstString());
+
+  // Append without notifying: the module-added notification pulls in symbol
+  // preloading and scripting-resource loading, which need a fully initialized
+  // Debugger.  This test only needs the module to be findable in the target's
+  // image list.
+  target.GetImages().Append(module_sp, /*notify=*/false);
+  return module_sp;
+}
+
+// Find the re-exported placeholder symbol named \p name in \p module_sp by
+// iterating the symbol table.  Looking a re-exported symbol up by name and
+// type through the module goes through the symtab name indexes, whose
+// handling of versioned/placeholder names is orthogonal to what is tested
+// here.
+static const Symbol *FindReExport(const ModuleSP &module_sp,
+                                  llvm::StringRef name) {
+  Symtab *symtab = module_sp->GetSymtab();
+  if (!symtab)
+    return nullptr;
+  for (size_t i = 0, e = symtab->GetNumSymbols(); i != e; ++i) {
+    const Symbol *symbol = symtab->SymbolAtIndex(i);
+    if (symbol->GetType() == eSymbolTypeReExported &&
+        symbol->GetName().GetStringRef() == name)
+      return symbol;
+  }
+  return nullptr;
+}
+
+TEST_F(ReExportedSymbolTest, ResolveThroughFilteesInOrder) {
+  // Note: the TestFiles are declared before the target so that their
+  // in-memory buffers outlive the modules the target holds.
+  auto filter_file = TestFile::fromYaml(k_filter_yaml);
+  ASSERT_THAT_EXPECTED(filter_file, llvm::Succeeded());
+  auto aux1_file = TestFile::fromYaml(k_aux1_yaml);
+  ASSERT_THAT_EXPECTED(aux1_file, llvm::Succeeded());
+  auto aux2_file = TestFile::fromYaml(k_aux2_yaml);
+  ASSERT_THAT_EXPECTED(aux2_file, llvm::Succeeded());
+
+  ArchSpec arch("x86_64-pc-linux");
+  Platform::SetHostPlatform(
+      platform_linux::PlatformLinux::CreateInstance(true, &arch));
+  DebuggerSP debugger_sp = Debugger::CreateInstance();
+  ASSERT_TRUE(debugger_sp);
+
+  PlatformSP platform_sp;
+  TargetSP target_sp;
+  debugger_sp->GetTargetList().CreateTarget(
+      *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
+  ASSERT_TRUE(target_sp);
+
+  ModuleSP filter_sp = AddModule(*target_sp, *filter_file, "libfilter.so");
+  ASSERT_TRUE(filter_sp);
+  ModuleSP aux1_sp = AddModule(*target_sp, *aux1_file, "libaux1.so");
+  ASSERT_TRUE(aux1_sp);
+  ModuleSP aux2_sp = AddModule(*target_sp, *aux2_file, "libaux2.so");
+  ASSERT_TRUE(aux2_sp);
+
+  // Sanity: the filter module parsed its symbols and its DT_AUXILIARY filtees
+  // were read in order.  Splitting these out pinpoints which layer fails if
+  // resolution below does.
+  ObjectFile *filter_of = filter_sp->GetObjectFile();
+  ASSERT_NE(nullptr, filter_of);
+  FileSpecList filtees = filter_of->GetReExportedLibraries();
+  ASSERT_EQ(2u, filtees.GetSize());
+  EXPECT_EQ(ConstString("libaux1.so"),
+            filtees.GetFileSpecAtIndex(0).GetFilename());
+  EXPECT_EQ(ConstString("libaux2.so"),
+            filtees.GetFileSpecAtIndex(1).GetFilename());
+  Symtab *filter_symtab = filter_sp->GetSymtab();
+  ASSERT_NE(nullptr, filter_symtab);
+  ASSERT_GT(filter_symtab->GetNumSymbols(), 0u);
+
+  // "bar" resolves through the library recorded on the symbol itself (the
+  // first filtee).
+  const Symbol *bar = FindReExport(filter_sp, "bar");
+  ASSERT_NE(nullptr, bar);
+  Symbol *bar_def = bar->ResolveReExportedSymbol(*target_sp, filter_sp);
+  ASSERT_NE(nullptr, bar_def);
+  EXPECT_EQ(ConstString("bar"), bar_def->GetName());
+  EXPECT_EQ(eSymbolTypeCode, bar_def->GetType());
+  EXPECT_EQ(aux1_sp, bar_def->GetAddress().GetModule());
+
+  // "foo" is not defined by the first filtee: resolution must continue with
+  // the remaining filtees in declaration order and find it in the second.
+  const Symbol *foo = FindReExport(filter_sp, "foo");
+  ASSERT_NE(nullptr, foo);
+  Symbol *foo_def = foo->ResolveReExportedSymbol(*target_sp, filter_sp);
+  ASSERT_NE(nullptr, foo_def);
+  EXPECT_EQ(ConstString("foo"), foo_def->GetName());
+  EXPECT_EQ(eSymbolTypeCode, foo_def->GetType());
+  EXPECT_EQ(aux2_sp, foo_def->GetAddress().GetModule());
+
+  // Without the containing module only the library recorded on the symbol
+  // is searched, so "foo" cannot be resolved.  This is why callers that
+  // have the module should pass it.
+  EXPECT_EQ(nullptr, foo->ResolveReExportedSymbol(*target_sp));
+}

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to