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