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