1 //===- InputFile.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 #ifndef LLVM_DEBUGINFO_PDB_NATIVE_INPUTFILE_H
10 #define LLVM_DEBUGINFO_PDB_NATIVE_INPUTFILE_H
11 
12 #include "llvm/ADT/Optional.h"
13 #include "llvm/ADT/PointerUnion.h"
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/ADT/iterator.h"
16 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
17 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
18 #include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
19 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
20 #include "llvm/Object/Binary.h"
21 #include "llvm/Object/ObjectFile.h"
22 #include "llvm/Support/Error.h"
23 
24 namespace llvm {
25 namespace codeview {
26 class LazyRandomTypeCollection;
27 }
28 namespace object {
29 class COFFObjectFile;
30 } // namespace object
31 
32 namespace pdb {
33 class InputFile;
34 class LinePrinter;
35 class PDBFile;
36 class NativeSession;
37 class SymbolGroupIterator;
38 class SymbolGroup;
39 
40 class InputFile {
41   InputFile();
42 
43   std::unique_ptr<NativeSession> PdbSession;
44   object::OwningBinary<object::Binary> CoffObject;
45   std::unique_ptr<MemoryBuffer> UnknownFile;
46   PointerUnion<PDBFile *, object::COFFObjectFile *, MemoryBuffer *> PdbOrObj;
47 
48   using TypeCollectionPtr = std::unique_ptr<codeview::LazyRandomTypeCollection>;
49 
50   TypeCollectionPtr Types;
51   TypeCollectionPtr Ids;
52 
53   enum TypeCollectionKind { kTypes, kIds };
54   codeview::LazyRandomTypeCollection &
55   getOrCreateTypeCollection(TypeCollectionKind Kind);
56 
57 public:
58   InputFile(PDBFile *Pdb) { PdbOrObj = Pdb; }
59   InputFile(object::COFFObjectFile *Obj) { PdbOrObj = Obj; }
60   InputFile(MemoryBuffer *Buffer) { PdbOrObj = Buffer; }
61   ~InputFile();
62   InputFile(InputFile &&Other) = default;
63 
64   static Expected<InputFile> open(StringRef Path,
65                                   bool AllowUnknownFile = false);
66 
67   PDBFile &pdb();
68   const PDBFile &pdb() const;
69   object::COFFObjectFile &obj();
70   const object::COFFObjectFile &obj() const;
71   MemoryBuffer &unknown();
72   const MemoryBuffer &unknown() const;
73 
74   StringRef getFilePath() const;
75 
76   bool hasTypes() const;
77   bool hasIds() const;
78 
79   codeview::LazyRandomTypeCollection &types();
80   codeview::LazyRandomTypeCollection &ids();
81 
82   iterator_range<SymbolGroupIterator> symbol_groups();
83   SymbolGroupIterator symbol_groups_begin();
84   SymbolGroupIterator symbol_groups_end();
85 
86   bool isPdb() const;
87   bool isObj() const;
88   bool isUnknown() const;
89 };
90 
91 class SymbolGroup {
92   friend class SymbolGroupIterator;
93 
94 public:
95   explicit SymbolGroup(InputFile *File, uint32_t GroupIndex = 0);
96 
97   Expected<StringRef> getNameFromStringTable(uint32_t Offset) const;
98   Expected<StringRef> getNameFromChecksums(uint32_t Offset) const;
99 
100   void formatFromFileName(LinePrinter &Printer, StringRef File,
101                           bool Append = false) const;
102 
103   void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset,
104                                  bool Append = false) const;
105 
106   StringRef name() const;
107 
108   codeview::DebugSubsectionArray getDebugSubsections() const {
109     return Subsections;
110   }
111   const ModuleDebugStreamRef &getPdbModuleStream() const;
112 
113   const InputFile &getFile() const { return *File; }
114   InputFile &getFile() { return *File; }
115 
116   bool hasDebugStream() const { return DebugStream != nullptr; }
117 
118 private:
119   void initializeForPdb(uint32_t Modi);
120   void updatePdbModi(uint32_t Modi);
121   void updateDebugS(const codeview::DebugSubsectionArray &SS);
122 
123   void rebuildChecksumMap();
124   InputFile *File = nullptr;
125   StringRef Name;
126   codeview::DebugSubsectionArray Subsections;
127   std::shared_ptr<ModuleDebugStreamRef> DebugStream;
128   codeview::StringsAndChecksumsRef SC;
129   StringMap<codeview::FileChecksumEntry> ChecksumsByFile;
130 };
131 
132 class SymbolGroupIterator
133     : public iterator_facade_base<SymbolGroupIterator,
134                                   std::forward_iterator_tag, SymbolGroup> {
135 public:
136   SymbolGroupIterator();
137   explicit SymbolGroupIterator(InputFile &File);
138   SymbolGroupIterator(const SymbolGroupIterator &Other) = default;
139   SymbolGroupIterator &operator=(const SymbolGroupIterator &R) = default;
140 
141   const SymbolGroup &operator*() const;
142   SymbolGroup &operator*();
143 
144   bool operator==(const SymbolGroupIterator &R) const;
145   SymbolGroupIterator &operator++();
146 
147 private:
148   void scanToNextDebugS();
149   bool isEnd() const;
150 
151   uint32_t Index = 0;
152   Optional<object::section_iterator> SectionIter;
153   SymbolGroup Value;
154 };
155 
156 Expected<ModuleDebugStreamRef>
157 getModuleDebugStream(PDBFile &File, StringRef &ModuleName, uint32_t Index);
158 Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
159                                                     uint32_t Index);
160 
161 bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group,
162                            const FilterOptions &Filters);
163 
164 // TODO: Change these callbacks to be function_refs (de-templatify them).
165 template <typename CallbackT>
166 Error iterateOneModule(InputFile &File, const PrintScope &HeaderScope,
167                        const SymbolGroup &SG, uint32_t Modi,
168                        CallbackT Callback) {
169   HeaderScope.P.formatLine(
170       "Mod {0:4} | `{1}`: ",
171       fmt_align(Modi, AlignStyle::Right, HeaderScope.LabelWidth), SG.name());
172 
173   AutoIndent Indent(HeaderScope);
174   return Callback(Modi, SG);
175 }
176 
177 template <typename CallbackT>
178 Error iterateSymbolGroups(InputFile &Input, const PrintScope &HeaderScope,
179                           CallbackT Callback) {
180   AutoIndent Indent(HeaderScope);
181 
182   FilterOptions Filters = HeaderScope.P.getFilters();
183   if (Filters.DumpModi) {
184     uint32_t Modi = *Filters.DumpModi;
185     SymbolGroup SG(&Input, Modi);
186     return iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)),
187                             SG, Modi, Callback);
188   }
189 
190   uint32_t I = 0;
191 
192   for (const auto &SG : Input.symbol_groups()) {
193     if (shouldDumpSymbolGroup(I, SG, Filters))
194       if (auto Err =
195               iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)),
196                                SG, I, Callback))
197         return Err;
198 
199     ++I;
200   }
201   return Error::success();
202 }
203 
204 template <typename SubsectionT>
205 Error iterateModuleSubsections(
206     InputFile &File, const PrintScope &HeaderScope,
207     llvm::function_ref<Error(uint32_t, const SymbolGroup &, SubsectionT &)>
208         Callback) {
209 
210   return iterateSymbolGroups(
211       File, HeaderScope, [&](uint32_t Modi, const SymbolGroup &SG) -> Error {
212         for (const auto &SS : SG.getDebugSubsections()) {
213           SubsectionT Subsection;
214 
215           if (SS.kind() != Subsection.kind())
216             continue;
217 
218           BinaryStreamReader Reader(SS.getRecordData());
219           if (auto Err = Subsection.initialize(Reader))
220             continue;
221           if (auto Err = Callback(Modi, SG, Subsection))
222             return Err;
223         }
224         return Error::success();
225       });
226 }
227 
228 } // namespace pdb
229 } // namespace llvm
230 
231 #endif
232