[Lldb-commits] [lldb] [lldb] Don't create functions for DWARF dead-code tombstones (PR #205691)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Fri Jun 26 09:22:38 PDT 2026
https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/205691
>From b04b9fb20548ae93ddaef108026c54ad873ccfd2 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Wed, 24 Jun 2026 15:34:35 -0700
Subject: [PATCH] [lldb] Don't create functions for DWARF dead-code tombstones
A function the linker eliminated (dead-stripped, or inlined into all its
callers) keeps a DWARF subprogram DIE whose DW_AT_low_pc is a "(dead
code)" tombstone: the all-ones value for the unit's address size. LLDB
has no explicit tombstone check; it only rejects dead code where
Address::IsValid() happens to catch it, i.e. when the tombstone equals
the 8-byte LLDB_INVALID_ADDRESS. On wasm32 the tombstone is the 4-byte
0xffffffff, which IsValid() lets through, so LLDB builds a section-less,
module-less lldb_private::Function and later crashes in
Block::GetRangeContainingAddress (reached from
Function::GetPrologueByteSize) dereferencing the empty module.
Require the low PC to resolve to a section in
SymbolFileDWARF::ParseFunction, using Address::IsSectionOffset() instead
of IsValid(). This is the single point where functions are created, so
it covers both the DW_AT_low/high_pc and DW_AT_ranges encodings, and it
rejects any low PC that doesn't land in real code regardless of address
width. It also avoids special-casing the all- ones tombstone value,
which is an LLVM convention; other linkers tombstone with zero or a
near-zero address, and those are already handled by the adjacent
range.valid()/m_first_code_address check.
---
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 5 +-
.../DWARF/Inputs/gnu-ref-strp-alt.yaml | 7 ++
.../SymbolFile/DWARF/gnu-ref-strp-alt.test | 2 +-
.../wasm-dead-code-function-breakpoint.yaml | 78 +++++++++++++++++++
4 files changed, 90 insertions(+), 2 deletions(-)
create mode 100644 lldb/test/Shell/SymbolFile/DWARF/wasm-dead-code-function-breakpoint.yaml
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 56fbf3fd771b5..5f629e90f006d 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -926,8 +926,11 @@ Function *SymbolFileDWARF::ParseFunction(CompileUnit &comp_unit,
for (const auto &range : *die_ranges) {
if (range.valid() && range.LowPC < m_first_code_address)
continue;
+ // Require the low PC to resolve to a section. This rejects addresses that
+ // don't correspond to any real code, such as the "(dead code)" tombstone
+ // a linker leaves on the DW_AT_low_pc of an eliminated function.
if (Address base_addr(range.LowPC, module_sp->GetSectionList());
- base_addr.IsValid() && FixupAddress(base_addr))
+ base_addr.IsSectionOffset() && FixupAddress(base_addr))
ranges.emplace_back(std::move(base_addr), range.HighPC - range.LowPC);
}
} else {
diff --git a/lldb/test/Shell/SymbolFile/DWARF/Inputs/gnu-ref-strp-alt.yaml b/lldb/test/Shell/SymbolFile/DWARF/Inputs/gnu-ref-strp-alt.yaml
index f4fb7d6d7c369..88752a40c03a0 100644
--- a/lldb/test/Shell/SymbolFile/DWARF/Inputs/gnu-ref-strp-alt.yaml
+++ b/lldb/test/Shell/SymbolFile/DWARF/Inputs/gnu-ref-strp-alt.yaml
@@ -5,6 +5,13 @@ FileHeader:
Type: ET_DYN
Machine: EM_X86_64
Entry: 0x1000
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x1000
+ AddressAlign: 0x10
+ Size: 0x100
DWARF:
debug_str:
- ''
diff --git a/lldb/test/Shell/SymbolFile/DWARF/gnu-ref-strp-alt.test b/lldb/test/Shell/SymbolFile/DWARF/gnu-ref-strp-alt.test
index c81c41a8b5fab..150fe16327268 100644
--- a/lldb/test/Shell/SymbolFile/DWARF/gnu-ref-strp-alt.test
+++ b/lldb/test/Shell/SymbolFile/DWARF/gnu-ref-strp-alt.test
@@ -9,4 +9,4 @@
# CHECK: (lldb) b bar
# CHECK-NOT: unsupported DW_FORM values:
-# CHECK: Breakpoint 1: address = 0x0000000000001000
+# CHECK: Breakpoint 1: {{.*}}address = 0x0000000000001000
diff --git a/lldb/test/Shell/SymbolFile/DWARF/wasm-dead-code-function-breakpoint.yaml b/lldb/test/Shell/SymbolFile/DWARF/wasm-dead-code-function-breakpoint.yaml
new file mode 100644
index 0000000000000..fb7f7d0f062ec
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/wasm-dead-code-function-breakpoint.yaml
@@ -0,0 +1,78 @@
+# A function the linker eliminated (dead-stripped, or inlined into all its
+# callers) keeps a DWARF subprogram DIE whose DW_AT_low_pc is a "(dead code)"
+# tombstone. Such a tombstone resolves to no section, meaning the DIE doesn't
+# describe real code, and hence shouldn't resolve to a breakpoint.
+
+# RUN: yaml2obj %s -o %t
+# RUN: %lldb %t -o "breakpoint set --name dead_stripped" \
+# RUN: -o "breakpoint set --name live" -o exit 2>&1 | FileCheck %s
+
+# CHECK: (lldb) breakpoint set --name dead_stripped
+# CHECK-NEXT: Breakpoint 1: no locations (pending).
+# CHECK: (lldb) breakpoint set --name live
+# CHECK-NEXT: Breakpoint 2: where = {{.*}}`live{{.*}}, address = 0x00000017
+
+--- !WASM
+FileHeader:
+ Version: 0x1
+Sections:
+ - Type: TYPE
+ Signatures:
+ - Index: 0
+ ParamTypes:
+ - I32
+ ReturnTypes:
+ - I32
+ - Type: FUNCTION
+ FunctionTypes: [ 0 ]
+ - Type: MEMORY
+ Memories:
+ - Minimum: 0x1
+ - Type: GLOBAL
+ Globals:
+ - Index: 0
+ Type: I32
+ Mutable: true
+ InitExpr:
+ Opcode: I32_CONST
+ Value: 65536
+ - Type: EXPORT
+ Exports:
+ - Name: memory
+ Kind: MEMORY
+ Index: 0
+ - Name: live
+ Kind: FUNCTION
+ Index: 0
+ - Type: CODE
+ Functions:
+ - Index: 0
+ Locals:
+ - Type: I32
+ Count: 1
+ Body: 23808080800041106B21012001200036020C200128020C4101740F0B
+ - Type: CUSTOM
+ Name: .debug_abbrev
+ Payload: 011101250E1305030E10171B0E110155170000022E01110112064018030E3A0B3B0B271949133F1900000305000218030E3A0B3B0B49130000042400030E3E0B0B0B000000
+ - Type: CUSTOM
+ HeaderSecSizeEncodingLen: 2
+ Name: .debug_info
+ Payload: 780000000400000000000401290000001D001E0000000000000006000000000000000000000002FFFFFFFF1F00000004ED00019F100000000101740000000302910C000000000101740000000002020000001F00000004ED00019F0B0000000102740000000302910C00000000010274000000000402000000050400
+ - Type: CUSTOM
+ Name: .debug_ranges
+ Payload: FEFFFFFFFEFFFFFF02000000210000000000000000000000
+ - Type: CUSTOM
+ Name: .debug_str
+ Payload: 7800696E74002F746D70006C69766500646561645F7374726970706564002F746D702F6D696E2E6300636C616E672076657273696F6E2032322E312E302D776173692D73646B202868747470733A2F2F6769746875622E636F6D2F6C6C766D2F6C6C766D2D70726F6A65637420343433346461626236393931363835366238323466363861363462303239633637313735653533322900
+ - Type: CUSTOM
+ Name: .debug_line
+ Payload: 5500000004001D000000010101FB0E0D000101010100000001000001006D696E2E630000000000000502FFFFFFFF0105230A084A05250658051C3C02020001010005020200000013051A0A084A051C065805133C0202000101
+ - Type: CUSTOM
+ Name: name
+ FunctionNames:
+ - Index: 0
+ Name: live
+ GlobalNames:
+ - Index: 0
+ Name: __stack_pointer
+...
More information about the lldb-commits
mailing list