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     Optional<uint64_t> LB;
23     Optional<uint64_t> Count;
24     Optional<uint64_t> UB;
25     Optional<unsigned> DefaultLB;
26     if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
27       LB = L->getAsUnsignedConstant();
28     if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count))
29       Count = CountV->getAsUnsignedConstant();
30     if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
31       UB = UpperV->getAsUnsignedConstant();
32     if (Optional<DWARFFormValue> LV =
33             D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
34       if (Optional<uint64_t> LC = LV->getAsUnsignedConstant())
35         if ((DefaultLB =
36                  LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
37           if (LB && *LB == *DefaultLB)
38             LB = None;
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_const_type:
147   case DW_TAG_volatile_type:
148     appendConstVolatileQualifierBefore(D);
149     break;
150   case DW_TAG_namespace: {
151     if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr))
152       OS << Name;
153     else
154       OS << "(anonymous namespace)";
155     break;
156   }
157   case DW_TAG_unspecified_type: {
158     StringRef TypeName = D.getShortName();
159     if (TypeName == "decltype(nullptr)")
160       TypeName = "std::nullptr_t";
161     Word = true;
162     OS << TypeName;
163     EndedWithTemplate = false;
164     break;
165   }
166     /*
167   case DW_TAG_structure_type:
168   case DW_TAG_class_type:
169   case DW_TAG_enumeration_type:
170   case DW_TAG_base_type:
171   */
172   default: {
173     const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr);
174     if (!NamePtr) {
175       appendTypeTagName(D.getTag());
176       return DWARFDie();
177     }
178     Word = true;
179     StringRef Name = NamePtr;
180     static constexpr StringRef MangledPrefix = "_STN|";
181     if (Name.startswith(MangledPrefix)) {
182       Name = Name.drop_front(MangledPrefix.size());
183       auto Separator = Name.find('|');
184       assert(Separator != StringRef::npos);
185       StringRef BaseName = Name.substr(0, Separator);
186       StringRef TemplateArgs = Name.substr(Separator + 1);
187       if (OriginalFullName)
188         *OriginalFullName = (BaseName + TemplateArgs).str();
189       Name = BaseName;
190     } else
191       EndedWithTemplate = Name.endswith(">");
192     OS << Name;
193     // This check would be insufficient for operator overloads like
194     // "operator>>" - but for now Clang doesn't try to simplify them, so this
195     // is OK. Add more nuanced operator overload handling here if/when needed.
196     if (Name.endswith(">"))
197       break;
198     if (!appendTemplateParameters(D))
199       break;
200 
201     if (EndedWithTemplate)
202       OS << ' ';
203     OS << '>';
204     EndedWithTemplate = true;
205     Word = true;
206     break;
207   }
208   }
209   return InnerDIE;
210 }
211 
212 void DWARFTypePrinter::appendUnqualifiedNameAfter(
213     DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) {
214   if (!D)
215     return;
216   switch (D.getTag()) {
217   case DW_TAG_subroutine_type: {
218     appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
219                               false);
220     break;
221   }
222   case DW_TAG_array_type: {
223     appendArrayType(D);
224     break;
225   }
226   case DW_TAG_const_type:
227   case DW_TAG_volatile_type:
228     appendConstVolatileQualifierAfter(D);
229     break;
230   case DW_TAG_ptr_to_member_type:
231   case DW_TAG_reference_type:
232   case DW_TAG_rvalue_reference_type:
233   case DW_TAG_pointer_type: {
234     if (needsParens(Inner))
235       OS << ')';
236     appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner),
237                                /*SkipFirstParamIfArtificial=*/D.getTag() ==
238                                    DW_TAG_ptr_to_member_type);
239     break;
240   }
241     /*
242   case DW_TAG_structure_type:
243   case DW_TAG_class_type:
244   case DW_TAG_enumeration_type:
245   case DW_TAG_base_type:
246   case DW_TAG_namespace:
247   */
248   default:
249     break;
250   }
251 }
252 
253 void DWARFTypePrinter::appendQualifiedName(DWARFDie D) {
254   if (D)
255     appendScopes(D.getParent());
256   appendUnqualifiedName(D);
257 }
258 DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) {
259   if (D)
260     appendScopes(D.getParent());
261   return appendUnqualifiedNameBefore(D);
262 }
263 bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D,
264                                                 bool *FirstParameter) {
265   bool FirstParameterValue = true;
266   bool IsTemplate = false;
267   if (!FirstParameter)
268     FirstParameter = &FirstParameterValue;
269   for (const DWARFDie &C : D) {
270     auto Sep = [&] {
271       if (*FirstParameter)
272         OS << '<';
273       else
274         OS << ", ";
275       IsTemplate = true;
276       EndedWithTemplate = false;
277       *FirstParameter = false;
278     };
279     if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
280       IsTemplate = true;
281       appendTemplateParameters(C, FirstParameter);
282     }
283     if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
284       DWARFDie T = resolveReferencedType(C);
285       Sep();
286       if (T.getTag() == DW_TAG_enumeration_type) {
287         OS << '(';
288         appendQualifiedName(T);
289         OS << ')';
290         auto V = C.find(DW_AT_const_value);
291         OS << std::to_string(*V->getAsSignedConstant());
292         continue;
293       }
294       // /Maybe/ we could do pointer type parameters, looking for the
295       // symbol in the ELF symbol table to get back to the variable...
296       // but probably not worth it.
297       if (T.getTag() == DW_TAG_pointer_type)
298         continue;
299       const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr);
300       assert(RawName);
301       StringRef Name = RawName;
302       auto V = C.find(DW_AT_const_value);
303       bool IsQualifiedChar = false;
304       if (Name == "bool") {
305         OS << (*V->getAsUnsignedConstant() ? "true" : "false");
306       } else if (Name == "short") {
307         OS << "(short)";
308         OS << std::to_string(*V->getAsSignedConstant());
309       } else if (Name == "unsigned short") {
310         OS << "(unsigned short)";
311         OS << std::to_string(*V->getAsSignedConstant());
312       } else if (Name == "int")
313         OS << std::to_string(*V->getAsSignedConstant());
314       else if (Name == "long") {
315         OS << std::to_string(*V->getAsSignedConstant());
316         OS << "L";
317       } else if (Name == "long long") {
318         OS << std::to_string(*V->getAsSignedConstant());
319         OS << "LL";
320       } else if (Name == "unsigned int") {
321         OS << std::to_string(*V->getAsUnsignedConstant());
322         OS << "U";
323       } else if (Name == "unsigned long") {
324         OS << std::to_string(*V->getAsUnsignedConstant());
325         OS << "UL";
326       } else if (Name == "unsigned long long") {
327         OS << std::to_string(*V->getAsUnsignedConstant());
328         OS << "ULL";
329       } else if (Name == "char" ||
330                  (IsQualifiedChar =
331                       (Name == "unsigned char" || Name == "signed char"))) {
332         // FIXME: check T's DW_AT_type to see if it's signed or not (since
333         // char signedness is implementation defined).
334         auto Val = *V->getAsSignedConstant();
335         // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
336         // (doesn't actually support different character types/widths, sign
337         // handling's not done, and doesn't correctly test if a character is
338         // printable or needs to use a numeric escape sequence instead)
339         if (IsQualifiedChar) {
340           OS << '(';
341           OS << Name;
342           OS << ')';
343         }
344         switch (Val) {
345         case '\\':
346           OS << "'\\\\'";
347           break;
348         case '\'':
349           OS << "'\\''";
350           break;
351         case '\a':
352           // TODO: K&R: the meaning of '\\a' is different in traditional C
353           OS << "'\\a'";
354           break;
355         case '\b':
356           OS << "'\\b'";
357           break;
358         case '\f':
359           OS << "'\\f'";
360           break;
361         case '\n':
362           OS << "'\\n'";
363           break;
364         case '\r':
365           OS << "'\\r'";
366           break;
367         case '\t':
368           OS << "'\\t'";
369           break;
370         case '\v':
371           OS << "'\\v'";
372           break;
373         default:
374           if ((Val & ~0xFFu) == ~0xFFu)
375             Val &= 0xFFu;
376           if (Val < 127 && Val >= 32) {
377             OS << "'";
378             OS << (char)Val;
379             OS << "'";
380           } else if (Val < 256)
381             OS << to_string(llvm::format("'\\x%02x'", Val));
382           else if (Val <= 0xFFFF)
383             OS << to_string(llvm::format("'\\u%04x'", Val));
384           else
385             OS << to_string(llvm::format("'\\U%08x'", Val));
386         }
387       }
388       continue;
389     }
390     if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
391       const char *RawName =
392           dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr);
393       assert(RawName);
394       StringRef Name = RawName;
395       Sep();
396       OS << Name;
397       continue;
398     }
399     if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
400       continue;
401     auto TypeAttr = C.find(DW_AT_type);
402     Sep();
403     appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr)
404                                  : DWARFDie());
405   }
406   if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
407     OS << '<';
408     EndedWithTemplate = false;
409   }
410   return IsTemplate;
411 }
412 void DWARFTypePrinter::decomposeConstVolatile(DWARFDie &N, DWARFDie &T,
413                                               DWARFDie &C, DWARFDie &V) {
414   (N.getTag() == DW_TAG_const_type ? C : V) = N;
415   T = resolveReferencedType(N);
416   if (T) {
417     auto Tag = T.getTag();
418     if (Tag == DW_TAG_const_type) {
419       C = T;
420       T = resolveReferencedType(T);
421     } else if (Tag == DW_TAG_volatile_type) {
422       V = T;
423       T = resolveReferencedType(T);
424     }
425   }
426 }
427 void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) {
428   DWARFDie C;
429   DWARFDie V;
430   DWARFDie T;
431   decomposeConstVolatile(N, T, C, V);
432   if (T && T.getTag() == DW_TAG_subroutine_type)
433     appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(),
434                               V.isValid());
435   else
436     appendUnqualifiedNameAfter(T, resolveReferencedType(T));
437 }
438 void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) {
439   DWARFDie C;
440   DWARFDie V;
441   DWARFDie T;
442   decomposeConstVolatile(N, T, C, V);
443   bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type;
444   DWARFDie A = T;
445   while (A && A.getTag() == DW_TAG_array_type)
446     A = resolveReferencedType(A);
447   bool Leading =
448       (!A || (A.getTag() != DW_TAG_pointer_type &&
449               A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
450       !Subroutine;
451   if (Leading) {
452     if (C)
453       OS << "const ";
454     if (V)
455       OS << "volatile ";
456   }
457   appendQualifiedNameBefore(T);
458   if (!Leading && !Subroutine) {
459     Word = true;
460     if (C)
461       OS << "const";
462     if (V) {
463       if (C)
464         OS << ' ';
465       OS << "volatile";
466     }
467   }
468 }
469 void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D,
470                                              std::string *OriginalFullName) {
471   // FIXME: We should have pretty printers per language. Currently we print
472   // everything as if it was C++ and fall back to the TAG type name.
473   DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
474   appendUnqualifiedNameAfter(D, Inner);
475 }
476 void DWARFTypePrinter::appendSubroutineNameAfter(
477     DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const,
478     bool Volatile) {
479   DWARFDie FirstParamIfArtificial;
480   OS << '(';
481   EndedWithTemplate = false;
482   bool First = true;
483   bool RealFirst = true;
484   for (DWARFDie P : D) {
485     if (P.getTag() != DW_TAG_formal_parameter &&
486         P.getTag() != DW_TAG_unspecified_parameters)
487       return;
488     DWARFDie T = resolveReferencedType(P);
489     if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) {
490       FirstParamIfArtificial = T;
491       RealFirst = false;
492       continue;
493     }
494     if (!First) {
495       OS << ", ";
496     }
497     First = false;
498     if (P.getTag() == DW_TAG_unspecified_parameters)
499       OS << "...";
500     else
501       appendQualifiedName(T);
502   }
503   EndedWithTemplate = false;
504   OS << ')';
505   if (FirstParamIfArtificial) {
506     if (DWARFDie P = FirstParamIfArtificial) {
507       if (P.getTag() == DW_TAG_pointer_type) {
508         auto CVStep = [&](DWARFDie CV) {
509           if (DWARFDie U = resolveReferencedType(CV)) {
510             Const |= U.getTag() == DW_TAG_const_type;
511             Volatile |= U.getTag() == DW_TAG_volatile_type;
512             return U;
513           }
514           return DWARFDie();
515         };
516         if (DWARFDie CV = CVStep(P)) {
517           CVStep(CV);
518         }
519       }
520     }
521   }
522 
523   if (auto CC = D.find(DW_AT_calling_convention)) {
524     switch (*CC->getAsUnsignedConstant()) {
525     case CallingConvention::DW_CC_BORLAND_stdcall:
526       OS << " __attribute__((stdcall))";
527       break;
528     case CallingConvention::DW_CC_BORLAND_msfastcall:
529       OS << " __attribute__((fastcall))";
530       break;
531     case CallingConvention::DW_CC_BORLAND_thiscall:
532       OS << " __attribute__((thiscall))";
533       break;
534     case CallingConvention::DW_CC_LLVM_vectorcall:
535       OS << " __attribute__((vectorcall))";
536       break;
537     case CallingConvention::DW_CC_BORLAND_pascal:
538       OS << " __attribute__((pascal))";
539       break;
540     case CallingConvention::DW_CC_LLVM_Win64:
541       OS << " __attribute__((ms_abi))";
542       break;
543     case CallingConvention::DW_CC_LLVM_X86_64SysV:
544       OS << " __attribute__((sysv_abi))";
545       break;
546     case CallingConvention::DW_CC_LLVM_AAPCS:
547       // AArch64VectorCall missing?
548       OS << " __attribute__((pcs(\"aapcs\")))";
549       break;
550     case CallingConvention::DW_CC_LLVM_AAPCS_VFP:
551       OS << " __attribute__((pcs(\"aapcs-vfp\")))";
552       break;
553     case CallingConvention::DW_CC_LLVM_IntelOclBicc:
554       OS << " __attribute__((intel_ocl_bicc))";
555       break;
556     case CallingConvention::DW_CC_LLVM_SpirFunction:
557     case CallingConvention::DW_CC_LLVM_OpenCLKernel:
558       // These aren't available as attributes, but maybe we should still
559       // render them somehow? (Clang doesn't render them, but that's an issue
560       // for template names too - since then the DWARF names of templates
561       // instantiated with function types with these calling conventions won't
562       // have distinct names - so we'd need to fix that too)
563       break;
564     case CallingConvention::DW_CC_LLVM_Swift:
565       // SwiftAsync missing
566       OS << " __attribute__((swiftcall))";
567       break;
568     case CallingConvention::DW_CC_LLVM_PreserveMost:
569       OS << " __attribute__((preserve_most))";
570       break;
571     case CallingConvention::DW_CC_LLVM_PreserveAll:
572       OS << " __attribute__((preserve_all))";
573       break;
574     case CallingConvention::DW_CC_LLVM_X86RegCall:
575       OS << " __attribute__((regcall))";
576       break;
577     }
578   }
579 
580   if (Const)
581     OS << " const";
582   if (Volatile)
583     OS << " volatile";
584   if (D.find(DW_AT_reference))
585     OS << " &";
586   if (D.find(DW_AT_rvalue_reference))
587     OS << " &&";
588 
589   appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner));
590 }
591 void DWARFTypePrinter::appendScopes(DWARFDie D) {
592   if (D.getTag() == DW_TAG_compile_unit)
593     return;
594   if (D.getTag() == DW_TAG_type_unit)
595     return;
596   if (D.getTag() == DW_TAG_skeleton_unit)
597     return;
598   if (D.getTag() == DW_TAG_subprogram)
599     return;
600   if (D.getTag() == DW_TAG_lexical_block)
601     return;
602   D = D.resolveTypeUnitReference();
603   if (DWARFDie P = D.getParent())
604     appendScopes(P);
605   appendUnqualifiedName(D);
606   OS << "::";
607 }
608 } // namespace llvm
609