From 62ef8f1799ef26a8fc64f2cf6bfc901d3ef3270f Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Thu, 19 Sep 2024 16:35:03 -0700 Subject: [PATCH 1/6] [DWARF] Generalize DWARFTypePrinter to a template class --- .../llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 786 +++++++++++++++++- llvm/lib/DebugInfo/DWARF/CMakeLists.txt | 1 - llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 4 +- llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp | 675 --------------- 4 files changed, 769 insertions(+), 697 deletions(-) delete mode 100644 llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h index e05271740e615..5315ac194f8ed 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h @@ -9,9 +9,10 @@ #ifndef LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H #define LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include @@ -19,9 +20,55 @@ namespace llvm { class raw_ostream; +inline std::optional getLanguage(DWARFDie D) { + if (std::optional LV = + D.getDwarfUnit()->getUnitDIE().find(dwarf::DW_AT_language)) + return LV->getAsUnsignedConstant(); + return std::nullopt; +} + +namespace detail { +inline llvm::SmallString<128> toString(const llvm::format_object_base &Fmt) { + size_t NextBufferSize = 127; + llvm::SmallString<128> V; + + while (true) { + V.resize_for_overwrite(NextBufferSize); + + // Try formatting into the SmallVector. + size_t BytesUsed = Fmt.print(V.data(), NextBufferSize); + + // If BytesUsed fit into the vector, we win. + if (BytesUsed <= NextBufferSize) { + V.resize(BytesUsed); + return V; + } + + // Otherwise, try again with a new size. + assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?"); + NextBufferSize = BytesUsed; + } +} + +/// Returns True if the DIE TAG is one of the ones that is scopped. +inline bool scopedTAGs(dwarf::Tag Tag) { + switch (Tag) { + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_union_type: + case dwarf::DW_TAG_namespace: + case dwarf::DW_TAG_enumeration_type: + return true; + default: + break; + } + return false; +} +} // namespace detail + // FIXME: We should have pretty printers per language. Currently we print // everything as if it was C++ and fall back to the TAG type name. -struct DWARFTypePrinter { +template struct DWARFTypePrinter { raw_ostream &OS; bool Word = true; bool EndedWithTemplate = false; @@ -31,37 +78,738 @@ struct DWARFTypePrinter { /// Dump the name encoded in the type tag. void appendTypeTagName(dwarf::Tag T); - void appendArrayType(const DWARFDie &D); + void appendArrayType(const DieType &D); - DWARFDie skipQualifiers(DWARFDie D); + DieType skipQualifiers(DieType D); - bool needsParens(DWARFDie D); + bool needsParens(DieType D); - void appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner, StringRef Ptr); + void appendPointerLikeTypeBefore(DieType D, DieType Inner, StringRef Ptr); - DWARFDie appendUnqualifiedNameBefore(DWARFDie D, - std::string *OriginalFullName = nullptr); + DieType appendUnqualifiedNameBefore(DieType D, + std::string *OriginalFullName = nullptr); - void appendUnqualifiedNameAfter(DWARFDie D, DWARFDie Inner, + void appendUnqualifiedNameAfter(DieType D, DieType Inner, bool SkipFirstParamIfArtificial = false); - void appendQualifiedName(DWARFDie D); - DWARFDie appendQualifiedNameBefore(DWARFDie D); - bool appendTemplateParameters(DWARFDie D, bool *FirstParameter = nullptr); - void decomposeConstVolatile(DWARFDie &N, DWARFDie &T, DWARFDie &C, - DWARFDie &V); - void appendConstVolatileQualifierAfter(DWARFDie N); - void appendConstVolatileQualifierBefore(DWARFDie N); + void appendQualifiedName(DieType D); + DieType appendQualifiedNameBefore(DieType D); + bool appendTemplateParameters(DieType D, bool *FirstParameter = nullptr); + void appendAndTerminateTemplateParameters(DieType D); + void decomposeConstVolatile(DieType &N, DieType &T, DieType &C, DieType &V); + void appendConstVolatileQualifierAfter(DieType N); + void appendConstVolatileQualifierBefore(DieType N); /// Recursively append the DIE type name when applicable. - void appendUnqualifiedName(DWARFDie D, + void appendUnqualifiedName(DieType D, std::string *OriginalFullName = nullptr); - void appendSubroutineNameAfter(DWARFDie D, DWARFDie Inner, + void appendSubroutineNameAfter(DieType D, DieType Inner, bool SkipFirstParamIfArtificial, bool Const, bool Volatile); - void appendScopes(DWARFDie D); + void appendScopes(DieType D); }; +template +void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) { + StringRef TagStr = TagString(T); + static constexpr StringRef Prefix = "DW_TAG_"; + static constexpr StringRef Suffix = "_type"; + if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(Suffix)) + return; + OS << TagStr.substr(Prefix.size(), + TagStr.size() - (Prefix.size() + Suffix.size())) + << " "; +} + +template +void DWARFTypePrinter::appendArrayType(const DieType &D) { + for (const DieType &C : D.children()) { + if (C.getTag() != dwarf::DW_TAG_subrange_type) + continue; + std::optional LB; + std::optional Count; + std::optional UB; + std::optional DefaultLB; + if (std::optional L = C.find(dwarf::DW_AT_lower_bound)) + LB = L->getAsUnsignedConstant(); + if (std::optional CountV = C.find(dwarf::DW_AT_count)) + Count = CountV->getAsUnsignedConstant(); + if (std::optional UpperV = C.find(dwarf::DW_AT_upper_bound)) + UB = UpperV->getAsUnsignedConstant(); + if (std::optional LV = + D.getDwarfUnit()->getUnitDIE().find(dwarf::DW_AT_language)) + if (std::optional LC = LV->getAsUnsignedConstant()) + if ((DefaultLB = + LanguageLowerBound(static_cast(*LC)))) + if (LB && *LB == *DefaultLB) + LB = std::nullopt; + if (!LB && !Count && !UB) + OS << "[]"; + else if (!LB && (Count || UB) && DefaultLB) + OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']'; + else { + OS << "[["; + if (LB) + OS << *LB; + else + OS << '?'; + OS << ", "; + if (Count) + if (LB) + OS << *LB + *Count; + else + OS << "? + " << *Count; + else if (UB) + OS << *UB + 1; + else + OS << '?'; + OS << ")]"; + } + } + EndedWithTemplate = false; +} + +namespace detail { +template +DieType resolveReferencedType(DieType D, + dwarf::Attribute Attr = dwarf::DW_AT_type) { + return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference(); +} +template +DieType resolveReferencedType(DieType D, DWARFFormValue F) { + return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference(); +} +} // namespace detail + +template +DieType DWARFTypePrinter::skipQualifiers(DieType D) { + while (D && (D.getTag() == dwarf::DW_TAG_const_type || + D.getTag() == dwarf::DW_TAG_volatile_type)) + D = detail::resolveReferencedType(D); + return D; +} + +template +bool DWARFTypePrinter::needsParens(DieType D) { + D = skipQualifiers(D); + return D && (D.getTag() == dwarf::DW_TAG_subroutine_type || + D.getTag() == dwarf::DW_TAG_array_type); +} + +template +void DWARFTypePrinter::appendPointerLikeTypeBefore(DieType D, + DieType Inner, + StringRef Ptr) { + appendQualifiedNameBefore(Inner); + if (Word) + OS << ' '; + if (needsParens(Inner)) + OS << '('; + OS << Ptr; + Word = false; + EndedWithTemplate = false; +} + +template +DieType DWARFTypePrinter::appendUnqualifiedNameBefore( + DieType D, std::string *OriginalFullName) { + Word = true; + if (!D) { + OS << "void"; + return DieType(); + } + DieType InnerDIE; + auto Inner = [&] { return InnerDIE = detail::resolveReferencedType(D); }; + const dwarf::Tag T = D.getTag(); + switch (T) { + case dwarf::DW_TAG_pointer_type: { + appendPointerLikeTypeBefore(D, Inner(), "*"); + break; + } + case dwarf::DW_TAG_subroutine_type: { + appendQualifiedNameBefore(Inner()); + if (Word) { + OS << ' '; + } + Word = false; + break; + } + case dwarf::DW_TAG_array_type: { + appendQualifiedNameBefore(Inner()); + break; + } + case dwarf::DW_TAG_reference_type: + appendPointerLikeTypeBefore(D, Inner(), "&"); + break; + case dwarf::DW_TAG_rvalue_reference_type: + appendPointerLikeTypeBefore(D, Inner(), "&&"); + break; + case dwarf::DW_TAG_ptr_to_member_type: { + appendQualifiedNameBefore(Inner()); + if (needsParens(InnerDIE)) + OS << '('; + else if (Word) + OS << ' '; + if (DieType Cont = + detail::resolveReferencedType(D, dwarf::DW_AT_containing_type)) { + appendQualifiedName(Cont); + EndedWithTemplate = false; + OS << "::"; + } + OS << "*"; + Word = false; + break; + } + case dwarf::DW_TAG_LLVM_ptrauth_type: + appendQualifiedNameBefore(Inner()); + break; + case dwarf::DW_TAG_const_type: + case dwarf::DW_TAG_volatile_type: + appendConstVolatileQualifierBefore(D); + break; + case dwarf::DW_TAG_namespace: { + if (const char *Name = dwarf::toString(D.find(dwarf::DW_AT_name), nullptr)) + OS << Name; + else + OS << "(anonymous namespace)"; + break; + } + case dwarf::DW_TAG_unspecified_type: { + StringRef TypeName = D.getShortName(); + if (TypeName == "decltype(nullptr)") + TypeName = "std::nullptr_t"; + Word = true; + OS << TypeName; + EndedWithTemplate = false; + break; + } + /* + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_enumeration_type: + case DW_TAG_base_type: + */ + default: { + const char *NamePtr = dwarf::toString(D.find(dwarf::DW_AT_name), nullptr); + if (!NamePtr) { + appendTypeTagName(D.getTag()); + return DieType(); + } + Word = true; + StringRef Name = NamePtr; + static constexpr StringRef MangledPrefix = "_STN|"; + if (Name.consume_front(MangledPrefix)) { + auto Separator = Name.find('|'); + assert(Separator != StringRef::npos); + StringRef BaseName = Name.substr(0, Separator); + StringRef TemplateArgs = Name.substr(Separator + 1); + if (OriginalFullName) + *OriginalFullName = (BaseName + TemplateArgs).str(); + Name = BaseName; + } else + EndedWithTemplate = Name.ends_with(">"); + OS << Name; + // This check would be insufficient for operator overloads like + // "operator>>" - but for now Clang doesn't try to simplify them, so this + // is OK. Add more nuanced operator overload handling here if/when needed. + if (Name.ends_with(">")) + break; + if (!appendTemplateParameters(D)) + break; + + if (EndedWithTemplate) + OS << ' '; + OS << '>'; + EndedWithTemplate = true; + Word = true; + break; + } + } + return InnerDIE; +} + +template +void DWARFTypePrinter::appendUnqualifiedNameAfter( + DieType D, DieType Inner, bool SkipFirstParamIfArtificial) { + if (!D) + return; + switch (D.getTag()) { + case dwarf::DW_TAG_subroutine_type: { + appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false, + false); + break; + } + case dwarf::DW_TAG_array_type: { + appendArrayType(D); + break; + } + case dwarf::DW_TAG_const_type: + case dwarf::DW_TAG_volatile_type: + appendConstVolatileQualifierAfter(D); + break; + case dwarf::DW_TAG_ptr_to_member_type: + case dwarf::DW_TAG_reference_type: + case dwarf::DW_TAG_rvalue_reference_type: + case dwarf::DW_TAG_pointer_type: { + if (needsParens(Inner)) + OS << ')'; + appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner), + /*SkipFirstParamIfArtificial=*/D.getTag() == + dwarf::DW_TAG_ptr_to_member_type); + break; + } + case dwarf::DW_TAG_LLVM_ptrauth_type: { + auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t { + if (auto Form = D.find(Attr)) + return *Form->getAsUnsignedConstant(); + return 0; + }; + SmallVector optionsVec; + if (getValOrNull(dwarf::DW_AT_LLVM_ptrauth_isa_pointer)) + optionsVec.push_back("isa-pointer"); + if (getValOrNull(dwarf::DW_AT_LLVM_ptrauth_authenticates_null_values)) + optionsVec.push_back("authenticates-null-values"); + if (auto AuthenticationMode = + D.find(dwarf::DW_AT_LLVM_ptrauth_authentication_mode)) { + switch (*AuthenticationMode->getAsUnsignedConstant()) { + case 0: + case 1: + optionsVec.push_back("strip"); + break; + case 2: + optionsVec.push_back("sign-and-strip"); + break; + default: + // Default authentication policy + break; + } + } + std::string options; + for (const auto *option : optionsVec) { + if (options.size()) + options += ","; + options += option; + } + if (options.size()) + options = ", \"" + options + "\""; + std::string PtrauthString; + llvm::raw_string_ostream PtrauthStream(PtrauthString); + PtrauthStream + << "__ptrauth(" << getValOrNull(dwarf::DW_AT_LLVM_ptrauth_key) << ", " + << getValOrNull(dwarf::DW_AT_LLVM_ptrauth_address_discriminated) + << ", 0x0" + << utohexstr( + getValOrNull(dwarf::DW_AT_LLVM_ptrauth_extra_discriminator), + true) + << options << ")"; + OS << PtrauthStream.str(); + break; + } + /* + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_enumeration_type: + case DW_TAG_base_type: + case DW_TAG_namespace: + */ + default: + break; + } +} + +template +void DWARFTypePrinter::appendQualifiedName(DieType D) { + if (D && detail::scopedTAGs(D.getTag())) + appendScopes(D.getParent()); + appendUnqualifiedName(D); +} + +template +DieType DWARFTypePrinter::appendQualifiedNameBefore(DieType D) { + if (D && detail::scopedTAGs(D.getTag())) + appendScopes(D.getParent()); + return appendUnqualifiedNameBefore(D); +} + +template +bool DWARFTypePrinter::appendTemplateParameters(DieType D, + bool *FirstParameter) { + bool FirstParameterValue = true; + bool IsTemplate = false; + if (!FirstParameter) + FirstParameter = &FirstParameterValue; + for (const DieType &C : D) { + auto Sep = [&] { + if (*FirstParameter) + OS << '<'; + else + OS << ", "; + IsTemplate = true; + EndedWithTemplate = false; + *FirstParameter = false; + }; + if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) { + IsTemplate = true; + appendTemplateParameters(C, FirstParameter); + } + if (C.getTag() == dwarf::DW_TAG_template_value_parameter) { + DieType T = detail::resolveReferencedType(C); + Sep(); + if (T.getTag() == dwarf::DW_TAG_enumeration_type) { + OS << '('; + appendQualifiedName(T); + OS << ')'; + auto V = C.find(dwarf::DW_AT_const_value); + OS << std::to_string(*V->getAsSignedConstant()); + continue; + } + // /Maybe/ we could do pointer/reference type parameters, looking for the + // symbol in the ELF symbol table to get back to the variable... + // but probably not worth it. + if (T.getTag() == dwarf::DW_TAG_pointer_type || + T.getTag() == dwarf::DW_TAG_reference_type) + continue; + const char *RawName = dwarf::toString(T.find(dwarf::DW_AT_name), nullptr); + assert(RawName); + StringRef Name = RawName; + auto V = C.find(dwarf::DW_AT_const_value); + bool IsQualifiedChar = false; + if (Name == "bool") { + OS << (*V->getAsUnsignedConstant() ? "true" : "false"); + } else if (Name == "short") { + OS << "(short)"; + OS << std::to_string(*V->getAsSignedConstant()); + } else if (Name == "unsigned short") { + OS << "(unsigned short)"; + OS << std::to_string(*V->getAsSignedConstant()); + } else if (Name == "int") + OS << std::to_string(*V->getAsSignedConstant()); + else if (Name == "long") { + OS << std::to_string(*V->getAsSignedConstant()); + OS << "L"; + } else if (Name == "long long") { + OS << std::to_string(*V->getAsSignedConstant()); + OS << "LL"; + } else if (Name == "unsigned int") { + OS << std::to_string(*V->getAsUnsignedConstant()); + OS << "U"; + } else if (Name == "unsigned long") { + OS << std::to_string(*V->getAsUnsignedConstant()); + OS << "UL"; + } else if (Name == "unsigned long long") { + OS << std::to_string(*V->getAsUnsignedConstant()); + OS << "ULL"; + } else if (Name == "char" || + (IsQualifiedChar = + (Name == "unsigned char" || Name == "signed char"))) { + // FIXME: check T's DW_AT_type to see if it's signed or not (since + // char signedness is implementation defined). + auto Val = *V->getAsSignedConstant(); + // Copied/hacked up from Clang's CharacterLiteral::print - incomplete + // (doesn't actually support different character types/widths, sign + // handling's not done, and doesn't correctly test if a character is + // printable or needs to use a numeric escape sequence instead) + if (IsQualifiedChar) { + OS << '('; + OS << Name; + OS << ')'; + } + switch (Val) { + case '\\': + OS << "'\\\\'"; + break; + case '\'': + OS << "'\\''"; + break; + case '\a': + // TODO: K&R: the meaning of '\\a' is different in traditional C + OS << "'\\a'"; + break; + case '\b': + OS << "'\\b'"; + break; + case '\f': + OS << "'\\f'"; + break; + case '\n': + OS << "'\\n'"; + break; + case '\r': + OS << "'\\r'"; + break; + case '\t': + OS << "'\\t'"; + break; + case '\v': + OS << "'\\v'"; + break; + default: + if ((Val & ~0xFFu) == ~0xFFu) + Val &= 0xFFu; + if (Val < 127 && Val >= 32) { + OS << "'"; + OS << (char)Val; + OS << "'"; + } else if (Val < 256) + OS << llvm::format("'\\x%02" PRIx64 "'", Val); + else if (Val <= 0xFFFF) + OS << llvm::format("'\\u%04" PRIx64 "'", Val); + else + OS << llvm::format("'\\U%08" PRIx64 "'", Val); + } + } + continue; + } + if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) { + const char *RawName = + dwarf::toString(C.find(dwarf::DW_AT_GNU_template_name), nullptr); + assert(RawName); + StringRef Name = RawName; + Sep(); + OS << Name; + continue; + } + if (C.getTag() != dwarf::DW_TAG_template_type_parameter) + continue; + auto TypeAttr = C.find(dwarf::DW_AT_type); + Sep(); + appendQualifiedName(TypeAttr ? detail::resolveReferencedType(C, *TypeAttr) + : DieType()); + } + if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) { + OS << '<'; + EndedWithTemplate = false; + } + return IsTemplate; +} + +template +void DWARFTypePrinter::appendAndTerminateTemplateParameters(DieType D) { + bool R = appendTemplateParameters(D); + if (!R) + return; + + if (EndedWithTemplate) + OS << " "; + OS << ">"; + EndedWithTemplate = true; + Word = true; +} + +template +void DWARFTypePrinter::decomposeConstVolatile(DieType &N, DieType &T, + DieType &C, DieType &V) { + (N.getTag() == dwarf::DW_TAG_const_type ? C : V) = N; + T = detail::resolveReferencedType(N); + if (T) { + auto Tag = T.getTag(); + if (Tag == dwarf::DW_TAG_const_type) { + C = T; + T = detail::resolveReferencedType(T); + } else if (Tag == dwarf::DW_TAG_volatile_type) { + V = T; + T = detail::resolveReferencedType(T); + } + } +} + +template +void DWARFTypePrinter::appendConstVolatileQualifierAfter(DieType N) { + DieType C; + DieType V; + DieType T; + decomposeConstVolatile(N, T, C, V); + if (T && T.getTag() == dwarf::DW_TAG_subroutine_type) + appendSubroutineNameAfter(T, detail::resolveReferencedType(T), false, + C.isValid(), V.isValid()); + else + appendUnqualifiedNameAfter(T, detail::resolveReferencedType(T)); +} + +template +void DWARFTypePrinter::appendConstVolatileQualifierBefore(DieType N) { + DieType C; + DieType V; + DieType T; + decomposeConstVolatile(N, T, C, V); + bool Subroutine = T && T.getTag() == dwarf::DW_TAG_subroutine_type; + DieType A = T; + while (A && A.getTag() == dwarf::DW_TAG_array_type) + A = detail::resolveReferencedType(A); + bool Leading = + (!A || (A.getTag() != dwarf::DW_TAG_pointer_type && + A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) && + !Subroutine; + if (Leading) { + if (C) + OS << "const "; + if (V) + OS << "volatile "; + } + appendQualifiedNameBefore(T); + if (!Leading && !Subroutine) { + Word = true; + if (C) + OS << "const"; + if (V) { + if (C) + OS << ' '; + OS << "volatile"; + } + } +} + +template +void DWARFTypePrinter::appendUnqualifiedName( + DieType D, std::string *OriginalFullName) { + // FIXME: We should have pretty printers per language. Currently we print + // everything as if it was C++ and fall back to the TAG type name. + DieType Inner = appendUnqualifiedNameBefore(D, OriginalFullName); + appendUnqualifiedNameAfter(D, Inner); +} + +template +void DWARFTypePrinter::appendSubroutineNameAfter( + DieType D, DieType Inner, bool SkipFirstParamIfArtificial, bool Const, + bool Volatile) { + DieType FirstParamIfArtificial; + OS << '('; + EndedWithTemplate = false; + bool First = true; + bool RealFirst = true; + for (DieType P : D) { + if (P.getTag() != dwarf::DW_TAG_formal_parameter && + P.getTag() != dwarf::DW_TAG_unspecified_parameters) + return; + DieType T = detail::resolveReferencedType(P); + if (SkipFirstParamIfArtificial && RealFirst && + P.find(dwarf::DW_AT_artificial)) { + FirstParamIfArtificial = T; + RealFirst = false; + continue; + } + if (!First) { + OS << ", "; + } + First = false; + if (P.getTag() == dwarf::DW_TAG_unspecified_parameters) + OS << "..."; + else + appendQualifiedName(T); + } + EndedWithTemplate = false; + OS << ')'; + if (FirstParamIfArtificial) { + if (DieType P = FirstParamIfArtificial) { + if (P.getTag() == dwarf::DW_TAG_pointer_type) { + auto CVStep = [&](DieType CV) { + if (DieType U = detail::resolveReferencedType(CV)) { + Const |= U.getTag() == dwarf::DW_TAG_const_type; + Volatile |= U.getTag() == dwarf::DW_TAG_volatile_type; + return U; + } + return DieType(); + }; + if (DieType CV = CVStep(P)) { + CVStep(CV); + } + } + } + } + + if (auto CC = D.find(dwarf::DW_AT_calling_convention)) { + switch (*CC->getAsUnsignedConstant()) { + case dwarf::CallingConvention::DW_CC_BORLAND_stdcall: + OS << " __attribute__((stdcall))"; + break; + case dwarf::CallingConvention::DW_CC_BORLAND_msfastcall: + OS << " __attribute__((fastcall))"; + break; + case dwarf::CallingConvention::DW_CC_BORLAND_thiscall: + OS << " __attribute__((thiscall))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_vectorcall: + OS << " __attribute__((vectorcall))"; + break; + case dwarf::CallingConvention::DW_CC_BORLAND_pascal: + OS << " __attribute__((pascal))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_Win64: + OS << " __attribute__((ms_abi))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_X86_64SysV: + OS << " __attribute__((sysv_abi))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_AAPCS: + // AArch64VectorCall missing? + OS << " __attribute__((pcs(\"aapcs\")))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_AAPCS_VFP: + OS << " __attribute__((pcs(\"aapcs-vfp\")))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_IntelOclBicc: + OS << " __attribute__((intel_ocl_bicc))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_SpirFunction: + case dwarf::CallingConvention::DW_CC_LLVM_OpenCLKernel: + // These aren't available as attributes, but maybe we should still + // render them somehow? (Clang doesn't render them, but that's an issue + // for template names too - since then the DWARF names of templates + // instantiated with function types with these calling conventions won't + // have distinct names - so we'd need to fix that too) + break; + case dwarf::CallingConvention::DW_CC_LLVM_Swift: + // SwiftAsync missing + OS << " __attribute__((swiftcall))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_PreserveMost: + OS << " __attribute__((preserve_most))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_PreserveAll: + OS << " __attribute__((preserve_all))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_PreserveNone: + OS << " __attribute__((preserve_none))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_X86RegCall: + OS << " __attribute__((regcall))"; + break; + case dwarf::CallingConvention::DW_CC_LLVM_M68kRTD: + OS << " __attribute__((m68k_rtd))"; + break; + } + } + + if (Const) + OS << " const"; + if (Volatile) + OS << " volatile"; + if (D.find(dwarf::DW_AT_reference)) + OS << " &"; + if (D.find(dwarf::DW_AT_rvalue_reference)) + OS << " &&"; + + appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner)); +} + +template +void DWARFTypePrinter::appendScopes(DieType D) { + if (D.getTag() == dwarf::DW_TAG_compile_unit) + return; + if (D.getTag() == dwarf::DW_TAG_type_unit) + return; + if (D.getTag() == dwarf::DW_TAG_skeleton_unit) + return; + if (D.getTag() == dwarf::DW_TAG_subprogram) + return; + if (D.getTag() == dwarf::DW_TAG_lexical_block) + return; + D = D.resolveTypeUnitReference(); + if (DieType P = D.getParent()) + appendScopes(P); + appendUnqualifiedName(D); + OS << "::"; +} } // namespace llvm #endif // LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H diff --git a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt index 0ca08b092b26c..e565821cf2942 100644 --- a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt +++ b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt @@ -10,7 +10,6 @@ add_llvm_component_library(LLVMDebugInfoDWARF DWARFDebugArangeSet.cpp DWARFDebugAranges.cpp DWARFDebugFrame.cpp - DWARFTypePrinter.cpp DWARFDebugInfoEntry.cpp DWARFDebugLine.cpp DWARFDebugLoc.cpp diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index 9c26c4f8892b0..e014f04f754b4 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -777,12 +777,12 @@ bool DWARFAttribute::mayHaveLocationExpr(dwarf::Attribute Attr) { namespace llvm { void dumpTypeQualifiedName(const DWARFDie &DIE, raw_ostream &OS) { - DWARFTypePrinter(OS).appendQualifiedName(DIE); + DWARFTypePrinter(OS).appendQualifiedName(DIE); } void dumpTypeUnqualifiedName(const DWARFDie &DIE, raw_ostream &OS, std::string *OriginalFullName) { - DWARFTypePrinter(OS).appendUnqualifiedName(DIE, OriginalFullName); + DWARFTypePrinter(OS).appendUnqualifiedName(DIE, OriginalFullName); } } // namespace llvm diff --git a/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp b/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp deleted file mode 100644 index a26431e8313f6..0000000000000 --- a/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp +++ /dev/null @@ -1,675 +0,0 @@ -#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h" -#include "llvm/DebugInfo/DWARF/DWARFDie.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/Support/ScopedPrinter.h" -namespace llvm { -using namespace dwarf; -void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) { - StringRef TagStr = TagString(T); - static constexpr StringRef Prefix = "DW_TAG_"; - static constexpr StringRef Suffix = "_type"; - if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(Suffix)) - return; - OS << TagStr.substr(Prefix.size(), - TagStr.size() - (Prefix.size() + Suffix.size())) - << " "; -} - -void DWARFTypePrinter::appendArrayType(const DWARFDie &D) { - for (const DWARFDie &C : D.children()) { - if (C.getTag() != DW_TAG_subrange_type) - continue; - std::optional LB; - std::optional Count; - std::optional UB; - std::optional DefaultLB; - if (std::optional L = C.find(DW_AT_lower_bound)) - LB = L->getAsUnsignedConstant(); - if (std::optional CountV = C.find(DW_AT_count)) - Count = CountV->getAsUnsignedConstant(); - if (std::optional UpperV = C.find(DW_AT_upper_bound)) - UB = UpperV->getAsUnsignedConstant(); - if (std::optional LV = - D.getDwarfUnit()->getUnitDIE().find(DW_AT_language)) - if (std::optional LC = LV->getAsUnsignedConstant()) - if ((DefaultLB = - LanguageLowerBound(static_cast(*LC)))) - if (LB && *LB == *DefaultLB) - LB = std::nullopt; - if (!LB && !Count && !UB) - OS << "[]"; - else if (!LB && (Count || UB) && DefaultLB) - OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']'; - else { - OS << "[["; - if (LB) - OS << *LB; - else - OS << '?'; - OS << ", "; - if (Count) - if (LB) - OS << *LB + *Count; - else - OS << "? + " << *Count; - else if (UB) - OS << *UB + 1; - else - OS << '?'; - OS << ")]"; - } - } - EndedWithTemplate = false; -} - -static DWARFDie resolveReferencedType(DWARFDie D, - dwarf::Attribute Attr = DW_AT_type) { - return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference(); -} -static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) { - return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference(); -} -DWARFDie DWARFTypePrinter::skipQualifiers(DWARFDie D) { - while (D && (D.getTag() == DW_TAG_const_type || - D.getTag() == DW_TAG_volatile_type)) - D = resolveReferencedType(D); - return D; -} - -bool DWARFTypePrinter::needsParens(DWARFDie D) { - D = skipQualifiers(D); - return D && (D.getTag() == DW_TAG_subroutine_type || - D.getTag() == DW_TAG_array_type); -} - -void DWARFTypePrinter::appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner, - StringRef Ptr) { - appendQualifiedNameBefore(Inner); - if (Word) - OS << ' '; - if (needsParens(Inner)) - OS << '('; - OS << Ptr; - Word = false; - EndedWithTemplate = false; -} - -DWARFDie -DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D, - std::string *OriginalFullName) { - Word = true; - if (!D) { - OS << "void"; - return DWARFDie(); - } - DWARFDie InnerDIE; - auto Inner = [&] { return InnerDIE = resolveReferencedType(D); }; - const dwarf::Tag T = D.getTag(); - switch (T) { - case DW_TAG_pointer_type: { - appendPointerLikeTypeBefore(D, Inner(), "*"); - break; - } - case DW_TAG_subroutine_type: { - appendQualifiedNameBefore(Inner()); - if (Word) { - OS << ' '; - } - Word = false; - break; - } - case DW_TAG_array_type: { - appendQualifiedNameBefore(Inner()); - break; - } - case DW_TAG_reference_type: - appendPointerLikeTypeBefore(D, Inner(), "&"); - break; - case DW_TAG_rvalue_reference_type: - appendPointerLikeTypeBefore(D, Inner(), "&&"); - break; - case DW_TAG_ptr_to_member_type: { - appendQualifiedNameBefore(Inner()); - if (needsParens(InnerDIE)) - OS << '('; - else if (Word) - OS << ' '; - if (DWARFDie Cont = resolveReferencedType(D, DW_AT_containing_type)) { - appendQualifiedName(Cont); - EndedWithTemplate = false; - OS << "::"; - } - OS << "*"; - Word = false; - break; - } - case DW_TAG_LLVM_ptrauth_type: - appendQualifiedNameBefore(Inner()); - break; - case DW_TAG_const_type: - case DW_TAG_volatile_type: - appendConstVolatileQualifierBefore(D); - break; - case DW_TAG_namespace: { - if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr)) - OS << Name; - else - OS << "(anonymous namespace)"; - break; - } - case DW_TAG_unspecified_type: { - StringRef TypeName = D.getShortName(); - if (TypeName == "decltype(nullptr)") - TypeName = "std::nullptr_t"; - Word = true; - OS << TypeName; - EndedWithTemplate = false; - break; - } - /* - case DW_TAG_structure_type: - case DW_TAG_class_type: - case DW_TAG_enumeration_type: - case DW_TAG_base_type: - */ - default: { - const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr); - if (!NamePtr) { - appendTypeTagName(D.getTag()); - return DWARFDie(); - } - Word = true; - StringRef Name = NamePtr; - static constexpr StringRef MangledPrefix = "_STN|"; - if (Name.consume_front(MangledPrefix)) { - auto Separator = Name.find('|'); - assert(Separator != StringRef::npos); - StringRef BaseName = Name.substr(0, Separator); - StringRef TemplateArgs = Name.substr(Separator + 1); - if (OriginalFullName) - *OriginalFullName = (BaseName + TemplateArgs).str(); - Name = BaseName; - } else - EndedWithTemplate = Name.ends_with(">"); - OS << Name; - // This check would be insufficient for operator overloads like - // "operator>>" - but for now Clang doesn't try to simplify them, so this - // is OK. Add more nuanced operator overload handling here if/when needed. - if (Name.ends_with(">")) - break; - if (!appendTemplateParameters(D)) - break; - - if (EndedWithTemplate) - OS << ' '; - OS << '>'; - EndedWithTemplate = true; - Word = true; - break; - } - } - return InnerDIE; -} - -void DWARFTypePrinter::appendUnqualifiedNameAfter( - DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) { - if (!D) - return; - switch (D.getTag()) { - case DW_TAG_subroutine_type: { - appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false, - false); - break; - } - case DW_TAG_array_type: { - appendArrayType(D); - break; - } - case DW_TAG_const_type: - case DW_TAG_volatile_type: - appendConstVolatileQualifierAfter(D); - break; - case DW_TAG_ptr_to_member_type: - case DW_TAG_reference_type: - case DW_TAG_rvalue_reference_type: - case DW_TAG_pointer_type: { - if (needsParens(Inner)) - OS << ')'; - appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner), - /*SkipFirstParamIfArtificial=*/D.getTag() == - DW_TAG_ptr_to_member_type); - break; - } - case DW_TAG_LLVM_ptrauth_type: { - auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t { - if (auto Form = D.find(Attr)) - return *Form->getAsUnsignedConstant(); - return 0; - }; - SmallVector optionsVec; - if (getValOrNull(DW_AT_LLVM_ptrauth_isa_pointer)) - optionsVec.push_back("isa-pointer"); - if (getValOrNull(DW_AT_LLVM_ptrauth_authenticates_null_values)) - optionsVec.push_back("authenticates-null-values"); - if (auto AuthenticationMode = - D.find(DW_AT_LLVM_ptrauth_authentication_mode)) { - switch (*AuthenticationMode->getAsUnsignedConstant()) { - case 0: - case 1: - optionsVec.push_back("strip"); - break; - case 2: - optionsVec.push_back("sign-and-strip"); - break; - default: - // Default authentication policy - break; - } - } - std::string options; - for (const auto *option : optionsVec) { - if (options.size()) - options += ","; - options += option; - } - if (options.size()) - options = ", \"" + options + "\""; - std::string PtrauthString; - llvm::raw_string_ostream PtrauthStream(PtrauthString); - PtrauthStream - << "__ptrauth(" << getValOrNull(DW_AT_LLVM_ptrauth_key) << ", " - << getValOrNull(DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0" - << utohexstr(getValOrNull(DW_AT_LLVM_ptrauth_extra_discriminator), true) - << options << ")"; - OS << PtrauthStream.str(); - break; - } - /* - case DW_TAG_structure_type: - case DW_TAG_class_type: - case DW_TAG_enumeration_type: - case DW_TAG_base_type: - case DW_TAG_namespace: - */ - default: - break; - } -} - -/// Returns True if the DIE TAG is one of the ones that is scopped. -static bool scopedTAGs(dwarf::Tag Tag) { - switch (Tag) { - case dwarf::DW_TAG_structure_type: - case dwarf::DW_TAG_class_type: - case dwarf::DW_TAG_union_type: - case dwarf::DW_TAG_namespace: - case dwarf::DW_TAG_enumeration_type: - return true; - default: - break; - } - return false; -} -void DWARFTypePrinter::appendQualifiedName(DWARFDie D) { - if (D && scopedTAGs(D.getTag())) - appendScopes(D.getParent()); - appendUnqualifiedName(D); -} -DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) { - if (D && scopedTAGs(D.getTag())) - appendScopes(D.getParent()); - return appendUnqualifiedNameBefore(D); -} -bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D, - bool *FirstParameter) { - bool FirstParameterValue = true; - bool IsTemplate = false; - if (!FirstParameter) - FirstParameter = &FirstParameterValue; - for (const DWARFDie &C : D) { - auto Sep = [&] { - if (*FirstParameter) - OS << '<'; - else - OS << ", "; - IsTemplate = true; - EndedWithTemplate = false; - *FirstParameter = false; - }; - if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) { - IsTemplate = true; - appendTemplateParameters(C, FirstParameter); - } - if (C.getTag() == dwarf::DW_TAG_template_value_parameter) { - DWARFDie T = resolveReferencedType(C); - Sep(); - if (T.getTag() == DW_TAG_enumeration_type) { - OS << '('; - appendQualifiedName(T); - OS << ')'; - auto V = C.find(DW_AT_const_value); - OS << std::to_string(*V->getAsSignedConstant()); - continue; - } - // /Maybe/ we could do pointer/reference type parameters, looking for the - // symbol in the ELF symbol table to get back to the variable... - // but probably not worth it. - if (T.getTag() == DW_TAG_pointer_type || - T.getTag() == DW_TAG_reference_type) - continue; - const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr); - assert(RawName); - StringRef Name = RawName; - auto V = C.find(DW_AT_const_value); - bool IsQualifiedChar = false; - if (Name == "bool") { - OS << (*V->getAsUnsignedConstant() ? "true" : "false"); - } else if (Name == "short") { - OS << "(short)"; - OS << std::to_string(*V->getAsSignedConstant()); - } else if (Name == "unsigned short") { - OS << "(unsigned short)"; - OS << std::to_string(*V->getAsSignedConstant()); - } else if (Name == "int") - OS << std::to_string(*V->getAsSignedConstant()); - else if (Name == "long") { - OS << std::to_string(*V->getAsSignedConstant()); - OS << "L"; - } else if (Name == "long long") { - OS << std::to_string(*V->getAsSignedConstant()); - OS << "LL"; - } else if (Name == "unsigned int") { - OS << std::to_string(*V->getAsUnsignedConstant()); - OS << "U"; - } else if (Name == "unsigned long") { - OS << std::to_string(*V->getAsUnsignedConstant()); - OS << "UL"; - } else if (Name == "unsigned long long") { - OS << std::to_string(*V->getAsUnsignedConstant()); - OS << "ULL"; - } else if (Name == "char" || - (IsQualifiedChar = - (Name == "unsigned char" || Name == "signed char"))) { - // FIXME: check T's DW_AT_type to see if it's signed or not (since - // char signedness is implementation defined). - auto Val = *V->getAsSignedConstant(); - // Copied/hacked up from Clang's CharacterLiteral::print - incomplete - // (doesn't actually support different character types/widths, sign - // handling's not done, and doesn't correctly test if a character is - // printable or needs to use a numeric escape sequence instead) - if (IsQualifiedChar) { - OS << '('; - OS << Name; - OS << ')'; - } - switch (Val) { - case '\\': - OS << "'\\\\'"; - break; - case '\'': - OS << "'\\''"; - break; - case '\a': - // TODO: K&R: the meaning of '\\a' is different in traditional C - OS << "'\\a'"; - break; - case '\b': - OS << "'\\b'"; - break; - case '\f': - OS << "'\\f'"; - break; - case '\n': - OS << "'\\n'"; - break; - case '\r': - OS << "'\\r'"; - break; - case '\t': - OS << "'\\t'"; - break; - case '\v': - OS << "'\\v'"; - break; - default: - if ((Val & ~0xFFu) == ~0xFFu) - Val &= 0xFFu; - if (Val < 127 && Val >= 32) { - OS << "'"; - OS << (char)Val; - OS << "'"; - } else if (Val < 256) - OS << llvm::format("'\\x%02" PRIx64 "'", Val); - else if (Val <= 0xFFFF) - OS << llvm::format("'\\u%04" PRIx64 "'", Val); - else - OS << llvm::format("'\\U%08" PRIx64 "'", Val); - } - } - continue; - } - if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) { - const char *RawName = - dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr); - assert(RawName); - StringRef Name = RawName; - Sep(); - OS << Name; - continue; - } - if (C.getTag() != dwarf::DW_TAG_template_type_parameter) - continue; - auto TypeAttr = C.find(DW_AT_type); - Sep(); - appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr) - : DWARFDie()); - } - if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) { - OS << '<'; - EndedWithTemplate = false; - } - return IsTemplate; -} -void DWARFTypePrinter::decomposeConstVolatile(DWARFDie &N, DWARFDie &T, - DWARFDie &C, DWARFDie &V) { - (N.getTag() == DW_TAG_const_type ? C : V) = N; - T = resolveReferencedType(N); - if (T) { - auto Tag = T.getTag(); - if (Tag == DW_TAG_const_type) { - C = T; - T = resolveReferencedType(T); - } else if (Tag == DW_TAG_volatile_type) { - V = T; - T = resolveReferencedType(T); - } - } -} -void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) { - DWARFDie C; - DWARFDie V; - DWARFDie T; - decomposeConstVolatile(N, T, C, V); - if (T && T.getTag() == DW_TAG_subroutine_type) - appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(), - V.isValid()); - else - appendUnqualifiedNameAfter(T, resolveReferencedType(T)); -} -void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) { - DWARFDie C; - DWARFDie V; - DWARFDie T; - decomposeConstVolatile(N, T, C, V); - bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type; - DWARFDie A = T; - while (A && A.getTag() == DW_TAG_array_type) - A = resolveReferencedType(A); - bool Leading = - (!A || (A.getTag() != DW_TAG_pointer_type && - A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) && - !Subroutine; - if (Leading) { - if (C) - OS << "const "; - if (V) - OS << "volatile "; - } - appendQualifiedNameBefore(T); - if (!Leading && !Subroutine) { - Word = true; - if (C) - OS << "const"; - if (V) { - if (C) - OS << ' '; - OS << "volatile"; - } - } -} -void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D, - std::string *OriginalFullName) { - // FIXME: We should have pretty printers per language. Currently we print - // everything as if it was C++ and fall back to the TAG type name. - DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName); - appendUnqualifiedNameAfter(D, Inner); -} -void DWARFTypePrinter::appendSubroutineNameAfter( - DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const, - bool Volatile) { - DWARFDie FirstParamIfArtificial; - OS << '('; - EndedWithTemplate = false; - bool First = true; - bool RealFirst = true; - for (DWARFDie P : D) { - if (P.getTag() != DW_TAG_formal_parameter && - P.getTag() != DW_TAG_unspecified_parameters) - return; - DWARFDie T = resolveReferencedType(P); - if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) { - FirstParamIfArtificial = T; - RealFirst = false; - continue; - } - if (!First) { - OS << ", "; - } - First = false; - if (P.getTag() == DW_TAG_unspecified_parameters) - OS << "..."; - else - appendQualifiedName(T); - } - EndedWithTemplate = false; - OS << ')'; - if (FirstParamIfArtificial) { - if (DWARFDie P = FirstParamIfArtificial) { - if (P.getTag() == DW_TAG_pointer_type) { - auto CVStep = [&](DWARFDie CV) { - if (DWARFDie U = resolveReferencedType(CV)) { - Const |= U.getTag() == DW_TAG_const_type; - Volatile |= U.getTag() == DW_TAG_volatile_type; - return U; - } - return DWARFDie(); - }; - if (DWARFDie CV = CVStep(P)) { - CVStep(CV); - } - } - } - } - - if (auto CC = D.find(DW_AT_calling_convention)) { - switch (*CC->getAsUnsignedConstant()) { - case CallingConvention::DW_CC_BORLAND_stdcall: - OS << " __attribute__((stdcall))"; - break; - case CallingConvention::DW_CC_BORLAND_msfastcall: - OS << " __attribute__((fastcall))"; - break; - case CallingConvention::DW_CC_BORLAND_thiscall: - OS << " __attribute__((thiscall))"; - break; - case CallingConvention::DW_CC_LLVM_vectorcall: - OS << " __attribute__((vectorcall))"; - break; - case CallingConvention::DW_CC_BORLAND_pascal: - OS << " __attribute__((pascal))"; - break; - case CallingConvention::DW_CC_LLVM_Win64: - OS << " __attribute__((ms_abi))"; - break; - case CallingConvention::DW_CC_LLVM_X86_64SysV: - OS << " __attribute__((sysv_abi))"; - break; - case CallingConvention::DW_CC_LLVM_AAPCS: - // AArch64VectorCall missing? - OS << " __attribute__((pcs(\"aapcs\")))"; - break; - case CallingConvention::DW_CC_LLVM_AAPCS_VFP: - OS << " __attribute__((pcs(\"aapcs-vfp\")))"; - break; - case CallingConvention::DW_CC_LLVM_IntelOclBicc: - OS << " __attribute__((intel_ocl_bicc))"; - break; - case CallingConvention::DW_CC_LLVM_SpirFunction: - case CallingConvention::DW_CC_LLVM_OpenCLKernel: - // These aren't available as attributes, but maybe we should still - // render them somehow? (Clang doesn't render them, but that's an issue - // for template names too - since then the DWARF names of templates - // instantiated with function types with these calling conventions won't - // have distinct names - so we'd need to fix that too) - break; - case CallingConvention::DW_CC_LLVM_Swift: - // SwiftAsync missing - OS << " __attribute__((swiftcall))"; - break; - case CallingConvention::DW_CC_LLVM_PreserveMost: - OS << " __attribute__((preserve_most))"; - break; - case CallingConvention::DW_CC_LLVM_PreserveAll: - OS << " __attribute__((preserve_all))"; - break; - case CallingConvention::DW_CC_LLVM_PreserveNone: - OS << " __attribute__((preserve_none))"; - break; - case CallingConvention::DW_CC_LLVM_X86RegCall: - OS << " __attribute__((regcall))"; - break; - case CallingConvention::DW_CC_LLVM_M68kRTD: - OS << " __attribute__((m68k_rtd))"; - break; - } - } - - if (Const) - OS << " const"; - if (Volatile) - OS << " volatile"; - if (D.find(DW_AT_reference)) - OS << " &"; - if (D.find(DW_AT_rvalue_reference)) - OS << " &&"; - - appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner)); -} -void DWARFTypePrinter::appendScopes(DWARFDie D) { - if (D.getTag() == DW_TAG_compile_unit) - return; - if (D.getTag() == DW_TAG_type_unit) - return; - if (D.getTag() == DW_TAG_skeleton_unit) - return; - if (D.getTag() == DW_TAG_subprogram) - return; - if (D.getTag() == DW_TAG_lexical_block) - return; - D = D.resolveTypeUnitReference(); - if (DWARFDie P = D.getParent()) - appendScopes(P); - appendUnqualifiedName(D); - OS << "::"; -} -} // namespace llvm From 47af5ba5727d79ed577e2c84b6b4639c99249037 Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Fri, 20 Sep 2024 12:18:15 -0700 Subject: [PATCH 2/6] format --- llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h index 5315ac194f8ed..f57f85fc42d1a 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h @@ -584,7 +584,8 @@ bool DWARFTypePrinter::appendTemplateParameters(DieType D, } template -void DWARFTypePrinter::appendAndTerminateTemplateParameters(DieType D) { +void DWARFTypePrinter::appendAndTerminateTemplateParameters( + DieType D) { bool R = appendTemplateParameters(D); if (!R) return; From 3b45531cb5281bd760275d245692af423a8c6524 Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Fri, 20 Sep 2024 17:39:11 -0700 Subject: [PATCH 3/6] Removed unused functions --- .../llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h index f57f85fc42d1a..136880296a33e 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h @@ -20,36 +20,7 @@ namespace llvm { class raw_ostream; -inline std::optional getLanguage(DWARFDie D) { - if (std::optional LV = - D.getDwarfUnit()->getUnitDIE().find(dwarf::DW_AT_language)) - return LV->getAsUnsignedConstant(); - return std::nullopt; -} - namespace detail { -inline llvm::SmallString<128> toString(const llvm::format_object_base &Fmt) { - size_t NextBufferSize = 127; - llvm::SmallString<128> V; - - while (true) { - V.resize_for_overwrite(NextBufferSize); - - // Try formatting into the SmallVector. - size_t BytesUsed = Fmt.print(V.data(), NextBufferSize); - - // If BytesUsed fit into the vector, we win. - if (BytesUsed <= NextBufferSize) { - V.resize(BytesUsed); - return V; - } - - // Otherwise, try again with a new size. - assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?"); - NextBufferSize = BytesUsed; - } -} - /// Returns True if the DIE TAG is one of the ones that is scopped. inline bool scopedTAGs(dwarf::Tag Tag) { switch (Tag) { From 54c7aa27f92702dd4b4c1609c77f5ec8ef826ffd Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Tue, 24 Sep 2024 10:47:07 -0700 Subject: [PATCH 4/6] Update includes --- llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h index 136880296a33e..11d228b1df963 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h @@ -9,10 +9,9 @@ #ifndef LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H #define LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include From 0af725c023df7f9e329a753d8058c70cb1b873ec Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Tue, 24 Sep 2024 10:50:13 -0700 Subject: [PATCH 5/6] address comments --- .../llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h index 11d228b1df963..0fabbdb550b28 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h @@ -19,23 +19,6 @@ namespace llvm { class raw_ostream; -namespace detail { -/// Returns True if the DIE TAG is one of the ones that is scopped. -inline bool scopedTAGs(dwarf::Tag Tag) { - switch (Tag) { - case dwarf::DW_TAG_structure_type: - case dwarf::DW_TAG_class_type: - case dwarf::DW_TAG_union_type: - case dwarf::DW_TAG_namespace: - case dwarf::DW_TAG_enumeration_type: - return true; - default: - break; - } - return false; -} -} // namespace detail - // FIXME: We should have pretty printers per language. Currently we print // everything as if it was C++ and fall back to the TAG type name. template struct DWARFTypePrinter { @@ -77,6 +60,22 @@ template struct DWARFTypePrinter { bool SkipFirstParamIfArtificial, bool Const, bool Volatile); void appendScopes(DieType D); + +private: + /// Returns True if the DIE TAG is one of the ones that is scopped. + static inline bool scopedTAGs(dwarf::Tag Tag) { + switch (Tag) { + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_union_type: + case dwarf::DW_TAG_namespace: + case dwarf::DW_TAG_enumeration_type: + return true; + default: + break; + } + return false; + } }; template @@ -389,14 +388,14 @@ void DWARFTypePrinter::appendUnqualifiedNameAfter( template void DWARFTypePrinter::appendQualifiedName(DieType D) { - if (D && detail::scopedTAGs(D.getTag())) + if (D && scopedTAGs(D.getTag())) appendScopes(D.getParent()); appendUnqualifiedName(D); } template DieType DWARFTypePrinter::appendQualifiedNameBefore(DieType D) { - if (D && detail::scopedTAGs(D.getTag())) + if (D && scopedTAGs(D.getTag())) appendScopes(D.getParent()); return appendUnqualifiedNameBefore(D); } From 97698422368a4b75babfc6a2cf0ed8580522a548 Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Fri, 4 Oct 2024 14:44:32 -0700 Subject: [PATCH 6/6] Remove dependency on llvm::DWARFFormValue. --- llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h | 3 +++ .../llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 18 ++++++++++-------- llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 7 +++++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h index 421b84d644db6..69c91835a4d9a 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -44,6 +44,7 @@ class DWARFDie { const DWARFDebugInfoEntry *Die = nullptr; public: + using DWARFFormValue = llvm::DWARFFormValue; DWARFDie() = default; DWARFDie(DWARFUnit *Unit, const DWARFDebugInfoEntry *D) : U(Unit), Die(D) {} @@ -183,6 +184,8 @@ class DWARFDie { DWARFDie resolveTypeUnitReference() const; + DWARFDie resolveReferencedType(dwarf::Attribute Attr) const; + DWARFDie resolveReferencedType(const DWARFFormValue &V) const; /// Extract the range base attribute from this DIE as absolute section offset. /// /// This is a utility function that checks for either the DW_AT_rnglists_base diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h index 0fabbdb550b28..87e876273c4b9 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h @@ -11,7 +11,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include @@ -99,13 +98,16 @@ void DWARFTypePrinter::appendArrayType(const DieType &D) { std::optional Count; std::optional UB; std::optional DefaultLB; - if (std::optional L = C.find(dwarf::DW_AT_lower_bound)) + if (std::optional L = + C.find(dwarf::DW_AT_lower_bound)) LB = L->getAsUnsignedConstant(); - if (std::optional CountV = C.find(dwarf::DW_AT_count)) + if (std::optional CountV = + C.find(dwarf::DW_AT_count)) Count = CountV->getAsUnsignedConstant(); - if (std::optional UpperV = C.find(dwarf::DW_AT_upper_bound)) + if (std::optional UpperV = + C.find(dwarf::DW_AT_upper_bound)) UB = UpperV->getAsUnsignedConstant(); - if (std::optional LV = + if (std::optional LV = D.getDwarfUnit()->getUnitDIE().find(dwarf::DW_AT_language)) if (std::optional LC = LV->getAsUnsignedConstant()) if ((DefaultLB = @@ -142,11 +144,11 @@ namespace detail { template DieType resolveReferencedType(DieType D, dwarf::Attribute Attr = dwarf::DW_AT_type) { - return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference(); + return D.resolveReferencedType(Attr); } template -DieType resolveReferencedType(DieType D, DWARFFormValue F) { - return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference(); +DieType resolveReferencedType(DieType D, typename DieType::DWARFFormValue F) { + return D.resolveReferencedType(F); } } // namespace detail diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index e014f04f754b4..6e7b5870dfa29 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -337,6 +337,13 @@ DWARFDie DWARFDie::resolveTypeUnitReference() const { return *this; } +DWARFDie DWARFDie::resolveReferencedType(dwarf::Attribute Attr) const { + return getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference(); +} +DWARFDie DWARFDie::resolveReferencedType(const DWARFFormValue &V) const { + return getAttributeValueAsReferencedDie(V).resolveTypeUnitReference(); +} + std::optional DWARFDie::getRangesBaseAttribute() const { return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base})); }