1 //===-- LVCodeViewReader.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 LVCodeViewReader class, which is used to describe a
10 // debug information (COFF) reader.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWREADER_H
15 #define LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWREADER_H
16 
17 #include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"
18 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
19 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
20 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
21 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
22 #include "llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h"
23 #include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h"
24 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
25 #include "llvm/DebugInfo/PDB/PDB.h"
26 #include "llvm/Support/BinaryByteStream.h"
27 #include "llvm/Support/BinaryItemStream.h"
28 #include "llvm/Support/BinaryStreamArray.h"
29 
30 namespace llvm {
31 template <> struct BinaryItemTraits<codeview::CVType> {
32   static size_t length(const codeview::CVType &Item) { return Item.length(); }
33   static ArrayRef<uint8_t> bytes(const codeview::CVType &Item) {
34     return Item.data();
35   }
36 };
37 
38 namespace codeview {
39 class LazyRandomTypeCollection;
40 }
41 namespace object {
42 struct coff_section;
43 }
44 namespace pdb {
45 class SymbolGroup;
46 }
47 namespace logicalview {
48 
49 class LVElement;
50 class LVLine;
51 class LVScope;
52 class LVScopeCompileUnit;
53 class LVSymbol;
54 class LVType;
55 class LVTypeVisitor;
56 class LVSymbolVisitor;
57 class LVSymbolVisitorDelegate;
58 
59 using LVNames = SmallVector<StringRef, 16>;
60 
61 // The ELF reader uses the DWARF constants to create the logical elements.
62 // The DW_TAG_* and DW_AT_* are used to select the logical object and to
63 // set specific attributes, such as name, type, etc.
64 // As the CodeView constants are different to the DWARF constants, the
65 // CodeView reader will map them to the DWARF ones.
66 
67 class LVCodeViewReader final : public LVBinaryReader {
68   friend class LVTypeVisitor;
69   friend class LVSymbolVisitor;
70   friend class LVSymbolVisitorDelegate;
71 
72   using LVModules = std::vector<LVScope *>;
73   LVModules Modules;
74 
75   // Encapsulates access to the input file and any dependent type server,
76   // including any precompiled header object.
77   llvm::pdb::InputFile Input;
78   std::shared_ptr<llvm::pdb::InputFile> TypeServer;
79   std::shared_ptr<LazyRandomTypeCollection> PrecompHeader;
80 
81   // Persistance data when loading a type server.
82   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr = nullptr;
83   std::unique_ptr<MemoryBuffer> MemBuffer;
84   std::unique_ptr<llvm::pdb::IPDBSession> Session;
85   std::unique_ptr<llvm::pdb::NativeSession> PdbSession;
86 
87   // Persistance data when loading a precompiled header.
88   BumpPtrAllocator BuilderAllocator;
89   std::unique_ptr<AppendingTypeTableBuilder> Builder;
90   std::unique_ptr<BinaryItemStream<CVType>> ItemStream;
91   std::unique_ptr<BinaryStreamReader> ReaderPrecomp;
92   std::vector<CVType> TypeArray;
93   CVTypeArray TypeStream;
94   CVTypeArray CVTypesPrecomp;
95 
96   // Persistance data when loading an executable file.
97   std::unique_ptr<MemoryBuffer> BinaryBuffer;
98   std::unique_ptr<llvm::object::Binary> BinaryExecutable;
99 
100   Error loadTargetInfo(const object::ObjectFile &Obj);
101   Error loadTargetInfo(const llvm::pdb::PDBFile &Pdb);
102 
103   void mapRangeAddress(const object::ObjectFile &Obj,
104                        const object::SectionRef &Section,
105                        bool IsComdat) override;
106 
107   llvm::object::COFFObjectFile &getObj() { return Input.obj(); }
108   llvm::pdb::PDBFile &getPdb() { return Input.pdb(); }
109   bool isObj() const { return Input.isObj(); }
110   bool isPdb() const { return Input.isPdb(); }
111   StringRef getFileName() { return Input.getFilePath(); }
112 
113   // Pathname to executable image.
114   std::string ExePath;
115 
116   LVOffset CurrentOffset = 0;
117   int32_t CurrentModule = -1;
118 
119   using RelocMapTy = DenseMap<const llvm::object::coff_section *,
120                               std::vector<llvm::object::RelocationRef>>;
121   RelocMapTy RelocMap;
122 
123   // Object files have only one type stream that contains both types and ids.
124   // Precompiled header objects don't contain an IPI stream. Use the TPI.
125   LazyRandomTypeCollection &types() {
126     return TypeServer ? TypeServer->types()
127                       : (PrecompHeader ? *PrecompHeader : Input.types());
128   }
129   LazyRandomTypeCollection &ids() {
130     return TypeServer ? TypeServer->ids()
131                       : (PrecompHeader ? *PrecompHeader : Input.ids());
132   }
133 
134   LVLogicalVisitor LogicalVisitor;
135 
136   Expected<StringRef>
137   getFileNameForFileOffset(uint32_t FileOffset,
138                            const llvm::pdb::SymbolGroup *SG = nullptr);
139   void printRelocatedField(StringRef Label,
140                            const llvm::object::coff_section *CoffSection,
141                            uint32_t RelocOffset, uint32_t Offset,
142                            StringRef *RelocSym);
143 
144   Error printFileNameForOffset(StringRef Label, uint32_t FileOffset,
145                                const llvm::pdb::SymbolGroup *SG = nullptr);
146 
147   Error loadPrecompiledObject(PrecompRecord &Precomp, CVTypeArray &CVTypesObj);
148   Error loadTypeServer(TypeServer2Record &TS);
149   Error traverseTypes(llvm::pdb::PDBFile &Pdb, LazyRandomTypeCollection &Types,
150                       LazyRandomTypeCollection &Ids);
151 
152   Error collectInlineeInfo(DebugInlineeLinesSubsectionRef &Lines,
153                            const llvm::pdb::SymbolGroup *SG = nullptr);
154 
155   void cacheRelocations();
156   Error resolveSymbol(const llvm::object::coff_section *CoffSection,
157                       uint64_t Offset, llvm::object::SymbolRef &Sym);
158   Error resolveSymbolName(const llvm::object::coff_section *CoffSection,
159                           uint64_t Offset, StringRef &Name);
160   Error traverseTypeSection(StringRef SectionName,
161                             const llvm::object::SectionRef &Section);
162   Error traverseSymbolSection(StringRef SectionName,
163                               const llvm::object::SectionRef &Section);
164   Error traverseInlineeLines(StringRef Subsection);
165 
166   DebugChecksumsSubsectionRef CVFileChecksumTable;
167   DebugStringTableSubsectionRef CVStringTable;
168 
169   Error traverseSymbolsSubsection(StringRef Subsection,
170                                   const llvm::object::SectionRef &Section,
171                                   StringRef SectionContents);
172 
173   /// Given a .debug$S section, find the string table and file checksum table.
174   /// This function taken from (COFFDumper.cpp).
175   /// TODO: It can be moved to the COFF library.
176   Error initializeFileAndStringTables(BinaryStreamReader &Reader);
177 
178   Error createLines(const FixedStreamArray<LineNumberEntry> &LineNumbers,
179                     LVAddress Addendum, uint32_t Segment, uint32_t Begin,
180                     uint32_t Size, uint32_t NameIndex,
181                     const llvm::pdb::SymbolGroup *SG = nullptr);
182   Error createScopes(llvm::object::COFFObjectFile &Obj);
183   Error createScopes(llvm::pdb::PDBFile &Pdb);
184   Error processModule();
185 
186 protected:
187   Error createScopes() override;
188   void sortScopes() override;
189 
190 public:
191   LVCodeViewReader() = delete;
192   LVCodeViewReader(StringRef Filename, StringRef FileFormatName,
193                    llvm::object::COFFObjectFile &Obj, ScopedPrinter &W,
194                    StringRef ExePath)
195       : LVBinaryReader(Filename, FileFormatName, W, LVBinaryType::COFF),
196         Input(&Obj), ExePath(ExePath), LogicalVisitor(this, W, Input) {}
197   LVCodeViewReader(StringRef Filename, StringRef FileFormatName,
198                    llvm::pdb::PDBFile &Pdb, ScopedPrinter &W, StringRef ExePath)
199       : LVBinaryReader(Filename, FileFormatName, W, LVBinaryType::COFF),
200         Input(&Pdb), ExePath(ExePath), LogicalVisitor(this, W, Input) {}
201   LVCodeViewReader(const LVCodeViewReader &) = delete;
202   LVCodeViewReader &operator=(const LVCodeViewReader &) = delete;
203   ~LVCodeViewReader() = default;
204 
205   void getLinkageName(const llvm::object::coff_section *CoffSection,
206                       uint32_t RelocOffset, uint32_t Offset,
207                       StringRef *RelocSym);
208 
209   void addModule(LVScope *Scope) { Modules.push_back(Scope); }
210   LVScope *getScopeForModule(uint32_t Modi) {
211     return Modi >= Modules.size() ? nullptr : Modules[Modi];
212   }
213 
214   // Get the string representation for the CodeView symbols.
215   static StringRef getSymbolKindName(SymbolKind Kind);
216   static std::string formatRegisterId(RegisterId Register, CPUType CPU);
217 
218   std::string getRegisterName(LVSmall Opcode,
219                               ArrayRef<uint64_t> Operands) override;
220 
221   bool isSystemEntry(LVElement *Element, StringRef Name) const override;
222 
223   void print(raw_ostream &OS) const;
224   void printRecords(raw_ostream &OS) const override {
225     LogicalVisitor.printRecords(OS);
226   };
227 
228 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
229   void dump() const { print(dbgs()); }
230 #endif
231 };
232 
233 } // end namespace logicalview
234 } // end namespace llvm
235 
236 #endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWREADER_H
237