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: |
57 | InputFile(PDBFile *Pdb) { PdbOrObj = Pdb; } |
58 | InputFile(object::COFFObjectFile *Obj) { PdbOrObj = Obj; } |
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 | |
107 | codeview::DebugSubsectionArray getDebugSubsections() const { |
108 | return Subsections; |
109 | } |
110 | const ModuleDebugStreamRef &getPdbModuleStream() const; |
111 | |
112 | const InputFile &getFile() const { return *File; } |
113 | InputFile &getFile() { return *File; } |
114 | |
115 | bool hasDebugStream() const { return DebugStream != nullptr; } |
116 | |
117 | private: |
118 | void initializeForPdb(uint32_t Modi); |
119 | void updatePdbModi(uint32_t Modi); |
120 | void (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> |
165 | Error iterateOneModule(InputFile &File, const PrintScope &, |
166 | const SymbolGroup &SG, uint32_t Modi, |
167 | CallbackT Callback) { |
168 | HeaderScope.P.formatLine( |
169 | Fmt: "Mod {0:4} | `{1}`: " , |
170 | Items: fmt_align(Item&: Modi, Where: AlignStyle::Right, Amount: HeaderScope.LabelWidth), Items: SG.name()); |
171 | |
172 | AutoIndent Indent(HeaderScope); |
173 | return Callback(Modi, SG); |
174 | } |
175 | |
176 | template <typename CallbackT> |
177 | Error iterateSymbolGroups(InputFile &Input, const PrintScope &, |
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(Scope: HeaderScope, W: NumDigits(N: Modi)), |
186 | SG, Modi, Callback); |
187 | } |
188 | |
189 | uint32_t I = 0; |
190 | |
191 | for (const auto &SG : Input.symbol_groups()) { |
192 | if (shouldDumpSymbolGroup(Idx: I, Group: SG, Filters)) |
193 | if (auto Err = |
194 | iterateOneModule(Input, withLabelWidth(Scope: HeaderScope, W: NumDigits(N: I)), |
195 | SG, I, Callback)) |
196 | return Err; |
197 | |
198 | ++I; |
199 | } |
200 | return Error::success(); |
201 | } |
202 | |
203 | template <typename SubsectionT> |
204 | Error iterateModuleSubsections( |
205 | InputFile &File, const PrintScope &, |
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 | |