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/TypeCollection.h"
12#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
13#include "llvm/DebugInfo/CodeView/TypeIndex.h"
14#include "llvm/DebugInfo/CodeView/TypeRecord.h"
15#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
16#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
17#include "llvm/Support/BinaryByteStream.h"
18#include "llvm/Support/BinaryStreamReader.h"
19
20using namespace llvm;
21using namespace llvm::codeview;
22
23
24template <typename T>
25static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
26 TypeRecordKind RK = static_cast<TypeRecordKind>(Record.kind());
27 T KnownRecord(RK);
28 if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
29 return EC;
30 return Error::success();
31}
32
33template <typename T>
34static 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
43static 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
72namespace {
73
74class CVTypeVisitor {
75public:
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
89private:
90 Error finishVisitation(CVType &Record);
91
92 /// The interface to the class that gets notified of each visitation.
93 TypeVisitorCallbacks &Callbacks;
94};
95
96CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
97 : Callbacks(Callbacks) {}
98
99Error CVTypeVisitor::finishVisitation(CVType &Record) {
100 switch (Record.kind()) {
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
124Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
125 if (auto EC = Callbacks.visitTypeBegin(Record, Index))
126 return EC;
127
128 return finishVisitation(Record);
129}
130
131Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
132 if (auto EC = Callbacks.visitTypeBegin(Record))
133 return EC;
134
135 return finishVisitation(Record);
136}
137
138Error 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.
143Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
144 for (auto I : Types) {
145 if (auto EC = visitTypeRecord(Record&: I))
146 return EC;
147 }
148 return Error::success();
149}
150
151Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
152 for (auto I : Types) {
153 if (auto EC = visitTypeRecord(Record&: I))
154 return EC;
155 }
156 return Error::success();
157}
158
159Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
160 std::optional<TypeIndex> I = Types.getFirst();
161 while (I) {
162 CVType Type = Types.getType(Index: *I);
163 if (auto EC = visitTypeRecord(Record&: Type, Index: *I))
164 return EC;
165 I = Types.getNext(Prev: *I);
166 }
167 return Error::success();
168}
169
170Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
171 TypeLeafKind Leaf;
172 while (!Reader.empty()) {
173 if (auto EC = Reader.readEnum(Dest&: 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
185struct FieldListVisitHelper {
186 FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
187 VisitorDataSource Source)
188 : Stream(Data, llvm::endianness::little), Reader(Stream),
189 Deserializer(Reader),
190 Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
191 if (Source == VDS_BytesPresent) {
192 Pipeline.addCallbackToPipeline(Callbacks&: 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
204struct VisitHelper {
205 VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
206 : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
207 if (Source == VDS_BytesPresent) {
208 Pipeline.addCallbackToPipeline(Callbacks&: Deserializer);
209 Pipeline.addCallbackToPipeline(Callbacks);
210 }
211 }
212
213 TypeDeserializer Deserializer;
214 TypeVisitorCallbackPipeline Pipeline;
215 CVTypeVisitor Visitor;
216};
217}
218
219Error 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
226Error llvm::codeview::visitTypeRecord(CVType &Record,
227 TypeVisitorCallbacks &Callbacks,
228 VisitorDataSource Source) {
229 VisitHelper V(Callbacks, Source);
230 return V.Visitor.visitTypeRecord(Record);
231}
232
233Error 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
240Error llvm::codeview::visitTypeStream(CVTypeRange Types,
241 TypeVisitorCallbacks &Callbacks) {
242 VisitHelper V(Callbacks, VDS_BytesPresent);
243 return V.Visitor.visitTypeStream(Types);
244}
245
246Error 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
255Error 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
262Error 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(Record: R, Callbacks, Source: VDS_BytesPresent);
269}
270
271Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
272 TypeVisitorCallbacks &Callbacks) {
273 FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
274 return V.Visitor.visitFieldListMemberStream(Reader&: V.Reader);
275}
276

source code of llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp