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