LLVM 20.0.0git
LVReader.cpp
Go to the documentation of this file.
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
18#include <tuple>
19
20using namespace llvm;
21using 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.
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;
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//===----------------------------------------------------------------------===//
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
131std::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
154 if (CurrentReader)
155 return *CurrentReader;
156 outs() << "Invalid instance reader.\n";
157 llvm_unreachable("Invalid instance reader.");
158}
160
161Error 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.
183StringRef 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.
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.
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.
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",
241
242 // Calculate symbol coverage and detect invalid debug locations and ranges.
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.
249
250 sortScopes();
251 return Error::success();
252}
253
254// Default handler for a generic reader.
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
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
296Error LVReader::printMatchedElements(bool UseMatchedElements) {
297 if (Error Err = createSplitFolder())
298 return Err;
299
300 return Root->doPrintMatches(OutputSplit, OS, UseMatchedElements);
301}
302
304 OS << "LVReader\n";
305 LLVM_DEBUG(dbgs() << "PrintReader\n");
306}
AMDGPU Register Bank Select
#define LLVM_DEBUG(...)
Definition: Debug.h:106
LVReader * CurrentReader
Definition: LVReader.cpp:152
bool checkIntegrityScopesTree(LVScope *Root)
Definition: LVReader.cpp:28
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
Stores all information relating to a compile unit, be it in its original instance in the object file ...
StringRef getName() const override
Definition: LVElement.h:184
virtual const char * kind() const
Definition: LVObject.h:275
uint64_t getID() const
Definition: LVObject.h:318
void addGenericPatterns(StringSet<> &Patterns)
Definition: LVOptions.cpp:439
void addOffsetPatterns(const LVOffsetSet &Patterns)
Definition: LVOptions.cpp:447
The logical reader owns of all the logical elements created during the debug information parsing.
Definition: LVReader.h:60
virtual void sortScopes()
Definition: LVReader.h:168
void print(raw_ostream &OS) const
Definition: LVReader.cpp:303
StringRef getFilename() const
Definition: LVReader.h:236
static LVReader & getInstance()
Definition: LVReader.cpp:153
static void setInstance(LVReader *Reader)
Definition: LVReader.cpp:159
virtual Error printMatchedElements(bool UseMatchedElements)
Definition: LVReader.cpp:296
virtual Error printScopes()
Definition: LVReader.cpp:280
virtual Error createScopes()
Definition: LVReader.h:141
Error doPrintMatches(bool Split, raw_ostream &OS, bool UseMatchedElements) const
Definition: LVScope.cpp:2058
const LVLines * getLines() const
Definition: LVScope.h:205
const LVScopes * getScopes() const
Definition: LVScope.h:207
const LVSymbols * getSymbols() const
Definition: LVScope.h:208
const LVTypes * getTypes() const
Definition: LVScope.h:209
Error doPrint(bool Split, bool Match, bool Print, raw_ostream &OS, bool Full=true) const override
Definition: LVScope.cpp:578
std::string getLocation() const
Definition: LVReader.h:53
Error createSplitFolder(StringRef Where)
Definition: LVReader.cpp:112
std::error_code open(std::string Name, std::string Extension, raw_ostream &OS)
Definition: LVReader.cpp:131
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LVPatterns & patterns()
Definition: LVOptions.h:642
std::string flattenedFilePath(StringRef Path)
Definition: LVSupport.cpp:48
LVOptions & options()
Definition: LVOptions.h:445
void make_absolute(const Twine &current_directory, SmallVectorImpl< char > &path)
Make path an absolute path.
Definition: Path.cpp:906
std::error_code create_directories(const Twine &path, bool IgnoreExisting=true, perms Perms=owner_all|group_all)
Create all the non-existent directories in path.
Definition: Path.cpp:967
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:98
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1291
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:125
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
support::detail::RepeatAdapter< T > fmt_repeat(T &&Item, size_t Count)