LLVM 23.0.0git
DWARFTypePrinter.h
Go to the documentation of this file.
1//===- DWARFTypePrinter.h ---------------------------------------*- C++ -*-===//
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#ifndef LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
10#define LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
11
13#include "llvm/ADT/StringRef.h"
15#include "llvm/Support/Error.h"
16
17#include <string>
18
19namespace llvm {
20
21class raw_ostream;
22
23// FIXME: We should have pretty printers per language. Currently we print
24// everything as if it was C++ and fall back to the TAG type name.
25template <typename DieType> struct DWARFTypePrinter {
27 bool Word = true;
28 bool EndedWithTemplate = false;
29
31
32 /// Dump the name encoded in the type tag.
34
35 void appendArrayType(const DieType &D);
36
37 DieType skipQualifiers(DieType D);
38
39 bool needsParens(DieType D);
40
41 void appendPointerLikeTypeBefore(DieType D, DieType Inner, StringRef Ptr);
42
43 DieType appendUnqualifiedNameBefore(DieType D,
44 std::string *OriginalFullName = nullptr);
45
46 void appendUnqualifiedNameAfter(DieType D, DieType Inner,
47 bool SkipFirstParamIfArtificial = false);
48 void appendQualifiedName(DieType D);
49 DieType appendQualifiedNameBefore(DieType D);
50 bool appendTemplateParameters(DieType D, bool *FirstParameter = nullptr);
52 void decomposeConstVolatile(DieType &N, DieType &T, DieType &C, DieType &V);
55
56 /// Recursively append the DIE type name when applicable.
57 void appendUnqualifiedName(DieType D,
58 std::string *OriginalFullName = nullptr);
59
60 void appendSubroutineNameAfter(DieType D, DieType Inner,
61 bool SkipFirstParamIfArtificial, bool Const,
62 bool Volatile);
63 void appendScopes(DieType D);
64
65private:
66 /// Returns True if the DIE TAG is one of the ones that is scopped.
67 static inline bool scopedTAGs(dwarf::Tag Tag) {
68 switch (Tag) {
69 case dwarf::DW_TAG_structure_type:
70 case dwarf::DW_TAG_class_type:
71 case dwarf::DW_TAG_union_type:
72 case dwarf::DW_TAG_namespace:
73 case dwarf::DW_TAG_enumeration_type:
74 case dwarf::DW_TAG_typedef:
75 return true;
76 default:
77 break;
78 }
79 return false;
80 }
81
82 /// If FormValue is a valid constant Form, print into \c OS the integral value
83 /// casted to the type referred to by \c Cast.
84 template <typename FormValueType>
85 void appendCastedValue(const FormValueType &FormValue, DieType Cast,
86 bool IsUnsigned);
87};
88
89template <typename DieType>
91 StringRef TagStr = TagString(T);
92 static constexpr StringRef Prefix = "DW_TAG_";
93 static constexpr StringRef Suffix = "_type";
94 if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(Suffix))
95 return;
96 OS << TagStr.substr(Prefix.size(),
97 TagStr.size() - (Prefix.size() + Suffix.size()))
98 << " ";
99}
100
101template <typename DieType>
103 for (const DieType &C : D.children()) {
104 if (C.getTag() != dwarf::DW_TAG_subrange_type)
105 continue;
106 std::optional<uint64_t> LB;
107 std::optional<uint64_t> Count;
108 std::optional<uint64_t> UB;
109 std::optional<unsigned> DefaultLB;
110 if (std::optional<typename DieType::DWARFFormValue> L =
111 C.find(dwarf::DW_AT_lower_bound))
112 LB = L->getAsUnsignedConstant();
113 if (std::optional<typename DieType::DWARFFormValue> CountV =
114 C.find(dwarf::DW_AT_count))
115 Count = CountV->getAsUnsignedConstant();
116 if (std::optional<typename DieType::DWARFFormValue> UpperV =
117 C.find(dwarf::DW_AT_upper_bound))
118 UB = UpperV->getAsUnsignedConstant();
119 if (std::optional<uint64_t> LV = D.getLanguage())
120 if ((DefaultLB =
121 LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LV))))
122 if (LB && *LB == *DefaultLB)
123 LB = std::nullopt;
124 if (!LB && !Count && !UB)
125 OS << "[]";
126 else if (!LB && (Count || UB) && DefaultLB)
127 OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
128 else {
129 OS << "[[";
130 if (LB)
131 OS << *LB;
132 else
133 OS << '?';
134 OS << ", ";
135 if (Count)
136 if (LB)
137 OS << *LB + *Count;
138 else
139 OS << "? + " << *Count;
140 else if (UB)
141 OS << *UB + 1;
142 else
143 OS << '?';
144 OS << ")]";
145 }
146 }
147 EndedWithTemplate = false;
148}
149
150namespace detail {
151template <typename DieType>
152DieType resolveReferencedType(DieType D,
153 dwarf::Attribute Attr = dwarf::DW_AT_type) {
154 return D.resolveReferencedType(Attr);
155}
156template <typename DieType>
157DieType resolveReferencedType(DieType D, typename DieType::DWARFFormValue F) {
158 return D.resolveReferencedType(F);
159}
160template <typename DWARFFormValueType>
161const char *toString(std::optional<DWARFFormValueType> F) {
162 if (F) {
163 llvm::Expected<const char *> E = F->getAsCString();
164 if (E)
165 return *E;
166 llvm::consumeError(E.takeError());
167 }
168 return nullptr;
169}
170
171/// Resolve the DW_AT_type of \c D until we reach a DIE that is not a
172/// DW_TAG_typedef.
173template <typename DieType> DieType unwrapReferencedTypedefType(DieType D) {
174 auto TypeAttr = D.find(dwarf::DW_AT_type);
175 if (!TypeAttr)
176 return DieType();
177
178 auto Unwrapped = detail::resolveReferencedType(D, *TypeAttr);
179 if (!Unwrapped)
180 return DieType();
181
182 if (Unwrapped.getTag() == dwarf::DW_TAG_typedef)
183 return unwrapReferencedTypedefType(Unwrapped);
184
185 return Unwrapped;
186}
187} // namespace detail
188
189template <typename DieType>
191 while (D && (D.getTag() == dwarf::DW_TAG_const_type ||
192 D.getTag() == dwarf::DW_TAG_volatile_type))
194 return D;
195}
196
197template <typename DieType>
199 D = skipQualifiers(D);
200 return D && (D.getTag() == dwarf::DW_TAG_subroutine_type ||
201 D.getTag() == dwarf::DW_TAG_array_type);
202}
203
204template <typename DieType>
206 DieType Inner,
207 StringRef Ptr) {
209 if (Word)
210 OS << ' ';
211 if (needsParens(Inner))
212 OS << '(';
213 OS << Ptr;
214 Word = false;
215 EndedWithTemplate = false;
216}
217
218template <typename DieType>
220 DieType D, std::string *OriginalFullName) {
221 Word = true;
222 if (!D) {
223 OS << "void";
224 return DieType();
225 }
226 DieType InnerDIE;
227 auto Inner = [&] { return InnerDIE = detail::resolveReferencedType(D); };
228 const dwarf::Tag T = D.getTag();
229 switch (T) {
230 case dwarf::DW_TAG_pointer_type: {
231 appendPointerLikeTypeBefore(D, Inner(), "*");
232 break;
233 }
234 case dwarf::DW_TAG_subroutine_type: {
236 if (Word) {
237 OS << ' ';
238 }
239 Word = false;
240 break;
241 }
242 case dwarf::DW_TAG_array_type: {
244 break;
245 }
246 case dwarf::DW_TAG_reference_type:
247 appendPointerLikeTypeBefore(D, Inner(), "&");
248 break;
249 case dwarf::DW_TAG_rvalue_reference_type:
250 appendPointerLikeTypeBefore(D, Inner(), "&&");
251 break;
252 case dwarf::DW_TAG_ptr_to_member_type: {
254 if (needsParens(InnerDIE))
255 OS << '(';
256 else if (Word)
257 OS << ' ';
258 if (DieType Cont =
259 detail::resolveReferencedType(D, dwarf::DW_AT_containing_type)) {
261 EndedWithTemplate = false;
262 OS << "::";
263 }
264 OS << "*";
265 Word = false;
266 break;
267 }
268 case dwarf::DW_TAG_LLVM_ptrauth_type:
270 break;
271 case dwarf::DW_TAG_const_type:
272 case dwarf::DW_TAG_volatile_type:
274 break;
275 case dwarf::DW_TAG_namespace: {
276 if (const char *Name = detail::toString(D.find(dwarf::DW_AT_name)))
277 OS << Name;
278 else
279 OS << "(anonymous namespace)";
280 break;
281 }
282 case dwarf::DW_TAG_unspecified_type: {
283 StringRef TypeName = D.getShortName();
284 if (TypeName == "decltype(nullptr)")
285 TypeName = "std::nullptr_t";
286 Word = true;
287 OS << TypeName;
288 EndedWithTemplate = false;
289 break;
290 }
291 /*
292 case DW_TAG_structure_type:
293 case DW_TAG_class_type:
294 case DW_TAG_enumeration_type:
295 case DW_TAG_base_type:
296 */
297 default: {
298 const char *NamePtr = detail::toString(D.find(dwarf::DW_AT_name));
299 if (!NamePtr) {
300 appendTypeTagName(D.getTag());
301 return DieType();
302 }
303 Word = true;
304 StringRef Name = NamePtr;
305 static constexpr StringRef MangledPrefix = "_STN|";
306 if (Name.consume_front(MangledPrefix)) {
307 auto Separator = Name.find('|');
308 assert(Separator != StringRef::npos);
309 StringRef BaseName = Name.substr(0, Separator);
310 StringRef TemplateArgs = Name.substr(Separator + 1);
311 if (OriginalFullName)
312 *OriginalFullName = (BaseName + TemplateArgs).str();
313 Name = BaseName;
314 } else
315 EndedWithTemplate = Name.ends_with(">");
316 OS << Name;
317 // This check would be insufficient for operator overloads like
318 // "operator>>" - but for now Clang doesn't try to simplify them, so this
319 // is OK. Add more nuanced operator overload handling here if/when needed.
320 if (Name.ends_with(">"))
321 break;
323 break;
324
326 OS << ' ';
327 OS << '>';
328 EndedWithTemplate = true;
329 Word = true;
330 break;
331 }
332 }
333 return InnerDIE;
334}
335
336template <typename DieType>
338 DieType D, DieType Inner, bool SkipFirstParamIfArtificial) {
339 if (!D)
340 return;
341 switch (D.getTag()) {
342 case dwarf::DW_TAG_subroutine_type: {
343 appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
344 false);
345 break;
346 }
347 case dwarf::DW_TAG_array_type: {
349 break;
350 }
351 case dwarf::DW_TAG_const_type:
352 case dwarf::DW_TAG_volatile_type:
354 break;
355 case dwarf::DW_TAG_ptr_to_member_type:
356 case dwarf::DW_TAG_reference_type:
357 case dwarf::DW_TAG_rvalue_reference_type:
358 case dwarf::DW_TAG_pointer_type: {
359 if (needsParens(Inner))
360 OS << ')';
362 /*SkipFirstParamIfArtificial=*/D.getTag() ==
363 dwarf::DW_TAG_ptr_to_member_type);
364 break;
365 }
366 case dwarf::DW_TAG_LLVM_ptrauth_type: {
367 auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t {
368 if (auto Form = D.find(Attr))
369 return *Form->getAsUnsignedConstant();
370 return 0;
371 };
373 if (getValOrNull(dwarf::DW_AT_LLVM_ptrauth_isa_pointer))
374 optionsVec.push_back("isa-pointer");
375 if (getValOrNull(dwarf::DW_AT_LLVM_ptrauth_authenticates_null_values))
376 optionsVec.push_back("authenticates-null-values");
377 if (auto AuthenticationMode =
378 D.find(dwarf::DW_AT_LLVM_ptrauth_authentication_mode)) {
379 switch (*AuthenticationMode->getAsUnsignedConstant()) {
380 case 0:
381 case 1:
382 optionsVec.push_back("strip");
383 break;
384 case 2:
385 optionsVec.push_back("sign-and-strip");
386 break;
387 default:
388 // Default authentication policy
389 break;
390 }
391 }
392 std::string options;
393 for (const auto *option : optionsVec) {
394 if (options.size())
395 options += ",";
396 options += option;
397 }
398 if (options.size())
399 options = ", \"" + options + "\"";
400 std::string PtrauthString;
401 llvm::raw_string_ostream PtrauthStream(PtrauthString);
402 PtrauthStream
403 << "__ptrauth(" << getValOrNull(dwarf::DW_AT_LLVM_ptrauth_key) << ", "
404 << getValOrNull(dwarf::DW_AT_LLVM_ptrauth_address_discriminated)
405 << ", 0x0"
406 << utohexstr(
407 getValOrNull(dwarf::DW_AT_LLVM_ptrauth_extra_discriminator),
408 true)
409 << options << ")";
410 OS << PtrauthStream.str();
411 break;
412 }
413 /*
414 case DW_TAG_structure_type:
415 case DW_TAG_class_type:
416 case DW_TAG_enumeration_type:
417 case DW_TAG_base_type:
418 case DW_TAG_namespace:
419 */
420 default:
421 break;
422 }
423}
424
425template <typename DieType>
427 if (D && scopedTAGs(D.getTag()))
428 appendScopes(D.getParent());
430}
431
432template <typename DieType>
434 if (D && scopedTAGs(D.getTag()))
435 appendScopes(D.getParent());
437}
438
439template <typename DieType>
440template <typename FormValueType>
441void DWARFTypePrinter<DieType>::appendCastedValue(
442 const FormValueType &FormValue, DieType Cast, bool IsUnsigned) {
443 std::string ValStr;
444 if (IsUnsigned) {
445 std::optional<uint64_t> UVal = FormValue.getAsUnsignedConstant();
446 if (!UVal)
447 return;
448
449 ValStr = std::to_string(*UVal);
450 } else {
451 std::optional<int64_t> SVal = FormValue.getAsSignedConstant();
452 if (!SVal)
453 return;
454
455 ValStr = std::to_string(*SVal);
456 }
457
458 OS << '(';
459 appendQualifiedName(Cast);
460 OS << ')';
461 OS << std::move(ValStr);
462}
463
464template <typename DieType>
466 bool *FirstParameter) {
467 bool FirstParameterValue = true;
468 bool IsTemplate = false;
469 if (!FirstParameter)
470 FirstParameter = &FirstParameterValue;
471 for (const DieType &C : D) {
472 auto Sep = [&] {
473 if (*FirstParameter)
474 OS << '<';
475 else
476 OS << ", ";
477 IsTemplate = true;
478 EndedWithTemplate = false;
479 *FirstParameter = false;
480 };
481 if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
482 IsTemplate = true;
483 appendTemplateParameters(C, FirstParameter);
484 }
485 if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
487 Sep();
488 if (T.getTag() == dwarf::DW_TAG_enumeration_type) {
489 auto V = C.find(dwarf::DW_AT_const_value);
490 appendCastedValue(*V, T, /*IsUnsigned=*/false);
491 continue;
492 }
493
494 // /Maybe/ we could do pointer/reference type parameters, looking for the
495 // symbol in the ELF symbol table to get back to the variable...
496 // but probably not worth it.
497 if (T.getTag() == dwarf::DW_TAG_pointer_type ||
498 T.getTag() == dwarf::DW_TAG_reference_type ||
499 T.getTag() == dwarf::DW_TAG_ptr_to_member_type)
500 continue;
501 const char *RawName = detail::toString(T.find(dwarf::DW_AT_name));
502 assert(RawName);
503 StringRef Name = RawName;
504 auto V = C.find(dwarf::DW_AT_const_value);
505 bool IsQualifiedChar = false;
506 if (Name == "bool") {
507 OS << (*V->getAsUnsignedConstant() ? "true" : "false");
508 } else if (Name == "short") {
509 OS << "(short)";
510 OS << std::to_string(*V->getAsSignedConstant());
511 } else if (Name == "unsigned short") {
512 OS << "(unsigned short)";
513 OS << std::to_string(*V->getAsSignedConstant());
514 } else if (Name == "int")
515 OS << std::to_string(*V->getAsSignedConstant());
516 else if (Name == "long") {
517 OS << std::to_string(*V->getAsSignedConstant());
518 OS << "L";
519 } else if (Name == "long long") {
520 OS << std::to_string(*V->getAsSignedConstant());
521 OS << "LL";
522 } else if (Name == "unsigned int") {
523 OS << std::to_string(*V->getAsUnsignedConstant());
524 OS << "U";
525 } else if (Name == "unsigned long") {
526 OS << std::to_string(*V->getAsUnsignedConstant());
527 OS << "UL";
528 } else if (Name == "unsigned long long") {
529 OS << std::to_string(*V->getAsUnsignedConstant());
530 OS << "ULL";
531 } else if (Name == "char" ||
532 (IsQualifiedChar =
533 (Name == "unsigned char" || Name == "signed char"))) {
534 // FIXME: check T's DW_AT_type to see if it's signed or not (since
535 // char signedness is implementation defined).
536 auto Val = *V->getAsSignedConstant();
537 // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
538 // (doesn't actually support different character types/widths, sign
539 // handling's not done, and doesn't correctly test if a character is
540 // printable or needs to use a numeric escape sequence instead)
541 if (IsQualifiedChar) {
542 OS << '(';
543 OS << Name;
544 OS << ')';
545 }
546 switch (Val) {
547 case '\\':
548 OS << "'\\\\'";
549 break;
550 case '\'':
551 OS << "'\\''";
552 break;
553 case '\a':
554 // TODO: K&R: the meaning of '\\a' is different in traditional C
555 OS << "'\\a'";
556 break;
557 case '\b':
558 OS << "'\\b'";
559 break;
560 case '\f':
561 OS << "'\\f'";
562 break;
563 case '\n':
564 OS << "'\\n'";
565 break;
566 case '\r':
567 OS << "'\\r'";
568 break;
569 case '\t':
570 OS << "'\\t'";
571 break;
572 case '\v':
573 OS << "'\\v'";
574 break;
575 default:
576 if ((Val & ~0xFFu) == ~0xFFu)
577 Val &= 0xFFu;
578 if (Val < 127 && Val >= 32) {
579 OS << "'";
580 OS << (char)Val;
581 OS << "'";
582 } else if (Val < 256)
583 OS << llvm::format("'\\x%02" PRIx64 "'", Val);
584 else if (Val <= 0xFFFF)
585 OS << llvm::format("'\\u%04" PRIx64 "'", Val);
586 else
587 OS << llvm::format("'\\U%08" PRIx64 "'", Val);
588 }
589 // FIXME: Handle _BitInt's larger than 64-bits which are emitted as
590 // block data.
591 } else if (Name.starts_with("_BitInt")) {
592 appendCastedValue(*V, T, /*IsUnsigned=*/false);
593 } else if (Name.starts_with("unsigned _BitInt")) {
594 appendCastedValue(*V, T, /*IsUnsigned=*/true);
595 }
596 continue;
597 }
598 if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
599 const char *RawName =
600 detail::toString(C.find(dwarf::DW_AT_GNU_template_name));
601 assert(RawName);
602 StringRef Name = RawName;
603 Sep();
604 OS << Name;
605 continue;
606 }
607 if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
608 continue;
609 Sep();
610
612 }
613 if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
614 OS << '<';
615 EndedWithTemplate = false;
616 }
617 return IsTemplate;
618}
619
620template <typename DieType>
622 DieType D) {
623 bool R = appendTemplateParameters(D);
624 if (!R)
625 return;
626
628 OS << " ";
629 OS << ">";
630 EndedWithTemplate = true;
631 Word = true;
632}
633
634template <typename DieType>
636 DieType &C, DieType &V) {
637 (N.getTag() == dwarf::DW_TAG_const_type ? C : V) = N;
639 if (T) {
640 auto Tag = T.getTag();
641 if (Tag == dwarf::DW_TAG_const_type) {
642 C = T;
644 } else if (Tag == dwarf::DW_TAG_volatile_type) {
645 V = T;
647 }
648 }
649}
650
651template <typename DieType>
653 DieType C;
654 DieType V;
655 DieType T;
657 if (T && T.getTag() == dwarf::DW_TAG_subroutine_type)
659 static_cast<bool>(C), static_cast<bool>(V));
660 else
662}
663
664template <typename DieType>
666 DieType C;
667 DieType V;
668 DieType T;
670 bool Subroutine = T && T.getTag() == dwarf::DW_TAG_subroutine_type;
671 DieType A = T;
672 while (A && A.getTag() == dwarf::DW_TAG_array_type)
674 bool Leading =
675 (!A || (A.getTag() != dwarf::DW_TAG_pointer_type &&
676 A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
677 !Subroutine;
678 if (Leading) {
679 if (C)
680 OS << "const ";
681 if (V)
682 OS << "volatile ";
683 }
685 if (!Leading && !Subroutine) {
686 Word = true;
687 if (C)
688 OS << "const";
689 if (V) {
690 if (C)
691 OS << ' ';
692 OS << "volatile";
693 }
694 }
695}
696
697template <typename DieType>
699 DieType D, std::string *OriginalFullName) {
700 // FIXME: We should have pretty printers per language. Currently we print
701 // everything as if it was C++ and fall back to the TAG type name.
702 DieType Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
704}
705
706template <typename DieType>
708 DieType D, DieType Inner, bool SkipFirstParamIfArtificial, bool Const,
709 bool Volatile) {
710 DieType FirstParamIfArtificial;
711 OS << '(';
712 EndedWithTemplate = false;
713 ListSeparator LS;
714 bool RealFirst = true;
715 for (DieType P : D) {
716 if (P.getTag() != dwarf::DW_TAG_formal_parameter &&
717 P.getTag() != dwarf::DW_TAG_unspecified_parameters)
718 return;
720 if (SkipFirstParamIfArtificial && RealFirst &&
721 P.find(dwarf::DW_AT_artificial)) {
722 FirstParamIfArtificial = T;
723 RealFirst = false;
724 continue;
725 }
726 OS << LS;
727 if (P.getTag() == dwarf::DW_TAG_unspecified_parameters)
728 OS << "...";
729 else
731 }
732 EndedWithTemplate = false;
733 OS << ')';
734 if (FirstParamIfArtificial) {
735 if (DieType P = FirstParamIfArtificial) {
736 if (P.getTag() == dwarf::DW_TAG_pointer_type) {
737 auto CVStep = [&](DieType CV) {
738 if (DieType U = detail::resolveReferencedType(CV)) {
739 Const |= U.getTag() == dwarf::DW_TAG_const_type;
740 Volatile |= U.getTag() == dwarf::DW_TAG_volatile_type;
741 return U;
742 }
743 return DieType();
744 };
745 if (DieType CV = CVStep(P)) {
746 CVStep(CV);
747 }
748 }
749 }
750 }
751
752 if (auto CC = D.find(dwarf::DW_AT_calling_convention)) {
753 switch (*CC->getAsUnsignedConstant()) {
754 case dwarf::CallingConvention::DW_CC_BORLAND_stdcall:
755 OS << " __attribute__((stdcall))";
756 break;
757 case dwarf::CallingConvention::DW_CC_BORLAND_msfastcall:
758 OS << " __attribute__((fastcall))";
759 break;
760 case dwarf::CallingConvention::DW_CC_BORLAND_thiscall:
761 OS << " __attribute__((thiscall))";
762 break;
763 case dwarf::CallingConvention::DW_CC_LLVM_vectorcall:
764 OS << " __attribute__((vectorcall))";
765 break;
766 case dwarf::CallingConvention::DW_CC_BORLAND_pascal:
767 OS << " __attribute__((pascal))";
768 break;
769 case dwarf::CallingConvention::DW_CC_LLVM_Win64:
770 OS << " __attribute__((ms_abi))";
771 break;
772 case dwarf::CallingConvention::DW_CC_LLVM_X86_64SysV:
773 OS << " __attribute__((sysv_abi))";
774 break;
775 case dwarf::CallingConvention::DW_CC_LLVM_AAPCS:
776 // AArch64VectorCall missing?
777 OS << " __attribute__((pcs(\"aapcs\")))";
778 break;
779 case dwarf::CallingConvention::DW_CC_LLVM_AAPCS_VFP:
780 OS << " __attribute__((pcs(\"aapcs-vfp\")))";
781 break;
782 case dwarf::CallingConvention::DW_CC_LLVM_IntelOclBicc:
783 OS << " __attribute__((intel_ocl_bicc))";
784 break;
785 case dwarf::CallingConvention::DW_CC_LLVM_SpirFunction:
786 // This isn't available as an attribute, but maybe we should still
787 // render it somehow? (Clang doesn't render it, but that's an issue
788 // for template names too - since then the DWARF names of templates
789 // instantiated with function types with these calling conventions won't
790 // have distinct names - so we'd need to fix that too)
791 break;
792 case dwarf::CallingConvention::DW_CC_LLVM_DeviceKernel:
793 OS << " __attribute__((device_kernel))";
794 break;
795 case dwarf::CallingConvention::DW_CC_LLVM_Swift:
796 // SwiftAsync missing
797 OS << " __attribute__((swiftcall))";
798 break;
799 case dwarf::CallingConvention::DW_CC_LLVM_PreserveMost:
800 OS << " __attribute__((preserve_most))";
801 break;
802 case dwarf::CallingConvention::DW_CC_LLVM_PreserveAll:
803 OS << " __attribute__((preserve_all))";
804 break;
805 case dwarf::CallingConvention::DW_CC_LLVM_PreserveNone:
806 OS << " __attribute__((preserve_none))";
807 break;
808 case dwarf::CallingConvention::DW_CC_LLVM_X86RegCall:
809 OS << " __attribute__((regcall))";
810 break;
811 case dwarf::CallingConvention::DW_CC_LLVM_M68kRTD:
812 OS << " __attribute__((m68k_rtd))";
813 break;
814 }
815 }
816
817 if (Const)
818 OS << " const";
819 if (Volatile)
820 OS << " volatile";
821 if (D.find(dwarf::DW_AT_reference))
822 OS << " &";
823 if (D.find(dwarf::DW_AT_rvalue_reference))
824 OS << " &&";
825
827}
828
829template <typename DieType>
831 if (D.getTag() == dwarf::DW_TAG_compile_unit)
832 return;
833 if (D.getTag() == dwarf::DW_TAG_type_unit)
834 return;
835 if (D.getTag() == dwarf::DW_TAG_skeleton_unit)
836 return;
837 if (D.getTag() == dwarf::DW_TAG_subprogram)
838 return;
839 if (D.getTag() == dwarf::DW_TAG_lexical_block)
840 return;
841 D = D.resolveTypeUnitReference();
842 if (DieType P = D.getParent())
845 OS << "::";
846}
847} // namespace llvm
848
849#endif // LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains constants used for implementing Dwarf debug support.
#define F(x, y, z)
Definition MD5.cpp:54
#define T
#define P(N)
This file contains some functions that are useful when dealing with strings.
static dwarf::Attribute TypeAttr[]
Tagged union holding either a T or a Error.
Definition Error.h:485
A helper class to return the specified delimiter string after the first invocation of operator String...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
static constexpr size_t npos
Definition StringRef.h:57
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition StringRef.h:591
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
constexpr size_t size() const
size - Get the string size.
Definition StringRef.h:143
bool ends_with(StringRef Suffix) const
Check if this string ends with the given Suffix.
Definition StringRef.h:270
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
A raw_ostream that writes to an std::string.
std::string & str()
Returns the string's reference.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
const char * toString(std::optional< DWARFFormValueType > F)
DieType resolveReferencedType(DieType D, dwarf::Attribute Attr=dwarf::DW_AT_type)
DieType unwrapReferencedTypedefType(DieType D)
Resolve the DW_AT_type of D until we reach a DIE that is not a DW_TAG_typedef.
Attribute
Attributes.
Definition Dwarf.h:125
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
std::string utohexstr(uint64_t X, bool LowerCase=false, unsigned Width=0)
FunctionAddr VTableAddr Count
Definition InstrProf.h:139
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition Format.h:129
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1083
#define N
void appendTypeTagName(dwarf::Tag T)
Dump the name encoded in the type tag.
bool needsParens(DieType D)
void appendArrayType(const DieType &D)
DieType appendQualifiedNameBefore(DieType D)
void appendQualifiedName(DieType D)
void decomposeConstVolatile(DieType &N, DieType &T, DieType &C, DieType &V)
DieType skipQualifiers(DieType D)
void appendUnqualifiedName(DieType D, std::string *OriginalFullName=nullptr)
Recursively append the DIE type name when applicable.
void appendConstVolatileQualifierBefore(DieType N)
void appendScopes(DieType D)
DWARFTypePrinter(raw_ostream &OS)
void appendSubroutineNameAfter(DieType D, DieType Inner, bool SkipFirstParamIfArtificial, bool Const, bool Volatile)
bool appendTemplateParameters(DieType D, bool *FirstParameter=nullptr)
void appendConstVolatileQualifierAfter(DieType N)
void appendAndTerminateTemplateParameters(DieType D)
void appendPointerLikeTypeBefore(DieType D, DieType Inner, StringRef Ptr)
void appendUnqualifiedNameAfter(DieType D, DieType Inner, bool SkipFirstParamIfArtificial=false)
DieType appendUnqualifiedNameBefore(DieType D, std::string *OriginalFullName=nullptr)