brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.1 KiB · c6fb405 Raw
566 lines · cpp
1//===-- LVElement.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-exception6//7//===----------------------------------------------------------------------===//8//9// This implements the LVElement class.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/DebugInfo/LogicalView/Core/LVElement.h"14#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"15#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"16#include "llvm/DebugInfo/LogicalView/Core/LVType.h"17 18using namespace llvm;19using namespace llvm::codeview;20using namespace llvm::logicalview;21 22#define DEBUG_TYPE "Element"23 24LVElementDispatch LVElement::Dispatch = {25    {LVElementKind::Discarded, &LVElement::getIsDiscarded},26    {LVElementKind::Global, &LVElement::getIsGlobalReference},27    {LVElementKind::Optimized, &LVElement::getIsOptimized}};28 29LVType *LVElement::getTypeAsType() const {30  return ElementType && ElementType->getIsType()31             ? static_cast<LVType *>(ElementType)32             : nullptr;33}34 35LVScope *LVElement::getTypeAsScope() const {36  return ElementType && ElementType->getIsScope()37             ? static_cast<LVScope *>(ElementType)38             : nullptr;39}40 41// Set the element type.42void LVElement::setGenericType(LVElement *Element) {43  if (!Element->isTemplateParam()) {44    setType(Element);45    return;46  }47  // For template parameters, the instance type can be a type or a scope.48  if (options().getAttributeArgument()) {49    if (Element->getIsKindType())50      setType(Element->getTypeAsType());51    else if (Element->getIsKindScope())52      setType(Element->getTypeAsScope());53  } else54    setType(Element);55}56 57// Discriminator as string.58std::string LVElement::discriminatorAsString() const {59  uint32_t Discriminator = getDiscriminator();60  std::string String;61  raw_string_ostream Stream(String);62  if (Discriminator && options().getAttributeDiscriminator())63    Stream << "," << Discriminator;64  return String;65}66 67// Get the type as a string.68StringRef LVElement::typeAsString() const {69  return getHasType() ? getTypeName() : typeVoid();70}71 72// Get name for element type.73StringRef LVElement::getTypeName() const {74  return ElementType ? ElementType->getName() : StringRef();75}76 77static size_t getStringIndex(StringRef Name) {78  // Convert the name to Unified format ('\' have been converted into '/').79  std::string Pathname(transformPath(Name));80 81  // Depending on the --attribute=filename and --attribute=pathname command82  // line options, use the basename or the full pathname as the name.83  if (!options().getAttributePathname()) {84    // Get the basename by ignoring any prefix up to the last slash ('/').85    StringRef Basename = Pathname;86    size_t Pos = Basename.rfind('/');87    if (Pos != std::string::npos)88      Basename = Basename.substr(Pos + 1);89    return getStringPool().getIndex(Basename);90  }91 92  return getStringPool().getIndex(Pathname);93}94 95void LVElement::setName(StringRef ElementName) {96  // In the case of Root or Compile Unit, get index for the flatted out name.97  NameIndex = getTransformName() ? getStringIndex(ElementName)98                                 : getStringPool().getIndex(ElementName);99}100 101void LVElement::setFilename(StringRef Filename) {102  // Get index for the flattened out filename.103  FilenameIndex = getStringIndex(Filename);104}105 106void LVElement::setInnerComponent(StringRef Name) {107  if (Name.size()) {108    StringRef InnerComponent;109    std::tie(std::ignore, InnerComponent) = getInnerComponent(Name);110    setName(InnerComponent);111  }112}113 114// Return the string representation of a DIE offset.115std::string LVElement::typeOffsetAsString() const {116  if (options().getAttributeOffset()) {117    LVElement *Element = getType();118    return hexSquareString(Element ? Element->getOffset() : 0);119  }120  return {};121}122 123StringRef LVElement::accessibilityString(uint32_t Access) const {124  uint32_t Value = getAccessibilityCode();125  switch (Value ? Value : Access) {126  case dwarf::DW_ACCESS_public:127    return "public";128  case dwarf::DW_ACCESS_protected:129    return "protected";130  case dwarf::DW_ACCESS_private:131    return "private";132  default:133    return StringRef();134  }135}136 137std::optional<uint32_t> LVElement::getAccessibilityCode(MemberAccess Access) {138  switch (Access) {139  case MemberAccess::Private:140    return dwarf::DW_ACCESS_private;141  case MemberAccess::Protected:142    return dwarf::DW_ACCESS_protected;143  case MemberAccess::Public:144    return dwarf::DW_ACCESS_public;145  default:146    return std::nullopt;147  }148}149 150StringRef LVElement::externalString() const {151  return getIsExternal() ? "extern" : StringRef();152}153 154StringRef LVElement::inlineCodeString(uint32_t Code) const {155  uint32_t Value = getInlineCode();156  switch (Value ? Value : Code) {157  case dwarf::DW_INL_not_inlined:158    return "not_inlined";159  case dwarf::DW_INL_inlined:160    return "inlined";161  case dwarf::DW_INL_declared_not_inlined:162    return "declared_not_inlined";163  case dwarf::DW_INL_declared_inlined:164    return "declared_inlined";165  default:166    return StringRef();167  }168}169 170StringRef LVElement::virtualityString(uint32_t Virtuality) const {171  uint32_t Value = getVirtualityCode();172  switch (Value ? Value : Virtuality) {173  case dwarf::DW_VIRTUALITY_none:174    return StringRef();175  case dwarf::DW_VIRTUALITY_virtual:176    return "virtual";177  case dwarf::DW_VIRTUALITY_pure_virtual:178    return "pure virtual";179  default:180    return StringRef();181  }182}183 184std::optional<uint32_t> LVElement::getVirtualityCode(MethodKind Virtuality) {185  switch (Virtuality) {186  case MethodKind::Virtual:187    return dwarf::DW_VIRTUALITY_virtual;188  case MethodKind::PureVirtual:189    return dwarf::DW_VIRTUALITY_pure_virtual;190  case MethodKind::IntroducingVirtual:191  case MethodKind::PureIntroducingVirtual:192    // No direct equivalents in DWARF. Assume Virtual.193    return dwarf::DW_VIRTUALITY_virtual;194  default:195    return std::nullopt;196  }197}198 199void LVElement::resolve() {200  if (getIsResolved())201    return;202  setIsResolved();203 204  resolveReferences();205  resolveParents();206  resolveExtra();207  resolveName();208}209 210// Set File/Line using the specification element.211void LVElement::setFileLine(LVElement *Specification) {212  // In the case of inlined functions, the correct scope must be associated213  // with the file and line information of the outline version.214  if (!isLined()) {215    setLineNumber(Specification->getLineNumber());216    setIsLineFromReference();217  }218  if (!isFiled()) {219    setFilenameIndex(Specification->getFilenameIndex());220    setIsFileFromReference();221  }222}223 224void LVElement::resolveName() {225  // Set the qualified name if requested.226  if (options().getAttributeQualified())227    resolveQualifiedName();228 229  setIsResolvedName();230}231 232// Resolve any parents.233void LVElement::resolveParents() {234  if (isRoot() || isCompileUnit())235    return;236 237  LVScope *Parent = getParentScope();238  if (Parent && !Parent->getIsCompileUnit())239    Parent->resolve();240}241 242// Generate a name for unnamed elements.243void LVElement::generateName(std::string &Prefix) const {244  LVScope *Scope = getParentScope();245  if (!Scope)246    return;247 248  // Use its parent name and any line information.249  Prefix.append(std::string(Scope->getName()));250  Prefix.append("::");251  Prefix.append(isLined() ? lineNumberAsString(/*ShowZero=*/true) : "?");252 253  // Remove any whitespaces.254  llvm::erase_if(Prefix, ::isspace);255}256 257// Generate a name for unnamed elements.258void LVElement::generateName() {259  setIsAnonymous();260  std::string Name;261  generateName(Name);262  setName(Name);263  setIsGeneratedName();264}265 266void LVElement::updateLevel(LVScope *Parent, bool Moved) {267  setLevel(Parent->getLevel() + 1);268  if (Moved)269    setHasMoved();270}271 272// Generate the full name for the element, to include special qualifiers.273void LVElement::resolveFullname(LVElement *BaseType, StringRef Name) {274  // For the following sample code,275  //   void *p;276  // some compilers do not generate an attribute for the associated type:277  //      DW_TAG_variable278  //        DW_AT_name 'p'279  //        DW_AT_type $1280  //        ...281  // $1:  DW_TAG_pointer_type282  //      ...283  // For those cases, generate the implicit 'void' type.284  StringRef BaseTypename = BaseType ? BaseType->getName() : emptyString();285  bool GetBaseTypename = false;286  bool UseBaseTypename = true;287  bool UseNameText = true;288 289  switch (getTag()) {290  case dwarf::DW_TAG_pointer_type: // "*";291    if (!BaseType)292      BaseTypename = typeVoid();293    break;294  case dwarf::DW_TAG_const_type:            // "const"295  case dwarf::DW_TAG_ptr_to_member_type:    // "*"296  case dwarf::DW_TAG_rvalue_reference_type: // "&&"297  case dwarf::DW_TAG_reference_type:        // "&"298  case dwarf::DW_TAG_restrict_type:         // "restrict"299  case dwarf::DW_TAG_volatile_type:         // "volatile"300  case dwarf::DW_TAG_unaligned:             // "unaligned"301    break;302  case dwarf::DW_TAG_base_type:303  case dwarf::DW_TAG_compile_unit:304  case dwarf::DW_TAG_class_type:305  case dwarf::DW_TAG_enumerator:306  case dwarf::DW_TAG_namespace:307  case dwarf::DW_TAG_skeleton_unit:308  case dwarf::DW_TAG_structure_type:309  case dwarf::DW_TAG_union_type:310  case dwarf::DW_TAG_unspecified_type:311  case dwarf::DW_TAG_GNU_template_parameter_pack:312    GetBaseTypename = true;313    break;314  case dwarf::DW_TAG_array_type:315  case dwarf::DW_TAG_call_site:316  case dwarf::DW_TAG_entry_point:317  case dwarf::DW_TAG_enumeration_type:318  case dwarf::DW_TAG_GNU_call_site:319  case dwarf::DW_TAG_imported_module:320  case dwarf::DW_TAG_imported_declaration:321  case dwarf::DW_TAG_inlined_subroutine:322  case dwarf::DW_TAG_label:323  case dwarf::DW_TAG_subprogram:324  case dwarf::DW_TAG_subrange_type:325  case dwarf::DW_TAG_subroutine_type:326  case dwarf::DW_TAG_typedef:327    GetBaseTypename = true;328    UseBaseTypename = false;329    break;330  case dwarf::DW_TAG_template_type_parameter:331  case dwarf::DW_TAG_template_value_parameter:332    UseBaseTypename = false;333    break;334  case dwarf::DW_TAG_GNU_template_template_param:335    break;336  case dwarf::DW_TAG_catch_block:337  case dwarf::DW_TAG_lexical_block:338  case dwarf::DW_TAG_try_block:339    UseNameText = false;340    break;341  default:342    llvm_unreachable("Invalid type.");343    return;344    break;345  }346 347  // Overwrite if no given value. 'Name' is empty when resolving for scopes348  // and symbols. In the case of types, it represents the type base name.349  if (Name.empty() && GetBaseTypename)350    Name = getName();351 352  // Concatenate the elements to get the full type name.353  // Type will be: base_parent + pre + base + parent + post.354  std::string Fullname;355 356  if (UseNameText && Name.size())357    Fullname.append(std::string(Name));358  if (UseBaseTypename && BaseTypename.size()) {359    if (UseNameText && Name.size())360      Fullname.append(" ");361    Fullname.append(std::string(BaseTypename));362  }363 364  // For a better and consistent layout, check if the generated name365  // contains double space sequences.366  assert((Fullname.find("  ", 0) == std::string::npos) &&367         "Extra double spaces in name.");368 369  LLVM_DEBUG({ dbgs() << "Fullname = '" << Fullname << "'\n"; });370  setName(Fullname);371}372 373void LVElement::setFile(LVElement *Reference) {374  if (!options().getAttributeAnySource())375    return;376 377  // At this point, any existing reference to another element, have been378  // resolved and the file ID extracted from the DI entry.379  if (Reference)380    setFileLine(Reference);381 382  // The file information is used to show the source file for any element383  // and display any new source file in relation to its parent element.384  // a) Elements that are not inlined.385  //    - We record the DW_AT_decl_line and DW_AT_decl_file.386  // b) Elements that are inlined.387  //    - We record the DW_AT_decl_line and DW_AT_decl_file.388  //    - We record the DW_AT_call_line and DW_AT_call_file.389  // For both cases, we use the DW_AT_decl_file value to detect any changes390  // in the source filename containing the element. Changes on this value391  // indicates that the element being printed is not contained in the392  // previous printed filename.393 394  // The source files are indexed starting at 0, but DW_AT_decl_file defines395  // that 0 means no file; a value of 1 means the 0th entry.396  size_t Index = 0;397 398  // An element with no source file information will use the reference399  // attribute (DW_AT_specification, DW_AT_abstract_origin, DW_AT_extension)400  // to update its information.401  if (getIsFileFromReference() && Reference) {402    Index = Reference->getFilenameIndex();403    if (Reference->getInvalidFilename())404      setInvalidFilename();405    setFilenameIndex(Index);406    return;407  }408 409  // The source files are indexed starting at 0, but DW_AT_decl_file410  // defines that 0 means no file; a value of 1 means the 0th entry.411  Index = getFilenameIndex();412  if (Index) {413    StringRef Filename = getReader().getFilename(this, Index);414    Filename.size() ? setFilename(Filename) : setInvalidFilename();415  }416}417 418LVScope *LVElement::traverseParents(LVScopeGetFunction GetFunction) const {419  LVScope *Parent = getParentScope();420  while (Parent && !(Parent->*GetFunction)())421    Parent = Parent->getParentScope();422  return Parent;423}424 425LVScope *LVElement::getFunctionParent() const {426  return traverseParents(&LVScope::getIsFunction);427}428 429LVScope *LVElement::getCompileUnitParent() const {430  return traverseParents(&LVScope::getIsCompileUnit);431}432 433// Resolve the qualified name to include the parent hierarchy names.434void LVElement::resolveQualifiedName() {435  if (!getIsReferencedType() || isBase() || getQualifiedResolved() ||436      !getIncludeInPrint())437    return;438 439  std::string Name;440 441  // Get the qualified name, excluding the Compile Unit.442  LVScope *Parent = getParentScope();443  if (Parent && !Parent->getIsRoot()) {444    while (Parent && !Parent->getIsCompileUnit()) {445      Name.insert(0, "::");446      if (Parent->isNamed())447        Name.insert(0, std::string(Parent->getName()));448      else {449        std::string Temp;450        Parent->generateName(Temp);451        Name.insert(0, Temp);452      }453      Parent = Parent->getParentScope();454    }455  }456 457  if (Name.size()) {458    setQualifiedName(Name);459    setQualifiedResolved();460  }461  LLVM_DEBUG({462    dbgs() << "Offset: " << hexSquareString(getOffset())463           << ", Kind: " << formattedKind(kind())464           << ", Name: " << formattedName(getName())465           << ", QualifiedName: " << formattedName(Name) << "\n";466  });467}468 469bool LVElement::referenceMatch(const LVElement *Element) const {470  return (getHasReference() && Element->getHasReference()) ||471         (!getHasReference() && !Element->getHasReference());472}473 474bool LVElement::equals(const LVElement *Element) const {475  // The minimum factors that must be the same for an equality are:476  // line number, level, name, qualified name and filename.477  LLVM_DEBUG({478    dbgs() << "\n[Element::equals]\n";479    if (options().getAttributeOffset()) {480      dbgs() << "Reference: " << hexSquareString(getOffset()) << "\n";481      dbgs() << "Target   : " << hexSquareString(Element->getOffset()) << "\n";482    }483    dbgs() << "Reference: "484           << "Kind = " << formattedKind(kind()) << ", "485           << "Name = " << formattedName(getName()) << ", "486           << "Qualified = " << formattedName(getQualifiedName()) << "\n"487           << "Target   : "488           << "Kind = " << formattedKind(Element->kind()) << ", "489           << "Name = " << formattedName(Element->getName()) << ", "490           << "Qualified = " << formattedName(Element->getQualifiedName())491           << "\n"492           << "Reference: "493           << "NameIndex = " << getNameIndex() << ", "494           << "QualifiedNameIndex = " << getQualifiedNameIndex() << ", "495           << "FilenameIndex = " << getFilenameIndex() << "\n"496           << "Target   : "497           << "NameIndex = " << Element->getNameIndex() << ", "498           << "QualifiedNameIndex = " << Element->getQualifiedNameIndex()499           << ", "500           << "FilenameIndex = " << Element->getFilenameIndex() << "\n";501  });502  if ((getLineNumber() != Element->getLineNumber()) ||503      (getLevel() != Element->getLevel()))504    return false;505 506  if ((getQualifiedNameIndex() != Element->getQualifiedNameIndex()) ||507      (getNameIndex() != Element->getNameIndex()) ||508      (getFilenameIndex() != Element->getFilenameIndex()))509    return false;510 511  if (!getType() && !Element->getType())512    return true;513  if (getType() && Element->getType())514    return getType()->equals(Element->getType());515  return false;516}517 518// Print the FileName Index.519void LVElement::printFileIndex(raw_ostream &OS, bool Full) const {520  if (options().getPrintFormatting() && options().getAttributeAnySource() &&521      getFilenameIndex()) {522 523    // Check if there is a change in the File ID sequence.524    size_t Index = getFilenameIndex();525    if (options().changeFilenameIndex(Index)) {526      // Just to keep a nice layout.527      OS << "\n";528      printAttributes(OS, /*Full=*/false);529 530      OS << "  {Source} ";531      if (getInvalidFilename())532        OS << format("[0x%08x]\n", Index);533      else534        OS << formattedName(getPathname()) << "\n";535    }536  }537}538 539void LVElement::printReference(raw_ostream &OS, bool Full,540                               LVElement *Parent) const {541  if (options().getPrintFormatting() && options().getAttributeReference())542    printAttributes(OS, Full, "{Reference} ", Parent,543                    referenceAsString(getLineNumber(), /*Spaces=*/false),544                    /*UseQuotes=*/false, /*PrintRef=*/true);545}546 547void LVElement::printLinkageName(raw_ostream &OS, bool Full,548                                 LVElement *Parent) const {549  if (options().getPrintFormatting() && options().getAttributeLinkage()) {550    printAttributes(OS, Full, "{Linkage} ", Parent, getLinkageName(),551                    /*UseQuotes=*/true, /*PrintRef=*/false);552  }553}554 555void LVElement::printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent,556                                 LVScope *Scope) const {557  if (options().getPrintFormatting() && options().getAttributeLinkage()) {558    LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope);559    std::string Text = (Twine(" 0x") + Twine::utohexstr(SectionIndex) +560                        Twine(" '") + Twine(getLinkageName()) + Twine("'"))561                           .str();562    printAttributes(OS, Full, "{Linkage} ", Parent, Text,563                    /*UseQuotes=*/false, /*PrintRef=*/false);564  }565}566