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:
InputFile(PDBFile * Pdb)58 InputFile(PDBFile *Pdb) { PdbOrObj = Pdb; }
InputFile(object::COFFObjectFile * Obj)59 InputFile(object::COFFObjectFile *Obj) { PdbOrObj = Obj; }
InputFile(MemoryBuffer * Buffer)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
getDebugSubsections()108 codeview::DebugSubsectionArray getDebugSubsections() const {
109 return Subsections;
110 }
111 const ModuleDebugStreamRef &getPdbModuleStream() const;
112
getFile()113 const InputFile &getFile() const { return *File; }
getFile()114 InputFile &getFile() { return *File; }
115
hasDebugStream()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>
iterateOneModule(InputFile & File,const PrintScope & HeaderScope,const SymbolGroup & SG,uint32_t Modi,CallbackT Callback)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>
iterateSymbolGroups(InputFile & Input,const PrintScope & HeaderScope,CallbackT Callback)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>
iterateModuleSubsections(InputFile & File,const PrintScope & HeaderScope,llvm::function_ref<Error (uint32_t,const SymbolGroup &,SubsectionT &)> Callback)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