diff options
Diffstat (limited to 'llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp')
-rw-r--r-- | llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp new file mode 100644 index 000000000000..88f66cf2093b --- /dev/null +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp @@ -0,0 +1,304 @@ +//===-- LVReader.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 LVReader class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/LogicalView/Core/LVReader.h" +#include "llvm/DebugInfo/LogicalView/Core/LVLine.h" +#include "llvm/DebugInfo/LogicalView/Core/LVScope.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" +#include <tuple> + +using namespace llvm; +using namespace llvm::logicalview; + +#define DEBUG_TYPE "Reader" + +// Detect elements that are inserted more than once at different scopes, +// causing a crash on the reader destruction, as the element is already +// deleted from other scope. Helper for CodeView reader. +bool checkIntegrityScopesTree(LVScope *Root) { + using LVDuplicateEntry = std::tuple<LVElement *, LVScope *, LVScope *>; + using LVDuplicate = std::vector<LVDuplicateEntry>; + LVDuplicate Duplicate; + + using LVIntegrity = std::map<LVElement *, LVScope *>; + LVIntegrity Integrity; + + // Add the given element to the integrity map. + auto AddElement = [&](LVElement *Element, LVScope *Scope) { + LVIntegrity::iterator Iter = Integrity.find(Element); + if (Iter == Integrity.end()) + Integrity.emplace(Element, Scope); + else + // We found a duplicate. + Duplicate.emplace_back(Element, Scope, Iter->second); + }; + + // Recursively add all the elements in the scope. + std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) { + auto Traverse = [&](const auto *Set) { + if (Set) + for (const auto &Entry : *Set) + AddElement(Entry, Parent); + }; + if (const LVScopes *Scopes = Parent->getScopes()) { + for (LVScope *Scope : *Scopes) { + AddElement(Scope, Parent); + TraverseScope(Scope); + } + } + Traverse(Parent->getSymbols()); + Traverse(Parent->getTypes()); + Traverse(Parent->getLines()); + }; + + // Start traversing the scopes root and print any duplicates. + TraverseScope(Root); + bool PassIntegrity = true; + if (Duplicate.size()) { + std::stable_sort(begin(Duplicate), end(Duplicate), + [](const auto &l, const auto &r) { + return std::get<0>(l)->getID() < std::get<0>(r)->getID(); + }); + + auto PrintIndex = [](unsigned Index) { + if (Index) + dbgs() << format("%8d: ", Index); + else + dbgs() << format("%8c: ", ' '); + }; + auto PrintElement = [&](LVElement *Element, unsigned Index = 0) { + PrintIndex(Index); + std::string ElementName(Element->getName()); + dbgs() << format("%15s ID=0x%08x '%s'\n", Element->kind(), + Element->getID(), ElementName.c_str()); + }; + + std::string RootName(Root->getName()); + dbgs() << formatv("{0}\n", fmt_repeat('=', 72)); + dbgs() << format("Root: '%s'\nDuplicated elements: %d\n", RootName.c_str(), + Duplicate.size()); + dbgs() << formatv("{0}\n", fmt_repeat('=', 72)); + + unsigned Index = 0; + for (const LVDuplicateEntry &Entry : Duplicate) { + LVElement *Element; + LVScope *First; + LVScope *Second; + std::tie(Element, First, Second) = Entry; + dbgs() << formatv("\n{0}\n", fmt_repeat('-', 72)); + PrintElement(Element, ++Index); + PrintElement(First); + PrintElement(Second); + dbgs() << formatv("{0}\n", fmt_repeat('-', 72)); + } + PassIntegrity = false; + } + return PassIntegrity; +} + +//===----------------------------------------------------------------------===// +// Class to represent a split context. +//===----------------------------------------------------------------------===// +Error LVSplitContext::createSplitFolder(StringRef Where) { + // The 'location' will represent the root directory for the output created + // by the context. It will contain the different CUs files, that will be + // extracted from a single ELF. + Location = std::string(Where); + + // Add a trailing slash, if there is none. + size_t Pos = Location.find_last_of('/'); + if (Location.length() != Pos + 1) + Location.append("/"); + + // Make sure the new directory exists, creating it if necessary. + if (std::error_code EC = llvm::sys::fs::create_directories(Location)) + return createStringError(EC, "Error: could not create directory %s", + Location.c_str()); + + return Error::success(); +} + +std::error_code LVSplitContext::open(std::string ContextName, + std::string Extension, raw_ostream &OS) { + assert(OutputFile == nullptr && "OutputFile already set."); + + // Transforms '/', '\', '.', ':' into '_'. + std::string Name(flattenedFilePath(ContextName)); + Name.append(Extension); + // Add the split context location folder name. + if (!Location.empty()) + Name.insert(0, Location); + + std::error_code EC; + OutputFile = std::make_unique<ToolOutputFile>(Name, EC, sys::fs::OF_None); + if (EC) + return EC; + + // Don't remove output file. + OutputFile->keep(); + return std::error_code(); +} + +LVReader *CurrentReader = nullptr; +LVReader &LVReader::getInstance() { + if (CurrentReader) + return *CurrentReader; + outs() << "Invalid instance reader.\n"; + llvm_unreachable("Invalid instance reader."); +} +void LVReader::setInstance(LVReader *Reader) { CurrentReader = Reader; } + +Error LVReader::createSplitFolder() { + if (OutputSplit) { + // If the '--output=split' was specified, but no '--split-folder' + // option, use the input file as base for the split location. + if (options().getOutputFolder().empty()) + options().setOutputFolder(getFilename().str() + "_cus"); + + SmallString<128> SplitFolder; + SplitFolder = options().getOutputFolder(); + sys::fs::make_absolute(SplitFolder); + + // Return error if unable to create a split context location. + if (Error Err = SplitContext.createSplitFolder(SplitFolder)) + return Err; + + OS << "\nSplit View Location: '" << SplitContext.getLocation() << "'\n"; + } + + return Error::success(); +} + +// Get the filename for given object. +StringRef LVReader::getFilename(LVObject *Object, size_t Index) const { + if (CompileUnits.size()) { + // Get Compile Unit for the given object. + LVCompileUnits::const_iterator Iter = + std::prev(CompileUnits.lower_bound(Object->getOffset())); + if (Iter != CompileUnits.end()) + return Iter->second->getFilename(Index); + } + + return CompileUnit ? CompileUnit->getFilename(Index) : StringRef(); +} + +// The Reader is the module that creates the logical view using the debug +// information contained in the binary file specified in the command line. +// This is the main entry point for the Reader and performs the following +// steps: +// - Process any patterns collected from the '--select' options. +// - For each compile unit in the debug information: +// * Create the logical elements (scopes, symbols, types, lines). +// * Collect debug ranges and debug locations. +// * Move the collected logical lines to their associated scopes. +// - Once all the compile units have been processed, traverse the scopes +// tree in order to: +// * Calculate symbol coverage. +// * Detect invalid ranges and locations. +// * "resolve" the logical elements. During this pass, the names and +// file information are updated, to reflect any dependency with other +// logical elements. +Error LVReader::doLoad() { + // Set current Reader instance. + setInstance(this); + + // Before any scopes creation, process any pattern specified by the + // --select and --select-offsets options. + patterns().addGenericPatterns(options().Select.Generic); + patterns().addOffsetPatterns(options().Select.Offsets); + + // Add any specific element printing requests based on the element kind. + patterns().addRequest(options().Select.Elements); + patterns().addRequest(options().Select.Lines); + patterns().addRequest(options().Select.Scopes); + patterns().addRequest(options().Select.Symbols); + patterns().addRequest(options().Select.Types); + + // Once we have processed the requests for any particular kind of elements, + // we need to update the report options, in order to have a default value. + patterns().updateReportOptions(); + + // Delegate the scope tree creation to the specific reader. + if (Error Err = createScopes()) + return Err; + + if (options().getInternalIntegrity() && !checkIntegrityScopesTree(Root)) + return llvm::make_error<StringError>("Duplicated elements in Scopes Tree", + inconvertibleErrorCode()); + + // Calculate symbol coverage and detect invalid debug locations and ranges. + Root->processRangeInformation(); + + // As the elements can depend on elements from a different compile unit, + // information such as name and file/line source information needs to be + // updated. + Root->resolveElements(); + + sortScopes(); + return Error::success(); +} + +// Default handler for a generic reader. +Error LVReader::doPrint() { + // Set current Reader instance. + setInstance(this); + + // Check for any '--report' request. + if (options().getReportExecute()) { + // Requested details. + if (options().getReportList()) + if (Error Err = printMatchedElements(/*UseMatchedElements=*/true)) + return Err; + // Requested only children. + if (options().getReportChildren() && !options().getReportParents()) + if (Error Err = printMatchedElements(/*UseMatchedElements=*/false)) + return Err; + // Requested (parents) or (parents and children). + if (options().getReportParents() || options().getReportView()) + if (Error Err = printScopes()) + return Err; + + return Error::success(); + } + + return printScopes(); +} + +Error LVReader::printScopes() { + if (bool DoPrint = + (options().getPrintExecute() || options().getComparePrint())) { + if (Error Err = createSplitFolder()) + return Err; + + // Start printing from the root. + bool DoMatch = options().getSelectGenericPattern() || + options().getSelectGenericKind() || + options().getSelectOffsetPattern(); + return Root->doPrint(OutputSplit, DoMatch, DoPrint, OS); + } + + return Error::success(); +} + +Error LVReader::printMatchedElements(bool UseMatchedElements) { + if (Error Err = createSplitFolder()) + return Err; + + return Root->doPrintMatches(OutputSplit, OS, UseMatchedElements); +} + +void LVReader::print(raw_ostream &OS) const { + OS << "LVReader\n"; + LLVM_DEBUG(dbgs() << "PrintReader\n"); +} |