| 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 | consumeError(Err: Publics.takeError()); |
| 393 | return nullptr; |
| 394 | } |
| 395 | |
| 396 | auto ExpectedSyms = Session.getPDBFile().getPDBSymbolStream(); |
| 397 | if (!ExpectedSyms) { |
| 398 | consumeError(Err: ExpectedSyms.takeError()); |
| 399 | return nullptr; |
| 400 | } |
| 401 | BinaryStreamRef SymStream = |
| 402 | ExpectedSyms->getSymbolArray().getUnderlyingStream(); |
| 403 | |
| 404 | // Use binary search to find the first public symbol with an address greater |
| 405 | // than or equal to Sect, Offset. |
| 406 | auto AddrMap = Publics->getAddressMap(); |
| 407 | auto First = AddrMap.begin(); |
| 408 | auto It = AddrMap.begin(); |
| 409 | size_t Count = AddrMap.size(); |
| 410 | size_t Half; |
| 411 | while (Count > 0) { |
| 412 | It = First; |
| 413 | Half = Count / 2; |
| 414 | It += Half; |
| 415 | Expected<CVSymbol> Sym = readSymbolFromStream(Stream: SymStream, Offset: *It); |
| 416 | if (!Sym) { |
| 417 | consumeError(Err: Sym.takeError()); |
| 418 | return nullptr; |
| 419 | } |
| 420 | |
| 421 | auto PS = |
| 422 | cantFail(ValOrErr: SymbolDeserializer::deserializeAs<PublicSym32>(Symbol: Sym.get())); |
| 423 | if (PS.Segment < Sect || (PS.Segment == Sect && PS.Offset <= Offset)) { |
| 424 | First = ++It; |
| 425 | Count -= Half + 1; |
| 426 | } else |
| 427 | Count = Half; |
| 428 | } |
| 429 | if (It == AddrMap.begin()) |
| 430 | return nullptr; |
| 431 | --It; |
| 432 | |
| 433 | Expected<CVSymbol> Sym = readSymbolFromStream(Stream: SymStream, Offset: *It); |
| 434 | if (!Sym) { |
| 435 | consumeError(Err: Sym.takeError()); |
| 436 | return nullptr; |
| 437 | } |
| 438 | |
| 439 | // Check if the symbol is already cached. |
| 440 | auto PS = cantFail(ValOrErr: SymbolDeserializer::deserializeAs<PublicSym32>(Symbol: Sym.get())); |
| 441 | auto Found = AddressToPublicSymId.find(Val: {PS.Segment, PS.Offset}); |
| 442 | if (Found != AddressToPublicSymId.end()) |
| 443 | return getSymbolById(SymbolId: Found->second); |
| 444 | |
| 445 | // Otherwise, create a new symbol. |
| 446 | SymIndexId Id = createSymbol<NativePublicSymbol>(ConstructorArgs&: PS); |
| 447 | AddressToPublicSymId.insert(KV: {{PS.Segment, PS.Offset}, Id}); |
| 448 | return getSymbolById(SymbolId: Id); |
| 449 | } |
| 450 | |
| 451 | std::vector<SymbolCache::LineTableEntry> |
| 452 | SymbolCache::findLineTable(uint16_t Modi) const { |
| 453 | // Check if this module has already been added. |
| 454 | auto [LineTableIter, Inserted] = LineTable.try_emplace(Key: Modi); |
| 455 | if (!Inserted) |
| 456 | return LineTableIter->second; |
| 457 | |
| 458 | std::vector<LineTableEntry> &ModuleLineTable = LineTableIter->second; |
| 459 | |
| 460 | // If there is an error or there are no lines, just return the |
| 461 | // empty vector. |
| 462 | Expected<ModuleDebugStreamRef> ExpectedModS = |
| 463 | Session.getModuleDebugStream(Index: Modi); |
| 464 | if (!ExpectedModS) { |
| 465 | consumeError(Err: ExpectedModS.takeError()); |
| 466 | return ModuleLineTable; |
| 467 | } |
| 468 | |
| 469 | std::vector<std::vector<LineTableEntry>> EntryList; |
| 470 | for (const auto &SS : ExpectedModS->getSubsectionsArray()) { |
| 471 | if (SS.kind() != DebugSubsectionKind::Lines) |
| 472 | continue; |
| 473 | |
| 474 | DebugLinesSubsectionRef Lines; |
| 475 | BinaryStreamReader Reader(SS.getRecordData()); |
| 476 | if (auto EC = Lines.initialize(Reader)) { |
| 477 | consumeError(Err: std::move(EC)); |
| 478 | continue; |
| 479 | } |
| 480 | |
| 481 | uint32_t RelocSegment = Lines.header()->RelocSegment; |
| 482 | uint32_t RelocOffset = Lines.header()->RelocOffset; |
| 483 | for (const LineColumnEntry &Group : Lines) { |
| 484 | if (Group.LineNumbers.empty()) |
| 485 | continue; |
| 486 | |
| 487 | std::vector<LineTableEntry> Entries; |
| 488 | |
| 489 | // If there are column numbers, then they should be in a parallel stream |
| 490 | // to the line numbers. |
| 491 | auto ColIt = Group.Columns.begin(); |
| 492 | auto ColsEnd = Group.Columns.end(); |
| 493 | |
| 494 | // Add a line to mark the beginning of this section. |
| 495 | uint64_t StartAddr = |
| 496 | Session.getVAFromSectOffset(Section: RelocSegment, Offset: RelocOffset); |
| 497 | LineInfo FirstLine(Group.LineNumbers.front().Flags); |
| 498 | uint32_t ColNum = |
| 499 | (Lines.hasColumnInfo()) ? Group.Columns.front().StartColumn : 0; |
| 500 | Entries.push_back(x: {.Addr: StartAddr, .Line: FirstLine, .ColumnNumber: ColNum, .FileNameIndex: Group.NameIndex, .IsTerminalEntry: false}); |
| 501 | |
| 502 | for (const LineNumberEntry &LN : Group.LineNumbers) { |
| 503 | uint64_t VA = |
| 504 | Session.getVAFromSectOffset(Section: RelocSegment, Offset: RelocOffset + LN.Offset); |
| 505 | LineInfo Line(LN.Flags); |
| 506 | ColNum = 0; |
| 507 | |
| 508 | if (Lines.hasColumnInfo() && ColIt != ColsEnd) { |
| 509 | ColNum = ColIt->StartColumn; |
| 510 | ++ColIt; |
| 511 | } |
| 512 | Entries.push_back(x: {.Addr: VA, .Line: Line, .ColumnNumber: ColNum, .FileNameIndex: Group.NameIndex, .IsTerminalEntry: false}); |
| 513 | } |
| 514 | |
| 515 | // Add a terminal entry line to mark the end of this subsection. |
| 516 | uint64_t EndAddr = StartAddr + Lines.header()->CodeSize; |
| 517 | LineInfo LastLine(Group.LineNumbers.back().Flags); |
| 518 | ColNum = (Lines.hasColumnInfo()) ? Group.Columns.back().StartColumn : 0; |
| 519 | Entries.push_back(x: {.Addr: EndAddr, .Line: LastLine, .ColumnNumber: ColNum, .FileNameIndex: Group.NameIndex, .IsTerminalEntry: true}); |
| 520 | |
| 521 | EntryList.push_back(x: Entries); |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | // Sort EntryList, and add flattened contents to the line table. |
| 526 | llvm::sort(C&: EntryList, Comp: [](const std::vector<LineTableEntry> &LHS, |
| 527 | const std::vector<LineTableEntry> &RHS) { |
| 528 | return LHS[0].Addr < RHS[0].Addr; |
| 529 | }); |
| 530 | for (std::vector<LineTableEntry> &I : EntryList) |
| 531 | llvm::append_range(C&: ModuleLineTable, R&: I); |
| 532 | |
| 533 | return ModuleLineTable; |
| 534 | } |
| 535 | |
| 536 | std::unique_ptr<IPDBEnumLineNumbers> |
| 537 | SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const { |
| 538 | uint16_t Modi; |
| 539 | if (!Session.moduleIndexForVA(VA, ModuleIndex&: Modi)) |
| 540 | return nullptr; |
| 541 | |
| 542 | std::vector<LineTableEntry> Lines = findLineTable(Modi); |
| 543 | if (Lines.empty()) |
| 544 | return nullptr; |
| 545 | |
| 546 | // Find the first line in the line table whose address is not greater than |
| 547 | // the one we are searching for. |
| 548 | auto LineIter = llvm::partition_point(Range&: Lines, P: [&](const LineTableEntry &E) { |
| 549 | return (E.Addr < VA || (E.Addr == VA && E.IsTerminalEntry)); |
| 550 | }); |
| 551 | |
| 552 | // Try to back up if we've gone too far. |
| 553 | if (LineIter == Lines.end() || LineIter->Addr > VA) { |
| 554 | if (LineIter == Lines.begin() || std::prev(x: LineIter)->IsTerminalEntry) |
| 555 | return nullptr; |
| 556 | --LineIter; |
| 557 | } |
| 558 | |
| 559 | Expected<ModuleDebugStreamRef> ExpectedModS = |
| 560 | Session.getModuleDebugStream(Index: Modi); |
| 561 | if (!ExpectedModS) { |
| 562 | consumeError(Err: ExpectedModS.takeError()); |
| 563 | return nullptr; |
| 564 | } |
| 565 | Expected<DebugChecksumsSubsectionRef> ExpectedChecksums = |
| 566 | ExpectedModS->findChecksumsSubsection(); |
| 567 | if (!ExpectedChecksums) { |
| 568 | consumeError(Err: ExpectedChecksums.takeError()); |
| 569 | return nullptr; |
| 570 | } |
| 571 | |
| 572 | // Populate a vector of NativeLineNumbers that have addresses in the given |
| 573 | // address range. |
| 574 | std::vector<NativeLineNumber> LineNumbers; |
| 575 | while (LineIter != Lines.end()) { |
| 576 | if (LineIter->IsTerminalEntry) { |
| 577 | ++LineIter; |
| 578 | continue; |
| 579 | } |
| 580 | |
| 581 | // If the line is still within the address range, create a NativeLineNumber |
| 582 | // and add to the list. |
| 583 | if (LineIter->Addr > VA + Length) |
| 584 | break; |
| 585 | |
| 586 | uint32_t LineSect, LineOff; |
| 587 | Session.addressForVA(VA: LineIter->Addr, Section&: LineSect, Offset&: LineOff); |
| 588 | uint32_t LineLength = std::next(x: LineIter)->Addr - LineIter->Addr; |
| 589 | auto ChecksumIter = |
| 590 | ExpectedChecksums->getArray().at(Offset: LineIter->FileNameIndex); |
| 591 | uint32_t SrcFileId = getOrCreateSourceFile(Checksum: *ChecksumIter); |
| 592 | NativeLineNumber LineNum(Session, LineIter->Line, LineIter->ColumnNumber, |
| 593 | LineSect, LineOff, LineLength, SrcFileId, Modi); |
| 594 | LineNumbers.push_back(x: LineNum); |
| 595 | ++LineIter; |
| 596 | } |
| 597 | return std::make_unique<NativeEnumLineNumbers>(args: std::move(LineNumbers)); |
| 598 | } |
| 599 | |
| 600 | std::unique_ptr<PDBSymbolCompiland> |
| 601 | SymbolCache::getOrCreateCompiland(uint32_t Index) { |
| 602 | if (!Dbi) |
| 603 | return nullptr; |
| 604 | |
| 605 | if (Index >= Compilands.size()) |
| 606 | return nullptr; |
| 607 | |
| 608 | if (Compilands[Index] == 0) { |
| 609 | const DbiModuleList &Modules = Dbi->modules(); |
| 610 | Compilands[Index] = |
| 611 | createSymbol<NativeCompilandSymbol>(ConstructorArgs: Modules.getModuleDescriptor(Modi: Index)); |
| 612 | } |
| 613 | |
| 614 | return Session.getConcreteSymbolById<PDBSymbolCompiland>(SymbolId: Compilands[Index]); |
| 615 | } |
| 616 | |
| 617 | std::unique_ptr<IPDBSourceFile> |
| 618 | SymbolCache::getSourceFileById(SymIndexId FileId) const { |
| 619 | assert(FileId < SourceFiles.size()); |
| 620 | |
| 621 | // Id 0 is reserved. |
| 622 | if (FileId == 0) |
| 623 | return nullptr; |
| 624 | |
| 625 | return std::make_unique<NativeSourceFile>(args&: *SourceFiles[FileId].get()); |
| 626 | } |
| 627 | |
| 628 | SymIndexId |
| 629 | SymbolCache::getOrCreateSourceFile(const FileChecksumEntry &Checksums) const { |
| 630 | auto [Iter, Inserted] = |
| 631 | FileNameOffsetToId.try_emplace(Key: Checksums.FileNameOffset); |
| 632 | if (!Inserted) |
| 633 | return Iter->second; |
| 634 | |
| 635 | SymIndexId Id = SourceFiles.size(); |
| 636 | auto SrcFile = std::make_unique<NativeSourceFile>(args&: Session, args&: Id, args: Checksums); |
| 637 | SourceFiles.push_back(x: std::move(SrcFile)); |
| 638 | Iter->second = Id; |
| 639 | return Id; |
| 640 | } |
| 641 | |
| 642 | |
| 643 | |