[Lldb-commits] [lldb] [lldb] Collect call sites nested in inline instances (PR #219213)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Sep 23 07:10:18 PDT 2026
https://github.com/firmiana402 updated https://github.com/llvm/llvm-project/pull/219213
>From 7f752ce4f65e00bcb12ab1f781953573f3b00594 Mon Sep 17 00:00:00 2001
From: firmiana402 <firmiana402 at gmail.com>
Date: Thu, 27 Aug 2026 20:30:45 +0800
Subject: [PATCH 1/2] [lldb] Collect call sites nested in inline instances
---
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 28 +++++---
.../SymbolFile/DWARF/SymbolFileDWARF.h | 4 +-
.../SymbolFile/DWARF/SymbolFileDWARFTests.cpp | 70 +++++++++++++++++++
3 files changed, 91 insertions(+), 11 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 41e3372584d4f4..9b2f24b908f20e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -4198,6 +4198,21 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) {
return parameters;
}
+static void CollectCallSiteDIEs(DWARFDIE parent,
+ std::vector<DWARFDIE> &call_site_dies) {
+ for (DWARFDIE child : parent.children()) {
+ if (child.Tag() == DW_TAG_call_site ||
+ child.Tag() == DW_TAG_GNU_call_site) {
+ call_site_dies.push_back(child);
+ continue;
+ }
+
+ // A nested subprogram owns its call sites independently of this function.
+ if (child.Tag() != DW_TAG_subprogram)
+ CollectCallSiteDIEs(child, call_site_dies);
+ }
+}
+
/// Collect call graph edges present in a function DIE.
std::vector<std::unique_ptr<lldb_private::CallEdge>>
SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) {
@@ -4213,16 +4228,11 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) {
LLDB_LOG(log, "CollectCallEdges: Found call site info in {0}",
function_die.GetPubname());
- // Scan the DIE for TAG_call_site entries.
- // TODO: A recursive scan of all blocks in the subprogram is needed in order
- // to be DWARF5-compliant. This may need to be done lazily to be performant.
- // For now, assume that all entries are nested directly under the subprogram
- // (this is the kind of DWARF LLVM produces) and parse them eagerly.
- std::vector<std::unique_ptr<CallEdge>> call_edges;
- for (DWARFDIE child : function_die.children()) {
- if (child.Tag() != DW_TAG_call_site && child.Tag() != DW_TAG_GNU_call_site)
- continue;
+ std::vector<DWARFDIE> call_site_dies;
+ CollectCallSiteDIEs(function_die, call_site_dies);
+ std::vector<std::unique_ptr<CallEdge>> call_edges;
+ for (DWARFDIE child : call_site_dies) {
std::optional<DWARFDIE> call_origin;
std::optional<DWARFExpressionList> call_target;
addr_t return_pc = LLDB_INVALID_ADDRESS;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index f76bcf16304ec8..42e6d962a80a19 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -488,8 +488,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
bool ClassContainsSelector(const DWARFDIE &class_die, ConstString selector);
- /// Parse call site entries (DW_TAG_call_site), including any nested call site
- /// parameters (DW_TAG_call_site_parameter).
+ /// Parse call site entries (DW_TAG_call_site), including entries in nested
+ /// scopes and their call site parameters (DW_TAG_call_site_parameter).
std::vector<std::unique_ptr<CallEdge>>
CollectCallEdges(lldb::ModuleSP module, DWARFDIE function_die);
diff --git a/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp b/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp
index 7f477f1913f9c4..d26a78d743bbf7 100644
--- a/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp
+++ b/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp
@@ -22,6 +22,7 @@
#include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/Symbol/YAMLModuleTester.h"
#include "TestingSupport/TestUtilities.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Module.h"
@@ -29,6 +30,7 @@
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/DataEncoder.h"
@@ -69,6 +71,74 @@ TEST_F(SymbolFileDWARFTests, TestAbilitiesForDWARF) {
EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
}
+TEST(SymbolFileDWARFCallEdgeTests, ParseCallSiteNestedInInline) {
+ const char *yamldata = R"(
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Code: 0x1
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ - Code: 0x2
+ Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_call_all_calls
+ Form: DW_FORM_flag_present
+ - Code: 0x3
+ Tag: DW_TAG_inlined_subroutine
+ Children: DW_CHILDREN_yes
+ - Code: 0x4
+ Tag: DW_TAG_call_site
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_call_target
+ Form: DW_FORM_exprloc
+ - Attribute: DW_AT_call_return_pc
+ Form: DW_FORM_addr
+ debug_info:
+ - Version: 5
+ UnitType: DW_UT_compile
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x1
+ - AbbrCode: 0x2
+ - AbbrCode: 0x3
+ - AbbrCode: 0x4
+ Values:
+ - Value: 0x1
+ BlockData:
+ - 0x50 # DW_OP_reg0
+ - Value: 0x1234
+ - AbbrCode: 0x0
+ - AbbrCode: 0x2
+ - AbbrCode: 0x4
+ Values:
+ - Value: 0x1
+ BlockData:
+ - 0x50 # DW_OP_reg0
+ - Value: 0x5678
+ - AbbrCode: 0x0
+ - AbbrCode: 0x0
+ - AbbrCode: 0x0
+)";
+
+ YAMLModuleTester t(yamldata);
+ auto *symbol_file =
+ llvm::cast<SymbolFileDWARF>(t.GetModule()->GetSymbolFile());
+ DWARFDIE function_die = t.GetDwarfUnit()->DIE().GetFirstChild();
+
+ auto call_edges = symbol_file->ParseCallEdgesInFunction(function_die.GetID());
+ ASSERT_EQ(call_edges.size(), 1u);
+ EXPECT_EQ(call_edges.front()->GetSortKey().second, 0x1234u);
+}
+
TEST_F(SymbolFileDWARFTests, ParseArangesNonzeroSegmentSize) {
// This `.debug_aranges` table header is a valid 32bit big-endian section
// according to the DWARFv5 spec:6.2.1, but contains segment selectors which
>From c48db6994f4ede8a24d8addcf4779a54eb4aac35 Mon Sep 17 00:00:00 2001
From: firmiana402 <firmiana402 at gmail.com>
Date: Wed, 23 Sep 2026 18:50:23 +0800
Subject: [PATCH 2/2] [lldb] Enhance call site collection with depth-limited
traversal
---
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 38 ++++++++++++++-----
1 file changed, 28 insertions(+), 10 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 9b2f24b908f20e..a0602daaac16a0 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -10,6 +10,7 @@
#include "clang/Basic/ABI.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
@@ -4198,18 +4199,35 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) {
return parameters;
}
-static void CollectCallSiteDIEs(DWARFDIE parent,
+static void CollectCallSiteDIEs(DWARFDIE function_die,
std::vector<DWARFDIE> &call_site_dies) {
- for (DWARFDIE child : parent.children()) {
- if (child.Tag() == DW_TAG_call_site ||
- child.Tag() == DW_TAG_GNU_call_site) {
- call_site_dies.push_back(child);
- continue;
- }
+ // Bound traversal depth so malformed or unusually deep DWARF cannot cause
+ // unbounded traversal.
+ constexpr unsigned MaxScopeDepth = 8;
+ struct WorkItem {
+ DWARFDIE die;
+ unsigned depth;
+ };
- // A nested subprogram owns its call sites independently of this function.
- if (child.Tag() != DW_TAG_subprogram)
- CollectCallSiteDIEs(child, call_site_dies);
+ llvm::SmallVector<WorkItem, 8> worklist;
+ worklist.push_back({function_die, 0});
+
+ while (!worklist.empty()) {
+ WorkItem item = worklist.pop_back_val();
+ for (DWARFDIE child : item.die.children()) {
+ if (child.Tag() == DW_TAG_call_site ||
+ child.Tag() == DW_TAG_GNU_call_site) {
+ call_site_dies.push_back(child);
+ continue;
+ }
+
+ // A nested subprogram owns its call sites independently of this
+ // function.
+ if (child.Tag() == DW_TAG_subprogram || item.depth >= MaxScopeDepth)
+ continue;
+
+ worklist.push_back({child, item.depth + 1});
+ }
}
}
More information about the lldb-commits
mailing list