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
<char> Data
,
32 bool IsLittleEndian
, unsigned AddressSize
,
33 const MCRegisterInfo
*MRI
, DWARFUnit
*U
) {
34 DWARFDataExtractor
Extractor(StringRef(Data
.data(), Data
.size()),
35 IsLittleEndian
, AddressSize
);
36 DWARFExpression(Extractor
, dwarf::DWARF_VERSION
, AddressSize
).print(OS
, MRI
, U
);
39 void DWARFDebugLoc::LocationList::dump(raw_ostream
&OS
, bool IsLittleEndian
,
41 const MCRegisterInfo
*MRI
,
44 unsigned Indent
) const {
45 for (const Entry
&E
: Entries
) {
48 OS
<< format("[0x%*.*" PRIx64
", ", AddressSize
* 2, AddressSize
* 2,
49 BaseAddress
+ E
.Begin
);
50 OS
<< format(" 0x%*.*" PRIx64
")", AddressSize
* 2, AddressSize
* 2,
54 dumpExpression(OS
, E
.Loc
, IsLittleEndian
, AddressSize
, MRI
, U
);
58 DWARFDebugLoc::LocationList
const *
59 DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset
) const {
60 auto It
= partition_point(
61 Locations
, [=](const LocationList
&L
) { return L
.Offset
< Offset
; });
62 if (It
!= Locations
.end() && It
->Offset
== Offset
)
67 void DWARFDebugLoc::dump(raw_ostream
&OS
, const MCRegisterInfo
*MRI
,
68 Optional
<uint64_t> Offset
) const {
69 auto DumpLocationList
= [&](const LocationList
&L
) {
70 OS
<< format("0x%8.8" PRIx64
": ", L
.Offset
);
71 L
.dump(OS
, IsLittleEndian
, AddressSize
, MRI
, nullptr, 0, 12);
76 if (auto *L
= getLocationListAtOffset(*Offset
))
81 for (const LocationList
&L
: Locations
) {
86 Optional
<DWARFDebugLoc::LocationList
>
87 DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data
, uint64_t *Offset
) {
91 // 2.6.2 Location Lists
92 // A location list entry consists of:
95 if (!Data
.isValidOffsetForDataOfSize(*Offset
, 2 * Data
.getAddressSize())) {
96 WithColor::error() << "location list overflows the debug_loc section.\n";
100 // 1. A beginning address offset. ...
101 E
.Begin
= Data
.getRelocatedAddress(Offset
);
103 // 2. An ending address offset. ...
104 E
.End
= Data
.getRelocatedAddress(Offset
);
106 // The end of any given location list is marked by an end of list entry,
107 // which consists of a 0 for the beginning address offset and a 0 for the
108 // ending address offset.
109 if (E
.Begin
== 0 && E
.End
== 0)
112 if (!Data
.isValidOffsetForDataOfSize(*Offset
, 2)) {
113 WithColor::error() << "location list overflows the debug_loc section.\n";
117 unsigned Bytes
= Data
.getU16(Offset
);
118 if (!Data
.isValidOffsetForDataOfSize(*Offset
, Bytes
)) {
119 WithColor::error() << "location list overflows the debug_loc section.\n";
122 // A single location description describing the location of the object...
123 StringRef str
= Data
.getData().substr(*Offset
, Bytes
);
125 E
.Loc
.reserve(str
.size());
126 llvm::copy(str
, std::back_inserter(E
.Loc
));
127 LL
.Entries
.push_back(std::move(E
));
131 void DWARFDebugLoc::parse(const DWARFDataExtractor
&data
) {
132 IsLittleEndian
= data
.isLittleEndian();
133 AddressSize
= data
.getAddressSize();
136 while (data
.isValidOffset(Offset
+ data
.getAddressSize() - 1)) {
137 if (auto LL
= parseOneLocationList(data
, &Offset
))
138 Locations
.push_back(std::move(*LL
));
142 if (data
.isValidOffset(Offset
))
143 WithColor::error() << "failed to consume entire .debug_loc section\n";
146 Optional
<DWARFDebugLoclists::LocationList
>
147 DWARFDebugLoclists::parseOneLocationList(DataExtractor Data
, uint64_t *Offset
,
152 // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list.
154 static_cast<dwarf::LocationListEntry
>(Data
.getU8(Offset
))) {
159 case dwarf::DW_LLE_startx_length
:
160 E
.Value0
= Data
.getULEB128(Offset
);
161 // Pre-DWARF 5 has different interpretation of the length field. We have
162 // to support both pre- and standartized styles for the compatibility.
164 E
.Value1
= Data
.getU32(Offset
);
166 E
.Value1
= Data
.getULEB128(Offset
);
168 case dwarf::DW_LLE_start_length
:
169 E
.Value0
= Data
.getAddress(Offset
);
170 E
.Value1
= Data
.getULEB128(Offset
);
172 case dwarf::DW_LLE_offset_pair
:
173 E
.Value0
= Data
.getULEB128(Offset
);
174 E
.Value1
= Data
.getULEB128(Offset
);
176 case dwarf::DW_LLE_base_address
:
177 E
.Value0
= Data
.getAddress(Offset
);
180 WithColor::error() << "dumping support for LLE of kind " << (int)Kind
181 << " not implemented\n";
185 if (Kind
!= dwarf::DW_LLE_base_address
) {
187 Version
>= 5 ? Data
.getULEB128(Offset
) : Data
.getU16(Offset
);
188 // A single location description describing the location of the object...
189 StringRef str
= Data
.getData().substr(*Offset
, Bytes
);
191 E
.Loc
.resize(str
.size());
192 llvm::copy(str
, E
.Loc
.begin());
195 LL
.Entries
.push_back(std::move(E
));
200 void DWARFDebugLoclists::parse(DataExtractor data
, unsigned Version
) {
201 IsLittleEndian
= data
.isLittleEndian();
202 AddressSize
= data
.getAddressSize();
205 while (data
.isValidOffset(Offset
)) {
206 if (auto LL
= parseOneLocationList(data
, &Offset
, Version
))
207 Locations
.push_back(std::move(*LL
));
213 DWARFDebugLoclists::LocationList
const *
214 DWARFDebugLoclists::getLocationListAtOffset(uint64_t Offset
) const {
215 auto It
= partition_point(
216 Locations
, [=](const LocationList
&L
) { return L
.Offset
< Offset
; });
217 if (It
!= Locations
.end() && It
->Offset
== Offset
)
222 void DWARFDebugLoclists::LocationList::dump(raw_ostream
&OS
, uint64_t BaseAddr
,
224 unsigned AddressSize
,
225 const MCRegisterInfo
*MRI
,
227 unsigned Indent
) const {
228 for (const Entry
&E
: Entries
) {
230 case dwarf::DW_LLE_startx_length
:
233 OS
<< "Addr idx " << E
.Value0
<< " (w/ length " << E
.Value1
<< "): ";
235 case dwarf::DW_LLE_start_length
:
238 OS
<< format("[0x%*.*" PRIx64
", 0x%*.*" PRIx64
"): ", AddressSize
* 2,
239 AddressSize
* 2, E
.Value0
, AddressSize
* 2, AddressSize
* 2,
240 E
.Value0
+ E
.Value1
);
242 case dwarf::DW_LLE_offset_pair
:
245 OS
<< format("[0x%*.*" PRIx64
", 0x%*.*" PRIx64
"): ", AddressSize
* 2,
246 AddressSize
* 2, BaseAddr
+ E
.Value0
, AddressSize
* 2,
247 AddressSize
* 2, BaseAddr
+ E
.Value1
);
249 case dwarf::DW_LLE_base_address
:
253 llvm_unreachable("unreachable locations list kind");
256 dumpExpression(OS
, E
.Loc
, IsLittleEndian
, AddressSize
, MRI
, U
);
260 void DWARFDebugLoclists::dump(raw_ostream
&OS
, uint64_t BaseAddr
,
261 const MCRegisterInfo
*MRI
,
262 Optional
<uint64_t> Offset
) const {
263 auto DumpLocationList
= [&](const LocationList
&L
) {
264 OS
<< format("0x%8.8" PRIx64
": ", L
.Offset
);
265 L
.dump(OS
, BaseAddr
, IsLittleEndian
, AddressSize
, MRI
, nullptr, /*Indent=*/12);
270 if (auto *L
= getLocationListAtOffset(*Offset
))
271 DumpLocationList(*L
);
275 for (const LocationList
&L
: Locations
) {