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