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