1 | #include "llvm/DebugInfo/PDB/Native/SymbolCache.h" |
2 | |
3 | #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" |
4 | #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" |
5 | #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" |
6 | #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" |
7 | #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" |
8 | #include "llvm/DebugInfo/CodeView/SymbolRecord.h" |
9 | #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" |
10 | #include "llvm/DebugInfo/CodeView/TypeRecord.h" |
11 | #include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" |
12 | #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" |
13 | #include "llvm/DebugInfo/PDB/Native/DbiModuleList.h" |
14 | #include "llvm/DebugInfo/PDB/Native/DbiStream.h" |
15 | #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" |
16 | #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" |
17 | #include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h" |
18 | #include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h" |
19 | #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" |
20 | #include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h" |
21 | #include "llvm/DebugInfo/PDB/Native/NativeInlineSiteSymbol.h" |
22 | #include "llvm/DebugInfo/PDB/Native/NativeLineNumber.h" |
23 | #include "llvm/DebugInfo/PDB/Native/NativePublicSymbol.h" |
24 | #include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" |
25 | #include "llvm/DebugInfo/PDB/Native/NativeSession.h" |
26 | #include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h" |
27 | #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" |
28 | #include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" |
29 | #include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h" |
30 | #include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" |
31 | #include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h" |
32 | #include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h" |
33 | #include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h" |
34 | #include "llvm/DebugInfo/PDB/Native/PDBFile.h" |
35 | #include "llvm/DebugInfo/PDB/Native/PublicsStream.h" |
36 | #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" |
37 | #include "llvm/DebugInfo/PDB/Native/TpiStream.h" |
38 | #include "llvm/DebugInfo/PDB/PDBSymbol.h" |
39 | #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" |
40 | |
41 | using namespace llvm; |
42 | using namespace llvm::codeview; |
43 | using namespace llvm::pdb; |
44 | |
45 | // Maps codeview::SimpleTypeKind of a built-in type to the parameters necessary |
46 | // to instantiate a NativeBuiltinSymbol for that type. |
47 | static const struct BuiltinTypeEntry { |
48 | codeview::SimpleTypeKind Kind; |
49 | PDB_BuiltinType Type; |
50 | uint32_t Size; |
51 | } BuiltinTypes[] = { |
52 | {.Kind: codeview::SimpleTypeKind::None, .Type: PDB_BuiltinType::None, .Size: 0}, |
53 | {.Kind: codeview::SimpleTypeKind::Void, .Type: PDB_BuiltinType::Void, .Size: 0}, |
54 | {.Kind: codeview::SimpleTypeKind::HResult, .Type: PDB_BuiltinType::HResult, .Size: 4}, |
55 | {.Kind: codeview::SimpleTypeKind::Int16Short, .Type: PDB_BuiltinType::Int, .Size: 2}, |
56 | {.Kind: codeview::SimpleTypeKind::UInt16Short, .Type: PDB_BuiltinType::UInt, .Size: 2}, |
57 | {.Kind: codeview::SimpleTypeKind::Int32, .Type: PDB_BuiltinType::Int, .Size: 4}, |
58 | {.Kind: codeview::SimpleTypeKind::UInt32, .Type: PDB_BuiltinType::UInt, .Size: 4}, |
59 | {.Kind: codeview::SimpleTypeKind::Int32Long, .Type: PDB_BuiltinType::Int, .Size: 4}, |
60 | {.Kind: codeview::SimpleTypeKind::UInt32Long, .Type: PDB_BuiltinType::UInt, .Size: 4}, |
61 | {.Kind: codeview::SimpleTypeKind::Int64Quad, .Type: PDB_BuiltinType::Int, .Size: 8}, |
62 | {.Kind: codeview::SimpleTypeKind::UInt64Quad, .Type: PDB_BuiltinType::UInt, .Size: 8}, |
63 | {.Kind: codeview::SimpleTypeKind::NarrowCharacter, .Type: PDB_BuiltinType::Char, .Size: 1}, |
64 | {.Kind: codeview::SimpleTypeKind::WideCharacter, .Type: PDB_BuiltinType::WCharT, .Size: 2}, |
65 | {.Kind: codeview::SimpleTypeKind::Character16, .Type: PDB_BuiltinType::Char16, .Size: 2}, |
66 | {.Kind: codeview::SimpleTypeKind::Character32, .Type: PDB_BuiltinType::Char32, .Size: 4}, |
67 | {.Kind: codeview::SimpleTypeKind::Character8, .Type: PDB_BuiltinType::Char8, .Size: 1}, |
68 | {.Kind: codeview::SimpleTypeKind::SignedCharacter, .Type: PDB_BuiltinType::Char, .Size: 1}, |
69 | {.Kind: codeview::SimpleTypeKind::UnsignedCharacter, .Type: PDB_BuiltinType::UInt, .Size: 1}, |
70 | {.Kind: codeview::SimpleTypeKind::Float32, .Type: PDB_BuiltinType::Float, .Size: 4}, |
71 | {.Kind: codeview::SimpleTypeKind::Float64, .Type: PDB_BuiltinType::Float, .Size: 8}, |
72 | {.Kind: codeview::SimpleTypeKind::Float80, .Type: PDB_BuiltinType::Float, .Size: 10}, |
73 | {.Kind: codeview::SimpleTypeKind::Boolean8, .Type: PDB_BuiltinType::Bool, .Size: 1}, |
74 | // This table can be grown as necessary, but these are the only types we've |
75 | // needed so far. |
76 | }; |
77 | |
78 | SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi) |
79 | : Session(Session), Dbi(Dbi) { |
80 | // Id 0 is reserved for the invalid symbol. |
81 | Cache.push_back(x: nullptr); |
82 | SourceFiles.push_back(x: nullptr); |
83 | |
84 | if (Dbi) |
85 | Compilands.resize(new_size: Dbi->modules().getModuleCount()); |
86 | } |
87 | |
88 | std::unique_ptr<IPDBEnumSymbols> |
89 | SymbolCache::createTypeEnumerator(TypeLeafKind Kind) { |
90 | return createTypeEnumerator(Kinds: std::vector<TypeLeafKind>{Kind}); |
91 | } |
92 | |
93 | std::unique_ptr<IPDBEnumSymbols> |
94 | SymbolCache::createTypeEnumerator(std::vector<TypeLeafKind> Kinds) { |
95 | auto Tpi = Session.getPDBFile().getPDBTpiStream(); |
96 | if (!Tpi) { |
97 | consumeError(Err: Tpi.takeError()); |
98 | return nullptr; |
99 | } |
100 | auto &Types = Tpi->typeCollection(); |
101 | return std::unique_ptr<IPDBEnumSymbols>( |
102 | new NativeEnumTypes(Session, Types, std::move(Kinds))); |
103 | } |
104 | |
105 | std::unique_ptr<IPDBEnumSymbols> |
106 | SymbolCache::createGlobalsEnumerator(codeview::SymbolKind Kind) { |
107 | return std::unique_ptr<IPDBEnumSymbols>( |
108 | new NativeEnumGlobals(Session, {Kind})); |
109 | } |
110 | |
111 | SymIndexId SymbolCache::createSimpleType(TypeIndex Index, |
112 | ModifierOptions Mods) const { |
113 | if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct) |
114 | return createSymbol<NativeTypePointer>(ConstructorArgs&: Index); |
115 | |
116 | const auto Kind = Index.getSimpleKind(); |
117 | const auto It = |
118 | llvm::find_if(Range: BuiltinTypes, P: [Kind](const BuiltinTypeEntry &Builtin) { |
119 | return Builtin.Kind == Kind; |
120 | }); |
121 | if (It == std::end(arr: BuiltinTypes)) |
122 | return 0; |
123 | return createSymbol<NativeTypeBuiltin>(ConstructorArgs&: Mods, ConstructorArgs: It->Type, ConstructorArgs: It->Size); |
124 | } |
125 | |
126 | SymIndexId |
127 | SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI, |
128 | codeview::CVType CVT) const { |
129 | ModifierRecord Record; |
130 | if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) { |
131 | consumeError(Err: std::move(EC)); |
132 | return 0; |
133 | } |
134 | |
135 | if (Record.ModifiedType.isSimple()) |
136 | return createSimpleType(Index: Record.ModifiedType, Mods: Record.Modifiers); |
137 | |
138 | // Make sure we create and cache a record for the unmodified type. |
139 | SymIndexId UnmodifiedId = findSymbolByTypeIndex(TI: Record.ModifiedType); |
140 | NativeRawSymbol &UnmodifiedNRS = *Cache[UnmodifiedId]; |
141 | |
142 | switch (UnmodifiedNRS.getSymTag()) { |
143 | case PDB_SymType::Enum: |
144 | return createSymbol<NativeTypeEnum>( |
145 | ConstructorArgs&: static_cast<NativeTypeEnum &>(UnmodifiedNRS), ConstructorArgs: std::move(Record)); |
146 | case PDB_SymType::UDT: |
147 | return createSymbol<NativeTypeUDT>( |
148 | ConstructorArgs&: static_cast<NativeTypeUDT &>(UnmodifiedNRS), ConstructorArgs: std::move(Record)); |
149 | default: |
150 | // No other types can be modified. (LF_POINTER, for example, records |
151 | // its modifiers a different way. |
152 | assert(false && "Invalid LF_MODIFIER record" ); |
153 | break; |
154 | } |
155 | return 0; |
156 | } |
157 | |
158 | SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) const { |
159 | // First see if it's already in our cache. |
160 | const auto Entry = TypeIndexToSymbolId.find(Val: Index); |
161 | if (Entry != TypeIndexToSymbolId.end()) |
162 | return Entry->second; |
163 | |
164 | // Symbols for built-in types are created on the fly. |
165 | if (Index.isSimple()) { |
166 | SymIndexId Result = createSimpleType(Index, Mods: ModifierOptions::None); |
167 | assert(TypeIndexToSymbolId.count(Index) == 0); |
168 | TypeIndexToSymbolId[Index] = Result; |
169 | return Result; |
170 | } |
171 | |
172 | // We need to instantiate and cache the desired type symbol. |
173 | auto Tpi = Session.getPDBFile().getPDBTpiStream(); |
174 | if (!Tpi) { |
175 | consumeError(Err: Tpi.takeError()); |
176 | return 0; |
177 | } |
178 | codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection(); |
179 | codeview::CVType CVT = Types.getType(Index); |
180 | |
181 | if (isUdtForwardRef(CVT)) { |
182 | Expected<TypeIndex> EFD = Tpi->findFullDeclForForwardRef(ForwardRefTI: Index); |
183 | |
184 | if (!EFD) |
185 | consumeError(Err: EFD.takeError()); |
186 | else if (*EFD != Index) { |
187 | assert(!isUdtForwardRef(Types.getType(*EFD))); |
188 | SymIndexId Result = findSymbolByTypeIndex(Index: *EFD); |
189 | // Record a mapping from ForwardRef -> SymIndex of complete type so that |
190 | // we'll take the fast path next time. |
191 | assert(TypeIndexToSymbolId.count(Index) == 0); |
192 | TypeIndexToSymbolId[Index] = Result; |
193 | return Result; |
194 | } |
195 | } |
196 | |
197 | // At this point if we still have a forward ref udt it means the full decl was |
198 | // not in the PDB. We just have to deal with it and use the forward ref. |
199 | SymIndexId Id = 0; |
200 | switch (CVT.kind()) { |
201 | case codeview::LF_ENUM: |
202 | Id = createSymbolForType<NativeTypeEnum, EnumRecord>(TI: Index, CVT: std::move(CVT)); |
203 | break; |
204 | case codeview::LF_ARRAY: |
205 | Id = createSymbolForType<NativeTypeArray, ArrayRecord>(TI: Index, |
206 | CVT: std::move(CVT)); |
207 | break; |
208 | case codeview::LF_CLASS: |
209 | case codeview::LF_STRUCTURE: |
210 | case codeview::LF_INTERFACE: |
211 | Id = createSymbolForType<NativeTypeUDT, ClassRecord>(TI: Index, CVT: std::move(CVT)); |
212 | break; |
213 | case codeview::LF_UNION: |
214 | Id = createSymbolForType<NativeTypeUDT, UnionRecord>(TI: Index, CVT: std::move(CVT)); |
215 | break; |
216 | case codeview::LF_POINTER: |
217 | Id = createSymbolForType<NativeTypePointer, PointerRecord>(TI: Index, |
218 | CVT: std::move(CVT)); |
219 | break; |
220 | case codeview::LF_MODIFIER: |
221 | Id = createSymbolForModifiedType(ModifierTI: Index, CVT: std::move(CVT)); |
222 | break; |
223 | case codeview::LF_PROCEDURE: |
224 | Id = createSymbolForType<NativeTypeFunctionSig, ProcedureRecord>( |
225 | TI: Index, CVT: std::move(CVT)); |
226 | break; |
227 | case codeview::LF_MFUNCTION: |
228 | Id = createSymbolForType<NativeTypeFunctionSig, MemberFunctionRecord>( |
229 | TI: Index, CVT: std::move(CVT)); |
230 | break; |
231 | case codeview::LF_VTSHAPE: |
232 | Id = createSymbolForType<NativeTypeVTShape, VFTableShapeRecord>( |
233 | TI: Index, CVT: std::move(CVT)); |
234 | break; |
235 | default: |
236 | Id = createSymbolPlaceholder(); |
237 | break; |
238 | } |
239 | if (Id != 0) { |
240 | assert(TypeIndexToSymbolId.count(Index) == 0); |
241 | TypeIndexToSymbolId[Index] = Id; |
242 | } |
243 | return Id; |
244 | } |
245 | |
246 | std::unique_ptr<PDBSymbol> |
247 | SymbolCache::getSymbolById(SymIndexId SymbolId) const { |
248 | assert(SymbolId < Cache.size()); |
249 | |
250 | // Id 0 is reserved. |
251 | if (SymbolId == 0 || SymbolId >= Cache.size()) |
252 | return nullptr; |
253 | |
254 | // Make sure to handle the case where we've inserted a placeholder symbol |
255 | // for types we don't yet support. |
256 | NativeRawSymbol *NRS = Cache[SymbolId].get(); |
257 | if (!NRS) |
258 | return nullptr; |
259 | |
260 | return PDBSymbol::create(PDBSession: Session, RawSymbol&: *NRS); |
261 | } |
262 | |
263 | NativeRawSymbol &SymbolCache::getNativeSymbolById(SymIndexId SymbolId) const { |
264 | return *Cache[SymbolId]; |
265 | } |
266 | |
267 | uint32_t SymbolCache::getNumCompilands() const { |
268 | if (!Dbi) |
269 | return 0; |
270 | |
271 | return Dbi->modules().getModuleCount(); |
272 | } |
273 | |
274 | SymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) { |
275 | auto Iter = GlobalOffsetToSymbolId.find(Val: Offset); |
276 | if (Iter != GlobalOffsetToSymbolId.end()) |
277 | return Iter->second; |
278 | |
279 | SymbolStream &SS = cantFail(ValOrErr: Session.getPDBFile().getPDBSymbolStream()); |
280 | CVSymbol CVS = SS.readRecord(Offset); |
281 | SymIndexId Id = 0; |
282 | switch (CVS.kind()) { |
283 | case SymbolKind::S_UDT: { |
284 | UDTSym US = cantFail(ValOrErr: SymbolDeserializer::deserializeAs<UDTSym>(Symbol: CVS)); |
285 | Id = createSymbol<NativeTypeTypedef>(ConstructorArgs: std::move(US)); |
286 | break; |
287 | } |
288 | default: |
289 | Id = createSymbolPlaceholder(); |
290 | break; |
291 | } |
292 | if (Id != 0) { |
293 | assert(GlobalOffsetToSymbolId.count(Offset) == 0); |
294 | GlobalOffsetToSymbolId[Offset] = Id; |
295 | } |
296 | |
297 | return Id; |
298 | } |
299 | |
300 | SymIndexId SymbolCache::getOrCreateInlineSymbol(InlineSiteSym Sym, |
301 | uint64_t ParentAddr, |
302 | uint16_t Modi, |
303 | uint32_t RecordOffset) const { |
304 | auto Iter = SymTabOffsetToSymbolId.find(Val: {Modi, RecordOffset}); |
305 | if (Iter != SymTabOffsetToSymbolId.end()) |
306 | return Iter->second; |
307 | |
308 | SymIndexId Id = createSymbol<NativeInlineSiteSymbol>(ConstructorArgs&: Sym, ConstructorArgs&: ParentAddr); |
309 | SymTabOffsetToSymbolId.insert(KV: {{Modi, RecordOffset}, Id}); |
310 | return Id; |
311 | } |
312 | |
313 | std::unique_ptr<PDBSymbol> |
314 | SymbolCache::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, |
315 | PDB_SymType Type) { |
316 | switch (Type) { |
317 | case PDB_SymType::Function: |
318 | return findFunctionSymbolBySectOffset(Sect, Offset); |
319 | case PDB_SymType::PublicSymbol: |
320 | return findPublicSymbolBySectOffset(Sect, Offset); |
321 | case PDB_SymType::Compiland: { |
322 | uint16_t Modi; |
323 | if (!Session.moduleIndexForSectOffset(Sect, Offset, ModuleIndex&: Modi)) |
324 | return nullptr; |
325 | return getOrCreateCompiland(Index: Modi); |
326 | } |
327 | case PDB_SymType::None: { |
328 | // FIXME: Implement for PDB_SymType::Data. The symbolizer calls this but |
329 | // only uses it to find the symbol length. |
330 | if (auto Sym = findFunctionSymbolBySectOffset(Sect, Offset)) |
331 | return Sym; |
332 | return nullptr; |
333 | } |
334 | default: |
335 | return nullptr; |
336 | } |
337 | } |
338 | |
339 | std::unique_ptr<PDBSymbol> |
340 | SymbolCache::findFunctionSymbolBySectOffset(uint32_t Sect, uint32_t Offset) { |
341 | auto Iter = AddressToSymbolId.find(Val: {Sect, Offset}); |
342 | if (Iter != AddressToSymbolId.end()) |
343 | return getSymbolById(SymbolId: Iter->second); |
344 | |
345 | if (!Dbi) |
346 | return nullptr; |
347 | |
348 | uint16_t Modi; |
349 | if (!Session.moduleIndexForSectOffset(Sect, Offset, ModuleIndex&: Modi)) |
350 | return nullptr; |
351 | |
352 | Expected<ModuleDebugStreamRef> ExpectedModS = |
353 | Session.getModuleDebugStream(Index: Modi); |
354 | if (!ExpectedModS) { |
355 | consumeError(Err: ExpectedModS.takeError()); |
356 | return nullptr; |
357 | } |
358 | CVSymbolArray Syms = ExpectedModS->getSymbolArray(); |
359 | |
360 | // Search for the symbol in this module. |
361 | for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) { |
362 | if (I->kind() != S_LPROC32 && I->kind() != S_GPROC32) |
363 | continue; |
364 | auto PS = cantFail(ValOrErr: SymbolDeserializer::deserializeAs<ProcSym>(Symbol: *I)); |
365 | if (Sect == PS.Segment && Offset >= PS.CodeOffset && |
366 | Offset < PS.CodeOffset + PS.CodeSize) { |
367 | // Check if the symbol is already cached. |
368 | auto Found = AddressToSymbolId.find(Val: {PS.Segment, PS.CodeOffset}); |
369 | if (Found != AddressToSymbolId.end()) |
370 | return getSymbolById(SymbolId: Found->second); |
371 | |
372 | // Otherwise, create a new symbol. |
373 | SymIndexId Id = createSymbol<NativeFunctionSymbol>(ConstructorArgs&: PS, ConstructorArgs: I.offset()); |
374 | AddressToSymbolId.insert(KV: {{PS.Segment, PS.CodeOffset}, Id}); |
375 | return getSymbolById(SymbolId: Id); |
376 | } |
377 | |
378 | // Jump to the end of this ProcSym. |
379 | I = Syms.at(Offset: PS.End); |
380 | } |
381 | return nullptr; |
382 | } |
383 | |
384 | std::unique_ptr<PDBSymbol> |
385 | SymbolCache::findPublicSymbolBySectOffset(uint32_t Sect, uint32_t Offset) { |
386 | auto Iter = AddressToPublicSymId.find(Val: {Sect, Offset}); |
387 | if (Iter != AddressToPublicSymId.end()) |
388 | return getSymbolById(SymbolId: Iter->second); |
389 | |
390 | auto Publics = Session.getPDBFile().getPDBPublicsStream(); |
391 | if (!Publics) |
392 | return nullptr; |
393 | |
394 | auto ExpectedSyms = Session.getPDBFile().getPDBSymbolStream(); |
395 | if (!ExpectedSyms) |
396 | return nullptr; |
397 | BinaryStreamRef SymStream = |
398 | ExpectedSyms->getSymbolArray().getUnderlyingStream(); |
399 | |
400 | // Use binary search to find the first public symbol with an address greater |
401 | // than or equal to Sect, Offset. |
402 | auto AddrMap = Publics->getAddressMap(); |
403 | auto First = AddrMap.begin(); |
404 | auto It = AddrMap.begin(); |
405 | size_t Count = AddrMap.size(); |
406 | size_t Half; |
407 | while (Count > 0) { |
408 | It = First; |
409 | Half = Count / 2; |
410 | It += Half; |
411 | Expected<CVSymbol> Sym = readSymbolFromStream(Stream: SymStream, Offset: *It); |
412 | if (!Sym) { |
413 | consumeError(Err: Sym.takeError()); |
414 | return nullptr; |
415 | } |
416 | |
417 | auto PS = |
418 | cantFail(ValOrErr: SymbolDeserializer::deserializeAs<PublicSym32>(Symbol: Sym.get())); |
419 | if (PS.Segment < Sect || (PS.Segment == Sect && PS.Offset <= Offset)) { |
420 | First = ++It; |
421 | Count -= Half + 1; |
422 | } else |
423 | Count = Half; |
424 | } |
425 | if (It == AddrMap.begin()) |
426 | return nullptr; |
427 | --It; |
428 | |
429 | Expected<CVSymbol> Sym = readSymbolFromStream(Stream: SymStream, Offset: *It); |
430 | if (!Sym) { |
431 | consumeError(Err: Sym.takeError()); |
432 | return nullptr; |
433 | } |
434 | |
435 | // Check if the symbol is already cached. |
436 | auto PS = cantFail(ValOrErr: SymbolDeserializer::deserializeAs<PublicSym32>(Symbol: Sym.get())); |
437 | auto Found = AddressToPublicSymId.find(Val: {PS.Segment, PS.Offset}); |
438 | if (Found != AddressToPublicSymId.end()) |
439 | return getSymbolById(SymbolId: Found->second); |
440 | |
441 | // Otherwise, create a new symbol. |
442 | SymIndexId Id = createSymbol<NativePublicSymbol>(ConstructorArgs&: PS); |
443 | AddressToPublicSymId.insert(KV: {{PS.Segment, PS.Offset}, Id}); |
444 | return getSymbolById(SymbolId: Id); |
445 | } |
446 | |
447 | std::vector<SymbolCache::LineTableEntry> |
448 | SymbolCache::findLineTable(uint16_t Modi) const { |
449 | // Check if this module has already been added. |
450 | auto LineTableIter = LineTable.find(Val: Modi); |
451 | if (LineTableIter != LineTable.end()) |
452 | return LineTableIter->second; |
453 | |
454 | std::vector<LineTableEntry> &ModuleLineTable = LineTable[Modi]; |
455 | |
456 | // If there is an error or there are no lines, just return the |
457 | // empty vector. |
458 | Expected<ModuleDebugStreamRef> ExpectedModS = |
459 | Session.getModuleDebugStream(Index: Modi); |
460 | if (!ExpectedModS) { |
461 | consumeError(Err: ExpectedModS.takeError()); |
462 | return ModuleLineTable; |
463 | } |
464 | |
465 | std::vector<std::vector<LineTableEntry>> EntryList; |
466 | for (const auto &SS : ExpectedModS->getSubsectionsArray()) { |
467 | if (SS.kind() != DebugSubsectionKind::Lines) |
468 | continue; |
469 | |
470 | DebugLinesSubsectionRef Lines; |
471 | BinaryStreamReader Reader(SS.getRecordData()); |
472 | if (auto EC = Lines.initialize(Reader)) { |
473 | consumeError(Err: std::move(EC)); |
474 | continue; |
475 | } |
476 | |
477 | uint32_t RelocSegment = Lines.header()->RelocSegment; |
478 | uint32_t RelocOffset = Lines.header()->RelocOffset; |
479 | for (const LineColumnEntry &Group : Lines) { |
480 | if (Group.LineNumbers.empty()) |
481 | continue; |
482 | |
483 | std::vector<LineTableEntry> Entries; |
484 | |
485 | // If there are column numbers, then they should be in a parallel stream |
486 | // to the line numbers. |
487 | auto ColIt = Group.Columns.begin(); |
488 | auto ColsEnd = Group.Columns.end(); |
489 | |
490 | // Add a line to mark the beginning of this section. |
491 | uint64_t StartAddr = |
492 | Session.getVAFromSectOffset(Section: RelocSegment, Offset: RelocOffset); |
493 | LineInfo FirstLine(Group.LineNumbers.front().Flags); |
494 | uint32_t ColNum = |
495 | (Lines.hasColumnInfo()) ? Group.Columns.front().StartColumn : 0; |
496 | Entries.push_back(x: {.Addr: StartAddr, .Line: FirstLine, .ColumnNumber: ColNum, .FileNameIndex: Group.NameIndex, .IsTerminalEntry: false}); |
497 | |
498 | for (const LineNumberEntry &LN : Group.LineNumbers) { |
499 | uint64_t VA = |
500 | Session.getVAFromSectOffset(Section: RelocSegment, Offset: RelocOffset + LN.Offset); |
501 | LineInfo Line(LN.Flags); |
502 | ColNum = 0; |
503 | |
504 | if (Lines.hasColumnInfo() && ColIt != ColsEnd) { |
505 | ColNum = ColIt->StartColumn; |
506 | ++ColIt; |
507 | } |
508 | Entries.push_back(x: {.Addr: VA, .Line: Line, .ColumnNumber: ColNum, .FileNameIndex: Group.NameIndex, .IsTerminalEntry: false}); |
509 | } |
510 | |
511 | // Add a terminal entry line to mark the end of this subsection. |
512 | uint64_t EndAddr = StartAddr + Lines.header()->CodeSize; |
513 | LineInfo LastLine(Group.LineNumbers.back().Flags); |
514 | ColNum = (Lines.hasColumnInfo()) ? Group.Columns.back().StartColumn : 0; |
515 | Entries.push_back(x: {.Addr: EndAddr, .Line: LastLine, .ColumnNumber: ColNum, .FileNameIndex: Group.NameIndex, .IsTerminalEntry: true}); |
516 | |
517 | EntryList.push_back(x: Entries); |
518 | } |
519 | } |
520 | |
521 | // Sort EntryList, and add flattened contents to the line table. |
522 | llvm::sort(C&: EntryList, Comp: [](const std::vector<LineTableEntry> &LHS, |
523 | const std::vector<LineTableEntry> &RHS) { |
524 | return LHS[0].Addr < RHS[0].Addr; |
525 | }); |
526 | for (std::vector<LineTableEntry> &I : EntryList) |
527 | llvm::append_range(C&: ModuleLineTable, R&: I); |
528 | |
529 | return ModuleLineTable; |
530 | } |
531 | |
532 | std::unique_ptr<IPDBEnumLineNumbers> |
533 | SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const { |
534 | uint16_t Modi; |
535 | if (!Session.moduleIndexForVA(VA, ModuleIndex&: Modi)) |
536 | return nullptr; |
537 | |
538 | std::vector<LineTableEntry> Lines = findLineTable(Modi); |
539 | if (Lines.empty()) |
540 | return nullptr; |
541 | |
542 | // Find the first line in the line table whose address is not greater than |
543 | // the one we are searching for. |
544 | auto LineIter = llvm::partition_point(Range&: Lines, P: [&](const LineTableEntry &E) { |
545 | return (E.Addr < VA || (E.Addr == VA && E.IsTerminalEntry)); |
546 | }); |
547 | |
548 | // Try to back up if we've gone too far. |
549 | if (LineIter == Lines.end() || LineIter->Addr > VA) { |
550 | if (LineIter == Lines.begin() || std::prev(x: LineIter)->IsTerminalEntry) |
551 | return nullptr; |
552 | --LineIter; |
553 | } |
554 | |
555 | Expected<ModuleDebugStreamRef> ExpectedModS = |
556 | Session.getModuleDebugStream(Index: Modi); |
557 | if (!ExpectedModS) { |
558 | consumeError(Err: ExpectedModS.takeError()); |
559 | return nullptr; |
560 | } |
561 | Expected<DebugChecksumsSubsectionRef> ExpectedChecksums = |
562 | ExpectedModS->findChecksumsSubsection(); |
563 | if (!ExpectedChecksums) { |
564 | consumeError(Err: ExpectedChecksums.takeError()); |
565 | return nullptr; |
566 | } |
567 | |
568 | // Populate a vector of NativeLineNumbers that have addresses in the given |
569 | // address range. |
570 | std::vector<NativeLineNumber> LineNumbers; |
571 | while (LineIter != Lines.end()) { |
572 | if (LineIter->IsTerminalEntry) { |
573 | ++LineIter; |
574 | continue; |
575 | } |
576 | |
577 | // If the line is still within the address range, create a NativeLineNumber |
578 | // and add to the list. |
579 | if (LineIter->Addr > VA + Length) |
580 | break; |
581 | |
582 | uint32_t LineSect, LineOff; |
583 | Session.addressForVA(VA: LineIter->Addr, Section&: LineSect, Offset&: LineOff); |
584 | uint32_t LineLength = std::next(x: LineIter)->Addr - LineIter->Addr; |
585 | auto ChecksumIter = |
586 | ExpectedChecksums->getArray().at(Offset: LineIter->FileNameIndex); |
587 | uint32_t SrcFileId = getOrCreateSourceFile(Checksum: *ChecksumIter); |
588 | NativeLineNumber LineNum(Session, LineIter->Line, LineIter->ColumnNumber, |
589 | LineSect, LineOff, LineLength, SrcFileId, Modi); |
590 | LineNumbers.push_back(x: LineNum); |
591 | ++LineIter; |
592 | } |
593 | return std::make_unique<NativeEnumLineNumbers>(args: std::move(LineNumbers)); |
594 | } |
595 | |
596 | std::unique_ptr<PDBSymbolCompiland> |
597 | SymbolCache::getOrCreateCompiland(uint32_t Index) { |
598 | if (!Dbi) |
599 | return nullptr; |
600 | |
601 | if (Index >= Compilands.size()) |
602 | return nullptr; |
603 | |
604 | if (Compilands[Index] == 0) { |
605 | const DbiModuleList &Modules = Dbi->modules(); |
606 | Compilands[Index] = |
607 | createSymbol<NativeCompilandSymbol>(ConstructorArgs: Modules.getModuleDescriptor(Modi: Index)); |
608 | } |
609 | |
610 | return Session.getConcreteSymbolById<PDBSymbolCompiland>(SymbolId: Compilands[Index]); |
611 | } |
612 | |
613 | std::unique_ptr<IPDBSourceFile> |
614 | SymbolCache::getSourceFileById(SymIndexId FileId) const { |
615 | assert(FileId < SourceFiles.size()); |
616 | |
617 | // Id 0 is reserved. |
618 | if (FileId == 0) |
619 | return nullptr; |
620 | |
621 | return std::make_unique<NativeSourceFile>(args&: *SourceFiles[FileId].get()); |
622 | } |
623 | |
624 | SymIndexId |
625 | SymbolCache::getOrCreateSourceFile(const FileChecksumEntry &Checksums) const { |
626 | auto Iter = FileNameOffsetToId.find(Val: Checksums.FileNameOffset); |
627 | if (Iter != FileNameOffsetToId.end()) |
628 | return Iter->second; |
629 | |
630 | SymIndexId Id = SourceFiles.size(); |
631 | auto SrcFile = std::make_unique<NativeSourceFile>(args&: Session, args&: Id, args: Checksums); |
632 | SourceFiles.push_back(x: std::move(SrcFile)); |
633 | FileNameOffsetToId[Checksums.FileNameOffset] = Id; |
634 | return Id; |
635 | } |
636 | |
637 | |
638 | |