1 //===- CVTypeVisitor.cpp ----------------------------------------*- 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 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
10
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"
18
19 using namespace llvm;
20 using namespace llvm::codeview;
21
22
23 template <typename T>
visitKnownRecord(CVType & Record,TypeVisitorCallbacks & Callbacks)24 static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
25 TypeRecordKind RK = static_cast<TypeRecordKind>(Record.kind());
26 T KnownRecord(RK);
27 if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
28 return EC;
29 return Error::success();
30 }
31
32 template <typename T>
visitKnownMember(CVMemberRecord & Record,TypeVisitorCallbacks & Callbacks)33 static Error visitKnownMember(CVMemberRecord &Record,
34 TypeVisitorCallbacks &Callbacks) {
35 TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind);
36 T KnownRecord(RK);
37 if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord))
38 return EC;
39 return Error::success();
40 }
41
visitMemberRecord(CVMemberRecord & Record,TypeVisitorCallbacks & Callbacks)42 static Error visitMemberRecord(CVMemberRecord &Record,
43 TypeVisitorCallbacks &Callbacks) {
44 if (auto EC = Callbacks.visitMemberBegin(Record))
45 return EC;
46
47 switch (Record.Kind) {
48 default:
49 if (auto EC = Callbacks.visitUnknownMember(Record))
50 return EC;
51 break;
52 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
53 case EnumName: { \
54 if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
55 return EC; \
56 break; \
57 }
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"
63 }
64
65 if (auto EC = Callbacks.visitMemberEnd(Record))
66 return EC;
67
68 return Error::success();
69 }
70
71 namespace {
72
73 class CVTypeVisitor {
74 public:
75 explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
76
77 Error visitTypeRecord(CVType &Record, TypeIndex Index);
78 Error visitTypeRecord(CVType &Record);
79
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);
84
85 Error visitMemberRecord(CVMemberRecord Record);
86 Error visitFieldListMemberStream(BinaryStreamReader &Stream);
87
88 private:
89 Error finishVisitation(CVType &Record);
90
91 /// The interface to the class that gets notified of each visitation.
92 TypeVisitorCallbacks &Callbacks;
93 };
94
CVTypeVisitor(TypeVisitorCallbacks & Callbacks)95 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
96 : Callbacks(Callbacks) {}
97
finishVisitation(CVType & Record)98 Error CVTypeVisitor::finishVisitation(CVType &Record) {
99 switch (Record.kind()) {
100 default:
101 if (auto EC = Callbacks.visitUnknownType(Record))
102 return EC;
103 break;
104 #define TYPE_RECORD(EnumName, EnumVal, Name) \
105 case EnumName: { \
106 if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
107 return EC; \
108 break; \
109 }
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"
115 }
116
117 if (auto EC = Callbacks.visitTypeEnd(Record))
118 return EC;
119
120 return Error::success();
121 }
122
visitTypeRecord(CVType & Record,TypeIndex Index)123 Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
124 if (auto EC = Callbacks.visitTypeBegin(Record, Index))
125 return EC;
126
127 return finishVisitation(Record);
128 }
129
visitTypeRecord(CVType & Record)130 Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
131 if (auto EC = Callbacks.visitTypeBegin(Record))
132 return EC;
133
134 return finishVisitation(Record);
135 }
136
visitMemberRecord(CVMemberRecord Record)137 Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
138 return ::visitMemberRecord(Record, Callbacks);
139 }
140
141 /// Visits the type records in Data. Sets the error flag on parse failures.
visitTypeStream(const CVTypeArray & Types)142 Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
143 for (auto I : Types) {
144 if (auto EC = visitTypeRecord(I))
145 return EC;
146 }
147 return Error::success();
148 }
149
visitTypeStream(CVTypeRange Types)150 Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
151 for (auto I : Types) {
152 if (auto EC = visitTypeRecord(I))
153 return EC;
154 }
155 return Error::success();
156 }
157
visitTypeStream(TypeCollection & Types)158 Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
159 Optional<TypeIndex> I = Types.getFirst();
160 while (I) {
161 CVType Type = Types.getType(*I);
162 if (auto EC = visitTypeRecord(Type, *I))
163 return EC;
164 I = Types.getNext(*I);
165 }
166 return Error::success();
167 }
168
visitFieldListMemberStream(BinaryStreamReader & Reader)169 Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
170 TypeLeafKind Leaf;
171 while (!Reader.empty()) {
172 if (auto EC = Reader.readEnum(Leaf))
173 return EC;
174
175 CVMemberRecord Record;
176 Record.Kind = Leaf;
177 if (auto EC = ::visitMemberRecord(Record, Callbacks))
178 return EC;
179 }
180
181 return Error::success();
182 }
183
184 struct FieldListVisitHelper {
FieldListVisitHelper__anon5992a6280111::FieldListVisitHelper185 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);
193 }
194 }
195
196 BinaryByteStream Stream;
197 BinaryStreamReader Reader;
198 FieldListDeserializer Deserializer;
199 TypeVisitorCallbackPipeline Pipeline;
200 CVTypeVisitor Visitor;
201 };
202
203 struct VisitHelper {
VisitHelper__anon5992a6280111::VisitHelper204 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);
209 }
210 }
211
VisitHelper__anon5992a6280111::VisitHelper212 VisitHelper(TypeVisitorCallbackPipeline &Callbacks, VisitorDataSource Source)
213 : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
214 if (Source == VDS_BytesPresent) {
215 Pipeline = Callbacks;
216 Pipeline.addCallbackToPipelineFront(Deserializer);
217 }
218 }
219
220 TypeDeserializer Deserializer;
221 TypeVisitorCallbackPipeline Pipeline;
222 CVTypeVisitor Visitor;
223 };
224 }
225
visitTypeRecord(CVType & Record,TypeIndex Index,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)226 Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
227 TypeVisitorCallbacks &Callbacks,
228 VisitorDataSource Source) {
229 VisitHelper V(Callbacks, Source);
230 return V.Visitor.visitTypeRecord(Record, Index);
231 }
232
visitTypeRecord(CVType & Record,TypeIndex Index,TypeVisitorCallbackPipeline & Callbacks,VisitorDataSource Source)233 Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
234 TypeVisitorCallbackPipeline &Callbacks,
235 VisitorDataSource Source) {
236 VisitHelper V(Callbacks, Source);
237 return V.Visitor.visitTypeRecord(Record, Index);
238 }
239
visitTypeRecord(CVType & Record,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)240 Error llvm::codeview::visitTypeRecord(CVType &Record,
241 TypeVisitorCallbacks &Callbacks,
242 VisitorDataSource Source) {
243 VisitHelper V(Callbacks, Source);
244 return V.Visitor.visitTypeRecord(Record);
245 }
246
visitTypeStream(const CVTypeArray & Types,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)247 Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
248 TypeVisitorCallbacks &Callbacks,
249 VisitorDataSource Source) {
250 VisitHelper V(Callbacks, Source);
251 return V.Visitor.visitTypeStream(Types);
252 }
253
visitTypeStream(CVTypeRange Types,TypeVisitorCallbacks & Callbacks)254 Error llvm::codeview::visitTypeStream(CVTypeRange Types,
255 TypeVisitorCallbacks &Callbacks) {
256 VisitHelper V(Callbacks, VDS_BytesPresent);
257 return V.Visitor.visitTypeStream(Types);
258 }
259
visitTypeStream(TypeCollection & Types,TypeVisitorCallbacks & Callbacks)260 Error llvm::codeview::visitTypeStream(TypeCollection &Types,
261 TypeVisitorCallbacks &Callbacks) {
262 // When the internal visitor calls Types.getType(Index) the interface is
263 // required to return a CVType with the bytes filled out. So we can assume
264 // that the bytes will be present when individual records are visited.
265 VisitHelper V(Callbacks, VDS_BytesPresent);
266 return V.Visitor.visitTypeStream(Types);
267 }
268
visitMemberRecord(CVMemberRecord Record,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)269 Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
270 TypeVisitorCallbacks &Callbacks,
271 VisitorDataSource Source) {
272 FieldListVisitHelper V(Callbacks, Record.Data, Source);
273 return V.Visitor.visitMemberRecord(Record);
274 }
275
visitMemberRecord(TypeLeafKind Kind,ArrayRef<uint8_t> Record,TypeVisitorCallbacks & Callbacks)276 Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
277 ArrayRef<uint8_t> Record,
278 TypeVisitorCallbacks &Callbacks) {
279 CVMemberRecord R;
280 R.Data = Record;
281 R.Kind = Kind;
282 return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
283 }
284
visitMemberRecordStream(ArrayRef<uint8_t> FieldList,TypeVisitorCallbacks & Callbacks)285 Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
286 TypeVisitorCallbacks &Callbacks) {
287 FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
288 return V.Visitor.visitFieldListMemberStream(V.Reader);
289 }
290