1 | //===-- LVReader.h ----------------------------------------------*- C++ -*-===// |
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 file defines the LVReader class, which is used to describe a debug |
10 | // information reader. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVREADER_H |
15 | #define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVREADER_H |
16 | |
17 | #include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" |
18 | #include "llvm/DebugInfo/LogicalView/Core/LVRange.h" |
19 | #include "llvm/Support/Errc.h" |
20 | #include "llvm/Support/Error.h" |
21 | #include "llvm/Support/ScopedPrinter.h" |
22 | #include "llvm/Support/ToolOutputFile.h" |
23 | #include <map> |
24 | |
25 | namespace llvm { |
26 | namespace logicalview { |
27 | |
28 | constexpr LVSectionIndex UndefinedSectionIndex = 0; |
29 | |
30 | class LVScopeCompileUnit; |
31 | class LVObject; |
32 | |
33 | class LVSplitContext final { |
34 | std::unique_ptr<ToolOutputFile> OutputFile; |
35 | std::string Location; |
36 | |
37 | public: |
38 | LVSplitContext() = default; |
39 | LVSplitContext(const LVSplitContext &) = delete; |
40 | LVSplitContext &operator=(const LVSplitContext &) = delete; |
41 | ~LVSplitContext() = default; |
42 | |
43 | Error createSplitFolder(StringRef Where); |
44 | std::error_code open(std::string Name, std::string Extension, |
45 | raw_ostream &OS); |
46 | void close() { |
47 | if (OutputFile) { |
48 | OutputFile->os().close(); |
49 | OutputFile = nullptr; |
50 | } |
51 | } |
52 | |
53 | std::string getLocation() const { return Location; } |
54 | raw_fd_ostream &os() { return OutputFile->os(); } |
55 | }; |
56 | |
57 | /// The logical reader owns of all the logical elements created during |
58 | /// the debug information parsing. For its creation it uses a specific |
59 | /// bump allocator for each type of logical element. |
60 | class LVReader { |
61 | LVBinaryType BinaryType; |
62 | |
63 | // Context used by '--output=split' command line option. |
64 | LVSplitContext SplitContext; |
65 | |
66 | // Compile Units DIE Offset => Scope. |
67 | using LVCompileUnits = std::map<LVOffset, LVScopeCompileUnit *>; |
68 | LVCompileUnits CompileUnits; |
69 | |
70 | // Added elements to be used during elements comparison. |
71 | LVLines Lines; |
72 | LVScopes Scopes; |
73 | LVSymbols Symbols; |
74 | LVTypes Types; |
75 | |
76 | // Create split folder. |
77 | Error createSplitFolder(); |
78 | bool OutputSplit = false; |
79 | |
80 | // Define a specific bump allocator for the given KIND. |
81 | #define LV_OBJECT_ALLOCATOR(KIND) \ |
82 | llvm::SpecificBumpPtrAllocator<LV##KIND> Allocated##KIND; |
83 | |
84 | // Lines allocator. |
85 | LV_OBJECT_ALLOCATOR(Line) |
86 | LV_OBJECT_ALLOCATOR(LineDebug) |
87 | LV_OBJECT_ALLOCATOR(LineAssembler) |
88 | |
89 | // Locations allocator. |
90 | LV_OBJECT_ALLOCATOR(Location) |
91 | LV_OBJECT_ALLOCATOR(LocationSymbol) |
92 | |
93 | // Operations allocator. |
94 | LV_OBJECT_ALLOCATOR(Operation) |
95 | |
96 | // Scopes allocator. |
97 | LV_OBJECT_ALLOCATOR(Scope) |
98 | LV_OBJECT_ALLOCATOR(ScopeAggregate) |
99 | LV_OBJECT_ALLOCATOR(ScopeAlias) |
100 | LV_OBJECT_ALLOCATOR(ScopeArray) |
101 | LV_OBJECT_ALLOCATOR(ScopeCompileUnit) |
102 | LV_OBJECT_ALLOCATOR(ScopeEnumeration) |
103 | LV_OBJECT_ALLOCATOR(ScopeFormalPack) |
104 | LV_OBJECT_ALLOCATOR(ScopeFunction) |
105 | LV_OBJECT_ALLOCATOR(ScopeFunctionInlined) |
106 | LV_OBJECT_ALLOCATOR(ScopeFunctionType) |
107 | LV_OBJECT_ALLOCATOR(ScopeNamespace) |
108 | LV_OBJECT_ALLOCATOR(ScopeRoot) |
109 | LV_OBJECT_ALLOCATOR(ScopeTemplatePack) |
110 | |
111 | // Symbols allocator. |
112 | LV_OBJECT_ALLOCATOR(Symbol) |
113 | |
114 | // Types allocator. |
115 | LV_OBJECT_ALLOCATOR(Type) |
116 | LV_OBJECT_ALLOCATOR(TypeDefinition) |
117 | LV_OBJECT_ALLOCATOR(TypeEnumerator) |
118 | LV_OBJECT_ALLOCATOR(TypeImport) |
119 | LV_OBJECT_ALLOCATOR(TypeParam) |
120 | LV_OBJECT_ALLOCATOR(TypeSubrange) |
121 | |
122 | #undef LV_OBJECT_ALLOCATOR |
123 | |
124 | protected: |
125 | LVScopeRoot *Root = nullptr; |
126 | std::string InputFilename; |
127 | std::string FileFormatName; |
128 | ScopedPrinter &W; |
129 | raw_ostream &OS; |
130 | LVScopeCompileUnit *CompileUnit = nullptr; |
131 | |
132 | // Only for ELF format. The CodeView is handled in a different way. |
133 | LVSectionIndex DotTextSectionIndex = UndefinedSectionIndex; |
134 | |
135 | // Record Compilation Unit entry. |
136 | void addCompileUnitOffset(LVOffset Offset, LVScopeCompileUnit *CompileUnit) { |
137 | CompileUnits.emplace(args&: Offset, args&: CompileUnit); |
138 | } |
139 | |
140 | // Create the Scope Root. |
141 | virtual Error createScopes() { |
142 | Root = createScopeRoot(); |
143 | Root->setName(getFilename()); |
144 | if (options().getAttributeFormat()) |
145 | Root->setFileFormatName(FileFormatName); |
146 | return Error::success(); |
147 | } |
148 | |
149 | // Return a pathname composed by: parent_path(InputFilename)/filename(From). |
150 | // This is useful when a type server (PDB file associated with an object |
151 | // file or a precompiled header file) or a DWARF split object have been |
152 | // moved from their original location. That is the case when running |
153 | // regression tests, where object files are created in one location and |
154 | // executed in a different location. |
155 | std::string createAlternativePath(StringRef From) { |
156 | // During the reader initialization, any backslashes in 'InputFilename' |
157 | // are converted to forward slashes. |
158 | SmallString<128> Path; |
159 | sys::path::append(path&: Path, style: sys::path::Style::posix, |
160 | a: sys::path::parent_path(path: InputFilename), |
161 | b: sys::path::filename(path: sys::path::convert_to_slash( |
162 | path: From, style: sys::path::Style::windows))); |
163 | return std::string(Path); |
164 | } |
165 | |
166 | virtual Error printScopes(); |
167 | virtual Error printMatchedElements(bool UseMatchedElements); |
168 | virtual void sortScopes() {} |
169 | |
170 | public: |
171 | LVReader() = delete; |
172 | LVReader(StringRef InputFilename, StringRef FileFormatName, ScopedPrinter &W, |
173 | LVBinaryType BinaryType = LVBinaryType::NONE) |
174 | : BinaryType(BinaryType), OutputSplit(options().getOutputSplit()), |
175 | InputFilename(InputFilename), FileFormatName(FileFormatName), W(W), |
176 | OS(W.getOStream()) {} |
177 | LVReader(const LVReader &) = delete; |
178 | LVReader &operator=(const LVReader &) = delete; |
179 | virtual ~LVReader() = default; |
180 | |
181 | // Creates a logical object of the given KIND. The signature for the created |
182 | // functions looks like: |
183 | // ... |
184 | // LVScope *createScope() |
185 | // LVScopeRoot *creatScopeRoot() |
186 | // LVType *createType(); |
187 | // ... |
188 | #define LV_CREATE_OBJECT(KIND) \ |
189 | LV##KIND *create##KIND() { \ |
190 | return new (Allocated##KIND.Allocate()) LV##KIND(); \ |
191 | } |
192 | |
193 | // Lines creation. |
194 | LV_CREATE_OBJECT(Line) |
195 | LV_CREATE_OBJECT(LineDebug) |
196 | LV_CREATE_OBJECT(LineAssembler) |
197 | |
198 | // Locations creation. |
199 | LV_CREATE_OBJECT(Location) |
200 | LV_CREATE_OBJECT(LocationSymbol) |
201 | |
202 | // Scopes creation. |
203 | LV_CREATE_OBJECT(Scope) |
204 | LV_CREATE_OBJECT(ScopeAggregate) |
205 | LV_CREATE_OBJECT(ScopeAlias) |
206 | LV_CREATE_OBJECT(ScopeArray) |
207 | LV_CREATE_OBJECT(ScopeCompileUnit) |
208 | LV_CREATE_OBJECT(ScopeEnumeration) |
209 | LV_CREATE_OBJECT(ScopeFormalPack) |
210 | LV_CREATE_OBJECT(ScopeFunction) |
211 | LV_CREATE_OBJECT(ScopeFunctionInlined) |
212 | LV_CREATE_OBJECT(ScopeFunctionType) |
213 | LV_CREATE_OBJECT(ScopeNamespace) |
214 | LV_CREATE_OBJECT(ScopeRoot) |
215 | LV_CREATE_OBJECT(ScopeTemplatePack) |
216 | |
217 | // Symbols creation. |
218 | LV_CREATE_OBJECT(Symbol) |
219 | |
220 | // Types creation. |
221 | LV_CREATE_OBJECT(Type) |
222 | LV_CREATE_OBJECT(TypeDefinition) |
223 | LV_CREATE_OBJECT(TypeEnumerator) |
224 | LV_CREATE_OBJECT(TypeImport) |
225 | LV_CREATE_OBJECT(TypeParam) |
226 | LV_CREATE_OBJECT(TypeSubrange) |
227 | |
228 | #undef LV_CREATE_OBJECT |
229 | |
230 | // Operations creation. |
231 | LVOperation *createOperation(LVSmall OpCode, ArrayRef<LVUnsigned> Operands) { |
232 | return new (AllocatedOperation.Allocate()) LVOperation(OpCode, Operands); |
233 | } |
234 | |
235 | StringRef getFilename(LVObject *Object, size_t Index) const; |
236 | StringRef getFilename() const { return InputFilename; } |
237 | void setFilename(std::string Name) { InputFilename = std::move(Name); } |
238 | StringRef getFileFormatName() const { return FileFormatName; } |
239 | |
240 | raw_ostream &outputStream() { return OS; } |
241 | |
242 | bool isBinaryTypeNone() const { return BinaryType == LVBinaryType::NONE; } |
243 | bool isBinaryTypeELF() const { return BinaryType == LVBinaryType::ELF; } |
244 | bool isBinaryTypeCOFF() const { return BinaryType == LVBinaryType::COFF; } |
245 | |
246 | LVScopeCompileUnit *getCompileUnit() const { return CompileUnit; } |
247 | void setCompileUnit(LVScope *Scope) { |
248 | assert(Scope && Scope->isCompileUnit() && "Scope is not a compile unit" ); |
249 | CompileUnit = static_cast<LVScopeCompileUnit *>(Scope); |
250 | } |
251 | void setCompileUnitCPUType(codeview::CPUType Type) { |
252 | CompileUnit->setCPUType(Type); |
253 | } |
254 | codeview::CPUType getCompileUnitCPUType() { |
255 | return CompileUnit->getCPUType(); |
256 | } |
257 | |
258 | // Access to the scopes root. |
259 | LVScopeRoot *getScopesRoot() const { return Root; } |
260 | |
261 | Error doPrint(); |
262 | Error doLoad(); |
263 | |
264 | virtual std::string getRegisterName(LVSmall Opcode, |
265 | ArrayRef<uint64_t> Operands) { |
266 | llvm_unreachable("Invalid instance reader." ); |
267 | return {}; |
268 | } |
269 | |
270 | LVSectionIndex getDotTextSectionIndex() const { return DotTextSectionIndex; } |
271 | virtual LVSectionIndex getSectionIndex(LVScope *Scope) { |
272 | return getDotTextSectionIndex(); |
273 | } |
274 | |
275 | virtual bool isSystemEntry(LVElement *Element, StringRef Name = {}) const { |
276 | return false; |
277 | }; |
278 | |
279 | // Access to split context. |
280 | LVSplitContext &getSplitContext() { return SplitContext; } |
281 | |
282 | // In the case of element comparison, register that added element. |
283 | void notifyAddedElement(LVLine *Line) { |
284 | if (!options().getCompareContext() && options().getCompareLines()) |
285 | Lines.push_back(Elt: Line); |
286 | } |
287 | void notifyAddedElement(LVScope *Scope) { |
288 | if (!options().getCompareContext() && options().getCompareScopes()) |
289 | Scopes.push_back(Elt: Scope); |
290 | } |
291 | void notifyAddedElement(LVSymbol *Symbol) { |
292 | if (!options().getCompareContext() && options().getCompareSymbols()) |
293 | Symbols.push_back(Elt: Symbol); |
294 | } |
295 | void notifyAddedElement(LVType *Type) { |
296 | if (!options().getCompareContext() && options().getCompareTypes()) |
297 | Types.push_back(Elt: Type); |
298 | } |
299 | |
300 | const LVLines &getLines() const { return Lines; } |
301 | const LVScopes &getScopes() const { return Scopes; } |
302 | const LVSymbols &getSymbols() const { return Symbols; } |
303 | const LVTypes &getTypes() const { return Types; } |
304 | |
305 | // Conditions to print an object. |
306 | bool doPrintLine(const LVLine *Line) const { |
307 | return patterns().printElement(Line); |
308 | } |
309 | bool doPrintLocation(const LVLocation *Location) const { |
310 | return patterns().printObject(Location); |
311 | } |
312 | bool doPrintScope(const LVScope *Scope) const { |
313 | return patterns().printElement(Scope); |
314 | } |
315 | bool doPrintSymbol(const LVSymbol *Symbol) const { |
316 | return patterns().printElement(Symbol); |
317 | } |
318 | bool doPrintType(const LVType *Type) const { |
319 | return patterns().printElement(Type); |
320 | } |
321 | |
322 | static LVReader &getInstance(); |
323 | static void setInstance(LVReader *Reader); |
324 | |
325 | void print(raw_ostream &OS) const; |
326 | virtual void printRecords(raw_ostream &OS) const {} |
327 | |
328 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
329 | void dump() const { print(OS&: dbgs()); } |
330 | #endif |
331 | }; |
332 | |
333 | inline LVReader &getReader() { return LVReader::getInstance(); } |
334 | inline LVSplitContext &getReaderSplitContext() { |
335 | return getReader().getSplitContext(); |
336 | } |
337 | inline LVScopeCompileUnit *getReaderCompileUnit() { |
338 | return getReader().getCompileUnit(); |
339 | } |
340 | |
341 | } // end namespace logicalview |
342 | } // end namespace llvm |
343 | |
344 | #endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVREADER_H |
345 | |