Index: lldb/trunk/lit/SymbolFile/DWARF/find-basic-function.cpp =================================================================== --- lldb/trunk/lit/SymbolFile/DWARF/find-basic-function.cpp +++ lldb/trunk/lit/SymbolFile/DWARF/find-basic-function.cpp @@ -29,6 +29,22 @@ // RUN: lldb-test symbols --name=not_there --find=function %t | \ // RUN: FileCheck --check-prefix=EMPTY %s +// RUN: clang %s -g -c -emit-llvm -o - --target=x86_64-pc-linux | \ +// RUN: llc -accel-tables=Dwarf -filetype=obj -o %t.o +// RUN: ld.lld %t.o -o %t +// RUN: lldb-test symbols --name=foo --find=function --function-flags=base %t | \ +// RUN: FileCheck --check-prefix=BASE %s +// RUN: lldb-test symbols --name=foo --find=function --function-flags=method %t | \ +// RUN: FileCheck --check-prefix=METHOD %s +// RUN: lldb-test symbols --name=foo --find=function --function-flags=full %t | \ +// RUN: FileCheck --check-prefix=FULL %s +// RUN: lldb-test symbols --name=_Z3fooi --find=function --function-flags=full %t | \ +// RUN: FileCheck --check-prefix=FULL-MANGLED %s +// RUN: lldb-test symbols --name=foo --context=context --find=function --function-flags=base %t | \ +// RUN: FileCheck --check-prefix=CONTEXT %s +// RUN: lldb-test symbols --name=not_there --find=function %t | \ +// RUN: FileCheck --check-prefix=EMPTY %s + // BASE: Found 4 functions: // BASE-DAG: name = "foo()", mangled = "_Z3foov" // BASE-DAG: name = "foo(int)", mangled = "_Z3fooi" Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp @@ -13,7 +13,6 @@ #include "Plugins/SymbolFile/DWARF/DWARFUnit.h" #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" -#include "Plugins/Language/ObjC/ObjCLanguage.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/Function.h" @@ -135,74 +134,15 @@ m_apple_namespaces_up->FindByName(name.GetStringRef(), offsets); } -static bool KeepFunctionDIE(DWARFDIE die, uint32_t name_type_mask) { - bool looking_for_methods = name_type_mask & eFunctionNameTypeMethod; - bool looking_for_functions = name_type_mask & eFunctionNameTypeBase; - if (looking_for_methods && looking_for_functions) - return true; - return looking_for_methods == die.IsMethod(); -} - void AppleDWARFIndex::GetFunctions(ConstString name, DWARFDebugInfo &info, const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, std::vector &dies) { - 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. - DIEArray offsets; - m_apple_names_up->FindByName(name.GetStringRef(), offsets); - for (const DIERef &die_ref: offsets) { - DWARFDIE die = info.GetDIE(die_ref); - if (!die) { - ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef()); - continue; - } - if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) - dies.push_back(die); - } - } - if (name_type_mask & eFunctionNameTypeSelector && - !parent_decl_ctx.IsValid()) { - DIEArray offsets; - 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 (const DIERef &die_ref: offsets) { - DWARFDIE die = info.GetDIE(die_ref); - if (!die) { - ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef()); - continue; - } - const char *die_name = die.GetName(); - if (ObjCLanguage::IsPossibleObjCMethodName(die_name)) - dies.push_back(die); - } - } - if (((name_type_mask & eFunctionNameTypeMethod) && - !parent_decl_ctx.IsValid()) || - 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. - - DIEArray offsets; - m_apple_names_up->FindByName(name.GetStringRef(), offsets); - - for (const DIERef &die_ref: offsets) { - DWARFDIE die = info.GetDIE(die_ref); - if (!die) { - ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef()); - continue; - } - if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die) && - KeepFunctionDIE(die, name_type_mask)) - dies.push_back(die); - } + DIEArray offsets; + m_apple_names_up->FindByName(name.GetStringRef(), offsets); + for (const DIERef &die_ref : offsets) { + ProcessFunctionDIE(name.GetStringRef(), die_ref, info, parent_decl_ctx, + name_type_mask, dies); } } Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/DIERef.h =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DIERef.h +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DIERef.h @@ -45,6 +45,10 @@ bool operator<(const DIERef &ref) { return die_offset < ref.die_offset; } + explicit operator bool() const { + return cu_offset != DW_INVALID_OFFSET || die_offset != DW_INVALID_OFFSET; + } + dw_offset_t cu_offset = DW_INVALID_OFFSET; dw_offset_t die_offset = DW_INVALID_OFFSET; }; Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFIndex.h =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFIndex.h +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFIndex.h @@ -11,6 +11,7 @@ #define LLDB_DWARFINDEX_H #include "Plugins/SymbolFile/DWARF/DIERef.h" +#include "Plugins/SymbolFile/DWARF/DWARFDIE.h" #include "Plugins/SymbolFile/DWARF/DWARFFormValue.h" class DWARFDebugInfo; @@ -53,6 +54,15 @@ protected: Module &m_module; + + /// Helper function implementing common logic for processing function dies. If + /// the function given by "ref" matches search criteria given by + /// "parent_decl_ctx" and "name_type_mask", it is inserted into the "dies" + /// vector. + void ProcessFunctionDIE(llvm::StringRef name, DIERef ref, + DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, std::vector &dies); }; } // namespace lldb_private Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp @@ -11,7 +11,58 @@ #include "Plugins/SymbolFile/DWARF/DWARFDIE.h" #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" +#include "Plugins/Language/ObjC/ObjCLanguage.h" + using namespace lldb_private; using namespace lldb; DWARFIndex::~DWARFIndex() = default; + +void DWARFIndex::ProcessFunctionDIE(llvm::StringRef name, DIERef ref, + DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector &dies) { + DWARFDIE die = info.GetDIE(ref); + if (!die) { + ReportInvalidDIEOffset(ref.die_offset, name); + return; + } + + // Exit early if we're searching exclusively for methods or selectors and + // we have a context specified (no methods in namespaces). + uint32_t looking_for_nonmethods = + name_type_mask & ~(eFunctionNameTypeMethod | eFunctionNameTypeSelector); + if (!looking_for_nonmethods && parent_decl_ctx.IsValid()) + return; + + // Otherwise, we need to also check that the context matches. If it does not + // match, we do nothing. + if (!SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) + return; + + // In case of a full match, we just insert everything we find. + if (name_type_mask & eFunctionNameTypeFull) { + dies.push_back(die); + return; + } + + // If looking for ObjC selectors, we need to also check if the name is a + // possible selector. + if (name_type_mask & eFunctionNameTypeSelector && + ObjCLanguage::IsPossibleObjCMethodName(die.GetName())) { + dies.push_back(die); + return; + } + + bool looking_for_methods = name_type_mask & lldb::eFunctionNameTypeMethod; + bool looking_for_functions = name_type_mask & lldb::eFunctionNameTypeBase; + if (looking_for_methods || looking_for_functions) { + // If we're looking for either methods or functions, we definitely want this + // die. Otherwise, only keep it if the die type matches what we are + // searching for. + if ((looking_for_methods && looking_for_functions) || + looking_for_methods == die.IsMethod()) + dies.push_back(die); + } +} Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -38,7 +38,7 @@ void GetFunctions(ConstString name, DWARFDebugInfo &info, const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, - std::vector &dies) override {} + std::vector &dies) override; void GetFunctions(const RegularExpression ®ex, DIEArray &offsets) override {} @@ -64,9 +64,11 @@ std::unique_ptr m_debug_names_up; ManualDWARFIndex m_fallback; - void Append(const DebugNames::Entry &entry, DIEArray &offsets); - void MaybeLogLookupError(llvm::Error error, const DebugNames::NameIndex &ni, - llvm::StringRef name); + static DIERef ToDIERef(const DebugNames::Entry &entry); + static void Append(const DebugNames::Entry &entry, DIEArray &offsets); + static void MaybeLogLookupError(llvm::Error error, + const DebugNames::NameIndex &ni, + llvm::StringRef name); static llvm::DenseSet GetUnits(const DebugNames &debug_names); }; Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" @@ -44,12 +45,18 @@ return result; } -void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry, - DIEArray &offsets) { +DIERef DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) { llvm::Optional cu_offset = entry.getCUOffset(); llvm::Optional die_offset = entry.getDIESectionOffset(); if (cu_offset && die_offset) - offsets.emplace_back(*cu_offset, *die_offset); + return DIERef(*cu_offset, *die_offset); + return DIERef(); +} + +void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry, + DIEArray &offsets) { + if (DIERef ref = ToDIERef(entry)) + offsets.push_back(ref); } void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error, @@ -118,6 +125,25 @@ } } +void DebugNamesDWARFIndex::GetFunctions( + ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, + std::vector &dies) { + + m_fallback.GetFunctions(name, info, parent_decl_ctx, name_type_mask, dies); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(name.GetStringRef())) { + Tag tag = entry.tag(); + if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) + continue; + + if (DIERef ref = ToDIERef(entry)) + ProcessFunctionDIE(name.GetStringRef(), ref, info, parent_decl_ctx, + name_type_mask, dies); + } +} + void DebugNamesDWARFIndex::Dump(Stream &s) { m_fallback.Dump(s);