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