| #include "llvm/DebugInfo/PDB/Native/SymbolCache.h" |
| |
| #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" |
| #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" |
| #include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" |
| #include "llvm/DebugInfo/PDB/Native/DbiStream.h" |
| #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeSession.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h" |
| #include "llvm/DebugInfo/PDB/Native/PDBFile.h" |
| #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" |
| #include "llvm/DebugInfo/PDB/Native/TpiStream.h" |
| #include "llvm/DebugInfo/PDB/PDBSymbol.h" |
| #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" |
| #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" |
| |
| using namespace llvm; |
| using namespace llvm::codeview; |
| using namespace llvm::pdb; |
| |
| // Maps codeview::SimpleTypeKind of a built-in type to the parameters necessary |
| // to instantiate a NativeBuiltinSymbol for that type. |
| static const struct BuiltinTypeEntry { |
| codeview::SimpleTypeKind Kind; |
| PDB_BuiltinType Type; |
| uint32_t Size; |
| } BuiltinTypes[] = { |
| {codeview::SimpleTypeKind::None, PDB_BuiltinType::None, 0}, |
| {codeview::SimpleTypeKind::Void, PDB_BuiltinType::Void, 0}, |
| {codeview::SimpleTypeKind::HResult, PDB_BuiltinType::HResult, 4}, |
| {codeview::SimpleTypeKind::Int16Short, PDB_BuiltinType::Int, 2}, |
| {codeview::SimpleTypeKind::UInt16Short, PDB_BuiltinType::UInt, 2}, |
| {codeview::SimpleTypeKind::Int32, PDB_BuiltinType::Int, 4}, |
| {codeview::SimpleTypeKind::UInt32, PDB_BuiltinType::UInt, 4}, |
| {codeview::SimpleTypeKind::Int32Long, PDB_BuiltinType::Int, 4}, |
| {codeview::SimpleTypeKind::UInt32Long, PDB_BuiltinType::UInt, 4}, |
| {codeview::SimpleTypeKind::Int64Quad, PDB_BuiltinType::Int, 8}, |
| {codeview::SimpleTypeKind::UInt64Quad, PDB_BuiltinType::UInt, 8}, |
| {codeview::SimpleTypeKind::NarrowCharacter, PDB_BuiltinType::Char, 1}, |
| {codeview::SimpleTypeKind::WideCharacter, PDB_BuiltinType::WCharT, 2}, |
| {codeview::SimpleTypeKind::Character16, PDB_BuiltinType::Char16, 2}, |
| {codeview::SimpleTypeKind::Character32, PDB_BuiltinType::Char32, 4}, |
| {codeview::SimpleTypeKind::SignedCharacter, PDB_BuiltinType::Char, 1}, |
| {codeview::SimpleTypeKind::UnsignedCharacter, PDB_BuiltinType::UInt, 1}, |
| {codeview::SimpleTypeKind::Float32, PDB_BuiltinType::Float, 4}, |
| {codeview::SimpleTypeKind::Float64, PDB_BuiltinType::Float, 8}, |
| {codeview::SimpleTypeKind::Float80, PDB_BuiltinType::Float, 10}, |
| {codeview::SimpleTypeKind::Boolean8, PDB_BuiltinType::Bool, 1}, |
| // This table can be grown as necessary, but these are the only types we've |
| // needed so far. |
| }; |
| |
| SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi) |
| : Session(Session), Dbi(Dbi) { |
| // Id 0 is reserved for the invalid symbol. |
| Cache.push_back(nullptr); |
| |
| if (Dbi) |
| Compilands.resize(Dbi->modules().getModuleCount()); |
| } |
| |
| std::unique_ptr<IPDBEnumSymbols> |
| SymbolCache::createTypeEnumerator(TypeLeafKind Kind) { |
| return createTypeEnumerator(std::vector<TypeLeafKind>{Kind}); |
| } |
| |
| std::unique_ptr<IPDBEnumSymbols> |
| SymbolCache::createTypeEnumerator(std::vector<TypeLeafKind> Kinds) { |
| auto Tpi = Session.getPDBFile().getPDBTpiStream(); |
| if (!Tpi) { |
| consumeError(Tpi.takeError()); |
| return nullptr; |
| } |
| auto &Types = Tpi->typeCollection(); |
| return std::unique_ptr<IPDBEnumSymbols>( |
| new NativeEnumTypes(Session, Types, std::move(Kinds))); |
| } |
| |
| std::unique_ptr<IPDBEnumSymbols> |
| SymbolCache::createGlobalsEnumerator(codeview::SymbolKind Kind) { |
| return std::unique_ptr<IPDBEnumSymbols>( |
| new NativeEnumGlobals(Session, {Kind})); |
| } |
| |
| SymIndexId SymbolCache::createSimpleType(TypeIndex Index, |
| ModifierOptions Mods) { |
| if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct) |
| return createSymbol<NativeTypePointer>(Index); |
| |
| const auto Kind = Index.getSimpleKind(); |
| const auto It = std::find_if( |
| std::begin(BuiltinTypes), std::end(BuiltinTypes), |
| [Kind](const BuiltinTypeEntry &Builtin) { return Builtin.Kind == Kind; }); |
| if (It == std::end(BuiltinTypes)) |
| return 0; |
| return createSymbol<NativeTypeBuiltin>(Mods, It->Type, It->Size); |
| } |
| |
| SymIndexId |
| SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI, |
| codeview::CVType CVT) { |
| ModifierRecord Record; |
| if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) { |
| consumeError(std::move(EC)); |
| return 0; |
| } |
| |
| if (Record.ModifiedType.isSimple()) |
| return createSimpleType(Record.ModifiedType, Record.Modifiers); |
| |
| // Make sure we create and cache a record for the unmodified type. |
| SymIndexId UnmodifiedId = findSymbolByTypeIndex(Record.ModifiedType); |
| NativeRawSymbol &UnmodifiedNRS = *Cache[UnmodifiedId]; |
| |
| switch (UnmodifiedNRS.getSymTag()) { |
| case PDB_SymType::Enum: |
| return createSymbol<NativeTypeEnum>( |
| static_cast<NativeTypeEnum &>(UnmodifiedNRS), std::move(Record)); |
| case PDB_SymType::UDT: |
| return createSymbol<NativeTypeUDT>( |
| static_cast<NativeTypeUDT &>(UnmodifiedNRS), std::move(Record)); |
| default: |
| // No other types can be modified. (LF_POINTER, for example, records |
| // its modifiers a different way. |
| assert(false && "Invalid LF_MODIFIER record"); |
| break; |
| } |
| return 0; |
| } |
| |
| SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) { |
| // First see if it's already in our cache. |
| const auto Entry = TypeIndexToSymbolId.find(Index); |
| if (Entry != TypeIndexToSymbolId.end()) |
| return Entry->second; |
| |
| // Symbols for built-in types are created on the fly. |
| if (Index.isSimple()) { |
| SymIndexId Result = createSimpleType(Index, ModifierOptions::None); |
| assert(TypeIndexToSymbolId.count(Index) == 0); |
| TypeIndexToSymbolId[Index] = Result; |
| return Result; |
| } |
| |
| // We need to instantiate and cache the desired type symbol. |
| auto Tpi = Session.getPDBFile().getPDBTpiStream(); |
| if (!Tpi) { |
| consumeError(Tpi.takeError()); |
| return 0; |
| } |
| codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection(); |
| codeview::CVType CVT = Types.getType(Index); |
| |
| if (isUdtForwardRef(CVT)) { |
| Expected<TypeIndex> EFD = Tpi->findFullDeclForForwardRef(Index); |
| |
| if (!EFD) |
| consumeError(EFD.takeError()); |
| else if (*EFD != Index) { |
| assert(!isUdtForwardRef(Types.getType(*EFD))); |
| SymIndexId Result = findSymbolByTypeIndex(*EFD); |
| // Record a mapping from ForwardRef -> SymIndex of complete type so that |
| // we'll take the fast path next time. |
| assert(TypeIndexToSymbolId.count(Index) == 0); |
| TypeIndexToSymbolId[Index] = Result; |
| return Result; |
| } |
| } |
| |
| // At this point if we still have a forward ref udt it means the full decl was |
| // not in the PDB. We just have to deal with it and use the forward ref. |
| SymIndexId Id = 0; |
| switch (CVT.kind()) { |
| case codeview::LF_ENUM: |
| Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT)); |
| break; |
| case codeview::LF_ARRAY: |
| Id = createSymbolForType<NativeTypeArray, ArrayRecord>(Index, |
| std::move(CVT)); |
| break; |
| case codeview::LF_CLASS: |
| case codeview::LF_STRUCTURE: |
| case codeview::LF_INTERFACE: |
| Id = createSymbolForType<NativeTypeUDT, ClassRecord>(Index, std::move(CVT)); |
| break; |
| case codeview::LF_UNION: |
| Id = createSymbolForType<NativeTypeUDT, UnionRecord>(Index, std::move(CVT)); |
| break; |
| case codeview::LF_POINTER: |
| Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index, |
| std::move(CVT)); |
| break; |
| case codeview::LF_MODIFIER: |
| Id = createSymbolForModifiedType(Index, std::move(CVT)); |
| break; |
| case codeview::LF_PROCEDURE: |
| Id = createSymbolForType<NativeTypeFunctionSig, ProcedureRecord>( |
| Index, std::move(CVT)); |
| break; |
| case codeview::LF_MFUNCTION: |
| Id = createSymbolForType<NativeTypeFunctionSig, MemberFunctionRecord>( |
| Index, std::move(CVT)); |
| break; |
| case codeview::LF_VTSHAPE: |
| Id = createSymbolForType<NativeTypeVTShape, VFTableShapeRecord>( |
| Index, std::move(CVT)); |
| break; |
| default: |
| Id = createSymbolPlaceholder(); |
| break; |
| } |
| if (Id != 0) { |
| assert(TypeIndexToSymbolId.count(Index) == 0); |
| TypeIndexToSymbolId[Index] = Id; |
| } |
| return Id; |
| } |
| |
| std::unique_ptr<PDBSymbol> |
| SymbolCache::getSymbolById(SymIndexId SymbolId) const { |
| assert(SymbolId < Cache.size()); |
| |
| // Id 0 is reserved. |
| if (SymbolId == 0 || SymbolId >= Cache.size()) |
| return nullptr; |
| |
| // Make sure to handle the case where we've inserted a placeholder symbol |
| // for types we don't yet suppport. |
| NativeRawSymbol *NRS = Cache[SymbolId].get(); |
| if (!NRS) |
| return nullptr; |
| |
| return PDBSymbol::create(Session, *NRS); |
| } |
| |
| NativeRawSymbol &SymbolCache::getNativeSymbolById(SymIndexId SymbolId) const { |
| return *Cache[SymbolId]; |
| } |
| |
| uint32_t SymbolCache::getNumCompilands() const { |
| if (!Dbi) |
| return 0; |
| |
| return Dbi->modules().getModuleCount(); |
| } |
| |
| SymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) { |
| auto Iter = GlobalOffsetToSymbolId.find(Offset); |
| if (Iter != GlobalOffsetToSymbolId.end()) |
| return Iter->second; |
| |
| SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream()); |
| CVSymbol CVS = SS.readRecord(Offset); |
| SymIndexId Id = 0; |
| switch (CVS.kind()) { |
| case SymbolKind::S_UDT: { |
| UDTSym US = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(CVS)); |
| Id = createSymbol<NativeTypeTypedef>(std::move(US)); |
| break; |
| } |
| default: |
| Id = createSymbolPlaceholder(); |
| break; |
| } |
| if (Id != 0) { |
| assert(GlobalOffsetToSymbolId.count(Offset) == 0); |
| GlobalOffsetToSymbolId[Offset] = Id; |
| } |
| |
| return Id; |
| } |
| |
| std::unique_ptr<PDBSymbolCompiland> |
| SymbolCache::getOrCreateCompiland(uint32_t Index) { |
| if (!Dbi) |
| return nullptr; |
| |
| if (Index >= Compilands.size()) |
| return nullptr; |
| |
| if (Compilands[Index] == 0) { |
| const DbiModuleList &Modules = Dbi->modules(); |
| Compilands[Index] = |
| createSymbol<NativeCompilandSymbol>(Modules.getModuleDescriptor(Index)); |
| } |
| |
| return Session.getConcreteSymbolById<PDBSymbolCompiland>(Compilands[Index]); |
| } |