Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
35293 views
#include "llvm/DebugInfo/PDB/Native/SymbolCache.h"12#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"3#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"4#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"5#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"6#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"7#include "llvm/DebugInfo/CodeView/SymbolRecord.h"8#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"9#include "llvm/DebugInfo/CodeView/TypeRecord.h"10#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"11#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"12#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"13#include "llvm/DebugInfo/PDB/Native/DbiStream.h"14#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"15#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"16#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h"17#include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h"18#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"19#include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h"20#include "llvm/DebugInfo/PDB/Native/NativeInlineSiteSymbol.h"21#include "llvm/DebugInfo/PDB/Native/NativeLineNumber.h"22#include "llvm/DebugInfo/PDB/Native/NativePublicSymbol.h"23#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"24#include "llvm/DebugInfo/PDB/Native/NativeSession.h"25#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h"26#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"27#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"28#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h"29#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h"30#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h"31#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h"32#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h"33#include "llvm/DebugInfo/PDB/Native/PDBFile.h"34#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"35#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"36#include "llvm/DebugInfo/PDB/Native/TpiStream.h"37#include "llvm/DebugInfo/PDB/PDBSymbol.h"38#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"3940using namespace llvm;41using namespace llvm::codeview;42using namespace llvm::pdb;4344// Maps codeview::SimpleTypeKind of a built-in type to the parameters necessary45// to instantiate a NativeBuiltinSymbol for that type.46static const struct BuiltinTypeEntry {47codeview::SimpleTypeKind Kind;48PDB_BuiltinType Type;49uint32_t Size;50} BuiltinTypes[] = {51{codeview::SimpleTypeKind::None, PDB_BuiltinType::None, 0},52{codeview::SimpleTypeKind::Void, PDB_BuiltinType::Void, 0},53{codeview::SimpleTypeKind::HResult, PDB_BuiltinType::HResult, 4},54{codeview::SimpleTypeKind::Int16Short, PDB_BuiltinType::Int, 2},55{codeview::SimpleTypeKind::UInt16Short, PDB_BuiltinType::UInt, 2},56{codeview::SimpleTypeKind::Int32, PDB_BuiltinType::Int, 4},57{codeview::SimpleTypeKind::UInt32, PDB_BuiltinType::UInt, 4},58{codeview::SimpleTypeKind::Int32Long, PDB_BuiltinType::Int, 4},59{codeview::SimpleTypeKind::UInt32Long, PDB_BuiltinType::UInt, 4},60{codeview::SimpleTypeKind::Int64Quad, PDB_BuiltinType::Int, 8},61{codeview::SimpleTypeKind::UInt64Quad, PDB_BuiltinType::UInt, 8},62{codeview::SimpleTypeKind::NarrowCharacter, PDB_BuiltinType::Char, 1},63{codeview::SimpleTypeKind::WideCharacter, PDB_BuiltinType::WCharT, 2},64{codeview::SimpleTypeKind::Character16, PDB_BuiltinType::Char16, 2},65{codeview::SimpleTypeKind::Character32, PDB_BuiltinType::Char32, 4},66{codeview::SimpleTypeKind::Character8, PDB_BuiltinType::Char8, 1},67{codeview::SimpleTypeKind::SignedCharacter, PDB_BuiltinType::Char, 1},68{codeview::SimpleTypeKind::UnsignedCharacter, PDB_BuiltinType::UInt, 1},69{codeview::SimpleTypeKind::Float32, PDB_BuiltinType::Float, 4},70{codeview::SimpleTypeKind::Float64, PDB_BuiltinType::Float, 8},71{codeview::SimpleTypeKind::Float80, PDB_BuiltinType::Float, 10},72{codeview::SimpleTypeKind::Boolean8, PDB_BuiltinType::Bool, 1},73// This table can be grown as necessary, but these are the only types we've74// needed so far.75};7677SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi)78: Session(Session), Dbi(Dbi) {79// Id 0 is reserved for the invalid symbol.80Cache.push_back(nullptr);81SourceFiles.push_back(nullptr);8283if (Dbi)84Compilands.resize(Dbi->modules().getModuleCount());85}8687std::unique_ptr<IPDBEnumSymbols>88SymbolCache::createTypeEnumerator(TypeLeafKind Kind) {89return createTypeEnumerator(std::vector<TypeLeafKind>{Kind});90}9192std::unique_ptr<IPDBEnumSymbols>93SymbolCache::createTypeEnumerator(std::vector<TypeLeafKind> Kinds) {94auto Tpi = Session.getPDBFile().getPDBTpiStream();95if (!Tpi) {96consumeError(Tpi.takeError());97return nullptr;98}99auto &Types = Tpi->typeCollection();100return std::unique_ptr<IPDBEnumSymbols>(101new NativeEnumTypes(Session, Types, std::move(Kinds)));102}103104std::unique_ptr<IPDBEnumSymbols>105SymbolCache::createGlobalsEnumerator(codeview::SymbolKind Kind) {106return std::unique_ptr<IPDBEnumSymbols>(107new NativeEnumGlobals(Session, {Kind}));108}109110SymIndexId SymbolCache::createSimpleType(TypeIndex Index,111ModifierOptions Mods) const {112if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct)113return createSymbol<NativeTypePointer>(Index);114115const auto Kind = Index.getSimpleKind();116const auto It =117llvm::find_if(BuiltinTypes, [Kind](const BuiltinTypeEntry &Builtin) {118return Builtin.Kind == Kind;119});120if (It == std::end(BuiltinTypes))121return 0;122return createSymbol<NativeTypeBuiltin>(Mods, It->Type, It->Size);123}124125SymIndexId126SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI,127codeview::CVType CVT) const {128ModifierRecord Record;129if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) {130consumeError(std::move(EC));131return 0;132}133134if (Record.ModifiedType.isSimple())135return createSimpleType(Record.ModifiedType, Record.Modifiers);136137// Make sure we create and cache a record for the unmodified type.138SymIndexId UnmodifiedId = findSymbolByTypeIndex(Record.ModifiedType);139NativeRawSymbol &UnmodifiedNRS = *Cache[UnmodifiedId];140141switch (UnmodifiedNRS.getSymTag()) {142case PDB_SymType::Enum:143return createSymbol<NativeTypeEnum>(144static_cast<NativeTypeEnum &>(UnmodifiedNRS), std::move(Record));145case PDB_SymType::UDT:146return createSymbol<NativeTypeUDT>(147static_cast<NativeTypeUDT &>(UnmodifiedNRS), std::move(Record));148default:149// No other types can be modified. (LF_POINTER, for example, records150// its modifiers a different way.151assert(false && "Invalid LF_MODIFIER record");152break;153}154return 0;155}156157SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) const {158// First see if it's already in our cache.159const auto Entry = TypeIndexToSymbolId.find(Index);160if (Entry != TypeIndexToSymbolId.end())161return Entry->second;162163// Symbols for built-in types are created on the fly.164if (Index.isSimple()) {165SymIndexId Result = createSimpleType(Index, ModifierOptions::None);166assert(TypeIndexToSymbolId.count(Index) == 0);167TypeIndexToSymbolId[Index] = Result;168return Result;169}170171// We need to instantiate and cache the desired type symbol.172auto Tpi = Session.getPDBFile().getPDBTpiStream();173if (!Tpi) {174consumeError(Tpi.takeError());175return 0;176}177codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection();178codeview::CVType CVT = Types.getType(Index);179180if (isUdtForwardRef(CVT)) {181Expected<TypeIndex> EFD = Tpi->findFullDeclForForwardRef(Index);182183if (!EFD)184consumeError(EFD.takeError());185else if (*EFD != Index) {186assert(!isUdtForwardRef(Types.getType(*EFD)));187SymIndexId Result = findSymbolByTypeIndex(*EFD);188// Record a mapping from ForwardRef -> SymIndex of complete type so that189// we'll take the fast path next time.190assert(TypeIndexToSymbolId.count(Index) == 0);191TypeIndexToSymbolId[Index] = Result;192return Result;193}194}195196// At this point if we still have a forward ref udt it means the full decl was197// not in the PDB. We just have to deal with it and use the forward ref.198SymIndexId Id = 0;199switch (CVT.kind()) {200case codeview::LF_ENUM:201Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT));202break;203case codeview::LF_ARRAY:204Id = createSymbolForType<NativeTypeArray, ArrayRecord>(Index,205std::move(CVT));206break;207case codeview::LF_CLASS:208case codeview::LF_STRUCTURE:209case codeview::LF_INTERFACE:210Id = createSymbolForType<NativeTypeUDT, ClassRecord>(Index, std::move(CVT));211break;212case codeview::LF_UNION:213Id = createSymbolForType<NativeTypeUDT, UnionRecord>(Index, std::move(CVT));214break;215case codeview::LF_POINTER:216Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index,217std::move(CVT));218break;219case codeview::LF_MODIFIER:220Id = createSymbolForModifiedType(Index, std::move(CVT));221break;222case codeview::LF_PROCEDURE:223Id = createSymbolForType<NativeTypeFunctionSig, ProcedureRecord>(224Index, std::move(CVT));225break;226case codeview::LF_MFUNCTION:227Id = createSymbolForType<NativeTypeFunctionSig, MemberFunctionRecord>(228Index, std::move(CVT));229break;230case codeview::LF_VTSHAPE:231Id = createSymbolForType<NativeTypeVTShape, VFTableShapeRecord>(232Index, std::move(CVT));233break;234default:235Id = createSymbolPlaceholder();236break;237}238if (Id != 0) {239assert(TypeIndexToSymbolId.count(Index) == 0);240TypeIndexToSymbolId[Index] = Id;241}242return Id;243}244245std::unique_ptr<PDBSymbol>246SymbolCache::getSymbolById(SymIndexId SymbolId) const {247assert(SymbolId < Cache.size());248249// Id 0 is reserved.250if (SymbolId == 0 || SymbolId >= Cache.size())251return nullptr;252253// Make sure to handle the case where we've inserted a placeholder symbol254// for types we don't yet support.255NativeRawSymbol *NRS = Cache[SymbolId].get();256if (!NRS)257return nullptr;258259return PDBSymbol::create(Session, *NRS);260}261262NativeRawSymbol &SymbolCache::getNativeSymbolById(SymIndexId SymbolId) const {263return *Cache[SymbolId];264}265266uint32_t SymbolCache::getNumCompilands() const {267if (!Dbi)268return 0;269270return Dbi->modules().getModuleCount();271}272273SymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) {274auto Iter = GlobalOffsetToSymbolId.find(Offset);275if (Iter != GlobalOffsetToSymbolId.end())276return Iter->second;277278SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream());279CVSymbol CVS = SS.readRecord(Offset);280SymIndexId Id = 0;281switch (CVS.kind()) {282case SymbolKind::S_UDT: {283UDTSym US = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(CVS));284Id = createSymbol<NativeTypeTypedef>(std::move(US));285break;286}287default:288Id = createSymbolPlaceholder();289break;290}291if (Id != 0) {292assert(GlobalOffsetToSymbolId.count(Offset) == 0);293GlobalOffsetToSymbolId[Offset] = Id;294}295296return Id;297}298299SymIndexId SymbolCache::getOrCreateInlineSymbol(InlineSiteSym Sym,300uint64_t ParentAddr,301uint16_t Modi,302uint32_t RecordOffset) const {303auto Iter = SymTabOffsetToSymbolId.find({Modi, RecordOffset});304if (Iter != SymTabOffsetToSymbolId.end())305return Iter->second;306307SymIndexId Id = createSymbol<NativeInlineSiteSymbol>(Sym, ParentAddr);308SymTabOffsetToSymbolId.insert({{Modi, RecordOffset}, Id});309return Id;310}311312std::unique_ptr<PDBSymbol>313SymbolCache::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,314PDB_SymType Type) {315switch (Type) {316case PDB_SymType::Function:317return findFunctionSymbolBySectOffset(Sect, Offset);318case PDB_SymType::PublicSymbol:319return findPublicSymbolBySectOffset(Sect, Offset);320case PDB_SymType::Compiland: {321uint16_t Modi;322if (!Session.moduleIndexForSectOffset(Sect, Offset, Modi))323return nullptr;324return getOrCreateCompiland(Modi);325}326case PDB_SymType::None: {327// FIXME: Implement for PDB_SymType::Data. The symbolizer calls this but328// only uses it to find the symbol length.329if (auto Sym = findFunctionSymbolBySectOffset(Sect, Offset))330return Sym;331return nullptr;332}333default:334return nullptr;335}336}337338std::unique_ptr<PDBSymbol>339SymbolCache::findFunctionSymbolBySectOffset(uint32_t Sect, uint32_t Offset) {340auto Iter = AddressToSymbolId.find({Sect, Offset});341if (Iter != AddressToSymbolId.end())342return getSymbolById(Iter->second);343344if (!Dbi)345return nullptr;346347uint16_t Modi;348if (!Session.moduleIndexForSectOffset(Sect, Offset, Modi))349return nullptr;350351Expected<ModuleDebugStreamRef> ExpectedModS =352Session.getModuleDebugStream(Modi);353if (!ExpectedModS) {354consumeError(ExpectedModS.takeError());355return nullptr;356}357CVSymbolArray Syms = ExpectedModS->getSymbolArray();358359// Search for the symbol in this module.360for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) {361if (I->kind() != S_LPROC32 && I->kind() != S_GPROC32)362continue;363auto PS = cantFail(SymbolDeserializer::deserializeAs<ProcSym>(*I));364if (Sect == PS.Segment && Offset >= PS.CodeOffset &&365Offset < PS.CodeOffset + PS.CodeSize) {366// Check if the symbol is already cached.367auto Found = AddressToSymbolId.find({PS.Segment, PS.CodeOffset});368if (Found != AddressToSymbolId.end())369return getSymbolById(Found->second);370371// Otherwise, create a new symbol.372SymIndexId Id = createSymbol<NativeFunctionSymbol>(PS, I.offset());373AddressToSymbolId.insert({{PS.Segment, PS.CodeOffset}, Id});374return getSymbolById(Id);375}376377// Jump to the end of this ProcSym.378I = Syms.at(PS.End);379}380return nullptr;381}382383std::unique_ptr<PDBSymbol>384SymbolCache::findPublicSymbolBySectOffset(uint32_t Sect, uint32_t Offset) {385auto Iter = AddressToPublicSymId.find({Sect, Offset});386if (Iter != AddressToPublicSymId.end())387return getSymbolById(Iter->second);388389auto Publics = Session.getPDBFile().getPDBPublicsStream();390if (!Publics)391return nullptr;392393auto ExpectedSyms = Session.getPDBFile().getPDBSymbolStream();394if (!ExpectedSyms)395return nullptr;396BinaryStreamRef SymStream =397ExpectedSyms->getSymbolArray().getUnderlyingStream();398399// Use binary search to find the first public symbol with an address greater400// than or equal to Sect, Offset.401auto AddrMap = Publics->getAddressMap();402auto First = AddrMap.begin();403auto It = AddrMap.begin();404size_t Count = AddrMap.size();405size_t Half;406while (Count > 0) {407It = First;408Half = Count / 2;409It += Half;410Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, *It);411if (!Sym) {412consumeError(Sym.takeError());413return nullptr;414}415416auto PS =417cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym.get()));418if (PS.Segment < Sect || (PS.Segment == Sect && PS.Offset <= Offset)) {419First = ++It;420Count -= Half + 1;421} else422Count = Half;423}424if (It == AddrMap.begin())425return nullptr;426--It;427428Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, *It);429if (!Sym) {430consumeError(Sym.takeError());431return nullptr;432}433434// Check if the symbol is already cached.435auto PS = cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym.get()));436auto Found = AddressToPublicSymId.find({PS.Segment, PS.Offset});437if (Found != AddressToPublicSymId.end())438return getSymbolById(Found->second);439440// Otherwise, create a new symbol.441SymIndexId Id = createSymbol<NativePublicSymbol>(PS);442AddressToPublicSymId.insert({{PS.Segment, PS.Offset}, Id});443return getSymbolById(Id);444}445446std::vector<SymbolCache::LineTableEntry>447SymbolCache::findLineTable(uint16_t Modi) const {448// Check if this module has already been added.449auto LineTableIter = LineTable.find(Modi);450if (LineTableIter != LineTable.end())451return LineTableIter->second;452453std::vector<LineTableEntry> &ModuleLineTable = LineTable[Modi];454455// If there is an error or there are no lines, just return the456// empty vector.457Expected<ModuleDebugStreamRef> ExpectedModS =458Session.getModuleDebugStream(Modi);459if (!ExpectedModS) {460consumeError(ExpectedModS.takeError());461return ModuleLineTable;462}463464std::vector<std::vector<LineTableEntry>> EntryList;465for (const auto &SS : ExpectedModS->getSubsectionsArray()) {466if (SS.kind() != DebugSubsectionKind::Lines)467continue;468469DebugLinesSubsectionRef Lines;470BinaryStreamReader Reader(SS.getRecordData());471if (auto EC = Lines.initialize(Reader)) {472consumeError(std::move(EC));473continue;474}475476uint32_t RelocSegment = Lines.header()->RelocSegment;477uint32_t RelocOffset = Lines.header()->RelocOffset;478for (const LineColumnEntry &Group : Lines) {479if (Group.LineNumbers.empty())480continue;481482std::vector<LineTableEntry> Entries;483484// If there are column numbers, then they should be in a parallel stream485// to the line numbers.486auto ColIt = Group.Columns.begin();487auto ColsEnd = Group.Columns.end();488489// Add a line to mark the beginning of this section.490uint64_t StartAddr =491Session.getVAFromSectOffset(RelocSegment, RelocOffset);492LineInfo FirstLine(Group.LineNumbers.front().Flags);493uint32_t ColNum =494(Lines.hasColumnInfo()) ? Group.Columns.front().StartColumn : 0;495Entries.push_back({StartAddr, FirstLine, ColNum, Group.NameIndex, false});496497for (const LineNumberEntry &LN : Group.LineNumbers) {498uint64_t VA =499Session.getVAFromSectOffset(RelocSegment, RelocOffset + LN.Offset);500LineInfo Line(LN.Flags);501ColNum = 0;502503if (Lines.hasColumnInfo() && ColIt != ColsEnd) {504ColNum = ColIt->StartColumn;505++ColIt;506}507Entries.push_back({VA, Line, ColNum, Group.NameIndex, false});508}509510// Add a terminal entry line to mark the end of this subsection.511uint64_t EndAddr = StartAddr + Lines.header()->CodeSize;512LineInfo LastLine(Group.LineNumbers.back().Flags);513ColNum = (Lines.hasColumnInfo()) ? Group.Columns.back().StartColumn : 0;514Entries.push_back({EndAddr, LastLine, ColNum, Group.NameIndex, true});515516EntryList.push_back(Entries);517}518}519520// Sort EntryList, and add flattened contents to the line table.521llvm::sort(EntryList, [](const std::vector<LineTableEntry> &LHS,522const std::vector<LineTableEntry> &RHS) {523return LHS[0].Addr < RHS[0].Addr;524});525for (std::vector<LineTableEntry> &I : EntryList)526llvm::append_range(ModuleLineTable, I);527528return ModuleLineTable;529}530531std::unique_ptr<IPDBEnumLineNumbers>532SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const {533uint16_t Modi;534if (!Session.moduleIndexForVA(VA, Modi))535return nullptr;536537std::vector<LineTableEntry> Lines = findLineTable(Modi);538if (Lines.empty())539return nullptr;540541// Find the first line in the line table whose address is not greater than542// the one we are searching for.543auto LineIter = llvm::partition_point(Lines, [&](const LineTableEntry &E) {544return (E.Addr < VA || (E.Addr == VA && E.IsTerminalEntry));545});546547// Try to back up if we've gone too far.548if (LineIter == Lines.end() || LineIter->Addr > VA) {549if (LineIter == Lines.begin() || std::prev(LineIter)->IsTerminalEntry)550return nullptr;551--LineIter;552}553554Expected<ModuleDebugStreamRef> ExpectedModS =555Session.getModuleDebugStream(Modi);556if (!ExpectedModS) {557consumeError(ExpectedModS.takeError());558return nullptr;559}560Expected<DebugChecksumsSubsectionRef> ExpectedChecksums =561ExpectedModS->findChecksumsSubsection();562if (!ExpectedChecksums) {563consumeError(ExpectedChecksums.takeError());564return nullptr;565}566567// Populate a vector of NativeLineNumbers that have addresses in the given568// address range.569std::vector<NativeLineNumber> LineNumbers;570while (LineIter != Lines.end()) {571if (LineIter->IsTerminalEntry) {572++LineIter;573continue;574}575576// If the line is still within the address range, create a NativeLineNumber577// and add to the list.578if (LineIter->Addr > VA + Length)579break;580581uint32_t LineSect, LineOff;582Session.addressForVA(LineIter->Addr, LineSect, LineOff);583uint32_t LineLength = std::next(LineIter)->Addr - LineIter->Addr;584auto ChecksumIter =585ExpectedChecksums->getArray().at(LineIter->FileNameIndex);586uint32_t SrcFileId = getOrCreateSourceFile(*ChecksumIter);587NativeLineNumber LineNum(Session, LineIter->Line, LineIter->ColumnNumber,588LineSect, LineOff, LineLength, SrcFileId, Modi);589LineNumbers.push_back(LineNum);590++LineIter;591}592return std::make_unique<NativeEnumLineNumbers>(std::move(LineNumbers));593}594595std::unique_ptr<PDBSymbolCompiland>596SymbolCache::getOrCreateCompiland(uint32_t Index) {597if (!Dbi)598return nullptr;599600if (Index >= Compilands.size())601return nullptr;602603if (Compilands[Index] == 0) {604const DbiModuleList &Modules = Dbi->modules();605Compilands[Index] =606createSymbol<NativeCompilandSymbol>(Modules.getModuleDescriptor(Index));607}608609return Session.getConcreteSymbolById<PDBSymbolCompiland>(Compilands[Index]);610}611612std::unique_ptr<IPDBSourceFile>613SymbolCache::getSourceFileById(SymIndexId FileId) const {614assert(FileId < SourceFiles.size());615616// Id 0 is reserved.617if (FileId == 0)618return nullptr;619620return std::make_unique<NativeSourceFile>(*SourceFiles[FileId].get());621}622623SymIndexId624SymbolCache::getOrCreateSourceFile(const FileChecksumEntry &Checksums) const {625auto Iter = FileNameOffsetToId.find(Checksums.FileNameOffset);626if (Iter != FileNameOffsetToId.end())627return Iter->second;628629SymIndexId Id = SourceFiles.size();630auto SrcFile = std::make_unique<NativeSourceFile>(Session, Id, Checksums);631SourceFiles.push_back(std::move(SrcFile));632FileNameOffsetToId[Checksums.FileNameOffset] = Id;633return Id;634}635636637638639