https://github.com/augusto2112 updated https://github.com/llvm/llvm-project/pull/168797
>From 8b04ffa007ded680a56733be79a5ee92589acdc6 Mon Sep 17 00:00:00 2001 From: Augusto Noronha <[email protected]> Date: Wed, 19 Nov 2025 15:57:16 -0800 Subject: [PATCH 1/6] [lldb] Refactor LookupInfo object to be per-language Some months ago, the LookupInfo constructor logic was refactored to not depend on language specific logic, and use languages plugins instead. In this refactor, when the language type is unknown, a single LookupInfo object will handle multiple languages. This doesn't work well, as multiple languages might want to configure the LookupInfo object in different ways. For example, different languages might want to set the m_lookup_name differently from each other, but the previous implementation would pick the first name a language provided, and effectively ignored every other language. Other fields of the LookupInfo object are also configured in incompatible ways. This approach doesn't seem to be a problem upstream, since only the C++/Objective-C language plugins are available, but it broke downstream on the Swift fork, as adding Swift to the list of default languages when the language type is unknown breaks C++ tests. This patch makes it so instead of building a single LookupInfo object for multiple languages, one LookupInfo object is built per language instead. rdar://159531216 --- lldb/include/lldb/Core/Module.h | 45 +++++++++- lldb/include/lldb/Symbol/SymbolContext.h | 14 +++ lldb/include/lldb/Symbol/SymbolFile.h | 4 + .../Breakpoint/BreakpointResolverName.cpp | 33 ++++--- lldb/source/Core/Module.cpp | 90 ++++++++++++------- lldb/source/Core/ModuleList.cpp | 48 +++++----- .../Breakpad/SymbolFileBreakpad.cpp | 2 +- .../Plugins/SymbolFile/DWARF/DWARFIndex.cpp | 8 ++ .../Plugins/SymbolFile/DWARF/DWARFIndex.h | 5 ++ .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 10 +-- lldb/source/Symbol/SymbolContext.cpp | 29 +++++- lldb/source/Symbol/SymbolFile.cpp | 8 ++ lldb/tools/lldb-test/lldb-test.cpp | 7 +- 13 files changed, 224 insertions(+), 79 deletions(-) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 8513e147ee523..de4e416218f73 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -315,6 +315,22 @@ class Module : public std::enable_shared_from_this<Module>, const ModuleFunctionSearchOptions &options, SymbolContextList &sc_list); + /// Find functions by a vector of lookup infos. + /// + /// If the function is an inlined function, it will have a block, + /// representing the inlined function, and the function will be the + /// containing function. If it is not inlined, then the block will be NULL. + /// + /// \param[in] lookup_infos + /// The vector of lookup infos of the function we are looking for. + /// + /// \param[out] sc_list + /// A symbol context list that gets filled in with all of the + /// matches. + void FindFunctions(const std::vector<LookupInfo> &lookup_infos, + const CompilerDeclContext &parent_decl_ctx, + const ModuleFunctionSearchOptions &options, + SymbolContextList &sc_list); /// Find functions by name. /// /// If the function is an inlined function, it will have a block, @@ -917,8 +933,29 @@ class Module : public std::enable_shared_from_this<Module>, public: LookupInfo() = default; - LookupInfo(ConstString name, lldb::FunctionNameType name_type_mask, - lldb::LanguageType language); + /// Creates a vector of lookup infos for function name resolution. + /// + /// \param[in] name + /// The function name to search for. This can be a simple name like + /// "foo" or a qualified name like "Class::method". + /// + /// \param[in] name_type_mask + /// A bitmask specifying what types of names to search for + /// (e.g., eFunctionNameTypeFull, eFunctionNameTypeBase, + /// eFunctionNameTypeMethod, eFunctionNameTypeAuto). Multiple types + /// can be combined with bitwise OR. + /// + /// \param[in] requested_lang_type + /// The language to create lookups for. If eLanguageTypeUnknown is + /// passed, creates one LookupInfo for each language plugin currently + /// available in LLDB. If a specific language is provided, creates only + // a single LookupInfo for that language. + /// + /// \return + /// A vector of LookupInfo objects, one per relevant language. + static std::vector<LookupInfo> + MakeLookupInfos(ConstString name, lldb::FunctionNameType name_type_mask, + lldb::LanguageType requested_lang_type); ConstString GetName() const { return m_name; } @@ -959,6 +996,10 @@ class Module : public std::enable_shared_from_this<Module>, /// If \b true, then demangled names that match will need to contain /// "m_name" in order to be considered a match bool m_match_name_after_lookup = false; + + private: + LookupInfo(ConstString name, lldb::FunctionNameType name_type_mask, + lldb::LanguageType lang_type); }; /// Get a unique hash for this module. diff --git a/lldb/include/lldb/Symbol/SymbolContext.h b/lldb/include/lldb/Symbol/SymbolContext.h index af2f694e554de..0834825cdbd25 100644 --- a/lldb/include/lldb/Symbol/SymbolContext.h +++ b/lldb/include/lldb/Symbol/SymbolContext.h @@ -231,6 +231,20 @@ class SymbolContext { lldb::LanguageType GetLanguage() const; + /// Compares the two symbol contexts, considering that the symbol may or may + /// not be present. If both symbols are present, compare them, if one of the + /// symbols is not present, consider the symbol contexts as equal as long as + /// the other fields are equal. + /// + /// This function exists because SymbolContexts are often created without the + /// symbol, which is filled in later on, after its creation. + static bool CompareConsideringPossiblyNullSymbol(const SymbolContext &lhs, + const SymbolContext &rhs); + + /// Compares the two symbol contexts, except for the symbol field. + static bool CompareWithoutSymbol(const SymbolContext &lhs, + const SymbolContext &rhs); + /// Find a block that defines the function represented by this symbol /// context. /// diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index 3b4d7bc01d132..305eb0f201b37 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -309,6 +309,10 @@ class SymbolFile : public PluginInterface { virtual void FindFunctions(const Module::LookupInfo &lookup_info, const CompilerDeclContext &parent_decl_ctx, bool include_inlines, SymbolContextList &sc_list); + virtual void + FindFunctions(const std::vector<Module::LookupInfo> &lookup_infos, + const CompilerDeclContext &parent_decl_ctx, + bool include_inlines, SymbolContextList &sc_list); virtual void FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list); diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp index 4f252f91cccdc..2025f59eacb92 100644 --- a/lldb/source/Breakpoint/BreakpointResolverName.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp @@ -218,19 +218,22 @@ StructuredData::ObjectSP BreakpointResolverName::SerializeToStructuredData() { void BreakpointResolverName::AddNameLookup(ConstString name, FunctionNameType name_type_mask) { - - Module::LookupInfo lookup(name, name_type_mask, m_language); - m_lookups.emplace_back(lookup); + std::vector<Module::LookupInfo> infos = + Module::LookupInfo::MakeLookupInfos(name, name_type_mask, m_language); + llvm::append_range(m_lookups, infos); auto add_variant_funcs = [&](Language *lang) { for (Language::MethodNameVariant variant : lang->GetMethodNameVariants(name)) { // FIXME: Should we be adding variants that aren't of type Full? if (variant.GetType() & lldb::eFunctionNameTypeFull) { - Module::LookupInfo variant_lookup(name, variant.GetType(), - lang->GetLanguageType()); - variant_lookup.SetLookupName(variant.GetName()); - m_lookups.emplace_back(variant_lookup); + std::vector<Module::LookupInfo> variant_lookups = + Module::LookupInfo::MakeLookupInfos(name, variant.GetType(), + lang->GetLanguageType()); + llvm::for_each(variant_lookups, [&](auto &variant_lookup) { + variant_lookup.SetLookupName(variant.GetName()); + }); + llvm::append_range(m_lookups, variant_lookups); } } return IterationAction::Continue; @@ -401,14 +404,22 @@ void BreakpointResolverName::GetDescription(Stream *s) { if (m_match_type == Breakpoint::Regexp) s->Printf("regex = '%s'", m_regex.GetText().str().c_str()); else { - size_t num_names = m_lookups.size(); - if (num_names == 1) - s->Printf("name = '%s'", m_lookups[0].GetName().GetCString()); + // Since there may be many lookups objects for the same name breakpoint (one + // per language available), unique them by name, and operate on those unique + // names. + std::vector<ConstString> unique_lookups; + for (auto &lookup : m_lookups) { + if (!llvm::is_contained(unique_lookups, lookup.GetName())) + unique_lookups.push_back(lookup.GetName()); + } + if (unique_lookups.size() == 1) + s->Printf("name = '%s'", unique_lookups[0].GetCString()); else { + size_t num_names = unique_lookups.size(); s->Printf("names = {"); for (size_t i = 0; i < num_names; i++) { s->Printf("%s'%s'", (i == 0 ? "" : ", "), - m_lookups[i].GetName().GetCString()); + unique_lookups[i].GetCString()); } s->Printf("}"); } diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 815cc9dada2c1..79be944b33998 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -643,26 +643,13 @@ void Module::FindCompileUnits(const FileSpec &path, Module::LookupInfo::LookupInfo(ConstString name, FunctionNameType name_type_mask, - LanguageType language) - : m_name(name), m_lookup_name(name), m_language(language) { + LanguageType lang_type) + : m_name(name), m_lookup_name(name), m_language(lang_type) { std::optional<ConstString> basename; - - std::vector<Language *> languages; - { - std::vector<LanguageType> lang_types; - if (language != eLanguageTypeUnknown) - lang_types.push_back(language); - else - lang_types = {eLanguageTypeObjC, eLanguageTypeC_plus_plus}; - - for (LanguageType lang_type : lang_types) { - if (Language *lang = Language::FindPlugin(lang_type)) - languages.push_back(lang); - } - } + Language *lang = Language::FindPlugin(lang_type); if (name_type_mask & eFunctionNameTypeAuto) { - for (Language *lang : languages) { + if (lang) { auto info = lang->GetFunctionNameInfo(name); if (info.first != eFunctionNameTypeNone) { m_name_type_mask |= info.first; @@ -679,7 +666,7 @@ Module::LookupInfo::LookupInfo(ConstString name, } else { m_name_type_mask = name_type_mask; - for (Language *lang : languages) { + if (lang) { auto info = lang->GetFunctionNameInfo(name); if (info.first & m_name_type_mask) { // If the user asked for FunctionNameTypes that aren't possible, @@ -688,14 +675,12 @@ Module::LookupInfo::LookupInfo(ConstString name, // ObjC) m_name_type_mask &= info.first; basename = info.second; - break; - } - // Still try and get a basename in case someone specifies a name type mask - // of eFunctionNameTypeFull and a name like "A::func" - if (name_type_mask & eFunctionNameTypeFull && - info.first != eFunctionNameTypeNone && !basename && info.second) { + } else if (name_type_mask & eFunctionNameTypeFull && + info.first != eFunctionNameTypeNone && !basename && + info.second) { + // Still try and get a basename in case someone specifies a name type + // mask of eFunctionNameTypeFull and a name like "A::func" basename = info.second; - break; } } } @@ -711,6 +696,36 @@ Module::LookupInfo::LookupInfo(ConstString name, } } +std::vector<Module::LookupInfo> +Module::LookupInfo::MakeLookupInfos(ConstString name, + lldb::FunctionNameType name_type_mask, + lldb::LanguageType requested_lang_type) { + std::vector<LanguageType> lang_types; + if (requested_lang_type != eLanguageTypeUnknown) { + lang_types.push_back(requested_lang_type); + } else { + // If the language type was not specified, look up in every language + // available. + Language::ForEach([&](Language *lang) { + auto lang_type = lang->GetLanguageType(); + if (!llvm::is_contained(lang_types, lang_type)) + lang_types.push_back(lang_type); + return IterationAction::Continue; + }); + + if (lang_types.empty()) + lang_types = {eLanguageTypeObjC, eLanguageTypeC_plus_plus}; + } + + std::vector<Module::LookupInfo> infos; + infos.reserve(lang_types.size()); + for (LanguageType lang_type : lang_types) { + Module::LookupInfo info(name, name_type_mask, lang_type); + infos.push_back(info); + } + return infos; +} + bool Module::LookupInfo::NameMatchesLookupInfo( ConstString function_name, LanguageType language_type) const { // We always keep unnamed symbols @@ -824,18 +839,29 @@ void Module::FindFunctions(const Module::LookupInfo &lookup_info, } } +void Module::FindFunctions(const std::vector<Module::LookupInfo> &lookup_infos, + const CompilerDeclContext &parent_decl_ctx, + const ModuleFunctionSearchOptions &options, + SymbolContextList &sc_list) { + for (auto &lookup_info : lookup_infos) + FindFunctions(lookup_info, parent_decl_ctx, options, sc_list); +} + void Module::FindFunctions(ConstString name, const CompilerDeclContext &parent_decl_ctx, FunctionNameType name_type_mask, const ModuleFunctionSearchOptions &options, SymbolContextList &sc_list) { - const size_t old_size = sc_list.GetSize(); - LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown); - FindFunctions(lookup_info, parent_decl_ctx, options, sc_list); - if (name_type_mask & eFunctionNameTypeAuto) { - const size_t new_size = sc_list.GetSize(); - if (old_size < new_size) - lookup_info.Prune(sc_list, old_size); + std::vector<LookupInfo> lookup_infos = + LookupInfo::MakeLookupInfos(name, name_type_mask, eLanguageTypeUnknown); + for (auto &lookup_info : lookup_infos) { + const size_t old_size = sc_list.GetSize(); + FindFunctions(lookup_info, parent_decl_ctx, options, sc_list); + if (name_type_mask & eFunctionNameTypeAuto) { + const size_t new_size = sc_list.GetSize(); + if (old_size < new_size) + lookup_info.Prune(sc_list, old_size); + } } } diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 5444c04e74522..be6ff723e0ffa 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -453,21 +453,22 @@ void ModuleList::FindFunctions(ConstString name, FunctionNameType name_type_mask, const ModuleFunctionSearchOptions &options, SymbolContextList &sc_list) const { - const size_t old_size = sc_list.GetSize(); - if (name_type_mask & eFunctionNameTypeAuto) { - Module::LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown); - + std::vector<Module::LookupInfo> lookup_infos = + Module::LookupInfo::MakeLookupInfos(name, name_type_mask, + eLanguageTypeUnknown); std::lock_guard<std::recursive_mutex> guard(m_modules_mutex); - for (const ModuleSP &module_sp : m_modules) { - module_sp->FindFunctions(lookup_info, CompilerDeclContext(), options, - sc_list); - } - - const size_t new_size = sc_list.GetSize(); + for (const auto &lookup_info : lookup_infos) { + const size_t old_size = sc_list.GetSize(); + for (const ModuleSP &module_sp : m_modules) { + module_sp->FindFunctions(lookup_info, CompilerDeclContext(), options, + sc_list); + } - if (old_size < new_size) - lookup_info.Prune(sc_list, old_size); + const size_t new_size = sc_list.GetSize(); + if (old_size < new_size) + lookup_info.Prune(sc_list, old_size); + } } else { std::lock_guard<std::recursive_mutex> guard(m_modules_mutex); for (const ModuleSP &module_sp : m_modules) { @@ -480,21 +481,24 @@ void ModuleList::FindFunctions(ConstString name, void ModuleList::FindFunctionSymbols(ConstString name, lldb::FunctionNameType name_type_mask, SymbolContextList &sc_list) { - const size_t old_size = sc_list.GetSize(); - if (name_type_mask & eFunctionNameTypeAuto) { - Module::LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown); + std::vector<Module::LookupInfo> lookup_infos = + Module::LookupInfo::MakeLookupInfos(name, name_type_mask, + eLanguageTypeUnknown); std::lock_guard<std::recursive_mutex> guard(m_modules_mutex); - for (const ModuleSP &module_sp : m_modules) { - module_sp->FindFunctionSymbols(lookup_info.GetLookupName(), - lookup_info.GetNameTypeMask(), sc_list); - } + for (const auto &lookup_info : lookup_infos) { + const size_t old_size = sc_list.GetSize(); + for (const ModuleSP &module_sp : m_modules) { + module_sp->FindFunctionSymbols(lookup_info.GetLookupName(), + lookup_info.GetNameTypeMask(), sc_list); + } - const size_t new_size = sc_list.GetSize(); + const size_t new_size = sc_list.GetSize(); - if (old_size < new_size) - lookup_info.Prune(sc_list, old_size); + if (old_size < new_size) + lookup_info.Prune(sc_list, old_size); + } } else { std::lock_guard<std::recursive_mutex> guard(m_modules_mutex); for (const ModuleSP &module_sp : m_modules) { diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp index ce2ba69be2e96..14932e957d081 100644 --- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -437,7 +437,7 @@ void SymbolFileBreakpad::FindFunctions( sc.comp_unit = cu_sp.get(); sc.function = func_sp.get(); sc.module_sp = func_sp->CalculateSymbolContextModule(); - sc_list.Append(sc); + sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/true); } } } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp index 64a8005308454..c4efc06ab7873 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp @@ -173,6 +173,14 @@ void DWARFIndex::GetNamespacesWithParents( }); } +void DWARFIndex::GetFunctions( + const std::vector<Module::LookupInfo> &lookup_infos, SymbolFileDWARF &dwarf, + const CompilerDeclContext &parent_decl_ctx, + llvm::function_ref<IterationAction(DWARFDIE die)> callback) { + for (auto &lookup_info : lookup_infos) + GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback); +} + IterationAction DWARFIndex::ProcessNamespaceDieMatchParents( const CompilerDeclContext &parent_decl_ctx, DWARFDIE die, llvm::function_ref<IterationAction(DWARFDIE die)> callback) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h index be73255aaf141..eaf1da123602e 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h @@ -86,6 +86,11 @@ class DWARFIndex { const CompilerDeclContext &parent_decl_ctx, llvm::function_ref<IterationAction(DWARFDIE die)> callback) = 0; virtual void + GetFunctions(const std::vector<Module::LookupInfo> &lookup_infos, + SymbolFileDWARF &dwarf, + const CompilerDeclContext &parent_decl_ctx, + llvm::function_ref<IterationAction(DWARFDIE die)> callback); + virtual void GetFunctions(const RegularExpression ®ex, llvm::function_ref<IterationAction(DWARFDIE die)> callback) = 0; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 7ba765371c54f..b755f3a6faaa0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2481,7 +2481,7 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, sc.block = function_block.FindBlockByID(inlined_die.GetOffset()); } - sc_list.Append(sc); + sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/true); return true; } @@ -2549,11 +2549,11 @@ SymbolFileDWARF::FindFunctionDefinition(const FunctionCallLabel &label, const DWARFDIE &declaration) { auto do_lookup = [this](llvm::StringRef lookup_name) -> DWARFDIE { DWARFDIE found; - Module::LookupInfo info(ConstString(lookup_name), - lldb::eFunctionNameTypeFull, - lldb::eLanguageTypeUnknown); + auto lookup_infos = Module::LookupInfo::MakeLookupInfos( + ConstString(lookup_name), lldb::eFunctionNameTypeFull, + lldb::eLanguageTypeUnknown); - m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) { + m_index->GetFunctions(lookup_infos, *this, {}, [&](DWARFDIE entry) { if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) return IterationAction::Continue; diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp index 3bbd1eff824e6..ead924afa9fc2 100644 --- a/lldb/source/Symbol/SymbolContext.cpp +++ b/lldb/source/Symbol/SymbolContext.cpp @@ -324,12 +324,32 @@ uint32_t SymbolContext::GetResolvedMask() const { bool lldb_private::operator==(const SymbolContext &lhs, const SymbolContext &rhs) { - return lhs.function == rhs.function && lhs.symbol == rhs.symbol && + return SymbolContext::CompareWithoutSymbol(lhs, rhs) && + lhs.symbol == rhs.symbol; +} + +bool SymbolContext::CompareConsideringPossiblyNullSymbol( + const SymbolContext &lhs, const SymbolContext &rhs) { + if (!CompareWithoutSymbol(lhs, rhs)) + return false; + + // If one (or both) of the symbol context's symbol is empty, consider them + // equal. + if (!lhs.symbol || !rhs.symbol) + return true; + + // If both symbols are present, make sure they're the same. + return lhs.symbol == rhs.symbol; +} + +bool SymbolContext::CompareWithoutSymbol(const SymbolContext &lhs, + const SymbolContext &rhs) { + return lhs.function == rhs.function && lhs.module_sp.get() == rhs.module_sp.get() && lhs.comp_unit == rhs.comp_unit && lhs.target_sp.get() == rhs.target_sp.get() && LineEntry::Compare(lhs.line_entry, rhs.line_entry) == 0 && - lhs.variable == rhs.variable; + lhs.variable == rhs.variable && lhs.block == rhs.block; } bool lldb_private::operator!=(const SymbolContext &lhs, @@ -1200,7 +1220,10 @@ bool SymbolContextList::AppendIfUnique(const SymbolContext &sc, bool merge_symbol_into_function) { collection::iterator pos, end = m_symbol_contexts.end(); for (pos = m_symbol_contexts.begin(); pos != end; ++pos) { - if (*pos == sc) + // Because symbol contexts might first be built without the symbol, + // which is then appended later on, compare the symbol contexts taking into + // accout that one (or either) of them might not have a symbol yet. + if (SymbolContext::CompareConsideringPossiblyNullSymbol(*pos, sc)) return false; } if (merge_symbol_into_function && sc.symbol != nullptr && diff --git a/lldb/source/Symbol/SymbolFile.cpp b/lldb/source/Symbol/SymbolFile.cpp index 870d778dca740..2aea802b6c826 100644 --- a/lldb/source/Symbol/SymbolFile.cpp +++ b/lldb/source/Symbol/SymbolFile.cpp @@ -126,6 +126,14 @@ void SymbolFile::FindFunctions(const Module::LookupInfo &lookup_info, bool include_inlines, SymbolContextList &sc_list) {} +void SymbolFile::FindFunctions( + const std::vector<Module::LookupInfo> &lookup_infos, + const CompilerDeclContext &parent_decl_ctx, bool include_inlines, + SymbolContextList &sc_list) { + for (const auto &lookup_info : lookup_infos) + FindFunctions(lookup_info, parent_decl_ctx, include_inlines, sc_list); +} + void SymbolFile::FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) {} diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp index 3f198d963a93b..84e83da230029 100644 --- a/lldb/tools/lldb-test/lldb-test.cpp +++ b/lldb/tools/lldb-test/lldb-test.cpp @@ -523,9 +523,10 @@ Error opts::symbols::findFunctions(lldb_private::Module &Module) { ContextOr->IsValid() ? *ContextOr : CompilerDeclContext(); List.Clear(); - lldb_private::Module::LookupInfo lookup_info( - ConstString(Name), getFunctionNameFlags(), eLanguageTypeUnknown); - Symfile.FindFunctions(lookup_info, ContextPtr, true, List); + std::vector<lldb_private::Module::LookupInfo> lookup_infos = + lldb_private::Module::LookupInfo::MakeLookupInfos( + ConstString(Name), getFunctionNameFlags(), eLanguageTypeUnknown); + Symfile.FindFunctions(lookup_infos, ContextPtr, true, List); } outs() << formatv("Found {0} functions:\n", List.GetSize()); StreamString Stream; >From e55e3780c33dc888efa6acd2e67a65ec48ebdcaf Mon Sep 17 00:00:00 2001 From: Augusto Noronha <[email protected]> Date: Tue, 2 Dec 2025 17:00:31 -0800 Subject: [PATCH 2/6] Add test --- lldb/include/lldb/Core/Module.h | 11 +-- lldb/source/Core/Module.cpp | 6 +- lldb/unittests/Core/CMakeLists.txt | 1 + lldb/unittests/Core/ModuleTest.cpp | 148 +++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 12 deletions(-) create mode 100644 lldb/unittests/Core/ModuleTest.cpp diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index de4e416218f73..96ae8364c94e5 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -320,13 +320,6 @@ class Module : public std::enable_shared_from_this<Module>, /// If the function is an inlined function, it will have a block, /// representing the inlined function, and the function will be the /// containing function. If it is not inlined, then the block will be NULL. - /// - /// \param[in] lookup_infos - /// The vector of lookup infos of the function we are looking for. - /// - /// \param[out] sc_list - /// A symbol context list that gets filled in with all of the - /// matches. void FindFunctions(const std::vector<LookupInfo> &lookup_infos, const CompilerDeclContext &parent_decl_ctx, const ModuleFunctionSearchOptions &options, @@ -945,7 +938,7 @@ class Module : public std::enable_shared_from_this<Module>, /// eFunctionNameTypeMethod, eFunctionNameTypeAuto). Multiple types /// can be combined with bitwise OR. /// - /// \param[in] requested_lang_type + /// \param[in] lang_type /// The language to create lookups for. If eLanguageTypeUnknown is /// passed, creates one LookupInfo for each language plugin currently /// available in LLDB. If a specific language is provided, creates only @@ -955,7 +948,7 @@ class Module : public std::enable_shared_from_this<Module>, /// A vector of LookupInfo objects, one per relevant language. static std::vector<LookupInfo> MakeLookupInfos(ConstString name, lldb::FunctionNameType name_type_mask, - lldb::LanguageType requested_lang_type); + lldb::LanguageType lang_type); ConstString GetName() const { return m_name; } diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 79be944b33998..eb2f95b105a5d 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -699,10 +699,10 @@ Module::LookupInfo::LookupInfo(ConstString name, std::vector<Module::LookupInfo> Module::LookupInfo::MakeLookupInfos(ConstString name, lldb::FunctionNameType name_type_mask, - lldb::LanguageType requested_lang_type) { + lldb::LanguageType lang_type) { std::vector<LanguageType> lang_types; - if (requested_lang_type != eLanguageTypeUnknown) { - lang_types.push_back(requested_lang_type); + if (lang_type != eLanguageTypeUnknown) { + lang_types.push_back(lang_type); } else { // If the language type was not specified, look up in every language // available. diff --git a/lldb/unittests/Core/CMakeLists.txt b/lldb/unittests/Core/CMakeLists.txt index f0c9a9a9d5056..d69432d332f44 100644 --- a/lldb/unittests/Core/CMakeLists.txt +++ b/lldb/unittests/Core/CMakeLists.txt @@ -9,6 +9,7 @@ add_lldb_unittest(LLDBCoreTests MangledTest.cpp ModuleListTest.cpp ModuleSpecTest.cpp + ModuleTest.cpp PluginManagerTest.cpp ProgressReportTest.cpp RichManglingContextTest.cpp diff --git a/lldb/unittests/Core/ModuleTest.cpp b/lldb/unittests/Core/ModuleTest.cpp new file mode 100644 index 0000000000000..446793dc389e3 --- /dev/null +++ b/lldb/unittests/Core/ModuleTest.cpp @@ -0,0 +1,148 @@ +//===-- ModuleTest.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 "lldb/Core/Module.h" +#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" +#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/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Target/Language.h" +#include "lldb/lldb-enumerations.h" +#include "gtest/gtest.h" +#include <optional> + +using namespace lldb; +using namespace lldb_private; + +// Test that Module::FindFunctions correctly finds C++ mangled symbols +// even when multiple language plugins are registered. +TEST(ModuleTest, FindFunctionsCppMangledName) { + // Create a mock language. The point of this language is to return something + // in GetFunctionNameInfo that would interfere with the C++ language plugin, + // were they sharing the same LookupInfo. + class MockLanguageWithBogusLookupInfo : public Language { + public: + MockLanguageWithBogusLookupInfo() = default; + ~MockLanguageWithBogusLookupInfo() override = default; + + lldb::LanguageType GetLanguageType() const override { + // The language here doesn't really matter, it just has to be something + // that is not C/C++/ObjC. + return lldb::eLanguageTypeSwift; + } + + llvm::StringRef GetPluginName() override { return "mock-bogus-language"; } + + bool IsSourceFile(llvm::StringRef file_path) const override { + return file_path.ends_with(".swift"); + } + + std::pair<lldb::FunctionNameType, std::optional<ConstString>> + GetFunctionNameInfo(ConstString name) const override { + // Say that every function is a selector. + return {lldb::eFunctionNameTypeSelector, ConstString("BOGUS_BASENAME")}; + } + + static void Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), "Mock Language", + CreateInstance); + } + + static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); } + + static lldb_private::Language *CreateInstance(lldb::LanguageType language) { + if (language == lldb::eLanguageTypeSwift) + return new MockLanguageWithBogusLookupInfo(); + return nullptr; + } + + static llvm::StringRef GetPluginNameStatic() { + return "mock-bogus-language"; + } + }; + SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab, + CPlusPlusLanguage, platform_linux::PlatformLinux, + MockLanguageWithBogusLookupInfo> + subsystems; + + ArchSpec arch("x86_64-pc-linux"); + Platform::SetHostPlatform( + platform_linux::PlatformLinux::CreateInstance(true, &arch)); + + std::call_once(TestUtilities::g_debugger_initialize_flag, + []() { Debugger::Initialize(nullptr); }); + + // Create a simple ELF module with std::vector::size() as the only symbol. + 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 + Size: 0x100 +Symbols: + - Name: _ZNSt6vectorIiE4sizeEv + Type: STT_FUNC + Section: .text + Value: 0x1030 + Size: 0x20 +... +)"); + ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); + + DebuggerSP debugger_sp = Debugger::CreateInstance(); + ASSERT_TRUE(debugger_sp); + + TargetSP target_sp; + PlatformSP platform_sp; + + Status error = debugger_sp->GetTargetList().CreateTarget( + *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp); + ASSERT_TRUE(error.Success()); + ASSERT_TRUE(target_sp); + + auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec()); + target_sp->GetImages().Append(module_sp); + + // Verify both C++ and our mock language are registered. + Language *cpp_lang = Language::FindPlugin(lldb::eLanguageTypeC_plus_plus); + Language *mock_lang = Language::FindPlugin(lldb::eLanguageTypeSwift); + ASSERT_NE(cpp_lang, nullptr) << "C++ language plugin should be registered"; + ASSERT_NE(mock_lang, nullptr) + << "Mock Swift language plugin should be registered"; + + ModuleFunctionSearchOptions function_options; + function_options.include_symbols = true; + + ConstString symbol_name("_ZNSt6vectorIiE4sizeEv"); + SymbolContextList results; + module_sp->FindFunctions(symbol_name, CompilerDeclContext(), + eFunctionNameTypeAuto, function_options, results); + + // Assert that we found one symbol. + ASSERT_EQ(results.GetSize(), 1u); + + auto result = results[0]; + auto name = result.GetFunctionName(); + // Assert that the symbol we found is what we expected. + ASSERT_EQ(name, "std::vector<int>::size()"); + ASSERT_EQ(result.GetLanguage(), eLanguageTypeC_plus_plus); +} >From 1567174e6b369cd318ed4f4aa045d220b2e20ab9 Mon Sep 17 00:00:00 2001 From: Augusto Noronha <[email protected]> Date: Wed, 3 Dec 2025 10:29:16 -0800 Subject: [PATCH 3/6] --wip-- [skip ci] --- lldb/unittests/Core/ModuleTest.cpp | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/lldb/unittests/Core/ModuleTest.cpp b/lldb/unittests/Core/ModuleTest.cpp index 446793dc389e3..f645479eaa9b3 100644 --- a/lldb/unittests/Core/ModuleTest.cpp +++ b/lldb/unittests/Core/ModuleTest.cpp @@ -72,13 +72,9 @@ TEST(ModuleTest, FindFunctionsCppMangledName) { } }; SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab, - CPlusPlusLanguage, platform_linux::PlatformLinux, - MockLanguageWithBogusLookupInfo> - subsystems; + CPlusPlusLanguage, + MockLanguageWithBogusLookupInfo> subsystems; - ArchSpec arch("x86_64-pc-linux"); - Platform::SetHostPlatform( - platform_linux::PlatformLinux::CreateInstance(true, &arch)); std::call_once(TestUtilities::g_debugger_initialize_flag, []() { Debugger::Initialize(nullptr); }); @@ -108,19 +104,7 @@ TEST(ModuleTest, FindFunctionsCppMangledName) { )"); ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); - DebuggerSP debugger_sp = Debugger::CreateInstance(); - ASSERT_TRUE(debugger_sp); - - TargetSP target_sp; - PlatformSP platform_sp; - - Status error = debugger_sp->GetTargetList().CreateTarget( - *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp); - ASSERT_TRUE(error.Success()); - ASSERT_TRUE(target_sp); - auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec()); - target_sp->GetImages().Append(module_sp); // Verify both C++ and our mock language are registered. Language *cpp_lang = Language::FindPlugin(lldb::eLanguageTypeC_plus_plus); >From c11b5d82958992e56f4228f941aee939629cffb9 Mon Sep 17 00:00:00 2001 From: Augusto Noronha <[email protected]> Date: Wed, 3 Dec 2025 10:33:44 -0800 Subject: [PATCH 4/6] Remove dependency on Linux --- lldb/unittests/Core/ModuleTest.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lldb/unittests/Core/ModuleTest.cpp b/lldb/unittests/Core/ModuleTest.cpp index f645479eaa9b3..f657f7206fa3e 100644 --- a/lldb/unittests/Core/ModuleTest.cpp +++ b/lldb/unittests/Core/ModuleTest.cpp @@ -9,16 +9,13 @@ #include "lldb/Core/Module.h" #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" #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/PluginManager.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" #include "lldb/Target/Language.h" -#include "lldb/lldb-enumerations.h" #include "gtest/gtest.h" #include <optional> @@ -72,12 +69,8 @@ TEST(ModuleTest, FindFunctionsCppMangledName) { } }; SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab, - CPlusPlusLanguage, - MockLanguageWithBogusLookupInfo> subsystems; - - - std::call_once(TestUtilities::g_debugger_initialize_flag, - []() { Debugger::Initialize(nullptr); }); + CPlusPlusLanguage, MockLanguageWithBogusLookupInfo> + subsystems; // Create a simple ELF module with std::vector::size() as the only symbol. auto ExpectedFile = TestFile::fromYaml(R"( >From 15edf30989d46b03d2b680b5b2c9da9cfce87f67 Mon Sep 17 00:00:00 2001 From: Augusto Noronha <[email protected]> Date: Wed, 3 Dec 2025 15:17:30 -0800 Subject: [PATCH 5/6] Update TestBreakpointSerialization --- .../breakpoint/serialize/TestBreakpointSerialization.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lldb/test/API/functionalities/breakpoint/serialize/TestBreakpointSerialization.py b/lldb/test/API/functionalities/breakpoint/serialize/TestBreakpointSerialization.py index 411ce9c67da02..55cc12e894d42 100644 --- a/lldb/test/API/functionalities/breakpoint/serialize/TestBreakpointSerialization.py +++ b/lldb/test/API/functionalities/breakpoint/serialize/TestBreakpointSerialization.py @@ -210,6 +210,11 @@ def check_equivalence(self, source_bps, do_write=True): "Source and dest breakpoints are not identical: \nsource: %s\ndest: %s" % (source_text, copy_text), ) + self.assertEqual( + source_bp.GetNumLocations(), + copy_bp.GetNumLocations(), + "Source and dest num locations are not the same", + ) def do_check_resolvers(self): """Use Python APIs to check serialization of breakpoint resolvers""" @@ -386,7 +391,7 @@ def do_check_appending(self): source_bps.Clear() bkpt = self.orig_target.BreakpointCreateByName( - "blubby", lldb.eFunctionNameTypeAuto, empty_module_list, empty_cu_list + "main", lldb.eFunctionNameTypeAuto, empty_module_list, empty_cu_list ) bkpt.SetIgnoreCount(10) bkpt.SetThreadName("grubby") @@ -394,7 +399,7 @@ def do_check_appending(self): all_bps.Append(bkpt) bkpt = self.orig_target.BreakpointCreateByName( - "blubby", lldb.eFunctionNameTypeFull, empty_module_list, empty_cu_list + "main", lldb.eFunctionNameTypeFull, empty_module_list, empty_cu_list ) bkpt.SetCondition("something != something_else") bkpt.SetQueueName("grubby") >From 78d4544c270cf1c977b588e92c3ca2b20be7d57f Mon Sep 17 00:00:00 2001 From: Augusto Noronha <[email protected]> Date: Wed, 3 Dec 2025 15:21:18 -0800 Subject: [PATCH 6/6] Address comment --- lldb/unittests/Core/ModuleTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/unittests/Core/ModuleTest.cpp b/lldb/unittests/Core/ModuleTest.cpp index f657f7206fa3e..011554d1b0939 100644 --- a/lldb/unittests/Core/ModuleTest.cpp +++ b/lldb/unittests/Core/ModuleTest.cpp @@ -1,4 +1,4 @@ -//===-- ModuleTest.cpp ----------------------------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
