diff options
Diffstat (limited to 'lib/DebugInfo/PDB/Native')
31 files changed, 2171 insertions, 463 deletions
diff --git a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index b97f1e90bcf83..ab93efc839a9a 100644 --- a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -19,7 +19,6 @@ #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/Support/BinaryItemStream.h" #include "llvm/Support/BinaryStreamWriter.h" using namespace llvm; @@ -66,12 +65,22 @@ void DbiModuleDescriptorBuilder::setFirstSectionContrib( } void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) { - Symbols.push_back(Symbol); - // Symbols written to a PDB file are required to be 4 byte aligned. The same + // Defer to the bulk API. It does the same thing. + addSymbolsInBulk(Symbol.data()); +} + +void DbiModuleDescriptorBuilder::addSymbolsInBulk( + ArrayRef<uint8_t> BulkSymbols) { + // Do nothing for empty runs of symbols. + if (BulkSymbols.empty()) + return; + + Symbols.push_back(BulkSymbols); + // Symbols written to a PDB file are required to be 4 byte aligned. The same // is not true of object files. - assert(Symbol.length() % alignOf(CodeViewContainer::Pdb) == 0 && + assert(BulkSymbols.size() % alignOf(CodeViewContainer::Pdb) == 0 && "Invalid Symbol alignment!"); - SymbolByteSize += Symbol.length(); + SymbolByteSize += BulkSymbols.size(); } void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) { @@ -145,16 +154,13 @@ Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter, if (auto EC = SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC)) return EC; - BinaryItemStream<CVSymbol> Records(llvm::support::endianness::little); - Records.setItems(Symbols); - BinaryStreamRef RecordsRef(Records); - if (auto EC = SymbolWriter.writeStreamRef(RecordsRef)) - return EC; - if (auto EC = SymbolWriter.padToAlignment(4)) - return EC; - // TODO: Write C11 Line data + for (ArrayRef<uint8_t> Syms : Symbols) { + if (auto EC = SymbolWriter.writeBytes(Syms)) + return EC; + } assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 && "Invalid debug section alignment!"); + // TODO: Write C11 Line data for (const auto &Builder : C13Builders) { assert(Builder && "Empty C13 Fragment Builder!"); if (auto EC = Builder->commit(SymbolWriter)) diff --git a/lib/DebugInfo/PDB/Native/DbiStream.cpp b/lib/DebugInfo/PDB/Native/DbiStream.cpp index edaa783398cae..60ac17b655a7b 100644 --- a/lib/DebugInfo/PDB/Native/DbiStream.cpp +++ b/lib/DebugInfo/PDB/Native/DbiStream.cpp @@ -197,7 +197,7 @@ PDB_Machine DbiStream::getMachineType() const { return static_cast<PDB_Machine>(Machine); } -FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() { +FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() const { return SectionHeaders; } diff --git a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp index f6043bfd7cf94..094216ea800a0 100644 --- a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" @@ -74,10 +75,27 @@ void DbiStreamBuilder::setPublicsStreamIndex(uint32_t Index) { PublicsStreamIndex = Index; } +void DbiStreamBuilder::addNewFpoData(const codeview::FrameData &FD) { + if (!NewFpoData.hasValue()) + NewFpoData.emplace(false); + + NewFpoData->addFrameData(FD); +} + +void DbiStreamBuilder::addOldFpoData(const object::FpoData &FD) { + OldFpoData.push_back(FD); +} + Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type, ArrayRef<uint8_t> Data) { + assert(Type != DbgHeaderType::NewFPO && + "NewFPO data should be written via addFrameData()!"); + DbgStreams[(int)Type].emplace(); - DbgStreams[(int)Type]->Data = Data; + DbgStreams[(int)Type]->Size = Data.size(); + DbgStreams[(int)Type]->WriteFn = [Data](BinaryStreamWriter &Writer) { + return Writer.writeArray(Data); + }; return Error::success(); } @@ -272,10 +290,30 @@ Error DbiStreamBuilder::finalize() { } Error DbiStreamBuilder::finalizeMsfLayout() { + if (NewFpoData.hasValue()) { + DbgStreams[(int)DbgHeaderType::NewFPO].emplace(); + DbgStreams[(int)DbgHeaderType::NewFPO]->Size = + NewFpoData->calculateSerializedSize(); + DbgStreams[(int)DbgHeaderType::NewFPO]->WriteFn = + [this](BinaryStreamWriter &Writer) { + return NewFpoData->commit(Writer); + }; + } + + if (!OldFpoData.empty()) { + DbgStreams[(int)DbgHeaderType::FPO].emplace(); + DbgStreams[(int)DbgHeaderType::FPO]->Size = + sizeof(object::FpoData) * OldFpoData.size(); + DbgStreams[(int)DbgHeaderType::FPO]->WriteFn = + [this](BinaryStreamWriter &Writer) { + return Writer.writeArray(makeArrayRef(OldFpoData)); + }; + } + for (auto &S : DbgStreams) { if (!S.hasValue()) continue; - auto ExpectedIndex = Msf.addStream(S->Data.size()); + auto ExpectedIndex = Msf.addStream(S->Size); if (!ExpectedIndex) return ExpectedIndex.takeError(); S->StreamNumber = *ExpectedIndex; @@ -406,7 +444,8 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, auto WritableStream = WritableMappedBlockStream::createIndexedStream( Layout, MsfBuffer, Stream->StreamNumber, Allocator); BinaryStreamWriter DbgStreamWriter(*WritableStream); - if (auto EC = DbgStreamWriter.writeArray(Stream->Data)) + + if (auto EC = Stream->WriteFn(DbgStreamWriter)) return EC; } diff --git a/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp index 58efc2256ae12..57da7003da2b8 100644 --- a/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp @@ -9,6 +9,7 @@ #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/DebugInfo/CodeView/RecordName.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" @@ -20,6 +21,7 @@ #include "llvm/DebugInfo/PDB/Native/Hash.h" #include "llvm/Support/BinaryItemStream.h" #include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/xxhash.h" #include <algorithm> #include <vector> @@ -29,8 +31,27 @@ using namespace llvm::pdb; using namespace llvm::codeview; struct llvm::pdb::GSIHashStreamBuilder { + struct UdtDenseMapInfo { + static inline CVSymbol getEmptyKey() { + static CVSymbol Empty; + return Empty; + } + static inline CVSymbol getTombstoneKey() { + static CVSymbol Tombstone(static_cast<SymbolKind>(-1), + ArrayRef<uint8_t>()); + return Tombstone; + } + static unsigned getHashValue(const CVSymbol &Val) { + return xxHash64(Val.RecordData); + } + static bool isEqual(const CVSymbol &LHS, const CVSymbol &RHS) { + return LHS.RecordData == RHS.RecordData; + } + }; + std::vector<CVSymbol> Records; uint32_t StreamIndex; + llvm::DenseSet<CVSymbol, UdtDenseMapInfo> UdtHashes; std::vector<PSHashRecord> HashRecords; std::array<support::ulittle32_t, (IPHR_HASH + 32) / 32> HashBitmap; std::vector<support::ulittle32_t> HashBuckets; @@ -42,10 +63,18 @@ struct llvm::pdb::GSIHashStreamBuilder { template <typename T> void addSymbol(const T &Symbol, MSFBuilder &Msf) { T Copy(Symbol); - Records.push_back(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(), - CodeViewContainer::Pdb)); + addSymbol(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(), + CodeViewContainer::Pdb)); + } + void addSymbol(const CVSymbol &Symbol) { + if (Symbol.kind() == S_UDT) { + auto Iter = UdtHashes.insert(Symbol); + if (!Iter.second) + return; + } + + Records.push_back(Symbol); } - void addSymbol(const CVSymbol &Symbol) { Records.push_back(Symbol); } }; uint32_t GSIHashStreamBuilder::calculateSerializedLength() const { @@ -144,11 +173,10 @@ void GSIHashStreamBuilder::finalizeBuckets(uint32_t RecordZeroOffset) { // can properly early-out when it detects the record won't be found. The // algorithm used here corredsponds to the function // caseInsensitiveComparePchPchCchCch in the reference implementation. - llvm::sort(Bucket.begin(), Bucket.end(), - [](const std::pair<StringRef, PSHashRecord> &Left, - const std::pair<StringRef, PSHashRecord> &Right) { - return gsiRecordLess(Left.first, Right.first); - }); + llvm::sort(Bucket, [](const std::pair<StringRef, PSHashRecord> &Left, + const std::pair<StringRef, PSHashRecord> &Right) { + return gsiRecordLess(Left.first, Right.first); + }); for (const auto &Entry : Bucket) HashRecords.push_back(Entry.second); @@ -273,10 +301,6 @@ void GSIStreamBuilder::addGlobalSymbol(const ConstantSym &Sym) { GSH->addSymbol(Sym, Msf); } -void GSIStreamBuilder::addGlobalSymbol(const UDTSym &Sym) { - GSH->addSymbol(Sym, Msf); -} - void GSIStreamBuilder::addGlobalSymbol(const codeview::CVSymbol &Sym) { GSH->addSymbol(Sym); } @@ -310,13 +334,14 @@ Error GSIStreamBuilder::commitPublicsHashStream( PublicsStreamHeader Header; // FIXME: Fill these in. They are for incremental linking. + Header.SymHash = PSH->calculateSerializedLength(); + Header.AddrMap = PSH->Records.size() * 4; Header.NumThunks = 0; Header.SizeOfThunk = 0; Header.ISectThunkTable = 0; + memset(Header.Padding, 0, sizeof(Header.Padding)); Header.OffThunkTable = 0; Header.NumSections = 0; - Header.SymHash = PSH->calculateSerializedLength(); - Header.AddrMap = PSH->Records.size() * 4; if (auto EC = Writer.writeObject(Header)) return EC; diff --git a/lib/DebugInfo/PDB/Native/GlobalsStream.cpp b/lib/DebugInfo/PDB/Native/GlobalsStream.cpp index 36076f436ad0a..e363195668219 100644 --- a/lib/DebugInfo/PDB/Native/GlobalsStream.cpp +++ b/lib/DebugInfo/PDB/Native/GlobalsStream.cpp @@ -20,7 +20,11 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" + +#include "llvm/DebugInfo/CodeView/RecordName.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" #include <algorithm> @@ -41,6 +45,43 @@ Error GlobalsStream::reload() { return Error::success(); } +std::vector<std::pair<uint32_t, codeview::CVSymbol>> +GlobalsStream::findRecordsByName(StringRef Name, + const SymbolStream &Symbols) const { + std::vector<std::pair<uint32_t, codeview::CVSymbol>> Result; + + // Hash the name to figure out which bucket this goes into. + size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH; + int32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex]; + if (CompressedBucketIndex == -1) + return Result; + + uint32_t LastBucketIndex = GlobalsTable.HashBuckets.size() - 1; + uint32_t StartRecordIndex = + GlobalsTable.HashBuckets[CompressedBucketIndex] / 12; + uint32_t EndRecordIndex = 0; + if (LLVM_LIKELY(uint32_t(CompressedBucketIndex) < LastBucketIndex)) { + EndRecordIndex = GlobalsTable.HashBuckets[CompressedBucketIndex + 1]; + } else { + // If this is the last bucket, it consists of all hash records until the end + // of the HashRecords array. + EndRecordIndex = GlobalsTable.HashRecords.size() * 12; + } + + EndRecordIndex /= 12; + + assert(EndRecordIndex <= GlobalsTable.HashRecords.size()); + while (StartRecordIndex < EndRecordIndex) { + PSHashRecord PSH = GlobalsTable.HashRecords[StartRecordIndex]; + uint32_t Off = PSH.Off - 1; + codeview::CVSymbol Record = Symbols.readRecord(Off); + if (codeview::getSymbolName(Record) == Name) + Result.push_back(std::make_pair(Off, std::move(Record))); + ++StartRecordIndex; + } + return Result; +} + static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) { if (HashHdr->VerHdr != GSIHashHeader::HdrVersion) return make_error<RawError>( @@ -86,7 +127,9 @@ static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords, static Error readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets, - ArrayRef<uint8_t> &HashBitmap, const GSIHashHeader *HashHdr, + FixedStreamArray<support::ulittle32_t> &HashBitmap, + const GSIHashHeader *HashHdr, + MutableArrayRef<int32_t> BucketMap, BinaryStreamReader &Reader) { if (auto EC = checkHashHdrVersion(HashHdr)) return EC; @@ -94,13 +137,27 @@ readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets, // Before the actual hash buckets, there is a bitmap of length determined by // IPHR_HASH. size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); - uint32_t NumBitmapEntries = BitmapSizeInBits / 8; - if (auto EC = Reader.readBytes(HashBitmap, NumBitmapEntries)) + uint32_t NumBitmapEntries = BitmapSizeInBits / 32; + if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Could not read a bitmap.")); + uint32_t NumBuckets1 = 0; + uint32_t CompressedBucketIdx = 0; + for (uint32_t I = 0; I <= IPHR_HASH; ++I) { + uint8_t WordIdx = I / 32; + uint8_t BitIdx = I % 32; + bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx); + if (IsSet) { + ++NumBuckets1; + BucketMap[I] = CompressedBucketIdx++; + } else { + BucketMap[I] = -1; + } + } + uint32_t NumBuckets = 0; - for (uint8_t B : HashBitmap) + for (uint32_t B : HashBitmap) NumBuckets += countPopulation(B); // Hash buckets follow. @@ -118,7 +175,8 @@ Error GSIHashTable::read(BinaryStreamReader &Reader) { if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader)) return EC; if (HashHdr->HrSize > 0) - if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, Reader)) + if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, + BucketMap, Reader)) return EC; return Error::success(); } diff --git a/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp index 54d6835f11215..3b5a2accdba65 100644 --- a/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp @@ -32,15 +32,20 @@ InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf, void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; } +void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) { + Features.push_back(Sig); +} + +void InfoStreamBuilder::setHashPDBContentsToGUID(bool B) { + HashPDBContentsToGUID = B; +} + void InfoStreamBuilder::setAge(uint32_t A) { Age = A; } void InfoStreamBuilder::setSignature(uint32_t S) { Signature = S; } void InfoStreamBuilder::setGuid(GUID G) { Guid = G; } -void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) { - Features.push_back(Sig); -} Error InfoStreamBuilder::finalizeMsfLayout() { uint32_t Length = sizeof(InfoStreamHeader) + diff --git a/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp b/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp index 2e1f61c7a25dc..8c97f4a012f03 100644 --- a/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp +++ b/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp @@ -11,7 +11,9 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/Support/BinaryStreamReader.h" @@ -47,7 +49,8 @@ Error ModuleDebugStreamRef::reload() { if (auto EC = Reader.readInteger(Signature)) return EC; - if (auto EC = Reader.readSubstream(SymbolsSubstream, SymbolSize - 4)) + Reader.setOffset(0); + if (auto EC = Reader.readSubstream(SymbolsSubstream, SymbolSize)) return EC; if (auto EC = Reader.readSubstream(C11LinesSubstream, C11Size)) return EC; @@ -55,8 +58,8 @@ Error ModuleDebugStreamRef::reload() { return EC; BinaryStreamReader SymbolReader(SymbolsSubstream.StreamData); - if (auto EC = - SymbolReader.readArray(SymbolArray, SymbolReader.bytesRemaining())) + if (auto EC = SymbolReader.readArray( + SymbolArray, SymbolReader.bytesRemaining(), sizeof(uint32_t))) return EC; BinaryStreamReader SubsectionsReader(C13LinesSubstream.StreamData); @@ -76,6 +79,11 @@ Error ModuleDebugStreamRef::reload() { return Error::success(); } +const codeview::CVSymbolArray +ModuleDebugStreamRef::getSymbolArrayForScope(uint32_t ScopeBegin) const { + return limitSymbolArrayToScope(SymbolArray, ScopeBegin); +} + BinarySubstreamRef ModuleDebugStreamRef::getSymbolsSubstream() const { return SymbolsSubstream; } @@ -97,6 +105,12 @@ ModuleDebugStreamRef::symbols(bool *HadError) const { return make_range(SymbolArray.begin(HadError), SymbolArray.end()); } +CVSymbol ModuleDebugStreamRef::readSymbolAtOffset(uint32_t Offset) const { + auto Iter = SymbolArray.at(Offset); + assert(Iter != SymbolArray.end()); + return *Iter; +} + iterator_range<ModuleDebugStreamRef::DebugSubsectionIterator> ModuleDebugStreamRef::subsections() const { return make_range(Subsections.begin(), Subsections.end()); diff --git a/lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp deleted file mode 100644 index 4644ddcf24e39..0000000000000 --- a/lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp +++ /dev/null @@ -1,47 +0,0 @@ -//===- NativeBuiltinSymbol.cpp ------------------------------------ C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeBuiltinSymbol.h" - - -namespace llvm { -namespace pdb { - -NativeBuiltinSymbol::NativeBuiltinSymbol(NativeSession &PDBSession, - SymIndexId Id, PDB_BuiltinType T, - uint64_t L) - : NativeRawSymbol(PDBSession, Id), Session(PDBSession), Type(T), Length(L) { -} - -NativeBuiltinSymbol::~NativeBuiltinSymbol() {} - -std::unique_ptr<NativeRawSymbol> NativeBuiltinSymbol::clone() const { - return llvm::make_unique<NativeBuiltinSymbol>(Session, SymbolId, Type, Length); -} - -void NativeBuiltinSymbol::dump(raw_ostream &OS, int Indent) const { - // TODO: Apparently nothing needs this yet. -} - -PDB_SymType NativeBuiltinSymbol::getSymTag() const { - return PDB_SymType::BuiltinType; -} - -PDB_BuiltinType NativeBuiltinSymbol::getBuiltinType() const { return Type; } - -bool NativeBuiltinSymbol::isConstType() const { return false; } - -uint64_t NativeBuiltinSymbol::getLength() const { return Length; } - -bool NativeBuiltinSymbol::isUnalignedType() const { return false; } - -bool NativeBuiltinSymbol::isVolatileType() const { return false; } - -} // namespace pdb -} // namespace llvm diff --git a/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp index 7132a99a9f160..efa70b0e7bd8b 100644 --- a/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp +++ b/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/ADT/STLExtras.h" @@ -17,21 +18,31 @@ namespace pdb { NativeCompilandSymbol::NativeCompilandSymbol(NativeSession &Session, SymIndexId SymbolId, DbiModuleDescriptor MI) - : NativeRawSymbol(Session, SymbolId), Module(MI) {} + : NativeRawSymbol(Session, PDB_SymType::Compiland, SymbolId), Module(MI) {} PDB_SymType NativeCompilandSymbol::getSymTag() const { return PDB_SymType::Compiland; } -std::unique_ptr<NativeRawSymbol> NativeCompilandSymbol::clone() const { - return llvm::make_unique<NativeCompilandSymbol>(Session, SymbolId, Module); +void NativeCompilandSymbol::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "libraryName", getLibraryName(), Indent); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolField(OS, "editAndContinueEnabled", isEditAndContinueEnabled(), + Indent); } bool NativeCompilandSymbol::isEditAndContinueEnabled() const { return Module.hasECInfo(); } -uint32_t NativeCompilandSymbol::getLexicalParentId() const { return 0; } +SymIndexId NativeCompilandSymbol::getLexicalParentId() const { return 0; } // The usage of getObjFileName for getLibraryName and getModuleName for getName // may seem backwards, but it is consistent with DIA, which is what this API diff --git a/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp b/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp new file mode 100644 index 0000000000000..6eece3df2db34 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp @@ -0,0 +1,55 @@ +//==- NativeEnumGlobals.cpp - Native Global Enumerator impl ------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h" + +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeEnumGlobals::NativeEnumGlobals(NativeSession &PDBSession, + std::vector<codeview::SymbolKind> Kinds) + : Index(0), Session(PDBSession) { + GlobalsStream &GS = cantFail(Session.getPDBFile().getPDBGlobalsStream()); + SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream()); + for (uint32_t Off : GS.getGlobalsTable()) { + CVSymbol S = SS.readRecord(Off); + if (!llvm::is_contained(Kinds, S.kind())) + continue; + MatchOffsets.push_back(Off); + } +} + +uint32_t NativeEnumGlobals::getChildCount() const { + return static_cast<uint32_t>(MatchOffsets.size()); +} + +std::unique_ptr<PDBSymbol> +NativeEnumGlobals::getChildAtIndex(uint32_t N) const { + if (N >= MatchOffsets.size()) + return nullptr; + + SymIndexId Id = + Session.getSymbolCache().getOrCreateGlobalSymbolByOffset(MatchOffsets[N]); + return Session.getSymbolCache().getSymbolById(Id); +} + +std::unique_ptr<PDBSymbol> NativeEnumGlobals::getNext() { + return getChildAtIndex(Index++); +} + +void NativeEnumGlobals::reset() { Index = 0; } diff --git a/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp b/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp index a65782e2d4fc6..6e4d56443a072 100644 --- a/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp +++ b/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp @@ -10,42 +10,35 @@ #include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h" #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/PDBSymbol.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" namespace llvm { namespace pdb { -NativeEnumModules::NativeEnumModules(NativeSession &PDBSession, - const DbiModuleList &Modules, - uint32_t Index) - : Session(PDBSession), Modules(Modules), Index(Index) {} +NativeEnumModules::NativeEnumModules(NativeSession &PDBSession, uint32_t Index) + : Session(PDBSession), Index(Index) {} uint32_t NativeEnumModules::getChildCount() const { - return static_cast<uint32_t>(Modules.getModuleCount()); + return Session.getSymbolCache().getNumCompilands(); } std::unique_ptr<PDBSymbol> -NativeEnumModules::getChildAtIndex(uint32_t Index) const { - if (Index >= Modules.getModuleCount()) - return nullptr; - return Session.createCompilandSymbol(Modules.getModuleDescriptor(Index)); +NativeEnumModules::getChildAtIndex(uint32_t N) const { + return Session.getSymbolCache().getOrCreateCompiland(N); } std::unique_ptr<PDBSymbol> NativeEnumModules::getNext() { - if (Index >= Modules.getModuleCount()) + if (Index >= getChildCount()) return nullptr; return getChildAtIndex(Index++); } void NativeEnumModules::reset() { Index = 0; } -NativeEnumModules *NativeEnumModules::clone() const { - return new NativeEnumModules(Session, Modules, Index); -} - } } diff --git a/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp deleted file mode 100644 index 38d65917306a7..0000000000000 --- a/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp +++ /dev/null @@ -1,108 +0,0 @@ -//===- NativeEnumSymbol.cpp - info about enum type --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h" - -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" - -#include <cassert> - -using namespace llvm; -using namespace llvm::pdb; - -NativeEnumSymbol::NativeEnumSymbol(NativeSession &Session, SymIndexId Id, - const codeview::CVType &CVT) - : NativeRawSymbol(Session, Id), CV(CVT), - Record(codeview::TypeRecordKind::Enum) { - assert(CV.kind() == codeview::TypeLeafKind::LF_ENUM); - cantFail(visitTypeRecord(CV, *this)); -} - -NativeEnumSymbol::~NativeEnumSymbol() {} - -std::unique_ptr<NativeRawSymbol> NativeEnumSymbol::clone() const { - return llvm::make_unique<NativeEnumSymbol>(Session, SymbolId, CV); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeEnumSymbol::findChildren(PDB_SymType Type) const { - switch (Type) { - case PDB_SymType::Data: { - // TODO(amccarth): Provide an actual implementation. - return nullptr; - } - default: - return nullptr; - } -} - -Error NativeEnumSymbol::visitKnownRecord(codeview::CVType &CVR, - codeview::EnumRecord &ER) { - Record = ER; - return Error::success(); -} - -Error NativeEnumSymbol::visitKnownMember(codeview::CVMemberRecord &CVM, - codeview::EnumeratorRecord &R) { - return Error::success(); -} - -PDB_SymType NativeEnumSymbol::getSymTag() const { return PDB_SymType::Enum; } - -uint32_t NativeEnumSymbol::getClassParentId() const { return 0xFFFFFFFF; } - -uint32_t NativeEnumSymbol::getUnmodifiedTypeId() const { return 0; } - -bool NativeEnumSymbol::hasConstructor() const { - return bool(Record.getOptions() & - codeview::ClassOptions::HasConstructorOrDestructor); -} - -bool NativeEnumSymbol::hasAssignmentOperator() const { - return bool(Record.getOptions() & - codeview::ClassOptions::HasOverloadedAssignmentOperator); -} - -bool NativeEnumSymbol::hasCastOperator() const { - return bool(Record.getOptions() & - codeview::ClassOptions::HasConversionOperator); -} - -uint64_t NativeEnumSymbol::getLength() const { - const auto Id = Session.findSymbolByTypeIndex(Record.getUnderlyingType()); - const auto UnderlyingType = - Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id); - return UnderlyingType ? UnderlyingType->getLength() : 0; -} - -std::string NativeEnumSymbol::getName() const { return Record.getName(); } - -bool NativeEnumSymbol::isNested() const { - return bool(Record.getOptions() & codeview::ClassOptions::Nested); -} - -bool NativeEnumSymbol::hasOverloadedOperator() const { - return bool(Record.getOptions() & - codeview::ClassOptions::HasOverloadedOperator); -} - -bool NativeEnumSymbol::isPacked() const { - return bool(Record.getOptions() & codeview::ClassOptions::Packed); -} - -bool NativeEnumSymbol::isScoped() const { - return bool(Record.getOptions() & codeview::ClassOptions::Scoped); -} - -uint32_t NativeEnumSymbol::getTypeId() const { - return Session.findSymbolByTypeIndex(Record.getUnderlyingType()); -} diff --git a/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp b/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp index 36a68a1c62de4..288a9128147ab 100644 --- a/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp +++ b/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp @@ -9,39 +9,58 @@ #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" #include "llvm/DebugInfo/PDB/PDBSymbol.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" -namespace llvm { -namespace pdb { +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession, - codeview::LazyRandomTypeCollection &Types, - codeview::TypeLeafKind Kind) - : Matches(), Index(0), Session(PDBSession), Kind(Kind) { - for (auto Index = Types.getFirst(); Index; - Index = Types.getNext(Index.getValue())) { - if (Types.getType(Index.getValue()).kind() == Kind) - Matches.push_back(Index.getValue()); + LazyRandomTypeCollection &Types, + std::vector<codeview::TypeLeafKind> Kinds) + : Matches(), Index(0), Session(PDBSession) { + Optional<TypeIndex> TI = Types.getFirst(); + while (TI) { + CVType CVT = Types.getType(*TI); + TypeLeafKind K = CVT.kind(); + if (llvm::is_contained(Kinds, K)) { + // Don't add forward refs, we'll find those later while enumerating. + if (!isUdtForwardRef(CVT)) + Matches.push_back(*TI); + } else if (K == TypeLeafKind::LF_MODIFIER) { + TypeIndex ModifiedTI = getModifiedType(CVT); + if (!ModifiedTI.isSimple()) { + CVType UnmodifiedCVT = Types.getType(ModifiedTI); + // LF_MODIFIERs point to forward refs, but don't worry about that + // here. We're pushing the TypeIndex of the LF_MODIFIER itself, + // so we'll worry about resolving forward refs later. + if (llvm::is_contained(Kinds, UnmodifiedCVT.kind())) + Matches.push_back(*TI); + } + } + TI = Types.getNext(*TI); } } -NativeEnumTypes::NativeEnumTypes( - NativeSession &PDBSession, const std::vector<codeview::TypeIndex> &Matches, - codeview::TypeLeafKind Kind) - : Matches(Matches), Index(0), Session(PDBSession), Kind(Kind) {} +NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession, + std::vector<codeview::TypeIndex> Indices) + : Matches(std::move(Indices)), Index(0), Session(PDBSession) {} uint32_t NativeEnumTypes::getChildCount() const { return static_cast<uint32_t>(Matches.size()); } -std::unique_ptr<PDBSymbol> -NativeEnumTypes::getChildAtIndex(uint32_t Index) const { - if (Index < Matches.size()) - return Session.createEnumSymbol(Matches[Index]); +std::unique_ptr<PDBSymbol> NativeEnumTypes::getChildAtIndex(uint32_t N) const { + if (N < Matches.size()) { + SymIndexId Id = Session.getSymbolCache().findSymbolByTypeIndex(Matches[N]); + return Session.getSymbolCache().getSymbolById(Id); + } return nullptr; } @@ -50,10 +69,3 @@ std::unique_ptr<PDBSymbol> NativeEnumTypes::getNext() { } void NativeEnumTypes::reset() { Index = 0; } - -NativeEnumTypes *NativeEnumTypes::clone() const { - return new NativeEnumTypes(Session, Matches, Kind); -} - -} // namespace pdb -} // namespace llvm diff --git a/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp index e8b06065fc607..6dde5d08a500b 100644 --- a/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp +++ b/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp @@ -12,34 +12,53 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" -namespace llvm { -namespace pdb { +using namespace llvm; +using namespace llvm::pdb; -NativeExeSymbol::NativeExeSymbol(NativeSession &Session, SymIndexId SymbolId) - : NativeRawSymbol(Session, SymbolId), File(Session.getPDBFile()) {} +static DbiStream *getDbiStreamPtr(NativeSession &Session) { + Expected<DbiStream &> DbiS = Session.getPDBFile().getPDBDbiStream(); + if (DbiS) + return &DbiS.get(); -std::unique_ptr<NativeRawSymbol> NativeExeSymbol::clone() const { - return llvm::make_unique<NativeExeSymbol>(Session, SymbolId); + consumeError(DbiS.takeError()); + return nullptr; } +NativeExeSymbol::NativeExeSymbol(NativeSession &Session, SymIndexId SymbolId) + : NativeRawSymbol(Session, PDB_SymType::Exe, SymbolId), + Dbi(getDbiStreamPtr(Session)) {} + std::unique_ptr<IPDBEnumSymbols> NativeExeSymbol::findChildren(PDB_SymType Type) const { switch (Type) { case PDB_SymType::Compiland: { - auto Dbi = File.getPDBDbiStream(); - if (Dbi) { - const DbiModuleList &Modules = Dbi->modules(); - return std::unique_ptr<IPDBEnumSymbols>( - new NativeEnumModules(Session, Modules)); - } - consumeError(Dbi.takeError()); + return std::unique_ptr<IPDBEnumSymbols>(new NativeEnumModules(Session)); break; } + case PDB_SymType::ArrayType: + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ARRAY); case PDB_SymType::Enum: - return Session.createTypeEnumerator(codeview::LF_ENUM); + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ENUM); + case PDB_SymType::PointerType: + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_POINTER); + case PDB_SymType::UDT: + return Session.getSymbolCache().createTypeEnumerator( + {codeview::LF_STRUCTURE, codeview::LF_CLASS, codeview::LF_UNION, + codeview::LF_INTERFACE}); + case PDB_SymType::VTableShape: + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_VTSHAPE); + case PDB_SymType::FunctionSig: + return Session.getSymbolCache().createTypeEnumerator( + {codeview::LF_PROCEDURE, codeview::LF_MFUNCTION}); + case PDB_SymType::Typedef: + return Session.getSymbolCache().createGlobalsEnumerator(codeview::S_UDT); + default: break; } @@ -47,7 +66,7 @@ NativeExeSymbol::findChildren(PDB_SymType Type) const { } uint32_t NativeExeSymbol::getAge() const { - auto IS = File.getPDBInfoStream(); + auto IS = Session.getPDBFile().getPDBInfoStream(); if (IS) return IS->getAge(); consumeError(IS.takeError()); @@ -55,11 +74,11 @@ uint32_t NativeExeSymbol::getAge() const { } std::string NativeExeSymbol::getSymbolsFileName() const { - return File.getFilePath(); + return Session.getPDBFile().getFilePath(); } codeview::GUID NativeExeSymbol::getGuid() const { - auto IS = File.getPDBInfoStream(); + auto IS = Session.getPDBFile().getPDBInfoStream(); if (IS) return IS->getGuid(); consumeError(IS.takeError()); @@ -67,7 +86,7 @@ codeview::GUID NativeExeSymbol::getGuid() const { } bool NativeExeSymbol::hasCTypes() const { - auto Dbi = File.getPDBDbiStream(); + auto Dbi = Session.getPDBFile().getPDBDbiStream(); if (Dbi) return Dbi->hasCTypes(); consumeError(Dbi.takeError()); @@ -75,12 +94,9 @@ bool NativeExeSymbol::hasCTypes() const { } bool NativeExeSymbol::hasPrivateSymbols() const { - auto Dbi = File.getPDBDbiStream(); + auto Dbi = Session.getPDBFile().getPDBDbiStream(); if (Dbi) return !Dbi->isStripped(); consumeError(Dbi.takeError()); return false; } - -} // namespace pdb -} // namespace llvm diff --git a/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp index a4b0295963145..62950cb3e52a6 100644 --- a/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp +++ b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp @@ -7,82 +7,92 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" #include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/Support/FormatVariadic.h" using namespace llvm; using namespace llvm::pdb; -NativeRawSymbol::NativeRawSymbol(NativeSession &PDBSession, SymIndexId SymbolId) - : Session(PDBSession), SymbolId(SymbolId) {} +NativeRawSymbol::NativeRawSymbol(NativeSession &PDBSession, PDB_SymType Tag, + SymIndexId SymbolId) + : Session(PDBSession), Tag(Tag), SymbolId(SymbolId) {} -void NativeRawSymbol::dump(raw_ostream &OS, int Indent) const {} +void NativeRawSymbol::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + dumpSymbolIdField(OS, "symIndexId", SymbolId, Indent, Session, + PdbSymbolIdField::SymIndexId, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "symTag", Tag, Indent); +} std::unique_ptr<IPDBEnumSymbols> NativeRawSymbol::findChildren(PDB_SymType Type) const { - return nullptr; + return llvm::make_unique<NullEnumerator<PDBSymbol>>(); } std::unique_ptr<IPDBEnumSymbols> NativeRawSymbol::findChildren(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags) const { - return nullptr; + return llvm::make_unique<NullEnumerator<PDBSymbol>>(); } std::unique_ptr<IPDBEnumSymbols> NativeRawSymbol::findChildrenByAddr(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, uint32_t Section, uint32_t Offset) const { - return nullptr; + return llvm::make_unique<NullEnumerator<PDBSymbol>>(); } std::unique_ptr<IPDBEnumSymbols> NativeRawSymbol::findChildrenByVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, uint64_t VA) const { - return nullptr; + return llvm::make_unique<NullEnumerator<PDBSymbol>>(); } std::unique_ptr<IPDBEnumSymbols> NativeRawSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, uint32_t RVA) const { - return nullptr; + return llvm::make_unique<NullEnumerator<PDBSymbol>>(); } std::unique_ptr<IPDBEnumSymbols> NativeRawSymbol::findInlineFramesByAddr(uint32_t Section, uint32_t Offset) const { - return nullptr; + return llvm::make_unique<NullEnumerator<PDBSymbol>>(); } std::unique_ptr<IPDBEnumSymbols> NativeRawSymbol::findInlineFramesByRVA(uint32_t RVA) const { - return nullptr; + return llvm::make_unique<NullEnumerator<PDBSymbol>>(); } std::unique_ptr<IPDBEnumSymbols> NativeRawSymbol::findInlineFramesByVA(uint64_t VA) const { - return nullptr; + return llvm::make_unique<NullEnumerator<PDBSymbol>>(); } std::unique_ptr<IPDBEnumLineNumbers> NativeRawSymbol::findInlineeLines() const { - return nullptr; + return llvm::make_unique<NullEnumerator<IPDBLineNumber>>(); } std::unique_ptr<IPDBEnumLineNumbers> NativeRawSymbol::findInlineeLinesByAddr(uint32_t Section, uint32_t Offset, uint32_t Length) const { - return nullptr; + return llvm::make_unique<NullEnumerator<IPDBLineNumber>>(); } std::unique_ptr<IPDBEnumLineNumbers> NativeRawSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const { - return nullptr; + return llvm::make_unique<NullEnumerator<IPDBLineNumber>>(); } std::unique_ptr<IPDBEnumLineNumbers> NativeRawSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const { - return nullptr; + return llvm::make_unique<NullEnumerator<IPDBLineNumber>>(); } void NativeRawSymbol::getDataBytes(SmallVector<uint8_t, 32> &bytes) const { @@ -105,9 +115,7 @@ uint32_t NativeRawSymbol::getAge() const { return 0; } -uint32_t NativeRawSymbol::getArrayIndexTypeId() const { - return 0; -} +SymIndexId NativeRawSymbol::getArrayIndexTypeId() const { return 0; } void NativeRawSymbol::getBackEndVersion(VersionInfo &Version) const { Version.Major = 0; @@ -124,9 +132,7 @@ uint32_t NativeRawSymbol::getBaseDataSlot() const { return 0; } -uint32_t NativeRawSymbol::getBaseSymbolId() const { - return 0; -} +SymIndexId NativeRawSymbol::getBaseSymbolId() const { return 0; } PDB_BuiltinType NativeRawSymbol::getBuiltinType() const { return PDB_BuiltinType::None; @@ -140,9 +146,7 @@ PDB_CallingConv NativeRawSymbol::getCallingConvention() const { return PDB_CallingConv::FarStdCall; } -uint32_t NativeRawSymbol::getClassParentId() const { - return 0; -} +SymIndexId NativeRawSymbol::getClassParentId() const { return 0; } std::string NativeRawSymbol::getCompilerName() const { return {}; @@ -167,9 +171,7 @@ PDB_Lang NativeRawSymbol::getLanguage() const { return PDB_Lang::Cobol; } -uint32_t NativeRawSymbol::getLexicalParentId() const { - return 0; -} +SymIndexId NativeRawSymbol::getLexicalParentId() const { return 0; } std::string NativeRawSymbol::getLibraryName() const { return {}; @@ -188,12 +190,10 @@ uint32_t NativeRawSymbol::getLiveRangeStartRelativeVirtualAddress() const { } codeview::RegisterId NativeRawSymbol::getLocalBasePointerRegisterId() const { - return codeview::RegisterId::CVRegEAX; + return codeview::RegisterId::EAX; } -uint32_t NativeRawSymbol::getLowerBoundId() const { - return 0; -} +SymIndexId NativeRawSymbol::getLowerBoundId() const { return 0; } uint32_t NativeRawSymbol::getMemorySpaceKind() const { return 0; @@ -231,9 +231,7 @@ uint32_t NativeRawSymbol::getOemId() const { return 0; } -uint32_t NativeRawSymbol::getOemSymbolId() const { - return 0; -} +SymIndexId NativeRawSymbol::getOemSymbolId() const { return 0; } uint32_t NativeRawSymbol::getOffsetInUdt() const { return 0; @@ -248,7 +246,7 @@ uint32_t NativeRawSymbol::getRank() const { } codeview::RegisterId NativeRawSymbol::getRegisterId() const { - return codeview::RegisterId::CVRegEAX; + return codeview::RegisterId::EAX; } uint32_t NativeRawSymbol::getRegisterType() const { @@ -288,13 +286,11 @@ uint32_t NativeRawSymbol::getStride() const { return 0; } -uint32_t NativeRawSymbol::getSubTypeId() const { - return 0; -} +SymIndexId NativeRawSymbol::getSubTypeId() const { return 0; } std::string NativeRawSymbol::getSymbolsFileName() const { return {}; } -uint32_t NativeRawSymbol::getSymIndexId() const { return SymbolId; } +SymIndexId NativeRawSymbol::getSymIndexId() const { return SymbolId; } uint32_t NativeRawSymbol::getTargetOffset() const { return 0; @@ -324,9 +320,7 @@ uint32_t NativeRawSymbol::getToken() const { return 0; } -uint32_t NativeRawSymbol::getTypeId() const { - return 0; -} +SymIndexId NativeRawSymbol::getTypeId() const { return 0; } uint32_t NativeRawSymbol::getUavSlot() const { return 0; @@ -341,13 +335,9 @@ std::string NativeRawSymbol::getUndecoratedNameEx( return {}; } -uint32_t NativeRawSymbol::getUnmodifiedTypeId() const { - return 0; -} +SymIndexId NativeRawSymbol::getUnmodifiedTypeId() const { return 0; } -uint32_t NativeRawSymbol::getUpperBoundId() const { - return 0; -} +SymIndexId NativeRawSymbol::getUpperBoundId() const { return 0; } Variant NativeRawSymbol::getValue() const { return Variant(); @@ -361,9 +351,7 @@ uint32_t NativeRawSymbol::getVirtualBaseOffset() const { return 0; } -uint32_t NativeRawSymbol::getVirtualTableShapeId() const { - return 0; -} +SymIndexId NativeRawSymbol::getVirtualTableShapeId() const { return 0; } std::unique_ptr<PDBSymbolTypeBuiltin> NativeRawSymbol::getVirtualBaseTableType() const { @@ -374,9 +362,7 @@ PDB_DataKind NativeRawSymbol::getDataKind() const { return PDB_DataKind::Unknown; } -PDB_SymType NativeRawSymbol::getSymTag() const { - return PDB_SymType::None; -} +PDB_SymType NativeRawSymbol::getSymTag() const { return Tag; } codeview::GUID NativeRawSymbol::getGuid() const { return codeview::GUID{{0}}; } diff --git a/lib/DebugInfo/PDB/Native/NativeSession.cpp b/lib/DebugInfo/PDB/Native/NativeSession.cpp index 086da13135c59..7807e312365c9 100644 --- a/lib/DebugInfo/PDB/Native/NativeSession.cpp +++ b/lib/DebugInfo/PDB/Native/NativeSession.cpp @@ -11,16 +11,16 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" -#include "llvm/DebugInfo/PDB/Native/NativeBuiltinSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" #include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" @@ -40,31 +40,19 @@ using namespace llvm; using namespace llvm::msf; using namespace llvm::pdb; -namespace { -// Maps codeview::SimpleTypeKind of a built-in type to the parameters necessary -// to instantiate a NativeBuiltinSymbol for that type. -static const struct BuiltinTypeEntry { - codeview::SimpleTypeKind Kind; - PDB_BuiltinType Type; - uint32_t Size; -} BuiltinTypes[] = { - {codeview::SimpleTypeKind::Int32, PDB_BuiltinType::Int, 4}, - {codeview::SimpleTypeKind::UInt32, PDB_BuiltinType::UInt, 4}, - {codeview::SimpleTypeKind::UInt32Long, PDB_BuiltinType::UInt, 4}, - {codeview::SimpleTypeKind::UInt64Quad, PDB_BuiltinType::UInt, 8}, - {codeview::SimpleTypeKind::NarrowCharacter, PDB_BuiltinType::Char, 1}, - {codeview::SimpleTypeKind::SignedCharacter, PDB_BuiltinType::Char, 1}, - {codeview::SimpleTypeKind::UnsignedCharacter, PDB_BuiltinType::UInt, 1}, - {codeview::SimpleTypeKind::UInt16Short, PDB_BuiltinType::UInt, 2}, - {codeview::SimpleTypeKind::Boolean8, PDB_BuiltinType::Bool, 1} - // This table can be grown as necessary, but these are the only types we've - // needed so far. -}; -} // namespace +static DbiStream *getDbiStreamPtr(PDBFile &File) { + Expected<DbiStream &> DbiS = File.getPDBDbiStream(); + if (DbiS) + return &DbiS.get(); + + consumeError(DbiS.takeError()); + return nullptr; +} NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile, std::unique_ptr<BumpPtrAllocator> Allocator) - : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)) {} + : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)), + Cache(*this, getDbiStreamPtr(*Pdb)) {} NativeSession::~NativeSession() = default; @@ -92,97 +80,17 @@ Error NativeSession::createFromExe(StringRef Path, return make_error<RawError>(raw_error_code::feature_unsupported); } -std::unique_ptr<PDBSymbolCompiland> -NativeSession::createCompilandSymbol(DbiModuleDescriptor MI) { - const auto Id = static_cast<SymIndexId>(SymbolCache.size()); - SymbolCache.push_back( - llvm::make_unique<NativeCompilandSymbol>(*this, Id, MI)); - return llvm::make_unique<PDBSymbolCompiland>( - *this, std::unique_ptr<IPDBRawSymbol>(SymbolCache[Id]->clone())); -} - -std::unique_ptr<PDBSymbolTypeEnum> -NativeSession::createEnumSymbol(codeview::TypeIndex Index) { - const auto Id = findSymbolByTypeIndex(Index); - return llvm::make_unique<PDBSymbolTypeEnum>( - *this, std::unique_ptr<IPDBRawSymbol>(SymbolCache[Id]->clone())); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeSession::createTypeEnumerator(codeview::TypeLeafKind Kind) { - auto Tpi = Pdb->getPDBTpiStream(); - if (!Tpi) { - consumeError(Tpi.takeError()); - return nullptr; - } - auto &Types = Tpi->typeCollection(); - return std::unique_ptr<IPDBEnumSymbols>( - new NativeEnumTypes(*this, Types, codeview::LF_ENUM)); -} - -SymIndexId NativeSession::findSymbolByTypeIndex(codeview::TypeIndex Index) { - // First see if it's already in our cache. - const auto Entry = TypeIndexToSymbolId.find(Index); - if (Entry != TypeIndexToSymbolId.end()) - return Entry->second; - - // Symbols for built-in types are created on the fly. - if (Index.isSimple()) { - // FIXME: We will eventually need to handle pointers to other simple types, - // which are still simple types in the world of CodeView TypeIndexes. - if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct) - return 0; - const auto Kind = Index.getSimpleKind(); - const auto It = - std::find_if(std::begin(BuiltinTypes), std::end(BuiltinTypes), - [Kind](const BuiltinTypeEntry &Builtin) { - return Builtin.Kind == Kind; - }); - if (It == std::end(BuiltinTypes)) - return 0; - SymIndexId Id = SymbolCache.size(); - SymbolCache.emplace_back( - llvm::make_unique<NativeBuiltinSymbol>(*this, Id, It->Type, It->Size)); - TypeIndexToSymbolId[Index] = Id; - return Id; - } - - // We need to instantiate and cache the desired type symbol. - auto Tpi = Pdb->getPDBTpiStream(); - if (!Tpi) { - consumeError(Tpi.takeError()); - return 0; - } - auto &Types = Tpi->typeCollection(); - const auto &I = Types.getType(Index); - const auto Id = static_cast<SymIndexId>(SymbolCache.size()); - // TODO(amccarth): Make this handle all types, not just LF_ENUMs. - assert(I.kind() == codeview::LF_ENUM); - SymbolCache.emplace_back(llvm::make_unique<NativeEnumSymbol>(*this, Id, I)); - TypeIndexToSymbolId[Index] = Id; - return Id; -} - uint64_t NativeSession::getLoadAddress() const { return 0; } bool NativeSession::setLoadAddress(uint64_t Address) { return false; } std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() { - const auto Id = static_cast<SymIndexId>(SymbolCache.size()); - SymbolCache.push_back(llvm::make_unique<NativeExeSymbol>(*this, Id)); - auto RawSymbol = SymbolCache[Id]->clone(); - auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol))); - std::unique_ptr<PDBSymbolExe> ExeSymbol( - static_cast<PDBSymbolExe *>(PdbSymbol.release())); - return ExeSymbol; + return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope()); } std::unique_ptr<PDBSymbol> -NativeSession::getSymbolById(uint32_t SymbolId) const { - // If the caller has a SymbolId, it'd better be in our SymbolCache. - return SymbolId < SymbolCache.size() - ? PDBSymbol::create(*this, SymbolCache[SymbolId]->clone()) - : nullptr; +NativeSession::getSymbolById(SymIndexId SymbolId) const { + return Cache.getSymbolById(SymbolId); } bool NativeSession::addressForVA(uint64_t VA, uint32_t &Section, @@ -291,3 +199,19 @@ std::unique_ptr<IPDBEnumSectionContribs> NativeSession::getSectionContribs() const { return nullptr; } + +std::unique_ptr<IPDBEnumFrameData> +NativeSession::getFrameData() const { + return nullptr; +} + +void NativeSession::initializeExeSymbol() { + if (ExeSymbol == 0) + ExeSymbol = Cache.createSymbol<NativeExeSymbol>(); +} + +NativeExeSymbol &NativeSession::getNativeGlobalScope() const { + const_cast<NativeSession &>(*this).initializeExeSymbol(); + + return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol); +} diff --git a/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp b/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp new file mode 100644 index 0000000000000..6ebb8cae3a656 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp @@ -0,0 +1,123 @@ +//===- NativeSymbolEnumerator.cpp - info about enumerators ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h" + +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeSymbolEnumerator::NativeSymbolEnumerator( + NativeSession &Session, SymIndexId Id, const NativeTypeEnum &Parent, + codeview::EnumeratorRecord Record) + : NativeRawSymbol(Session, PDB_SymType::Data, Id), Parent(Parent), + Record(std::move(Record)) {} + +NativeSymbolEnumerator::~NativeSymbolEnumerator() {} + +void NativeSymbolEnumerator::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session, + PdbSymbolIdField::ClassParent, ShowIdFields, + RecurseIdFields); + dumpSymbolIdField(OS, "lexicalParentId", getLexicalParentId(), Indent, + Session, PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + dumpSymbolField(OS, "dataKind", getDataKind(), Indent); + dumpSymbolField(OS, "locationType", getLocationType(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); + dumpSymbolField(OS, "value", getValue(), Indent); +} + +SymIndexId NativeSymbolEnumerator::getClassParentId() const { + return Parent.getSymIndexId(); +} + +SymIndexId NativeSymbolEnumerator::getLexicalParentId() const { return 0; } + +std::string NativeSymbolEnumerator::getName() const { return Record.Name; } + +SymIndexId NativeSymbolEnumerator::getTypeId() const { + return Parent.getTypeId(); +} + +PDB_DataKind NativeSymbolEnumerator::getDataKind() const { + return PDB_DataKind::Constant; +} + +PDB_LocType NativeSymbolEnumerator::getLocationType() const { + return PDB_LocType::Constant; +} + +bool NativeSymbolEnumerator::isConstType() const { return false; } + +bool NativeSymbolEnumerator::isVolatileType() const { return false; } + +bool NativeSymbolEnumerator::isUnalignedType() const { return false; } + +Variant NativeSymbolEnumerator::getValue() const { + const NativeTypeBuiltin &BT = Parent.getUnderlyingBuiltinType(); + + switch (BT.getBuiltinType()) { + case PDB_BuiltinType::Int: + case PDB_BuiltinType::Long: + case PDB_BuiltinType::Char: { + assert(Record.Value.isSignedIntN(BT.getLength() * 8)); + int64_t N = Record.Value.getSExtValue(); + switch (BT.getLength()) { + case 1: + return Variant{static_cast<int8_t>(N)}; + case 2: + return Variant{static_cast<int16_t>(N)}; + case 4: + return Variant{static_cast<int32_t>(N)}; + case 8: + return Variant{static_cast<int64_t>(N)}; + } + break; + } + case PDB_BuiltinType::UInt: + case PDB_BuiltinType::ULong: { + assert(Record.Value.isIntN(BT.getLength() * 8)); + uint64_t U = Record.Value.getZExtValue(); + switch (BT.getLength()) { + case 1: + return Variant{static_cast<uint8_t>(U)}; + case 2: + return Variant{static_cast<uint16_t>(U)}; + case 4: + return Variant{static_cast<uint32_t>(U)}; + case 8: + return Variant{static_cast<uint64_t>(U)}; + } + break; + } + case PDB_BuiltinType::Bool: { + assert(Record.Value.isIntN(BT.getLength() * 8)); + uint64_t U = Record.Value.getZExtValue(); + return Variant{static_cast<bool>(U)}; + } + default: + assert(false && "Invalid enumeration type"); + break; + } + + return Variant{Record.Value.getSExtValue()}; +} diff --git a/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp b/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp new file mode 100644 index 0000000000000..a52561728a98d --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp @@ -0,0 +1,67 @@ +//===- NativeTypeArray.cpp - info about arrays ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h" + +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeArray::NativeTypeArray(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, + codeview::ArrayRecord Record) + : NativeRawSymbol(Session, PDB_SymType::ArrayType, Id), Record(Record), + Index(TI) {} +NativeTypeArray::~NativeTypeArray() {} + +void NativeTypeArray::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolField(OS, "arrayIndexTypeId", getArrayIndexTypeId(), Indent); + dumpSymbolIdField(OS, "elementTypeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "count", getCount(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +SymIndexId NativeTypeArray::getArrayIndexTypeId() const { + return Session.getSymbolCache().findSymbolByTypeIndex(Record.getIndexType()); +} + +bool NativeTypeArray::isConstType() const { return false; } + +bool NativeTypeArray::isUnalignedType() const { return false; } + +bool NativeTypeArray::isVolatileType() const { return false; } + +uint32_t NativeTypeArray::getCount() const { + NativeRawSymbol &Element = + Session.getSymbolCache().getNativeSymbolById(getTypeId()); + return getLength() / Element.getLength(); +} + +SymIndexId NativeTypeArray::getTypeId() const { + return Session.getSymbolCache().findSymbolByTypeIndex( + Record.getElementType()); +} + +uint64_t NativeTypeArray::getLength() const { return Record.Size; }
\ No newline at end of file diff --git a/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp b/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp new file mode 100644 index 0000000000000..7b0f13f3c0750 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp @@ -0,0 +1,47 @@ +//===- NativeTypeBuiltin.cpp -------------------------------------- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeBuiltin::NativeTypeBuiltin(NativeSession &PDBSession, SymIndexId Id, + ModifierOptions Mods, PDB_BuiltinType T, + uint64_t L) + : NativeRawSymbol(PDBSession, PDB_SymType::BuiltinType, Id), + Session(PDBSession), Mods(Mods), Type(T), Length(L) {} + +NativeTypeBuiltin::~NativeTypeBuiltin() {} + +void NativeTypeBuiltin::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const {} + +PDB_SymType NativeTypeBuiltin::getSymTag() const { + return PDB_SymType::BuiltinType; +} + +PDB_BuiltinType NativeTypeBuiltin::getBuiltinType() const { return Type; } + +bool NativeTypeBuiltin::isConstType() const { + return (Mods & ModifierOptions::Const) != ModifierOptions::None; +} + +uint64_t NativeTypeBuiltin::getLength() const { return Length; } + +bool NativeTypeBuiltin::isUnalignedType() const { + return (Mods & ModifierOptions::Unaligned) != ModifierOptions::None; +} + +bool NativeTypeBuiltin::isVolatileType() const { + return (Mods & ModifierOptions::Volatile) != ModifierOptions::None; +} diff --git a/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp b/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp new file mode 100644 index 0000000000000..37176fe083b97 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp @@ -0,0 +1,382 @@ +//===- NativeTypeEnum.cpp - info about enum type ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" + +#include "llvm/Support/FormatVariadic.h" + +#include <cassert> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +namespace { +// Yea, this is a pretty terrible class name. But if we have an enum: +// +// enum Foo { +// A, +// B +// }; +// +// then A and B are the "enumerators" of the "enum" Foo. And we need +// to enumerate them. +class NativeEnumEnumEnumerators : public IPDBEnumSymbols, TypeVisitorCallbacks { +public: + NativeEnumEnumEnumerators(NativeSession &Session, + const NativeTypeEnum &ClassParent); + + uint32_t getChildCount() const override; + std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override; + std::unique_ptr<PDBSymbol> getNext() override; + void reset() override; + +private: + Error visitKnownMember(CVMemberRecord &CVM, + EnumeratorRecord &Record) override; + Error visitKnownMember(CVMemberRecord &CVM, + ListContinuationRecord &Record) override; + + NativeSession &Session; + const NativeTypeEnum &ClassParent; + std::vector<EnumeratorRecord> Enumerators; + Optional<TypeIndex> ContinuationIndex; + uint32_t Index = 0; +}; +} // namespace + +NativeEnumEnumEnumerators::NativeEnumEnumEnumerators( + NativeSession &Session, const NativeTypeEnum &ClassParent) + : Session(Session), ClassParent(ClassParent) { + TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream()); + LazyRandomTypeCollection &Types = Tpi.typeCollection(); + + ContinuationIndex = ClassParent.getEnumRecord().FieldList; + while (ContinuationIndex) { + CVType FieldList = Types.getType(*ContinuationIndex); + assert(FieldList.kind() == LF_FIELDLIST); + ContinuationIndex.reset(); + cantFail(visitMemberRecordStream(FieldList.data(), *this)); + } +} + +Error NativeEnumEnumEnumerators::visitKnownMember(CVMemberRecord &CVM, + EnumeratorRecord &Record) { + Enumerators.push_back(Record); + return Error::success(); +} + +Error NativeEnumEnumEnumerators::visitKnownMember( + CVMemberRecord &CVM, ListContinuationRecord &Record) { + ContinuationIndex = Record.ContinuationIndex; + return Error::success(); +} + +uint32_t NativeEnumEnumEnumerators::getChildCount() const { + return Enumerators.size(); +} + +std::unique_ptr<PDBSymbol> +NativeEnumEnumEnumerators::getChildAtIndex(uint32_t Index) const { + if (Index >= getChildCount()) + return nullptr; + + SymIndexId Id = Session.getSymbolCache() + .getOrCreateFieldListMember<NativeSymbolEnumerator>( + ClassParent.getEnumRecord().FieldList, Index, + ClassParent, Enumerators[Index]); + return Session.getSymbolCache().getSymbolById(Id); +} + +std::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::getNext() { + if (Index >= getChildCount()) + return nullptr; + + return getChildAtIndex(Index++); +} + +void NativeEnumEnumEnumerators::reset() { Index = 0; } + +NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id, + TypeIndex Index, EnumRecord Record) + : NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(Index), + Record(std::move(Record)) {} + +NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id, + NativeTypeEnum &UnmodifiedType, + codeview::ModifierRecord Modifier) + : NativeRawSymbol(Session, PDB_SymType::Enum, Id), + UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {} + +NativeTypeEnum::~NativeTypeEnum() {} + +void NativeTypeEnum::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolField(OS, "baseType", static_cast<uint32_t>(getBuiltinType()), + Indent); + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + if (Modifiers.hasValue()) + dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent, + Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "constructor", hasConstructor(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent); + dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent); + dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent); + dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent); + dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent); + dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent); + dumpSymbolField(OS, "nested", isNested(), Indent); + dumpSymbolField(OS, "packed", isPacked(), Indent); + dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent); + dumpSymbolField(OS, "scoped", isScoped(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeTypeEnum::findChildren(PDB_SymType Type) const { + if (Type != PDB_SymType::Data) + return llvm::make_unique<NullEnumerator<PDBSymbol>>(); + + const NativeTypeEnum *ClassParent = nullptr; + if (!Modifiers) + ClassParent = this; + else + ClassParent = UnmodifiedType; + return llvm::make_unique<NativeEnumEnumEnumerators>(Session, *ClassParent); +} + +PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; } + +PDB_BuiltinType NativeTypeEnum::getBuiltinType() const { + if (UnmodifiedType) + return UnmodifiedType->getBuiltinType(); + + Session.getSymbolCache().findSymbolByTypeIndex(Record->getUnderlyingType()); + + codeview::TypeIndex Underlying = Record->getUnderlyingType(); + + // This indicates a corrupt record. + if (!Underlying.isSimple() || + Underlying.getSimpleMode() != SimpleTypeMode::Direct) { + return PDB_BuiltinType::None; + } + + switch (Underlying.getSimpleKind()) { + case SimpleTypeKind::Boolean128: + case SimpleTypeKind::Boolean64: + case SimpleTypeKind::Boolean32: + case SimpleTypeKind::Boolean16: + case SimpleTypeKind::Boolean8: + return PDB_BuiltinType::Bool; + case SimpleTypeKind::NarrowCharacter: + case SimpleTypeKind::UnsignedCharacter: + case SimpleTypeKind::SignedCharacter: + return PDB_BuiltinType::Char; + case SimpleTypeKind::WideCharacter: + return PDB_BuiltinType::WCharT; + case SimpleTypeKind::Character16: + return PDB_BuiltinType::Char16; + case SimpleTypeKind::Character32: + return PDB_BuiltinType::Char32; + case SimpleTypeKind::Int128: + case SimpleTypeKind::Int128Oct: + case SimpleTypeKind::Int16: + case SimpleTypeKind::Int16Short: + case SimpleTypeKind::Int32: + case SimpleTypeKind::Int32Long: + case SimpleTypeKind::Int64: + case SimpleTypeKind::Int64Quad: + return PDB_BuiltinType::Int; + case SimpleTypeKind::UInt128: + case SimpleTypeKind::UInt128Oct: + case SimpleTypeKind::UInt16: + case SimpleTypeKind::UInt16Short: + case SimpleTypeKind::UInt32: + case SimpleTypeKind::UInt32Long: + case SimpleTypeKind::UInt64: + case SimpleTypeKind::UInt64Quad: + return PDB_BuiltinType::UInt; + case SimpleTypeKind::HResult: + return PDB_BuiltinType::HResult; + case SimpleTypeKind::Complex16: + case SimpleTypeKind::Complex32: + case SimpleTypeKind::Complex32PartialPrecision: + case SimpleTypeKind::Complex64: + case SimpleTypeKind::Complex80: + case SimpleTypeKind::Complex128: + return PDB_BuiltinType::Complex; + case SimpleTypeKind::Float16: + case SimpleTypeKind::Float32: + case SimpleTypeKind::Float32PartialPrecision: + case SimpleTypeKind::Float48: + case SimpleTypeKind::Float64: + case SimpleTypeKind::Float80: + case SimpleTypeKind::Float128: + return PDB_BuiltinType::Float; + default: + return PDB_BuiltinType::None; + } + llvm_unreachable("Unreachable"); +} + +SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const { + return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0; +} + +bool NativeTypeEnum::hasConstructor() const { + if (UnmodifiedType) + return UnmodifiedType->hasConstructor(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasConstructorOrDestructor); +} + +bool NativeTypeEnum::hasAssignmentOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasAssignmentOperator(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasOverloadedAssignmentOperator); +} + +bool NativeTypeEnum::hasNestedTypes() const { + if (UnmodifiedType) + return UnmodifiedType->hasNestedTypes(); + + return bool(Record->getOptions() & + codeview::ClassOptions::ContainsNestedClass); +} + +bool NativeTypeEnum::isIntrinsic() const { + if (UnmodifiedType) + return UnmodifiedType->isIntrinsic(); + + return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic); +} + +bool NativeTypeEnum::hasCastOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasCastOperator(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasConversionOperator); +} + +uint64_t NativeTypeEnum::getLength() const { + if (UnmodifiedType) + return UnmodifiedType->getLength(); + + const auto Id = Session.getSymbolCache().findSymbolByTypeIndex( + Record->getUnderlyingType()); + const auto UnderlyingType = + Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id); + return UnderlyingType ? UnderlyingType->getLength() : 0; +} + +std::string NativeTypeEnum::getName() const { + if (UnmodifiedType) + return UnmodifiedType->getName(); + + return Record->getName(); +} + +bool NativeTypeEnum::isNested() const { + if (UnmodifiedType) + return UnmodifiedType->isNested(); + + return bool(Record->getOptions() & codeview::ClassOptions::Nested); +} + +bool NativeTypeEnum::hasOverloadedOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasOverloadedOperator(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasOverloadedOperator); +} + +bool NativeTypeEnum::isPacked() const { + if (UnmodifiedType) + return UnmodifiedType->isPacked(); + + return bool(Record->getOptions() & codeview::ClassOptions::Packed); +} + +bool NativeTypeEnum::isScoped() const { + if (UnmodifiedType) + return UnmodifiedType->isScoped(); + + return bool(Record->getOptions() & codeview::ClassOptions::Scoped); +} + +SymIndexId NativeTypeEnum::getTypeId() const { + if (UnmodifiedType) + return UnmodifiedType->getTypeId(); + + return Session.getSymbolCache().findSymbolByTypeIndex( + Record->getUnderlyingType()); +} + +bool NativeTypeEnum::isRefUdt() const { return false; } + +bool NativeTypeEnum::isValueUdt() const { return false; } + +bool NativeTypeEnum::isInterfaceUdt() const { return false; } + +bool NativeTypeEnum::isConstType() const { + if (!Modifiers) + return false; + return ((Modifiers->getModifiers() & ModifierOptions::Const) != + ModifierOptions::None); +} + +bool NativeTypeEnum::isVolatileType() const { + if (!Modifiers) + return false; + return ((Modifiers->getModifiers() & ModifierOptions::Volatile) != + ModifierOptions::None); +} + +bool NativeTypeEnum::isUnalignedType() const { + if (!Modifiers) + return false; + return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) != + ModifierOptions::None); +} + +const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const { + if (UnmodifiedType) + return UnmodifiedType->getUnderlyingBuiltinType(); + + return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>( + getTypeId()); +} diff --git a/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp b/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp new file mode 100644 index 0000000000000..a9590fffdb87e --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp @@ -0,0 +1,200 @@ +//===- NativeTypeFunctionSig.cpp - info about function signature -*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h" + +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +namespace { +// This is kind of a silly class, hence why we keep it private to the file. +// It's only purpose is to wrap the real type record. I guess this is so that +// we can have the lexical parent point to the function instead of the global +// scope. +class NativeTypeFunctionArg : public NativeRawSymbol { +public: + NativeTypeFunctionArg(NativeSession &Session, + std::unique_ptr<PDBSymbol> RealType) + : NativeRawSymbol(Session, PDB_SymType::FunctionArg, 0), + RealType(std::move(RealType)) {} + + void dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const override { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + } + + SymIndexId getTypeId() const override { return RealType->getSymIndexId(); } + + std::unique_ptr<PDBSymbol> RealType; +}; + +class NativeEnumFunctionArgs : public IPDBEnumChildren<PDBSymbol> { +public: + NativeEnumFunctionArgs(NativeSession &Session, + std::unique_ptr<NativeEnumTypes> TypeEnumerator) + : Session(Session), TypeEnumerator(std::move(TypeEnumerator)) {} + + uint32_t getChildCount() const override { + return TypeEnumerator->getChildCount(); + } + std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override { + return wrap(TypeEnumerator->getChildAtIndex(Index)); + } + std::unique_ptr<PDBSymbol> getNext() override { + return wrap(TypeEnumerator->getNext()); + } + + void reset() override { TypeEnumerator->reset(); } + +private: + std::unique_ptr<PDBSymbol> wrap(std::unique_ptr<PDBSymbol> S) const { + if (!S) + return nullptr; + auto NTFA = llvm::make_unique<NativeTypeFunctionArg>(Session, std::move(S)); + return PDBSymbol::create(Session, std::move(NTFA)); + } + NativeSession &Session; + std::unique_ptr<NativeEnumTypes> TypeEnumerator; +}; +} // namespace + +NativeTypeFunctionSig::NativeTypeFunctionSig(NativeSession &Session, + SymIndexId Id, + codeview::TypeIndex Index, + codeview::ProcedureRecord Proc) + : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id), + Proc(std::move(Proc)), Index(Index), IsMemberFunction(false) {} + +NativeTypeFunctionSig::NativeTypeFunctionSig( + NativeSession &Session, SymIndexId Id, codeview::TypeIndex Index, + codeview::MemberFunctionRecord MemberFunc) + : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id), + MemberFunc(std::move(MemberFunc)), Index(Index), IsMemberFunction(true) {} + +void NativeTypeFunctionSig::initialize() { + if (IsMemberFunction) { + ClassParentId = + Session.getSymbolCache().findSymbolByTypeIndex(MemberFunc.ClassType); + initializeArgList(MemberFunc.ArgumentList); + } else { + initializeArgList(Proc.ArgumentList); + } +} + +NativeTypeFunctionSig::~NativeTypeFunctionSig() {} + +void NativeTypeFunctionSig::initializeArgList(codeview::TypeIndex ArgListTI) { + TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream()); + CVType CVT = Tpi.typeCollection().getType(ArgListTI); + + cantFail(TypeDeserializer::deserializeAs<ArgListRecord>(CVT, ArgList)); +} + +void NativeTypeFunctionSig::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + + dumpSymbolField(OS, "callingConvention", getCallingConvention(), Indent); + dumpSymbolField(OS, "count", getCount(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + if (IsMemberFunction) + dumpSymbolField(OS, "thisAdjust", getThisAdjust(), Indent); + dumpSymbolField(OS, "constructor", hasConstructor(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "isConstructorVirtualBase", isConstructorVirtualBase(), + Indent); + dumpSymbolField(OS, "isCxxReturnUdt", isCxxReturnUdt(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeTypeFunctionSig::findChildren(PDB_SymType Type) const { + if (Type != PDB_SymType::FunctionArg) + return llvm::make_unique<NullEnumerator<PDBSymbol>>(); + + auto NET = llvm::make_unique<NativeEnumTypes>(Session, + /* copy */ ArgList.ArgIndices); + return std::unique_ptr<IPDBEnumSymbols>( + new NativeEnumFunctionArgs(Session, std::move(NET))); +} + +SymIndexId NativeTypeFunctionSig::getClassParentId() const { + if (!IsMemberFunction) + return 0; + + return ClassParentId; +} + +PDB_CallingConv NativeTypeFunctionSig::getCallingConvention() const { + return IsMemberFunction ? MemberFunc.CallConv : Proc.CallConv; +} + +uint32_t NativeTypeFunctionSig::getCount() const { + return IsMemberFunction ? (1 + MemberFunc.getParameterCount()) + : Proc.getParameterCount(); +} + +SymIndexId NativeTypeFunctionSig::getTypeId() const { + TypeIndex ReturnTI = + IsMemberFunction ? MemberFunc.getReturnType() : Proc.getReturnType(); + + SymIndexId Result = Session.getSymbolCache().findSymbolByTypeIndex(ReturnTI); + return Result; +} + +int32_t NativeTypeFunctionSig::getThisAdjust() const { + return IsMemberFunction ? MemberFunc.getThisPointerAdjustment() : 0; +} + +bool NativeTypeFunctionSig::hasConstructor() const { + if (!IsMemberFunction) + return false; + + return (MemberFunc.getOptions() & FunctionOptions::Constructor) != + FunctionOptions::None; +} + +bool NativeTypeFunctionSig::isConstType() const { return false; } + +bool NativeTypeFunctionSig::isConstructorVirtualBase() const { + if (!IsMemberFunction) + return false; + + return (MemberFunc.getOptions() & + FunctionOptions::ConstructorWithVirtualBases) != + FunctionOptions::None; +} + +bool NativeTypeFunctionSig::isCxxReturnUdt() const { + FunctionOptions Options = + IsMemberFunction ? MemberFunc.getOptions() : Proc.getOptions(); + return (Options & FunctionOptions::CxxReturnUdt) != FunctionOptions::None; +} + +bool NativeTypeFunctionSig::isUnalignedType() const { return false; } + +bool NativeTypeFunctionSig::isVolatileType() const { return false; } diff --git a/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp b/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp new file mode 100644 index 0000000000000..bd8ecb6c4007b --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp @@ -0,0 +1,194 @@ +//===- NativeTypePointer.cpp - info about pointer type ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" + +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" + +#include <cassert> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI) + : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI) { + assert(TI.isSimple()); + assert(TI.getSimpleMode() != SimpleTypeMode::Direct); +} + +NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, + codeview::PointerRecord Record) + : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI), + Record(std::move(Record)) {} + +NativeTypePointer::~NativeTypePointer() {} + +void NativeTypePointer::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + if (isMemberPointer()) { + dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session, + PdbSymbolIdField::ClassParent, ShowIdFields, + RecurseIdFields); + } + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "isPointerToDataMember", isPointerToDataMember(), Indent); + dumpSymbolField(OS, "isPointerToMemberFunction", isPointerToMemberFunction(), + Indent); + dumpSymbolField(OS, "RValueReference", isRValueReference(), Indent); + dumpSymbolField(OS, "reference", isReference(), Indent); + dumpSymbolField(OS, "restrictedType", isRestrictedType(), Indent); + if (isMemberPointer()) { + if (isSingleInheritance()) + dumpSymbolField(OS, "isSingleInheritance", 1, Indent); + else if (isMultipleInheritance()) + dumpSymbolField(OS, "isMultipleInheritance", 1, Indent); + else if (isVirtualInheritance()) + dumpSymbolField(OS, "isVirtualInheritance", 1, Indent); + } + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +SymIndexId NativeTypePointer::getClassParentId() const { + if (!isMemberPointer()) + return 0; + + assert(Record); + const MemberPointerInfo &MPI = Record->getMemberInfo(); + return Session.getSymbolCache().findSymbolByTypeIndex(MPI.ContainingType); +} + +uint64_t NativeTypePointer::getLength() const { + if (Record) + return Record->getSize(); + + switch (TI.getSimpleMode()) { + case SimpleTypeMode::NearPointer: + case SimpleTypeMode::FarPointer: + case SimpleTypeMode::HugePointer: + return 2; + case SimpleTypeMode::NearPointer32: + case SimpleTypeMode::FarPointer32: + return 4; + case SimpleTypeMode::NearPointer64: + return 8; + case SimpleTypeMode::NearPointer128: + return 16; + default: + assert(false && "invalid simple type mode!"); + } + return 0; +} + +SymIndexId NativeTypePointer::getTypeId() const { + // This is the pointee SymIndexId. + TypeIndex Referent = Record ? Record->ReferentType : TI.makeDirect(); + + return Session.getSymbolCache().findSymbolByTypeIndex(Referent); +} + +bool NativeTypePointer::isReference() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::LValueReference; +} + +bool NativeTypePointer::isRValueReference() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::RValueReference; +} + +bool NativeTypePointer::isPointerToDataMember() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::PointerToDataMember; +} + +bool NativeTypePointer::isPointerToMemberFunction() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::PointerToMemberFunction; +} + +bool NativeTypePointer::isConstType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Const) != PointerOptions::None; +} + +bool NativeTypePointer::isRestrictedType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Restrict) != + PointerOptions::None; +} + +bool NativeTypePointer::isVolatileType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Volatile) != + PointerOptions::None; +} + +bool NativeTypePointer::isUnalignedType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Unaligned) != + PointerOptions::None; +} + +static inline bool isInheritanceKind(const MemberPointerInfo &MPI, + PointerToMemberRepresentation P1, + PointerToMemberRepresentation P2) { + return (MPI.getRepresentation() == P1 || MPI.getRepresentation() == P2); +} + +bool NativeTypePointer::isSingleInheritance() const { + if (!isMemberPointer()) + return false; + return isInheritanceKind( + Record->getMemberInfo(), + PointerToMemberRepresentation::SingleInheritanceData, + PointerToMemberRepresentation::SingleInheritanceFunction); +} + +bool NativeTypePointer::isMultipleInheritance() const { + if (!isMemberPointer()) + return false; + return isInheritanceKind( + Record->getMemberInfo(), + PointerToMemberRepresentation::MultipleInheritanceData, + PointerToMemberRepresentation::MultipleInheritanceFunction); +} + +bool NativeTypePointer::isVirtualInheritance() const { + if (!isMemberPointer()) + return false; + return isInheritanceKind( + Record->getMemberInfo(), + PointerToMemberRepresentation::VirtualInheritanceData, + PointerToMemberRepresentation::VirtualInheritanceFunction); +} + +bool NativeTypePointer::isMemberPointer() const { + return isPointerToDataMember() || isPointerToMemberFunction(); +} diff --git a/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp b/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp new file mode 100644 index 0000000000000..60b3732822670 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp @@ -0,0 +1,27 @@ +#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeTypedef::NativeTypeTypedef(NativeSession &Session, SymIndexId Id, + codeview::UDTSym Typedef) + : NativeRawSymbol(Session, PDB_SymType::Typedef, Id), + Record(std::move(Typedef)) {} + +NativeTypeTypedef::~NativeTypeTypedef() {} + +void NativeTypeTypedef::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); +} + +std::string NativeTypeTypedef::getName() const { return Record.Name; } + +SymIndexId NativeTypeTypedef::getTypeId() const { + return Session.getSymbolCache().findSymbolByTypeIndex(Record.Type); +} diff --git a/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp b/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp new file mode 100644 index 0000000000000..3abf91dcc6a38 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp @@ -0,0 +1,221 @@ +//===- NativeTypeUDT.cpp - info about class/struct type ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h" + +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" + +#include <cassert> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, codeview::ClassRecord CR) + : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI), + Class(std::move(CR)), Tag(Class.getPointer()) {} + +NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, codeview::UnionRecord UR) + : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI), + Union(std::move(UR)), Tag(Union.getPointer()) {} + +NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, + NativeTypeUDT &UnmodifiedType, + codeview::ModifierRecord Modifier) + : NativeRawSymbol(Session, PDB_SymType::UDT, Id), + UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {} + +NativeTypeUDT::~NativeTypeUDT() {} + +void NativeTypeUDT::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + if (Modifiers.hasValue()) + dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent, + Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields, + RecurseIdFields); + if (getUdtKind() != PDB_UdtType::Union) + dumpSymbolField(OS, "virtualTableShapeId", getVirtualTableShapeId(), + Indent); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "udtKind", getUdtKind(), Indent); + dumpSymbolField(OS, "constructor", hasConstructor(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent); + dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent); + dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent); + dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent); + dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent); + dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent); + dumpSymbolField(OS, "nested", isNested(), Indent); + dumpSymbolField(OS, "packed", isPacked(), Indent); + dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent); + dumpSymbolField(OS, "scoped", isScoped(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +std::string NativeTypeUDT::getName() const { + if (UnmodifiedType) + return UnmodifiedType->getName(); + + return Tag->getName(); +} + +SymIndexId NativeTypeUDT::getLexicalParentId() const { return 0; } + +SymIndexId NativeTypeUDT::getUnmodifiedTypeId() const { + if (UnmodifiedType) + return UnmodifiedType->getSymIndexId(); + + return 0; +} + +SymIndexId NativeTypeUDT::getVirtualTableShapeId() const { + if (UnmodifiedType) + return UnmodifiedType->getVirtualTableShapeId(); + + if (Class) + return Session.getSymbolCache().findSymbolByTypeIndex(Class->VTableShape); + + return 0; +} + +uint64_t NativeTypeUDT::getLength() const { + if (UnmodifiedType) + return UnmodifiedType->getLength(); + + if (Class) + return Class->getSize(); + + return Union->getSize(); +} + +PDB_UdtType NativeTypeUDT::getUdtKind() const { + if (UnmodifiedType) + return UnmodifiedType->getUdtKind(); + + switch (Tag->Kind) { + case TypeRecordKind::Class: + return PDB_UdtType::Class; + case TypeRecordKind::Union: + return PDB_UdtType::Union; + case TypeRecordKind::Struct: + return PDB_UdtType::Struct; + case TypeRecordKind::Interface: + return PDB_UdtType::Interface; + default: + llvm_unreachable("Unexected udt kind"); + } +} + +bool NativeTypeUDT::hasConstructor() const { + if (UnmodifiedType) + return UnmodifiedType->hasConstructor(); + + return (Tag->Options & ClassOptions::HasConstructorOrDestructor) != + ClassOptions::None; +} + +bool NativeTypeUDT::isConstType() const { + if (!Modifiers) + return false; + return (Modifiers->Modifiers & ModifierOptions::Const) != + ModifierOptions::None; +} + +bool NativeTypeUDT::hasAssignmentOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasAssignmentOperator(); + + return (Tag->Options & ClassOptions::HasOverloadedAssignmentOperator) != + ClassOptions::None; +} + +bool NativeTypeUDT::hasCastOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasCastOperator(); + + return (Tag->Options & ClassOptions::HasConversionOperator) != + ClassOptions::None; +} + +bool NativeTypeUDT::hasNestedTypes() const { + if (UnmodifiedType) + return UnmodifiedType->hasNestedTypes(); + + return (Tag->Options & ClassOptions::ContainsNestedClass) != + ClassOptions::None; +} + +bool NativeTypeUDT::hasOverloadedOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasOverloadedOperator(); + + return (Tag->Options & ClassOptions::HasOverloadedOperator) != + ClassOptions::None; +} + +bool NativeTypeUDT::isInterfaceUdt() const { return false; } + +bool NativeTypeUDT::isIntrinsic() const { + if (UnmodifiedType) + return UnmodifiedType->isIntrinsic(); + + return (Tag->Options & ClassOptions::Intrinsic) != ClassOptions::None; +} + +bool NativeTypeUDT::isNested() const { + if (UnmodifiedType) + return UnmodifiedType->isNested(); + + return (Tag->Options & ClassOptions::Nested) != ClassOptions::None; +} + +bool NativeTypeUDT::isPacked() const { + if (UnmodifiedType) + return UnmodifiedType->isPacked(); + + return (Tag->Options & ClassOptions::Packed) != ClassOptions::None; +} + +bool NativeTypeUDT::isRefUdt() const { return false; } + +bool NativeTypeUDT::isScoped() const { + if (UnmodifiedType) + return UnmodifiedType->isScoped(); + + return (Tag->Options & ClassOptions::Scoped) != ClassOptions::None; +} + +bool NativeTypeUDT::isValueUdt() const { return false; } + +bool NativeTypeUDT::isUnalignedType() const { + if (!Modifiers) + return false; + return (Modifiers->Modifiers & ModifierOptions::Unaligned) != + ModifierOptions::None; +} + +bool NativeTypeUDT::isVolatileType() const { + if (!Modifiers) + return false; + return (Modifiers->Modifiers & ModifierOptions::Volatile) != + ModifierOptions::None; +} diff --git a/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp b/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp new file mode 100644 index 0000000000000..837fe19ec88c0 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp @@ -0,0 +1,35 @@ +#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h" + +using namespace llvm; +using namespace llvm::pdb; + +// Create a pointer record for a non-simple type. +NativeTypeVTShape::NativeTypeVTShape(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, + codeview::VFTableShapeRecord SR) + : NativeRawSymbol(Session, PDB_SymType::VTableShape, Id), TI(TI), + Record(std::move(SR)) {} + +NativeTypeVTShape::~NativeTypeVTShape() {} + +void NativeTypeVTShape::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "count", getCount(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +bool NativeTypeVTShape::isConstType() const { return false; } + +bool NativeTypeVTShape::isVolatileType() const { return false; } + +bool NativeTypeVTShape::isUnalignedType() const { return false; } + +uint32_t NativeTypeVTShape::getCount() const { return Record.Slots.size(); } diff --git a/lib/DebugInfo/PDB/Native/PDBFile.cpp b/lib/DebugInfo/PDB/Native/PDBFile.cpp index 78b11937f051d..a1f8786ff12fb 100644 --- a/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -125,7 +125,7 @@ Error PDBFile::parseFileHeaders() { if (auto EC = Reader.readObject(SB)) { consumeError(std::move(EC)); return make_error<RawError>(raw_error_code::corrupt_file, - "Does not contain superblock"); + "MSF superblock is missing"); } if (auto EC = msf::validateSuperBlock(*SB)) @@ -401,7 +401,9 @@ uint32_t PDBFile::getPointerSize() { return 4; } -bool PDBFile::hasPDBDbiStream() const { return StreamDBI < getNumStreams(); } +bool PDBFile::hasPDBDbiStream() const { + return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0; +} bool PDBFile::hasPDBGlobalsStream() { auto DbiS = getPDBDbiStream(); diff --git a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp index e164e7cf1c52b..e0ceb7499ee53 100644 --- a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -12,7 +12,6 @@ #include "llvm/ADT/BitVector.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" @@ -26,6 +25,7 @@ #include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/JamCRC.h" #include "llvm/Support/Path.h" +#include "llvm/Support/xxhash.h" using namespace llvm; using namespace llvm::codeview; @@ -262,13 +262,14 @@ void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer, } } -Error PDBFileBuilder::commit(StringRef Filename) { +Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) { assert(!Filename.empty()); if (auto EC = finalizeMsfLayout()) return EC; MSFLayout Layout; - auto ExpectedMsfBuffer = Msf->commit(Filename, Layout); + Expected<FileBufferByteStream> ExpectedMsfBuffer = + Msf->commit(Filename, Layout); if (!ExpectedMsfBuffer) return ExpectedMsfBuffer.takeError(); FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer); @@ -330,11 +331,28 @@ Error PDBFileBuilder::commit(StringRef Filename) { // Set the build id at the very end, after every other byte of the PDB // has been written. - // FIXME: Use a hash of the PDB rather than time(nullptr) for the signature. - H->Age = Info->getAge(); - H->Guid = Info->getGuid(); - Optional<uint32_t> Sig = Info->getSignature(); - H->Signature = Sig.hasValue() ? *Sig : time(nullptr); + if (Info->hashPDBContentsToGUID()) { + // Compute a hash of all sections of the output file. + uint64_t Digest = + xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()}); + + H->Age = 1; + + memcpy(H->Guid.Guid, &Digest, 8); + // xxhash only gives us 8 bytes, so put some fixed data in the other half. + memcpy(H->Guid.Guid + 8, "LLD PDB.", 8); + + // Put the hash in the Signature field too. + H->Signature = static_cast<uint32_t>(Digest); + + // Return GUID to caller. + memcpy(Guid, H->Guid.Guid, 16); + } else { + H->Age = Info->getAge(); + H->Guid = Info->getGuid(); + Optional<uint32_t> Sig = Info->getSignature(); + H->Signature = Sig.hasValue() ? *Sig : time(nullptr); + } return Buffer.commit(); } diff --git a/lib/DebugInfo/PDB/Native/RawError.cpp b/lib/DebugInfo/PDB/Native/RawError.cpp index 548289fff3dfe..dec9797088f23 100644 --- a/lib/DebugInfo/PDB/Native/RawError.cpp +++ b/lib/DebugInfo/PDB/Native/RawError.cpp @@ -5,14 +5,12 @@ using namespace llvm; using namespace llvm::pdb; -namespace { // FIXME: This class is only here to support the transition to llvm::Error. It // will be removed once this transition is complete. Clients should prefer to // deal with the Error value directly, rather than converting to error_code. class RawErrorCategory : public std::error_category { public: const char *name() const noexcept override { return "llvm.pdb.raw"; } - std::string message(int Condition) const override { switch (static_cast<raw_error_code>(Condition)) { case raw_error_code::unspecified: @@ -46,30 +44,8 @@ public: llvm_unreachable("Unrecognized raw_error_code"); } }; -} // end anonymous namespace - -static ManagedStatic<RawErrorCategory> Category; - -char RawError::ID = 0; - -RawError::RawError(raw_error_code C) : RawError(C, "") {} - -RawError::RawError(const std::string &Context) - : RawError(raw_error_code::unspecified, Context) {} - -RawError::RawError(raw_error_code C, const std::string &Context) : Code(C) { - ErrMsg = "Native PDB Error: "; - std::error_code EC = convertToErrorCode(); - if (Code != raw_error_code::unspecified) - ErrMsg += EC.message() + " "; - if (!Context.empty()) - ErrMsg += Context; -} - -void RawError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } -const std::string &RawError::getErrorMessage() const { return ErrMsg; } +static llvm::ManagedStatic<RawErrorCategory> RawCategory; +const std::error_category &llvm::pdb::RawErrCategory() { return *RawCategory; } -std::error_code RawError::convertToErrorCode() const { - return std::error_code(static_cast<int>(Code), *Category); -} +char RawError::ID; diff --git a/lib/DebugInfo/PDB/Native/SymbolCache.cpp b/lib/DebugInfo/PDB/Native/SymbolCache.cpp new file mode 100644 index 0000000000000..5cdd628312fe5 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/SymbolCache.cpp @@ -0,0 +1,299 @@ +#include "llvm/DebugInfo/PDB/Native/SymbolCache.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/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h" +#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/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +// Maps codeview::SimpleTypeKind of a built-in type to the parameters necessary +// to instantiate a NativeBuiltinSymbol for that type. +static const struct BuiltinTypeEntry { + codeview::SimpleTypeKind Kind; + PDB_BuiltinType Type; + uint32_t Size; +} BuiltinTypes[] = { + {codeview::SimpleTypeKind::None, PDB_BuiltinType::None, 0}, + {codeview::SimpleTypeKind::Void, PDB_BuiltinType::Void, 0}, + {codeview::SimpleTypeKind::HResult, PDB_BuiltinType::HResult, 4}, + {codeview::SimpleTypeKind::Int16Short, PDB_BuiltinType::Int, 2}, + {codeview::SimpleTypeKind::UInt16Short, PDB_BuiltinType::UInt, 2}, + {codeview::SimpleTypeKind::Int32, PDB_BuiltinType::Int, 4}, + {codeview::SimpleTypeKind::UInt32, PDB_BuiltinType::UInt, 4}, + {codeview::SimpleTypeKind::Int32Long, PDB_BuiltinType::Int, 4}, + {codeview::SimpleTypeKind::UInt32Long, PDB_BuiltinType::UInt, 4}, + {codeview::SimpleTypeKind::Int64Quad, PDB_BuiltinType::Int, 8}, + {codeview::SimpleTypeKind::UInt64Quad, PDB_BuiltinType::UInt, 8}, + {codeview::SimpleTypeKind::NarrowCharacter, PDB_BuiltinType::Char, 1}, + {codeview::SimpleTypeKind::WideCharacter, PDB_BuiltinType::WCharT, 2}, + {codeview::SimpleTypeKind::Character16, PDB_BuiltinType::Char16, 2}, + {codeview::SimpleTypeKind::Character32, PDB_BuiltinType::Char32, 4}, + {codeview::SimpleTypeKind::SignedCharacter, PDB_BuiltinType::Char, 1}, + {codeview::SimpleTypeKind::UnsignedCharacter, PDB_BuiltinType::UInt, 1}, + {codeview::SimpleTypeKind::Float32, PDB_BuiltinType::Float, 4}, + {codeview::SimpleTypeKind::Float64, PDB_BuiltinType::Float, 8}, + {codeview::SimpleTypeKind::Float80, PDB_BuiltinType::Float, 10}, + {codeview::SimpleTypeKind::Boolean8, PDB_BuiltinType::Bool, 1}, + // This table can be grown as necessary, but these are the only types we've + // needed so far. +}; + +SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi) + : Session(Session), Dbi(Dbi) { + // Id 0 is reserved for the invalid symbol. + Cache.push_back(nullptr); + + if (Dbi) + Compilands.resize(Dbi->modules().getModuleCount()); +} + +std::unique_ptr<IPDBEnumSymbols> +SymbolCache::createTypeEnumerator(TypeLeafKind Kind) { + return createTypeEnumerator(std::vector<TypeLeafKind>{Kind}); +} + +std::unique_ptr<IPDBEnumSymbols> +SymbolCache::createTypeEnumerator(std::vector<TypeLeafKind> Kinds) { + auto Tpi = Session.getPDBFile().getPDBTpiStream(); + if (!Tpi) { + consumeError(Tpi.takeError()); + return nullptr; + } + auto &Types = Tpi->typeCollection(); + return std::unique_ptr<IPDBEnumSymbols>( + new NativeEnumTypes(Session, Types, std::move(Kinds))); +} + +std::unique_ptr<IPDBEnumSymbols> +SymbolCache::createGlobalsEnumerator(codeview::SymbolKind Kind) { + return std::unique_ptr<IPDBEnumSymbols>( + new NativeEnumGlobals(Session, {Kind})); +} + +SymIndexId SymbolCache::createSimpleType(TypeIndex Index, + ModifierOptions Mods) { + if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct) + return createSymbol<NativeTypePointer>(Index); + + const auto Kind = Index.getSimpleKind(); + const auto It = std::find_if( + std::begin(BuiltinTypes), std::end(BuiltinTypes), + [Kind](const BuiltinTypeEntry &Builtin) { return Builtin.Kind == Kind; }); + if (It == std::end(BuiltinTypes)) + return 0; + return createSymbol<NativeTypeBuiltin>(Mods, It->Type, It->Size); +} + +SymIndexId +SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI, + codeview::CVType CVT) { + ModifierRecord Record; + if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) { + consumeError(std::move(EC)); + return 0; + } + + if (Record.ModifiedType.isSimple()) + return createSimpleType(Record.ModifiedType, Record.Modifiers); + + // Make sure we create and cache a record for the unmodified type. + SymIndexId UnmodifiedId = findSymbolByTypeIndex(Record.ModifiedType); + NativeRawSymbol &UnmodifiedNRS = *Cache[UnmodifiedId]; + + switch (UnmodifiedNRS.getSymTag()) { + case PDB_SymType::Enum: + return createSymbol<NativeTypeEnum>( + static_cast<NativeTypeEnum &>(UnmodifiedNRS), std::move(Record)); + case PDB_SymType::UDT: + return createSymbol<NativeTypeUDT>( + static_cast<NativeTypeUDT &>(UnmodifiedNRS), std::move(Record)); + default: + // No other types can be modified. (LF_POINTER, for example, records + // its modifiers a different way. + assert(false && "Invalid LF_MODIFIER record"); + break; + } + return 0; +} + +SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) { + // First see if it's already in our cache. + const auto Entry = TypeIndexToSymbolId.find(Index); + if (Entry != TypeIndexToSymbolId.end()) + return Entry->second; + + // Symbols for built-in types are created on the fly. + if (Index.isSimple()) { + SymIndexId Result = createSimpleType(Index, ModifierOptions::None); + assert(TypeIndexToSymbolId.count(Index) == 0); + TypeIndexToSymbolId[Index] = Result; + return Result; + } + + // We need to instantiate and cache the desired type symbol. + auto Tpi = Session.getPDBFile().getPDBTpiStream(); + if (!Tpi) { + consumeError(Tpi.takeError()); + return 0; + } + codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection(); + codeview::CVType CVT = Types.getType(Index); + + if (isUdtForwardRef(CVT)) { + Expected<TypeIndex> EFD = Tpi->findFullDeclForForwardRef(Index); + + if (!EFD) + consumeError(EFD.takeError()); + else if (*EFD != Index) { + assert(!isUdtForwardRef(Types.getType(*EFD))); + SymIndexId Result = findSymbolByTypeIndex(*EFD); + // Record a mapping from ForwardRef -> SymIndex of complete type so that + // we'll take the fast path next time. + assert(TypeIndexToSymbolId.count(Index) == 0); + TypeIndexToSymbolId[Index] = Result; + return Result; + } + } + + // At this point if we still have a forward ref udt it means the full decl was + // not in the PDB. We just have to deal with it and use the forward ref. + SymIndexId Id = 0; + switch (CVT.kind()) { + case codeview::LF_ENUM: + Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT)); + break; + case codeview::LF_ARRAY: + Id = createSymbolForType<NativeTypeArray, ArrayRecord>(Index, + std::move(CVT)); + break; + case codeview::LF_CLASS: + case codeview::LF_STRUCTURE: + case codeview::LF_INTERFACE: + Id = createSymbolForType<NativeTypeUDT, ClassRecord>(Index, std::move(CVT)); + break; + case codeview::LF_UNION: + Id = createSymbolForType<NativeTypeUDT, UnionRecord>(Index, std::move(CVT)); + break; + case codeview::LF_POINTER: + Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index, + std::move(CVT)); + break; + case codeview::LF_MODIFIER: + Id = createSymbolForModifiedType(Index, std::move(CVT)); + break; + case codeview::LF_PROCEDURE: + Id = createSymbolForType<NativeTypeFunctionSig, ProcedureRecord>( + Index, std::move(CVT)); + break; + case codeview::LF_MFUNCTION: + Id = createSymbolForType<NativeTypeFunctionSig, MemberFunctionRecord>( + Index, std::move(CVT)); + break; + case codeview::LF_VTSHAPE: + Id = createSymbolForType<NativeTypeVTShape, VFTableShapeRecord>( + Index, std::move(CVT)); + break; + default: + Id = createSymbolPlaceholder(); + break; + } + if (Id != 0) { + assert(TypeIndexToSymbolId.count(Index) == 0); + TypeIndexToSymbolId[Index] = Id; + } + return Id; +} + +std::unique_ptr<PDBSymbol> +SymbolCache::getSymbolById(SymIndexId SymbolId) const { + assert(SymbolId < Cache.size()); + + // Id 0 is reserved. + if (SymbolId == 0 || SymbolId >= Cache.size()) + return nullptr; + + // Make sure to handle the case where we've inserted a placeholder symbol + // for types we don't yet suppport. + NativeRawSymbol *NRS = Cache[SymbolId].get(); + if (!NRS) + return nullptr; + + return PDBSymbol::create(Session, *NRS); +} + +NativeRawSymbol &SymbolCache::getNativeSymbolById(SymIndexId SymbolId) const { + return *Cache[SymbolId]; +} + +uint32_t SymbolCache::getNumCompilands() const { + if (!Dbi) + return 0; + + return Dbi->modules().getModuleCount(); +} + +SymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) { + auto Iter = GlobalOffsetToSymbolId.find(Offset); + if (Iter != GlobalOffsetToSymbolId.end()) + return Iter->second; + + SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream()); + CVSymbol CVS = SS.readRecord(Offset); + SymIndexId Id = 0; + switch (CVS.kind()) { + case SymbolKind::S_UDT: { + UDTSym US = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(CVS)); + Id = createSymbol<NativeTypeTypedef>(std::move(US)); + break; + } + default: + Id = createSymbolPlaceholder(); + break; + } + if (Id != 0) { + assert(GlobalOffsetToSymbolId.count(Offset) == 0); + GlobalOffsetToSymbolId[Offset] = Id; + } + + return Id; +} + +std::unique_ptr<PDBSymbolCompiland> +SymbolCache::getOrCreateCompiland(uint32_t Index) { + if (!Dbi) + return nullptr; + + if (Index >= Compilands.size()) + return nullptr; + + if (Compilands[Index] == 0) { + const DbiModuleList &Modules = Dbi->modules(); + Compilands[Index] = + createSymbol<NativeCompilandSymbol>(Modules.getModuleDescriptor(Index)); + } + + return Session.getConcreteSymbolById<PDBSymbolCompiland>(Compilands[Index]); +} diff --git a/lib/DebugInfo/PDB/Native/TpiHashing.cpp b/lib/DebugInfo/PDB/Native/TpiHashing.cpp index 77a2d57a83698..18708826ffc78 100644 --- a/lib/DebugInfo/PDB/Native/TpiHashing.cpp +++ b/lib/DebugInfo/PDB/Native/TpiHashing.cpp @@ -50,6 +50,32 @@ static Expected<uint32_t> getHashForUdt(const CVType &Rec) { } template <typename T> +static Expected<TagRecordHash> getTagRecordHashForUdt(const CVType &Rec) { + T Deserialized; + if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), + Deserialized)) + return std::move(E); + + ClassOptions Opts = Deserialized.getOptions(); + + bool ForwardRef = bool(Opts & ClassOptions::ForwardReference); + + uint32_t ThisRecordHash = getHashForUdt(Deserialized, Rec.data()); + + // If we don't have a forward ref we can't compute the hash of it from the + // full record because it requires hashing the entire buffer. + if (!ForwardRef) + return TagRecordHash{std::move(Deserialized), ThisRecordHash, 0}; + + bool Scoped = bool(Opts & ClassOptions::Scoped); + + StringRef NameToHash = + Scoped ? Deserialized.getUniqueName() : Deserialized.getName(); + uint32_t FullHash = hashStringV1(NameToHash); + return TagRecordHash{std::move(Deserialized), FullHash, ThisRecordHash}; +} + +template <typename T> static Expected<uint32_t> getSourceLineHash(const CVType &Rec) { T Deserialized; if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), @@ -60,6 +86,23 @@ static Expected<uint32_t> getSourceLineHash(const CVType &Rec) { return hashStringV1(StringRef(Buf, 4)); } +Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) { + switch (Type.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: + return getTagRecordHashForUdt<ClassRecord>(Type); + case LF_UNION: + return getTagRecordHashForUdt<UnionRecord>(Type); + case LF_ENUM: + return getTagRecordHashForUdt<EnumRecord>(Type); + default: + assert(false && "Type is not a tag record!"); + } + return make_error<StringError>("Invalid record type", + inconvertibleErrorCode()); +} + Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) { switch (Rec.kind()) { case LF_CLASS: diff --git a/lib/DebugInfo/PDB/Native/TpiStream.cpp b/lib/DebugInfo/PDB/Native/TpiStream.cpp index 0680b673380a6..f234d446e6a09 100644 --- a/lib/DebugInfo/PDB/Native/TpiStream.cpp +++ b/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -11,8 +11,11 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/RecordName.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" @@ -140,6 +143,88 @@ uint16_t TpiStream::getTypeHashStreamAuxIndex() const { uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; } uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; } +void TpiStream::buildHashMap() { + if (!HashMap.empty()) + return; + if (HashValues.empty()) + return; + + HashMap.resize(Header->NumHashBuckets); + + TypeIndex TIB{Header->TypeIndexBegin}; + TypeIndex TIE{Header->TypeIndexEnd}; + while (TIB < TIE) { + uint32_t HV = HashValues[TIB.toArrayIndex()]; + HashMap[HV].push_back(TIB++); + } +} + +std::vector<TypeIndex> TpiStream::findRecordsByName(StringRef Name) const { + if (!supportsTypeLookup()) + const_cast<TpiStream*>(this)->buildHashMap(); + + uint32_t Bucket = hashStringV1(Name) % Header->NumHashBuckets; + if (Bucket > HashMap.size()) + return {}; + + std::vector<TypeIndex> Result; + for (TypeIndex TI : HashMap[Bucket]) { + std::string ThisName = computeTypeName(*Types, TI); + if (ThisName == Name) + Result.push_back(TI); + } + return Result; +} + +bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); } + +Expected<TypeIndex> +TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const { + if (!supportsTypeLookup()) + const_cast<TpiStream*>(this)->buildHashMap(); + + CVType F = Types->getType(ForwardRefTI); + if (!isUdtForwardRef(F)) + return ForwardRefTI; + + Expected<TagRecordHash> ForwardTRH = hashTagRecord(F); + if (!ForwardTRH) + return ForwardTRH.takeError(); + + uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets; + + for (TypeIndex TI : HashMap[BucketIdx]) { + CVType CVT = Types->getType(TI); + if (CVT.kind() != F.kind()) + continue; + + Expected<TagRecordHash> FullTRH = hashTagRecord(CVT); + if (!FullTRH) + return FullTRH.takeError(); + if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash) + continue; + TagRecord &ForwardTR = ForwardTRH->getRecord(); + TagRecord &FullTR = FullTRH->getRecord(); + + if (!ForwardTR.hasUniqueName()) { + if (ForwardTR.getName() == FullTR.getName()) + return TI; + continue; + } + + if (!FullTR.hasUniqueName()) + continue; + if (ForwardTR.getUniqueName() == FullTR.getUniqueName()) + return TI; + } + return ForwardRefTI; +} + +codeview::CVType TpiStream::getType(codeview::TypeIndex Index) { + assert(!Index.isSimple()); + return Types->getType(Index); +} + BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const { return TypeRecordsSubstream; } |
