Skip to content
8 changes: 8 additions & 0 deletions llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ using LVTypes = SmallVector<LVType *, 8>;

using LVOffsets = SmallVector<LVOffset, 8>;

// The following DWARF documents detail the 'tombstone' concept:
// https://dwarfstd.org/issues/231013.1.html
// https://dwarfstd.org/issues/200609.1.html
//
// The value of the largest representable address offset (for example,
// 0xffffffff when the size of an address is 32 bits).
//
// -1 (0xffffffff) => Valid tombstone
const LVAddress MaxAddress = std::numeric_limits<uint64_t>::max();

enum class LVBinaryType { NONE, ELF, COFF };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class LVDWARFReader final : public LVBinaryReader {
bool FoundLowPC = false;
bool FoundHighPC = false;

// The value is updated for each Compile Unit that is processed.
std::optional<LVAddress> TombstoneAddress;

// Cross references (Elements).
using LVElementSet = std::unordered_set<LVElement *>;
struct LVElementEntry {
Expand Down Expand Up @@ -127,6 +130,12 @@ class LVDWARFReader final : public LVBinaryReader {
LVAddress getCUHighAddress() const { return CUHighAddress; }
void setCUHighAddress(LVAddress Address) { CUHighAddress = Address; }

void setTombstoneAddress(LVAddress Address) { TombstoneAddress = Address; }
LVAddress getTombstoneAddress() const {
assert(TombstoneAddress && "Unset tombstone value");
return TombstoneAddress.value();
}

const LVSymbols &GetSymbolsWithLocations() const {
return SymbolsWithLocations;
}
Expand Down
15 changes: 11 additions & 4 deletions llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,11 @@ void LVDWARFReader::processOneAttribute(const DWARFDie &Die,
}
}
if (FoundLowPC) {
if (CurrentLowPC == MaxAddress)
if (CurrentLowPC == getTombstoneAddress())
CurrentElement->setIsDiscarded();
// Consider the case of WebAssembly.
CurrentLowPC += WasmCodeSectionOffset;
else
// Consider the case of WebAssembly.
CurrentLowPC += WasmCodeSectionOffset;
if (CurrentElement->isCompileUnit())
setCUBaseAddress(CurrentLowPC);
}
Expand Down Expand Up @@ -271,7 +272,8 @@ void LVDWARFReader::processOneAttribute(const DWARFDie &Die,
DWARFAddressRangesVector Ranges = RangesOrError.get();
for (DWARFAddressRange &Range : Ranges) {
// This seems to be a tombstone for empty ranges.
if (Range.LowPC == Range.HighPC)
if ((Range.LowPC == Range.HighPC) ||
(Range.LowPC = getTombstoneAddress()))
continue;
// Store the real upper limit for the address range.
if (UpdateHighAddress && Range.HighPC > 0)
Expand Down Expand Up @@ -629,6 +631,11 @@ Error LVDWARFReader::createScopes() {
: DwarfContext->dwo_compile_units();
for (const std::unique_ptr<DWARFUnit> &CU : CompileUnits) {

// Take into account the address byte size for a correct 'tombstone'
// value identification.
setTombstoneAddress(
dwarf::computeTombstoneAddress(CU->getAddressByteSize()));

// Deduction of index used for the line records.
//
// For the following test case: test.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# REQUIRES: x86-registered-target

# Test that DWARF tombstones are correctly detected/respected in wasm
# 32 bit object files.

# The test case was produced by the following steps:
#
# // test-clang.cpp
# void foo() {
# }
#
# 1) clang --target=wasm32 -S -g test-clang.cpp
# -o Inputs/wasm-32bit-tombstone.s
#
# 2) Creating a single function, tombstoning it in the assembly, by
# manually changing the DW_AT_low_pc for the DW_TAG_subprogram:
# .Lfunc_begin0 to 0xffffffff to mark the function as dead code:
#
# .int8 2 # Abbrev [2] 0x26:0x1b DW_TAG_subprogram
# .int32 .Lfunc_begin0 # DW_AT_low_pc <---------
# .int32 .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc

# .int8 2 # Abbrev [2] 0x26:0x1b DW_TAG_subprogram
# .int32 0xffffffff # DW_AT_low_pc <---------
# .int32 .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc

# RUN: llvm-mc -arch=wasm32 -filetype=obj \
# RUN: %p/wasm-32bit-tombstone.s \
# RUN: -o %t.wasm-32bit-tombstone.wasm

# RUN: llvm-debuginfo-analyzer --select-elements=Discarded \
# RUN: --print=elements \
# RUN: %t.wasm-32bit-tombstone.wasm 2>&1 | \
# RUN: FileCheck --strict-whitespace -check-prefix=ONE %s

# ONE: Logical View:
# ONE-NEXT: {File} '{{.*}}wasm-32bit-tombstone.wasm'
# ONE-EMPTY:
# ONE-NEXT: {CompileUnit} 'test-clang.cpp'
# ONE-NEXT: {Function} not_inlined 'foo' -> 'void'

# RUN: llvm-dwarfdump --debug-info %t.wasm-32bit-tombstone.wasm | \
# RUN: FileCheck %s --check-prefix=TWO

# TWO: DW_TAG_subprogram
# TWO-NEXT: DW_AT_low_pc (dead code)
# TWO-NEXT: DW_AT_high_pc
# TWO-NEXT: DW_AT_name ("foo")

.text
.file "test-clang.cpp"
.functype _Z3foov () -> ()
.section .text._Z3foov,"",@
_Z3foov: # @_Z3foov
.Lfunc_begin0:
.functype _Z3foov () -> ()
return
end_function
.Lfunc_end0:
# -- End function
.section .debug_abbrev,"",@
.int8 1 # Abbreviation Code
.int8 17 # DW_TAG_compile_unit
.int8 1 # DW_CHILDREN_yes
.int8 3 # DW_AT_name
.int8 14 # DW_FORM_strp
.int8 17 # DW_AT_low_pc
.int8 1 # DW_FORM_addr
.int8 18 # DW_AT_high_pc
.int8 6 # DW_FORM_data4
.int8 0 # EOM(1)
.int8 0 # EOM(2)
.int8 2 # Abbreviation Code
.int8 46 # DW_TAG_subprogram
.int8 0 # DW_CHILDREN_no
.int8 17 # DW_AT_low_pc
.int8 1 # DW_FORM_addr
.int8 18 # DW_AT_high_pc
.int8 6 # DW_FORM_data4
.int8 3 # DW_AT_name
.int8 14 # DW_FORM_strp
.int8 0 # EOM(1)
.int8 0 # EOM(2)
.int8 0 # EOM(3)
.section .debug_info,"",@
.Lcu_begin0:
.int32 .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
.Ldebug_info_start0:
.int16 4 # DWARF version number
.int32 .debug_abbrev0 # Offset Into Abbrev. Section
.int8 4 # Address Size (in bytes)
.int8 1 # Abbrev [1] 0xb:0x37 DW_TAG_compile_unit
.int32 .Linfo_string1 # DW_AT_name
.int32 .Lfunc_begin0 # DW_AT_low_pc
.int32 .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.int8 2 # Abbrev [2] 0x26:0x1b DW_TAG_subprogram
.int32 0xffffffff # DW_AT_low_pc
.int32 .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.int32 .Linfo_string4 # DW_AT_name
.int8 0 # End Of Children Mark
.Ldebug_info_end0:
.section .debug_str,"S",@
.Linfo_string1:
.asciz "test-clang.cpp" # string offset=176
.Linfo_string4:
.asciz "foo" # string offset=241
.ident "clang version 19.0.0"
Loading