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