| //===-- LVSymbol.cpp ------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This implements the LVSymbol class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVLocation.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" |
| |
| using namespace llvm; |
| using namespace llvm::logicalview; |
| |
| #define DEBUG_TYPE "Symbol" |
| |
| namespace { |
| const char *const KindCallSiteParameter = "CallSiteParameter"; |
| const char *const KindConstant = "Constant"; |
| const char *const KindInherits = "Inherits"; |
| const char *const KindMember = "Member"; |
| const char *const KindParameter = "Parameter"; |
| const char *const KindUndefined = "Undefined"; |
| const char *const KindUnspecified = "Unspecified"; |
| const char *const KindVariable = "Variable"; |
| } // end anonymous namespace |
| |
| // Return a string representation for the symbol kind. |
| const char *LVSymbol::kind() const { |
| const char *Kind = KindUndefined; |
| if (getIsCallSiteParameter()) |
| Kind = KindCallSiteParameter; |
| else if (getIsConstant()) |
| Kind = KindConstant; |
| else if (getIsInheritance()) |
| Kind = KindInherits; |
| else if (getIsMember()) |
| Kind = KindMember; |
| else if (getIsParameter()) |
| Kind = KindParameter; |
| else if (getIsUnspecified()) |
| Kind = KindUnspecified; |
| else if (getIsVariable()) |
| Kind = KindVariable; |
| return Kind; |
| } |
| |
| LVSymbolDispatch LVSymbol::Dispatch = { |
| {LVSymbolKind::IsCallSiteParameter, &LVSymbol::getIsCallSiteParameter}, |
| {LVSymbolKind::IsConstant, &LVSymbol::getIsConstant}, |
| {LVSymbolKind::IsInheritance, &LVSymbol::getIsInheritance}, |
| {LVSymbolKind::IsMember, &LVSymbol::getIsMember}, |
| {LVSymbolKind::IsParameter, &LVSymbol::getIsParameter}, |
| {LVSymbolKind::IsUnspecified, &LVSymbol::getIsUnspecified}, |
| {LVSymbolKind::IsVariable, &LVSymbol::getIsVariable}}; |
| |
| // Add a Location Entry. |
| void LVSymbol::addLocation(dwarf::Attribute Attr, LVAddress LowPC, |
| LVAddress HighPC, LVUnsigned SectionOffset, |
| uint64_t LocDescOffset, bool CallSiteLocation) { |
| if (!Locations) |
| Locations = new LVAutoLocations(); |
| |
| // Create the location entry. |
| CurrentLocation = new LVLocationSymbol(); |
| CurrentLocation->setParent(this); |
| CurrentLocation->setAttr(Attr); |
| if (CallSiteLocation) |
| CurrentLocation->setIsCallSite(); |
| CurrentLocation->addObject(LowPC, HighPC, SectionOffset, LocDescOffset); |
| Locations->push_back(CurrentLocation); |
| |
| // Mark the symbol as having location information. |
| setHasLocation(); |
| } |
| |
| // Add a Location Record. |
| void LVSymbol::addLocationOperands(LVSmall Opcode, uint64_t Operand1, |
| uint64_t Operand2) { |
| if (CurrentLocation) |
| CurrentLocation->addObject(Opcode, Operand1, Operand2); |
| } |
| |
| // Add a Location Entry. |
| void LVSymbol::addLocationConstant(dwarf::Attribute Attr, LVUnsigned Constant, |
| uint64_t LocDescOffset) { |
| // Create a Location Entry, with the global information. |
| addLocation(Attr, |
| /*LowPC=*/0, /*HighPC=*/-1, |
| /*SectionOffset=*/0, LocDescOffset); |
| |
| // Add records to Location Entry. |
| addLocationOperands(/*Opcode=*/LVLocationMemberOffset, |
| /*Operand1=*/Constant, /*Operand2=*/0); |
| } |
| |
| LVLocations::iterator LVSymbol::addLocationGap(LVLocations::iterator Pos, |
| LVAddress LowPC, |
| LVAddress HighPC) { |
| // Create a location entry for the gap. |
| LVLocation *Gap = new LVLocationSymbol(); |
| Gap->setParent(this); |
| Gap->setAttr(dwarf::DW_AT_location); |
| Gap->addObject(LowPC, HighPC, |
| /*section_offset=*/0, |
| /*locdesc_offset=*/0); |
| |
| LVLocations::iterator Iter = Locations->insert(Pos, Gap); |
| |
| // Add gap to Location Entry. |
| Gap->addObject(/*op=*/dwarf::DW_OP_hi_user, |
| /*opd1=*/0, /*opd2=*/0); |
| |
| // Mark the entry as a gap. |
| Gap->setIsGapEntry(); |
| |
| return Iter; |
| } |
| |
| void LVSymbol::fillLocationGaps() { |
| // The symbol has locations records. Fill gaps in the location list. |
| if (!getHasLocation() || !getFillGaps()) |
| return; |
| |
| // Get the parent range information and add dummy location entries. |
| const LVLocations *Ranges = getParentScope()->getRanges(); |
| if (!Ranges) |
| return; |
| |
| for (const LVLocation *Entry : *Ranges) { |
| LVAddress ParentLowPC = Entry->getLowerAddress(); |
| LVAddress ParentHighPC = Entry->getUpperAddress(); |
| |
| // Traverse the symbol locations and for each location contained in |
| // the current parent range, insert locations for any existing gap. |
| LVLocation *Location; |
| LVAddress LowPC = 0; |
| LVAddress Marker = ParentLowPC; |
| for (LVLocations::iterator Iter = Locations->begin(); |
| Iter != Locations->end(); ++Iter) { |
| Location = *Iter; |
| LowPC = Location->getLowerAddress(); |
| if (LowPC != Marker) { |
| // We have a gap at [Marker,LowPC - 1]. |
| Iter = addLocationGap(Iter, Marker, LowPC - 1); |
| ++Iter; |
| } |
| |
| // Move to the next item in the location list. |
| Marker = Location->getUpperAddress() + 1; |
| } |
| |
| // Check any gap at the end. |
| if (Marker < ParentHighPC) |
| // We have a gap at [Marker,ParentHighPC]. |
| addLocationGap(Locations->end(), Marker, ParentHighPC); |
| } |
| } |
| |
| // Get all the locations based on the valid function. |
| void LVSymbol::getLocations(LVLocations &LocationList, |
| LVValidLocation ValidLocation, bool RecordInvalid) { |
| if (!Locations) |
| return; |
| |
| for (LVLocation *Location : *Locations) { |
| // Add the invalid location object. |
| if (!(Location->*ValidLocation)() && RecordInvalid) |
| LocationList.push_back(Location); |
| } |
| |
| // Calculate coverage factor. |
| calculateCoverage(); |
| } |
| |
| void LVSymbol::getLocations(LVLocations &LocationList) const { |
| if (!Locations) |
| return; |
| |
| for (LVLocation *Location : *Locations) |
| LocationList.push_back(Location); |
| } |
| |
| // Calculate coverage factor. |
| void LVSymbol::calculateCoverage() { |
| if (!LVLocation::calculateCoverage(Locations, CoverageFactor, |
| CoveragePercentage)) { |
| LVScope *Parent = getParentScope(); |
| if (Parent->getIsInlinedFunction()) { |
| // For symbols representing the inlined function parameters and its |
| // variables, get the outer most parent that contains their location |
| // lower address. |
| // The symbol can have a set of non-contiguous locations. We are using |
| // only the first location entry to get the outermost parent. |
| // If no scope contains the location, assume its enclosing parent. |
| LVScope *Scope = |
| Parent->outermostParent(Locations->front()->getLowerAddress()); |
| if (Scope) |
| Parent = Scope; |
| } |
| unsigned CoverageParent = Parent->getCoverageFactor(); |
| // Get a percentage rounded to two decimal digits. This avoids |
| // implementation-defined rounding inside printing functions. |
| CoveragePercentage = |
| CoverageParent |
| ? rint((double(CoverageFactor) / CoverageParent) * 100.0 * 100.0) / |
| 100.0 |
| : 0; |
| // Record invalid coverage entry. |
| if (options().getWarningCoverages() && CoveragePercentage > 100) |
| getReaderCompileUnit()->addInvalidCoverage(this); |
| } |
| } |
| |
| void LVSymbol::resolveName() { |
| if (getIsResolvedName()) |
| return; |
| setIsResolvedName(); |
| |
| LVElement::resolveName(); |
| |
| // Resolve any given pattern. |
| patterns().resolvePatternMatch(this); |
| } |
| |
| void LVSymbol::resolveReferences() { |
| // The symbols can have the following references to other elements: |
| // A Type: |
| // DW_AT_type -> Type or Scope |
| // DW_AT_import -> Type |
| // A Reference: |
| // DW_AT_specification -> Symbol |
| // DW_AT_abstract_origin -> Symbol |
| // DW_AT_extension -> Symbol |
| |
| // Resolve any referenced symbol. |
| LVSymbol *Reference = getReference(); |
| if (Reference) { |
| Reference->resolve(); |
| // Recursively resolve the symbol names. |
| resolveReferencesChain(); |
| } |
| |
| // Set the file/line information using the Debug Information entry. |
| setFile(Reference); |
| |
| // Resolve symbol type. |
| if (LVElement *Element = getType()) { |
| Element->resolve(); |
| |
| // In the case of demoted typedefs, use the underlying type. |
| if (Element->getIsTypedefReduced()) { |
| Element = Element->getType(); |
| Element->resolve(); |
| } |
| |
| // If the type is a template parameter, get its type, which can |
| // point to a type or scope, depending on the argument instance. |
| setGenericType(Element); |
| } |
| |
| // Resolve the variable associated type. |
| if (!getType() && Reference) |
| setType(Reference->getType()); |
| } |
| |
| StringRef LVSymbol::resolveReferencesChain() { |
| // If the symbol have a DW_AT_specification or DW_AT_abstract_origin, |
| // follow the chain to resolve the name from those references. |
| if (getHasReference() && !isNamed()) |
| setName(getReference()->resolveReferencesChain()); |
| |
| return getName(); |
| } |
| |
| void LVSymbol::markMissingParents(const LVSymbols *References, |
| const LVSymbols *Targets) { |
| if (!(References && Targets)) |
| return; |
| |
| LLVM_DEBUG({ |
| dbgs() << "\n[LVSymbol::markMissingParents]\n"; |
| for (const LVSymbol *Reference : *References) |
| dbgs() << "References: " |
| << "Kind = " << formattedKind(Reference->kind()) << ", " |
| << "Name = " << formattedName(Reference->getName()) << "\n"; |
| for (const LVSymbol *Target : *Targets) |
| dbgs() << "Targets : " |
| << "Kind = " << formattedKind(Target->kind()) << ", " |
| << "Name = " << formattedName(Target->getName()) << "\n"; |
| }); |
| |
| for (LVSymbol *Reference : *References) { |
| LLVM_DEBUG({ |
| dbgs() << "Search Reference: Name = " |
| << formattedName(Reference->getName()) << "\n"; |
| }); |
| if (!Reference->findIn(Targets)) |
| Reference->markBranchAsMissing(); |
| } |
| } |
| |
| LVSymbol *LVSymbol::findIn(const LVSymbols *Targets) const { |
| if (!Targets) |
| return nullptr; |
| |
| LLVM_DEBUG({ |
| dbgs() << "\n[LVSymbol::findIn]\n" |
| << "Reference: " |
| << "Level = " << getLevel() << ", " |
| << "Kind = " << formattedKind(kind()) << ", " |
| << "Name = " << formattedName(getName()) << "\n"; |
| for (const LVSymbol *Target : *Targets) |
| dbgs() << "Target : " |
| << "Level = " << Target->getLevel() << ", " |
| << "Kind = " << formattedKind(Target->kind()) << ", " |
| << "Name = " << formattedName(Target->getName()) << "\n"; |
| }); |
| |
| for (LVSymbol *Target : *Targets) |
| if (equals(Target)) |
| return Target; |
| |
| return nullptr; |
| } |
| |
| // Check for a match on the arguments of a function. |
| bool LVSymbol::parametersMatch(const LVSymbols *References, |
| const LVSymbols *Targets) { |
| if (!References && !Targets) |
| return true; |
| if (References && Targets) { |
| LVSymbols ReferenceParams; |
| getParameters(References, &ReferenceParams); |
| LVSymbols TargetParams; |
| getParameters(Targets, &TargetParams); |
| return LVSymbol::equals(&ReferenceParams, &TargetParams); |
| } |
| return false; |
| } |
| |
| // Return the symbols which are parameters. |
| void LVSymbol::getParameters(const LVSymbols *Symbols, LVSymbols *Parameters) { |
| if (Symbols) |
| for (LVSymbol *Symbol : *Symbols) |
| if (Symbol->getIsParameter()) |
| Parameters->push_back(Symbol); |
| } |
| |
| bool LVSymbol::equals(const LVSymbol *Symbol) const { |
| if (!LVElement::equals(Symbol)) |
| return false; |
| |
| // Check if any reference is the same. |
| if (!referenceMatch(Symbol)) |
| return false; |
| |
| if (getReference() && !getReference()->equals(Symbol->getReference())) |
| return false; |
| |
| return true; |
| } |
| |
| bool LVSymbol::equals(const LVSymbols *References, const LVSymbols *Targets) { |
| if (!References && !Targets) |
| return true; |
| if (References && Targets && References->size() == Targets->size()) { |
| for (const LVSymbol *Reference : *References) |
| if (!Reference->findIn(Targets)) |
| return false; |
| return true; |
| } |
| return false; |
| } |
| |
| void LVSymbol::report(LVComparePass Pass) { |
| getComparator().printItem(this, Pass); |
| } |
| |
| void LVSymbol::printLocations(raw_ostream &OS, bool Full) const { |
| if (Locations) |
| for (const LVLocation *Location : *Locations) |
| Location->printRaw(OS, Full); |
| } |
| |
| void LVSymbol::print(raw_ostream &OS, bool Full) const { |
| if (getIncludeInPrint() && getReader().doPrintSymbol(this)) { |
| getReaderCompileUnit()->incrementPrintedSymbols(); |
| LVElement::print(OS, Full); |
| printExtra(OS, Full); |
| } |
| } |
| |
| void LVSymbol::printExtra(raw_ostream &OS, bool Full) const { |
| // Accessibility depends on the parent (class, structure). |
| uint32_t AccessCode = 0; |
| if (getIsMember() || getIsInheritance()) |
| AccessCode = getParentScope()->getIsClass() ? dwarf::DW_ACCESS_private |
| : dwarf::DW_ACCESS_public; |
| |
| const LVSymbol *Symbol = getIsInlined() ? Reference : this; |
| std::string Attributes = |
| Symbol->getIsCallSiteParameter() |
| ? "" |
| : formatAttributes(Symbol->externalString(), |
| Symbol->accessibilityString(AccessCode), |
| virtualityString()); |
| |
| OS << formattedKind(Symbol->kind()) << " " << Attributes; |
| if (Symbol->getIsUnspecified()) |
| OS << formattedName(Symbol->getName()); |
| else { |
| if (Symbol->getIsInheritance()) |
| OS << Symbol->typeOffsetAsString() |
| << formattedNames(Symbol->getTypeQualifiedName(), |
| Symbol->typeAsString()); |
| else { |
| OS << formattedName(Symbol->getName()); |
| // Print any bitfield information. |
| if (uint32_t Size = getBitSize()) |
| OS << ":" << Size; |
| OS << " -> " << Symbol->typeOffsetAsString() |
| << formattedNames(Symbol->getTypeQualifiedName(), |
| Symbol->typeAsString()); |
| } |
| } |
| |
| // Print any initial value if any. |
| if (ValueIndex) |
| OS << " = " << formattedName(getValue()); |
| OS << "\n"; |
| |
| if (Full && options().getPrintFormatting()) { |
| if (getLinkageNameIndex()) |
| printLinkageName(OS, Full, const_cast<LVSymbol *>(this)); |
| if (LVSymbol *Reference = getReference()) |
| Reference->printReference(OS, Full, const_cast<LVSymbol *>(this)); |
| |
| // Print location information. |
| LVLocation::print(Locations, OS, Full); |
| } |
| } |