LLVM 20.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
83template <typename DieType>
85 StringRef TagStr = TagString(T);
86 static constexpr StringRef Prefix = "DW_TAG_";
87 static constexpr StringRef Suffix = "_type";
88 if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(Suffix))
89 return;
90 OS << TagStr.substr(Prefix.size(),
91 TagStr.size() - (Prefix.size() + Suffix.size()))
92 << " ";
93}
94
95template <typename DieType>
97 for (const DieType &C : D.children()) {
98 if (C.getTag() != dwarf::DW_TAG_subrange_type)
99 continue;
100 std::optional<uint64_t> LB;
101 std::optional<uint64_t> Count;
102 std::optional<uint64_t> UB;
103 std::optional<unsigned> DefaultLB;
104 if (std::optional<typename DieType::DWARFFormValue> L =
105 C.find(dwarf::DW_AT_lower_bound))
106 LB = L->getAsUnsignedConstant();
107 if (std::optional<typename DieType::DWARFFormValue> CountV =
108 C.find(dwarf::DW_AT_count))
109 Count = CountV->getAsUnsignedConstant();
110 if (std::optional<typename DieType::DWARFFormValue> UpperV =
111 C.find(dwarf::DW_AT_upper_bound))
112 UB = UpperV->getAsUnsignedConstant();
113 if (std::optional<uint64_t> LV = D.getLanguage())
114 if ((DefaultLB =
115 LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LV))))
116 if (LB && *LB == *DefaultLB)
117 LB = std::nullopt;
118 if (!LB && !Count && !UB)
119 OS << "[]";
120 else if (!LB && (Count || UB) && DefaultLB)
121 OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
122 else {
123 OS << "[[";
124 if (LB)
125 OS << *LB;
126 else
127 OS << '?';
128 OS << ", ";
129 if (Count)
130 if (LB)
131 OS << *LB + *Count;
132 else
133 OS << "? + " << *Count;
134 else if (UB)
135 OS << *UB + 1;
136 else
137 OS << '?';
138 OS << ")]";
139 }
140 }
141 EndedWithTemplate = false;
142}
143
144namespace detail {
145template <typename DieType>
146DieType resolveReferencedType(DieType D,
147 dwarf::Attribute Attr = dwarf::DW_AT_type) {
148 return D.resolveReferencedType(Attr);
149}
150template <typename DieType>
151DieType resolveReferencedType(DieType D, typename DieType::DWARFFormValue F) {
152 return D.resolveReferencedType(F);
153}
154template <typename DWARFFormValueType>
155const char *toString(std::optional<DWARFFormValueType> F) {
156 if (F) {
157 llvm::Expected<const char *> E = F->getAsCString();
158 if (E)
159 return *E;
160 llvm::consumeError(E.takeError());
161 }
162 return nullptr;
163}
164} // namespace detail
165
166template <typename DieType>
168 while (D && (D.getTag() == dwarf::DW_TAG_const_type ||
169 D.getTag() == dwarf::DW_TAG_volatile_type))
171 return D;
172}
173
174template <typename DieType>
176 D = skipQualifiers(D);
177 return D && (D.getTag() == dwarf::DW_TAG_subroutine_type ||
178 D.getTag() == dwarf::DW_TAG_array_type);
179}
180
181template <typename DieType>
183 DieType Inner,
184 StringRef Ptr) {
185 appendQualifiedNameBefore(Inner);
186 if (Word)
187 OS << ' ';
188 if (needsParens(Inner))
189 OS << '(';
190 OS << Ptr;
191 Word = false;
192 EndedWithTemplate = false;
193}
194
195template <typename DieType>
197 DieType D, std::string *OriginalFullName) {
198 Word = true;
199 if (!D) {
200 OS << "void";
201 return DieType();
202 }
203 DieType InnerDIE;
204 auto Inner = [&] { return InnerDIE = detail::resolveReferencedType(D); };
205 const dwarf::Tag T = D.getTag();
206 switch (T) {
207 case dwarf::DW_TAG_pointer_type: {
208 appendPointerLikeTypeBefore(D, Inner(), "*");
209 break;
210 }
211 case dwarf::DW_TAG_subroutine_type: {
212 appendQualifiedNameBefore(Inner());
213 if (Word) {
214 OS << ' ';
215 }
216 Word = false;
217 break;
218 }
219 case dwarf::DW_TAG_array_type: {
220 appendQualifiedNameBefore(Inner());
221 break;
222 }
223 case dwarf::DW_TAG_reference_type:
224 appendPointerLikeTypeBefore(D, Inner(), "&");
225 break;
226 case dwarf::DW_TAG_rvalue_reference_type:
227 appendPointerLikeTypeBefore(D, Inner(), "&&");
228 break;
229 case dwarf::DW_TAG_ptr_to_member_type: {
230 appendQualifiedNameBefore(Inner());
231 if (needsParens(InnerDIE))
232 OS << '(';
233 else if (Word)
234 OS << ' ';
235 if (DieType Cont =
236 detail::resolveReferencedType(D, dwarf::DW_AT_containing_type)) {
237 appendQualifiedName(Cont);
238 EndedWithTemplate = false;
239 OS << "::";
240 }
241 OS << "*";
242 Word = false;
243 break;
244 }
245 case dwarf::DW_TAG_LLVM_ptrauth_type:
246 appendQualifiedNameBefore(Inner());
247 break;
248 case dwarf::DW_TAG_const_type:
249 case dwarf::DW_TAG_volatile_type:
250 appendConstVolatileQualifierBefore(D);
251 break;
252 case dwarf::DW_TAG_namespace: {
253 if (const char *Name = detail::toString(D.find(dwarf::DW_AT_name)))
254 OS << Name;
255 else
256 OS << "(anonymous namespace)";
257 break;
258 }
259 case dwarf::DW_TAG_unspecified_type: {
260 StringRef TypeName = D.getShortName();
261 if (TypeName == "decltype(nullptr)")
262 TypeName = "std::nullptr_t";
263 Word = true;
264 OS << TypeName;
265 EndedWithTemplate = false;
266 break;
267 }
268 /*
269 case DW_TAG_structure_type:
270 case DW_TAG_class_type:
271 case DW_TAG_enumeration_type:
272 case DW_TAG_base_type:
273 */
274 default: {
275 const char *NamePtr = detail::toString(D.find(dwarf::DW_AT_name));
276 if (!NamePtr) {
277 appendTypeTagName(D.getTag());
278 return DieType();
279 }
280 Word = true;
281 StringRef Name = NamePtr;
282 static constexpr StringRef MangledPrefix = "_STN|";
283 if (Name.consume_front(MangledPrefix)) {
284 auto Separator = Name.find('|');
285 assert(Separator != StringRef::npos);
286 StringRef BaseName = Name.substr(0, Separator);
287 StringRef TemplateArgs = Name.substr(Separator + 1);
288 if (OriginalFullName)
289 *OriginalFullName = (BaseName + TemplateArgs).str();
290 Name = BaseName;
291 } else
292 EndedWithTemplate = Name.ends_with(">");
293 OS << Name;
294 // This check would be insufficient for operator overloads like
295 // "operator>>" - but for now Clang doesn't try to simplify them, so this
296 // is OK. Add more nuanced operator overload handling here if/when needed.
297 if (Name.ends_with(">"))
298 break;
299 if (!appendTemplateParameters(D))
300 break;
301
302 if (EndedWithTemplate)
303 OS << ' ';
304 OS << '>';
305 EndedWithTemplate = true;
306 Word = true;
307 break;
308 }
309 }
310 return InnerDIE;
311}
312
313template <typename DieType>
315 DieType D, DieType Inner, bool SkipFirstParamIfArtificial) {
316 if (!D)
317 return;
318 switch (D.getTag()) {
319 case dwarf::DW_TAG_subroutine_type: {
320 appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
321 false);
322 break;
323 }
324 case dwarf::DW_TAG_array_type: {
325 appendArrayType(D);
326 break;
327 }
328 case dwarf::DW_TAG_const_type:
329 case dwarf::DW_TAG_volatile_type:
330 appendConstVolatileQualifierAfter(D);
331 break;
332 case dwarf::DW_TAG_ptr_to_member_type:
333 case dwarf::DW_TAG_reference_type:
334 case dwarf::DW_TAG_rvalue_reference_type:
335 case dwarf::DW_TAG_pointer_type: {
336 if (needsParens(Inner))
337 OS << ')';
338 appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner),
339 /*SkipFirstParamIfArtificial=*/D.getTag() ==
340 dwarf::DW_TAG_ptr_to_member_type);
341 break;
342 }
343 case dwarf::DW_TAG_LLVM_ptrauth_type: {
344 auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t {
345 if (auto Form = D.find(Attr))
346 return *Form->getAsUnsignedConstant();
347 return 0;
348 };
350 if (getValOrNull(dwarf::DW_AT_LLVM_ptrauth_isa_pointer))
351 optionsVec.push_back("isa-pointer");
352 if (getValOrNull(dwarf::DW_AT_LLVM_ptrauth_authenticates_null_values))
353 optionsVec.push_back("authenticates-null-values");
354 if (auto AuthenticationMode =
355 D.find(dwarf::DW_AT_LLVM_ptrauth_authentication_mode)) {
356 switch (*AuthenticationMode->getAsUnsignedConstant()) {
357 case 0:
358 case 1:
359 optionsVec.push_back("strip");
360 break;
361 case 2:
362 optionsVec.push_back("sign-and-strip");
363 break;
364 default:
365 // Default authentication policy
366 break;
367 }
368 }
369 std::string options;
370 for (const auto *option : optionsVec) {
371 if (options.size())
372 options += ",";
373 options += option;
374 }
375 if (options.size())
376 options = ", \"" + options + "\"";
377 std::string PtrauthString;
378 llvm::raw_string_ostream PtrauthStream(PtrauthString);
379 PtrauthStream
380 << "__ptrauth(" << getValOrNull(dwarf::DW_AT_LLVM_ptrauth_key) << ", "
381 << getValOrNull(dwarf::DW_AT_LLVM_ptrauth_address_discriminated)
382 << ", 0x0"
383 << utohexstr(
384 getValOrNull(dwarf::DW_AT_LLVM_ptrauth_extra_discriminator),
385 true)
386 << options << ")";
387 OS << PtrauthStream.str();
388 break;
389 }
390 /*
391 case DW_TAG_structure_type:
392 case DW_TAG_class_type:
393 case DW_TAG_enumeration_type:
394 case DW_TAG_base_type:
395 case DW_TAG_namespace:
396 */
397 default:
398 break;
399 }
400}
401
402template <typename DieType>
404 if (D && scopedTAGs(D.getTag()))
405 appendScopes(D.getParent());
406 appendUnqualifiedName(D);
407}
408
409template <typename DieType>
411 if (D && scopedTAGs(D.getTag()))
412 appendScopes(D.getParent());
413 return appendUnqualifiedNameBefore(D);
414}
415
416template <typename DieType>
418 bool *FirstParameter) {
419 bool FirstParameterValue = true;
420 bool IsTemplate = false;
421 if (!FirstParameter)
422 FirstParameter = &FirstParameterValue;
423 for (const DieType &C : D) {
424 auto Sep = [&] {
425 if (*FirstParameter)
426 OS << '<';
427 else
428 OS << ", ";
429 IsTemplate = true;
430 EndedWithTemplate = false;
431 *FirstParameter = false;
432 };
433 if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
434 IsTemplate = true;
435 appendTemplateParameters(C, FirstParameter);
436 }
437 if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
439 Sep();
440 if (T.getTag() == dwarf::DW_TAG_enumeration_type) {
441 OS << '(';
442 appendQualifiedName(T);
443 OS << ')';
444 auto V = C.find(dwarf::DW_AT_const_value);
445 OS << std::to_string(*V->getAsSignedConstant());
446 continue;
447 }
448 // /Maybe/ we could do pointer/reference type parameters, looking for the
449 // symbol in the ELF symbol table to get back to the variable...
450 // but probably not worth it.
451 if (T.getTag() == dwarf::DW_TAG_pointer_type ||
452 T.getTag() == dwarf::DW_TAG_reference_type)
453 continue;
454 const char *RawName = detail::toString(T.find(dwarf::DW_AT_name));
455 assert(RawName);
456 StringRef Name = RawName;
457 auto V = C.find(dwarf::DW_AT_const_value);
458 bool IsQualifiedChar = false;
459 if (Name == "bool") {
460 OS << (*V->getAsUnsignedConstant() ? "true" : "false");
461 } else if (Name == "short") {
462 OS << "(short)";
463 OS << std::to_string(*V->getAsSignedConstant());
464 } else if (Name == "unsigned short") {
465 OS << "(unsigned short)";
466 OS << std::to_string(*V->getAsSignedConstant());
467 } else if (Name == "int")
468 OS << std::to_string(*V->getAsSignedConstant());
469 else if (Name == "long") {
470 OS << std::to_string(*V->getAsSignedConstant());
471 OS << "L";
472 } else if (Name == "long long") {
473 OS << std::to_string(*V->getAsSignedConstant());
474 OS << "LL";
475 } else if (Name == "unsigned int") {
476 OS << std::to_string(*V->getAsUnsignedConstant());
477 OS << "U";
478 } else if (Name == "unsigned long") {
479 OS << std::to_string(*V->getAsUnsignedConstant());
480 OS << "UL";
481 } else if (Name == "unsigned long long") {
482 OS << std::to_string(*V->getAsUnsignedConstant());
483 OS << "ULL";
484 } else if (Name == "char" ||
485 (IsQualifiedChar =
486 (Name == "unsigned char" || Name == "signed char"))) {
487 // FIXME: check T's DW_AT_type to see if it's signed or not (since
488 // char signedness is implementation defined).
489 auto Val = *V->getAsSignedConstant();
490 // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
491 // (doesn't actually support different character types/widths, sign
492 // handling's not done, and doesn't correctly test if a character is
493 // printable or needs to use a numeric escape sequence instead)
494 if (IsQualifiedChar) {
495 OS << '(';
496 OS << Name;
497 OS << ')';
498 }
499 switch (Val) {
500 case '\\':
501 OS << "'\\\\'";
502 break;
503 case '\'':
504 OS << "'\\''";
505 break;
506 case '\a':
507 // TODO: K&R: the meaning of '\\a' is different in traditional C
508 OS << "'\\a'";
509 break;
510 case '\b':
511 OS << "'\\b'";
512 break;
513 case '\f':
514 OS << "'\\f'";
515 break;
516 case '\n':
517 OS << "'\\n'";
518 break;
519 case '\r':
520 OS << "'\\r'";
521 break;
522 case '\t':
523 OS << "'\\t'";
524 break;
525 case '\v':
526 OS << "'\\v'";
527 break;
528 default:
529 if ((Val & ~0xFFu) == ~0xFFu)
530 Val &= 0xFFu;
531 if (Val < 127 && Val >= 32) {
532 OS << "'";
533 OS << (char)Val;
534 OS << "'";
535 } else if (Val < 256)
536 OS << llvm::format("'\\x%02" PRIx64 "'", Val);
537 else if (Val <= 0xFFFF)
538 OS << llvm::format("'\\u%04" PRIx64 "'", Val);
539 else
540 OS << llvm::format("'\\U%08" PRIx64 "'", Val);
541 }
542 }
543 continue;
544 }
545 if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
546 const char *RawName =
547 detail::toString(C.find(dwarf::DW_AT_GNU_template_name));
548 assert(RawName);
549 StringRef Name = RawName;
550 Sep();
551 OS << Name;
552 continue;
553 }
554 if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
555 continue;
556 auto TypeAttr = C.find(dwarf::DW_AT_type);
557 Sep();
558 appendQualifiedName(TypeAttr ? detail::resolveReferencedType(C, *TypeAttr)
559 : DieType());
560 }
561 if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
562 OS << '<';
563 EndedWithTemplate = false;
564 }
565 return IsTemplate;
566}
567
568template <typename DieType>
570 DieType D) {
571 bool R = appendTemplateParameters(D);
572 if (!R)
573 return;
574
575 if (EndedWithTemplate)
576 OS << " ";
577 OS << ">";
578 EndedWithTemplate = true;
579 Word = true;
580}
581
582template <typename DieType>
584 DieType &C, DieType &V) {
585 (N.getTag() == dwarf::DW_TAG_const_type ? C : V) = N;
587 if (T) {
588 auto Tag = T.getTag();
589 if (Tag == dwarf::DW_TAG_const_type) {
590 C = T;
592 } else if (Tag == dwarf::DW_TAG_volatile_type) {
593 V = T;
595 }
596 }
597}
598
599template <typename DieType>
601 DieType C;
602 DieType V;
603 DieType T;
604 decomposeConstVolatile(N, T, C, V);
605 if (T && T.getTag() == dwarf::DW_TAG_subroutine_type)
606 appendSubroutineNameAfter(T, detail::resolveReferencedType(T), false,
607 static_cast<bool>(C), static_cast<bool>(V));
608 else
609 appendUnqualifiedNameAfter(T, detail::resolveReferencedType(T));
610}
611
612template <typename DieType>
614 DieType C;
615 DieType V;
616 DieType T;
617 decomposeConstVolatile(N, T, C, V);
618 bool Subroutine = T && T.getTag() == dwarf::DW_TAG_subroutine_type;
619 DieType A = T;
620 while (A && A.getTag() == dwarf::DW_TAG_array_type)
622 bool Leading =
623 (!A || (A.getTag() != dwarf::DW_TAG_pointer_type &&
624 A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
625 !Subroutine;
626 if (Leading) {
627 if (C)
628 OS << "const ";
629 if (V)
630 OS << "volatile ";
631 }
632 appendQualifiedNameBefore(T);
633 if (!Leading && !Subroutine) {
634 Word = true;
635 if (C)
636 OS << "const";
637 if (V) {
638 if (C)
639 OS << ' ';
640 OS << "volatile";
641 }
642 }
643}
644
645template <typename DieType>
647 DieType D, std::string *OriginalFullName) {
648 // FIXME: We should have pretty printers per language. Currently we print
649 // everything as if it was C++ and fall back to the TAG type name.
650 DieType Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
651 appendUnqualifiedNameAfter(D, Inner);
652}
653
654template <typename DieType>
656 DieType D, DieType Inner, bool SkipFirstParamIfArtificial, bool Const,
657 bool Volatile) {
658 DieType FirstParamIfArtificial;
659 OS << '(';
660 EndedWithTemplate = false;
661 bool First = true;
662 bool RealFirst = true;
663 for (DieType P : D) {
664 if (P.getTag() != dwarf::DW_TAG_formal_parameter &&
665 P.getTag() != dwarf::DW_TAG_unspecified_parameters)
666 return;
668 if (SkipFirstParamIfArtificial && RealFirst &&
669 P.find(dwarf::DW_AT_artificial)) {
670 FirstParamIfArtificial = T;
671 RealFirst = false;
672 continue;
673 }
674 if (!First) {
675 OS << ", ";
676 }
677 First = false;
678 if (P.getTag() == dwarf::DW_TAG_unspecified_parameters)
679 OS << "...";
680 else
681 appendQualifiedName(T);
682 }
683 EndedWithTemplate = false;
684 OS << ')';
685 if (FirstParamIfArtificial) {
686 if (DieType P = FirstParamIfArtificial) {
687 if (P.getTag() == dwarf::DW_TAG_pointer_type) {
688 auto CVStep = [&](DieType CV) {
689 if (DieType U = detail::resolveReferencedType(CV)) {
690 Const |= U.getTag() == dwarf::DW_TAG_const_type;
691 Volatile |= U.getTag() == dwarf::DW_TAG_volatile_type;
692 return U;
693 }
694 return DieType();
695 };
696 if (DieType CV = CVStep(P)) {
697 CVStep(CV);
698 }
699 }
700 }
701 }
702
703 if (auto CC = D.find(dwarf::DW_AT_calling_convention)) {
704 switch (*CC->getAsUnsignedConstant()) {
705 case dwarf::CallingConvention::DW_CC_BORLAND_stdcall:
706 OS << " __attribute__((stdcall))";
707 break;
708 case dwarf::CallingConvention::DW_CC_BORLAND_msfastcall:
709 OS << " __attribute__((fastcall))";
710 break;
711 case dwarf::CallingConvention::DW_CC_BORLAND_thiscall:
712 OS << " __attribute__((thiscall))";
713 break;
714 case dwarf::CallingConvention::DW_CC_LLVM_vectorcall:
715 OS << " __attribute__((vectorcall))";
716 break;
717 case dwarf::CallingConvention::DW_CC_BORLAND_pascal:
718 OS << " __attribute__((pascal))";
719 break;
720 case dwarf::CallingConvention::DW_CC_LLVM_Win64:
721 OS << " __attribute__((ms_abi))";
722 break;
723 case dwarf::CallingConvention::DW_CC_LLVM_X86_64SysV:
724 OS << " __attribute__((sysv_abi))";
725 break;
726 case dwarf::CallingConvention::DW_CC_LLVM_AAPCS:
727 // AArch64VectorCall missing?
728 OS << " __attribute__((pcs(\"aapcs\")))";
729 break;
730 case dwarf::CallingConvention::DW_CC_LLVM_AAPCS_VFP:
731 OS << " __attribute__((pcs(\"aapcs-vfp\")))";
732 break;
733 case dwarf::CallingConvention::DW_CC_LLVM_IntelOclBicc:
734 OS << " __attribute__((intel_ocl_bicc))";
735 break;
736 case dwarf::CallingConvention::DW_CC_LLVM_SpirFunction:
737 case dwarf::CallingConvention::DW_CC_LLVM_OpenCLKernel:
738 // These aren't available as attributes, but maybe we should still
739 // render them somehow? (Clang doesn't render them, but that's an issue
740 // for template names too - since then the DWARF names of templates
741 // instantiated with function types with these calling conventions won't
742 // have distinct names - so we'd need to fix that too)
743 break;
744 case dwarf::CallingConvention::DW_CC_LLVM_Swift:
745 // SwiftAsync missing
746 OS << " __attribute__((swiftcall))";
747 break;
748 case dwarf::CallingConvention::DW_CC_LLVM_PreserveMost:
749 OS << " __attribute__((preserve_most))";
750 break;
751 case dwarf::CallingConvention::DW_CC_LLVM_PreserveAll:
752 OS << " __attribute__((preserve_all))";
753 break;
754 case dwarf::CallingConvention::DW_CC_LLVM_PreserveNone:
755 OS << " __attribute__((preserve_none))";
756 break;
757 case dwarf::CallingConvention::DW_CC_LLVM_X86RegCall:
758 OS << " __attribute__((regcall))";
759 break;
760 case dwarf::CallingConvention::DW_CC_LLVM_M68kRTD:
761 OS << " __attribute__((m68k_rtd))";
762 break;
763 }
764 }
765
766 if (Const)
767 OS << " const";
768 if (Volatile)
769 OS << " volatile";
770 if (D.find(dwarf::DW_AT_reference))
771 OS << " &";
772 if (D.find(dwarf::DW_AT_rvalue_reference))
773 OS << " &&";
774
775 appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner));
776}
777
778template <typename DieType>
780 if (D.getTag() == dwarf::DW_TAG_compile_unit)
781 return;
782 if (D.getTag() == dwarf::DW_TAG_type_unit)
783 return;
784 if (D.getTag() == dwarf::DW_TAG_skeleton_unit)
785 return;
786 if (D.getTag() == dwarf::DW_TAG_subprogram)
787 return;
788 if (D.getTag() == dwarf::DW_TAG_lexical_block)
789 return;
790 D = D.resolveTypeUnitReference();
791 if (DieType P = D.getParent())
792 appendScopes(P);
793 appendUnqualifiedName(D);
794 OS << "::";
795}
796} // namespace llvm
797
798#endif // LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
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.
std::string Name
#define F(x, y, z)
Definition: MD5.cpp:55
#define T
#define P(N)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
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:481
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:571
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:265
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:150
bool ends_with(StringRef Suffix) const
Check if this string ends with the given Suffix.
Definition: StringRef.h:277
static constexpr size_t npos
Definition: StringRef.h:53
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:661
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:679
@ 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)
Attribute
Attributes.
Definition: Dwarf.h:123
SourceLanguage
Definition: Dwarf.h:207
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:125
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1069
#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)