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