Skip to content

Commit c8b74ee

Browse files
committed
[lldb/DWARF] Add support for DW_AT_loclists_base&DW_FORM_loclistx
Summary: This adds support for DWARF5 location lists which are specified indirectly, via an index into the debug_loclists offset table. This includes parsing the DW_AT_loclists_base attribute which determines the location of this offset table, and support for new form DW_FORM_loclistx which is used in conjuction with DW_AT_location to refer to the location lists in this way. The code uses the llvm class to parse the offset information, and I've also tried to structure it similarly to how the relevant llvm functionality works. Reviewers: JDevlieghere, aprantl, clayborg Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D71268
1 parent 4682208 commit c8b74ee

File tree

6 files changed

+174
-3
lines changed

6 files changed

+174
-3
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data,
156156

157157
// signed or unsigned LEB 128 values
158158
case DW_FORM_addrx:
159+
case DW_FORM_loclistx:
159160
case DW_FORM_rnglistx:
160161
case DW_FORM_sdata:
161162
case DW_FORM_udata:

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data,
107107
m_value.value.uval = data.GetU64(offset_ptr);
108108
break;
109109
case DW_FORM_addrx:
110+
case DW_FORM_loclistx:
110111
case DW_FORM_rnglistx:
111112
case DW_FORM_strx:
112113
case DW_FORM_udata:
@@ -305,6 +306,7 @@ bool DWARFFormValue::SkipValue(dw_form_t form,
305306

306307
// signed or unsigned LEB 128 values
307308
case DW_FORM_addrx:
309+
case DW_FORM_loclistx:
308310
case DW_FORM_rnglistx:
309311
case DW_FORM_sdata:
310312
case DW_FORM_udata:
@@ -699,6 +701,7 @@ bool DWARFFormValue::FormIsSupported(dw_form_t form) {
699701
switch (form) {
700702
case DW_FORM_addr:
701703
case DW_FORM_addrx:
704+
case DW_FORM_loclistx:
702705
case DW_FORM_rnglistx:
703706
case DW_FORM_block2:
704707
case DW_FORM_block4:

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
306306
if (!attributes.ExtractFormValueAtIndex(i, form_value))
307307
continue;
308308
switch (attr) {
309+
case DW_AT_loclists_base:
310+
SetLoclistsBase(form_value.Unsigned());
311+
break;
309312
case DW_AT_rnglists_base:
310313
ranges_base = form_value.Unsigned();
311314
SetRangesBase(*ranges_base);
@@ -452,6 +455,23 @@ ParseListTableHeader(const llvm::DWARFDataExtractor &data, uint64_t offset,
452455
return Table;
453456
}
454457

458+
void DWARFUnit::SetLoclistsBase(dw_addr_t loclists_base) {
459+
m_loclists_base = loclists_base;
460+
461+
uint64_t header_size = llvm::DWARFListTableHeader::getHeaderSize(DWARF32);
462+
if (loclists_base < header_size)
463+
return;
464+
465+
m_loclist_table_header.emplace(".debug_loclists", "locations");
466+
uint64_t offset = loclists_base - header_size;
467+
if (llvm::Error E = m_loclist_table_header->extract(
468+
m_dwarf.get_debug_loclists_data().GetAsLLVM(), &offset)) {
469+
GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
470+
"Failed to extract location list table at offset 0x%" PRIx64 ": %s",
471+
loclists_base, toString(std::move(E)).c_str());
472+
}
473+
}
474+
455475
void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) {
456476
m_ranges_base = ranges_base;
457477

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class DWARFUnit : public lldb_private::UserID {
147147
dw_addr_t GetRangesBase() const { return m_ranges_base; }
148148
dw_addr_t GetStrOffsetsBase() const { return m_str_offsets_base; }
149149
void SetAddrBase(dw_addr_t addr_base);
150+
void SetLoclistsBase(dw_addr_t loclists_base);
150151
void SetRangesBase(dw_addr_t ranges_base);
151152
void SetStrOffsetsBase(dw_offset_t str_offsets_base);
152153
virtual void BuildAddressRangeTable(DWARFDebugAranges *debug_aranges) = 0;
@@ -234,6 +235,16 @@ class DWARFUnit : public lldb_private::UserID {
234235
return llvm::None;
235236
}
236237

238+
llvm::Optional<uint64_t> GetLoclistOffset(uint32_t Index) {
239+
if (!m_loclist_table_header)
240+
return llvm::None;
241+
242+
llvm::Optional<uint64_t> Offset = m_loclist_table_header->getOffsetEntry(Index);
243+
if (!Offset)
244+
return llvm::None;
245+
return *Offset + m_loclists_base;
246+
}
247+
237248
protected:
238249
DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid,
239250
const DWARFUnitHeader &header,
@@ -292,15 +303,17 @@ class DWARFUnit : public lldb_private::UserID {
292303
lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate;
293304
llvm::Optional<lldb_private::FileSpec> m_comp_dir;
294305
llvm::Optional<lldb_private::FileSpec> m_file_spec;
295-
dw_addr_t m_addr_base = 0; // Value of DW_AT_addr_base
296-
dw_addr_t m_ranges_base = 0; // Value of DW_AT_ranges_base
306+
dw_addr_t m_addr_base = 0; ///< Value of DW_AT_addr_base.
307+
dw_addr_t m_loclists_base = 0; ///< Value of DW_AT_loclists_base.
308+
dw_addr_t m_ranges_base = 0; ///< Value of DW_AT_rnglists_base.
297309

298310
/// Value of DW_AT_stmt_list.
299311
dw_offset_t m_line_table_offset = DW_INVALID_OFFSET;
300312

301313
dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base.
302314

303315
llvm::Optional<llvm::DWARFDebugRnglistTable> m_rnglist_table;
316+
llvm::Optional<llvm::DWARFListTableHeader> m_loclist_table_header;
304317

305318
const DIERef::Section m_section;
306319

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3357,7 +3357,9 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
33573357
die.GetCU());
33583358
} else {
33593359
DataExtractor data = DebugLocData();
3360-
const dw_offset_t offset = form_value.Unsigned();
3360+
dw_offset_t offset = form_value.Unsigned();
3361+
if (form_value.Form() == DW_FORM_loclistx)
3362+
offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1);
33613363
if (data.ValidOffset(offset)) {
33623364
data = DataExtractor(data, offset, data.GetByteSize() - offset);
33633365
location = DWARFExpression(module, data, die.GetCU());
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
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_loclists" -o exit | FileCheck %s
5+
6+
# CHECK-LABEL: image lookup -v -s lookup_loclists
7+
# CHECK: Variable: {{.*}}, name = "x0", type = "int", location = DW_OP_reg0 RAX,
8+
# CHECK: Variable: {{.*}}, name = "x1", type = "int", location = ,
9+
10+
loclists:
11+
nop
12+
.Ltmp0:
13+
nop
14+
lookup_loclists:
15+
.Ltmp1:
16+
nop
17+
.Ltmp2:
18+
nop
19+
.Ltmp3:
20+
nop
21+
.Ltmp4:
22+
nop
23+
.Lloclists_end:
24+
25+
.section .debug_loclists,"",@progbits
26+
.long .Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0 # Length
27+
.Ldebug_loclist_table_start0:
28+
.short 5 # Version
29+
.byte 8 # Address size
30+
.byte 0 # Segment selector size
31+
.long 1 # Offset entry count
32+
.Lloclists_table_base:
33+
.long .Ldebug_loc0-.Lloclists_table_base
34+
.long .Ldebug_loc1-.Lloclists_table_base
35+
.Ldebug_loc0:
36+
.byte 4 # DW_LLE_offset_pair
37+
.uleb128 loclists-loclists
38+
.uleb128 .Ltmp2-loclists
39+
.uleb128 1 # Expression size
40+
.byte 80 # super-register DW_OP_reg0
41+
.byte 0 # DW_LLE_end_of_list
42+
.Ldebug_loc1:
43+
.byte 4 # DW_LLE_offset_pair
44+
.uleb128 .Ltmp3-loclists
45+
.uleb128 .Ltmp4-loclists
46+
.uleb128 1 # Expression size
47+
.byte 81 # super-register DW_OP_reg1
48+
.byte 0 # DW_LLE_end_of_list
49+
.Ldebug_loclist_table_end0:
50+
51+
.section .debug_abbrev,"",@progbits
52+
.byte 1 # Abbreviation Code
53+
.byte 17 # DW_TAG_compile_unit
54+
.byte 1 # DW_CHILDREN_yes
55+
.byte 37 # DW_AT_producer
56+
.byte 8 # DW_FORM_string
57+
.byte 19 # DW_AT_language
58+
.byte 5 # DW_FORM_data2
59+
.uleb128 0x8c # DW_AT_loclists_base
60+
.byte 0x17 # DW_FORM_sec_offset
61+
.byte 0 # EOM(1)
62+
.byte 0 # EOM(2)
63+
.byte 2 # Abbreviation Code
64+
.byte 46 # DW_TAG_subprogram
65+
.byte 1 # DW_CHILDREN_yes
66+
.byte 17 # DW_AT_low_pc
67+
.byte 1 # DW_FORM_addr
68+
.byte 18 # DW_AT_high_pc
69+
.byte 6 # DW_FORM_data4
70+
.byte 3 # DW_AT_name
71+
.byte 8 # DW_FORM_string
72+
.byte 73 # DW_AT_type
73+
.byte 19 # DW_FORM_ref4
74+
.byte 0 # EOM(1)
75+
.byte 0 # EOM(2)
76+
.byte 3 # Abbreviation Code
77+
.byte 5 # DW_TAG_formal_parameter
78+
.byte 0 # DW_CHILDREN_no
79+
.byte 2 # DW_AT_location
80+
.byte 0x22 # DW_FORM_loclistx
81+
.byte 3 # DW_AT_name
82+
.byte 8 # DW_FORM_string
83+
.byte 73 # DW_AT_type
84+
.byte 19 # DW_FORM_ref4
85+
.byte 0 # EOM(1)
86+
.byte 0 # EOM(2)
87+
.byte 4 # Abbreviation Code
88+
.byte 36 # DW_TAG_base_type
89+
.byte 0 # DW_CHILDREN_no
90+
.byte 3 # DW_AT_name
91+
.byte 8 # DW_FORM_string
92+
.byte 62 # DW_AT_encoding
93+
.byte 11 # DW_FORM_data1
94+
.byte 11 # DW_AT_byte_size
95+
.byte 11 # DW_FORM_data1
96+
.byte 0 # EOM(1)
97+
.byte 0 # EOM(2)
98+
.byte 0 # EOM(3)
99+
100+
.section .debug_info,"",@progbits
101+
.Lcu_begin0:
102+
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
103+
.Ldebug_info_start0:
104+
.short 5 # DWARF version number
105+
.byte 1 # DWARF Unit Type
106+
.byte 8 # Address Size (in bytes)
107+
.long .debug_abbrev # Offset Into Abbrev. Section
108+
.byte 1 # Abbrev [1] 0xb:0x50 DW_TAG_compile_unit
109+
.asciz "Hand-written DWARF" # DW_AT_producer
110+
.short 12 # DW_AT_language
111+
.long .Lloclists_table_base # DW_AT_loclists_base
112+
.byte 2 # Abbrev [2] 0x2a:0x29 DW_TAG_subprogram
113+
.quad loclists # DW_AT_low_pc
114+
.long .Lloclists_end-loclists # DW_AT_high_pc
115+
.asciz "loclists" # DW_AT_name
116+
.long .Lint # DW_AT_type
117+
.byte 3 # Abbrev [3] DW_TAG_formal_parameter
118+
.uleb128 0 # DW_AT_location
119+
.asciz "x0" # DW_AT_name
120+
.long .Lint-.Lcu_begin0 # DW_AT_type
121+
.byte 3 # Abbrev [3] DW_TAG_formal_parameter
122+
.uleb128 1 # DW_AT_location
123+
.asciz "x1" # DW_AT_name
124+
.long .Lint-.Lcu_begin0 # DW_AT_type
125+
.byte 0 # End Of Children Mark
126+
.Lint:
127+
.byte 4 # Abbrev [4] 0x53:0x7 DW_TAG_base_type
128+
.asciz "int" # DW_AT_name
129+
.byte 5 # DW_AT_encoding
130+
.byte 4 # DW_AT_byte_size
131+
.byte 0 # End Of Children Mark
132+
.Ldebug_info_end0:

0 commit comments

Comments
 (0)