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