• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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