[llvm] 61fac2c - Incomplete attempt to pull DWARFTypePrinter into its own file for reuse
David Blaikie via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 16 15:29:01 PDT 2022
Author: David Blaikie
Date: 2022-06-16T22:28:28Z
New Revision: 61fac2c370b92cb77e6441abe2237e7112cd1a9a
URL: https://github.com/llvm/llvm-project/commit/61fac2c370b92cb77e6441abe2237e7112cd1a9a
DIFF: https://github.com/llvm/llvm-project/commit/61fac2c370b92cb77e6441abe2237e7112cd1a9a.diff
LOG: Incomplete attempt to pull DWARFTypePrinter into its own file for reuse
from lldb
Added:
llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp
Modified:
llvm/lib/DebugInfo/DWARF/CMakeLists.txt
llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
new file mode 100644
index 0000000000000..e05271740e615
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
@@ -0,0 +1,67 @@
+//===- DWARFTypePrinter.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
+#define LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+
+#include <string>
+
+namespace llvm {
+
+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 {
+ raw_ostream &OS;
+ bool Word = true;
+ bool EndedWithTemplate = false;
+
+ DWARFTypePrinter(raw_ostream &OS) : OS(OS) {}
+
+ /// Dump the name encoded in the type tag.
+ void appendTypeTagName(dwarf::Tag T);
+
+ void appendArrayType(const DWARFDie &D);
+
+ DWARFDie skipQualifiers(DWARFDie D);
+
+ bool needsParens(DWARFDie D);
+
+ void appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner, StringRef Ptr);
+
+ DWARFDie appendUnqualifiedNameBefore(DWARFDie D,
+ std::string *OriginalFullName = nullptr);
+
+ void appendUnqualifiedNameAfter(DWARFDie D, DWARFDie 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);
+
+ /// Recursively append the DIE type name when applicable.
+ void appendUnqualifiedName(DWARFDie D,
+ std::string *OriginalFullName = nullptr);
+
+ void appendSubroutineNameAfter(DWARFDie D, DWARFDie Inner,
+ bool SkipFirstParamIfArtificial, bool Const,
+ bool Volatile);
+ void appendScopes(DWARFDie D);
+};
+
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
diff --git a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
index 4bcc0d5ad513a..5ff72add9faf9 100644
--- a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
@@ -10,6 +10,7 @@ add_llvm_component_library(LLVMDebugInfoDWARF
DWARFDebugArangeSet.cpp
DWARFDebugAranges.cpp
DWARFDebugFrame.cpp
+ DWARFTypePrinter.cpp
DWARFDebugInfoEntry.cpp
DWARFDebugLine.cpp
DWARFDebugLoc.cpp
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index b375fc5ecbe07..9bbe09fccfe69 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -18,6 +18,7 @@
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
#include "llvm/Object/ObjectFile.h"
@@ -107,623 +108,10 @@ static void dumpLocationExpr(raw_ostream &OS, const DWARFFormValue &FormValue,
.print(OS, DumpOpts, MRI, U);
}
-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();
}
-namespace {
-
-// 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 {
- raw_ostream &OS;
- bool Word = true;
- bool EndedWithTemplate = false;
-
- DWARFTypePrinter(raw_ostream &OS) : OS(OS) {}
-
- /// Dump the name encoded in the type tag.
- void appendTypeTagName(dwarf::Tag T) {
- StringRef TagStr = TagString(T);
- static constexpr StringRef Prefix = "DW_TAG_";
- static constexpr StringRef Suffix = "_type";
- if (!TagStr.startswith(Prefix) || !TagStr.endswith(Suffix))
- return;
- OS << TagStr.substr(Prefix.size(),
- TagStr.size() - (Prefix.size() + Suffix.size()))
- << " ";
- }
-
- void appendArrayType(const DWARFDie &D) {
- for (const DWARFDie &C : D.children()) {
- if (C.getTag() != DW_TAG_subrange_type)
- continue;
- Optional<uint64_t> LB;
- Optional<uint64_t> Count;
- Optional<uint64_t> UB;
- Optional<unsigned> DefaultLB;
- if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
- LB = L->getAsUnsignedConstant();
- if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count))
- Count = CountV->getAsUnsignedConstant();
- if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
- UB = UpperV->getAsUnsignedConstant();
- if (Optional<DWARFFormValue> LV =
- D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
- if (Optional<uint64_t> LC = LV->getAsUnsignedConstant())
- if ((DefaultLB =
- LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
- if (LB && *LB == *DefaultLB)
- LB = None;
- 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;
- }
-
- DWARFDie skipQualifiers(DWARFDie D) {
- while (D && (D.getTag() == DW_TAG_const_type ||
- D.getTag() == DW_TAG_volatile_type))
- D = resolveReferencedType(D);
- return D;
- }
-
- bool needsParens(DWARFDie D) {
- D = skipQualifiers(D);
- return D && (D.getTag() == DW_TAG_subroutine_type || D.getTag() == DW_TAG_array_type);
- }
-
- void appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner, StringRef Ptr) {
- appendQualifiedNameBefore(Inner);
- if (Word)
- OS << ' ';
- if (needsParens(Inner))
- OS << '(';
- OS << Ptr;
- Word = false;
- EndedWithTemplate = false;
- }
-
- DWARFDie
- appendUnqualifiedNameBefore(DWARFDie D,
- std::string *OriginalFullName = nullptr) {
- 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_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.startswith(MangledPrefix)) {
- Name = Name.drop_front(MangledPrefix.size());
- 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.endswith(">");
- 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.endswith(">"))
- break;
- if (!appendTemplateParameters(D))
- break;
-
- if (EndedWithTemplate)
- OS << ' ';
- OS << '>';
- EndedWithTemplate = true;
- Word = true;
- break;
- }
- }
- return InnerDIE;
- }
-
- void appendUnqualifiedNameAfter(DWARFDie D, DWARFDie Inner,
- bool SkipFirstParamIfArtificial = false) {
- 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_structure_type:
- case DW_TAG_class_type:
- case DW_TAG_enumeration_type:
- case DW_TAG_base_type:
- case DW_TAG_namespace:
- */
- default:
- break;
- }
- }
-
- void appendQualifiedName(DWARFDie D) {
- if (D)
- appendScopes(D.getParent());
- appendUnqualifiedName(D);
- }
- DWARFDie appendQualifiedNameBefore(DWARFDie D) {
- if (D)
- appendScopes(D.getParent());
- return appendUnqualifiedNameBefore(D);
- }
- bool appendTemplateParameters(DWARFDie D, bool *FirstParameter = nullptr) {
- 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 << 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 << to_string(*V->getAsSignedConstant());
- } else if (Name == "unsigned short") {
- OS << "(unsigned short)";
- OS << to_string(*V->getAsSignedConstant());
- } else if (Name == "int")
- OS << to_string(*V->getAsSignedConstant());
- else if (Name == "long") {
- OS << to_string(*V->getAsSignedConstant());
- OS << "L";
- } else if (Name == "long long") {
- OS << to_string(*V->getAsSignedConstant());
- OS << "LL";
- } else if (Name == "unsigned int") {
- OS << to_string(*V->getAsUnsignedConstant());
- OS << "U";
- } else if (Name == "unsigned long") {
- OS << to_string(*V->getAsUnsignedConstant());
- OS << "UL";
- } else if (Name == "unsigned long long") {
- OS << 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
diff erent 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
diff erent 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 << to_string(llvm::format("'\\x%02x'", Val));
- else if (Val <= 0xFFFF)
- OS << to_string(llvm::format("'\\u%04x'", Val));
- else
- OS << to_string(llvm::format("'\\U%08x'", 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 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 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 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";
- }
- }
- }
-
- /// Recursively append the DIE type name when applicable.
- void appendUnqualifiedName(DWARFDie D,
- std::string *OriginalFullName = nullptr) {
- // 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 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_X86RegCall:
- OS << " __attribute__((regcall))";
- 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 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 << "::";
- }
-};
-} // anonymous namespace
-
static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
const DWARFAttribute &AttrValue, unsigned Indent,
DIDumpOptions DumpOpts) {
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp b/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp
new file mode 100644
index 0000000000000..86cc07b0d0f29
--- /dev/null
+++ b/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp
@@ -0,0 +1,608 @@
+#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.startswith(Prefix) || !TagStr.endswith(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;
+ Optional<uint64_t> LB;
+ Optional<uint64_t> Count;
+ Optional<uint64_t> UB;
+ Optional<unsigned> DefaultLB;
+ if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
+ LB = L->getAsUnsignedConstant();
+ if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count))
+ Count = CountV->getAsUnsignedConstant();
+ if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
+ UB = UpperV->getAsUnsignedConstant();
+ if (Optional<DWARFFormValue> LV =
+ D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
+ if (Optional<uint64_t> LC = LV->getAsUnsignedConstant())
+ if ((DefaultLB =
+ LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
+ if (LB && *LB == *DefaultLB)
+ LB = None;
+ 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_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.startswith(MangledPrefix)) {
+ Name = Name.drop_front(MangledPrefix.size());
+ 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.endswith(">");
+ 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.endswith(">"))
+ 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_structure_type:
+ case DW_TAG_class_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_base_type:
+ case DW_TAG_namespace:
+ */
+ default:
+ break;
+ }
+}
+
+void DWARFTypePrinter::appendQualifiedName(DWARFDie D) {
+ if (D)
+ appendScopes(D.getParent());
+ appendUnqualifiedName(D);
+}
+DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) {
+ if (D)
+ 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
diff erent 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
diff erent 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 << to_string(llvm::format("'\\x%02x'", Val));
+ else if (Val <= 0xFFFF)
+ OS << to_string(llvm::format("'\\u%04x'", Val));
+ else
+ OS << to_string(llvm::format("'\\U%08x'", 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_X86RegCall:
+ OS << " __attribute__((regcall))";
+ 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
More information about the llvm-commits
mailing list