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 : 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 &; |
56 | const NativeTypeEnum &; |
57 | std::vector<EnumeratorRecord> ; |
58 | std::optional<TypeIndex> ; |
59 | uint32_t = 0; |
60 | }; |
61 | } // namespace |
62 | |
63 | NativeEnumEnumEnumerators::( |
64 | NativeSession &Session, const NativeTypeEnum &ClassParent) |
65 | : Session(Session), ClassParent(ClassParent) { |
66 | TpiStream &Tpi = cantFail(ValOrErr: Session.getPDBFile().getPDBTpiStream()); |
67 | LazyRandomTypeCollection &Types = Tpi.typeCollection(); |
68 | |
69 | ContinuationIndex = ClassParent.getEnumRecord().FieldList; |
70 | while (ContinuationIndex) { |
71 | CVType FieldListCVT = Types.getType(Index: *ContinuationIndex); |
72 | assert(FieldListCVT.kind() == LF_FIELDLIST); |
73 | ContinuationIndex.reset(); |
74 | FieldListRecord FieldList; |
75 | cantFail(Err: TypeDeserializer::deserializeAs<FieldListRecord>(CVT&: FieldListCVT, |
76 | Record&: FieldList)); |
77 | cantFail(Err: visitMemberRecordStream(FieldList: FieldList.Data, Callbacks&: *this)); |
78 | } |
79 | } |
80 | |
81 | Error NativeEnumEnumEnumerators::(CVMemberRecord &CVM, |
82 | EnumeratorRecord &Record) { |
83 | Enumerators.push_back(x: Record); |
84 | return Error::success(); |
85 | } |
86 | |
87 | Error NativeEnumEnumEnumerators::( |
88 | CVMemberRecord &CVM, ListContinuationRecord &Record) { |
89 | ContinuationIndex = Record.ContinuationIndex; |
90 | return Error::success(); |
91 | } |
92 | |
93 | uint32_t NativeEnumEnumEnumerators::() const { |
94 | return Enumerators.size(); |
95 | } |
96 | |
97 | std::unique_ptr<PDBSymbol> |
98 | NativeEnumEnumEnumerators::(uint32_t Index) const { |
99 | if (Index >= getChildCount()) |
100 | return nullptr; |
101 | |
102 | SymIndexId Id = Session.getSymbolCache() |
103 | .getOrCreateFieldListMember<NativeSymbolEnumerator>( |
104 | FieldListTI: ClassParent.getEnumRecord().FieldList, Index, |
105 | ConstructorArgs: ClassParent, ConstructorArgs: Enumerators[Index]); |
106 | return Session.getSymbolCache().getSymbolById(SymbolId: Id); |
107 | } |
108 | |
109 | std::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::() { |
110 | if (Index >= getChildCount()) |
111 | return nullptr; |
112 | |
113 | return getChildAtIndex(Index: Index++); |
114 | } |
115 | |
116 | void NativeEnumEnumEnumerators::() { Index = 0; } |
117 | |
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 | |
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 | |
131 | 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, Name: "baseType" , Value: static_cast<uint32_t>(getBuiltinType()), |
137 | Indent); |
138 | dumpSymbolIdField(OS, Name: "lexicalParentId" , Value: 0, Indent, Session, |
139 | FieldId: PdbSymbolIdField::LexicalParent, ShowFlags: ShowIdFields, |
140 | RecurseFlags: RecurseIdFields); |
141 | dumpSymbolField(OS, Name: "name" , Value: getName(), Indent); |
142 | dumpSymbolIdField(OS, Name: "typeId" , Value: getTypeId(), Indent, Session, |
143 | FieldId: PdbSymbolIdField::Type, ShowFlags: ShowIdFields, RecurseFlags: RecurseIdFields); |
144 | if (Modifiers) |
145 | dumpSymbolIdField(OS, Name: "unmodifiedTypeId" , Value: getUnmodifiedTypeId(), Indent, |
146 | Session, FieldId: PdbSymbolIdField::UnmodifiedType, ShowFlags: ShowIdFields, |
147 | RecurseFlags: RecurseIdFields); |
148 | dumpSymbolField(OS, Name: "length" , Value: getLength(), Indent); |
149 | dumpSymbolField(OS, Name: "constructor" , Value: hasConstructor(), Indent); |
150 | dumpSymbolField(OS, Name: "constType" , Value: isConstType(), Indent); |
151 | dumpSymbolField(OS, Name: "hasAssignmentOperator" , Value: hasAssignmentOperator(), Indent); |
152 | dumpSymbolField(OS, Name: "hasCastOperator" , Value: hasCastOperator(), Indent); |
153 | dumpSymbolField(OS, Name: "hasNestedTypes" , Value: hasNestedTypes(), Indent); |
154 | dumpSymbolField(OS, Name: "overloadedOperator" , Value: hasOverloadedOperator(), Indent); |
155 | dumpSymbolField(OS, Name: "isInterfaceUdt" , Value: isInterfaceUdt(), Indent); |
156 | dumpSymbolField(OS, Name: "intrinsic" , Value: isIntrinsic(), Indent); |
157 | dumpSymbolField(OS, Name: "nested" , Value: isNested(), Indent); |
158 | dumpSymbolField(OS, Name: "packed" , Value: isPacked(), Indent); |
159 | dumpSymbolField(OS, Name: "isRefUdt" , Value: isRefUdt(), Indent); |
160 | dumpSymbolField(OS, Name: "scoped" , Value: isScoped(), Indent); |
161 | dumpSymbolField(OS, Name: "unalignedType" , Value: isUnalignedType(), Indent); |
162 | dumpSymbolField(OS, Name: "isValueUdt" , Value: isValueUdt(), Indent); |
163 | dumpSymbolField(OS, Name: "volatileType" , Value: isVolatileType(), Indent); |
164 | } |
165 | |
166 | std::unique_ptr<IPDBEnumSymbols> |
167 | 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>(args&: Session, args: *ClassParent); |
177 | } |
178 | |
179 | PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; } |
180 | |
181 | PDB_BuiltinType NativeTypeEnum::getBuiltinType() const { |
182 | if (UnmodifiedType) |
183 | return UnmodifiedType->getBuiltinType(); |
184 | |
185 | Session.getSymbolCache().findSymbolByTypeIndex(TI: 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 | |
255 | SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const { |
256 | return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0; |
257 | } |
258 | |
259 | bool NativeTypeEnum::hasConstructor() const { |
260 | if (UnmodifiedType) |
261 | return UnmodifiedType->hasConstructor(); |
262 | |
263 | return bool(Record->getOptions() & |
264 | codeview::ClassOptions::HasConstructorOrDestructor); |
265 | } |
266 | |
267 | bool NativeTypeEnum::hasAssignmentOperator() const { |
268 | if (UnmodifiedType) |
269 | return UnmodifiedType->hasAssignmentOperator(); |
270 | |
271 | return bool(Record->getOptions() & |
272 | codeview::ClassOptions::HasOverloadedAssignmentOperator); |
273 | } |
274 | |
275 | bool NativeTypeEnum::hasNestedTypes() const { |
276 | if (UnmodifiedType) |
277 | return UnmodifiedType->hasNestedTypes(); |
278 | |
279 | return bool(Record->getOptions() & |
280 | codeview::ClassOptions::ContainsNestedClass); |
281 | } |
282 | |
283 | bool NativeTypeEnum::isIntrinsic() const { |
284 | if (UnmodifiedType) |
285 | return UnmodifiedType->isIntrinsic(); |
286 | |
287 | return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic); |
288 | } |
289 | |
290 | bool NativeTypeEnum::hasCastOperator() const { |
291 | if (UnmodifiedType) |
292 | return UnmodifiedType->hasCastOperator(); |
293 | |
294 | return bool(Record->getOptions() & |
295 | codeview::ClassOptions::HasConversionOperator); |
296 | } |
297 | |
298 | uint64_t NativeTypeEnum::getLength() const { |
299 | if (UnmodifiedType) |
300 | return UnmodifiedType->getLength(); |
301 | |
302 | const auto Id = Session.getSymbolCache().findSymbolByTypeIndex( |
303 | TI: Record->getUnderlyingType()); |
304 | const auto UnderlyingType = |
305 | Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(SymbolId: Id); |
306 | return UnderlyingType ? UnderlyingType->getLength() : 0; |
307 | } |
308 | |
309 | std::string NativeTypeEnum::getName() const { |
310 | if (UnmodifiedType) |
311 | return UnmodifiedType->getName(); |
312 | |
313 | return std::string(Record->getName()); |
314 | } |
315 | |
316 | bool NativeTypeEnum::isNested() const { |
317 | if (UnmodifiedType) |
318 | return UnmodifiedType->isNested(); |
319 | |
320 | return bool(Record->getOptions() & codeview::ClassOptions::Nested); |
321 | } |
322 | |
323 | bool NativeTypeEnum::hasOverloadedOperator() const { |
324 | if (UnmodifiedType) |
325 | return UnmodifiedType->hasOverloadedOperator(); |
326 | |
327 | return bool(Record->getOptions() & |
328 | codeview::ClassOptions::HasOverloadedOperator); |
329 | } |
330 | |
331 | bool NativeTypeEnum::isPacked() const { |
332 | if (UnmodifiedType) |
333 | return UnmodifiedType->isPacked(); |
334 | |
335 | return bool(Record->getOptions() & codeview::ClassOptions::Packed); |
336 | } |
337 | |
338 | bool NativeTypeEnum::isScoped() const { |
339 | if (UnmodifiedType) |
340 | return UnmodifiedType->isScoped(); |
341 | |
342 | return bool(Record->getOptions() & codeview::ClassOptions::Scoped); |
343 | } |
344 | |
345 | SymIndexId NativeTypeEnum::getTypeId() const { |
346 | if (UnmodifiedType) |
347 | return UnmodifiedType->getTypeId(); |
348 | |
349 | return Session.getSymbolCache().findSymbolByTypeIndex( |
350 | TI: Record->getUnderlyingType()); |
351 | } |
352 | |
353 | bool NativeTypeEnum::isRefUdt() const { return false; } |
354 | |
355 | bool NativeTypeEnum::isValueUdt() const { return false; } |
356 | |
357 | bool NativeTypeEnum::isInterfaceUdt() const { return false; } |
358 | |
359 | bool NativeTypeEnum::isConstType() const { |
360 | if (!Modifiers) |
361 | return false; |
362 | return ((Modifiers->getModifiers() & ModifierOptions::Const) != |
363 | ModifierOptions::None); |
364 | } |
365 | |
366 | bool NativeTypeEnum::isVolatileType() const { |
367 | if (!Modifiers) |
368 | return false; |
369 | return ((Modifiers->getModifiers() & ModifierOptions::Volatile) != |
370 | ModifierOptions::None); |
371 | } |
372 | |
373 | bool NativeTypeEnum::isUnalignedType() const { |
374 | if (!Modifiers) |
375 | return false; |
376 | return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) != |
377 | ModifierOptions::None); |
378 | } |
379 | |
380 | const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const { |
381 | if (UnmodifiedType) |
382 | return UnmodifiedType->getUnderlyingBuiltinType(); |
383 | |
384 | return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>( |
385 | SymbolId: getTypeId()); |
386 | } |
387 | |