Skip to content

Commit f69f923

Browse files
committed
[lldb/DWARF] Fix DW_AT_addr_base & DW_AT_low_pc interaction
In DWARF5 DW_AT_low_pc (and DW_AT_entry_pc, and possibly others) can use DW_FORM_addrx to refer to the address indirectly. This means we need to have processed the DW_AT_addr_base attribute before we can do anything with these. Since we were processing the unit attributes serially, this created a problem in cases where the DW_AT_addr_base comes after DW_AT_low_pc -- we would end up computing the wrong unit base address, which also corrupted any values which later depended on that (for instance range lists). Clang currently always emits DW_AT_addr_base last. The fix is simple -- process DW_AT_addr_base first, regardless of its position in the attribute list.
1 parent b6e2cf3 commit f69f923

File tree

2 files changed

+119
-4
lines changed

2 files changed

+119
-4
lines changed

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,16 +287,25 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
287287

288288
DWARFAttributes attributes;
289289
size_t num_attributes = cu_die.GetAttributes(this, attributes);
290+
291+
// Extract DW_AT_addr_base first, as other attributes may need it.
292+
for (size_t i = 0; i < num_attributes; ++i) {
293+
if (attributes.AttributeAtIndex(i) != DW_AT_addr_base)
294+
continue;
295+
DWARFFormValue form_value;
296+
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
297+
addr_base = form_value.Unsigned();
298+
SetAddrBase(*addr_base);
299+
break;
300+
}
301+
}
302+
290303
for (size_t i = 0; i < num_attributes; ++i) {
291304
dw_attr_t attr = attributes.AttributeAtIndex(i);
292305
DWARFFormValue form_value;
293306
if (!attributes.ExtractFormValueAtIndex(i, form_value))
294307
continue;
295308
switch (attr) {
296-
case DW_AT_addr_base:
297-
addr_base = form_value.Unsigned();
298-
SetAddrBase(*addr_base);
299-
break;
300309
case DW_AT_rnglists_base:
301310
ranges_base = form_value.Unsigned();
302311
SetRangesBase(*ranges_base);
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# REQUIRES: x86
2+
3+
# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj %s > %t
4+
# RUN: %lldb %t -o "image lookup -v -s lookup_rnglists" \
5+
# RUN: -o exit | FileCheck %s
6+
7+
# CHECK-LABEL: image lookup -v -s lookup_rnglists
8+
# CHECK: Function: id = {0x7fffffff0000002d}, name = "rnglists", range = [0x0000000000000000-0x0000000000000003)
9+
# CHECK: Blocks: id = {0x7fffffff0000002d}, range = [0x00000000-0x00000003)
10+
# CHECK-NEXT: id = {0x7fffffff00000043}, range = [0x00000001-0x00000002)
11+
12+
.text
13+
rnglists:
14+
nop
15+
.Lblock1_begin:
16+
lookup_rnglists:
17+
nop
18+
.Lblock1_end:
19+
nop
20+
.Lrnglists_end:
21+
22+
.section .debug_abbrev,"",@progbits
23+
.byte 1 # Abbreviation Code
24+
.byte 17 # DW_TAG_compile_unit
25+
.byte 1 # DW_CHILDREN_yes
26+
.byte 37 # DW_AT_producer
27+
.byte 8 # DW_FORM_string
28+
.byte 17 # DW_AT_low_pc
29+
.byte 27 # DW_FORM_addrx
30+
.byte 18 # DW_AT_high_pc
31+
.byte 6 # DW_FORM_data4
32+
.byte 116 # DW_AT_rnglists_base
33+
.byte 23 # DW_FORM_sec_offset
34+
.byte 115 # DW_AT_addr_base
35+
.byte 23 # DW_FORM_sec_offset
36+
.byte 0 # EOM(1)
37+
.byte 0 # EOM(2)
38+
.byte 2 # Abbreviation Code
39+
.byte 46 # DW_TAG_subprogram
40+
.byte 1 # DW_CHILDREN_yes
41+
.byte 17 # DW_AT_low_pc
42+
.byte 1 # DW_FORM_addr
43+
.byte 18 # DW_AT_high_pc
44+
.byte 6 # DW_FORM_data4
45+
.byte 3 # DW_AT_name
46+
.byte 8 # DW_FORM_string
47+
.byte 0 # EOM(1)
48+
.byte 0 # EOM(2)
49+
.byte 5 # Abbreviation Code
50+
.byte 11 # DW_TAG_lexical_block
51+
.byte 0 # DW_CHILDREN_no
52+
.byte 85 # DW_AT_ranges
53+
.byte 35 # DW_FORM_rnglistx
54+
.byte 0 # EOM(1)
55+
.byte 0 # EOM(2)
56+
.byte 0 # EOM(3)
57+
58+
.section .debug_info,"",@progbits
59+
.Lcu_begin0:
60+
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
61+
.Ldebug_info_start0:
62+
.short 5 # DWARF version number
63+
.byte 1 # DWARF Unit Type
64+
.byte 8 # Address Size (in bytes)
65+
.long .debug_abbrev # Offset Into Abbrev. Section
66+
.byte 1 # Abbrev [1] 0xc:0x5f DW_TAG_compile_unit
67+
.asciz "Hand-written DWARF" # DW_AT_producer
68+
.byte 0 # DW_AT_low_pc
69+
.long .Lrnglists_end-rnglists # DW_AT_high_pc
70+
.long .Lrnglists_table_base0 # DW_AT_rnglists_base
71+
.long .Laddr_table_base0 # DW_AT_addr_base
72+
.byte 2 # Abbrev [2] 0x2b:0x37 DW_TAG_subprogram
73+
.quad rnglists # DW_AT_low_pc
74+
.long .Lrnglists_end-rnglists # DW_AT_high_pc
75+
.asciz "rnglists" # DW_AT_name
76+
.byte 5 # Abbrev [5] 0x52:0xf DW_TAG_lexical_block
77+
.byte 0 # DW_AT_ranges
78+
.byte 0 # End Of Children Mark
79+
.byte 0 # End Of Children Mark
80+
.Ldebug_info_end0:
81+
82+
.section .debug_addr,"",@progbits
83+
.long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
84+
.Ldebug_addr_start0:
85+
.short 5 # DWARF version number
86+
.byte 8 # Address size
87+
.byte 0 # Segment selector size
88+
.Laddr_table_base0:
89+
.quad rnglists
90+
.Ldebug_addr_end0:
91+
92+
.section .debug_rnglists,"",@progbits
93+
.long .Ldebug_rnglist_table_end0-.Ldebug_rnglist_table_start0 # Length
94+
.Ldebug_rnglist_table_start0:
95+
.short 5 # Version
96+
.byte 8 # Address size
97+
.byte 0 # Segment selector size
98+
.long 1 # Offset entry count
99+
.Lrnglists_table_base0:
100+
.long .Ldebug_ranges0-.Lrnglists_table_base0
101+
.Ldebug_ranges0:
102+
.byte 4 # DW_RLE_offset_pair
103+
.uleb128 .Lblock1_begin-rnglists # starting offset
104+
.uleb128 .Lblock1_end-rnglists # ending offset
105+
.byte 0 # DW_RLE_end_of_list
106+
.Ldebug_rnglist_table_end0:

0 commit comments

Comments
 (0)