Index: source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h =================================================================== --- source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h +++ source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h @@ -37,21 +37,19 @@ void GetGlobalVariables(const RegularExpression ®ex, DIEArray &offsets) override; void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) override; - void GetObjCMethods(ConstString class_name, DIEArray &offsets) override; + void GetObjCMethodsForClass(ConstString class_name, DIEArray &offsets) override; void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, DIEArray &offsets) override; void GetTypes(ConstString name, DIEArray &offsets) override; void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) override; void GetNamespaces(ConstString name, DIEArray &offsets) override; - void GetFunctions( - ConstString name, DWARFDebugInfo &info, - llvm::function_ref - resolve_function, - llvm::function_ref - get_decl_context_containing_uid, - const CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask, - bool include_inlines, SymbolContextList &sc_list) override; + void GetFunctionsByFullName(ConstString name, DIEArray &offsets) override; + void GetObjCMethodsByName(ConstString name, DIEArray &offsets) override; + void GetFunctionsByBaseOrMethodName(ConstString name, + lldb::FunctionNameType flags, + DIEArray &base_offsets, + DIEArray &method_offsets, + DIEArray &unknown_offsets) override; void GetFunctions( const RegularExpression ®ex, DWARFDebugInfo &info, llvm::function_refFindByName(class_name.GetStringRef(), offsets); @@ -146,134 +145,29 @@ m_apple_namespaces_up->FindByName(name.GetStringRef(), offsets); } -void AppleDWARFIndex::GetFunctions( - ConstString name, DWARFDebugInfo &info, - llvm::function_ref - resolve_function, - llvm::function_ref - get_decl_context_containing_uid, - const CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask, - bool include_inlines, SymbolContextList &sc_list) { - if (!m_apple_names_up) - return; - - std::set resolved_dies; - DIEArray offsets; - - uint32_t num_matches = 0; - - if (name_type_mask & eFunctionNameTypeFull) { - // If they asked for the full name, match what they typed. At some - // point we may want to canonicalize this (strip double spaces, etc. - // For now, we just add all the dies that we find by exact match. - num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets); - for (uint32_t i = 0; i < num_matches; i++) { - const DIERef &die_ref = offsets[i]; - DWARFDIE die = info.GetDIE(die_ref); - if (die) { - if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match - - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (resolve_function(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } else - ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef()); - } - } - - if (name_type_mask & eFunctionNameTypeSelector) { - if (parent_decl_ctx && parent_decl_ctx->IsValid()) - return; // no selectors in namespaces - - num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets); - // Now make sure these are actually ObjC methods. In this case we can - // simply look up the name, and if it is an ObjC method name, we're - // good. - - for (uint32_t i = 0; i < num_matches; i++) { - const DIERef &die_ref = offsets[i]; - DWARFDIE die = info.GetDIE(die_ref); - if (die) { - const char *die_name = die.GetName(); - if (ObjCLanguage::IsPossibleObjCMethodName(die_name)) { - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (resolve_function(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } - } else - ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef()); - } - offsets.clear(); - } - - if (((name_type_mask & eFunctionNameTypeMethod) && !parent_decl_ctx) || - name_type_mask & eFunctionNameTypeBase) { - // The apple_names table stores just the "base name" of C++ methods in - // the table. So we have to extract the base name, look that up, and - // if there is any other information in the name we were passed in we - // have to post-filter based on that. - - // FIXME: Arrange the logic above so that we don't calculate the base - // name twice: - num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets); - - for (uint32_t i = 0; i < num_matches; i++) { - const DIERef &die_ref = offsets[i]; - DWARFDIE die = info.GetDIE(die_ref); - if (die) { - if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match +void AppleDWARFIndex::GetFunctionsByFullName(ConstString name, + DIEArray &offsets) { + // If they asked for the full name, match what they typed. At some point we + // may want to canonicalize this (strip double spaces, etc. For now, we just + // add all the dies that we find by exact match. + if (m_apple_names_up) + m_apple_names_up->FindByName(name.GetStringRef(), offsets); +} - // If we get to here, the die is good, and we should add it: - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end() && - resolve_function(die, include_inlines, sc_list)) { - bool keep_die = true; - if ((name_type_mask & - (eFunctionNameTypeBase | eFunctionNameTypeMethod)) != - (eFunctionNameTypeBase | eFunctionNameTypeMethod)) { - // We are looking for either basenames or methods, so we need - // to trim out the ones we won't want by looking at the type - SymbolContext sc; - if (sc_list.GetLastContext(sc)) { - if (sc.block) { - // We have an inlined function - } else if (sc.function) { - Type *type = sc.function->GetType(); +void AppleDWARFIndex::GetObjCMethodsByName(ConstString name, + DIEArray &offsets) { + if (m_apple_names_up) + m_apple_names_up->FindByName(name.GetStringRef(), offsets); +} - if (type) { - CompilerDeclContext decl_ctx = - get_decl_context_containing_uid(type->GetID()); - if (decl_ctx.IsStructUnionOrClass()) { - if (name_type_mask & eFunctionNameTypeBase) { - sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1); - keep_die = false; - } - } else { - if (name_type_mask & eFunctionNameTypeMethod) { - sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1); - keep_die = false; - } - } - } else { - m_module.ReportWarning( - "function at die offset 0x%8.8x had no function type", - die_ref.die_offset); - } - } - } - } - if (keep_die) - resolved_dies.insert(die.GetDIE()); - } - } else - ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef()); - } - offsets.clear(); - } +void AppleDWARFIndex::GetFunctionsByBaseOrMethodName( + ConstString name, lldb::FunctionNameType flags, DIEArray &base_offsets, + DIEArray &method_offsets, DIEArray &unknown_offsets) { + // It's impossible to tell functions and methods apart from the apple_names + // contents alone. So, we just extract the data into the unknown_offsets and + // let the caller filter that. + if (m_apple_names_up) + m_apple_names_up->FindByName(name.GetStringRef(), unknown_offsets); } void AppleDWARFIndex::GetFunctions( Index: source/Plugins/SymbolFile/DWARF/DWARFIndex.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFIndex.h +++ source/Plugins/SymbolFile/DWARF/DWARFIndex.h @@ -29,22 +29,28 @@ virtual void GetGlobalVariables(const RegularExpression ®ex, DIEArray &offsets) = 0; virtual void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) = 0; - virtual void GetObjCMethods(ConstString class_name, DIEArray &offsets) = 0; + virtual void GetObjCMethodsForClass(ConstString class_name, DIEArray &offsets) = 0; virtual void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, DIEArray &offsets) = 0; virtual void GetTypes(ConstString name, DIEArray &offsets) = 0; virtual void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) = 0; virtual void GetNamespaces(ConstString name, DIEArray &offsets) = 0; - virtual void GetFunctions( - ConstString name, DWARFDebugInfo &info, - llvm::function_ref - resolve_function, - llvm::function_ref - get_decl_context_containing_uid, - const CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask, - bool include_inlines, SymbolContextList &sc_list) = 0; + virtual void GetFunctionsByFullName(ConstString name, DIEArray &offsets) = 0; + virtual void GetObjCMethodsByName(ConstString name, DIEArray &offsets) = 0; + + /// Find functions or methods with the given name. Only the + /// eFunctionNameTypeMethod and eFunctionNameTypeBase bits in the input flags + /// are inspected. If the implementation is certain a given DIE represents a + /// (non-member) function, it should put it in the base_offsets array. Method + /// DIEs should go into the method_offsets array. An implementation can put a + /// DIE into the unknown_offsets array if it cannot determine its type. It is up + /// to the caller to correctly classify these. + virtual void GetFunctionsByBaseOrMethodName(ConstString name, + lldb::FunctionNameType flags, + DIEArray &base_offsets, + DIEArray &method_offsets, + DIEArray &unknown_offsets) = 0; virtual void GetFunctions( const RegularExpression ®ex, DWARFDebugInfo &info, llvm::function_ref - resolve_function, - llvm::function_ref - get_decl_context_containing_uid, - const CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask, - bool include_inlines, SymbolContextList &sc_list) override; + void GetFunctionsByFullName(ConstString name, DIEArray &offsets) override; + void GetObjCMethodsByName(ConstString name, DIEArray &offsets) override; + void GetFunctionsByBaseOrMethodName(ConstString name, + lldb::FunctionNameType flags, + DIEArray &base_offsets, + DIEArray &method_offsets, + DIEArray &unknown_offsets) override; void GetFunctions( const RegularExpression ®ex, DWARFDebugInfo &info, llvm::function_ref - resolve_function, - llvm::function_ref - get_decl_context_containing_uid, - const CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask, - bool include_inlines, SymbolContextList &sc_list) { - +void ManualDWARFIndex::GetFunctionsByFullName(ConstString name, DIEArray &offsets) { Index(); + m_function_basenames.Find(name, offsets); + m_function_methods.Find(name, offsets); + m_function_fullnames.Find(name, offsets); +} - std::set resolved_dies; - DIEArray offsets; - if (name_type_mask & eFunctionNameTypeFull) { - uint32_t num_matches = m_function_basenames.Find(name, offsets); - num_matches += m_function_methods.Find(name, offsets); - num_matches += m_function_fullnames.Find(name, offsets); - for (uint32_t i = 0; i < num_matches; i++) { - const DIERef &die_ref = offsets[i]; - DWARFDIE die = info.GetDIE(die_ref); - if (die) { - if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match - - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (resolve_function(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } - } - offsets.clear(); - } - if (name_type_mask & eFunctionNameTypeBase) { - uint32_t num_base = m_function_basenames.Find(name, offsets); - for (uint32_t i = 0; i < num_base; i++) { - DWARFDIE die = info.GetDIE(offsets[i]); - if (die) { - if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match - - // If we get to here, the die is good, and we should add it: - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (resolve_function(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } - } - offsets.clear(); - } +void ManualDWARFIndex::GetObjCMethodsByName(ConstString name, + DIEArray &offsets) { + Index(); + m_function_selectors.Find(name, offsets); +} - if (name_type_mask & eFunctionNameTypeMethod) { - if (parent_decl_ctx && parent_decl_ctx->IsValid()) - return; // no methods in namespaces +void ManualDWARFIndex::GetFunctionsByBaseOrMethodName( + ConstString name, lldb::FunctionNameType flags, DIEArray &base_offsets, + DIEArray &method_offsets, DIEArray &unknown_offsets) { + Index(); - uint32_t num_base = m_function_methods.Find(name, offsets); - { - for (uint32_t i = 0; i < num_base; i++) { - DWARFDIE die = info.GetDIE(offsets[i]); - if (die) { - // If we get to here, the die is good, and we should add it: - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (resolve_function(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } - } - } - offsets.clear(); - } + // We have checked the type of DIEs while building the index, so we can give + // exact answers here. + if (flags & eFunctionNameTypeBase) + m_function_basenames.Find(name, base_offsets); - if ((name_type_mask & eFunctionNameTypeSelector) && - (!parent_decl_ctx || !parent_decl_ctx->IsValid())) { - uint32_t num_selectors = m_function_selectors.Find(name, offsets); - for (uint32_t i = 0; i < num_selectors; i++) { - DWARFDIE die = info.GetDIE(offsets[i]); - if (die) { - // If we get to here, the die is good, and we should add it: - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (resolve_function(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } - } - } + if (flags & eFunctionNameTypeMethod) + m_function_methods.Find(name, method_offsets); } void ManualDWARFIndex::GetFunctions( Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -27,6 +27,7 @@ #include "lldb/Utility/Timer.h" #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" +#include "Plugins/Language/ObjC/ObjCLanguage.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" @@ -1475,7 +1476,7 @@ size_t SymbolFileDWARF::GetObjCMethodDIEOffsets(ConstString class_name, DIEArray &method_die_offsets) { method_die_offsets.clear(); - m_index->GetObjCMethods(class_name, method_die_offsets); + m_index->GetObjCMethodsForClass(class_name, method_die_offsets); return method_die_offsets.size(); } @@ -2214,6 +2215,9 @@ if (!append) sc_list.Clear(); + if (parent_decl_ctx && !parent_decl_ctx->IsValid()) + parent_decl_ctx = nullptr; + if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) return 0; @@ -2230,16 +2234,121 @@ if (info == NULL) return 0; - m_index->GetFunctions(name, *info, - [this](const DWARFDIE &die, bool include_inlines, - lldb_private::SymbolContextList &sc_list) { - return ResolveFunction(die, include_inlines, sc_list); - }, - [this](lldb::user_id_t type_uid) { - return GetDeclContextContainingUID(type_uid); - }, - parent_decl_ctx, name_type_mask, include_inlines, - sc_list); + llvm::DenseSet resolved_dies; + if (name_type_mask & eFunctionNameTypeFull) { + DIEArray offsets; + m_index->GetFunctionsByFullName(name, offsets); + for (const DIERef &ref : offsets) { + DWARFDIE die = info->GetDIE(ref); + if (!die) { + m_index->ReportInvalidDIEOffset(ref.die_offset, name.GetStringRef()); + continue; + } + if (!DIEInDeclContext(parent_decl_ctx, die)) + continue; // The containing decl contexts don't match + + if (resolved_dies.insert(die.GetDIE()).second) + ResolveFunction(die, include_inlines, sc_list); + } + } + if (name_type_mask & eFunctionNameTypeSelector && !parent_decl_ctx) { + DIEArray offsets; + m_index->GetObjCMethodsByName(name, offsets); + + // Now make sure these are actually ObjC methods. In this case we can + // simply look up the name, and if it is an ObjC method name, we're + // good. + for (const DIERef &ref : offsets) { + DWARFDIE die = info->GetDIE(ref); + if (!die) { + m_index->ReportInvalidDIEOffset(ref.die_offset, name.GetStringRef()); + continue; + } + if (!ObjCLanguage::IsPossibleObjCMethodName(die.GetName())) + continue; + if (resolved_dies.insert(die.GetDIE()).second) + ResolveFunction(die, include_inlines, sc_list); + } + } + if (((name_type_mask & eFunctionNameTypeMethod) && !parent_decl_ctx) || + name_type_mask & eFunctionNameTypeBase) { + DIEArray base_offsets, method_offsets, unknown_offsets; + m_index->GetFunctionsByBaseOrMethodName( + name, FunctionNameType(name_type_mask), base_offsets, method_offsets, + unknown_offsets); + + for (const DIERef &ref : base_offsets) { + DWARFDIE die = info->GetDIE(ref); + if (!die) { + m_index->ReportInvalidDIEOffset(ref.die_offset, name.GetStringRef()); + continue; + } + if (!DIEInDeclContext(parent_decl_ctx, die)) + continue; // The containing decl contexts don't match + + if (resolved_dies.insert(die.GetDIE()).second) + ResolveFunction(die, include_inlines, sc_list); + } + + if (!parent_decl_ctx) { + for (const DIERef &ref : method_offsets) { + DWARFDIE die = info->GetDIE(ref); + if (!die) { + m_index->ReportInvalidDIEOffset(ref.die_offset, name.GetStringRef()); + continue; + } + if (resolved_dies.insert(die.GetDIE()).second) + ResolveFunction(die, include_inlines, sc_list); + } + } + + for (const DIERef &ref : unknown_offsets) { + DWARFDIE die = info->GetDIE(ref); + if (!die) { + m_index->ReportInvalidDIEOffset(ref.die_offset, name.GetStringRef()); + continue; + } + if (!DIEInDeclContext(parent_decl_ctx, die)) + continue; // The containing decl contexts don't match + + // If we get to here, the die is good, so add it to our list + // provisionally. + if (resolved_dies.insert(die.GetDIE()).second && + ResolveFunction(die, include_inlines, sc_list)) { + if (name_type_mask & eFunctionNameTypeBase && + name_type_mask & eFunctionNameTypeMethod) + continue; + + // We are looking for either basenames or methods, so we need to trim + // out the ones we won't want by looking at the type + const bool looking_for_methods = + name_type_mask & eFunctionNameTypeMethod; + + SymbolContext sc; + sc_list.GetLastContext(sc); + if (sc.block) + continue; // We have an inlined function + if (!sc.function) + continue; + + Type *type = sc.function->GetType(); + if (!type) { + GetObjectFile()->GetModule()->ReportWarning( + "function at die offset 0x%8.8x had no function type", + ref.die_offset); + continue; + } + + CompilerDeclContext decl_ctx = + GetDeclContextContainingUID(type->GetID()); + if (decl_ctx.IsStructUnionOrClass() != looking_for_methods) { + // We have a mismatch, remove our function from the list. + sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1); + resolved_dies.erase(die.GetDIE()); + } + } + } + } // Return the number of variable that were appended to the list const uint32_t num_matches = sc_list.GetSize() - original_size;