aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp')
-rw-r--r--llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp304
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");
+}