1 #include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
2 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
3 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
4 #include "llvm/Support/ScopedPrinter.h"
5 namespace llvm {
6 using namespace dwarf;
7 void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) {
8   StringRef TagStr = TagString(T);
9   static constexpr StringRef Prefix = "DW_TAG_";
10   static constexpr StringRef Suffix = "_type";
11   if (!TagStr.startswith(Prefix) || !TagStr.endswith(Suffix))
12     return;
13   OS << TagStr.substr(Prefix.size(),
14                       TagStr.size() - (Prefix.size() + Suffix.size()))
15      << " ";
16 }
17 
18 void DWARFTypePrinter::appendArrayType(const DWARFDie &D) {
19   for (const DWARFDie &C : D.children()) {
20     if (C.getTag() != DW_TAG_subrange_type)
21       continue;
22     std::optional<uint64_t> LB;
23     std::optional<uint64_t> Count;
24     std::optional<uint64_t> UB;
25     std::optional<unsigned> DefaultLB;
26     if (std::optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
27       LB = L->getAsUnsignedConstant();
28     if (std::optional<DWARFFormValue> CountV = C.find(DW_AT_count))
29       Count = CountV->getAsUnsignedConstant();
30     if (std::optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
31       UB = UpperV->getAsUnsignedConstant();
32     if (std::optional<DWARFFormValue> LV =
33             D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
34       if (std::optional<uint64_t> LC = LV->getAsUnsignedConstant())
35         if ((DefaultLB =
36                  LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
37           if (LB && *LB == *DefaultLB)
38             LB = std::nullopt;
39     if (!LB && !Count && !UB)
40       OS << "[]";
41     else if (!LB && (Count || UB) && DefaultLB)
42       OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
43     else {
44       OS << "[[";
45       if (LB)
46         OS << *LB;
47       else
48         OS << '?';
49       OS << ", ";
50       if (Count)
51         if (LB)
52           OS << *LB + *Count;
53         else
54           OS << "? + " << *Count;
55       else if (UB)
56         OS << *UB + 1;
57       else
58         OS << '?';
59       OS << ")]";
60     }
61   }
62   EndedWithTemplate = false;
63 }
64 
65 static DWARFDie resolveReferencedType(DWARFDie D,
66                                       dwarf::Attribute Attr = DW_AT_type) {
67   return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference();
68 }
69 static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) {
70   return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference();
71 }
72 DWARFDie DWARFTypePrinter::skipQualifiers(DWARFDie D) {
73   while (D && (D.getTag() == DW_TAG_const_type ||
74                D.getTag() == DW_TAG_volatile_type))
75     D = resolveReferencedType(D);
76   return D;
77 }
78 
79 bool DWARFTypePrinter::needsParens(DWARFDie D) {
80   D = skipQualifiers(D);
81   return D && (D.getTag() == DW_TAG_subroutine_type ||
82                D.getTag() == DW_TAG_array_type);
83 }
84 
85 void DWARFTypePrinter::appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner,
86                                                    StringRef Ptr) {
87   appendQualifiedNameBefore(Inner);
88   if (Word)
89     OS << ' ';
90   if (needsParens(Inner))
91     OS << '(';
92   OS << Ptr;
93   Word = false;
94   EndedWithTemplate = false;
95 }
96 
97 DWARFDie
98 DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D,
99                                               std::string *OriginalFullName) {
100   Word = true;
101   if (!D) {
102     OS << "void";
103     return DWARFDie();
104   }
105   DWARFDie InnerDIE;
106   auto Inner = [&] { return InnerDIE = resolveReferencedType(D); };
107   const dwarf::Tag T = D.getTag();
108   switch (T) {
109   case DW_TAG_pointer_type: {
110     appendPointerLikeTypeBefore(D, Inner(), "*");
111     break;
112   }
113   case DW_TAG_subroutine_type: {
114     appendQualifiedNameBefore(Inner());
115     if (Word) {
116       OS << ' ';
117     }
118     Word = false;
119     break;
120   }
121   case DW_TAG_array_type: {
122     appendQualifiedNameBefore(Inner());
123     break;
124   }
125   case DW_TAG_reference_type:
126     appendPointerLikeTypeBefore(D, Inner(), "&");
127     break;
128   case DW_TAG_rvalue_reference_type:
129     appendPointerLikeTypeBefore(D, Inner(), "&&");
130     break;
131   case DW_TAG_ptr_to_member_type: {
132     appendQualifiedNameBefore(Inner());
133     if (needsParens(InnerDIE))
134       OS << '(';
135     else if (Word)
136       OS << ' ';
137     if (DWARFDie Cont = resolveReferencedType(D, DW_AT_containing_type)) {
138       appendQualifiedName(Cont);
139       EndedWithTemplate = false;
140       OS << "::";
141     }
142     OS << "*";
143     Word = false;
144     break;
145   }
146   case DW_TAG_LLVM_ptrauth_type:
147     appendQualifiedNameBefore(Inner());
148     break;
149   case DW_TAG_const_type:
150   case DW_TAG_volatile_type:
151     appendConstVolatileQualifierBefore(D);
152     break;
153   case DW_TAG_namespace: {
154     if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr))
155       OS << Name;
156     else
157       OS << "(anonymous namespace)";
158     break;
159   }
160   case DW_TAG_unspecified_type: {
161     StringRef TypeName = D.getShortName();
162     if (TypeName == "decltype(nullptr)")
163       TypeName = "std::nullptr_t";
164     Word = true;
165     OS << TypeName;
166     EndedWithTemplate = false;
167     break;
168   }
169     /*
170   case DW_TAG_structure_type:
171   case DW_TAG_class_type:
172   case DW_TAG_enumeration_type:
173   case DW_TAG_base_type:
174   */
175   default: {
176     const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr);
177     if (!NamePtr) {
178       appendTypeTagName(D.getTag());
179       return DWARFDie();
180     }
181     Word = true;
182     StringRef Name = NamePtr;
183     static constexpr StringRef MangledPrefix = "_STN|";
184     if (Name.startswith(MangledPrefix)) {
185       Name = Name.drop_front(MangledPrefix.size());
186       auto Separator = Name.find('|');
187       assert(Separator != StringRef::npos);
188       StringRef BaseName = Name.substr(0, Separator);
189       StringRef TemplateArgs = Name.substr(Separator + 1);
190       if (OriginalFullName)
191         *OriginalFullName = (BaseName + TemplateArgs).str();
192       Name = BaseName;
193     } else
194       EndedWithTemplate = Name.endswith(">");
195     OS << Name;
196     // This check would be insufficient for operator overloads like
197     // "operator>>" - but for now Clang doesn't try to simplify them, so this
198     // is OK. Add more nuanced operator overload handling here if/when needed.
199     if (Name.endswith(">"))
200       break;
201     if (!appendTemplateParameters(D))
202       break;
203 
204     if (EndedWithTemplate)
205       OS << ' ';
206     OS << '>';
207     EndedWithTemplate = true;
208     Word = true;
209     break;
210   }
211   }
212   return InnerDIE;
213 }
214 
215 void DWARFTypePrinter::appendUnqualifiedNameAfter(
216     DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) {
217   if (!D)
218     return;
219   switch (D.getTag()) {
220   case DW_TAG_subroutine_type: {
221     appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
222                               false);
223     break;
224   }
225   case DW_TAG_array_type: {
226     appendArrayType(D);
227     break;
228   }
229   case DW_TAG_const_type:
230   case DW_TAG_volatile_type:
231     appendConstVolatileQualifierAfter(D);
232     break;
233   case DW_TAG_ptr_to_member_type:
234   case DW_TAG_reference_type:
235   case DW_TAG_rvalue_reference_type:
236   case DW_TAG_pointer_type: {
237     if (needsParens(Inner))
238       OS << ')';
239     appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner),
240                                /*SkipFirstParamIfArtificial=*/D.getTag() ==
241                                    DW_TAG_ptr_to_member_type);
242     break;
243   }
244   case DW_TAG_LLVM_ptrauth_type: {
245     auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t {
246       if (auto Form = D.find(Attr))
247         return *Form->getAsUnsignedConstant();
248       return 0;
249     };
250     SmallVector<const char *, 2> optionsVec;
251     if (getValOrNull(DW_AT_LLVM_ptrauth_isa_pointer))
252       optionsVec.push_back("isa-pointer");
253     if (getValOrNull(DW_AT_LLVM_ptrauth_authenticates_null_values))
254       optionsVec.push_back("authenticates-null-values");
255     std::string options;
256     for (const auto *option : optionsVec) {
257       if (options.size())
258         options += ",";
259       options += option;
260     }
261     if (options.size())
262       options = ", \"" + options + "\"";
263     std::string PtrauthString;
264     llvm::raw_string_ostream PtrauthStream(PtrauthString);
265     PtrauthStream
266         << "__ptrauth(" << getValOrNull(DW_AT_LLVM_ptrauth_key) << ", "
267         << getValOrNull(DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0"
268         << utohexstr(getValOrNull(DW_AT_LLVM_ptrauth_extra_discriminator), true)
269         << options << ")";
270     OS << PtrauthStream.str();
271     break;
272   }
273     /*
274   case DW_TAG_structure_type:
275   case DW_TAG_class_type:
276   case DW_TAG_enumeration_type:
277   case DW_TAG_base_type:
278   case DW_TAG_namespace:
279   */
280   default:
281     break;
282   }
283 }
284 
285 /// Returns True if the DIE TAG is one of the ones that is scopped.
286 static bool scopedTAGs(dwarf::Tag Tag) {
287   switch (Tag) {
288   case dwarf::DW_TAG_structure_type:
289   case dwarf::DW_TAG_class_type:
290   case dwarf::DW_TAG_union_type:
291   case dwarf::DW_TAG_namespace:
292   case dwarf::DW_TAG_enumeration_type:
293     return true;
294   default:
295     break;
296   }
297   return false;
298 }
299 void DWARFTypePrinter::appendQualifiedName(DWARFDie D) {
300   if (D && scopedTAGs(D.getTag()))
301     appendScopes(D.getParent());
302   appendUnqualifiedName(D);
303 }
304 DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) {
305   if (D && scopedTAGs(D.getTag()))
306     appendScopes(D.getParent());
307   return appendUnqualifiedNameBefore(D);
308 }
309 bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D,
310                                                 bool *FirstParameter) {
311   bool FirstParameterValue = true;
312   bool IsTemplate = false;
313   if (!FirstParameter)
314     FirstParameter = &FirstParameterValue;
315   for (const DWARFDie &C : D) {
316     auto Sep = [&] {
317       if (*FirstParameter)
318         OS << '<';
319       else
320         OS << ", ";
321       IsTemplate = true;
322       EndedWithTemplate = false;
323       *FirstParameter = false;
324     };
325     if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
326       IsTemplate = true;
327       appendTemplateParameters(C, FirstParameter);
328     }
329     if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
330       DWARFDie T = resolveReferencedType(C);
331       Sep();
332       if (T.getTag() == DW_TAG_enumeration_type) {
333         OS << '(';
334         appendQualifiedName(T);
335         OS << ')';
336         auto V = C.find(DW_AT_const_value);
337         OS << std::to_string(*V->getAsSignedConstant());
338         continue;
339       }
340       // /Maybe/ we could do pointer type parameters, looking for the
341       // symbol in the ELF symbol table to get back to the variable...
342       // but probably not worth it.
343       if (T.getTag() == DW_TAG_pointer_type)
344         continue;
345       const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr);
346       assert(RawName);
347       StringRef Name = RawName;
348       auto V = C.find(DW_AT_const_value);
349       bool IsQualifiedChar = false;
350       if (Name == "bool") {
351         OS << (*V->getAsUnsignedConstant() ? "true" : "false");
352       } else if (Name == "short") {
353         OS << "(short)";
354         OS << std::to_string(*V->getAsSignedConstant());
355       } else if (Name == "unsigned short") {
356         OS << "(unsigned short)";
357         OS << std::to_string(*V->getAsSignedConstant());
358       } else if (Name == "int")
359         OS << std::to_string(*V->getAsSignedConstant());
360       else if (Name == "long") {
361         OS << std::to_string(*V->getAsSignedConstant());
362         OS << "L";
363       } else if (Name == "long long") {
364         OS << std::to_string(*V->getAsSignedConstant());
365         OS << "LL";
366       } else if (Name == "unsigned int") {
367         OS << std::to_string(*V->getAsUnsignedConstant());
368         OS << "U";
369       } else if (Name == "unsigned long") {
370         OS << std::to_string(*V->getAsUnsignedConstant());
371         OS << "UL";
372       } else if (Name == "unsigned long long") {
373         OS << std::to_string(*V->getAsUnsignedConstant());
374         OS << "ULL";
375       } else if (Name == "char" ||
376                  (IsQualifiedChar =
377                       (Name == "unsigned char" || Name == "signed char"))) {
378         // FIXME: check T's DW_AT_type to see if it's signed or not (since
379         // char signedness is implementation defined).
380         auto Val = *V->getAsSignedConstant();
381         // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
382         // (doesn't actually support different character types/widths, sign
383         // handling's not done, and doesn't correctly test if a character is
384         // printable or needs to use a numeric escape sequence instead)
385         if (IsQualifiedChar) {
386           OS << '(';
387           OS << Name;
388           OS << ')';
389         }
390         switch (Val) {
391         case '\\':
392           OS << "'\\\\'";
393           break;
394         case '\'':
395           OS << "'\\''";
396           break;
397         case '\a':
398           // TODO: K&R: the meaning of '\\a' is different in traditional C
399           OS << "'\\a'";
400           break;
401         case '\b':
402           OS << "'\\b'";
403           break;
404         case '\f':
405           OS << "'\\f'";
406           break;
407         case '\n':
408           OS << "'\\n'";
409           break;
410         case '\r':
411           OS << "'\\r'";
412           break;
413         case '\t':
414           OS << "'\\t'";
415           break;
416         case '\v':
417           OS << "'\\v'";
418           break;
419         default:
420           if ((Val & ~0xFFu) == ~0xFFu)
421             Val &= 0xFFu;
422           if (Val < 127 && Val >= 32) {
423             OS << "'";
424             OS << (char)Val;
425             OS << "'";
426           } else if (Val < 256)
427             OS << to_string(llvm::format("'\\x%02x'", Val));
428           else if (Val <= 0xFFFF)
429             OS << to_string(llvm::format("'\\u%04x'", Val));
430           else
431             OS << to_string(llvm::format("'\\U%08x'", Val));
432         }
433       }
434       continue;
435     }
436     if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
437       const char *RawName =
438           dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr);
439       assert(RawName);
440       StringRef Name = RawName;
441       Sep();
442       OS << Name;
443       continue;
444     }
445     if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
446       continue;
447     auto TypeAttr = C.find(DW_AT_type);
448     Sep();
449     appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr)
450                                  : DWARFDie());
451   }
452   if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
453     OS << '<';
454     EndedWithTemplate = false;
455   }
456   return IsTemplate;
457 }
458 void DWARFTypePrinter::decomposeConstVolatile(DWARFDie &N, DWARFDie &T,
459                                               DWARFDie &C, DWARFDie &V) {
460   (N.getTag() == DW_TAG_const_type ? C : V) = N;
461   T = resolveReferencedType(N);
462   if (T) {
463     auto Tag = T.getTag();
464     if (Tag == DW_TAG_const_type) {
465       C = T;
466       T = resolveReferencedType(T);
467     } else if (Tag == DW_TAG_volatile_type) {
468       V = T;
469       T = resolveReferencedType(T);
470     }
471   }
472 }
473 void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) {
474   DWARFDie C;
475   DWARFDie V;
476   DWARFDie T;
477   decomposeConstVolatile(N, T, C, V);
478   if (T && T.getTag() == DW_TAG_subroutine_type)
479     appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(),
480                               V.isValid());
481   else
482     appendUnqualifiedNameAfter(T, resolveReferencedType(T));
483 }
484 void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) {
485   DWARFDie C;
486   DWARFDie V;
487   DWARFDie T;
488   decomposeConstVolatile(N, T, C, V);
489   bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type;
490   DWARFDie A = T;
491   while (A && A.getTag() == DW_TAG_array_type)
492     A = resolveReferencedType(A);
493   bool Leading =
494       (!A || (A.getTag() != DW_TAG_pointer_type &&
495               A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
496       !Subroutine;
497   if (Leading) {
498     if (C)
499       OS << "const ";
500     if (V)
501       OS << "volatile ";
502   }
503   appendQualifiedNameBefore(T);
504   if (!Leading && !Subroutine) {
505     Word = true;
506     if (C)
507       OS << "const";
508     if (V) {
509       if (C)
510         OS << ' ';
511       OS << "volatile";
512     }
513   }
514 }
515 void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D,
516                                              std::string *OriginalFullName) {
517   // FIXME: We should have pretty printers per language. Currently we print
518   // everything as if it was C++ and fall back to the TAG type name.
519   DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
520   appendUnqualifiedNameAfter(D, Inner);
521 }
522 void DWARFTypePrinter::appendSubroutineNameAfter(
523     DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const,
524     bool Volatile) {
525   DWARFDie FirstParamIfArtificial;
526   OS << '(';
527   EndedWithTemplate = false;
528   bool First = true;
529   bool RealFirst = true;
530   for (DWARFDie P : D) {
531     if (P.getTag() != DW_TAG_formal_parameter &&
532         P.getTag() != DW_TAG_unspecified_parameters)
533       return;
534     DWARFDie T = resolveReferencedType(P);
535     if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) {
536       FirstParamIfArtificial = T;
537       RealFirst = false;
538       continue;
539     }
540     if (!First) {
541       OS << ", ";
542     }
543     First = false;
544     if (P.getTag() == DW_TAG_unspecified_parameters)
545       OS << "...";
546     else
547       appendQualifiedName(T);
548   }
549   EndedWithTemplate = false;
550   OS << ')';
551   if (FirstParamIfArtificial) {
552     if (DWARFDie P = FirstParamIfArtificial) {
553       if (P.getTag() == DW_TAG_pointer_type) {
554         auto CVStep = [&](DWARFDie CV) {
555           if (DWARFDie U = resolveReferencedType(CV)) {
556             Const |= U.getTag() == DW_TAG_const_type;
557             Volatile |= U.getTag() == DW_TAG_volatile_type;
558             return U;
559           }
560           return DWARFDie();
561         };
562         if (DWARFDie CV = CVStep(P)) {
563           CVStep(CV);
564         }
565       }
566     }
567   }
568 
569   if (auto CC = D.find(DW_AT_calling_convention)) {
570     switch (*CC->getAsUnsignedConstant()) {
571     case CallingConvention::DW_CC_BORLAND_stdcall:
572       OS << " __attribute__((stdcall))";
573       break;
574     case CallingConvention::DW_CC_BORLAND_msfastcall:
575       OS << " __attribute__((fastcall))";
576       break;
577     case CallingConvention::DW_CC_BORLAND_thiscall:
578       OS << " __attribute__((thiscall))";
579       break;
580     case CallingConvention::DW_CC_LLVM_vectorcall:
581       OS << " __attribute__((vectorcall))";
582       break;
583     case CallingConvention::DW_CC_BORLAND_pascal:
584       OS << " __attribute__((pascal))";
585       break;
586     case CallingConvention::DW_CC_LLVM_Win64:
587       OS << " __attribute__((ms_abi))";
588       break;
589     case CallingConvention::DW_CC_LLVM_X86_64SysV:
590       OS << " __attribute__((sysv_abi))";
591       break;
592     case CallingConvention::DW_CC_LLVM_AAPCS:
593       // AArch64VectorCall missing?
594       OS << " __attribute__((pcs(\"aapcs\")))";
595       break;
596     case CallingConvention::DW_CC_LLVM_AAPCS_VFP:
597       OS << " __attribute__((pcs(\"aapcs-vfp\")))";
598       break;
599     case CallingConvention::DW_CC_LLVM_IntelOclBicc:
600       OS << " __attribute__((intel_ocl_bicc))";
601       break;
602     case CallingConvention::DW_CC_LLVM_SpirFunction:
603     case CallingConvention::DW_CC_LLVM_OpenCLKernel:
604       // These aren't available as attributes, but maybe we should still
605       // render them somehow? (Clang doesn't render them, but that's an issue
606       // for template names too - since then the DWARF names of templates
607       // instantiated with function types with these calling conventions won't
608       // have distinct names - so we'd need to fix that too)
609       break;
610     case CallingConvention::DW_CC_LLVM_Swift:
611       // SwiftAsync missing
612       OS << " __attribute__((swiftcall))";
613       break;
614     case CallingConvention::DW_CC_LLVM_PreserveMost:
615       OS << " __attribute__((preserve_most))";
616       break;
617     case CallingConvention::DW_CC_LLVM_PreserveAll:
618       OS << " __attribute__((preserve_all))";
619       break;
620     case CallingConvention::DW_CC_LLVM_X86RegCall:
621       OS << " __attribute__((regcall))";
622       break;
623     }
624   }
625 
626   if (Const)
627     OS << " const";
628   if (Volatile)
629     OS << " volatile";
630   if (D.find(DW_AT_reference))
631     OS << " &";
632   if (D.find(DW_AT_rvalue_reference))
633     OS << " &&";
634 
635   appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner));
636 }
637 void DWARFTypePrinter::appendScopes(DWARFDie D) {
638   if (D.getTag() == DW_TAG_compile_unit)
639     return;
640   if (D.getTag() == DW_TAG_type_unit)
641     return;
642   if (D.getTag() == DW_TAG_skeleton_unit)
643     return;
644   if (D.getTag() == DW_TAG_subprogram)
645     return;
646   if (D.getTag() == DW_TAG_lexical_block)
647     return;
648   D = D.resolveTypeUnitReference();
649   if (DWARFDie P = D.getParent())
650     appendScopes(P);
651   appendUnqualifiedName(D);
652   OS << "::";
653 }
654 } // namespace llvm
655