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;
appendTypeTagName(dwarf::Tag T)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";
115f757f3fSDimitry Andric   if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(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 
appendArrayType(const DWARFDie & D)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;
22bdd1243dSDimitry Andric     std::optional<uint64_t> LB;
23bdd1243dSDimitry Andric     std::optional<uint64_t> Count;
24bdd1243dSDimitry Andric     std::optional<uint64_t> UB;
25bdd1243dSDimitry Andric     std::optional<unsigned> DefaultLB;
26bdd1243dSDimitry Andric     if (std::optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
2781ad6265SDimitry Andric       LB = L->getAsUnsignedConstant();
28bdd1243dSDimitry Andric     if (std::optional<DWARFFormValue> CountV = C.find(DW_AT_count))
2981ad6265SDimitry Andric       Count = CountV->getAsUnsignedConstant();
30bdd1243dSDimitry Andric     if (std::optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
3181ad6265SDimitry Andric       UB = UpperV->getAsUnsignedConstant();
32bdd1243dSDimitry Andric     if (std::optional<DWARFFormValue> LV =
3381ad6265SDimitry Andric             D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
34bdd1243dSDimitry 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)
38bdd1243dSDimitry 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 
resolveReferencedType(DWARFDie D,dwarf::Attribute Attr=DW_AT_type)6581ad6265SDimitry Andric static DWARFDie resolveReferencedType(DWARFDie D,
6681ad6265SDimitry Andric                                       dwarf::Attribute Attr = DW_AT_type) {
6781ad6265SDimitry Andric   return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference();
6881ad6265SDimitry Andric }
resolveReferencedType(DWARFDie D,DWARFFormValue F)6981ad6265SDimitry Andric static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) {
7081ad6265SDimitry Andric   return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference();
7181ad6265SDimitry Andric }
skipQualifiers(DWARFDie D)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 
needsParens(DWARFDie D)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 
appendPointerLikeTypeBefore(DWARFDie D,DWARFDie Inner,StringRef Ptr)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
appendUnqualifiedNameBefore(DWARFDie D,std::string * OriginalFullName)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   }
146bdd1243dSDimitry Andric   case DW_TAG_LLVM_ptrauth_type:
147bdd1243dSDimitry Andric     appendQualifiedNameBefore(Inner());
148bdd1243dSDimitry 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|";
184*7a6dacacSDimitry Andric     if (Name.consume_front(MangledPrefix)) {
18581ad6265SDimitry Andric       auto Separator = Name.find('|');
18681ad6265SDimitry Andric       assert(Separator != StringRef::npos);
18781ad6265SDimitry Andric       StringRef BaseName = Name.substr(0, Separator);
18881ad6265SDimitry Andric       StringRef TemplateArgs = Name.substr(Separator + 1);
18981ad6265SDimitry Andric       if (OriginalFullName)
19081ad6265SDimitry Andric         *OriginalFullName = (BaseName + TemplateArgs).str();
19181ad6265SDimitry Andric       Name = BaseName;
19281ad6265SDimitry Andric     } else
1935f757f3fSDimitry Andric       EndedWithTemplate = Name.ends_with(">");
19481ad6265SDimitry Andric     OS << Name;
19581ad6265SDimitry Andric     // This check would be insufficient for operator overloads like
19681ad6265SDimitry Andric     // "operator>>" - but for now Clang doesn't try to simplify them, so this
19781ad6265SDimitry Andric     // is OK. Add more nuanced operator overload handling here if/when needed.
1985f757f3fSDimitry Andric     if (Name.ends_with(">"))
19981ad6265SDimitry Andric       break;
20081ad6265SDimitry Andric     if (!appendTemplateParameters(D))
20181ad6265SDimitry Andric       break;
20281ad6265SDimitry Andric 
20381ad6265SDimitry Andric     if (EndedWithTemplate)
20481ad6265SDimitry Andric       OS << ' ';
20581ad6265SDimitry Andric     OS << '>';
20681ad6265SDimitry Andric     EndedWithTemplate = true;
20781ad6265SDimitry Andric     Word = true;
20881ad6265SDimitry Andric     break;
20981ad6265SDimitry Andric   }
21081ad6265SDimitry Andric   }
21181ad6265SDimitry Andric   return InnerDIE;
21281ad6265SDimitry Andric }
21381ad6265SDimitry Andric 
appendUnqualifiedNameAfter(DWARFDie D,DWARFDie Inner,bool SkipFirstParamIfArtificial)21481ad6265SDimitry Andric void DWARFTypePrinter::appendUnqualifiedNameAfter(
21581ad6265SDimitry Andric     DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) {
21681ad6265SDimitry Andric   if (!D)
21781ad6265SDimitry Andric     return;
21881ad6265SDimitry Andric   switch (D.getTag()) {
21981ad6265SDimitry Andric   case DW_TAG_subroutine_type: {
22081ad6265SDimitry Andric     appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
22181ad6265SDimitry Andric                               false);
22281ad6265SDimitry Andric     break;
22381ad6265SDimitry Andric   }
22481ad6265SDimitry Andric   case DW_TAG_array_type: {
22581ad6265SDimitry Andric     appendArrayType(D);
22681ad6265SDimitry Andric     break;
22781ad6265SDimitry Andric   }
22881ad6265SDimitry Andric   case DW_TAG_const_type:
22981ad6265SDimitry Andric   case DW_TAG_volatile_type:
23081ad6265SDimitry Andric     appendConstVolatileQualifierAfter(D);
23181ad6265SDimitry Andric     break;
23281ad6265SDimitry Andric   case DW_TAG_ptr_to_member_type:
23381ad6265SDimitry Andric   case DW_TAG_reference_type:
23481ad6265SDimitry Andric   case DW_TAG_rvalue_reference_type:
23581ad6265SDimitry Andric   case DW_TAG_pointer_type: {
23681ad6265SDimitry Andric     if (needsParens(Inner))
23781ad6265SDimitry Andric       OS << ')';
23881ad6265SDimitry Andric     appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner),
23981ad6265SDimitry Andric                                /*SkipFirstParamIfArtificial=*/D.getTag() ==
24081ad6265SDimitry Andric                                    DW_TAG_ptr_to_member_type);
24181ad6265SDimitry Andric     break;
24281ad6265SDimitry Andric   }
243bdd1243dSDimitry Andric   case DW_TAG_LLVM_ptrauth_type: {
244bdd1243dSDimitry Andric     auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t {
245bdd1243dSDimitry Andric       if (auto Form = D.find(Attr))
246bdd1243dSDimitry Andric         return *Form->getAsUnsignedConstant();
247bdd1243dSDimitry Andric       return 0;
248bdd1243dSDimitry Andric     };
249bdd1243dSDimitry Andric     SmallVector<const char *, 2> optionsVec;
250bdd1243dSDimitry Andric     if (getValOrNull(DW_AT_LLVM_ptrauth_isa_pointer))
251bdd1243dSDimitry Andric       optionsVec.push_back("isa-pointer");
252bdd1243dSDimitry Andric     if (getValOrNull(DW_AT_LLVM_ptrauth_authenticates_null_values))
253bdd1243dSDimitry Andric       optionsVec.push_back("authenticates-null-values");
254bdd1243dSDimitry Andric     std::string options;
255bdd1243dSDimitry Andric     for (const auto *option : optionsVec) {
256bdd1243dSDimitry Andric       if (options.size())
257bdd1243dSDimitry Andric         options += ",";
258bdd1243dSDimitry Andric       options += option;
259bdd1243dSDimitry Andric     }
260bdd1243dSDimitry Andric     if (options.size())
261bdd1243dSDimitry Andric       options = ", \"" + options + "\"";
262bdd1243dSDimitry Andric     std::string PtrauthString;
263bdd1243dSDimitry Andric     llvm::raw_string_ostream PtrauthStream(PtrauthString);
264bdd1243dSDimitry Andric     PtrauthStream
265bdd1243dSDimitry Andric         << "__ptrauth(" << getValOrNull(DW_AT_LLVM_ptrauth_key) << ", "
266bdd1243dSDimitry Andric         << getValOrNull(DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0"
267bdd1243dSDimitry Andric         << utohexstr(getValOrNull(DW_AT_LLVM_ptrauth_extra_discriminator), true)
268bdd1243dSDimitry Andric         << options << ")";
269bdd1243dSDimitry Andric     OS << PtrauthStream.str();
270bdd1243dSDimitry Andric     break;
271bdd1243dSDimitry Andric   }
27281ad6265SDimitry Andric     /*
27381ad6265SDimitry Andric   case DW_TAG_structure_type:
27481ad6265SDimitry Andric   case DW_TAG_class_type:
27581ad6265SDimitry Andric   case DW_TAG_enumeration_type:
27681ad6265SDimitry Andric   case DW_TAG_base_type:
27781ad6265SDimitry Andric   case DW_TAG_namespace:
27881ad6265SDimitry Andric   */
27981ad6265SDimitry Andric   default:
28081ad6265SDimitry Andric     break;
28181ad6265SDimitry Andric   }
28281ad6265SDimitry Andric }
28381ad6265SDimitry Andric 
284bdd1243dSDimitry Andric /// Returns True if the DIE TAG is one of the ones that is scopped.
scopedTAGs(dwarf::Tag Tag)285bdd1243dSDimitry Andric static bool scopedTAGs(dwarf::Tag Tag) {
286bdd1243dSDimitry Andric   switch (Tag) {
287bdd1243dSDimitry Andric   case dwarf::DW_TAG_structure_type:
288bdd1243dSDimitry Andric   case dwarf::DW_TAG_class_type:
289bdd1243dSDimitry Andric   case dwarf::DW_TAG_union_type:
290bdd1243dSDimitry Andric   case dwarf::DW_TAG_namespace:
291bdd1243dSDimitry Andric   case dwarf::DW_TAG_enumeration_type:
292bdd1243dSDimitry Andric     return true;
293bdd1243dSDimitry Andric   default:
294bdd1243dSDimitry Andric     break;
295bdd1243dSDimitry Andric   }
296bdd1243dSDimitry Andric   return false;
297bdd1243dSDimitry Andric }
appendQualifiedName(DWARFDie D)29881ad6265SDimitry Andric void DWARFTypePrinter::appendQualifiedName(DWARFDie D) {
299bdd1243dSDimitry Andric   if (D && scopedTAGs(D.getTag()))
30081ad6265SDimitry Andric     appendScopes(D.getParent());
30181ad6265SDimitry Andric   appendUnqualifiedName(D);
30281ad6265SDimitry Andric }
appendQualifiedNameBefore(DWARFDie D)30381ad6265SDimitry Andric DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) {
304bdd1243dSDimitry Andric   if (D && scopedTAGs(D.getTag()))
30581ad6265SDimitry Andric     appendScopes(D.getParent());
30681ad6265SDimitry Andric   return appendUnqualifiedNameBefore(D);
30781ad6265SDimitry Andric }
appendTemplateParameters(DWARFDie D,bool * FirstParameter)30881ad6265SDimitry Andric bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D,
30981ad6265SDimitry Andric                                                 bool *FirstParameter) {
31081ad6265SDimitry Andric   bool FirstParameterValue = true;
31181ad6265SDimitry Andric   bool IsTemplate = false;
31281ad6265SDimitry Andric   if (!FirstParameter)
31381ad6265SDimitry Andric     FirstParameter = &FirstParameterValue;
31481ad6265SDimitry Andric   for (const DWARFDie &C : D) {
31581ad6265SDimitry Andric     auto Sep = [&] {
31681ad6265SDimitry Andric       if (*FirstParameter)
31781ad6265SDimitry Andric         OS << '<';
31881ad6265SDimitry Andric       else
31981ad6265SDimitry Andric         OS << ", ";
32081ad6265SDimitry Andric       IsTemplate = true;
32181ad6265SDimitry Andric       EndedWithTemplate = false;
32281ad6265SDimitry Andric       *FirstParameter = false;
32381ad6265SDimitry Andric     };
32481ad6265SDimitry Andric     if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
32581ad6265SDimitry Andric       IsTemplate = true;
32681ad6265SDimitry Andric       appendTemplateParameters(C, FirstParameter);
32781ad6265SDimitry Andric     }
32881ad6265SDimitry Andric     if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
32981ad6265SDimitry Andric       DWARFDie T = resolveReferencedType(C);
33081ad6265SDimitry Andric       Sep();
33181ad6265SDimitry Andric       if (T.getTag() == DW_TAG_enumeration_type) {
33281ad6265SDimitry Andric         OS << '(';
33381ad6265SDimitry Andric         appendQualifiedName(T);
33481ad6265SDimitry Andric         OS << ')';
33581ad6265SDimitry Andric         auto V = C.find(DW_AT_const_value);
33681ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
33781ad6265SDimitry Andric         continue;
33881ad6265SDimitry Andric       }
33981ad6265SDimitry Andric       // /Maybe/ we could do pointer type parameters, looking for the
34081ad6265SDimitry Andric       // symbol in the ELF symbol table to get back to the variable...
34181ad6265SDimitry Andric       // but probably not worth it.
34281ad6265SDimitry Andric       if (T.getTag() == DW_TAG_pointer_type)
34381ad6265SDimitry Andric         continue;
34481ad6265SDimitry Andric       const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr);
34581ad6265SDimitry Andric       assert(RawName);
34681ad6265SDimitry Andric       StringRef Name = RawName;
34781ad6265SDimitry Andric       auto V = C.find(DW_AT_const_value);
34881ad6265SDimitry Andric       bool IsQualifiedChar = false;
34981ad6265SDimitry Andric       if (Name == "bool") {
35081ad6265SDimitry Andric         OS << (*V->getAsUnsignedConstant() ? "true" : "false");
35181ad6265SDimitry Andric       } else if (Name == "short") {
35281ad6265SDimitry Andric         OS << "(short)";
35381ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
35481ad6265SDimitry Andric       } else if (Name == "unsigned short") {
35581ad6265SDimitry Andric         OS << "(unsigned short)";
35681ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
35781ad6265SDimitry Andric       } else if (Name == "int")
35881ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
35981ad6265SDimitry Andric       else if (Name == "long") {
36081ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
36181ad6265SDimitry Andric         OS << "L";
36281ad6265SDimitry Andric       } else if (Name == "long long") {
36381ad6265SDimitry Andric         OS << std::to_string(*V->getAsSignedConstant());
36481ad6265SDimitry Andric         OS << "LL";
36581ad6265SDimitry Andric       } else if (Name == "unsigned int") {
36681ad6265SDimitry Andric         OS << std::to_string(*V->getAsUnsignedConstant());
36781ad6265SDimitry Andric         OS << "U";
36881ad6265SDimitry Andric       } else if (Name == "unsigned long") {
36981ad6265SDimitry Andric         OS << std::to_string(*V->getAsUnsignedConstant());
37081ad6265SDimitry Andric         OS << "UL";
37181ad6265SDimitry Andric       } else if (Name == "unsigned long long") {
37281ad6265SDimitry Andric         OS << std::to_string(*V->getAsUnsignedConstant());
37381ad6265SDimitry Andric         OS << "ULL";
37481ad6265SDimitry Andric       } else if (Name == "char" ||
37581ad6265SDimitry Andric                  (IsQualifiedChar =
37681ad6265SDimitry Andric                       (Name == "unsigned char" || Name == "signed char"))) {
37781ad6265SDimitry Andric         // FIXME: check T's DW_AT_type to see if it's signed or not (since
37881ad6265SDimitry Andric         // char signedness is implementation defined).
37981ad6265SDimitry Andric         auto Val = *V->getAsSignedConstant();
38081ad6265SDimitry Andric         // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
38181ad6265SDimitry Andric         // (doesn't actually support different character types/widths, sign
38281ad6265SDimitry Andric         // handling's not done, and doesn't correctly test if a character is
38381ad6265SDimitry Andric         // printable or needs to use a numeric escape sequence instead)
38481ad6265SDimitry Andric         if (IsQualifiedChar) {
38581ad6265SDimitry Andric           OS << '(';
38681ad6265SDimitry Andric           OS << Name;
38781ad6265SDimitry Andric           OS << ')';
38881ad6265SDimitry Andric         }
38981ad6265SDimitry Andric         switch (Val) {
39081ad6265SDimitry Andric         case '\\':
39181ad6265SDimitry Andric           OS << "'\\\\'";
39281ad6265SDimitry Andric           break;
39381ad6265SDimitry Andric         case '\'':
39481ad6265SDimitry Andric           OS << "'\\''";
39581ad6265SDimitry Andric           break;
39681ad6265SDimitry Andric         case '\a':
39781ad6265SDimitry Andric           // TODO: K&R: the meaning of '\\a' is different in traditional C
39881ad6265SDimitry Andric           OS << "'\\a'";
39981ad6265SDimitry Andric           break;
40081ad6265SDimitry Andric         case '\b':
40181ad6265SDimitry Andric           OS << "'\\b'";
40281ad6265SDimitry Andric           break;
40381ad6265SDimitry Andric         case '\f':
40481ad6265SDimitry Andric           OS << "'\\f'";
40581ad6265SDimitry Andric           break;
40681ad6265SDimitry Andric         case '\n':
40781ad6265SDimitry Andric           OS << "'\\n'";
40881ad6265SDimitry Andric           break;
40981ad6265SDimitry Andric         case '\r':
41081ad6265SDimitry Andric           OS << "'\\r'";
41181ad6265SDimitry Andric           break;
41281ad6265SDimitry Andric         case '\t':
41381ad6265SDimitry Andric           OS << "'\\t'";
41481ad6265SDimitry Andric           break;
41581ad6265SDimitry Andric         case '\v':
41681ad6265SDimitry Andric           OS << "'\\v'";
41781ad6265SDimitry Andric           break;
41881ad6265SDimitry Andric         default:
41981ad6265SDimitry Andric           if ((Val & ~0xFFu) == ~0xFFu)
42081ad6265SDimitry Andric             Val &= 0xFFu;
42181ad6265SDimitry Andric           if (Val < 127 && Val >= 32) {
42281ad6265SDimitry Andric             OS << "'";
42381ad6265SDimitry Andric             OS << (char)Val;
42481ad6265SDimitry Andric             OS << "'";
42581ad6265SDimitry Andric           } else if (Val < 256)
42606c3fb27SDimitry Andric             OS << llvm::format("'\\x%02" PRIx64 "'", Val);
42781ad6265SDimitry Andric           else if (Val <= 0xFFFF)
42806c3fb27SDimitry Andric             OS << llvm::format("'\\u%04" PRIx64 "'", Val);
42981ad6265SDimitry Andric           else
43006c3fb27SDimitry Andric             OS << llvm::format("'\\U%08" PRIx64 "'", Val);
43181ad6265SDimitry Andric         }
43281ad6265SDimitry Andric       }
43381ad6265SDimitry Andric       continue;
43481ad6265SDimitry Andric     }
43581ad6265SDimitry Andric     if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
43681ad6265SDimitry Andric       const char *RawName =
43781ad6265SDimitry Andric           dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr);
43881ad6265SDimitry Andric       assert(RawName);
43981ad6265SDimitry Andric       StringRef Name = RawName;
44081ad6265SDimitry Andric       Sep();
44181ad6265SDimitry Andric       OS << Name;
44281ad6265SDimitry Andric       continue;
44381ad6265SDimitry Andric     }
44481ad6265SDimitry Andric     if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
44581ad6265SDimitry Andric       continue;
44681ad6265SDimitry Andric     auto TypeAttr = C.find(DW_AT_type);
44781ad6265SDimitry Andric     Sep();
44881ad6265SDimitry Andric     appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr)
44981ad6265SDimitry Andric                                  : DWARFDie());
45081ad6265SDimitry Andric   }
45181ad6265SDimitry Andric   if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
45281ad6265SDimitry Andric     OS << '<';
45381ad6265SDimitry Andric     EndedWithTemplate = false;
45481ad6265SDimitry Andric   }
45581ad6265SDimitry Andric   return IsTemplate;
45681ad6265SDimitry Andric }
decomposeConstVolatile(DWARFDie & N,DWARFDie & T,DWARFDie & C,DWARFDie & V)45781ad6265SDimitry Andric void DWARFTypePrinter::decomposeConstVolatile(DWARFDie &N, DWARFDie &T,
45881ad6265SDimitry Andric                                               DWARFDie &C, DWARFDie &V) {
45981ad6265SDimitry Andric   (N.getTag() == DW_TAG_const_type ? C : V) = N;
46081ad6265SDimitry Andric   T = resolveReferencedType(N);
46181ad6265SDimitry Andric   if (T) {
46281ad6265SDimitry Andric     auto Tag = T.getTag();
46381ad6265SDimitry Andric     if (Tag == DW_TAG_const_type) {
46481ad6265SDimitry Andric       C = T;
46581ad6265SDimitry Andric       T = resolveReferencedType(T);
46681ad6265SDimitry Andric     } else if (Tag == DW_TAG_volatile_type) {
46781ad6265SDimitry Andric       V = T;
46881ad6265SDimitry Andric       T = resolveReferencedType(T);
46981ad6265SDimitry Andric     }
47081ad6265SDimitry Andric   }
47181ad6265SDimitry Andric }
appendConstVolatileQualifierAfter(DWARFDie N)47281ad6265SDimitry Andric void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) {
47381ad6265SDimitry Andric   DWARFDie C;
47481ad6265SDimitry Andric   DWARFDie V;
47581ad6265SDimitry Andric   DWARFDie T;
47681ad6265SDimitry Andric   decomposeConstVolatile(N, T, C, V);
47781ad6265SDimitry Andric   if (T && T.getTag() == DW_TAG_subroutine_type)
47881ad6265SDimitry Andric     appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(),
47981ad6265SDimitry Andric                               V.isValid());
48081ad6265SDimitry Andric   else
48181ad6265SDimitry Andric     appendUnqualifiedNameAfter(T, resolveReferencedType(T));
48281ad6265SDimitry Andric }
appendConstVolatileQualifierBefore(DWARFDie N)48381ad6265SDimitry Andric void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) {
48481ad6265SDimitry Andric   DWARFDie C;
48581ad6265SDimitry Andric   DWARFDie V;
48681ad6265SDimitry Andric   DWARFDie T;
48781ad6265SDimitry Andric   decomposeConstVolatile(N, T, C, V);
48881ad6265SDimitry Andric   bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type;
48981ad6265SDimitry Andric   DWARFDie A = T;
49081ad6265SDimitry Andric   while (A && A.getTag() == DW_TAG_array_type)
49181ad6265SDimitry Andric     A = resolveReferencedType(A);
49281ad6265SDimitry Andric   bool Leading =
49381ad6265SDimitry Andric       (!A || (A.getTag() != DW_TAG_pointer_type &&
49481ad6265SDimitry Andric               A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
49581ad6265SDimitry Andric       !Subroutine;
49681ad6265SDimitry Andric   if (Leading) {
49781ad6265SDimitry Andric     if (C)
49881ad6265SDimitry Andric       OS << "const ";
49981ad6265SDimitry Andric     if (V)
50081ad6265SDimitry Andric       OS << "volatile ";
50181ad6265SDimitry Andric   }
50281ad6265SDimitry Andric   appendQualifiedNameBefore(T);
50381ad6265SDimitry Andric   if (!Leading && !Subroutine) {
50481ad6265SDimitry Andric     Word = true;
50581ad6265SDimitry Andric     if (C)
50681ad6265SDimitry Andric       OS << "const";
50781ad6265SDimitry Andric     if (V) {
50881ad6265SDimitry Andric       if (C)
50981ad6265SDimitry Andric         OS << ' ';
51081ad6265SDimitry Andric       OS << "volatile";
51181ad6265SDimitry Andric     }
51281ad6265SDimitry Andric   }
51381ad6265SDimitry Andric }
appendUnqualifiedName(DWARFDie D,std::string * OriginalFullName)51481ad6265SDimitry Andric void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D,
51581ad6265SDimitry Andric                                              std::string *OriginalFullName) {
51681ad6265SDimitry Andric   // FIXME: We should have pretty printers per language. Currently we print
51781ad6265SDimitry Andric   // everything as if it was C++ and fall back to the TAG type name.
51881ad6265SDimitry Andric   DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
51981ad6265SDimitry Andric   appendUnqualifiedNameAfter(D, Inner);
52081ad6265SDimitry Andric }
appendSubroutineNameAfter(DWARFDie D,DWARFDie Inner,bool SkipFirstParamIfArtificial,bool Const,bool Volatile)52181ad6265SDimitry Andric void DWARFTypePrinter::appendSubroutineNameAfter(
52281ad6265SDimitry Andric     DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const,
52381ad6265SDimitry Andric     bool Volatile) {
52481ad6265SDimitry Andric   DWARFDie FirstParamIfArtificial;
52581ad6265SDimitry Andric   OS << '(';
52681ad6265SDimitry Andric   EndedWithTemplate = false;
52781ad6265SDimitry Andric   bool First = true;
52881ad6265SDimitry Andric   bool RealFirst = true;
52981ad6265SDimitry Andric   for (DWARFDie P : D) {
53081ad6265SDimitry Andric     if (P.getTag() != DW_TAG_formal_parameter &&
53181ad6265SDimitry Andric         P.getTag() != DW_TAG_unspecified_parameters)
53281ad6265SDimitry Andric       return;
53381ad6265SDimitry Andric     DWARFDie T = resolveReferencedType(P);
53481ad6265SDimitry Andric     if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) {
53581ad6265SDimitry Andric       FirstParamIfArtificial = T;
53681ad6265SDimitry Andric       RealFirst = false;
53781ad6265SDimitry Andric       continue;
53881ad6265SDimitry Andric     }
53981ad6265SDimitry Andric     if (!First) {
54081ad6265SDimitry Andric       OS << ", ";
54181ad6265SDimitry Andric     }
54281ad6265SDimitry Andric     First = false;
54381ad6265SDimitry Andric     if (P.getTag() == DW_TAG_unspecified_parameters)
54481ad6265SDimitry Andric       OS << "...";
54581ad6265SDimitry Andric     else
54681ad6265SDimitry Andric       appendQualifiedName(T);
54781ad6265SDimitry Andric   }
54881ad6265SDimitry Andric   EndedWithTemplate = false;
54981ad6265SDimitry Andric   OS << ')';
55081ad6265SDimitry Andric   if (FirstParamIfArtificial) {
55181ad6265SDimitry Andric     if (DWARFDie P = FirstParamIfArtificial) {
55281ad6265SDimitry Andric       if (P.getTag() == DW_TAG_pointer_type) {
55381ad6265SDimitry Andric         auto CVStep = [&](DWARFDie CV) {
55481ad6265SDimitry Andric           if (DWARFDie U = resolveReferencedType(CV)) {
55581ad6265SDimitry Andric             Const |= U.getTag() == DW_TAG_const_type;
55681ad6265SDimitry Andric             Volatile |= U.getTag() == DW_TAG_volatile_type;
55781ad6265SDimitry Andric             return U;
55881ad6265SDimitry Andric           }
55981ad6265SDimitry Andric           return DWARFDie();
56081ad6265SDimitry Andric         };
56181ad6265SDimitry Andric         if (DWARFDie CV = CVStep(P)) {
56281ad6265SDimitry Andric           CVStep(CV);
56381ad6265SDimitry Andric         }
56481ad6265SDimitry Andric       }
56581ad6265SDimitry Andric     }
56681ad6265SDimitry Andric   }
56781ad6265SDimitry Andric 
56881ad6265SDimitry Andric   if (auto CC = D.find(DW_AT_calling_convention)) {
56981ad6265SDimitry Andric     switch (*CC->getAsUnsignedConstant()) {
57081ad6265SDimitry Andric     case CallingConvention::DW_CC_BORLAND_stdcall:
57181ad6265SDimitry Andric       OS << " __attribute__((stdcall))";
57281ad6265SDimitry Andric       break;
57381ad6265SDimitry Andric     case CallingConvention::DW_CC_BORLAND_msfastcall:
57481ad6265SDimitry Andric       OS << " __attribute__((fastcall))";
57581ad6265SDimitry Andric       break;
57681ad6265SDimitry Andric     case CallingConvention::DW_CC_BORLAND_thiscall:
57781ad6265SDimitry Andric       OS << " __attribute__((thiscall))";
57881ad6265SDimitry Andric       break;
57981ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_vectorcall:
58081ad6265SDimitry Andric       OS << " __attribute__((vectorcall))";
58181ad6265SDimitry Andric       break;
58281ad6265SDimitry Andric     case CallingConvention::DW_CC_BORLAND_pascal:
58381ad6265SDimitry Andric       OS << " __attribute__((pascal))";
58481ad6265SDimitry Andric       break;
58581ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_Win64:
58681ad6265SDimitry Andric       OS << " __attribute__((ms_abi))";
58781ad6265SDimitry Andric       break;
58881ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_X86_64SysV:
58981ad6265SDimitry Andric       OS << " __attribute__((sysv_abi))";
59081ad6265SDimitry Andric       break;
59181ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_AAPCS:
59281ad6265SDimitry Andric       // AArch64VectorCall missing?
59381ad6265SDimitry Andric       OS << " __attribute__((pcs(\"aapcs\")))";
59481ad6265SDimitry Andric       break;
59581ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_AAPCS_VFP:
59681ad6265SDimitry Andric       OS << " __attribute__((pcs(\"aapcs-vfp\")))";
59781ad6265SDimitry Andric       break;
59881ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_IntelOclBicc:
59981ad6265SDimitry Andric       OS << " __attribute__((intel_ocl_bicc))";
60081ad6265SDimitry Andric       break;
60181ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_SpirFunction:
60281ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_OpenCLKernel:
60381ad6265SDimitry Andric       // These aren't available as attributes, but maybe we should still
60481ad6265SDimitry Andric       // render them somehow? (Clang doesn't render them, but that's an issue
60581ad6265SDimitry Andric       // for template names too - since then the DWARF names of templates
60681ad6265SDimitry Andric       // instantiated with function types with these calling conventions won't
60781ad6265SDimitry Andric       // have distinct names - so we'd need to fix that too)
60881ad6265SDimitry Andric       break;
60981ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_Swift:
61081ad6265SDimitry Andric       // SwiftAsync missing
61181ad6265SDimitry Andric       OS << " __attribute__((swiftcall))";
61281ad6265SDimitry Andric       break;
61381ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_PreserveMost:
61481ad6265SDimitry Andric       OS << " __attribute__((preserve_most))";
61581ad6265SDimitry Andric       break;
61681ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_PreserveAll:
61781ad6265SDimitry Andric       OS << " __attribute__((preserve_all))";
61881ad6265SDimitry Andric       break;
61981ad6265SDimitry Andric     case CallingConvention::DW_CC_LLVM_X86RegCall:
62081ad6265SDimitry Andric       OS << " __attribute__((regcall))";
62181ad6265SDimitry Andric       break;
6225f757f3fSDimitry Andric     case CallingConvention::DW_CC_LLVM_M68kRTD:
6235f757f3fSDimitry Andric       OS << " __attribute__((m68k_rtd))";
6245f757f3fSDimitry Andric       break;
62581ad6265SDimitry Andric     }
62681ad6265SDimitry Andric   }
62781ad6265SDimitry Andric 
62881ad6265SDimitry Andric   if (Const)
62981ad6265SDimitry Andric     OS << " const";
63081ad6265SDimitry Andric   if (Volatile)
63181ad6265SDimitry Andric     OS << " volatile";
63281ad6265SDimitry Andric   if (D.find(DW_AT_reference))
63381ad6265SDimitry Andric     OS << " &";
63481ad6265SDimitry Andric   if (D.find(DW_AT_rvalue_reference))
63581ad6265SDimitry Andric     OS << " &&";
63681ad6265SDimitry Andric 
63781ad6265SDimitry Andric   appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner));
63881ad6265SDimitry Andric }
appendScopes(DWARFDie D)63981ad6265SDimitry Andric void DWARFTypePrinter::appendScopes(DWARFDie D) {
64081ad6265SDimitry Andric   if (D.getTag() == DW_TAG_compile_unit)
64181ad6265SDimitry Andric     return;
64281ad6265SDimitry Andric   if (D.getTag() == DW_TAG_type_unit)
64381ad6265SDimitry Andric     return;
64481ad6265SDimitry Andric   if (D.getTag() == DW_TAG_skeleton_unit)
64581ad6265SDimitry Andric     return;
64681ad6265SDimitry Andric   if (D.getTag() == DW_TAG_subprogram)
64781ad6265SDimitry Andric     return;
64881ad6265SDimitry Andric   if (D.getTag() == DW_TAG_lexical_block)
64981ad6265SDimitry Andric     return;
65081ad6265SDimitry Andric   D = D.resolveTypeUnitReference();
65181ad6265SDimitry Andric   if (DWARFDie P = D.getParent())
65281ad6265SDimitry Andric     appendScopes(P);
65381ad6265SDimitry Andric   appendUnqualifiedName(D);
65481ad6265SDimitry Andric   OS << "::";
65581ad6265SDimitry Andric }
65681ad6265SDimitry Andric } // namespace llvm
657