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 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