brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.6 KiB · d973a47 Raw
553 lines · cpp
1//===-- LVReader.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 LVReader class.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"14#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"15#include "llvm/Support/FileSystem.h"16#include "llvm/Support/FormatAdapters.h"17#include "llvm/Support/FormatVariadic.h"18#include <tuple>19 20using namespace llvm;21using namespace llvm::logicalview;22 23#define DEBUG_TYPE "Reader"24 25// Detect elements that are inserted more than once at different scopes,26// causing a crash on the reader destruction, as the element is already27// deleted from other scope. Helper for CodeView reader.28bool checkIntegrityScopesTree(LVScope *Root) {29  using LVDuplicateEntry = std::tuple<LVElement *, LVScope *, LVScope *>;30  using LVDuplicate = std::vector<LVDuplicateEntry>;31  LVDuplicate Duplicate;32 33  using LVIntegrity = std::map<LVElement *, LVScope *>;34  LVIntegrity Integrity;35 36  // Add the given element to the integrity map.37  auto AddElement = [&](LVElement *Element, LVScope *Scope) {38    LVIntegrity::iterator Iter = Integrity.find(Element);39    if (Iter == Integrity.end())40      Integrity.emplace(Element, Scope);41    else42      // We found a duplicate.43      Duplicate.emplace_back(Element, Scope, Iter->second);44  };45 46  // Recursively add all the elements in the scope.47  std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) {48    auto Traverse = [&](const auto *Set) {49      if (Set)50        for (const auto &Entry : *Set)51          AddElement(Entry, Parent);52    };53    if (const LVScopes *Scopes = Parent->getScopes()) {54      for (LVScope *Scope : *Scopes) {55        AddElement(Scope, Parent);56        TraverseScope(Scope);57      }58    }59    Traverse(Parent->getSymbols());60    Traverse(Parent->getTypes());61    Traverse(Parent->getLines());62  };63 64  // Start traversing the scopes root and print any duplicates.65  TraverseScope(Root);66  bool PassIntegrity = true;67  if (Duplicate.size()) {68    llvm::stable_sort(Duplicate, [](const auto &l, const auto &r) {69      return std::get<0>(l)->getID() < std::get<0>(r)->getID();70    });71 72    auto PrintIndex = [](unsigned Index) {73      if (Index)74        dbgs() << format("%8d: ", Index);75      else76        dbgs() << format("%8c: ", ' ');77    };78    auto PrintElement = [&](LVElement *Element, unsigned Index = 0) {79      PrintIndex(Index);80      std::string ElementName(Element->getName());81      dbgs() << format("%15s ID=0x%08x '%s'\n", Element->kind(),82                       Element->getID(), ElementName.c_str());83    };84 85    std::string RootName(Root->getName());86    dbgs() << formatv("{0}\n", fmt_repeat('=', 72));87    dbgs() << format("Root: '%s'\nDuplicated elements: %d\n", RootName.c_str(),88                     Duplicate.size());89    dbgs() << formatv("{0}\n", fmt_repeat('=', 72));90 91    unsigned Index = 0;92    for (const LVDuplicateEntry &Entry : Duplicate) {93      LVElement *Element;94      LVScope *First;95      LVScope *Second;96      std::tie(Element, First, Second) = Entry;97      dbgs() << formatv("\n{0}\n", fmt_repeat('-', 72));98      PrintElement(Element, ++Index);99      PrintElement(First);100      PrintElement(Second);101      dbgs() << formatv("{0}\n", fmt_repeat('-', 72));102    }103    PassIntegrity = false;104  }105  return PassIntegrity;106}107 108//===----------------------------------------------------------------------===//109// Class to represent a split context.110//===----------------------------------------------------------------------===//111Error LVSplitContext::createSplitFolder(StringRef Where) {112  // The 'location' will represent the root directory for the output created113  // by the context. It will contain the different CUs files, that will be114  // extracted from a single ELF.115  Location = std::string(Where);116 117  // Add a trailing slash, if there is none.118  size_t Pos = Location.find_last_of('/');119  if (Location.length() != Pos + 1)120    Location.append("/");121 122  // Make sure the new directory exists, creating it if necessary.123  if (std::error_code EC = llvm::sys::fs::create_directories(Location))124    return createStringError(EC, "Error: could not create directory %s",125                             Location.c_str());126 127  return Error::success();128}129 130std::error_code LVSplitContext::open(std::string ContextName,131                                     std::string Extension, raw_ostream &OS) {132  assert(OutputFile == nullptr && "OutputFile already set.");133 134  // Transforms '/', '\', '.', ':' into '_'.135  std::string Name(flattenedFilePath(ContextName));136  Name.append(Extension);137  // Add the split context location folder name.138  if (!Location.empty())139    Name.insert(0, Location);140 141  std::error_code EC;142  OutputFile = std::make_unique<ToolOutputFile>(Name, EC, sys::fs::OF_None);143  if (EC)144    return EC;145 146  // Don't remove output file.147  OutputFile->keep();148  return std::error_code();149}150 151static LVReader *CurrentReader = nullptr;152LVReader &LVReader::getInstance() {153  if (CurrentReader)154    return *CurrentReader;155  outs() << "Invalid instance reader.\n";156  llvm_unreachable("Invalid instance reader.");157}158void LVReader::setInstance(LVReader *Reader) { CurrentReader = Reader; }159 160Error LVReader::createSplitFolder() {161  if (OutputSplit) {162    // If the '--output=split' was specified, but no '--split-folder'163    // option, use the input file as base for the split location.164    if (options().getOutputFolder().empty())165      options().setOutputFolder(getFilename().str() + "_cus");166 167    SmallString<128> SplitFolder;168    SplitFolder = options().getOutputFolder();169    sys::fs::make_absolute(SplitFolder);170 171    // Return error if unable to create a split context location.172    if (Error Err = SplitContext.createSplitFolder(SplitFolder))173      return Err;174 175    OS << "\nSplit View Location: '" << SplitContext.getLocation() << "'\n";176  }177 178  return Error::success();179}180 181// Get the filename for given object.182StringRef LVReader::getFilename(LVObject *Object, size_t Index) const {183  // TODO: The current CodeView Reader implementation does not have support184  // for multiple compile units. Until we have a proper offset calculation,185  // check only in the current compile unit.186  if (CompileUnits.size()) {187    // Get Compile Unit for the given object.188    LVCompileUnits::const_iterator Iter =189        std::prev(CompileUnits.lower_bound(Object->getOffset()));190    if (Iter != CompileUnits.end())191      return Iter->second->getFilename(Index);192  }193 194  return CompileUnit ? CompileUnit->getFilename(Index) : StringRef();195}196 197void LVReader::addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope) {198  LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);199  ScopesWithRanges->addEntry(Scope);200}201 202void LVReader::addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope,203                               LVAddress LowerAddress, LVAddress UpperAddress) {204  LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);205  ScopesWithRanges->addEntry(Scope, LowerAddress, UpperAddress);206}207 208LVRange *LVReader::getSectionRanges(LVSectionIndex SectionIndex) {209  // Check if we already have a mapping for this section index.210  LVSectionRanges::iterator IterSection = SectionRanges.find(SectionIndex);211  if (IterSection == SectionRanges.end())212    IterSection =213        SectionRanges.emplace(SectionIndex, std::make_unique<LVRange>()).first;214  LVRange *Range = IterSection->second.get();215  assert(Range && "Range is null.");216  return Range;217}218 219LVElement *LVReader::createElement(dwarf::Tag Tag) {220  CurrentScope = nullptr;221  CurrentSymbol = nullptr;222  CurrentType = nullptr;223  CurrentRanges.clear();224 225  LLVM_DEBUG(226      { dbgs() << "\n[createElement] " << dwarf::TagString(Tag) << "\n"; });227 228  if (!options().getPrintSymbols()) {229    switch (Tag) {230    // As the command line options did not specify a request to print231    // logical symbols (--print=symbols or --print=all or --print=elements),232    // skip its creation.233    case dwarf::DW_TAG_formal_parameter:234    case dwarf::DW_TAG_unspecified_parameters:235    case dwarf::DW_TAG_member:236    case dwarf::DW_TAG_variable:237    case dwarf::DW_TAG_inheritance:238    case dwarf::DW_TAG_constant:239    case dwarf::DW_TAG_call_site_parameter:240    case dwarf::DW_TAG_GNU_call_site_parameter:241      return nullptr;242    default:243      break;244    }245  }246 247  switch (Tag) {248  // Types.249  case dwarf::DW_TAG_base_type:250    CurrentType = createType();251    CurrentType->setIsBase();252    if (options().getAttributeBase())253      CurrentType->setIncludeInPrint();254    return CurrentType;255  case dwarf::DW_TAG_const_type:256    CurrentType = createType();257    CurrentType->setIsConst();258    CurrentType->setName("const");259    return CurrentType;260  case dwarf::DW_TAG_enumerator:261    CurrentType = createTypeEnumerator();262    return CurrentType;263  case dwarf::DW_TAG_imported_declaration:264    CurrentType = createTypeImport();265    CurrentType->setIsImportDeclaration();266    return CurrentType;267  case dwarf::DW_TAG_imported_module:268    CurrentType = createTypeImport();269    CurrentType->setIsImportModule();270    return CurrentType;271  case dwarf::DW_TAG_pointer_type:272    CurrentType = createType();273    CurrentType->setIsPointer();274    CurrentType->setName("*");275    return CurrentType;276  case dwarf::DW_TAG_ptr_to_member_type:277    CurrentType = createType();278    CurrentType->setIsPointerMember();279    CurrentType->setName("*");280    return CurrentType;281  case dwarf::DW_TAG_reference_type:282    CurrentType = createType();283    CurrentType->setIsReference();284    CurrentType->setName("&");285    return CurrentType;286  case dwarf::DW_TAG_restrict_type:287    CurrentType = createType();288    CurrentType->setIsRestrict();289    CurrentType->setName("restrict");290    return CurrentType;291  case dwarf::DW_TAG_rvalue_reference_type:292    CurrentType = createType();293    CurrentType->setIsRvalueReference();294    CurrentType->setName("&&");295    return CurrentType;296  case dwarf::DW_TAG_subrange_type:297    CurrentType = createTypeSubrange();298    return CurrentType;299  case dwarf::DW_TAG_template_value_parameter:300    CurrentType = createTypeParam();301    CurrentType->setIsTemplateValueParam();302    return CurrentType;303  case dwarf::DW_TAG_template_type_parameter:304    CurrentType = createTypeParam();305    CurrentType->setIsTemplateTypeParam();306    return CurrentType;307  case dwarf::DW_TAG_GNU_template_template_param:308    CurrentType = createTypeParam();309    CurrentType->setIsTemplateTemplateParam();310    return CurrentType;311  case dwarf::DW_TAG_typedef:312    CurrentType = createTypeDefinition();313    return CurrentType;314  case dwarf::DW_TAG_unspecified_type:315    CurrentType = createType();316    CurrentType->setIsUnspecified();317    return CurrentType;318  case dwarf::DW_TAG_volatile_type:319    CurrentType = createType();320    CurrentType->setIsVolatile();321    CurrentType->setName("volatile");322    return CurrentType;323 324  // Symbols.325  case dwarf::DW_TAG_formal_parameter:326    CurrentSymbol = createSymbol();327    CurrentSymbol->setIsParameter();328    return CurrentSymbol;329  case dwarf::DW_TAG_unspecified_parameters:330    CurrentSymbol = createSymbol();331    CurrentSymbol->setIsUnspecified();332    CurrentSymbol->setName("...");333    return CurrentSymbol;334  case dwarf::DW_TAG_member:335    CurrentSymbol = createSymbol();336    CurrentSymbol->setIsMember();337    return CurrentSymbol;338  case dwarf::DW_TAG_variable:339    CurrentSymbol = createSymbol();340    CurrentSymbol->setIsVariable();341    return CurrentSymbol;342  case dwarf::DW_TAG_inheritance:343    CurrentSymbol = createSymbol();344    CurrentSymbol->setIsInheritance();345    return CurrentSymbol;346  case dwarf::DW_TAG_call_site_parameter:347  case dwarf::DW_TAG_GNU_call_site_parameter:348    CurrentSymbol = createSymbol();349    CurrentSymbol->setIsCallSiteParameter();350    return CurrentSymbol;351  case dwarf::DW_TAG_constant:352    CurrentSymbol = createSymbol();353    CurrentSymbol->setIsConstant();354    return CurrentSymbol;355 356  // Scopes.357  case dwarf::DW_TAG_catch_block:358    CurrentScope = createScope();359    CurrentScope->setIsCatchBlock();360    return CurrentScope;361  case dwarf::DW_TAG_lexical_block:362    CurrentScope = createScope();363    CurrentScope->setIsLexicalBlock();364    return CurrentScope;365  case dwarf::DW_TAG_try_block:366    CurrentScope = createScope();367    CurrentScope->setIsTryBlock();368    return CurrentScope;369  case dwarf::DW_TAG_compile_unit:370  case dwarf::DW_TAG_skeleton_unit:371    CurrentScope = createScopeCompileUnit();372    CompileUnit = static_cast<LVScopeCompileUnit *>(CurrentScope);373    return CurrentScope;374  case dwarf::DW_TAG_inlined_subroutine:375    CurrentScope = createScopeFunctionInlined();376    return CurrentScope;377  case dwarf::DW_TAG_namespace:378    CurrentScope = createScopeNamespace();379    return CurrentScope;380  case dwarf::DW_TAG_template_alias:381    CurrentScope = createScopeAlias();382    return CurrentScope;383  case dwarf::DW_TAG_array_type:384    CurrentScope = createScopeArray();385    return CurrentScope;386  case dwarf::DW_TAG_call_site:387  case dwarf::DW_TAG_GNU_call_site:388    CurrentScope = createScopeFunction();389    CurrentScope->setIsCallSite();390    return CurrentScope;391  case dwarf::DW_TAG_entry_point:392    CurrentScope = createScopeFunction();393    CurrentScope->setIsEntryPoint();394    return CurrentScope;395  case dwarf::DW_TAG_subprogram:396    CurrentScope = createScopeFunction();397    CurrentScope->setIsSubprogram();398    return CurrentScope;399  case dwarf::DW_TAG_subroutine_type:400    CurrentScope = createScopeFunctionType();401    return CurrentScope;402  case dwarf::DW_TAG_label:403    CurrentScope = createScopeFunction();404    CurrentScope->setIsLabel();405    return CurrentScope;406  case dwarf::DW_TAG_class_type:407    CurrentScope = createScopeAggregate();408    CurrentScope->setIsClass();409    return CurrentScope;410  case dwarf::DW_TAG_structure_type:411    CurrentScope = createScopeAggregate();412    CurrentScope->setIsStructure();413    return CurrentScope;414  case dwarf::DW_TAG_union_type:415    CurrentScope = createScopeAggregate();416    CurrentScope->setIsUnion();417    return CurrentScope;418  case dwarf::DW_TAG_enumeration_type:419    CurrentScope = createScopeEnumeration();420    return CurrentScope;421  case dwarf::DW_TAG_GNU_formal_parameter_pack:422    CurrentScope = createScopeFormalPack();423    return CurrentScope;424  case dwarf::DW_TAG_GNU_template_parameter_pack:425    CurrentScope = createScopeTemplatePack();426    return CurrentScope;427  case dwarf::DW_TAG_module:428    CurrentScope = createScopeModule();429    return CurrentScope;430  default:431    // Collect TAGs not implemented.432    if (options().getInternalTag() && Tag)433      CompileUnit->addDebugTag(Tag, CurrentOffset);434    break;435  }436 437  LLVM_DEBUG({438    dbgs() << "DWARF Tag not implemented: " << dwarf::TagString(Tag) << "\n";439  });440 441  return nullptr;442}443 444// The Reader is the module that creates the logical view using the debug445// information contained in the binary file specified in the command line.446// This is the main entry point for the Reader and performs the following447// steps:448// - Process any patterns collected from the '--select' options.449// - For each compile unit in the debug information:450//   * Create the logical elements (scopes, symbols, types, lines).451//   * Collect debug ranges and debug locations.452//   * Move the collected logical lines to their associated scopes.453// - Once all the compile units have been processed, traverse the scopes454//   tree in order to:455//   * Calculate symbol coverage.456//   * Detect invalid ranges and locations.457//   * "resolve" the logical elements. During this pass, the names and458//      file information are updated, to reflect any dependency with other459//     logical elements.460Error LVReader::doLoad() {461  // Set current Reader instance.462  setInstance(this);463 464  // Before any scopes creation, process any pattern specified by the465  // --select and --select-offsets options.466  patterns().addGenericPatterns(options().Select.Generic);467  patterns().addOffsetPatterns(options().Select.Offsets);468 469  // Add any specific element printing requests based on the element kind.470  patterns().addRequest(options().Select.Elements);471  patterns().addRequest(options().Select.Lines);472  patterns().addRequest(options().Select.Scopes);473  patterns().addRequest(options().Select.Symbols);474  patterns().addRequest(options().Select.Types);475 476  // Once we have processed the requests for any particular kind of elements,477  // we need to update the report options, in order to have a default value.478  patterns().updateReportOptions();479 480  // Delegate the scope tree creation to the specific reader.481  if (Error Err = createScopes())482    return Err;483 484  if (options().getInternalIntegrity() && !checkIntegrityScopesTree(Root))485    return llvm::make_error<StringError>("Duplicated elements in Scopes Tree",486                                         inconvertibleErrorCode());487 488  // Calculate symbol coverage and detect invalid debug locations and ranges.489  Root->processRangeInformation();490 491  // As the elements can depend on elements from a different compile unit,492  // information such as name and file/line source information needs to be493  // updated.494  Root->resolveElements();495 496  sortScopes();497  return Error::success();498}499 500// Default handler for a generic reader.501Error LVReader::doPrint() {502  // Set current Reader instance.503  setInstance(this);504 505  // Check for any '--report' request.506  if (options().getReportExecute()) {507    // Requested details.508    if (options().getReportList())509      if (Error Err = printMatchedElements(/*UseMatchedElements=*/true))510        return Err;511    // Requested only children.512    if (options().getReportChildren() && !options().getReportParents())513      if (Error Err = printMatchedElements(/*UseMatchedElements=*/false))514        return Err;515    // Requested (parents) or (parents and children).516    if (options().getReportParents() || options().getReportView())517      if (Error Err = printScopes())518        return Err;519 520    return Error::success();521  }522 523  return printScopes();524}525 526Error LVReader::printScopes() {527  if (bool DoPrint =528          (options().getPrintExecute() || options().getComparePrint())) {529    if (Error Err = createSplitFolder())530      return Err;531 532    // Start printing from the root.533    bool DoMatch = options().getSelectGenericPattern() ||534                   options().getSelectGenericKind() ||535                   options().getSelectOffsetPattern();536    return Root->doPrint(OutputSplit, DoMatch, DoPrint, OS);537  }538 539  return Error::success();540}541 542Error LVReader::printMatchedElements(bool UseMatchedElements) {543  if (Error Err = createSplitFolder())544    return Err;545 546  return Root->doPrintMatches(OutputSplit, OS, UseMatchedElements);547}548 549void LVReader::print(raw_ostream &OS) const {550  OS << "LVReader\n";551  LLVM_DEBUG(dbgs() << "PrintReader\n");552}553