Skip to content

Commit d131081

Browse files
committed
[lldb] 2/2: Fix DW_AT_ranges DW_FORM_sec_offset not using DW_AT_rnglists_base (used by GCC)
DW_AT_ranges can use DW_FORM_sec_offset (instead of DW_FORM_rnglistx). In such case DW_AT_rnglists_base does not need to be present. DWARF-5 spec: "If the offset_entry_count is zero, then DW_FORM_rnglistx cannot be used to access a range list; DW_FORM_sec_offset must be used instead. If the offset_entry_count is non-zero, then DW_FORM_rnglistx may be used to access a range list;" This fix is for TestTypeCompletion.py category `dwarf` using GCC with DWARF-5. The fix just provides GetRnglist() lazy getter for `m_rnglist_table`. The testcase is easier to review by: diff -u lldb/test/Shell/SymbolFile/DWARF/DW_AT_low_pc-addrx.s \ lldb/test/Shell/SymbolFile/DWARF/DW_AT_range-DW_FORM_sec_offset.s Differential Revision: https://reviews.llvm.org/D98289
1 parent 9dd861a commit d131081

File tree

3 files changed

+160
-12
lines changed

3 files changed

+160
-12
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -485,28 +485,37 @@ DWARFDataExtractor DWARFUnit::GetLocationData() const {
485485
}
486486

487487
void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) {
488-
m_ranges_base = ranges_base;
489-
490-
if (GetVersion() < 5)
491-
return;
488+
lldbassert(!m_rnglist_table_done);
492489

493-
if (auto table_or_error = ParseListTableHeader<llvm::DWARFDebugRnglistTable>(
494-
m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(),
495-
ranges_base, DWARF32))
496-
m_rnglist_table = std::move(table_or_error.get());
497-
else
498-
GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
499-
"Failed to extract range list table at offset 0x%" PRIx64 ": %s",
500-
ranges_base, toString(table_or_error.takeError()).c_str());
490+
m_ranges_base = ranges_base;
501491
}
502492

503493
const llvm::Optional<llvm::DWARFDebugRnglistTable> &DWARFUnit::GetRnglist() {
494+
if (GetVersion() >= 5 && !m_rnglist_table_done) {
495+
m_rnglist_table_done = true;
496+
if (auto table_or_error =
497+
ParseListTableHeader<llvm::DWARFDebugRnglistTable>(
498+
m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(),
499+
m_ranges_base, DWARF32))
500+
m_rnglist_table = std::move(table_or_error.get());
501+
else
502+
GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
503+
"Failed to extract range list table at offset 0x%" PRIx64 ": %s",
504+
m_ranges_base, toString(table_or_error.takeError()).c_str());
505+
}
504506
return m_rnglist_table;
505507
}
506508

509+
// This function is called only for DW_FORM_rnglistx.
507510
llvm::Optional<uint64_t> DWARFUnit::GetRnglistOffset(uint32_t Index) {
508511
if (!GetRnglist())
509512
return llvm::None;
513+
if (!m_ranges_base) {
514+
GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
515+
"%8.8x: DW_FORM_rnglistx cannot be used without DW_AT_rnglists_base",
516+
GetOffset());
517+
return llvm::None;
518+
}
510519
if (llvm::Optional<uint64_t> off = GetRnglist()->getOffsetEntry(
511520
m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), Index))
512521
return *off + m_ranges_base;

lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ class DWARFUnit : public lldb_private::UserID {
325325
dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base.
326326

327327
llvm::Optional<llvm::DWARFDebugRnglistTable> m_rnglist_table;
328+
bool m_rnglist_table_done = false;
328329
llvm::Optional<llvm::DWARFListTableHeader> m_loclist_table_header;
329330

330331
const DIERef::Section m_section;
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# DW_AT_ranges can use DW_FORM_sec_offset (instead of DW_FORM_rnglistx).
2+
# In such case DW_AT_rnglists_base does not need to be present.
3+
4+
# REQUIRES: x86
5+
6+
# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj %s > %t
7+
# RUN: %lldb %t -o "image lookup -v -s lookup_rnglists" \
8+
# RUN: -o exit | FileCheck %s
9+
10+
# Failure was the block range 1..2 was not printed plus:
11+
# error: DW_AT_range-DW_FORM_sec_offset.s.tmp {0x0000003f}: DIE has DW_AT_ranges(0xc) attribute, but range extraction failed (missing or invalid range list table), please file a bug and attach the file at the start of this error message
12+
13+
# CHECK-LABEL: image lookup -v -s lookup_rnglists
14+
# CHECK: Function: id = {0x00000029}, name = "rnglists", range = [0x0000000000000000-0x0000000000000003)
15+
# CHECK: Blocks: id = {0x00000029}, range = [0x00000000-0x00000003)
16+
# CHECK-NEXT: id = {0x0000003f}, range = [0x00000001-0x00000002)
17+
18+
# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj \
19+
# RUN: --defsym RNGLISTX=0 %s > %t-rnglistx
20+
# RUN: %lldb %t-rnglistx -o "image lookup -v -s lookup_rnglists" \
21+
# RUN: -o exit 2>&1 | FileCheck --check-prefix=RNGLISTX %s
22+
23+
# RNGLISTX-LABEL: image lookup -v -s lookup_rnglists
24+
# RNGLISTX: error: {{.*}} 00000000: DW_FORM_rnglistx cannot be used without DW_AT_rnglists_base
25+
26+
# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj \
27+
# RUN: --defsym RNGLISTX=0 --defsym RNGLISTBASE=0 %s > %t-rnglistbase
28+
# RUN: %lldb %t-rnglistbase -o "image lookup -v -s lookup_rnglists" \
29+
# RUN: -o exit 2>&1 | FileCheck --check-prefix=RNGLISTBASE %s
30+
31+
# RNGLISTBASE-LABEL: image lookup -v -s lookup_rnglists
32+
# RNGLISTBASE: error: {{.*}}-rnglistbase {0x00000043}: DIE has DW_AT_ranges(0x0) attribute, but range extraction failed (invalid range list table index 0), please file a bug and attach the file at the start of this error message
33+
34+
.text
35+
rnglists:
36+
nop
37+
.Lblock1_begin:
38+
lookup_rnglists:
39+
nop
40+
.Lblock1_end:
41+
nop
42+
.Lrnglists_end:
43+
44+
.section .debug_abbrev,"",@progbits
45+
.byte 1 # Abbreviation Code
46+
.byte 17 # DW_TAG_compile_unit
47+
.byte 1 # DW_CHILDREN_yes
48+
.byte 37 # DW_AT_producer
49+
.byte 8 # DW_FORM_string
50+
.byte 17 # DW_AT_low_pc
51+
.byte 27 # DW_FORM_addrx
52+
.byte 18 # DW_AT_high_pc
53+
.byte 6 # DW_FORM_data4
54+
.byte 115 # DW_AT_addr_base
55+
.byte 23 # DW_FORM_sec_offset
56+
.ifdef RNGLISTBASE
57+
.byte 0x74 # DW_AT_rnglists_base
58+
.byte 23 # DW_FORM_sec_offset
59+
.endif
60+
.byte 0 # EOM(1)
61+
.byte 0 # EOM(2)
62+
.byte 2 # Abbreviation Code
63+
.byte 46 # DW_TAG_subprogram
64+
.byte 1 # DW_CHILDREN_yes
65+
.byte 17 # DW_AT_low_pc
66+
.byte 1 # DW_FORM_addr
67+
.byte 18 # DW_AT_high_pc
68+
.byte 6 # DW_FORM_data4
69+
.byte 3 # DW_AT_name
70+
.byte 8 # DW_FORM_string
71+
.byte 0 # EOM(1)
72+
.byte 0 # EOM(2)
73+
.byte 5 # Abbreviation Code
74+
.byte 11 # DW_TAG_lexical_block
75+
.byte 0 # DW_CHILDREN_no
76+
.byte 85 # DW_AT_ranges
77+
.ifndef RNGLISTX
78+
.byte 0x17 # DW_FORM_sec_offset
79+
.else
80+
.byte 0x23 # DW_FORM_rnglistx
81+
.endif
82+
.byte 0 # EOM(1)
83+
.byte 0 # EOM(2)
84+
.byte 0 # EOM(3)
85+
86+
.section .debug_info,"",@progbits
87+
.Lcu_begin0:
88+
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
89+
.Ldebug_info_start0:
90+
.short 5 # DWARF version number
91+
.byte 1 # DWARF Unit Type
92+
.byte 8 # Address Size (in bytes)
93+
.long .debug_abbrev # Offset Into Abbrev. Section
94+
.byte 1 # Abbrev [1] 0xc:0x5f DW_TAG_compile_unit
95+
.asciz "Hand-written DWARF" # DW_AT_producer
96+
.byte 0 # DW_AT_low_pc
97+
.long .Lrnglists_end-rnglists # DW_AT_high_pc
98+
.long .Laddr_table_base0 # DW_AT_addr_base
99+
.ifdef RNGLISTBASE
100+
.long .Ldebug_ranges0 # DW_AT_rnglists_base
101+
.endif
102+
.byte 2 # Abbrev [2] 0x2b:0x37 DW_TAG_subprogram
103+
.quad rnglists # DW_AT_low_pc
104+
.long .Lrnglists_end-rnglists # DW_AT_high_pc
105+
.asciz "rnglists" # DW_AT_name
106+
.byte 5 # Abbrev [5] 0x52:0xf DW_TAG_lexical_block
107+
.ifndef RNGLISTX
108+
.long .Ldebug_ranges0 # DW_AT_ranges DW_FORM_sec_offset
109+
.else
110+
.uleb128 0 # DW_AT_ranges DW_FORM_rnglistx
111+
.endif
112+
.byte 0 # End Of Children Mark
113+
.byte 0 # End Of Children Mark
114+
.Ldebug_info_end0:
115+
116+
.section .debug_addr,"",@progbits
117+
.long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
118+
.Ldebug_addr_start0:
119+
.short 5 # DWARF version number
120+
.byte 8 # Address size
121+
.byte 0 # Segment selector size
122+
.Laddr_table_base0:
123+
.quad rnglists
124+
.Ldebug_addr_end0:
125+
126+
.section .debug_rnglists,"",@progbits
127+
.long .Ldebug_rnglist_table_end0-.Ldebug_rnglist_table_start0 # Length
128+
.Ldebug_rnglist_table_start0:
129+
.short 5 # Version
130+
.byte 8 # Address size
131+
.byte 0 # Segment selector size
132+
.long 0 # Offset entry count
133+
.Ldebug_ranges0:
134+
.byte 4 # DW_RLE_offset_pair
135+
.uleb128 .Lblock1_begin-rnglists # starting offset
136+
.uleb128 .Lblock1_end-rnglists # ending offset
137+
.byte 0 # DW_RLE_end_of_list
138+
.Ldebug_rnglist_table_end0:

0 commit comments

Comments
 (0)