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 #include <optional>
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 std::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 FieldListCVT = Types.getType(*ContinuationIndex);
72 assert(FieldListCVT.kind() == LF_FIELDLIST);
73 ContinuationIndex.reset();
74 FieldListRecord FieldList;
75 cantFail(TypeDeserializer::deserializeAs<FieldListRecord>(FieldListCVT,
76 FieldList));
77 cantFail(visitMemberRecordStream(FieldList.Data, *this));
78 }
79 }
80
visitKnownMember(CVMemberRecord & CVM,EnumeratorRecord & Record)81 Error NativeEnumEnumEnumerators::visitKnownMember(CVMemberRecord &CVM,
82 EnumeratorRecord &Record) {
83 Enumerators.push_back(Record);
84 return Error::success();
85 }
86
visitKnownMember(CVMemberRecord & CVM,ListContinuationRecord & Record)87 Error NativeEnumEnumEnumerators::visitKnownMember(
88 CVMemberRecord &CVM, ListContinuationRecord &Record) {
89 ContinuationIndex = Record.ContinuationIndex;
90 return Error::success();
91 }
92
getChildCount() const93 uint32_t NativeEnumEnumEnumerators::getChildCount() const {
94 return Enumerators.size();
95 }
96
97 std::unique_ptr<PDBSymbol>
getChildAtIndex(uint32_t Index) const98 NativeEnumEnumEnumerators::getChildAtIndex(uint32_t Index) const {
99 if (Index >= getChildCount())
100 return nullptr;
101
102 SymIndexId Id = Session.getSymbolCache()
103 .getOrCreateFieldListMember<NativeSymbolEnumerator>(
104 ClassParent.getEnumRecord().FieldList, Index,
105 ClassParent, Enumerators[Index]);
106 return Session.getSymbolCache().getSymbolById(Id);
107 }
108
getNext()109 std::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::getNext() {
110 if (Index >= getChildCount())
111 return nullptr;
112
113 return getChildAtIndex(Index++);
114 }
115
reset()116 void NativeEnumEnumEnumerators::reset() { Index = 0; }
117
NativeTypeEnum(NativeSession & Session,SymIndexId Id,TypeIndex Index,EnumRecord Record)118 NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
119 TypeIndex Index, EnumRecord Record)
120 : NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(Index),
121 Record(std::move(Record)) {}
122
NativeTypeEnum(NativeSession & Session,SymIndexId Id,NativeTypeEnum & UnmodifiedType,codeview::ModifierRecord Modifier)123 NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
124 NativeTypeEnum &UnmodifiedType,
125 codeview::ModifierRecord Modifier)
126 : NativeRawSymbol(Session, PDB_SymType::Enum, Id),
127 UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {}
128
129 NativeTypeEnum::~NativeTypeEnum() = default;
130
dump(raw_ostream & OS,int Indent,PdbSymbolIdField ShowIdFields,PdbSymbolIdField RecurseIdFields) const131 void NativeTypeEnum::dump(raw_ostream &OS, int Indent,
132 PdbSymbolIdField ShowIdFields,
133 PdbSymbolIdField RecurseIdFields) const {
134 NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
135
136 dumpSymbolField(OS, "baseType", static_cast<uint32_t>(getBuiltinType()),
137 Indent);
138 dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
139 PdbSymbolIdField::LexicalParent, ShowIdFields,
140 RecurseIdFields);
141 dumpSymbolField(OS, "name", getName(), Indent);
142 dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
143 PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
144 if (Modifiers)
145 dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent,
146 Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields,
147 RecurseIdFields);
148 dumpSymbolField(OS, "length", getLength(), Indent);
149 dumpSymbolField(OS, "constructor", hasConstructor(), Indent);
150 dumpSymbolField(OS, "constType", isConstType(), Indent);
151 dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent);
152 dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent);
153 dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent);
154 dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent);
155 dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent);
156 dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent);
157 dumpSymbolField(OS, "nested", isNested(), Indent);
158 dumpSymbolField(OS, "packed", isPacked(), Indent);
159 dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent);
160 dumpSymbolField(OS, "scoped", isScoped(), Indent);
161 dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
162 dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent);
163 dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
164 }
165
166 std::unique_ptr<IPDBEnumSymbols>
findChildren(PDB_SymType Type) const167 NativeTypeEnum::findChildren(PDB_SymType Type) const {
168 if (Type != PDB_SymType::Data)
169 return std::make_unique<NullEnumerator<PDBSymbol>>();
170
171 const NativeTypeEnum *ClassParent = nullptr;
172 if (!Modifiers)
173 ClassParent = this;
174 else
175 ClassParent = UnmodifiedType;
176 return std::make_unique<NativeEnumEnumEnumerators>(Session, *ClassParent);
177 }
178
getSymTag() const179 PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; }
180
getBuiltinType() const181 PDB_BuiltinType NativeTypeEnum::getBuiltinType() const {
182 if (UnmodifiedType)
183 return UnmodifiedType->getBuiltinType();
184
185 Session.getSymbolCache().findSymbolByTypeIndex(Record->getUnderlyingType());
186
187 codeview::TypeIndex Underlying = Record->getUnderlyingType();
188
189 // This indicates a corrupt record.
190 if (!Underlying.isSimple() ||
191 Underlying.getSimpleMode() != SimpleTypeMode::Direct) {
192 return PDB_BuiltinType::None;
193 }
194
195 switch (Underlying.getSimpleKind()) {
196 case SimpleTypeKind::Boolean128:
197 case SimpleTypeKind::Boolean64:
198 case SimpleTypeKind::Boolean32:
199 case SimpleTypeKind::Boolean16:
200 case SimpleTypeKind::Boolean8:
201 return PDB_BuiltinType::Bool;
202 case SimpleTypeKind::NarrowCharacter:
203 case SimpleTypeKind::UnsignedCharacter:
204 case SimpleTypeKind::SignedCharacter:
205 return PDB_BuiltinType::Char;
206 case SimpleTypeKind::WideCharacter:
207 return PDB_BuiltinType::WCharT;
208 case SimpleTypeKind::Character16:
209 return PDB_BuiltinType::Char16;
210 case SimpleTypeKind::Character32:
211 return PDB_BuiltinType::Char32;
212 case SimpleTypeKind::Character8:
213 return PDB_BuiltinType::Char8;
214 case SimpleTypeKind::Int128:
215 case SimpleTypeKind::Int128Oct:
216 case SimpleTypeKind::Int16:
217 case SimpleTypeKind::Int16Short:
218 case SimpleTypeKind::Int32:
219 case SimpleTypeKind::Int32Long:
220 case SimpleTypeKind::Int64:
221 case SimpleTypeKind::Int64Quad:
222 return PDB_BuiltinType::Int;
223 case SimpleTypeKind::UInt128:
224 case SimpleTypeKind::UInt128Oct:
225 case SimpleTypeKind::UInt16:
226 case SimpleTypeKind::UInt16Short:
227 case SimpleTypeKind::UInt32:
228 case SimpleTypeKind::UInt32Long:
229 case SimpleTypeKind::UInt64:
230 case SimpleTypeKind::UInt64Quad:
231 return PDB_BuiltinType::UInt;
232 case SimpleTypeKind::HResult:
233 return PDB_BuiltinType::HResult;
234 case SimpleTypeKind::Complex16:
235 case SimpleTypeKind::Complex32:
236 case SimpleTypeKind::Complex32PartialPrecision:
237 case SimpleTypeKind::Complex64:
238 case SimpleTypeKind::Complex80:
239 case SimpleTypeKind::Complex128:
240 return PDB_BuiltinType::Complex;
241 case SimpleTypeKind::Float16:
242 case SimpleTypeKind::Float32:
243 case SimpleTypeKind::Float32PartialPrecision:
244 case SimpleTypeKind::Float48:
245 case SimpleTypeKind::Float64:
246 case SimpleTypeKind::Float80:
247 case SimpleTypeKind::Float128:
248 return PDB_BuiltinType::Float;
249 default:
250 return PDB_BuiltinType::None;
251 }
252 llvm_unreachable("Unreachable");
253 }
254
getUnmodifiedTypeId() const255 SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const {
256 return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0;
257 }
258
hasConstructor() const259 bool NativeTypeEnum::hasConstructor() const {
260 if (UnmodifiedType)
261 return UnmodifiedType->hasConstructor();
262
263 return bool(Record->getOptions() &
264 codeview::ClassOptions::HasConstructorOrDestructor);
265 }
266
hasAssignmentOperator() const267 bool NativeTypeEnum::hasAssignmentOperator() const {
268 if (UnmodifiedType)
269 return UnmodifiedType->hasAssignmentOperator();
270
271 return bool(Record->getOptions() &
272 codeview::ClassOptions::HasOverloadedAssignmentOperator);
273 }
274
hasNestedTypes() const275 bool NativeTypeEnum::hasNestedTypes() const {
276 if (UnmodifiedType)
277 return UnmodifiedType->hasNestedTypes();
278
279 return bool(Record->getOptions() &
280 codeview::ClassOptions::ContainsNestedClass);
281 }
282
isIntrinsic() const283 bool NativeTypeEnum::isIntrinsic() const {
284 if (UnmodifiedType)
285 return UnmodifiedType->isIntrinsic();
286
287 return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic);
288 }
289
hasCastOperator() const290 bool NativeTypeEnum::hasCastOperator() const {
291 if (UnmodifiedType)
292 return UnmodifiedType->hasCastOperator();
293
294 return bool(Record->getOptions() &
295 codeview::ClassOptions::HasConversionOperator);
296 }
297
getLength() const298 uint64_t NativeTypeEnum::getLength() const {
299 if (UnmodifiedType)
300 return UnmodifiedType->getLength();
301
302 const auto Id = Session.getSymbolCache().findSymbolByTypeIndex(
303 Record->getUnderlyingType());
304 const auto UnderlyingType =
305 Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id);
306 return UnderlyingType ? UnderlyingType->getLength() : 0;
307 }
308
getName() const309 std::string NativeTypeEnum::getName() const {
310 if (UnmodifiedType)
311 return UnmodifiedType->getName();
312
313 return std::string(Record->getName());
314 }
315
isNested() const316 bool NativeTypeEnum::isNested() const {
317 if (UnmodifiedType)
318 return UnmodifiedType->isNested();
319
320 return bool(Record->getOptions() & codeview::ClassOptions::Nested);
321 }
322
hasOverloadedOperator() const323 bool NativeTypeEnum::hasOverloadedOperator() const {
324 if (UnmodifiedType)
325 return UnmodifiedType->hasOverloadedOperator();
326
327 return bool(Record->getOptions() &
328 codeview::ClassOptions::HasOverloadedOperator);
329 }
330
isPacked() const331 bool NativeTypeEnum::isPacked() const {
332 if (UnmodifiedType)
333 return UnmodifiedType->isPacked();
334
335 return bool(Record->getOptions() & codeview::ClassOptions::Packed);
336 }
337
isScoped() const338 bool NativeTypeEnum::isScoped() const {
339 if (UnmodifiedType)
340 return UnmodifiedType->isScoped();
341
342 return bool(Record->getOptions() & codeview::ClassOptions::Scoped);
343 }
344
getTypeId() const345 SymIndexId NativeTypeEnum::getTypeId() const {
346 if (UnmodifiedType)
347 return UnmodifiedType->getTypeId();
348
349 return Session.getSymbolCache().findSymbolByTypeIndex(
350 Record->getUnderlyingType());
351 }
352
isRefUdt() const353 bool NativeTypeEnum::isRefUdt() const { return false; }
354
isValueUdt() const355 bool NativeTypeEnum::isValueUdt() const { return false; }
356
isInterfaceUdt() const357 bool NativeTypeEnum::isInterfaceUdt() const { return false; }
358
isConstType() const359 bool NativeTypeEnum::isConstType() const {
360 if (!Modifiers)
361 return false;
362 return ((Modifiers->getModifiers() & ModifierOptions::Const) !=
363 ModifierOptions::None);
364 }
365
isVolatileType() const366 bool NativeTypeEnum::isVolatileType() const {
367 if (!Modifiers)
368 return false;
369 return ((Modifiers->getModifiers() & ModifierOptions::Volatile) !=
370 ModifierOptions::None);
371 }
372
isUnalignedType() const373 bool NativeTypeEnum::isUnalignedType() const {
374 if (!Modifiers)
375 return false;
376 return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) !=
377 ModifierOptions::None);
378 }
379
getUnderlyingBuiltinType() const380 const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const {
381 if (UnmodifiedType)
382 return UnmodifiedType->getUnderlyingBuiltinType();
383
384 return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>(
385 getTypeId());
386 }
387