1 //===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
11 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
12 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
13 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
14 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
15 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
16 #include "llvm/Support/BinaryByteStream.h"
17 #include "llvm/Support/BinaryStreamReader.h"
20 using namespace llvm::codeview
;
24 static Error
visitKnownRecord(CVType
&Record
, TypeVisitorCallbacks
&Callbacks
) {
25 TypeRecordKind RK
= static_cast<TypeRecordKind
>(Record
.kind());
27 if (auto EC
= Callbacks
.visitKnownRecord(Record
, KnownRecord
))
29 return Error::success();
33 static Error
visitKnownMember(CVMemberRecord
&Record
,
34 TypeVisitorCallbacks
&Callbacks
) {
35 TypeRecordKind RK
= static_cast<TypeRecordKind
>(Record
.Kind
);
37 if (auto EC
= Callbacks
.visitKnownMember(Record
, KnownRecord
))
39 return Error::success();
42 static Error
visitMemberRecord(CVMemberRecord
&Record
,
43 TypeVisitorCallbacks
&Callbacks
) {
44 if (auto EC
= Callbacks
.visitMemberBegin(Record
))
47 switch (Record
.Kind
) {
49 if (auto EC
= Callbacks
.visitUnknownMember(Record
))
52 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
54 if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
58 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
59 MEMBER_RECORD(EnumVal, EnumVal, AliasName)
60 #define TYPE_RECORD(EnumName, EnumVal, Name)
61 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
62 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
65 if (auto EC
= Callbacks
.visitMemberEnd(Record
))
68 return Error::success();
75 explicit CVTypeVisitor(TypeVisitorCallbacks
&Callbacks
);
77 Error
visitTypeRecord(CVType
&Record
, TypeIndex Index
);
78 Error
visitTypeRecord(CVType
&Record
);
80 /// Visits the type records in Data. Sets the error flag on parse failures.
81 Error
visitTypeStream(const CVTypeArray
&Types
);
82 Error
visitTypeStream(CVTypeRange Types
);
83 Error
visitTypeStream(TypeCollection
&Types
);
85 Error
visitMemberRecord(CVMemberRecord Record
);
86 Error
visitFieldListMemberStream(BinaryStreamReader
&Stream
);
89 Error
finishVisitation(CVType
&Record
);
91 /// The interface to the class that gets notified of each visitation.
92 TypeVisitorCallbacks
&Callbacks
;
95 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks
&Callbacks
)
96 : Callbacks(Callbacks
) {}
98 Error
CVTypeVisitor::finishVisitation(CVType
&Record
) {
99 switch (Record
.kind()) {
101 if (auto EC
= Callbacks
.visitUnknownType(Record
))
104 #define TYPE_RECORD(EnumName, EnumVal, Name) \
106 if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
110 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
111 TYPE_RECORD(EnumVal, EnumVal, AliasName)
112 #define MEMBER_RECORD(EnumName, EnumVal, Name)
113 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
114 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
117 if (auto EC
= Callbacks
.visitTypeEnd(Record
))
120 return Error::success();
123 Error
CVTypeVisitor::visitTypeRecord(CVType
&Record
, TypeIndex Index
) {
124 if (auto EC
= Callbacks
.visitTypeBegin(Record
, Index
))
127 return finishVisitation(Record
);
130 Error
CVTypeVisitor::visitTypeRecord(CVType
&Record
) {
131 if (auto EC
= Callbacks
.visitTypeBegin(Record
))
134 return finishVisitation(Record
);
137 Error
CVTypeVisitor::visitMemberRecord(CVMemberRecord Record
) {
138 return ::visitMemberRecord(Record
, Callbacks
);
141 /// Visits the type records in Data. Sets the error flag on parse failures.
142 Error
CVTypeVisitor::visitTypeStream(const CVTypeArray
&Types
) {
143 for (auto I
: Types
) {
144 if (auto EC
= visitTypeRecord(I
))
147 return Error::success();
150 Error
CVTypeVisitor::visitTypeStream(CVTypeRange Types
) {
151 for (auto I
: Types
) {
152 if (auto EC
= visitTypeRecord(I
))
155 return Error::success();
158 Error
CVTypeVisitor::visitTypeStream(TypeCollection
&Types
) {
159 Optional
<TypeIndex
> I
= Types
.getFirst();
161 CVType Type
= Types
.getType(*I
);
162 if (auto EC
= visitTypeRecord(Type
, *I
))
164 I
= Types
.getNext(*I
);
166 return Error::success();
169 Error
CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader
&Reader
) {
171 while (!Reader
.empty()) {
172 if (auto EC
= Reader
.readEnum(Leaf
))
175 CVMemberRecord Record
;
177 if (auto EC
= ::visitMemberRecord(Record
, Callbacks
))
181 return Error::success();
184 struct FieldListVisitHelper
{
185 FieldListVisitHelper(TypeVisitorCallbacks
&Callbacks
, ArrayRef
<uint8_t> Data
,
186 VisitorDataSource Source
)
187 : Stream(Data
, llvm::support::little
), Reader(Stream
),
188 Deserializer(Reader
),
189 Visitor((Source
== VDS_BytesPresent
) ? Pipeline
: Callbacks
) {
190 if (Source
== VDS_BytesPresent
) {
191 Pipeline
.addCallbackToPipeline(Deserializer
);
192 Pipeline
.addCallbackToPipeline(Callbacks
);
196 BinaryByteStream Stream
;
197 BinaryStreamReader Reader
;
198 FieldListDeserializer Deserializer
;
199 TypeVisitorCallbackPipeline Pipeline
;
200 CVTypeVisitor Visitor
;
204 VisitHelper(TypeVisitorCallbacks
&Callbacks
, VisitorDataSource Source
)
205 : Visitor((Source
== VDS_BytesPresent
) ? Pipeline
: Callbacks
) {
206 if (Source
== VDS_BytesPresent
) {
207 Pipeline
.addCallbackToPipeline(Deserializer
);
208 Pipeline
.addCallbackToPipeline(Callbacks
);
212 TypeDeserializer Deserializer
;
213 TypeVisitorCallbackPipeline Pipeline
;
214 CVTypeVisitor Visitor
;
218 Error
llvm::codeview::visitTypeRecord(CVType
&Record
, TypeIndex Index
,
219 TypeVisitorCallbacks
&Callbacks
,
220 VisitorDataSource Source
) {
221 VisitHelper
V(Callbacks
, Source
);
222 return V
.Visitor
.visitTypeRecord(Record
, Index
);
225 Error
llvm::codeview::visitTypeRecord(CVType
&Record
,
226 TypeVisitorCallbacks
&Callbacks
,
227 VisitorDataSource Source
) {
228 VisitHelper
V(Callbacks
, Source
);
229 return V
.Visitor
.visitTypeRecord(Record
);
232 Error
llvm::codeview::visitTypeStream(const CVTypeArray
&Types
,
233 TypeVisitorCallbacks
&Callbacks
,
234 VisitorDataSource Source
) {
235 VisitHelper
V(Callbacks
, Source
);
236 return V
.Visitor
.visitTypeStream(Types
);
239 Error
llvm::codeview::visitTypeStream(CVTypeRange Types
,
240 TypeVisitorCallbacks
&Callbacks
) {
241 VisitHelper
V(Callbacks
, VDS_BytesPresent
);
242 return V
.Visitor
.visitTypeStream(Types
);
245 Error
llvm::codeview::visitTypeStream(TypeCollection
&Types
,
246 TypeVisitorCallbacks
&Callbacks
) {
247 // When the internal visitor calls Types.getType(Index) the interface is
248 // required to return a CVType with the bytes filled out. So we can assume
249 // that the bytes will be present when individual records are visited.
250 VisitHelper
V(Callbacks
, VDS_BytesPresent
);
251 return V
.Visitor
.visitTypeStream(Types
);
254 Error
llvm::codeview::visitMemberRecord(CVMemberRecord Record
,
255 TypeVisitorCallbacks
&Callbacks
,
256 VisitorDataSource Source
) {
257 FieldListVisitHelper
V(Callbacks
, Record
.Data
, Source
);
258 return V
.Visitor
.visitMemberRecord(Record
);
261 Error
llvm::codeview::visitMemberRecord(TypeLeafKind Kind
,
262 ArrayRef
<uint8_t> Record
,
263 TypeVisitorCallbacks
&Callbacks
) {
267 return visitMemberRecord(R
, Callbacks
, VDS_BytesPresent
);
270 Error
llvm::codeview::visitMemberRecordStream(ArrayRef
<uint8_t> FieldList
,
271 TypeVisitorCallbacks
&Callbacks
) {
272 FieldListVisitHelper
V(Callbacks
, FieldList
, VDS_BytesPresent
);
273 return V
.Visitor
.visitFieldListMemberStream(V
.Reader
);