1 #include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
2 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
3 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
4 #include "llvm/Support/ScopedPrinter.h"
7 void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T
) {
8 StringRef TagStr
= TagString(T
);
9 static constexpr StringRef Prefix
= "DW_TAG_";
10 static constexpr StringRef Suffix
= "_type";
11 if (!TagStr
.starts_with(Prefix
) || !TagStr
.ends_with(Suffix
))
13 OS
<< TagStr
.substr(Prefix
.size(),
14 TagStr
.size() - (Prefix
.size() + Suffix
.size()))
18 void DWARFTypePrinter::appendArrayType(const DWARFDie
&D
) {
19 for (const DWARFDie
&C
: D
.children()) {
20 if (C
.getTag() != DW_TAG_subrange_type
)
22 std::optional
<uint64_t> LB
;
23 std::optional
<uint64_t> Count
;
24 std::optional
<uint64_t> UB
;
25 std::optional
<unsigned> DefaultLB
;
26 if (std::optional
<DWARFFormValue
> L
= C
.find(DW_AT_lower_bound
))
27 LB
= L
->getAsUnsignedConstant();
28 if (std::optional
<DWARFFormValue
> CountV
= C
.find(DW_AT_count
))
29 Count
= CountV
->getAsUnsignedConstant();
30 if (std::optional
<DWARFFormValue
> UpperV
= C
.find(DW_AT_upper_bound
))
31 UB
= UpperV
->getAsUnsignedConstant();
32 if (std::optional
<DWARFFormValue
> LV
=
33 D
.getDwarfUnit()->getUnitDIE().find(DW_AT_language
))
34 if (std::optional
<uint64_t> LC
= LV
->getAsUnsignedConstant())
36 LanguageLowerBound(static_cast<dwarf::SourceLanguage
>(*LC
))))
37 if (LB
&& *LB
== *DefaultLB
)
39 if (!LB
&& !Count
&& !UB
)
41 else if (!LB
&& (Count
|| UB
) && DefaultLB
)
42 OS
<< '[' << (Count
? *Count
: *UB
- *DefaultLB
+ 1) << ']';
54 OS
<< "? + " << *Count
;
62 EndedWithTemplate
= false;
65 static DWARFDie
resolveReferencedType(DWARFDie D
,
66 dwarf::Attribute Attr
= DW_AT_type
) {
67 return D
.getAttributeValueAsReferencedDie(Attr
).resolveTypeUnitReference();
69 static DWARFDie
resolveReferencedType(DWARFDie D
, DWARFFormValue F
) {
70 return D
.getAttributeValueAsReferencedDie(F
).resolveTypeUnitReference();
72 DWARFDie
DWARFTypePrinter::skipQualifiers(DWARFDie D
) {
73 while (D
&& (D
.getTag() == DW_TAG_const_type
||
74 D
.getTag() == DW_TAG_volatile_type
))
75 D
= resolveReferencedType(D
);
79 bool DWARFTypePrinter::needsParens(DWARFDie D
) {
80 D
= skipQualifiers(D
);
81 return D
&& (D
.getTag() == DW_TAG_subroutine_type
||
82 D
.getTag() == DW_TAG_array_type
);
85 void DWARFTypePrinter::appendPointerLikeTypeBefore(DWARFDie D
, DWARFDie Inner
,
87 appendQualifiedNameBefore(Inner
);
90 if (needsParens(Inner
))
94 EndedWithTemplate
= false;
98 DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D
,
99 std::string
*OriginalFullName
) {
106 auto Inner
= [&] { return InnerDIE
= resolveReferencedType(D
); };
107 const dwarf::Tag T
= D
.getTag();
109 case DW_TAG_pointer_type
: {
110 appendPointerLikeTypeBefore(D
, Inner(), "*");
113 case DW_TAG_subroutine_type
: {
114 appendQualifiedNameBefore(Inner());
121 case DW_TAG_array_type
: {
122 appendQualifiedNameBefore(Inner());
125 case DW_TAG_reference_type
:
126 appendPointerLikeTypeBefore(D
, Inner(), "&");
128 case DW_TAG_rvalue_reference_type
:
129 appendPointerLikeTypeBefore(D
, Inner(), "&&");
131 case DW_TAG_ptr_to_member_type
: {
132 appendQualifiedNameBefore(Inner());
133 if (needsParens(InnerDIE
))
137 if (DWARFDie Cont
= resolveReferencedType(D
, DW_AT_containing_type
)) {
138 appendQualifiedName(Cont
);
139 EndedWithTemplate
= false;
146 case DW_TAG_LLVM_ptrauth_type
:
147 appendQualifiedNameBefore(Inner());
149 case DW_TAG_const_type
:
150 case DW_TAG_volatile_type
:
151 appendConstVolatileQualifierBefore(D
);
153 case DW_TAG_namespace
: {
154 if (const char *Name
= dwarf::toString(D
.find(DW_AT_name
), nullptr))
157 OS
<< "(anonymous namespace)";
160 case DW_TAG_unspecified_type
: {
161 StringRef TypeName
= D
.getShortName();
162 if (TypeName
== "decltype(nullptr)")
163 TypeName
= "std::nullptr_t";
166 EndedWithTemplate
= false;
170 case DW_TAG_structure_type:
171 case DW_TAG_class_type:
172 case DW_TAG_enumeration_type:
173 case DW_TAG_base_type:
176 const char *NamePtr
= dwarf::toString(D
.find(DW_AT_name
), nullptr);
178 appendTypeTagName(D
.getTag());
182 StringRef Name
= NamePtr
;
183 static constexpr StringRef MangledPrefix
= "_STN|";
184 if (Name
.consume_front(MangledPrefix
)) {
185 auto Separator
= Name
.find('|');
186 assert(Separator
!= StringRef::npos
);
187 StringRef BaseName
= Name
.substr(0, Separator
);
188 StringRef TemplateArgs
= Name
.substr(Separator
+ 1);
189 if (OriginalFullName
)
190 *OriginalFullName
= (BaseName
+ TemplateArgs
).str();
193 EndedWithTemplate
= Name
.ends_with(">");
195 // This check would be insufficient for operator overloads like
196 // "operator>>" - but for now Clang doesn't try to simplify them, so this
197 // is OK. Add more nuanced operator overload handling here if/when needed.
198 if (Name
.ends_with(">"))
200 if (!appendTemplateParameters(D
))
203 if (EndedWithTemplate
)
206 EndedWithTemplate
= true;
214 void DWARFTypePrinter::appendUnqualifiedNameAfter(
215 DWARFDie D
, DWARFDie Inner
, bool SkipFirstParamIfArtificial
) {
218 switch (D
.getTag()) {
219 case DW_TAG_subroutine_type
: {
220 appendSubroutineNameAfter(D
, Inner
, SkipFirstParamIfArtificial
, false,
224 case DW_TAG_array_type
: {
228 case DW_TAG_const_type
:
229 case DW_TAG_volatile_type
:
230 appendConstVolatileQualifierAfter(D
);
232 case DW_TAG_ptr_to_member_type
:
233 case DW_TAG_reference_type
:
234 case DW_TAG_rvalue_reference_type
:
235 case DW_TAG_pointer_type
: {
236 if (needsParens(Inner
))
238 appendUnqualifiedNameAfter(Inner
, resolveReferencedType(Inner
),
239 /*SkipFirstParamIfArtificial=*/D
.getTag() ==
240 DW_TAG_ptr_to_member_type
);
243 case DW_TAG_LLVM_ptrauth_type
: {
244 auto getValOrNull
= [&](dwarf::Attribute Attr
) -> uint64_t {
245 if (auto Form
= D
.find(Attr
))
246 return *Form
->getAsUnsignedConstant();
249 SmallVector
<const char *, 2> optionsVec
;
250 if (getValOrNull(DW_AT_LLVM_ptrauth_isa_pointer
))
251 optionsVec
.push_back("isa-pointer");
252 if (getValOrNull(DW_AT_LLVM_ptrauth_authenticates_null_values
))
253 optionsVec
.push_back("authenticates-null-values");
255 for (const auto *option
: optionsVec
) {
261 options
= ", \"" + options
+ "\"";
262 std::string PtrauthString
;
263 llvm::raw_string_ostream
PtrauthStream(PtrauthString
);
265 << "__ptrauth(" << getValOrNull(DW_AT_LLVM_ptrauth_key
) << ", "
266 << getValOrNull(DW_AT_LLVM_ptrauth_address_discriminated
) << ", 0x0"
267 << utohexstr(getValOrNull(DW_AT_LLVM_ptrauth_extra_discriminator
), true)
269 OS
<< PtrauthStream
.str();
273 case DW_TAG_structure_type:
274 case DW_TAG_class_type:
275 case DW_TAG_enumeration_type:
276 case DW_TAG_base_type:
277 case DW_TAG_namespace:
284 /// Returns True if the DIE TAG is one of the ones that is scopped.
285 static bool scopedTAGs(dwarf::Tag Tag
) {
287 case dwarf::DW_TAG_structure_type
:
288 case dwarf::DW_TAG_class_type
:
289 case dwarf::DW_TAG_union_type
:
290 case dwarf::DW_TAG_namespace
:
291 case dwarf::DW_TAG_enumeration_type
:
298 void DWARFTypePrinter::appendQualifiedName(DWARFDie D
) {
299 if (D
&& scopedTAGs(D
.getTag()))
300 appendScopes(D
.getParent());
301 appendUnqualifiedName(D
);
303 DWARFDie
DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D
) {
304 if (D
&& scopedTAGs(D
.getTag()))
305 appendScopes(D
.getParent());
306 return appendUnqualifiedNameBefore(D
);
308 bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D
,
309 bool *FirstParameter
) {
310 bool FirstParameterValue
= true;
311 bool IsTemplate
= false;
313 FirstParameter
= &FirstParameterValue
;
314 for (const DWARFDie
&C
: D
) {
321 EndedWithTemplate
= false;
322 *FirstParameter
= false;
324 if (C
.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack
) {
326 appendTemplateParameters(C
, FirstParameter
);
328 if (C
.getTag() == dwarf::DW_TAG_template_value_parameter
) {
329 DWARFDie T
= resolveReferencedType(C
);
331 if (T
.getTag() == DW_TAG_enumeration_type
) {
333 appendQualifiedName(T
);
335 auto V
= C
.find(DW_AT_const_value
);
336 OS
<< std::to_string(*V
->getAsSignedConstant());
339 // /Maybe/ we could do pointer type parameters, looking for the
340 // symbol in the ELF symbol table to get back to the variable...
341 // but probably not worth it.
342 if (T
.getTag() == DW_TAG_pointer_type
)
344 const char *RawName
= dwarf::toString(T
.find(DW_AT_name
), nullptr);
346 StringRef Name
= RawName
;
347 auto V
= C
.find(DW_AT_const_value
);
348 bool IsQualifiedChar
= false;
349 if (Name
== "bool") {
350 OS
<< (*V
->getAsUnsignedConstant() ? "true" : "false");
351 } else if (Name
== "short") {
353 OS
<< std::to_string(*V
->getAsSignedConstant());
354 } else if (Name
== "unsigned short") {
355 OS
<< "(unsigned short)";
356 OS
<< std::to_string(*V
->getAsSignedConstant());
357 } else if (Name
== "int")
358 OS
<< std::to_string(*V
->getAsSignedConstant());
359 else if (Name
== "long") {
360 OS
<< std::to_string(*V
->getAsSignedConstant());
362 } else if (Name
== "long long") {
363 OS
<< std::to_string(*V
->getAsSignedConstant());
365 } else if (Name
== "unsigned int") {
366 OS
<< std::to_string(*V
->getAsUnsignedConstant());
368 } else if (Name
== "unsigned long") {
369 OS
<< std::to_string(*V
->getAsUnsignedConstant());
371 } else if (Name
== "unsigned long long") {
372 OS
<< std::to_string(*V
->getAsUnsignedConstant());
374 } else if (Name
== "char" ||
376 (Name
== "unsigned char" || Name
== "signed char"))) {
377 // FIXME: check T's DW_AT_type to see if it's signed or not (since
378 // char signedness is implementation defined).
379 auto Val
= *V
->getAsSignedConstant();
380 // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
381 // (doesn't actually support different character types/widths, sign
382 // handling's not done, and doesn't correctly test if a character is
383 // printable or needs to use a numeric escape sequence instead)
384 if (IsQualifiedChar
) {
397 // TODO: K&R: the meaning of '\\a' is different in traditional C
419 if ((Val
& ~0xFFu
) == ~0xFFu
)
421 if (Val
< 127 && Val
>= 32) {
425 } else if (Val
< 256)
426 OS
<< llvm::format("'\\x%02" PRIx64
"'", Val
);
427 else if (Val
<= 0xFFFF)
428 OS
<< llvm::format("'\\u%04" PRIx64
"'", Val
);
430 OS
<< llvm::format("'\\U%08" PRIx64
"'", Val
);
435 if (C
.getTag() == dwarf::DW_TAG_GNU_template_template_param
) {
436 const char *RawName
=
437 dwarf::toString(C
.find(DW_AT_GNU_template_name
), nullptr);
439 StringRef Name
= RawName
;
444 if (C
.getTag() != dwarf::DW_TAG_template_type_parameter
)
446 auto TypeAttr
= C
.find(DW_AT_type
);
448 appendQualifiedName(TypeAttr
? resolveReferencedType(C
, *TypeAttr
)
451 if (IsTemplate
&& *FirstParameter
&& FirstParameter
== &FirstParameterValue
) {
453 EndedWithTemplate
= false;
457 void DWARFTypePrinter::decomposeConstVolatile(DWARFDie
&N
, DWARFDie
&T
,
458 DWARFDie
&C
, DWARFDie
&V
) {
459 (N
.getTag() == DW_TAG_const_type
? C
: V
) = N
;
460 T
= resolveReferencedType(N
);
462 auto Tag
= T
.getTag();
463 if (Tag
== DW_TAG_const_type
) {
465 T
= resolveReferencedType(T
);
466 } else if (Tag
== DW_TAG_volatile_type
) {
468 T
= resolveReferencedType(T
);
472 void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N
) {
476 decomposeConstVolatile(N
, T
, C
, V
);
477 if (T
&& T
.getTag() == DW_TAG_subroutine_type
)
478 appendSubroutineNameAfter(T
, resolveReferencedType(T
), false, C
.isValid(),
481 appendUnqualifiedNameAfter(T
, resolveReferencedType(T
));
483 void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N
) {
487 decomposeConstVolatile(N
, T
, C
, V
);
488 bool Subroutine
= T
&& T
.getTag() == DW_TAG_subroutine_type
;
490 while (A
&& A
.getTag() == DW_TAG_array_type
)
491 A
= resolveReferencedType(A
);
493 (!A
|| (A
.getTag() != DW_TAG_pointer_type
&&
494 A
.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type
)) &&
502 appendQualifiedNameBefore(T
);
503 if (!Leading
&& !Subroutine
) {
514 void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D
,
515 std::string
*OriginalFullName
) {
516 // FIXME: We should have pretty printers per language. Currently we print
517 // everything as if it was C++ and fall back to the TAG type name.
518 DWARFDie Inner
= appendUnqualifiedNameBefore(D
, OriginalFullName
);
519 appendUnqualifiedNameAfter(D
, Inner
);
521 void DWARFTypePrinter::appendSubroutineNameAfter(
522 DWARFDie D
, DWARFDie Inner
, bool SkipFirstParamIfArtificial
, bool Const
,
524 DWARFDie FirstParamIfArtificial
;
526 EndedWithTemplate
= false;
528 bool RealFirst
= true;
529 for (DWARFDie P
: D
) {
530 if (P
.getTag() != DW_TAG_formal_parameter
&&
531 P
.getTag() != DW_TAG_unspecified_parameters
)
533 DWARFDie T
= resolveReferencedType(P
);
534 if (SkipFirstParamIfArtificial
&& RealFirst
&& P
.find(DW_AT_artificial
)) {
535 FirstParamIfArtificial
= T
;
543 if (P
.getTag() == DW_TAG_unspecified_parameters
)
546 appendQualifiedName(T
);
548 EndedWithTemplate
= false;
550 if (FirstParamIfArtificial
) {
551 if (DWARFDie P
= FirstParamIfArtificial
) {
552 if (P
.getTag() == DW_TAG_pointer_type
) {
553 auto CVStep
= [&](DWARFDie CV
) {
554 if (DWARFDie U
= resolveReferencedType(CV
)) {
555 Const
|= U
.getTag() == DW_TAG_const_type
;
556 Volatile
|= U
.getTag() == DW_TAG_volatile_type
;
561 if (DWARFDie CV
= CVStep(P
)) {
568 if (auto CC
= D
.find(DW_AT_calling_convention
)) {
569 switch (*CC
->getAsUnsignedConstant()) {
570 case CallingConvention::DW_CC_BORLAND_stdcall
:
571 OS
<< " __attribute__((stdcall))";
573 case CallingConvention::DW_CC_BORLAND_msfastcall
:
574 OS
<< " __attribute__((fastcall))";
576 case CallingConvention::DW_CC_BORLAND_thiscall
:
577 OS
<< " __attribute__((thiscall))";
579 case CallingConvention::DW_CC_LLVM_vectorcall
:
580 OS
<< " __attribute__((vectorcall))";
582 case CallingConvention::DW_CC_BORLAND_pascal
:
583 OS
<< " __attribute__((pascal))";
585 case CallingConvention::DW_CC_LLVM_Win64
:
586 OS
<< " __attribute__((ms_abi))";
588 case CallingConvention::DW_CC_LLVM_X86_64SysV
:
589 OS
<< " __attribute__((sysv_abi))";
591 case CallingConvention::DW_CC_LLVM_AAPCS
:
592 // AArch64VectorCall missing?
593 OS
<< " __attribute__((pcs(\"aapcs\")))";
595 case CallingConvention::DW_CC_LLVM_AAPCS_VFP
:
596 OS
<< " __attribute__((pcs(\"aapcs-vfp\")))";
598 case CallingConvention::DW_CC_LLVM_IntelOclBicc
:
599 OS
<< " __attribute__((intel_ocl_bicc))";
601 case CallingConvention::DW_CC_LLVM_SpirFunction
:
602 case CallingConvention::DW_CC_LLVM_OpenCLKernel
:
603 // These aren't available as attributes, but maybe we should still
604 // render them somehow? (Clang doesn't render them, but that's an issue
605 // for template names too - since then the DWARF names of templates
606 // instantiated with function types with these calling conventions won't
607 // have distinct names - so we'd need to fix that too)
609 case CallingConvention::DW_CC_LLVM_Swift
:
610 // SwiftAsync missing
611 OS
<< " __attribute__((swiftcall))";
613 case CallingConvention::DW_CC_LLVM_PreserveMost
:
614 OS
<< " __attribute__((preserve_most))";
616 case CallingConvention::DW_CC_LLVM_PreserveAll
:
617 OS
<< " __attribute__((preserve_all))";
619 case CallingConvention::DW_CC_LLVM_X86RegCall
:
620 OS
<< " __attribute__((regcall))";
622 case CallingConvention::DW_CC_LLVM_M68kRTD
:
623 OS
<< " __attribute__((m68k_rtd))";
632 if (D
.find(DW_AT_reference
))
634 if (D
.find(DW_AT_rvalue_reference
))
637 appendUnqualifiedNameAfter(Inner
, resolveReferencedType(Inner
));
639 void DWARFTypePrinter::appendScopes(DWARFDie D
) {
640 if (D
.getTag() == DW_TAG_compile_unit
)
642 if (D
.getTag() == DW_TAG_type_unit
)
644 if (D
.getTag() == DW_TAG_skeleton_unit
)
646 if (D
.getTag() == DW_TAG_subprogram
)
648 if (D
.getTag() == DW_TAG_lexical_block
)
650 D
= D
.resolveTypeUnitReference();
651 if (DWARFDie P
= D
.getParent())
653 appendUnqualifiedName(D
);