| 1 | //===-- LVSymbol.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 LVSymbol class. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h" |
| 14 | #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h" |
| 15 | #include "llvm/DebugInfo/LogicalView/Core/LVLocation.h" |
| 16 | #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" |
| 17 | #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" |
| 18 | |
| 19 | using namespace llvm; |
| 20 | using namespace llvm::logicalview; |
| 21 | |
| 22 | #define DEBUG_TYPE "Symbol" |
| 23 | |
| 24 | namespace { |
| 25 | const char *const KindCallSiteParameter = "CallSiteParameter" ; |
| 26 | const char *const KindConstant = "Constant" ; |
| 27 | const char *const KindInherits = "Inherits" ; |
| 28 | const char *const KindMember = "Member" ; |
| 29 | const char *const KindParameter = "Parameter" ; |
| 30 | const char *const KindUndefined = "Undefined" ; |
| 31 | const char *const KindUnspecified = "Unspecified" ; |
| 32 | const char *const KindVariable = "Variable" ; |
| 33 | } // end anonymous namespace |
| 34 | |
| 35 | // Return a string representation for the symbol kind. |
| 36 | const char *LVSymbol::kind() const { |
| 37 | const char *Kind = KindUndefined; |
| 38 | if (getIsCallSiteParameter()) |
| 39 | Kind = KindCallSiteParameter; |
| 40 | else if (getIsConstant()) |
| 41 | Kind = KindConstant; |
| 42 | else if (getIsInheritance()) |
| 43 | Kind = KindInherits; |
| 44 | else if (getIsMember()) |
| 45 | Kind = KindMember; |
| 46 | else if (getIsParameter()) |
| 47 | Kind = KindParameter; |
| 48 | else if (getIsUnspecified()) |
| 49 | Kind = KindUnspecified; |
| 50 | else if (getIsVariable()) |
| 51 | Kind = KindVariable; |
| 52 | return Kind; |
| 53 | } |
| 54 | |
| 55 | LVSymbolDispatch LVSymbol::Dispatch = { |
| 56 | {LVSymbolKind::IsCallSiteParameter, &LVSymbol::getIsCallSiteParameter}, |
| 57 | {LVSymbolKind::IsConstant, &LVSymbol::getIsConstant}, |
| 58 | {LVSymbolKind::IsInheritance, &LVSymbol::getIsInheritance}, |
| 59 | {LVSymbolKind::IsMember, &LVSymbol::getIsMember}, |
| 60 | {LVSymbolKind::IsParameter, &LVSymbol::getIsParameter}, |
| 61 | {LVSymbolKind::IsUnspecified, &LVSymbol::getIsUnspecified}, |
| 62 | {LVSymbolKind::IsVariable, &LVSymbol::getIsVariable}}; |
| 63 | |
| 64 | // Add a Location Entry. |
| 65 | void LVSymbol::addLocation(dwarf::Attribute Attr, LVAddress LowPC, |
| 66 | LVAddress HighPC, LVUnsigned SectionOffset, |
| 67 | uint64_t LocDescOffset, bool CallSiteLocation) { |
| 68 | if (!Locations) |
| 69 | Locations = std::make_unique<LVLocations>(); |
| 70 | |
| 71 | // Create the location entry. |
| 72 | CurrentLocation = getReader().createLocationSymbol(); |
| 73 | CurrentLocation->setParent(this); |
| 74 | CurrentLocation->setAttr(Attr); |
| 75 | if (CallSiteLocation) |
| 76 | CurrentLocation->setIsCallSite(); |
| 77 | CurrentLocation->addObject(LowPC, HighPC, SectionOffset, LocDescOffset); |
| 78 | Locations->push_back(Elt: CurrentLocation); |
| 79 | |
| 80 | // Mark the symbol as having location information. |
| 81 | setHasLocation(); |
| 82 | } |
| 83 | |
| 84 | // Add a Location Record. |
| 85 | void LVSymbol::addLocationOperands(LVSmall Opcode, |
| 86 | ArrayRef<uint64_t> Operands) { |
| 87 | if (CurrentLocation) |
| 88 | CurrentLocation->addObject(Opcode, Operands); |
| 89 | } |
| 90 | |
| 91 | // Add a Location Entry. |
| 92 | void LVSymbol::addLocationConstant(dwarf::Attribute Attr, LVUnsigned Constant, |
| 93 | uint64_t LocDescOffset) { |
| 94 | // Create a Location Entry, with the global information. |
| 95 | addLocation(Attr, |
| 96 | /*LowPC=*/0, /*HighPC=*/-1, |
| 97 | /*SectionOffset=*/0, LocDescOffset); |
| 98 | |
| 99 | // Add records to Location Entry. |
| 100 | addLocationOperands(/*Opcode=*/LVLocationMemberOffset, Operands: {Constant}); |
| 101 | } |
| 102 | |
| 103 | LVLocations::iterator LVSymbol::addLocationGap(LVLocations::iterator Pos, |
| 104 | LVAddress LowPC, |
| 105 | LVAddress HighPC) { |
| 106 | // Create a location entry for the gap. |
| 107 | LVLocation *Gap = getReader().createLocationSymbol(); |
| 108 | Gap->setParent(this); |
| 109 | Gap->setAttr(dwarf::DW_AT_location); |
| 110 | Gap->addObject(LowPC, HighPC, |
| 111 | /*section_offset=*/SectionOffset: 0, |
| 112 | /*locdesc_offset=*/LocDescOffset: 0); |
| 113 | |
| 114 | LVLocations::iterator Iter = Locations->insert(I: Pos, Elt: Gap); |
| 115 | |
| 116 | // Add gap to Location Entry. |
| 117 | Gap->addObject(Opcode: dwarf::DW_OP_hi_user, Operands: {}); |
| 118 | |
| 119 | // Mark the entry as a gap. |
| 120 | Gap->setIsGapEntry(); |
| 121 | |
| 122 | return Iter; |
| 123 | } |
| 124 | |
| 125 | void LVSymbol::fillLocationGaps() { |
| 126 | // The symbol has locations records. Fill gaps in the location list. |
| 127 | if (!getHasLocation() || !getFillGaps()) |
| 128 | return; |
| 129 | |
| 130 | // Get the parent range information and add dummy location entries. |
| 131 | const LVLocations *Ranges = getParentScope()->getRanges(); |
| 132 | if (!Ranges) |
| 133 | return; |
| 134 | |
| 135 | for (const LVLocation *Entry : *Ranges) { |
| 136 | LVAddress ParentLowPC = Entry->getLowerAddress(); |
| 137 | LVAddress ParentHighPC = Entry->getUpperAddress(); |
| 138 | |
| 139 | // Traverse the symbol locations and for each location contained in |
| 140 | // the current parent range, insert locations for any existing gap. |
| 141 | LVLocation *Location; |
| 142 | LVAddress LowPC = 0; |
| 143 | LVAddress Marker = ParentLowPC; |
| 144 | for (LVLocations::iterator Iter = Locations->begin(); |
| 145 | Iter != Locations->end(); ++Iter) { |
| 146 | Location = *Iter; |
| 147 | LowPC = Location->getLowerAddress(); |
| 148 | if (LowPC != Marker) { |
| 149 | // We have a gap at [Marker,LowPC - 1]. |
| 150 | Iter = addLocationGap(Pos: Iter, LowPC: Marker, HighPC: LowPC - 1); |
| 151 | ++Iter; |
| 152 | } |
| 153 | |
| 154 | // Move to the next item in the location list. |
| 155 | Marker = Location->getUpperAddress() + 1; |
| 156 | } |
| 157 | |
| 158 | // Check any gap at the end. |
| 159 | if (Marker < ParentHighPC) |
| 160 | // We have a gap at [Marker,ParentHighPC]. |
| 161 | addLocationGap(Pos: Locations->end(), LowPC: Marker, HighPC: ParentHighPC); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | // Get all the locations based on the valid function. |
| 166 | void LVSymbol::getLocations(LVLocations &LocationList, |
| 167 | LVValidLocation ValidLocation, bool RecordInvalid) { |
| 168 | if (!Locations) |
| 169 | return; |
| 170 | |
| 171 | for (LVLocation *Location : *Locations) { |
| 172 | // Add the invalid location object. |
| 173 | if (!(Location->*ValidLocation)() && RecordInvalid) |
| 174 | LocationList.push_back(Elt: Location); |
| 175 | } |
| 176 | |
| 177 | // Calculate coverage factor. |
| 178 | calculateCoverage(); |
| 179 | } |
| 180 | |
| 181 | void LVSymbol::getLocations(LVLocations &LocationList) const { |
| 182 | if (!Locations) |
| 183 | return; |
| 184 | |
| 185 | llvm::append_range(C&: LocationList, R&: *Locations); |
| 186 | } |
| 187 | |
| 188 | // Calculate coverage factor. |
| 189 | void LVSymbol::calculateCoverage() { |
| 190 | if (!LVLocation::calculateCoverage(Locations: Locations.get(), Factor&: CoverageFactor, |
| 191 | Percentage&: CoveragePercentage)) { |
| 192 | LVScope *Parent = getParentScope(); |
| 193 | if (Parent->getIsInlinedFunction()) { |
| 194 | // For symbols representing the inlined function parameters and its |
| 195 | // variables, get the outer most parent that contains their location |
| 196 | // lower address. |
| 197 | // The symbol can have a set of non-contiguous locations. We are using |
| 198 | // only the first location entry to get the outermost parent. |
| 199 | // If no scope contains the location, assume its enclosing parent. |
| 200 | LVScope *Scope = |
| 201 | Parent->outermostParent(Address: Locations->front()->getLowerAddress()); |
| 202 | if (Scope) |
| 203 | Parent = Scope; |
| 204 | } |
| 205 | unsigned CoverageParent = Parent->getCoverageFactor(); |
| 206 | // Get a percentage rounded to two decimal digits. This avoids |
| 207 | // implementation-defined rounding inside printing functions. |
| 208 | CoveragePercentage = |
| 209 | CoverageParent |
| 210 | ? rint(x: (double(CoverageFactor) / CoverageParent) * 100.0 * 100.0) / |
| 211 | 100.0 |
| 212 | : 0; |
| 213 | // Record invalid coverage entry. |
| 214 | if (options().getWarningCoverages() && CoveragePercentage > 100) |
| 215 | getReaderCompileUnit()->addInvalidCoverage(Symbol: this); |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | void LVSymbol::resolveName() { |
| 220 | if (getIsResolvedName()) |
| 221 | return; |
| 222 | setIsResolvedName(); |
| 223 | |
| 224 | LVElement::resolveName(); |
| 225 | |
| 226 | // Resolve any given pattern. |
| 227 | patterns().resolvePatternMatch(Symbol: this); |
| 228 | } |
| 229 | |
| 230 | void LVSymbol::resolveReferences() { |
| 231 | // The symbols can have the following references to other elements: |
| 232 | // A Type: |
| 233 | // DW_AT_type -> Type or Scope |
| 234 | // DW_AT_import -> Type |
| 235 | // A Reference: |
| 236 | // DW_AT_specification -> Symbol |
| 237 | // DW_AT_abstract_origin -> Symbol |
| 238 | // DW_AT_extension -> Symbol |
| 239 | |
| 240 | // Resolve any referenced symbol. |
| 241 | LVSymbol *Reference = getReference(); |
| 242 | if (Reference) { |
| 243 | Reference->resolve(); |
| 244 | // Recursively resolve the symbol names. |
| 245 | resolveReferencesChain(); |
| 246 | } |
| 247 | |
| 248 | // Set the file/line information using the Debug Information entry. |
| 249 | setFile(Reference); |
| 250 | |
| 251 | // Resolve symbol type. |
| 252 | if (LVElement *Element = getType()) { |
| 253 | Element->resolve(); |
| 254 | |
| 255 | // In the case of demoted typedefs, use the underlying type. |
| 256 | if (Element->getIsTypedefReduced()) { |
| 257 | Element = Element->getType(); |
| 258 | Element->resolve(); |
| 259 | } |
| 260 | |
| 261 | // If the type is a template parameter, get its type, which can |
| 262 | // point to a type or scope, depending on the argument instance. |
| 263 | setGenericType(Element); |
| 264 | } |
| 265 | |
| 266 | // Resolve the variable associated type. |
| 267 | if (!getType() && Reference) |
| 268 | setType(Reference->getType()); |
| 269 | } |
| 270 | |
| 271 | StringRef LVSymbol::resolveReferencesChain() { |
| 272 | // If the symbol have a DW_AT_specification or DW_AT_abstract_origin, |
| 273 | // follow the chain to resolve the name from those references. |
| 274 | if (getHasReference() && !isNamed()) |
| 275 | setName(getReference()->resolveReferencesChain()); |
| 276 | |
| 277 | return getName(); |
| 278 | } |
| 279 | |
| 280 | void LVSymbol::markMissingParents(const LVSymbols *References, |
| 281 | const LVSymbols *Targets) { |
| 282 | if (!(References && Targets)) |
| 283 | return; |
| 284 | |
| 285 | LLVM_DEBUG({ |
| 286 | dbgs() << "\n[LVSymbol::markMissingParents]\n" ; |
| 287 | for (const LVSymbol *Reference : *References) |
| 288 | dbgs() << "References: " |
| 289 | << "Kind = " << formattedKind(Reference->kind()) << ", " |
| 290 | << "Name = " << formattedName(Reference->getName()) << "\n" ; |
| 291 | for (const LVSymbol *Target : *Targets) |
| 292 | dbgs() << "Targets : " |
| 293 | << "Kind = " << formattedKind(Target->kind()) << ", " |
| 294 | << "Name = " << formattedName(Target->getName()) << "\n" ; |
| 295 | }); |
| 296 | |
| 297 | for (LVSymbol *Reference : *References) { |
| 298 | LLVM_DEBUG({ |
| 299 | dbgs() << "Search Reference: Name = " |
| 300 | << formattedName(Reference->getName()) << "\n" ; |
| 301 | }); |
| 302 | if (!Reference->findIn(Targets)) |
| 303 | Reference->markBranchAsMissing(); |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | LVSymbol *LVSymbol::findIn(const LVSymbols *Targets) const { |
| 308 | if (!Targets) |
| 309 | return nullptr; |
| 310 | |
| 311 | LLVM_DEBUG({ |
| 312 | dbgs() << "\n[LVSymbol::findIn]\n" |
| 313 | << "Reference: " |
| 314 | << "Level = " << getLevel() << ", " |
| 315 | << "Kind = " << formattedKind(kind()) << ", " |
| 316 | << "Name = " << formattedName(getName()) << "\n" ; |
| 317 | for (const LVSymbol *Target : *Targets) |
| 318 | dbgs() << "Target : " |
| 319 | << "Level = " << Target->getLevel() << ", " |
| 320 | << "Kind = " << formattedKind(Target->kind()) << ", " |
| 321 | << "Name = " << formattedName(Target->getName()) << "\n" ; |
| 322 | }); |
| 323 | |
| 324 | for (LVSymbol *Target : *Targets) |
| 325 | if (equals(Symbol: Target)) |
| 326 | return Target; |
| 327 | |
| 328 | return nullptr; |
| 329 | } |
| 330 | |
| 331 | // Check for a match on the arguments of a function. |
| 332 | bool LVSymbol::parametersMatch(const LVSymbols *References, |
| 333 | const LVSymbols *Targets) { |
| 334 | if (!References && !Targets) |
| 335 | return true; |
| 336 | if (References && Targets) { |
| 337 | LVSymbols ReferenceParams; |
| 338 | getParameters(Symbols: References, Parameters: &ReferenceParams); |
| 339 | LVSymbols TargetParams; |
| 340 | getParameters(Symbols: Targets, Parameters: &TargetParams); |
| 341 | return LVSymbol::equals(References: &ReferenceParams, Targets: &TargetParams); |
| 342 | } |
| 343 | return false; |
| 344 | } |
| 345 | |
| 346 | // Return the symbols which are parameters. |
| 347 | void LVSymbol::getParameters(const LVSymbols *Symbols, LVSymbols *Parameters) { |
| 348 | if (Symbols) |
| 349 | for (LVSymbol *Symbol : *Symbols) |
| 350 | if (Symbol->getIsParameter()) |
| 351 | Parameters->push_back(Elt: Symbol); |
| 352 | } |
| 353 | |
| 354 | bool LVSymbol::equals(const LVSymbol *Symbol) const { |
| 355 | if (!LVElement::equals(Element: Symbol)) |
| 356 | return false; |
| 357 | |
| 358 | // Check if any reference is the same. |
| 359 | if (!referenceMatch(Element: Symbol)) |
| 360 | return false; |
| 361 | |
| 362 | if (getReference() && !getReference()->equals(Symbol: Symbol->getReference())) |
| 363 | return false; |
| 364 | |
| 365 | return true; |
| 366 | } |
| 367 | |
| 368 | bool LVSymbol::equals(const LVSymbols *References, const LVSymbols *Targets) { |
| 369 | if (!References && !Targets) |
| 370 | return true; |
| 371 | if (References && Targets && References->size() == Targets->size()) { |
| 372 | for (const LVSymbol *Reference : *References) |
| 373 | if (!Reference->findIn(Targets)) |
| 374 | return false; |
| 375 | return true; |
| 376 | } |
| 377 | return false; |
| 378 | } |
| 379 | |
| 380 | void LVSymbol::report(LVComparePass Pass) { |
| 381 | getComparator().printItem(Element: this, Pass); |
| 382 | } |
| 383 | |
| 384 | void LVSymbol::printLocations(raw_ostream &OS, bool Full) const { |
| 385 | if (Locations) |
| 386 | for (const LVLocation *Location : *Locations) |
| 387 | Location->printRaw(OS, Full); |
| 388 | } |
| 389 | |
| 390 | void LVSymbol::print(raw_ostream &OS, bool Full) const { |
| 391 | if (getIncludeInPrint() && getReader().doPrintSymbol(Symbol: this)) { |
| 392 | getReaderCompileUnit()->incrementPrintedSymbols(); |
| 393 | LVElement::print(OS, Full); |
| 394 | printExtra(OS, Full); |
| 395 | } |
| 396 | } |
| 397 | |
| 398 | void LVSymbol::(raw_ostream &OS, bool Full) const { |
| 399 | // Accessibility depends on the parent (class, structure). |
| 400 | uint32_t AccessCode = 0; |
| 401 | if (getIsMember() || getIsInheritance()) |
| 402 | AccessCode = getParentScope()->getIsClass() ? dwarf::DW_ACCESS_private |
| 403 | : dwarf::DW_ACCESS_public; |
| 404 | |
| 405 | const LVSymbol *Symbol = getIsInlined() ? Reference : this; |
| 406 | std::string Attributes = |
| 407 | Symbol->getIsCallSiteParameter() |
| 408 | ? "" |
| 409 | : formatAttributes(First: Symbol->externalString(), |
| 410 | Others: Symbol->accessibilityString(Access: AccessCode), |
| 411 | Others: virtualityString()); |
| 412 | |
| 413 | OS << formattedKind(Kind: Symbol->kind()) << " " << Attributes; |
| 414 | if (Symbol->getIsUnspecified()) |
| 415 | OS << formattedName(Name: Symbol->getName()); |
| 416 | else { |
| 417 | if (Symbol->getIsInheritance()) |
| 418 | OS << Symbol->typeOffsetAsString() |
| 419 | << formattedNames(Name1: Symbol->getTypeQualifiedName(), |
| 420 | Name2: Symbol->typeAsString()); |
| 421 | else { |
| 422 | OS << formattedName(Name: Symbol->getName()); |
| 423 | // Print any bitfield information. |
| 424 | if (uint32_t Size = getBitSize()) |
| 425 | OS << ":" << Size; |
| 426 | OS << " -> " << Symbol->typeOffsetAsString() |
| 427 | << formattedNames(Name1: Symbol->getTypeQualifiedName(), |
| 428 | Name2: Symbol->typeAsString()); |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | // Print any initial value if any. |
| 433 | if (ValueIndex) |
| 434 | OS << " = " << formattedName(Name: getValue()); |
| 435 | OS << "\n" ; |
| 436 | |
| 437 | if (Full && options().getPrintFormatting()) { |
| 438 | if (getLinkageNameIndex()) |
| 439 | printLinkageName(OS, Full, Parent: const_cast<LVSymbol *>(this)); |
| 440 | if (LVSymbol *Reference = getReference()) |
| 441 | Reference->printReference(OS, Full, Parent: const_cast<LVSymbol *>(this)); |
| 442 | |
| 443 | // Print location information. |
| 444 | LVLocation::print(Locations: Locations.get(), OS, Full); |
| 445 | } |
| 446 | } |
| 447 | |