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