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"
5namespace llvm {
6using namespace dwarf;
7void 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
18void 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
65static DWARFDie resolveReferencedType(DWARFDie D,
66                                      dwarf::Attribute Attr = DW_AT_type) {
67  return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference();
68}
69static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) {
70  return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference();
71}
72DWARFDie 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
79bool 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
85void 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
97DWARFDie
98DWARFTypePrinter::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
215void 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.
286static 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}
299void DWARFTypePrinter::appendQualifiedName(DWARFDie D) {
300  if (D && scopedTAGs(D.getTag()))
301    appendScopes(D.getParent());
302  appendUnqualifiedName(D);
303}
304DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) {
305  if (D && scopedTAGs(D.getTag()))
306    appendScopes(D.getParent());
307  return appendUnqualifiedNameBefore(D);
308}
309bool 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}
458void 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}
473void 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}
484void 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}
515void 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}
522void 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}
637void 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