Skip to content

Commit e1f8c8a

Browse files
committed
DWARFDebugLoclists: Move to a incremental parsing model
Summary: This patch stems from the discussion D68270 (including some offline talks). The idea is to provide an "incremental" api for parsing ___location lists, which will avoid caching or materializing parsed data. An additional goal is to provide a high level ___location list api, which abstracts the differences between different encoding schemes, and can be used by users which don't care about those (such as LLDB). This patch implements the first part. It implements a call-back based "visitLocationList" api. This function parses a single ___location list, calling a user-specified callback for each entry. This is going to be the base api, which other ___location list functions (right now, just the dumping code) are going to be based on. Future patches will do something similar for the v4 ___location lists, and add a mechanism to translate raw entries into concrete address ranges. Reviewers: dblaikie, probinson, JDevlieghere, aprantl, SouraVX Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D69672
1 parent bde3293 commit e1f8c8a

File tree

11 files changed

+184
-193
lines changed

11 files changed

+184
-193
lines changed

llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ class DWARFContext : public DIContext {
7575

7676
DWARFUnitVector DWOUnits;
7777
std::unique_ptr<DWARFDebugAbbrev> AbbrevDWO;
78-
std::unique_ptr<DWARFDebugLoclists> LocDWO;
7978

8079
/// The maximum DWARF version of all units.
8180
unsigned MaxVersion = 0;
@@ -260,9 +259,6 @@ class DWARFContext : public DIContext {
260259
/// Get a pointer to the parsed dwo abbreviations object.
261260
const DWARFDebugAbbrev *getDebugAbbrevDWO();
262261

263-
/// Get a pointer to the parsed DebugLoc object.
264-
const DWARFDebugLoclists *getDebugLocDWO();
265-
266262
/// Get a pointer to the parsed DebugAranges object.
267263
const DWARFDebugAranges *getDebugAranges();
268264

llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ class DWARFDebugLoc {
7676

7777
class DWARFDebugLoclists {
7878
public:
79+
// Unconstructible.
80+
DWARFDebugLoclists() = delete;
81+
7982
struct Entry {
8083
uint8_t Kind;
8184
uint64_t Offset;
@@ -87,35 +90,30 @@ class DWARFDebugLoclists {
8790
DIDumpOptions DumpOpts, unsigned Indent, size_t MaxEncodingStringLength) const;
8891
};
8992

90-
struct LocationList {
91-
uint64_t Offset;
92-
SmallVector<Entry, 2> Entries;
93-
void dump(raw_ostream &OS, uint64_t BaseAddr, bool IsLittleEndian,
94-
unsigned AddressSize, const MCRegisterInfo *RegInfo,
95-
DWARFUnit *U, DIDumpOptions DumpOpts, unsigned Indent) const;
96-
};
97-
98-
private:
99-
using LocationLists = SmallVector<LocationList, 4>;
100-
101-
LocationLists Locations;
102-
103-
unsigned AddressSize;
104-
105-
bool IsLittleEndian;
106-
107-
public:
108-
void parse(const DWARFDataExtractor &data, uint64_t Offset,
109-
uint64_t EndOffset, uint16_t Version);
110-
void dump(raw_ostream &OS, uint64_t BaseAddr, const MCRegisterInfo *RegInfo,
111-
DIDumpOptions DumpOpts, Optional<uint64_t> Offset) const;
112-
113-
/// Return the ___location list at the given offset or nullptr.
114-
LocationList const *getLocationListAtOffset(uint64_t Offset) const;
115-
116-
static Expected<LocationList>
117-
parseOneLocationList(const DWARFDataExtractor &Data, uint64_t *Offset,
118-
unsigned Version);
93+
/// Call the user-provided callback for each entry (including the end-of-list
94+
/// entry) in the ___location list starting at \p Offset. The callback can return
95+
/// false to terminate the iteration early. Returns an error if it was unable
96+
/// to parse the entire ___location list correctly. Upon successful termination
97+
/// \p Offset will be updated point past the end of the list.
98+
static Error visitLocationList(const DWARFDataExtractor &Data,
99+
uint64_t *Offset, uint16_t Version,
100+
llvm::function_ref<bool(const Entry &)> F);
101+
102+
/// Dump the ___location list at the given \p Offset. The function returns true
103+
/// iff it has successfully reched the end of the list. This means that one
104+
/// can attempt to parse another list after the current one (\p Offset will be
105+
/// updated to point past the end of the current list).
106+
static bool dumpLocationList(const DWARFDataExtractor &Data, uint64_t *Offset,
107+
uint16_t Version, raw_ostream &OS,
108+
uint64_t BaseAddr, const MCRegisterInfo *MRI,
109+
DWARFUnit *U, DIDumpOptions DumpOpts,
110+
unsigned Indent);
111+
112+
/// Dump all ___location lists within the given range.
113+
static void dumpRange(const DWARFDataExtractor &Data, uint64_t StartOffset,
114+
uint64_t Size, uint16_t Version, raw_ostream &OS,
115+
uint64_t BaseAddr, const MCRegisterInfo *MRI,
116+
DIDumpOptions DumpOpts);
119117
};
120118

121119
} // end namespace llvm

llvm/lib/DebugInfo/DWARF/DWARFContext.cpp

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -300,11 +300,21 @@ static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts,
300300

301301
Header.dump(OS, DumpOpts);
302302

303-
DWARFDebugLoclists Loclists;
304303
uint64_t EndOffset = Header.length() + Header.getHeaderOffset();
305304
Data.setAddressSize(Header.getAddrSize());
306-
Loclists.parse(Data, Offset, EndOffset, Header.getVersion());
307-
Loclists.dump(OS, 0, MRI, DumpOpts, DumpOffset);
305+
if (DumpOffset) {
306+
if (DumpOffset >= Offset && DumpOffset < EndOffset) {
307+
Offset = *DumpOffset;
308+
DWARFDebugLoclists::dumpLocationList(Data, &Offset, Header.getVersion(),
309+
OS, /*BaseAddr=*/0, MRI, nullptr,
310+
DumpOpts, /*Indent=*/0);
311+
OS << "\n";
312+
return;
313+
}
314+
} else {
315+
DWARFDebugLoclists::dumpRange(Data, Offset, EndOffset - Offset,
316+
Header.getVersion(), OS, 0, MRI, DumpOpts);
317+
}
308318
Offset = EndOffset;
309319
}
310320
}
@@ -393,7 +403,19 @@ void DWARFContext::dump(
393403
if (const auto *Off =
394404
shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc,
395405
DObj->getLocDWOSection().Data)) {
396-
getDebugLocDWO()->dump(OS, 0, getRegisterInfo(), DumpOpts, *Off);
406+
DWARFDataExtractor Data(*DObj, DObj->getLocDWOSection(), isLittleEndian(),
407+
4);
408+
if (*Off) {
409+
uint64_t Offset = **Off;
410+
DWARFDebugLoclists::dumpLocationList(Data, &Offset, /*Version=*/4, OS,
411+
/*BaseAddr=*/0, getRegisterInfo(),
412+
nullptr, DumpOpts, /*Indent=*/0);
413+
OS << "\n";
414+
} else {
415+
DWARFDebugLoclists::dumpRange(Data, 0, Data.getData().size(),
416+
/*Version=*/4, OS, /*BaseAddr=*/0,
417+
getRegisterInfo(), DumpOpts);
418+
}
397419
}
398420

399421
if (const auto *Off = shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
@@ -724,23 +746,6 @@ const DWARFDebugLoc *DWARFContext::getDebugLoc() {
724746
return Loc.get();
725747
}
726748

727-
const DWARFDebugLoclists *DWARFContext::getDebugLocDWO() {
728-
if (LocDWO)
729-
return LocDWO.get();
730-
731-
LocDWO.reset(new DWARFDebugLoclists());
732-
// Assume all compile units have the same address byte size.
733-
// FIXME: We don't need AddressSize for split DWARF since relocatable
734-
// addresses cannot appear there. At the moment DWARFExpression requires it.
735-
DWARFDataExtractor LocData(*DObj, DObj->getLocDWOSection(), isLittleEndian(),
736-
4);
737-
// Use version 4. DWO does not support the DWARF v5 .debug_loclists yet and
738-
// that means we are parsing the new style .debug_loc (pre-standatized version
739-
// of the .debug_loclists).
740-
LocDWO->parse(LocData, 0, LocData.getData().size(), 4 /* Version */);
741-
return LocDWO.get();
742-
}
743-
744749
const DWARFDebugAranges *DWARFContext::getDebugAranges() {
745750
if (Aranges)
746751
return Aranges.get();

llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp

Lines changed: 68 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -139,19 +139,19 @@ void DWARFDebugLoc::parse(const DWARFDataExtractor &data) {
139139
}
140140
}
141141

142-
Expected<DWARFDebugLoclists::LocationList>
143-
DWARFDebugLoclists::parseOneLocationList(const DWARFDataExtractor &Data,
144-
uint64_t *Offset, unsigned Version) {
145-
LocationList LL;
146-
LL.Offset = *Offset;
147-
DataExtractor::Cursor C(*Offset);
142+
Error DWARFDebugLoclists::visitLocationList(
143+
const DWARFDataExtractor &Data, uint64_t *Offset, uint16_t Version,
144+
llvm::function_ref<bool(const Entry &)> F) {
148145

149-
// dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list.
150-
while (auto Kind = Data.getU8(C)) {
146+
DataExtractor::Cursor C(*Offset);
147+
bool Continue = true;
148+
while (Continue) {
151149
Entry E;
152-
E.Kind = Kind;
153-
E.Offset = C.tell() - 1;
154-
switch (Kind) {
150+
E.Offset = C.tell();
151+
E.Kind = Data.getU8(C);
152+
switch (E.Kind) {
153+
case dwarf::DW_LLE_end_of_list:
154+
break;
155155
case dwarf::DW_LLE_base_addressx:
156156
E.Value0 = Data.getULEB128(C);
157157
break;
@@ -164,64 +164,69 @@ DWARFDebugLoclists::parseOneLocationList(const DWARFDataExtractor &Data,
164164
else
165165
E.Value1 = Data.getULEB128(C);
166166
break;
167-
case dwarf::DW_LLE_start_length:
168-
E.Value0 = Data.getRelocatedAddress(C);
169-
E.Value1 = Data.getULEB128(C);
170-
break;
171167
case dwarf::DW_LLE_offset_pair:
172168
E.Value0 = Data.getULEB128(C);
173169
E.Value1 = Data.getULEB128(C);
174170
break;
175171
case dwarf::DW_LLE_base_address:
176172
E.Value0 = Data.getRelocatedAddress(C);
177173
break;
174+
case dwarf::DW_LLE_start_length:
175+
E.Value0 = Data.getRelocatedAddress(C);
176+
E.Value1 = Data.getULEB128(C);
177+
break;
178+
case dwarf::DW_LLE_startx_endx:
179+
case dwarf::DW_LLE_default_location:
180+
case dwarf::DW_LLE_start_end:
178181
default:
179182
cantFail(C.takeError());
180183
return createStringError(errc::illegal_byte_sequence,
181-
"LLE of kind %x not supported", (int)Kind);
184+
"LLE of kind %x not supported", (int)E.Kind);
182185
}
183186

184-
if (Kind != dwarf::DW_LLE_base_address &&
185-
Kind != dwarf::DW_LLE_base_addressx) {
187+
if (E.Kind != dwarf::DW_LLE_base_address &&
188+
E.Kind != dwarf::DW_LLE_base_addressx &&
189+
E.Kind != dwarf::DW_LLE_end_of_list) {
186190
unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C);
187191
// A single ___location description describing the ___location of the object...
188192
Data.getU8(C, E.Loc, Bytes);
189193
}
190194

191-
LL.Entries.push_back(std::move(E));
195+
if (!C)
196+
return C.takeError();
197+
Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list;
192198
}
193-
if (Error Err = C.takeError())
194-
return std::move(Err);
195-
Entry E;
196-
E.Kind = dwarf::DW_LLE_end_of_list;
197-
E.Offset = C.tell() - 1;
198-
LL.Entries.push_back(E);
199199
*Offset = C.tell();
200-
return LL;
200+
return Error::success();
201201
}
202202

203-
void DWARFDebugLoclists::parse(const DWARFDataExtractor &data, uint64_t Offset,
204-
uint64_t EndOffset, uint16_t Version) {
205-
IsLittleEndian = data.isLittleEndian();
206-
AddressSize = data.getAddressSize();
207-
208-
while (Offset < EndOffset) {
209-
if (auto LL = parseOneLocationList(data, &Offset, Version))
210-
Locations.push_back(std::move(*LL));
211-
else {
212-
logAllUnhandledErrors(LL.takeError(), WithColor::error());
213-
return;
214-
}
203+
bool DWARFDebugLoclists::dumpLocationList(const DWARFDataExtractor &Data,
204+
uint64_t *Offset, uint16_t Version,
205+
raw_ostream &OS, uint64_t BaseAddr,
206+
const MCRegisterInfo *MRI,
207+
DWARFUnit *U, DIDumpOptions DumpOpts,
208+
unsigned Indent) {
209+
size_t MaxEncodingStringLength = 0;
210+
if (DumpOpts.Verbose) {
211+
#define HANDLE_DW_LLE(ID, NAME) \
212+
MaxEncodingStringLength = std::max(MaxEncodingStringLength, \
213+
dwarf::LocListEncodingString(ID).size());
214+
#include "llvm/BinaryFormat/Dwarf.def"
215215
}
216-
}
217216

218-
DWARFDebugLoclists::LocationList const *
219-
DWARFDebugLoclists::getLocationListAtOffset(uint64_t Offset) const {
220-
auto It = partition_point(
221-
Locations, [=](const LocationList &L) { return L.Offset < Offset; });
222-
if (It != Locations.end() && It->Offset == Offset)
223-
return &(*It);
224-
return nullptr;
217+
OS << format("0x%8.8" PRIx64 ": ", *Offset);
218+
Error E = visitLocationList(Data, Offset, Version, [&](const Entry &E) {
219+
E.dump(OS, BaseAddr, Data.isLittleEndian(), Data.getAddressSize(), MRI, U,
220+
DumpOpts, Indent, MaxEncodingStringLength);
221+
return true;
222+
});
223+
if (E) {
224+
OS << "\n";
225+
OS.indent(Indent);
226+
OS << "error: " << toString(std::move(E));
227+
return false;
228+
}
229+
return true;
225230
}
226231

227232
void DWARFDebugLoclists::Entry::dump(raw_ostream &OS, uint64_t &BaseAddr,
@@ -297,44 +302,25 @@ void DWARFDebugLoclists::Entry::dump(raw_ostream &OS, uint64_t &BaseAddr,
297302

298303
dumpExpression(OS, Loc, IsLittleEndian, AddressSize, MRI, U);
299304
}
300-
void DWARFDebugLoclists::LocationList::dump(raw_ostream &OS, uint64_t BaseAddr,
301-
bool IsLittleEndian,
302-
unsigned AddressSize,
303-
const MCRegisterInfo *MRI,
304-
DWARFUnit *U,
305-
DIDumpOptions DumpOpts,
306-
unsigned Indent) const {
307-
size_t MaxEncodingStringLength = 0;
308-
if (DumpOpts.Verbose)
309-
for (const auto &Entry : Entries)
310-
MaxEncodingStringLength =
311-
std::max(MaxEncodingStringLength,
312-
dwarf::LocListEncodingString(Entry.Kind).size());
313-
314-
for (const Entry &E : Entries)
315-
E.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, U, DumpOpts, Indent,
316-
MaxEncodingStringLength);
317-
}
318-
319-
void DWARFDebugLoclists::dump(raw_ostream &OS, uint64_t BaseAddr,
320-
const MCRegisterInfo *MRI, DIDumpOptions DumpOpts,
321-
Optional<uint64_t> Offset) const {
322-
auto DumpLocationList = [&](const LocationList &L) {
323-
OS << format("0x%8.8" PRIx64 ": ", L.Offset);
324-
L.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, nullptr, DumpOpts,
325-
/*Indent=*/12);
326-
OS << "\n";
327-
};
328305

329-
if (Offset) {
330-
if (auto *L = getLocationListAtOffset(*Offset))
331-
DumpLocationList(*L);
306+
void DWARFDebugLoclists::dumpRange(const DWARFDataExtractor &Data,
307+
uint64_t StartOffset, uint64_t Size,
308+
uint16_t Version, raw_ostream &OS,
309+
uint64_t BaseAddr, const MCRegisterInfo *MRI,
310+
DIDumpOptions DumpOpts) {
311+
if (!Data.isValidOffsetForDataOfSize(StartOffset, Size)) {
312+
OS << "Invalid dump range\n";
332313
return;
333314
}
334-
335-
for (const LocationList &L : Locations) {
336-
DumpLocationList(L);
337-
if (&L != &Locations.back())
338-
OS << '\n';
315+
uint64_t Offset = StartOffset;
316+
StringRef Separator;
317+
bool CanContinue = true;
318+
while (CanContinue && Offset < StartOffset + Size) {
319+
OS << Separator;
320+
Separator = "\n";
321+
322+
CanContinue = dumpLocationList(Data, &Offset, Version, OS, BaseAddr, MRI,
323+
nullptr, DumpOpts, /*Indent=*/12);
324+
OS << '\n';
339325
}
340326
}

0 commit comments

Comments
 (0)