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/DWARF/DWARFContext.h"
13 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
14 #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
15 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
16 #include "llvm/Support/Compiler.h"
17 #include "llvm/Support/Format.h"
18 #include "llvm/Support/WithColor.h"
19 #include "llvm/Support/raw_ostream.h"
26 // When directly dumping the .debug_loc without a compile unit, we have to guess
27 // at the DWARF version. This only affects DW_OP_call_ref, which is a rare
28 // expression that LLVM doesn't produce. Guessing the wrong version means we
29 // won't be able to pretty print expressions in DWARF2 binaries produced by
31 static void dumpExpression(raw_ostream
&OS
, ArrayRef
<uint8_t> Data
,
32 bool IsLittleEndian
, unsigned AddressSize
,
33 const MCRegisterInfo
*MRI
, DWARFUnit
*U
) {
34 DWARFDataExtractor
Extractor(toStringRef(Data
), IsLittleEndian
, AddressSize
);
35 DWARFExpression(Extractor
, dwarf::DWARF_VERSION
, AddressSize
).print(OS
, MRI
, U
);
38 void DWARFDebugLoc::LocationList::dump(raw_ostream
&OS
, uint64_t BaseAddress
,
41 const MCRegisterInfo
*MRI
, DWARFUnit
*U
,
42 DIDumpOptions DumpOpts
,
43 unsigned Indent
) const {
44 for (const Entry
&E
: Entries
) {
47 OS
<< format("[0x%*.*" PRIx64
", ", AddressSize
* 2, AddressSize
* 2,
48 BaseAddress
+ E
.Begin
);
49 OS
<< format(" 0x%*.*" PRIx64
")", AddressSize
* 2, AddressSize
* 2,
53 dumpExpression(OS
, E
.Loc
, IsLittleEndian
, AddressSize
, MRI
, U
);
57 DWARFDebugLoc::LocationList
const *
58 DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset
) const {
59 auto It
= partition_point(
60 Locations
, [=](const LocationList
&L
) { return L
.Offset
< Offset
; });
61 if (It
!= Locations
.end() && It
->Offset
== Offset
)
66 void DWARFDebugLoc::dump(raw_ostream
&OS
, const MCRegisterInfo
*MRI
, DIDumpOptions DumpOpts
,
67 Optional
<uint64_t> Offset
) const {
68 auto DumpLocationList
= [&](const LocationList
&L
) {
69 OS
<< format("0x%8.8" PRIx64
": ", L
.Offset
);
70 L
.dump(OS
, 0, IsLittleEndian
, AddressSize
, MRI
, nullptr, DumpOpts
, 12);
75 if (auto *L
= getLocationListAtOffset(*Offset
))
80 for (const LocationList
&L
: Locations
) {
82 if (&L
!= &Locations
.back())
87 Expected
<DWARFDebugLoc::LocationList
>
88 DWARFDebugLoc::parseOneLocationList(const DWARFDataExtractor
&Data
,
92 AddressSize
= Data
.getAddressSize();
93 DataExtractor::Cursor
C(*Offset
);
95 // 2.6.2 Location Lists
96 // A location list entry consists of:
100 // 1. A beginning address offset. ...
101 E
.Begin
= Data
.getRelocatedAddress(C
);
103 // 2. An ending address offset. ...
104 E
.End
= Data
.getRelocatedAddress(C
);
106 if (Error Err
= C
.takeError())
107 return std::move(Err
);
109 // The end of any given location list is marked by an end of list entry,
110 // which consists of a 0 for the beginning address offset and a 0 for the
111 // ending address offset.
112 if (E
.Begin
== 0 && E
.End
== 0) {
117 if (E
.Begin
!= (AddressSize
== 4 ? -1U : -1ULL)) {
118 unsigned Bytes
= Data
.getU16(C
);
119 // A single location description describing the location of the object...
120 Data
.getU8(C
, E
.Loc
, Bytes
);
123 LL
.Entries
.push_back(std::move(E
));
127 void DWARFDebugLoc::parse(const DWARFDataExtractor
&data
) {
128 IsLittleEndian
= data
.isLittleEndian();
129 AddressSize
= data
.getAddressSize();
132 while (Offset
< data
.getData().size()) {
133 if (auto LL
= parseOneLocationList(data
, &Offset
))
134 Locations
.push_back(std::move(*LL
));
136 logAllUnhandledErrors(LL
.takeError(), WithColor::error());
142 Expected
<DWARFDebugLoclists::LocationList
>
143 DWARFDebugLoclists::parseOneLocationList(const DataExtractor
&Data
,
144 uint64_t *Offset
, unsigned Version
) {
147 DataExtractor::Cursor
C(*Offset
);
149 // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list.
150 while (auto Kind
= Data
.getU8(C
)) {
153 E
.Offset
= C
.tell() - 1;
155 case dwarf::DW_LLE_base_addressx
:
156 E
.Value0
= Data
.getULEB128(C
);
158 case dwarf::DW_LLE_startx_length
:
159 E
.Value0
= Data
.getULEB128(C
);
160 // Pre-DWARF 5 has different interpretation of the length field. We have
161 // to support both pre- and standartized styles for the compatibility.
163 E
.Value1
= Data
.getU32(C
);
165 E
.Value1
= Data
.getULEB128(C
);
167 case dwarf::DW_LLE_start_length
:
168 E
.Value0
= Data
.getAddress(C
);
169 E
.Value1
= Data
.getULEB128(C
);
171 case dwarf::DW_LLE_offset_pair
:
172 E
.Value0
= Data
.getULEB128(C
);
173 E
.Value1
= Data
.getULEB128(C
);
175 case dwarf::DW_LLE_base_address
:
176 E
.Value0
= Data
.getAddress(C
);
179 cantFail(C
.takeError());
180 return createStringError(errc::illegal_byte_sequence
,
181 "LLE of kind %x not supported", (int)Kind
);
184 if (Kind
!= dwarf::DW_LLE_base_address
&&
185 Kind
!= dwarf::DW_LLE_base_addressx
) {
186 unsigned Bytes
= Version
>= 5 ? Data
.getULEB128(C
) : Data
.getU16(C
);
187 // A single location description describing the location of the object...
188 Data
.getU8(C
, E
.Loc
, Bytes
);
191 LL
.Entries
.push_back(std::move(E
));
193 if (Error Err
= C
.takeError())
194 return std::move(Err
);
196 E
.Kind
= dwarf::DW_LLE_end_of_list
;
197 E
.Offset
= C
.tell() - 1;
198 LL
.Entries
.push_back(E
);
203 void DWARFDebugLoclists::parse(DataExtractor data
, uint64_t Offset
, uint64_t EndOffset
, uint16_t Version
) {
204 IsLittleEndian
= data
.isLittleEndian();
205 AddressSize
= data
.getAddressSize();
207 while (Offset
< EndOffset
) {
208 if (auto LL
= parseOneLocationList(data
, &Offset
, Version
))
209 Locations
.push_back(std::move(*LL
));
211 logAllUnhandledErrors(LL
.takeError(), WithColor::error());
217 DWARFDebugLoclists::LocationList
const *
218 DWARFDebugLoclists::getLocationListAtOffset(uint64_t Offset
) const {
219 auto It
= partition_point(
220 Locations
, [=](const LocationList
&L
) { return L
.Offset
< Offset
; });
221 if (It
!= Locations
.end() && It
->Offset
== Offset
)
226 void DWARFDebugLoclists::Entry::dump(raw_ostream
&OS
, uint64_t &BaseAddr
,
227 bool IsLittleEndian
, unsigned AddressSize
,
228 const MCRegisterInfo
*MRI
, DWARFUnit
*U
,
229 DIDumpOptions DumpOpts
, unsigned Indent
,
230 size_t MaxEncodingStringLength
) const {
231 if (DumpOpts
.Verbose
) {
234 auto EncodingString
= dwarf::LocListEncodingString(Kind
);
235 // Unsupported encodings should have been reported during parsing.
236 assert(!EncodingString
.empty() && "Unknown loclist entry encoding");
237 OS
<< format("%s%*c", EncodingString
.data(),
238 MaxEncodingStringLength
- EncodingString
.size() + 1, '(');
240 case dwarf::DW_LLE_startx_length
:
241 case dwarf::DW_LLE_start_length
:
242 case dwarf::DW_LLE_offset_pair
:
243 OS
<< format("0x%*.*" PRIx64
", 0x%*.*" PRIx64
, AddressSize
* 2,
244 AddressSize
* 2, Value0
, AddressSize
* 2, AddressSize
* 2,
247 case dwarf::DW_LLE_base_addressx
:
248 case dwarf::DW_LLE_base_address
:
249 OS
<< format("0x%*.*" PRIx64
, AddressSize
* 2, AddressSize
* 2,
252 case dwarf::DW_LLE_end_of_list
:
257 auto PrintPrefix
= [&] {
260 if (DumpOpts
.Verbose
)
261 OS
<< format("%*s", MaxEncodingStringLength
, (const char *)"=> ");
264 case dwarf::DW_LLE_startx_length
:
266 OS
<< "Addr idx " << Value0
<< " (w/ length " << Value1
<< "): ";
268 case dwarf::DW_LLE_start_length
:
270 DWARFAddressRange(Value0
, Value0
+ Value1
)
271 .dump(OS
, AddressSize
, DumpOpts
);
274 case dwarf::DW_LLE_offset_pair
:
276 DWARFAddressRange(BaseAddr
+ Value0
, BaseAddr
+ Value1
)
277 .dump(OS
, AddressSize
, DumpOpts
);
280 case dwarf::DW_LLE_base_addressx
:
281 if (!DumpOpts
.Verbose
)
284 case dwarf::DW_LLE_end_of_list
:
285 if (!DumpOpts
.Verbose
)
288 case dwarf::DW_LLE_base_address
:
290 if (!DumpOpts
.Verbose
)
294 llvm_unreachable("unreachable locations list kind");
297 dumpExpression(OS
, Loc
, IsLittleEndian
, AddressSize
, MRI
, U
);
299 void DWARFDebugLoclists::LocationList::dump(raw_ostream
&OS
, uint64_t BaseAddr
,
301 unsigned AddressSize
,
302 const MCRegisterInfo
*MRI
,
304 DIDumpOptions DumpOpts
,
305 unsigned Indent
) const {
306 size_t MaxEncodingStringLength
= 0;
307 if (DumpOpts
.Verbose
)
308 for (const auto &Entry
: Entries
)
309 MaxEncodingStringLength
=
310 std::max(MaxEncodingStringLength
,
311 dwarf::LocListEncodingString(Entry
.Kind
).size());
313 for (const Entry
&E
: Entries
)
314 E
.dump(OS
, BaseAddr
, IsLittleEndian
, AddressSize
, MRI
, U
, DumpOpts
, Indent
,
315 MaxEncodingStringLength
);
318 void DWARFDebugLoclists::dump(raw_ostream
&OS
, uint64_t BaseAddr
,
319 const MCRegisterInfo
*MRI
, DIDumpOptions DumpOpts
,
320 Optional
<uint64_t> Offset
) const {
321 auto DumpLocationList
= [&](const LocationList
&L
) {
322 OS
<< format("0x%8.8" PRIx64
": ", L
.Offset
);
323 L
.dump(OS
, BaseAddr
, IsLittleEndian
, AddressSize
, MRI
, nullptr, DumpOpts
,
329 if (auto *L
= getLocationListAtOffset(*Offset
))
330 DumpLocationList(*L
);
334 for (const LocationList
&L
: Locations
) {
336 if (&L
!= &Locations
.back())