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 Prefix.erase(std::remove_if(Prefix.begin(), Prefix.end(), ::isspace), 256 Prefix.end()); 257 } 258 259 // Generate a name for unnamed elements. 260 void LVElement::generateName() { 261 setIsAnonymous(); 262 std::string Name; 263 generateName(Name); 264 setName(Name); 265 setIsGeneratedName(); 266 } 267 268 void LVElement::updateLevel(LVScope *Parent, bool Moved) { 269 setLevel(Parent->getLevel() + 1); 270 if (Moved) 271 setHasMoved(); 272 } 273 274 // Generate the full name for the element, to include special qualifiers. 275 void LVElement::resolveFullname(LVElement *BaseType, StringRef Name) { 276 // For the following sample code, 277 // void *p; 278 // some compilers do not generate an attribute for the associated type: 279 // DW_TAG_variable 280 // DW_AT_name 'p' 281 // DW_AT_type $1 282 // ... 283 // $1: DW_TAG_pointer_type 284 // ... 285 // For those cases, generate the implicit 'void' type. 286 StringRef BaseTypename = BaseType ? BaseType->getName() : emptyString(); 287 bool GetBaseTypename = false; 288 bool UseBaseTypename = true; 289 bool UseNameText = true; 290 291 switch (getTag()) { 292 case dwarf::DW_TAG_pointer_type: // "*"; 293 if (!BaseType) 294 BaseTypename = typeVoid(); 295 break; 296 case dwarf::DW_TAG_const_type: // "const" 297 case dwarf::DW_TAG_ptr_to_member_type: // "*" 298 case dwarf::DW_TAG_rvalue_reference_type: // "&&" 299 case dwarf::DW_TAG_reference_type: // "&" 300 case dwarf::DW_TAG_restrict_type: // "restrict" 301 case dwarf::DW_TAG_volatile_type: // "volatile" 302 case dwarf::DW_TAG_unaligned: // "unaligned" 303 break; 304 case dwarf::DW_TAG_base_type: 305 case dwarf::DW_TAG_compile_unit: 306 case dwarf::DW_TAG_class_type: 307 case dwarf::DW_TAG_enumerator: 308 case dwarf::DW_TAG_namespace: 309 case dwarf::DW_TAG_skeleton_unit: 310 case dwarf::DW_TAG_structure_type: 311 case dwarf::DW_TAG_union_type: 312 case dwarf::DW_TAG_unspecified_type: 313 case dwarf::DW_TAG_GNU_template_parameter_pack: 314 GetBaseTypename = true; 315 break; 316 case dwarf::DW_TAG_array_type: 317 case dwarf::DW_TAG_call_site: 318 case dwarf::DW_TAG_entry_point: 319 case dwarf::DW_TAG_enumeration_type: 320 case dwarf::DW_TAG_GNU_call_site: 321 case dwarf::DW_TAG_imported_module: 322 case dwarf::DW_TAG_imported_declaration: 323 case dwarf::DW_TAG_inlined_subroutine: 324 case dwarf::DW_TAG_label: 325 case dwarf::DW_TAG_subprogram: 326 case dwarf::DW_TAG_subrange_type: 327 case dwarf::DW_TAG_subroutine_type: 328 case dwarf::DW_TAG_typedef: 329 GetBaseTypename = true; 330 UseBaseTypename = false; 331 break; 332 case dwarf::DW_TAG_template_type_parameter: 333 case dwarf::DW_TAG_template_value_parameter: 334 UseBaseTypename = false; 335 break; 336 case dwarf::DW_TAG_GNU_template_template_param: 337 break; 338 case dwarf::DW_TAG_catch_block: 339 case dwarf::DW_TAG_lexical_block: 340 case dwarf::DW_TAG_try_block: 341 UseNameText = false; 342 break; 343 default: 344 llvm_unreachable("Invalid type."); 345 return; 346 break; 347 } 348 349 // Overwrite if no given value. 'Name' is empty when resolving for scopes 350 // and symbols. In the case of types, it represents the type base name. 351 if (Name.empty() && GetBaseTypename) 352 Name = getName(); 353 354 // Concatenate the elements to get the full type name. 355 // Type will be: base_parent + pre + base + parent + post. 356 std::string Fullname; 357 358 if (UseNameText && Name.size()) 359 Fullname.append(std::string(Name)); 360 if (UseBaseTypename && BaseTypename.size()) { 361 if (UseNameText && Name.size()) 362 Fullname.append(" "); 363 Fullname.append(std::string(BaseTypename)); 364 } 365 366 // For a better and consistent layout, check if the generated name 367 // contains double space sequences. 368 assert((Fullname.find(" ", 0) == std::string::npos) && 369 "Extra double spaces in name."); 370 371 LLVM_DEBUG({ dbgs() << "Fullname = '" << Fullname << "'\n"; }); 372 setName(Fullname); 373 } 374 375 void LVElement::setFile(LVElement *Reference) { 376 if (!options().getAttributeAnySource()) 377 return; 378 379 // At this point, any existing reference to another element, have been 380 // resolved and the file ID extracted from the DI entry. 381 if (Reference) 382 setFileLine(Reference); 383 384 // The file information is used to show the source file for any element 385 // and display any new source file in relation to its parent element. 386 // a) Elements that are not inlined. 387 // - We record the DW_AT_decl_line and DW_AT_decl_file. 388 // b) Elements that are inlined. 389 // - We record the DW_AT_decl_line and DW_AT_decl_file. 390 // - We record the DW_AT_call_line and DW_AT_call_file. 391 // For both cases, we use the DW_AT_decl_file value to detect any changes 392 // in the source filename containing the element. Changes on this value 393 // indicates that the element being printed is not contained in the 394 // previous printed filename. 395 396 // The source files are indexed starting at 0, but DW_AT_decl_file defines 397 // that 0 means no file; a value of 1 means the 0th entry. 398 size_t Index = 0; 399 400 // An element with no source file information will use the reference 401 // attribute (DW_AT_specification, DW_AT_abstract_origin, DW_AT_extension) 402 // to update its information. 403 if (getIsFileFromReference() && Reference) { 404 Index = Reference->getFilenameIndex(); 405 if (Reference->getInvalidFilename()) 406 setInvalidFilename(); 407 setFilenameIndex(Index); 408 return; 409 } 410 411 // The source files are indexed starting at 0, but DW_AT_decl_file 412 // defines that 0 means no file; a value of 1 means the 0th entry. 413 Index = getFilenameIndex(); 414 if (Index) { 415 StringRef Filename = getReader().getFilename(this, Index); 416 Filename.size() ? setFilename(Filename) : setInvalidFilename(); 417 } 418 } 419 420 LVScope *LVElement::traverseParents(LVScopeGetFunction GetFunction) const { 421 LVScope *Parent = getParentScope(); 422 while (Parent && !(Parent->*GetFunction)()) 423 Parent = Parent->getParentScope(); 424 return Parent; 425 } 426 427 LVScope *LVElement::getFunctionParent() const { 428 return traverseParents(&LVScope::getIsFunction); 429 } 430 431 LVScope *LVElement::getCompileUnitParent() const { 432 return traverseParents(&LVScope::getIsCompileUnit); 433 } 434 435 // Resolve the qualified name to include the parent hierarchy names. 436 void LVElement::resolveQualifiedName() { 437 if (!getIsReferencedType() || isBase() || getQualifiedResolved() || 438 !getIncludeInPrint()) 439 return; 440 441 std::string Name; 442 443 // Get the qualified name, excluding the Compile Unit. 444 LVScope *Parent = getParentScope(); 445 if (Parent && !Parent->getIsRoot()) { 446 while (Parent && !Parent->getIsCompileUnit()) { 447 Name.insert(0, "::"); 448 if (Parent->isNamed()) 449 Name.insert(0, std::string(Parent->getName())); 450 else { 451 std::string Temp; 452 Parent->generateName(Temp); 453 Name.insert(0, Temp); 454 } 455 Parent = Parent->getParentScope(); 456 } 457 } 458 459 if (Name.size()) { 460 setQualifiedName(Name); 461 setQualifiedResolved(); 462 } 463 LLVM_DEBUG({ 464 dbgs() << "Offset: " << hexSquareString(getOffset()) 465 << ", Kind: " << formattedKind(kind()) 466 << ", Name: " << formattedName(getName()) 467 << ", QualifiedName: " << formattedName(Name) << "\n"; 468 }); 469 } 470 471 bool LVElement::referenceMatch(const LVElement *Element) const { 472 return (getHasReference() && Element->getHasReference()) || 473 (!getHasReference() && !Element->getHasReference()); 474 } 475 476 bool LVElement::equals(const LVElement *Element) const { 477 // The minimum factors that must be the same for an equality are: 478 // line number, level, name, qualified name and filename. 479 LLVM_DEBUG({ 480 dbgs() << "\n[Element::equals]\n"; 481 if (options().getAttributeOffset()) { 482 dbgs() << "Reference: " << hexSquareString(getOffset()) << "\n"; 483 dbgs() << "Target : " << hexSquareString(Element->getOffset()) << "\n"; 484 } 485 dbgs() << "Reference: " 486 << "Kind = " << formattedKind(kind()) << ", " 487 << "Name = " << formattedName(getName()) << ", " 488 << "Qualified = " << formattedName(getQualifiedName()) << "\n" 489 << "Target : " 490 << "Kind = " << formattedKind(Element->kind()) << ", " 491 << "Name = " << formattedName(Element->getName()) << ", " 492 << "Qualified = " << formattedName(Element->getQualifiedName()) 493 << "\n" 494 << "Reference: " 495 << "NameIndex = " << getNameIndex() << ", " 496 << "QualifiedNameIndex = " << getQualifiedNameIndex() << ", " 497 << "FilenameIndex = " << getFilenameIndex() << "\n" 498 << "Target : " 499 << "NameIndex = " << Element->getNameIndex() << ", " 500 << "QualifiedNameIndex = " << Element->getQualifiedNameIndex() 501 << ", " 502 << "FilenameIndex = " << Element->getFilenameIndex() << "\n"; 503 }); 504 if ((getLineNumber() != Element->getLineNumber()) || 505 (getLevel() != Element->getLevel())) 506 return false; 507 508 if ((getQualifiedNameIndex() != Element->getQualifiedNameIndex()) || 509 (getNameIndex() != Element->getNameIndex()) || 510 (getFilenameIndex() != Element->getFilenameIndex())) 511 return false; 512 513 if (!getType() && !Element->getType()) 514 return true; 515 if (getType() && Element->getType()) 516 return getType()->equals(Element->getType()); 517 return false; 518 } 519 520 // Print the FileName Index. 521 void LVElement::printFileIndex(raw_ostream &OS, bool Full) const { 522 if (options().getPrintFormatting() && options().getAttributeAnySource() && 523 getFilenameIndex()) { 524 525 // Check if there is a change in the File ID sequence. 526 size_t Index = getFilenameIndex(); 527 if (options().changeFilenameIndex(Index)) { 528 // Just to keep a nice layout. 529 OS << "\n"; 530 printAttributes(OS, /*Full=*/false); 531 532 OS << " {Source} "; 533 if (getInvalidFilename()) 534 OS << format("[0x%08x]\n", Index); 535 else 536 OS << formattedName(getPathname()) << "\n"; 537 } 538 } 539 } 540 541 void LVElement::printReference(raw_ostream &OS, bool Full, 542 LVElement *Parent) const { 543 if (options().getPrintFormatting() && options().getAttributeReference()) 544 printAttributes(OS, Full, "{Reference} ", Parent, 545 referenceAsString(getLineNumber(), /*Spaces=*/false), 546 /*UseQuotes=*/false, /*PrintRef=*/true); 547 } 548 549 void LVElement::printLinkageName(raw_ostream &OS, bool Full, 550 LVElement *Parent) const { 551 if (options().getPrintFormatting() && options().getAttributeLinkage()) { 552 printAttributes(OS, Full, "{Linkage} ", Parent, getLinkageName(), 553 /*UseQuotes=*/true, /*PrintRef=*/false); 554 } 555 } 556 557 void LVElement::printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent, 558 LVScope *Scope) const { 559 if (options().getPrintFormatting() && options().getAttributeLinkage()) { 560 LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope); 561 std::string Text = (Twine(" 0x") + Twine::utohexstr(SectionIndex) + 562 Twine(" '") + Twine(getLinkageName()) + Twine("'")) 563 .str(); 564 printAttributes(OS, Full, "{Linkage} ", Parent, Text, 565 /*UseQuotes=*/false, /*PrintRef=*/false); 566 } 567 } 568