1 //===-- LVReader.cpp ------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This implements the LVReader class.
11 //===----------------------------------------------------------------------===//
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"
22 using namespace llvm::logicalview
;
24 #define DEBUG_TYPE "Reader"
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.
29 bool checkIntegrityScopesTree(LVScope
*Root
) {
30 using LVDuplicateEntry
= std::tuple
<LVElement
*, LVScope
*, LVScope
*>;
31 using LVDuplicate
= std::vector
<LVDuplicateEntry
>;
32 LVDuplicate Duplicate
;
34 using LVIntegrity
= std::map
<LVElement
*, LVScope
*>;
35 LVIntegrity Integrity
;
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
);
43 // We found a duplicate.
44 Duplicate
.emplace_back(Element
, Scope
, Iter
->second
);
47 // Recursively add all the elements in the scope.
48 std::function
<void(LVScope
* Parent
)> TraverseScope
= [&](LVScope
*Parent
) {
49 auto Traverse
= [&](const auto *Set
) {
51 for (const auto &Entry
: *Set
)
52 AddElement(Entry
, Parent
);
54 if (const LVScopes
*Scopes
= Parent
->getScopes()) {
55 for (LVScope
*Scope
: *Scopes
) {
56 AddElement(Scope
, Parent
);
60 Traverse(Parent
->getSymbols());
61 Traverse(Parent
->getTypes());
62 Traverse(Parent
->getLines());
65 // Start traversing the scopes root and print any duplicates.
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();
74 auto PrintIndex
= [](unsigned Index
) {
76 dbgs() << format("%8d: ", Index
);
78 dbgs() << format("%8c: ", ' ');
80 auto PrintElement
= [&](LVElement
*Element
, unsigned Index
= 0) {
82 std::string
ElementName(Element
->getName());
83 dbgs() << format("%15s ID=0x%08x '%s'\n", Element
->kind(),
84 Element
->getID(), ElementName
.c_str());
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(),
91 dbgs() << formatv("{0}\n", fmt_repeat('=', 72));
94 for (const LVDuplicateEntry
&Entry
: Duplicate
) {
98 std::tie(Element
, First
, Second
) = Entry
;
99 dbgs() << formatv("\n{0}\n", fmt_repeat('-', 72));
100 PrintElement(Element
, ++Index
);
102 PrintElement(Second
);
103 dbgs() << formatv("{0}\n", fmt_repeat('-', 72));
105 PassIntegrity
= false;
107 return PassIntegrity
;
110 //===----------------------------------------------------------------------===//
111 // Class to represent a split context.
112 //===----------------------------------------------------------------------===//
113 Error
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
);
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("/");
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",
129 return Error::success();
132 std::error_code
LVSplitContext::open(std::string ContextName
,
133 std::string Extension
, raw_ostream
&OS
) {
134 assert(OutputFile
== nullptr && "OutputFile already set.");
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
);
144 OutputFile
= std::make_unique
<ToolOutputFile
>(Name
, EC
, sys::fs::OF_None
);
148 // Don't remove output file.
150 return std::error_code();
153 LVReader
*CurrentReader
= nullptr;
154 LVReader
&LVReader::getInstance() {
156 return *CurrentReader
;
157 outs() << "Invalid instance reader.\n";
158 llvm_unreachable("Invalid instance reader.");
160 void LVReader::setInstance(LVReader
*Reader
) { CurrentReader
= Reader
; }
162 Error
LVReader::createSplitFolder() {
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");
169 SmallString
<128> SplitFolder
;
170 SplitFolder
= options().getOutputFolder();
171 sys::fs::make_absolute(SplitFolder
);
173 // Return error if unable to create a split context location.
174 if (Error Err
= SplitContext
.createSplitFolder(SplitFolder
))
177 OS
<< "\nSplit View Location: '" << SplitContext
.getLocation() << "'\n";
180 return Error::success();
183 // Get the filename for given object.
184 StringRef
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
);
196 return CompileUnit
? CompileUnit
->getFilename(Index
) : StringRef();
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
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
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
215 Error
LVReader::doLoad() {
216 // Set current Reader instance.
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
);
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
);
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();
235 // Delegate the scope tree creation to the specific reader.
236 if (Error Err
= createScopes())
239 if (options().getInternalIntegrity() && !checkIntegrityScopesTree(Root
))
240 return llvm::make_error
<StringError
>("Duplicated elements in Scopes Tree",
241 inconvertibleErrorCode());
243 // Calculate symbol coverage and detect invalid debug locations and ranges.
244 Root
->processRangeInformation();
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
249 Root
->resolveElements();
252 return Error::success();
255 // Default handler for a generic reader.
256 Error
LVReader::doPrint() {
257 // Set current Reader instance.
260 // Check for any '--report' request.
261 if (options().getReportExecute()) {
262 // Requested details.
263 if (options().getReportList())
264 if (Error Err
= printMatchedElements(/*UseMatchedElements=*/true))
266 // Requested only children.
267 if (options().getReportChildren() && !options().getReportParents())
268 if (Error Err
= printMatchedElements(/*UseMatchedElements=*/false))
270 // Requested (parents) or (parents and children).
271 if (options().getReportParents() || options().getReportView())
272 if (Error Err
= printScopes())
275 return Error::success();
278 return printScopes();
281 Error
LVReader::printScopes() {
283 (options().getPrintExecute() || options().getComparePrint())) {
284 if (Error Err
= createSplitFolder())
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
);
294 return Error::success();
297 Error
LVReader::printMatchedElements(bool UseMatchedElements
) {
298 if (Error Err
= createSplitFolder())
301 return Root
->doPrintMatches(OutputSplit
, OS
, UseMatchedElements
);
304 void LVReader::print(raw_ostream
&OS
) const {
306 LLVM_DEBUG(dbgs() << "PrintReader\n");