xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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