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.startswith(Prefix) || !TagStr.endswith(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 Optional<uint64_t> LB; 23 Optional<uint64_t> Count; 24 Optional<uint64_t> UB; 25 Optional<unsigned> DefaultLB; 26 if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound)) 27 LB = L->getAsUnsignedConstant(); 28 if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count)) 29 Count = CountV->getAsUnsignedConstant(); 30 if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound)) 31 UB = UpperV->getAsUnsignedConstant(); 32 if (Optional<DWARFFormValue> LV = 33 D.getDwarfUnit()->getUnitDIE().find(DW_AT_language)) 34 if (Optional<uint64_t> LC = LV->getAsUnsignedConstant()) 35 if ((DefaultLB = 36 LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC)))) 37 if (LB && *LB == *DefaultLB) 38 LB = None; 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_const_type: 147 case DW_TAG_volatile_type: 148 appendConstVolatileQualifierBefore(D); 149 break; 150 case DW_TAG_namespace: { 151 if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr)) 152 OS << Name; 153 else 154 OS << "(anonymous namespace)"; 155 break; 156 } 157 case DW_TAG_unspecified_type: { 158 StringRef TypeName = D.getShortName(); 159 if (TypeName == "decltype(nullptr)") 160 TypeName = "std::nullptr_t"; 161 Word = true; 162 OS << TypeName; 163 EndedWithTemplate = false; 164 break; 165 } 166 /* 167 case DW_TAG_structure_type: 168 case DW_TAG_class_type: 169 case DW_TAG_enumeration_type: 170 case DW_TAG_base_type: 171 */ 172 default: { 173 const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr); 174 if (!NamePtr) { 175 appendTypeTagName(D.getTag()); 176 return DWARFDie(); 177 } 178 Word = true; 179 StringRef Name = NamePtr; 180 static constexpr StringRef MangledPrefix = "_STN|"; 181 if (Name.startswith(MangledPrefix)) { 182 Name = Name.drop_front(MangledPrefix.size()); 183 auto Separator = Name.find('|'); 184 assert(Separator != StringRef::npos); 185 StringRef BaseName = Name.substr(0, Separator); 186 StringRef TemplateArgs = Name.substr(Separator + 1); 187 if (OriginalFullName) 188 *OriginalFullName = (BaseName + TemplateArgs).str(); 189 Name = BaseName; 190 } else 191 EndedWithTemplate = Name.endswith(">"); 192 OS << Name; 193 // This check would be insufficient for operator overloads like 194 // "operator>>" - but for now Clang doesn't try to simplify them, so this 195 // is OK. Add more nuanced operator overload handling here if/when needed. 196 if (Name.endswith(">")) 197 break; 198 if (!appendTemplateParameters(D)) 199 break; 200 201 if (EndedWithTemplate) 202 OS << ' '; 203 OS << '>'; 204 EndedWithTemplate = true; 205 Word = true; 206 break; 207 } 208 } 209 return InnerDIE; 210 } 211 212 void DWARFTypePrinter::appendUnqualifiedNameAfter( 213 DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) { 214 if (!D) 215 return; 216 switch (D.getTag()) { 217 case DW_TAG_subroutine_type: { 218 appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false, 219 false); 220 break; 221 } 222 case DW_TAG_array_type: { 223 appendArrayType(D); 224 break; 225 } 226 case DW_TAG_const_type: 227 case DW_TAG_volatile_type: 228 appendConstVolatileQualifierAfter(D); 229 break; 230 case DW_TAG_ptr_to_member_type: 231 case DW_TAG_reference_type: 232 case DW_TAG_rvalue_reference_type: 233 case DW_TAG_pointer_type: { 234 if (needsParens(Inner)) 235 OS << ')'; 236 appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner), 237 /*SkipFirstParamIfArtificial=*/D.getTag() == 238 DW_TAG_ptr_to_member_type); 239 break; 240 } 241 /* 242 case DW_TAG_structure_type: 243 case DW_TAG_class_type: 244 case DW_TAG_enumeration_type: 245 case DW_TAG_base_type: 246 case DW_TAG_namespace: 247 */ 248 default: 249 break; 250 } 251 } 252 253 void DWARFTypePrinter::appendQualifiedName(DWARFDie D) { 254 if (D) 255 appendScopes(D.getParent()); 256 appendUnqualifiedName(D); 257 } 258 DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) { 259 if (D) 260 appendScopes(D.getParent()); 261 return appendUnqualifiedNameBefore(D); 262 } 263 bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D, 264 bool *FirstParameter) { 265 bool FirstParameterValue = true; 266 bool IsTemplate = false; 267 if (!FirstParameter) 268 FirstParameter = &FirstParameterValue; 269 for (const DWARFDie &C : D) { 270 auto Sep = [&] { 271 if (*FirstParameter) 272 OS << '<'; 273 else 274 OS << ", "; 275 IsTemplate = true; 276 EndedWithTemplate = false; 277 *FirstParameter = false; 278 }; 279 if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) { 280 IsTemplate = true; 281 appendTemplateParameters(C, FirstParameter); 282 } 283 if (C.getTag() == dwarf::DW_TAG_template_value_parameter) { 284 DWARFDie T = resolveReferencedType(C); 285 Sep(); 286 if (T.getTag() == DW_TAG_enumeration_type) { 287 OS << '('; 288 appendQualifiedName(T); 289 OS << ')'; 290 auto V = C.find(DW_AT_const_value); 291 OS << std::to_string(*V->getAsSignedConstant()); 292 continue; 293 } 294 // /Maybe/ we could do pointer type parameters, looking for the 295 // symbol in the ELF symbol table to get back to the variable... 296 // but probably not worth it. 297 if (T.getTag() == DW_TAG_pointer_type) 298 continue; 299 const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr); 300 assert(RawName); 301 StringRef Name = RawName; 302 auto V = C.find(DW_AT_const_value); 303 bool IsQualifiedChar = false; 304 if (Name == "bool") { 305 OS << (*V->getAsUnsignedConstant() ? "true" : "false"); 306 } else if (Name == "short") { 307 OS << "(short)"; 308 OS << std::to_string(*V->getAsSignedConstant()); 309 } else if (Name == "unsigned short") { 310 OS << "(unsigned short)"; 311 OS << std::to_string(*V->getAsSignedConstant()); 312 } else if (Name == "int") 313 OS << std::to_string(*V->getAsSignedConstant()); 314 else if (Name == "long") { 315 OS << std::to_string(*V->getAsSignedConstant()); 316 OS << "L"; 317 } else if (Name == "long long") { 318 OS << std::to_string(*V->getAsSignedConstant()); 319 OS << "LL"; 320 } else if (Name == "unsigned int") { 321 OS << std::to_string(*V->getAsUnsignedConstant()); 322 OS << "U"; 323 } else if (Name == "unsigned long") { 324 OS << std::to_string(*V->getAsUnsignedConstant()); 325 OS << "UL"; 326 } else if (Name == "unsigned long long") { 327 OS << std::to_string(*V->getAsUnsignedConstant()); 328 OS << "ULL"; 329 } else if (Name == "char" || 330 (IsQualifiedChar = 331 (Name == "unsigned char" || Name == "signed char"))) { 332 // FIXME: check T's DW_AT_type to see if it's signed or not (since 333 // char signedness is implementation defined). 334 auto Val = *V->getAsSignedConstant(); 335 // Copied/hacked up from Clang's CharacterLiteral::print - incomplete 336 // (doesn't actually support different character types/widths, sign 337 // handling's not done, and doesn't correctly test if a character is 338 // printable or needs to use a numeric escape sequence instead) 339 if (IsQualifiedChar) { 340 OS << '('; 341 OS << Name; 342 OS << ')'; 343 } 344 switch (Val) { 345 case '\\': 346 OS << "'\\\\'"; 347 break; 348 case '\'': 349 OS << "'\\''"; 350 break; 351 case '\a': 352 // TODO: K&R: the meaning of '\\a' is different in traditional C 353 OS << "'\\a'"; 354 break; 355 case '\b': 356 OS << "'\\b'"; 357 break; 358 case '\f': 359 OS << "'\\f'"; 360 break; 361 case '\n': 362 OS << "'\\n'"; 363 break; 364 case '\r': 365 OS << "'\\r'"; 366 break; 367 case '\t': 368 OS << "'\\t'"; 369 break; 370 case '\v': 371 OS << "'\\v'"; 372 break; 373 default: 374 if ((Val & ~0xFFu) == ~0xFFu) 375 Val &= 0xFFu; 376 if (Val < 127 && Val >= 32) { 377 OS << "'"; 378 OS << (char)Val; 379 OS << "'"; 380 } else if (Val < 256) 381 OS << to_string(llvm::format("'\\x%02x'", Val)); 382 else if (Val <= 0xFFFF) 383 OS << to_string(llvm::format("'\\u%04x'", Val)); 384 else 385 OS << to_string(llvm::format("'\\U%08x'", Val)); 386 } 387 } 388 continue; 389 } 390 if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) { 391 const char *RawName = 392 dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr); 393 assert(RawName); 394 StringRef Name = RawName; 395 Sep(); 396 OS << Name; 397 continue; 398 } 399 if (C.getTag() != dwarf::DW_TAG_template_type_parameter) 400 continue; 401 auto TypeAttr = C.find(DW_AT_type); 402 Sep(); 403 appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr) 404 : DWARFDie()); 405 } 406 if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) { 407 OS << '<'; 408 EndedWithTemplate = false; 409 } 410 return IsTemplate; 411 } 412 void DWARFTypePrinter::decomposeConstVolatile(DWARFDie &N, DWARFDie &T, 413 DWARFDie &C, DWARFDie &V) { 414 (N.getTag() == DW_TAG_const_type ? C : V) = N; 415 T = resolveReferencedType(N); 416 if (T) { 417 auto Tag = T.getTag(); 418 if (Tag == DW_TAG_const_type) { 419 C = T; 420 T = resolveReferencedType(T); 421 } else if (Tag == DW_TAG_volatile_type) { 422 V = T; 423 T = resolveReferencedType(T); 424 } 425 } 426 } 427 void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) { 428 DWARFDie C; 429 DWARFDie V; 430 DWARFDie T; 431 decomposeConstVolatile(N, T, C, V); 432 if (T && T.getTag() == DW_TAG_subroutine_type) 433 appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(), 434 V.isValid()); 435 else 436 appendUnqualifiedNameAfter(T, resolveReferencedType(T)); 437 } 438 void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) { 439 DWARFDie C; 440 DWARFDie V; 441 DWARFDie T; 442 decomposeConstVolatile(N, T, C, V); 443 bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type; 444 DWARFDie A = T; 445 while (A && A.getTag() == DW_TAG_array_type) 446 A = resolveReferencedType(A); 447 bool Leading = 448 (!A || (A.getTag() != DW_TAG_pointer_type && 449 A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) && 450 !Subroutine; 451 if (Leading) { 452 if (C) 453 OS << "const "; 454 if (V) 455 OS << "volatile "; 456 } 457 appendQualifiedNameBefore(T); 458 if (!Leading && !Subroutine) { 459 Word = true; 460 if (C) 461 OS << "const"; 462 if (V) { 463 if (C) 464 OS << ' '; 465 OS << "volatile"; 466 } 467 } 468 } 469 void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D, 470 std::string *OriginalFullName) { 471 // FIXME: We should have pretty printers per language. Currently we print 472 // everything as if it was C++ and fall back to the TAG type name. 473 DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName); 474 appendUnqualifiedNameAfter(D, Inner); 475 } 476 void DWARFTypePrinter::appendSubroutineNameAfter( 477 DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const, 478 bool Volatile) { 479 DWARFDie FirstParamIfArtificial; 480 OS << '('; 481 EndedWithTemplate = false; 482 bool First = true; 483 bool RealFirst = true; 484 for (DWARFDie P : D) { 485 if (P.getTag() != DW_TAG_formal_parameter && 486 P.getTag() != DW_TAG_unspecified_parameters) 487 return; 488 DWARFDie T = resolveReferencedType(P); 489 if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) { 490 FirstParamIfArtificial = T; 491 RealFirst = false; 492 continue; 493 } 494 if (!First) { 495 OS << ", "; 496 } 497 First = false; 498 if (P.getTag() == DW_TAG_unspecified_parameters) 499 OS << "..."; 500 else 501 appendQualifiedName(T); 502 } 503 EndedWithTemplate = false; 504 OS << ')'; 505 if (FirstParamIfArtificial) { 506 if (DWARFDie P = FirstParamIfArtificial) { 507 if (P.getTag() == DW_TAG_pointer_type) { 508 auto CVStep = [&](DWARFDie CV) { 509 if (DWARFDie U = resolveReferencedType(CV)) { 510 Const |= U.getTag() == DW_TAG_const_type; 511 Volatile |= U.getTag() == DW_TAG_volatile_type; 512 return U; 513 } 514 return DWARFDie(); 515 }; 516 if (DWARFDie CV = CVStep(P)) { 517 CVStep(CV); 518 } 519 } 520 } 521 } 522 523 if (auto CC = D.find(DW_AT_calling_convention)) { 524 switch (*CC->getAsUnsignedConstant()) { 525 case CallingConvention::DW_CC_BORLAND_stdcall: 526 OS << " __attribute__((stdcall))"; 527 break; 528 case CallingConvention::DW_CC_BORLAND_msfastcall: 529 OS << " __attribute__((fastcall))"; 530 break; 531 case CallingConvention::DW_CC_BORLAND_thiscall: 532 OS << " __attribute__((thiscall))"; 533 break; 534 case CallingConvention::DW_CC_LLVM_vectorcall: 535 OS << " __attribute__((vectorcall))"; 536 break; 537 case CallingConvention::DW_CC_BORLAND_pascal: 538 OS << " __attribute__((pascal))"; 539 break; 540 case CallingConvention::DW_CC_LLVM_Win64: 541 OS << " __attribute__((ms_abi))"; 542 break; 543 case CallingConvention::DW_CC_LLVM_X86_64SysV: 544 OS << " __attribute__((sysv_abi))"; 545 break; 546 case CallingConvention::DW_CC_LLVM_AAPCS: 547 // AArch64VectorCall missing? 548 OS << " __attribute__((pcs(\"aapcs\")))"; 549 break; 550 case CallingConvention::DW_CC_LLVM_AAPCS_VFP: 551 OS << " __attribute__((pcs(\"aapcs-vfp\")))"; 552 break; 553 case CallingConvention::DW_CC_LLVM_IntelOclBicc: 554 OS << " __attribute__((intel_ocl_bicc))"; 555 break; 556 case CallingConvention::DW_CC_LLVM_SpirFunction: 557 case CallingConvention::DW_CC_LLVM_OpenCLKernel: 558 // These aren't available as attributes, but maybe we should still 559 // render them somehow? (Clang doesn't render them, but that's an issue 560 // for template names too - since then the DWARF names of templates 561 // instantiated with function types with these calling conventions won't 562 // have distinct names - so we'd need to fix that too) 563 break; 564 case CallingConvention::DW_CC_LLVM_Swift: 565 // SwiftAsync missing 566 OS << " __attribute__((swiftcall))"; 567 break; 568 case CallingConvention::DW_CC_LLVM_PreserveMost: 569 OS << " __attribute__((preserve_most))"; 570 break; 571 case CallingConvention::DW_CC_LLVM_PreserveAll: 572 OS << " __attribute__((preserve_all))"; 573 break; 574 case CallingConvention::DW_CC_LLVM_X86RegCall: 575 OS << " __attribute__((regcall))"; 576 break; 577 } 578 } 579 580 if (Const) 581 OS << " const"; 582 if (Volatile) 583 OS << " volatile"; 584 if (D.find(DW_AT_reference)) 585 OS << " &"; 586 if (D.find(DW_AT_rvalue_reference)) 587 OS << " &&"; 588 589 appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner)); 590 } 591 void DWARFTypePrinter::appendScopes(DWARFDie D) { 592 if (D.getTag() == DW_TAG_compile_unit) 593 return; 594 if (D.getTag() == DW_TAG_type_unit) 595 return; 596 if (D.getTag() == DW_TAG_skeleton_unit) 597 return; 598 if (D.getTag() == DW_TAG_subprogram) 599 return; 600 if (D.getTag() == DW_TAG_lexical_block) 601 return; 602 D = D.resolveTypeUnitReference(); 603 if (DWARFDie P = D.getParent()) 604 appendScopes(P); 605 appendUnqualifiedName(D); 606 OS << "::"; 607 } 608 } // namespace llvm 609