1343171Sdim#include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
2343171Sdim
3343171Sdim#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
4343171Sdim#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
5343171Sdim#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
6343171Sdim#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
7343171Sdim#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
8343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
9343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h"
10343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
11343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"
12343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
13343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h"
14343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
15343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
16343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h"
17343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h"
18343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h"
19343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h"
20343171Sdim#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h"
21343171Sdim#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
22343171Sdim#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
23343171Sdim#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
24343171Sdim#include "llvm/DebugInfo/PDB/PDBSymbol.h"
25343171Sdim#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
26343171Sdim#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
27343171Sdim
28343171Sdimusing namespace llvm;
29343171Sdimusing namespace llvm::codeview;
30343171Sdimusing namespace llvm::pdb;
31343171Sdim
32343171Sdim// Maps codeview::SimpleTypeKind of a built-in type to the parameters necessary
33343171Sdim// to instantiate a NativeBuiltinSymbol for that type.
34343171Sdimstatic const struct BuiltinTypeEntry {
35343171Sdim  codeview::SimpleTypeKind Kind;
36343171Sdim  PDB_BuiltinType Type;
37343171Sdim  uint32_t Size;
38343171Sdim} BuiltinTypes[] = {
39343171Sdim    {codeview::SimpleTypeKind::None, PDB_BuiltinType::None, 0},
40343171Sdim    {codeview::SimpleTypeKind::Void, PDB_BuiltinType::Void, 0},
41343171Sdim    {codeview::SimpleTypeKind::HResult, PDB_BuiltinType::HResult, 4},
42343171Sdim    {codeview::SimpleTypeKind::Int16Short, PDB_BuiltinType::Int, 2},
43343171Sdim    {codeview::SimpleTypeKind::UInt16Short, PDB_BuiltinType::UInt, 2},
44343171Sdim    {codeview::SimpleTypeKind::Int32, PDB_BuiltinType::Int, 4},
45343171Sdim    {codeview::SimpleTypeKind::UInt32, PDB_BuiltinType::UInt, 4},
46343171Sdim    {codeview::SimpleTypeKind::Int32Long, PDB_BuiltinType::Int, 4},
47343171Sdim    {codeview::SimpleTypeKind::UInt32Long, PDB_BuiltinType::UInt, 4},
48343171Sdim    {codeview::SimpleTypeKind::Int64Quad, PDB_BuiltinType::Int, 8},
49343171Sdim    {codeview::SimpleTypeKind::UInt64Quad, PDB_BuiltinType::UInt, 8},
50343171Sdim    {codeview::SimpleTypeKind::NarrowCharacter, PDB_BuiltinType::Char, 1},
51343171Sdim    {codeview::SimpleTypeKind::WideCharacter, PDB_BuiltinType::WCharT, 2},
52343171Sdim    {codeview::SimpleTypeKind::Character16, PDB_BuiltinType::Char16, 2},
53343171Sdim    {codeview::SimpleTypeKind::Character32, PDB_BuiltinType::Char32, 4},
54343171Sdim    {codeview::SimpleTypeKind::SignedCharacter, PDB_BuiltinType::Char, 1},
55343171Sdim    {codeview::SimpleTypeKind::UnsignedCharacter, PDB_BuiltinType::UInt, 1},
56343171Sdim    {codeview::SimpleTypeKind::Float32, PDB_BuiltinType::Float, 4},
57343171Sdim    {codeview::SimpleTypeKind::Float64, PDB_BuiltinType::Float, 8},
58343171Sdim    {codeview::SimpleTypeKind::Float80, PDB_BuiltinType::Float, 10},
59343171Sdim    {codeview::SimpleTypeKind::Boolean8, PDB_BuiltinType::Bool, 1},
60343171Sdim    // This table can be grown as necessary, but these are the only types we've
61343171Sdim    // needed so far.
62343171Sdim};
63343171Sdim
64343171SdimSymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi)
65343171Sdim    : Session(Session), Dbi(Dbi) {
66343171Sdim  // Id 0 is reserved for the invalid symbol.
67343171Sdim  Cache.push_back(nullptr);
68343171Sdim
69343171Sdim  if (Dbi)
70343171Sdim    Compilands.resize(Dbi->modules().getModuleCount());
71343171Sdim}
72343171Sdim
73343171Sdimstd::unique_ptr<IPDBEnumSymbols>
74343171SdimSymbolCache::createTypeEnumerator(TypeLeafKind Kind) {
75343171Sdim  return createTypeEnumerator(std::vector<TypeLeafKind>{Kind});
76343171Sdim}
77343171Sdim
78343171Sdimstd::unique_ptr<IPDBEnumSymbols>
79343171SdimSymbolCache::createTypeEnumerator(std::vector<TypeLeafKind> Kinds) {
80343171Sdim  auto Tpi = Session.getPDBFile().getPDBTpiStream();
81343171Sdim  if (!Tpi) {
82343171Sdim    consumeError(Tpi.takeError());
83343171Sdim    return nullptr;
84343171Sdim  }
85343171Sdim  auto &Types = Tpi->typeCollection();
86343171Sdim  return std::unique_ptr<IPDBEnumSymbols>(
87343171Sdim      new NativeEnumTypes(Session, Types, std::move(Kinds)));
88343171Sdim}
89343171Sdim
90343171Sdimstd::unique_ptr<IPDBEnumSymbols>
91343171SdimSymbolCache::createGlobalsEnumerator(codeview::SymbolKind Kind) {
92343171Sdim  return std::unique_ptr<IPDBEnumSymbols>(
93343171Sdim      new NativeEnumGlobals(Session, {Kind}));
94343171Sdim}
95343171Sdim
96343171SdimSymIndexId SymbolCache::createSimpleType(TypeIndex Index,
97343171Sdim                                         ModifierOptions Mods) {
98343171Sdim  if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct)
99343171Sdim    return createSymbol<NativeTypePointer>(Index);
100343171Sdim
101343171Sdim  const auto Kind = Index.getSimpleKind();
102343171Sdim  const auto It = std::find_if(
103343171Sdim      std::begin(BuiltinTypes), std::end(BuiltinTypes),
104343171Sdim      [Kind](const BuiltinTypeEntry &Builtin) { return Builtin.Kind == Kind; });
105343171Sdim  if (It == std::end(BuiltinTypes))
106343171Sdim    return 0;
107343171Sdim  return createSymbol<NativeTypeBuiltin>(Mods, It->Type, It->Size);
108343171Sdim}
109343171Sdim
110343171SdimSymIndexId
111343171SdimSymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI,
112343171Sdim                                         codeview::CVType CVT) {
113343171Sdim  ModifierRecord Record;
114343171Sdim  if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) {
115343171Sdim    consumeError(std::move(EC));
116343171Sdim    return 0;
117343171Sdim  }
118343171Sdim
119343171Sdim  if (Record.ModifiedType.isSimple())
120343171Sdim    return createSimpleType(Record.ModifiedType, Record.Modifiers);
121343171Sdim
122343171Sdim  // Make sure we create and cache a record for the unmodified type.
123343171Sdim  SymIndexId UnmodifiedId = findSymbolByTypeIndex(Record.ModifiedType);
124343171Sdim  NativeRawSymbol &UnmodifiedNRS = *Cache[UnmodifiedId];
125343171Sdim
126343171Sdim  switch (UnmodifiedNRS.getSymTag()) {
127343171Sdim  case PDB_SymType::Enum:
128343171Sdim    return createSymbol<NativeTypeEnum>(
129343171Sdim        static_cast<NativeTypeEnum &>(UnmodifiedNRS), std::move(Record));
130343171Sdim  case PDB_SymType::UDT:
131343171Sdim    return createSymbol<NativeTypeUDT>(
132343171Sdim        static_cast<NativeTypeUDT &>(UnmodifiedNRS), std::move(Record));
133343171Sdim  default:
134343171Sdim    // No other types can be modified.  (LF_POINTER, for example, records
135343171Sdim    // its modifiers a different way.
136343171Sdim    assert(false && "Invalid LF_MODIFIER record");
137343171Sdim    break;
138343171Sdim  }
139343171Sdim  return 0;
140343171Sdim}
141343171Sdim
142343171SdimSymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) {
143343171Sdim  // First see if it's already in our cache.
144343171Sdim  const auto Entry = TypeIndexToSymbolId.find(Index);
145343171Sdim  if (Entry != TypeIndexToSymbolId.end())
146343171Sdim    return Entry->second;
147343171Sdim
148343171Sdim  // Symbols for built-in types are created on the fly.
149343171Sdim  if (Index.isSimple()) {
150343171Sdim    SymIndexId Result = createSimpleType(Index, ModifierOptions::None);
151343171Sdim    assert(TypeIndexToSymbolId.count(Index) == 0);
152343171Sdim    TypeIndexToSymbolId[Index] = Result;
153343171Sdim    return Result;
154343171Sdim  }
155343171Sdim
156343171Sdim  // We need to instantiate and cache the desired type symbol.
157343171Sdim  auto Tpi = Session.getPDBFile().getPDBTpiStream();
158343171Sdim  if (!Tpi) {
159343171Sdim    consumeError(Tpi.takeError());
160343171Sdim    return 0;
161343171Sdim  }
162343171Sdim  codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection();
163343171Sdim  codeview::CVType CVT = Types.getType(Index);
164343171Sdim
165343171Sdim  if (isUdtForwardRef(CVT)) {
166343171Sdim    Expected<TypeIndex> EFD = Tpi->findFullDeclForForwardRef(Index);
167343171Sdim
168343171Sdim    if (!EFD)
169343171Sdim      consumeError(EFD.takeError());
170343171Sdim    else if (*EFD != Index) {
171343171Sdim      assert(!isUdtForwardRef(Types.getType(*EFD)));
172343171Sdim      SymIndexId Result = findSymbolByTypeIndex(*EFD);
173343171Sdim      // Record a mapping from ForwardRef -> SymIndex of complete type so that
174343171Sdim      // we'll take the fast path next time.
175343171Sdim      assert(TypeIndexToSymbolId.count(Index) == 0);
176343171Sdim      TypeIndexToSymbolId[Index] = Result;
177343171Sdim      return Result;
178343171Sdim    }
179343171Sdim  }
180343171Sdim
181343171Sdim  // At this point if we still have a forward ref udt it means the full decl was
182343171Sdim  // not in the PDB.  We just have to deal with it and use the forward ref.
183343171Sdim  SymIndexId Id = 0;
184343171Sdim  switch (CVT.kind()) {
185343171Sdim  case codeview::LF_ENUM:
186343171Sdim    Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT));
187343171Sdim    break;
188343171Sdim  case codeview::LF_ARRAY:
189343171Sdim    Id = createSymbolForType<NativeTypeArray, ArrayRecord>(Index,
190343171Sdim                                                           std::move(CVT));
191343171Sdim    break;
192343171Sdim  case codeview::LF_CLASS:
193343171Sdim  case codeview::LF_STRUCTURE:
194343171Sdim  case codeview::LF_INTERFACE:
195343171Sdim    Id = createSymbolForType<NativeTypeUDT, ClassRecord>(Index, std::move(CVT));
196343171Sdim    break;
197343171Sdim  case codeview::LF_UNION:
198343171Sdim    Id = createSymbolForType<NativeTypeUDT, UnionRecord>(Index, std::move(CVT));
199343171Sdim    break;
200343171Sdim  case codeview::LF_POINTER:
201343171Sdim    Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index,
202343171Sdim                                                               std::move(CVT));
203343171Sdim    break;
204343171Sdim  case codeview::LF_MODIFIER:
205343171Sdim    Id = createSymbolForModifiedType(Index, std::move(CVT));
206343171Sdim    break;
207343171Sdim  case codeview::LF_PROCEDURE:
208343171Sdim    Id = createSymbolForType<NativeTypeFunctionSig, ProcedureRecord>(
209343171Sdim        Index, std::move(CVT));
210343171Sdim    break;
211343171Sdim  case codeview::LF_MFUNCTION:
212343171Sdim    Id = createSymbolForType<NativeTypeFunctionSig, MemberFunctionRecord>(
213343171Sdim        Index, std::move(CVT));
214343171Sdim    break;
215343171Sdim  case codeview::LF_VTSHAPE:
216343171Sdim    Id = createSymbolForType<NativeTypeVTShape, VFTableShapeRecord>(
217343171Sdim        Index, std::move(CVT));
218343171Sdim    break;
219343171Sdim  default:
220343171Sdim    Id = createSymbolPlaceholder();
221343171Sdim    break;
222343171Sdim  }
223343171Sdim  if (Id != 0) {
224343171Sdim    assert(TypeIndexToSymbolId.count(Index) == 0);
225343171Sdim    TypeIndexToSymbolId[Index] = Id;
226343171Sdim  }
227343171Sdim  return Id;
228343171Sdim}
229343171Sdim
230343171Sdimstd::unique_ptr<PDBSymbol>
231343171SdimSymbolCache::getSymbolById(SymIndexId SymbolId) const {
232343171Sdim  assert(SymbolId < Cache.size());
233343171Sdim
234343171Sdim  // Id 0 is reserved.
235343171Sdim  if (SymbolId == 0 || SymbolId >= Cache.size())
236343171Sdim    return nullptr;
237343171Sdim
238343171Sdim  // Make sure to handle the case where we've inserted a placeholder symbol
239343171Sdim  // for types we don't yet suppport.
240343171Sdim  NativeRawSymbol *NRS = Cache[SymbolId].get();
241343171Sdim  if (!NRS)
242343171Sdim    return nullptr;
243343171Sdim
244343171Sdim  return PDBSymbol::create(Session, *NRS);
245343171Sdim}
246343171Sdim
247343171SdimNativeRawSymbol &SymbolCache::getNativeSymbolById(SymIndexId SymbolId) const {
248343171Sdim  return *Cache[SymbolId];
249343171Sdim}
250343171Sdim
251343171Sdimuint32_t SymbolCache::getNumCompilands() const {
252343171Sdim  if (!Dbi)
253343171Sdim    return 0;
254343171Sdim
255343171Sdim  return Dbi->modules().getModuleCount();
256343171Sdim}
257343171Sdim
258343171SdimSymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) {
259343171Sdim  auto Iter = GlobalOffsetToSymbolId.find(Offset);
260343171Sdim  if (Iter != GlobalOffsetToSymbolId.end())
261343171Sdim    return Iter->second;
262343171Sdim
263343171Sdim  SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream());
264343171Sdim  CVSymbol CVS = SS.readRecord(Offset);
265343171Sdim  SymIndexId Id = 0;
266343171Sdim  switch (CVS.kind()) {
267343171Sdim  case SymbolKind::S_UDT: {
268343171Sdim    UDTSym US = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(CVS));
269343171Sdim    Id = createSymbol<NativeTypeTypedef>(std::move(US));
270343171Sdim    break;
271343171Sdim  }
272343171Sdim  default:
273343171Sdim    Id = createSymbolPlaceholder();
274343171Sdim    break;
275343171Sdim  }
276343171Sdim  if (Id != 0) {
277343171Sdim    assert(GlobalOffsetToSymbolId.count(Offset) == 0);
278343171Sdim    GlobalOffsetToSymbolId[Offset] = Id;
279343171Sdim  }
280343171Sdim
281343171Sdim  return Id;
282343171Sdim}
283343171Sdim
284343171Sdimstd::unique_ptr<PDBSymbolCompiland>
285343171SdimSymbolCache::getOrCreateCompiland(uint32_t Index) {
286343171Sdim  if (!Dbi)
287343171Sdim    return nullptr;
288343171Sdim
289343171Sdim  if (Index >= Compilands.size())
290343171Sdim    return nullptr;
291343171Sdim
292343171Sdim  if (Compilands[Index] == 0) {
293343171Sdim    const DbiModuleList &Modules = Dbi->modules();
294343171Sdim    Compilands[Index] =
295343171Sdim        createSymbol<NativeCompilandSymbol>(Modules.getModuleDescriptor(Index));
296343171Sdim  }
297343171Sdim
298343171Sdim  return Session.getConcreteSymbolById<PDBSymbolCompiland>(Compilands[Index]);
299343171Sdim}
300