1 #include "llvm/DebugInfo/PDB/Native/SymbolCache.h" 2 3 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" 4 #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 5 #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" 6 #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" 7 #include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" 8 #include "llvm/DebugInfo/PDB/Native/NativeSession.h" 9 #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" 10 #include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" 11 #include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" 12 #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 13 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 14 #include "llvm/DebugInfo/PDB/PDBSymbol.h" 15 #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" 16 #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" 17 18 using namespace llvm; 19 using namespace llvm::codeview; 20 using namespace llvm::pdb; 21 22 // Maps codeview::SimpleTypeKind of a built-in type to the parameters necessary 23 // to instantiate a NativeBuiltinSymbol for that type. 24 static const struct BuiltinTypeEntry { 25 codeview::SimpleTypeKind Kind; 26 PDB_BuiltinType Type; 27 uint32_t Size; 28 } BuiltinTypes[] = { 29 {codeview::SimpleTypeKind::Int16Short, PDB_BuiltinType::Int, 2}, 30 {codeview::SimpleTypeKind::UInt16Short, PDB_BuiltinType::UInt, 2}, 31 {codeview::SimpleTypeKind::Int32, PDB_BuiltinType::Int, 4}, 32 {codeview::SimpleTypeKind::UInt32, PDB_BuiltinType::UInt, 4}, 33 {codeview::SimpleTypeKind::Int32Long, PDB_BuiltinType::Int, 4}, 34 {codeview::SimpleTypeKind::UInt32Long, PDB_BuiltinType::UInt, 4}, 35 {codeview::SimpleTypeKind::Int64Quad, PDB_BuiltinType::Int, 8}, 36 {codeview::SimpleTypeKind::UInt64Quad, PDB_BuiltinType::UInt, 8}, 37 {codeview::SimpleTypeKind::NarrowCharacter, PDB_BuiltinType::Char, 1}, 38 {codeview::SimpleTypeKind::SignedCharacter, PDB_BuiltinType::Char, 1}, 39 {codeview::SimpleTypeKind::UnsignedCharacter, PDB_BuiltinType::UInt, 1}, 40 {codeview::SimpleTypeKind::Boolean8, PDB_BuiltinType::Bool, 1} 41 // This table can be grown as necessary, but these are the only types we've 42 // needed so far. 43 }; 44 45 SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi) 46 : Session(Session), Dbi(Dbi) { 47 // Id 0 is reserved for the invalid symbol. 48 Cache.push_back(nullptr); 49 50 if (Dbi) 51 Compilands.resize(Dbi->modules().getModuleCount()); 52 } 53 54 std::unique_ptr<IPDBEnumSymbols> 55 SymbolCache::createTypeEnumerator(codeview::TypeLeafKind Kind) { 56 auto Tpi = Session.getPDBFile().getPDBTpiStream(); 57 if (!Tpi) { 58 consumeError(Tpi.takeError()); 59 return nullptr; 60 } 61 auto &Types = Tpi->typeCollection(); 62 return std::unique_ptr<IPDBEnumSymbols>( 63 new NativeEnumTypes(Session, Types, Kind)); 64 } 65 66 SymIndexId SymbolCache::createSimpleType(TypeIndex Index, 67 ModifierOptions Mods) { 68 // FIXME: We will eventually need to handle pointers to other simple types, 69 // which are still simple types in the world of CodeView TypeIndexes. 70 if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct) 71 return 0; 72 73 const auto Kind = Index.getSimpleKind(); 74 const auto It = std::find_if( 75 std::begin(BuiltinTypes), std::end(BuiltinTypes), 76 [Kind](const BuiltinTypeEntry &Builtin) { return Builtin.Kind == Kind; }); 77 if (It == std::end(BuiltinTypes)) 78 return 0; 79 SymIndexId Id = Cache.size(); 80 Cache.emplace_back(llvm::make_unique<NativeTypeBuiltin>(Session, Id, Mods, 81 It->Type, It->Size)); 82 TypeIndexToSymbolId[Index] = Id; 83 return Id; 84 } 85 86 SymIndexId 87 SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI, 88 codeview::CVType CVT) { 89 ModifierRecord Record; 90 if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) { 91 consumeError(std::move(EC)); 92 return 0; 93 } 94 95 if (Record.ModifiedType.isSimple()) 96 return createSimpleType(Record.ModifiedType, Record.Modifiers); 97 98 auto Tpi = Session.getPDBFile().getPDBTpiStream(); 99 if (!Tpi) { 100 consumeError(Tpi.takeError()); 101 return 0; 102 } 103 codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection(); 104 105 codeview::CVType UnmodifiedType = Types.getType(Record.ModifiedType); 106 107 switch (UnmodifiedType.kind()) { 108 case LF_ENUM: { 109 EnumRecord ER; 110 if (auto EC = 111 TypeDeserializer::deserializeAs<EnumRecord>(UnmodifiedType, ER)) { 112 consumeError(std::move(EC)); 113 return 0; 114 } 115 return createSymbol<NativeTypeEnum>(Record.ModifiedType, std::move(Record), 116 std::move(ER)); 117 } 118 case LF_STRUCTURE: 119 case LF_UNION: 120 case LF_CLASS: 121 // FIXME: Handle these 122 break; 123 default: 124 // No other types can be modified. (LF_POINTER, for example, records 125 // its modifiers a different way. 126 assert(false && "Invalid LF_MODIFIER record"); 127 break; 128 } 129 return createSymbolPlaceholder(); 130 } 131 132 SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) { 133 // First see if it's already in our cache. 134 const auto Entry = TypeIndexToSymbolId.find(Index); 135 if (Entry != TypeIndexToSymbolId.end()) 136 return Entry->second; 137 138 // Symbols for built-in types are created on the fly. 139 if (Index.isSimple()) 140 return createSimpleType(Index, ModifierOptions::None); 141 142 // We need to instantiate and cache the desired type symbol. 143 auto Tpi = Session.getPDBFile().getPDBTpiStream(); 144 if (!Tpi) { 145 consumeError(Tpi.takeError()); 146 return 0; 147 } 148 codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection(); 149 codeview::CVType CVT = Types.getType(Index); 150 // TODO(amccarth): Make this handle all types. 151 SymIndexId Id = 0; 152 153 switch (CVT.kind()) { 154 case codeview::LF_ENUM: 155 Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT)); 156 break; 157 case codeview::LF_POINTER: 158 Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index, 159 std::move(CVT)); 160 break; 161 case codeview::LF_MODIFIER: 162 Id = createSymbolForModifiedType(Index, std::move(CVT)); 163 break; 164 default: 165 Id = createSymbolPlaceholder(); 166 break; 167 } 168 if (Id != 0) 169 TypeIndexToSymbolId[Index] = Id; 170 return Id; 171 } 172 173 std::unique_ptr<PDBSymbol> 174 SymbolCache::getSymbolById(SymIndexId SymbolId) const { 175 assert(SymbolId < Cache.size()); 176 177 // Id 0 is reserved. 178 if (SymbolId == 0) 179 return nullptr; 180 181 // If the caller has a SymbolId, it'd better be in our SymbolCache. 182 return SymbolId < Cache.size() ? PDBSymbol::create(Session, *Cache[SymbolId]) 183 : nullptr; 184 } 185 186 NativeRawSymbol &SymbolCache::getNativeSymbolById(SymIndexId SymbolId) const { 187 return *Cache[SymbolId]; 188 } 189 190 uint32_t SymbolCache::getNumCompilands() const { 191 if (!Dbi) 192 return 0; 193 194 return Dbi->modules().getModuleCount(); 195 } 196 197 std::unique_ptr<PDBSymbolCompiland> 198 SymbolCache::getOrCreateCompiland(uint32_t Index) { 199 if (!Dbi) 200 return nullptr; 201 202 if (Index >= Compilands.size()) 203 return nullptr; 204 205 if (Compilands[Index] == 0) { 206 const DbiModuleList &Modules = Dbi->modules(); 207 Compilands[Index] = 208 createSymbol<NativeCompilandSymbol>(Modules.getModuleDescriptor(Index)); 209 } 210 211 return Session.getConcreteSymbolById<PDBSymbolCompiland>(Compilands[Index]); 212 } 213