1 //===- DWARFDebugLoc.cpp --------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/BinaryFormat/Dwarf.h"
12 #include "llvm/DebugInfo/DIContext.h"
13 #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
14 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
15 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
16 #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h"
17 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
18 #include "llvm/Support/Format.h"
19 #include "llvm/Support/raw_ostream.h"
25 using object::SectionedAddress
;
32 class DWARFLocationInterpreter
{
33 std::optional
<object::SectionedAddress
> Base
;
34 std::function
<std::optional
<object::SectionedAddress
>(uint32_t)> LookupAddr
;
37 DWARFLocationInterpreter(
38 std::optional
<object::SectionedAddress
> Base
,
39 std::function
<std::optional
<object::SectionedAddress
>(uint32_t)>
41 : Base(Base
), LookupAddr(std::move(LookupAddr
)) {}
43 Expected
<std::optional
<DWARFLocationExpression
>>
44 Interpret(const DWARFLocationEntry
&E
);
48 static Error
createResolverError(uint32_t Index
, unsigned Kind
) {
49 return make_error
<ResolverError
>(Index
, (dwarf::LoclistEntries
)Kind
);
52 Expected
<std::optional
<DWARFLocationExpression
>>
53 DWARFLocationInterpreter::Interpret(const DWARFLocationEntry
&E
) {
55 case dwarf::DW_LLE_end_of_list
:
57 case dwarf::DW_LLE_base_addressx
: {
58 Base
= LookupAddr(E
.Value0
);
60 return createResolverError(E
.Value0
, E
.Kind
);
63 case dwarf::DW_LLE_startx_endx
: {
64 std::optional
<SectionedAddress
> LowPC
= LookupAddr(E
.Value0
);
66 return createResolverError(E
.Value0
, E
.Kind
);
67 std::optional
<SectionedAddress
> HighPC
= LookupAddr(E
.Value1
);
69 return createResolverError(E
.Value1
, E
.Kind
);
70 return DWARFLocationExpression
{
71 DWARFAddressRange
{LowPC
->Address
, HighPC
->Address
, LowPC
->SectionIndex
},
74 case dwarf::DW_LLE_startx_length
: {
75 std::optional
<SectionedAddress
> LowPC
= LookupAddr(E
.Value0
);
77 return createResolverError(E
.Value0
, E
.Kind
);
78 return DWARFLocationExpression
{DWARFAddressRange
{LowPC
->Address
,
79 LowPC
->Address
+ E
.Value1
,
83 case dwarf::DW_LLE_offset_pair
: {
85 return createStringError(inconvertibleErrorCode(),
86 "Unable to resolve location list offset pair: "
87 "Base address not defined");
89 DWARFAddressRange Range
{Base
->Address
+ E
.Value0
, Base
->Address
+ E
.Value1
,
91 if (Range
.SectionIndex
== SectionedAddress::UndefSection
)
92 Range
.SectionIndex
= E
.SectionIndex
;
93 return DWARFLocationExpression
{Range
, E
.Loc
};
95 case dwarf::DW_LLE_default_location
:
96 return DWARFLocationExpression
{std::nullopt
, E
.Loc
};
97 case dwarf::DW_LLE_base_address
:
98 Base
= SectionedAddress
{E
.Value0
, E
.SectionIndex
};
100 case dwarf::DW_LLE_start_end
:
101 return DWARFLocationExpression
{
102 DWARFAddressRange
{E
.Value0
, E
.Value1
, E
.SectionIndex
}, E
.Loc
};
103 case dwarf::DW_LLE_start_length
:
104 return DWARFLocationExpression
{
105 DWARFAddressRange
{E
.Value0
, E
.Value0
+ E
.Value1
, E
.SectionIndex
},
108 llvm_unreachable("unreachable locations list kind");
112 static void dumpExpression(raw_ostream
&OS
, DIDumpOptions DumpOpts
,
113 ArrayRef
<uint8_t> Data
, bool IsLittleEndian
,
114 unsigned AddressSize
, DWARFUnit
*U
) {
115 DWARFDataExtractor
Extractor(Data
, IsLittleEndian
, AddressSize
);
116 // Note. We do not pass any format to DWARFExpression, even if the
117 // corresponding unit is known. For now, there is only one operation,
118 // DW_OP_call_ref, which depends on the format; it is rarely used, and
119 // is unexpected in location tables.
120 DWARFExpression(Extractor
, AddressSize
).print(OS
, DumpOpts
, U
);
123 bool DWARFLocationTable::dumpLocationList(
124 uint64_t *Offset
, raw_ostream
&OS
, std::optional
<SectionedAddress
> BaseAddr
,
125 const DWARFObject
&Obj
, DWARFUnit
*U
, DIDumpOptions DumpOpts
,
126 unsigned Indent
) const {
127 DWARFLocationInterpreter
Interp(
128 BaseAddr
, [U
](uint32_t Index
) -> std::optional
<SectionedAddress
> {
130 return U
->getAddrOffsetSectionItem(Index
);
133 OS
<< format("0x%8.8" PRIx64
": ", *Offset
);
134 Error E
= visitLocationList(Offset
, [&](const DWARFLocationEntry
&E
) {
135 Expected
<std::optional
<DWARFLocationExpression
>> Loc
= Interp
.Interpret(E
);
136 if (!Loc
|| DumpOpts
.DisplayRawContents
)
137 dumpRawEntry(E
, OS
, Indent
, DumpOpts
, Obj
);
141 if (DumpOpts
.DisplayRawContents
)
144 DIDumpOptions
RangeDumpOpts(DumpOpts
);
145 RangeDumpOpts
.DisplayRawContents
= false;
146 if (Loc
.get()->Range
)
147 Loc
.get()->Range
->dump(OS
, Data
.getAddressSize(), RangeDumpOpts
, &Obj
);
152 consumeError(Loc
.takeError());
154 if (E
.Kind
!= dwarf::DW_LLE_base_address
&&
155 E
.Kind
!= dwarf::DW_LLE_base_addressx
&&
156 E
.Kind
!= dwarf::DW_LLE_end_of_list
) {
158 dumpExpression(OS
, DumpOpts
, E
.Loc
, Data
.isLittleEndian(),
159 Data
.getAddressSize(), U
);
164 DumpOpts
.RecoverableErrorHandler(std::move(E
));
170 Error
DWARFLocationTable::visitAbsoluteLocationList(
171 uint64_t Offset
, std::optional
<SectionedAddress
> BaseAddr
,
172 std::function
<std::optional
<SectionedAddress
>(uint32_t)> LookupAddr
,
173 function_ref
<bool(Expected
<DWARFLocationExpression
>)> Callback
) const {
174 DWARFLocationInterpreter
Interp(BaseAddr
, std::move(LookupAddr
));
175 return visitLocationList(&Offset
, [&](const DWARFLocationEntry
&E
) {
176 Expected
<std::optional
<DWARFLocationExpression
>> Loc
= Interp
.Interpret(E
);
178 return Callback(Loc
.takeError());
180 return Callback(**Loc
);
185 void DWARFDebugLoc::dump(raw_ostream
&OS
, const DWARFObject
&Obj
,
186 DIDumpOptions DumpOpts
,
187 std::optional
<uint64_t> DumpOffset
) const {
188 auto BaseAddr
= std::nullopt
;
189 unsigned Indent
= 12;
191 dumpLocationList(&*DumpOffset
, OS
, BaseAddr
, Obj
, nullptr, DumpOpts
,
196 bool CanContinue
= true;
197 while (CanContinue
&& Data
.isValidOffset(Offset
)) {
201 CanContinue
= dumpLocationList(&Offset
, OS
, BaseAddr
, Obj
, nullptr,
208 Error
DWARFDebugLoc::visitLocationList(
210 function_ref
<bool(const DWARFLocationEntry
&)> Callback
) const {
211 DataExtractor::Cursor
C(*Offset
);
213 uint64_t SectionIndex
;
214 uint64_t Value0
= Data
.getRelocatedAddress(C
);
215 uint64_t Value1
= Data
.getRelocatedAddress(C
, &SectionIndex
);
217 DWARFLocationEntry E
;
219 // The end of any given location list is marked by an end of list entry,
220 // which consists of a 0 for the beginning address offset and a 0 for the
221 // ending address offset. A beginning offset of 0xff...f marks the base
222 // address selection entry.
223 if (Value0
== 0 && Value1
== 0) {
224 E
.Kind
= dwarf::DW_LLE_end_of_list
;
225 } else if (Value0
== (Data
.getAddressSize() == 4 ? -1U : -1ULL)) {
226 E
.Kind
= dwarf::DW_LLE_base_address
;
228 E
.SectionIndex
= SectionIndex
;
230 E
.Kind
= dwarf::DW_LLE_offset_pair
;
233 E
.SectionIndex
= SectionIndex
;
234 unsigned Bytes
= Data
.getU16(C
);
235 // A single location description describing the location of the object...
236 Data
.getU8(C
, E
.Loc
, Bytes
);
240 return C
.takeError();
241 if (!Callback(E
) || E
.Kind
== dwarf::DW_LLE_end_of_list
)
245 return Error::success();
248 void DWARFDebugLoc::dumpRawEntry(const DWARFLocationEntry
&Entry
,
249 raw_ostream
&OS
, unsigned Indent
,
250 DIDumpOptions DumpOpts
,
251 const DWARFObject
&Obj
) const {
252 uint64_t Value0
, Value1
;
253 switch (Entry
.Kind
) {
254 case dwarf::DW_LLE_base_address
:
255 Value0
= Data
.getAddressSize() == 4 ? -1U : -1ULL;
256 Value1
= Entry
.Value0
;
258 case dwarf::DW_LLE_offset_pair
:
259 Value0
= Entry
.Value0
;
260 Value1
= Entry
.Value1
;
262 case dwarf::DW_LLE_end_of_list
:
265 llvm_unreachable("Not possible in DWARF4!");
269 OS
<< '(' << format_hex(Value0
, 2 + Data
.getAddressSize() * 2) << ", "
270 << format_hex(Value1
, 2 + Data
.getAddressSize() * 2) << ')';
271 DWARFFormValue::dumpAddressSection(Obj
, OS
, DumpOpts
, Entry
.SectionIndex
);
274 Error
DWARFDebugLoclists::visitLocationList(
275 uint64_t *Offset
, function_ref
<bool(const DWARFLocationEntry
&)> F
) const {
277 DataExtractor::Cursor
C(*Offset
);
278 bool Continue
= true;
280 DWARFLocationEntry E
;
281 E
.Kind
= Data
.getU8(C
);
283 case dwarf::DW_LLE_end_of_list
:
285 case dwarf::DW_LLE_base_addressx
:
286 E
.Value0
= Data
.getULEB128(C
);
288 case dwarf::DW_LLE_startx_endx
:
289 E
.Value0
= Data
.getULEB128(C
);
290 E
.Value1
= Data
.getULEB128(C
);
292 case dwarf::DW_LLE_startx_length
:
293 E
.Value0
= Data
.getULEB128(C
);
294 // Pre-DWARF 5 has different interpretation of the length field. We have
295 // to support both pre- and standartized styles for the compatibility.
297 E
.Value1
= Data
.getU32(C
);
299 E
.Value1
= Data
.getULEB128(C
);
301 case dwarf::DW_LLE_offset_pair
:
302 E
.Value0
= Data
.getULEB128(C
);
303 E
.Value1
= Data
.getULEB128(C
);
304 E
.SectionIndex
= SectionedAddress::UndefSection
;
306 case dwarf::DW_LLE_default_location
:
308 case dwarf::DW_LLE_base_address
:
309 E
.Value0
= Data
.getRelocatedAddress(C
, &E
.SectionIndex
);
311 case dwarf::DW_LLE_start_end
:
312 E
.Value0
= Data
.getRelocatedAddress(C
, &E
.SectionIndex
);
313 E
.Value1
= Data
.getRelocatedAddress(C
);
315 case dwarf::DW_LLE_start_length
:
316 E
.Value0
= Data
.getRelocatedAddress(C
, &E
.SectionIndex
);
317 E
.Value1
= Data
.getULEB128(C
);
320 cantFail(C
.takeError());
321 return createStringError(errc::illegal_byte_sequence
,
322 "LLE of kind %x not supported", (int)E
.Kind
);
325 if (E
.Kind
!= dwarf::DW_LLE_base_address
&&
326 E
.Kind
!= dwarf::DW_LLE_base_addressx
&&
327 E
.Kind
!= dwarf::DW_LLE_end_of_list
) {
328 unsigned Bytes
= Version
>= 5 ? Data
.getULEB128(C
) : Data
.getU16(C
);
329 // A single location description describing the location of the object...
330 Data
.getU8(C
, E
.Loc
, Bytes
);
334 return C
.takeError();
335 Continue
= F(E
) && E
.Kind
!= dwarf::DW_LLE_end_of_list
;
338 return Error::success();
341 void DWARFDebugLoclists::dumpRawEntry(const DWARFLocationEntry
&Entry
,
342 raw_ostream
&OS
, unsigned Indent
,
343 DIDumpOptions DumpOpts
,
344 const DWARFObject
&Obj
) const {
345 size_t MaxEncodingStringLength
= 0;
346 #define HANDLE_DW_LLE(ID, NAME) \
347 MaxEncodingStringLength = std::max(MaxEncodingStringLength, \
348 dwarf::LocListEncodingString(ID).size());
349 #include "llvm/BinaryFormat/Dwarf.def"
353 StringRef EncodingString
= dwarf::LocListEncodingString(Entry
.Kind
);
354 // Unsupported encodings should have been reported during parsing.
355 assert(!EncodingString
.empty() && "Unknown loclist entry encoding");
356 OS
<< format("%-*s(", MaxEncodingStringLength
, EncodingString
.data());
357 unsigned FieldSize
= 2 + 2 * Data
.getAddressSize();
358 switch (Entry
.Kind
) {
359 case dwarf::DW_LLE_end_of_list
:
360 case dwarf::DW_LLE_default_location
:
362 case dwarf::DW_LLE_startx_endx
:
363 case dwarf::DW_LLE_startx_length
:
364 case dwarf::DW_LLE_offset_pair
:
365 case dwarf::DW_LLE_start_end
:
366 case dwarf::DW_LLE_start_length
:
367 OS
<< format_hex(Entry
.Value0
, FieldSize
) << ", "
368 << format_hex(Entry
.Value1
, FieldSize
);
370 case dwarf::DW_LLE_base_addressx
:
371 case dwarf::DW_LLE_base_address
:
372 OS
<< format_hex(Entry
.Value0
, FieldSize
);
376 switch (Entry
.Kind
) {
377 case dwarf::DW_LLE_base_address
:
378 case dwarf::DW_LLE_start_end
:
379 case dwarf::DW_LLE_start_length
:
380 DWARFFormValue::dumpAddressSection(Obj
, OS
, DumpOpts
, Entry
.SectionIndex
);
387 void DWARFDebugLoclists::dumpRange(uint64_t StartOffset
, uint64_t Size
,
388 raw_ostream
&OS
, const DWARFObject
&Obj
,
389 DIDumpOptions DumpOpts
) {
390 if (!Data
.isValidOffsetForDataOfSize(StartOffset
, Size
)) {
391 OS
<< "Invalid dump range\n";
394 uint64_t Offset
= StartOffset
;
396 bool CanContinue
= true;
397 while (CanContinue
&& Offset
< StartOffset
+ Size
) {
401 CanContinue
= dumpLocationList(&Offset
, OS
, /*BaseAddr=*/std::nullopt
, Obj
,
402 nullptr, DumpOpts
, /*Indent=*/12);
407 void llvm::ResolverError::log(raw_ostream
&OS
) const {
408 OS
<< format("unable to resolve indirect address %u for: %s", Index
,
409 dwarf::LocListEncodingString(Kind
).data());
412 char llvm::ResolverError::ID
;