xref: /llvm-project/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp (revision 0060c54e0da6d1429875da2d30895faa7562b706)
1e28b9357SCarlos Alberto Enciso //===-- LVReader.cpp ------------------------------------------------------===//
2e28b9357SCarlos Alberto Enciso //
3e28b9357SCarlos Alberto Enciso // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e28b9357SCarlos Alberto Enciso // See https://llvm.org/LICENSE.txt for license information.
5e28b9357SCarlos Alberto Enciso // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e28b9357SCarlos Alberto Enciso //
7e28b9357SCarlos Alberto Enciso //===----------------------------------------------------------------------===//
8e28b9357SCarlos Alberto Enciso //
9e28b9357SCarlos Alberto Enciso // This implements the LVReader class.
10e28b9357SCarlos Alberto Enciso //
11e28b9357SCarlos Alberto Enciso //===----------------------------------------------------------------------===//
12e28b9357SCarlos Alberto Enciso 
13e28b9357SCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
14e28b9357SCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
15e28b9357SCarlos Alberto Enciso #include "llvm/Support/FileSystem.h"
16e28b9357SCarlos Alberto Enciso #include "llvm/Support/FormatAdapters.h"
17e28b9357SCarlos Alberto Enciso #include "llvm/Support/FormatVariadic.h"
18e28b9357SCarlos Alberto Enciso #include <tuple>
19e28b9357SCarlos Alberto Enciso 
20e28b9357SCarlos Alberto Enciso using namespace llvm;
21e28b9357SCarlos Alberto Enciso using namespace llvm::logicalview;
22e28b9357SCarlos Alberto Enciso 
23e28b9357SCarlos Alberto Enciso #define DEBUG_TYPE "Reader"
24e28b9357SCarlos Alberto Enciso 
252c155d37SCarlos Alberto Enciso // Detect elements that are inserted more than once at different scopes,
262c155d37SCarlos Alberto Enciso // causing a crash on the reader destruction, as the element is already
272c155d37SCarlos Alberto Enciso // deleted from other scope. Helper for CodeView reader.
282c155d37SCarlos Alberto Enciso bool checkIntegrityScopesTree(LVScope *Root) {
292c155d37SCarlos Alberto Enciso   using LVDuplicateEntry = std::tuple<LVElement *, LVScope *, LVScope *>;
302c155d37SCarlos Alberto Enciso   using LVDuplicate = std::vector<LVDuplicateEntry>;
312c155d37SCarlos Alberto Enciso   LVDuplicate Duplicate;
322c155d37SCarlos Alberto Enciso 
332c155d37SCarlos Alberto Enciso   using LVIntegrity = std::map<LVElement *, LVScope *>;
342c155d37SCarlos Alberto Enciso   LVIntegrity Integrity;
352c155d37SCarlos Alberto Enciso 
362c155d37SCarlos Alberto Enciso   // Add the given element to the integrity map.
372c155d37SCarlos Alberto Enciso   auto AddElement = [&](LVElement *Element, LVScope *Scope) {
382c155d37SCarlos Alberto Enciso     LVIntegrity::iterator Iter = Integrity.find(Element);
392c155d37SCarlos Alberto Enciso     if (Iter == Integrity.end())
402c155d37SCarlos Alberto Enciso       Integrity.emplace(Element, Scope);
412c155d37SCarlos Alberto Enciso     else
422c155d37SCarlos Alberto Enciso       // We found a duplicate.
432c155d37SCarlos Alberto Enciso       Duplicate.emplace_back(Element, Scope, Iter->second);
442c155d37SCarlos Alberto Enciso   };
452c155d37SCarlos Alberto Enciso 
462c155d37SCarlos Alberto Enciso   // Recursively add all the elements in the scope.
472c155d37SCarlos Alberto Enciso   std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) {
482c155d37SCarlos Alberto Enciso     auto Traverse = [&](const auto *Set) {
492c155d37SCarlos Alberto Enciso       if (Set)
502c155d37SCarlos Alberto Enciso         for (const auto &Entry : *Set)
512c155d37SCarlos Alberto Enciso           AddElement(Entry, Parent);
522c155d37SCarlos Alberto Enciso     };
532c155d37SCarlos Alberto Enciso     if (const LVScopes *Scopes = Parent->getScopes()) {
542c155d37SCarlos Alberto Enciso       for (LVScope *Scope : *Scopes) {
552c155d37SCarlos Alberto Enciso         AddElement(Scope, Parent);
562c155d37SCarlos Alberto Enciso         TraverseScope(Scope);
572c155d37SCarlos Alberto Enciso       }
582c155d37SCarlos Alberto Enciso     }
592c155d37SCarlos Alberto Enciso     Traverse(Parent->getSymbols());
602c155d37SCarlos Alberto Enciso     Traverse(Parent->getTypes());
612c155d37SCarlos Alberto Enciso     Traverse(Parent->getLines());
622c155d37SCarlos Alberto Enciso   };
632c155d37SCarlos Alberto Enciso 
642c155d37SCarlos Alberto Enciso   // Start traversing the scopes root and print any duplicates.
652c155d37SCarlos Alberto Enciso   TraverseScope(Root);
662c155d37SCarlos Alberto Enciso   bool PassIntegrity = true;
672c155d37SCarlos Alberto Enciso   if (Duplicate.size()) {
682c155d37SCarlos Alberto Enciso     std::stable_sort(begin(Duplicate), end(Duplicate),
692c155d37SCarlos Alberto Enciso                      [](const auto &l, const auto &r) {
702c155d37SCarlos Alberto Enciso                        return std::get<0>(l)->getID() < std::get<0>(r)->getID();
712c155d37SCarlos Alberto Enciso                      });
722c155d37SCarlos Alberto Enciso 
732c155d37SCarlos Alberto Enciso     auto PrintIndex = [](unsigned Index) {
742c155d37SCarlos Alberto Enciso       if (Index)
752c155d37SCarlos Alberto Enciso         dbgs() << format("%8d: ", Index);
762c155d37SCarlos Alberto Enciso       else
772c155d37SCarlos Alberto Enciso         dbgs() << format("%8c: ", ' ');
782c155d37SCarlos Alberto Enciso     };
792c155d37SCarlos Alberto Enciso     auto PrintElement = [&](LVElement *Element, unsigned Index = 0) {
802c155d37SCarlos Alberto Enciso       PrintIndex(Index);
812c155d37SCarlos Alberto Enciso       std::string ElementName(Element->getName());
822c155d37SCarlos Alberto Enciso       dbgs() << format("%15s ID=0x%08x '%s'\n", Element->kind(),
832c155d37SCarlos Alberto Enciso                        Element->getID(), ElementName.c_str());
842c155d37SCarlos Alberto Enciso     };
852c155d37SCarlos Alberto Enciso 
862c155d37SCarlos Alberto Enciso     std::string RootName(Root->getName());
872c155d37SCarlos Alberto Enciso     dbgs() << formatv("{0}\n", fmt_repeat('=', 72));
882c155d37SCarlos Alberto Enciso     dbgs() << format("Root: '%s'\nDuplicated elements: %d\n", RootName.c_str(),
892c155d37SCarlos Alberto Enciso                      Duplicate.size());
902c155d37SCarlos Alberto Enciso     dbgs() << formatv("{0}\n", fmt_repeat('=', 72));
912c155d37SCarlos Alberto Enciso 
922c155d37SCarlos Alberto Enciso     unsigned Index = 0;
932c155d37SCarlos Alberto Enciso     for (const LVDuplicateEntry &Entry : Duplicate) {
942c155d37SCarlos Alberto Enciso       LVElement *Element;
952c155d37SCarlos Alberto Enciso       LVScope *First;
962c155d37SCarlos Alberto Enciso       LVScope *Second;
972c155d37SCarlos Alberto Enciso       std::tie(Element, First, Second) = Entry;
982c155d37SCarlos Alberto Enciso       dbgs() << formatv("\n{0}\n", fmt_repeat('-', 72));
992c155d37SCarlos Alberto Enciso       PrintElement(Element, ++Index);
1002c155d37SCarlos Alberto Enciso       PrintElement(First);
1012c155d37SCarlos Alberto Enciso       PrintElement(Second);
1022c155d37SCarlos Alberto Enciso       dbgs() << formatv("{0}\n", fmt_repeat('-', 72));
1032c155d37SCarlos Alberto Enciso     }
1042c155d37SCarlos Alberto Enciso     PassIntegrity = false;
1052c155d37SCarlos Alberto Enciso   }
1062c155d37SCarlos Alberto Enciso   return PassIntegrity;
1072c155d37SCarlos Alberto Enciso }
1082c155d37SCarlos Alberto Enciso 
109e28b9357SCarlos Alberto Enciso //===----------------------------------------------------------------------===//
110e28b9357SCarlos Alberto Enciso // Class to represent a split context.
111e28b9357SCarlos Alberto Enciso //===----------------------------------------------------------------------===//
112e28b9357SCarlos Alberto Enciso Error LVSplitContext::createSplitFolder(StringRef Where) {
113e28b9357SCarlos Alberto Enciso   // The 'location' will represent the root directory for the output created
114e28b9357SCarlos Alberto Enciso   // by the context. It will contain the different CUs files, that will be
115e28b9357SCarlos Alberto Enciso   // extracted from a single ELF.
116e28b9357SCarlos Alberto Enciso   Location = std::string(Where);
117e28b9357SCarlos Alberto Enciso 
118e28b9357SCarlos Alberto Enciso   // Add a trailing slash, if there is none.
119e28b9357SCarlos Alberto Enciso   size_t Pos = Location.find_last_of('/');
120e28b9357SCarlos Alberto Enciso   if (Location.length() != Pos + 1)
121e28b9357SCarlos Alberto Enciso     Location.append("/");
122e28b9357SCarlos Alberto Enciso 
123e28b9357SCarlos Alberto Enciso   // Make sure the new directory exists, creating it if necessary.
124e28b9357SCarlos Alberto Enciso   if (std::error_code EC = llvm::sys::fs::create_directories(Location))
125e28b9357SCarlos Alberto Enciso     return createStringError(EC, "Error: could not create directory %s",
126e28b9357SCarlos Alberto Enciso                              Location.c_str());
127e28b9357SCarlos Alberto Enciso 
128e28b9357SCarlos Alberto Enciso   return Error::success();
129e28b9357SCarlos Alberto Enciso }
130e28b9357SCarlos Alberto Enciso 
131e28b9357SCarlos Alberto Enciso std::error_code LVSplitContext::open(std::string ContextName,
132e28b9357SCarlos Alberto Enciso                                      std::string Extension, raw_ostream &OS) {
133e28b9357SCarlos Alberto Enciso   assert(OutputFile == nullptr && "OutputFile already set.");
134e28b9357SCarlos Alberto Enciso 
135e28b9357SCarlos Alberto Enciso   // Transforms '/', '\', '.', ':' into '_'.
136e28b9357SCarlos Alberto Enciso   std::string Name(flattenedFilePath(ContextName));
137e28b9357SCarlos Alberto Enciso   Name.append(Extension);
138e28b9357SCarlos Alberto Enciso   // Add the split context location folder name.
139e28b9357SCarlos Alberto Enciso   if (!Location.empty())
140e28b9357SCarlos Alberto Enciso     Name.insert(0, Location);
141e28b9357SCarlos Alberto Enciso 
142e28b9357SCarlos Alberto Enciso   std::error_code EC;
143e28b9357SCarlos Alberto Enciso   OutputFile = std::make_unique<ToolOutputFile>(Name, EC, sys::fs::OF_None);
144e28b9357SCarlos Alberto Enciso   if (EC)
145e28b9357SCarlos Alberto Enciso     return EC;
146e28b9357SCarlos Alberto Enciso 
147e28b9357SCarlos Alberto Enciso   // Don't remove output file.
148e28b9357SCarlos Alberto Enciso   OutputFile->keep();
149e28b9357SCarlos Alberto Enciso   return std::error_code();
150e28b9357SCarlos Alberto Enciso }
151e28b9357SCarlos Alberto Enciso 
152e28b9357SCarlos Alberto Enciso LVReader *CurrentReader = nullptr;
153e28b9357SCarlos Alberto Enciso LVReader &LVReader::getInstance() {
154e28b9357SCarlos Alberto Enciso   if (CurrentReader)
155e28b9357SCarlos Alberto Enciso     return *CurrentReader;
156e28b9357SCarlos Alberto Enciso   outs() << "Invalid instance reader.\n";
157e28b9357SCarlos Alberto Enciso   llvm_unreachable("Invalid instance reader.");
158e28b9357SCarlos Alberto Enciso }
159e28b9357SCarlos Alberto Enciso void LVReader::setInstance(LVReader *Reader) { CurrentReader = Reader; }
160e28b9357SCarlos Alberto Enciso 
161e28b9357SCarlos Alberto Enciso Error LVReader::createSplitFolder() {
162e28b9357SCarlos Alberto Enciso   if (OutputSplit) {
163e28b9357SCarlos Alberto Enciso     // If the '--output=split' was specified, but no '--split-folder'
164e28b9357SCarlos Alberto Enciso     // option, use the input file as base for the split location.
165e28b9357SCarlos Alberto Enciso     if (options().getOutputFolder().empty())
166e28b9357SCarlos Alberto Enciso       options().setOutputFolder(getFilename().str() + "_cus");
167e28b9357SCarlos Alberto Enciso 
168e28b9357SCarlos Alberto Enciso     SmallString<128> SplitFolder;
169e28b9357SCarlos Alberto Enciso     SplitFolder = options().getOutputFolder();
170e28b9357SCarlos Alberto Enciso     sys::fs::make_absolute(SplitFolder);
171e28b9357SCarlos Alberto Enciso 
172e28b9357SCarlos Alberto Enciso     // Return error if unable to create a split context location.
173e28b9357SCarlos Alberto Enciso     if (Error Err = SplitContext.createSplitFolder(SplitFolder))
174e28b9357SCarlos Alberto Enciso       return Err;
175e28b9357SCarlos Alberto Enciso 
176e28b9357SCarlos Alberto Enciso     OS << "\nSplit View Location: '" << SplitContext.getLocation() << "'\n";
177e28b9357SCarlos Alberto Enciso   }
178e28b9357SCarlos Alberto Enciso 
179e28b9357SCarlos Alberto Enciso   return Error::success();
180e28b9357SCarlos Alberto Enciso }
181e28b9357SCarlos Alberto Enciso 
182e28b9357SCarlos Alberto Enciso // Get the filename for given object.
183e28b9357SCarlos Alberto Enciso StringRef LVReader::getFilename(LVObject *Object, size_t Index) const {
184*e7950fceSCarlos Alberto Enciso   // TODO: The current CodeView Reader implementation does not have support
185*e7950fceSCarlos Alberto Enciso   // for multiple compile units. Until we have a proper offset calculation,
186*e7950fceSCarlos Alberto Enciso   // check only in the current compile unit.
187e28b9357SCarlos Alberto Enciso   if (CompileUnits.size()) {
188e28b9357SCarlos Alberto Enciso     // Get Compile Unit for the given object.
189e28b9357SCarlos Alberto Enciso     LVCompileUnits::const_iterator Iter =
190e28b9357SCarlos Alberto Enciso         std::prev(CompileUnits.lower_bound(Object->getOffset()));
191e28b9357SCarlos Alberto Enciso     if (Iter != CompileUnits.end())
192e28b9357SCarlos Alberto Enciso       return Iter->second->getFilename(Index);
193e28b9357SCarlos Alberto Enciso   }
194e28b9357SCarlos Alberto Enciso 
195e28b9357SCarlos Alberto Enciso   return CompileUnit ? CompileUnit->getFilename(Index) : StringRef();
196e28b9357SCarlos Alberto Enciso }
197e28b9357SCarlos Alberto Enciso 
198e28b9357SCarlos Alberto Enciso // The Reader is the module that creates the logical view using the debug
199e28b9357SCarlos Alberto Enciso // information contained in the binary file specified in the command line.
200e28b9357SCarlos Alberto Enciso // This is the main entry point for the Reader and performs the following
201e28b9357SCarlos Alberto Enciso // steps:
202e28b9357SCarlos Alberto Enciso // - Process any patterns collected from the '--select' options.
203e28b9357SCarlos Alberto Enciso // - For each compile unit in the debug information:
204e28b9357SCarlos Alberto Enciso //   * Create the logical elements (scopes, symbols, types, lines).
205e28b9357SCarlos Alberto Enciso //   * Collect debug ranges and debug locations.
206e28b9357SCarlos Alberto Enciso //   * Move the collected logical lines to their associated scopes.
207e28b9357SCarlos Alberto Enciso // - Once all the compile units have been processed, traverse the scopes
208e28b9357SCarlos Alberto Enciso //   tree in order to:
209e28b9357SCarlos Alberto Enciso //   * Calculate symbol coverage.
210e28b9357SCarlos Alberto Enciso //   * Detect invalid ranges and locations.
211e28b9357SCarlos Alberto Enciso //   * "resolve" the logical elements. During this pass, the names and
212e28b9357SCarlos Alberto Enciso //      file information are updated, to reflect any dependency with other
213e28b9357SCarlos Alberto Enciso //     logical elements.
214e28b9357SCarlos Alberto Enciso Error LVReader::doLoad() {
215e28b9357SCarlos Alberto Enciso   // Set current Reader instance.
216e28b9357SCarlos Alberto Enciso   setInstance(this);
217e28b9357SCarlos Alberto Enciso 
2180332a8e7SCarlos Alberto Enciso   // Before any scopes creation, process any pattern specified by the
2190332a8e7SCarlos Alberto Enciso   // --select and --select-offsets options.
2200332a8e7SCarlos Alberto Enciso   patterns().addGenericPatterns(options().Select.Generic);
2210332a8e7SCarlos Alberto Enciso   patterns().addOffsetPatterns(options().Select.Offsets);
2220332a8e7SCarlos Alberto Enciso 
2230332a8e7SCarlos Alberto Enciso   // Add any specific element printing requests based on the element kind.
2240332a8e7SCarlos Alberto Enciso   patterns().addRequest(options().Select.Elements);
2250332a8e7SCarlos Alberto Enciso   patterns().addRequest(options().Select.Lines);
2260332a8e7SCarlos Alberto Enciso   patterns().addRequest(options().Select.Scopes);
2270332a8e7SCarlos Alberto Enciso   patterns().addRequest(options().Select.Symbols);
2280332a8e7SCarlos Alberto Enciso   patterns().addRequest(options().Select.Types);
2290332a8e7SCarlos Alberto Enciso 
2300332a8e7SCarlos Alberto Enciso   // Once we have processed the requests for any particular kind of elements,
2310332a8e7SCarlos Alberto Enciso   // we need to update the report options, in order to have a default value.
2320332a8e7SCarlos Alberto Enciso   patterns().updateReportOptions();
2330332a8e7SCarlos Alberto Enciso 
234e28b9357SCarlos Alberto Enciso   // Delegate the scope tree creation to the specific reader.
235e28b9357SCarlos Alberto Enciso   if (Error Err = createScopes())
236e28b9357SCarlos Alberto Enciso     return Err;
237e28b9357SCarlos Alberto Enciso 
2382c155d37SCarlos Alberto Enciso   if (options().getInternalIntegrity() && !checkIntegrityScopesTree(Root))
2392c155d37SCarlos Alberto Enciso     return llvm::make_error<StringError>("Duplicated elements in Scopes Tree",
2402c155d37SCarlos Alberto Enciso                                          inconvertibleErrorCode());
2412c155d37SCarlos Alberto Enciso 
2423c397c90SCarlos Alberto Enciso   // Calculate symbol coverage and detect invalid debug locations and ranges.
2433c397c90SCarlos Alberto Enciso   Root->processRangeInformation();
2443c397c90SCarlos Alberto Enciso 
245e28b9357SCarlos Alberto Enciso   // As the elements can depend on elements from a different compile unit,
246e28b9357SCarlos Alberto Enciso   // information such as name and file/line source information needs to be
247e28b9357SCarlos Alberto Enciso   // updated.
248e28b9357SCarlos Alberto Enciso   Root->resolveElements();
249e28b9357SCarlos Alberto Enciso 
250e28b9357SCarlos Alberto Enciso   sortScopes();
251e28b9357SCarlos Alberto Enciso   return Error::success();
252e28b9357SCarlos Alberto Enciso }
253e28b9357SCarlos Alberto Enciso 
254e28b9357SCarlos Alberto Enciso // Default handler for a generic reader.
255e28b9357SCarlos Alberto Enciso Error LVReader::doPrint() {
256e28b9357SCarlos Alberto Enciso   // Set current Reader instance.
257e28b9357SCarlos Alberto Enciso   setInstance(this);
258e28b9357SCarlos Alberto Enciso 
2590332a8e7SCarlos Alberto Enciso   // Check for any '--report' request.
2600332a8e7SCarlos Alberto Enciso   if (options().getReportExecute()) {
2610332a8e7SCarlos Alberto Enciso     // Requested details.
2620332a8e7SCarlos Alberto Enciso     if (options().getReportList())
2630332a8e7SCarlos Alberto Enciso       if (Error Err = printMatchedElements(/*UseMatchedElements=*/true))
2640332a8e7SCarlos Alberto Enciso         return Err;
2650332a8e7SCarlos Alberto Enciso     // Requested only children.
2660332a8e7SCarlos Alberto Enciso     if (options().getReportChildren() && !options().getReportParents())
2670332a8e7SCarlos Alberto Enciso       if (Error Err = printMatchedElements(/*UseMatchedElements=*/false))
2680332a8e7SCarlos Alberto Enciso         return Err;
2690332a8e7SCarlos Alberto Enciso     // Requested (parents) or (parents and children).
2700332a8e7SCarlos Alberto Enciso     if (options().getReportParents() || options().getReportView())
2710332a8e7SCarlos Alberto Enciso       if (Error Err = printScopes())
2720332a8e7SCarlos Alberto Enciso         return Err;
2730332a8e7SCarlos Alberto Enciso 
2740332a8e7SCarlos Alberto Enciso     return Error::success();
2750332a8e7SCarlos Alberto Enciso   }
2760332a8e7SCarlos Alberto Enciso 
277e28b9357SCarlos Alberto Enciso   return printScopes();
278e28b9357SCarlos Alberto Enciso }
279e28b9357SCarlos Alberto Enciso 
280e28b9357SCarlos Alberto Enciso Error LVReader::printScopes() {
281e98a4c5aSCarlos Alberto Enciso   if (bool DoPrint =
282e98a4c5aSCarlos Alberto Enciso           (options().getPrintExecute() || options().getComparePrint())) {
283e28b9357SCarlos Alberto Enciso     if (Error Err = createSplitFolder())
284e28b9357SCarlos Alberto Enciso       return Err;
285e28b9357SCarlos Alberto Enciso 
286e28b9357SCarlos Alberto Enciso     // Start printing from the root.
2870332a8e7SCarlos Alberto Enciso     bool DoMatch = options().getSelectGenericPattern() ||
2880332a8e7SCarlos Alberto Enciso                    options().getSelectGenericKind() ||
2890332a8e7SCarlos Alberto Enciso                    options().getSelectOffsetPattern();
290e28b9357SCarlos Alberto Enciso     return Root->doPrint(OutputSplit, DoMatch, DoPrint, OS);
291e28b9357SCarlos Alberto Enciso   }
292e28b9357SCarlos Alberto Enciso 
293e28b9357SCarlos Alberto Enciso   return Error::success();
294e28b9357SCarlos Alberto Enciso }
295e28b9357SCarlos Alberto Enciso 
296e28b9357SCarlos Alberto Enciso Error LVReader::printMatchedElements(bool UseMatchedElements) {
297e28b9357SCarlos Alberto Enciso   if (Error Err = createSplitFolder())
298e28b9357SCarlos Alberto Enciso     return Err;
299e28b9357SCarlos Alberto Enciso 
300e28b9357SCarlos Alberto Enciso   return Root->doPrintMatches(OutputSplit, OS, UseMatchedElements);
301e28b9357SCarlos Alberto Enciso }
302e28b9357SCarlos Alberto Enciso 
303e28b9357SCarlos Alberto Enciso void LVReader::print(raw_ostream &OS) const {
304e28b9357SCarlos Alberto Enciso   OS << "LVReader\n";
305e28b9357SCarlos Alberto Enciso   LLVM_DEBUG(dbgs() << "PrintReader\n");
306e28b9357SCarlos Alberto Enciso }
307