diff options
Diffstat (limited to 'lib/DebugInfo/PDB/Native')
22 files changed, 731 insertions, 395 deletions
diff --git a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index 897f78c51032..d765485bdb6d 100644 --- a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -16,6 +16,7 @@ #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#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" @@ -26,16 +27,6 @@ using namespace llvm::codeview; using namespace llvm::msf; using namespace llvm::pdb; -namespace llvm { -template <> struct BinaryItemTraits<CVSymbol> { - static size_t length(const CVSymbol &Item) { return Item.RecordData.size(); } - - static ArrayRef<uint8_t> bytes(const CVSymbol &Item) { - return Item.RecordData; - } -}; -} - static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize, uint32_t C13Size) { uint32_t Size = sizeof(uint32_t); // Signature @@ -98,14 +89,6 @@ uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const { return alignTo(L + M + O, sizeof(uint32_t)); } -template <typename T> struct Foo { - explicit Foo(T &&Answer) : Answer(Answer) {} - - T Answer; -}; - -template <typename T> Foo<T> makeFoo(T &&t) { return Foo<T>(std::move(t)); } - void DbiModuleDescriptorBuilder::finalize() { Layout.SC.ModuleIndex = Layout.Mod; Layout.FileNameOffs = 0; // TODO: Fix this diff --git a/lib/DebugInfo/PDB/Native/DbiStream.cpp b/lib/DebugInfo/PDB/Native/DbiStream.cpp index 0eeac7e4c084..04e6664c68db 100644 --- a/lib/DebugInfo/PDB/Native/DbiStream.cpp +++ b/lib/DebugInfo/PDB/Native/DbiStream.cpp @@ -12,7 +12,6 @@ #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" diff --git a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp index 25076e40fc98..c96553ff9b16 100644 --- a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -49,6 +49,10 @@ void DbiStreamBuilder::setSectionMap(ArrayRef<SecMapEntry> SecMap) { SectionMap = SecMap; } +void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) { + GlobalsStreamIndex = Index; +} + void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) { SymRecordStreamIndex = Index; } @@ -86,24 +90,9 @@ uint32_t DbiStreamBuilder::calculateSerializedLength() const { Expected<DbiModuleDescriptorBuilder &> DbiStreamBuilder::addModuleInfo(StringRef ModuleName) { uint32_t Index = ModiList.size(); - auto MIB = - llvm::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf); - auto M = MIB.get(); - auto Result = ModiMap.insert(std::make_pair(ModuleName, std::move(MIB))); - - if (!Result.second) - return make_error<RawError>(raw_error_code::duplicate_entry, - "The specified module already exists"); - ModiList.push_back(M); - return *M; -} - -Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) { - auto ModIter = ModiMap.find(Module); - if (ModIter == ModiMap.end()) - return make_error<RawError>(raw_error_code::no_entry, - "The specified module was not found"); - return addModuleSourceFile(*ModIter->second, File); + ModiList.push_back( + llvm::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf)); + return *ModiList.back(); } Error DbiStreamBuilder::addModuleSourceFile(DbiModuleDescriptorBuilder &Module, @@ -270,7 +259,7 @@ Error DbiStreamBuilder::finalize() { H->SymRecordStreamIndex = SymRecordStreamIndex; H->PublicSymbolStreamIndex = PublicsStreamIndex; H->MFCTypeServerIndex = kInvalidStreamIndex; - H->GlobalSymbolStreamIndex = kInvalidStreamIndex; + H->GlobalSymbolStreamIndex = GlobalsStreamIndex; Header = H; return Error::success(); @@ -307,19 +296,6 @@ static uint16_t toSecMapFlags(uint32_t Flags) { return Ret; } -void DbiStreamBuilder::addSectionContrib(DbiModuleDescriptorBuilder *ModuleDbi, - const object::coff_section *SecHdr) { - SectionContrib SC; - memset(&SC, 0, sizeof(SC)); - SC.ISect = (uint16_t)~0U; // This represents nil. - SC.Off = SecHdr->PointerToRawData; - SC.Size = SecHdr->SizeOfRawData; - SC.Characteristics = SecHdr->Characteristics; - // Use the module index in the module dbi stream or nil (-1). - SC.Imod = ModuleDbi ? ModuleDbi->getModuleIndex() : (uint16_t)~0U; - SectionContribs.emplace_back(SC); -} - // A utility function to create a Section Map for a given list of COFF sections. // // A Section Map seem to be a copy of a COFF section list in other format. diff --git a/lib/DebugInfo/PDB/Native/GSI.cpp b/lib/DebugInfo/PDB/Native/GSI.cpp deleted file mode 100644 index b219fe275f73..000000000000 --- a/lib/DebugInfo/PDB/Native/GSI.cpp +++ /dev/null @@ -1,93 +0,0 @@ -//===- GSI.cpp - Common Functions for GlobalsStream and PublicsStream ----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "GSI.h" - -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryStreamArray.h" -#include "llvm/Support/BinaryStreamReader.h" - -#include "llvm/Support/Error.h" - -namespace llvm { -namespace pdb { - -static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) { - if (HashHdr->VerHdr != GSIHashHeader::HdrVersion) - return make_error<RawError>( - raw_error_code::feature_unsupported, - "Encountered unsupported globals stream version."); - - return Error::success(); -} - -Error readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets, - const GSIHashHeader *HashHdr, - BinaryStreamReader &Reader) { - if (auto EC = checkHashHdrVersion(HashHdr)) - return EC; - - // Before the actual hash buckets, there is a bitmap of length determined by - // IPHR_HASH. - ArrayRef<uint8_t> Bitmap; - size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); - uint32_t NumBitmapEntries = BitmapSizeInBits / 8; - if (auto EC = Reader.readBytes(Bitmap, NumBitmapEntries)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Could not read a bitmap.")); - uint32_t NumBuckets = 0; - for (uint8_t B : Bitmap) - NumBuckets += countPopulation(B); - - // Hash buckets follow. - if (auto EC = Reader.readArray(HashBuckets, NumBuckets)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Hash buckets corrupted.")); - - return Error::success(); -} - -Error readGSIHashHeader(const GSIHashHeader *&HashHdr, - BinaryStreamReader &Reader) { - if (Reader.readObject(HashHdr)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Stream does not contain a GSIHashHeader."); - - if (HashHdr->VerSignature != GSIHashHeader::HdrSignature) - return make_error<RawError>( - raw_error_code::feature_unsupported, - "GSIHashHeader signature (0xffffffff) not found."); - - return Error::success(); -} - -Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords, - const GSIHashHeader *HashHdr, - BinaryStreamReader &Reader) { - if (auto EC = checkHashHdrVersion(HashHdr)) - return EC; - - // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have. - // Verify that we can read them all. - if (HashHdr->HrSize % sizeof(PSHashRecord)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid HR array size."); - uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord); - if (auto EC = Reader.readArray(HashRecords, NumHashRecords)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Error reading hash records.")); - - return Error::success(); -} -} -} diff --git a/lib/DebugInfo/PDB/Native/GSI.h b/lib/DebugInfo/PDB/Native/GSI.h deleted file mode 100644 index 9e63bc83548f..000000000000 --- a/lib/DebugInfo/PDB/Native/GSI.h +++ /dev/null @@ -1,68 +0,0 @@ -//===- GSI.h - Common Declarations for GlobalsStream and PublicsStream ----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// The data structures defined in this file are based on the reference -// implementation which is available at -// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h -// -// When you are reading the reference source code, you'd find the -// information below useful. -// -// - ppdb1->m_fMinimalDbgInfo seems to be always true. -// - SMALLBUCKETS macro is defined. -// -// The reference doesn't compile, so I learned just by reading code. -// It's not guaranteed to be correct. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_DEBUGINFO_PDB_RAW_GSI_H -#define LLVM_LIB_DEBUGINFO_PDB_RAW_GSI_H - -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryStreamArray.h" - -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" - -namespace llvm { - -class BinaryStreamReader; - -namespace pdb { - -/// From https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.cpp -static const unsigned IPHR_HASH = 4096; - -/// Header of the hash tables found in the globals and publics sections. -/// Based on GSIHashHeader in -/// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h -struct GSIHashHeader { - enum : unsigned { - HdrSignature = ~0U, - HdrVersion = 0xeffe0000 + 19990810, - }; - support::ulittle32_t VerSignature; - support::ulittle32_t VerHdr; - support::ulittle32_t HrSize; - support::ulittle32_t NumBuckets; -}; - -Error readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets, - const GSIHashHeader *HashHdr, - BinaryStreamReader &Reader); -Error readGSIHashHeader(const GSIHashHeader *&HashHdr, - BinaryStreamReader &Reader); -Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords, - const GSIHashHeader *HashHdr, - BinaryStreamReader &Reader); -} -} - -#endif diff --git a/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp new file mode 100644 index 000000000000..e84f25dfeefa --- /dev/null +++ b/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp @@ -0,0 +1,322 @@ +//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- 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/GSIStreamBuilder.h" + +#include "llvm/DebugInfo/CodeView/RecordName.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolSerializer.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/Support/BinaryItemStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include <algorithm> +#include <vector> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::pdb; +using namespace llvm::codeview; + +struct llvm::pdb::GSIHashStreamBuilder { + std::vector<CVSymbol> Records; + uint32_t StreamIndex; + std::vector<PSHashRecord> HashRecords; + std::array<support::ulittle32_t, (IPHR_HASH + 32) / 32> HashBitmap; + std::vector<support::ulittle32_t> HashBuckets; + + uint32_t calculateSerializedLength() const; + uint32_t calculateRecordByteSize() const; + Error commit(BinaryStreamWriter &Writer); + void finalizeBuckets(uint32_t RecordZeroOffset); + + template <typename T> void addSymbol(const T &Symbol, MSFBuilder &Msf) { + T Copy(Symbol); + Records.push_back(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(), + CodeViewContainer::Pdb)); + } + void addSymbol(const CVSymbol &Symbol) { Records.push_back(Symbol); } +}; + +uint32_t GSIHashStreamBuilder::calculateSerializedLength() const { + uint32_t Size = sizeof(GSIHashHeader); + Size += HashRecords.size() * sizeof(PSHashRecord); + Size += HashBitmap.size() * sizeof(uint32_t); + Size += HashBuckets.size() * sizeof(uint32_t); + return Size; +} + +uint32_t GSIHashStreamBuilder::calculateRecordByteSize() const { + uint32_t Size = 0; + for (const auto &Sym : Records) + Size += Sym.length(); + return Size; +} + +Error GSIHashStreamBuilder::commit(BinaryStreamWriter &Writer) { + GSIHashHeader Header; + Header.VerSignature = GSIHashHeader::HdrSignature; + Header.VerHdr = GSIHashHeader::HdrVersion; + Header.HrSize = HashRecords.size() * sizeof(PSHashRecord); + Header.NumBuckets = HashBitmap.size() * 4 + HashBuckets.size() * 4; + + if (auto EC = Writer.writeObject(Header)) + return EC; + + if (auto EC = Writer.writeArray(makeArrayRef(HashRecords))) + return EC; + if (auto EC = Writer.writeArray(makeArrayRef(HashBitmap))) + return EC; + if (auto EC = Writer.writeArray(makeArrayRef(HashBuckets))) + return EC; + return Error::success(); +} + +void GSIHashStreamBuilder::finalizeBuckets(uint32_t RecordZeroOffset) { + std::array<std::vector<PSHashRecord>, IPHR_HASH + 1> TmpBuckets; + uint32_t SymOffset = RecordZeroOffset; + for (const CVSymbol &Sym : Records) { + PSHashRecord HR; + // Add one when writing symbol offsets to disk. See GSI1::fixSymRecs. + HR.Off = SymOffset + 1; + HR.CRef = 1; // Always use a refcount of 1. + + // Hash the name to figure out which bucket this goes into. + StringRef Name = getSymbolName(Sym); + size_t BucketIdx = hashStringV1(Name) % IPHR_HASH; + TmpBuckets[BucketIdx].push_back(HR); // FIXME: Does order matter? + + SymOffset += Sym.length(); + } + + // Compute the three tables: the hash records in bucket and chain order, the + // bucket presence bitmap, and the bucket chain start offsets. + HashRecords.reserve(Records.size()); + for (ulittle32_t &Word : HashBitmap) + Word = 0; + for (size_t BucketIdx = 0; BucketIdx < IPHR_HASH + 1; ++BucketIdx) { + auto &Bucket = TmpBuckets[BucketIdx]; + if (Bucket.empty()) + continue; + HashBitmap[BucketIdx / 32] |= 1U << (BucketIdx % 32); + + // Calculate what the offset of the first hash record in the chain would + // be if it were inflated to contain 32-bit pointers. On a 32-bit system, + // each record would be 12 bytes. See HROffsetCalc in gsi.h. + const int SizeOfHROffsetCalc = 12; + ulittle32_t ChainStartOff = + ulittle32_t(HashRecords.size() * SizeOfHROffsetCalc); + HashBuckets.push_back(ChainStartOff); + for (const auto &HR : Bucket) + HashRecords.push_back(HR); + } +} + +GSIStreamBuilder::GSIStreamBuilder(msf::MSFBuilder &Msf) + : Msf(Msf), PSH(llvm::make_unique<GSIHashStreamBuilder>()), + GSH(llvm::make_unique<GSIHashStreamBuilder>()) {} + +GSIStreamBuilder::~GSIStreamBuilder() {} + +uint32_t GSIStreamBuilder::calculatePublicsHashStreamSize() const { + uint32_t Size = 0; + Size += sizeof(PublicsStreamHeader); + Size += PSH->calculateSerializedLength(); + Size += PSH->Records.size() * sizeof(uint32_t); // AddrMap + // FIXME: Add thunk map and section offsets for incremental linking. + + return Size; +} + +uint32_t GSIStreamBuilder::calculateGlobalsHashStreamSize() const { + return GSH->calculateSerializedLength(); +} + +Error GSIStreamBuilder::finalizeMsfLayout() { + // First we write public symbol records, then we write global symbol records. + uint32_t PSHZero = 0; + uint32_t GSHZero = PSH->calculateRecordByteSize(); + + PSH->finalizeBuckets(PSHZero); + GSH->finalizeBuckets(GSHZero); + + Expected<uint32_t> Idx = Msf.addStream(calculatePublicsHashStreamSize()); + if (!Idx) + return Idx.takeError(); + PSH->StreamIndex = *Idx; + Idx = Msf.addStream(calculateGlobalsHashStreamSize()); + if (!Idx) + return Idx.takeError(); + GSH->StreamIndex = *Idx; + + uint32_t RecordBytes = + GSH->calculateRecordByteSize() + PSH->calculateRecordByteSize(); + + Idx = Msf.addStream(RecordBytes); + if (!Idx) + return Idx.takeError(); + RecordStreamIdx = *Idx; + return Error::success(); +} + +static bool comparePubSymByAddrAndName( + const std::pair<const CVSymbol *, const PublicSym32 *> &LS, + const std::pair<const CVSymbol *, const PublicSym32 *> &RS) { + if (LS.second->Segment != RS.second->Segment) + return LS.second->Segment < RS.second->Segment; + if (LS.second->Offset != RS.second->Offset) + return LS.second->Offset < RS.second->Offset; + + return LS.second->Name < RS.second->Name; +} + +/// Compute the address map. The address map is an array of symbol offsets +/// sorted so that it can be binary searched by address. +static std::vector<ulittle32_t> computeAddrMap(ArrayRef<CVSymbol> Records) { + // Make a vector of pointers to the symbols so we can sort it by address. + // Also gather the symbol offsets while we're at it. + + std::vector<PublicSym32> DeserializedPublics; + std::vector<std::pair<const CVSymbol *, const PublicSym32 *>> PublicsByAddr; + std::vector<uint32_t> SymOffsets; + DeserializedPublics.reserve(Records.size()); + PublicsByAddr.reserve(Records.size()); + SymOffsets.reserve(Records.size()); + + uint32_t SymOffset = 0; + for (const CVSymbol &Sym : Records) { + assert(Sym.kind() == SymbolKind::S_PUB32); + DeserializedPublics.push_back( + cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym))); + PublicsByAddr.emplace_back(&Sym, &DeserializedPublics.back()); + SymOffsets.push_back(SymOffset); + SymOffset += Sym.length(); + } + std::stable_sort(PublicsByAddr.begin(), PublicsByAddr.end(), + comparePubSymByAddrAndName); + + // Fill in the symbol offsets in the appropriate order. + std::vector<ulittle32_t> AddrMap; + AddrMap.reserve(Records.size()); + for (auto &Sym : PublicsByAddr) { + ptrdiff_t Idx = std::distance(Records.data(), Sym.first); + assert(Idx >= 0 && size_t(Idx) < Records.size()); + AddrMap.push_back(ulittle32_t(SymOffsets[Idx])); + } + return AddrMap; +} + +uint32_t GSIStreamBuilder::getPublicsStreamIndex() const { + return PSH->StreamIndex; +} + +uint32_t GSIStreamBuilder::getGlobalsStreamIndex() const { + return GSH->StreamIndex; +} + +void GSIStreamBuilder::addPublicSymbol(const PublicSym32 &Pub) { + PSH->addSymbol(Pub, Msf); +} + +void GSIStreamBuilder::addGlobalSymbol(const ProcRefSym &Sym) { + GSH->addSymbol(Sym, Msf); +} + +void GSIStreamBuilder::addGlobalSymbol(const DataSym &Sym) { + GSH->addSymbol(Sym, Msf); +} + +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); +} + +static Error writeRecords(BinaryStreamWriter &Writer, + ArrayRef<CVSymbol> Records) { + BinaryItemStream<CVSymbol> ItemStream(support::endianness::little); + ItemStream.setItems(Records); + BinaryStreamRef RecordsRef(ItemStream); + return Writer.writeStreamRef(RecordsRef); +} + +Error GSIStreamBuilder::commitSymbolRecordStream( + WritableBinaryStreamRef Stream) { + BinaryStreamWriter Writer(Stream); + + // Write public symbol records first, followed by global symbol records. This + // must match the order that we assume in finalizeMsfLayout when computing + // PSHZero and GSHZero. + if (auto EC = writeRecords(Writer, PSH->Records)) + return EC; + if (auto EC = writeRecords(Writer, GSH->Records)) + return EC; + + return Error::success(); +} + +Error GSIStreamBuilder::commitPublicsHashStream( + WritableBinaryStreamRef Stream) { + BinaryStreamWriter Writer(Stream); + PublicsStreamHeader Header; + + // FIXME: Fill these in. They are for incremental linking. + Header.NumThunks = 0; + Header.SizeOfThunk = 0; + Header.ISectThunkTable = 0; + Header.OffThunkTable = 0; + Header.NumSections = 0; + Header.SymHash = PSH->calculateSerializedLength(); + Header.AddrMap = PSH->Records.size() * 4; + if (auto EC = Writer.writeObject(Header)) + return EC; + + if (auto EC = PSH->commit(Writer)) + return EC; + + std::vector<ulittle32_t> AddrMap = computeAddrMap(PSH->Records); + if (auto EC = Writer.writeArray(makeArrayRef(AddrMap))) + return EC; + + return Error::success(); +} + +Error GSIStreamBuilder::commitGlobalsHashStream( + WritableBinaryStreamRef Stream) { + BinaryStreamWriter Writer(Stream); + return GSH->commit(Writer); +} + +Error GSIStreamBuilder::commit(const msf::MSFLayout &Layout, + WritableBinaryStreamRef Buffer) { + auto GS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, getGlobalsStreamIndex(), Msf.getAllocator()); + auto PS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, getPublicsStreamIndex(), Msf.getAllocator()); + auto PRS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, getRecordStreamIdx(), Msf.getAllocator()); + + if (auto EC = commitSymbolRecordStream(*PRS)) + return EC; + if (auto EC = commitGlobalsHashStream(*GS)) + return EC; + if (auto EC = commitPublicsHashStream(*PS)) + return EC; + return Error::success(); +} diff --git a/lib/DebugInfo/PDB/Native/GlobalsStream.cpp b/lib/DebugInfo/PDB/Native/GlobalsStream.cpp index a2ee0f047c58..36076f436ad0 100644 --- a/lib/DebugInfo/PDB/Native/GlobalsStream.cpp +++ b/lib/DebugInfo/PDB/Native/GlobalsStream.cpp @@ -1,4 +1,4 @@ -//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---- ----*- C++ -*-===// +//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,9 +6,21 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +// +// The on-disk structores used in this file are based on the reference +// implementation which is available at +// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h +// +// When you are reading the reference source code, you'd find the +// information below useful. +// +// - ppdb1->m_fMinimalDbgInfo seems to be always true. +// - SMALLBUCKETS macro is defined. +// +//===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" -#include "GSI.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" #include <algorithm> @@ -24,19 +36,89 @@ GlobalsStream::~GlobalsStream() = default; Error GlobalsStream::reload() { BinaryStreamReader Reader(*Stream); + if (auto E = GlobalsTable.read(Reader)) + return E; + return Error::success(); +} - const GSIHashHeader *HashHdr; - if (auto EC = readGSIHashHeader(HashHdr, Reader)) - return EC; +static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) { + if (HashHdr->VerHdr != GSIHashHeader::HdrVersion) + return make_error<RawError>( + raw_error_code::feature_unsupported, + "Encountered unsupported globals stream version."); - if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader)) + return Error::success(); +} + +static Error readGSIHashHeader(const GSIHashHeader *&HashHdr, + BinaryStreamReader &Reader) { + if (Reader.readObject(HashHdr)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Stream does not contain a GSIHashHeader."); + + if (HashHdr->VerSignature != GSIHashHeader::HdrSignature) + return make_error<RawError>( + raw_error_code::feature_unsupported, + "GSIHashHeader signature (0xffffffff) not found."); + + return Error::success(); +} + +static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords, + const GSIHashHeader *HashHdr, + BinaryStreamReader &Reader) { + if (auto EC = checkHashHdrVersion(HashHdr)) return EC; - if (auto EC = readGSIHashBuckets(HashBuckets, HashHdr, Reader)) + // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have. + // Verify that we can read them all. + if (HashHdr->HrSize % sizeof(PSHashRecord)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid HR array size."); + uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord); + if (auto EC = Reader.readArray(HashRecords, NumHashRecords)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Error reading hash records.")); + + return Error::success(); +} + +static Error +readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets, + ArrayRef<uint8_t> &HashBitmap, const GSIHashHeader *HashHdr, + BinaryStreamReader &Reader) { + if (auto EC = checkHashHdrVersion(HashHdr)) return EC; - NumBuckets = HashBuckets.size(); + + // 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)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read a bitmap.")); + uint32_t NumBuckets = 0; + for (uint8_t B : HashBitmap) + NumBuckets += countPopulation(B); + + // Hash buckets follow. + if (auto EC = Reader.readArray(HashBuckets, NumBuckets)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Hash buckets corrupted.")); return Error::success(); } -Error GlobalsStream::commit() { return Error::success(); } +Error GSIHashTable::read(BinaryStreamReader &Reader) { + if (auto EC = readGSIHashHeader(HashHdr, Reader)) + return EC; + if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader)) + return EC; + if (HashHdr->HrSize > 0) + if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, Reader)) + return EC; + return Error::success(); +} diff --git a/lib/DebugInfo/PDB/Native/InfoStream.cpp b/lib/DebugInfo/PDB/Native/InfoStream.cpp index 829879060c33..17c9392a9dd5 100644 --- a/lib/DebugInfo/PDB/Native/InfoStream.cpp +++ b/lib/DebugInfo/PDB/Native/InfoStream.cpp @@ -10,12 +10,10 @@ #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamWriter.h" using namespace llvm; using namespace llvm::codeview; diff --git a/lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp index 60416f69e137..4644ddcf24e3 100644 --- a/lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp +++ b/lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp @@ -9,7 +9,6 @@ #include "llvm/DebugInfo/PDB/Native/NativeBuiltinSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" namespace llvm { namespace pdb { diff --git a/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp new file mode 100644 index 000000000000..38d65917306a --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp @@ -0,0 +1,108 @@ +//===- 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 new file mode 100644 index 000000000000..36a68a1c62de --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp @@ -0,0 +1,59 @@ +//==- NativeEnumTypes.cpp - Native Type 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/NativeEnumTypes.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/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +namespace llvm { +namespace 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()); + } +} + +NativeEnumTypes::NativeEnumTypes( + NativeSession &PDBSession, const std::vector<codeview::TypeIndex> &Matches, + codeview::TypeLeafKind Kind) + : Matches(Matches), Index(0), Session(PDBSession), Kind(Kind) {} + +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]); + return nullptr; +} + +std::unique_ptr<PDBSymbol> NativeEnumTypes::getNext() { + return getChildAtIndex(Index++); +} + +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 3241000b06db..e8b06065fc60 100644 --- a/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp +++ b/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp @@ -38,6 +38,8 @@ NativeExeSymbol::findChildren(PDB_SymType Type) const { consumeError(Dbi.takeError()); break; } + case PDB_SymType::Enum: + return Session.createTypeEnumerator(codeview::LF_ENUM); default: break; } diff --git a/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp index df3f418052a9..d23ee0a09196 100644 --- a/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp +++ b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp @@ -286,6 +286,11 @@ std::string NativeRawSymbol::getUndecoratedName() const { return {}; } +std::string NativeRawSymbol::getUndecoratedNameEx( + PDB_UndnameFlags Flags) const { + return {}; +} + uint32_t NativeRawSymbol::getUnmodifiedTypeId() const { return 0; } diff --git a/lib/DebugInfo/PDB/Native/NativeSession.cpp b/lib/DebugInfo/PDB/Native/NativeSession.cpp index 76de0d8f9e7e..b01c2b54796c 100644 --- a/lib/DebugInfo/PDB/Native/NativeSession.cpp +++ b/lib/DebugInfo/PDB/Native/NativeSession.cpp @@ -16,11 +16,15 @@ #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/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Error.h" @@ -28,6 +32,7 @@ #include "llvm/Support/MemoryBuffer.h" #include <algorithm> +#include <cassert> #include <memory> #include <utility> @@ -63,15 +68,9 @@ NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile, NativeSession::~NativeSession() = default; -Error NativeSession::createFromPdb(StringRef Path, +Error NativeSession::createFromPdb(std::unique_ptr<MemoryBuffer> Buffer, std::unique_ptr<IPDBSession> &Session) { - ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = - MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, - /*RequiresNullTerminator=*/false); - if (!ErrorOrBuffer) - return make_error<GenericError>(generic_error_code::invalid_path); - - std::unique_ptr<MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); + StringRef Path = Buffer->getBufferIdentifier(); auto Stream = llvm::make_unique<MemoryBufferByteStream>( std::move(Buffer), llvm::support::little); @@ -102,6 +101,25 @@ NativeSession::createCompilandSymbol(DbiModuleDescriptor MI) { *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); @@ -129,9 +147,20 @@ SymIndexId NativeSession::findSymbolByTypeIndex(codeview::TypeIndex Index) { return Id; } - // TODO: Look up PDB type by type index - - return 0; + // 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; } @@ -216,3 +245,7 @@ NativeSession::getSourceFileById(uint32_t FileId) const { std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const { return nullptr; } + +std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const { + return nullptr; +} diff --git a/lib/DebugInfo/PDB/Native/PDBFile.cpp b/lib/DebugInfo/PDB/Native/PDBFile.cpp index 0b6492efc70f..15b31d821b1c 100644 --- a/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -85,6 +85,11 @@ uint32_t PDBFile::getNumStreams() const { return ContainerLayout.StreamSizes.size(); } +uint32_t PDBFile::getMaxStreamSize() const { + return *std::max_element(ContainerLayout.StreamSizes.begin(), + ContainerLayout.StreamSizes.end()); +} + uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const { return ContainerLayout.StreamSizes[StreamIndex]; } @@ -150,8 +155,7 @@ Error PDBFile::parseFileHeaders() { MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator); BinaryStreamReader FpmReader(*FpmStream); ArrayRef<uint8_t> FpmBytes; - if (auto EC = FpmReader.readBytes(FpmBytes, - msf::getFullFpmByteSize(ContainerLayout))) + if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining())) return EC; uint32_t BlocksRemaining = getBlockCount(); uint32_t BI = 0; @@ -230,6 +234,13 @@ ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const { return ContainerLayout.DirectoryBlocks; } +std::unique_ptr<MappedBlockStream> PDBFile::createIndexedStream(uint16_t SN) { + if (SN == kInvalidStreamIndex) + return nullptr; + return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN, + Allocator); +} + MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const { MSFStreamLayout Result; auto Blocks = getStreamBlockList(StreamIdx); @@ -238,6 +249,10 @@ MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const { return Result; } +msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const { + return msf::getFpmStreamLayout(ContainerLayout); +} + Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() { if (!Globals) { auto DbiS = getPDBDbiStream(); @@ -297,6 +312,9 @@ Expected<TpiStream &> PDBFile::getPDBTpiStream() { Expected<TpiStream &> PDBFile::getPDBIpiStream() { if (!Ipi) { + if (!hasPDBIpiStream()) + return make_error<RawError>(raw_error_code::no_stream); + auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI); if (!IpiS) return IpiS.takeError(); @@ -318,8 +336,7 @@ Expected<PublicsStream &> PDBFile::getPDBPublicsStream() { ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex()); if (!PublicS) return PublicS.takeError(); - auto TempPublics = - llvm::make_unique<PublicsStream>(*this, std::move(*PublicS)); + auto TempPublics = llvm::make_unique<PublicsStream>(std::move(*PublicS)); if (auto EC = TempPublics->reload()) return std::move(EC); Publics = std::move(TempPublics); @@ -393,9 +410,18 @@ bool PDBFile::hasPDBGlobalsStream() { return DbiS->getGlobalSymbolStreamIndex() < getNumStreams(); } -bool PDBFile::hasPDBInfoStream() { return StreamPDB < getNumStreams(); } +bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); } + +bool PDBFile::hasPDBIpiStream() const { + if (!hasPDBInfoStream()) + return false; + + if (StreamIPI >= getNumStreams()) + return false; -bool PDBFile::hasPDBIpiStream() const { return StreamIPI < getNumStreams(); } + auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream()); + return InfoStream.containsIdStream(); +} bool PDBFile::hasPDBPublicsStream() { auto DbiS = getPDBDbiStream(); diff --git a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp index 9f35fd73629c..dee27c621fac 100644 --- a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -15,10 +15,10 @@ #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" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" -#include "llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" @@ -74,10 +74,10 @@ PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() { return Strings; } -PublicsStreamBuilder &PDBFileBuilder::getPublicsBuilder() { - if (!Publics) - Publics = llvm::make_unique<PublicsStreamBuilder>(*Msf); - return *Publics; +GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() { + if (!Gsi) + Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf); + return *Gsi; } Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) { @@ -122,12 +122,13 @@ Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() { if (auto EC = Ipi->finalizeMsfLayout()) return std::move(EC); } - if (Publics) { - if (auto EC = Publics->finalizeMsfLayout()) + if (Gsi) { + if (auto EC = Gsi->finalizeMsfLayout()) return std::move(EC); if (Dbi) { - Dbi->setPublicsStreamIndex(Publics->getStreamIndex()); - Dbi->setSymbolRecordStreamIndex(Publics->getRecordStreamIdx()); + Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); + Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); + Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx()); } } @@ -141,6 +142,31 @@ Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { return SN; } +void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer, + const MSFLayout &Layout) { + auto FpmStream = + WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator); + + // We only need to create the alt fpm stream so that it gets initialized. + WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator, + true); + + uint32_t BI = 0; + BinaryStreamWriter FpmWriter(*FpmStream); + while (BI < Layout.SB->NumBlocks) { + uint8_t ThisByte = 0; + for (uint32_t I = 0; I < 8; ++I) { + bool IsFree = + (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true; + uint8_t Mask = uint8_t(IsFree) << I; + ThisByte |= Mask; + ++BI; + } + cantFail(FpmWriter.writeObject(ThisByte)); + } + assert(FpmWriter.bytesRemaining() == 0); +} + Error PDBFileBuilder::commit(StringRef Filename) { assert(!Filename.empty()); auto ExpectedLayout = finalizeMsfLayout(); @@ -150,15 +176,17 @@ Error PDBFileBuilder::commit(StringRef Filename) { uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks; auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize); - if (OutFileOrError.getError()) - return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path, - Filename); + if (auto E = OutFileOrError.takeError()) + return E; FileBufferByteStream Buffer(std::move(*OutFileOrError), llvm::support::little); BinaryStreamWriter Writer(Buffer); if (auto EC = Writer.writeObject(*Layout.SB)) return EC; + + commitFpm(Buffer, Layout); + uint32_t BlockMapOffset = msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); Writer.setOffset(BlockMapOffset); @@ -209,11 +237,8 @@ Error PDBFileBuilder::commit(StringRef Filename) { return EC; } - if (Publics) { - auto PS = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, Publics->getStreamIndex(), Allocator); - BinaryStreamWriter PSWriter(*PS); - if (auto EC = Publics->commit(PSWriter)) + if (Gsi) { + if (auto EC = Gsi->commit(Layout, Buffer)) return EC; } diff --git a/lib/DebugInfo/PDB/Native/PDBStringTable.cpp b/lib/DebugInfo/PDB/Native/PDBStringTable.cpp index acd45f7a6219..f1c10357132b 100644 --- a/lib/DebugInfo/PDB/Native/PDBStringTable.cpp +++ b/lib/DebugInfo/PDB/Native/PDBStringTable.cpp @@ -10,7 +10,6 @@ #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/Hash.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" diff --git a/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp b/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp index 90acfadd311f..ece3e00b1a87 100644 --- a/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp @@ -10,9 +10,7 @@ #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Endian.h" diff --git a/lib/DebugInfo/PDB/Native/PublicsStream.cpp b/lib/DebugInfo/PDB/Native/PublicsStream.cpp index 9c3e654f808b..f6466eb80464 100644 --- a/lib/DebugInfo/PDB/Native/PublicsStream.cpp +++ b/lib/DebugInfo/PDB/Native/PublicsStream.cpp @@ -23,13 +23,10 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Native/PublicsStream.h" -#include "GSI.h" #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -41,14 +38,18 @@ using namespace llvm::msf; using namespace llvm::support; using namespace llvm::pdb; -PublicsStream::PublicsStream(PDBFile &File, - std::unique_ptr<MappedBlockStream> Stream) - : Pdb(File), Stream(std::move(Stream)) {} +PublicsStream::PublicsStream(std::unique_ptr<MappedBlockStream> Stream) + : Stream(std::move(Stream)) {} PublicsStream::~PublicsStream() = default; uint32_t PublicsStream::getSymHash() const { return Header->SymHash; } -uint32_t PublicsStream::getAddrMap() const { return Header->AddrMap; } +uint16_t PublicsStream::getThunkTableSection() const { + return Header->ISectThunkTable; +} +uint32_t PublicsStream::getThunkTableOffset() const { + return Header->OffThunkTable; +} // Publics stream contains fixed-size headers and a serialized hash table. // This implementation is not complete yet. It reads till the end of the @@ -64,20 +65,14 @@ Error PublicsStream::reload() { return make_error<RawError>(raw_error_code::corrupt_file, "Publics Stream does not contain a header."); - // Read PSGSIHDR and GSIHashHdr structs. + // Read PSGSIHDR struct. if (Reader.readObject(Header)) return make_error<RawError>(raw_error_code::corrupt_file, "Publics Stream does not contain a header."); - if (auto EC = readGSIHashHeader(HashHdr, Reader)) - return EC; - - if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader)) - return EC; - - if (auto EC = readGSIHashBuckets(HashBuckets, HashHdr, Reader)) - return EC; - NumBuckets = HashBuckets.size(); + // Read the hash table. + if (auto E = PublicsTable.read(Reader)) + return E; // Something called "address map" follows. uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t); @@ -105,26 +100,3 @@ Error PublicsStream::reload() { "Corrupted publics stream."); return Error::success(); } - -iterator_range<codeview::CVSymbolArray::Iterator> -PublicsStream::getSymbols(bool *HadError) const { - auto SymbolS = Pdb.getPDBSymbolStream(); - if (SymbolS.takeError()) { - codeview::CVSymbolArray::Iterator Iter; - return make_range(Iter, Iter); - } - SymbolStream &SS = SymbolS.get(); - - return SS.getSymbols(HadError); -} - -Expected<const codeview::CVSymbolArray &> -PublicsStream::getSymbolArray() const { - auto SymbolS = Pdb.getPDBSymbolStream(); - if (!SymbolS) - return SymbolS.takeError(); - - return SymbolS->getSymbolArray(); -} - -Error PublicsStream::commit() { return Error::success(); } diff --git a/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp deleted file mode 100644 index 28c4a8fc35d9..000000000000 --- a/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp +++ /dev/null @@ -1,89 +0,0 @@ -//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- 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/PublicsStreamBuilder.h" - -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" - -#include "GSI.h" - -using namespace llvm; -using namespace llvm::msf; -using namespace llvm::pdb; - -PublicsStreamBuilder::PublicsStreamBuilder(msf::MSFBuilder &Msf) : Msf(Msf) {} - -PublicsStreamBuilder::~PublicsStreamBuilder() {} - -uint32_t PublicsStreamBuilder::calculateSerializedLength() const { - uint32_t Size = 0; - Size += sizeof(PublicsStreamHeader); - Size += sizeof(GSIHashHeader); - Size += HashRecords.size() * sizeof(PSHashRecord); - size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); - uint32_t NumBitmapEntries = BitmapSizeInBits / 8; - Size += NumBitmapEntries; - - // FIXME: Account for hash buckets. For now since we we write a zero-bitmap - // indicating that no hash buckets are valid, we also write zero byets of hash - // bucket data. - Size += 0; - return Size; -} - -Error PublicsStreamBuilder::finalizeMsfLayout() { - Expected<uint32_t> Idx = Msf.addStream(calculateSerializedLength()); - if (!Idx) - return Idx.takeError(); - StreamIdx = *Idx; - - Expected<uint32_t> RecordIdx = Msf.addStream(0); - if (!RecordIdx) - return RecordIdx.takeError(); - RecordStreamIdx = *RecordIdx; - return Error::success(); -} - -Error PublicsStreamBuilder::commit(BinaryStreamWriter &PublicsWriter) { - PublicsStreamHeader PSH; - GSIHashHeader GSH; - - // FIXME: Figure out what to put for these values. - PSH.AddrMap = 0; - PSH.ISectThunkTable = 0; - PSH.NumSections = 0; - PSH.NumThunks = 0; - PSH.OffThunkTable = 0; - PSH.SizeOfThunk = 0; - PSH.SymHash = 0; - - GSH.VerSignature = GSIHashHeader::HdrSignature; - GSH.VerHdr = GSIHashHeader::HdrVersion; - GSH.HrSize = 0; - GSH.NumBuckets = 0; - - if (auto EC = PublicsWriter.writeObject(PSH)) - return EC; - if (auto EC = PublicsWriter.writeObject(GSH)) - return EC; - if (auto EC = PublicsWriter.writeArray(makeArrayRef(HashRecords))) - return EC; - - size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); - uint32_t NumBitmapEntries = BitmapSizeInBits / 8; - std::vector<uint8_t> BitmapData(NumBitmapEntries); - // FIXME: Build an actual bitmap - if (auto EC = PublicsWriter.writeBytes(makeArrayRef(BitmapData))) - return EC; - - // FIXME: Write actual hash buckets. - return Error::success(); -} diff --git a/lib/DebugInfo/PDB/Native/SymbolStream.cpp b/lib/DebugInfo/PDB/Native/SymbolStream.cpp index 9e9ebd11495b..2d8d04ceca4d 100644 --- a/lib/DebugInfo/PDB/Native/SymbolStream.cpp +++ b/lib/DebugInfo/PDB/Native/SymbolStream.cpp @@ -10,11 +10,8 @@ #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" #include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" @@ -43,3 +40,7 @@ SymbolStream::getSymbols(bool *HadError) const { } Error SymbolStream::commit() { return Error::success(); } + +codeview::CVSymbol SymbolStream::readRecord(uint32_t Offset) const { + return *SymbolRecords.at(Offset); +} diff --git a/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp index 9e943c7f114d..8dd30018028e 100644 --- a/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp @@ -17,7 +17,6 @@ #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/BinaryStreamArray.h" |
