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/Compiler.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 LLVM_ABI ~InputFile();
62 InputFile(InputFile &&Other) = default;
63
64 LLVM_ABI static Expected<InputFile> open(StringRef Path,
65 bool AllowUnknownFile = false);
66
67 LLVM_ABI PDBFile &pdb();
68 LLVM_ABI const PDBFile &pdb() const;
69 LLVM_ABI object::COFFObjectFile &obj();
70 LLVM_ABI const object::COFFObjectFile &obj() const;
71 LLVM_ABI MemoryBuffer &unknown();
72 LLVM_ABI const MemoryBuffer &unknown() const;
73
74 LLVM_ABI StringRef getFilePath() const;
75
76 LLVM_ABI bool hasTypes() const;
77 LLVM_ABI bool hasIds() const;
78
79 LLVM_ABI codeview::LazyRandomTypeCollection &types();
80 LLVM_ABI codeview::LazyRandomTypeCollection &ids();
81
82 LLVM_ABI iterator_range<SymbolGroupIterator> symbol_groups();
83 LLVM_ABI SymbolGroupIterator symbol_groups_begin();
84 LLVM_ABI SymbolGroupIterator symbol_groups_end();
85
86 LLVM_ABI bool isPdb() const;
87 LLVM_ABI bool isObj() const;
88 LLVM_ABI bool isUnknown() const;
89 };
90
91 class SymbolGroup {
92 friend class SymbolGroupIterator;
93
94 public:
95 LLVM_ABI explicit SymbolGroup(InputFile *File, uint32_t GroupIndex = 0);
96
97 LLVM_ABI Expected<StringRef> getNameFromStringTable(uint32_t Offset) const;
98 LLVM_ABI Expected<StringRef> getNameFromChecksums(uint32_t Offset) const;
99
100 LLVM_ABI void formatFromFileName(LinePrinter &Printer, StringRef File,
101 bool Append = false) const;
102
103 LLVM_ABI void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset,
104 bool Append = false) const;
105
106 LLVM_ABI StringRef name() const;
107
getDebugSubsections()108 codeview::DebugSubsectionArray getDebugSubsections() const {
109 return Subsections;
110 }
111 LLVM_ABI 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 LLVM_ABI SymbolGroupIterator();
137 LLVM_ABI explicit SymbolGroupIterator(InputFile &File);
138 SymbolGroupIterator(const SymbolGroupIterator &Other) = default;
139 SymbolGroupIterator &operator=(const SymbolGroupIterator &R) = default;
140
141 LLVM_ABI const SymbolGroup &operator*() const;
142 LLVM_ABI SymbolGroup &operator*();
143
144 LLVM_ABI bool operator==(const SymbolGroupIterator &R) const;
145 LLVM_ABI SymbolGroupIterator &operator++();
146
147 private:
148 void scanToNextDebugS();
149 bool isEnd() const;
150
151 uint32_t Index = 0;
152 std::optional<object::section_iterator> SectionIter;
153 SymbolGroup Value;
154 };
155
156 LLVM_ABI Expected<ModuleDebugStreamRef>
157 getModuleDebugStream(PDBFile &File, StringRef &ModuleName, uint32_t Index);
158 LLVM_ABI Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
159 uint32_t Index);
160
161 LLVM_ABI 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