1 | //===-- LVCodeViewVisitor.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 | // This file defines the LVCodeViewVisitor class, which is used to describe a |
10 | // debug information (CodeView) visitor. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWVISITOR_H |
15 | #define LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWVISITOR_H |
16 | |
17 | #include "llvm/ADT/iterator.h" |
18 | #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" |
19 | #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" |
20 | #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" |
21 | #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" |
22 | #include "llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h" |
23 | #include "llvm/DebugInfo/PDB/Native/InputFile.h" |
24 | #include "llvm/Object/Binary.h" |
25 | #include "llvm/Object/ObjectFile.h" |
26 | #include "llvm/Support/Error.h" |
27 | #include <stack> |
28 | #include <utility> |
29 | |
30 | namespace llvm { |
31 | namespace logicalview { |
32 | |
33 | using namespace llvm::codeview; |
34 | |
35 | class LVCodeViewReader; |
36 | class LVLogicalVisitor; |
37 | struct LVShared; |
38 | |
39 | class LVTypeVisitor final : public TypeVisitorCallbacks { |
40 | ScopedPrinter &W; |
41 | LVLogicalVisitor *LogicalVisitor; |
42 | LazyRandomTypeCollection &Types; |
43 | LazyRandomTypeCollection &Ids; |
44 | uint32_t StreamIdx; |
45 | LVShared *Shared = nullptr; |
46 | |
47 | // In a PDB, a type index may refer to a type (TPI) or an item ID (IPI). |
48 | // In a COFF or PDB (/Z7), the type index always refer to a type (TPI). |
49 | // When creating logical elements, we must access the correct element |
50 | // table, while searching for a type index. |
51 | bool HasIds = false; |
52 | |
53 | // Current type index during the types traversal. |
54 | TypeIndex CurrentTypeIndex = TypeIndex::None(); |
55 | |
56 | void printTypeIndex(StringRef FieldName, TypeIndex TI, |
57 | uint32_t StreamIdx) const; |
58 | |
59 | public: |
60 | LVTypeVisitor(ScopedPrinter &W, LVLogicalVisitor *LogicalVisitor, |
61 | LazyRandomTypeCollection &Types, LazyRandomTypeCollection &Ids, |
62 | uint32_t StreamIdx, LVShared *Shared) |
63 | : TypeVisitorCallbacks(), W(W), LogicalVisitor(LogicalVisitor), |
64 | Types(Types), Ids(Ids), StreamIdx(StreamIdx), Shared(Shared) { |
65 | HasIds = &Types != &Ids; |
66 | } |
67 | |
68 | Error visitTypeBegin(CVType &Record) override; |
69 | Error visitTypeBegin(CVType &Record, TypeIndex TI) override; |
70 | Error visitMemberBegin(CVMemberRecord &Record) override; |
71 | Error visitMemberEnd(CVMemberRecord &Record) override; |
72 | Error visitUnknownMember(CVMemberRecord &Record) override; |
73 | |
74 | Error visitKnownRecord(CVType &Record, BuildInfoRecord &Args) override; |
75 | Error visitKnownRecord(CVType &Record, ClassRecord &Class) override; |
76 | Error visitKnownRecord(CVType &Record, EnumRecord &Enum) override; |
77 | Error visitKnownRecord(CVType &Record, FuncIdRecord &Func) override; |
78 | Error visitKnownRecord(CVType &Record, ProcedureRecord &Proc) override; |
79 | Error visitKnownRecord(CVType &Record, StringIdRecord &String) override; |
80 | Error visitKnownRecord(CVType &Record, UdtSourceLineRecord &Line) override; |
81 | Error visitKnownRecord(CVType &Record, UnionRecord &Union) override; |
82 | Error visitUnknownType(CVType &Record) override; |
83 | }; |
84 | |
85 | class LVSymbolVisitorDelegate final : public SymbolVisitorDelegate { |
86 | LVCodeViewReader *Reader; |
87 | const llvm::object::coff_section *CoffSection; |
88 | StringRef SectionContents; |
89 | |
90 | public: |
91 | LVSymbolVisitorDelegate(LVCodeViewReader *Reader, |
92 | const llvm::object::SectionRef &Section, |
93 | const llvm::object::COFFObjectFile *Obj, |
94 | StringRef SectionContents) |
95 | : Reader(Reader), SectionContents(SectionContents) { |
96 | CoffSection = Obj->getCOFFSection(Section); |
97 | } |
98 | |
99 | uint32_t getRecordOffset(BinaryStreamReader Reader) override { |
100 | ArrayRef<uint8_t> Data; |
101 | if (Error Err = Reader.readLongestContiguousChunk(Buffer&: Data)) { |
102 | llvm::consumeError(Err: std::move(Err)); |
103 | return 0; |
104 | } |
105 | return Data.data() - SectionContents.bytes_begin(); |
106 | } |
107 | |
108 | void printRelocatedField(StringRef Label, uint32_t RelocOffset, |
109 | uint32_t Offset, StringRef *RelocSym = nullptr); |
110 | |
111 | void getLinkageName(uint32_t RelocOffset, uint32_t Offset, |
112 | StringRef *RelocSym = nullptr); |
113 | |
114 | StringRef getFileNameForFileOffset(uint32_t FileOffset) override; |
115 | DebugStringTableSubsectionRef getStringTable() override; |
116 | }; |
117 | |
118 | class LVElement; |
119 | class LVScope; |
120 | class LVSymbol; |
121 | class LVType; |
122 | |
123 | // Visitor for CodeView symbol streams found in COFF object files and PDB files. |
124 | class LVSymbolVisitor final : public SymbolVisitorCallbacks { |
125 | LVCodeViewReader *Reader; |
126 | ScopedPrinter &W; |
127 | LVLogicalVisitor *LogicalVisitor; |
128 | LazyRandomTypeCollection &Types; |
129 | LazyRandomTypeCollection &Ids; |
130 | LVSymbolVisitorDelegate *ObjDelegate; |
131 | LVShared *Shared; |
132 | |
133 | // Symbol offset when processing PDB streams. |
134 | uint32_t CurrentOffset = 0; |
135 | // Current object name collected from S_OBJNAME. |
136 | StringRef CurrentObjectName; |
137 | // Last symbol processed by S_LOCAL. |
138 | LVSymbol *LocalSymbol = nullptr; |
139 | |
140 | bool HasIds; |
141 | bool InFunctionScope = false; |
142 | bool IsCompileUnit = false; |
143 | |
144 | // Register for the locals and parameters symbols in the current frame. |
145 | RegisterId LocalFrameRegister = RegisterId::NONE; |
146 | RegisterId ParamFrameRegister = RegisterId::NONE; |
147 | |
148 | void printLocalVariableAddrRange(const LocalVariableAddrRange &Range, |
149 | uint32_t RelocationOffset); |
150 | void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps); |
151 | void printTypeIndex(StringRef FieldName, TypeIndex TI) const; |
152 | |
153 | // Return true if this symbol is a Compile Unit. |
154 | bool symbolIsCompileUnit(SymbolKind Kind) { |
155 | switch (Kind) { |
156 | case SymbolKind::S_COMPILE2: |
157 | case SymbolKind::S_COMPILE3: |
158 | return true; |
159 | default: |
160 | return false; |
161 | } |
162 | } |
163 | |
164 | // Determine symbol kind (local or parameter). |
165 | void determineSymbolKind(LVSymbol *Symbol, RegisterId Register) { |
166 | if (Register == LocalFrameRegister) { |
167 | Symbol->setIsVariable(); |
168 | return; |
169 | } |
170 | if (Register == ParamFrameRegister) { |
171 | Symbol->setIsParameter(); |
172 | return; |
173 | } |
174 | // Assume is a variable. |
175 | Symbol->setIsVariable(); |
176 | } |
177 | |
178 | public: |
179 | LVSymbolVisitor(LVCodeViewReader *Reader, ScopedPrinter &W, |
180 | LVLogicalVisitor *LogicalVisitor, |
181 | LazyRandomTypeCollection &Types, |
182 | LazyRandomTypeCollection &Ids, |
183 | LVSymbolVisitorDelegate *ObjDelegate, LVShared *Shared) |
184 | : Reader(Reader), W(W), LogicalVisitor(LogicalVisitor), Types(Types), |
185 | Ids(Ids), ObjDelegate(ObjDelegate), Shared(Shared) { |
186 | HasIds = &Types != &Ids; |
187 | } |
188 | |
189 | Error visitSymbolBegin(CVSymbol &Record) override; |
190 | Error visitSymbolBegin(CVSymbol &Record, uint32_t Offset) override; |
191 | Error visitSymbolEnd(CVSymbol &Record) override; |
192 | Error visitUnknownSymbol(CVSymbol &Record) override; |
193 | |
194 | Error visitKnownRecord(CVSymbol &Record, BlockSym &Block) override; |
195 | Error visitKnownRecord(CVSymbol &Record, BPRelativeSym &Local) override; |
196 | Error visitKnownRecord(CVSymbol &Record, BuildInfoSym &BuildInfo) override; |
197 | Error visitKnownRecord(CVSymbol &Record, Compile2Sym &Compile2) override; |
198 | Error visitKnownRecord(CVSymbol &Record, Compile3Sym &Compile3) override; |
199 | Error visitKnownRecord(CVSymbol &Record, ConstantSym &Constant) override; |
200 | Error visitKnownRecord(CVSymbol &Record, DataSym &Data) override; |
201 | Error visitKnownRecord(CVSymbol &Record, |
202 | DefRangeFramePointerRelFullScopeSym |
203 | &DefRangeFramePointerRelFullScope) override; |
204 | Error visitKnownRecord( |
205 | CVSymbol &Record, |
206 | DefRangeFramePointerRelSym &DefRangeFramePointerRel) override; |
207 | Error visitKnownRecord(CVSymbol &Record, |
208 | DefRangeRegisterRelSym &DefRangeRegisterRel) override; |
209 | Error visitKnownRecord(CVSymbol &Record, |
210 | DefRangeRegisterSym &DefRangeRegister) override; |
211 | Error visitKnownRecord( |
212 | CVSymbol &Record, |
213 | DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) override; |
214 | Error visitKnownRecord(CVSymbol &Record, |
215 | DefRangeSubfieldSym &DefRangeSubfield) override; |
216 | Error visitKnownRecord(CVSymbol &Record, DefRangeSym &DefRange) override; |
217 | Error visitKnownRecord(CVSymbol &Record, FrameProcSym &FrameProc) override; |
218 | Error visitKnownRecord(CVSymbol &Record, InlineSiteSym &InlineSite) override; |
219 | Error visitKnownRecord(CVSymbol &Record, LocalSym &Local) override; |
220 | Error visitKnownRecord(CVSymbol &Record, ObjNameSym &ObjName) override; |
221 | Error visitKnownRecord(CVSymbol &Record, ProcSym &Proc) override; |
222 | Error visitKnownRecord(CVSymbol &Record, RegRelativeSym &Local) override; |
223 | Error visitKnownRecord(CVSymbol &Record, ScopeEndSym &ScopeEnd) override; |
224 | Error visitKnownRecord(CVSymbol &Record, Thunk32Sym &Thunk) override; |
225 | Error visitKnownRecord(CVSymbol &Record, UDTSym &UDT) override; |
226 | Error visitKnownRecord(CVSymbol &Record, UsingNamespaceSym &UN) override; |
227 | Error visitKnownRecord(CVSymbol &Record, JumpTableSym &JumpTable) override; |
228 | Error visitKnownRecord(CVSymbol &Record, CallerSym &Caller) override; |
229 | }; |
230 | |
231 | // Visitor for CodeView types and symbols to populate elements. |
232 | class LVLogicalVisitor final { |
233 | LVCodeViewReader *Reader; |
234 | ScopedPrinter &W; |
235 | |
236 | // Encapsulates access to the input file and any dependent type server, |
237 | // including any precompiled header object. |
238 | llvm::pdb::InputFile &Input; |
239 | std::shared_ptr<llvm::pdb::InputFile> TypeServer = nullptr; |
240 | std::shared_ptr<LazyRandomTypeCollection> = nullptr; |
241 | |
242 | std::shared_ptr<LVShared> Shared; |
243 | |
244 | // Object files have only one type stream that contains both types and ids. |
245 | // Precompiled header objects don't contain an IPI stream. Use the TPI. |
246 | LazyRandomTypeCollection &types() { |
247 | return TypeServer ? TypeServer->types() |
248 | : (PrecompHeader ? *PrecompHeader : Input.types()); |
249 | } |
250 | LazyRandomTypeCollection &ids() { |
251 | return TypeServer ? TypeServer->ids() |
252 | : (PrecompHeader ? *PrecompHeader : Input.ids()); |
253 | } |
254 | |
255 | using LVScopeStack = std::stack<LVScope *>; |
256 | LVScopeStack ScopeStack; |
257 | LVScope *ReaderParent = nullptr; |
258 | LVScope *ReaderScope = nullptr; |
259 | bool InCompileUnitScope = false; |
260 | |
261 | // Allow processing of argument list. |
262 | bool ProcessArgumentList = false; |
263 | StringRef OverloadedMethodName; |
264 | std::string CompileUnitName; |
265 | |
266 | // Inlined functions source information. |
267 | using LVInlineeEntry = std::pair<uint32_t, StringRef>; |
268 | using LVInlineeInfo = std::map<TypeIndex, LVInlineeEntry>; |
269 | LVInlineeInfo InlineeInfo; |
270 | |
271 | Error visitFieldListMemberStream(TypeIndex TI, LVElement *Element, |
272 | ArrayRef<uint8_t> FieldList); |
273 | |
274 | LVType *createBaseType(TypeIndex TI, StringRef TypeName); |
275 | LVType *createPointerType(TypeIndex TI, StringRef TypeName); |
276 | LVSymbol *createParameter(TypeIndex TI, StringRef Name, LVScope *Parent); |
277 | LVSymbol *createParameter(LVElement *Element, StringRef Name, |
278 | LVScope *Parent); |
279 | void createDataMember(CVMemberRecord &Record, LVScope *Parent, StringRef Name, |
280 | TypeIndex Type, MemberAccess Access); |
281 | void createParents(StringRef ScopedName, LVElement *Element); |
282 | |
283 | public: |
284 | LVLogicalVisitor(LVCodeViewReader *Reader, ScopedPrinter &W, |
285 | llvm::pdb::InputFile &Input); |
286 | |
287 | // Current elements during the processing of a RecordType or RecordSymbol. |
288 | // They are shared with the SymbolVisitor. |
289 | LVElement *CurrentElement = nullptr; |
290 | LVScope *CurrentScope = nullptr; |
291 | LVSymbol *CurrentSymbol = nullptr; |
292 | LVType *CurrentType = nullptr; |
293 | |
294 | // Input source in the case of type server or precompiled header. |
295 | void setInput(std::shared_ptr<llvm::pdb::InputFile> TypeServer) { |
296 | this->TypeServer = TypeServer; |
297 | } |
298 | void setInput(std::shared_ptr<LazyRandomTypeCollection> ) { |
299 | this->PrecompHeader = PrecompHeader; |
300 | } |
301 | |
302 | void addInlineeInfo(TypeIndex TI, uint32_t LineNumber, StringRef Filename) { |
303 | InlineeInfo.emplace(args: std::piecewise_construct, args: std::forward_as_tuple(args&: TI), |
304 | args: std::forward_as_tuple(args&: LineNumber, args&: Filename)); |
305 | } |
306 | |
307 | void printTypeIndex(StringRef FieldName, TypeIndex TI, uint32_t StreamIdx); |
308 | void printMemberAttributes(MemberAttributes Attrs); |
309 | void printMemberAttributes(MemberAccess Access, MethodKind Kind, |
310 | MethodOptions Options); |
311 | |
312 | LVElement *createElement(TypeLeafKind Kind); |
313 | LVElement *createElement(SymbolKind Kind); |
314 | LVElement *createElement(TypeIndex TI, TypeLeafKind Kind); |
315 | |
316 | // Break down the annotation byte code and calculate code and line offsets. |
317 | Error inlineSiteAnnotation(LVScope *AbstractFunction, |
318 | LVScope *InlinedFunction, |
319 | InlineSiteSym &InlineSite); |
320 | |
321 | void pushScope(LVScope *Scope) { |
322 | ScopeStack.push(x: ReaderParent); |
323 | ReaderParent = ReaderScope; |
324 | ReaderScope = Scope; |
325 | } |
326 | void popScope() { |
327 | ReaderScope = ReaderParent; |
328 | ReaderParent = ScopeStack.top(); |
329 | ScopeStack.pop(); |
330 | } |
331 | void closeScope() { |
332 | if (InCompileUnitScope) { |
333 | InCompileUnitScope = false; |
334 | popScope(); |
335 | } |
336 | } |
337 | void setRoot(LVScope *Root) { ReaderScope = Root; } |
338 | |
339 | void addElement(LVScope *Scope, bool IsCompileUnit); |
340 | void addElement(LVSymbol *Symbol); |
341 | void addElement(LVType *Type); |
342 | |
343 | std::string getCompileUnitName() { return CompileUnitName; } |
344 | void setCompileUnitName(std::string Name) { |
345 | CompileUnitName = std::move(Name); |
346 | } |
347 | |
348 | LVElement *getElement(uint32_t StreamIdx, TypeIndex TI, |
349 | LVScope *Parent = nullptr); |
350 | LVShared *getShared() { return Shared.get(); } |
351 | |
352 | LVScope *getReaderScope() const { return ReaderScope; } |
353 | |
354 | void printTypeBegin(CVType &Record, TypeIndex TI, LVElement *Element, |
355 | uint32_t StreamIdx); |
356 | void printTypeEnd(CVType &Record); |
357 | void printMemberBegin(CVMemberRecord &Record, TypeIndex TI, |
358 | LVElement *Element, uint32_t StreamIdx); |
359 | void printMemberEnd(CVMemberRecord &Record); |
360 | |
361 | void startProcessArgumentList() { ProcessArgumentList = true; } |
362 | void stopProcessArgumentList() { ProcessArgumentList = false; } |
363 | |
364 | void processFiles(); |
365 | void processLines(); |
366 | void processNamespaces(); |
367 | |
368 | void printRecords(raw_ostream &OS) const; |
369 | |
370 | Error visitUnknownType(CVType &Record, TypeIndex TI); |
371 | Error visitKnownRecord(CVType &Record, ArgListRecord &Args, TypeIndex TI, |
372 | LVElement *Element); |
373 | Error visitKnownRecord(CVType &Record, ArrayRecord &AT, TypeIndex TI, |
374 | LVElement *Element); |
375 | Error visitKnownRecord(CVType &Record, BitFieldRecord &BF, TypeIndex TI, |
376 | LVElement *Element); |
377 | Error visitKnownRecord(CVType &Record, BuildInfoRecord &BI, TypeIndex TI, |
378 | LVElement *Element); |
379 | Error visitKnownRecord(CVType &Record, ClassRecord &Class, TypeIndex TI, |
380 | LVElement *Element); |
381 | Error visitKnownRecord(CVType &Record, EnumRecord &Enum, TypeIndex TI, |
382 | LVElement *Element); |
383 | Error visitKnownRecord(CVType &Record, FieldListRecord &FieldList, |
384 | TypeIndex TI, LVElement *Element); |
385 | Error visitKnownRecord(CVType &Record, FuncIdRecord &Func, TypeIndex TI, |
386 | LVElement *Element); |
387 | Error visitKnownRecord(CVType &Record, LabelRecord &LR, TypeIndex TI, |
388 | LVElement *Element); |
389 | Error visitKnownRecord(CVType &Record, ModifierRecord &Mod, TypeIndex TI, |
390 | LVElement *Element); |
391 | Error visitKnownRecord(CVType &Record, MemberFuncIdRecord &Id, TypeIndex TI, |
392 | LVElement *Element); |
393 | Error visitKnownRecord(CVType &Record, MemberFunctionRecord &MF, TypeIndex TI, |
394 | LVElement *Element); |
395 | Error visitKnownRecord(CVType &Record, MethodOverloadListRecord &Overloads, |
396 | TypeIndex TI, LVElement *Element); |
397 | Error visitKnownRecord(CVType &Record, PointerRecord &Ptr, TypeIndex TI, |
398 | LVElement *Element); |
399 | Error visitKnownRecord(CVType &Record, ProcedureRecord &Proc, TypeIndex TI, |
400 | LVElement *Element); |
401 | Error visitKnownRecord(CVType &Record, UnionRecord &Union, TypeIndex TI, |
402 | LVElement *Element); |
403 | Error visitKnownRecord(CVType &Record, TypeServer2Record &TS, TypeIndex TI, |
404 | LVElement *Element); |
405 | Error visitKnownRecord(CVType &Record, VFTableRecord &VFT, TypeIndex TI, |
406 | LVElement *Element); |
407 | Error visitKnownRecord(CVType &Record, VFTableShapeRecord &Shape, |
408 | TypeIndex TI, LVElement *Element); |
409 | Error visitKnownRecord(CVType &Record, StringListRecord &Strings, |
410 | TypeIndex TI, LVElement *Element); |
411 | Error visitKnownRecord(CVType &Record, StringIdRecord &String, TypeIndex TI, |
412 | LVElement *Element); |
413 | Error visitKnownRecord(CVType &Record, UdtSourceLineRecord &SourceLine, |
414 | TypeIndex TI, LVElement *Element); |
415 | Error visitKnownRecord(CVType &Record, UdtModSourceLineRecord &ModSourceLine, |
416 | TypeIndex TI, LVElement *Element); |
417 | Error visitKnownRecord(CVType &Record, PrecompRecord &Precomp, TypeIndex TI, |
418 | LVElement *Element); |
419 | Error visitKnownRecord(CVType &Record, EndPrecompRecord &EndPrecomp, |
420 | TypeIndex TI, LVElement *Element); |
421 | |
422 | Error visitUnknownMember(CVMemberRecord &Record, TypeIndex TI); |
423 | Error visitKnownMember(CVMemberRecord &Record, BaseClassRecord &Base, |
424 | TypeIndex TI, LVElement *Element); |
425 | Error visitKnownMember(CVMemberRecord &Record, DataMemberRecord &Field, |
426 | TypeIndex TI, LVElement *Element); |
427 | Error visitKnownMember(CVMemberRecord &Record, EnumeratorRecord &Enum, |
428 | TypeIndex TI, LVElement *Element); |
429 | Error visitKnownMember(CVMemberRecord &Record, ListContinuationRecord &Cont, |
430 | TypeIndex TI, LVElement *Element); |
431 | Error visitKnownMember(CVMemberRecord &Record, NestedTypeRecord &Nested, |
432 | TypeIndex TI, LVElement *Element); |
433 | Error visitKnownMember(CVMemberRecord &Record, OneMethodRecord &Method, |
434 | TypeIndex TI, LVElement *Element); |
435 | Error visitKnownMember(CVMemberRecord &Record, OverloadedMethodRecord &Method, |
436 | TypeIndex TI, LVElement *Element); |
437 | Error visitKnownMember(CVMemberRecord &Record, StaticDataMemberRecord &Field, |
438 | TypeIndex TI, LVElement *Element); |
439 | Error visitKnownMember(CVMemberRecord &Record, VFPtrRecord &VFTable, |
440 | TypeIndex TI, LVElement *Element); |
441 | Error visitKnownMember(CVMemberRecord &Record, VirtualBaseClassRecord &Base, |
442 | TypeIndex TI, LVElement *Element); |
443 | |
444 | template <typename T> |
445 | Error visitKnownMember(CVMemberRecord &Record, |
446 | TypeVisitorCallbacks &Callbacks, TypeIndex TI, |
447 | LVElement *Element) { |
448 | TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind); |
449 | T KnownRecord(RK); |
450 | if (Error Err = Callbacks.visitKnownMember(Record, KnownRecord)) |
451 | return Err; |
452 | if (Error Err = visitKnownMember(Record, KnownRecord, TI, Element)) |
453 | return Err; |
454 | return Error::success(); |
455 | } |
456 | |
457 | template <typename T> |
458 | Error visitKnownRecord(CVType &Record, TypeIndex TI, LVElement *Element) { |
459 | TypeRecordKind RK = static_cast<TypeRecordKind>(Record.kind()); |
460 | T KnownRecord(RK); |
461 | if (Error Err = TypeDeserializer::deserializeAs( |
462 | const_cast<CVType &>(Record), KnownRecord)) |
463 | return Err; |
464 | if (Error Err = visitKnownRecord(Record, KnownRecord, TI, Element)) |
465 | return Err; |
466 | return Error::success(); |
467 | } |
468 | |
469 | Error visitMemberRecord(CVMemberRecord &Record, |
470 | TypeVisitorCallbacks &Callbacks, TypeIndex TI, |
471 | LVElement *Element); |
472 | Error finishVisitation(CVType &Record, TypeIndex TI, LVElement *Element); |
473 | }; |
474 | |
475 | } // namespace logicalview |
476 | } // namespace llvm |
477 | |
478 | #endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_CODEVIEWVISITOR_H |
479 | |