1 //==- SymbolCache.h - Cache of native symbols and ids ------------*- C++ -*-==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_DEBUGINFO_PDB_NATIVE_SYMBOLCACHE_H
10 #define LLVM_DEBUGINFO_PDB_NATIVE_SYMBOLCACHE_H
11 
12 #include "llvm/ADT/DenseMap.h"
13 #include "llvm/DebugInfo/CodeView/CVRecord.h"
14 #include "llvm/DebugInfo/CodeView/CodeView.h"
15 #include "llvm/DebugInfo/CodeView/Line.h"
16 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
17 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
18 #include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"
19 #include "llvm/DebugInfo/PDB/Native/NativeSourceFile.h"
20 #include "llvm/DebugInfo/PDB/PDBTypes.h"
21 
22 #include <memory>
23 #include <vector>
24 
25 namespace llvm {
26 namespace codeview {
27 class InlineSiteSym;
28 struct FileChecksumEntry;
29 } // namespace codeview
30 namespace pdb {
31 class IPDBSourceFile;
32 class NativeSession;
33 class PDBSymbol;
34 class PDBSymbolCompiland;
35 class DbiStream;
36 
37 class SymbolCache {
38   NativeSession &Session;
39   DbiStream *Dbi = nullptr;
40 
41   /// Cache of all stable symbols, indexed by SymIndexId.  Just because a
42   /// symbol has been parsed does not imply that it will be stable and have
43   /// an Id.  Id allocation is an implementation, with the only guarantee
44   /// being that once an Id is allocated, the symbol can be assumed to be
45   /// cached.
46   mutable std::vector<std::unique_ptr<NativeRawSymbol>> Cache;
47 
48   /// For type records from the TPI stream which have been paresd and cached,
49   /// stores a mapping to SymIndexId of the cached symbol.
50   mutable DenseMap<codeview::TypeIndex, SymIndexId> TypeIndexToSymbolId;
51 
52   /// For field list members which have been parsed and cached, stores a mapping
53   /// from (IndexOfClass, MemberIndex) to the corresponding SymIndexId of the
54   /// cached symbol.
55   mutable DenseMap<std::pair<codeview::TypeIndex, uint32_t>, SymIndexId>
56       FieldListMembersToSymbolId;
57 
58   /// List of SymIndexIds for each compiland, indexed by compiland index as they
59   /// appear in the PDB file.
60   mutable std::vector<SymIndexId> Compilands;
61 
62   /// List of source files, indexed by unique source file index.
63   mutable std::vector<std::unique_ptr<NativeSourceFile>> SourceFiles;
64 
65   /// Map from string table offset to source file Id.
66   mutable DenseMap<uint32_t, SymIndexId> FileNameOffsetToId;
67 
68   /// Map from global symbol offset to SymIndexId.
69   mutable DenseMap<uint32_t, SymIndexId> GlobalOffsetToSymbolId;
70 
71   /// Map from segment and code offset to function symbols.
72   mutable DenseMap<std::pair<uint32_t, uint32_t>, SymIndexId> AddressToSymbolId;
73   /// Map from segment and code offset to public symbols.
74   mutable DenseMap<std::pair<uint32_t, uint32_t>, SymIndexId>
75       AddressToPublicSymId;
76 
77   /// Map from module index and symbol table offset to SymIndexId.
78   mutable DenseMap<std::pair<uint16_t, uint32_t>, SymIndexId>
79       SymTabOffsetToSymbolId;
80 
81   struct LineTableEntry {
82     uint64_t Addr;
83     codeview::LineInfo Line;
84     uint32_t ColumnNumber;
85     uint32_t FileNameIndex;
86     bool IsTerminalEntry;
87   };
88 
89   std::vector<LineTableEntry> findLineTable(uint16_t Modi) const;
90   mutable DenseMap<uint16_t, std::vector<LineTableEntry>> LineTable;
91 
92   SymIndexId createSymbolPlaceholder() const {
93     SymIndexId Id = Cache.size();
94     Cache.push_back(nullptr);
95     return Id;
96   }
97 
98   template <typename ConcreteSymbolT, typename CVRecordT, typename... Args>
99   SymIndexId createSymbolForType(codeview::TypeIndex TI, codeview::CVType CVT,
100                                  Args &&...ConstructorArgs) const {
101     CVRecordT Record;
102     if (auto EC =
103             codeview::TypeDeserializer::deserializeAs<CVRecordT>(CVT, Record)) {
104       consumeError(std::move(EC));
105       return 0;
106     }
107 
108     return createSymbol<ConcreteSymbolT>(
109         TI, std::move(Record), std::forward<Args>(ConstructorArgs)...);
110   }
111 
112   SymIndexId createSymbolForModifiedType(codeview::TypeIndex ModifierTI,
113                                          codeview::CVType CVT) const;
114 
115   SymIndexId createSimpleType(codeview::TypeIndex TI,
116                               codeview::ModifierOptions Mods) const;
117 
118   std::unique_ptr<PDBSymbol> findFunctionSymbolBySectOffset(uint32_t Sect,
119                                                             uint32_t Offset);
120   std::unique_ptr<PDBSymbol> findPublicSymbolBySectOffset(uint32_t Sect,
121                                                           uint32_t Offset);
122 
123 public:
124   SymbolCache(NativeSession &Session, DbiStream *Dbi);
125 
126   template <typename ConcreteSymbolT, typename... Args>
127   SymIndexId createSymbol(Args &&...ConstructorArgs) const {
128     SymIndexId Id = Cache.size();
129 
130     // Initial construction must not access the cache, since it must be done
131     // atomically.
132     auto Result = std::make_unique<ConcreteSymbolT>(
133         Session, Id, std::forward<Args>(ConstructorArgs)...);
134     Result->SymbolId = Id;
135 
136     NativeRawSymbol *NRS = static_cast<NativeRawSymbol *>(Result.get());
137     Cache.push_back(std::move(Result));
138 
139     // After the item is in the cache, we can do further initialization which
140     // is then allowed to access the cache.
141     NRS->initialize();
142     return Id;
143   }
144 
145   std::unique_ptr<IPDBEnumSymbols>
146   createTypeEnumerator(codeview::TypeLeafKind Kind);
147 
148   std::unique_ptr<IPDBEnumSymbols>
149   createTypeEnumerator(std::vector<codeview::TypeLeafKind> Kinds);
150 
151   std::unique_ptr<IPDBEnumSymbols>
152   createGlobalsEnumerator(codeview::SymbolKind Kind);
153 
154   SymIndexId findSymbolByTypeIndex(codeview::TypeIndex TI) const;
155 
156   template <typename ConcreteSymbolT, typename... Args>
157   SymIndexId getOrCreateFieldListMember(codeview::TypeIndex FieldListTI,
158                                         uint32_t Index,
159                                         Args &&... ConstructorArgs) {
160     SymIndexId SymId = Cache.size();
161     std::pair<codeview::TypeIndex, uint32_t> Key{FieldListTI, Index};
162     auto Result = FieldListMembersToSymbolId.try_emplace(Key, SymId);
163     if (Result.second)
164       SymId =
165           createSymbol<ConcreteSymbolT>(std::forward<Args>(ConstructorArgs)...);
166     else
167       SymId = Result.first->second;
168     return SymId;
169   }
170 
171   SymIndexId getOrCreateGlobalSymbolByOffset(uint32_t Offset);
172   SymIndexId getOrCreateInlineSymbol(codeview::InlineSiteSym Sym,
173                                      uint64_t ParentAddr, uint16_t Modi,
174                                      uint32_t RecordOffset) const;
175 
176   std::unique_ptr<PDBSymbol>
177   findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, PDB_SymType Type);
178 
179   std::unique_ptr<IPDBEnumLineNumbers>
180   findLineNumbersByVA(uint64_t VA, uint32_t Length) const;
181 
182   std::unique_ptr<PDBSymbolCompiland> getOrCreateCompiland(uint32_t Index);
183   uint32_t getNumCompilands() const;
184 
185   std::unique_ptr<PDBSymbol> getSymbolById(SymIndexId SymbolId) const;
186 
187   NativeRawSymbol &getNativeSymbolById(SymIndexId SymbolId) const;
188 
189   template <typename ConcreteT>
190   ConcreteT &getNativeSymbolById(SymIndexId SymbolId) const {
191     return static_cast<ConcreteT &>(getNativeSymbolById(SymbolId));
192   }
193 
194   std::unique_ptr<IPDBSourceFile> getSourceFileById(SymIndexId FileId) const;
195   SymIndexId
196   getOrCreateSourceFile(const codeview::FileChecksumEntry &Checksum) const;
197 };
198 
199 } // namespace pdb
200 } // namespace llvm
201 
202 #endif
203