diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h index c6f30cde81867..eda74475a764e 100644 --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -286,6 +286,9 @@ class TypeQuery { std::vector &GetContextRef() { return m_context; } + const std::vector &GetContextRef() const { + return m_context; + } protected: /// A full or partial compiler context array where the parent declaration diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index dc4cfc96b86f0..f7c33f39a8a89 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include +#include +#include #include "DWARFASTParser.h" #include "DWARFASTParserClang.h" @@ -44,6 +46,8 @@ #include "clang/AST/Type.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h" + #include #include #include @@ -865,11 +869,20 @@ DWARFASTParserClang::GetDIEClassTemplateParams(const DWARFDIE &die) { if (llvm::StringRef(die.GetName()).contains("<")) return ConstString(); + //std::cerr << "rebuilding template params for " << die.GetDIE()->GetOffset() << "\n"; +#if 1 + std::string R; + llvm::raw_string_ostream OS(R); + llvm::DWARFTypePrinter p(OS); + p.appendAndTerminateTemplateParameters(die); + return ConstString(R); +#else TypeSystemClang::TemplateParameterInfos template_param_infos; if (ParseTemplateParameterInfos(die, template_param_infos)) { return ConstString(m_ast.PrintTemplateParams(template_param_infos)); } return ConstString(); +#endif } TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, @@ -1621,6 +1634,17 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) { const char *name = die.GetName(); if (!name) return ""; +#if 0 + static int indent = 0; + std::cerr << std::string(indent, ' ') << "starting qualified name for: " << name << '\n'; + auto &FS = die.GetCU()->GetSymbolFileDWARF().GetObjectFile()->GetFileSpec(); + std::string Directory = FS.GetDirectory().AsCString(""); + std::cerr << std::string(indent, ' ') + << Directory.substr(std::min(59ul, Directory.size())) << '/' + << FS.GetFilename().AsCString("") << ':' << std::hex + << die.GetDIE()->GetOffset() << '\n'; + ++indent; +#endif std::string qualified_name; DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE(); // TODO: change this to get the correct decl context parent.... @@ -1645,9 +1669,9 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) { case DW_TAG_structure_type: case DW_TAG_union_type: { if (const char *class_union_struct_name = parent_decl_ctx_die.GetName()) { + qualified_name.insert(0, "::"); qualified_name.insert( 0, GetDIEClassTemplateParams(parent_decl_ctx_die).AsCString("")); - qualified_name.insert(0, "::"); qualified_name.insert(0, class_union_struct_name); } parent_decl_ctx_die = parent_decl_ctx_die.GetParentDeclContextDIE(); @@ -1666,6 +1690,11 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) { qualified_name.append(name); qualified_name.append(GetDIEClassTemplateParams(die).AsCString("")); +#if 0 + --indent; + std::cerr << std::string(indent, ' ') << "computed qualified name: " << qualified_name << '\n'; +#endif + return qualified_name; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h index 235343d227122..2cb7b247f5940 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h @@ -24,6 +24,7 @@ class DWARFUnit; class DWARFDebugInfoEntry; class DWARFDeclContext; class SymbolFileDWARF; +class DWARFFormValue; class DWARFBaseDIE { public: @@ -47,6 +48,8 @@ class DWARFBaseDIE { bool IsValid() const { return m_cu && m_die; } + bool isValid() const { return IsValid(); } + bool HasChildren() const; bool Supports_DW_AT_APPLE_objc_complete_type() const; @@ -84,6 +87,10 @@ class DWARFBaseDIE { // Accessing information about a DIE dw_tag_t Tag() const; + dw_tag_t getTag() const { + return Tag(); + } + using DWARFFormValue = dwarf::DWARFFormValue; dw_offset_t GetOffset() const; @@ -94,6 +101,9 @@ class DWARFBaseDIE { lldb::user_id_t GetID() const; const char *GetName() const; + const char *getShortName() const { + return GetName(); + } lldb::ModuleSP GetModule() const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index 7cf92adc6ef57..a3d6237ada87b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -118,7 +118,13 @@ DWARFDIE::GetReferencedDIE(const dw_attr_t attr) const { } DWARFDIE -DWARFDIE::GetDIE(dw_offset_t die_offset) const { +DWARFDIE::getAttributeValueAsReferencedDie(DWARFFormValue value) const { + if (IsValid()) + return value.Reference(); + return {}; +} + +DWARFDIE DWARFDIE::GetDIE(dw_offset_t die_offset) const { if (IsValid()) return m_cu->GetDIE(die_offset); else @@ -545,3 +551,23 @@ bool DWARFDIE::GetDIENamesAndRanges( llvm::iterator_range DWARFDIE::children() const { return llvm::make_range(child_iterator(*this), child_iterator()); } + +DWARFDIE::child_iterator DWARFDIE::begin() const { + return child_iterator(*this); +} +DWARFDIE::child_iterator DWARFDIE::end() const { + return child_iterator(); +} +std::optional DWARFDIE::find(const dw_attr_t attr) const { + DWARFFormValue form_value; + if (m_die->GetAttributeValue(m_cu, attr, form_value, nullptr, false)) + return form_value; + return std::nullopt; +} + +std::optional llvm::getLanguage(lldb_private::plugin::dwarf::DWARFDIE D) { + if (auto I = D.GetCU()->GetDWARFLanguageType()) + return I; + return std::nullopt; +} + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index 511ca62d0197a..ae32f980db241 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -47,6 +47,8 @@ class DWARFDIE : public DWARFBaseDIE { DWARFDIE GetParent() const; + DWARFDIE getParent() const { return GetParent(); } + DWARFDIE GetFirstChild() const; @@ -56,6 +58,12 @@ class DWARFDIE : public DWARFBaseDIE { DWARFDIE GetReferencedDIE(const dw_attr_t attr) const; + DWARFDIE getAttributeValueAsReferencedDie(const dw_attr_t attr) const { + return GetReferencedDIE(attr); + } + + DWARFDIE getAttributeValueAsReferencedDie(DWARFFormValue) const; + // Get a another DIE from the same DWARF file as this DIE. This will // check the current DIE's compile unit first to see if "die_offset" is // in the same compile unit, and fall back to checking the DWARF file. @@ -97,6 +105,8 @@ class DWARFDIE : public DWARFBaseDIE { DWARFDIE GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const; + std::optional find(const dw_attr_t attr) const; + bool GetDIENamesAndRanges( const char *&name, const char *&mangled, DWARFRangeList &ranges, std::optional &decl_file, std::optional &decl_line, @@ -106,6 +116,9 @@ class DWARFDIE : public DWARFBaseDIE { /// The range of all the children of this DIE. llvm::iterator_range children() const; + + child_iterator begin() const; + child_iterator end() const; }; class DWARFDIE::child_iterator @@ -143,4 +156,8 @@ class DWARFDIE::child_iterator } // namespace dwarf } // namespace lldb_private::plugin +namespace llvm { +std::optional getLanguage(lldb_private::plugin::dwarf::DWARFDIE D); +} + #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDIE_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index fdd5b3c278a4e..42a9b9e8e7f50 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -69,6 +69,30 @@ class DWARFFormValue { uint64_t Reference(dw_offset_t offset) const; bool Boolean() const { return m_value.value.uval != 0; } uint64_t Unsigned() const { return m_value.value.uval; } + std::optional getAsUnsignedConstant() const { + if ((!IsDataForm(m_form)) || m_form == lldb_private::dwarf::DW_FORM_sdata) + return std::nullopt; + return m_value.value.uval; + } + std::optional getAsSignedConstant() const { + if ((!IsDataForm(m_form)) || + (m_form == lldb_private::dwarf::DW_FORM_udata && + uint64_t(std::numeric_limits::max()) < m_value.value.uval)) + return std::nullopt; + switch (m_form) { + case lldb_private::dwarf::DW_FORM_data4: + return int32_t(m_value.value.uval); + case lldb_private::dwarf::DW_FORM_data2: + return int16_t(m_value.value.uval); + case lldb_private::dwarf::DW_FORM_data1: + return int8_t(m_value.value.uval); + case lldb_private::dwarf::DW_FORM_sdata: + case lldb_private::dwarf::DW_FORM_data8: + default: + return m_value.value.sval; + } + } + void SetUnsigned(uint64_t uval) { m_value.value.uval = uval; } int64_t Signed() const { return m_value.value.sval; } void SetSigned(int64_t sval) { m_value.value.sval = sval; } @@ -93,6 +117,19 @@ class DWARFFormValue { dw_form_t m_form = dw_form_t(0); // Form for this value ValueType m_value; // Contains all data for the form }; + +inline const char* toString(DWARFFormValue Value, const char* Default) { + if (const char* R = Value.AsCString()) + return R; + return Default; +} +inline const char* toString(std::optional Value, const char* Default) { + if (!Value) + return Default; + if (const char* R = Value->AsCString()) + return R; + return Default; +} } // namespace dwarf } // namespace lldb_private::plugin diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 661e4a78a0215..dacf2ce6094c1 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -38,6 +38,8 @@ #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueProperties.h" +#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h" + #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" @@ -2785,33 +2787,21 @@ void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) { return true; // Keep iterating over index types, language mismatch. } - // Check the context matches - std::vector die_context; - if (query.GetModuleSearch()) - die_context = die.GetDeclContext(); - else - die_context = die.GetTypeLookupContext(); - assert(!die_context.empty()); - if (!query_simple.ContextMatches(die_context)) - return true; // Keep iterating over index types, context mismatch. - - // Try to resolve the type. - if (Type *matching_type = ResolveType(die, true, true)) { - ConstString name = matching_type->GetQualifiedName(); - // We have found a type that still might not match due to template - // parameters. If we create a new TypeQuery that uses the new type's - // fully qualified name, we can find out if this type matches at all - // context levels. We can't use just the "match_simple" context - // because all template parameters were stripped off. The fully - // qualified name of the type will have the template parameters and - // will allow us to make sure it matches correctly. - TypeQuery die_query(name.GetStringRef(), - TypeQueryOptions::e_exact_match); - if (!query.ContextMatches(die_query.GetContextRef())) - return true; // Keep iterating over index types, context mismatch. - - results.InsertUnique(matching_type->shared_from_this()); - } + bool Success = true; + const auto &Context = query.GetContextRef(); + assert(Context.size() == 1); + llvm::StringRef remaining = Context.front().name; + auto Visitor = [&](llvm::StringRef S) { + Success &= remaining.consume_front(S); + return Success; + }; + llvm::DWARFTypePrinter p(Visitor); + p.appendQualifiedName(die); + + if (Success && remaining.empty()) + if (Type *matching_type = ResolveType(die, true, true)) + results.InsertUnique(matching_type->shared_from_this()); + return !results.Done(query); // Keep iterating if we aren't done. }); if (results.Done(query)) @@ -3219,31 +3209,21 @@ SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) { type_dwarf_decl_ctx.GetQualifiedName()); } - Type *resolved_type = ResolveType(type_die, false); - if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED) - return true; - // With -gsimple-template-names, the DIE name may not contain the template // parameters. If the declaration has template parameters but doesn't // contain '<', check that the child template parameters match. if (template_params) { - llvm::StringRef test_base_name = - GetTypeForDIE(type_die)->GetBaseName().GetStringRef(); - auto i = test_base_name.find('<'); - - // Full name from clang AST doesn't contain '<' so this type_die isn't - // a template parameter, but we're expecting template parameters, so - // bail. - if (i == llvm::StringRef::npos) - return true; - - llvm::StringRef test_template_params = - test_base_name.slice(i, test_base_name.size()); + ConstString test_template_params = + type_system->GetDWARFParser()->GetDIEClassTemplateParams(type_die); // Bail if template parameters don't match. - if (test_template_params != template_params.GetStringRef()) + if (test_template_params != template_params) return true; } + Type *resolved_type = ResolveType(type_die, false); + if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED) + return true; + type_sp = resolved_type->shared_from_this(); return false; }); diff --git a/llvm/include/llvm-c/Error.h b/llvm/include/llvm-c/Error.h index c3baaf65186aa..81a30133d5835 100644 --- a/llvm/include/llvm-c/Error.h +++ b/llvm/include/llvm-c/Error.h @@ -51,6 +51,14 @@ LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err); */ void LLVMConsumeError(LLVMErrorRef Err); +/** + * Report a fatal error if Err is a failure value. + * + * This function can be used to wrap calls to fallible functions ONLY when it + * is known that the Error will always be a success value. + */ +void LLVMCantFail(LLVMErrorRef Err); + /** * Returns the given string's error message. This operation consumes the error, * and the given LLVMErrorRef value is not usable once this call returns. diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h index 421b84d644db6..50eabdf6b0511 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFAttribute.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" #include #include @@ -44,6 +45,7 @@ class DWARFDie { const DWARFDebugInfoEntry *Die = nullptr; public: + using DWARFFormValue = llvm::DWARFFormValue; DWARFDie() = default; DWARFDie(DWARFUnit *Unit, const DWARFDebugInfoEntry *D) : U(Unit), Die(D) {} diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h index 2dcd7805b6c96..88d207d984777 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -168,8 +168,6 @@ class DWARFFormValue { void dumpString(raw_ostream &OS) const; }; -namespace dwarf { - /// Take an optional DWARFFormValue and try to extract a string value from it. /// /// \param V and optional DWARFFormValue to attempt to extract the value from. @@ -219,6 +217,11 @@ inline const char *toString(const std::optional &V, return Default; } +namespace dwarf { + +using llvm::toString; +using llvm::toStringRef; + /// Take an optional DWARFFormValue and try to extract an unsigned constant. /// /// \param V and optional DWARFFormValue to attempt to extract the value from. diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h index e05271740e615..698eaf822afc3 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h @@ -11,7 +11,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/ADT/SmallString.h" #include @@ -19,49 +19,834 @@ 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 { +struct DefaultVisitor { + raw_ostream &OS; + DefaultVisitor(raw_ostream &OS) : OS(OS) { } + bool operator()(StringRef S) const { + OS << S; + return true; + } +}; + +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; + } +} +} + +#define LLVM_QUICK_EXIT(expr) if (!(expr)) return false +#define LLVM_QUICK_EXIT_NONE(expr) if (!(expr)) return std::nullopt + // 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 { - raw_ostream &OS; + Visitor V; bool Word = true; bool EndedWithTemplate = false; - DWARFTypePrinter(raw_ostream &OS) : OS(OS) {} + DWARFTypePrinter(raw_ostream &OS) : V(OS) { + } + template + DWARFTypePrinter(T &&V) : V(std::forward(V)) {} /// Dump the name encoded in the type tag. - void appendTypeTagName(dwarf::Tag T); + bool appendTypeTagName(dwarf::Tag T); - void appendArrayType(const DWARFDie &D); + bool 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); + bool appendPointerLikeTypeBefore(DieType D, DieType Inner, StringRef Ptr); - DWARFDie appendUnqualifiedNameBefore(DWARFDie D, - std::string *OriginalFullName = nullptr); + std::optional + appendUnqualifiedNameBefore(DieType D, + std::string *OriginalFullName = nullptr); - void appendUnqualifiedNameAfter(DWARFDie D, DWARFDie Inner, + bool 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); + bool appendQualifiedName(DieType D); + std::optional appendQualifiedNameBefore(DieType D); + std::optional appendTemplateParameters(DieType D, bool *FirstParameter = nullptr); + bool appendAndTerminateTemplateParameters(DieType D); + void decomposeConstVolatile(DieType &N, DieType &T, DieType &C, DieType &V); + bool appendConstVolatileQualifierAfter(DieType N); + bool appendConstVolatileQualifierBefore(DieType N); /// Recursively append the DIE type name when applicable. - void appendUnqualifiedName(DWARFDie D, + bool appendUnqualifiedName(DieType D, std::string *OriginalFullName = nullptr); - void appendSubroutineNameAfter(DWARFDie D, DWARFDie Inner, + bool appendSubroutineNameAfter(DieType D, DieType Inner, bool SkipFirstParamIfArtificial, bool Const, bool Volatile); - void appendScopes(DWARFDie D); + bool appendScopes(DieType D); }; +template +bool DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) { + StringRef TagStr = TagString(T); + static constexpr StringRef Prefix = "dwarf::DW_TAG_"; + static constexpr StringRef Suffix = "_type"; + if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(Suffix)) + return true; + LLVM_QUICK_EXIT(V(TagStr.substr( + Prefix.size(), TagStr.size() - (Prefix.size() + Suffix.size())))); + LLVM_QUICK_EXIT(V(" ")); + return true; +} + +template +bool 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 LC = getLanguage(D)) + DefaultLB = + LanguageLowerBound(static_cast(*LC)); + + if (DefaultLB == LB) + LB = std::nullopt; + if (!LB && !Count && !UB) { + LLVM_QUICK_EXIT(V("[]")); + } else if (!LB && (Count || UB) && DefaultLB) { + LLVM_QUICK_EXIT(V("[") && + V(Twine(Count ? *Count : *UB - *DefaultLB + 1).str()) && + V("]")); + } else { + LLVM_QUICK_EXIT(V("[[")); + if (LB) { + LLVM_QUICK_EXIT(V(Twine(*LB).str())); + } else { + LLVM_QUICK_EXIT(V("?")); + } + LLVM_QUICK_EXIT(V(", ")); + if (Count) { + if (LB) { + LLVM_QUICK_EXIT(V(Twine(*LB + *Count).str())); + } else { + LLVM_QUICK_EXIT(V("? + ") && V(Twine(*Count).str())); + } + } else if (UB) { + LLVM_QUICK_EXIT(V(Twine(*UB + 1).str())); + } else { + LLVM_QUICK_EXIT(V("?")); + } + LLVM_QUICK_EXIT(V(")]")); + } + } + EndedWithTemplate = false; + return true; +} + +namespace detail { +template +DieType resolveReferencedType(DieType D, + dwarf::Attribute Attr = dwarf::DW_AT_type) { + return D.getAttributeValueAsReferencedDie(Attr); // .resolveTypeUnitReference(); +} +template +DieType resolveReferencedType(DieType D, typename DieType::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 +bool DWARFTypePrinter::appendPointerLikeTypeBefore( + DieType D, DieType Inner, StringRef Ptr) { + LLVM_QUICK_EXIT(appendQualifiedNameBefore(Inner)); + if (Word) + LLVM_QUICK_EXIT(V(" ")); + if (needsParens(Inner)) + LLVM_QUICK_EXIT(V("(")); + LLVM_QUICK_EXIT(V(Ptr)); + Word = false; + EndedWithTemplate = false; + return true; +} + +template +std::optional DWARFTypePrinter::appendUnqualifiedNameBefore( + DieType D, std::string *OriginalFullName) { + Word = true; + if (!D) { + LLVM_QUICK_EXIT_NONE(V("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: { + LLVM_QUICK_EXIT_NONE(appendPointerLikeTypeBefore(D, Inner(), "*")); + break; + } + case dwarf::DW_TAG_subroutine_type: { + LLVM_QUICK_EXIT_NONE(appendQualifiedNameBefore(Inner())); + if (Word) { + LLVM_QUICK_EXIT_NONE(V(" ")); + } + Word = false; + break; + } + case dwarf::DW_TAG_array_type: { + LLVM_QUICK_EXIT_NONE(appendQualifiedNameBefore(Inner())); + break; + } + case dwarf::DW_TAG_reference_type: + LLVM_QUICK_EXIT_NONE(appendPointerLikeTypeBefore(D, Inner(), "&")); + break; + case dwarf::DW_TAG_rvalue_reference_type: + LLVM_QUICK_EXIT_NONE(appendPointerLikeTypeBefore(D, Inner(), "&&")); + break; + case dwarf::DW_TAG_ptr_to_member_type: { + LLVM_QUICK_EXIT_NONE(appendQualifiedNameBefore(Inner())); + if (needsParens(InnerDIE)) { + LLVM_QUICK_EXIT_NONE(V("(")); + } else if (Word) { + LLVM_QUICK_EXIT_NONE(V(" ")); + } if (DieType Cont = detail::resolveReferencedType(D, dwarf::DW_AT_containing_type)) { + appendQualifiedName(Cont); + EndedWithTemplate = false; + LLVM_QUICK_EXIT_NONE(V("::")); + } + LLVM_QUICK_EXIT_NONE(V("*")); + Word = false; + break; + } + case dwarf::DW_TAG_LLVM_ptrauth_type: + LLVM_QUICK_EXIT_NONE(appendQualifiedNameBefore(Inner())); + break; + case dwarf::DW_TAG_const_type: + case dwarf::DW_TAG_volatile_type: + LLVM_QUICK_EXIT_NONE(appendConstVolatileQualifierBefore(D)); + break; + case dwarf::DW_TAG_namespace: { + if (const char *Name = toString(D.find(dwarf::DW_AT_name), nullptr)) { + LLVM_QUICK_EXIT_NONE(V(Name)); + } else { + LLVM_QUICK_EXIT_NONE(V("(anonymous namespace)")); + } + break; + } + case dwarf::DW_TAG_unspecified_type: { + StringRef TypeName = D.getShortName(); + if (TypeName == "decltype(nullptr)") + TypeName = "std::nullptr_t"; + Word = true; + LLVM_QUICK_EXIT_NONE(V(TypeName)); + EndedWithTemplate = false; + break; + } + /* + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_enumeration_type: + case dwarf::DW_TAG_base_type: + */ + default: { + const char *NamePtr = toString(D.find(dwarf::DW_AT_name), nullptr); + if (!NamePtr) { + LLVM_QUICK_EXIT_NONE(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(">"); + LLVM_QUICK_EXIT_NONE(V(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; + LLVM_QUICK_EXIT_NONE(appendAndTerminateTemplateParameters(D)); + break; + } + } + return InnerDIE; +} + +template +bool DWARFTypePrinter::appendAndTerminateTemplateParameters(DieType D) { + std::optional R = appendTemplateParameters(D); + if (!R) + return false; + if (!*R) + return true; + + if (EndedWithTemplate) + LLVM_QUICK_EXIT(V(" ")); + LLVM_QUICK_EXIT(V(">")); + EndedWithTemplate = true; + Word = true; + return true; +} + +template +bool DWARFTypePrinter::appendUnqualifiedNameAfter( + DieType D, DieType Inner, bool SkipFirstParamIfArtificial) { + if (!D) + return true; + switch (D.getTag()) { + case dwarf::DW_TAG_subroutine_type: { + LLVM_QUICK_EXIT(appendSubroutineNameAfter( + D, Inner, SkipFirstParamIfArtificial, false, false)); + break; + } + case dwarf::DW_TAG_array_type: { + LLVM_QUICK_EXIT(appendArrayType(D)); + break; + } + case dwarf::DW_TAG_const_type: + case dwarf::DW_TAG_volatile_type: + LLVM_QUICK_EXIT(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)) + LLVM_QUICK_EXIT(V(")")); + 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 << ")"; + LLVM_QUICK_EXIT(V(PtrauthStream.str())); + break; + } + /* + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_enumeration_type: + case dwarf::DW_TAG_base_type: + case dwarf::DW_TAG_namespace: + */ + default: + break; + } + return true; +} + +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 +template +bool DWARFTypePrinter::appendQualifiedName(DieType D) { + if (D && detail::scopedTAGs(D.getTag())) + LLVM_QUICK_EXIT(appendScopes(D.getParent())); + LLVM_QUICK_EXIT(appendUnqualifiedName(D)); + return true; +} +template +std::optional DWARFTypePrinter::appendQualifiedNameBefore(DieType D) { + if (D && detail::scopedTAGs(D.getTag())) + LLVM_QUICK_EXIT_NONE(appendScopes(D.getParent())); + return appendUnqualifiedNameBefore(D); +} +template +std::optional +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) { + LLVM_QUICK_EXIT(V("<")); + } else { + LLVM_QUICK_EXIT(V(", ")); + } + IsTemplate = true; + EndedWithTemplate = false; + *FirstParameter = false; + return true; + }; + 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); + LLVM_QUICK_EXIT_NONE(Sep()); + if (T.getTag() == dwarf::DW_TAG_enumeration_type) { + LLVM_QUICK_EXIT_NONE(V("(")); + appendQualifiedName(T); + LLVM_QUICK_EXIT_NONE(V(")")); + auto Value = C.find(dwarf::DW_AT_const_value); + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsSignedConstant()))); + continue; + } + // /Maybe/ we could do pointer 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) + continue; + const char *RawName = toString(T.find(dwarf::DW_AT_name), nullptr); + assert(RawName); + StringRef Name = RawName; + auto Value = C.find(dwarf::DW_AT_const_value); + bool IsQualifiedChar = false; + if (Name == "bool") { + LLVM_QUICK_EXIT_NONE(V((*Value->getAsUnsignedConstant() ? "true" : "false"))); + } else if (Name == "short") { + LLVM_QUICK_EXIT_NONE(V("(short)")); + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsSignedConstant()))); + } else if (Name == "unsigned short") { + LLVM_QUICK_EXIT_NONE(V("(unsigned short)")); + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsSignedConstant()))); + } else if (Name == "int") { + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsSignedConstant()))); + } else if (Name == "long") { + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsSignedConstant()))); + LLVM_QUICK_EXIT_NONE(V("L")); + } else if (Name == "long long") { + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsSignedConstant()))); + LLVM_QUICK_EXIT_NONE(V("LL")); + } else if (Name == "unsigned int") { + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsUnsignedConstant()))); + LLVM_QUICK_EXIT_NONE(V("U")); + } else if (Name == "unsigned long") { + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsUnsignedConstant()))); + LLVM_QUICK_EXIT_NONE(V("UL")); + } else if (Name == "unsigned long long") { + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsUnsignedConstant()))); + LLVM_QUICK_EXIT_NONE(V("ULL")); + } else if (Name == "char" || + (IsQualifiedChar = + (Name == "unsigned char" || Name == "signed char"))) { + // FIXME: check T's dwarf::DW_AT_type to see if it's signed or not (since + // char signedness is implementation defined). + auto Val = *Value->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) { + LLVM_QUICK_EXIT_NONE(V("(")); + LLVM_QUICK_EXIT_NONE(V(Name)); + LLVM_QUICK_EXIT_NONE(V(")")); + } + switch (Val) { + case '\\': + LLVM_QUICK_EXIT_NONE(V("'\\\\'")); + break; + case '\'': + LLVM_QUICK_EXIT_NONE(V("'\\''")); + break; + case '\a': + // TODO: K&R: the meaning of '\\a' is different in traditional C + LLVM_QUICK_EXIT_NONE(V("'\\a'")); + break; + case '\b': + LLVM_QUICK_EXIT_NONE(V("'\\b'")); + break; + case '\f': + LLVM_QUICK_EXIT_NONE(V("'\\f'")); + break; + case '\n': + LLVM_QUICK_EXIT_NONE(V("'\\n'")); + break; + case '\r': + LLVM_QUICK_EXIT_NONE(V("'\\r'")); + break; + case '\t': + LLVM_QUICK_EXIT_NONE(V("'\\t'")); + break; + case '\v': + LLVM_QUICK_EXIT_NONE(V("'\\v'")); + break; + default: + if ((Val & ~0xFFu) == ~0xFFu) + Val &= 0xFFu; + if (Val < 127 && Val >= 32) { + LLVM_QUICK_EXIT_NONE(V("'")); + LLVM_QUICK_EXIT_NONE(V(Twine((char)Val).str())); + LLVM_QUICK_EXIT_NONE(V("'")); + } else if (Val < 256) { + LLVM_QUICK_EXIT_NONE(V(detail::toString(llvm::format("'\\x%02" PRIx64 "'", Val)))); + } else if (Val <= 0xFFFF) { + LLVM_QUICK_EXIT_NONE( + V(detail::toString(llvm::format("'\\u%04" PRIx64 "'", Val)))); + } else { + LLVM_QUICK_EXIT_NONE( + V(detail::toString(llvm::format("'\\U%08" PRIx64 "'", Val)))); + } + } + } + continue; + } + if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) { + const char *RawName = + toString(C.find(dwarf::DW_AT_GNU_template_name), nullptr); + assert(RawName); + StringRef Name = RawName; + LLVM_QUICK_EXIT_NONE(Sep()); + LLVM_QUICK_EXIT_NONE(V(Name)); + continue; + } + if (C.getTag() != dwarf::DW_TAG_template_type_parameter) + continue; + auto TypeAttr = C.find(dwarf::DW_AT_type); + LLVM_QUICK_EXIT_NONE(Sep()); + appendQualifiedName(TypeAttr ? detail::resolveReferencedType(C, *TypeAttr) + : DieType()); + } + if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) { + LLVM_QUICK_EXIT_NONE(V("<")); + EndedWithTemplate = false; + } + return IsTemplate; +} +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 +bool DWARFTypePrinter::appendConstVolatileQualifierAfter(DieType N) { + DieType C; + DieType V; + DieType T; + decomposeConstVolatile(N, T, C, V); + if (T && T.getTag() == dwarf::DW_TAG_subroutine_type) { + LLVM_QUICK_EXIT(appendSubroutineNameAfter(T, detail::resolveReferencedType(T), false, C.isValid(), + V.isValid())); + } else { + LLVM_QUICK_EXIT(appendUnqualifiedNameAfter(T, detail::resolveReferencedType(T))); + } + return true; +} +template +bool DWARFTypePrinter::appendConstVolatileQualifierBefore(DieType N) { + DieType C; + DieType Vol; + DieType T; + decomposeConstVolatile(N, T, C, Vol); + 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) { + LLVM_QUICK_EXIT(V("const ")); + } + if (Vol) { + LLVM_QUICK_EXIT(V("volatile ")); + } + } + appendQualifiedNameBefore(T); + if (!Leading && !Subroutine) { + Word = true; + if (C) { + LLVM_QUICK_EXIT(V("const")); + } + if (Vol) { + if (C) { + LLVM_QUICK_EXIT(V(" ")); + } + LLVM_QUICK_EXIT(V("volatile")); + } + } + return true; +} +template +bool 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. + std::optional Inner = + appendUnqualifiedNameBefore(D, OriginalFullName); + LLVM_QUICK_EXIT(Inner); + LLVM_QUICK_EXIT(appendUnqualifiedNameAfter(D, *Inner)); + return true; +} +template +bool DWARFTypePrinter::appendSubroutineNameAfter( + DieType D, DieType Inner, bool SkipFirstParamIfArtificial, bool Const, + bool Volatile) { + DieType FirstParamIfArtificial; + LLVM_QUICK_EXIT(V("(")); + 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 true; + DieType T = detail::resolveReferencedType(P); + if (SkipFirstParamIfArtificial && RealFirst && P.find(dwarf::DW_AT_artificial)) { + FirstParamIfArtificial = T; + RealFirst = false; + continue; + } + if (!First) { + LLVM_QUICK_EXIT(V(", ")); + } + First = false; + if (P.getTag() == dwarf::DW_TAG_unspecified_parameters) { + LLVM_QUICK_EXIT(V("...")); + } else { + LLVM_QUICK_EXIT(appendQualifiedName(T)); + } + } + EndedWithTemplate = false; + LLVM_QUICK_EXIT(V(")")); + 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: + LLVM_QUICK_EXIT(V(" __attribute__((stdcall))")); + break; + case dwarf::CallingConvention::DW_CC_BORLAND_msfastcall: + LLVM_QUICK_EXIT(V(" __attribute__((fastcall))")); + break; + case dwarf::CallingConvention::DW_CC_BORLAND_thiscall: + LLVM_QUICK_EXIT(V(" __attribute__((thiscall))")); + break; + case dwarf::CallingConvention::DW_CC_LLVM_vectorcall: + LLVM_QUICK_EXIT(V(" __attribute__((vectorcall))")); + break; + case dwarf::CallingConvention::DW_CC_BORLAND_pascal: + LLVM_QUICK_EXIT(V(" __attribute__((pascal))")); + break; + case dwarf::CallingConvention::DW_CC_LLVM_Win64: + LLVM_QUICK_EXIT(V(" __attribute__((ms_abi))")); + break; + case dwarf::CallingConvention::DW_CC_LLVM_X86_64SysV: + LLVM_QUICK_EXIT(V(" __attribute__((sysv_abi))")); + break; + case dwarf::CallingConvention::DW_CC_LLVM_AAPCS: + // AArch64VectorCall missing? + LLVM_QUICK_EXIT(V(" __attribute__((pcs(\"aapcs\")))")); + break; + case dwarf::CallingConvention::DW_CC_LLVM_AAPCS_VFP: + LLVM_QUICK_EXIT(V(" __attribute__((pcs(\"aapcs-vfp\")))")); + break; + case dwarf::CallingConvention::DW_CC_LLVM_IntelOclBicc: + LLVM_QUICK_EXIT(V(" __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 + LLVM_QUICK_EXIT(V(" __attribute__((swiftcall))")); + break; + case dwarf::CallingConvention::DW_CC_LLVM_PreserveMost: + LLVM_QUICK_EXIT(V(" __attribute__((preserve_most))")); + break; + case dwarf::CallingConvention::DW_CC_LLVM_PreserveAll: + LLVM_QUICK_EXIT(V(" __attribute__((preserve_all))")); + break; + case dwarf::CallingConvention::DW_CC_LLVM_PreserveNone: + LLVM_QUICK_EXIT(V(" __attribute__((preserve_none))")); + break; + case dwarf::CallingConvention::DW_CC_LLVM_X86RegCall: + LLVM_QUICK_EXIT(V(" __attribute__((regcall))")); + break; + case dwarf::CallingConvention::DW_CC_LLVM_M68kRTD: + LLVM_QUICK_EXIT(V(" __attribute__((m68k_rtd))")); + break; + } + } + + if (Const) { + LLVM_QUICK_EXIT(V(" const")); + } + if (Volatile) { + LLVM_QUICK_EXIT(V(" volatile")); + } + if (D.find(dwarf::DW_AT_reference)) { + LLVM_QUICK_EXIT(V(" &")); + } + if (D.find(dwarf::DW_AT_rvalue_reference)) { + LLVM_QUICK_EXIT(V(" &&")); + } + + LLVM_QUICK_EXIT( + appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner))); + return true; +} +template +bool DWARFTypePrinter::appendScopes(DieType D) { + if (D.getTag() == dwarf::DW_TAG_compile_unit) + return true; + if (D.getTag() == dwarf::DW_TAG_type_unit) + return true; + if (D.getTag() == dwarf::DW_TAG_skeleton_unit) + return true; + if (D.getTag() == dwarf::DW_TAG_subprogram) + return true; + if (D.getTag() == dwarf::DW_TAG_lexical_block) + return true; + //D = D.resolveTypeUnitReference(); + if (DieType P = D.getParent()) { + LLVM_QUICK_EXIT(appendScopes(P)); + } + LLVM_QUICK_EXIT(appendUnqualifiedName(D)); + LLVM_QUICK_EXIT(V("::")); + return true; +} } // namespace llvm +#undef LLVM_QUICK_EXIT +#undef LLVM_QUICK_EXIT_NONE + #endif // LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index 410842a80b015..8686717e9e900 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -775,12 +775,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 index 05dee8a3d7129..e69de29bb2d1d 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp @@ -1,674 +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 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) - 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