| 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(Path: 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(C: '/'); |
| 87 | if (Pos != std::string::npos) |
| 88 | Basename = Basename.substr(Start: Pos + 1); |
| 89 | return getStringPool().getIndex(Key: Basename); |
| 90 | } |
| 91 | |
| 92 | return getStringPool().getIndex(Key: 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(Name: ElementName) |
| 98 | : getStringPool().getIndex(Key: ElementName); |
| 99 | } |
| 100 | |
| 101 | void LVElement::setFilename(StringRef Filename) { |
| 102 | // Get index for the flattened out filename. |
| 103 | FilenameIndex = getStringIndex(Name: Filename); |
| 104 | } |
| 105 | |
| 106 | void LVElement::setInnerComponent(StringRef Name) { |
| 107 | if (Name.size()) { |
| 108 | StringRef InnerComponent; |
| 109 | std::tie(args: std::ignore, args&: 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(Value: 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(str: std::string(Scope->getName())); |
| 250 | Prefix.append(s: "::" ); |
| 251 | Prefix.append(str: isLined() ? lineNumberAsString(/*ShowZero=*/true) : "?" ); |
| 252 | |
| 253 | // Remove any whitespaces. |
| 254 | llvm::erase_if(C&: Prefix, P: ::isspace); |
| 255 | } |
| 256 | |
| 257 | // Generate a name for unnamed elements. |
| 258 | void LVElement::generateName() { |
| 259 | setIsAnonymous(); |
| 260 | std::string Name; |
| 261 | generateName(Prefix&: 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(str: std::string(Name)); |
| 358 | if (UseBaseTypename && BaseTypename.size()) { |
| 359 | if (UseNameText && Name.size()) |
| 360 | Fullname.append(s: " " ); |
| 361 | Fullname.append(str: 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(Object: 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(GetFunction: &LVScope::getIsFunction); |
| 427 | } |
| 428 | |
| 429 | LVScope *LVElement::getCompileUnitParent() const { |
| 430 | return traverseParents(GetFunction: &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(pos: 0, s: "::" ); |
| 446 | if (Parent->isNamed()) |
| 447 | Name.insert(pos1: 0, str: std::string(Parent->getName())); |
| 448 | else { |
| 449 | std::string Temp; |
| 450 | Parent->generateName(Prefix&: Temp); |
| 451 | Name.insert(pos1: 0, str: 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: 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(Fmt: "[0x%08x]\n" , Vals: Index); |
| 533 | else |
| 534 | OS << formattedName(Name: 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, Name: "{Reference} " , Parent, |
| 543 | Value: referenceAsString(LineNumber: 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, Name: "{Linkage} " , Parent, Value: 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(Val: SectionIndex) + |
| 560 | Twine(" '" ) + Twine(getLinkageName()) + Twine("'" )) |
| 561 | .str(); |
| 562 | printAttributes(OS, Full, Name: "{Linkage} " , Parent, Value: Text, |
| 563 | /*UseQuotes=*/false, /*PrintRef=*/false); |
| 564 | } |
| 565 | } |
| 566 | |