LLVM  10.0.0svn
CVTypeVisitor.cpp
Go to the documentation of this file.
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 
10 
18 
19 using namespace llvm;
20 using namespace llvm::codeview;
21 
22 
23 template <typename T>
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>
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 
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 
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);
84 
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 
95 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
96  : Callbacks(Callbacks) {}
97 
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 
124  if (auto EC = Callbacks.visitTypeBegin(Record, Index))
125  return EC;
126 
127  return finishVisitation(Record);
128 }
129 
131  if (auto EC = Callbacks.visitTypeBegin(Record))
132  return EC;
133 
134  return finishVisitation(Record);
135 }
136 
138  return ::visitMemberRecord(Record, Callbacks);
139 }
140 
141 /// Visits the type records in Data. Sets the error flag on parse failures.
143  for (auto I : Types) {
144  if (auto EC = visitTypeRecord(I))
145  return EC;
146  }
147  return Error::success();
148 }
149 
151  for (auto I : Types) {
152  if (auto EC = visitTypeRecord(I))
153  return EC;
154  }
155  return Error::success();
156 }
157 
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 
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 {
185  FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
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;
200  CVTypeVisitor Visitor;
201 };
202 
203 struct VisitHelper {
204  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 
212  TypeDeserializer Deserializer;
214  CVTypeVisitor Visitor;
215 };
216 }
217 
219  TypeVisitorCallbacks &Callbacks,
221  VisitHelper V(Callbacks, Source);
222  return V.Visitor.visitTypeRecord(Record, Index);
223 }
224 
226  TypeVisitorCallbacks &Callbacks,
228  VisitHelper V(Callbacks, Source);
229  return V.Visitor.visitTypeRecord(Record);
230 }
231 
233  TypeVisitorCallbacks &Callbacks,
235  VisitHelper V(Callbacks, Source);
236  return V.Visitor.visitTypeStream(Types);
237 }
238 
240  TypeVisitorCallbacks &Callbacks) {
241  VisitHelper V(Callbacks, VDS_BytesPresent);
242  return V.Visitor.visitTypeStream(Types);
243 }
244 
246  TypeVisitorCallbacks &Callbacks) {
247  // When the internal visitor calls Types.getType(Index) the interface is
248  // required to return a CVType with the bytes filled out. So we can assume
249  // that the bytes will be present when individual records are visited.
250  VisitHelper V(Callbacks, VDS_BytesPresent);
251  return V.Visitor.visitTypeStream(Types);
252 }
253 
255  TypeVisitorCallbacks &Callbacks,
257  FieldListVisitHelper V(Callbacks, Record.Data, Source);
258  return V.Visitor.visitMemberRecord(Record);
259 }
260 
263  TypeVisitorCallbacks &Callbacks) {
264  CVMemberRecord R;
265  R.Data = Record;
266  R.Kind = Kind;
267  return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
268 }
269 
271  TypeVisitorCallbacks &Callbacks) {
272  FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
273  return V.Visitor.visitFieldListMemberStream(V.Reader);
274 }
An implementation of BinaryStream which holds its entire data set in a single contiguous buffer...
Kind kind() const
Definition: CVRecord.h:43
virtual Optional< TypeIndex > getNext(TypeIndex Prev)=0
This class represents lattice values for constants.
Definition: AllocatorList.h:23
TypeLeafKind
Duplicate copy of the above enum, but using the official CV names.
Definition: CodeView.h:33
ArrayRef< uint8_t > Data
Definition: TypeRecord.h:40
virtual CVType getType(TypeIndex Index)=0
Error visitMemberRecordStream(ArrayRef< uint8_t > FieldList, TypeVisitorCallbacks &Callbacks)
virtual Optional< TypeIndex > getFirst()=0
virtual Error visitUnknownMember(CVMemberRecord &Record)
virtual Error visitUnknownType(CVType &Record)
Action to take on unknown types. By default, they are ignored.
A 32-bit type reference.
Definition: TypeIndex.h:95
virtual Error visitTypeEnd(CVType &Record)
TypeRecordKind
Distinguishes individual records in .debug$T or .debug$P section or PDB type stream.
Definition: CodeView.h:26
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:46
static Error visitKnownMember(CVMemberRecord &Record, TypeVisitorCallbacks &Callbacks)
static Error visitMemberRecord(CVMemberRecord &Record, TypeVisitorCallbacks &Callbacks)
Error visitTypeRecord(CVType &Record, TypeIndex Index, TypeVisitorCallbacks &Callbacks, VisitorDataSource Source=VDS_BytesPresent)
Error visitTypeStream(const CVTypeArray &Types, TypeVisitorCallbacks &Callbacks, VisitorDataSource Source=VDS_BytesPresent)
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
virtual Error visitMemberBegin(CVMemberRecord &Record)
Error visitMemberRecord(CVMemberRecord Record, TypeVisitorCallbacks &Callbacks, VisitorDataSource Source=VDS_BytesPresent)
virtual Error visitTypeBegin(CVType &Record)
Paired begin/end actions for all types.
A range adaptor for a pair of iterators.
#define I(x, y, z)
Definition: MD5.cpp:58
static Error finishVisitation(CVSymbol &Record, SymbolVisitorCallbacks &Callbacks)
static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks)
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
Provides read only access to a subclass of BinaryStream.
Error readEnum(T &Dest)
Similar to readInteger.
virtual Error visitMemberEnd(CVMemberRecord &Record)