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

>From 0b85e1e9f569820064e6cbf999a9853e7bdb3f8b Mon Sep 17 00:00:00 2001
From: ShengYi Hung <[email protected]>
Date: Sat, 11 Jul 2026 19:11:57 +0800
Subject: [PATCH 1/6] Support Re-export Symbol for FunctionCall

A symbol can be a stub that is re-exported to another library. For
example, ELF can specify an auxiliary library and emit a zero-sized
symbol in the symbol table. This can cause expression evaluation to
resolve the stub instead of the actual function. Fix this by resolving
re-exported symbols to their actual addressed.
---
 .../Process/Utility/InferiorCallPOSIX.cpp     | 34 +++++++++++++++----
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp 
b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index 5226b9bbe7c78..f190b589ad704 100644
--- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -33,6 +33,30 @@
 using namespace lldb;
 using namespace lldb_private;
 
+/// Pick a call target from \p sc_list.  Re-exported symbols have no code of
+/// their own and are resolved through the library that actually defines
+/// them, mirroring what the dynamic linker does.
+static Address GetCallableAddress(Target &target,
+                                  const SymbolContextList &sc_list) {
+  const uint32_t count = sc_list.GetSize();
+  for (uint32_t i = 0; i < count; ++i) {
+    SymbolContext sc;
+    if (!sc_list.GetContextAtIndex(i, sc))
+      continue;
+    if (sc.symbol && sc.symbol->GetType() == eSymbolTypeReExported) {
+      // Pass the containing module so all of its re-exported libraries
+      // (e.g. an ELF filter library's filtees) are searched in order.
+      if (Symbol *actual =
+              sc.symbol->ResolveReExportedSymbol(target, sc.module_sp))
+        return actual->GetAddress();
+      // Unresolvable re-export: not callable.
+      continue;
+    }
+    return sc.GetFunctionOrSymbolAddress();
+  }
+  return Address();
+}
+
 bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
                                     addr_t addr, addr_t length, unsigned prot,
                                     unsigned flags, addr_t fd, addr_t offset) {
@@ -50,8 +74,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t 
&allocated_addr,
       ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list);
   const uint32_t count = sc_list.GetSize();
   if (count > 0) {
-    SymbolContext sc;
-    if (sc_list.GetContextAtIndex(0, sc)) {
+    {
       EvaluateExpressionOptions options;
       options.SetStopOthers(true);
       options.SetUnwindOnError(true);
@@ -74,7 +97,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t 
&allocated_addr,
           prot_arg |= PROT_WRITE;
       }
 
-      Address mmap_addr = sc.GetFunctionOrSymbolAddress();
+      Address mmap_addr = GetCallableAddress(process->GetTarget(), sc_list);
       if (mmap_addr.IsValid()) {
         auto type_system_or_err =
             process->GetTarget().GetScratchTypeSystemForLanguage(
@@ -142,8 +165,7 @@ bool lldb_private::InferiorCallMunmap(Process *process, 
addr_t addr,
       ConstString("munmap"), eFunctionNameTypeFull, function_options, sc_list);
   const uint32_t count = sc_list.GetSize();
   if (count > 0) {
-    SymbolContext sc;
-    if (sc_list.GetContextAtIndex(0, sc)) {
+    {
       EvaluateExpressionOptions options;
       options.SetStopOthers(true);
       options.SetUnwindOnError(true);
@@ -153,7 +175,7 @@ bool lldb_private::InferiorCallMunmap(Process *process, 
addr_t addr,
       options.SetTimeout(process->GetUtilityExpressionTimeout());
       options.SetTrapExceptions(false);
 
-      Address munmap_addr = sc.GetFunctionOrSymbolAddress();
+      Address munmap_addr = GetCallableAddress(process->GetTarget(), sc_list);
       if (munmap_addr.IsValid()) {
         lldb::addr_t args[] = {addr, length};
         lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction(

>From cff87246629c8aeef17459c99d76b1f88c4a3486 Mon Sep 17 00:00:00 2001
From: ShengYi Hung <[email protected]>
Date: Tue, 14 Jul 2026 21:38:36 +0800
Subject: [PATCH 2/6] fixup! Support Re-export Symbol for FunctionCall

---
 .../Plugins/Process/Utility/InferiorCallPOSIX.cpp | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp 
b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index f190b589ad704..dbc53ce5fcee6 100644
--- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -33,9 +33,10 @@
 using namespace lldb;
 using namespace lldb_private;
 
-/// Pick a call target from \p sc_list.  Re-exported symbols have no code of
-/// their own and are resolved through the library that actually defines
-/// them, mirroring what the dynamic linker does.
+/// Pick a call target from \p sc_list.  A symbol from an ELF filter/auxiliary
+/// library is resolved through its filtee(s) first, falling back to its own
+/// definition only if none of them provide it, mirroring what the dynamic
+/// linker does.
 static Address GetCallableAddress(Target &target,
                                   const SymbolContextList &sc_list) {
   const uint32_t count = sc_list.GetSize();
@@ -43,14 +44,16 @@ static Address GetCallableAddress(Target &target,
     SymbolContext sc;
     if (!sc_list.GetContextAtIndex(i, sc))
       continue;
-    if (sc.symbol && sc.symbol->GetType() == eSymbolTypeReExported) {
+    if (sc.symbol) {
       // Pass the containing module so all of its re-exported libraries
       // (e.g. an ELF filter library's filtees) are searched in order.
       if (Symbol *actual =
               sc.symbol->ResolveReExportedSymbol(target, sc.module_sp))
         return actual->GetAddress();
-      // Unresolvable re-export: not callable.
-      continue;
+      // A pure re-export placeholder with no filtee providing a definition
+      // has no code of its own and isn't callable.
+      if (sc.symbol->GetType() == eSymbolTypeReExported)
+        continue;
     }
     return sc.GetFunctionOrSymbolAddress();
   }

>From 66dc68d21562acbe70b4ae035e46e121603f125c Mon Sep 17 00:00:00 2001
From: ShengYi Hung <[email protected]>
Date: Tue, 14 Jul 2026 22:31:57 +0800
Subject: [PATCH 3/6] fixup! Support Re-export Symbol for FunctionCall

---
 .../Process/Utility/InferiorCallPOSIX.cpp     | 123 +++++++++---------
 1 file changed, 60 insertions(+), 63 deletions(-)

diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp 
b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index dbc53ce5fcee6..f11594f2327d1 100644
--- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -77,72 +77,69 @@ bool lldb_private::InferiorCallMmap(Process *process, 
addr_t &allocated_addr,
       ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list);
   const uint32_t count = sc_list.GetSize();
   if (count > 0) {
-    {
-      EvaluateExpressionOptions options;
-      options.SetStopOthers(true);
-      options.SetUnwindOnError(true);
-      options.SetIgnoreBreakpoints(true);
-      options.SetTryAllThreads(true);
-      options.SetDebug(false);
-      options.SetTimeout(process->GetUtilityExpressionTimeout());
-      options.SetTrapExceptions(false);
+    EvaluateExpressionOptions options;
+    options.SetStopOthers(true);
+    options.SetUnwindOnError(true);
+    options.SetIgnoreBreakpoints(true);
+    options.SetTryAllThreads(true);
+    options.SetDebug(false);
+    options.SetTimeout(process->GetUtilityExpressionTimeout());
+    options.SetTrapExceptions(false);
+
+    addr_t prot_arg;
+    if (prot == eMmapProtNone)
+      prot_arg = PROT_NONE;
+    else {
+      prot_arg = 0;
+      if (prot & eMmapProtExec)
+        prot_arg |= PROT_EXEC;
+      if (prot & eMmapProtRead)
+        prot_arg |= PROT_READ;
+      if (prot & eMmapProtWrite)
+        prot_arg |= PROT_WRITE;
+    }
 
-      addr_t prot_arg;
-      if (prot == eMmapProtNone)
-        prot_arg = PROT_NONE;
-      else {
-        prot_arg = 0;
-        if (prot & eMmapProtExec)
-          prot_arg |= PROT_EXEC;
-        if (prot & eMmapProtRead)
-          prot_arg |= PROT_READ;
-        if (prot & eMmapProtWrite)
-          prot_arg |= PROT_WRITE;
+    Address mmap_addr = GetCallableAddress(process->GetTarget(), sc_list);
+    if (mmap_addr.IsValid()) {
+      auto type_system_or_err =
+          process->GetTarget().GetScratchTypeSystemForLanguage(eLanguageTypeC);
+      if (!type_system_or_err) {
+        llvm::consumeError(type_system_or_err.takeError());
+        return false;
       }
-
-      Address mmap_addr = GetCallableAddress(process->GetTarget(), sc_list);
-      if (mmap_addr.IsValid()) {
-        auto type_system_or_err =
-            process->GetTarget().GetScratchTypeSystemForLanguage(
-                eLanguageTypeC);
-        if (!type_system_or_err) {
-          llvm::consumeError(type_system_or_err.takeError());
-          return false;
-        }
-        auto ts = *type_system_or_err;
-        if (!ts)
-          return false;
-        CompilerType void_ptr_type =
-            ts->GetBasicTypeFromAST(eBasicTypeVoid).GetPointerType();
-        const ArchSpec arch = process->GetTarget().GetArchitecture();
-        MmapArgList args =
-            process->GetTarget().GetPlatform()->GetMmapArgumentList(
-                arch, addr, length, prot_arg, flags, fd, offset);
-        lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction(
-            *thread, mmap_addr, void_ptr_type, args, options));
-        if (call_plan_sp) {
-          DiagnosticManager diagnostics;
-
-          StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
-          if (frame) {
-            ExecutionContext exe_ctx;
-            frame->CalculateExecutionContext(exe_ctx);
-            ExpressionResults result = process->RunThreadPlan(
-                exe_ctx, call_plan_sp, options, diagnostics);
-            if (result == eExpressionCompleted) {
-
-              allocated_addr =
-                  call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(
-                      LLDB_INVALID_ADDRESS);
-              if (process->GetAddressByteSize() == 4) {
-                if (allocated_addr == UINT32_MAX)
-                  return false;
-              } else if (process->GetAddressByteSize() == 8) {
-                if (allocated_addr == UINT64_MAX)
-                  return false;
-              }
-              return true;
+      auto ts = *type_system_or_err;
+      if (!ts)
+        return false;
+      CompilerType void_ptr_type =
+          ts->GetBasicTypeFromAST(eBasicTypeVoid).GetPointerType();
+      const ArchSpec arch = process->GetTarget().GetArchitecture();
+      MmapArgList args =
+          process->GetTarget().GetPlatform()->GetMmapArgumentList(
+              arch, addr, length, prot_arg, flags, fd, offset);
+      lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction(
+          *thread, mmap_addr, void_ptr_type, args, options));
+      if (call_plan_sp) {
+        DiagnosticManager diagnostics;
+
+        StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+        if (frame) {
+          ExecutionContext exe_ctx;
+          frame->CalculateExecutionContext(exe_ctx);
+          ExpressionResults result = process->RunThreadPlan(
+              exe_ctx, call_plan_sp, options, diagnostics);
+          if (result == eExpressionCompleted) {
+
+            allocated_addr =
+                call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(
+                    LLDB_INVALID_ADDRESS);
+            if (process->GetAddressByteSize() == 4) {
+              if (allocated_addr == UINT32_MAX)
+                return false;
+            } else if (process->GetAddressByteSize() == 8) {
+              if (allocated_addr == UINT64_MAX)
+                return false;
             }
+            return true;
           }
         }
       }

>From 25c3eefe80778940d141af28fd9455eb0baee2ba Mon Sep 17 00:00:00 2001
From: ShengYi Hung <[email protected]>
Date: Thu, 16 Jul 2026 22:42:37 +0800
Subject: [PATCH 4/6] fixup! Support Re-export Symbol for FunctionCall

---
 .../Process/Utility/InferiorCallPOSIX.cpp     | 52 +++++++++----------
 1 file changed, 25 insertions(+), 27 deletions(-)

diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp 
b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index f11594f2327d1..d4d79e712a83d 100644
--- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -165,33 +165,31 @@ bool lldb_private::InferiorCallMunmap(Process *process, 
addr_t addr,
       ConstString("munmap"), eFunctionNameTypeFull, function_options, sc_list);
   const uint32_t count = sc_list.GetSize();
   if (count > 0) {
-    {
-      EvaluateExpressionOptions options;
-      options.SetStopOthers(true);
-      options.SetUnwindOnError(true);
-      options.SetIgnoreBreakpoints(true);
-      options.SetTryAllThreads(true);
-      options.SetDebug(false);
-      options.SetTimeout(process->GetUtilityExpressionTimeout());
-      options.SetTrapExceptions(false);
-
-      Address munmap_addr = GetCallableAddress(process->GetTarget(), sc_list);
-      if (munmap_addr.IsValid()) {
-        lldb::addr_t args[] = {addr, length};
-        lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction(
-            *thread, munmap_addr, CompilerType(), args, options));
-        if (call_plan_sp) {
-          DiagnosticManager diagnostics;
-
-          StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
-          if (frame) {
-            ExecutionContext exe_ctx;
-            frame->CalculateExecutionContext(exe_ctx);
-            ExpressionResults result = process->RunThreadPlan(
-                exe_ctx, call_plan_sp, options, diagnostics);
-            if (result == eExpressionCompleted) {
-              return true;
-            }
+    EvaluateExpressionOptions options;
+    options.SetStopOthers(true);
+    options.SetUnwindOnError(true);
+    options.SetIgnoreBreakpoints(true);
+    options.SetTryAllThreads(true);
+    options.SetDebug(false);
+    options.SetTimeout(process->GetUtilityExpressionTimeout());
+    options.SetTrapExceptions(false);
+
+    Address munmap_addr = GetCallableAddress(process->GetTarget(), sc_list);
+    if (munmap_addr.IsValid()) {
+      lldb::addr_t args[] = {addr, length};
+      lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallFunction(
+          *thread, munmap_addr, CompilerType(), args, options));
+      if (call_plan_sp) {
+        DiagnosticManager diagnostics;
+
+        StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+        if (frame) {
+          ExecutionContext exe_ctx;
+          frame->CalculateExecutionContext(exe_ctx);
+          ExpressionResults result = process->RunThreadPlan(
+              exe_ctx, call_plan_sp, options, diagnostics);
+          if (result == eExpressionCompleted) {
+            return true;
           }
         }
       }

>From 6fe6d4d8c8cf7b5255d62b8600f72d8e83d90adb Mon Sep 17 00:00:00 2001
From: ShengYi Hung <[email protected]>
Date: Fri, 17 Jul 2026 16:55:13 +0800
Subject: [PATCH 5/6] fixup! [LLDB] Support Auxiliary library in ELF format

---
 .../Plugins/ObjectFile/ELF/ObjectFileELF.cpp      | 15 ---------------
 lldb/source/Symbol/Symbol.cpp                     |  7 ++++++-
 2 files changed, 6 insertions(+), 16 deletions(-)

diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp 
b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 14092fc494cf7..dbcda730c1a2e 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -2352,11 +2352,6 @@ 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
@@ -2683,16 +2678,6 @@ 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/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp
index dea61c1c3eb58..fbb144d1c3f8e 100644
--- a/lldb/source/Symbol/Symbol.cpp
+++ b/lldb/source/Symbol/Symbol.cpp
@@ -456,7 +456,7 @@ Symbol *Symbol::ResolveReExportedSymbolInModuleSpec(
     module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny,
                                           sc_list);
     for (const SymbolContext &sc : sc_list) {
-      if (!sc.symbol->IsExternal())
+      if (!sc.symbol->IsExternal() && !sc.symbol->IsWeak())
         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
@@ -514,6 +514,11 @@ Symbol *Symbol::ResolveReExportedSymbol(
         !object_file->ReExportedLibrariesShadowLocalDefinitions())
       return nullptr;
 
+    // Only exported (global or weak) definitions take part in dynamic
+    // linking, so local symbols are never shadowed by a filtee.
+    if (!IsExternal() && !IsWeak())
+      return nullptr;
+
     // Use this symbol's own (version-suffix-stripped) name so the filtees
     // below are searched for it.
     reexport_name = GetName();

>From ddf626b83017e76da1a680c081e67a6f59f8580b Mon Sep 17 00:00:00 2001
From: ShengYi Hung <[email protected]>
Date: Fri, 17 Jul 2026 16:55:13 +0800
Subject: [PATCH 6/6] fixup! Add unit tests for ELF filter-library symbol
 handling.

---
 .../ObjectFile/ELF/TestObjectFileELF.cpp      |  49 +++----
 .../unittests/Target/ReExportedSymbolTest.cpp | 137 ++++++++++++++----
 2 files changed, 129 insertions(+), 57 deletions(-)

diff --git a/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp 
b/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp
index 90ae974337090..4126fbbbab156 100644
--- a/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp
+++ b/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp
@@ -563,8 +563,12 @@ TEST_F(ObjectFileELFTest, SkipsLocalMappingAndDotLSymbols) 
{
 // 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.
+// Check that the filtees are reported in dynamic-section order and that the
+// symbol table itself is left untouched: marking a symbol as re-exported
+// reuses its address range as string-pointer storage (see
+// Symbol::SetReExportedSymbolName), which would corrupt the file-address
+// indexes for symbols that have a section.  Filtee shadowing happens at
+// resolution time instead (see ReExportedSymbolTest.cpp).
 TEST_F(ObjectFileELFTest, FilterLibraryPlaceholderSymbols) {
   auto ExpectedFile = TestFile::fromYaml(R"(
 --- !ELF
@@ -639,41 +643,28 @@ TEST_F(ObjectFileELFTest, 
FilterLibraryPlaceholderSymbols) {
   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.
+  // Filtee shadowing is a resolution-time concern: no symbol may be marked
+  // eSymbolTypeReExported, which would clobber its address range.
   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;
+    const Symbol *symbol = symtab->SymbolAtIndex(i);
+    EXPECT_NE(eSymbolTypeReExported, symbol->GetType())
+        << "symbol: " << symbol->GetName().GetStringRef().str();
   }
-  ASSERT_NE(nullptr, versioned);
-  EXPECT_EQ(ConstString("open"), versioned->GetReExportedSymbolName());
+
+  // The zero-sized placeholder stays a plain code symbol whose address (and
+  // thus the file-address indexes built from it) is intact.
+  const Symbol *placeholder = module_sp->FindFirstSymbolWithNameAndType(
+      ConstString("mmap"), eSymbolTypeCode);
+  ASSERT_NE(nullptr, placeholder);
+  EXPECT_TRUE(placeholder->ValueIsAddress());
+  EXPECT_EQ(0x1000U, placeholder->GetAddress().GetFileAddress());
+  EXPECT_TRUE(placeholder->GetReExportedSymbolName().IsEmpty());
 
   // 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/ReExportedSymbolTest.cpp 
b/lldb/unittests/Target/ReExportedSymbolTest.cpp
index bd5512b2d0e34..5d62ac4818142 100644
--- a/lldb/unittests/Target/ReExportedSymbolTest.cpp
+++ b/lldb/unittests/Target/ReExportedSymbolTest.cpp
@@ -37,10 +37,14 @@ class ReExportedSymbolTest : public testing::Test {
 } // 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.
+// exported functions "foo", "bar" and "open@@FBSD_1.0" are placeholders the
+// dynamic linker resolves through the filtees.  ObjectFileELF leaves them as
+// plain code symbols (re-export marking would clobber their address ranges);
+// Symbol::ResolveReExportedSymbol shadows them at resolution time.  "bar" is
+// defined by the first filtee, "foo" only by the second, so resolving "foo"
+// exercises the ordered search across filtees.  "open@@FBSD_1.0" exercises
+// version-suffix stripping, and the local "hidden_helper" must not be
+// shadowed even though the first filtee exports that name.
 //
 // .dynstr content: "\0libaux1.so\0libaux2.so\0"
 //   offset 0x1: "libaux1.so"
@@ -58,7 +62,7 @@ static const char *k_filter_yaml = R"(
     Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
     Address:         0x1000
     AddressAlign:    0x10
-    Content:         C3C3C3C3
+    Content:         C3C3C3C3C3C3C3C3
   - Name:            .dynstr
     Type:            SHT_STRTAB
     Flags:           [ SHF_ALLOC ]
@@ -79,6 +83,11 @@ static const char *k_filter_yaml = R"(
       - Tag:             DT_NULL
         Value:           0x0
 Symbols:
+  - Name:            hidden_helper
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1003
+    Binding:         STB_LOCAL
   - Name:            foo
     Type:            STT_FUNC
     Section:         .text
@@ -89,6 +98,11 @@ static const char *k_filter_yaml = R"(
     Section:         .text
     Value:           0x1001
     Binding:         STB_GLOBAL
+  - Name:            "open@@FBSD_1.0"
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1001
+    Binding:         STB_WEAK
   # 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
@@ -100,6 +114,16 @@ static const char *k_filter_yaml = R"(
     Value:           0x1002
     Size:            0x2
     Binding:         STB_GLOBAL
+  # A genuine (nonzero-sized) implementation that the first filtee *also*
+  # defines.  The dynamic linker always searches the filtees before the
+  # filter object's own definition, so the filtee must win even though the
+  # filter's definition is real code and not a placeholder.
+  - Name:            dup_impl
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1004
+    Size:            0x2
+    Binding:         STB_GLOBAL
 ...
 )";
 
@@ -116,17 +140,32 @@ static const char *k_aux1_yaml = R"(
     Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
     Address:         0x1000
     AddressAlign:    0x10
-    Content:         C3C3C3C3
+    Content:         C3C3C3C3C3C3C3C3
 Symbols:
   - Name:            bar
     Type:            STT_FUNC
     Section:         .text
     Value:           0x1000
-    Size:            0x4
+    Size:            0x2
+    Binding:         STB_GLOBAL
+  - Name:            hidden_helper
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1002
+    Size:            0x2
+    Binding:         STB_GLOBAL
+  - Name:            dup_impl
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1004
+    Size:            0x2
     Binding:         STB_GLOBAL
 ...
 )";
 
+// The second filtee's definitions are weak: that is how FreeBSD's
+// libsys.so.7 exports its syscall stubs, and weak definitions take part in
+// dynamic linking just like global ones.
 static const char *k_aux2_yaml = R"(
 --- !ELF
 FileHeader:
@@ -146,8 +185,14 @@ static const char *k_aux2_yaml = R"(
     Type:            STT_FUNC
     Section:         .text
     Value:           0x1000
-    Size:            0x4
-    Binding:         STB_GLOBAL
+    Size:            0x2
+    Binding:         STB_WEAK
+  - Name:            open
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1002
+    Size:            0x2
+    Binding:         STB_WEAK
 ...
 )";
 
@@ -159,9 +204,8 @@ static ModuleSP AddModule(Target &target, TestFile &file, 
const char *name) {
 
   // 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.
+  //  - GetReExportedLibraries() parses and caches the dynamic section, which
+  //    re-export resolution reads later.
   //  - 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
@@ -179,20 +223,19 @@ static ModuleSP AddModule(Target &target, TestFile &file, 
const char *name) {
   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) {
+// Find the symbol whose name is \p name, ignoring any @VERSION suffix, in
+// \p module_sp by iterating the symbol table.  Iterating keeps the lookup
+// independent of how the symtab name indexes treat versioned names, which is
+// orthogonal to what is tested here.
+static const Symbol *FindFilterSymbol(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)
+    llvm::StringRef symbol_name = symbol->GetName().GetStringRef();
+    if (symbol_name.substr(0, symbol_name.find('@')) == name)
       return symbol;
   }
   return nullptr;
@@ -242,10 +285,14 @@ TEST_F(ReExportedSymbolTest, 
ResolveThroughFilteesInOrder) {
   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");
+  // The placeholders stay plain code symbols: marking them as re-exported
+  // would reuse their address ranges as string-pointer storage and corrupt
+  // the file-address indexes.
+  const Symbol *bar = FindFilterSymbol(filter_sp, "bar");
   ASSERT_NE(nullptr, bar);
+  EXPECT_EQ(eSymbolTypeCode, bar->GetType());
+
+  // "bar" is found in the first filtee.
   Symbol *bar_def = bar->ResolveReExportedSymbol(*target_sp, filter_sp);
   ASSERT_NE(nullptr, bar_def);
   EXPECT_EQ(ConstString("bar"), bar_def->GetName());
@@ -254,7 +301,7 @@ TEST_F(ReExportedSymbolTest, ResolveThroughFilteesInOrder) {
 
   // "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");
+  const Symbol *foo = FindFilterSymbol(filter_sp, "foo");
   ASSERT_NE(nullptr, foo);
   Symbol *foo_def = foo->ResolveReExportedSymbol(*target_sp, filter_sp);
   ASSERT_NE(nullptr, foo_def);
@@ -262,8 +309,42 @@ TEST_F(ReExportedSymbolTest, ResolveThroughFilteesInOrder) 
{
   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.
+  // "open@@FBSD_1.0": the @VERSION suffix is stripped before the filtees are
+  // searched, since the filtee exports the plain name.
+  const Symbol *open_sym = FindFilterSymbol(filter_sp, "open");
+  ASSERT_NE(nullptr, open_sym);
+  Symbol *open_def = open_sym->ResolveReExportedSymbol(*target_sp, filter_sp);
+  ASSERT_NE(nullptr, open_def);
+  EXPECT_EQ(ConstString("open"), open_def->GetName());
+  EXPECT_EQ(aux2_sp, open_def->GetAddress().GetModule());
+
+  // A local symbol is invisible to the dynamic linker and must not be
+  // shadowed, even though the first filtee exports the same name.
+  const Symbol *hidden = FindFilterSymbol(filter_sp, "hidden_helper");
+  ASSERT_NE(nullptr, hidden);
+  EXPECT_EQ(nullptr, hidden->ResolveReExportedSymbol(*target_sp, filter_sp));
+
+  // A name no filtee provides resolves to nothing; callers then fall back
+  // to the filter's own (intact) definition.
+  const Symbol *filter_local = FindFilterSymbol(filter_sp, "filter_local");
+  ASSERT_NE(nullptr, filter_local);
+  EXPECT_EQ(nullptr,
+            filter_local->ResolveReExportedSymbol(*target_sp, filter_sp));
+
+  // Both the filter and the first filtee genuinely define "dup_impl"
+  // (nonzero-sized code on both sides).  The dynamic linker searches the
+  // filtees before the filter object's own definition, so the filtee's
+  // definition must win.
+  const Symbol *dup = FindFilterSymbol(filter_sp, "dup_impl");
+  ASSERT_NE(nullptr, dup);
+  EXPECT_EQ(eSymbolTypeCode, dup->GetType());
+  Symbol *dup_def = dup->ResolveReExportedSymbol(*target_sp, filter_sp);
+  ASSERT_NE(nullptr, dup_def);
+  EXPECT_EQ(ConstString("dup_impl"), dup_def->GetName());
+  EXPECT_EQ(aux1_sp, dup_def->GetAddress().GetModule());
+
+  // Without the containing module nothing connects the symbol to the
+  // filtees, so "foo" cannot be resolved.  This is why callers that have
+  // the module should pass it.
   EXPECT_EQ(nullptr, foo->ResolveReExportedSymbol(*target_sp));
 }

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

Reply via email to