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-exception
6//
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/LVLine.h"
15#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
16#include "llvm/Support/FileSystem.h"
17#include "llvm/Support/FormatAdapters.h"
18#include "llvm/Support/FormatVariadic.h"
19#include <tuple>
20
21using namespace llvm;
22using namespace llvm::logicalview;
23
24#define DEBUG_TYPE "Reader"
25
26// Detect elements that are inserted more than once at different scopes,
27// causing a crash on the reader destruction, as the element is already
28// deleted from other scope. Helper for CodeView reader.
29bool checkIntegrityScopesTree(LVScope *Root) {
30  using LVDuplicateEntry = std::tuple<LVElement *, LVScope *, LVScope *>;
31  using LVDuplicate = std::vector<LVDuplicateEntry>;
32  LVDuplicate Duplicate;
33
34  using LVIntegrity = std::map<LVElement *, LVScope *>;
35  LVIntegrity Integrity;
36
37  // Add the given element to the integrity map.
38  auto AddElement = [&](LVElement *Element, LVScope *Scope) {
39    LVIntegrity::iterator Iter = Integrity.find(Element);
40    if (Iter == Integrity.end())
41      Integrity.emplace(Element, Scope);
42    else
43      // We found a duplicate.
44      Duplicate.emplace_back(Element, Scope, Iter->second);
45  };
46
47  // Recursively add all the elements in the scope.
48  std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) {
49    auto Traverse = [&](const auto *Set) {
50      if (Set)
51        for (const auto &Entry : *Set)
52          AddElement(Entry, Parent);
53    };
54    if (const LVScopes *Scopes = Parent->getScopes()) {
55      for (LVScope *Scope : *Scopes) {
56        AddElement(Scope, Parent);
57        TraverseScope(Scope);
58      }
59    }
60    Traverse(Parent->getSymbols());
61    Traverse(Parent->getTypes());
62    Traverse(Parent->getLines());
63  };
64
65  // Start traversing the scopes root and print any duplicates.
66  TraverseScope(Root);
67  bool PassIntegrity = true;
68  if (Duplicate.size()) {
69    std::stable_sort(begin(Duplicate), end(Duplicate),
70                     [](const auto &l, const auto &r) {
71                       return std::get<0>(l)->getID() < std::get<0>(r)->getID();
72                     });
73
74    auto PrintIndex = [](unsigned Index) {
75      if (Index)
76        dbgs() << format("%8d: ", Index);
77      else
78        dbgs() << format("%8c: ", ' ');
79    };
80    auto PrintElement = [&](LVElement *Element, unsigned Index = 0) {
81      PrintIndex(Index);
82      std::string ElementName(Element->getName());
83      dbgs() << format("%15s ID=0x%08x '%s'\n", Element->kind(),
84                       Element->getID(), ElementName.c_str());
85    };
86
87    std::string RootName(Root->getName());
88    dbgs() << formatv("{0}\n", fmt_repeat('=', 72));
89    dbgs() << format("Root: '%s'\nDuplicated elements: %d\n", RootName.c_str(),
90                     Duplicate.size());
91    dbgs() << formatv("{0}\n", fmt_repeat('=', 72));
92
93    unsigned Index = 0;
94    for (const LVDuplicateEntry &Entry : Duplicate) {
95      LVElement *Element;
96      LVScope *First;
97      LVScope *Second;
98      std::tie(Element, First, Second) = Entry;
99      dbgs() << formatv("\n{0}\n", fmt_repeat('-', 72));
100      PrintElement(Element, ++Index);
101      PrintElement(First);
102      PrintElement(Second);
103      dbgs() << formatv("{0}\n", fmt_repeat('-', 72));
104    }
105    PassIntegrity = false;
106  }
107  return PassIntegrity;
108}
109
110//===----------------------------------------------------------------------===//
111// Class to represent a split context.
112//===----------------------------------------------------------------------===//
113Error LVSplitContext::createSplitFolder(StringRef Where) {
114  // The 'location' will represent the root directory for the output created
115  // by the context. It will contain the different CUs files, that will be
116  // extracted from a single ELF.
117  Location = std::string(Where);
118
119  // Add a trailing slash, if there is none.
120  size_t Pos = Location.find_last_of('/');
121  if (Location.length() != Pos + 1)
122    Location.append("/");
123
124  // Make sure the new directory exists, creating it if necessary.
125  if (std::error_code EC = llvm::sys::fs::create_directories(Location))
126    return createStringError(EC, "Error: could not create directory %s",
127                             Location.c_str());
128
129  return Error::success();
130}
131
132std::error_code LVSplitContext::open(std::string ContextName,
133                                     std::string Extension, raw_ostream &OS) {
134  assert(OutputFile == nullptr && "OutputFile already set.");
135
136  // Transforms '/', '\', '.', ':' into '_'.
137  std::string Name(flattenedFilePath(ContextName));
138  Name.append(Extension);
139  // Add the split context location folder name.
140  if (!Location.empty())
141    Name.insert(0, Location);
142
143  std::error_code EC;
144  OutputFile = std::make_unique<ToolOutputFile>(Name, EC, sys::fs::OF_None);
145  if (EC)
146    return EC;
147
148  // Don't remove output file.
149  OutputFile->keep();
150  return std::error_code();
151}
152
153LVReader *CurrentReader = nullptr;
154LVReader &LVReader::getInstance() {
155  if (CurrentReader)
156    return *CurrentReader;
157  outs() << "Invalid instance reader.\n";
158  llvm_unreachable("Invalid instance reader.");
159}
160void LVReader::setInstance(LVReader *Reader) { CurrentReader = Reader; }
161
162Error LVReader::createSplitFolder() {
163  if (OutputSplit) {
164    // If the '--output=split' was specified, but no '--split-folder'
165    // option, use the input file as base for the split location.
166    if (options().getOutputFolder().empty())
167      options().setOutputFolder(getFilename().str() + "_cus");
168
169    SmallString<128> SplitFolder;
170    SplitFolder = options().getOutputFolder();
171    sys::fs::make_absolute(SplitFolder);
172
173    // Return error if unable to create a split context location.
174    if (Error Err = SplitContext.createSplitFolder(SplitFolder))
175      return Err;
176
177    OS << "\nSplit View Location: '" << SplitContext.getLocation() << "'\n";
178  }
179
180  return Error::success();
181}
182
183// Get the filename for given object.
184StringRef LVReader::getFilename(LVObject *Object, size_t Index) const {
185  // TODO: The current CodeView Reader implementation does not have support
186  // for multiple compile units. Until we have a proper offset calculation,
187  // check only in the current compile unit.
188  if (CompileUnits.size()) {
189    // Get Compile Unit for the given object.
190    LVCompileUnits::const_iterator Iter =
191        std::prev(CompileUnits.lower_bound(Object->getOffset()));
192    if (Iter != CompileUnits.end())
193      return Iter->second->getFilename(Index);
194  }
195
196  return CompileUnit ? CompileUnit->getFilename(Index) : StringRef();
197}
198
199// The Reader is the module that creates the logical view using the debug
200// information contained in the binary file specified in the command line.
201// This is the main entry point for the Reader and performs the following
202// steps:
203// - Process any patterns collected from the '--select' options.
204// - For each compile unit in the debug information:
205//   * Create the logical elements (scopes, symbols, types, lines).
206//   * Collect debug ranges and debug locations.
207//   * Move the collected logical lines to their associated scopes.
208// - Once all the compile units have been processed, traverse the scopes
209//   tree in order to:
210//   * Calculate symbol coverage.
211//   * Detect invalid ranges and locations.
212//   * "resolve" the logical elements. During this pass, the names and
213//      file information are updated, to reflect any dependency with other
214//     logical elements.
215Error LVReader::doLoad() {
216  // Set current Reader instance.
217  setInstance(this);
218
219  // Before any scopes creation, process any pattern specified by the
220  // --select and --select-offsets options.
221  patterns().addGenericPatterns(options().Select.Generic);
222  patterns().addOffsetPatterns(options().Select.Offsets);
223
224  // Add any specific element printing requests based on the element kind.
225  patterns().addRequest(options().Select.Elements);
226  patterns().addRequest(options().Select.Lines);
227  patterns().addRequest(options().Select.Scopes);
228  patterns().addRequest(options().Select.Symbols);
229  patterns().addRequest(options().Select.Types);
230
231  // Once we have processed the requests for any particular kind of elements,
232  // we need to update the report options, in order to have a default value.
233  patterns().updateReportOptions();
234
235  // Delegate the scope tree creation to the specific reader.
236  if (Error Err = createScopes())
237    return Err;
238
239  if (options().getInternalIntegrity() && !checkIntegrityScopesTree(Root))
240    return llvm::make_error<StringError>("Duplicated elements in Scopes Tree",
241                                         inconvertibleErrorCode());
242
243  // Calculate symbol coverage and detect invalid debug locations and ranges.
244  Root->processRangeInformation();
245
246  // As the elements can depend on elements from a different compile unit,
247  // information such as name and file/line source information needs to be
248  // updated.
249  Root->resolveElements();
250
251  sortScopes();
252  return Error::success();
253}
254
255// Default handler for a generic reader.
256Error LVReader::doPrint() {
257  // Set current Reader instance.
258  setInstance(this);
259
260  // Check for any '--report' request.
261  if (options().getReportExecute()) {
262    // Requested details.
263    if (options().getReportList())
264      if (Error Err = printMatchedElements(/*UseMatchedElements=*/true))
265        return Err;
266    // Requested only children.
267    if (options().getReportChildren() && !options().getReportParents())
268      if (Error Err = printMatchedElements(/*UseMatchedElements=*/false))
269        return Err;
270    // Requested (parents) or (parents and children).
271    if (options().getReportParents() || options().getReportView())
272      if (Error Err = printScopes())
273        return Err;
274
275    return Error::success();
276  }
277
278  return printScopes();
279}
280
281Error LVReader::printScopes() {
282  if (bool DoPrint =
283          (options().getPrintExecute() || options().getComparePrint())) {
284    if (Error Err = createSplitFolder())
285      return Err;
286
287    // Start printing from the root.
288    bool DoMatch = options().getSelectGenericPattern() ||
289                   options().getSelectGenericKind() ||
290                   options().getSelectOffsetPattern();
291    return Root->doPrint(OutputSplit, DoMatch, DoPrint, OS);
292  }
293
294  return Error::success();
295}
296
297Error LVReader::printMatchedElements(bool UseMatchedElements) {
298  if (Error Err = createSplitFolder())
299    return Err;
300
301  return Root->doPrintMatches(OutputSplit, OS, UseMatchedElements);
302}
303
304void LVReader::print(raw_ostream &OS) const {
305  OS << "LVReader\n";
306  LLVM_DEBUG(dbgs() << "PrintReader\n");
307}
308