From 2922fed151d345f12b944754fa10b9994acc7edb Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Fri, 19 Apr 2024 03:34:27 +0000 Subject: [PATCH 1/7] DO NOT SUBMIT: lldb DWARF-Clang AST parsing tracing --- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index dc4cfc96b86f0..971bddc3e7867 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include +#include #include "DWARFASTParser.h" #include "DWARFASTParserClang.h" @@ -1621,6 +1622,15 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) { const char *name = die.GetName(); if (!name) return ""; + 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; std::string qualified_name; DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE(); // TODO: change this to get the correct decl context parent.... @@ -1666,6 +1676,9 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) { qualified_name.append(name); qualified_name.append(GetDIEClassTemplateParams(die).AsCString("")); + --indent; + std::cerr << std::string(indent, ' ') << "computed qualified name: " << qualified_name << '\n'; + return qualified_name; } From b98e417de184ea44ce7a88241cd03f07be0e94ec Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Thu, 25 Apr 2024 00:28:57 +0000 Subject: [PATCH 2/7] Fix scope operator ordering --- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 971bddc3e7867..0c60589329371 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1655,9 +1655,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(); From 3966ec6c39262f5e055e9cb7deded5f6554a8d8d Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Thu, 25 Apr 2024 00:46:48 +0000 Subject: [PATCH 3/7] DO NOT SUBMIT: Really dodgy demonstration of DWARFTypePrinter reuse in lldb The hacks necessary to make lldb's DWARFDIE APIs sufficiently compatible with LLVM's DWARFDie API aren't shippable, but maybe somewhere to start the conversation. With all these changes, an internal example that would crash expanding too many types (computing the fully qualified name for 414671 types before crashing due to running out of stack) - but with these patches applied, it comes down to 856 expansions (compared to 848 for non-simplified template names inputs) --- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 11 + .../Plugins/SymbolFile/DWARF/DWARFBaseDIE.h | 10 + .../Plugins/SymbolFile/DWARF/DWARFDIE.cpp | 21 +- .../Plugins/SymbolFile/DWARF/DWARFDIE.h | 13 + .../Plugins/SymbolFile/DWARF/DWARFFormValue.h | 37 + .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 24 +- llvm/include/llvm-c/Error.h | 8 + llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h | 2 + .../llvm/DebugInfo/DWARF/DWARFFormValue.h | 7 +- .../llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 734 +++++++++++++++++- llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 4 +- llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp | 674 ---------------- 12 files changed, 830 insertions(+), 715 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 0c60589329371..a70d788f8eae8 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "DWARFASTParser.h" #include "DWARFASTParserClang.h" @@ -45,6 +46,8 @@ #include "clang/AST/Type.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h" + #include #include #include @@ -866,11 +869,19 @@ DWARFASTParserClang::GetDIEClassTemplateParams(const DWARFDIE &die) { if (llvm::StringRef(die.GetName()).contains("<")) return ConstString(); +#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, 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..23eeaa0c937f5 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,16 @@ 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; +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index 511ca62d0197a..e3e2f725cfdf6 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 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..9500096a9f5b6 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3219,31 +3219,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..abc0ab8e27976 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/DWARFDie.h" #include @@ -21,7 +20,7 @@ class raw_ostream; // 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 +30,734 @@ 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 = "dwarf::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, 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 +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 = 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 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) { + 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; + appendAndTerminateTemplateParameters(D); + break; + } + } + return InnerDIE; +} + +template +void DWARFTypePrinter::appendAndTerminateTemplateParameters(DieType D) { + if (!appendTemplateParameters(D)) + return; + + if (EndedWithTemplate) + OS << ' '; + OS << '>'; + EndedWithTemplate = true; + Word = true; +} + +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 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; + } +} + +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 +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 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 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 dwarf::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 = + 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::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/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 From ff1d538fac78dae91e8e4599767a1159a7e0359d Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Mon, 29 Apr 2024 18:28:59 +0000 Subject: [PATCH 4/7] More prototyping --- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index a70d788f8eae8..f7c33f39a8a89 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -869,6 +869,7 @@ 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); @@ -1633,6 +1634,7 @@ 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(); @@ -1642,6 +1644,7 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) { << 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.... @@ -1687,8 +1690,10 @@ 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; } From ae672eddc50312604876f1c8948022f10fd56c91 Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Fri, 31 May 2024 22:08:03 +0000 Subject: [PATCH 5/7] Another case of string comparison rather than AST comparison --- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 38 ++++++------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 9500096a9f5b6..94283adeee960 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,15 @@ 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()); - } + std::string R; + llvm::raw_string_ostream OS(R); + llvm::DWARFTypePrinter p(OS); + p.appendQualifiedName(die); + + TypeQuery die_query(R, TypeQueryOptions::e_exact_match); + if (query.ContextMatches(die_query.GetContextRef())) + 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)) From 5da641c7e7c4ac638fde003a571ac6da74dc8cd2 Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Wed, 5 Jun 2024 23:35:35 +0000 Subject: [PATCH 6/7] Perform DIE-to-string comparison Rough prototype, doesn't handle namespace/context --- lldb/include/lldb/Symbol/Type.h | 3 + .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 15 +- .../llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 327 ++++++++++-------- 3 files changed, 194 insertions(+), 151 deletions(-) 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/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 94283adeee960..c8cf87cfb549d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2787,15 +2787,20 @@ void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) { return true; // Keep iterating over index types, language mismatch. } - std::string R; - llvm::raw_string_ostream OS(R); - llvm::DWARFTypePrinter p(OS); + 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); + }; + llvm::DWARFTypePrinter p(Visitor); p.appendQualifiedName(die); - TypeQuery die_query(R, TypeQueryOptions::e_exact_match); - if (query.ContextMatches(die_query.GetContextRef())) + 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)) diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h index abc0ab8e27976..59f1b2f6ee921 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h @@ -11,6 +11,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/ADT/SmallString.h" #include @@ -18,14 +19,48 @@ namespace llvm { class raw_ostream; +namespace detail { +struct DefaultVisitor { + raw_ostream &OS; + DefaultVisitor(raw_ostream &OS) : OS(OS) { } + void operator()(StringRef S) const { + OS << S; + } +}; + +inline llvm::SmallString<128> toString(const llvm::format_object_base &Fmt) { + size_t NextBufferSize = 127; + llvm::SmallString<128> V; + + while (true) { + V.resize(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) + return V; + + // Otherwise, try again with a new size. + assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?"); + NextBufferSize = BytesUsed; + } +} +} + // 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; +template +struct DWARFTypePrinter { + 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); @@ -61,20 +96,20 @@ template struct DWARFTypePrinter { void appendScopes(DieType D); }; -template -void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) { +template +void 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; - OS << TagStr.substr(Prefix.size(), - TagStr.size() - (Prefix.size() + Suffix.size())) - << " "; + V(TagStr.substr(Prefix.size(), + TagStr.size() - (Prefix.size() + Suffix.size()))); + V(" "); } -template -void DWARFTypePrinter::appendArrayType(const DieType &D) { +template +void DWARFTypePrinter::appendArrayType(const DieType &D) { for (const DieType &C : D.children()) { if (C.getTag() != dwarf::DW_TAG_subrange_type) continue; @@ -98,26 +133,26 @@ void DWARFTypePrinter::appendArrayType(const DieType &D) { LB = std::nullopt; */ if (!LB && !Count && !UB) - OS << "[]"; + V("[]"); else if (!LB && (Count || UB) && DefaultLB) - OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']'; + V("["), V(Twine(Count ? *Count : *UB - *DefaultLB + 1).str()), V("]"); else { - OS << "[["; + V("[["); if (LB) - OS << *LB; + V(Twine(*LB).str()); else - OS << '?'; - OS << ", "; + V("?"); + V(", "); if (Count) if (LB) - OS << *LB + *Count; + V(Twine(*LB + *Count).str()); else - OS << "? + " << *Count; + V("? + "), V(Twine(*Count).str()); else if (UB) - OS << *UB + 1; + V(Twine(*UB + 1).str()); else - OS << '?'; - OS << ")]"; + V("?"); + V(")]"); } } EndedWithTemplate = false; @@ -135,41 +170,41 @@ DieType resolveReferencedType(DieType D, typename DieType::DWARFFormValue F) { } } // namespace detail -template -DieType DWARFTypePrinter::skipQualifiers(DieType D) { +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) { +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, +template +void DWARFTypePrinter::appendPointerLikeTypeBefore(DieType D, DieType Inner, StringRef Ptr) { appendQualifiedNameBefore(Inner); if (Word) - OS << ' '; + V(" "); if (needsParens(Inner)) - OS << '('; - OS << Ptr; + V("("); + V(Ptr); Word = false; EndedWithTemplate = false; } -template -DieType DWARFTypePrinter::appendUnqualifiedNameBefore( +template +DieType DWARFTypePrinter::appendUnqualifiedNameBefore( DieType D, std::string *OriginalFullName) { Word = true; if (!D) { - OS << "void"; + V("void"); return DieType(); } DieType InnerDIE; @@ -183,7 +218,7 @@ DieType DWARFTypePrinter::appendUnqualifiedNameBefore( case dwarf::DW_TAG_subroutine_type: { appendQualifiedNameBefore(Inner()); if (Word) { - OS << ' '; + V(" "); } Word = false; break; @@ -201,15 +236,15 @@ DieType DWARFTypePrinter::appendUnqualifiedNameBefore( case dwarf::DW_TAG_ptr_to_member_type: { appendQualifiedNameBefore(Inner()); if (needsParens(InnerDIE)) - OS << '('; + V("("); else if (Word) - OS << ' '; + V(" "); if (DieType Cont = detail::resolveReferencedType(D, dwarf::DW_AT_containing_type)) { appendQualifiedName(Cont); EndedWithTemplate = false; - OS << "::"; + V("::"); } - OS << "*"; + V("*"); Word = false; break; } @@ -222,9 +257,9 @@ DieType DWARFTypePrinter::appendUnqualifiedNameBefore( break; case dwarf::DW_TAG_namespace: { if (const char *Name = toString(D.find(dwarf::DW_AT_name), nullptr)) - OS << Name; + V(Name); else - OS << "(anonymous namespace)"; + V("(anonymous namespace)"); break; } case dwarf::DW_TAG_unspecified_type: { @@ -232,7 +267,7 @@ DieType DWARFTypePrinter::appendUnqualifiedNameBefore( if (TypeName == "decltype(nullptr)") TypeName = "std::nullptr_t"; Word = true; - OS << TypeName; + V(TypeName); EndedWithTemplate = false; break; } @@ -261,7 +296,7 @@ DieType DWARFTypePrinter::appendUnqualifiedNameBefore( Name = BaseName; } else EndedWithTemplate = Name.ends_with(">"); - OS << Name; + 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. @@ -274,20 +309,20 @@ DieType DWARFTypePrinter::appendUnqualifiedNameBefore( return InnerDIE; } -template -void DWARFTypePrinter::appendAndTerminateTemplateParameters(DieType D) { +template +void DWARFTypePrinter::appendAndTerminateTemplateParameters(DieType D) { if (!appendTemplateParameters(D)) return; if (EndedWithTemplate) - OS << ' '; - OS << '>'; + V(" "); + V(">"); EndedWithTemplate = true; Word = true; } -template -void DWARFTypePrinter::appendUnqualifiedNameAfter( +template +void DWARFTypePrinter::appendUnqualifiedNameAfter( DieType D, DieType Inner, bool SkipFirstParamIfArtificial) { if (!D) return; @@ -310,7 +345,7 @@ void DWARFTypePrinter::appendUnqualifiedNameAfter( case dwarf::DW_TAG_rvalue_reference_type: case dwarf::DW_TAG_pointer_type: { if (needsParens(Inner)) - OS << ')'; + V(")"); appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner), /*SkipFirstParamIfArtificial=*/D.getTag() == dwarf::DW_TAG_ptr_to_member_type); @@ -357,7 +392,7 @@ void DWARFTypePrinter::appendUnqualifiedNameAfter( << getValOrNull(dwarf::DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0" << utohexstr(getValOrNull(dwarf::DW_AT_LLVM_ptrauth_extra_discriminator), true) << options << ")"; - OS << PtrauthStream.str(); + V(PtrauthStream.str()); break; } /* @@ -388,20 +423,20 @@ inline bool scopedTAGs(dwarf::Tag Tag) { return false; } } // namespace detail -template -void DWARFTypePrinter::appendQualifiedName(DieType D) { +template +void DWARFTypePrinter::appendQualifiedName(DieType D) { if (D && detail::scopedTAGs(D.getTag())) appendScopes(D.getParent()); appendUnqualifiedName(D); } -template -DieType DWARFTypePrinter::appendQualifiedNameBefore(DieType 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, +template +bool DWARFTypePrinter::appendTemplateParameters(DieType D, bool *FirstParameter) { bool FirstParameterValue = true; bool IsTemplate = false; @@ -410,9 +445,9 @@ bool DWARFTypePrinter::appendTemplateParameters(DieType D, for (const DieType &C : D) { auto Sep = [&] { if (*FirstParameter) - OS << '<'; + V("<"); else - OS << ", "; + V(", "); IsTemplate = true; EndedWithTemplate = false; *FirstParameter = false; @@ -425,11 +460,11 @@ bool DWARFTypePrinter::appendTemplateParameters(DieType D, DieType T = detail::resolveReferencedType(C); Sep(); if (T.getTag() == dwarf::DW_TAG_enumeration_type) { - OS << '('; + V("("); appendQualifiedName(T); - OS << ')'; - auto V = C.find(dwarf::DW_AT_const_value); - OS << std::to_string(*V->getAsSignedConstant()); + V(")"); + auto Value = C.find(dwarf::DW_AT_const_value); + V(std::to_string(*Value->getAsSignedConstant())); continue; } // /Maybe/ we could do pointer type parameters, looking for the @@ -440,90 +475,90 @@ bool DWARFTypePrinter::appendTemplateParameters(DieType D, const char *RawName = toString(T.find(dwarf::DW_AT_name), nullptr); assert(RawName); StringRef Name = RawName; - auto V = C.find(dwarf::DW_AT_const_value); + auto Value = C.find(dwarf::DW_AT_const_value); bool IsQualifiedChar = false; if (Name == "bool") { - OS << (*V->getAsUnsignedConstant() ? "true" : "false"); + V((*Value->getAsUnsignedConstant() ? "true" : "false")); } else if (Name == "short") { - OS << "(short)"; - OS << std::to_string(*V->getAsSignedConstant()); + V("(short)"); + V(std::to_string(*Value->getAsSignedConstant())); } else if (Name == "unsigned short") { - OS << "(unsigned short)"; - OS << std::to_string(*V->getAsSignedConstant()); + V("(unsigned short)"); + V(std::to_string(*Value->getAsSignedConstant())); } else if (Name == "int") - OS << std::to_string(*V->getAsSignedConstant()); + V(std::to_string(*Value->getAsSignedConstant())); else if (Name == "long") { - OS << std::to_string(*V->getAsSignedConstant()); - OS << "L"; + V(std::to_string(*Value->getAsSignedConstant())); + V("L"); } else if (Name == "long long") { - OS << std::to_string(*V->getAsSignedConstant()); - OS << "LL"; + V(std::to_string(*Value->getAsSignedConstant())); + V("LL"); } else if (Name == "unsigned int") { - OS << std::to_string(*V->getAsUnsignedConstant()); - OS << "U"; + V(std::to_string(*Value->getAsUnsignedConstant())); + V("U"); } else if (Name == "unsigned long") { - OS << std::to_string(*V->getAsUnsignedConstant()); - OS << "UL"; + V(std::to_string(*Value->getAsUnsignedConstant())); + V("UL"); } else if (Name == "unsigned long long") { - OS << std::to_string(*V->getAsUnsignedConstant()); - OS << "ULL"; + V(std::to_string(*Value->getAsUnsignedConstant())); + 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 = *V->getAsSignedConstant(); + 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) { - OS << '('; - OS << Name; - OS << ')'; + V("("); + V(Name); + V(")"); } switch (Val) { case '\\': - OS << "'\\\\'"; + V("'\\\\'"); break; case '\'': - OS << "'\\''"; + V("'\\''"); break; case '\a': // TODO: K&R: the meaning of '\\a' is different in traditional C - OS << "'\\a'"; + V("'\\a'"); break; case '\b': - OS << "'\\b'"; + V("'\\b'"); break; case '\f': - OS << "'\\f'"; + V("'\\f'"); break; case '\n': - OS << "'\\n'"; + V("'\\n'"); break; case '\r': - OS << "'\\r'"; + V("'\\r'"); break; case '\t': - OS << "'\\t'"; + V("'\\t'"); break; case '\v': - OS << "'\\v'"; + V("'\\v'"); break; default: if ((Val & ~0xFFu) == ~0xFFu) Val &= 0xFFu; if (Val < 127 && Val >= 32) { - OS << "'"; - OS << (char)Val; - OS << "'"; + V("'"); + V(Twine((char)Val).str()); + V("'"); } else if (Val < 256) - OS << llvm::format("'\\x%02" PRIx64 "'", Val); + V(detail::toString(llvm::format("'\\x%02" PRIx64 "'", Val))); else if (Val <= 0xFFFF) - OS << llvm::format("'\\u%04" PRIx64 "'", Val); + V(detail::toString(llvm::format("'\\u%04" PRIx64 "'", Val))); else - OS << llvm::format("'\\U%08" PRIx64 "'", Val); + V(detail::toString(llvm::format("'\\U%08" PRIx64 "'", Val))); } } continue; @@ -534,7 +569,7 @@ bool DWARFTypePrinter::appendTemplateParameters(DieType D, assert(RawName); StringRef Name = RawName; Sep(); - OS << Name; + V(Name); continue; } if (C.getTag() != dwarf::DW_TAG_template_type_parameter) @@ -545,13 +580,13 @@ bool DWARFTypePrinter::appendTemplateParameters(DieType D, : DieType()); } if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) { - OS << '<'; + V("<"); EndedWithTemplate = false; } return IsTemplate; } -template -void DWARFTypePrinter::decomposeConstVolatile(DieType &N, DieType &T, +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); @@ -566,8 +601,8 @@ void DWARFTypePrinter::decomposeConstVolatile(DieType &N, DieType &T, } } } -template -void DWARFTypePrinter::appendConstVolatileQualifierAfter(DieType N) { +template +void DWARFTypePrinter::appendConstVolatileQualifierAfter(DieType N) { DieType C; DieType V; DieType T; @@ -578,12 +613,12 @@ void DWARFTypePrinter::appendConstVolatileQualifierAfter(DieType N) { else appendUnqualifiedNameAfter(T, detail::resolveReferencedType(T)); } -template -void DWARFTypePrinter::appendConstVolatileQualifierBefore(DieType N) { +template +void DWARFTypePrinter::appendConstVolatileQualifierBefore(DieType N) { DieType C; - DieType V; + DieType Vol; DieType T; - decomposeConstVolatile(N, T, C, V); + 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) @@ -594,36 +629,36 @@ void DWARFTypePrinter::appendConstVolatileQualifierBefore(DieType N) { !Subroutine; if (Leading) { if (C) - OS << "const "; - if (V) - OS << "volatile "; + V("const "); + if (Vol) + V("volatile "); } appendQualifiedNameBefore(T); if (!Leading && !Subroutine) { Word = true; if (C) - OS << "const"; - if (V) { + V("const"); + if (Vol) { if (C) - OS << ' '; - OS << "volatile"; + V(" "); + V("volatile"); } } } -template -void DWARFTypePrinter::appendUnqualifiedName( +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( +template +void DWARFTypePrinter::appendSubroutineNameAfter( DieType D, DieType Inner, bool SkipFirstParamIfArtificial, bool Const, bool Volatile) { DieType FirstParamIfArtificial; - OS << '('; + V("("); EndedWithTemplate = false; bool First = true; bool RealFirst = true; @@ -638,16 +673,16 @@ void DWARFTypePrinter::appendSubroutineNameAfter( continue; } if (!First) { - OS << ", "; + V(", "); } First = false; if (P.getTag() == dwarf::DW_TAG_unspecified_parameters) - OS << "..."; + V("..."); else appendQualifiedName(T); } EndedWithTemplate = false; - OS << ')'; + V(")"); if (FirstParamIfArtificial) { if (DieType P = FirstParamIfArtificial) { if (P.getTag() == dwarf::DW_TAG_pointer_type) { @@ -669,35 +704,35 @@ void DWARFTypePrinter::appendSubroutineNameAfter( if (auto CC = D.find(dwarf::DW_AT_calling_convention)) { switch (*CC->getAsUnsignedConstant()) { case dwarf::CallingConvention::DW_CC_BORLAND_stdcall: - OS << " __attribute__((stdcall))"; + V(" __attribute__((stdcall))"); break; case dwarf::CallingConvention::DW_CC_BORLAND_msfastcall: - OS << " __attribute__((fastcall))"; + V(" __attribute__((fastcall))"); break; case dwarf::CallingConvention::DW_CC_BORLAND_thiscall: - OS << " __attribute__((thiscall))"; + V(" __attribute__((thiscall))"); break; case dwarf::CallingConvention::DW_CC_LLVM_vectorcall: - OS << " __attribute__((vectorcall))"; + V(" __attribute__((vectorcall))"); break; case dwarf::CallingConvention::DW_CC_BORLAND_pascal: - OS << " __attribute__((pascal))"; + V(" __attribute__((pascal))"); break; case dwarf::CallingConvention::DW_CC_LLVM_Win64: - OS << " __attribute__((ms_abi))"; + V(" __attribute__((ms_abi))"); break; case dwarf::CallingConvention::DW_CC_LLVM_X86_64SysV: - OS << " __attribute__((sysv_abi))"; + V(" __attribute__((sysv_abi))"); break; case dwarf::CallingConvention::DW_CC_LLVM_AAPCS: // AArch64VectorCall missing? - OS << " __attribute__((pcs(\"aapcs\")))"; + V(" __attribute__((pcs(\"aapcs\")))"); break; case dwarf::CallingConvention::DW_CC_LLVM_AAPCS_VFP: - OS << " __attribute__((pcs(\"aapcs-vfp\")))"; + V(" __attribute__((pcs(\"aapcs-vfp\")))"); break; case dwarf::CallingConvention::DW_CC_LLVM_IntelOclBicc: - OS << " __attribute__((intel_ocl_bicc))"; + V(" __attribute__((intel_ocl_bicc))"); break; case dwarf::CallingConvention::DW_CC_LLVM_SpirFunction: case dwarf::CallingConvention::DW_CC_LLVM_OpenCLKernel: @@ -709,39 +744,39 @@ void DWARFTypePrinter::appendSubroutineNameAfter( break; case dwarf::CallingConvention::DW_CC_LLVM_Swift: // SwiftAsync missing - OS << " __attribute__((swiftcall))"; + V(" __attribute__((swiftcall))"); break; case dwarf::CallingConvention::DW_CC_LLVM_PreserveMost: - OS << " __attribute__((preserve_most))"; + V(" __attribute__((preserve_most))"); break; case dwarf::CallingConvention::DW_CC_LLVM_PreserveAll: - OS << " __attribute__((preserve_all))"; + V(" __attribute__((preserve_all))"); break; case dwarf::CallingConvention::DW_CC_LLVM_PreserveNone: - OS << " __attribute__((preserve_none))"; + V(" __attribute__((preserve_none))"); break; case dwarf::CallingConvention::DW_CC_LLVM_X86RegCall: - OS << " __attribute__((regcall))"; + V(" __attribute__((regcall))"); break; case dwarf::CallingConvention::DW_CC_LLVM_M68kRTD: - OS << " __attribute__((m68k_rtd))"; + V(" __attribute__((m68k_rtd))"); break; } } if (Const) - OS << " const"; + V(" const"); if (Volatile) - OS << " volatile"; + V(" volatile"); if (D.find(dwarf::DW_AT_reference)) - OS << " &"; + V(" &"); if (D.find(dwarf::DW_AT_rvalue_reference)) - OS << " &&"; + V(" &&"); appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner)); } -template -void DWARFTypePrinter::appendScopes(DieType D) { +template +void DWARFTypePrinter::appendScopes(DieType D) { if (D.getTag() == dwarf::DW_TAG_compile_unit) return; if (D.getTag() == dwarf::DW_TAG_type_unit) @@ -756,7 +791,7 @@ void DWARFTypePrinter::appendScopes(DieType D) { if (DieType P = D.getParent()) appendScopes(P); appendUnqualifiedName(D); - OS << "::"; + V("::"); } } // namespace llvm From 334301ae2ede954c21bc7f228d079341ea372b5a Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Fri, 7 Jun 2024 20:20:38 +0000 Subject: [PATCH 7/7] DIE-to-consumer (string, in this case) matching, with quick exit on failure --- .../Plugins/SymbolFile/DWARF/DWARFDIE.cpp | 7 + .../Plugins/SymbolFile/DWARF/DWARFDIE.h | 4 + .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 1 + .../llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 498 ++++++++++-------- 4 files changed, 288 insertions(+), 222 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index 23eeaa0c937f5..a3d6237ada87b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -564,3 +564,10 @@ std::optional DWARFDIE::find(const dw_attr_t attr) const { 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 e3e2f725cfdf6..ae32f980db241 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -156,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/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index c8cf87cfb549d..dacf2ce6094c1 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2793,6 +2793,7 @@ void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) { 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); diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h index 59f1b2f6ee921..698eaf822afc3 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h @@ -19,12 +19,20 @@ 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) { } - void operator()(StringRef S) const { + bool operator()(StringRef S) const { OS << S; + return true; } }; @@ -33,14 +41,16 @@ inline llvm::SmallString<128> toString(const llvm::format_object_base &Fmt) { llvm::SmallString<128> V; while (true) { - V.resize(NextBufferSize); + 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) + if (BytesUsed <= NextBufferSize) { + V.resize(BytesUsed); return V; + } // Otherwise, try again with a new size. assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?"); @@ -49,6 +59,9 @@ inline llvm::SmallString<128> toString(const llvm::format_object_base &Fmt) { } } +#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 @@ -63,99 +76,105 @@ struct DWARFTypePrinter { 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 DieType &D); + bool appendArrayType(const DieType &D); DieType skipQualifiers(DieType D); bool needsParens(DieType D); - void appendPointerLikeTypeBefore(DieType D, DieType Inner, StringRef Ptr); + bool appendPointerLikeTypeBefore(DieType D, DieType Inner, StringRef Ptr); - DieType appendUnqualifiedNameBefore(DieType D, - std::string *OriginalFullName = nullptr); + std::optional + appendUnqualifiedNameBefore(DieType D, + std::string *OriginalFullName = nullptr); - void appendUnqualifiedNameAfter(DieType D, DieType Inner, + bool appendUnqualifiedNameAfter(DieType D, DieType Inner, bool SkipFirstParamIfArtificial = false); - void appendQualifiedName(DieType D); - DieType appendQualifiedNameBefore(DieType D); - bool appendTemplateParameters(DieType D, bool *FirstParameter = nullptr); - void appendAndTerminateTemplateParameters(DieType D); + 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); - void appendConstVolatileQualifierAfter(DieType N); - void appendConstVolatileQualifierBefore(DieType N); + bool appendConstVolatileQualifierAfter(DieType N); + bool appendConstVolatileQualifierBefore(DieType N); /// Recursively append the DIE type name when applicable. - void appendUnqualifiedName(DieType D, + bool appendUnqualifiedName(DieType D, std::string *OriginalFullName = nullptr); - void appendSubroutineNameAfter(DieType D, DieType Inner, + bool appendSubroutineNameAfter(DieType D, DieType Inner, bool SkipFirstParamIfArtificial, bool Const, bool Volatile); - void appendScopes(DieType D); + bool appendScopes(DieType D); }; template -void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) { +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; - V(TagStr.substr(Prefix.size(), - TagStr.size() - (Prefix.size() + Suffix.size()))); - V(" "); + return true; + LLVM_QUICK_EXIT(V(TagStr.substr( + Prefix.size(), TagStr.size() - (Prefix.size() + Suffix.size())))); + LLVM_QUICK_EXIT(V(" ")); + return true; } template -void DWARFTypePrinter::appendArrayType(const DieType &D) { +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; + 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) - V("[]"); - else if (!LB && (Count || UB) && DefaultLB) - V("["), V(Twine(Count ? *Count : *UB - *DefaultLB + 1).str()), V("]"); - else { - V("[["); - if (LB) - V(Twine(*LB).str()); - else - V("?"); - V(", "); - if (Count) - if (LB) - V(Twine(*LB + *Count).str()); - else - V("? + "), V(Twine(*Count).str()); - else if (UB) - V(Twine(*UB + 1).str()); - else - V("?"); - V(")]"); + + 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 { @@ -186,25 +205,25 @@ bool DWARFTypePrinter::needsParens(DieType D) { } template -void DWARFTypePrinter::appendPointerLikeTypeBefore(DieType D, - DieType Inner, - StringRef Ptr) { - appendQualifiedNameBefore(Inner); +bool DWARFTypePrinter::appendPointerLikeTypeBefore( + DieType D, DieType Inner, StringRef Ptr) { + LLVM_QUICK_EXIT(appendQualifiedNameBefore(Inner)); if (Word) - V(" "); + LLVM_QUICK_EXIT(V(" ")); if (needsParens(Inner)) - V("("); - V(Ptr); + LLVM_QUICK_EXIT(V("(")); + LLVM_QUICK_EXIT(V(Ptr)); Word = false; EndedWithTemplate = false; + return true; } template -DieType DWARFTypePrinter::appendUnqualifiedNameBefore( +std::optional DWARFTypePrinter::appendUnqualifiedNameBefore( DieType D, std::string *OriginalFullName) { Word = true; if (!D) { - V("void"); + LLVM_QUICK_EXIT_NONE(V("void")); return DieType(); } DieType InnerDIE; @@ -212,54 +231,55 @@ DieType DWARFTypePrinter::appendUnqualifiedNameBefore( const dwarf::Tag T = D.getTag(); switch (T) { case dwarf::DW_TAG_pointer_type: { - appendPointerLikeTypeBefore(D, Inner(), "*"); + LLVM_QUICK_EXIT_NONE(appendPointerLikeTypeBefore(D, Inner(), "*")); break; } case dwarf::DW_TAG_subroutine_type: { - appendQualifiedNameBefore(Inner()); + LLVM_QUICK_EXIT_NONE(appendQualifiedNameBefore(Inner())); if (Word) { - V(" "); + LLVM_QUICK_EXIT_NONE(V(" ")); } Word = false; break; } case dwarf::DW_TAG_array_type: { - appendQualifiedNameBefore(Inner()); + LLVM_QUICK_EXIT_NONE(appendQualifiedNameBefore(Inner())); break; } case dwarf::DW_TAG_reference_type: - appendPointerLikeTypeBefore(D, Inner(), "&"); + LLVM_QUICK_EXIT_NONE(appendPointerLikeTypeBefore(D, Inner(), "&")); break; case dwarf::DW_TAG_rvalue_reference_type: - appendPointerLikeTypeBefore(D, Inner(), "&&"); + LLVM_QUICK_EXIT_NONE(appendPointerLikeTypeBefore(D, Inner(), "&&")); break; case dwarf::DW_TAG_ptr_to_member_type: { - appendQualifiedNameBefore(Inner()); - if (needsParens(InnerDIE)) - V("("); - else if (Word) - V(" "); - if (DieType Cont = detail::resolveReferencedType(D, dwarf::DW_AT_containing_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; - V("::"); + LLVM_QUICK_EXIT_NONE(V("::")); } - V("*"); + LLVM_QUICK_EXIT_NONE(V("*")); Word = false; break; } case dwarf::DW_TAG_LLVM_ptrauth_type: - appendQualifiedNameBefore(Inner()); + LLVM_QUICK_EXIT_NONE(appendQualifiedNameBefore(Inner())); break; case dwarf::DW_TAG_const_type: case dwarf::DW_TAG_volatile_type: - appendConstVolatileQualifierBefore(D); + LLVM_QUICK_EXIT_NONE(appendConstVolatileQualifierBefore(D)); break; case dwarf::DW_TAG_namespace: { - if (const char *Name = toString(D.find(dwarf::DW_AT_name), nullptr)) - V(Name); - else - V("(anonymous 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: { @@ -267,7 +287,7 @@ DieType DWARFTypePrinter::appendUnqualifiedNameBefore( if (TypeName == "decltype(nullptr)") TypeName = "std::nullptr_t"; Word = true; - V(TypeName); + LLVM_QUICK_EXIT_NONE(V(TypeName)); EndedWithTemplate = false; break; } @@ -280,7 +300,7 @@ DieType DWARFTypePrinter::appendUnqualifiedNameBefore( default: { const char *NamePtr = toString(D.find(dwarf::DW_AT_name), nullptr); if (!NamePtr) { - appendTypeTagName(D.getTag()); + LLVM_QUICK_EXIT_NONE(appendTypeTagName(D.getTag())); return DieType(); } Word = true; @@ -296,13 +316,13 @@ DieType DWARFTypePrinter::appendUnqualifiedNameBefore( Name = BaseName; } else EndedWithTemplate = Name.ends_with(">"); - V(Name); + 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; - appendAndTerminateTemplateParameters(D); + LLVM_QUICK_EXIT_NONE(appendAndTerminateTemplateParameters(D)); break; } } @@ -310,42 +330,46 @@ DieType DWARFTypePrinter::appendUnqualifiedNameBefore( } template -void DWARFTypePrinter::appendAndTerminateTemplateParameters(DieType D) { - if (!appendTemplateParameters(D)) - return; +bool DWARFTypePrinter::appendAndTerminateTemplateParameters(DieType D) { + std::optional R = appendTemplateParameters(D); + if (!R) + return false; + if (!*R) + return true; if (EndedWithTemplate) - V(" "); - V(">"); + LLVM_QUICK_EXIT(V(" ")); + LLVM_QUICK_EXIT(V(">")); EndedWithTemplate = true; Word = true; + return true; } template -void DWARFTypePrinter::appendUnqualifiedNameAfter( +bool DWARFTypePrinter::appendUnqualifiedNameAfter( DieType D, DieType Inner, bool SkipFirstParamIfArtificial) { if (!D) - return; + return true; switch (D.getTag()) { case dwarf::DW_TAG_subroutine_type: { - appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false, - false); + LLVM_QUICK_EXIT(appendSubroutineNameAfter( + D, Inner, SkipFirstParamIfArtificial, false, false)); break; } case dwarf::DW_TAG_array_type: { - appendArrayType(D); + LLVM_QUICK_EXIT(appendArrayType(D)); break; } case dwarf::DW_TAG_const_type: case dwarf::DW_TAG_volatile_type: - appendConstVolatileQualifierAfter(D); + 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)) - V(")"); + LLVM_QUICK_EXIT(V(")")); appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner), /*SkipFirstParamIfArtificial=*/D.getTag() == dwarf::DW_TAG_ptr_to_member_type); @@ -392,7 +416,7 @@ void DWARFTypePrinter::appendUnqualifiedNameAfter( << getValOrNull(dwarf::DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0" << utohexstr(getValOrNull(dwarf::DW_AT_LLVM_ptrauth_extra_discriminator), true) << options << ")"; - V(PtrauthStream.str()); + LLVM_QUICK_EXIT(V(PtrauthStream.str())); break; } /* @@ -405,6 +429,7 @@ void DWARFTypePrinter::appendUnqualifiedNameAfter( default: break; } + return true; } namespace detail { @@ -424,33 +449,37 @@ inline bool scopedTAGs(dwarf::Tag Tag) { } } // namespace detail template -void DWARFTypePrinter::appendQualifiedName(DieType D) { +bool DWARFTypePrinter::appendQualifiedName(DieType D) { if (D && detail::scopedTAGs(D.getTag())) - appendScopes(D.getParent()); - appendUnqualifiedName(D); + LLVM_QUICK_EXIT(appendScopes(D.getParent())); + LLVM_QUICK_EXIT(appendUnqualifiedName(D)); + return true; } template -DieType DWARFTypePrinter::appendQualifiedNameBefore(DieType D) { +std::optional DWARFTypePrinter::appendQualifiedNameBefore(DieType D) { if (D && detail::scopedTAGs(D.getTag())) - appendScopes(D.getParent()); + LLVM_QUICK_EXIT_NONE(appendScopes(D.getParent())); return appendUnqualifiedNameBefore(D); } template -bool DWARFTypePrinter::appendTemplateParameters(DieType D, - bool *FirstParameter) { +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) - V("<"); - else - V(", "); + 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; @@ -458,13 +487,13 @@ bool DWARFTypePrinter::appendTemplateParameters(DieType D, } if (C.getTag() == dwarf::DW_TAG_template_value_parameter) { DieType T = detail::resolveReferencedType(C); - Sep(); + LLVM_QUICK_EXIT_NONE(Sep()); if (T.getTag() == dwarf::DW_TAG_enumeration_type) { - V("("); + LLVM_QUICK_EXIT_NONE(V("(")); appendQualifiedName(T); - V(")"); + LLVM_QUICK_EXIT_NONE(V(")")); auto Value = C.find(dwarf::DW_AT_const_value); - V(std::to_string(*Value->getAsSignedConstant())); + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsSignedConstant()))); continue; } // /Maybe/ we could do pointer type parameters, looking for the @@ -478,30 +507,30 @@ bool DWARFTypePrinter::appendTemplateParameters(DieType D, auto Value = C.find(dwarf::DW_AT_const_value); bool IsQualifiedChar = false; if (Name == "bool") { - V((*Value->getAsUnsignedConstant() ? "true" : "false")); + LLVM_QUICK_EXIT_NONE(V((*Value->getAsUnsignedConstant() ? "true" : "false"))); } else if (Name == "short") { - V("(short)"); - V(std::to_string(*Value->getAsSignedConstant())); + LLVM_QUICK_EXIT_NONE(V("(short)")); + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsSignedConstant()))); } else if (Name == "unsigned short") { - V("(unsigned short)"); - V(std::to_string(*Value->getAsSignedConstant())); - } else if (Name == "int") - V(std::to_string(*Value->getAsSignedConstant())); - else if (Name == "long") { - V(std::to_string(*Value->getAsSignedConstant())); - V("L"); + 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") { - V(std::to_string(*Value->getAsSignedConstant())); - V("LL"); + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsSignedConstant()))); + LLVM_QUICK_EXIT_NONE(V("LL")); } else if (Name == "unsigned int") { - V(std::to_string(*Value->getAsUnsignedConstant())); - V("U"); + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsUnsignedConstant()))); + LLVM_QUICK_EXIT_NONE(V("U")); } else if (Name == "unsigned long") { - V(std::to_string(*Value->getAsUnsignedConstant())); - V("UL"); + LLVM_QUICK_EXIT_NONE(V(std::to_string(*Value->getAsUnsignedConstant()))); + LLVM_QUICK_EXIT_NONE(V("UL")); } else if (Name == "unsigned long long") { - V(std::to_string(*Value->getAsUnsignedConstant())); - V("ULL"); + 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"))) { @@ -513,52 +542,55 @@ bool DWARFTypePrinter::appendTemplateParameters(DieType D, // 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) { - V("("); - V(Name); - V(")"); + LLVM_QUICK_EXIT_NONE(V("(")); + LLVM_QUICK_EXIT_NONE(V(Name)); + LLVM_QUICK_EXIT_NONE(V(")")); } switch (Val) { case '\\': - V("'\\\\'"); + LLVM_QUICK_EXIT_NONE(V("'\\\\'")); break; case '\'': - V("'\\''"); + LLVM_QUICK_EXIT_NONE(V("'\\''")); break; case '\a': // TODO: K&R: the meaning of '\\a' is different in traditional C - V("'\\a'"); + LLVM_QUICK_EXIT_NONE(V("'\\a'")); break; case '\b': - V("'\\b'"); + LLVM_QUICK_EXIT_NONE(V("'\\b'")); break; case '\f': - V("'\\f'"); + LLVM_QUICK_EXIT_NONE(V("'\\f'")); break; case '\n': - V("'\\n'"); + LLVM_QUICK_EXIT_NONE(V("'\\n'")); break; case '\r': - V("'\\r'"); + LLVM_QUICK_EXIT_NONE(V("'\\r'")); break; case '\t': - V("'\\t'"); + LLVM_QUICK_EXIT_NONE(V("'\\t'")); break; case '\v': - V("'\\v'"); + LLVM_QUICK_EXIT_NONE(V("'\\v'")); break; default: if ((Val & ~0xFFu) == ~0xFFu) Val &= 0xFFu; if (Val < 127 && Val >= 32) { - V("'"); - V(Twine((char)Val).str()); - V("'"); - } else if (Val < 256) - V(detail::toString(llvm::format("'\\x%02" PRIx64 "'", Val))); - else if (Val <= 0xFFFF) - V(detail::toString(llvm::format("'\\u%04" PRIx64 "'", Val))); - else - V(detail::toString(llvm::format("'\\U%08" PRIx64 "'", Val))); + 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; @@ -568,19 +600,19 @@ bool DWARFTypePrinter::appendTemplateParameters(DieType D, toString(C.find(dwarf::DW_AT_GNU_template_name), nullptr); assert(RawName); StringRef Name = RawName; - Sep(); - V(Name); + 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); - Sep(); + LLVM_QUICK_EXIT_NONE(Sep()); appendQualifiedName(TypeAttr ? detail::resolveReferencedType(C, *TypeAttr) : DieType()); } if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) { - V("<"); + LLVM_QUICK_EXIT_NONE(V("<")); EndedWithTemplate = false; } return IsTemplate; @@ -602,19 +634,21 @@ void DWARFTypePrinter::decomposeConstVolatile(DieType &N, DieT } } template -void DWARFTypePrinter::appendConstVolatileQualifierAfter(DieType N) { +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) - appendSubroutineNameAfter(T, detail::resolveReferencedType(T), false, C.isValid(), - V.isValid()); - else - appendUnqualifiedNameAfter(T, detail::resolveReferencedType(T)); + 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 -void DWARFTypePrinter::appendConstVolatileQualifierBefore(DieType N) { +bool DWARFTypePrinter::appendConstVolatileQualifierBefore(DieType N) { DieType C; DieType Vol; DieType T; @@ -628,44 +662,52 @@ void DWARFTypePrinter::appendConstVolatileQualifierBefore(DieT A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) && !Subroutine; if (Leading) { - if (C) - V("const "); - if (Vol) - V("volatile "); + if (C) { + LLVM_QUICK_EXIT(V("const ")); + } + if (Vol) { + LLVM_QUICK_EXIT(V("volatile ")); + } } appendQualifiedNameBefore(T); if (!Leading && !Subroutine) { Word = true; - if (C) - V("const"); + if (C) { + LLVM_QUICK_EXIT(V("const")); + } if (Vol) { - if (C) - V(" "); - V("volatile"); + if (C) { + LLVM_QUICK_EXIT(V(" ")); + } + LLVM_QUICK_EXIT(V("volatile")); } } + return true; } template -void DWARFTypePrinter::appendUnqualifiedName( +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. - DieType Inner = appendUnqualifiedNameBefore(D, OriginalFullName); - appendUnqualifiedNameAfter(D, Inner); + std::optional Inner = + appendUnqualifiedNameBefore(D, OriginalFullName); + LLVM_QUICK_EXIT(Inner); + LLVM_QUICK_EXIT(appendUnqualifiedNameAfter(D, *Inner)); + return true; } template -void DWARFTypePrinter::appendSubroutineNameAfter( +bool DWARFTypePrinter::appendSubroutineNameAfter( DieType D, DieType Inner, bool SkipFirstParamIfArtificial, bool Const, bool Volatile) { DieType FirstParamIfArtificial; - V("("); + 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; + return true; DieType T = detail::resolveReferencedType(P); if (SkipFirstParamIfArtificial && RealFirst && P.find(dwarf::DW_AT_artificial)) { FirstParamIfArtificial = T; @@ -673,16 +715,17 @@ void DWARFTypePrinter::appendSubroutineNameAfter( continue; } if (!First) { - V(", "); + LLVM_QUICK_EXIT(V(", ")); } First = false; - if (P.getTag() == dwarf::DW_TAG_unspecified_parameters) - V("..."); - else - appendQualifiedName(T); + if (P.getTag() == dwarf::DW_TAG_unspecified_parameters) { + LLVM_QUICK_EXIT(V("...")); + } else { + LLVM_QUICK_EXIT(appendQualifiedName(T)); + } } EndedWithTemplate = false; - V(")"); + LLVM_QUICK_EXIT(V(")")); if (FirstParamIfArtificial) { if (DieType P = FirstParamIfArtificial) { if (P.getTag() == dwarf::DW_TAG_pointer_type) { @@ -704,35 +747,35 @@ void DWARFTypePrinter::appendSubroutineNameAfter( if (auto CC = D.find(dwarf::DW_AT_calling_convention)) { switch (*CC->getAsUnsignedConstant()) { case dwarf::CallingConvention::DW_CC_BORLAND_stdcall: - V(" __attribute__((stdcall))"); + LLVM_QUICK_EXIT(V(" __attribute__((stdcall))")); break; case dwarf::CallingConvention::DW_CC_BORLAND_msfastcall: - V(" __attribute__((fastcall))"); + LLVM_QUICK_EXIT(V(" __attribute__((fastcall))")); break; case dwarf::CallingConvention::DW_CC_BORLAND_thiscall: - V(" __attribute__((thiscall))"); + LLVM_QUICK_EXIT(V(" __attribute__((thiscall))")); break; case dwarf::CallingConvention::DW_CC_LLVM_vectorcall: - V(" __attribute__((vectorcall))"); + LLVM_QUICK_EXIT(V(" __attribute__((vectorcall))")); break; case dwarf::CallingConvention::DW_CC_BORLAND_pascal: - V(" __attribute__((pascal))"); + LLVM_QUICK_EXIT(V(" __attribute__((pascal))")); break; case dwarf::CallingConvention::DW_CC_LLVM_Win64: - V(" __attribute__((ms_abi))"); + LLVM_QUICK_EXIT(V(" __attribute__((ms_abi))")); break; case dwarf::CallingConvention::DW_CC_LLVM_X86_64SysV: - V(" __attribute__((sysv_abi))"); + LLVM_QUICK_EXIT(V(" __attribute__((sysv_abi))")); break; case dwarf::CallingConvention::DW_CC_LLVM_AAPCS: // AArch64VectorCall missing? - V(" __attribute__((pcs(\"aapcs\")))"); + LLVM_QUICK_EXIT(V(" __attribute__((pcs(\"aapcs\")))")); break; case dwarf::CallingConvention::DW_CC_LLVM_AAPCS_VFP: - V(" __attribute__((pcs(\"aapcs-vfp\")))"); + LLVM_QUICK_EXIT(V(" __attribute__((pcs(\"aapcs-vfp\")))")); break; case dwarf::CallingConvention::DW_CC_LLVM_IntelOclBicc: - V(" __attribute__((intel_ocl_bicc))"); + LLVM_QUICK_EXIT(V(" __attribute__((intel_ocl_bicc))")); break; case dwarf::CallingConvention::DW_CC_LLVM_SpirFunction: case dwarf::CallingConvention::DW_CC_LLVM_OpenCLKernel: @@ -744,55 +787,66 @@ void DWARFTypePrinter::appendSubroutineNameAfter( break; case dwarf::CallingConvention::DW_CC_LLVM_Swift: // SwiftAsync missing - V(" __attribute__((swiftcall))"); + LLVM_QUICK_EXIT(V(" __attribute__((swiftcall))")); break; case dwarf::CallingConvention::DW_CC_LLVM_PreserveMost: - V(" __attribute__((preserve_most))"); + LLVM_QUICK_EXIT(V(" __attribute__((preserve_most))")); break; case dwarf::CallingConvention::DW_CC_LLVM_PreserveAll: - V(" __attribute__((preserve_all))"); + LLVM_QUICK_EXIT(V(" __attribute__((preserve_all))")); break; case dwarf::CallingConvention::DW_CC_LLVM_PreserveNone: - V(" __attribute__((preserve_none))"); + LLVM_QUICK_EXIT(V(" __attribute__((preserve_none))")); break; case dwarf::CallingConvention::DW_CC_LLVM_X86RegCall: - V(" __attribute__((regcall))"); + LLVM_QUICK_EXIT(V(" __attribute__((regcall))")); break; case dwarf::CallingConvention::DW_CC_LLVM_M68kRTD: - V(" __attribute__((m68k_rtd))"); + LLVM_QUICK_EXIT(V(" __attribute__((m68k_rtd))")); break; } } - if (Const) - V(" const"); - if (Volatile) - V(" volatile"); - if (D.find(dwarf::DW_AT_reference)) - V(" &"); - if (D.find(dwarf::DW_AT_rvalue_reference)) - V(" &&"); + 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(" &&")); + } - appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner)); + LLVM_QUICK_EXIT( + appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner))); + return true; } template -void DWARFTypePrinter::appendScopes(DieType D) { +bool DWARFTypePrinter::appendScopes(DieType D) { if (D.getTag() == dwarf::DW_TAG_compile_unit) - return; + return true; if (D.getTag() == dwarf::DW_TAG_type_unit) - return; + return true; if (D.getTag() == dwarf::DW_TAG_skeleton_unit) - return; + return true; if (D.getTag() == dwarf::DW_TAG_subprogram) - return; + return true; if (D.getTag() == dwarf::DW_TAG_lexical_block) - return; + return true; //D = D.resolveTypeUnitReference(); - if (DieType P = D.getParent()) - appendScopes(P); - appendUnqualifiedName(D); - V("::"); + 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