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/DWARFExpressionPrinter.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/DebugInfo/DWARF/LowLevel/DWARFExpression.h" |
19 | #include "llvm/Support/Format.h" |
20 | #include "llvm/Support/raw_ostream.h" |
21 | #include <algorithm> |
22 | #include <cinttypes> |
23 | #include <cstdint> |
24 | |
25 | using namespace llvm; |
26 | using object::SectionedAddress; |
27 | |
28 | namespace llvm { |
29 | class DWARFObject; |
30 | } |
31 | |
32 | namespace { |
33 | class DWARFLocationInterpreter { |
34 | std::optional<object::SectionedAddress> Base; |
35 | std::function<std::optional<object::SectionedAddress>(uint32_t)> LookupAddr; |
36 | |
37 | public: |
38 | DWARFLocationInterpreter( |
39 | std::optional<object::SectionedAddress> Base, |
40 | std::function<std::optional<object::SectionedAddress>(uint32_t)> |
41 | LookupAddr) |
42 | : Base(Base), LookupAddr(std::move(LookupAddr)) {} |
43 | |
44 | Expected<std::optional<DWARFLocationExpression>> |
45 | Interpret(const DWARFLocationEntry &E); |
46 | }; |
47 | } // namespace |
48 | |
49 | static Error createResolverError(uint32_t Index, unsigned Kind) { |
50 | return make_error<ResolverError>(Args&: Index, Args: (dwarf::LoclistEntries)Kind); |
51 | } |
52 | |
53 | Expected<std::optional<DWARFLocationExpression>> |
54 | DWARFLocationInterpreter::Interpret(const DWARFLocationEntry &E) { |
55 | switch (E.Kind) { |
56 | case dwarf::DW_LLE_end_of_list: |
57 | return std::nullopt; |
58 | case dwarf::DW_LLE_base_addressx: { |
59 | Base = LookupAddr(E.Value0); |
60 | if (!Base) |
61 | return createResolverError(Index: E.Value0, Kind: E.Kind); |
62 | return std::nullopt; |
63 | } |
64 | case dwarf::DW_LLE_startx_endx: { |
65 | std::optional<SectionedAddress> LowPC = LookupAddr(E.Value0); |
66 | if (!LowPC) |
67 | return createResolverError(Index: E.Value0, Kind: E.Kind); |
68 | std::optional<SectionedAddress> HighPC = LookupAddr(E.Value1); |
69 | if (!HighPC) |
70 | return createResolverError(Index: E.Value1, Kind: E.Kind); |
71 | return DWARFLocationExpression{ |
72 | .Range: DWARFAddressRange{LowPC->Address, HighPC->Address, LowPC->SectionIndex}, |
73 | .Expr: E.Loc}; |
74 | } |
75 | case dwarf::DW_LLE_startx_length: { |
76 | std::optional<SectionedAddress> LowPC = LookupAddr(E.Value0); |
77 | if (!LowPC) |
78 | return createResolverError(Index: E.Value0, Kind: E.Kind); |
79 | return DWARFLocationExpression{.Range: DWARFAddressRange{LowPC->Address, |
80 | LowPC->Address + E.Value1, |
81 | LowPC->SectionIndex}, |
82 | .Expr: E.Loc}; |
83 | } |
84 | case dwarf::DW_LLE_offset_pair: { |
85 | if (!Base) { |
86 | return createStringError(EC: inconvertibleErrorCode(), |
87 | S: "Unable to resolve location list offset pair: " |
88 | "Base address not defined" ); |
89 | } |
90 | DWARFAddressRange Range{Base->Address + E.Value0, Base->Address + E.Value1, |
91 | Base->SectionIndex}; |
92 | if (Range.SectionIndex == SectionedAddress::UndefSection) |
93 | Range.SectionIndex = E.SectionIndex; |
94 | return DWARFLocationExpression{.Range: Range, .Expr: E.Loc}; |
95 | } |
96 | case dwarf::DW_LLE_default_location: |
97 | return DWARFLocationExpression{.Range: std::nullopt, .Expr: E.Loc}; |
98 | case dwarf::DW_LLE_base_address: |
99 | Base = SectionedAddress{.Address: E.Value0, .SectionIndex: E.SectionIndex}; |
100 | return std::nullopt; |
101 | case dwarf::DW_LLE_start_end: |
102 | return DWARFLocationExpression{ |
103 | .Range: DWARFAddressRange{E.Value0, E.Value1, E.SectionIndex}, .Expr: E.Loc}; |
104 | case dwarf::DW_LLE_start_length: |
105 | return DWARFLocationExpression{ |
106 | .Range: DWARFAddressRange{E.Value0, E.Value0 + E.Value1, E.SectionIndex}, |
107 | .Expr: E.Loc}; |
108 | default: |
109 | llvm_unreachable("unreachable locations list kind" ); |
110 | } |
111 | } |
112 | |
113 | static void dumpExpression(raw_ostream &OS, DIDumpOptions DumpOpts, |
114 | ArrayRef<uint8_t> Data, bool IsLittleEndian, |
115 | unsigned AddressSize, DWARFUnit *U) { |
116 | DWARFDataExtractor (Data, IsLittleEndian, AddressSize); |
117 | std::optional<dwarf::DwarfFormat> Format; |
118 | if (U) |
119 | Format = U->getFormat(); |
120 | DWARFExpression E(Extractor, AddressSize, Format); |
121 | printDwarfExpression(E: &E, OS, DumpOpts, U); |
122 | } |
123 | |
124 | bool DWARFLocationTable::dumpLocationList( |
125 | uint64_t *Offset, raw_ostream &OS, std::optional<SectionedAddress> BaseAddr, |
126 | const DWARFObject &Obj, DWARFUnit *U, DIDumpOptions DumpOpts, |
127 | unsigned Indent) const { |
128 | DWARFLocationInterpreter Interp( |
129 | BaseAddr, [U](uint32_t Index) -> std::optional<SectionedAddress> { |
130 | if (U) |
131 | return U->getAddrOffsetSectionItem(Index); |
132 | return std::nullopt; |
133 | }); |
134 | OS << format(Fmt: "0x%8.8" PRIx64 ": " , Vals: *Offset); |
135 | Error E = visitLocationList(Offset, Callback: [&](const DWARFLocationEntry &E) { |
136 | Expected<std::optional<DWARFLocationExpression>> Loc = Interp.Interpret(E); |
137 | if (!Loc || DumpOpts.DisplayRawContents) |
138 | dumpRawEntry(Entry: E, OS, Indent, DumpOpts, Obj); |
139 | if (Loc && *Loc) { |
140 | OS << "\n" ; |
141 | OS.indent(NumSpaces: Indent); |
142 | if (DumpOpts.DisplayRawContents) |
143 | OS << " => " ; |
144 | |
145 | DIDumpOptions RangeDumpOpts(DumpOpts); |
146 | RangeDumpOpts.DisplayRawContents = false; |
147 | if (Loc.get()->Range) |
148 | Loc.get()->Range->dump(OS, AddressSize: Data.getAddressSize(), DumpOpts: RangeDumpOpts, Obj: &Obj); |
149 | else |
150 | OS << "<default>" ; |
151 | } |
152 | if (!Loc) |
153 | consumeError(Err: Loc.takeError()); |
154 | |
155 | if (E.Kind != dwarf::DW_LLE_base_address && |
156 | E.Kind != dwarf::DW_LLE_base_addressx && |
157 | E.Kind != dwarf::DW_LLE_end_of_list) { |
158 | OS << ": " ; |
159 | dumpExpression(OS, DumpOpts, Data: E.Loc, IsLittleEndian: Data.isLittleEndian(), |
160 | AddressSize: Data.getAddressSize(), U); |
161 | } |
162 | return true; |
163 | }); |
164 | if (E) { |
165 | DumpOpts.RecoverableErrorHandler(std::move(E)); |
166 | return false; |
167 | } |
168 | return true; |
169 | } |
170 | |
171 | Error DWARFLocationTable::visitAbsoluteLocationList( |
172 | uint64_t Offset, std::optional<SectionedAddress> BaseAddr, |
173 | std::function<std::optional<SectionedAddress>(uint32_t)> LookupAddr, |
174 | function_ref<bool(Expected<DWARFLocationExpression>)> Callback) const { |
175 | DWARFLocationInterpreter Interp(BaseAddr, std::move(LookupAddr)); |
176 | return visitLocationList(Offset: &Offset, Callback: [&](const DWARFLocationEntry &E) { |
177 | Expected<std::optional<DWARFLocationExpression>> Loc = Interp.Interpret(E); |
178 | if (!Loc) |
179 | return Callback(Loc.takeError()); |
180 | if (*Loc) |
181 | return Callback(**Loc); |
182 | return true; |
183 | }); |
184 | } |
185 | |
186 | void DWARFDebugLoc::dump(raw_ostream &OS, const DWARFObject &Obj, |
187 | DIDumpOptions DumpOpts, |
188 | std::optional<uint64_t> DumpOffset) const { |
189 | auto BaseAddr = std::nullopt; |
190 | unsigned Indent = 12; |
191 | if (DumpOffset) { |
192 | dumpLocationList(Offset: &*DumpOffset, OS, BaseAddr, Obj, U: nullptr, DumpOpts, |
193 | Indent); |
194 | } else { |
195 | uint64_t Offset = 0; |
196 | StringRef Separator; |
197 | bool CanContinue = true; |
198 | while (CanContinue && Data.isValidOffset(offset: Offset)) { |
199 | OS << Separator; |
200 | Separator = "\n" ; |
201 | |
202 | CanContinue = dumpLocationList(Offset: &Offset, OS, BaseAddr, Obj, U: nullptr, |
203 | DumpOpts, Indent); |
204 | OS << '\n'; |
205 | } |
206 | } |
207 | } |
208 | |
209 | Error DWARFDebugLoc::visitLocationList( |
210 | uint64_t *Offset, |
211 | function_ref<bool(const DWARFLocationEntry &)> Callback) const { |
212 | DataExtractor::Cursor C(*Offset); |
213 | while (true) { |
214 | uint64_t SectionIndex; |
215 | uint64_t Value0 = Data.getRelocatedAddress(C); |
216 | uint64_t Value1 = Data.getRelocatedAddress(C, SecIx: &SectionIndex); |
217 | |
218 | DWARFLocationEntry E; |
219 | |
220 | // The end of any given location list is marked by an end of list entry, |
221 | // which consists of a 0 for the beginning address offset and a 0 for the |
222 | // ending address offset. A beginning offset of 0xff...f marks the base |
223 | // address selection entry. |
224 | if (Value0 == 0 && Value1 == 0) { |
225 | E.Kind = dwarf::DW_LLE_end_of_list; |
226 | } else if (Value0 == (Data.getAddressSize() == 4 ? -1U : -1ULL)) { |
227 | E.Kind = dwarf::DW_LLE_base_address; |
228 | E.Value0 = Value1; |
229 | E.SectionIndex = SectionIndex; |
230 | } else { |
231 | E.Kind = dwarf::DW_LLE_offset_pair; |
232 | E.Value0 = Value0; |
233 | E.Value1 = Value1; |
234 | E.SectionIndex = SectionIndex; |
235 | unsigned Bytes = Data.getU16(C); |
236 | // A single location description describing the location of the object... |
237 | Data.getU8(C, Dst&: E.Loc, Count: Bytes); |
238 | } |
239 | |
240 | if (!C) |
241 | return C.takeError(); |
242 | if (!Callback(E) || E.Kind == dwarf::DW_LLE_end_of_list) |
243 | break; |
244 | } |
245 | *Offset = C.tell(); |
246 | return Error::success(); |
247 | } |
248 | |
249 | void DWARFDebugLoc::dumpRawEntry(const DWARFLocationEntry &Entry, |
250 | raw_ostream &OS, unsigned Indent, |
251 | DIDumpOptions DumpOpts, |
252 | const DWARFObject &Obj) const { |
253 | uint64_t Value0, Value1; |
254 | switch (Entry.Kind) { |
255 | case dwarf::DW_LLE_base_address: |
256 | Value0 = Data.getAddressSize() == 4 ? -1U : -1ULL; |
257 | Value1 = Entry.Value0; |
258 | break; |
259 | case dwarf::DW_LLE_offset_pair: |
260 | Value0 = Entry.Value0; |
261 | Value1 = Entry.Value1; |
262 | break; |
263 | case dwarf::DW_LLE_end_of_list: |
264 | return; |
265 | default: |
266 | llvm_unreachable("Not possible in DWARF4!" ); |
267 | } |
268 | OS << '\n'; |
269 | OS.indent(NumSpaces: Indent); |
270 | OS << '(' << format_hex(N: Value0, Width: 2 + Data.getAddressSize() * 2) << ", " |
271 | << format_hex(N: Value1, Width: 2 + Data.getAddressSize() * 2) << ')'; |
272 | DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, SectionIndex: Entry.SectionIndex); |
273 | } |
274 | |
275 | Error DWARFDebugLoclists::visitLocationList( |
276 | uint64_t *Offset, function_ref<bool(const DWARFLocationEntry &)> F) const { |
277 | |
278 | DataExtractor::Cursor C(*Offset); |
279 | bool Continue = true; |
280 | while (Continue) { |
281 | DWARFLocationEntry E; |
282 | E.Kind = Data.getU8(C); |
283 | switch (E.Kind) { |
284 | case dwarf::DW_LLE_end_of_list: |
285 | break; |
286 | case dwarf::DW_LLE_base_addressx: |
287 | E.Value0 = Data.getULEB128(C); |
288 | break; |
289 | case dwarf::DW_LLE_startx_endx: |
290 | E.Value0 = Data.getULEB128(C); |
291 | E.Value1 = Data.getULEB128(C); |
292 | break; |
293 | case dwarf::DW_LLE_startx_length: |
294 | E.Value0 = Data.getULEB128(C); |
295 | // Pre-DWARF 5 has different interpretation of the length field. We have |
296 | // to support both pre- and standartized styles for the compatibility. |
297 | if (Version < 5) |
298 | E.Value1 = Data.getU32(C); |
299 | else |
300 | E.Value1 = Data.getULEB128(C); |
301 | break; |
302 | case dwarf::DW_LLE_offset_pair: |
303 | E.Value0 = Data.getULEB128(C); |
304 | E.Value1 = Data.getULEB128(C); |
305 | E.SectionIndex = SectionedAddress::UndefSection; |
306 | break; |
307 | case dwarf::DW_LLE_default_location: |
308 | break; |
309 | case dwarf::DW_LLE_base_address: |
310 | E.Value0 = Data.getRelocatedAddress(C, SecIx: &E.SectionIndex); |
311 | break; |
312 | case dwarf::DW_LLE_start_end: |
313 | E.Value0 = Data.getRelocatedAddress(C, SecIx: &E.SectionIndex); |
314 | E.Value1 = Data.getRelocatedAddress(C); |
315 | break; |
316 | case dwarf::DW_LLE_start_length: |
317 | E.Value0 = Data.getRelocatedAddress(C, SecIx: &E.SectionIndex); |
318 | E.Value1 = Data.getULEB128(C); |
319 | break; |
320 | default: |
321 | cantFail(Err: C.takeError()); |
322 | return createStringError(EC: errc::illegal_byte_sequence, |
323 | Fmt: "LLE of kind %x not supported" , Vals: (int)E.Kind); |
324 | } |
325 | |
326 | if (E.Kind != dwarf::DW_LLE_base_address && |
327 | E.Kind != dwarf::DW_LLE_base_addressx && |
328 | E.Kind != dwarf::DW_LLE_end_of_list) { |
329 | unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C); |
330 | // A single location description describing the location of the object... |
331 | Data.getU8(C, Dst&: E.Loc, Count: Bytes); |
332 | } |
333 | |
334 | if (!C) |
335 | return C.takeError(); |
336 | Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list; |
337 | } |
338 | *Offset = C.tell(); |
339 | return Error::success(); |
340 | } |
341 | |
342 | void DWARFDebugLoclists::dumpRawEntry(const DWARFLocationEntry &Entry, |
343 | raw_ostream &OS, unsigned Indent, |
344 | DIDumpOptions DumpOpts, |
345 | const DWARFObject &Obj) const { |
346 | size_t MaxEncodingStringLength = 0; |
347 | #define HANDLE_DW_LLE(ID, NAME) \ |
348 | MaxEncodingStringLength = std::max(MaxEncodingStringLength, \ |
349 | dwarf::LocListEncodingString(ID).size()); |
350 | #include "llvm/BinaryFormat/Dwarf.def" |
351 | |
352 | OS << "\n" ; |
353 | OS.indent(NumSpaces: Indent); |
354 | StringRef EncodingString = dwarf::LocListEncodingString(Encoding: Entry.Kind); |
355 | // Unsupported encodings should have been reported during parsing. |
356 | assert(!EncodingString.empty() && "Unknown loclist entry encoding" ); |
357 | OS << format(Fmt: "%-*s(" , Vals: MaxEncodingStringLength, Vals: EncodingString.data()); |
358 | unsigned FieldSize = 2 + 2 * Data.getAddressSize(); |
359 | switch (Entry.Kind) { |
360 | case dwarf::DW_LLE_end_of_list: |
361 | case dwarf::DW_LLE_default_location: |
362 | break; |
363 | case dwarf::DW_LLE_startx_endx: |
364 | case dwarf::DW_LLE_startx_length: |
365 | case dwarf::DW_LLE_offset_pair: |
366 | case dwarf::DW_LLE_start_end: |
367 | case dwarf::DW_LLE_start_length: |
368 | OS << format_hex(N: Entry.Value0, Width: FieldSize) << ", " |
369 | << format_hex(N: Entry.Value1, Width: FieldSize); |
370 | break; |
371 | case dwarf::DW_LLE_base_addressx: |
372 | case dwarf::DW_LLE_base_address: |
373 | OS << format_hex(N: Entry.Value0, Width: FieldSize); |
374 | break; |
375 | } |
376 | OS << ')'; |
377 | switch (Entry.Kind) { |
378 | case dwarf::DW_LLE_base_address: |
379 | case dwarf::DW_LLE_start_end: |
380 | case dwarf::DW_LLE_start_length: |
381 | DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, SectionIndex: Entry.SectionIndex); |
382 | break; |
383 | default: |
384 | break; |
385 | } |
386 | } |
387 | |
388 | void DWARFDebugLoclists::dumpRange(uint64_t StartOffset, uint64_t Size, |
389 | raw_ostream &OS, const DWARFObject &Obj, |
390 | DIDumpOptions DumpOpts) { |
391 | if (!Data.isValidOffsetForDataOfSize(offset: StartOffset, length: Size)) { |
392 | OS << "Invalid dump range\n" ; |
393 | return; |
394 | } |
395 | uint64_t Offset = StartOffset; |
396 | StringRef Separator; |
397 | bool CanContinue = true; |
398 | while (CanContinue && Offset < StartOffset + Size) { |
399 | OS << Separator; |
400 | Separator = "\n" ; |
401 | |
402 | CanContinue = dumpLocationList(Offset: &Offset, OS, /*BaseAddr=*/std::nullopt, Obj, |
403 | U: nullptr, DumpOpts, /*Indent=*/12); |
404 | OS << '\n'; |
405 | } |
406 | } |
407 | |
408 | void llvm::ResolverError::log(raw_ostream &OS) const { |
409 | OS << format(Fmt: "unable to resolve indirect address %u for: %s" , Vals: Index, |
410 | Vals: dwarf::LocListEncodingString(Encoding: Kind).data()); |
411 | } |
412 | |
413 | char llvm::ResolverError::ID; |
414 | |