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