diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index f4973cdda1efc..0188057247a68 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -337,6 +337,12 @@ class Module : public std::enable_shared_from_this, const ModuleFunctionSearchOptions &options, SymbolContextList &sc_list); + /// Find functions by compiler context. + void FindFunctions(llvm::ArrayRef compiler_ctx, + lldb::FunctionNameType name_type_mask, + const ModuleFunctionSearchOptions &options, + SymbolContextList &sc_list); + /// Find functions by name. /// /// If the function is an inlined function, it will have a block, diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index c0574b724ace7..331cf32466411 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -855,6 +855,23 @@ void Module::FindFunctions(ConstString name, } } +void Module::FindFunctions(llvm::ArrayRef compiler_ctx, + FunctionNameType name_type_mask, + const ModuleFunctionSearchOptions &options, + SymbolContextList &sc_list) { + if (compiler_ctx.empty() || + compiler_ctx.back().kind != CompilerContextKind::Function) + return; + ConstString name = compiler_ctx.back().name; + SymbolContextList unfiltered; + FindFunctions(name, CompilerDeclContext(), name_type_mask, options, + unfiltered); + // Filter by context. + for (auto &sc : unfiltered) + if (sc.function && compiler_ctx.equals(sc.function->GetCompilerContext())) + sc_list.Append(sc); +} + void Module::FindFunctions(const RegularExpression ®ex, const ModuleFunctionSearchOptions &options, SymbolContextList &sc_list) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index bed68f45426f6..d4446befd83b0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -373,44 +373,51 @@ std::vector DWARFDIE::GetDeclContextDIEs() const { return result; } -std::vector DWARFDIE::GetDeclContext() const { +static std::vector +GetDeclContextImpl(llvm::SmallSet &seen, DWARFDIE die) { std::vector context; - const dw_tag_t tag = Tag(); - if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) + // Stop if we hit a cycle. + if (!die || !seen.insert(die.GetID()).second) return context; - DWARFDIE parent = GetParent(); - if (parent) - context = parent.GetDeclContext(); + + // Handle outline member function DIEs by following the specification. + if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_specification)) + return GetDeclContextImpl(seen, spec); + + // Get the parent context chain. + context = GetDeclContextImpl(seen, die.GetParent()); + + // Add this DIE's contribution at the end of the chain. auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) { context.push_back({kind, ConstString(name)}); }; - switch (tag) { + switch (die.Tag()) { case DW_TAG_module: - push_ctx(CompilerContextKind::Module, GetName()); + push_ctx(CompilerContextKind::Module, die.GetName()); break; case DW_TAG_namespace: - push_ctx(CompilerContextKind::Namespace, GetName()); + push_ctx(CompilerContextKind::Namespace, die.GetName()); break; case DW_TAG_structure_type: - push_ctx(CompilerContextKind::Struct, GetName()); + push_ctx(CompilerContextKind::Struct, die.GetName()); break; case DW_TAG_union_type: - push_ctx(CompilerContextKind::Union, GetName()); + push_ctx(CompilerContextKind::Union, die.GetName()); break; case DW_TAG_class_type: - push_ctx(CompilerContextKind::Class, GetName()); + push_ctx(CompilerContextKind::Class, die.GetName()); break; case DW_TAG_enumeration_type: - push_ctx(CompilerContextKind::Enum, GetName()); + push_ctx(CompilerContextKind::Enum, die.GetName()); break; case DW_TAG_subprogram: - push_ctx(CompilerContextKind::Function, GetPubname()); + push_ctx(CompilerContextKind::Function, die.GetName()); break; case DW_TAG_variable: - push_ctx(CompilerContextKind::Variable, GetPubname()); + push_ctx(CompilerContextKind::Variable, die.GetPubname()); break; case DW_TAG_typedef: - push_ctx(CompilerContextKind::Typedef, GetName()); + push_ctx(CompilerContextKind::Typedef, die.GetName()); break; default: break; @@ -418,6 +425,11 @@ std::vector DWARFDIE::GetDeclContext() const { return context; } +std::vector DWARFDIE::GetDeclContext() const { + llvm::SmallSet seen; + return GetDeclContextImpl(seen, *this); +} + std::vector DWARFDIE::GetTypeLookupContext() const { std::vector context; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 447930ffe07b3..f539ed5d2ae57 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2574,11 +2574,12 @@ void SymbolFileDWARF::FindFunctions(const Module::LookupInfo &lookup_info, Module::LookupInfo no_tp_lookup_info(lookup_info); no_tp_lookup_info.SetLookupName(ConstString(name_no_template_params)); - m_index->GetFunctions(no_tp_lookup_info, *this, parent_decl_ctx, [&](DWARFDIE die) { - if (resolved_dies.insert(die.GetDIE()).second) - ResolveFunction(die, include_inlines, sc_list); - return true; - }); + m_index->GetFunctions(no_tp_lookup_info, *this, parent_decl_ctx, + [&](DWARFDIE die) { + if (resolved_dies.insert(die.GetDIE()).second) + ResolveFunction(die, include_inlines, sc_list); + return true; + }); } } diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/find-basic-function.cpp b/lldb/test/Shell/SymbolFile/DWARF/x86/find-basic-function.cpp index 204568a446d0a..30143a41d5e73 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/find-basic-function.cpp +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/find-basic-function.cpp @@ -34,6 +34,8 @@ // RUN: FileCheck --check-prefix=FULL-MANGLED-METHOD %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 --compiler-context=Struct:sbar,Function:foo -language=c++ -find=function -function-flags=method %t | \ +// RUN: FileCheck --check-prefix=COMPILER-CONTEXT %s // RUN: lldb-test symbols --name=not_there --find=function %t | \ // RUN: FileCheck --check-prefix=EMPTY %s @@ -84,6 +86,10 @@ // CONTEXT: Found 1 functions: // CONTEXT-DAG: name = "bar::foo()", mangled = "_ZN3bar3fooEv", decl_context = {Namespace(bar)} +// COMPILER-CONTEXT: Found 2 functions: +// COMPILER-CONTEXT-DAG: name = "sbar::foo()", mangled = "_ZN4sbar3fooEv" +// COMPILER-CONTEXT-DAG: name = "sbar::foo(int)", mangled = "_ZN4sbar3fooEi" + // EMPTY: Found 0 functions: void foo() {} diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp index e326a84c1dbd2..33281cfb15074 100644 --- a/lldb/tools/lldb-test/lldb-test.cpp +++ b/lldb/tools/lldb-test/lldb-test.cpp @@ -466,6 +466,7 @@ static lldb::DescriptionLevel GetDescriptionLevel() { Error opts::symbols::findFunctions(lldb_private::Module &Module) { SymbolFile &Symfile = *Module.GetSymbolFile(); SymbolContextList List; + auto compiler_context = parseCompilerContext(); if (!File.empty()) { assert(Line != 0); @@ -498,6 +499,9 @@ Error opts::symbols::findFunctions(lldb_private::Module &Module) { assert(RE.IsValid()); List.Clear(); Symfile.FindFunctions(RE, true, List); + } else if (!compiler_context.empty()) { + List.Clear(); + Module.FindFunctions(compiler_context, getFunctionNameFlags(), {}, List); } else { Expected ContextOr = getDeclContext(Symfile); if (!ContextOr)