forked from OSchip/llvm-project
465 lines
14 KiB
C++
465 lines
14 KiB
C++
//===-- LVElement.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 LVElement class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
|
|
#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
|
|
#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
|
|
#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
|
|
#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::logicalview;
|
|
|
|
#define DEBUG_TYPE "Element"
|
|
|
|
LVType *LVElement::getTypeAsType() const {
|
|
return ElementType && ElementType->getIsType()
|
|
? static_cast<LVType *>(ElementType)
|
|
: nullptr;
|
|
}
|
|
|
|
LVScope *LVElement::getTypeAsScope() const {
|
|
return ElementType && ElementType->getIsScope()
|
|
? static_cast<LVScope *>(ElementType)
|
|
: nullptr;
|
|
}
|
|
|
|
// Set the element type.
|
|
void LVElement::setGenericType(LVElement *Element) {
|
|
if (!Element->isTemplateParam()) {
|
|
setType(Element);
|
|
return;
|
|
}
|
|
// For template parameters, the instance type can be a type or a scope.
|
|
if (options().getAttributeArgument()) {
|
|
if (Element->getIsKindType())
|
|
setType(Element->getTypeAsType());
|
|
else if (Element->getIsKindScope())
|
|
setType(Element->getTypeAsScope());
|
|
} else
|
|
setType(Element);
|
|
}
|
|
|
|
// Discriminator as string.
|
|
std::string LVElement::discriminatorAsString() const {
|
|
uint32_t Discriminator = getDiscriminator();
|
|
std::string String;
|
|
raw_string_ostream Stream(String);
|
|
if (Discriminator && options().getAttributeDiscriminator())
|
|
Stream << "," << Discriminator;
|
|
return String;
|
|
}
|
|
|
|
// Get the type as a string.
|
|
StringRef LVElement::typeAsString() const {
|
|
return getHasType() ? getTypeName() : typeVoid();
|
|
}
|
|
|
|
// Get name for element type.
|
|
StringRef LVElement::getTypeName() const {
|
|
return ElementType ? ElementType->getName() : StringRef();
|
|
}
|
|
|
|
static size_t getStringIndex(StringRef Name) {
|
|
// Convert the name to Unified format ('\' have been converted into '/').
|
|
std::string Pathname(transformPath(Name));
|
|
|
|
// Depending on the --attribute=filename and --attribute=pathname command
|
|
// line options, use the basename or the full pathname as the name.
|
|
if (!options().getAttributePathname()) {
|
|
// Get the basename by ignoring any prefix up to the last slash ('/').
|
|
StringRef Basename = Pathname;
|
|
size_t Pos = Basename.rfind('/');
|
|
if (Pos != std::string::npos)
|
|
Basename = Basename.substr(Pos + 1);
|
|
return getStringPool().getIndex(Basename);
|
|
}
|
|
|
|
return getStringPool().getIndex(Pathname);
|
|
}
|
|
|
|
void LVElement::setName(StringRef ElementName) {
|
|
// In the case of Root or Compile Unit, get index for the flatted out name.
|
|
NameIndex = getTransformName() ? getStringIndex(ElementName)
|
|
: getStringPool().getIndex(ElementName);
|
|
}
|
|
|
|
void LVElement::setFilename(StringRef Filename) {
|
|
// Get index for the flattened out filename.
|
|
FilenameIndex = getStringIndex(Filename);
|
|
}
|
|
|
|
// Return the string representation of a DIE offset.
|
|
std::string LVElement::typeOffsetAsString() const {
|
|
if (options().getAttributeOffset()) {
|
|
LVElement *Element = getType();
|
|
return hexSquareString(Element ? Element->getOffset() : 0);
|
|
}
|
|
return {};
|
|
}
|
|
|
|
StringRef LVElement::accessibilityString(uint32_t Access) const {
|
|
uint32_t Value = getAccessibilityCode();
|
|
switch (Value ? Value : Access) {
|
|
case dwarf::DW_ACCESS_public:
|
|
return "public";
|
|
case dwarf::DW_ACCESS_protected:
|
|
return "protected";
|
|
case dwarf::DW_ACCESS_private:
|
|
return "private";
|
|
default:
|
|
return StringRef();
|
|
}
|
|
}
|
|
|
|
StringRef LVElement::externalString() const {
|
|
return getIsExternal() ? "extern" : StringRef();
|
|
}
|
|
|
|
StringRef LVElement::inlineCodeString(uint32_t Code) const {
|
|
uint32_t Value = getInlineCode();
|
|
switch (Value ? Value : Code) {
|
|
case dwarf::DW_INL_not_inlined:
|
|
return "not_inlined";
|
|
case dwarf::DW_INL_inlined:
|
|
return "inlined";
|
|
case dwarf::DW_INL_declared_not_inlined:
|
|
return "declared_not_inlined";
|
|
case dwarf::DW_INL_declared_inlined:
|
|
return "declared_inlined";
|
|
default:
|
|
return StringRef();
|
|
}
|
|
}
|
|
|
|
StringRef LVElement::virtualityString(uint32_t Virtuality) const {
|
|
uint32_t Value = getVirtualityCode();
|
|
switch (Value ? Value : Virtuality) {
|
|
case dwarf::DW_VIRTUALITY_none:
|
|
return StringRef();
|
|
case dwarf::DW_VIRTUALITY_virtual:
|
|
return "virtual";
|
|
case dwarf::DW_VIRTUALITY_pure_virtual:
|
|
return "pure virtual";
|
|
default:
|
|
return StringRef();
|
|
}
|
|
}
|
|
|
|
void LVElement::resolve() {
|
|
if (getIsResolved())
|
|
return;
|
|
setIsResolved();
|
|
|
|
resolveReferences();
|
|
resolveParents();
|
|
resolveExtra();
|
|
resolveName();
|
|
}
|
|
|
|
// Set File/Line using the specification element.
|
|
void LVElement::setFileLine(LVElement *Specification) {
|
|
// In the case of inlined functions, the correct scope must be associated
|
|
// with the file and line information of the outline version.
|
|
if (!isLined()) {
|
|
setLineNumber(Specification->getLineNumber());
|
|
setIsLineFromReference();
|
|
}
|
|
if (!isFiled()) {
|
|
setFilenameIndex(Specification->getFilenameIndex());
|
|
setIsFileFromReference();
|
|
}
|
|
}
|
|
|
|
void LVElement::resolveName() {
|
|
// Set the qualified name if requested.
|
|
if (options().getAttributeQualified())
|
|
resolveQualifiedName();
|
|
|
|
setIsResolvedName();
|
|
}
|
|
|
|
// Resolve any parents.
|
|
void LVElement::resolveParents() {
|
|
if (isRoot() || isCompileUnit())
|
|
return;
|
|
|
|
LVScope *Parent = getParentScope();
|
|
if (Parent && !Parent->getIsCompileUnit())
|
|
Parent->resolve();
|
|
}
|
|
|
|
// Generate a name for unnamed elements.
|
|
void LVElement::generateName(std::string &Prefix) const {
|
|
LVScope *Scope = getParentScope();
|
|
if (!Scope)
|
|
return;
|
|
|
|
// Use its parent name and any line information.
|
|
Prefix.append(std::string(Scope->getName()));
|
|
Prefix.append("::");
|
|
Prefix.append(isLined() ? lineNumberAsString(/*ShowZero=*/true) : "?");
|
|
|
|
// Remove any whitespaces.
|
|
Prefix.erase(std::remove_if(Prefix.begin(), Prefix.end(), ::isspace),
|
|
Prefix.end());
|
|
}
|
|
|
|
// Generate a name for unnamed elements.
|
|
void LVElement::generateName() {
|
|
setIsAnonymous();
|
|
std::string Name;
|
|
generateName(Name);
|
|
setName(Name);
|
|
setIsGeneratedName();
|
|
}
|
|
|
|
void LVElement::updateLevel(LVScope *Parent, bool Moved) {
|
|
setLevel(Parent->getLevel() + 1);
|
|
if (Moved)
|
|
setHasMoved();
|
|
}
|
|
|
|
// Generate the full name for the element, to include special qualifiers.
|
|
void LVElement::resolveFullname(LVElement *BaseType, StringRef Name) {
|
|
// For the following sample code,
|
|
// void *p;
|
|
// some compilers do not generate an attribute for the associated type:
|
|
// DW_TAG_variable
|
|
// DW_AT_name 'p'
|
|
// DW_AT_type $1
|
|
// ...
|
|
// $1: DW_TAG_pointer_type
|
|
// ...
|
|
// For those cases, generate the implicit 'void' type.
|
|
StringRef BaseTypename = BaseType ? BaseType->getName() : emptyString();
|
|
bool GetBaseTypename = false;
|
|
bool UseBaseTypename = true;
|
|
bool UseNameText = true;
|
|
|
|
switch (getTag()) {
|
|
case dwarf::DW_TAG_pointer_type: // "*";
|
|
if (!BaseType)
|
|
BaseTypename = typeVoid();
|
|
break;
|
|
case dwarf::DW_TAG_const_type: // "const"
|
|
case dwarf::DW_TAG_ptr_to_member_type: // "*"
|
|
case dwarf::DW_TAG_rvalue_reference_type: // "&&"
|
|
case dwarf::DW_TAG_reference_type: // "&"
|
|
case dwarf::DW_TAG_restrict_type: // "restrict"
|
|
case dwarf::DW_TAG_volatile_type: // "volatile"
|
|
case dwarf::DW_TAG_unaligned: // "unaligned"
|
|
break;
|
|
case dwarf::DW_TAG_base_type:
|
|
case dwarf::DW_TAG_compile_unit:
|
|
case dwarf::DW_TAG_class_type:
|
|
case dwarf::DW_TAG_enumerator:
|
|
case dwarf::DW_TAG_namespace:
|
|
case dwarf::DW_TAG_skeleton_unit:
|
|
case dwarf::DW_TAG_structure_type:
|
|
case dwarf::DW_TAG_union_type:
|
|
case dwarf::DW_TAG_unspecified_type:
|
|
case dwarf::DW_TAG_GNU_template_parameter_pack:
|
|
GetBaseTypename = true;
|
|
break;
|
|
case dwarf::DW_TAG_array_type:
|
|
case dwarf::DW_TAG_call_site:
|
|
case dwarf::DW_TAG_entry_point:
|
|
case dwarf::DW_TAG_enumeration_type:
|
|
case dwarf::DW_TAG_GNU_call_site:
|
|
case dwarf::DW_TAG_imported_module:
|
|
case dwarf::DW_TAG_imported_declaration:
|
|
case dwarf::DW_TAG_inlined_subroutine:
|
|
case dwarf::DW_TAG_label:
|
|
case dwarf::DW_TAG_subprogram:
|
|
case dwarf::DW_TAG_subrange_type:
|
|
case dwarf::DW_TAG_subroutine_type:
|
|
case dwarf::DW_TAG_typedef:
|
|
GetBaseTypename = true;
|
|
UseBaseTypename = false;
|
|
break;
|
|
case dwarf::DW_TAG_template_type_parameter:
|
|
case dwarf::DW_TAG_template_value_parameter:
|
|
UseBaseTypename = false;
|
|
break;
|
|
case dwarf::DW_TAG_GNU_template_template_param:
|
|
break;
|
|
case dwarf::DW_TAG_catch_block:
|
|
case dwarf::DW_TAG_lexical_block:
|
|
case dwarf::DW_TAG_try_block:
|
|
UseNameText = false;
|
|
break;
|
|
default:
|
|
llvm_unreachable("Invalid type.");
|
|
return;
|
|
break;
|
|
}
|
|
|
|
// Overwrite if no given value. 'Name' is empty when resolving for scopes
|
|
// and symbols. In the case of types, it represents the type base name.
|
|
if (Name.empty() && GetBaseTypename)
|
|
Name = getName();
|
|
|
|
// Concatenate the elements to get the full type name.
|
|
// Type will be: base_parent + pre + base + parent + post.
|
|
std::string Fullname;
|
|
|
|
if (UseNameText && Name.size())
|
|
Fullname.append(std::string(Name));
|
|
if (UseBaseTypename && BaseTypename.size()) {
|
|
if (UseNameText && Name.size())
|
|
Fullname.append(" ");
|
|
Fullname.append(std::string(BaseTypename));
|
|
}
|
|
|
|
// For a better and consistent layout, check if the generated name
|
|
// contains double space sequences.
|
|
assert((Fullname.find(" ", 0) == std::string::npos) &&
|
|
"Extra double spaces in name.");
|
|
|
|
LLVM_DEBUG({ dbgs() << "Fullname = '" << Fullname << "'\n"; });
|
|
setName(Fullname.c_str());
|
|
}
|
|
|
|
void LVElement::setFile(LVElement *Reference) {
|
|
if (!options().getAttributeAnySource())
|
|
return;
|
|
|
|
// At this point, any existing reference to another element, have been
|
|
// resolved and the file ID extracted from the DI entry.
|
|
if (Reference)
|
|
setFileLine(Reference);
|
|
|
|
// The file information is used to show the source file for any element
|
|
// and display any new source file in relation to its parent element.
|
|
// a) Elements that are not inlined.
|
|
// - We record the DW_AT_decl_line and DW_AT_decl_file.
|
|
// b) Elements that are inlined.
|
|
// - We record the DW_AT_decl_line and DW_AT_decl_file.
|
|
// - We record the DW_AT_call_line and DW_AT_call_file.
|
|
// For both cases, we use the DW_AT_decl_file value to detect any changes
|
|
// in the source filename containing the element. Changes on this value
|
|
// indicates that the element being printed is not contained in the
|
|
// previous printed filename.
|
|
|
|
// The source files are indexed starting at 0, but DW_AT_decl_file defines
|
|
// that 0 means no file; a value of 1 means the 0th entry.
|
|
size_t Index = 0;
|
|
|
|
// An element with no source file information will use the reference
|
|
// attribute (DW_AT_specification, DW_AT_abstract_origin, DW_AT_extension)
|
|
// to update its information.
|
|
if (getIsFileFromReference() && Reference) {
|
|
Index = Reference->getFilenameIndex();
|
|
if (Reference->getInvalidFilename())
|
|
setInvalidFilename();
|
|
setFilenameIndex(Index);
|
|
return;
|
|
}
|
|
|
|
// The source files are indexed starting at 0, but DW_AT_decl_file
|
|
// defines that 0 means no file; a value of 1 means the 0th entry.
|
|
Index = getFilenameIndex();
|
|
if (Index) {
|
|
StringRef Filename = getReader().getFilename(this, Index);
|
|
Filename.size() ? setFilename(Filename) : setInvalidFilename();
|
|
}
|
|
}
|
|
|
|
LVScope *LVElement::traverseParents(LVScopeGetFunction GetFunction) const {
|
|
LVScope *Parent = getParentScope();
|
|
while (Parent && !(Parent->*GetFunction)())
|
|
Parent = Parent->getParentScope();
|
|
return Parent;
|
|
}
|
|
|
|
LVScope *LVElement::getFunctionParent() const {
|
|
return traverseParents(&LVScope::getIsFunction);
|
|
}
|
|
|
|
LVScope *LVElement::getCompileUnitParent() const {
|
|
return traverseParents(&LVScope::getIsCompileUnit);
|
|
}
|
|
|
|
// Resolve the qualified name to include the parent hierarchy names.
|
|
void LVElement::resolveQualifiedName() {
|
|
if (!getIsReferencedType() || isBase() || getQualifiedResolved() ||
|
|
!getIncludeInPrint())
|
|
return;
|
|
|
|
std::string Name;
|
|
|
|
// Get the qualified name, excluding the Compile Unit.
|
|
LVScope *Parent = getParentScope();
|
|
if (Parent && !Parent->getIsRoot()) {
|
|
while (Parent && !Parent->getIsCompileUnit()) {
|
|
Name.insert(0, "::");
|
|
if (Parent->isNamed())
|
|
Name.insert(0, std::string(Parent->getName()));
|
|
else {
|
|
std::string Temp;
|
|
Parent->generateName(Temp);
|
|
Name.insert(0, Temp);
|
|
}
|
|
Parent = Parent->getParentScope();
|
|
}
|
|
}
|
|
|
|
if (Name.size()) {
|
|
setQualifiedName(Name);
|
|
setQualifiedResolved();
|
|
}
|
|
LLVM_DEBUG({
|
|
dbgs() << "Offset: " << hexSquareString(getOffset())
|
|
<< ", Kind: " << formattedKind(kind())
|
|
<< ", Name: " << formattedName(getName())
|
|
<< ", QualifiedName: " << formattedName(Name) << "\n";
|
|
});
|
|
}
|
|
|
|
// Print the FileName Index.
|
|
void LVElement::printFileIndex(raw_ostream &OS, bool Full) const {
|
|
if (options().getPrintFormatting() && options().getAttributeAnySource() &&
|
|
getFilenameIndex()) {
|
|
|
|
// Check if there is a change in the File ID sequence.
|
|
size_t Index = getFilenameIndex();
|
|
if (options().changeFilenameIndex(Index)) {
|
|
// Just to keep a nice layout.
|
|
OS << "\n";
|
|
printAttributes(OS, /*Full=*/false);
|
|
|
|
OS << " {Source} ";
|
|
if (getInvalidFilename())
|
|
OS << format("[0x%08x]\n", Index);
|
|
else
|
|
OS << formattedName(getPathname()) << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
void LVElement::printReference(raw_ostream &OS, bool Full,
|
|
LVElement *Parent) const {
|
|
if (options().getPrintFormatting() && options().getAttributeReference())
|
|
printAttributes(OS, Full, "{Reference} ", Parent,
|
|
referenceAsString(getLineNumber(), /*Spaces=*/false),
|
|
/*UseQuotes=*/false, /*PrintRef=*/true);
|
|
}
|
|
|
|
void LVElement::printLinkageName(raw_ostream &OS, bool Full,
|
|
LVElement *Parent) const {
|
|
if (options().getPrintFormatting() && options().getAttributeLinkage()) {
|
|
printAttributes(OS, Full, "{Linkage} ", Parent, getLinkageName(),
|
|
/*UseQuotes=*/true, /*PrintRef=*/false);
|
|
}
|
|
}
|