1 #include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h" 2 #include "llvm/DebugInfo/DWARF/DWARFDie.h" 3 #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 4 #include "llvm/Support/ScopedPrinter.h" 5 namespace llvm { 6 using namespace dwarf; 7 void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) { 8 StringRef TagStr = TagString(T); 9 static constexpr StringRef Prefix = "DW_TAG_"; 10 static constexpr StringRef Suffix = "_type"; 11 if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(Suffix)) 12 return; 13 OS << TagStr.substr(Prefix.size(), 14 TagStr.size() - (Prefix.size() + Suffix.size())) 15 << " "; 16 } 17 18 void DWARFTypePrinter::appendArrayType(const DWARFDie &D) { 19 for (const DWARFDie &C : D.children()) { 20 if (C.getTag() != DW_TAG_subrange_type) 21 continue; 22 std::optional<uint64_t> LB; 23 std::optional<uint64_t> Count; 24 std::optional<uint64_t> UB; 25 std::optional<unsigned> DefaultLB; 26 if (std::optional<DWARFFormValue> L = C.find(DW_AT_lower_bound)) 27 LB = L->getAsUnsignedConstant(); 28 if (std::optional<DWARFFormValue> CountV = C.find(DW_AT_count)) 29 Count = CountV->getAsUnsignedConstant(); 30 if (std::optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound)) 31 UB = UpperV->getAsUnsignedConstant(); 32 if (std::optional<DWARFFormValue> LV = 33 D.getDwarfUnit()->getUnitDIE().find(DW_AT_language)) 34 if (std::optional<uint64_t> LC = LV->getAsUnsignedConstant()) 35 if ((DefaultLB = 36 LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC)))) 37 if (LB && *LB == *DefaultLB) 38 LB = std::nullopt; 39 if (!LB && !Count && !UB) 40 OS << "[]"; 41 else if (!LB && (Count || UB) && DefaultLB) 42 OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']'; 43 else { 44 OS << "[["; 45 if (LB) 46 OS << *LB; 47 else 48 OS << '?'; 49 OS << ", "; 50 if (Count) 51 if (LB) 52 OS << *LB + *Count; 53 else 54 OS << "? + " << *Count; 55 else if (UB) 56 OS << *UB + 1; 57 else 58 OS << '?'; 59 OS << ")]"; 60 } 61 } 62 EndedWithTemplate = false; 63 } 64 65 static DWARFDie resolveReferencedType(DWARFDie D, 66 dwarf::Attribute Attr = DW_AT_type) { 67 return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference(); 68 } 69 static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) { 70 return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference(); 71 } 72 DWARFDie DWARFTypePrinter::skipQualifiers(DWARFDie D) { 73 while (D && (D.getTag() == DW_TAG_const_type || 74 D.getTag() == DW_TAG_volatile_type)) 75 D = resolveReferencedType(D); 76 return D; 77 } 78 79 bool DWARFTypePrinter::needsParens(DWARFDie D) { 80 D = skipQualifiers(D); 81 return D && (D.getTag() == DW_TAG_subroutine_type || 82 D.getTag() == DW_TAG_array_type); 83 } 84 85 void DWARFTypePrinter::appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner, 86 StringRef Ptr) { 87 appendQualifiedNameBefore(Inner); 88 if (Word) 89 OS << ' '; 90 if (needsParens(Inner)) 91 OS << '('; 92 OS << Ptr; 93 Word = false; 94 EndedWithTemplate = false; 95 } 96 97 DWARFDie 98 DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D, 99 std::string *OriginalFullName) { 100 Word = true; 101 if (!D) { 102 OS << "void"; 103 return DWARFDie(); 104 } 105 DWARFDie InnerDIE; 106 auto Inner = [&] { return InnerDIE = resolveReferencedType(D); }; 107 const dwarf::Tag T = D.getTag(); 108 switch (T) { 109 case DW_TAG_pointer_type: { 110 appendPointerLikeTypeBefore(D, Inner(), "*"); 111 break; 112 } 113 case DW_TAG_subroutine_type: { 114 appendQualifiedNameBefore(Inner()); 115 if (Word) { 116 OS << ' '; 117 } 118 Word = false; 119 break; 120 } 121 case DW_TAG_array_type: { 122 appendQualifiedNameBefore(Inner()); 123 break; 124 } 125 case DW_TAG_reference_type: 126 appendPointerLikeTypeBefore(D, Inner(), "&"); 127 break; 128 case DW_TAG_rvalue_reference_type: 129 appendPointerLikeTypeBefore(D, Inner(), "&&"); 130 break; 131 case DW_TAG_ptr_to_member_type: { 132 appendQualifiedNameBefore(Inner()); 133 if (needsParens(InnerDIE)) 134 OS << '('; 135 else if (Word) 136 OS << ' '; 137 if (DWARFDie Cont = resolveReferencedType(D, DW_AT_containing_type)) { 138 appendQualifiedName(Cont); 139 EndedWithTemplate = false; 140 OS << "::"; 141 } 142 OS << "*"; 143 Word = false; 144 break; 145 } 146 case DW_TAG_LLVM_ptrauth_type: 147 appendQualifiedNameBefore(Inner()); 148 break; 149 case DW_TAG_const_type: 150 case DW_TAG_volatile_type: 151 appendConstVolatileQualifierBefore(D); 152 break; 153 case DW_TAG_namespace: { 154 if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr)) 155 OS << Name; 156 else 157 OS << "(anonymous namespace)"; 158 break; 159 } 160 case DW_TAG_unspecified_type: { 161 StringRef TypeName = D.getShortName(); 162 if (TypeName == "decltype(nullptr)") 163 TypeName = "std::nullptr_t"; 164 Word = true; 165 OS << TypeName; 166 EndedWithTemplate = false; 167 break; 168 } 169 /* 170 case DW_TAG_structure_type: 171 case DW_TAG_class_type: 172 case DW_TAG_enumeration_type: 173 case DW_TAG_base_type: 174 */ 175 default: { 176 const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr); 177 if (!NamePtr) { 178 appendTypeTagName(D.getTag()); 179 return DWARFDie(); 180 } 181 Word = true; 182 StringRef Name = NamePtr; 183 static constexpr StringRef MangledPrefix = "_STN|"; 184 if (Name.consume_front(MangledPrefix)) { 185 auto Separator = Name.find('|'); 186 assert(Separator != StringRef::npos); 187 StringRef BaseName = Name.substr(0, Separator); 188 StringRef TemplateArgs = Name.substr(Separator + 1); 189 if (OriginalFullName) 190 *OriginalFullName = (BaseName + TemplateArgs).str(); 191 Name = BaseName; 192 } else 193 EndedWithTemplate = Name.ends_with(">"); 194 OS << Name; 195 // This check would be insufficient for operator overloads like 196 // "operator>>" - but for now Clang doesn't try to simplify them, so this 197 // is OK. Add more nuanced operator overload handling here if/when needed. 198 if (Name.ends_with(">")) 199 break; 200 if (!appendTemplateParameters(D)) 201 break; 202 203 if (EndedWithTemplate) 204 OS << ' '; 205 OS << '>'; 206 EndedWithTemplate = true; 207 Word = true; 208 break; 209 } 210 } 211 return InnerDIE; 212 } 213 214 void DWARFTypePrinter::appendUnqualifiedNameAfter( 215 DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) { 216 if (!D) 217 return; 218 switch (D.getTag()) { 219 case DW_TAG_subroutine_type: { 220 appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false, 221 false); 222 break; 223 } 224 case DW_TAG_array_type: { 225 appendArrayType(D); 226 break; 227 } 228 case DW_TAG_const_type: 229 case DW_TAG_volatile_type: 230 appendConstVolatileQualifierAfter(D); 231 break; 232 case DW_TAG_ptr_to_member_type: 233 case DW_TAG_reference_type: 234 case DW_TAG_rvalue_reference_type: 235 case DW_TAG_pointer_type: { 236 if (needsParens(Inner)) 237 OS << ')'; 238 appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner), 239 /*SkipFirstParamIfArtificial=*/D.getTag() == 240 DW_TAG_ptr_to_member_type); 241 break; 242 } 243 case DW_TAG_LLVM_ptrauth_type: { 244 auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t { 245 if (auto Form = D.find(Attr)) 246 return *Form->getAsUnsignedConstant(); 247 return 0; 248 }; 249 SmallVector<const char *, 2> optionsVec; 250 if (getValOrNull(DW_AT_LLVM_ptrauth_isa_pointer)) 251 optionsVec.push_back("isa-pointer"); 252 if (getValOrNull(DW_AT_LLVM_ptrauth_authenticates_null_values)) 253 optionsVec.push_back("authenticates-null-values"); 254 if (auto AuthenticationMode = 255 D.find(DW_AT_LLVM_ptrauth_authentication_mode)) { 256 switch (*AuthenticationMode->getAsUnsignedConstant()) { 257 case 0: 258 case 1: 259 optionsVec.push_back("strip"); 260 break; 261 case 2: 262 optionsVec.push_back("sign-and-strip"); 263 break; 264 default: 265 // Default authentication policy 266 break; 267 } 268 } 269 std::string options; 270 for (const auto *option : optionsVec) { 271 if (options.size()) 272 options += ","; 273 options += option; 274 } 275 if (options.size()) 276 options = ", \"" + options + "\""; 277 std::string PtrauthString; 278 llvm::raw_string_ostream PtrauthStream(PtrauthString); 279 PtrauthStream 280 << "__ptrauth(" << getValOrNull(DW_AT_LLVM_ptrauth_key) << ", " 281 << getValOrNull(DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0" 282 << utohexstr(getValOrNull(DW_AT_LLVM_ptrauth_extra_discriminator), true) 283 << options << ")"; 284 OS << PtrauthStream.str(); 285 break; 286 } 287 /* 288 case DW_TAG_structure_type: 289 case DW_TAG_class_type: 290 case DW_TAG_enumeration_type: 291 case DW_TAG_base_type: 292 case DW_TAG_namespace: 293 */ 294 default: 295 break; 296 } 297 } 298 299 /// Returns True if the DIE TAG is one of the ones that is scopped. 300 static bool scopedTAGs(dwarf::Tag Tag) { 301 switch (Tag) { 302 case dwarf::DW_TAG_structure_type: 303 case dwarf::DW_TAG_class_type: 304 case dwarf::DW_TAG_union_type: 305 case dwarf::DW_TAG_namespace: 306 case dwarf::DW_TAG_enumeration_type: 307 return true; 308 default: 309 break; 310 } 311 return false; 312 } 313 void DWARFTypePrinter::appendQualifiedName(DWARFDie D) { 314 if (D && scopedTAGs(D.getTag())) 315 appendScopes(D.getParent()); 316 appendUnqualifiedName(D); 317 } 318 DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) { 319 if (D && scopedTAGs(D.getTag())) 320 appendScopes(D.getParent()); 321 return appendUnqualifiedNameBefore(D); 322 } 323 bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D, 324 bool *FirstParameter) { 325 bool FirstParameterValue = true; 326 bool IsTemplate = false; 327 if (!FirstParameter) 328 FirstParameter = &FirstParameterValue; 329 for (const DWARFDie &C : D) { 330 auto Sep = [&] { 331 if (*FirstParameter) 332 OS << '<'; 333 else 334 OS << ", "; 335 IsTemplate = true; 336 EndedWithTemplate = false; 337 *FirstParameter = false; 338 }; 339 if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) { 340 IsTemplate = true; 341 appendTemplateParameters(C, FirstParameter); 342 } 343 if (C.getTag() == dwarf::DW_TAG_template_value_parameter) { 344 DWARFDie T = resolveReferencedType(C); 345 Sep(); 346 if (T.getTag() == DW_TAG_enumeration_type) { 347 OS << '('; 348 appendQualifiedName(T); 349 OS << ')'; 350 auto V = C.find(DW_AT_const_value); 351 OS << std::to_string(*V->getAsSignedConstant()); 352 continue; 353 } 354 // /Maybe/ we could do pointer/reference type parameters, looking for the 355 // symbol in the ELF symbol table to get back to the variable... 356 // but probably not worth it. 357 if (T.getTag() == DW_TAG_pointer_type || 358 T.getTag() == DW_TAG_reference_type) 359 continue; 360 const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr); 361 assert(RawName); 362 StringRef Name = RawName; 363 auto V = C.find(DW_AT_const_value); 364 bool IsQualifiedChar = false; 365 if (Name == "bool") { 366 OS << (*V->getAsUnsignedConstant() ? "true" : "false"); 367 } else if (Name == "short") { 368 OS << "(short)"; 369 OS << std::to_string(*V->getAsSignedConstant()); 370 } else if (Name == "unsigned short") { 371 OS << "(unsigned short)"; 372 OS << std::to_string(*V->getAsSignedConstant()); 373 } else if (Name == "int") 374 OS << std::to_string(*V->getAsSignedConstant()); 375 else if (Name == "long") { 376 OS << std::to_string(*V->getAsSignedConstant()); 377 OS << "L"; 378 } else if (Name == "long long") { 379 OS << std::to_string(*V->getAsSignedConstant()); 380 OS << "LL"; 381 } else if (Name == "unsigned int") { 382 OS << std::to_string(*V->getAsUnsignedConstant()); 383 OS << "U"; 384 } else if (Name == "unsigned long") { 385 OS << std::to_string(*V->getAsUnsignedConstant()); 386 OS << "UL"; 387 } else if (Name == "unsigned long long") { 388 OS << std::to_string(*V->getAsUnsignedConstant()); 389 OS << "ULL"; 390 } else if (Name == "char" || 391 (IsQualifiedChar = 392 (Name == "unsigned char" || Name == "signed char"))) { 393 // FIXME: check T's DW_AT_type to see if it's signed or not (since 394 // char signedness is implementation defined). 395 auto Val = *V->getAsSignedConstant(); 396 // Copied/hacked up from Clang's CharacterLiteral::print - incomplete 397 // (doesn't actually support different character types/widths, sign 398 // handling's not done, and doesn't correctly test if a character is 399 // printable or needs to use a numeric escape sequence instead) 400 if (IsQualifiedChar) { 401 OS << '('; 402 OS << Name; 403 OS << ')'; 404 } 405 switch (Val) { 406 case '\\': 407 OS << "'\\\\'"; 408 break; 409 case '\'': 410 OS << "'\\''"; 411 break; 412 case '\a': 413 // TODO: K&R: the meaning of '\\a' is different in traditional C 414 OS << "'\\a'"; 415 break; 416 case '\b': 417 OS << "'\\b'"; 418 break; 419 case '\f': 420 OS << "'\\f'"; 421 break; 422 case '\n': 423 OS << "'\\n'"; 424 break; 425 case '\r': 426 OS << "'\\r'"; 427 break; 428 case '\t': 429 OS << "'\\t'"; 430 break; 431 case '\v': 432 OS << "'\\v'"; 433 break; 434 default: 435 if ((Val & ~0xFFu) == ~0xFFu) 436 Val &= 0xFFu; 437 if (Val < 127 && Val >= 32) { 438 OS << "'"; 439 OS << (char)Val; 440 OS << "'"; 441 } else if (Val < 256) 442 OS << llvm::format("'\\x%02" PRIx64 "'", Val); 443 else if (Val <= 0xFFFF) 444 OS << llvm::format("'\\u%04" PRIx64 "'", Val); 445 else 446 OS << llvm::format("'\\U%08" PRIx64 "'", Val); 447 } 448 } 449 continue; 450 } 451 if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) { 452 const char *RawName = 453 dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr); 454 assert(RawName); 455 StringRef Name = RawName; 456 Sep(); 457 OS << Name; 458 continue; 459 } 460 if (C.getTag() != dwarf::DW_TAG_template_type_parameter) 461 continue; 462 auto TypeAttr = C.find(DW_AT_type); 463 Sep(); 464 appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr) 465 : DWARFDie()); 466 } 467 if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) { 468 OS << '<'; 469 EndedWithTemplate = false; 470 } 471 return IsTemplate; 472 } 473 void DWARFTypePrinter::decomposeConstVolatile(DWARFDie &N, DWARFDie &T, 474 DWARFDie &C, DWARFDie &V) { 475 (N.getTag() == DW_TAG_const_type ? C : V) = N; 476 T = resolveReferencedType(N); 477 if (T) { 478 auto Tag = T.getTag(); 479 if (Tag == DW_TAG_const_type) { 480 C = T; 481 T = resolveReferencedType(T); 482 } else if (Tag == DW_TAG_volatile_type) { 483 V = T; 484 T = resolveReferencedType(T); 485 } 486 } 487 } 488 void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) { 489 DWARFDie C; 490 DWARFDie V; 491 DWARFDie T; 492 decomposeConstVolatile(N, T, C, V); 493 if (T && T.getTag() == DW_TAG_subroutine_type) 494 appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(), 495 V.isValid()); 496 else 497 appendUnqualifiedNameAfter(T, resolveReferencedType(T)); 498 } 499 void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) { 500 DWARFDie C; 501 DWARFDie V; 502 DWARFDie T; 503 decomposeConstVolatile(N, T, C, V); 504 bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type; 505 DWARFDie A = T; 506 while (A && A.getTag() == DW_TAG_array_type) 507 A = resolveReferencedType(A); 508 bool Leading = 509 (!A || (A.getTag() != DW_TAG_pointer_type && 510 A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) && 511 !Subroutine; 512 if (Leading) { 513 if (C) 514 OS << "const "; 515 if (V) 516 OS << "volatile "; 517 } 518 appendQualifiedNameBefore(T); 519 if (!Leading && !Subroutine) { 520 Word = true; 521 if (C) 522 OS << "const"; 523 if (V) { 524 if (C) 525 OS << ' '; 526 OS << "volatile"; 527 } 528 } 529 } 530 void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D, 531 std::string *OriginalFullName) { 532 // FIXME: We should have pretty printers per language. Currently we print 533 // everything as if it was C++ and fall back to the TAG type name. 534 DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName); 535 appendUnqualifiedNameAfter(D, Inner); 536 } 537 void DWARFTypePrinter::appendSubroutineNameAfter( 538 DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const, 539 bool Volatile) { 540 DWARFDie FirstParamIfArtificial; 541 OS << '('; 542 EndedWithTemplate = false; 543 bool First = true; 544 bool RealFirst = true; 545 for (DWARFDie P : D) { 546 if (P.getTag() != DW_TAG_formal_parameter && 547 P.getTag() != DW_TAG_unspecified_parameters) 548 return; 549 DWARFDie T = resolveReferencedType(P); 550 if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) { 551 FirstParamIfArtificial = T; 552 RealFirst = false; 553 continue; 554 } 555 if (!First) { 556 OS << ", "; 557 } 558 First = false; 559 if (P.getTag() == DW_TAG_unspecified_parameters) 560 OS << "..."; 561 else 562 appendQualifiedName(T); 563 } 564 EndedWithTemplate = false; 565 OS << ')'; 566 if (FirstParamIfArtificial) { 567 if (DWARFDie P = FirstParamIfArtificial) { 568 if (P.getTag() == DW_TAG_pointer_type) { 569 auto CVStep = [&](DWARFDie CV) { 570 if (DWARFDie U = resolveReferencedType(CV)) { 571 Const |= U.getTag() == DW_TAG_const_type; 572 Volatile |= U.getTag() == DW_TAG_volatile_type; 573 return U; 574 } 575 return DWARFDie(); 576 }; 577 if (DWARFDie CV = CVStep(P)) { 578 CVStep(CV); 579 } 580 } 581 } 582 } 583 584 if (auto CC = D.find(DW_AT_calling_convention)) { 585 switch (*CC->getAsUnsignedConstant()) { 586 case CallingConvention::DW_CC_BORLAND_stdcall: 587 OS << " __attribute__((stdcall))"; 588 break; 589 case CallingConvention::DW_CC_BORLAND_msfastcall: 590 OS << " __attribute__((fastcall))"; 591 break; 592 case CallingConvention::DW_CC_BORLAND_thiscall: 593 OS << " __attribute__((thiscall))"; 594 break; 595 case CallingConvention::DW_CC_LLVM_vectorcall: 596 OS << " __attribute__((vectorcall))"; 597 break; 598 case CallingConvention::DW_CC_BORLAND_pascal: 599 OS << " __attribute__((pascal))"; 600 break; 601 case CallingConvention::DW_CC_LLVM_Win64: 602 OS << " __attribute__((ms_abi))"; 603 break; 604 case CallingConvention::DW_CC_LLVM_X86_64SysV: 605 OS << " __attribute__((sysv_abi))"; 606 break; 607 case CallingConvention::DW_CC_LLVM_AAPCS: 608 // AArch64VectorCall missing? 609 OS << " __attribute__((pcs(\"aapcs\")))"; 610 break; 611 case CallingConvention::DW_CC_LLVM_AAPCS_VFP: 612 OS << " __attribute__((pcs(\"aapcs-vfp\")))"; 613 break; 614 case CallingConvention::DW_CC_LLVM_IntelOclBicc: 615 OS << " __attribute__((intel_ocl_bicc))"; 616 break; 617 case CallingConvention::DW_CC_LLVM_SpirFunction: 618 case CallingConvention::DW_CC_LLVM_OpenCLKernel: 619 // These aren't available as attributes, but maybe we should still 620 // render them somehow? (Clang doesn't render them, but that's an issue 621 // for template names too - since then the DWARF names of templates 622 // instantiated with function types with these calling conventions won't 623 // have distinct names - so we'd need to fix that too) 624 break; 625 case CallingConvention::DW_CC_LLVM_Swift: 626 // SwiftAsync missing 627 OS << " __attribute__((swiftcall))"; 628 break; 629 case CallingConvention::DW_CC_LLVM_PreserveMost: 630 OS << " __attribute__((preserve_most))"; 631 break; 632 case CallingConvention::DW_CC_LLVM_PreserveAll: 633 OS << " __attribute__((preserve_all))"; 634 break; 635 case CallingConvention::DW_CC_LLVM_PreserveNone: 636 OS << " __attribute__((preserve_none))"; 637 break; 638 case CallingConvention::DW_CC_LLVM_X86RegCall: 639 OS << " __attribute__((regcall))"; 640 break; 641 case CallingConvention::DW_CC_LLVM_M68kRTD: 642 OS << " __attribute__((m68k_rtd))"; 643 break; 644 } 645 } 646 647 if (Const) 648 OS << " const"; 649 if (Volatile) 650 OS << " volatile"; 651 if (D.find(DW_AT_reference)) 652 OS << " &"; 653 if (D.find(DW_AT_rvalue_reference)) 654 OS << " &&"; 655 656 appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner)); 657 } 658 void DWARFTypePrinter::appendScopes(DWARFDie D) { 659 if (D.getTag() == DW_TAG_compile_unit) 660 return; 661 if (D.getTag() == DW_TAG_type_unit) 662 return; 663 if (D.getTag() == DW_TAG_skeleton_unit) 664 return; 665 if (D.getTag() == DW_TAG_subprogram) 666 return; 667 if (D.getTag() == DW_TAG_lexical_block) 668 return; 669 D = D.resolveTypeUnitReference(); 670 if (DWARFDie P = D.getParent()) 671 appendScopes(P); 672 appendUnqualifiedName(D); 673 OS << "::"; 674 } 675 } // namespace llvm 676