1 //===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
12 #include "llvm/ADT/TinyPtrVector.h"
13 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
14 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
15 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
16 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
17 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
18 #include "llvm/Support/BinaryByteStream.h"
19 #include "llvm/Support/BinaryStreamReader.h"
22 using namespace llvm::codeview;
26 static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
27 TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Type);
29 if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
31 return Error::success();
35 static Error visitKnownMember(CVMemberRecord &Record,
36 TypeVisitorCallbacks &Callbacks) {
37 TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind);
39 if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord))
41 return Error::success();
44 static Error visitMemberRecord(CVMemberRecord &Record,
45 TypeVisitorCallbacks &Callbacks) {
46 if (auto EC = Callbacks.visitMemberBegin(Record))
49 switch (Record.Kind) {
51 if (auto EC = Callbacks.visitUnknownMember(Record))
54 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
56 if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
60 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
61 MEMBER_RECORD(EnumVal, EnumVal, AliasName)
62 #define TYPE_RECORD(EnumName, EnumVal, Name)
63 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
64 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
67 if (auto EC = Callbacks.visitMemberEnd(Record))
70 return Error::success();
77 explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
79 Error visitTypeRecord(CVType &Record, TypeIndex Index);
80 Error visitTypeRecord(CVType &Record);
82 /// Visits the type records in Data. Sets the error flag on parse failures.
83 Error visitTypeStream(const CVTypeArray &Types);
84 Error visitTypeStream(CVTypeRange Types);
85 Error visitTypeStream(TypeCollection &Types);
87 Error visitMemberRecord(CVMemberRecord Record);
88 Error visitFieldListMemberStream(BinaryStreamReader &Stream);
91 Error finishVisitation(CVType &Record);
93 /// The interface to the class that gets notified of each visitation.
94 TypeVisitorCallbacks &Callbacks;
97 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
98 : Callbacks(Callbacks) {}
100 Error CVTypeVisitor::finishVisitation(CVType &Record) {
101 switch (Record.Type) {
103 if (auto EC = Callbacks.visitUnknownType(Record))
106 #define TYPE_RECORD(EnumName, EnumVal, Name) \
108 if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
112 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
113 TYPE_RECORD(EnumVal, EnumVal, AliasName)
114 #define MEMBER_RECORD(EnumName, EnumVal, Name)
115 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
116 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
119 if (auto EC = Callbacks.visitTypeEnd(Record))
122 return Error::success();
125 Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
126 if (auto EC = Callbacks.visitTypeBegin(Record, Index))
129 return finishVisitation(Record);
132 Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
133 if (auto EC = Callbacks.visitTypeBegin(Record))
136 return finishVisitation(Record);
139 Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
140 return ::visitMemberRecord(Record, Callbacks);
143 /// Visits the type records in Data. Sets the error flag on parse failures.
144 Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
145 for (auto I : Types) {
146 if (auto EC = visitTypeRecord(I))
149 return Error::success();
152 Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
153 for (auto I : Types) {
154 if (auto EC = visitTypeRecord(I))
157 return Error::success();
160 Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
161 Optional<TypeIndex> I = Types.getFirst();
163 CVType Type = Types.getType(*I);
164 if (auto EC = visitTypeRecord(Type, *I))
166 I = Types.getNext(*I);
168 return Error::success();
171 Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
173 while (!Reader.empty()) {
174 if (auto EC = Reader.readEnum(Leaf))
177 CVMemberRecord Record;
179 if (auto EC = ::visitMemberRecord(Record, Callbacks))
183 return Error::success();
186 struct FieldListVisitHelper {
187 FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
188 VisitorDataSource Source)
189 : Stream(Data, llvm::support::little), Reader(Stream),
190 Deserializer(Reader),
191 Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
192 if (Source == VDS_BytesPresent) {
193 Pipeline.addCallbackToPipeline(Deserializer);
194 Pipeline.addCallbackToPipeline(Callbacks);
198 BinaryByteStream Stream;
199 BinaryStreamReader Reader;
200 FieldListDeserializer Deserializer;
201 TypeVisitorCallbackPipeline Pipeline;
202 CVTypeVisitor Visitor;
206 VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
207 : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
208 if (Source == VDS_BytesPresent) {
209 Pipeline.addCallbackToPipeline(Deserializer);
210 Pipeline.addCallbackToPipeline(Callbacks);
214 TypeDeserializer Deserializer;
215 TypeVisitorCallbackPipeline Pipeline;
216 CVTypeVisitor Visitor;
220 Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
221 TypeVisitorCallbacks &Callbacks,
222 VisitorDataSource Source) {
223 VisitHelper V(Callbacks, Source);
224 return V.Visitor.visitTypeRecord(Record, Index);
227 Error llvm::codeview::visitTypeRecord(CVType &Record,
228 TypeVisitorCallbacks &Callbacks,
229 VisitorDataSource Source) {
230 VisitHelper V(Callbacks, Source);
231 return V.Visitor.visitTypeRecord(Record);
234 Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
235 TypeVisitorCallbacks &Callbacks,
236 VisitorDataSource Source) {
237 VisitHelper V(Callbacks, Source);
238 return V.Visitor.visitTypeStream(Types);
241 Error llvm::codeview::visitTypeStream(CVTypeRange Types,
242 TypeVisitorCallbacks &Callbacks) {
243 VisitHelper V(Callbacks, VDS_BytesPresent);
244 return V.Visitor.visitTypeStream(Types);
247 Error llvm::codeview::visitTypeStream(TypeCollection &Types,
248 TypeVisitorCallbacks &Callbacks) {
249 // When the internal visitor calls Types.getType(Index) the interface is
250 // required to return a CVType with the bytes filled out. So we can assume
251 // that the bytes will be present when individual records are visited.
252 VisitHelper V(Callbacks, VDS_BytesPresent);
253 return V.Visitor.visitTypeStream(Types);
256 Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
257 TypeVisitorCallbacks &Callbacks,
258 VisitorDataSource Source) {
259 FieldListVisitHelper V(Callbacks, Record.Data, Source);
260 return V.Visitor.visitMemberRecord(Record);
263 Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
264 ArrayRef<uint8_t> Record,
265 TypeVisitorCallbacks &Callbacks) {
269 return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
272 Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
273 TypeVisitorCallbacks &Callbacks) {
274 FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
275 return V.Visitor.visitFieldListMemberStream(V.Reader);