forked from OSchip/llvm-project
450 lines
14 KiB
C++
450 lines
14 KiB
C++
//===-- 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);
|
|
}
|
|
}
|