Skip to content

Commit

Permalink
Fix crash after looking up dwo_id=0 in CU index.
Browse files Browse the repository at this point in the history
In the current state, if getFromHash(0) is called and there's no CU with
dwo_id=0, the lookup will stop at an empty slot, then the check
`Rows[H].getSignature() != S` won't cause the lookup to fail and return
a nullptr (as it should), because the empty slot has a 0 in the
signature field, and a pointer to the empty slot will be incorrectly
returned.

This patch fixes this by using the index field in the hash entry to
check for empty slots: signature = 0 can match a valid hash but
according to the spec the index for an occupied slot will always be
non-zero.

Differential Revision: https://reviews.llvm.org/D91670
  • Loading branch information
slackito committed Nov 19, 2020
1 parent ad5a195 commit 314a0d7
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 2 deletions.
8 changes: 6 additions & 2 deletions llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
Expand Up @@ -286,10 +286,14 @@ const DWARFUnitIndex::Entry *DWARFUnitIndex::getFromHash(uint64_t S) const {

auto H = S & Mask;
auto HP = ((S >> 32) & Mask) | 1;
while (Rows[H].getSignature() != S && Rows[H].getSignature() != 0)
// The spec says "while 0 is a valid hash value, the row index in a used slot
// will always be non-zero". Loop until we find a match or an empty slot.
while (Rows[H].getSignature() != S && Rows[H].Index != nullptr)
H = (H + HP) & Mask;

if (Rows[H].getSignature() != S)
// If the slot is empty, we don't care whether the signature matches (it could
// be zero and still match the zeros in the empty slot).
if (Rows[H].Index == nullptr)
return nullptr;

return &Rows[H];
Expand Down
118 changes: 118 additions & 0 deletions llvm/test/tools/llvm-symbolizer/split-dwarf-zero-signature-not-found.s
@@ -0,0 +1,118 @@
## This test checks that looking up a zero hash in the .debug_cu_index hash
## table works correctly when there's no CU with signature = 0.
##
## LLVM used to check just the signature bits to decide if the hash lookup ended
## at a match or at an empty slot. This is wrong when signature = 0 because
## empty slots have all zeros in the signature field too, and LLVM would return
## the empty slot as a valid result.

# REQUIRES: x86-registered-target

# RUN: llvm-mc --filetype=obj --triple x86_64 %s -o %t --defsym MAIN=0
# RUN: llvm-mc --filetype=obj --triple x86_64 %s -o %t.dwp
# RUN: llvm-symbolizer --obj=%t --dwp=%t.dwp 0x0 | FileCheck %s

## This expected output is very uninteresting, but it's better than a crash.
# CHECK: ??:0:0

.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 0 # DW_CHILDREN_no
.ascii "\260B" # DW_AT_GNU_dwo_name
.byte 8 # DW_FORM_string
.ascii "\261B" # DW_AT_GNU_dwo_id
.byte 7 # DW_FORM_data8
.ascii "\263B" # DW_AT_GNU_addr_base
.byte 23 # DW_FORM_sec_offset
.byte 85 # DW_AT_ranges
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)

## Create two CUs, with dwo_ids 0 and 1 respectively.
.ifdef MAIN
.irpc I,01
.data
A\I:
.long \I

.text
F\I:
nop

.section .debug_info,"",@progbits
.Lcu_begin\I:
.long .Ldebug_info_end\I-.Ldebug_info_start\I # Length of Unit
.Ldebug_info_start\I:
.short 4 # DWARF version number
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 8 # Address Size (in bytes)
.byte 1 # Abbrev [1] 0xb:0x25 DW_TAG_compile_unit
.asciz "A.dwo" # DW_AT_GNU_dwo_name
.quad \I # DW_AT_GNU_dwo_id
.long .debug_addr # DW_AT_GNU_addr_base
.long .Lranges\I # DW_AT_ranges
.Ldebug_info_end\I:

.section .debug_addr,"",@progbits
.quad A\I
.quad F\I

.section .debug_ranges,"",@progbits
.Lranges\I:
.quad F\I
.quad F\I+1
.quad 0
.quad 0
.endr
.else
## Deliberately omit compile unit 0 in the DWP. We want to check the case where
## a signature = 0 matches an empty hash slot in .debug_cu_index and the index
## in the parallel table has to be checked.
.section .debug_abbrev.dwo,"e",@progbits
.Labbrev1:
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 0 # DW_CHILDREN_no
.byte 37 # DW_AT_producer
.byte 8 # DW_FORM_string
.byte 3 # DW_AT_name
.byte 8 # DW_FORM_string
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.Labbrev_end1:

.section .debug_info.dwo,"e",@progbits
.Lcu_begin1:
.long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit
.Ldebug_info_start1:
.short 4 # DWARF version number
.long 0 # Offset Into Abbrev. Section
.byte 8 # Address Size (in bytes)
.byte 1 # Abbrev DW_TAG_compile_unit
.asciz "Hand-written DWARF" # DW_AT_producer
.byte '1', '.', 'c', 0 # DW_AT_name
.Ldebug_info_end1:

.section .debug_cu_index,"",@progbits
.long 2 # DWARF version number
.long 2 # Section count
.long 1 # Unit count
.long 8 # Slot count

.quad 1, 0, 0, 0, 0, 0, 0, 0 # Hash table
.long 1, 0, 0, 0, 0, 0, 0, 0 # Index table

.long 1 # DW_SECT_INFO
.long 3 # DW_SECT_ABBREV

.long .Lcu_begin1-.debug_info.dwo
.long .Labbrev1-.debug_abbrev.dwo

.long .Ldebug_info_end1-.Lcu_begin1
.long .Labbrev_end1-.Labbrev1

.endif

0 comments on commit 314a0d7

Please sign in to comment.