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