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