1343171Sdim//===- NativeTypeEnum.cpp - info about enum type ----------------*- C++ -*-===// 2343171Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343171Sdim// 7343171Sdim//===----------------------------------------------------------------------===// 8343171Sdim 9343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" 10343171Sdim 11343171Sdim#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" 12343171Sdim#include "llvm/DebugInfo/CodeView/TypeRecord.h" 13343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" 14343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h" 15343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" 16343171Sdim#include "llvm/DebugInfo/PDB/Native/PDBFile.h" 17343171Sdim#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" 18343171Sdim#include "llvm/DebugInfo/PDB/Native/TpiStream.h" 19343171Sdim#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" 20343171Sdim 21343171Sdim#include "llvm/Support/FormatVariadic.h" 22343171Sdim 23343171Sdim#include <cassert> 24343171Sdim 25343171Sdimusing namespace llvm; 26343171Sdimusing namespace llvm::codeview; 27343171Sdimusing namespace llvm::pdb; 28343171Sdim 29343171Sdimnamespace { 30343171Sdim// Yea, this is a pretty terrible class name. But if we have an enum: 31343171Sdim// 32343171Sdim// enum Foo { 33343171Sdim// A, 34343171Sdim// B 35343171Sdim// }; 36343171Sdim// 37343171Sdim// then A and B are the "enumerators" of the "enum" Foo. And we need 38343171Sdim// to enumerate them. 39343171Sdimclass NativeEnumEnumEnumerators : public IPDBEnumSymbols, TypeVisitorCallbacks { 40343171Sdimpublic: 41343171Sdim NativeEnumEnumEnumerators(NativeSession &Session, 42343171Sdim const NativeTypeEnum &ClassParent); 43343171Sdim 44343171Sdim uint32_t getChildCount() const override; 45343171Sdim std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override; 46343171Sdim std::unique_ptr<PDBSymbol> getNext() override; 47343171Sdim void reset() override; 48343171Sdim 49343171Sdimprivate: 50343171Sdim Error visitKnownMember(CVMemberRecord &CVM, 51343171Sdim EnumeratorRecord &Record) override; 52343171Sdim Error visitKnownMember(CVMemberRecord &CVM, 53343171Sdim ListContinuationRecord &Record) override; 54343171Sdim 55343171Sdim NativeSession &Session; 56343171Sdim const NativeTypeEnum &ClassParent; 57343171Sdim std::vector<EnumeratorRecord> Enumerators; 58343171Sdim Optional<TypeIndex> ContinuationIndex; 59343171Sdim uint32_t Index = 0; 60343171Sdim}; 61343171Sdim} // namespace 62343171Sdim 63343171SdimNativeEnumEnumEnumerators::NativeEnumEnumEnumerators( 64343171Sdim NativeSession &Session, const NativeTypeEnum &ClassParent) 65343171Sdim : Session(Session), ClassParent(ClassParent) { 66343171Sdim TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream()); 67343171Sdim LazyRandomTypeCollection &Types = Tpi.typeCollection(); 68343171Sdim 69343171Sdim ContinuationIndex = ClassParent.getEnumRecord().FieldList; 70343171Sdim while (ContinuationIndex) { 71343171Sdim CVType FieldList = Types.getType(*ContinuationIndex); 72343171Sdim assert(FieldList.kind() == LF_FIELDLIST); 73343171Sdim ContinuationIndex.reset(); 74343171Sdim cantFail(visitMemberRecordStream(FieldList.data(), *this)); 75343171Sdim } 76343171Sdim} 77343171Sdim 78343171SdimError NativeEnumEnumEnumerators::visitKnownMember(CVMemberRecord &CVM, 79343171Sdim EnumeratorRecord &Record) { 80343171Sdim Enumerators.push_back(Record); 81343171Sdim return Error::success(); 82343171Sdim} 83343171Sdim 84343171SdimError NativeEnumEnumEnumerators::visitKnownMember( 85343171Sdim CVMemberRecord &CVM, ListContinuationRecord &Record) { 86343171Sdim ContinuationIndex = Record.ContinuationIndex; 87343171Sdim return Error::success(); 88343171Sdim} 89343171Sdim 90343171Sdimuint32_t NativeEnumEnumEnumerators::getChildCount() const { 91343171Sdim return Enumerators.size(); 92343171Sdim} 93343171Sdim 94343171Sdimstd::unique_ptr<PDBSymbol> 95343171SdimNativeEnumEnumEnumerators::getChildAtIndex(uint32_t Index) const { 96343171Sdim if (Index >= getChildCount()) 97343171Sdim return nullptr; 98343171Sdim 99343171Sdim SymIndexId Id = Session.getSymbolCache() 100343171Sdim .getOrCreateFieldListMember<NativeSymbolEnumerator>( 101343171Sdim ClassParent.getEnumRecord().FieldList, Index, 102343171Sdim ClassParent, Enumerators[Index]); 103343171Sdim return Session.getSymbolCache().getSymbolById(Id); 104343171Sdim} 105343171Sdim 106343171Sdimstd::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::getNext() { 107343171Sdim if (Index >= getChildCount()) 108343171Sdim return nullptr; 109343171Sdim 110343171Sdim return getChildAtIndex(Index++); 111343171Sdim} 112343171Sdim 113343171Sdimvoid NativeEnumEnumEnumerators::reset() { Index = 0; } 114343171Sdim 115343171SdimNativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id, 116343171Sdim TypeIndex Index, EnumRecord Record) 117343171Sdim : NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(Index), 118343171Sdim Record(std::move(Record)) {} 119343171Sdim 120343171SdimNativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id, 121343171Sdim NativeTypeEnum &UnmodifiedType, 122343171Sdim codeview::ModifierRecord Modifier) 123343171Sdim : NativeRawSymbol(Session, PDB_SymType::Enum, Id), 124343171Sdim UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {} 125343171Sdim 126343171SdimNativeTypeEnum::~NativeTypeEnum() {} 127343171Sdim 128343171Sdimvoid NativeTypeEnum::dump(raw_ostream &OS, int Indent, 129343171Sdim PdbSymbolIdField ShowIdFields, 130343171Sdim PdbSymbolIdField RecurseIdFields) const { 131343171Sdim NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); 132343171Sdim 133343171Sdim dumpSymbolField(OS, "baseType", static_cast<uint32_t>(getBuiltinType()), 134343171Sdim Indent); 135343171Sdim dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, 136343171Sdim PdbSymbolIdField::LexicalParent, ShowIdFields, 137343171Sdim RecurseIdFields); 138343171Sdim dumpSymbolField(OS, "name", getName(), Indent); 139343171Sdim dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, 140343171Sdim PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); 141343171Sdim if (Modifiers.hasValue()) 142343171Sdim dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent, 143343171Sdim Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields, 144343171Sdim RecurseIdFields); 145343171Sdim dumpSymbolField(OS, "length", getLength(), Indent); 146343171Sdim dumpSymbolField(OS, "constructor", hasConstructor(), Indent); 147343171Sdim dumpSymbolField(OS, "constType", isConstType(), Indent); 148343171Sdim dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent); 149343171Sdim dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent); 150343171Sdim dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent); 151343171Sdim dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent); 152343171Sdim dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent); 153343171Sdim dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent); 154343171Sdim dumpSymbolField(OS, "nested", isNested(), Indent); 155343171Sdim dumpSymbolField(OS, "packed", isPacked(), Indent); 156343171Sdim dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent); 157343171Sdim dumpSymbolField(OS, "scoped", isScoped(), Indent); 158343171Sdim dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); 159343171Sdim dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent); 160343171Sdim dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); 161343171Sdim} 162343171Sdim 163343171Sdimstd::unique_ptr<IPDBEnumSymbols> 164343171SdimNativeTypeEnum::findChildren(PDB_SymType Type) const { 165343171Sdim if (Type != PDB_SymType::Data) 166360784Sdim return std::make_unique<NullEnumerator<PDBSymbol>>(); 167343171Sdim 168343171Sdim const NativeTypeEnum *ClassParent = nullptr; 169343171Sdim if (!Modifiers) 170343171Sdim ClassParent = this; 171343171Sdim else 172343171Sdim ClassParent = UnmodifiedType; 173360784Sdim return std::make_unique<NativeEnumEnumEnumerators>(Session, *ClassParent); 174343171Sdim} 175343171Sdim 176343171SdimPDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; } 177343171Sdim 178343171SdimPDB_BuiltinType NativeTypeEnum::getBuiltinType() const { 179343171Sdim if (UnmodifiedType) 180343171Sdim return UnmodifiedType->getBuiltinType(); 181343171Sdim 182343171Sdim Session.getSymbolCache().findSymbolByTypeIndex(Record->getUnderlyingType()); 183343171Sdim 184343171Sdim codeview::TypeIndex Underlying = Record->getUnderlyingType(); 185343171Sdim 186343171Sdim // This indicates a corrupt record. 187343171Sdim if (!Underlying.isSimple() || 188343171Sdim Underlying.getSimpleMode() != SimpleTypeMode::Direct) { 189343171Sdim return PDB_BuiltinType::None; 190343171Sdim } 191343171Sdim 192343171Sdim switch (Underlying.getSimpleKind()) { 193343171Sdim case SimpleTypeKind::Boolean128: 194343171Sdim case SimpleTypeKind::Boolean64: 195343171Sdim case SimpleTypeKind::Boolean32: 196343171Sdim case SimpleTypeKind::Boolean16: 197343171Sdim case SimpleTypeKind::Boolean8: 198343171Sdim return PDB_BuiltinType::Bool; 199343171Sdim case SimpleTypeKind::NarrowCharacter: 200343171Sdim case SimpleTypeKind::UnsignedCharacter: 201343171Sdim case SimpleTypeKind::SignedCharacter: 202343171Sdim return PDB_BuiltinType::Char; 203343171Sdim case SimpleTypeKind::WideCharacter: 204343171Sdim return PDB_BuiltinType::WCharT; 205343171Sdim case SimpleTypeKind::Character16: 206343171Sdim return PDB_BuiltinType::Char16; 207343171Sdim case SimpleTypeKind::Character32: 208343171Sdim return PDB_BuiltinType::Char32; 209343171Sdim case SimpleTypeKind::Int128: 210343171Sdim case SimpleTypeKind::Int128Oct: 211343171Sdim case SimpleTypeKind::Int16: 212343171Sdim case SimpleTypeKind::Int16Short: 213343171Sdim case SimpleTypeKind::Int32: 214343171Sdim case SimpleTypeKind::Int32Long: 215343171Sdim case SimpleTypeKind::Int64: 216343171Sdim case SimpleTypeKind::Int64Quad: 217343171Sdim return PDB_BuiltinType::Int; 218343171Sdim case SimpleTypeKind::UInt128: 219343171Sdim case SimpleTypeKind::UInt128Oct: 220343171Sdim case SimpleTypeKind::UInt16: 221343171Sdim case SimpleTypeKind::UInt16Short: 222343171Sdim case SimpleTypeKind::UInt32: 223343171Sdim case SimpleTypeKind::UInt32Long: 224343171Sdim case SimpleTypeKind::UInt64: 225343171Sdim case SimpleTypeKind::UInt64Quad: 226343171Sdim return PDB_BuiltinType::UInt; 227343171Sdim case SimpleTypeKind::HResult: 228343171Sdim return PDB_BuiltinType::HResult; 229343171Sdim case SimpleTypeKind::Complex16: 230343171Sdim case SimpleTypeKind::Complex32: 231343171Sdim case SimpleTypeKind::Complex32PartialPrecision: 232343171Sdim case SimpleTypeKind::Complex64: 233343171Sdim case SimpleTypeKind::Complex80: 234343171Sdim case SimpleTypeKind::Complex128: 235343171Sdim return PDB_BuiltinType::Complex; 236343171Sdim case SimpleTypeKind::Float16: 237343171Sdim case SimpleTypeKind::Float32: 238343171Sdim case SimpleTypeKind::Float32PartialPrecision: 239343171Sdim case SimpleTypeKind::Float48: 240343171Sdim case SimpleTypeKind::Float64: 241343171Sdim case SimpleTypeKind::Float80: 242343171Sdim case SimpleTypeKind::Float128: 243343171Sdim return PDB_BuiltinType::Float; 244343171Sdim default: 245343171Sdim return PDB_BuiltinType::None; 246343171Sdim } 247343171Sdim llvm_unreachable("Unreachable"); 248343171Sdim} 249343171Sdim 250343171SdimSymIndexId NativeTypeEnum::getUnmodifiedTypeId() const { 251343171Sdim return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0; 252343171Sdim} 253343171Sdim 254343171Sdimbool NativeTypeEnum::hasConstructor() const { 255343171Sdim if (UnmodifiedType) 256343171Sdim return UnmodifiedType->hasConstructor(); 257343171Sdim 258343171Sdim return bool(Record->getOptions() & 259343171Sdim codeview::ClassOptions::HasConstructorOrDestructor); 260343171Sdim} 261343171Sdim 262343171Sdimbool NativeTypeEnum::hasAssignmentOperator() const { 263343171Sdim if (UnmodifiedType) 264343171Sdim return UnmodifiedType->hasAssignmentOperator(); 265343171Sdim 266343171Sdim return bool(Record->getOptions() & 267343171Sdim codeview::ClassOptions::HasOverloadedAssignmentOperator); 268343171Sdim} 269343171Sdim 270343171Sdimbool NativeTypeEnum::hasNestedTypes() const { 271343171Sdim if (UnmodifiedType) 272343171Sdim return UnmodifiedType->hasNestedTypes(); 273343171Sdim 274343171Sdim return bool(Record->getOptions() & 275343171Sdim codeview::ClassOptions::ContainsNestedClass); 276343171Sdim} 277343171Sdim 278343171Sdimbool NativeTypeEnum::isIntrinsic() const { 279343171Sdim if (UnmodifiedType) 280343171Sdim return UnmodifiedType->isIntrinsic(); 281343171Sdim 282343171Sdim return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic); 283343171Sdim} 284343171Sdim 285343171Sdimbool NativeTypeEnum::hasCastOperator() const { 286343171Sdim if (UnmodifiedType) 287343171Sdim return UnmodifiedType->hasCastOperator(); 288343171Sdim 289343171Sdim return bool(Record->getOptions() & 290343171Sdim codeview::ClassOptions::HasConversionOperator); 291343171Sdim} 292343171Sdim 293343171Sdimuint64_t NativeTypeEnum::getLength() const { 294343171Sdim if (UnmodifiedType) 295343171Sdim return UnmodifiedType->getLength(); 296343171Sdim 297343171Sdim const auto Id = Session.getSymbolCache().findSymbolByTypeIndex( 298343171Sdim Record->getUnderlyingType()); 299343171Sdim const auto UnderlyingType = 300343171Sdim Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id); 301343171Sdim return UnderlyingType ? UnderlyingType->getLength() : 0; 302343171Sdim} 303343171Sdim 304343171Sdimstd::string NativeTypeEnum::getName() const { 305343171Sdim if (UnmodifiedType) 306343171Sdim return UnmodifiedType->getName(); 307343171Sdim 308343171Sdim return Record->getName(); 309343171Sdim} 310343171Sdim 311343171Sdimbool NativeTypeEnum::isNested() const { 312343171Sdim if (UnmodifiedType) 313343171Sdim return UnmodifiedType->isNested(); 314343171Sdim 315343171Sdim return bool(Record->getOptions() & codeview::ClassOptions::Nested); 316343171Sdim} 317343171Sdim 318343171Sdimbool NativeTypeEnum::hasOverloadedOperator() const { 319343171Sdim if (UnmodifiedType) 320343171Sdim return UnmodifiedType->hasOverloadedOperator(); 321343171Sdim 322343171Sdim return bool(Record->getOptions() & 323343171Sdim codeview::ClassOptions::HasOverloadedOperator); 324343171Sdim} 325343171Sdim 326343171Sdimbool NativeTypeEnum::isPacked() const { 327343171Sdim if (UnmodifiedType) 328343171Sdim return UnmodifiedType->isPacked(); 329343171Sdim 330343171Sdim return bool(Record->getOptions() & codeview::ClassOptions::Packed); 331343171Sdim} 332343171Sdim 333343171Sdimbool NativeTypeEnum::isScoped() const { 334343171Sdim if (UnmodifiedType) 335343171Sdim return UnmodifiedType->isScoped(); 336343171Sdim 337343171Sdim return bool(Record->getOptions() & codeview::ClassOptions::Scoped); 338343171Sdim} 339343171Sdim 340343171SdimSymIndexId NativeTypeEnum::getTypeId() const { 341343171Sdim if (UnmodifiedType) 342343171Sdim return UnmodifiedType->getTypeId(); 343343171Sdim 344343171Sdim return Session.getSymbolCache().findSymbolByTypeIndex( 345343171Sdim Record->getUnderlyingType()); 346343171Sdim} 347343171Sdim 348343171Sdimbool NativeTypeEnum::isRefUdt() const { return false; } 349343171Sdim 350343171Sdimbool NativeTypeEnum::isValueUdt() const { return false; } 351343171Sdim 352343171Sdimbool NativeTypeEnum::isInterfaceUdt() const { return false; } 353343171Sdim 354343171Sdimbool NativeTypeEnum::isConstType() const { 355343171Sdim if (!Modifiers) 356343171Sdim return false; 357343171Sdim return ((Modifiers->getModifiers() & ModifierOptions::Const) != 358343171Sdim ModifierOptions::None); 359343171Sdim} 360343171Sdim 361343171Sdimbool NativeTypeEnum::isVolatileType() const { 362343171Sdim if (!Modifiers) 363343171Sdim return false; 364343171Sdim return ((Modifiers->getModifiers() & ModifierOptions::Volatile) != 365343171Sdim ModifierOptions::None); 366343171Sdim} 367343171Sdim 368343171Sdimbool NativeTypeEnum::isUnalignedType() const { 369343171Sdim if (!Modifiers) 370343171Sdim return false; 371343171Sdim return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) != 372343171Sdim ModifierOptions::None); 373343171Sdim} 374343171Sdim 375343171Sdimconst NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const { 376343171Sdim if (UnmodifiedType) 377343171Sdim return UnmodifiedType->getUnderlyingBuiltinType(); 378343171Sdim 379343171Sdim return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>( 380343171Sdim getTypeId()); 381343171Sdim} 382