Index: lld/trunk/COFF/PDB.cpp =================================================================== --- lld/trunk/COFF/PDB.cpp +++ lld/trunk/COFF/PDB.cpp @@ -30,13 +30,13 @@ #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.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/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" -#include "llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/TpiHashing.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" @@ -641,14 +641,10 @@ [](const PublicSym32 &L, const PublicSym32 &R) { return L.Name < R.Name; }); - auto &PublicsBuilder = Builder.getPublicsBuilder(); + auto &GsiBuilder = Builder.getGsiBuilder(); for (const PublicSym32 &Pub : Publics) - PublicsBuilder.addPublicSymbol(Pub); + GsiBuilder.addPublicSymbol(Pub); } - // Add globals stream. For now we don't actually write any thing useful to - // the globals stream, but the act of "getting" it also creates it lazily so - // that we write an empty stream. - (void)Builder.getGlobalsBuilder(); } static void addLinkerModuleSymbols(StringRef Path, Index: lld/trunk/test/COFF/pdb-diff.test =================================================================== --- lld/trunk/test/COFF/pdb-diff.test +++ lld/trunk/test/COFF/pdb-diff.test @@ -55,10 +55,10 @@ CHECK-NEXT: |------------------------------+---| CHECK-NEXT: | Public Symbol Hash | {{[EI]}} | CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Public Symbol Records | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| CHECK-NEXT: | Global Symbol Hash | {{[EI]}} | CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Public Symbol Records | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| CHECK-NEXT: ------------------------------------ CHECK-NEXT: | String Table | CHECK-NEXT: |------------------------------+---| Index: llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h @@ -46,6 +46,12 @@ return EC; return Error::success(); } + template static Expected deserializeAs(CVSymbol Symbol) { + T Record(Symbol.kind()); + if (auto EC = deserializeAs(Symbol, Record)) + return std::move(EC); + return Record; + } explicit SymbolDeserializer(SymbolVisitorDelegate *Delegate, CodeViewContainer Container) Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h @@ -0,0 +1,76 @@ +//===- GSIStreamBuilder.h - PDB Publics/Globals Stream Creation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_GSISTREAMBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_GSISTREAMBUILDER_H + +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryItemStream.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { + +template <> struct BinaryItemTraits { + static size_t length(const codeview::CVSymbol &Item) { + return Item.RecordData.size(); + } + static ArrayRef bytes(const codeview::CVSymbol &Item) { + return Item.RecordData; + } +}; + +namespace msf { +class MSFBuilder; +struct MSFLayout; +} // namespace msf +namespace pdb { +struct GSIHashStreamBuilder; + +class GSIStreamBuilder { + +public: + explicit GSIStreamBuilder(msf::MSFBuilder &Msf); + ~GSIStreamBuilder(); + + GSIStreamBuilder(const GSIStreamBuilder &) = delete; + GSIStreamBuilder &operator=(const GSIStreamBuilder &) = delete; + + Error finalizeMsfLayout(); + + Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer); + + uint32_t getPublicsStreamIndex() const; + uint32_t getGlobalsStreamIndex() const; + uint32_t getRecordStreamIdx() const { return RecordStreamIdx; } + + void addPublicSymbol(const codeview::PublicSym32 &Pub); + +private: + uint32_t calculatePublicsHashStreamSize() const; + uint32_t calculateGlobalsHashStreamSize() const; + Error commitSymbolRecordStream(WritableBinaryStreamRef Stream); + Error commitPublicsHashStream(WritableBinaryStreamRef Stream); + Error commitGlobalsHashStream(WritableBinaryStreamRef Stream); + + uint32_t RecordStreamIdx = kInvalidStreamIndex; + std::unique_ptr PSH; + std::unique_ptr GSH; + msf::MSFBuilder &Msf; +}; +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/GlobalsStreamBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/GlobalsStreamBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/GlobalsStreamBuilder.h @@ -1,50 +0,0 @@ -//===- GlobalsStreamBuilder.h - PDB Globals Stream Creation -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBGLOBALSTREAMBUILDER_H -#define LLVM_DEBUGINFO_PDB_RAW_PDBGLOBALSTREAMBUILDER_H - -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/BinaryStreamRef.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" - -namespace llvm { -namespace msf { -class MSFBuilder; -} -namespace pdb { -class GlobalsStream; - -class GlobalsStreamBuilder { -public: - explicit GlobalsStreamBuilder(msf::MSFBuilder &Msf); - ~GlobalsStreamBuilder(); - - GlobalsStreamBuilder(const GlobalsStreamBuilder &) = delete; - GlobalsStreamBuilder &operator=(const GlobalsStreamBuilder &) = delete; - - Error finalizeMsfLayout(); - uint32_t calculateSerializedLength() const; - - Error commit(BinaryStreamWriter &PublicsWriter); - - uint32_t getStreamIndex() const { return StreamIdx; } - -private: - uint32_t StreamIdx = kInvalidStreamIndex; - msf::MSFBuilder &Msf; -}; -} // namespace pdb -} // namespace llvm - -#endif Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h @@ -31,8 +31,7 @@ namespace pdb { class DbiStreamBuilder; class InfoStreamBuilder; -class PublicsStreamBuilder; -class GlobalsStreamBuilder; +class GSIStreamBuilder; class TpiStreamBuilder; class PDBFileBuilder { @@ -50,8 +49,7 @@ TpiStreamBuilder &getTpiBuilder(); TpiStreamBuilder &getIpiBuilder(); PDBStringTableBuilder &getStringTableBuilder(); - PublicsStreamBuilder &getPublicsBuilder(); - GlobalsStreamBuilder &getGlobalsBuilder(); + GSIStreamBuilder &getGsiBuilder(); Error commit(StringRef Filename); @@ -68,8 +66,7 @@ std::unique_ptr Msf; std::unique_ptr Info; std::unique_ptr Dbi; - std::unique_ptr Globals; - std::unique_ptr Publics; + std::unique_ptr Gsi; std::unique_ptr Tpi; std::unique_ptr Ipi; Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h @@ -1,79 +0,0 @@ -//===- PublicsStreamBuilder.h - PDB Publics Stream Creation -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBPUBLICSTREAMBUILDER_H -#define LLVM_DEBUGINFO_PDB_RAW_PDBPUBLICSTREAMBUILDER_H - -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/BinaryItemStream.h" -#include "llvm/Support/BinaryStreamRef.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" - -namespace llvm { - -template <> struct BinaryItemTraits { - static size_t length(const codeview::CVSymbol &Item) { - return Item.RecordData.size(); - } - static ArrayRef bytes(const codeview::CVSymbol &Item) { - return Item.RecordData; - } -}; - -namespace msf { -class MSFBuilder; -} -namespace pdb { -class PublicsStream; -struct PublicsStreamHeader; - -struct GSIHashTableBuilder { - void addSymbols(ArrayRef Symbols); - - std::vector HashRecords; - std::array HashBitmap; - std::vector HashBuckets; -}; - -class PublicsStreamBuilder { -public: - explicit PublicsStreamBuilder(msf::MSFBuilder &Msf); - ~PublicsStreamBuilder(); - - PublicsStreamBuilder(const PublicsStreamBuilder &) = delete; - PublicsStreamBuilder &operator=(const PublicsStreamBuilder &) = delete; - - Error finalizeMsfLayout(); - uint32_t calculateSerializedLength() const; - - Error commit(BinaryStreamWriter &PublicsWriter, - BinaryStreamWriter &RecWriter); - - uint32_t getStreamIndex() const { return StreamIdx; } - uint32_t getRecordStreamIdx() const { return RecordStreamIdx; } - - void addPublicSymbol(const codeview::PublicSym32 &Pub); - -private: - uint32_t StreamIdx = kInvalidStreamIndex; - uint32_t RecordStreamIdx = kInvalidStreamIndex; - std::unique_ptr Table; - std::vector Publics; - msf::MSFBuilder &Msf; -}; -} // namespace pdb -} // namespace llvm - -#endif Index: llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt +++ llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt @@ -35,7 +35,6 @@ Native/DbiStreamBuilder.cpp Native/EnumTables.cpp Native/GlobalsStream.cpp - Native/GlobalsStreamBuilder.cpp Native/Hash.cpp Native/HashTable.cpp Native/InfoStream.cpp @@ -55,7 +54,7 @@ Native/PDBStringTable.cpp Native/PDBStringTableBuilder.cpp Native/PublicsStream.cpp - Native/PublicsStreamBuilder.cpp + Native/GSIStreamBuilder.cpp Native/RawError.cpp Native/SymbolStream.cpp Native/TpiHashing.cpp Index: llvm/trunk/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -16,7 +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/PublicsStreamBuilder.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" Index: llvm/trunk/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp @@ -0,0 +1,312 @@ +//===- 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/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 +#include + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::pdb; +using namespace llvm::codeview; + +static StringRef getSymbolName(const CVSymbol &Sym) { + assert(Sym.kind() == S_PUB32 && "handle other kinds"); + PublicSym32 PSL = + cantFail(SymbolDeserializer::deserializeAs(Sym)); + return PSL.Name; +} + +struct llvm::pdb::GSIHashStreamBuilder { + std::vector Records; + uint32_t StreamIndex; + std::vector HashRecords; + std::array HashBitmap; + std::vector HashBuckets; + + uint32_t calculateSerializedLength() const; + uint32_t calculateRecordByteSize() const; + Error commit(BinaryStreamWriter &Writer); + void finalizeBuckets(uint32_t RecordZeroOffset); +}; + +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, 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()), + GSH(llvm::make_unique()) {} + +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 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(); +} + +bool comparePubSymByAddrAndName(const CVSymbol *LS, const CVSymbol *RS) { + assert(LS->kind() == SymbolKind::S_PUB32); + assert(RS->kind() == SymbolKind::S_PUB32); + + PublicSym32 PSL = + cantFail(SymbolDeserializer::deserializeAs(*LS)); + PublicSym32 PSR = + cantFail(SymbolDeserializer::deserializeAs(*RS)); + + if (PSL.Segment != PSR.Segment) + return PSL.Segment < PSR.Segment; + if (PSL.Offset != PSR.Offset) + return PSL.Offset < PSR.Offset; + + return PSL.Name < PSR.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 computeAddrMap(ArrayRef 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 PublicsByAddr; + std::vector SymOffsets; + PublicsByAddr.reserve(Records.size()); + uint32_t SymOffset = 0; + for (const CVSymbol &Sym : Records) { + PublicsByAddr.push_back(&Sym); + 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 AddrMap; + AddrMap.reserve(Records.size()); + for (const CVSymbol *Sym : PublicsByAddr) { + ptrdiff_t Idx = std::distance(Records.data(), Sym); + 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) { + PublicSym32 Copy(Pub); + PSH->Records.push_back(SymbolSerializer::writeOneSymbol( + Copy, Msf.getAllocator(), CodeViewContainer::Pdb)); +} + +static Error writeRecords(BinaryStreamWriter &Writer, + ArrayRef Records) { + BinaryItemStream 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) { + // Skip the publics stream header so that we can write the GSH header first. + // Then seek back to the beginning and update the publics stream header with + // the byte offset after the GSH header. + BinaryStreamWriter Writer(Stream); + Writer.setOffset(sizeof(PublicsStreamHeader)); + + if (auto EC = PSH->commit(Writer)) + return EC; + uint32_t OffsetAfterGSIHashes = Writer.getOffset(); + + Writer.setOffset(0); + + // FIXME: Fill these in. They are for incremental linking. + PublicsStreamHeader Header; + Header.AddrMap = PSH->Records.size() * 4; + + Header.NumThunks = 0; + Header.SizeOfThunk = 0; + Header.ISectThunkTable = 0; + Header.OffThunkTable = 0; + Header.NumSections = 0; + Header.SymHash = OffsetAfterGSIHashes; + if (auto EC = Writer.writeObject(Header)) + return EC; + + Writer.setOffset(OffsetAfterGSIHashes); + + std::vector 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(); +} Index: llvm/trunk/lib/DebugInfo/PDB/Native/GlobalsStreamBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/GlobalsStreamBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/GlobalsStreamBuilder.cpp @@ -1,79 +0,0 @@ -//===- GlobalsStreamBuilder.cpp - PDB Globals 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/GlobalsStreamBuilder.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" - -using namespace llvm; -using namespace llvm::msf; -using namespace llvm::pdb; - -GlobalsStreamBuilder::GlobalsStreamBuilder(msf::MSFBuilder &Msf) : Msf(Msf) {} - -GlobalsStreamBuilder::~GlobalsStreamBuilder() {} - -uint32_t GlobalsStreamBuilder::calculateSerializedLength() const { - uint32_t Size = 0; - // First is the header - Size += sizeof(GSIHashHeader); - - // Next is the records. For now we don't write any records, just an empty - // stream. - // FIXME: Write records and account for their size here. - Size += 0; - - // Next is a bitmap indicating which hash buckets are valid. The bitmap - // is alway present, but we only write buckets for bitmap entries which are - // non-zero, which now is noting. - 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 GlobalsStreamBuilder::finalizeMsfLayout() { - Expected Idx = Msf.addStream(calculateSerializedLength()); - if (!Idx) - return Idx.takeError(); - StreamIdx = *Idx; - return Error::success(); -} - -Error GlobalsStreamBuilder::commit(BinaryStreamWriter &PublicsWriter) { - GSIHashHeader GSH; - - GSH.VerSignature = GSIHashHeader::HdrSignature; - GSH.VerHdr = GSIHashHeader::HdrVersion; - GSH.HrSize = 0; - GSH.NumBuckets = 0; - - if (auto EC = PublicsWriter.writeObject(GSH)) - return EC; - - // FIXME: Once we start writing a value other than 0 for GSH.HrSize, we need - // to write the hash records here. - size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); - uint32_t NumBitmapEntries = BitmapSizeInBits / 8; - std::vector BitmapData(NumBitmapEntries); - // FIXME: Build an actual bitmap - if (auto EC = PublicsWriter.writeBytes(makeArrayRef(BitmapData))) - return EC; - - // FIXME: Write actual hash buckets. - return Error::success(); -} Index: llvm/trunk/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -15,11 +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/GlobalsStreamBuilder.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" @@ -75,16 +74,10 @@ return Strings; } -PublicsStreamBuilder &PDBFileBuilder::getPublicsBuilder() { - if (!Publics) - Publics = llvm::make_unique(*Msf); - return *Publics; -} - -GlobalsStreamBuilder &PDBFileBuilder::getGlobalsBuilder() { - if (!Globals) - Globals = llvm::make_unique(*Msf); - return *Globals; +GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() { + if (!Gsi) + Gsi = llvm::make_unique(*Msf); + return *Gsi; } Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) { @@ -129,22 +122,16 @@ 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()); } } - if (Globals) { - if (auto EC = Globals->finalizeMsfLayout()) - return std::move(EC); - if (Dbi) - Dbi->setGlobalsStreamIndex(Globals->getStreamIndex()); - } - return Msf->build(); } @@ -251,22 +238,8 @@ return EC; } - if (Publics) { - auto PS = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, Publics->getStreamIndex(), Allocator); - auto PRS = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, Publics->getRecordStreamIdx(), Allocator); - BinaryStreamWriter PSWriter(*PS); - BinaryStreamWriter RecWriter(*PRS); - if (auto EC = Publics->commit(PSWriter, RecWriter)) - return EC; - } - - if (Globals) { - auto GS = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, Globals->getStreamIndex(), Allocator); - BinaryStreamWriter GSWriter(*GS); - if (auto EC = Globals->commit(GSWriter)) + if (Gsi) { + if (auto EC = Gsi->commit(Layout, Buffer)) return EC; } Index: llvm/trunk/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp @@ -1,222 +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/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 -#include - -using namespace llvm; -using namespace llvm::msf; -using namespace llvm::pdb; -using namespace llvm::codeview; - -PublicsStreamBuilder::PublicsStreamBuilder(msf::MSFBuilder &Msf) - : Table(new GSIHashTableBuilder), Msf(Msf) {} - -PublicsStreamBuilder::~PublicsStreamBuilder() {} - -uint32_t PublicsStreamBuilder::calculateSerializedLength() const { - uint32_t Size = 0; - Size += sizeof(PublicsStreamHeader); - Size += sizeof(GSIHashHeader); - Size += Table->HashRecords.size() * sizeof(PSHashRecord); - Size += Table->HashBitmap.size() * sizeof(uint32_t); - Size += Table->HashBuckets.size() * sizeof(uint32_t); - - Size += Publics.size() * sizeof(uint32_t); // AddrMap - - // FIXME: Add thunk map and section offsets for incremental linking. - - return Size; -} - -Error PublicsStreamBuilder::finalizeMsfLayout() { - Table->addSymbols(Publics); - - Expected Idx = Msf.addStream(calculateSerializedLength()); - if (!Idx) - return Idx.takeError(); - StreamIdx = *Idx; - - uint32_t PublicRecordBytes = 0; - for (auto &Pub : Publics) - PublicRecordBytes += Pub.length(); - - Expected RecordIdx = Msf.addStream(PublicRecordBytes); - if (!RecordIdx) - return RecordIdx.takeError(); - RecordStreamIdx = *RecordIdx; - return Error::success(); -} - -void PublicsStreamBuilder::addPublicSymbol(const PublicSym32 &Pub) { - Publics.push_back(SymbolSerializer::writeOneSymbol( - const_cast(Pub), Msf.getAllocator(), - CodeViewContainer::Pdb)); -} - -// FIXME: Put this back in the header. -struct PubSymLayout { - ulittle16_t reclen; - ulittle16_t reckind; - ulittle32_t flags; - ulittle32_t off; - ulittle16_t seg; - char name[1]; -}; - -bool comparePubSymByAddrAndName(const CVSymbol *LS, const CVSymbol *RS) { - assert(LS->length() > sizeof(PubSymLayout) && - RS->length() > sizeof(PubSymLayout)); - auto *L = reinterpret_cast(LS->data().data()); - auto *R = reinterpret_cast(RS->data().data()); - if (L->seg < R->seg) - return true; - if (L->seg > R->seg) - return false; - if (L->off < R->off) - return true; - if (L->off > R->off) - return false; - return strcmp(L->name, R->name) < 0; -} - -static StringRef getSymbolName(const CVSymbol &Sym) { - assert(Sym.kind() == S_PUB32 && "handle other kinds"); - ArrayRef NameBytes = - Sym.data().drop_front(offsetof(PubSymLayout, name)); - return StringRef(reinterpret_cast(NameBytes.data()), - NameBytes.size()) - .trim('\0'); -} - -/// 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 computeAddrMap(ArrayRef Publics) { - // 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 PublicsByAddr; - std::vector SymOffsets; - PublicsByAddr.reserve(Publics.size()); - uint32_t SymOffset = 0; - for (const CVSymbol &Sym : Publics) { - PublicsByAddr.push_back(&Sym); - 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 AddrMap; - AddrMap.reserve(Publics.size()); - for (const CVSymbol *Sym : PublicsByAddr) { - ptrdiff_t Idx = std::distance(Publics.data(), Sym); - assert(Idx >= 0 && size_t(Idx) < Publics.size()); - AddrMap.push_back(ulittle32_t(SymOffsets[Idx])); - } - return AddrMap; -} - -Error PublicsStreamBuilder::commit(BinaryStreamWriter &PublicsWriter, - BinaryStreamWriter &RecWriter) { - assert(Table->HashRecords.size() == Publics.size()); - - PublicsStreamHeader PSH; - GSIHashHeader GSH; - - PSH.AddrMap = Publics.size() * 4; - - // FIXME: Fill these in. They are for incremental linking. - PSH.NumThunks = 0; - PSH.SizeOfThunk = 0; - PSH.ISectThunkTable = 0; - PSH.OffThunkTable = 0; - PSH.NumSections = 0; - - GSH.VerSignature = GSIHashHeader::HdrSignature; - GSH.VerHdr = GSIHashHeader::HdrVersion; - GSH.HrSize = Table->HashRecords.size() * sizeof(PSHashRecord); - GSH.NumBuckets = Table->HashBitmap.size() * 4 + Table->HashBuckets.size() * 4; - - PSH.SymHash = sizeof(GSH) + GSH.HrSize + GSH.NumBuckets; - - if (auto EC = PublicsWriter.writeObject(PSH)) - return EC; - if (auto EC = PublicsWriter.writeObject(GSH)) - return EC; - - if (auto EC = PublicsWriter.writeArray(makeArrayRef(Table->HashRecords))) - return EC; - if (auto EC = PublicsWriter.writeArray(makeArrayRef(Table->HashBitmap))) - return EC; - if (auto EC = PublicsWriter.writeArray(makeArrayRef(Table->HashBuckets))) - return EC; - - std::vector AddrMap = computeAddrMap(Publics); - if (auto EC = PublicsWriter.writeArray(makeArrayRef(AddrMap))) - return EC; - - BinaryItemStream Records(support::endianness::little); - Records.setItems(Publics); - BinaryStreamRef RecordsRef(Records); - if (auto EC = RecWriter.writeStreamRef(RecordsRef)) - return EC; - - return Error::success(); -} - -void GSIHashTableBuilder::addSymbols(ArrayRef Symbols) { - std::array, IPHR_HASH + 1> TmpBuckets; - uint32_t SymOffset = 0; - for (const CVSymbol &Sym : Symbols) { - 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(Symbols.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); - } -}