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 25using namespace llvm; 26using namespace llvm::codeview; 27using namespace llvm::pdb; 28 29namespace { 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. 39class NativeEnumEnumEnumerators : public IPDBEnumSymbols, TypeVisitorCallbacks { 40public: 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 49private: 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 63NativeEnumEnumEnumerators::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 81Error NativeEnumEnumEnumerators::visitKnownMember(CVMemberRecord &CVM, 82 EnumeratorRecord &Record) { 83 Enumerators.push_back(Record); 84 return Error::success(); 85} 86 87Error NativeEnumEnumEnumerators::visitKnownMember( 88 CVMemberRecord &CVM, ListContinuationRecord &Record) { 89 ContinuationIndex = Record.ContinuationIndex; 90 return Error::success(); 91} 92 93uint32_t NativeEnumEnumEnumerators::getChildCount() const { 94 return Enumerators.size(); 95} 96 97std::unique_ptr<PDBSymbol> 98NativeEnumEnumEnumerators::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 109std::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::getNext() { 110 if (Index >= getChildCount()) 111 return nullptr; 112 113 return getChildAtIndex(Index++); 114} 115 116void NativeEnumEnumEnumerators::reset() { Index = 0; } 117 118NativeTypeEnum::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 123NativeTypeEnum::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 129NativeTypeEnum::~NativeTypeEnum() = default; 130 131void 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 166std::unique_ptr<IPDBEnumSymbols> 167NativeTypeEnum::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 179PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; } 180 181PDB_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 255SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const { 256 return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0; 257} 258 259bool NativeTypeEnum::hasConstructor() const { 260 if (UnmodifiedType) 261 return UnmodifiedType->hasConstructor(); 262 263 return bool(Record->getOptions() & 264 codeview::ClassOptions::HasConstructorOrDestructor); 265} 266 267bool NativeTypeEnum::hasAssignmentOperator() const { 268 if (UnmodifiedType) 269 return UnmodifiedType->hasAssignmentOperator(); 270 271 return bool(Record->getOptions() & 272 codeview::ClassOptions::HasOverloadedAssignmentOperator); 273} 274 275bool NativeTypeEnum::hasNestedTypes() const { 276 if (UnmodifiedType) 277 return UnmodifiedType->hasNestedTypes(); 278 279 return bool(Record->getOptions() & 280 codeview::ClassOptions::ContainsNestedClass); 281} 282 283bool NativeTypeEnum::isIntrinsic() const { 284 if (UnmodifiedType) 285 return UnmodifiedType->isIntrinsic(); 286 287 return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic); 288} 289 290bool NativeTypeEnum::hasCastOperator() const { 291 if (UnmodifiedType) 292 return UnmodifiedType->hasCastOperator(); 293 294 return bool(Record->getOptions() & 295 codeview::ClassOptions::HasConversionOperator); 296} 297 298uint64_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 309std::string NativeTypeEnum::getName() const { 310 if (UnmodifiedType) 311 return UnmodifiedType->getName(); 312 313 return std::string(Record->getName()); 314} 315 316bool NativeTypeEnum::isNested() const { 317 if (UnmodifiedType) 318 return UnmodifiedType->isNested(); 319 320 return bool(Record->getOptions() & codeview::ClassOptions::Nested); 321} 322 323bool NativeTypeEnum::hasOverloadedOperator() const { 324 if (UnmodifiedType) 325 return UnmodifiedType->hasOverloadedOperator(); 326 327 return bool(Record->getOptions() & 328 codeview::ClassOptions::HasOverloadedOperator); 329} 330 331bool NativeTypeEnum::isPacked() const { 332 if (UnmodifiedType) 333 return UnmodifiedType->isPacked(); 334 335 return bool(Record->getOptions() & codeview::ClassOptions::Packed); 336} 337 338bool NativeTypeEnum::isScoped() const { 339 if (UnmodifiedType) 340 return UnmodifiedType->isScoped(); 341 342 return bool(Record->getOptions() & codeview::ClassOptions::Scoped); 343} 344 345SymIndexId NativeTypeEnum::getTypeId() const { 346 if (UnmodifiedType) 347 return UnmodifiedType->getTypeId(); 348 349 return Session.getSymbolCache().findSymbolByTypeIndex( 350 Record->getUnderlyingType()); 351} 352 353bool NativeTypeEnum::isRefUdt() const { return false; } 354 355bool NativeTypeEnum::isValueUdt() const { return false; } 356 357bool NativeTypeEnum::isInterfaceUdt() const { return false; } 358 359bool NativeTypeEnum::isConstType() const { 360 if (!Modifiers) 361 return false; 362 return ((Modifiers->getModifiers() & ModifierOptions::Const) != 363 ModifierOptions::None); 364} 365 366bool NativeTypeEnum::isVolatileType() const { 367 if (!Modifiers) 368 return false; 369 return ((Modifiers->getModifiers() & ModifierOptions::Volatile) != 370 ModifierOptions::None); 371} 372 373bool NativeTypeEnum::isUnalignedType() const { 374 if (!Modifiers) 375 return false; 376 return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) != 377 ModifierOptions::None); 378} 379 380const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const { 381 if (UnmodifiedType) 382 return UnmodifiedType->getUnderlyingBuiltinType(); 383 384 return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>( 385 getTypeId()); 386} 387