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