diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/DebugInfo/PDB/CMakeLists.txt | 3 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp | 312 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/PDB/Native/GlobalsStreamBuilder.cpp | 79 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp | 51 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp | 222 |
6 files changed, 326 insertions, 343 deletions
diff --git a/llvm/lib/DebugInfo/PDB/CMakeLists.txt b/llvm/lib/DebugInfo/PDB/CMakeLists.txt index 37eca01f81c..aad4bf31756 100644 --- a/llvm/lib/DebugInfo/PDB/CMakeLists.txt +++ b/llvm/lib/DebugInfo/PDB/CMakeLists.txt @@ -35,7 +35,6 @@ add_pdb_impl_folder(Native 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 @@ add_pdb_impl_folder(Native Native/PDBStringTable.cpp Native/PDBStringTableBuilder.cpp Native/PublicsStream.cpp - Native/PublicsStreamBuilder.cpp + Native/GSIStreamBuilder.cpp Native/RawError.cpp Native/SymbolStream.cpp Native/TpiHashing.cpp diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index 557dd4f041e..75542a255c7 100644 --- a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ b/llvm/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" diff --git a/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp new file mode 100644 index 00000000000..eb7a0bbcc3d --- /dev/null +++ b/llvm/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 <algorithm> +#include <vector> + +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<PublicSym32>(Sym)); + return PSL.Name; +} + +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); +}; + +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(); +} + +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<PublicSym32>(*LS)); + PublicSym32 PSR = + cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(*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<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<const CVSymbol *> PublicsByAddr; + std::vector<uint32_t> 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<ulittle32_t> 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<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) { + // 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<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/llvm/lib/DebugInfo/PDB/Native/GlobalsStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/GlobalsStreamBuilder.cpp deleted file mode 100644 index 004691e78e7..00000000000 --- a/llvm/lib/DebugInfo/PDB/Native/GlobalsStreamBuilder.cpp +++ /dev/null @@ -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<uint32_t> 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<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/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp index 09e86bf0c13..dd8e2ac8b53 100644 --- a/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ b/llvm/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 @@ PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() { return Strings; } -PublicsStreamBuilder &PDBFileBuilder::getPublicsBuilder() { - if (!Publics) - Publics = llvm::make_unique<PublicsStreamBuilder>(*Msf); - return *Publics; -} - -GlobalsStreamBuilder &PDBFileBuilder::getGlobalsBuilder() { - if (!Globals) - Globals = llvm::make_unique<GlobalsStreamBuilder>(*Msf); - return *Globals; +GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() { + if (!Gsi) + Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf); + return *Gsi; } Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) { @@ -129,22 +122,16 @@ 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()); } } - if (Globals) { - if (auto EC = Globals->finalizeMsfLayout()) - return std::move(EC); - if (Dbi) - Dbi->setGlobalsStreamIndex(Globals->getStreamIndex()); - } - return Msf->build(); } @@ -251,22 +238,8 @@ Error PDBFileBuilder::commit(StringRef Filename) { 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; } diff --git a/llvm/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp deleted file mode 100644 index 9b807c1653e..00000000000 --- a/llvm/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp +++ /dev/null @@ -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 <algorithm> -#include <vector> - -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<uint32_t> Idx = Msf.addStream(calculateSerializedLength()); - if (!Idx) - return Idx.takeError(); - StreamIdx = *Idx; - - uint32_t PublicRecordBytes = 0; - for (auto &Pub : Publics) - PublicRecordBytes += Pub.length(); - - Expected<uint32_t> 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<PublicSym32 &>(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<const PubSymLayout *>(LS->data().data()); - auto *R = reinterpret_cast<const PubSymLayout *>(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<uint8_t> NameBytes = - Sym.data().drop_front(offsetof(PubSymLayout, name)); - return StringRef(reinterpret_cast<const char *>(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<ulittle32_t> computeAddrMap(ArrayRef<CVSymbol> 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<const CVSymbol *> PublicsByAddr; - std::vector<uint32_t> 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<ulittle32_t> 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<ulittle32_t> AddrMap = computeAddrMap(Publics); - if (auto EC = PublicsWriter.writeArray(makeArrayRef(AddrMap))) - return EC; - - BinaryItemStream<CVSymbol> 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<CVSymbol> Symbols) { - std::array<std::vector<PSHashRecord>, 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); - } -} |