[llvm-shlib] Fix the version naming style of libLLVM for Windows (#85710)
[llvm-project.git] / llvm / lib / DebugInfo / DWARF / DWARFTypePrinter.cpp
blob76817fda441db1e23fb2d4b1b202be4abd74e444
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"
5 namespace llvm {
6 using namespace dwarf;
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))
12 return;
13 OS << TagStr.substr(Prefix.size(),
14 TagStr.size() - (Prefix.size() + Suffix.size()))
15 << " ";
18 void DWARFTypePrinter::appendArrayType(const DWARFDie &D) {
19 for (const DWARFDie &C : D.children()) {
20 if (C.getTag() != DW_TAG_subrange_type)
21 continue;
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())
35 if ((DefaultLB =
36 LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
37 if (LB && *LB == *DefaultLB)
38 LB = std::nullopt;
39 if (!LB && !Count && !UB)
40 OS << "[]";
41 else if (!LB && (Count || UB) && DefaultLB)
42 OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
43 else {
44 OS << "[[";
45 if (LB)
46 OS << *LB;
47 else
48 OS << '?';
49 OS << ", ";
50 if (Count)
51 if (LB)
52 OS << *LB + *Count;
53 else
54 OS << "? + " << *Count;
55 else if (UB)
56 OS << *UB + 1;
57 else
58 OS << '?';
59 OS << ")]";
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);
76 return 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,
86 StringRef Ptr) {
87 appendQualifiedNameBefore(Inner);
88 if (Word)
89 OS << ' ';
90 if (needsParens(Inner))
91 OS << '(';
92 OS << Ptr;
93 Word = false;
94 EndedWithTemplate = false;
97 DWARFDie
98 DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D,
99 std::string *OriginalFullName) {
100 Word = true;
101 if (!D) {
102 OS << "void";
103 return DWARFDie();
105 DWARFDie InnerDIE;
106 auto Inner = [&] { return InnerDIE = resolveReferencedType(D); };
107 const dwarf::Tag T = D.getTag();
108 switch (T) {
109 case DW_TAG_pointer_type: {
110 appendPointerLikeTypeBefore(D, Inner(), "*");
111 break;
113 case DW_TAG_subroutine_type: {
114 appendQualifiedNameBefore(Inner());
115 if (Word) {
116 OS << ' ';
118 Word = false;
119 break;
121 case DW_TAG_array_type: {
122 appendQualifiedNameBefore(Inner());
123 break;
125 case DW_TAG_reference_type:
126 appendPointerLikeTypeBefore(D, Inner(), "&");
127 break;
128 case DW_TAG_rvalue_reference_type:
129 appendPointerLikeTypeBefore(D, Inner(), "&&");
130 break;
131 case DW_TAG_ptr_to_member_type: {
132 appendQualifiedNameBefore(Inner());
133 if (needsParens(InnerDIE))
134 OS << '(';
135 else if (Word)
136 OS << ' ';
137 if (DWARFDie Cont = resolveReferencedType(D, DW_AT_containing_type)) {
138 appendQualifiedName(Cont);
139 EndedWithTemplate = false;
140 OS << "::";
142 OS << "*";
143 Word = false;
144 break;
146 case DW_TAG_LLVM_ptrauth_type:
147 appendQualifiedNameBefore(Inner());
148 break;
149 case DW_TAG_const_type:
150 case DW_TAG_volatile_type:
151 appendConstVolatileQualifierBefore(D);
152 break;
153 case DW_TAG_namespace: {
154 if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr))
155 OS << Name;
156 else
157 OS << "(anonymous namespace)";
158 break;
160 case DW_TAG_unspecified_type: {
161 StringRef TypeName = D.getShortName();
162 if (TypeName == "decltype(nullptr)")
163 TypeName = "std::nullptr_t";
164 Word = true;
165 OS << TypeName;
166 EndedWithTemplate = false;
167 break;
170 case DW_TAG_structure_type:
171 case DW_TAG_class_type:
172 case DW_TAG_enumeration_type:
173 case DW_TAG_base_type:
175 default: {
176 const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr);
177 if (!NamePtr) {
178 appendTypeTagName(D.getTag());
179 return DWARFDie();
181 Word = true;
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();
191 Name = BaseName;
192 } else
193 EndedWithTemplate = Name.ends_with(">");
194 OS << Name;
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(">"))
199 break;
200 if (!appendTemplateParameters(D))
201 break;
203 if (EndedWithTemplate)
204 OS << ' ';
205 OS << '>';
206 EndedWithTemplate = true;
207 Word = true;
208 break;
211 return InnerDIE;
214 void DWARFTypePrinter::appendUnqualifiedNameAfter(
215 DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) {
216 if (!D)
217 return;
218 switch (D.getTag()) {
219 case DW_TAG_subroutine_type: {
220 appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
221 false);
222 break;
224 case DW_TAG_array_type: {
225 appendArrayType(D);
226 break;
228 case DW_TAG_const_type:
229 case DW_TAG_volatile_type:
230 appendConstVolatileQualifierAfter(D);
231 break;
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))
237 OS << ')';
238 appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner),
239 /*SkipFirstParamIfArtificial=*/D.getTag() ==
240 DW_TAG_ptr_to_member_type);
241 break;
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();
247 return 0;
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");
254 std::string options;
255 for (const auto *option : optionsVec) {
256 if (options.size())
257 options += ",";
258 options += option;
260 if (options.size())
261 options = ", \"" + options + "\"";
262 std::string PtrauthString;
263 llvm::raw_string_ostream PtrauthStream(PtrauthString);
264 PtrauthStream
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)
268 << options << ")";
269 OS << PtrauthStream.str();
270 break;
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:
279 default:
280 break;
284 /// Returns True if the DIE TAG is one of the ones that is scopped.
285 static bool scopedTAGs(dwarf::Tag Tag) {
286 switch (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:
292 return true;
293 default:
294 break;
296 return false;
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;
312 if (!FirstParameter)
313 FirstParameter = &FirstParameterValue;
314 for (const DWARFDie &C : D) {
315 auto Sep = [&] {
316 if (*FirstParameter)
317 OS << '<';
318 else
319 OS << ", ";
320 IsTemplate = true;
321 EndedWithTemplate = false;
322 *FirstParameter = false;
324 if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
325 IsTemplate = true;
326 appendTemplateParameters(C, FirstParameter);
328 if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
329 DWARFDie T = resolveReferencedType(C);
330 Sep();
331 if (T.getTag() == DW_TAG_enumeration_type) {
332 OS << '(';
333 appendQualifiedName(T);
334 OS << ')';
335 auto V = C.find(DW_AT_const_value);
336 OS << std::to_string(*V->getAsSignedConstant());
337 continue;
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)
343 continue;
344 const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr);
345 assert(RawName);
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") {
352 OS << "(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());
361 OS << "L";
362 } else if (Name == "long long") {
363 OS << std::to_string(*V->getAsSignedConstant());
364 OS << "LL";
365 } else if (Name == "unsigned int") {
366 OS << std::to_string(*V->getAsUnsignedConstant());
367 OS << "U";
368 } else if (Name == "unsigned long") {
369 OS << std::to_string(*V->getAsUnsignedConstant());
370 OS << "UL";
371 } else if (Name == "unsigned long long") {
372 OS << std::to_string(*V->getAsUnsignedConstant());
373 OS << "ULL";
374 } else if (Name == "char" ||
375 (IsQualifiedChar =
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) {
385 OS << '(';
386 OS << Name;
387 OS << ')';
389 switch (Val) {
390 case '\\':
391 OS << "'\\\\'";
392 break;
393 case '\'':
394 OS << "'\\''";
395 break;
396 case '\a':
397 // TODO: K&R: the meaning of '\\a' is different in traditional C
398 OS << "'\\a'";
399 break;
400 case '\b':
401 OS << "'\\b'";
402 break;
403 case '\f':
404 OS << "'\\f'";
405 break;
406 case '\n':
407 OS << "'\\n'";
408 break;
409 case '\r':
410 OS << "'\\r'";
411 break;
412 case '\t':
413 OS << "'\\t'";
414 break;
415 case '\v':
416 OS << "'\\v'";
417 break;
418 default:
419 if ((Val & ~0xFFu) == ~0xFFu)
420 Val &= 0xFFu;
421 if (Val < 127 && Val >= 32) {
422 OS << "'";
423 OS << (char)Val;
424 OS << "'";
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);
429 else
430 OS << llvm::format("'\\U%08" PRIx64 "'", Val);
433 continue;
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);
438 assert(RawName);
439 StringRef Name = RawName;
440 Sep();
441 OS << Name;
442 continue;
444 if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
445 continue;
446 auto TypeAttr = C.find(DW_AT_type);
447 Sep();
448 appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr)
449 : DWARFDie());
451 if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
452 OS << '<';
453 EndedWithTemplate = false;
455 return IsTemplate;
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);
461 if (T) {
462 auto Tag = T.getTag();
463 if (Tag == DW_TAG_const_type) {
464 C = T;
465 T = resolveReferencedType(T);
466 } else if (Tag == DW_TAG_volatile_type) {
467 V = T;
468 T = resolveReferencedType(T);
472 void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) {
473 DWARFDie C;
474 DWARFDie V;
475 DWARFDie T;
476 decomposeConstVolatile(N, T, C, V);
477 if (T && T.getTag() == DW_TAG_subroutine_type)
478 appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(),
479 V.isValid());
480 else
481 appendUnqualifiedNameAfter(T, resolveReferencedType(T));
483 void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) {
484 DWARFDie C;
485 DWARFDie V;
486 DWARFDie T;
487 decomposeConstVolatile(N, T, C, V);
488 bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type;
489 DWARFDie A = T;
490 while (A && A.getTag() == DW_TAG_array_type)
491 A = resolveReferencedType(A);
492 bool Leading =
493 (!A || (A.getTag() != DW_TAG_pointer_type &&
494 A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
495 !Subroutine;
496 if (Leading) {
497 if (C)
498 OS << "const ";
499 if (V)
500 OS << "volatile ";
502 appendQualifiedNameBefore(T);
503 if (!Leading && !Subroutine) {
504 Word = true;
505 if (C)
506 OS << "const";
507 if (V) {
508 if (C)
509 OS << ' ';
510 OS << "volatile";
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,
523 bool Volatile) {
524 DWARFDie FirstParamIfArtificial;
525 OS << '(';
526 EndedWithTemplate = false;
527 bool First = true;
528 bool RealFirst = true;
529 for (DWARFDie P : D) {
530 if (P.getTag() != DW_TAG_formal_parameter &&
531 P.getTag() != DW_TAG_unspecified_parameters)
532 return;
533 DWARFDie T = resolveReferencedType(P);
534 if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) {
535 FirstParamIfArtificial = T;
536 RealFirst = false;
537 continue;
539 if (!First) {
540 OS << ", ";
542 First = false;
543 if (P.getTag() == DW_TAG_unspecified_parameters)
544 OS << "...";
545 else
546 appendQualifiedName(T);
548 EndedWithTemplate = false;
549 OS << ')';
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;
557 return U;
559 return DWARFDie();
561 if (DWARFDie CV = CVStep(P)) {
562 CVStep(CV);
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))";
572 break;
573 case CallingConvention::DW_CC_BORLAND_msfastcall:
574 OS << " __attribute__((fastcall))";
575 break;
576 case CallingConvention::DW_CC_BORLAND_thiscall:
577 OS << " __attribute__((thiscall))";
578 break;
579 case CallingConvention::DW_CC_LLVM_vectorcall:
580 OS << " __attribute__((vectorcall))";
581 break;
582 case CallingConvention::DW_CC_BORLAND_pascal:
583 OS << " __attribute__((pascal))";
584 break;
585 case CallingConvention::DW_CC_LLVM_Win64:
586 OS << " __attribute__((ms_abi))";
587 break;
588 case CallingConvention::DW_CC_LLVM_X86_64SysV:
589 OS << " __attribute__((sysv_abi))";
590 break;
591 case CallingConvention::DW_CC_LLVM_AAPCS:
592 // AArch64VectorCall missing?
593 OS << " __attribute__((pcs(\"aapcs\")))";
594 break;
595 case CallingConvention::DW_CC_LLVM_AAPCS_VFP:
596 OS << " __attribute__((pcs(\"aapcs-vfp\")))";
597 break;
598 case CallingConvention::DW_CC_LLVM_IntelOclBicc:
599 OS << " __attribute__((intel_ocl_bicc))";
600 break;
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)
608 break;
609 case CallingConvention::DW_CC_LLVM_Swift:
610 // SwiftAsync missing
611 OS << " __attribute__((swiftcall))";
612 break;
613 case CallingConvention::DW_CC_LLVM_PreserveMost:
614 OS << " __attribute__((preserve_most))";
615 break;
616 case CallingConvention::DW_CC_LLVM_PreserveAll:
617 OS << " __attribute__((preserve_all))";
618 break;
619 case CallingConvention::DW_CC_LLVM_X86RegCall:
620 OS << " __attribute__((regcall))";
621 break;
622 case CallingConvention::DW_CC_LLVM_M68kRTD:
623 OS << " __attribute__((m68k_rtd))";
624 break;
628 if (Const)
629 OS << " const";
630 if (Volatile)
631 OS << " volatile";
632 if (D.find(DW_AT_reference))
633 OS << " &";
634 if (D.find(DW_AT_rvalue_reference))
635 OS << " &&";
637 appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner));
639 void DWARFTypePrinter::appendScopes(DWARFDie D) {
640 if (D.getTag() == DW_TAG_compile_unit)
641 return;
642 if (D.getTag() == DW_TAG_type_unit)
643 return;
644 if (D.getTag() == DW_TAG_skeleton_unit)
645 return;
646 if (D.getTag() == DW_TAG_subprogram)
647 return;
648 if (D.getTag() == DW_TAG_lexical_block)
649 return;
650 D = D.resolveTypeUnitReference();
651 if (DWARFDie P = D.getParent())
652 appendScopes(P);
653 appendUnqualifiedName(D);
654 OS << "::";
656 } // namespace llvm