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