aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:04 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:11 +0000
commite3b557809604d036af6e00c60f012c2025b59a5e (patch)
tree8a11ba2269a3b669601e2fd41145b174008f4da8 /llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
parent08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff)
Diffstat (limited to 'llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp')
-rw-r--r--llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp530
1 files changed, 530 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
new file mode 100644
index 000000000000..a320752befc4
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
@@ -0,0 +1,530 @@
+//===-- 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"
+
+LVElementDispatch LVElement::Dispatch = {
+ {LVElementKind::Discarded, &LVElement::getIsDiscarded},
+ {LVElementKind::Global, &LVElement::getIsGlobalReference},
+ {LVElementKind::Optimized, &LVElement::getIsOptimized}};
+
+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);
+}
+
+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";
+ });
+}
+
+bool LVElement::referenceMatch(const LVElement *Element) const {
+ return (getHasReference() && Element->getHasReference()) ||
+ (!getHasReference() && !Element->getHasReference());
+}
+
+bool LVElement::equals(const LVElement *Element) const {
+ // The minimum factors that must be the same for an equality are:
+ // line number, level, name, qualified name and filename.
+ LLVM_DEBUG({
+ dbgs() << "\n[Element::equals]\n";
+ if (options().getAttributeOffset()) {
+ dbgs() << "Reference: " << hexSquareString(getOffset()) << "\n";
+ dbgs() << "Target : " << hexSquareString(Element->getOffset()) << "\n";
+ }
+ dbgs() << "Reference: "
+ << "Kind = " << formattedKind(kind()) << ", "
+ << "Name = " << formattedName(getName()) << ", "
+ << "Qualified = " << formattedName(getQualifiedName()) << "\n"
+ << "Target : "
+ << "Kind = " << formattedKind(Element->kind()) << ", "
+ << "Name = " << formattedName(Element->getName()) << ", "
+ << "Qualified = " << formattedName(Element->getQualifiedName())
+ << "\n"
+ << "Reference: "
+ << "NameIndex = " << getNameIndex() << ", "
+ << "QualifiedNameIndex = " << getQualifiedNameIndex() << ", "
+ << "FilenameIndex = " << getFilenameIndex() << "\n"
+ << "Target : "
+ << "NameIndex = " << Element->getNameIndex() << ", "
+ << "QualifiedNameIndex = " << Element->getQualifiedNameIndex()
+ << ", "
+ << "FilenameIndex = " << Element->getFilenameIndex() << "\n";
+ });
+ if ((getLineNumber() != Element->getLineNumber()) ||
+ (getLevel() != Element->getLevel()))
+ return false;
+
+ if ((getQualifiedNameIndex() != Element->getQualifiedNameIndex()) ||
+ (getNameIndex() != Element->getNameIndex()) ||
+ (getFilenameIndex() != Element->getFilenameIndex()))
+ return false;
+
+ if (!getType() && !Element->getType())
+ return true;
+ if (getType() && Element->getType())
+ return getType()->equals(Element->getType());
+ return false;
+}
+
+// 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);
+ }
+}
+
+void LVElement::printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent,
+ LVScope *Scope) const {
+ if (options().getPrintFormatting() && options().getAttributeLinkage()) {
+ LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope);
+ std::string Text = (Twine(" 0x") + Twine::utohexstr(SectionIndex) +
+ Twine(" '") + Twine(getLinkageName()) + Twine("'"))
+ .str();
+ printAttributes(OS, Full, "{Linkage} ", Parent, Text,
+ /*UseQuotes=*/false, /*PrintRef=*/false);
+ }
+}