summaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp')
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp377
1 files changed, 376 insertions, 1 deletions
diff --git a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
index 5cdd628312fe5..9f15907b519e8 100644
--- a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp
@@ -1,13 +1,18 @@
#include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
+#include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativePublicSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h"
@@ -19,6 +24,7 @@
#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h"
#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/PDBSymbol.h"
@@ -62,9 +68,10 @@ static const struct BuiltinTypeEntry {
};
SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi)
- : Session(Session), Dbi(Dbi) {
+ : Session(Session), Dbi(Dbi), AddrToModuleIndex(IMapAllocator) {
// Id 0 is reserved for the invalid symbol.
Cache.push_back(nullptr);
+ SourceFiles.push_back(nullptr);
if (Dbi)
Compilands.resize(Dbi->modules().getModuleCount());
@@ -281,6 +288,312 @@ SymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) {
return Id;
}
+Expected<ModuleDebugStreamRef>
+SymbolCache::getModuleDebugStream(uint32_t Index) const {
+ assert(Dbi && "Dbi stream not present");
+
+ DbiModuleDescriptor Modi = Dbi->modules().getModuleDescriptor(Index);
+
+ uint16_t ModiStream = Modi.getModuleStreamIndex();
+ if (ModiStream == kInvalidStreamIndex)
+ return make_error<RawError>("Module stream not present");
+
+ std::unique_ptr<msf::MappedBlockStream> ModStreamData =
+ Session.getPDBFile().createIndexedStream(ModiStream);
+
+ ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
+ if (auto EC = ModS.reload())
+ return std::move(EC);
+
+ return std::move(ModS);
+}
+
+std::unique_ptr<PDBSymbol>
+SymbolCache::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,
+ PDB_SymType Type) {
+ if (AddrToModuleIndex.empty())
+ parseSectionContribs();
+
+ switch (Type) {
+ case PDB_SymType::Function:
+ return findFunctionSymbolBySectOffset(Sect, Offset);
+ case PDB_SymType::PublicSymbol:
+ return findPublicSymbolBySectOffset(Sect, Offset);
+ case PDB_SymType::None: {
+ // FIXME: Implement for PDB_SymType::Data.
+ if (auto Sym = findFunctionSymbolBySectOffset(Sect, Offset))
+ return Sym;
+ return nullptr;
+ }
+ default:
+ return nullptr;
+ }
+}
+
+std::unique_ptr<PDBSymbol>
+SymbolCache::findFunctionSymbolBySectOffset(uint32_t Sect, uint32_t Offset) {
+ auto Iter = AddressToFunctionSymId.find({Sect, Offset});
+ if (Iter != AddressToFunctionSymId.end())
+ return getSymbolById(Iter->second);
+
+ if (!Dbi)
+ return nullptr;
+
+ auto Modi = getModuleIndexForAddr(Session.getVAFromSectOffset(Sect, Offset));
+ if (!Modi)
+ return nullptr;
+
+ auto ExpectedModS = getModuleDebugStream(*Modi);
+ if (!ExpectedModS) {
+ consumeError(ExpectedModS.takeError());
+ return nullptr;
+ }
+ CVSymbolArray Syms = ExpectedModS->getSymbolArray();
+
+ // Search for the symbol in this module.
+ for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) {
+ if (I->kind() != S_LPROC32 && I->kind() != S_GPROC32)
+ continue;
+ auto PS = cantFail(SymbolDeserializer::deserializeAs<ProcSym>(*I));
+ if (Sect == PS.Segment && Offset >= PS.CodeOffset &&
+ Offset < PS.CodeOffset + PS.CodeSize) {
+ SymIndexId Id = createSymbol<NativeFunctionSymbol>(PS);
+ AddressToFunctionSymId.insert({{Sect, Offset}, Id});
+ return getSymbolById(Id);
+ }
+
+ // Jump to the end of this ProcSym.
+ I = Syms.at(PS.End);
+ }
+ return nullptr;
+}
+
+std::unique_ptr<PDBSymbol>
+SymbolCache::findPublicSymbolBySectOffset(uint32_t Sect, uint32_t Offset) {
+ auto Iter = AddressToPublicSymId.find({Sect, Offset});
+ if (Iter != AddressToPublicSymId.end())
+ return getSymbolById(Iter->second);
+
+ auto Publics = Session.getPDBFile().getPDBPublicsStream();
+ if (!Publics)
+ return nullptr;
+
+ auto ExpectedSyms = Session.getPDBFile().getPDBSymbolStream();
+ if (!ExpectedSyms)
+ return nullptr;
+ BinaryStreamRef SymStream =
+ ExpectedSyms->getSymbolArray().getUnderlyingStream();
+
+ // Use binary search to find the first public symbol with an address greater
+ // than or equal to Sect, Offset.
+ auto AddrMap = Publics->getAddressMap();
+ auto First = AddrMap.begin();
+ auto It = AddrMap.begin();
+ size_t Count = AddrMap.size();
+ size_t Half;
+ while (Count > 0) {
+ It = First;
+ Half = Count / 2;
+ It += Half;
+ Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, *It);
+ if (!Sym) {
+ consumeError(Sym.takeError());
+ return nullptr;
+ }
+
+ auto PS =
+ cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym.get()));
+ if (PS.Segment < Sect || (PS.Segment == Sect && PS.Offset <= Offset)) {
+ First = ++It;
+ Count -= Half + 1;
+ } else
+ Count = Half;
+ }
+ if (It == AddrMap.begin())
+ return nullptr;
+ --It;
+
+ Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, *It);
+ if (!Sym) {
+ consumeError(Sym.takeError());
+ return nullptr;
+ }
+ auto PS = cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym.get()));
+ SymIndexId Id = createSymbol<NativePublicSymbol>(PS);
+ AddressToPublicSymId.insert({{Sect, Offset}, Id});
+ return getSymbolById(Id);
+}
+
+std::vector<SymbolCache::LineTableEntry>
+SymbolCache::findLineTable(uint16_t Modi) const {
+ // Check if this module has already been added.
+ auto LineTableIter = LineTable.find(Modi);
+ if (LineTableIter != LineTable.end())
+ return LineTableIter->second;
+
+ std::vector<LineTableEntry> &ModuleLineTable = LineTable[Modi];
+
+ // If there is an error or there are no lines, just return the
+ // empty vector.
+ Expected<ModuleDebugStreamRef> ExpectedModS = getModuleDebugStream(Modi);
+ if (!ExpectedModS) {
+ consumeError(ExpectedModS.takeError());
+ return ModuleLineTable;
+ }
+
+ std::vector<std::vector<LineTableEntry>> EntryList;
+ for (const auto &SS : ExpectedModS->getSubsectionsArray()) {
+ if (SS.kind() != DebugSubsectionKind::Lines)
+ continue;
+
+ DebugLinesSubsectionRef Lines;
+ BinaryStreamReader Reader(SS.getRecordData());
+ if (auto EC = Lines.initialize(Reader)) {
+ consumeError(std::move(EC));
+ continue;
+ }
+
+ uint32_t RelocSegment = Lines.header()->RelocSegment;
+ uint32_t RelocOffset = Lines.header()->RelocOffset;
+ for (const LineColumnEntry &Group : Lines) {
+ if (Group.LineNumbers.empty())
+ continue;
+
+ std::vector<LineTableEntry> Entries;
+
+ // If there are column numbers, then they should be in a parallel stream
+ // to the line numbers.
+ auto ColIt = Group.Columns.begin();
+ auto ColsEnd = Group.Columns.end();
+
+ for (const LineNumberEntry &LN : Group.LineNumbers) {
+ uint64_t VA =
+ Session.getVAFromSectOffset(RelocSegment, RelocOffset + LN.Offset);
+ LineInfo Line(LN.Flags);
+ uint32_t ColNum = 0;
+
+ if (Lines.hasColumnInfo() && ColIt != ColsEnd) {
+ ColNum = ColIt->StartColumn;
+ ++ColIt;
+ }
+ Entries.push_back({VA, Line, ColNum, Group.NameIndex, false});
+ }
+
+ // Add a terminal entry line to mark the end of this subsection.
+ uint64_t VA = Session.getVAFromSectOffset(
+ RelocSegment, RelocOffset + Lines.header()->CodeSize);
+ LineInfo LastLine(Group.LineNumbers.back().Flags);
+ uint32_t ColNum =
+ (Lines.hasColumnInfo()) ? Group.Columns.back().StartColumn : 0;
+ Entries.push_back({VA, LastLine, ColNum, Group.NameIndex, true});
+
+ EntryList.push_back(Entries);
+ }
+ }
+
+ // Sort EntryList, and add flattened contents to the line table.
+ std::sort(EntryList.begin(), EntryList.end(),
+ [](const std::vector<LineTableEntry> &LHS,
+ const std::vector<LineTableEntry> &RHS) {
+ return LHS[0].Addr < RHS[0].Addr;
+ });
+ for (size_t I = 0; I < EntryList.size(); ++I)
+ ModuleLineTable.insert(ModuleLineTable.end(), EntryList[I].begin(),
+ EntryList[I].end());
+
+ return ModuleLineTable;
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const {
+ Optional<uint16_t> MaybeModi = getModuleIndexForAddr(VA);
+ if (!MaybeModi)
+ return nullptr;
+ uint16_t Modi = *MaybeModi;
+
+ std::vector<LineTableEntry> Lines = findLineTable(Modi);
+ if (Lines.empty())
+ return nullptr;
+
+ // Find the first line in the line table whose address is not greater than
+ // the one we are searching for.
+ auto LineIter = llvm::partition_point(Lines, [&](const LineTableEntry &E) {
+ return (E.Addr < VA || (E.Addr == VA && E.IsTerminalEntry));
+ });
+
+ // Try to back up if we've gone too far.
+ if (LineIter == Lines.end() || LineIter->Addr > VA) {
+ if (LineIter == Lines.begin() || std::prev(LineIter)->IsTerminalEntry)
+ return nullptr;
+ --LineIter;
+ }
+
+ Expected<ModuleDebugStreamRef> ExpectedModS = getModuleDebugStream(Modi);
+ if (!ExpectedModS) {
+ consumeError(ExpectedModS.takeError());
+ return nullptr;
+ }
+ Expected<DebugChecksumsSubsectionRef> ExpectedChecksums =
+ ExpectedModS->findChecksumsSubsection();
+ if (!ExpectedChecksums) {
+ consumeError(ExpectedChecksums.takeError());
+ return nullptr;
+ }
+
+ // Populate a vector of NativeLineNumbers that have addresses in the given
+ // address range.
+ Optional<uint16_t> EndModi = getModuleIndexForAddr(VA + Length);
+ if (!EndModi)
+ return nullptr;
+ std::vector<NativeLineNumber> LineNumbers;
+ while (Modi <= *EndModi) {
+ // If we reached the end of the current module, increment Modi and get the
+ // new line table and checksums array.
+ if (LineIter == Lines.end()) {
+ ++Modi;
+
+ ExpectedModS = getModuleDebugStream(Modi);
+ if (!ExpectedModS) {
+ consumeError(ExpectedModS.takeError());
+ break;
+ }
+ ExpectedChecksums = ExpectedModS->findChecksumsSubsection();
+ if (!ExpectedChecksums) {
+ consumeError(ExpectedChecksums.takeError());
+ break;
+ }
+
+ Lines = findLineTable(Modi);
+ LineIter = Lines.begin();
+
+ if (Lines.empty())
+ continue;
+ }
+
+ if (LineIter->IsTerminalEntry) {
+ ++LineIter;
+ continue;
+ }
+
+ // If the line is still within the address range, create a NativeLineNumber
+ // and add to the list.
+ if (LineIter->Addr > VA + Length)
+ break;
+
+ uint32_t LineSect, LineOff;
+ Session.addressForVA(LineIter->Addr, LineSect, LineOff);
+ uint32_t LineLength = std::next(LineIter)->Addr - LineIter->Addr;
+ auto ChecksumIter =
+ ExpectedChecksums->getArray().at(LineIter->FileNameIndex);
+ uint32_t SrcFileId = getOrCreateSourceFile(*ChecksumIter);
+ NativeLineNumber LineNum(Session, LineIter->Line, LineIter->ColumnNumber,
+ LineSect, LineOff, LineLength, SrcFileId);
+ LineNumbers.push_back(LineNum);
+ ++LineIter;
+ }
+ return std::make_unique<NativeEnumLineNumbers>(std::move(LineNumbers));
+}
+
std::unique_ptr<PDBSymbolCompiland>
SymbolCache::getOrCreateCompiland(uint32_t Index) {
if (!Dbi)
@@ -297,3 +610,65 @@ SymbolCache::getOrCreateCompiland(uint32_t Index) {
return Session.getConcreteSymbolById<PDBSymbolCompiland>(Compilands[Index]);
}
+
+std::unique_ptr<IPDBSourceFile>
+SymbolCache::getSourceFileById(SymIndexId FileId) const {
+ assert(FileId < SourceFiles.size());
+
+ // Id 0 is reserved.
+ if (FileId == 0)
+ return nullptr;
+
+ return std::unique_ptr<NativeSourceFile>(
+ new NativeSourceFile(*SourceFiles[FileId].get()));
+}
+
+SymIndexId
+SymbolCache::getOrCreateSourceFile(const FileChecksumEntry &Checksums) const {
+ auto Iter = FileNameOffsetToId.find(Checksums.FileNameOffset);
+ if (Iter != FileNameOffsetToId.end())
+ return Iter->second;
+
+ SymIndexId Id = SourceFiles.size();
+ auto SrcFile = std::make_unique<NativeSourceFile>(Session, Id, Checksums);
+ SourceFiles.push_back(std::move(SrcFile));
+ FileNameOffsetToId[Checksums.FileNameOffset] = Id;
+ return Id;
+}
+
+void SymbolCache::parseSectionContribs() {
+ if (!Dbi)
+ return;
+
+ class Visitor : public ISectionContribVisitor {
+ NativeSession &Session;
+ IMap &AddrMap;
+
+ public:
+ Visitor(NativeSession &Session, IMap &AddrMap)
+ : Session(Session), AddrMap(AddrMap) {}
+ void visit(const SectionContrib &C) override {
+ if (C.Size == 0)
+ return;
+
+ uint64_t VA = Session.getVAFromSectOffset(C.ISect, C.Off);
+ uint64_t End = VA + C.Size;
+
+ // Ignore overlapping sections based on the assumption that a valid
+ // PDB file should not have overlaps.
+ if (!AddrMap.overlaps(VA, End))
+ AddrMap.insert(VA, End, C.Imod);
+ }
+ void visit(const SectionContrib2 &C) override { visit(C.Base); }
+ };
+
+ Visitor V(Session, AddrToModuleIndex);
+ Dbi->visitSectionContributions(V);
+}
+
+Optional<uint16_t> SymbolCache::getModuleIndexForAddr(uint64_t Addr) const {
+ auto Iter = AddrToModuleIndex.find(Addr);
+ if (Iter == AddrToModuleIndex.end())
+ return None;
+ return Iter.value();
+}