[Lldb-commits] [lldb] 5d7bda4 - [lldb] Turn GetDeclContextDIEContainingDIE into a worklist (NFC) (#224453)

via lldb-commits lldb-commits at lists.llvm.org
Thu Sep 17 20:46:59 PDT 2026


Author: Jonas Devlieghere
Date: 2026-09-18T03:46:53Z
New Revision: 5d7bda4e51049f43d39ce6a35d7c44fa44036509

URL: https://github.com/llvm/llvm-project/commit/5d7bda4e51049f43d39ce6a35d7c44fa44036509
DIFF: https://github.com/llvm/llvm-project/commit/5d7bda4e51049f43d39ce6a35d7c44fa44036509.diff

LOG: [lldb] Turn GetDeclContextDIEContainingDIE into a worklist (NFC) (#224453)

Convert GetDeclContextDIEContainingDIE from a recursive to a worklist
approach, avoiding a stack frame per DIE for long chains. The behavior
remains the same.

Added: 
    

Modified: 
    lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
    lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 53e515cc180b5..6aac04131cec6 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -3059,19 +3059,23 @@ TypeSP SymbolFileDWARF::GetTypeForDIE(const DWARFDIE &die,
   return type_sp;
 }
 
-/// Helper for the public \ref SymbolFileDWARF::GetDeclContextDIEContainingDIE
-/// API. Specifications and abstract origins the walk has already descended
-/// into are in \c seen and are not followed again.
-static DWARFDIE GetDeclContextDIEContainingDIE(
-    const DWARFDIE &orig_die,
-    llvm::SmallPtrSetImpl<const DWARFDebugInfoEntry *> &seen) {
-  DWARFDIE die = orig_die;
+DWARFDIE
+SymbolFileDWARF::GetDeclContextDIEContainingDIE(const DWARFDIE &orig_die) {
+  // Elaborations of the search DIE cannot be its declaration context.
+  llvm::SmallVector<std::pair<DWARFDIE, bool>, 4> worklist;
+  if (orig_die)
+    worklist.emplace_back(orig_die, /*is_elaboration=*/true);
 
-  while (die) {
-    // If this is the original DIE that we are searching for a declaration
-    // for, then don't look in the cache as we don't want our own decl
-    // context to be our decl context...
-    if (orig_die != die) {
+  // Bound the search on self-referential DWARF.
+  llvm::SmallPtrSet<const DWARFDebugInfoEntry *, 4> seen;
+
+  while (!worklist.empty()) {
+    auto [die, is_elaboration] = worklist.pop_back_val();
+
+    if (is_elaboration) {
+      if (!seen.insert(die.GetDIE()).second)
+        continue;
+    } else {
       switch (die.Tag()) {
       case DW_TAG_compile_unit:
       case DW_TAG_partial_unit:
@@ -3082,47 +3086,27 @@ static DWARFDIE GetDeclContextDIEContainingDIE(
       case DW_TAG_lexical_block:
       case DW_TAG_subprogram:
         return die;
-      case DW_TAG_inlined_subroutine: {
-        DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin);
-        if (abs_die) {
+      case DW_TAG_inlined_subroutine:
+        if (DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin))
           return abs_die;
-        }
         break;
-      }
       default:
         break;
       }
     }
 
-    DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification);
-    if (spec_die && seen.insert(spec_die.GetDIE()).second) {
-      DWARFDIE decl_ctx_die = ::GetDeclContextDIEContainingDIE(spec_die, seen);
-      if (decl_ctx_die)
-        return decl_ctx_die;
-    }
-
-    DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin);
-    if (abs_die && seen.insert(abs_die.GetDIE()).second) {
-      DWARFDIE decl_ctx_die = ::GetDeclContextDIEContainingDIE(abs_die, seen);
-      if (decl_ctx_die)
-        return decl_ctx_die;
-    }
-
-    die = die.GetParent();
+    // Traverse specifications and abstract origins before parent contexts.
+    if (DWARFDIE parent = die.GetParent())
+      worklist.emplace_back(parent, /*is_elaboration=*/false);
+    if (DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin))
+      worklist.emplace_back(abs_die, /*is_elaboration=*/true);
+    if (DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification))
+      worklist.emplace_back(spec_die, /*is_elaboration=*/true);
   }
 
   return DWARFDIE();
 }
 
-DWARFDIE
-SymbolFileDWARF::GetDeclContextDIEContainingDIE(const DWARFDIE &orig_die) {
-  if (!orig_die)
-    return DWARFDIE();
-
-  llvm::SmallPtrSet<const DWARFDebugInfoEntry *, 4> seen{orig_die.GetDIE()};
-  return ::GetDeclContextDIEContainingDIE(orig_die, seen);
-}
-
 Symbol *SymbolFileDWARF::GetObjCClassSymbol(ConstString objc_class_name) {
   Symbol *objc_class_symbol = nullptr;
   if (m_objfile_sp) {

diff  --git a/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp
index 4e36125dbfde5..0b8551c7cfd89 100644
--- a/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp
+++ b/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp
@@ -9,6 +9,7 @@
 #include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
 #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
 #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
 #include "TestingSupport/Symbol/YAMLModuleTester.h"
 #include "TestingSupport/TestUtilities.h"
 #include "lldb/Core/Debugger.h"
@@ -1272,6 +1273,296 @@ INSTANTIATE_TEST_SUITE_P(GetDIENamesAndRangesTests,
                          testing::Values(DW_AT_specification,
                                          DW_AT_abstract_origin));
 
+TEST(DWARFDIETest, GetDeclContextDIEContainingDIE_Specification) {
+  // The context is the DIE containing the specification rather than the
+  // specification itself.
+  //
+  // DW_TAG_namespace "N"
+  //   DW_TAG_subprogram "foo"  <-+
+  // DW_TAG_subprogram            |
+  //   DW_AT_specification -------+
+
+  const char *yamldata = R"(
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_AARCH64
+DWARF:
+  debug_abbrev:
+    - ID:              0
+      Table:
+        - Code:            0x1
+          Tag:             DW_TAG_compile_unit
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_language
+              Form:            DW_FORM_data2
+        - Code:            0x2
+          Tag:             DW_TAG_namespace
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_string
+        - Code:            0x3
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_string
+        - Code:            0x4
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_specification
+              Form:            DW_FORM_ref4
+  debug_info:
+     - Version:         5
+       UnitType:        DW_UT_compile
+       AddrSize:        8
+       Entries:
+
+        - AbbrCode:        0x1
+          Values:
+            - Value:           0x04
+
+        - AbbrCode:        0x2
+          Values:
+            - CStr:            N
+
+        - AbbrCode:        0x3
+          Values:
+            - CStr:            foo
+
+        - AbbrCode: 0x0
+
+        - AbbrCode:        0x4
+          Values:
+            - Value:           0x12
+
+        - AbbrCode: 0x0
+...
+)";
+  YAMLModuleTester t(yamldata);
+
+  DWARFUnit *unit = t.GetDwarfUnit();
+  ASSERT_NE(unit, nullptr);
+  const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
+  ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
+  DWARFDIE cu_die(unit, cu_entry);
+
+  DWARFDIE ns = cu_die.GetFirstChild();
+  ASSERT_TRUE(ns.IsValid());
+  ASSERT_EQ(ns.Tag(), DW_TAG_namespace);
+
+  DWARFDIE def = ns.GetSibling();
+  ASSERT_TRUE(def.IsValid());
+  ASSERT_EQ(def.Tag(), DW_TAG_subprogram);
+
+  DWARFDIE ctx = unit->GetSymbolFileDWARF().GetDeclContextDIEContainingDIE(def);
+  EXPECT_EQ(ctx.Tag(), DW_TAG_namespace);
+  EXPECT_EQ(ctx, ns);
+}
+
+TEST(DWARFDIETest, GetDeclContextDIEContainingDIE_SpecificationBeforeOrigin) {
+  // Follow specifications before abstract origins.
+  //
+  // DW_TAG_namespace "N"
+  //   DW_TAG_subprogram "foo"    <-+
+  // DW_TAG_structure_type "S"      |
+  //   DW_TAG_subprogram "bar"  <-+ |
+  // DW_TAG_subprogram            | |
+  //   DW_AT_specification ---------+
+  //   DW_AT_abstract_origin ----+
+
+  const char *yamldata = R"(
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_AARCH64
+DWARF:
+  debug_abbrev:
+    - ID:              0
+      Table:
+        - Code:            0x1
+          Tag:             DW_TAG_compile_unit
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_language
+              Form:            DW_FORM_data2
+        - Code:            0x2
+          Tag:             DW_TAG_namespace
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_string
+        - Code:            0x3
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_string
+        - Code:            0x4
+          Tag:             DW_TAG_structure_type
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_string
+        - Code:            0x5
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_specification
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_abstract_origin
+              Form:            DW_FORM_ref4
+  debug_info:
+     - Version:         5
+       UnitType:        DW_UT_compile
+       AddrSize:        8
+       Entries:
+
+        - AbbrCode:        0x1
+          Values:
+            - Value:           0x04
+
+        - AbbrCode:        0x2
+          Values:
+            - CStr:            N
+
+        - AbbrCode:        0x3
+          Values:
+            - CStr:            foo
+
+        - AbbrCode: 0x0
+
+        - AbbrCode:        0x4
+          Values:
+            - CStr:            S
+
+        - AbbrCode:        0x3
+          Values:
+            - CStr:            bar
+
+        - AbbrCode: 0x0
+
+        - AbbrCode:        0x5
+          Values:
+            - Value:           0x12
+            - Value:           0x1b
+
+        - AbbrCode: 0x0
+...
+)";
+  YAMLModuleTester t(yamldata);
+
+  DWARFUnit *unit = t.GetDwarfUnit();
+  ASSERT_NE(unit, nullptr);
+  const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
+  ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
+  DWARFDIE cu_die(unit, cu_entry);
+
+  DWARFDIE ns = cu_die.GetFirstChild();
+  ASSERT_TRUE(ns.IsValid());
+  ASSERT_EQ(ns.Tag(), DW_TAG_namespace);
+
+  DWARFDIE record = ns.GetSibling();
+  ASSERT_TRUE(record.IsValid());
+  ASSERT_EQ(record.Tag(), DW_TAG_structure_type);
+
+  DWARFDIE def = record.GetSibling();
+  ASSERT_TRUE(def.IsValid());
+  ASSERT_EQ(def.Tag(), DW_TAG_subprogram);
+
+  DWARFDIE ctx = unit->GetSymbolFileDWARF().GetDeclContextDIEContainingDIE(def);
+  EXPECT_EQ(ctx.Tag(), DW_TAG_namespace);
+  EXPECT_EQ(ctx, ns);
+}
+
+TEST(DWARFDIETest, GetDeclContextDIEContainingDIE_Cycle) {
+  // Terminate specification cycles and fall back to the parent context.
+  //
+  // DW_TAG_namespace "N"
+  //   DW_TAG_subprogram      <-+
+  //     DW_AT_specification ---+
+
+  const char *yamldata = R"(
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_AARCH64
+DWARF:
+  debug_abbrev:
+    - ID:              0
+      Table:
+        - Code:            0x1
+          Tag:             DW_TAG_compile_unit
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_language
+              Form:            DW_FORM_data2
+        - Code:            0x2
+          Tag:             DW_TAG_namespace
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_string
+        - Code:            0x3
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_specification
+              Form:            DW_FORM_ref4
+  debug_info:
+     - Version:         5
+       UnitType:        DW_UT_compile
+       AddrSize:        8
+       Entries:
+
+        - AbbrCode:        0x1
+          Values:
+            - Value:           0x04
+
+        - AbbrCode:        0x2
+          Values:
+            - CStr:            N
+
+        - AbbrCode:        0x3
+          Values:
+            - Value:           0x12
+
+        - AbbrCode: 0x0
+
+        - AbbrCode: 0x0
+...
+)";
+  YAMLModuleTester t(yamldata);
+
+  DWARFUnit *unit = t.GetDwarfUnit();
+  ASSERT_NE(unit, nullptr);
+  const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
+  ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
+  DWARFDIE cu_die(unit, cu_entry);
+
+  DWARFDIE ns = cu_die.GetFirstChild();
+  ASSERT_TRUE(ns.IsValid());
+  ASSERT_EQ(ns.Tag(), DW_TAG_namespace);
+
+  DWARFDIE func = ns.GetFirstChild();
+  ASSERT_TRUE(func.IsValid());
+  ASSERT_EQ(func.Tag(), DW_TAG_subprogram);
+
+  DWARFDIE ctx =
+      unit->GetSymbolFileDWARF().GetDeclContextDIEContainingDIE(func);
+  EXPECT_EQ(ctx.Tag(), DW_TAG_namespace);
+  EXPECT_EQ(ctx, ns);
+}
+
 // Exercises fallback in SymbolFileDWARF::ParseVariableDIE (added for
 // Swift) that walks the type chain for DW_AT_byte_size when the
 // TypeSystem cannot determine the size of a variable's storage. The


        


More information about the lldb-commits mailing list