[Lldb-commits] [lldb] [lldb] DWARFDIE: Follow DW_AT_specification when computing CompilerCo… (PR #77157)

Adrian Prantl via lldb-commits lldb-commits at lists.llvm.org
Mon Jan 8 15:00:46 PST 2024


https://github.com/adrian-prantl updated https://github.com/llvm/llvm-project/pull/77157

>From 5f34a103d0b06220bb93b55525865e23694854b4 Mon Sep 17 00:00:00 2001
From: Adrian Prantl <aprantl at apple.com>
Date: Fri, 5 Jan 2024 15:11:24 -0800
Subject: [PATCH] [lldb] DWARFDIE: Follow DW_AT_specification when computing
 CompilerContext

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
---
 lldb/include/lldb/Core/Module.h               |  6 +++
 lldb/source/Core/Module.cpp                   | 17 +++++++
 .../Plugins/SymbolFile/DWARF/DWARFDIE.cpp     | 44 ++++++++++++-------
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      | 11 ++---
 .../DWARF/x86/find-basic-function.cpp         |  6 +++
 lldb/tools/lldb-test/lldb-test.cpp            |  4 ++
 6 files changed, 67 insertions(+), 21 deletions(-)

diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index f4973cdda1efcc..0188057247a68b 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<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,
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index c0574b724ace7b..331cf324664114 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<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) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
index bed68f45426f67..d4446befd83b05 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
@@ -373,44 +373,51 @@ 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;
@@ -418,6 +425,11 @@ std::vector<lldb_private::CompilerContext> DWARFDIE::GetDeclContext() const {
   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;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 447930ffe07b3f..f539ed5d2ae570 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 204568a446d0a4..30143a41d5e734 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 e326a84c1dbd2f..33281cfb150747 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<CompilerDeclContext> ContextOr = getDeclContext(Symfile);
     if (!ContextOr)



More information about the lldb-commits mailing list