diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 597359c48c43b..8c3f6e2edd2e3 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -317,6 +317,15 @@ class Module : public std::enable_shared_from_this, 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. + void FindFunctions(const std::vector &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, @@ -952,8 +961,29 @@ class Module : public std::enable_shared_from_this, 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] 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 + MakeLookupInfos(ConstString name, lldb::FunctionNameType name_type_mask, + lldb::LanguageType lang_type); ConstString GetName() const { return m_name; } @@ -994,6 +1024,10 @@ class Module : public std::enable_shared_from_this, /// 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 ad78af7419269..ac64a89bd034e 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -313,6 +313,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 &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); /// Finds imported declarations whose name match \p name. diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp index 33ebbab302ed5..e72df43cc065e 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 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 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 true; @@ -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 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 731aa6688d275..60cb28f6d5864 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -651,26 +651,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 basename; - - std::vector languages; - { - std::vector 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; @@ -687,7 +674,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, @@ -696,14 +683,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; } } } @@ -719,6 +704,36 @@ Module::LookupInfo::LookupInfo(ConstString name, } } +std::vector +Module::LookupInfo::MakeLookupInfos(ConstString name, + lldb::FunctionNameType name_type_mask, + lldb::LanguageType lang_type) { + std::vector lang_types; + if (lang_type != eLanguageTypeUnknown) { + lang_types.push_back(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 true; + }); + + if (lang_types.empty()) + lang_types = {eLanguageTypeObjC, eLanguageTypeC_plus_plus}; + } + + std::vector 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 @@ -837,18 +852,29 @@ void Module::FindFunctions(const Module::LookupInfo &lookup_info, } } +void Module::FindFunctions(const std::vector &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 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 119a8798c12da..699e2ac3da44e 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -645,21 +645,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 lookup_infos = + Module::LookupInfo::MakeLookupInfos(name, name_type_mask, + eLanguageTypeUnknown); std::lock_guard 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 guard(m_modules_mutex); for (const ModuleSP &module_sp : m_modules) { @@ -672,21 +673,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 lookup_infos = + Module::LookupInfo::MakeLookupInfos(name, name_type_mask, + eLanguageTypeUnknown); std::lock_guard 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 guard(m_modules_mutex); for (const ModuleSP &module_sp : m_modules) { diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeNames.cpp b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeNames.cpp index 46969652f914f..d644a24d2acbf 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeNames.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeNames.cpp @@ -1539,10 +1539,10 @@ SwiftLanguageRuntime::GetGenericSignature(llvm::StringRef function_name, /// Returns true if a function called `symbol_name` exists in `module`. static bool SymbolExists(StringRef symbol_name, Module &module) { SymbolContextList sc_list; - Module::LookupInfo lookup_info(ConstString(symbol_name), - lldb::FunctionNameType::eFunctionNameTypeFull, - lldb::eLanguageTypeSwift); - module.FindFunctions(lookup_info, CompilerDeclContext(), + auto lookup_infos = Module::LookupInfo::MakeLookupInfos( + ConstString(symbol_name), lldb::FunctionNameType::eFunctionNameTypeFull, + lldb::eLanguageTypeSwift); + module.FindFunctions(lookup_infos, CompilerDeclContext(), ModuleFunctionSearchOptions(), sc_list); return !sc_list.IsEmpty(); } 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 &lookup_infos, SymbolFileDWARF &dwarf, + const CompilerDeclContext &parent_decl_ctx, + llvm::function_ref 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 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 callback) = 0; virtual void + GetFunctions(const std::vector &lookup_infos, + SymbolFileDWARF &dwarf, + const CompilerDeclContext &parent_decl_ctx, + llvm::function_ref callback); + virtual void GetFunctions(const RegularExpression ®ex, llvm::function_ref callback) = 0; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 011aa1d8b593c..1d57841bf6964 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2516,7 +2516,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; } @@ -2582,11 +2582,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 8d98052e7a40f..df46dfdce554e 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, @@ -1202,7 +1222,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 1da28485dadf5..e2db0af9a13af 100644 --- a/lldb/source/Symbol/SymbolFile.cpp +++ b/lldb/source/Symbol/SymbolFile.cpp @@ -134,6 +134,14 @@ void SymbolFile::FindFunctions(const Module::LookupInfo &lookup_info, bool include_inlines, SymbolContextList &sc_list) {} +void SymbolFile::FindFunctions( + const std::vector &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/source/Target/Language.cpp b/lldb/source/Target/Language.cpp index 61ced29dee60f..b85e412944b18 100644 --- a/lldb/source/Target/Language.cpp +++ b/lldb/source/Target/Language.cpp @@ -625,10 +625,10 @@ GetParentFunctionsWhileClosure(const SymbolContext &sc, // Find the enclosing function, if it exists. SymbolContextList sc_list; - Module::LookupInfo lookup_info( + auto lookup_infos = Module::LookupInfo::MakeLookupInfos( ConstString(parent), lldb::FunctionNameType::eFunctionNameTypeFull, lldb::eLanguageTypeSwift); - sc.module_sp->FindFunctions(lookup_info, CompilerDeclContext(), + sc.module_sp->FindFunctions(lookup_infos, CompilerDeclContext(), ModuleFunctionSearchOptions(), sc_list); if (sc_list.GetSize() != 1 || sc_list[0].function == nullptr) break; 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") 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 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; diff --git a/lldb/unittests/Core/CMakeLists.txt b/lldb/unittests/Core/CMakeLists.txt index 9d11c02d9837c..4720d433fba1f 100644 --- a/lldb/unittests/Core/CMakeLists.txt +++ b/lldb/unittests/Core/CMakeLists.txt @@ -16,6 +16,7 @@ add_lldb_unittest(LLDBCoreTests FormatEntityTest.cpp MangledTest.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..011554d1b0939 --- /dev/null +++ b/lldb/unittests/Core/ModuleTest.cpp @@ -0,0 +1,125 @@ +//===----------------------------------------------------------------------===// +// +// 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/SymbolFile/Symtab/SymbolFileSymtab.h" +#include "TestingSupport/SubsystemRAII.h" +#include "TestingSupport/TestUtilities.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Target/Language.h" +#include "gtest/gtest.h" +#include + +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> + 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 + subsystems; + + // 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()); + + auto module_sp = std::make_shared(ExpectedFile->moduleSpec()); + + // 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::size()"); + ASSERT_EQ(result.GetLanguage(), eLanguageTypeC_plus_plus); +}