https://github.com/aokblast created https://github.com/llvm/llvm-project/pull/208905
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 libraries may export placeholder symbols 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. >From 95315a11d9044b1befbd1485c05b7ede033176cf Mon Sep 17 00:00:00 2001 From: ShengYi Hung <[email protected]> Date: Sat, 11 Jul 2026 15:43:35 +0800 Subject: [PATCH] [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 libraries may export placeholder symbols 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. --- lldb/include/lldb/Symbol/Symbol.h | 12 ++++- .../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 32 +++++++++++ .../Plugins/ObjectFile/ELF/ObjectFileELF.h | 2 + lldb/source/Symbol/Symbol.cpp | 54 +++++++++++++++---- 4 files changed, 89 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..ad668f9362c9a 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,17 @@ 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..83c1d363cc156 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,44 @@ 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; } _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
