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/DebugInfo/CodeView/CodeViewError.h"
13 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
14 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
15 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
16 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
17 #include "llvm/Support/BinaryByteStream.h"
18 #include "llvm/Support/BinaryStreamReader.h"
21 using namespace llvm::codeview
;
25 static Error
visitKnownRecord(CVType
&Record
, TypeVisitorCallbacks
&Callbacks
) {
26 TypeRecordKind RK
= static_cast<TypeRecordKind
>(Record
.Type
);
28 if (auto EC
= Callbacks
.visitKnownRecord(Record
, KnownRecord
))
30 return Error::success();
34 static Error
visitKnownMember(CVMemberRecord
&Record
,
35 TypeVisitorCallbacks
&Callbacks
) {
36 TypeRecordKind RK
= static_cast<TypeRecordKind
>(Record
.Kind
);
38 if (auto EC
= Callbacks
.visitKnownMember(Record
, KnownRecord
))
40 return Error::success();
43 static Error
visitMemberRecord(CVMemberRecord
&Record
,
44 TypeVisitorCallbacks
&Callbacks
) {
45 if (auto EC
= Callbacks
.visitMemberBegin(Record
))
48 switch (Record
.Kind
) {
50 if (auto EC
= Callbacks
.visitUnknownMember(Record
))
53 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
55 if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
59 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
60 MEMBER_RECORD(EnumVal, EnumVal, AliasName)
61 #define TYPE_RECORD(EnumName, EnumVal, Name)
62 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
63 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
66 if (auto EC
= Callbacks
.visitMemberEnd(Record
))
69 return Error::success();
76 explicit CVTypeVisitor(TypeVisitorCallbacks
&Callbacks
);
78 Error
visitTypeRecord(CVType
&Record
, TypeIndex Index
);
79 Error
visitTypeRecord(CVType
&Record
);
81 /// Visits the type records in Data. Sets the error flag on parse failures.
82 Error
visitTypeStream(const CVTypeArray
&Types
);
83 Error
visitTypeStream(CVTypeRange Types
);
84 Error
visitTypeStream(TypeCollection
&Types
);
86 Error
visitMemberRecord(CVMemberRecord Record
);
87 Error
visitFieldListMemberStream(BinaryStreamReader
&Stream
);
90 Error
finishVisitation(CVType
&Record
);
92 /// The interface to the class that gets notified of each visitation.
93 TypeVisitorCallbacks
&Callbacks
;
96 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks
&Callbacks
)
97 : Callbacks(Callbacks
) {}
99 Error
CVTypeVisitor::finishVisitation(CVType
&Record
) {
100 switch (Record
.Type
) {
102 if (auto EC
= Callbacks
.visitUnknownType(Record
))
105 #define TYPE_RECORD(EnumName, EnumVal, Name) \
107 if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
111 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
112 TYPE_RECORD(EnumVal, EnumVal, AliasName)
113 #define MEMBER_RECORD(EnumName, EnumVal, Name)
114 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
115 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
118 if (auto EC
= Callbacks
.visitTypeEnd(Record
))
121 return Error::success();
124 Error
CVTypeVisitor::visitTypeRecord(CVType
&Record
, TypeIndex Index
) {
125 if (auto EC
= Callbacks
.visitTypeBegin(Record
, Index
))
128 return finishVisitation(Record
);
131 Error
CVTypeVisitor::visitTypeRecord(CVType
&Record
) {
132 if (auto EC
= Callbacks
.visitTypeBegin(Record
))
135 return finishVisitation(Record
);
138 Error
CVTypeVisitor::visitMemberRecord(CVMemberRecord Record
) {
139 return ::visitMemberRecord(Record
, Callbacks
);
142 /// Visits the type records in Data. Sets the error flag on parse failures.
143 Error
CVTypeVisitor::visitTypeStream(const CVTypeArray
&Types
) {
144 for (auto I
: Types
) {
145 if (auto EC
= visitTypeRecord(I
))
148 return Error::success();
151 Error
CVTypeVisitor::visitTypeStream(CVTypeRange Types
) {
152 for (auto I
: Types
) {
153 if (auto EC
= visitTypeRecord(I
))
156 return Error::success();
159 Error
CVTypeVisitor::visitTypeStream(TypeCollection
&Types
) {
160 Optional
<TypeIndex
> I
= Types
.getFirst();
162 CVType Type
= Types
.getType(*I
);
163 if (auto EC
= visitTypeRecord(Type
, *I
))
165 I
= Types
.getNext(*I
);
167 return Error::success();
170 Error
CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader
&Reader
) {
172 while (!Reader
.empty()) {
173 if (auto EC
= Reader
.readEnum(Leaf
))
176 CVMemberRecord Record
;
178 if (auto EC
= ::visitMemberRecord(Record
, Callbacks
))
182 return Error::success();
185 struct FieldListVisitHelper
{
186 FieldListVisitHelper(TypeVisitorCallbacks
&Callbacks
, ArrayRef
<uint8_t> Data
,
187 VisitorDataSource Source
)
188 : Stream(Data
, llvm::support::little
), Reader(Stream
),
189 Deserializer(Reader
),
190 Visitor((Source
== VDS_BytesPresent
) ? Pipeline
: Callbacks
) {
191 if (Source
== VDS_BytesPresent
) {
192 Pipeline
.addCallbackToPipeline(Deserializer
);
193 Pipeline
.addCallbackToPipeline(Callbacks
);
197 BinaryByteStream Stream
;
198 BinaryStreamReader Reader
;
199 FieldListDeserializer Deserializer
;
200 TypeVisitorCallbackPipeline Pipeline
;
201 CVTypeVisitor Visitor
;
205 VisitHelper(TypeVisitorCallbacks
&Callbacks
, VisitorDataSource Source
)
206 : Visitor((Source
== VDS_BytesPresent
) ? Pipeline
: Callbacks
) {
207 if (Source
== VDS_BytesPresent
) {
208 Pipeline
.addCallbackToPipeline(Deserializer
);
209 Pipeline
.addCallbackToPipeline(Callbacks
);
213 TypeDeserializer Deserializer
;
214 TypeVisitorCallbackPipeline Pipeline
;
215 CVTypeVisitor Visitor
;
219 Error
llvm::codeview::visitTypeRecord(CVType
&Record
, TypeIndex Index
,
220 TypeVisitorCallbacks
&Callbacks
,
221 VisitorDataSource Source
) {
222 VisitHelper
V(Callbacks
, Source
);
223 return V
.Visitor
.visitTypeRecord(Record
, Index
);
226 Error
llvm::codeview::visitTypeRecord(CVType
&Record
,
227 TypeVisitorCallbacks
&Callbacks
,
228 VisitorDataSource Source
) {
229 VisitHelper
V(Callbacks
, Source
);
230 return V
.Visitor
.visitTypeRecord(Record
);
233 Error
llvm::codeview::visitTypeStream(const CVTypeArray
&Types
,
234 TypeVisitorCallbacks
&Callbacks
,
235 VisitorDataSource Source
) {
236 VisitHelper
V(Callbacks
, Source
);
237 return V
.Visitor
.visitTypeStream(Types
);
240 Error
llvm::codeview::visitTypeStream(CVTypeRange Types
,
241 TypeVisitorCallbacks
&Callbacks
) {
242 VisitHelper
V(Callbacks
, VDS_BytesPresent
);
243 return V
.Visitor
.visitTypeStream(Types
);
246 Error
llvm::codeview::visitTypeStream(TypeCollection
&Types
,
247 TypeVisitorCallbacks
&Callbacks
) {
248 // When the internal visitor calls Types.getType(Index) the interface is
249 // required to return a CVType with the bytes filled out. So we can assume
250 // that the bytes will be present when individual records are visited.
251 VisitHelper
V(Callbacks
, VDS_BytesPresent
);
252 return V
.Visitor
.visitTypeStream(Types
);
255 Error
llvm::codeview::visitMemberRecord(CVMemberRecord Record
,
256 TypeVisitorCallbacks
&Callbacks
,
257 VisitorDataSource Source
) {
258 FieldListVisitHelper
V(Callbacks
, Record
.Data
, Source
);
259 return V
.Visitor
.visitMemberRecord(Record
);
262 Error
llvm::codeview::visitMemberRecord(TypeLeafKind Kind
,
263 ArrayRef
<uint8_t> Record
,
264 TypeVisitorCallbacks
&Callbacks
) {
268 return visitMemberRecord(R
, Callbacks
, VDS_BytesPresent
);
271 Error
llvm::codeview::visitMemberRecordStream(ArrayRef
<uint8_t> FieldList
,
272 TypeVisitorCallbacks
&Callbacks
) {
273 FieldListVisitHelper
V(Callbacks
, FieldList
, VDS_BytesPresent
);
274 return V
.Visitor
.visitFieldListMemberStream(V
.Reader
);