Line data Source code
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>
25 9361 : static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
26 9361 : TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Type);
27 : T KnownRecord(RK);
28 18722 : if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
29 : return EC;
30 : return Error::success();
31 : }
32 11 :
33 11 : template <typename T>
34 : static Error visitKnownMember(CVMemberRecord &Record,
35 22 : TypeVisitorCallbacks &Callbacks) {
36 : TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind);
37 : T KnownRecord(RK);
38 : if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord))
39 1075 : return EC;
40 1075 : return Error::success();
41 : }
42 2150 :
43 : static Error visitMemberRecord(CVMemberRecord &Record,
44 : TypeVisitorCallbacks &Callbacks) {
45 : if (auto EC = Callbacks.visitMemberBegin(Record))
46 191 : return EC;
47 191 :
48 : switch (Record.Kind) {
49 382 : default:
50 : if (auto EC = Callbacks.visitUnknownMember(Record))
51 : return EC;
52 : break;
53 458 : #define MEMBER_RECORD(EnumName, EnumVal, Name) \
54 458 : case EnumName: { \
55 : if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
56 916 : return EC; \
57 : break; \
58 : }
59 : #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
60 1128 : MEMBER_RECORD(EnumVal, EnumVal, AliasName)
61 1128 : #define TYPE_RECORD(EnumName, EnumVal, Name)
62 : #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
63 2256 : #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
64 : }
65 :
66 : if (auto EC = Callbacks.visitMemberEnd(Record))
67 1 : return EC;
68 1 :
69 : return Error::success();
70 2 : }
71 :
72 : namespace {
73 :
74 752 : class CVTypeVisitor {
75 752 : public:
76 : explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
77 1504 :
78 : Error visitTypeRecord(CVType &Record, TypeIndex Index);
79 : Error visitTypeRecord(CVType &Record);
80 :
81 1004 : /// Visits the type records in Data. Sets the error flag on parse failures.
82 1004 : Error visitTypeStream(const CVTypeArray &Types);
83 : Error visitTypeStream(CVTypeRange Types);
84 2008 : Error visitTypeStream(TypeCollection &Types);
85 :
86 : Error visitMemberRecord(CVMemberRecord Record);
87 : Error visitFieldListMemberStream(BinaryStreamReader &Stream);
88 84 :
89 84 : private:
90 : Error finishVisitation(CVType &Record);
91 168 :
92 : /// The interface to the class that gets notified of each visitation.
93 : TypeVisitorCallbacks &Callbacks;
94 : };
95 1650 :
96 1650 : CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
97 : : Callbacks(Callbacks) {}
98 3300 :
99 : Error CVTypeVisitor::finishVisitation(CVType &Record) {
100 : switch (Record.Type) {
101 : default:
102 39 : if (auto EC = Callbacks.visitUnknownType(Record))
103 39 : return EC;
104 : break;
105 78 : #define TYPE_RECORD(EnumName, EnumVal, Name) \
106 : case EnumName: { \
107 : if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
108 : return EC; \
109 210 : break; \
110 210 : }
111 : #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
112 420 : 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 0 : }
117 0 :
118 : if (auto EC = Callbacks.visitTypeEnd(Record))
119 0 : return EC;
120 :
121 : return Error::success();
122 : }
123 2 :
124 2 : Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
125 : if (auto EC = Callbacks.visitTypeBegin(Record, Index))
126 4 : return EC;
127 :
128 : return finishVisitation(Record);
129 : }
130 38 :
131 38 : Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
132 : if (auto EC = Callbacks.visitTypeBegin(Record))
133 76 : return EC;
134 :
135 : return finishVisitation(Record);
136 : }
137 18 :
138 18 : Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
139 : return ::visitMemberRecord(Record, Callbacks);
140 36 : }
141 :
142 : /// Visits the type records in Data. Sets the error flag on parse failures.
143 : Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
144 470 : for (auto I : Types) {
145 470 : if (auto EC = visitTypeRecord(I))
146 : return EC;
147 940 : }
148 : return Error::success();
149 : }
150 :
151 106 : Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
152 106 : for (auto I : Types) {
153 : if (auto EC = visitTypeRecord(I))
154 212 : return EC;
155 : }
156 : return Error::success();
157 : }
158 260 :
159 260 : Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
160 : Optional<TypeIndex> I = Types.getFirst();
161 520 : while (I) {
162 : CVType Type = Types.getType(*I);
163 : if (auto EC = visitTypeRecord(Type, *I))
164 : return EC;
165 47 : I = Types.getNext(*I);
166 47 : }
167 : return Error::success();
168 94 : }
169 :
170 : Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
171 : TypeLeafKind Leaf;
172 1023 : while (!Reader.empty()) {
173 1023 : if (auto EC = Reader.readEnum(Leaf))
174 : return EC;
175 2046 :
176 : CVMemberRecord Record;
177 : Record.Kind = Leaf;
178 : if (auto EC = ::visitMemberRecord(Record, Callbacks))
179 540 : return EC;
180 540 : }
181 :
182 1080 : return Error::success();
183 : }
184 :
185 : struct FieldListVisitHelper {
186 8 : FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
187 8 : VisitorDataSource Source)
188 : : Stream(Data, llvm::support::little), Reader(Stream),
189 16 : Deserializer(Reader),
190 : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
191 : if (Source == VDS_BytesPresent) {
192 : Pipeline.addCallbackToPipeline(Deserializer);
193 244 : Pipeline.addCallbackToPipeline(Callbacks);
194 244 : }
195 : }
196 488 :
197 : BinaryByteStream Stream;
198 : BinaryStreamReader Reader;
199 : FieldListDeserializer Deserializer;
200 2 : TypeVisitorCallbackPipeline Pipeline;
201 2 : CVTypeVisitor Visitor;
202 : };
203 4 :
204 : struct VisitHelper {
205 : VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
206 : : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
207 : if (Source == VDS_BytesPresent) {
208 : Pipeline.addCallbackToPipeline(Deserializer);
209 9132 : Pipeline.addCallbackToPipeline(Callbacks);
210 : }
211 9132 : }
212 :
213 18264 : TypeDeserializer Deserializer;
214 : TypeVisitorCallbackPipeline Pipeline;
215 : CVTypeVisitor Visitor;
216 : };
217 4 : }
218 :
219 4 : Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
220 : TypeVisitorCallbacks &Callbacks,
221 8 : VisitorDataSource Source) {
222 : VisitHelper V(Callbacks, Source);
223 : return V.Visitor.visitTypeRecord(Record, Index);
224 : }
225 6938 :
226 : Error llvm::codeview::visitTypeRecord(CVType &Record,
227 6938 : TypeVisitorCallbacks &Callbacks,
228 : VisitorDataSource Source) {
229 13876 : VisitHelper V(Callbacks, Source);
230 : return V.Visitor.visitTypeRecord(Record);
231 : }
232 :
233 419 : Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
234 : TypeVisitorCallbacks &Callbacks,
235 419 : VisitorDataSource Source) {
236 : VisitHelper V(Callbacks, Source);
237 838 : return V.Visitor.visitTypeStream(Types);
238 : }
239 :
240 : Error llvm::codeview::visitTypeStream(CVTypeRange Types,
241 173 : TypeVisitorCallbacks &Callbacks) {
242 : VisitHelper V(Callbacks, VDS_BytesPresent);
243 173 : return V.Visitor.visitTypeStream(Types);
244 : }
245 346 :
246 : Error llvm::codeview::visitTypeStream(TypeCollection &Types,
247 : TypeVisitorCallbacks &Callbacks) {
248 : // When the internal visitor calls Types.getType(Index) the interface is
249 1180 : // 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 1180 : VisitHelper V(Callbacks, VDS_BytesPresent);
252 : return V.Visitor.visitTypeStream(Types);
253 2360 : }
254 :
255 : Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
256 : TypeVisitorCallbacks &Callbacks,
257 231 : VisitorDataSource Source) {
258 : FieldListVisitHelper V(Callbacks, Record.Data, Source);
259 231 : return V.Visitor.visitMemberRecord(Record);
260 : }
261 462 :
262 : Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
263 : ArrayRef<uint8_t> Record,
264 : TypeVisitorCallbacks &Callbacks) {
265 120 : CVMemberRecord R;
266 : R.Data = Record;
267 120 : R.Kind = Kind;
268 : return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
269 240 : }
270 :
271 : Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
272 : TypeVisitorCallbacks &Callbacks) {
273 19 : FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
274 : return V.Visitor.visitFieldListMemberStream(V.Reader);
275 19 : }
|