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/TypeServerHandler.h"
18 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
19 #include "llvm/Support/BinaryByteStream.h"
20 #include "llvm/Support/BinaryStreamReader.h"
23 using namespace llvm::codeview;
27 static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
28 TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Type);
30 if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
32 return Error::success();
36 static Error visitKnownMember(CVMemberRecord &Record,
37 TypeVisitorCallbacks &Callbacks) {
38 TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind);
40 if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord))
42 return Error::success();
45 static Expected<TypeServer2Record> deserializeTypeServerRecord(CVType &Record) {
46 TypeServer2Record R(TypeRecordKind::TypeServer2);
47 if (auto EC = TypeDeserializer::deserializeAs(Record, R))
52 static Error visitMemberRecord(CVMemberRecord &Record,
53 TypeVisitorCallbacks &Callbacks) {
54 if (auto EC = Callbacks.visitMemberBegin(Record))
57 switch (Record.Kind) {
59 if (auto EC = Callbacks.visitUnknownMember(Record))
62 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
64 if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
68 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
69 MEMBER_RECORD(EnumVal, EnumVal, AliasName)
70 #define TYPE_RECORD(EnumName, EnumVal, Name)
71 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
72 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
75 if (auto EC = Callbacks.visitMemberEnd(Record))
78 return Error::success();
85 explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
87 void addTypeServerHandler(TypeServerHandler &Handler);
89 Error visitTypeRecord(CVType &Record, TypeIndex Index);
90 Error visitTypeRecord(CVType &Record);
92 /// Visits the type records in Data. Sets the error flag on parse failures.
93 Error visitTypeStream(const CVTypeArray &Types);
94 Error visitTypeStream(CVTypeRange Types);
95 Error visitTypeStream(TypeCollection &Types);
97 Error visitMemberRecord(CVMemberRecord Record);
98 Error visitFieldListMemberStream(BinaryStreamReader &Stream);
101 Expected<bool> handleTypeServer(CVType &Record);
102 Error finishVisitation(CVType &Record);
104 /// The interface to the class that gets notified of each visitation.
105 TypeVisitorCallbacks &Callbacks;
107 TinyPtrVector<TypeServerHandler *> Handlers;
110 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
111 : Callbacks(Callbacks) {}
113 void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) {
114 Handlers.push_back(&Handler);
117 Expected<bool> CVTypeVisitor::handleTypeServer(CVType &Record) {
118 if (Record.Type == TypeLeafKind::LF_TYPESERVER2 && !Handlers.empty()) {
119 auto TS = deserializeTypeServerRecord(Record);
121 return TS.takeError();
123 for (auto Handler : Handlers) {
124 auto ExpectedResult = Handler->handle(*TS, Callbacks);
125 // If there was an error, return the error.
127 return ExpectedResult.takeError();
129 // If the handler processed the record, return success.
133 // Otherwise keep searching for a handler, eventually falling out and
134 // using the default record handler.
140 Error CVTypeVisitor::finishVisitation(CVType &Record) {
141 switch (Record.Type) {
143 if (auto EC = Callbacks.visitUnknownType(Record))
146 #define TYPE_RECORD(EnumName, EnumVal, Name) \
148 if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
152 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
153 TYPE_RECORD(EnumVal, EnumVal, AliasName)
154 #define MEMBER_RECORD(EnumName, EnumVal, Name)
155 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
156 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
159 if (auto EC = Callbacks.visitTypeEnd(Record))
162 return Error::success();
165 Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
166 auto ExpectedResult = handleTypeServer(Record);
168 return ExpectedResult.takeError();
170 return Error::success();
172 if (auto EC = Callbacks.visitTypeBegin(Record, Index))
175 return finishVisitation(Record);
178 Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
179 auto ExpectedResult = handleTypeServer(Record);
181 return ExpectedResult.takeError();
183 return Error::success();
185 if (auto EC = Callbacks.visitTypeBegin(Record))
188 return finishVisitation(Record);
191 Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
192 return ::visitMemberRecord(Record, Callbacks);
195 /// Visits the type records in Data. Sets the error flag on parse failures.
196 Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
197 for (auto I : Types) {
198 if (auto EC = visitTypeRecord(I))
201 return Error::success();
204 Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
205 for (auto I : Types) {
206 if (auto EC = visitTypeRecord(I))
209 return Error::success();
212 Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
213 Optional<TypeIndex> I = Types.getFirst();
215 CVType Type = Types.getType(*I);
216 if (auto EC = visitTypeRecord(Type, *I))
218 I = Types.getNext(*I);
220 return Error::success();
223 Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
225 while (!Reader.empty()) {
226 if (auto EC = Reader.readEnum(Leaf))
229 CVMemberRecord Record;
231 if (auto EC = ::visitMemberRecord(Record, Callbacks))
235 return Error::success();
238 struct FieldListVisitHelper {
239 FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
240 VisitorDataSource Source)
241 : Stream(Data, llvm::support::little), Reader(Stream),
242 Deserializer(Reader),
243 Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
244 if (Source == VDS_BytesPresent) {
245 Pipeline.addCallbackToPipeline(Deserializer);
246 Pipeline.addCallbackToPipeline(Callbacks);
250 BinaryByteStream Stream;
251 BinaryStreamReader Reader;
252 FieldListDeserializer Deserializer;
253 TypeVisitorCallbackPipeline Pipeline;
254 CVTypeVisitor Visitor;
258 VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
259 : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
260 if (Source == VDS_BytesPresent) {
261 Pipeline.addCallbackToPipeline(Deserializer);
262 Pipeline.addCallbackToPipeline(Callbacks);
266 TypeDeserializer Deserializer;
267 TypeVisitorCallbackPipeline Pipeline;
268 CVTypeVisitor Visitor;
272 Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
273 TypeVisitorCallbacks &Callbacks,
274 VisitorDataSource Source,
275 TypeServerHandler *TS) {
276 VisitHelper V(Callbacks, Source);
278 V.Visitor.addTypeServerHandler(*TS);
279 return V.Visitor.visitTypeRecord(Record, Index);
282 Error llvm::codeview::visitTypeRecord(CVType &Record,
283 TypeVisitorCallbacks &Callbacks,
284 VisitorDataSource Source,
285 TypeServerHandler *TS) {
286 VisitHelper V(Callbacks, Source);
288 V.Visitor.addTypeServerHandler(*TS);
289 return V.Visitor.visitTypeRecord(Record);
292 Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
293 TypeVisitorCallbacks &Callbacks,
294 VisitorDataSource Source,
295 TypeServerHandler *TS) {
296 VisitHelper V(Callbacks, Source);
298 V.Visitor.addTypeServerHandler(*TS);
299 return V.Visitor.visitTypeStream(Types);
302 Error llvm::codeview::visitTypeStream(CVTypeRange Types,
303 TypeVisitorCallbacks &Callbacks,
304 TypeServerHandler *TS) {
305 VisitHelper V(Callbacks, VDS_BytesPresent);
307 V.Visitor.addTypeServerHandler(*TS);
308 return V.Visitor.visitTypeStream(Types);
311 Error llvm::codeview::visitTypeStream(TypeCollection &Types,
312 TypeVisitorCallbacks &Callbacks,
313 TypeServerHandler *TS) {
314 // When the internal visitor calls Types.getType(Index) the interface is
315 // required to return a CVType with the bytes filled out. So we can assume
316 // that the bytes will be present when individual records are visited.
317 VisitHelper V(Callbacks, VDS_BytesPresent);
319 V.Visitor.addTypeServerHandler(*TS);
320 return V.Visitor.visitTypeStream(Types);
323 Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
324 TypeVisitorCallbacks &Callbacks,
325 VisitorDataSource Source) {
326 FieldListVisitHelper V(Callbacks, Record.Data, Source);
327 return V.Visitor.visitMemberRecord(Record);
330 Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
331 ArrayRef<uint8_t> Record,
332 TypeVisitorCallbacks &Callbacks) {
336 return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
339 Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
340 TypeVisitorCallbacks &Callbacks) {
341 FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
342 return V.Visitor.visitFieldListMemberStream(V.Reader);