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 
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 
78 Error NativeEnumEnumEnumerators::visitKnownMember(CVMemberRecord &CVM,
79                                                   EnumeratorRecord &Record) {
80   Enumerators.push_back(Record);
81   return Error::success();
82 }
83 
84 Error NativeEnumEnumEnumerators::visitKnownMember(
85     CVMemberRecord &CVM, ListContinuationRecord &Record) {
86   ContinuationIndex = Record.ContinuationIndex;
87   return Error::success();
88 }
89 
90 uint32_t NativeEnumEnumEnumerators::getChildCount() const {
91   return Enumerators.size();
92 }
93 
94 std::unique_ptr<PDBSymbol>
95 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 
106 std::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::getNext() {
107   if (Index >= getChildCount())
108     return nullptr;
109 
110   return getChildAtIndex(Index++);
111 }
112 
113 void NativeEnumEnumEnumerators::reset() { Index = 0; }
114 
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 
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 
126 NativeTypeEnum::~NativeTypeEnum() {}
127 
128 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>
164 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 
176 PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; }
177 
178 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 
250 SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const {
251   return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0;
252 }
253 
254 bool NativeTypeEnum::hasConstructor() const {
255   if (UnmodifiedType)
256     return UnmodifiedType->hasConstructor();
257 
258   return bool(Record->getOptions() &
259               codeview::ClassOptions::HasConstructorOrDestructor);
260 }
261 
262 bool NativeTypeEnum::hasAssignmentOperator() const {
263   if (UnmodifiedType)
264     return UnmodifiedType->hasAssignmentOperator();
265 
266   return bool(Record->getOptions() &
267               codeview::ClassOptions::HasOverloadedAssignmentOperator);
268 }
269 
270 bool NativeTypeEnum::hasNestedTypes() const {
271   if (UnmodifiedType)
272     return UnmodifiedType->hasNestedTypes();
273 
274   return bool(Record->getOptions() &
275               codeview::ClassOptions::ContainsNestedClass);
276 }
277 
278 bool NativeTypeEnum::isIntrinsic() const {
279   if (UnmodifiedType)
280     return UnmodifiedType->isIntrinsic();
281 
282   return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic);
283 }
284 
285 bool NativeTypeEnum::hasCastOperator() const {
286   if (UnmodifiedType)
287     return UnmodifiedType->hasCastOperator();
288 
289   return bool(Record->getOptions() &
290               codeview::ClassOptions::HasConversionOperator);
291 }
292 
293 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 
304 std::string NativeTypeEnum::getName() const {
305   if (UnmodifiedType)
306     return UnmodifiedType->getName();
307 
308   return std::string(Record->getName());
309 }
310 
311 bool NativeTypeEnum::isNested() const {
312   if (UnmodifiedType)
313     return UnmodifiedType->isNested();
314 
315   return bool(Record->getOptions() & codeview::ClassOptions::Nested);
316 }
317 
318 bool NativeTypeEnum::hasOverloadedOperator() const {
319   if (UnmodifiedType)
320     return UnmodifiedType->hasOverloadedOperator();
321 
322   return bool(Record->getOptions() &
323               codeview::ClassOptions::HasOverloadedOperator);
324 }
325 
326 bool NativeTypeEnum::isPacked() const {
327   if (UnmodifiedType)
328     return UnmodifiedType->isPacked();
329 
330   return bool(Record->getOptions() & codeview::ClassOptions::Packed);
331 }
332 
333 bool NativeTypeEnum::isScoped() const {
334   if (UnmodifiedType)
335     return UnmodifiedType->isScoped();
336 
337   return bool(Record->getOptions() & codeview::ClassOptions::Scoped);
338 }
339 
340 SymIndexId NativeTypeEnum::getTypeId() const {
341   if (UnmodifiedType)
342     return UnmodifiedType->getTypeId();
343 
344   return Session.getSymbolCache().findSymbolByTypeIndex(
345       Record->getUnderlyingType());
346 }
347 
348 bool NativeTypeEnum::isRefUdt() const { return false; }
349 
350 bool NativeTypeEnum::isValueUdt() const { return false; }
351 
352 bool NativeTypeEnum::isInterfaceUdt() const { return false; }
353 
354 bool NativeTypeEnum::isConstType() const {
355   if (!Modifiers)
356     return false;
357   return ((Modifiers->getModifiers() & ModifierOptions::Const) !=
358           ModifierOptions::None);
359 }
360 
361 bool NativeTypeEnum::isVolatileType() const {
362   if (!Modifiers)
363     return false;
364   return ((Modifiers->getModifiers() & ModifierOptions::Volatile) !=
365           ModifierOptions::None);
366 }
367 
368 bool NativeTypeEnum::isUnalignedType() const {
369   if (!Modifiers)
370     return false;
371   return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) !=
372           ModifierOptions::None);
373 }
374 
375 const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const {
376   if (UnmodifiedType)
377     return UnmodifiedType->getUnderlyingBuiltinType();
378 
379   return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>(
380       getTypeId());
381 }
382