Skip to content

Commit

Permalink
[lldb] DWARFDIE: Follow DW_AT_specification when computing CompilerCo…
Browse files Browse the repository at this point in the history
…ntext

Following the specification chain seems to be clearly the expected
behavior of GetDeclContext(). Otherwise C++ methods have an empty
CompilerContext instead of being nested in their struct/class.

Theprimary motivation for this functionality is the Swift plugin. In
order to test the change I added a proof-of-concept implementation of
a Module::FindFunction() variant that takes a CompilerContext, expesed
via lldb-test.

rdar://120553412
  • Loading branch information
adrian-prantl committed Jan 8, 2024
1 parent 93d2e49 commit 5f34a10
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 21 deletions.
6 changes: 6 additions & 0 deletions lldb/include/lldb/Core/Module.h
Expand Up @@ -337,6 +337,12 @@ class Module : public std::enable_shared_from_this<Module>,
const ModuleFunctionSearchOptions &options,
SymbolContextList &sc_list);

/// Find functions by compiler context.
void FindFunctions(llvm::ArrayRef<CompilerContext> 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,
Expand Down
17 changes: 17 additions & 0 deletions lldb/source/Core/Module.cpp
Expand Up @@ -855,6 +855,23 @@ void Module::FindFunctions(ConstString name,
}
}

void Module::FindFunctions(llvm::ArrayRef<CompilerContext> 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 &regex,
const ModuleFunctionSearchOptions &options,
SymbolContextList &sc_list) {
Expand Down
44 changes: 28 additions & 16 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
Expand Up @@ -373,51 +373,63 @@ std::vector<DWARFDIE> DWARFDIE::GetDeclContextDIEs() const {
return result;
}

std::vector<lldb_private::CompilerContext> DWARFDIE::GetDeclContext() const {
static std::vector<lldb_private::CompilerContext>
GetDeclContextImpl(llvm::SmallSet<lldb::user_id_t, 4> &seen, DWARFDIE die) {
std::vector<lldb_private::CompilerContext> 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;
}
return context;
}

std::vector<lldb_private::CompilerContext> DWARFDIE::GetDeclContext() const {
llvm::SmallSet<lldb::user_id_t, 4> seen;
return GetDeclContextImpl(seen, *this);
}

std::vector<lldb_private::CompilerContext>
DWARFDIE::GetTypeLookupContext() const {
std::vector<lldb_private::CompilerContext> context;
Expand Down
11 changes: 6 additions & 5 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Expand Up @@ -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;
});
}
}

Expand Down
6 changes: 6 additions & 0 deletions lldb/test/Shell/SymbolFile/DWARF/x86/find-basic-function.cpp
Expand Up @@ -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

Expand Down Expand Up @@ -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() {}
Expand Down
4 changes: 4 additions & 0 deletions lldb/tools/lldb-test/lldb-test.cpp
Expand Up @@ -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);

Expand Down Expand Up @@ -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<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
if (!ContextOr)
Expand Down

0 comments on commit 5f34a10

Please sign in to comment.