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 <[email protected]> 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 <[email protected]> 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: _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
