181ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
281ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDie.h"
381ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
481ad6265SDimitry Andric #include "llvm/Support/ScopedPrinter.h"
581ad6265SDimitry Andric namespace llvm {
681ad6265SDimitry Andric using namespace dwarf;
781ad6265SDimitry Andric void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) {
881ad6265SDimitry Andric   StringRef TagStr = TagString(T);
981ad6265SDimitry Andric   static constexpr StringRef Prefix = "DW_TAG_";
1081ad6265SDimitry Andric   static constexpr StringRef Suffix = "_type";
1181ad6265SDimitry Andric   if (!TagStr.startswith(Prefix) || !TagStr.endswith(Suffix))
1281ad6265SDimitry Andric     return;
1381ad6265SDimitry Andric   OS << TagStr.substr(Prefix.size(),
1481ad6265SDimitry Andric                       TagStr.size() - (Prefix.size() + Suffix.size()))
1581ad6265SDimitry Andric      << " ";
1681ad6265SDimitry Andric }
1781ad6265SDimitry Andric 
1881ad6265SDimitry Andric void DWARFTypePrinter::appendArrayType(const DWARFDie &D) {
1981ad6265SDimitry Andric   for (const DWARFDie &C : D.children()) {
2081ad6265SDimitry Andric     if (C.getTag() != DW_TAG_subrange_type)
2181ad6265SDimitry Andric       continue;
22*bdd1243dSDimitry Andric     std::optional<uint64_t> LB;
23*bdd1243dSDimitry Andric     std::optional<uint64_t> Count;
24*bdd1243dSDimitry Andric     std::optional<uint64_t> UB;
25*bdd1243dSDimitry Andric     std::optional<unsigned> DefaultLB;
26*bdd1243dSDimitry Andric     if (std::optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
2781ad6265SDimitry Andric       LB = L->getAsUnsignedConstant();
28*bdd1243dSDimitry Andric     if (std::optional<DWARFFormValue> CountV = C.find(DW_AT_count))
2981ad6265SDimitry Andric       Count = CountV->getAsUnsignedConstant();
30*bdd1243dSDimitry Andric     if (std::optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
3181ad6265SDimitry Andric       UB = UpperV->getAsUnsignedConstant();
32*bdd1243dSDimitry Andric     if (std::optional<DWARFFormValue> LV =
3381ad6265SDimitry Andric             D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
34*bdd1243dSDimitry Andric       if (std::optional<uint64_t> LC = LV->getAsUnsignedConstant())
3581ad6265SDimitry Andric         if ((DefaultLB =
3681ad6265SDimitry Andric                  LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
3781ad6265SDimitry Andric           if (LB && *LB == *DefaultLB)
38*bdd1243dSDimitry Andric             LB = std::nullopt;
3981ad6265SDimitry Andric     if (!LB && !Count && !UB)
4081ad6265SDimitry Andric       OS << "[]";
4181ad6265SDimitry Andric     else if (!LB && (Count || UB) && DefaultLB)
4281ad6265SDimitry Andric       OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
4381ad6265SDimitry Andric     else {
4481ad6265SDimitry Andric       OS << "[[";
4581ad6265SDimitry Andric       if (LB)
4681ad6265SDimitry Andric         OS << *LB;
4781ad6265SDimitry Andric       else
4881ad6265SDimitry Andric         OS << '?';
4981ad6265SDimitry Andric       OS << ", ";
5081ad6265SDimitry Andric       if (Count)
5181ad6265SDimitry Andric         if (LB)
5281ad6265SDimitry Andric           OS << *LB + *Count;
5381ad6265SDimitry Andric         else
5481ad6265SDimitry Andric           OS << "? + " << *Count;
5581ad6265SDimitry Andric       else if (UB)
5681ad6265SDimitry Andric         OS << *UB + 1;
5781ad6265SDimitry Andric       else
5881ad6265SDimitry Andric         OS << '?';
5981ad6265SDimitry Andric       OS << ")]";
6081ad6265SDimitry Andric     }
6181ad6265SDimitry Andric   }
6281ad6265SDimitry Andric   EndedWithTemplate = false;
6381ad6265SDimitry Andric }
6481ad6265SDimitry Andric 
6581ad6265SDimitry Andric static DWARFDie resolveReferencedType(DWARFDie D,
6681ad6265SDimitry Andric                                       dwarf::Attribute Attr = DW_AT_type) {
6781ad6265SDimitry Andric   return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference();
6881ad6265SDimitry Andric }
6981ad6265SDimitry Andric static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) {
7081ad6265SDimitry Andric   return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference();
7181ad6265SDimitry Andric }
7281ad6265SDimitry Andric DWARFDie DWARFTypePrinter::skipQualifiers(DWARFDie D) {
7381ad6265SDimitry Andric   while (D && (D.getTag() == DW_TAG_const_type ||
7481ad6265SDimitry Andric                D.getTag() == DW_TAG_volatile_type))
7581ad6265SDimitry Andric     D = resolveReferencedType(D);
7681ad6265SDimitry Andric   return D;
7781ad6265SDimitry Andric }
7881ad6265SDimitry Andric 
7981ad6265SDimitry Andric bool DWARFTypePrinter::needsParens(DWARFDie D) {
8081ad6265SDimitry Andric   D = skipQualifiers(D);
8181ad6265SDimitry Andric   return D && (D.getTag() == DW_TAG_subroutine_type ||
8281ad6265SDimitry Andric                D.getTag() == DW_TAG_array_type);
8381ad6265SDimitry Andric }
8481ad6265SDimitry Andric 
8581ad6265SDimitry Andric void DWARFTypePrinter::appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner,
8681ad6265SDimitry Andric                                                    StringRef Ptr) {
8781ad6265SDimitry Andric   appendQualifiedNameBefore(Inner);
8881ad6265SDimitry Andric   if (Word)
8981ad6265SDimitry Andric     OS << ' ';
9081ad6265SDimitry Andric   if (needsParens(Inner))
9181ad6265SDimitry Andric     OS << '(';
9281ad6265SDimitry Andric   OS << Ptr;
9381ad6265SDimitry Andric   Word = false;
9481ad6265SDimitry Andric   EndedWithTemplate = false;
9581ad6265SDimitry Andric }
9681ad6265SDimitry Andric 
9781ad6265SDimitry Andric DWARFDie
9881ad6265SDimitry Andric DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D,
9981ad6265SDimitry Andric                                               std::string *OriginalFullName) {
10081ad6265SDimitry Andric   Word = true;
10181ad6265SDimitry Andric   if (!D) {
10281ad6265SDimitry Andric     OS << "void";
10381ad6265SDimitry Andric     return DWARFDie();
10481ad6265SDimitry Andric   }
10581ad6265SDimitry Andric   DWARFDie InnerDIE;
10681ad6265SDimitry Andric   auto Inner = [&] { return InnerDIE = resolveReferencedType(D); };
10781ad6265SDimitry Andric   const dwarf::Tag T = D.getTag();
10881ad6265SDimitry Andric   switch (T) {
10981ad6265SDimitry Andric   case DW_TAG_pointer_type: {
11081ad6265SDimitry Andric     appendPointerLikeTypeBefore(D, Inner(), "*");
11181ad6265SDimitry Andric     break;
11281ad6265SDimitry Andric   }
11381ad6265SDimitry Andric   case DW_TAG_subroutine_type: {
11481ad6265SDimitry Andric     appendQualifiedNameBefore(Inner());
11581ad6265SDimitry Andric     if (Word) {
11681ad6265SDimitry Andric       OS << ' ';
11781ad6265SDimitry Andric     }
11881ad6265SDimitry Andric     Word = false;
11981ad6265SDimitry Andric     break;
12081ad6265SDimitry Andric   }
12181ad6265SDimitry Andric   case DW_TAG_array_type: {
12281ad6265SDimitry Andric     appendQualifiedNameBefore(Inner());
12381ad6265SDimitry Andric     break;
12481ad6265SDimitry Andric   }
12581ad6265SDimitry Andric   case DW_TAG_reference_type:
12681ad6265SDimitry Andric     appendPointerLikeTypeBefore(D, Inner(), "&");
12781ad6265SDimitry Andric     break;
12881ad6265SDimitry Andric   case DW_TAG_rvalue_reference_type:
12981ad6265SDimitry Andric     appendPointerLikeTypeBefore(D, Inner(), "&&");
13081ad6265SDimitry Andric     break;
13181ad6265SDimitry Andric   case DW_TAG_ptr_to_member_type: {
13281ad6265SDimitry Andric     appendQualifiedNameBefore(Inner());
13381ad6265SDimitry Andric     if (needsParens(InnerDIE))
13481ad6265SDimitry Andric       OS << '(';
13581ad6265SDimitry Andric     else if (Word)
13681ad6265SDimitry Andric       OS << ' ';
13781ad6265SDimitry Andric     if (DWARFDie Cont = resolveReferencedType(D, DW_AT_containing_type)) {
13881ad6265SDimitry Andric       appendQualifiedName(Cont);
13981ad6265SDimitry Andric       EndedWithTemplate = false;
14081ad6265SDimitry Andric       OS << "::";
14181ad6265SDimitry Andric     }
14281ad6265SDimitry Andric     OS << "*";
14381ad6265SDimitry Andric     Word = false;
14481ad6265SDimitry Andric     break;
14581ad6265SDimitry Andric   }
146*bdd1243dSDimitry Andric   case DW_TAG_LLVM_ptrauth_type:
147*bdd1243dSDimitry Andric     appendQualifiedNameBefore(Inner());
148*bdd1243dSDimitry Andric     break;
14981ad6265SDimitry Andric   case DW_TAG_const_type:
15081ad6265SDimitry Andric   case DW_TAG_volatile_type:
15181ad6265SDimitry Andric     appendConstVolatileQualifierBefore(D);
15281ad6265SDimitry Andric     break;
15381ad6265SDimitry Andric   case DW_TAG_namespace: {
15481ad6265SDimitry Andric     if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr))
15581ad6265SDimitry Andric       OS << Name;
15681ad6265SDimitry Andric     else
15781ad6265SDimitry Andric       OS << "(anonymous namespace)";
15881ad6265SDimitry Andric     break;
15981ad6265SDimitry Andric   }
16081ad6265SDimitry Andric   case DW_TAG_unspecified_type: {
16181ad6265SDimitry Andric     StringRef TypeName = D.getShortName();
16281ad6265SDimitry Andric     if (TypeName == "decltype(nullptr)")
16381ad6265SDimitry Andric       TypeName = "std::nullptr_t";
16481ad6265SDimitry Andric     Word = true;
16581ad6265SDimitry Andric     OS << TypeName;
16681ad6265SDimitry Andric     EndedWithTemplate = false;
16781ad6265SDimitry Andric     break;
16881ad6265SDimitry Andric   }
16981ad6265SDimitry Andric     /*
17081ad6265SDimitry Andric   case DW_TAG_structure_type:
17181ad6265SDimitry Andric   case DW_TAG_class_type:
17281ad6265SDimitry Andric   case DW_TAG_enumeration_type:
17381ad6265SDimitry Andric   case DW_TAG_base_type:
17481ad6265SDimitry Andric   */
17581ad6265SDimitry Andric   default: {
17681ad6265SDimitry Andric     const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr);
17781ad6265SDimitry Andric     if (!NamePtr) {
17881ad6265SDimitry Andric       appendTypeTagName(D.getTag());
17981ad6265SDimitry Andric       return DWARFDie();
18081ad6265SDimitry Andric     }
18181ad6265SDimitry Andric     Word = true;
18281ad6265SDimitry Andric     StringRef Name = NamePtr;
18381ad6265SDimitry Andric     static constexpr StringRef MangledPrefix = "_STN|";
18481ad6265SDimitry Andric     if (Name.startswith(MangledPrefix)) {
18581ad6265SDimitry Andric       Name = Name.drop_front(MangledPrefix.size());
18681ad6265SDimitry Andric       auto Separator = Name.find('|');
18781ad6265SDimitry Andric       assert(Separator != StringRef::npos);
18881ad6265SDimitry Andric       StringRef BaseName = Name.substr(0, Separator);
18981ad6265SDimitry Andric       StringRef TemplateArgs = Name.substr(Separator + 1);
19081ad6265SDimitry Andric       if (OriginalFullName)
19181ad6265SDimitry Andric         *OriginalFullName = (BaseName + TemplateArgs).str();
19281ad6265SDimitry Andric       Name = BaseName;
19381ad6265SDimitry Andric     } else
19481ad6265SDimitry Andric       EndedWithTemplate = Name.endswith(">");
19581ad6265SDimitry Andric     OS << Name;
19681ad6265SDimitry Andric     // This check would be insufficient for operator overloads like
19781ad6265SDimitry Andric     // "operator>>" - but for now Clang doesn't try to simplify them, so this
19881ad6265SDimitry Andric     // is OK. Add more nuanced operator overload handling here if/when needed.
19981ad6265SDimitry Andric     if (Name.endswith(">"))
20081ad6265SDimitry Andric       break;
20181ad6265SDimitry Andric     if (!appendTemplateParameters(D))
20281ad6265SDimitry Andric       break;
20381ad6265SDimitry Andric 
20481ad6265SDimitry Andric     if (EndedWithTemplate)
20581ad6265SDimitry Andric       OS << ' ';
20681ad6265SDimitry Andric     OS << '>';
20781ad6265SDimitry Andric     EndedWithTemplate = true;
20881ad6265SDimitry Andric     Word = true;
20981ad6265SDimitry Andric     break;
21081ad6265SDimitry Andric   }
21181ad6265SDimitry Andric   }
21281ad6265SDimitry Andric   return InnerDIE;
21381ad6265SDimitry Andric }
21481ad6265SDimitry Andric 
21581ad6265SDimitry Andric void DWARFTypePrinter::appendUnqualifiedNameAfter(
21681ad6265SDimitry Andric     DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) {
21781ad6265SDimitry Andric   if (!D)
21881ad6265SDimitry Andric     return;
21981ad6265SDimitry Andric   switch (D.getTag()) {
22081ad6265SDimitry Andric   case DW_TAG_subroutine_type: {
22181ad6265SDimitry Andric     appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
22281ad6265SDimitry Andric                               false);
22381ad6265SDimitry Andric     break;
22481ad6265SDimitry Andric   }
22581ad6265SDimitry Andric   case DW_TAG_array_type: {
22681ad6265SDimitry Andric     appendArrayType(D);
22781ad6265SDimitry Andric     break;
22881ad6265SDimitry Andric   }
22981ad6265SDimitry Andric   case DW_TAG_const_type:
23081ad6265SDimitry Andric   case DW_TAG_volatile_type:
23181ad6265SDimitry Andric     appendConstVolatileQualifierAfter(D);
23281ad6265SDimitry Andric     break;
23381ad6265SDimitry Andric   case DW_TAG_ptr_to_member_type:
23481ad6265SDimitry Andric   case DW_TAG_reference_type:
23581ad6265SDimitry Andric   case DW_TAG_rvalue_reference_type:
23681ad6265SDimitry Andric   case DW_TAG_pointer_type: {
23781ad6265SDimitry Andric     if (needsParens(Inner))
23881ad6265SDimitry Andric       OS << ')';
23981ad6265SDimitry Andric     appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner),
24081ad6265SDimitry Andric                                /*SkipFirstParamIfArtificial=*/D.getTag() ==
24181ad6265SDimitry Andric                                    DW_TAG_ptr_to_member_type);
24281ad6265SDimitry Andric     break;
24381ad6265SDimitry Andric   }
244*bdd1243dSDimitry Andric   case DW_TAG_LLVM_ptrauth_type: {
245*bdd1243dSDimitry Andric     auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t {
246*bdd1243dSDimitry Andric       if (auto Form = D.find(Attr))
247*bdd1243dSDimitry Andric         return *Form->getAsUnsignedConstant();
248*bdd1243dSDimitry Andric       return 0;
249*bdd1243dSDimitry Andric     };
250*bdd1243dSDimitry Andric     SmallVector<const char *, 2> optionsVec;
251*bdd1243dSDimitry Andric     if (getValOrNull(DW_AT_LLVM_ptrauth_isa_pointer))
252*bdd1243dSDimitry Andric       optionsVec.push_back("isa-pointer");
253*bdd1243dSDimitry Andric     if (getValOrNull(DW_AT_LLVM_ptrauth_authenticates_null_values))
254*bdd1243dSDimitry Andric       optionsVec.push_back("authenticates-null-values");
255*bdd1243dSDimitry Andric     std::string options;
256*bdd1243dSDimitry Andric     for (const auto *option : optionsVec) {
257*bdd1243dSDimitry Andric       if (options.size())
258*bdd1243dSDimitry Andric         options += ",";
259*bdd1243dSDimitry Andric       options += option;
260*bdd1243dSDimitry Andric     }
261*bdd1243dSDimitry Andric     if (options.size())
262*bdd1243dSDimitry Andric       options = ", \"" + options + "\"";
263*bdd1243dSDimitry Andric     std::string PtrauthString;
264*bdd1243dSDimitry Andric     llvm::raw_string_ostream PtrauthStream(PtrauthString);
265*bdd1243dSDimitry Andric     PtrauthStream
266*bdd1243dSDimitry Andric         << "__ptrauth(" << getValOrNull(DW_AT_LLVM_ptrauth_key) << ", "
267*bdd1243dSDimitry Andric         << getValOrNull(DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0"
268*bdd1243dSDimitry Andric         << utohexstr(getValOrNull(DW_AT_LLVM_ptrauth_extra_discriminator), true)
269*bdd1243dSDimitry Andric         << options << ")";
270*bdd1243dSDimitry Andric     OS << PtrauthStream.str();
271*bdd1243dSDimitry Andric     break;
272*bdd1243dSDimitry Andric   }
27381ad6265SDimitry Andric     /*
27481ad6265SDimitry Andric   case DW_TAG_structure_type:
27581ad6265SDimitry Andric   case DW_TAG_class_type:
27681ad6265SDimitry Andric   case DW_TAG_enumeration_type:
27781ad6265SDimitry Andric   case DW_TAG_base_type:
27881ad6265SDimitry Andric   case DW_TAG_namespace:
27981ad6265SDimitry Andric   */
28081ad6265SDimitry Andric   default:
28181ad6265SDimitry Andric     break;
28281ad6265SDimitry Andric   }
28381ad6265SDimitry Andric }
28481ad6265SDimitry Andric 
285*bdd1243dSDimitry Andric /// Returns True if the DIE TAG is one of the ones that is scopped.
286*bdd1243dSDimitry Andric static bool scopedTAGs(dwarf::Tag Tag) {
287*bdd1243dSDimitry Andric   switch (Tag) {
288*bdd1243dSDimitry Andric   case dwarf::DW_TAG_structure_type:
289*bdd1243dSDimitry Andric   case dwarf::DW_TAG_class_type:
290*bdd1243dSDimitry Andric   case dwarf::DW_TAG_union_type:
291*bdd1243dSDimitry Andric   case dwarf::DW_TAG_namespace:
292*bdd1243dSDimitry Andric   case dwarf::DW_TAG_enumeration_type:
293*bdd1243dSDimitry Andric     return true;
294*bdd1243dSDimitry Andric   default:
295*bdd1243dSDimitry Andric     break;
296*bdd1243dSDimitry Andric   }
297*bdd1243dSDimitry Andric   return false;
298*bdd1243dSDimitry Andric }
29981ad6265SDimitry Andric void DWARFTypePrinter::appendQualifiedName(DWARFDie D) {
300*bdd1243dSDimitry Andric   if (D && scopedTAGs(D.getTag()))
30181ad6265SDimitry Andric     appendScopes(D.getParent());
30281ad6265SDimitry Andric   appendUnqualifiedName(D);
30381ad6265SDimitry Andric }
30481ad6265SDimitry Andric DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) {
305*bdd1243dSDimitry Andric   if (D && scopedTAGs(D.getTag()))
30681ad6265SDimitry Andric     appendScopes(D.getParent());
30781ad6265SDimitry Andric   return appendUnqualifiedNameBefore(D);
30881ad6265SDimitry Andric }
30981ad6265SDimitry Andric bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D,
31081ad6265SDimitry Andric                                                 bool *FirstParameter) {
31181ad6265SDimitry Andric   bool FirstParameterValue = true;
31281ad6265SDimitry Andric   bool IsTemplate = false;
31381ad6265SDimitry Andric   if (!FirstParameter)
31481ad6265SDimitry Andric     FirstParameter = &FirstParameterValue;
31581ad6265SDimitry Andric   for (const DWARFDie &C : D) {
31681ad6265SDimitry Andric     auto Sep = [&] {
31781ad6265SDimitry Andric       if (*FirstParameter)
31881ad6265SDimitry Andric         OS << '<';
31981ad6265SDimitry Andric       else
32081ad6265SDimitry Andric         OS << ", ";
32181ad6265SDimitry Andric       IsTemplate = true;
32281ad6265SDimitry Andric       EndedWithTemplate = false;
32381ad6265SDimitry Andric       *FirstParameter = false;
32481ad6265SDimitry Andric     };
32581ad6265SDimitry Andric     if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
32681ad6265SDimitry Andric       IsTemplate = true;
32781ad6265SDimitry Andric       appendTemplateParameters(C, FirstParameter);
32881ad6265SDimitry Andric     }
32981ad6265SDimitry Andric     if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
33081ad6265SDimitry Andric       DWARFDie T = resolveReferencedType(C);
33181ad6265SDimitry Andric       Sep();
33281ad6265SDimitry Andric       if (T.getTag() == DW_TAG_enumeration_type) {
33381ad6265SDimitry Andric         OS << '(';
33481ad6265SDimitry Andric         appendQualifiedName(T);
33581ad6265SDimitry Andric         OS << ')';
33681ad6265SDimitry Andric         auto V = C.find(DW_AT_const_value);
33781ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
33881ad6265SDimitry Andric         continue;
33981ad6265SDimitry Andric       }
34081ad6265SDimitry Andric       // /Maybe/ we could do pointer type parameters, looking for the
34181ad6265SDimitry Andric       // symbol in the ELF symbol table to get back to the variable...
34281ad6265SDimitry Andric       // but probably not worth it.
34381ad6265SDimitry Andric       if (T.getTag() == DW_TAG_pointer_type)
34481ad6265SDimitry Andric         continue;
34581ad6265SDimitry Andric       const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr);
34681ad6265SDimitry Andric       assert(RawName);
34781ad6265SDimitry Andric       StringRef Name = RawName;
34881ad6265SDimitry Andric       auto V = C.find(DW_AT_const_value);
34981ad6265SDimitry Andric       bool IsQualifiedChar = false;
35081ad6265SDimitry Andric       if (Name == "bool") {
35181ad6265SDimitry Andric         OS << (*V->getAsUnsignedConstant() ? "true" : "false");
35281ad6265SDimitry Andric       } else if (Name == "short") {
35381ad6265SDimitry Andric         OS << "(short)";
35481ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
35581ad6265SDimitry Andric       } else if (Name == "unsigned short") {
35681ad6265SDimitry Andric         OS << "(unsigned short)";
35781ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
35881ad6265SDimitry Andric       } else if (Name == "int")
35981ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
36081ad6265SDimitry Andric       else if (Name == "long") {
36181ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
36281ad6265SDimitry Andric         OS << "L";
36381ad6265SDimitry Andric       } else if (Name == "long long") {
36481ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
36581ad6265SDimitry Andric         OS << "LL";
36681ad6265SDimitry Andric       } else if (Name == "unsigned int") {
36781ad6265SDimitry Andric         OS << std::to_string(*V->getAsUnsignedConstant());
36881ad6265SDimitry Andric         OS << "U";
36981ad6265SDimitry Andric       } else if (Name == "unsigned long") {
37081ad6265SDimitry Andric         OS << std::to_string(*V->getAsUnsignedConstant());
37181ad6265SDimitry Andric         OS << "UL";
37281ad6265SDimitry Andric       } else if (Name == "unsigned long long") {
37381ad6265SDimitry Andric         OS << std::to_string(*V->getAsUnsignedConstant());
37481ad6265SDimitry Andric         OS << "ULL";
37581ad6265SDimitry Andric       } else if (Name == "char" ||
37681ad6265SDimitry Andric                  (IsQualifiedChar =
37781ad6265SDimitry Andric                       (Name == "unsigned char" || Name == "signed char"))) {
37881ad6265SDimitry Andric         // FIXME: check T's DW_AT_type to see if it's signed or not (since
37981ad6265SDimitry Andric         // char signedness is implementation defined).
38081ad6265SDimitry Andric         auto Val = *V->getAsSignedConstant();
38181ad6265SDimitry Andric         // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
38281ad6265SDimitry Andric         // (doesn't actually support different character types/widths, sign
38381ad6265SDimitry Andric         // handling's not done, and doesn't correctly test if a character is
38481ad6265SDimitry Andric         // printable or needs to use a numeric escape sequence instead)
38581ad6265SDimitry Andric         if (IsQualifiedChar) {
38681ad6265SDimitry Andric           OS << '(';
38781ad6265SDimitry Andric           OS << Name;
38881ad6265SDimitry Andric           OS << ')';
38981ad6265SDimitry Andric         }
39081ad6265SDimitry Andric         switch (Val) {
39181ad6265SDimitry Andric         case '\\':
39281ad6265SDimitry Andric           OS << "'\\\\'";
39381ad6265SDimitry Andric           break;
39481ad6265SDimitry Andric         case '\'':
39581ad6265SDimitry Andric           OS << "'\\''";
39681ad6265SDimitry Andric           break;
39781ad6265SDimitry Andric         case '\a':
39881ad6265SDimitry Andric           // TODO: K&R: the meaning of '\\a' is different in traditional C
39981ad6265SDimitry Andric           OS << "'\\a'";
40081ad6265SDimitry Andric           break;
40181ad6265SDimitry Andric         case '\b':
40281ad6265SDimitry Andric           OS << "'\\b'";
40381ad6265SDimitry Andric           break;
40481ad6265SDimitry Andric         case '\f':
40581ad6265SDimitry Andric           OS << "'\\f'";
40681ad6265SDimitry Andric           break;
40781ad6265SDimitry Andric         case '\n':
40881ad6265SDimitry Andric           OS << "'\\n'";
40981ad6265SDimitry Andric           break;
41081ad6265SDimitry Andric         case '\r':
41181ad6265SDimitry Andric           OS << "'\\r'";
41281ad6265SDimitry Andric           break;
41381ad6265SDimitry Andric         case '\t':
41481ad6265SDimitry Andric           OS << "'\\t'";
41581ad6265SDimitry Andric           break;
41681ad6265SDimitry Andric         case '\v':
41781ad6265SDimitry Andric           OS << "'\\v'";
41881ad6265SDimitry Andric           break;
41981ad6265SDimitry Andric         default:
42081ad6265SDimitry Andric           if ((Val & ~0xFFu) == ~0xFFu)
42181ad6265SDimitry Andric             Val &= 0xFFu;
42281ad6265SDimitry Andric           if (Val < 127 && Val >= 32) {
42381ad6265SDimitry Andric             OS << "'";
42481ad6265SDimitry Andric             OS << (char)Val;
42581ad6265SDimitry Andric             OS << "'";
42681ad6265SDimitry Andric           } else if (Val < 256)
42781ad6265SDimitry Andric             OS << to_string(llvm::format("'\\x%02x'", Val));
42881ad6265SDimitry Andric           else if (Val <= 0xFFFF)
42981ad6265SDimitry Andric             OS << to_string(llvm::format("'\\u%04x'", Val));
43081ad6265SDimitry Andric           else
43181ad6265SDimitry Andric             OS << to_string(llvm::format("'\\U%08x'", Val));
43281ad6265SDimitry Andric         }
43381ad6265SDimitry Andric       }
43481ad6265SDimitry Andric       continue;
43581ad6265SDimitry Andric     }
43681ad6265SDimitry Andric     if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
43781ad6265SDimitry Andric       const char *RawName =
43881ad6265SDimitry Andric           dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr);
43981ad6265SDimitry Andric       assert(RawName);
44081ad6265SDimitry Andric       StringRef Name = RawName;
44181ad6265SDimitry Andric       Sep();
44281ad6265SDimitry Andric       OS << Name;
44381ad6265SDimitry Andric       continue;
44481ad6265SDimitry Andric     }
44581ad6265SDimitry Andric     if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
44681ad6265SDimitry Andric       continue;
44781ad6265SDimitry Andric     auto TypeAttr = C.find(DW_AT_type);
44881ad6265SDimitry Andric     Sep();
44981ad6265SDimitry Andric     appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr)
45081ad6265SDimitry Andric                                  : DWARFDie());
45181ad6265SDimitry Andric   }
45281ad6265SDimitry Andric   if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
45381ad6265SDimitry Andric     OS << '<';
45481ad6265SDimitry Andric     EndedWithTemplate = false;
45581ad6265SDimitry Andric   }
45681ad6265SDimitry Andric   return IsTemplate;
45781ad6265SDimitry Andric }
45881ad6265SDimitry Andric void DWARFTypePrinter::decomposeConstVolatile(DWARFDie &N, DWARFDie &T,
45981ad6265SDimitry Andric                                               DWARFDie &C, DWARFDie &V) {
46081ad6265SDimitry Andric   (N.getTag() == DW_TAG_const_type ? C : V) = N;
46181ad6265SDimitry Andric   T = resolveReferencedType(N);
46281ad6265SDimitry Andric   if (T) {
46381ad6265SDimitry Andric     auto Tag = T.getTag();
46481ad6265SDimitry Andric     if (Tag == DW_TAG_const_type) {
46581ad6265SDimitry Andric       C = T;
46681ad6265SDimitry Andric       T = resolveReferencedType(T);
46781ad6265SDimitry Andric     } else if (Tag == DW_TAG_volatile_type) {
46881ad6265SDimitry Andric       V = T;
46981ad6265SDimitry Andric       T = resolveReferencedType(T);
47081ad6265SDimitry Andric     }
47181ad6265SDimitry Andric   }
47281ad6265SDimitry Andric }
47381ad6265SDimitry Andric void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) {
47481ad6265SDimitry Andric   DWARFDie C;
47581ad6265SDimitry Andric   DWARFDie V;
47681ad6265SDimitry Andric   DWARFDie T;
47781ad6265SDimitry Andric   decomposeConstVolatile(N, T, C, V);
47881ad6265SDimitry Andric   if (T && T.getTag() == DW_TAG_subroutine_type)
47981ad6265SDimitry Andric     appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(),
48081ad6265SDimitry Andric                               V.isValid());
48181ad6265SDimitry Andric   else
48281ad6265SDimitry Andric     appendUnqualifiedNameAfter(T, resolveReferencedType(T));
48381ad6265SDimitry Andric }
48481ad6265SDimitry Andric void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) {
48581ad6265SDimitry Andric   DWARFDie C;
48681ad6265SDimitry Andric   DWARFDie V;
48781ad6265SDimitry Andric   DWARFDie T;
48881ad6265SDimitry Andric   decomposeConstVolatile(N, T, C, V);
48981ad6265SDimitry Andric   bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type;
49081ad6265SDimitry Andric   DWARFDie A = T;
49181ad6265SDimitry Andric   while (A && A.getTag() == DW_TAG_array_type)
49281ad6265SDimitry Andric     A = resolveReferencedType(A);
49381ad6265SDimitry Andric   bool Leading =
49481ad6265SDimitry Andric       (!A || (A.getTag() != DW_TAG_pointer_type &&
49581ad6265SDimitry Andric               A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
49681ad6265SDimitry Andric       !Subroutine;
49781ad6265SDimitry Andric   if (Leading) {
49881ad6265SDimitry Andric     if (C)
49981ad6265SDimitry Andric       OS << "const ";
50081ad6265SDimitry Andric     if (V)
50181ad6265SDimitry Andric       OS << "volatile ";
50281ad6265SDimitry Andric   }
50381ad6265SDimitry Andric   appendQualifiedNameBefore(T);
50481ad6265SDimitry Andric   if (!Leading && !Subroutine) {
50581ad6265SDimitry Andric     Word = true;
50681ad6265SDimitry Andric     if (C)
50781ad6265SDimitry Andric       OS << "const";
50881ad6265SDimitry Andric     if (V) {
50981ad6265SDimitry Andric       if (C)
51081ad6265SDimitry Andric         OS << ' ';
51181ad6265SDimitry Andric       OS << "volatile";
51281ad6265SDimitry Andric     }
51381ad6265SDimitry Andric   }
51481ad6265SDimitry Andric }
51581ad6265SDimitry Andric void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D,
51681ad6265SDimitry Andric                                              std::string *OriginalFullName) {
51781ad6265SDimitry Andric   // FIXME: We should have pretty printers per language. Currently we print
51881ad6265SDimitry Andric   // everything as if it was C++ and fall back to the TAG type name.
51981ad6265SDimitry Andric   DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
52081ad6265SDimitry Andric   appendUnqualifiedNameAfter(D, Inner);
52181ad6265SDimitry Andric }
52281ad6265SDimitry Andric void DWARFTypePrinter::appendSubroutineNameAfter(
52381ad6265SDimitry Andric     DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const,
52481ad6265SDimitry Andric     bool Volatile) {
52581ad6265SDimitry Andric   DWARFDie FirstParamIfArtificial;
52681ad6265SDimitry Andric   OS << '(';
52781ad6265SDimitry Andric   EndedWithTemplate = false;
52881ad6265SDimitry Andric   bool First = true;
52981ad6265SDimitry Andric   bool RealFirst = true;
53081ad6265SDimitry Andric   for (DWARFDie P : D) {
53181ad6265SDimitry Andric     if (P.getTag() != DW_TAG_formal_parameter &&
53281ad6265SDimitry Andric         P.getTag() != DW_TAG_unspecified_parameters)
53381ad6265SDimitry Andric       return;
53481ad6265SDimitry Andric     DWARFDie T = resolveReferencedType(P);
53581ad6265SDimitry Andric     if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) {
53681ad6265SDimitry Andric       FirstParamIfArtificial = T;
53781ad6265SDimitry Andric       RealFirst = false;
53881ad6265SDimitry Andric       continue;
53981ad6265SDimitry Andric     }
54081ad6265SDimitry Andric     if (!First) {
54181ad6265SDimitry Andric       OS << ", ";
54281ad6265SDimitry Andric     }
54381ad6265SDimitry Andric     First = false;
54481ad6265SDimitry Andric     if (P.getTag() == DW_TAG_unspecified_parameters)
54581ad6265SDimitry Andric       OS << "...";
54681ad6265SDimitry Andric     else
54781ad6265SDimitry Andric       appendQualifiedName(T);
54881ad6265SDimitry Andric   }
54981ad6265SDimitry Andric   EndedWithTemplate = false;
55081ad6265SDimitry Andric   OS << ')';
55181ad6265SDimitry Andric   if (FirstParamIfArtificial) {
55281ad6265SDimitry Andric     if (DWARFDie P = FirstParamIfArtificial) {
55381ad6265SDimitry Andric       if (P.getTag() == DW_TAG_pointer_type) {
55481ad6265SDimitry Andric         auto CVStep = [&](DWARFDie CV) {
55581ad6265SDimitry Andric           if (DWARFDie U = resolveReferencedType(CV)) {
55681ad6265SDimitry Andric             Const |= U.getTag() == DW_TAG_const_type;
55781ad6265SDimitry Andric             Volatile |= U.getTag() == DW_TAG_volatile_type;
55881ad6265SDimitry Andric             return U;
55981ad6265SDimitry Andric           }
56081ad6265SDimitry Andric           return DWARFDie();
56181ad6265SDimitry Andric         };
56281ad6265SDimitry Andric         if (DWARFDie CV = CVStep(P)) {
56381ad6265SDimitry Andric           CVStep(CV);
56481ad6265SDimitry Andric         }
56581ad6265SDimitry Andric       }
56681ad6265SDimitry Andric     }
56781ad6265SDimitry Andric   }
56881ad6265SDimitry Andric 
56981ad6265SDimitry Andric   if (auto CC = D.find(DW_AT_calling_convention)) {
57081ad6265SDimitry Andric     switch (*CC->getAsUnsignedConstant()) {
57181ad6265SDimitry Andric     case CallingConvention::DW_CC_BORLAND_stdcall:
57281ad6265SDimitry Andric       OS << " __attribute__((stdcall))";
57381ad6265SDimitry Andric       break;
57481ad6265SDimitry Andric     case CallingConvention::DW_CC_BORLAND_msfastcall:
57581ad6265SDimitry Andric       OS << " __attribute__((fastcall))";
57681ad6265SDimitry Andric       break;
57781ad6265SDimitry Andric     case CallingConvention::DW_CC_BORLAND_thiscall:
57881ad6265SDimitry Andric       OS << " __attribute__((thiscall))";
57981ad6265SDimitry Andric       break;
58081ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_vectorcall:
58181ad6265SDimitry Andric       OS << " __attribute__((vectorcall))";
58281ad6265SDimitry Andric       break;
58381ad6265SDimitry Andric     case CallingConvention::DW_CC_BORLAND_pascal:
58481ad6265SDimitry Andric       OS << " __attribute__((pascal))";
58581ad6265SDimitry Andric       break;
58681ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_Win64:
58781ad6265SDimitry Andric       OS << " __attribute__((ms_abi))";
58881ad6265SDimitry Andric       break;
58981ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_X86_64SysV:
59081ad6265SDimitry Andric       OS << " __attribute__((sysv_abi))";
59181ad6265SDimitry Andric       break;
59281ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_AAPCS:
59381ad6265SDimitry Andric       // AArch64VectorCall missing?
59481ad6265SDimitry Andric       OS << " __attribute__((pcs(\"aapcs\")))";
59581ad6265SDimitry Andric       break;
59681ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_AAPCS_VFP:
59781ad6265SDimitry Andric       OS << " __attribute__((pcs(\"aapcs-vfp\")))";
59881ad6265SDimitry Andric       break;
59981ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_IntelOclBicc:
60081ad6265SDimitry Andric       OS << " __attribute__((intel_ocl_bicc))";
60181ad6265SDimitry Andric       break;
60281ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_SpirFunction:
60381ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_OpenCLKernel:
60481ad6265SDimitry Andric       // These aren't available as attributes, but maybe we should still
60581ad6265SDimitry Andric       // render them somehow? (Clang doesn't render them, but that's an issue
60681ad6265SDimitry Andric       // for template names too - since then the DWARF names of templates
60781ad6265SDimitry Andric       // instantiated with function types with these calling conventions won't
60881ad6265SDimitry Andric       // have distinct names - so we'd need to fix that too)
60981ad6265SDimitry Andric       break;
61081ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_Swift:
61181ad6265SDimitry Andric       // SwiftAsync missing
61281ad6265SDimitry Andric       OS << " __attribute__((swiftcall))";
61381ad6265SDimitry Andric       break;
61481ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_PreserveMost:
61581ad6265SDimitry Andric       OS << " __attribute__((preserve_most))";
61681ad6265SDimitry Andric       break;
61781ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_PreserveAll:
61881ad6265SDimitry Andric       OS << " __attribute__((preserve_all))";
61981ad6265SDimitry Andric       break;
62081ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_X86RegCall:
62181ad6265SDimitry Andric       OS << " __attribute__((regcall))";
62281ad6265SDimitry Andric       break;
62381ad6265SDimitry Andric     }
62481ad6265SDimitry Andric   }
62581ad6265SDimitry Andric 
62681ad6265SDimitry Andric   if (Const)
62781ad6265SDimitry Andric     OS << " const";
62881ad6265SDimitry Andric   if (Volatile)
62981ad6265SDimitry Andric     OS << " volatile";
63081ad6265SDimitry Andric   if (D.find(DW_AT_reference))
63181ad6265SDimitry Andric     OS << " &";
63281ad6265SDimitry Andric   if (D.find(DW_AT_rvalue_reference))
63381ad6265SDimitry Andric     OS << " &&";
63481ad6265SDimitry Andric 
63581ad6265SDimitry Andric   appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner));
63681ad6265SDimitry Andric }
63781ad6265SDimitry Andric void DWARFTypePrinter::appendScopes(DWARFDie D) {
63881ad6265SDimitry Andric   if (D.getTag() == DW_TAG_compile_unit)
63981ad6265SDimitry Andric     return;
64081ad6265SDimitry Andric   if (D.getTag() == DW_TAG_type_unit)
64181ad6265SDimitry Andric     return;
64281ad6265SDimitry Andric   if (D.getTag() == DW_TAG_skeleton_unit)
64381ad6265SDimitry Andric     return;
64481ad6265SDimitry Andric   if (D.getTag() == DW_TAG_subprogram)
64581ad6265SDimitry Andric     return;
64681ad6265SDimitry Andric   if (D.getTag() == DW_TAG_lexical_block)
64781ad6265SDimitry Andric     return;
64881ad6265SDimitry Andric   D = D.resolveTypeUnitReference();
64981ad6265SDimitry Andric   if (DWARFDie P = D.getParent())
65081ad6265SDimitry Andric     appendScopes(P);
65181ad6265SDimitry Andric   appendUnqualifiedName(D);
65281ad6265SDimitry Andric   OS << "::";
65381ad6265SDimitry Andric }
65481ad6265SDimitry Andric } // namespace llvm
655