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/StringExtras.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/BinaryFormat/Dwarf.h"
15 #include "llvm/Support/Error.h"
16
17 #include <string>
18
19 namespace llvm {
20
21 class 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.
25 template <typename DieType> struct DWARFTypePrinter {
26 raw_ostream &OS;
27 bool Word = true;
28 bool EndedWithTemplate = false;
29
DWARFTypePrinterDWARFTypePrinter30 DWARFTypePrinter(raw_ostream &OS) : OS(OS) {}
31
32 /// Dump the name encoded in the type tag.
33 void appendTypeTagName(dwarf::Tag T);
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);
51 void appendAndTerminateTemplateParameters(DieType D);
52 void decomposeConstVolatile(DieType &N, DieType &T, DieType &C, DieType &V);
53 void appendConstVolatileQualifierAfter(DieType N);
54 void appendConstVolatileQualifierBefore(DieType N);
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
65 private:
66 /// Returns True if the DIE TAG is one of the ones that is scopped.
scopedTAGsDWARFTypePrinter67 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
83 template <typename DieType>
appendTypeTagName(dwarf::Tag T)84 void DWARFTypePrinter<DieType>::appendTypeTagName(dwarf::Tag T) {
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
95 template <typename DieType>
appendArrayType(const DieType & D)96 void DWARFTypePrinter<DieType>::appendArrayType(const DieType &D) {
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
144 namespace detail {
145 template <typename DieType>
146 DieType resolveReferencedType(DieType D,
147 dwarf::Attribute Attr = dwarf::DW_AT_type) {
148 return D.resolveReferencedType(Attr);
149 }
150 template <typename DieType>
resolveReferencedType(DieType D,typename DieType::DWARFFormValue F)151 DieType resolveReferencedType(DieType D, typename DieType::DWARFFormValue F) {
152 return D.resolveReferencedType(F);
153 }
154 template <typename DWARFFormValueType>
toString(std::optional<DWARFFormValueType> F)155 const 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
166 template <typename DieType>
skipQualifiers(DieType D)167 DieType DWARFTypePrinter<DieType>::skipQualifiers(DieType D) {
168 while (D && (D.getTag() == dwarf::DW_TAG_const_type ||
169 D.getTag() == dwarf::DW_TAG_volatile_type))
170 D = detail::resolveReferencedType(D);
171 return D;
172 }
173
174 template <typename DieType>
needsParens(DieType D)175 bool DWARFTypePrinter<DieType>::needsParens(DieType D) {
176 D = skipQualifiers(D);
177 return D && (D.getTag() == dwarf::DW_TAG_subroutine_type ||
178 D.getTag() == dwarf::DW_TAG_array_type);
179 }
180
181 template <typename DieType>
appendPointerLikeTypeBefore(DieType D,DieType Inner,StringRef Ptr)182 void DWARFTypePrinter<DieType>::appendPointerLikeTypeBefore(DieType D,
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
195 template <typename DieType>
appendUnqualifiedNameBefore(DieType D,std::string * OriginalFullName)196 DieType DWARFTypePrinter<DieType>::appendUnqualifiedNameBefore(
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
313 template <typename DieType>
appendUnqualifiedNameAfter(DieType D,DieType Inner,bool SkipFirstParamIfArtificial)314 void DWARFTypePrinter<DieType>::appendUnqualifiedNameAfter(
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 };
349 SmallVector<const char *, 2> optionsVec;
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
402 template <typename DieType>
appendQualifiedName(DieType D)403 void DWARFTypePrinter<DieType>::appendQualifiedName(DieType D) {
404 if (D && scopedTAGs(D.getTag()))
405 appendScopes(D.getParent());
406 appendUnqualifiedName(D);
407 }
408
409 template <typename DieType>
appendQualifiedNameBefore(DieType D)410 DieType DWARFTypePrinter<DieType>::appendQualifiedNameBefore(DieType D) {
411 if (D && scopedTAGs(D.getTag()))
412 appendScopes(D.getParent());
413 return appendUnqualifiedNameBefore(D);
414 }
415
416 template <typename DieType>
appendTemplateParameters(DieType D,bool * FirstParameter)417 bool DWARFTypePrinter<DieType>::appendTemplateParameters(DieType D,
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) {
438 DieType T = detail::resolveReferencedType(C);
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
568 template <typename DieType>
appendAndTerminateTemplateParameters(DieType D)569 void DWARFTypePrinter<DieType>::appendAndTerminateTemplateParameters(
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
582 template <typename DieType>
decomposeConstVolatile(DieType & N,DieType & T,DieType & C,DieType & V)583 void DWARFTypePrinter<DieType>::decomposeConstVolatile(DieType &N, DieType &T,
584 DieType &C, DieType &V) {
585 (N.getTag() == dwarf::DW_TAG_const_type ? C : V) = N;
586 T = detail::resolveReferencedType(N);
587 if (T) {
588 auto Tag = T.getTag();
589 if (Tag == dwarf::DW_TAG_const_type) {
590 C = T;
591 T = detail::resolveReferencedType(T);
592 } else if (Tag == dwarf::DW_TAG_volatile_type) {
593 V = T;
594 T = detail::resolveReferencedType(T);
595 }
596 }
597 }
598
599 template <typename DieType>
appendConstVolatileQualifierAfter(DieType N)600 void DWARFTypePrinter<DieType>::appendConstVolatileQualifierAfter(DieType N) {
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
612 template <typename DieType>
appendConstVolatileQualifierBefore(DieType N)613 void DWARFTypePrinter<DieType>::appendConstVolatileQualifierBefore(DieType N) {
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)
621 A = detail::resolveReferencedType(A);
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
645 template <typename DieType>
appendUnqualifiedName(DieType D,std::string * OriginalFullName)646 void DWARFTypePrinter<DieType>::appendUnqualifiedName(
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
654 template <typename DieType>
appendSubroutineNameAfter(DieType D,DieType Inner,bool SkipFirstParamIfArtificial,bool Const,bool Volatile)655 void DWARFTypePrinter<DieType>::appendSubroutineNameAfter(
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;
667 DieType T = detail::resolveReferencedType(P);
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 // This isn't available as an attribute, but maybe we should still
738 // render it somehow? (Clang doesn't render it, but that's an issue
739 // for template names too - since then the DWARF names of templates
740 // instantiated with function types with these calling conventions won't
741 // have distinct names - so we'd need to fix that too)
742 break;
743 case dwarf::CallingConvention::DW_CC_LLVM_DeviceKernel:
744 OS << " __attribute__((device_kernel))";
745 break;
746 case dwarf::CallingConvention::DW_CC_LLVM_Swift:
747 // SwiftAsync missing
748 OS << " __attribute__((swiftcall))";
749 break;
750 case dwarf::CallingConvention::DW_CC_LLVM_PreserveMost:
751 OS << " __attribute__((preserve_most))";
752 break;
753 case dwarf::CallingConvention::DW_CC_LLVM_PreserveAll:
754 OS << " __attribute__((preserve_all))";
755 break;
756 case dwarf::CallingConvention::DW_CC_LLVM_PreserveNone:
757 OS << " __attribute__((preserve_none))";
758 break;
759 case dwarf::CallingConvention::DW_CC_LLVM_X86RegCall:
760 OS << " __attribute__((regcall))";
761 break;
762 case dwarf::CallingConvention::DW_CC_LLVM_M68kRTD:
763 OS << " __attribute__((m68k_rtd))";
764 break;
765 }
766 }
767
768 if (Const)
769 OS << " const";
770 if (Volatile)
771 OS << " volatile";
772 if (D.find(dwarf::DW_AT_reference))
773 OS << " &";
774 if (D.find(dwarf::DW_AT_rvalue_reference))
775 OS << " &&";
776
777 appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner));
778 }
779
780 template <typename DieType>
appendScopes(DieType D)781 void DWARFTypePrinter<DieType>::appendScopes(DieType D) {
782 if (D.getTag() == dwarf::DW_TAG_compile_unit)
783 return;
784 if (D.getTag() == dwarf::DW_TAG_type_unit)
785 return;
786 if (D.getTag() == dwarf::DW_TAG_skeleton_unit)
787 return;
788 if (D.getTag() == dwarf::DW_TAG_subprogram)
789 return;
790 if (D.getTag() == dwarf::DW_TAG_lexical_block)
791 return;
792 D = D.resolveTypeUnitReference();
793 if (DieType P = D.getParent())
794 appendScopes(P);
795 appendUnqualifiedName(D);
796 OS << "::";
797 }
798 } // namespace llvm
799
800 #endif // LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
801