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
, bool IsLittleEndian
,
40 const MCRegisterInfo
*MRI
,
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
,
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
, IsLittleEndian
, AddressSize
, MRI
, nullptr, 0, 12);
75 if (auto *L
= getLocationListAtOffset(*Offset
))
80 for (const LocationList
&L
: Locations
) {
85 Expected
<DWARFDebugLoc::LocationList
>
86 DWARFDebugLoc::parseOneLocationList(const DWARFDataExtractor
&Data
,
90 DataExtractor::Cursor
C(*Offset
);
92 // 2.6.2 Location Lists
93 // A location list entry consists of:
97 // 1. A beginning address offset. ...
98 E
.Begin
= Data
.getRelocatedAddress(C
);
100 // 2. An ending address offset. ...
101 E
.End
= Data
.getRelocatedAddress(C
);
103 if (Error Err
= C
.takeError())
104 return std::move(Err
);
105 // The end of any given location list is marked by an end of list entry,
106 // which consists of a 0 for the beginning address offset and a 0 for the
107 // ending address offset.
108 if (E
.Begin
== 0 && E
.End
== 0) {
113 unsigned Bytes
= Data
.getU16(C
);
114 // A single location description describing the location of the object...
115 Data
.getU8(C
, E
.Loc
, Bytes
);
116 LL
.Entries
.push_back(std::move(E
));
120 void DWARFDebugLoc::parse(const DWARFDataExtractor
&data
) {
121 IsLittleEndian
= data
.isLittleEndian();
122 AddressSize
= data
.getAddressSize();
125 while (Offset
< data
.getData().size()) {
126 if (auto LL
= parseOneLocationList(data
, &Offset
))
127 Locations
.push_back(std::move(*LL
));
129 logAllUnhandledErrors(LL
.takeError(), WithColor::error());
135 Expected
<DWARFDebugLoclists::LocationList
>
136 DWARFDebugLoclists::parseOneLocationList(const DataExtractor
&Data
,
137 uint64_t *Offset
, unsigned Version
) {
140 DataExtractor::Cursor
C(*Offset
);
142 // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list.
143 while (auto Kind
= static_cast<dwarf::LocationListEntry
>(Data
.getU8(C
))) {
147 case dwarf::DW_LLE_startx_length
:
148 E
.Value0
= Data
.getULEB128(C
);
149 // Pre-DWARF 5 has different interpretation of the length field. We have
150 // to support both pre- and standartized styles for the compatibility.
152 E
.Value1
= Data
.getU32(C
);
154 E
.Value1
= Data
.getULEB128(C
);
156 case dwarf::DW_LLE_start_length
:
157 E
.Value0
= Data
.getAddress(C
);
158 E
.Value1
= Data
.getULEB128(C
);
160 case dwarf::DW_LLE_offset_pair
:
161 E
.Value0
= Data
.getULEB128(C
);
162 E
.Value1
= Data
.getULEB128(C
);
164 case dwarf::DW_LLE_base_address
:
165 E
.Value0
= Data
.getAddress(C
);
168 cantFail(C
.takeError());
169 return createStringError(errc::illegal_byte_sequence
,
170 "LLE of kind %x not supported", (int)Kind
);
173 if (Kind
!= dwarf::DW_LLE_base_address
) {
174 unsigned Bytes
= Version
>= 5 ? Data
.getULEB128(C
) : Data
.getU16(C
);
175 // A single location description describing the location of the object...
176 Data
.getU8(C
, E
.Loc
, Bytes
);
179 LL
.Entries
.push_back(std::move(E
));
181 if (Error Err
= C
.takeError())
182 return std::move(Err
);
187 void DWARFDebugLoclists::parse(DataExtractor data
, unsigned Version
) {
188 IsLittleEndian
= data
.isLittleEndian();
189 AddressSize
= data
.getAddressSize();
192 while (Offset
< data
.getData().size()) {
193 if (auto LL
= parseOneLocationList(data
, &Offset
, Version
))
194 Locations
.push_back(std::move(*LL
));
196 logAllUnhandledErrors(LL
.takeError(), WithColor::error());
202 DWARFDebugLoclists::LocationList
const *
203 DWARFDebugLoclists::getLocationListAtOffset(uint64_t Offset
) const {
204 auto It
= partition_point(
205 Locations
, [=](const LocationList
&L
) { return L
.Offset
< Offset
; });
206 if (It
!= Locations
.end() && It
->Offset
== Offset
)
211 void DWARFDebugLoclists::LocationList::dump(raw_ostream
&OS
, uint64_t BaseAddr
,
213 unsigned AddressSize
,
214 const MCRegisterInfo
*MRI
,
216 unsigned Indent
) const {
217 for (const Entry
&E
: Entries
) {
219 case dwarf::DW_LLE_startx_length
:
222 OS
<< "Addr idx " << E
.Value0
<< " (w/ length " << E
.Value1
<< "): ";
224 case dwarf::DW_LLE_start_length
:
227 OS
<< format("[0x%*.*" PRIx64
", 0x%*.*" PRIx64
"): ", AddressSize
* 2,
228 AddressSize
* 2, E
.Value0
, AddressSize
* 2, AddressSize
* 2,
229 E
.Value0
+ E
.Value1
);
231 case dwarf::DW_LLE_offset_pair
:
234 OS
<< format("[0x%*.*" PRIx64
", 0x%*.*" PRIx64
"): ", AddressSize
* 2,
235 AddressSize
* 2, BaseAddr
+ E
.Value0
, AddressSize
* 2,
236 AddressSize
* 2, BaseAddr
+ E
.Value1
);
238 case dwarf::DW_LLE_base_address
:
242 llvm_unreachable("unreachable locations list kind");
245 dumpExpression(OS
, E
.Loc
, IsLittleEndian
, AddressSize
, MRI
, U
);
249 void DWARFDebugLoclists::dump(raw_ostream
&OS
, uint64_t BaseAddr
,
250 const MCRegisterInfo
*MRI
,
251 Optional
<uint64_t> Offset
) const {
252 auto DumpLocationList
= [&](const LocationList
&L
) {
253 OS
<< format("0x%8.8" PRIx64
": ", L
.Offset
);
254 L
.dump(OS
, BaseAddr
, IsLittleEndian
, AddressSize
, MRI
, nullptr, /*Indent=*/12);
259 if (auto *L
= getLocationListAtOffset(*Offset
))
260 DumpLocationList(*L
);
264 for (const LocationList
&L
: Locations
) {