[Lldb-commits] [lldb] [lldb] Guard against a null module in Block::GetRangeContainingAddress (PR #205691)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Thu Jun 25 09:09:17 PDT 2026
https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/205691
>From 28046b89f231c7dfd56cce38f4db4c3a73149f9f 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 1/2] [lldb] Guard against a null module in
Block::GetRangeContainingAddress
Block::GetRangeContainingAddress built the range's base address from
func_addr.GetModule()->GetSectionList(), assuming a function always
resolves to an owning module. That is not always true: a function the
linker eliminated (e.g. dead-stripped, or inlined into all its callers)
keeps a DWARF subprogram DIE whose DW_AT_low_pc is a "(dead code)"
tombstone. LLDB represents such a function with a section-less, invalid
address whose GetModule() is empty, so the dereference crashes.
This is reached from Function::GetPrologueByteSize()'s fallback for an
entry with no covering line row. Bail out when there is no module
mirroring the existing null-module guards in Block::GetRangeAtIndex and
CallEdge::GetLoadAddress.
Added a test case based on the WebAssembly code I observed this with.
---
lldb/source/Symbol/Block.cpp | 7 +-
.../wasm-dead-code-function-breakpoint.yaml | 73 +++++++++++++++++++
2 files changed, 79 insertions(+), 1 deletion(-)
create mode 100644 lldb/test/Shell/SymbolFile/DWARF/wasm-dead-code-function-breakpoint.yaml
diff --git a/lldb/source/Symbol/Block.cpp b/lldb/source/Symbol/Block.cpp
index 3de3e5eecbf35..950d88c1f0bf4 100644
--- a/lldb/source/Symbol/Block.cpp
+++ b/lldb/source/Symbol/Block.cpp
@@ -253,9 +253,14 @@ bool Block::GetRangeContainingAddress(const Address &addr,
assert(range_ptr);
Address func_addr = function.GetAddress();
+ ModuleSP module_sp = func_addr.GetModule();
+ if (!module_sp) {
+ range.Clear();
+ return false;
+ }
range.GetBaseAddress() =
Address(func_addr.GetFileAddress() + range_ptr->GetRangeBase(),
- func_addr.GetModule()->GetSectionList());
+ module_sp->GetSectionList());
range.SetByteSize(range_ptr->GetByteSize());
return true;
}
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..f05f34cf299af
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/wasm-dead-code-function-breakpoint.yaml
@@ -0,0 +1,73 @@
+# A WebAssembly 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 (0xffffffff).
+
+# RUN: yaml2obj %s -o %t
+# RUN: %lldb %t -o "breakpoint set --name dead_stripped" -o exit 2>&1 | FileCheck %s
+
+# CHECK: Breakpoint 1: address = 0xffffffff
+
+--- !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
+...
>From 4b58f4f987059e4c3653236fa7086101108e4c2c Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 25 Jun 2026 09:08:21 -0700
Subject: [PATCH 2/2] Fix tombstone comparison
---
.../SymbolFile/DWARF/DWARFDebugInfoEntry.cpp | 4 +++-
.../wasm-dead-code-function-breakpoint.yaml | 18 +++++++++++++-----
2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
index 849f5738b62d7..aefac8bbaede5 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -19,6 +19,7 @@
#include "lldb/Expression/DWARFExpression.h"
#include "lldb/Symbol/ObjectFile.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatAdapters.h"
@@ -549,7 +550,8 @@ DWARFDebugInfoEntry::GetAttributeAddressRanges(
dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
if (GetAttributeAddressRange(cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS,
check_elaborating_dies) &&
- lo_pc < hi_pc)
+ lo_pc < hi_pc &&
+ lo_pc != llvm::dwarf::computeTombstoneAddress(cu->GetAddressByteSize()))
return llvm::DWARFAddressRangesVector{{lo_pc, hi_pc}};
}
return llvm::createStringError("DIE has no address range information");
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
index f05f34cf299af..7a128acd3e8de 100644
--- a/lldb/test/Shell/SymbolFile/DWARF/wasm-dead-code-function-breakpoint.yaml
+++ b/lldb/test/Shell/SymbolFile/DWARF/wasm-dead-code-function-breakpoint.yaml
@@ -1,11 +1,19 @@
-# A WebAssembly 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 (0xffffffff).
+# 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. For wasm32 that is
+# the 4-byte 0xffffffff, which is narrower than LLDB_INVALID_ADDRESS, so it is
+# not caught by the generic invalid-address guards and must be recognized as a
+# tombstone. Such a DIE describes no real code, so it must not produce a
+# function nor a breakpoint location, while a live sibling still resolves.
# RUN: yaml2obj %s -o %t
-# RUN: %lldb %t -o "breakpoint set --name dead_stripped" -o exit 2>&1 | FileCheck %s
+# RUN: %lldb %t -o "breakpoint set --name dead_stripped" \
+# RUN: -o "breakpoint set --name live" -o exit 2>&1 | FileCheck %s
-# CHECK: Breakpoint 1: address = 0xffffffff
+# 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:
More information about the lldb-commits
mailing list