1 | //===- DWARFDebugLoc.cpp --------------------------------------------------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
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" |
20 | #include <algorithm> |
21 | #include <cinttypes> |
22 | #include <cstdint> |
23 | |
24 | using namespace llvm; |
25 | using object::SectionedAddress; |
26 | |
27 | namespace llvm { |
28 | class DWARFObject; |
29 | } |
30 | |
31 | namespace { |
32 | class DWARFLocationInterpreter { |
33 | std::optional<object::SectionedAddress> Base; |
34 | std::function<std::optional<object::SectionedAddress>(uint32_t)> LookupAddr; |
35 | |
36 | public: |
37 | DWARFLocationInterpreter( |
38 | std::optional<object::SectionedAddress> Base, |
39 | std::function<std::optional<object::SectionedAddress>(uint32_t)> |
40 | LookupAddr) |
41 | : Base(Base), LookupAddr(std::move(LookupAddr)) {} |
42 | |
43 | Expected<std::optional<DWARFLocationExpression>> |
44 | Interpret(const DWARFLocationEntry &E); |
45 | }; |
46 | } // namespace |
47 | |
48 | static Error createResolverError(uint32_t Index, unsigned Kind) { |
49 | return make_error<ResolverError>(Args&: Index, Args: (dwarf::LoclistEntries)Kind); |
50 | } |
51 | |
52 | Expected<std::optional<DWARFLocationExpression>> |
53 | DWARFLocationInterpreter::Interpret(const DWARFLocationEntry &E) { |
54 | switch (E.Kind) { |
55 | case dwarf::DW_LLE_end_of_list: |
56 | return std::nullopt; |
57 | case dwarf::DW_LLE_base_addressx: { |
58 | Base = LookupAddr(E.Value0); |
59 | if (!Base) |
60 | return createResolverError(Index: E.Value0, Kind: E.Kind); |
61 | return std::nullopt; |
62 | } |
63 | case dwarf::DW_LLE_startx_endx: { |
64 | std::optional<SectionedAddress> LowPC = LookupAddr(E.Value0); |
65 | if (!LowPC) |
66 | return createResolverError(Index: E.Value0, Kind: E.Kind); |
67 | std::optional<SectionedAddress> HighPC = LookupAddr(E.Value1); |
68 | if (!HighPC) |
69 | return createResolverError(Index: E.Value1, Kind: E.Kind); |
70 | return DWARFLocationExpression{ |
71 | .Range: DWARFAddressRange{LowPC->Address, HighPC->Address, LowPC->SectionIndex}, |
72 | .Expr: E.Loc}; |
73 | } |
74 | case dwarf::DW_LLE_startx_length: { |
75 | std::optional<SectionedAddress> LowPC = LookupAddr(E.Value0); |
76 | if (!LowPC) |
77 | return createResolverError(Index: E.Value0, Kind: E.Kind); |
78 | return DWARFLocationExpression{.Range: DWARFAddressRange{LowPC->Address, |
79 | LowPC->Address + E.Value1, |
80 | LowPC->SectionIndex}, |
81 | .Expr: E.Loc}; |
82 | } |
83 | case dwarf::DW_LLE_offset_pair: { |
84 | if (!Base) { |
85 | return createStringError(EC: inconvertibleErrorCode(), |
86 | S: "Unable to resolve location list offset pair: " |
87 | "Base address not defined" ); |
88 | } |
89 | DWARFAddressRange Range{Base->Address + E.Value0, Base->Address + E.Value1, |
90 | Base->SectionIndex}; |
91 | if (Range.SectionIndex == SectionedAddress::UndefSection) |
92 | Range.SectionIndex = E.SectionIndex; |
93 | return DWARFLocationExpression{.Range: Range, .Expr: E.Loc}; |
94 | } |
95 | case dwarf::DW_LLE_default_location: |
96 | return DWARFLocationExpression{.Range: std::nullopt, .Expr: E.Loc}; |
97 | case dwarf::DW_LLE_base_address: |
98 | Base = SectionedAddress{.Address: E.Value0, .SectionIndex: E.SectionIndex}; |
99 | return std::nullopt; |
100 | case dwarf::DW_LLE_start_end: |
101 | return DWARFLocationExpression{ |
102 | .Range: DWARFAddressRange{E.Value0, E.Value1, E.SectionIndex}, .Expr: E.Loc}; |
103 | case dwarf::DW_LLE_start_length: |
104 | return DWARFLocationExpression{ |
105 | .Range: DWARFAddressRange{E.Value0, E.Value0 + E.Value1, E.SectionIndex}, |
106 | .Expr: E.Loc}; |
107 | default: |
108 | llvm_unreachable("unreachable locations list kind" ); |
109 | } |
110 | } |
111 | |
112 | static void dumpExpression(raw_ostream &OS, DIDumpOptions DumpOpts, |
113 | ArrayRef<uint8_t> Data, bool IsLittleEndian, |
114 | unsigned AddressSize, DWARFUnit *U) { |
115 | DWARFDataExtractor (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); |
121 | } |
122 | |
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> { |
129 | if (U) |
130 | return U->getAddrOffsetSectionItem(Index); |
131 | return std::nullopt; |
132 | }); |
133 | OS << format(Fmt: "0x%8.8" PRIx64 ": " , Vals: *Offset); |
134 | Error E = visitLocationList(Offset, Callback: [&](const DWARFLocationEntry &E) { |
135 | Expected<std::optional<DWARFLocationExpression>> Loc = Interp.Interpret(E); |
136 | if (!Loc || DumpOpts.DisplayRawContents) |
137 | dumpRawEntry(Entry: E, OS, Indent, DumpOpts, Obj); |
138 | if (Loc && *Loc) { |
139 | OS << "\n" ; |
140 | OS.indent(NumSpaces: Indent); |
141 | if (DumpOpts.DisplayRawContents) |
142 | OS << " => " ; |
143 | |
144 | DIDumpOptions RangeDumpOpts(DumpOpts); |
145 | RangeDumpOpts.DisplayRawContents = false; |
146 | if (Loc.get()->Range) |
147 | Loc.get()->Range->dump(OS, AddressSize: Data.getAddressSize(), DumpOpts: RangeDumpOpts, Obj: &Obj); |
148 | else |
149 | OS << "<default>" ; |
150 | } |
151 | if (!Loc) |
152 | consumeError(Err: Loc.takeError()); |
153 | |
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) { |
157 | OS << ": " ; |
158 | dumpExpression(OS, DumpOpts, Data: E.Loc, IsLittleEndian: Data.isLittleEndian(), |
159 | AddressSize: Data.getAddressSize(), U); |
160 | } |
161 | return true; |
162 | }); |
163 | if (E) { |
164 | DumpOpts.RecoverableErrorHandler(std::move(E)); |
165 | return false; |
166 | } |
167 | return true; |
168 | } |
169 | |
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: &Offset, Callback: [&](const DWARFLocationEntry &E) { |
176 | Expected<std::optional<DWARFLocationExpression>> Loc = Interp.Interpret(E); |
177 | if (!Loc) |
178 | return Callback(Loc.takeError()); |
179 | if (*Loc) |
180 | return Callback(**Loc); |
181 | return true; |
182 | }); |
183 | } |
184 | |
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; |
190 | if (DumpOffset) { |
191 | dumpLocationList(Offset: &*DumpOffset, OS, BaseAddr, Obj, U: nullptr, DumpOpts, |
192 | Indent); |
193 | } else { |
194 | uint64_t Offset = 0; |
195 | StringRef Separator; |
196 | bool CanContinue = true; |
197 | while (CanContinue && Data.isValidOffset(offset: Offset)) { |
198 | OS << Separator; |
199 | Separator = "\n" ; |
200 | |
201 | CanContinue = dumpLocationList(Offset: &Offset, OS, BaseAddr, Obj, U: nullptr, |
202 | DumpOpts, Indent); |
203 | OS << '\n'; |
204 | } |
205 | } |
206 | } |
207 | |
208 | Error DWARFDebugLoc::visitLocationList( |
209 | uint64_t *Offset, |
210 | function_ref<bool(const DWARFLocationEntry &)> Callback) const { |
211 | DataExtractor::Cursor C(*Offset); |
212 | while (true) { |
213 | uint64_t SectionIndex; |
214 | uint64_t Value0 = Data.getRelocatedAddress(C); |
215 | uint64_t Value1 = Data.getRelocatedAddress(C, SecIx: &SectionIndex); |
216 | |
217 | DWARFLocationEntry E; |
218 | |
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; |
227 | E.Value0 = Value1; |
228 | E.SectionIndex = SectionIndex; |
229 | } else { |
230 | E.Kind = dwarf::DW_LLE_offset_pair; |
231 | E.Value0 = Value0; |
232 | E.Value1 = Value1; |
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, Dst&: E.Loc, Count: Bytes); |
237 | } |
238 | |
239 | if (!C) |
240 | return C.takeError(); |
241 | if (!Callback(E) || E.Kind == dwarf::DW_LLE_end_of_list) |
242 | break; |
243 | } |
244 | *Offset = C.tell(); |
245 | return Error::success(); |
246 | } |
247 | |
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; |
257 | break; |
258 | case dwarf::DW_LLE_offset_pair: |
259 | Value0 = Entry.Value0; |
260 | Value1 = Entry.Value1; |
261 | break; |
262 | case dwarf::DW_LLE_end_of_list: |
263 | return; |
264 | default: |
265 | llvm_unreachable("Not possible in DWARF4!" ); |
266 | } |
267 | OS << '\n'; |
268 | OS.indent(NumSpaces: Indent); |
269 | OS << '(' << format_hex(N: Value0, Width: 2 + Data.getAddressSize() * 2) << ", " |
270 | << format_hex(N: Value1, Width: 2 + Data.getAddressSize() * 2) << ')'; |
271 | DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, SectionIndex: Entry.SectionIndex); |
272 | } |
273 | |
274 | Error DWARFDebugLoclists::visitLocationList( |
275 | uint64_t *Offset, function_ref<bool(const DWARFLocationEntry &)> F) const { |
276 | |
277 | DataExtractor::Cursor C(*Offset); |
278 | bool Continue = true; |
279 | while (Continue) { |
280 | DWARFLocationEntry E; |
281 | E.Kind = Data.getU8(C); |
282 | switch (E.Kind) { |
283 | case dwarf::DW_LLE_end_of_list: |
284 | break; |
285 | case dwarf::DW_LLE_base_addressx: |
286 | E.Value0 = Data.getULEB128(C); |
287 | break; |
288 | case dwarf::DW_LLE_startx_endx: |
289 | E.Value0 = Data.getULEB128(C); |
290 | E.Value1 = Data.getULEB128(C); |
291 | break; |
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. |
296 | if (Version < 5) |
297 | E.Value1 = Data.getU32(C); |
298 | else |
299 | E.Value1 = Data.getULEB128(C); |
300 | break; |
301 | case dwarf::DW_LLE_offset_pair: |
302 | E.Value0 = Data.getULEB128(C); |
303 | E.Value1 = Data.getULEB128(C); |
304 | E.SectionIndex = SectionedAddress::UndefSection; |
305 | break; |
306 | case dwarf::DW_LLE_default_location: |
307 | break; |
308 | case dwarf::DW_LLE_base_address: |
309 | E.Value0 = Data.getRelocatedAddress(C, SecIx: &E.SectionIndex); |
310 | break; |
311 | case dwarf::DW_LLE_start_end: |
312 | E.Value0 = Data.getRelocatedAddress(C, SecIx: &E.SectionIndex); |
313 | E.Value1 = Data.getRelocatedAddress(C); |
314 | break; |
315 | case dwarf::DW_LLE_start_length: |
316 | E.Value0 = Data.getRelocatedAddress(C, SecIx: &E.SectionIndex); |
317 | E.Value1 = Data.getULEB128(C); |
318 | break; |
319 | default: |
320 | cantFail(Err: C.takeError()); |
321 | return createStringError(EC: errc::illegal_byte_sequence, |
322 | Fmt: "LLE of kind %x not supported" , Vals: (int)E.Kind); |
323 | } |
324 | |
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, Dst&: E.Loc, Count: Bytes); |
331 | } |
332 | |
333 | if (!C) |
334 | return C.takeError(); |
335 | Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list; |
336 | } |
337 | *Offset = C.tell(); |
338 | return Error::success(); |
339 | } |
340 | |
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" |
350 | |
351 | OS << "\n" ; |
352 | OS.indent(NumSpaces: Indent); |
353 | StringRef EncodingString = dwarf::LocListEncodingString(Encoding: Entry.Kind); |
354 | // Unsupported encodings should have been reported during parsing. |
355 | assert(!EncodingString.empty() && "Unknown loclist entry encoding" ); |
356 | OS << format(Fmt: "%-*s(" , Vals: MaxEncodingStringLength, Vals: 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: |
361 | break; |
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(N: Entry.Value0, Width: FieldSize) << ", " |
368 | << format_hex(N: Entry.Value1, Width: FieldSize); |
369 | break; |
370 | case dwarf::DW_LLE_base_addressx: |
371 | case dwarf::DW_LLE_base_address: |
372 | OS << format_hex(N: Entry.Value0, Width: FieldSize); |
373 | break; |
374 | } |
375 | OS << ')'; |
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, SectionIndex: Entry.SectionIndex); |
381 | break; |
382 | default: |
383 | break; |
384 | } |
385 | } |
386 | |
387 | void DWARFDebugLoclists::dumpRange(uint64_t StartOffset, uint64_t Size, |
388 | raw_ostream &OS, const DWARFObject &Obj, |
389 | DIDumpOptions DumpOpts) { |
390 | if (!Data.isValidOffsetForDataOfSize(offset: StartOffset, length: Size)) { |
391 | OS << "Invalid dump range\n" ; |
392 | return; |
393 | } |
394 | uint64_t Offset = StartOffset; |
395 | StringRef Separator; |
396 | bool CanContinue = true; |
397 | while (CanContinue && Offset < StartOffset + Size) { |
398 | OS << Separator; |
399 | Separator = "\n" ; |
400 | |
401 | CanContinue = dumpLocationList(Offset: &Offset, OS, /*BaseAddr=*/std::nullopt, Obj, |
402 | U: nullptr, DumpOpts, /*Indent=*/12); |
403 | OS << '\n'; |
404 | } |
405 | } |
406 | |
407 | void llvm::ResolverError::log(raw_ostream &OS) const { |
408 | OS << format(Fmt: "unable to resolve indirect address %u for: %s" , Vals: Index, |
409 | Vals: dwarf::LocListEncodingString(Encoding: Kind).data()); |
410 | } |
411 | |
412 | char llvm::ResolverError::ID; |
413 | |