181ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
281ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDie.h"
381ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
481ad6265SDimitry Andric #include "llvm/Support/ScopedPrinter.h"
581ad6265SDimitry Andric namespace llvm {
681ad6265SDimitry Andric using namespace dwarf;
appendTypeTagName(dwarf::Tag T)781ad6265SDimitry Andric void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) {
881ad6265SDimitry Andric StringRef TagStr = TagString(T);
981ad6265SDimitry Andric static constexpr StringRef Prefix = "DW_TAG_";
1081ad6265SDimitry Andric static constexpr StringRef Suffix = "_type";
115f757f3fSDimitry Andric if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(Suffix))
1281ad6265SDimitry Andric return;
1381ad6265SDimitry Andric OS << TagStr.substr(Prefix.size(),
1481ad6265SDimitry Andric TagStr.size() - (Prefix.size() + Suffix.size()))
1581ad6265SDimitry Andric << " ";
1681ad6265SDimitry Andric }
1781ad6265SDimitry Andric
appendArrayType(const DWARFDie & D)1881ad6265SDimitry Andric void DWARFTypePrinter::appendArrayType(const DWARFDie &D) {
1981ad6265SDimitry Andric for (const DWARFDie &C : D.children()) {
2081ad6265SDimitry Andric if (C.getTag() != DW_TAG_subrange_type)
2181ad6265SDimitry Andric continue;
22bdd1243dSDimitry Andric std::optional<uint64_t> LB;
23bdd1243dSDimitry Andric std::optional<uint64_t> Count;
24bdd1243dSDimitry Andric std::optional<uint64_t> UB;
25bdd1243dSDimitry Andric std::optional<unsigned> DefaultLB;
26bdd1243dSDimitry Andric if (std::optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
2781ad6265SDimitry Andric LB = L->getAsUnsignedConstant();
28bdd1243dSDimitry Andric if (std::optional<DWARFFormValue> CountV = C.find(DW_AT_count))
2981ad6265SDimitry Andric Count = CountV->getAsUnsignedConstant();
30bdd1243dSDimitry Andric if (std::optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
3181ad6265SDimitry Andric UB = UpperV->getAsUnsignedConstant();
32bdd1243dSDimitry Andric if (std::optional<DWARFFormValue> LV =
3381ad6265SDimitry Andric D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
34bdd1243dSDimitry Andric if (std::optional<uint64_t> LC = LV->getAsUnsignedConstant())
3581ad6265SDimitry Andric if ((DefaultLB =
3681ad6265SDimitry Andric LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
3781ad6265SDimitry Andric if (LB && *LB == *DefaultLB)
38bdd1243dSDimitry Andric LB = std::nullopt;
3981ad6265SDimitry Andric if (!LB && !Count && !UB)
4081ad6265SDimitry Andric OS << "[]";
4181ad6265SDimitry Andric else if (!LB && (Count || UB) && DefaultLB)
4281ad6265SDimitry Andric OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
4381ad6265SDimitry Andric else {
4481ad6265SDimitry Andric OS << "[[";
4581ad6265SDimitry Andric if (LB)
4681ad6265SDimitry Andric OS << *LB;
4781ad6265SDimitry Andric else
4881ad6265SDimitry Andric OS << '?';
4981ad6265SDimitry Andric OS << ", ";
5081ad6265SDimitry Andric if (Count)
5181ad6265SDimitry Andric if (LB)
5281ad6265SDimitry Andric OS << *LB + *Count;
5381ad6265SDimitry Andric else
5481ad6265SDimitry Andric OS << "? + " << *Count;
5581ad6265SDimitry Andric else if (UB)
5681ad6265SDimitry Andric OS << *UB + 1;
5781ad6265SDimitry Andric else
5881ad6265SDimitry Andric OS << '?';
5981ad6265SDimitry Andric OS << ")]";
6081ad6265SDimitry Andric }
6181ad6265SDimitry Andric }
6281ad6265SDimitry Andric EndedWithTemplate = false;
6381ad6265SDimitry Andric }
6481ad6265SDimitry Andric
resolveReferencedType(DWARFDie D,dwarf::Attribute Attr=DW_AT_type)6581ad6265SDimitry Andric static DWARFDie resolveReferencedType(DWARFDie D,
6681ad6265SDimitry Andric dwarf::Attribute Attr = DW_AT_type) {
6781ad6265SDimitry Andric return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference();
6881ad6265SDimitry Andric }
resolveReferencedType(DWARFDie D,DWARFFormValue F)6981ad6265SDimitry Andric static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) {
7081ad6265SDimitry Andric return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference();
7181ad6265SDimitry Andric }
skipQualifiers(DWARFDie D)7281ad6265SDimitry Andric DWARFDie DWARFTypePrinter::skipQualifiers(DWARFDie D) {
7381ad6265SDimitry Andric while (D && (D.getTag() == DW_TAG_const_type ||
7481ad6265SDimitry Andric D.getTag() == DW_TAG_volatile_type))
7581ad6265SDimitry Andric D = resolveReferencedType(D);
7681ad6265SDimitry Andric return D;
7781ad6265SDimitry Andric }
7881ad6265SDimitry Andric
needsParens(DWARFDie D)7981ad6265SDimitry Andric bool DWARFTypePrinter::needsParens(DWARFDie D) {
8081ad6265SDimitry Andric D = skipQualifiers(D);
8181ad6265SDimitry Andric return D && (D.getTag() == DW_TAG_subroutine_type ||
8281ad6265SDimitry Andric D.getTag() == DW_TAG_array_type);
8381ad6265SDimitry Andric }
8481ad6265SDimitry Andric
appendPointerLikeTypeBefore(DWARFDie D,DWARFDie Inner,StringRef Ptr)8581ad6265SDimitry Andric void DWARFTypePrinter::appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner,
8681ad6265SDimitry Andric StringRef Ptr) {
8781ad6265SDimitry Andric appendQualifiedNameBefore(Inner);
8881ad6265SDimitry Andric if (Word)
8981ad6265SDimitry Andric OS << ' ';
9081ad6265SDimitry Andric if (needsParens(Inner))
9181ad6265SDimitry Andric OS << '(';
9281ad6265SDimitry Andric OS << Ptr;
9381ad6265SDimitry Andric Word = false;
9481ad6265SDimitry Andric EndedWithTemplate = false;
9581ad6265SDimitry Andric }
9681ad6265SDimitry Andric
9781ad6265SDimitry Andric DWARFDie
appendUnqualifiedNameBefore(DWARFDie D,std::string * OriginalFullName)9881ad6265SDimitry Andric DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D,
9981ad6265SDimitry Andric std::string *OriginalFullName) {
10081ad6265SDimitry Andric Word = true;
10181ad6265SDimitry Andric if (!D) {
10281ad6265SDimitry Andric OS << "void";
10381ad6265SDimitry Andric return DWARFDie();
10481ad6265SDimitry Andric }
10581ad6265SDimitry Andric DWARFDie InnerDIE;
10681ad6265SDimitry Andric auto Inner = [&] { return InnerDIE = resolveReferencedType(D); };
10781ad6265SDimitry Andric const dwarf::Tag T = D.getTag();
10881ad6265SDimitry Andric switch (T) {
10981ad6265SDimitry Andric case DW_TAG_pointer_type: {
11081ad6265SDimitry Andric appendPointerLikeTypeBefore(D, Inner(), "*");
11181ad6265SDimitry Andric break;
11281ad6265SDimitry Andric }
11381ad6265SDimitry Andric case DW_TAG_subroutine_type: {
11481ad6265SDimitry Andric appendQualifiedNameBefore(Inner());
11581ad6265SDimitry Andric if (Word) {
11681ad6265SDimitry Andric OS << ' ';
11781ad6265SDimitry Andric }
11881ad6265SDimitry Andric Word = false;
11981ad6265SDimitry Andric break;
12081ad6265SDimitry Andric }
12181ad6265SDimitry Andric case DW_TAG_array_type: {
12281ad6265SDimitry Andric appendQualifiedNameBefore(Inner());
12381ad6265SDimitry Andric break;
12481ad6265SDimitry Andric }
12581ad6265SDimitry Andric case DW_TAG_reference_type:
12681ad6265SDimitry Andric appendPointerLikeTypeBefore(D, Inner(), "&");
12781ad6265SDimitry Andric break;
12881ad6265SDimitry Andric case DW_TAG_rvalue_reference_type:
12981ad6265SDimitry Andric appendPointerLikeTypeBefore(D, Inner(), "&&");
13081ad6265SDimitry Andric break;
13181ad6265SDimitry Andric case DW_TAG_ptr_to_member_type: {
13281ad6265SDimitry Andric appendQualifiedNameBefore(Inner());
13381ad6265SDimitry Andric if (needsParens(InnerDIE))
13481ad6265SDimitry Andric OS << '(';
13581ad6265SDimitry Andric else if (Word)
13681ad6265SDimitry Andric OS << ' ';
13781ad6265SDimitry Andric if (DWARFDie Cont = resolveReferencedType(D, DW_AT_containing_type)) {
13881ad6265SDimitry Andric appendQualifiedName(Cont);
13981ad6265SDimitry Andric EndedWithTemplate = false;
14081ad6265SDimitry Andric OS << "::";
14181ad6265SDimitry Andric }
14281ad6265SDimitry Andric OS << "*";
14381ad6265SDimitry Andric Word = false;
14481ad6265SDimitry Andric break;
14581ad6265SDimitry Andric }
146bdd1243dSDimitry Andric case DW_TAG_LLVM_ptrauth_type:
147bdd1243dSDimitry Andric appendQualifiedNameBefore(Inner());
148bdd1243dSDimitry Andric break;
14981ad6265SDimitry Andric case DW_TAG_const_type:
15081ad6265SDimitry Andric case DW_TAG_volatile_type:
15181ad6265SDimitry Andric appendConstVolatileQualifierBefore(D);
15281ad6265SDimitry Andric break;
15381ad6265SDimitry Andric case DW_TAG_namespace: {
15481ad6265SDimitry Andric if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr))
15581ad6265SDimitry Andric OS << Name;
15681ad6265SDimitry Andric else
15781ad6265SDimitry Andric OS << "(anonymous namespace)";
15881ad6265SDimitry Andric break;
15981ad6265SDimitry Andric }
16081ad6265SDimitry Andric case DW_TAG_unspecified_type: {
16181ad6265SDimitry Andric StringRef TypeName = D.getShortName();
16281ad6265SDimitry Andric if (TypeName == "decltype(nullptr)")
16381ad6265SDimitry Andric TypeName = "std::nullptr_t";
16481ad6265SDimitry Andric Word = true;
16581ad6265SDimitry Andric OS << TypeName;
16681ad6265SDimitry Andric EndedWithTemplate = false;
16781ad6265SDimitry Andric break;
16881ad6265SDimitry Andric }
16981ad6265SDimitry Andric /*
17081ad6265SDimitry Andric case DW_TAG_structure_type:
17181ad6265SDimitry Andric case DW_TAG_class_type:
17281ad6265SDimitry Andric case DW_TAG_enumeration_type:
17381ad6265SDimitry Andric case DW_TAG_base_type:
17481ad6265SDimitry Andric */
17581ad6265SDimitry Andric default: {
17681ad6265SDimitry Andric const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr);
17781ad6265SDimitry Andric if (!NamePtr) {
17881ad6265SDimitry Andric appendTypeTagName(D.getTag());
17981ad6265SDimitry Andric return DWARFDie();
18081ad6265SDimitry Andric }
18181ad6265SDimitry Andric Word = true;
18281ad6265SDimitry Andric StringRef Name = NamePtr;
18381ad6265SDimitry Andric static constexpr StringRef MangledPrefix = "_STN|";
184*7a6dacacSDimitry Andric if (Name.consume_front(MangledPrefix)) {
18581ad6265SDimitry Andric auto Separator = Name.find('|');
18681ad6265SDimitry Andric assert(Separator != StringRef::npos);
18781ad6265SDimitry Andric StringRef BaseName = Name.substr(0, Separator);
18881ad6265SDimitry Andric StringRef TemplateArgs = Name.substr(Separator + 1);
18981ad6265SDimitry Andric if (OriginalFullName)
19081ad6265SDimitry Andric *OriginalFullName = (BaseName + TemplateArgs).str();
19181ad6265SDimitry Andric Name = BaseName;
19281ad6265SDimitry Andric } else
1935f757f3fSDimitry Andric EndedWithTemplate = Name.ends_with(">");
19481ad6265SDimitry Andric OS << Name;
19581ad6265SDimitry Andric // This check would be insufficient for operator overloads like
19681ad6265SDimitry Andric // "operator>>" - but for now Clang doesn't try to simplify them, so this
19781ad6265SDimitry Andric // is OK. Add more nuanced operator overload handling here if/when needed.
1985f757f3fSDimitry Andric if (Name.ends_with(">"))
19981ad6265SDimitry Andric break;
20081ad6265SDimitry Andric if (!appendTemplateParameters(D))
20181ad6265SDimitry Andric break;
20281ad6265SDimitry Andric
20381ad6265SDimitry Andric if (EndedWithTemplate)
20481ad6265SDimitry Andric OS << ' ';
20581ad6265SDimitry Andric OS << '>';
20681ad6265SDimitry Andric EndedWithTemplate = true;
20781ad6265SDimitry Andric Word = true;
20881ad6265SDimitry Andric break;
20981ad6265SDimitry Andric }
21081ad6265SDimitry Andric }
21181ad6265SDimitry Andric return InnerDIE;
21281ad6265SDimitry Andric }
21381ad6265SDimitry Andric
appendUnqualifiedNameAfter(DWARFDie D,DWARFDie Inner,bool SkipFirstParamIfArtificial)21481ad6265SDimitry Andric void DWARFTypePrinter::appendUnqualifiedNameAfter(
21581ad6265SDimitry Andric DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) {
21681ad6265SDimitry Andric if (!D)
21781ad6265SDimitry Andric return;
21881ad6265SDimitry Andric switch (D.getTag()) {
21981ad6265SDimitry Andric case DW_TAG_subroutine_type: {
22081ad6265SDimitry Andric appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
22181ad6265SDimitry Andric false);
22281ad6265SDimitry Andric break;
22381ad6265SDimitry Andric }
22481ad6265SDimitry Andric case DW_TAG_array_type: {
22581ad6265SDimitry Andric appendArrayType(D);
22681ad6265SDimitry Andric break;
22781ad6265SDimitry Andric }
22881ad6265SDimitry Andric case DW_TAG_const_type:
22981ad6265SDimitry Andric case DW_TAG_volatile_type:
23081ad6265SDimitry Andric appendConstVolatileQualifierAfter(D);
23181ad6265SDimitry Andric break;
23281ad6265SDimitry Andric case DW_TAG_ptr_to_member_type:
23381ad6265SDimitry Andric case DW_TAG_reference_type:
23481ad6265SDimitry Andric case DW_TAG_rvalue_reference_type:
23581ad6265SDimitry Andric case DW_TAG_pointer_type: {
23681ad6265SDimitry Andric if (needsParens(Inner))
23781ad6265SDimitry Andric OS << ')';
23881ad6265SDimitry Andric appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner),
23981ad6265SDimitry Andric /*SkipFirstParamIfArtificial=*/D.getTag() ==
24081ad6265SDimitry Andric DW_TAG_ptr_to_member_type);
24181ad6265SDimitry Andric break;
24281ad6265SDimitry Andric }
243bdd1243dSDimitry Andric case DW_TAG_LLVM_ptrauth_type: {
244bdd1243dSDimitry Andric auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t {
245bdd1243dSDimitry Andric if (auto Form = D.find(Attr))
246bdd1243dSDimitry Andric return *Form->getAsUnsignedConstant();
247bdd1243dSDimitry Andric return 0;
248bdd1243dSDimitry Andric };
249bdd1243dSDimitry Andric SmallVector<const char *, 2> optionsVec;
250bdd1243dSDimitry Andric if (getValOrNull(DW_AT_LLVM_ptrauth_isa_pointer))
251bdd1243dSDimitry Andric optionsVec.push_back("isa-pointer");
252bdd1243dSDimitry Andric if (getValOrNull(DW_AT_LLVM_ptrauth_authenticates_null_values))
253bdd1243dSDimitry Andric optionsVec.push_back("authenticates-null-values");
254bdd1243dSDimitry Andric std::string options;
255bdd1243dSDimitry Andric for (const auto *option : optionsVec) {
256bdd1243dSDimitry Andric if (options.size())
257bdd1243dSDimitry Andric options += ",";
258bdd1243dSDimitry Andric options += option;
259bdd1243dSDimitry Andric }
260bdd1243dSDimitry Andric if (options.size())
261bdd1243dSDimitry Andric options = ", \"" + options + "\"";
262bdd1243dSDimitry Andric std::string PtrauthString;
263bdd1243dSDimitry Andric llvm::raw_string_ostream PtrauthStream(PtrauthString);
264bdd1243dSDimitry Andric PtrauthStream
265bdd1243dSDimitry Andric << "__ptrauth(" << getValOrNull(DW_AT_LLVM_ptrauth_key) << ", "
266bdd1243dSDimitry Andric << getValOrNull(DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0"
267bdd1243dSDimitry Andric << utohexstr(getValOrNull(DW_AT_LLVM_ptrauth_extra_discriminator), true)
268bdd1243dSDimitry Andric << options << ")";
269bdd1243dSDimitry Andric OS << PtrauthStream.str();
270bdd1243dSDimitry Andric break;
271bdd1243dSDimitry Andric }
27281ad6265SDimitry Andric /*
27381ad6265SDimitry Andric case DW_TAG_structure_type:
27481ad6265SDimitry Andric case DW_TAG_class_type:
27581ad6265SDimitry Andric case DW_TAG_enumeration_type:
27681ad6265SDimitry Andric case DW_TAG_base_type:
27781ad6265SDimitry Andric case DW_TAG_namespace:
27881ad6265SDimitry Andric */
27981ad6265SDimitry Andric default:
28081ad6265SDimitry Andric break;
28181ad6265SDimitry Andric }
28281ad6265SDimitry Andric }
28381ad6265SDimitry Andric
284bdd1243dSDimitry Andric /// Returns True if the DIE TAG is one of the ones that is scopped.
scopedTAGs(dwarf::Tag Tag)285bdd1243dSDimitry Andric static bool scopedTAGs(dwarf::Tag Tag) {
286bdd1243dSDimitry Andric switch (Tag) {
287bdd1243dSDimitry Andric case dwarf::DW_TAG_structure_type:
288bdd1243dSDimitry Andric case dwarf::DW_TAG_class_type:
289bdd1243dSDimitry Andric case dwarf::DW_TAG_union_type:
290bdd1243dSDimitry Andric case dwarf::DW_TAG_namespace:
291bdd1243dSDimitry Andric case dwarf::DW_TAG_enumeration_type:
292bdd1243dSDimitry Andric return true;
293bdd1243dSDimitry Andric default:
294bdd1243dSDimitry Andric break;
295bdd1243dSDimitry Andric }
296bdd1243dSDimitry Andric return false;
297bdd1243dSDimitry Andric }
appendQualifiedName(DWARFDie D)29881ad6265SDimitry Andric void DWARFTypePrinter::appendQualifiedName(DWARFDie D) {
299bdd1243dSDimitry Andric if (D && scopedTAGs(D.getTag()))
30081ad6265SDimitry Andric appendScopes(D.getParent());
30181ad6265SDimitry Andric appendUnqualifiedName(D);
30281ad6265SDimitry Andric }
appendQualifiedNameBefore(DWARFDie D)30381ad6265SDimitry Andric DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) {
304bdd1243dSDimitry Andric if (D && scopedTAGs(D.getTag()))
30581ad6265SDimitry Andric appendScopes(D.getParent());
30681ad6265SDimitry Andric return appendUnqualifiedNameBefore(D);
30781ad6265SDimitry Andric }
appendTemplateParameters(DWARFDie D,bool * FirstParameter)30881ad6265SDimitry Andric bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D,
30981ad6265SDimitry Andric bool *FirstParameter) {
31081ad6265SDimitry Andric bool FirstParameterValue = true;
31181ad6265SDimitry Andric bool IsTemplate = false;
31281ad6265SDimitry Andric if (!FirstParameter)
31381ad6265SDimitry Andric FirstParameter = &FirstParameterValue;
31481ad6265SDimitry Andric for (const DWARFDie &C : D) {
31581ad6265SDimitry Andric auto Sep = [&] {
31681ad6265SDimitry Andric if (*FirstParameter)
31781ad6265SDimitry Andric OS << '<';
31881ad6265SDimitry Andric else
31981ad6265SDimitry Andric OS << ", ";
32081ad6265SDimitry Andric IsTemplate = true;
32181ad6265SDimitry Andric EndedWithTemplate = false;
32281ad6265SDimitry Andric *FirstParameter = false;
32381ad6265SDimitry Andric };
32481ad6265SDimitry Andric if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
32581ad6265SDimitry Andric IsTemplate = true;
32681ad6265SDimitry Andric appendTemplateParameters(C, FirstParameter);
32781ad6265SDimitry Andric }
32881ad6265SDimitry Andric if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
32981ad6265SDimitry Andric DWARFDie T = resolveReferencedType(C);
33081ad6265SDimitry Andric Sep();
33181ad6265SDimitry Andric if (T.getTag() == DW_TAG_enumeration_type) {
33281ad6265SDimitry Andric OS << '(';
33381ad6265SDimitry Andric appendQualifiedName(T);
33481ad6265SDimitry Andric OS << ')';
33581ad6265SDimitry Andric auto V = C.find(DW_AT_const_value);
33681ad6265SDimitry Andric OS << std::to_string(*V->getAsSignedConstant());
33781ad6265SDimitry Andric continue;
33881ad6265SDimitry Andric }
33981ad6265SDimitry Andric // /Maybe/ we could do pointer type parameters, looking for the
34081ad6265SDimitry Andric // symbol in the ELF symbol table to get back to the variable...
34181ad6265SDimitry Andric // but probably not worth it.
34281ad6265SDimitry Andric if (T.getTag() == DW_TAG_pointer_type)
34381ad6265SDimitry Andric continue;
34481ad6265SDimitry Andric const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr);
34581ad6265SDimitry Andric assert(RawName);
34681ad6265SDimitry Andric StringRef Name = RawName;
34781ad6265SDimitry Andric auto V = C.find(DW_AT_const_value);
34881ad6265SDimitry Andric bool IsQualifiedChar = false;
34981ad6265SDimitry Andric if (Name == "bool") {
35081ad6265SDimitry Andric OS << (*V->getAsUnsignedConstant() ? "true" : "false");
35181ad6265SDimitry Andric } else if (Name == "short") {
35281ad6265SDimitry Andric OS << "(short)";
35381ad6265SDimitry Andric OS << std::to_string(*V->getAsSignedConstant());
35481ad6265SDimitry Andric } else if (Name == "unsigned short") {
35581ad6265SDimitry Andric OS << "(unsigned short)";
35681ad6265SDimitry Andric OS << std::to_string(*V->getAsSignedConstant());
35781ad6265SDimitry Andric } else if (Name == "int")
35881ad6265SDimitry Andric OS << std::to_string(*V->getAsSignedConstant());
35981ad6265SDimitry Andric else if (Name == "long") {
36081ad6265SDimitry Andric OS << std::to_string(*V->getAsSignedConstant());
36181ad6265SDimitry Andric OS << "L";
36281ad6265SDimitry Andric } else if (Name == "long long") {
36381ad6265SDimitry Andric OS << std::to_string(*V->getAsSignedConstant());
36481ad6265SDimitry Andric OS << "LL";
36581ad6265SDimitry Andric } else if (Name == "unsigned int") {
36681ad6265SDimitry Andric OS << std::to_string(*V->getAsUnsignedConstant());
36781ad6265SDimitry Andric OS << "U";
36881ad6265SDimitry Andric } else if (Name == "unsigned long") {
36981ad6265SDimitry Andric OS << std::to_string(*V->getAsUnsignedConstant());
37081ad6265SDimitry Andric OS << "UL";
37181ad6265SDimitry Andric } else if (Name == "unsigned long long") {
37281ad6265SDimitry Andric OS << std::to_string(*V->getAsUnsignedConstant());
37381ad6265SDimitry Andric OS << "ULL";
37481ad6265SDimitry Andric } else if (Name == "char" ||
37581ad6265SDimitry Andric (IsQualifiedChar =
37681ad6265SDimitry Andric (Name == "unsigned char" || Name == "signed char"))) {
37781ad6265SDimitry Andric // FIXME: check T's DW_AT_type to see if it's signed or not (since
37881ad6265SDimitry Andric // char signedness is implementation defined).
37981ad6265SDimitry Andric auto Val = *V->getAsSignedConstant();
38081ad6265SDimitry Andric // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
38181ad6265SDimitry Andric // (doesn't actually support different character types/widths, sign
38281ad6265SDimitry Andric // handling's not done, and doesn't correctly test if a character is
38381ad6265SDimitry Andric // printable or needs to use a numeric escape sequence instead)
38481ad6265SDimitry Andric if (IsQualifiedChar) {
38581ad6265SDimitry Andric OS << '(';
38681ad6265SDimitry Andric OS << Name;
38781ad6265SDimitry Andric OS << ')';
38881ad6265SDimitry Andric }
38981ad6265SDimitry Andric switch (Val) {
39081ad6265SDimitry Andric case '\\':
39181ad6265SDimitry Andric OS << "'\\\\'";
39281ad6265SDimitry Andric break;
39381ad6265SDimitry Andric case '\'':
39481ad6265SDimitry Andric OS << "'\\''";
39581ad6265SDimitry Andric break;
39681ad6265SDimitry Andric case '\a':
39781ad6265SDimitry Andric // TODO: K&R: the meaning of '\\a' is different in traditional C
39881ad6265SDimitry Andric OS << "'\\a'";
39981ad6265SDimitry Andric break;
40081ad6265SDimitry Andric case '\b':
40181ad6265SDimitry Andric OS << "'\\b'";
40281ad6265SDimitry Andric break;
40381ad6265SDimitry Andric case '\f':
40481ad6265SDimitry Andric OS << "'\\f'";
40581ad6265SDimitry Andric break;
40681ad6265SDimitry Andric case '\n':
40781ad6265SDimitry Andric OS << "'\\n'";
40881ad6265SDimitry Andric break;
40981ad6265SDimitry Andric case '\r':
41081ad6265SDimitry Andric OS << "'\\r'";
41181ad6265SDimitry Andric break;
41281ad6265SDimitry Andric case '\t':
41381ad6265SDimitry Andric OS << "'\\t'";
41481ad6265SDimitry Andric break;
41581ad6265SDimitry Andric case '\v':
41681ad6265SDimitry Andric OS << "'\\v'";
41781ad6265SDimitry Andric break;
41881ad6265SDimitry Andric default:
41981ad6265SDimitry Andric if ((Val & ~0xFFu) == ~0xFFu)
42081ad6265SDimitry Andric Val &= 0xFFu;
42181ad6265SDimitry Andric if (Val < 127 && Val >= 32) {
42281ad6265SDimitry Andric OS << "'";
42381ad6265SDimitry Andric OS << (char)Val;
42481ad6265SDimitry Andric OS << "'";
42581ad6265SDimitry Andric } else if (Val < 256)
42606c3fb27SDimitry Andric OS << llvm::format("'\\x%02" PRIx64 "'", Val);
42781ad6265SDimitry Andric else if (Val <= 0xFFFF)
42806c3fb27SDimitry Andric OS << llvm::format("'\\u%04" PRIx64 "'", Val);
42981ad6265SDimitry Andric else
43006c3fb27SDimitry Andric OS << llvm::format("'\\U%08" PRIx64 "'", Val);
43181ad6265SDimitry Andric }
43281ad6265SDimitry Andric }
43381ad6265SDimitry Andric continue;
43481ad6265SDimitry Andric }
43581ad6265SDimitry Andric if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
43681ad6265SDimitry Andric const char *RawName =
43781ad6265SDimitry Andric dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr);
43881ad6265SDimitry Andric assert(RawName);
43981ad6265SDimitry Andric StringRef Name = RawName;
44081ad6265SDimitry Andric Sep();
44181ad6265SDimitry Andric OS << Name;
44281ad6265SDimitry Andric continue;
44381ad6265SDimitry Andric }
44481ad6265SDimitry Andric if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
44581ad6265SDimitry Andric continue;
44681ad6265SDimitry Andric auto TypeAttr = C.find(DW_AT_type);
44781ad6265SDimitry Andric Sep();
44881ad6265SDimitry Andric appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr)
44981ad6265SDimitry Andric : DWARFDie());
45081ad6265SDimitry Andric }
45181ad6265SDimitry Andric if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
45281ad6265SDimitry Andric OS << '<';
45381ad6265SDimitry Andric EndedWithTemplate = false;
45481ad6265SDimitry Andric }
45581ad6265SDimitry Andric return IsTemplate;
45681ad6265SDimitry Andric }
decomposeConstVolatile(DWARFDie & N,DWARFDie & T,DWARFDie & C,DWARFDie & V)45781ad6265SDimitry Andric void DWARFTypePrinter::decomposeConstVolatile(DWARFDie &N, DWARFDie &T,
45881ad6265SDimitry Andric DWARFDie &C, DWARFDie &V) {
45981ad6265SDimitry Andric (N.getTag() == DW_TAG_const_type ? C : V) = N;
46081ad6265SDimitry Andric T = resolveReferencedType(N);
46181ad6265SDimitry Andric if (T) {
46281ad6265SDimitry Andric auto Tag = T.getTag();
46381ad6265SDimitry Andric if (Tag == DW_TAG_const_type) {
46481ad6265SDimitry Andric C = T;
46581ad6265SDimitry Andric T = resolveReferencedType(T);
46681ad6265SDimitry Andric } else if (Tag == DW_TAG_volatile_type) {
46781ad6265SDimitry Andric V = T;
46881ad6265SDimitry Andric T = resolveReferencedType(T);
46981ad6265SDimitry Andric }
47081ad6265SDimitry Andric }
47181ad6265SDimitry Andric }
appendConstVolatileQualifierAfter(DWARFDie N)47281ad6265SDimitry Andric void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) {
47381ad6265SDimitry Andric DWARFDie C;
47481ad6265SDimitry Andric DWARFDie V;
47581ad6265SDimitry Andric DWARFDie T;
47681ad6265SDimitry Andric decomposeConstVolatile(N, T, C, V);
47781ad6265SDimitry Andric if (T && T.getTag() == DW_TAG_subroutine_type)
47881ad6265SDimitry Andric appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(),
47981ad6265SDimitry Andric V.isValid());
48081ad6265SDimitry Andric else
48181ad6265SDimitry Andric appendUnqualifiedNameAfter(T, resolveReferencedType(T));
48281ad6265SDimitry Andric }
appendConstVolatileQualifierBefore(DWARFDie N)48381ad6265SDimitry Andric void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) {
48481ad6265SDimitry Andric DWARFDie C;
48581ad6265SDimitry Andric DWARFDie V;
48681ad6265SDimitry Andric DWARFDie T;
48781ad6265SDimitry Andric decomposeConstVolatile(N, T, C, V);
48881ad6265SDimitry Andric bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type;
48981ad6265SDimitry Andric DWARFDie A = T;
49081ad6265SDimitry Andric while (A && A.getTag() == DW_TAG_array_type)
49181ad6265SDimitry Andric A = resolveReferencedType(A);
49281ad6265SDimitry Andric bool Leading =
49381ad6265SDimitry Andric (!A || (A.getTag() != DW_TAG_pointer_type &&
49481ad6265SDimitry Andric A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
49581ad6265SDimitry Andric !Subroutine;
49681ad6265SDimitry Andric if (Leading) {
49781ad6265SDimitry Andric if (C)
49881ad6265SDimitry Andric OS << "const ";
49981ad6265SDimitry Andric if (V)
50081ad6265SDimitry Andric OS << "volatile ";
50181ad6265SDimitry Andric }
50281ad6265SDimitry Andric appendQualifiedNameBefore(T);
50381ad6265SDimitry Andric if (!Leading && !Subroutine) {
50481ad6265SDimitry Andric Word = true;
50581ad6265SDimitry Andric if (C)
50681ad6265SDimitry Andric OS << "const";
50781ad6265SDimitry Andric if (V) {
50881ad6265SDimitry Andric if (C)
50981ad6265SDimitry Andric OS << ' ';
51081ad6265SDimitry Andric OS << "volatile";
51181ad6265SDimitry Andric }
51281ad6265SDimitry Andric }
51381ad6265SDimitry Andric }
appendUnqualifiedName(DWARFDie D,std::string * OriginalFullName)51481ad6265SDimitry Andric void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D,
51581ad6265SDimitry Andric std::string *OriginalFullName) {
51681ad6265SDimitry Andric // FIXME: We should have pretty printers per language. Currently we print
51781ad6265SDimitry Andric // everything as if it was C++ and fall back to the TAG type name.
51881ad6265SDimitry Andric DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
51981ad6265SDimitry Andric appendUnqualifiedNameAfter(D, Inner);
52081ad6265SDimitry Andric }
appendSubroutineNameAfter(DWARFDie D,DWARFDie Inner,bool SkipFirstParamIfArtificial,bool Const,bool Volatile)52181ad6265SDimitry Andric void DWARFTypePrinter::appendSubroutineNameAfter(
52281ad6265SDimitry Andric DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const,
52381ad6265SDimitry Andric bool Volatile) {
52481ad6265SDimitry Andric DWARFDie FirstParamIfArtificial;
52581ad6265SDimitry Andric OS << '(';
52681ad6265SDimitry Andric EndedWithTemplate = false;
52781ad6265SDimitry Andric bool First = true;
52881ad6265SDimitry Andric bool RealFirst = true;
52981ad6265SDimitry Andric for (DWARFDie P : D) {
53081ad6265SDimitry Andric if (P.getTag() != DW_TAG_formal_parameter &&
53181ad6265SDimitry Andric P.getTag() != DW_TAG_unspecified_parameters)
53281ad6265SDimitry Andric return;
53381ad6265SDimitry Andric DWARFDie T = resolveReferencedType(P);
53481ad6265SDimitry Andric if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) {
53581ad6265SDimitry Andric FirstParamIfArtificial = T;
53681ad6265SDimitry Andric RealFirst = false;
53781ad6265SDimitry Andric continue;
53881ad6265SDimitry Andric }
53981ad6265SDimitry Andric if (!First) {
54081ad6265SDimitry Andric OS << ", ";
54181ad6265SDimitry Andric }
54281ad6265SDimitry Andric First = false;
54381ad6265SDimitry Andric if (P.getTag() == DW_TAG_unspecified_parameters)
54481ad6265SDimitry Andric OS << "...";
54581ad6265SDimitry Andric else
54681ad6265SDimitry Andric appendQualifiedName(T);
54781ad6265SDimitry Andric }
54881ad6265SDimitry Andric EndedWithTemplate = false;
54981ad6265SDimitry Andric OS << ')';
55081ad6265SDimitry Andric if (FirstParamIfArtificial) {
55181ad6265SDimitry Andric if (DWARFDie P = FirstParamIfArtificial) {
55281ad6265SDimitry Andric if (P.getTag() == DW_TAG_pointer_type) {
55381ad6265SDimitry Andric auto CVStep = [&](DWARFDie CV) {
55481ad6265SDimitry Andric if (DWARFDie U = resolveReferencedType(CV)) {
55581ad6265SDimitry Andric Const |= U.getTag() == DW_TAG_const_type;
55681ad6265SDimitry Andric Volatile |= U.getTag() == DW_TAG_volatile_type;
55781ad6265SDimitry Andric return U;
55881ad6265SDimitry Andric }
55981ad6265SDimitry Andric return DWARFDie();
56081ad6265SDimitry Andric };
56181ad6265SDimitry Andric if (DWARFDie CV = CVStep(P)) {
56281ad6265SDimitry Andric CVStep(CV);
56381ad6265SDimitry Andric }
56481ad6265SDimitry Andric }
56581ad6265SDimitry Andric }
56681ad6265SDimitry Andric }
56781ad6265SDimitry Andric
56881ad6265SDimitry Andric if (auto CC = D.find(DW_AT_calling_convention)) {
56981ad6265SDimitry Andric switch (*CC->getAsUnsignedConstant()) {
57081ad6265SDimitry Andric case CallingConvention::DW_CC_BORLAND_stdcall:
57181ad6265SDimitry Andric OS << " __attribute__((stdcall))";
57281ad6265SDimitry Andric break;
57381ad6265SDimitry Andric case CallingConvention::DW_CC_BORLAND_msfastcall:
57481ad6265SDimitry Andric OS << " __attribute__((fastcall))";
57581ad6265SDimitry Andric break;
57681ad6265SDimitry Andric case CallingConvention::DW_CC_BORLAND_thiscall:
57781ad6265SDimitry Andric OS << " __attribute__((thiscall))";
57881ad6265SDimitry Andric break;
57981ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_vectorcall:
58081ad6265SDimitry Andric OS << " __attribute__((vectorcall))";
58181ad6265SDimitry Andric break;
58281ad6265SDimitry Andric case CallingConvention::DW_CC_BORLAND_pascal:
58381ad6265SDimitry Andric OS << " __attribute__((pascal))";
58481ad6265SDimitry Andric break;
58581ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_Win64:
58681ad6265SDimitry Andric OS << " __attribute__((ms_abi))";
58781ad6265SDimitry Andric break;
58881ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_X86_64SysV:
58981ad6265SDimitry Andric OS << " __attribute__((sysv_abi))";
59081ad6265SDimitry Andric break;
59181ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_AAPCS:
59281ad6265SDimitry Andric // AArch64VectorCall missing?
59381ad6265SDimitry Andric OS << " __attribute__((pcs(\"aapcs\")))";
59481ad6265SDimitry Andric break;
59581ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_AAPCS_VFP:
59681ad6265SDimitry Andric OS << " __attribute__((pcs(\"aapcs-vfp\")))";
59781ad6265SDimitry Andric break;
59881ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_IntelOclBicc:
59981ad6265SDimitry Andric OS << " __attribute__((intel_ocl_bicc))";
60081ad6265SDimitry Andric break;
60181ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_SpirFunction:
60281ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_OpenCLKernel:
60381ad6265SDimitry Andric // These aren't available as attributes, but maybe we should still
60481ad6265SDimitry Andric // render them somehow? (Clang doesn't render them, but that's an issue
60581ad6265SDimitry Andric // for template names too - since then the DWARF names of templates
60681ad6265SDimitry Andric // instantiated with function types with these calling conventions won't
60781ad6265SDimitry Andric // have distinct names - so we'd need to fix that too)
60881ad6265SDimitry Andric break;
60981ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_Swift:
61081ad6265SDimitry Andric // SwiftAsync missing
61181ad6265SDimitry Andric OS << " __attribute__((swiftcall))";
61281ad6265SDimitry Andric break;
61381ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_PreserveMost:
61481ad6265SDimitry Andric OS << " __attribute__((preserve_most))";
61581ad6265SDimitry Andric break;
61681ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_PreserveAll:
61781ad6265SDimitry Andric OS << " __attribute__((preserve_all))";
61881ad6265SDimitry Andric break;
61981ad6265SDimitry Andric case CallingConvention::DW_CC_LLVM_X86RegCall:
62081ad6265SDimitry Andric OS << " __attribute__((regcall))";
62181ad6265SDimitry Andric break;
6225f757f3fSDimitry Andric case CallingConvention::DW_CC_LLVM_M68kRTD:
6235f757f3fSDimitry Andric OS << " __attribute__((m68k_rtd))";
6245f757f3fSDimitry Andric break;
62581ad6265SDimitry Andric }
62681ad6265SDimitry Andric }
62781ad6265SDimitry Andric
62881ad6265SDimitry Andric if (Const)
62981ad6265SDimitry Andric OS << " const";
63081ad6265SDimitry Andric if (Volatile)
63181ad6265SDimitry Andric OS << " volatile";
63281ad6265SDimitry Andric if (D.find(DW_AT_reference))
63381ad6265SDimitry Andric OS << " &";
63481ad6265SDimitry Andric if (D.find(DW_AT_rvalue_reference))
63581ad6265SDimitry Andric OS << " &&";
63681ad6265SDimitry Andric
63781ad6265SDimitry Andric appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner));
63881ad6265SDimitry Andric }
appendScopes(DWARFDie D)63981ad6265SDimitry Andric void DWARFTypePrinter::appendScopes(DWARFDie D) {
64081ad6265SDimitry Andric if (D.getTag() == DW_TAG_compile_unit)
64181ad6265SDimitry Andric return;
64281ad6265SDimitry Andric if (D.getTag() == DW_TAG_type_unit)
64381ad6265SDimitry Andric return;
64481ad6265SDimitry Andric if (D.getTag() == DW_TAG_skeleton_unit)
64581ad6265SDimitry Andric return;
64681ad6265SDimitry Andric if (D.getTag() == DW_TAG_subprogram)
64781ad6265SDimitry Andric return;
64881ad6265SDimitry Andric if (D.getTag() == DW_TAG_lexical_block)
64981ad6265SDimitry Andric return;
65081ad6265SDimitry Andric D = D.resolveTypeUnitReference();
65181ad6265SDimitry Andric if (DWARFDie P = D.getParent())
65281ad6265SDimitry Andric appendScopes(P);
65381ad6265SDimitry Andric appendUnqualifiedName(D);
65481ad6265SDimitry Andric OS << "::";
65581ad6265SDimitry Andric }
65681ad6265SDimitry Andric } // namespace llvm
657