1 //===-- LVElement.cpp -----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This implements the LVElement class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/DebugInfo/LogicalView/Core/LVElement.h" 14 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" 15 #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" 16 #include "llvm/DebugInfo/LogicalView/Core/LVType.h" 17 18 using namespace llvm; 19 using namespace llvm::codeview; 20 using namespace llvm::logicalview; 21 22 #define DEBUG_TYPE "Element" 23 24 LVElementDispatch LVElement::Dispatch = { 25 {LVElementKind::Discarded, &LVElement::getIsDiscarded}, 26 {LVElementKind::Global, &LVElement::getIsGlobalReference}, 27 {LVElementKind::Optimized, &LVElement::getIsOptimized}}; 28 29 LVType *LVElement::getTypeAsType() const { 30 return ElementType && ElementType->getIsType() 31 ? static_cast<LVType *>(ElementType) 32 : nullptr; 33 } 34 35 LVScope *LVElement::getTypeAsScope() const { 36 return ElementType && ElementType->getIsScope() 37 ? static_cast<LVScope *>(ElementType) 38 : nullptr; 39 } 40 41 // Set the element type. 42 void LVElement::setGenericType(LVElement *Element) { 43 if (!Element->isTemplateParam()) { 44 setType(Element); 45 return; 46 } 47 // For template parameters, the instance type can be a type or a scope. 48 if (options().getAttributeArgument()) { 49 if (Element->getIsKindType()) 50 setType(Element->getTypeAsType()); 51 else if (Element->getIsKindScope()) 52 setType(Element->getTypeAsScope()); 53 } else 54 setType(Element); 55 } 56 57 // Discriminator as string. 58 std::string LVElement::discriminatorAsString() const { 59 uint32_t Discriminator = getDiscriminator(); 60 std::string String; 61 raw_string_ostream Stream(String); 62 if (Discriminator && options().getAttributeDiscriminator()) 63 Stream << "," << Discriminator; 64 return String; 65 } 66 67 // Get the type as a string. 68 StringRef LVElement::typeAsString() const { 69 return getHasType() ? getTypeName() : typeVoid(); 70 } 71 72 // Get name for element type. 73 StringRef LVElement::getTypeName() const { 74 return ElementType ? ElementType->getName() : StringRef(); 75 } 76 77 static size_t getStringIndex(StringRef Name) { 78 // Convert the name to Unified format ('\' have been converted into '/'). 79 std::string Pathname(transformPath(Name)); 80 81 // Depending on the --attribute=filename and --attribute=pathname command 82 // line options, use the basename or the full pathname as the name. 83 if (!options().getAttributePathname()) { 84 // Get the basename by ignoring any prefix up to the last slash ('/'). 85 StringRef Basename = Pathname; 86 size_t Pos = Basename.rfind('/'); 87 if (Pos != std::string::npos) 88 Basename = Basename.substr(Pos + 1); 89 return getStringPool().getIndex(Basename); 90 } 91 92 return getStringPool().getIndex(Pathname); 93 } 94 95 void LVElement::setName(StringRef ElementName) { 96 // In the case of Root or Compile Unit, get index for the flatted out name. 97 NameIndex = getTransformName() ? getStringIndex(ElementName) 98 : getStringPool().getIndex(ElementName); 99 } 100 101 void LVElement::setFilename(StringRef Filename) { 102 // Get index for the flattened out filename. 103 FilenameIndex = getStringIndex(Filename); 104 } 105 106 void LVElement::setInnerComponent(StringRef Name) { 107 if (Name.size()) { 108 StringRef InnerComponent; 109 std::tie(std::ignore, InnerComponent) = getInnerComponent(Name); 110 setName(InnerComponent); 111 } 112 } 113 114 // Return the string representation of a DIE offset. 115 std::string LVElement::typeOffsetAsString() const { 116 if (options().getAttributeOffset()) { 117 LVElement *Element = getType(); 118 return hexSquareString(Element ? Element->getOffset() : 0); 119 } 120 return {}; 121 } 122 123 StringRef LVElement::accessibilityString(uint32_t Access) const { 124 uint32_t Value = getAccessibilityCode(); 125 switch (Value ? Value : Access) { 126 case dwarf::DW_ACCESS_public: 127 return "public"; 128 case dwarf::DW_ACCESS_protected: 129 return "protected"; 130 case dwarf::DW_ACCESS_private: 131 return "private"; 132 default: 133 return StringRef(); 134 } 135 } 136 137 std::optional<uint32_t> LVElement::getAccessibilityCode(MemberAccess Access) { 138 switch (Access) { 139 case MemberAccess::Private: 140 return dwarf::DW_ACCESS_private; 141 case MemberAccess::Protected: 142 return dwarf::DW_ACCESS_protected; 143 case MemberAccess::Public: 144 return dwarf::DW_ACCESS_public; 145 default: 146 return std::nullopt; 147 } 148 } 149 150 StringRef LVElement::externalString() const { 151 return getIsExternal() ? "extern" : StringRef(); 152 } 153 154 StringRef LVElement::inlineCodeString(uint32_t Code) const { 155 uint32_t Value = getInlineCode(); 156 switch (Value ? Value : Code) { 157 case dwarf::DW_INL_not_inlined: 158 return "not_inlined"; 159 case dwarf::DW_INL_inlined: 160 return "inlined"; 161 case dwarf::DW_INL_declared_not_inlined: 162 return "declared_not_inlined"; 163 case dwarf::DW_INL_declared_inlined: 164 return "declared_inlined"; 165 default: 166 return StringRef(); 167 } 168 } 169 170 StringRef LVElement::virtualityString(uint32_t Virtuality) const { 171 uint32_t Value = getVirtualityCode(); 172 switch (Value ? Value : Virtuality) { 173 case dwarf::DW_VIRTUALITY_none: 174 return StringRef(); 175 case dwarf::DW_VIRTUALITY_virtual: 176 return "virtual"; 177 case dwarf::DW_VIRTUALITY_pure_virtual: 178 return "pure virtual"; 179 default: 180 return StringRef(); 181 } 182 } 183 184 std::optional<uint32_t> LVElement::getVirtualityCode(MethodKind Virtuality) { 185 switch (Virtuality) { 186 case MethodKind::Virtual: 187 return dwarf::DW_VIRTUALITY_virtual; 188 case MethodKind::PureVirtual: 189 return dwarf::DW_VIRTUALITY_pure_virtual; 190 case MethodKind::IntroducingVirtual: 191 case MethodKind::PureIntroducingVirtual: 192 // No direct equivalents in DWARF. Assume Virtual. 193 return dwarf::DW_VIRTUALITY_virtual; 194 default: 195 return std::nullopt; 196 } 197 } 198 199 void LVElement::resolve() { 200 if (getIsResolved()) 201 return; 202 setIsResolved(); 203 204 resolveReferences(); 205 resolveParents(); 206 resolveExtra(); 207 resolveName(); 208 } 209 210 // Set File/Line using the specification element. 211 void LVElement::setFileLine(LVElement *Specification) { 212 // In the case of inlined functions, the correct scope must be associated 213 // with the file and line information of the outline version. 214 if (!isLined()) { 215 setLineNumber(Specification->getLineNumber()); 216 setIsLineFromReference(); 217 } 218 if (!isFiled()) { 219 setFilenameIndex(Specification->getFilenameIndex()); 220 setIsFileFromReference(); 221 } 222 } 223 224 void LVElement::resolveName() { 225 // Set the qualified name if requested. 226 if (options().getAttributeQualified()) 227 resolveQualifiedName(); 228 229 setIsResolvedName(); 230 } 231 232 // Resolve any parents. 233 void LVElement::resolveParents() { 234 if (isRoot() || isCompileUnit()) 235 return; 236 237 LVScope *Parent = getParentScope(); 238 if (Parent && !Parent->getIsCompileUnit()) 239 Parent->resolve(); 240 } 241 242 // Generate a name for unnamed elements. 243 void LVElement::generateName(std::string &Prefix) const { 244 LVScope *Scope = getParentScope(); 245 if (!Scope) 246 return; 247 248 // Use its parent name and any line information. 249 Prefix.append(std::string(Scope->getName())); 250 Prefix.append("::"); 251 Prefix.append(isLined() ? lineNumberAsString(/*ShowZero=*/true) : "?"); 252 253 // Remove any whitespaces. 254 llvm::erase_if(Prefix, ::isspace); 255 } 256 257 // Generate a name for unnamed elements. 258 void LVElement::generateName() { 259 setIsAnonymous(); 260 std::string Name; 261 generateName(Name); 262 setName(Name); 263 setIsGeneratedName(); 264 } 265 266 void LVElement::updateLevel(LVScope *Parent, bool Moved) { 267 setLevel(Parent->getLevel() + 1); 268 if (Moved) 269 setHasMoved(); 270 } 271 272 // Generate the full name for the element, to include special qualifiers. 273 void LVElement::resolveFullname(LVElement *BaseType, StringRef Name) { 274 // For the following sample code, 275 // void *p; 276 // some compilers do not generate an attribute for the associated type: 277 // DW_TAG_variable 278 // DW_AT_name 'p' 279 // DW_AT_type $1 280 // ... 281 // $1: DW_TAG_pointer_type 282 // ... 283 // For those cases, generate the implicit 'void' type. 284 StringRef BaseTypename = BaseType ? BaseType->getName() : emptyString(); 285 bool GetBaseTypename = false; 286 bool UseBaseTypename = true; 287 bool UseNameText = true; 288 289 switch (getTag()) { 290 case dwarf::DW_TAG_pointer_type: // "*"; 291 if (!BaseType) 292 BaseTypename = typeVoid(); 293 break; 294 case dwarf::DW_TAG_const_type: // "const" 295 case dwarf::DW_TAG_ptr_to_member_type: // "*" 296 case dwarf::DW_TAG_rvalue_reference_type: // "&&" 297 case dwarf::DW_TAG_reference_type: // "&" 298 case dwarf::DW_TAG_restrict_type: // "restrict" 299 case dwarf::DW_TAG_volatile_type: // "volatile" 300 case dwarf::DW_TAG_unaligned: // "unaligned" 301 break; 302 case dwarf::DW_TAG_base_type: 303 case dwarf::DW_TAG_compile_unit: 304 case dwarf::DW_TAG_class_type: 305 case dwarf::DW_TAG_enumerator: 306 case dwarf::DW_TAG_namespace: 307 case dwarf::DW_TAG_skeleton_unit: 308 case dwarf::DW_TAG_structure_type: 309 case dwarf::DW_TAG_union_type: 310 case dwarf::DW_TAG_unspecified_type: 311 case dwarf::DW_TAG_GNU_template_parameter_pack: 312 GetBaseTypename = true; 313 break; 314 case dwarf::DW_TAG_array_type: 315 case dwarf::DW_TAG_call_site: 316 case dwarf::DW_TAG_entry_point: 317 case dwarf::DW_TAG_enumeration_type: 318 case dwarf::DW_TAG_GNU_call_site: 319 case dwarf::DW_TAG_imported_module: 320 case dwarf::DW_TAG_imported_declaration: 321 case dwarf::DW_TAG_inlined_subroutine: 322 case dwarf::DW_TAG_label: 323 case dwarf::DW_TAG_subprogram: 324 case dwarf::DW_TAG_subrange_type: 325 case dwarf::DW_TAG_subroutine_type: 326 case dwarf::DW_TAG_typedef: 327 GetBaseTypename = true; 328 UseBaseTypename = false; 329 break; 330 case dwarf::DW_TAG_template_type_parameter: 331 case dwarf::DW_TAG_template_value_parameter: 332 UseBaseTypename = false; 333 break; 334 case dwarf::DW_TAG_GNU_template_template_param: 335 break; 336 case dwarf::DW_TAG_catch_block: 337 case dwarf::DW_TAG_lexical_block: 338 case dwarf::DW_TAG_try_block: 339 UseNameText = false; 340 break; 341 default: 342 llvm_unreachable("Invalid type."); 343 return; 344 break; 345 } 346 347 // Overwrite if no given value. 'Name' is empty when resolving for scopes 348 // and symbols. In the case of types, it represents the type base name. 349 if (Name.empty() && GetBaseTypename) 350 Name = getName(); 351 352 // Concatenate the elements to get the full type name. 353 // Type will be: base_parent + pre + base + parent + post. 354 std::string Fullname; 355 356 if (UseNameText && Name.size()) 357 Fullname.append(std::string(Name)); 358 if (UseBaseTypename && BaseTypename.size()) { 359 if (UseNameText && Name.size()) 360 Fullname.append(" "); 361 Fullname.append(std::string(BaseTypename)); 362 } 363 364 // For a better and consistent layout, check if the generated name 365 // contains double space sequences. 366 assert((Fullname.find(" ", 0) == std::string::npos) && 367 "Extra double spaces in name."); 368 369 LLVM_DEBUG({ dbgs() << "Fullname = '" << Fullname << "'\n"; }); 370 setName(Fullname); 371 } 372 373 void LVElement::setFile(LVElement *Reference) { 374 if (!options().getAttributeAnySource()) 375 return; 376 377 // At this point, any existing reference to another element, have been 378 // resolved and the file ID extracted from the DI entry. 379 if (Reference) 380 setFileLine(Reference); 381 382 // The file information is used to show the source file for any element 383 // and display any new source file in relation to its parent element. 384 // a) Elements that are not inlined. 385 // - We record the DW_AT_decl_line and DW_AT_decl_file. 386 // b) Elements that are inlined. 387 // - We record the DW_AT_decl_line and DW_AT_decl_file. 388 // - We record the DW_AT_call_line and DW_AT_call_file. 389 // For both cases, we use the DW_AT_decl_file value to detect any changes 390 // in the source filename containing the element. Changes on this value 391 // indicates that the element being printed is not contained in the 392 // previous printed filename. 393 394 // The source files are indexed starting at 0, but DW_AT_decl_file defines 395 // that 0 means no file; a value of 1 means the 0th entry. 396 size_t Index = 0; 397 398 // An element with no source file information will use the reference 399 // attribute (DW_AT_specification, DW_AT_abstract_origin, DW_AT_extension) 400 // to update its information. 401 if (getIsFileFromReference() && Reference) { 402 Index = Reference->getFilenameIndex(); 403 if (Reference->getInvalidFilename()) 404 setInvalidFilename(); 405 setFilenameIndex(Index); 406 return; 407 } 408 409 // The source files are indexed starting at 0, but DW_AT_decl_file 410 // defines that 0 means no file; a value of 1 means the 0th entry. 411 Index = getFilenameIndex(); 412 if (Index) { 413 StringRef Filename = getReader().getFilename(this, Index); 414 Filename.size() ? setFilename(Filename) : setInvalidFilename(); 415 } 416 } 417 418 LVScope *LVElement::traverseParents(LVScopeGetFunction GetFunction) const { 419 LVScope *Parent = getParentScope(); 420 while (Parent && !(Parent->*GetFunction)()) 421 Parent = Parent->getParentScope(); 422 return Parent; 423 } 424 425 LVScope *LVElement::getFunctionParent() const { 426 return traverseParents(&LVScope::getIsFunction); 427 } 428 429 LVScope *LVElement::getCompileUnitParent() const { 430 return traverseParents(&LVScope::getIsCompileUnit); 431 } 432 433 // Resolve the qualified name to include the parent hierarchy names. 434 void LVElement::resolveQualifiedName() { 435 if (!getIsReferencedType() || isBase() || getQualifiedResolved() || 436 !getIncludeInPrint()) 437 return; 438 439 std::string Name; 440 441 // Get the qualified name, excluding the Compile Unit. 442 LVScope *Parent = getParentScope(); 443 if (Parent && !Parent->getIsRoot()) { 444 while (Parent && !Parent->getIsCompileUnit()) { 445 Name.insert(0, "::"); 446 if (Parent->isNamed()) 447 Name.insert(0, std::string(Parent->getName())); 448 else { 449 std::string Temp; 450 Parent->generateName(Temp); 451 Name.insert(0, Temp); 452 } 453 Parent = Parent->getParentScope(); 454 } 455 } 456 457 if (Name.size()) { 458 setQualifiedName(Name); 459 setQualifiedResolved(); 460 } 461 LLVM_DEBUG({ 462 dbgs() << "Offset: " << hexSquareString(getOffset()) 463 << ", Kind: " << formattedKind(kind()) 464 << ", Name: " << formattedName(getName()) 465 << ", QualifiedName: " << formattedName(Name) << "\n"; 466 }); 467 } 468 469 bool LVElement::referenceMatch(const LVElement *Element) const { 470 return (getHasReference() && Element->getHasReference()) || 471 (!getHasReference() && !Element->getHasReference()); 472 } 473 474 bool LVElement::equals(const LVElement *Element) const { 475 // The minimum factors that must be the same for an equality are: 476 // line number, level, name, qualified name and filename. 477 LLVM_DEBUG({ 478 dbgs() << "\n[Element::equals]\n"; 479 if (options().getAttributeOffset()) { 480 dbgs() << "Reference: " << hexSquareString(getOffset()) << "\n"; 481 dbgs() << "Target : " << hexSquareString(Element->getOffset()) << "\n"; 482 } 483 dbgs() << "Reference: " 484 << "Kind = " << formattedKind(kind()) << ", " 485 << "Name = " << formattedName(getName()) << ", " 486 << "Qualified = " << formattedName(getQualifiedName()) << "\n" 487 << "Target : " 488 << "Kind = " << formattedKind(Element->kind()) << ", " 489 << "Name = " << formattedName(Element->getName()) << ", " 490 << "Qualified = " << formattedName(Element->getQualifiedName()) 491 << "\n" 492 << "Reference: " 493 << "NameIndex = " << getNameIndex() << ", " 494 << "QualifiedNameIndex = " << getQualifiedNameIndex() << ", " 495 << "FilenameIndex = " << getFilenameIndex() << "\n" 496 << "Target : " 497 << "NameIndex = " << Element->getNameIndex() << ", " 498 << "QualifiedNameIndex = " << Element->getQualifiedNameIndex() 499 << ", " 500 << "FilenameIndex = " << Element->getFilenameIndex() << "\n"; 501 }); 502 if ((getLineNumber() != Element->getLineNumber()) || 503 (getLevel() != Element->getLevel())) 504 return false; 505 506 if ((getQualifiedNameIndex() != Element->getQualifiedNameIndex()) || 507 (getNameIndex() != Element->getNameIndex()) || 508 (getFilenameIndex() != Element->getFilenameIndex())) 509 return false; 510 511 if (!getType() && !Element->getType()) 512 return true; 513 if (getType() && Element->getType()) 514 return getType()->equals(Element->getType()); 515 return false; 516 } 517 518 // Print the FileName Index. 519 void LVElement::printFileIndex(raw_ostream &OS, bool Full) const { 520 if (options().getPrintFormatting() && options().getAttributeAnySource() && 521 getFilenameIndex()) { 522 523 // Check if there is a change in the File ID sequence. 524 size_t Index = getFilenameIndex(); 525 if (options().changeFilenameIndex(Index)) { 526 // Just to keep a nice layout. 527 OS << "\n"; 528 printAttributes(OS, /*Full=*/false); 529 530 OS << " {Source} "; 531 if (getInvalidFilename()) 532 OS << format("[0x%08x]\n", Index); 533 else 534 OS << formattedName(getPathname()) << "\n"; 535 } 536 } 537 } 538 539 void LVElement::printReference(raw_ostream &OS, bool Full, 540 LVElement *Parent) const { 541 if (options().getPrintFormatting() && options().getAttributeReference()) 542 printAttributes(OS, Full, "{Reference} ", Parent, 543 referenceAsString(getLineNumber(), /*Spaces=*/false), 544 /*UseQuotes=*/false, /*PrintRef=*/true); 545 } 546 547 void LVElement::printLinkageName(raw_ostream &OS, bool Full, 548 LVElement *Parent) const { 549 if (options().getPrintFormatting() && options().getAttributeLinkage()) { 550 printAttributes(OS, Full, "{Linkage} ", Parent, getLinkageName(), 551 /*UseQuotes=*/true, /*PrintRef=*/false); 552 } 553 } 554 555 void LVElement::printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent, 556 LVScope *Scope) const { 557 if (options().getPrintFormatting() && options().getAttributeLinkage()) { 558 LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope); 559 std::string Text = (Twine(" 0x") + Twine::utohexstr(SectionIndex) + 560 Twine(" '") + Twine(getLinkageName()) + Twine("'")) 561 .str(); 562 printAttributes(OS, Full, "{Linkage} ", Parent, Text, 563 /*UseQuotes=*/false, /*PrintRef=*/false); 564 } 565 } 566