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 (auto SpecRef = V.getAsRelativeReference()) { |
317 | if (SpecRef->Unit) |
318 | Result = SpecRef->Unit->getDIEForOffset(Offset: SpecRef->Unit->getOffset() + |
319 | SpecRef->Offset); |
320 | else if (auto SpecUnit = |
321 | U->getUnitVector().getUnitForOffset(Offset: SpecRef->Offset)) |
322 | Result = SpecUnit->getDIEForOffset(Offset: SpecRef->Offset); |
323 | } |
324 | return Result; |
325 | } |
326 | |
327 | DWARFDie DWARFDie::resolveTypeUnitReference() const { |
328 | if (auto Attr = find(Attr: DW_AT_signature)) { |
329 | if (std::optional<uint64_t> Sig = Attr->getAsReferenceUVal()) { |
330 | if (DWARFTypeUnit *TU = U->getContext().getTypeUnitForHash( |
331 | Version: U->getVersion(), Hash: *Sig, IsDWO: U->isDWOUnit())) |
332 | return TU->getDIEForOffset(Offset: TU->getTypeOffset() + TU->getOffset()); |
333 | } |
334 | } |
335 | return *this; |
336 | } |
337 | |
338 | std::optional<uint64_t> DWARFDie::getRangesBaseAttribute() const { |
339 | return toSectionOffset(V: find(Attrs: {DW_AT_rnglists_base, DW_AT_GNU_ranges_base})); |
340 | } |
341 | |
342 | std::optional<uint64_t> DWARFDie::getLocBaseAttribute() const { |
343 | return toSectionOffset(V: find(Attr: DW_AT_loclists_base)); |
344 | } |
345 | |
346 | std::optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const { |
347 | uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressByteSize: U->getAddressByteSize()); |
348 | if (LowPC == Tombstone) |
349 | return std::nullopt; |
350 | if (auto FormValue = find(Attr: DW_AT_high_pc)) { |
351 | if (auto Address = FormValue->getAsAddress()) { |
352 | // High PC is an address. |
353 | return Address; |
354 | } |
355 | if (auto Offset = FormValue->getAsUnsignedConstant()) { |
356 | // High PC is an offset from LowPC. |
357 | return LowPC + *Offset; |
358 | } |
359 | } |
360 | return std::nullopt; |
361 | } |
362 | |
363 | bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC, |
364 | uint64_t &SectionIndex) const { |
365 | auto F = find(Attr: DW_AT_low_pc); |
366 | auto LowPcAddr = toSectionedAddress(V: F); |
367 | if (!LowPcAddr) |
368 | return false; |
369 | if (auto HighPcAddr = getHighPC(LowPC: LowPcAddr->Address)) { |
370 | LowPC = LowPcAddr->Address; |
371 | HighPC = *HighPcAddr; |
372 | SectionIndex = LowPcAddr->SectionIndex; |
373 | return true; |
374 | } |
375 | return false; |
376 | } |
377 | |
378 | Expected<DWARFAddressRangesVector> DWARFDie::getAddressRanges() const { |
379 | if (isNULL()) |
380 | return DWARFAddressRangesVector(); |
381 | // Single range specified by low/high PC. |
382 | uint64_t LowPC, HighPC, Index; |
383 | if (getLowAndHighPC(LowPC, HighPC, SectionIndex&: Index)) |
384 | return DWARFAddressRangesVector{{LowPC, HighPC, Index}}; |
385 | |
386 | std::optional<DWARFFormValue> Value = find(Attr: DW_AT_ranges); |
387 | if (Value) { |
388 | if (Value->getForm() == DW_FORM_rnglistx) |
389 | return U->findRnglistFromIndex(Index: *Value->getAsSectionOffset()); |
390 | return U->findRnglistFromOffset(Offset: *Value->getAsSectionOffset()); |
391 | } |
392 | return DWARFAddressRangesVector(); |
393 | } |
394 | |
395 | bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const { |
396 | auto RangesOrError = getAddressRanges(); |
397 | if (!RangesOrError) { |
398 | llvm::consumeError(Err: RangesOrError.takeError()); |
399 | return false; |
400 | } |
401 | |
402 | for (const auto &R : RangesOrError.get()) |
403 | if (R.LowPC <= Address && Address < R.HighPC) |
404 | return true; |
405 | return false; |
406 | } |
407 | |
408 | Expected<DWARFLocationExpressionsVector> |
409 | DWARFDie::getLocations(dwarf::Attribute Attr) const { |
410 | std::optional<DWARFFormValue> Location = find(Attr); |
411 | if (!Location) |
412 | return createStringError(EC: inconvertibleErrorCode(), Fmt: "No %s" , |
413 | Vals: dwarf::AttributeString(Attribute: Attr).data()); |
414 | |
415 | if (std::optional<uint64_t> Off = Location->getAsSectionOffset()) { |
416 | uint64_t Offset = *Off; |
417 | |
418 | if (Location->getForm() == DW_FORM_loclistx) { |
419 | if (auto LoclistOffset = U->getLoclistOffset(Index: Offset)) |
420 | Offset = *LoclistOffset; |
421 | else |
422 | return createStringError(EC: inconvertibleErrorCode(), |
423 | Msg: "Loclist table not found" ); |
424 | } |
425 | return U->findLoclistFromOffset(Offset); |
426 | } |
427 | |
428 | if (std::optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) { |
429 | return DWARFLocationExpressionsVector{ |
430 | DWARFLocationExpression{.Range: std::nullopt, .Expr: to_vector<4>(Range&: *Expr)}}; |
431 | } |
432 | |
433 | return createStringError( |
434 | EC: inconvertibleErrorCode(), Fmt: "Unsupported %s encoding: %s" , |
435 | Vals: dwarf::AttributeString(Attribute: Attr).data(), |
436 | Vals: dwarf::FormEncodingString(Encoding: Location->getForm()).data()); |
437 | } |
438 | |
439 | const char *DWARFDie::getSubroutineName(DINameKind Kind) const { |
440 | if (!isSubroutineDIE()) |
441 | return nullptr; |
442 | return getName(Kind); |
443 | } |
444 | |
445 | const char *DWARFDie::getName(DINameKind Kind) const { |
446 | if (!isValid() || Kind == DINameKind::None) |
447 | return nullptr; |
448 | // Try to get mangled name only if it was asked for. |
449 | if (Kind == DINameKind::LinkageName) { |
450 | if (auto Name = getLinkageName()) |
451 | return Name; |
452 | } |
453 | return getShortName(); |
454 | } |
455 | |
456 | const char *DWARFDie::getShortName() const { |
457 | if (!isValid()) |
458 | return nullptr; |
459 | |
460 | return dwarf::toString(V: findRecursively(Attrs: dwarf::DW_AT_name), Default: nullptr); |
461 | } |
462 | |
463 | const char *DWARFDie::getLinkageName() const { |
464 | if (!isValid()) |
465 | return nullptr; |
466 | |
467 | return dwarf::toString(V: findRecursively(Attrs: {dwarf::DW_AT_MIPS_linkage_name, |
468 | dwarf::DW_AT_linkage_name}), |
469 | Default: nullptr); |
470 | } |
471 | |
472 | uint64_t DWARFDie::getDeclLine() const { |
473 | return toUnsigned(V: findRecursively(Attrs: DW_AT_decl_line), Default: 0); |
474 | } |
475 | |
476 | std::string |
477 | DWARFDie::getDeclFile(DILineInfoSpecifier::FileLineInfoKind Kind) const { |
478 | if (auto FormValue = findRecursively(Attrs: DW_AT_decl_file)) |
479 | if (auto OptString = FormValue->getAsFile(Kind)) |
480 | return *OptString; |
481 | return {}; |
482 | } |
483 | |
484 | void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, |
485 | uint32_t &CallColumn, |
486 | uint32_t &CallDiscriminator) const { |
487 | CallFile = toUnsigned(V: find(Attr: DW_AT_call_file), Default: 0); |
488 | CallLine = toUnsigned(V: find(Attr: DW_AT_call_line), Default: 0); |
489 | CallColumn = toUnsigned(V: find(Attr: DW_AT_call_column), Default: 0); |
490 | CallDiscriminator = toUnsigned(V: find(Attr: DW_AT_GNU_discriminator), Default: 0); |
491 | } |
492 | |
493 | static std::optional<uint64_t> |
494 | getTypeSizeImpl(DWARFDie Die, uint64_t PointerSize, |
495 | SmallPtrSetImpl<const DWARFDebugInfoEntry *> &Visited) { |
496 | // Cycle detected? |
497 | if (!Visited.insert(Ptr: Die.getDebugInfoEntry()).second) |
498 | return {}; |
499 | if (auto SizeAttr = Die.find(Attr: DW_AT_byte_size)) |
500 | if (std::optional<uint64_t> Size = SizeAttr->getAsUnsignedConstant()) |
501 | return Size; |
502 | |
503 | switch (Die.getTag()) { |
504 | case DW_TAG_pointer_type: |
505 | case DW_TAG_reference_type: |
506 | case DW_TAG_rvalue_reference_type: |
507 | return PointerSize; |
508 | case DW_TAG_ptr_to_member_type: { |
509 | if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(Attr: DW_AT_type)) |
510 | if (BaseType.getTag() == DW_TAG_subroutine_type) |
511 | return 2 * PointerSize; |
512 | return PointerSize; |
513 | } |
514 | case DW_TAG_const_type: |
515 | case DW_TAG_immutable_type: |
516 | case DW_TAG_volatile_type: |
517 | case DW_TAG_restrict_type: |
518 | case DW_TAG_template_alias: |
519 | case DW_TAG_typedef: { |
520 | if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(Attr: DW_AT_type)) |
521 | return getTypeSizeImpl(Die: BaseType, PointerSize, Visited); |
522 | break; |
523 | } |
524 | case DW_TAG_array_type: { |
525 | DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(Attr: DW_AT_type); |
526 | if (!BaseType) |
527 | return std::nullopt; |
528 | std::optional<uint64_t> BaseSize = |
529 | getTypeSizeImpl(Die: BaseType, PointerSize, Visited); |
530 | if (!BaseSize) |
531 | return std::nullopt; |
532 | uint64_t Size = *BaseSize; |
533 | for (DWARFDie Child : Die) { |
534 | if (Child.getTag() != DW_TAG_subrange_type) |
535 | continue; |
536 | |
537 | if (auto ElemCountAttr = Child.find(Attr: DW_AT_count)) |
538 | if (std::optional<uint64_t> ElemCount = |
539 | ElemCountAttr->getAsUnsignedConstant()) |
540 | Size *= *ElemCount; |
541 | if (auto UpperBoundAttr = Child.find(Attr: DW_AT_upper_bound)) |
542 | if (std::optional<int64_t> UpperBound = |
543 | UpperBoundAttr->getAsSignedConstant()) { |
544 | int64_t LowerBound = 0; |
545 | if (auto LowerBoundAttr = Child.find(Attr: DW_AT_lower_bound)) |
546 | LowerBound = LowerBoundAttr->getAsSignedConstant().value_or(u: 0); |
547 | Size *= *UpperBound - LowerBound + 1; |
548 | } |
549 | } |
550 | return Size; |
551 | } |
552 | default: |
553 | if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(Attr: DW_AT_type)) |
554 | return getTypeSizeImpl(Die: BaseType, PointerSize, Visited); |
555 | break; |
556 | } |
557 | return std::nullopt; |
558 | } |
559 | |
560 | std::optional<uint64_t> DWARFDie::getTypeSize(uint64_t PointerSize) { |
561 | SmallPtrSet<const DWARFDebugInfoEntry *, 4> Visited; |
562 | return getTypeSizeImpl(Die: *this, PointerSize, Visited); |
563 | } |
564 | |
565 | /// Helper to dump a DIE with all of its parents, but no siblings. |
566 | static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent, |
567 | DIDumpOptions DumpOpts, unsigned Depth = 0) { |
568 | if (!Die) |
569 | return Indent; |
570 | if (DumpOpts.ParentRecurseDepth > 0 && Depth >= DumpOpts.ParentRecurseDepth) |
571 | return Indent; |
572 | Indent = dumpParentChain(Die: Die.getParent(), OS, Indent, DumpOpts, Depth: Depth + 1); |
573 | Die.dump(OS, indent: Indent, DumpOpts); |
574 | return Indent + 2; |
575 | } |
576 | |
577 | void DWARFDie::dump(raw_ostream &OS, unsigned Indent, |
578 | DIDumpOptions DumpOpts) const { |
579 | if (!isValid()) |
580 | return; |
581 | DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor(); |
582 | const uint64_t Offset = getOffset(); |
583 | uint64_t offset = Offset; |
584 | if (DumpOpts.ShowParents) { |
585 | DIDumpOptions ParentDumpOpts = DumpOpts; |
586 | ParentDumpOpts.ShowParents = false; |
587 | ParentDumpOpts.ShowChildren = false; |
588 | Indent = dumpParentChain(Die: getParent(), OS, Indent, DumpOpts: ParentDumpOpts); |
589 | } |
590 | |
591 | if (debug_info_data.isValidOffset(offset)) { |
592 | uint32_t abbrCode = debug_info_data.getULEB128(offset_ptr: &offset); |
593 | if (DumpOpts.ShowAddresses) |
594 | WithColor(OS, HighlightColor::Address).get() |
595 | << format(Fmt: "\n0x%8.8" PRIx64 ": " , Vals: Offset); |
596 | |
597 | if (abbrCode) { |
598 | auto AbbrevDecl = getAbbreviationDeclarationPtr(); |
599 | if (AbbrevDecl) { |
600 | WithColor(OS, HighlightColor::Tag).get().indent(NumSpaces: Indent) |
601 | << formatv(Fmt: "{0}" , Vals: getTag()); |
602 | if (DumpOpts.Verbose) { |
603 | OS << format(Fmt: " [%u] %c" , Vals: abbrCode, |
604 | Vals: AbbrevDecl->hasChildren() ? '*' : ' '); |
605 | if (std::optional<uint32_t> ParentIdx = Die->getParentIdx()) |
606 | OS << format(Fmt: " (0x%8.8" PRIx64 ")" , |
607 | Vals: U->getDIEAtIndex(Index: *ParentIdx).getOffset()); |
608 | } |
609 | OS << '\n'; |
610 | |
611 | // Dump all data in the DIE for the attributes. |
612 | for (const DWARFAttribute &AttrValue : attributes()) |
613 | dumpAttribute(OS, Die: *this, AttrValue, Indent, DumpOpts); |
614 | |
615 | if (DumpOpts.ShowChildren && DumpOpts.ChildRecurseDepth > 0) { |
616 | DWARFDie Child = getFirstChild(); |
617 | DumpOpts.ChildRecurseDepth--; |
618 | DIDumpOptions ChildDumpOpts = DumpOpts; |
619 | ChildDumpOpts.ShowParents = false; |
620 | while (Child) { |
621 | Child.dump(OS, Indent: Indent + 2, DumpOpts: ChildDumpOpts); |
622 | Child = Child.getSibling(); |
623 | } |
624 | } |
625 | } else { |
626 | OS << "Abbreviation code not found in 'debug_abbrev' class for code: " |
627 | << abbrCode << '\n'; |
628 | } |
629 | } else { |
630 | OS.indent(NumSpaces: Indent) << "NULL\n" ; |
631 | } |
632 | } |
633 | } |
634 | |
635 | LLVM_DUMP_METHOD void DWARFDie::dump() const { dump(OS&: llvm::errs(), Indent: 0); } |
636 | |
637 | DWARFDie DWARFDie::getParent() const { |
638 | if (isValid()) |
639 | return U->getParent(Die); |
640 | return DWARFDie(); |
641 | } |
642 | |
643 | DWARFDie DWARFDie::getSibling() const { |
644 | if (isValid()) |
645 | return U->getSibling(Die); |
646 | return DWARFDie(); |
647 | } |
648 | |
649 | DWARFDie DWARFDie::getPreviousSibling() const { |
650 | if (isValid()) |
651 | return U->getPreviousSibling(Die); |
652 | return DWARFDie(); |
653 | } |
654 | |
655 | DWARFDie DWARFDie::getFirstChild() const { |
656 | if (isValid()) |
657 | return U->getFirstChild(Die); |
658 | return DWARFDie(); |
659 | } |
660 | |
661 | DWARFDie DWARFDie::getLastChild() const { |
662 | if (isValid()) |
663 | return U->getLastChild(Die); |
664 | return DWARFDie(); |
665 | } |
666 | |
667 | iterator_range<DWARFDie::attribute_iterator> DWARFDie::attributes() const { |
668 | return make_range(x: attribute_iterator(*this, false), |
669 | y: attribute_iterator(*this, true)); |
670 | } |
671 | |
672 | DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End) |
673 | : Die(D), Index(0) { |
674 | auto AbbrDecl = Die.getAbbreviationDeclarationPtr(); |
675 | assert(AbbrDecl && "Must have abbreviation declaration" ); |
676 | if (End) { |
677 | // This is the end iterator so we set the index to the attribute count. |
678 | Index = AbbrDecl->getNumAttributes(); |
679 | } else { |
680 | // This is the begin iterator so we extract the value for this->Index. |
681 | AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize(); |
682 | updateForIndex(AbbrDecl: *AbbrDecl, I: 0); |
683 | } |
684 | } |
685 | |
686 | void DWARFDie::attribute_iterator::updateForIndex( |
687 | const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I) { |
688 | Index = I; |
689 | // AbbrDecl must be valid before calling this function. |
690 | auto NumAttrs = AbbrDecl.getNumAttributes(); |
691 | if (Index < NumAttrs) { |
692 | AttrValue.Attr = AbbrDecl.getAttrByIndex(idx: Index); |
693 | // Add the previous byte size of any previous attribute value. |
694 | AttrValue.Offset += AttrValue.ByteSize; |
695 | uint64_t ParseOffset = AttrValue.Offset; |
696 | if (AbbrDecl.getAttrIsImplicitConstByIndex(idx: Index)) |
697 | AttrValue.Value = DWARFFormValue::createFromSValue( |
698 | F: AbbrDecl.getFormByIndex(idx: Index), |
699 | V: AbbrDecl.getAttrImplicitConstValueByIndex(idx: Index)); |
700 | else { |
701 | auto U = Die.getDwarfUnit(); |
702 | assert(U && "Die must have valid DWARF unit" ); |
703 | AttrValue.Value = DWARFFormValue::createFromUnit( |
704 | F: AbbrDecl.getFormByIndex(idx: Index), Unit: U, OffsetPtr: &ParseOffset); |
705 | } |
706 | AttrValue.ByteSize = ParseOffset - AttrValue.Offset; |
707 | } else { |
708 | assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only" ); |
709 | AttrValue = {}; |
710 | } |
711 | } |
712 | |
713 | DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() { |
714 | if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr()) |
715 | updateForIndex(AbbrDecl: *AbbrDecl, I: Index + 1); |
716 | return *this; |
717 | } |
718 | |
719 | bool DWARFAttribute::mayHaveLocationList(dwarf::Attribute Attr) { |
720 | switch(Attr) { |
721 | case DW_AT_location: |
722 | case DW_AT_string_length: |
723 | case DW_AT_return_addr: |
724 | case DW_AT_data_member_location: |
725 | case DW_AT_frame_base: |
726 | case DW_AT_static_link: |
727 | case DW_AT_segment: |
728 | case DW_AT_use_location: |
729 | case DW_AT_vtable_elem_location: |
730 | return true; |
731 | default: |
732 | return false; |
733 | } |
734 | } |
735 | |
736 | bool DWARFAttribute::mayHaveLocationExpr(dwarf::Attribute Attr) { |
737 | switch (Attr) { |
738 | // From the DWARF v5 specification. |
739 | case DW_AT_location: |
740 | case DW_AT_byte_size: |
741 | case DW_AT_bit_offset: |
742 | case DW_AT_bit_size: |
743 | case DW_AT_string_length: |
744 | case DW_AT_lower_bound: |
745 | case DW_AT_return_addr: |
746 | case DW_AT_bit_stride: |
747 | case DW_AT_upper_bound: |
748 | case DW_AT_count: |
749 | case DW_AT_data_member_location: |
750 | case DW_AT_frame_base: |
751 | case DW_AT_segment: |
752 | case DW_AT_static_link: |
753 | case DW_AT_use_location: |
754 | case DW_AT_vtable_elem_location: |
755 | case DW_AT_allocated: |
756 | case DW_AT_associated: |
757 | case DW_AT_data_location: |
758 | case DW_AT_byte_stride: |
759 | case DW_AT_rank: |
760 | case DW_AT_call_value: |
761 | case DW_AT_call_origin: |
762 | case DW_AT_call_target: |
763 | case DW_AT_call_target_clobbered: |
764 | case DW_AT_call_data_location: |
765 | case DW_AT_call_data_value: |
766 | // Extensions. |
767 | case DW_AT_GNU_call_site_value: |
768 | case DW_AT_GNU_call_site_target: |
769 | return true; |
770 | default: |
771 | return false; |
772 | } |
773 | } |
774 | |
775 | namespace llvm { |
776 | |
777 | void dumpTypeQualifiedName(const DWARFDie &DIE, raw_ostream &OS) { |
778 | DWARFTypePrinter(OS).appendQualifiedName(D: DIE); |
779 | } |
780 | |
781 | void dumpTypeUnqualifiedName(const DWARFDie &DIE, raw_ostream &OS, |
782 | std::string *OriginalFullName) { |
783 | DWARFTypePrinter(OS).appendUnqualifiedName(D: DIE, OriginalFullName); |
784 | } |
785 | |
786 | } // namespace llvm |
787 | |