1 //===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
11
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"
19
20 using namespace llvm;
21 using namespace llvm::codeview;
22
23
24 template <typename T>
visitKnownRecord(CVType & Record,TypeVisitorCallbacks & Callbacks)25 static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
26 TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Type);
27 T KnownRecord(RK);
28 if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
29 return EC;
30 return Error::success();
31 }
32
33 template <typename T>
visitKnownMember(CVMemberRecord & Record,TypeVisitorCallbacks & Callbacks)34 static Error visitKnownMember(CVMemberRecord &Record,
35 TypeVisitorCallbacks &Callbacks) {
36 TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind);
37 T KnownRecord(RK);
38 if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord))
39 return EC;
40 return Error::success();
41 }
42
visitMemberRecord(CVMemberRecord & Record,TypeVisitorCallbacks & Callbacks)43 static Error visitMemberRecord(CVMemberRecord &Record,
44 TypeVisitorCallbacks &Callbacks) {
45 if (auto EC = Callbacks.visitMemberBegin(Record))
46 return EC;
47
48 switch (Record.Kind) {
49 default:
50 if (auto EC = Callbacks.visitUnknownMember(Record))
51 return EC;
52 break;
53 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
54 case EnumName: { \
55 if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
56 return EC; \
57 break; \
58 }
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"
64 }
65
66 if (auto EC = Callbacks.visitMemberEnd(Record))
67 return EC;
68
69 return Error::success();
70 }
71
72 namespace {
73
74 class CVTypeVisitor {
75 public:
76 explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
77
78 Error visitTypeRecord(CVType &Record, TypeIndex Index);
79 Error visitTypeRecord(CVType &Record);
80
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);
85
86 Error visitMemberRecord(CVMemberRecord Record);
87 Error visitFieldListMemberStream(BinaryStreamReader &Stream);
88
89 private:
90 Error finishVisitation(CVType &Record);
91
92 /// The interface to the class that gets notified of each visitation.
93 TypeVisitorCallbacks &Callbacks;
94 };
95
CVTypeVisitor(TypeVisitorCallbacks & Callbacks)96 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
97 : Callbacks(Callbacks) {}
98
finishVisitation(CVType & Record)99 Error CVTypeVisitor::finishVisitation(CVType &Record) {
100 switch (Record.Type) {
101 default:
102 if (auto EC = Callbacks.visitUnknownType(Record))
103 return EC;
104 break;
105 #define TYPE_RECORD(EnumName, EnumVal, Name) \
106 case EnumName: { \
107 if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
108 return EC; \
109 break; \
110 }
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"
116 }
117
118 if (auto EC = Callbacks.visitTypeEnd(Record))
119 return EC;
120
121 return Error::success();
122 }
123
visitTypeRecord(CVType & Record,TypeIndex Index)124 Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
125 if (auto EC = Callbacks.visitTypeBegin(Record, Index))
126 return EC;
127
128 return finishVisitation(Record);
129 }
130
visitTypeRecord(CVType & Record)131 Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
132 if (auto EC = Callbacks.visitTypeBegin(Record))
133 return EC;
134
135 return finishVisitation(Record);
136 }
137
visitMemberRecord(CVMemberRecord Record)138 Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
139 return ::visitMemberRecord(Record, Callbacks);
140 }
141
142 /// Visits the type records in Data. Sets the error flag on parse failures.
visitTypeStream(const CVTypeArray & Types)143 Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
144 for (auto I : Types) {
145 if (auto EC = visitTypeRecord(I))
146 return EC;
147 }
148 return Error::success();
149 }
150
visitTypeStream(CVTypeRange Types)151 Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
152 for (auto I : Types) {
153 if (auto EC = visitTypeRecord(I))
154 return EC;
155 }
156 return Error::success();
157 }
158
visitTypeStream(TypeCollection & Types)159 Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
160 Optional<TypeIndex> I = Types.getFirst();
161 while (I) {
162 CVType Type = Types.getType(*I);
163 if (auto EC = visitTypeRecord(Type, *I))
164 return EC;
165 I = Types.getNext(*I);
166 }
167 return Error::success();
168 }
169
visitFieldListMemberStream(BinaryStreamReader & Reader)170 Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
171 TypeLeafKind Leaf;
172 while (!Reader.empty()) {
173 if (auto EC = Reader.readEnum(Leaf))
174 return EC;
175
176 CVMemberRecord Record;
177 Record.Kind = Leaf;
178 if (auto EC = ::visitMemberRecord(Record, Callbacks))
179 return EC;
180 }
181
182 return Error::success();
183 }
184
185 struct FieldListVisitHelper {
FieldListVisitHelper__anon281550450111::FieldListVisitHelper186 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);
194 }
195 }
196
197 BinaryByteStream Stream;
198 BinaryStreamReader Reader;
199 FieldListDeserializer Deserializer;
200 TypeVisitorCallbackPipeline Pipeline;
201 CVTypeVisitor Visitor;
202 };
203
204 struct VisitHelper {
VisitHelper__anon281550450111::VisitHelper205 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);
210 }
211 }
212
213 TypeDeserializer Deserializer;
214 TypeVisitorCallbackPipeline Pipeline;
215 CVTypeVisitor Visitor;
216 };
217 }
218
visitTypeRecord(CVType & Record,TypeIndex Index,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)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);
224 }
225
visitTypeRecord(CVType & Record,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)226 Error llvm::codeview::visitTypeRecord(CVType &Record,
227 TypeVisitorCallbacks &Callbacks,
228 VisitorDataSource Source) {
229 VisitHelper V(Callbacks, Source);
230 return V.Visitor.visitTypeRecord(Record);
231 }
232
visitTypeStream(const CVTypeArray & Types,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)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);
238 }
239
visitTypeStream(CVTypeRange Types,TypeVisitorCallbacks & Callbacks)240 Error llvm::codeview::visitTypeStream(CVTypeRange Types,
241 TypeVisitorCallbacks &Callbacks) {
242 VisitHelper V(Callbacks, VDS_BytesPresent);
243 return V.Visitor.visitTypeStream(Types);
244 }
245
visitTypeStream(TypeCollection & Types,TypeVisitorCallbacks & Callbacks)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);
253 }
254
visitMemberRecord(CVMemberRecord Record,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)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);
260 }
261
visitMemberRecord(TypeLeafKind Kind,ArrayRef<uint8_t> Record,TypeVisitorCallbacks & Callbacks)262 Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
263 ArrayRef<uint8_t> Record,
264 TypeVisitorCallbacks &Callbacks) {
265 CVMemberRecord R;
266 R.Data = Record;
267 R.Kind = Kind;
268 return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
269 }
270
visitMemberRecordStream(ArrayRef<uint8_t> FieldList,TypeVisitorCallbacks & Callbacks)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);
275 }
276