[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