1 //===- NativeTypeEnum.cpp - info about enum type ----------------*- 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/PDB/Native/NativeTypeEnum.h"
11
12 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
13 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
14 #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
15 #include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h"
16 #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
17 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
18 #include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
19 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
20 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
21
22 #include "llvm/Support/FormatVariadic.h"
23
24 #include <cassert>
25
26 using namespace llvm;
27 using namespace llvm::codeview;
28 using namespace llvm::pdb;
29
30 namespace {
31 // Yea, this is a pretty terrible class name. But if we have an enum:
32 //
33 // enum Foo {
34 // A,
35 // B
36 // };
37 //
38 // then A and B are the "enumerators" of the "enum" Foo. And we need
39 // to enumerate them.
40 class NativeEnumEnumEnumerators : public IPDBEnumSymbols, TypeVisitorCallbacks {
41 public:
42 NativeEnumEnumEnumerators(NativeSession &Session,
43 const NativeTypeEnum &ClassParent);
44
45 uint32_t getChildCount() const override;
46 std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override;
47 std::unique_ptr<PDBSymbol> getNext() override;
48 void reset() override;
49
50 private:
51 Error visitKnownMember(CVMemberRecord &CVM,
52 EnumeratorRecord &Record) override;
53 Error visitKnownMember(CVMemberRecord &CVM,
54 ListContinuationRecord &Record) override;
55
56 NativeSession &Session;
57 const NativeTypeEnum &ClassParent;
58 std::vector<EnumeratorRecord> Enumerators;
59 Optional<TypeIndex> ContinuationIndex;
60 uint32_t Index = 0;
61 };
62 } // namespace
63
NativeEnumEnumEnumerators(NativeSession & Session,const NativeTypeEnum & ClassParent)64 NativeEnumEnumEnumerators::NativeEnumEnumEnumerators(
65 NativeSession &Session, const NativeTypeEnum &ClassParent)
66 : Session(Session), ClassParent(ClassParent) {
67 TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream());
68 LazyRandomTypeCollection &Types = Tpi.typeCollection();
69
70 ContinuationIndex = ClassParent.getEnumRecord().FieldList;
71 while (ContinuationIndex) {
72 CVType FieldList = Types.getType(*ContinuationIndex);
73 assert(FieldList.kind() == LF_FIELDLIST);
74 ContinuationIndex.reset();
75 cantFail(visitMemberRecordStream(FieldList.data(), *this));
76 }
77 }
78
visitKnownMember(CVMemberRecord & CVM,EnumeratorRecord & Record)79 Error NativeEnumEnumEnumerators::visitKnownMember(CVMemberRecord &CVM,
80 EnumeratorRecord &Record) {
81 Enumerators.push_back(Record);
82 return Error::success();
83 }
84
visitKnownMember(CVMemberRecord & CVM,ListContinuationRecord & Record)85 Error NativeEnumEnumEnumerators::visitKnownMember(
86 CVMemberRecord &CVM, ListContinuationRecord &Record) {
87 ContinuationIndex = Record.ContinuationIndex;
88 return Error::success();
89 }
90
getChildCount() const91 uint32_t NativeEnumEnumEnumerators::getChildCount() const {
92 return Enumerators.size();
93 }
94
95 std::unique_ptr<PDBSymbol>
getChildAtIndex(uint32_t Index) const96 NativeEnumEnumEnumerators::getChildAtIndex(uint32_t Index) const {
97 if (Index >= getChildCount())
98 return nullptr;
99
100 SymIndexId Id = Session.getSymbolCache()
101 .getOrCreateFieldListMember<NativeSymbolEnumerator>(
102 ClassParent.getEnumRecord().FieldList, Index,
103 ClassParent, Enumerators[Index]);
104 return Session.getSymbolCache().getSymbolById(Id);
105 }
106
getNext()107 std::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::getNext() {
108 if (Index >= getChildCount())
109 return nullptr;
110
111 return getChildAtIndex(Index++);
112 }
113
reset()114 void NativeEnumEnumEnumerators::reset() { Index = 0; }
115
NativeTypeEnum(NativeSession & Session,SymIndexId Id,TypeIndex Index,EnumRecord Record)116 NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
117 TypeIndex Index, EnumRecord Record)
118 : NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(Index),
119 Record(std::move(Record)) {}
120
NativeTypeEnum(NativeSession & Session,SymIndexId Id,NativeTypeEnum & UnmodifiedType,codeview::ModifierRecord Modifier)121 NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
122 NativeTypeEnum &UnmodifiedType,
123 codeview::ModifierRecord Modifier)
124 : NativeRawSymbol(Session, PDB_SymType::Enum, Id),
125 UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {}
126
~NativeTypeEnum()127 NativeTypeEnum::~NativeTypeEnum() {}
128
dump(raw_ostream & OS,int Indent,PdbSymbolIdField ShowIdFields,PdbSymbolIdField RecurseIdFields) const129 void NativeTypeEnum::dump(raw_ostream &OS, int Indent,
130 PdbSymbolIdField ShowIdFields,
131 PdbSymbolIdField RecurseIdFields) const {
132 NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
133
134 dumpSymbolField(OS, "baseType", static_cast<uint32_t>(getBuiltinType()),
135 Indent);
136 dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
137 PdbSymbolIdField::LexicalParent, ShowIdFields,
138 RecurseIdFields);
139 dumpSymbolField(OS, "name", getName(), Indent);
140 dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
141 PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
142 if (Modifiers.hasValue())
143 dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent,
144 Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields,
145 RecurseIdFields);
146 dumpSymbolField(OS, "length", getLength(), Indent);
147 dumpSymbolField(OS, "constructor", hasConstructor(), Indent);
148 dumpSymbolField(OS, "constType", isConstType(), Indent);
149 dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent);
150 dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent);
151 dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent);
152 dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent);
153 dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent);
154 dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent);
155 dumpSymbolField(OS, "nested", isNested(), Indent);
156 dumpSymbolField(OS, "packed", isPacked(), Indent);
157 dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent);
158 dumpSymbolField(OS, "scoped", isScoped(), Indent);
159 dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
160 dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent);
161 dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
162 }
163
164 std::unique_ptr<IPDBEnumSymbols>
findChildren(PDB_SymType Type) const165 NativeTypeEnum::findChildren(PDB_SymType Type) const {
166 if (Type != PDB_SymType::Data)
167 return llvm::make_unique<NullEnumerator<PDBSymbol>>();
168
169 const NativeTypeEnum *ClassParent = nullptr;
170 if (!Modifiers)
171 ClassParent = this;
172 else
173 ClassParent = UnmodifiedType;
174 return llvm::make_unique<NativeEnumEnumEnumerators>(Session, *ClassParent);
175 }
176
getSymTag() const177 PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; }
178
getBuiltinType() const179 PDB_BuiltinType NativeTypeEnum::getBuiltinType() const {
180 if (UnmodifiedType)
181 return UnmodifiedType->getBuiltinType();
182
183 Session.getSymbolCache().findSymbolByTypeIndex(Record->getUnderlyingType());
184
185 codeview::TypeIndex Underlying = Record->getUnderlyingType();
186
187 // This indicates a corrupt record.
188 if (!Underlying.isSimple() ||
189 Underlying.getSimpleMode() != SimpleTypeMode::Direct) {
190 return PDB_BuiltinType::None;
191 }
192
193 switch (Underlying.getSimpleKind()) {
194 case SimpleTypeKind::Boolean128:
195 case SimpleTypeKind::Boolean64:
196 case SimpleTypeKind::Boolean32:
197 case SimpleTypeKind::Boolean16:
198 case SimpleTypeKind::Boolean8:
199 return PDB_BuiltinType::Bool;
200 case SimpleTypeKind::NarrowCharacter:
201 case SimpleTypeKind::UnsignedCharacter:
202 case SimpleTypeKind::SignedCharacter:
203 return PDB_BuiltinType::Char;
204 case SimpleTypeKind::WideCharacter:
205 return PDB_BuiltinType::WCharT;
206 case SimpleTypeKind::Character16:
207 return PDB_BuiltinType::Char16;
208 case SimpleTypeKind::Character32:
209 return PDB_BuiltinType::Char32;
210 case SimpleTypeKind::Int128:
211 case SimpleTypeKind::Int128Oct:
212 case SimpleTypeKind::Int16:
213 case SimpleTypeKind::Int16Short:
214 case SimpleTypeKind::Int32:
215 case SimpleTypeKind::Int32Long:
216 case SimpleTypeKind::Int64:
217 case SimpleTypeKind::Int64Quad:
218 return PDB_BuiltinType::Int;
219 case SimpleTypeKind::UInt128:
220 case SimpleTypeKind::UInt128Oct:
221 case SimpleTypeKind::UInt16:
222 case SimpleTypeKind::UInt16Short:
223 case SimpleTypeKind::UInt32:
224 case SimpleTypeKind::UInt32Long:
225 case SimpleTypeKind::UInt64:
226 case SimpleTypeKind::UInt64Quad:
227 return PDB_BuiltinType::UInt;
228 case SimpleTypeKind::HResult:
229 return PDB_BuiltinType::HResult;
230 case SimpleTypeKind::Complex16:
231 case SimpleTypeKind::Complex32:
232 case SimpleTypeKind::Complex32PartialPrecision:
233 case SimpleTypeKind::Complex64:
234 case SimpleTypeKind::Complex80:
235 case SimpleTypeKind::Complex128:
236 return PDB_BuiltinType::Complex;
237 case SimpleTypeKind::Float16:
238 case SimpleTypeKind::Float32:
239 case SimpleTypeKind::Float32PartialPrecision:
240 case SimpleTypeKind::Float48:
241 case SimpleTypeKind::Float64:
242 case SimpleTypeKind::Float80:
243 case SimpleTypeKind::Float128:
244 return PDB_BuiltinType::Float;
245 default:
246 return PDB_BuiltinType::None;
247 }
248 llvm_unreachable("Unreachable");
249 }
250
getUnmodifiedTypeId() const251 SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const {
252 return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0;
253 }
254
hasConstructor() const255 bool NativeTypeEnum::hasConstructor() const {
256 if (UnmodifiedType)
257 return UnmodifiedType->hasConstructor();
258
259 return bool(Record->getOptions() &
260 codeview::ClassOptions::HasConstructorOrDestructor);
261 }
262
hasAssignmentOperator() const263 bool NativeTypeEnum::hasAssignmentOperator() const {
264 if (UnmodifiedType)
265 return UnmodifiedType->hasAssignmentOperator();
266
267 return bool(Record->getOptions() &
268 codeview::ClassOptions::HasOverloadedAssignmentOperator);
269 }
270
hasNestedTypes() const271 bool NativeTypeEnum::hasNestedTypes() const {
272 if (UnmodifiedType)
273 return UnmodifiedType->hasNestedTypes();
274
275 return bool(Record->getOptions() &
276 codeview::ClassOptions::ContainsNestedClass);
277 }
278
isIntrinsic() const279 bool NativeTypeEnum::isIntrinsic() const {
280 if (UnmodifiedType)
281 return UnmodifiedType->isIntrinsic();
282
283 return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic);
284 }
285
hasCastOperator() const286 bool NativeTypeEnum::hasCastOperator() const {
287 if (UnmodifiedType)
288 return UnmodifiedType->hasCastOperator();
289
290 return bool(Record->getOptions() &
291 codeview::ClassOptions::HasConversionOperator);
292 }
293
getLength() const294 uint64_t NativeTypeEnum::getLength() const {
295 if (UnmodifiedType)
296 return UnmodifiedType->getLength();
297
298 const auto Id = Session.getSymbolCache().findSymbolByTypeIndex(
299 Record->getUnderlyingType());
300 const auto UnderlyingType =
301 Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id);
302 return UnderlyingType ? UnderlyingType->getLength() : 0;
303 }
304
getName() const305 std::string NativeTypeEnum::getName() const {
306 if (UnmodifiedType)
307 return UnmodifiedType->getName();
308
309 return Record->getName();
310 }
311
isNested() const312 bool NativeTypeEnum::isNested() const {
313 if (UnmodifiedType)
314 return UnmodifiedType->isNested();
315
316 return bool(Record->getOptions() & codeview::ClassOptions::Nested);
317 }
318
hasOverloadedOperator() const319 bool NativeTypeEnum::hasOverloadedOperator() const {
320 if (UnmodifiedType)
321 return UnmodifiedType->hasOverloadedOperator();
322
323 return bool(Record->getOptions() &
324 codeview::ClassOptions::HasOverloadedOperator);
325 }
326
isPacked() const327 bool NativeTypeEnum::isPacked() const {
328 if (UnmodifiedType)
329 return UnmodifiedType->isPacked();
330
331 return bool(Record->getOptions() & codeview::ClassOptions::Packed);
332 }
333
isScoped() const334 bool NativeTypeEnum::isScoped() const {
335 if (UnmodifiedType)
336 return UnmodifiedType->isScoped();
337
338 return bool(Record->getOptions() & codeview::ClassOptions::Scoped);
339 }
340
getTypeId() const341 SymIndexId NativeTypeEnum::getTypeId() const {
342 if (UnmodifiedType)
343 return UnmodifiedType->getTypeId();
344
345 return Session.getSymbolCache().findSymbolByTypeIndex(
346 Record->getUnderlyingType());
347 }
348
isRefUdt() const349 bool NativeTypeEnum::isRefUdt() const { return false; }
350
isValueUdt() const351 bool NativeTypeEnum::isValueUdt() const { return false; }
352
isInterfaceUdt() const353 bool NativeTypeEnum::isInterfaceUdt() const { return false; }
354
isConstType() const355 bool NativeTypeEnum::isConstType() const {
356 if (!Modifiers)
357 return false;
358 return ((Modifiers->getModifiers() & ModifierOptions::Const) !=
359 ModifierOptions::None);
360 }
361
isVolatileType() const362 bool NativeTypeEnum::isVolatileType() const {
363 if (!Modifiers)
364 return false;
365 return ((Modifiers->getModifiers() & ModifierOptions::Volatile) !=
366 ModifierOptions::None);
367 }
368
isUnalignedType() const369 bool NativeTypeEnum::isUnalignedType() const {
370 if (!Modifiers)
371 return false;
372 return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) !=
373 ModifierOptions::None);
374 }
375
getUnderlyingBuiltinType() const376 const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const {
377 if (UnmodifiedType)
378 return UnmodifiedType->getUnderlyingBuiltinType();
379
380 return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>(
381 getTypeId());
382 }
383