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);
close()46   void close() {
47     if (OutputFile) {
48       OutputFile->os().close();
49       OutputFile = nullptr;
50     }
51   }
52 
getLocation()53   std::string getLocation() const { return Location; }
os()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.
addCompileUnitOffset(LVOffset Offset,LVScopeCompileUnit * CompileUnit)136   void addCompileUnitOffset(LVOffset Offset, LVScopeCompileUnit *CompileUnit) {
137     CompileUnits.emplace(Offset, CompileUnit);
138   }
139 
140   // Create the Scope Root.
createScopes()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.
createAlternativePath(StringRef From)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, sys::path::Style::posix,
160                       sys::path::parent_path(InputFilename),
161                       sys::path::filename(sys::path::convert_to_slash(
162                           From, sys::path::Style::windows)));
163     return std::string(Path);
164   }
165 
166   virtual Error printScopes();
167   virtual Error printMatchedElements(bool UseMatchedElements);
sortScopes()168   virtual void sortScopes() {}
169 
170 public:
171   LVReader() = delete;
172   LVReader(StringRef InputFilename, StringRef FileFormatName, ScopedPrinter &W,
173            LVBinaryType BinaryType = LVBinaryType::NONE)
BinaryType(BinaryType)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)
LV_CREATE_OBJECT(LineDebug)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;
getFilename()236   StringRef getFilename() const { return InputFilename; }
setFilename(std::string Name)237   void setFilename(std::string Name) { InputFilename = std::move(Name); }
getFileFormatName()238   StringRef getFileFormatName() const { return FileFormatName; }
239 
outputStream()240   raw_ostream &outputStream() { return OS; }
241 
isBinaryTypeNone()242   bool isBinaryTypeNone() const { return BinaryType == LVBinaryType::NONE; }
isBinaryTypeELF()243   bool isBinaryTypeELF() const { return BinaryType == LVBinaryType::ELF; }
isBinaryTypeCOFF()244   bool isBinaryTypeCOFF() const { return BinaryType == LVBinaryType::COFF; }
245 
getCompileUnit()246   LVScopeCompileUnit *getCompileUnit() const { return CompileUnit; }
setCompileUnit(LVScope * Scope)247   void setCompileUnit(LVScope *Scope) {
248     assert(Scope && Scope->isCompileUnit() && "Scope is not a compile unit");
249     CompileUnit = static_cast<LVScopeCompileUnit *>(Scope);
250   }
setCompileUnitCPUType(codeview::CPUType Type)251   void setCompileUnitCPUType(codeview::CPUType Type) {
252     CompileUnit->setCPUType(Type);
253   }
getCompileUnitCPUType()254   codeview::CPUType getCompileUnitCPUType() {
255     return CompileUnit->getCPUType();
256   }
257 
258   // Access to the scopes root.
getScopesRoot()259   LVScopeRoot *getScopesRoot() const { return Root; }
260 
261   Error doPrint();
262   Error doLoad();
263 
getRegisterName(LVSmall Opcode,ArrayRef<uint64_t> Operands)264   virtual std::string getRegisterName(LVSmall Opcode,
265                                       ArrayRef<uint64_t> Operands) {
266     llvm_unreachable("Invalid instance reader.");
267     return {};
268   }
269 
getDotTextSectionIndex()270   LVSectionIndex getDotTextSectionIndex() const { return DotTextSectionIndex; }
getSectionIndex(LVScope * Scope)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.
getSplitContext()280   LVSplitContext &getSplitContext() { return SplitContext; }
281 
282   // In the case of element comparison, register that added element.
notifyAddedElement(LVLine * Line)283   void notifyAddedElement(LVLine *Line) {
284     if (!options().getCompareContext() && options().getCompareLines())
285       Lines.push_back(Line);
286   }
notifyAddedElement(LVScope * Scope)287   void notifyAddedElement(LVScope *Scope) {
288     if (!options().getCompareContext() && options().getCompareScopes())
289       Scopes.push_back(Scope);
290   }
notifyAddedElement(LVSymbol * Symbol)291   void notifyAddedElement(LVSymbol *Symbol) {
292     if (!options().getCompareContext() && options().getCompareSymbols())
293       Symbols.push_back(Symbol);
294   }
notifyAddedElement(LVType * Type)295   void notifyAddedElement(LVType *Type) {
296     if (!options().getCompareContext() && options().getCompareTypes())
297       Types.push_back(Type);
298   }
299 
getLines()300   const LVLines &getLines() const { return Lines; }
getScopes()301   const LVScopes &getScopes() const { return Scopes; }
getSymbols()302   const LVSymbols &getSymbols() const { return Symbols; }
getTypes()303   const LVTypes &getTypes() const { return Types; }
304 
305   // Conditions to print an object.
doPrintLine(const LVLine * Line)306   bool doPrintLine(const LVLine *Line) const {
307     return patterns().printElement(Line);
308   }
doPrintLocation(const LVLocation * Location)309   bool doPrintLocation(const LVLocation *Location) const {
310     return patterns().printObject(Location);
311   }
doPrintScope(const LVScope * Scope)312   bool doPrintScope(const LVScope *Scope) const {
313     return patterns().printElement(Scope);
314   }
doPrintSymbol(const LVSymbol * Symbol)315   bool doPrintSymbol(const LVSymbol *Symbol) const {
316     return patterns().printElement(Symbol);
317   }
doPrintType(const LVType * Type)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;
printRecords(raw_ostream & OS)326   virtual void printRecords(raw_ostream &OS) const {}
327 
328 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump()329   void dump() const { print(dbgs()); }
330 #endif
331 };
332 
getReader()333 inline LVReader &getReader() { return LVReader::getInstance(); }
getReaderSplitContext()334 inline LVSplitContext &getReaderSplitContext() {
335   return getReader().getSplitContext();
336 }
getReaderCompileUnit()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