1 | //===- DWARFDie.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/DWARFDie.h" |
10 | #include "llvm/ADT/SmallPtrSet.h" |
11 | #include "llvm/ADT/SmallSet.h" |
12 | #include "llvm/ADT/StringRef.h" |
13 | #include "llvm/BinaryFormat/Dwarf.h" |
14 | #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" |
15 | #include "llvm/DebugInfo/DWARF/DWARFContext.h" |
16 | #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" |
17 | #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" |
18 | #include "llvm/DebugInfo/DWARF/DWARFExpression.h" |
19 | #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" |
20 | #include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h" |
21 | #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" |
22 | #include "llvm/DebugInfo/DWARF/DWARFUnit.h" |
23 | #include "llvm/Object/ObjectFile.h" |
24 | #include "llvm/Support/DataExtractor.h" |
25 | #include "llvm/Support/Format.h" |
26 | #include "llvm/Support/FormatVariadic.h" |
27 | #include "llvm/Support/MathExtras.h" |
28 | #include "llvm/Support/WithColor.h" |
29 | #include "llvm/Support/raw_ostream.h" |
30 | #include <cassert> |
31 | #include <cinttypes> |
32 | #include <cstdint> |
33 | #include <string> |
34 | #include <utility> |
35 | |
36 | using namespace llvm; |
37 | using namespace dwarf; |
38 | using namespace object; |
39 | |
40 | static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) { |
41 | OS << " (" ; |
42 | do { |
43 | uint64_t Shift = llvm::countr_zero(Val); |
44 | assert(Shift < 64 && "undefined behavior" ); |
45 | uint64_t Bit = 1ULL << Shift; |
46 | auto PropName = ApplePropertyString(Bit); |
47 | if (!PropName.empty()) |
48 | OS << PropName; |
49 | else |
50 | OS << format(Fmt: "DW_APPLE_PROPERTY_0x%" PRIx64, Vals: Bit); |
51 | if (!(Val ^= Bit)) |
52 | break; |
53 | OS << ", " ; |
54 | } while (true); |
55 | OS << ")" ; |
56 | } |
57 | |
58 | static void dumpRanges(const DWARFObject &Obj, raw_ostream &OS, |
59 | const DWARFAddressRangesVector &Ranges, |
60 | unsigned AddressSize, unsigned Indent, |
61 | const DIDumpOptions &DumpOpts) { |
62 | if (!DumpOpts.ShowAddresses) |
63 | return; |
64 | |
65 | for (const DWARFAddressRange &R : Ranges) { |
66 | OS << '\n'; |
67 | OS.indent(NumSpaces: Indent); |
68 | R.dump(OS, AddressSize, DumpOpts, Obj: &Obj); |
69 | } |
70 | } |
71 | |
72 | static void dumpLocationList(raw_ostream &OS, const DWARFFormValue &FormValue, |
73 | DWARFUnit *U, unsigned Indent, |
74 | DIDumpOptions DumpOpts) { |
75 | assert(FormValue.isFormClass(DWARFFormValue::FC_SectionOffset) && |
76 | "bad FORM for location list" ); |
77 | DWARFContext &Ctx = U->getContext(); |
78 | uint64_t Offset = *FormValue.getAsSectionOffset(); |
79 | |
80 | if (FormValue.getForm() == DW_FORM_loclistx) { |
81 | FormValue.dump(OS, DumpOpts); |
82 | |
83 | if (auto LoclistOffset = U->getLoclistOffset(Index: Offset)) |
84 | Offset = *LoclistOffset; |
85 | else |
86 | return; |
87 | } |
88 | U->getLocationTable().dumpLocationList( |
89 | Offset: &Offset, OS, BaseAddr: U->getBaseAddress(), Obj: Ctx.getDWARFObj(), U, DumpOpts, Indent); |
90 | } |
91 | |
92 | static void dumpLocationExpr(raw_ostream &OS, const DWARFFormValue &FormValue, |
93 | DWARFUnit *U, unsigned Indent, |
94 | DIDumpOptions DumpOpts) { |
95 | assert((FormValue.isFormClass(DWARFFormValue::FC_Block) || |
96 | FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) && |
97 | "bad FORM for location expression" ); |
98 | DWARFContext &Ctx = U->getContext(); |
99 | ArrayRef<uint8_t> Expr = *FormValue.getAsBlock(); |
100 | DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()), |
101 | Ctx.isLittleEndian(), 0); |
102 | DWARFExpression(Data, U->getAddressByteSize(), U->getFormParams().Format) |
103 | .print(OS, DumpOpts, U); |
104 | } |
105 | |
106 | static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) { |
107 | return D.getAttributeValueAsReferencedDie(V: F).resolveTypeUnitReference(); |
108 | } |
109 | |
110 | static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, |
111 | const DWARFAttribute &AttrValue, unsigned Indent, |
112 | DIDumpOptions DumpOpts) { |
113 | if (!Die.isValid()) |
114 | return; |
115 | const char BaseIndent[] = " " ; |
116 | OS << BaseIndent; |
117 | OS.indent(NumSpaces: Indent + 2); |
118 | dwarf::Attribute Attr = AttrValue.Attr; |
119 | WithColor(OS, HighlightColor::Attribute) << formatv(Fmt: "{0}" , Vals&: Attr); |
120 | |
121 | dwarf::Form Form = AttrValue.Value.getForm(); |
122 | if (DumpOpts.Verbose || DumpOpts.ShowForm) |
123 | OS << formatv(Fmt: " [{0}]" , Vals&: Form); |
124 | |
125 | DWARFUnit *U = Die.getDwarfUnit(); |
126 | const DWARFFormValue &FormValue = AttrValue.Value; |
127 | |
128 | OS << "\t(" ; |
129 | |
130 | StringRef Name; |
131 | std::string File; |
132 | auto Color = HighlightColor::Enumerator; |
133 | if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) { |
134 | Color = HighlightColor::String; |
135 | if (const auto *LT = U->getContext().getLineTableForUnit(U)) { |
136 | if (std::optional<uint64_t> Val = FormValue.getAsUnsignedConstant()) { |
137 | if (LT->getFileNameByIndex( |
138 | FileIndex: *Val, CompDir: U->getCompilationDir(), |
139 | Kind: DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, |
140 | Result&: File)) { |
141 | File = '"' + File + '"'; |
142 | Name = File; |
143 | } |
144 | } |
145 | } |
146 | } else if (std::optional<uint64_t> Val = FormValue.getAsUnsignedConstant()) |
147 | Name = AttributeValueString(Attr, Val: *Val); |
148 | |
149 | if (!Name.empty()) |
150 | WithColor(OS, Color) << Name; |
151 | else if (Attr == DW_AT_decl_line || Attr == DW_AT_decl_column || |
152 | Attr == DW_AT_call_line || Attr == DW_AT_call_column) { |
153 | if (std::optional<uint64_t> Val = FormValue.getAsUnsignedConstant()) |
154 | OS << *Val; |
155 | else |
156 | FormValue.dump(OS, DumpOpts); |
157 | } else if (Attr == DW_AT_low_pc && |
158 | (FormValue.getAsAddress() == |
159 | dwarf::computeTombstoneAddress(AddressByteSize: U->getAddressByteSize()))) { |
160 | if (DumpOpts.Verbose) { |
161 | FormValue.dump(OS, DumpOpts); |
162 | OS << " (" ; |
163 | } |
164 | OS << "dead code" ; |
165 | if (DumpOpts.Verbose) |
166 | OS << ')'; |
167 | } else if (Attr == DW_AT_high_pc && !DumpOpts.ShowForm && !DumpOpts.Verbose && |
168 | FormValue.getAsUnsignedConstant()) { |
169 | if (DumpOpts.ShowAddresses) { |
170 | // Print the actual address rather than the offset. |
171 | uint64_t LowPC, HighPC, Index; |
172 | if (Die.getLowAndHighPC(LowPC, HighPC, SectionIndex&: Index)) |
173 | DWARFFormValue::dumpAddress(OS, AddressSize: U->getAddressByteSize(), Address: HighPC); |
174 | else |
175 | FormValue.dump(OS, DumpOpts); |
176 | } |
177 | } else if (DWARFAttribute::mayHaveLocationList(Attr) && |
178 | FormValue.isFormClass(FC: DWARFFormValue::FC_SectionOffset)) |
179 | dumpLocationList(OS, FormValue, U, Indent: sizeof(BaseIndent) + Indent + 4, |
180 | DumpOpts); |
181 | else if (FormValue.isFormClass(FC: DWARFFormValue::FC_Exprloc) || |
182 | (DWARFAttribute::mayHaveLocationExpr(Attr) && |
183 | FormValue.isFormClass(FC: DWARFFormValue::FC_Block))) |
184 | dumpLocationExpr(OS, FormValue, U, Indent: sizeof(BaseIndent) + Indent + 4, |
185 | DumpOpts); |
186 | else |
187 | FormValue.dump(OS, DumpOpts); |
188 | |
189 | std::string Space = DumpOpts.ShowAddresses ? " " : "" ; |
190 | |
191 | // We have dumped the attribute raw value. For some attributes |
192 | // having both the raw value and the pretty-printed value is |
193 | // interesting. These attributes are handled below. |
194 | if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin || |
195 | Attr == DW_AT_call_origin) { |
196 | if (const char *Name = |
197 | Die.getAttributeValueAsReferencedDie(V: FormValue).getName( |
198 | Kind: DINameKind::LinkageName)) |
199 | OS << Space << "\"" << Name << '\"'; |
200 | } else if (Attr == DW_AT_type || Attr == DW_AT_containing_type) { |
201 | DWARFDie D = resolveReferencedType(D: Die, F: FormValue); |
202 | if (D && !D.isNULL()) { |
203 | OS << Space << "\"" ; |
204 | dumpTypeQualifiedName(DIE: D, OS); |
205 | OS << '"'; |
206 | } |
207 | } else if (Attr == DW_AT_APPLE_property_attribute) { |
208 | if (std::optional<uint64_t> OptVal = FormValue.getAsUnsignedConstant()) |
209 | dumpApplePropertyAttribute(OS, Val: *OptVal); |
210 | } else if (Attr == DW_AT_ranges) { |
211 | const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj(); |
212 | // For DW_FORM_rnglistx we need to dump the offset separately, since |
213 | // we have only dumped the index so far. |
214 | if (FormValue.getForm() == DW_FORM_rnglistx) |
215 | if (auto RangeListOffset = |
216 | U->getRnglistOffset(Index: *FormValue.getAsSectionOffset())) { |
217 | DWARFFormValue FV = DWARFFormValue::createFromUValue( |
218 | F: dwarf::DW_FORM_sec_offset, V: *RangeListOffset); |
219 | FV.dump(OS, DumpOpts); |
220 | } |
221 | if (auto RangesOrError = Die.getAddressRanges()) |
222 | dumpRanges(Obj, OS, Ranges: RangesOrError.get(), AddressSize: U->getAddressByteSize(), |
223 | Indent: sizeof(BaseIndent) + Indent + 4, DumpOpts); |
224 | else |
225 | DumpOpts.RecoverableErrorHandler(createStringError( |
226 | EC: errc::invalid_argument, Fmt: "decoding address ranges: %s" , |
227 | Vals: toString(E: RangesOrError.takeError()).c_str())); |
228 | } |
229 | |
230 | OS << ")\n" ; |
231 | } |
232 | |
233 | void DWARFDie::getFullName(raw_string_ostream &OS, |
234 | std::string *OriginalFullName) const { |
235 | const char *NamePtr = getShortName(); |
236 | if (!NamePtr) |
237 | return; |
238 | if (getTag() == DW_TAG_GNU_template_parameter_pack) |
239 | return; |
240 | dumpTypeUnqualifiedName(DIE: *this, OS, OriginalFullName); |
241 | } |
242 | |
243 | bool DWARFDie::isSubprogramDIE() const { return getTag() == DW_TAG_subprogram; } |
244 | |
245 | bool DWARFDie::isSubroutineDIE() const { |
246 | auto Tag = getTag(); |
247 | return Tag == DW_TAG_subprogram || Tag == DW_TAG_inlined_subroutine; |
248 | } |
249 | |
250 | std::optional<DWARFFormValue> DWARFDie::find(dwarf::Attribute Attr) const { |
251 | if (!isValid()) |
252 | return std::nullopt; |
253 | auto AbbrevDecl = getAbbreviationDeclarationPtr(); |
254 | if (AbbrevDecl) |
255 | return AbbrevDecl->getAttributeValue(DIEOffset: getOffset(), Attr, U: *U); |
256 | return std::nullopt; |
257 | } |
258 | |
259 | std::optional<DWARFFormValue> |
260 | DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const { |
261 | if (!isValid()) |
262 | return std::nullopt; |
263 | auto AbbrevDecl = getAbbreviationDeclarationPtr(); |
264 | if (AbbrevDecl) { |
265 | for (auto Attr : Attrs) { |
266 | if (auto Value = AbbrevDecl->getAttributeValue(DIEOffset: getOffset(), Attr, U: *U)) |
267 | return Value; |
268 | } |
269 | } |
270 | return std::nullopt; |
271 | } |
272 | |
273 | std::optional<DWARFFormValue> |
274 | DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const { |
275 | SmallVector<DWARFDie, 3> Worklist; |
276 | Worklist.push_back(Elt: *this); |
277 | |
278 | // Keep track if DIEs already seen to prevent infinite recursion. |
279 | // Empirically we rarely see a depth of more than 3 when dealing with valid |
280 | // DWARF. This corresponds to following the DW_AT_abstract_origin and |
281 | // DW_AT_specification just once. |
282 | SmallSet<DWARFDie, 3> Seen; |
283 | Seen.insert(V: *this); |
284 | |
285 | while (!Worklist.empty()) { |
286 | DWARFDie Die = Worklist.pop_back_val(); |
287 | |
288 | if (!Die.isValid()) |
289 | continue; |
290 | |
291 | if (auto Value = Die.find(Attrs)) |
292 | return Value; |
293 | |
294 | if (auto D = Die.getAttributeValueAsReferencedDie(Attr: DW_AT_abstract_origin)) |
295 | if (Seen.insert(V: D).second) |
296 | Worklist.push_back(Elt: D); |
297 | |
298 | if (auto D = Die.getAttributeValueAsReferencedDie(Attr: DW_AT_specification)) |
299 | if (Seen.insert(V: D).second) |
300 | Worklist.push_back(Elt: D); |
301 | } |
302 | |
303 | return std::nullopt; |
304 | } |
305 | |
306 | DWARFDie |
307 | DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { |
308 | if (std::optional<DWARFFormValue> F = find(Attr)) |
309 | return getAttributeValueAsReferencedDie(V: *F); |
310 | return DWARFDie(); |
311 | } |
312 | |
313 | DWARFDie |
314 | DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const { |
315 | DWARFDie Result; |
316 | if (std::optional<uint64_t> Offset = V.getAsRelativeReference()) { |
317 | Result = const_cast<DWARFUnit *>(V.getUnit()) |
318 | ->getDIEForOffset(Offset: V.getUnit()->getOffset() + *Offset); |
319 | } else if (Offset = V.getAsDebugInfoReference(); Offset) { |
320 | if (DWARFUnit *SpecUnit = U->getUnitVector().getUnitForOffset(Offset: *Offset)) |
321 | Result = SpecUnit->getDIEForOffset(Offset: *Offset); |
322 | } |
323 | return Result; |
324 | } |
325 | |
326 | DWARFDie DWARFDie::resolveTypeUnitReference() const { |
327 | if (auto Attr = find(Attr: DW_AT_signature)) { |
328 | if (std::optional<uint64_t> Sig = Attr->getAsReferenceUVal()) { |
329 | if (DWARFTypeUnit *TU = U->getContext().getTypeUnitForHash( |
330 | Version: U->getVersion(), Hash: *Sig, IsDWO: U->isDWOUnit())) |
331 | return TU->getDIEForOffset(Offset: TU->getTypeOffset() + TU->getOffset()); |
332 | } |
333 | } |
334 | return *this; |
335 | } |
336 | |
337 | std::optional<uint64_t> DWARFDie::getRangesBaseAttribute() const { |
338 | return toSectionOffset(V: find(Attrs: {DW_AT_rnglists_base, DW_AT_GNU_ranges_base})); |
339 | } |
340 | |
341 | std::optional<uint64_t> DWARFDie::getLocBaseAttribute() const { |
342 | return toSectionOffset(V: find(Attr: DW_AT_loclists_base)); |
343 | } |
344 | |
345 | std::optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const { |
346 | uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressByteSize: U->getAddressByteSize()); |
347 | if (LowPC == Tombstone) |
348 | return std::nullopt; |
349 | if (auto FormValue = find(Attr: DW_AT_high_pc)) { |
350 | if (auto Address = FormValue->getAsAddress()) { |
351 | // High PC is an address. |
352 | return Address; |
353 | } |
354 | if (auto Offset = FormValue->getAsUnsignedConstant()) { |
355 | // High PC is an offset from LowPC. |
356 | return LowPC + *Offset; |
357 | } |
358 | } |
359 | return std::nullopt; |
360 | } |
361 | |
362 | bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC, |
363 | uint64_t &SectionIndex) const { |
364 | auto F = find(Attr: DW_AT_low_pc); |
365 | auto LowPcAddr = toSectionedAddress(V: F); |
366 | if (!LowPcAddr) |
367 | return false; |
368 | if (auto HighPcAddr = getHighPC(LowPC: LowPcAddr->Address)) { |
369 | LowPC = LowPcAddr->Address; |
370 | HighPC = *HighPcAddr; |
371 | SectionIndex = LowPcAddr->SectionIndex; |
372 | return true; |
373 | } |
374 | return false; |
375 | } |
376 | |
377 | Expected<DWARFAddressRangesVector> DWARFDie::getAddressRanges() const { |
378 | if (isNULL()) |
379 | return DWARFAddressRangesVector(); |
380 | // Single range specified by low/high PC. |
381 | uint64_t LowPC, HighPC, Index; |
382 | if (getLowAndHighPC(LowPC, HighPC, SectionIndex&: Index)) |
383 | return DWARFAddressRangesVector{{LowPC, HighPC, Index}}; |
384 | |
385 | std::optional<DWARFFormValue> Value = find(Attr: DW_AT_ranges); |
386 | if (Value) { |
387 | if (Value->getForm() == DW_FORM_rnglistx) |
388 | return U->findRnglistFromIndex(Index: *Value->getAsSectionOffset()); |
389 | return U->findRnglistFromOffset(Offset: *Value->getAsSectionOffset()); |
390 | } |
391 | return DWARFAddressRangesVector(); |
392 | } |
393 | |
394 | bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const { |
395 | auto RangesOrError = getAddressRanges(); |
396 | if (!RangesOrError) { |
397 | llvm::consumeError(Err: RangesOrError.takeError()); |
398 | return false; |
399 | } |
400 | |
401 | for (const auto &R : RangesOrError.get()) |
402 | if (R.LowPC <= Address && Address < R.HighPC) |
403 | return true; |
404 | return false; |
405 | } |
406 | |
407 | Expected<DWARFLocationExpressionsVector> |
408 | DWARFDie::getLocations(dwarf::Attribute Attr) const { |
409 | std::optional<DWARFFormValue> Location = find(Attr); |
410 | if (!Location) |
411 | return createStringError(EC: inconvertibleErrorCode(), Fmt: "No %s" , |
412 | Vals: dwarf::AttributeString(Attribute: Attr).data()); |
413 | |
414 | if (std::optional<uint64_t> Off = Location->getAsSectionOffset()) { |
415 | uint64_t Offset = *Off; |
416 | |
417 | if (Location->getForm() == DW_FORM_loclistx) { |
418 | if (auto LoclistOffset = U->getLoclistOffset(Index: Offset)) |
419 | Offset = *LoclistOffset; |
420 | else |
421 | return createStringError(EC: inconvertibleErrorCode(), |
422 | S: "Loclist table not found" ); |
423 | } |
424 | return U->findLoclistFromOffset(Offset); |
425 | } |
426 | |
427 | if (std::optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) { |
428 | return DWARFLocationExpressionsVector{ |
429 | DWARFLocationExpression{.Range: std::nullopt, .Expr: to_vector<4>(Range&: *Expr)}}; |
430 | } |
431 | |
432 | return createStringError( |
433 | EC: inconvertibleErrorCode(), Fmt: "Unsupported %s encoding: %s" , |
434 | Vals: dwarf::AttributeString(Attribute: Attr).data(), |
435 | Vals: dwarf::FormEncodingString(Encoding: Location->getForm()).data()); |
436 | } |
437 | |
438 | const char *DWARFDie::getSubroutineName(DINameKind Kind) const { |
439 | if (!isSubroutineDIE()) |
440 | return nullptr; |
441 | return getName(Kind); |
442 | } |
443 | |
444 | const char *DWARFDie::getName(DINameKind Kind) const { |
445 | if (!isValid() || Kind == DINameKind::None) |
446 | return nullptr; |
447 | // Try to get mangled name only if it was asked for. |
448 | if (Kind == DINameKind::LinkageName) { |
449 | if (auto Name = getLinkageName()) |
450 | return Name; |
451 | } |
452 | return getShortName(); |
453 | } |
454 | |
455 | const char *DWARFDie::getShortName() const { |
456 | if (!isValid()) |
457 | return nullptr; |
458 | |
459 | return dwarf::toString(V: findRecursively(Attrs: dwarf::DW_AT_name), Default: nullptr); |
460 | } |
461 | |
462 | const char *DWARFDie::getLinkageName() const { |
463 | if (!isValid()) |
464 | return nullptr; |
465 | |
466 | return dwarf::toString(V: findRecursively(Attrs: {dwarf::DW_AT_MIPS_linkage_name, |
467 | dwarf::DW_AT_linkage_name}), |
468 | Default: nullptr); |
469 | } |
470 | |
471 | uint64_t DWARFDie::getDeclLine() const { |
472 | return toUnsigned(V: findRecursively(Attrs: DW_AT_decl_line), Default: 0); |
473 | } |
474 | |
475 | std::string |
476 | DWARFDie::getDeclFile(DILineInfoSpecifier::FileLineInfoKind Kind) const { |
477 | if (auto FormValue = findRecursively(Attrs: DW_AT_decl_file)) |
478 | if (auto OptString = FormValue->getAsFile(Kind)) |
479 | return *OptString; |
480 | return {}; |
481 | } |
482 | |
483 | void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, |
484 | uint32_t &CallColumn, |
485 | uint32_t &CallDiscriminator) const { |
486 | CallFile = toUnsigned(V: find(Attr: DW_AT_call_file), Default: 0); |
487 | CallLine = toUnsigned(V: find(Attr: DW_AT_call_line), Default: 0); |
488 | CallColumn = toUnsigned(V: find(Attr: DW_AT_call_column), Default: 0); |
489 | CallDiscriminator = toUnsigned(V: find(Attr: DW_AT_GNU_discriminator), Default: 0); |
490 | } |
491 | |
492 | static std::optional<uint64_t> |
493 | getTypeSizeImpl(DWARFDie Die, uint64_t PointerSize, |
494 | SmallPtrSetImpl<const DWARFDebugInfoEntry *> &Visited) { |
495 | // Cycle detected? |
496 | if (!Visited.insert(Ptr: Die.getDebugInfoEntry()).second) |
497 | return {}; |
498 | if (auto SizeAttr = Die.find(Attr: DW_AT_byte_size)) |
499 | if (std::optional<uint64_t> Size = SizeAttr->getAsUnsignedConstant()) |
500 | return Size; |
501 | |
502 | switch (Die.getTag()) { |
503 | case DW_TAG_pointer_type: |
504 | case DW_TAG_reference_type: |
505 | case DW_TAG_rvalue_reference_type: |
506 | return PointerSize; |
507 | case DW_TAG_ptr_to_member_type: { |
508 | if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(Attr: DW_AT_type)) |
509 | if (BaseType.getTag() == DW_TAG_subroutine_type) |
510 | return 2 * PointerSize; |
511 | return PointerSize; |
512 | } |
513 | case DW_TAG_const_type: |
514 | case DW_TAG_immutable_type: |
515 | case DW_TAG_volatile_type: |
516 | case DW_TAG_restrict_type: |
517 | case DW_TAG_template_alias: |
518 | case DW_TAG_typedef: { |
519 | if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(Attr: DW_AT_type)) |
520 | return getTypeSizeImpl(Die: BaseType, PointerSize, Visited); |
521 | break; |
522 | } |
523 | case DW_TAG_array_type: { |
524 | DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(Attr: DW_AT_type); |
525 | if (!BaseType) |
526 | return std::nullopt; |
527 | std::optional<uint64_t> BaseSize = |
528 | getTypeSizeImpl(Die: BaseType, PointerSize, Visited); |
529 | if (!BaseSize) |
530 | return std::nullopt; |
531 | uint64_t Size = *BaseSize; |
532 | for (DWARFDie Child : Die) { |
533 | if (Child.getTag() != DW_TAG_subrange_type) |
534 | continue; |
535 | |
536 | if (auto ElemCountAttr = Child.find(Attr: DW_AT_count)) |
537 | if (std::optional<uint64_t> ElemCount = |
538 | ElemCountAttr->getAsUnsignedConstant()) |
539 | Size *= *ElemCount; |
540 | if (auto UpperBoundAttr = Child.find(Attr: DW_AT_upper_bound)) |
541 | if (std::optional<int64_t> UpperBound = |
542 | UpperBoundAttr->getAsSignedConstant()) { |
543 | int64_t LowerBound = 0; |
544 | if (auto LowerBoundAttr = Child.find(Attr: DW_AT_lower_bound)) |
545 | LowerBound = LowerBoundAttr->getAsSignedConstant().value_or(u: 0); |
546 | Size *= *UpperBound - LowerBound + 1; |
547 | } |
548 | } |
549 | return Size; |
550 | } |
551 | default: |
552 | if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(Attr: DW_AT_type)) |
553 | return getTypeSizeImpl(Die: BaseType, PointerSize, Visited); |
554 | break; |
555 | } |
556 | return std::nullopt; |
557 | } |
558 | |
559 | std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) { |
560 | SmallPtrSet<const DWARFDebugInfoEntry *, 4> Visited; |
561 | return getTypeSizeImpl(Die: *this, PointerSize, Visited); |
562 | } |
563 | |
564 | /// Helper to dump a DIE with all of its parents, but no siblings. |
565 | static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent, |
566 | DIDumpOptions DumpOpts, unsigned Depth = 0) { |
567 | if (!Die) |
568 | return Indent; |
569 | if (DumpOpts.ParentRecurseDepth > 0 && Depth >= DumpOpts.ParentRecurseDepth) |
570 | return Indent; |
571 | Indent = dumpParentChain(Die: Die.getParent(), OS, Indent, DumpOpts, Depth: Depth + 1); |
572 | Die.dump(OS, indent: Indent, DumpOpts); |
573 | return Indent + 2; |
574 | } |
575 | |
576 | void DWARFDie::dump(raw_ostream &OS, unsigned Indent, |
577 | DIDumpOptions DumpOpts) const { |
578 | if (!isValid()) |
579 | return; |
580 | DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor(); |
581 | const uint64_t Offset = getOffset(); |
582 | uint64_t offset = Offset; |
583 | if (DumpOpts.ShowParents) { |
584 | DIDumpOptions ParentDumpOpts = DumpOpts; |
585 | ParentDumpOpts.ShowParents = false; |
586 | ParentDumpOpts.ShowChildren = false; |
587 | Indent = dumpParentChain(Die: getParent(), OS, Indent, DumpOpts: ParentDumpOpts); |
588 | } |
589 | |
590 | if (debug_info_data.isValidOffset(offset)) { |
591 | uint32_t abbrCode = debug_info_data.getULEB128(offset_ptr: &offset); |
592 | if (DumpOpts.ShowAddresses) |
593 | WithColor(OS, HighlightColor::Address).get() |
594 | << format(Fmt: "\n0x%8.8" PRIx64 ": " , Vals: Offset); |
595 | |
596 | if (abbrCode) { |
597 | auto AbbrevDecl = getAbbreviationDeclarationPtr(); |
598 | if (AbbrevDecl) { |
599 | WithColor(OS, HighlightColor::Tag).get().indent(NumSpaces: Indent) |
600 | << formatv(Fmt: "{0}" , Vals: getTag()); |
601 | if (DumpOpts.Verbose) { |
602 | OS << format(Fmt: " [%u] %c" , Vals: abbrCode, |
603 | Vals: AbbrevDecl->hasChildren() ? '*' : ' '); |
604 | if (std::optional<uint32_t> ParentIdx = Die->getParentIdx()) |
605 | OS << format(Fmt: " (0x%8.8" PRIx64 ")" , |
606 | Vals: U->getDIEAtIndex(Index: *ParentIdx).getOffset()); |
607 | } |
608 | OS << '\n'; |
609 | |
610 | // Dump all data in the DIE for the attributes. |
611 | for (const DWARFAttribute &AttrValue : attributes()) |
612 | dumpAttribute(OS, Die: *this, AttrValue, Indent, DumpOpts); |
613 | |
614 | if (DumpOpts.ShowChildren && DumpOpts.ChildRecurseDepth > 0) { |
615 | DWARFDie Child = getFirstChild(); |
616 | DumpOpts.ChildRecurseDepth--; |
617 | DIDumpOptions ChildDumpOpts = DumpOpts; |
618 | ChildDumpOpts.ShowParents = false; |
619 | while (Child) { |
620 | Child.dump(OS, Indent: Indent + 2, DumpOpts: ChildDumpOpts); |
621 | Child = Child.getSibling(); |
622 | } |
623 | } |
624 | } else { |
625 | OS << "Abbreviation code not found in 'debug_abbrev' class for code: " |
626 | << abbrCode << '\n'; |
627 | } |
628 | } else { |
629 | OS.indent(NumSpaces: Indent) << "NULL\n" ; |
630 | } |
631 | } |
632 | } |
633 | |
634 | LLVM_DUMP_METHOD void DWARFDie::dump() const { dump(OS&: llvm::errs(), Indent: 0); } |
635 | |
636 | DWARFDie DWARFDie::getParent() const { |
637 | if (isValid()) |
638 | return U->getParent(Die); |
639 | return DWARFDie(); |
640 | } |
641 | |
642 | DWARFDie DWARFDie::getSibling() const { |
643 | if (isValid()) |
644 | return U->getSibling(Die); |
645 | return DWARFDie(); |
646 | } |
647 | |
648 | DWARFDie DWARFDie::getPreviousSibling() const { |
649 | if (isValid()) |
650 | return U->getPreviousSibling(Die); |
651 | return DWARFDie(); |
652 | } |
653 | |
654 | DWARFDie DWARFDie::getFirstChild() const { |
655 | if (isValid()) |
656 | return U->getFirstChild(Die); |
657 | return DWARFDie(); |
658 | } |
659 | |
660 | DWARFDie DWARFDie::getLastChild() const { |
661 | if (isValid()) |
662 | return U->getLastChild(Die); |
663 | return DWARFDie(); |
664 | } |
665 | |
666 | iterator_range<DWARFDie::attribute_iterator> DWARFDie::attributes() const { |
667 | return make_range(x: attribute_iterator(*this, false), |
668 | y: attribute_iterator(*this, true)); |
669 | } |
670 | |
671 | DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End) |
672 | : Die(D), Index(0) { |
673 | auto AbbrDecl = Die.getAbbreviationDeclarationPtr(); |
674 | assert(AbbrDecl && "Must have abbreviation declaration" ); |
675 | if (End) { |
676 | // This is the end iterator so we set the index to the attribute count. |
677 | Index = AbbrDecl->getNumAttributes(); |
678 | } else { |
679 | // This is the begin iterator so we extract the value for this->Index. |
680 | AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize(); |
681 | updateForIndex(AbbrDecl: *AbbrDecl, I: 0); |
682 | } |
683 | } |
684 | |
685 | void DWARFDie::attribute_iterator::updateForIndex( |
686 | const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I) { |
687 | Index = I; |
688 | // AbbrDecl must be valid before calling this function. |
689 | auto NumAttrs = AbbrDecl.getNumAttributes(); |
690 | if (Index < NumAttrs) { |
691 | AttrValue.Attr = AbbrDecl.getAttrByIndex(idx: Index); |
692 | // Add the previous byte size of any previous attribute value. |
693 | AttrValue.Offset += AttrValue.ByteSize; |
694 | uint64_t ParseOffset = AttrValue.Offset; |
695 | if (AbbrDecl.getAttrIsImplicitConstByIndex(idx: Index)) |
696 | AttrValue.Value = DWARFFormValue::createFromSValue( |
697 | F: AbbrDecl.getFormByIndex(idx: Index), |
698 | V: AbbrDecl.getAttrImplicitConstValueByIndex(idx: Index)); |
699 | else { |
700 | auto U = Die.getDwarfUnit(); |
701 | assert(U && "Die must have valid DWARF unit" ); |
702 | AttrValue.Value = DWARFFormValue::createFromUnit( |
703 | F: AbbrDecl.getFormByIndex(idx: Index), Unit: U, OffsetPtr: &ParseOffset); |
704 | } |
705 | AttrValue.ByteSize = ParseOffset - AttrValue.Offset; |
706 | } else { |
707 | assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only" ); |
708 | AttrValue = {}; |
709 | } |
710 | } |
711 | |
712 | DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() { |
713 | if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr()) |
714 | updateForIndex(AbbrDecl: *AbbrDecl, I: Index + 1); |
715 | return *this; |
716 | } |
717 | |
718 | bool DWARFAttribute::mayHaveLocationList(dwarf::Attribute Attr) { |
719 | switch(Attr) { |
720 | case DW_AT_location: |
721 | case DW_AT_string_length: |
722 | case DW_AT_return_addr: |
723 | case DW_AT_data_member_location: |
724 | case DW_AT_frame_base: |
725 | case DW_AT_static_link: |
726 | case DW_AT_segment: |
727 | case DW_AT_use_location: |
728 | case DW_AT_vtable_elem_location: |
729 | return true; |
730 | default: |
731 | return false; |
732 | } |
733 | } |
734 | |
735 | bool DWARFAttribute::mayHaveLocationExpr(dwarf::Attribute Attr) { |
736 | switch (Attr) { |
737 | // From the DWARF v5 specification. |
738 | case DW_AT_location: |
739 | case DW_AT_byte_size: |
740 | case DW_AT_bit_offset: |
741 | case DW_AT_bit_size: |
742 | case DW_AT_string_length: |
743 | case DW_AT_lower_bound: |
744 | case DW_AT_return_addr: |
745 | case DW_AT_bit_stride: |
746 | case DW_AT_upper_bound: |
747 | case DW_AT_count: |
748 | case DW_AT_data_member_location: |
749 | case DW_AT_frame_base: |
750 | case DW_AT_segment: |
751 | case DW_AT_static_link: |
752 | case DW_AT_use_location: |
753 | case DW_AT_vtable_elem_location: |
754 | case DW_AT_allocated: |
755 | case DW_AT_associated: |
756 | case DW_AT_data_location: |
757 | case DW_AT_byte_stride: |
758 | case DW_AT_rank: |
759 | case DW_AT_call_value: |
760 | case DW_AT_call_origin: |
761 | case DW_AT_call_target: |
762 | case DW_AT_call_target_clobbered: |
763 | case DW_AT_call_data_location: |
764 | case DW_AT_call_data_value: |
765 | // Extensions. |
766 | case DW_AT_GNU_call_site_value: |
767 | case DW_AT_GNU_call_site_target: |
768 | return true; |
769 | default: |
770 | return false; |
771 | } |
772 | } |
773 | |
774 | namespace llvm { |
775 | |
776 | void dumpTypeQualifiedName(const DWARFDie &DIE, raw_ostream &OS) { |
777 | DWARFTypePrinter(OS).appendQualifiedName(D: DIE); |
778 | } |
779 | |
780 | void dumpTypeUnqualifiedName(const DWARFDie &DIE, raw_ostream &OS, |
781 | std::string *OriginalFullName) { |
782 | DWARFTypePrinter(OS).appendUnqualifiedName(D: DIE, OriginalFullName); |
783 | } |
784 | |
785 | } // namespace llvm |
786 | |