return EC;
return Error::success();
}
+ template <typename T> static Expected<T> deserializeAs(CVSymbol Symbol) {
+ T Record(Symbol.kind());
+ if (auto EC = deserializeAs<T>(Symbol, Record))
+ return std::move(EC);
+ return Record;
+ }
explicit SymbolDeserializer(SymbolVisitorDelegate *Delegate,
CodeViewContainer Container)
-//===- PublicsStreamBuilder.h - PDB Publics Stream Creation -----*- C++ -*-===//
+//===- GSIStreamBuilder.h - PDB Publics/Globals Stream Creation -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBPUBLICSTREAMBUILDER_H
-#define LLVM_DEBUGINFO_PDB_RAW_PDBPUBLICSTREAMBUILDER_H
+#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/DebugInfo/PDB/Native/GlobalsStream.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/BinaryItemStream.h"
#include "llvm/Support/BinaryStreamRef.h"
namespace msf {
class MSFBuilder;
-}
+struct MSFLayout;
+} // namespace msf
namespace pdb {
-class PublicsStream;
-struct PublicsStreamHeader;
+struct GSIHashStreamBuilder;
-struct GSIHashTableBuilder {
- void addSymbols(ArrayRef<codeview::CVSymbol> Symbols);
+class GSIStreamBuilder {
- std::vector<PSHashRecord> HashRecords;
- std::array<support::ulittle32_t, (IPHR_HASH + 32) / 32> HashBitmap;
- std::vector<support::ulittle32_t> HashBuckets;
-};
-
-class PublicsStreamBuilder {
public:
- explicit PublicsStreamBuilder(msf::MSFBuilder &Msf);
- ~PublicsStreamBuilder();
+ explicit GSIStreamBuilder(msf::MSFBuilder &Msf);
+ ~GSIStreamBuilder();
- PublicsStreamBuilder(const PublicsStreamBuilder &) = delete;
- PublicsStreamBuilder &operator=(const PublicsStreamBuilder &) = delete;
+ GSIStreamBuilder(const GSIStreamBuilder &) = delete;
+ GSIStreamBuilder &operator=(const GSIStreamBuilder &) = delete;
Error finalizeMsfLayout();
- uint32_t calculateSerializedLength() const;
- Error commit(BinaryStreamWriter &PublicsWriter,
- BinaryStreamWriter &RecWriter);
+ Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer);
- uint32_t getStreamIndex() const { return StreamIdx; }
+ uint32_t getPublicsStreamIndex() const;
+ uint32_t getGlobalsStreamIndex() const;
uint32_t getRecordStreamIdx() const { return RecordStreamIdx; }
void addPublicSymbol(const codeview::PublicSym32 &Pub);
private:
- uint32_t StreamIdx = kInvalidStreamIndex;
+ 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<GSIHashTableBuilder> Table;
- std::vector<codeview::CVSymbol> Publics;
+ std::unique_ptr<GSIHashStreamBuilder> PSH;
+ std::unique_ptr<GSIHashStreamBuilder> GSH;
msf::MSFBuilder &Msf;
};
} // namespace pdb
+++ /dev/null
-//===- 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
namespace pdb {
class DbiStreamBuilder;
class InfoStreamBuilder;
-class PublicsStreamBuilder;
-class GlobalsStreamBuilder;
+class GSIStreamBuilder;
class TpiStreamBuilder;
class PDBFileBuilder {
TpiStreamBuilder &getTpiBuilder();
TpiStreamBuilder &getIpiBuilder();
PDBStringTableBuilder &getStringTableBuilder();
- PublicsStreamBuilder &getPublicsBuilder();
- GlobalsStreamBuilder &getGlobalsBuilder();
+ GSIStreamBuilder &getGsiBuilder();
Error commit(StringRef Filename);
std::unique_ptr<msf::MSFBuilder> Msf;
std::unique_ptr<InfoStreamBuilder> Info;
std::unique_ptr<DbiStreamBuilder> Dbi;
- std::unique_ptr<GlobalsStreamBuilder> Globals;
- std::unique_ptr<PublicsStreamBuilder> Publics;
+ std::unique_ptr<GSIStreamBuilder> Gsi;
std::unique_ptr<TpiStreamBuilder> Tpi;
std::unique_ptr<TpiStreamBuilder> Ipi;
Native/DbiStreamBuilder.cpp
Native/EnumTables.cpp
Native/GlobalsStream.cpp
- Native/GlobalsStreamBuilder.cpp
Native/Hash.cpp
Native/HashTable.cpp
Native/InfoStream.cpp
Native/PDBStringTable.cpp
Native/PDBStringTableBuilder.cpp
Native/PublicsStream.cpp
- Native/PublicsStreamBuilder.cpp
+ Native/GSIStreamBuilder.cpp
Native/RawError.cpp
Native/SymbolStream.cpp
Native/TpiHashing.cpp
#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"
--- /dev/null
+//===- 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();
+}
+++ /dev/null
-//===- 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();
-}
#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"
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) {
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();
}
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;
}
+++ /dev/null
-//===- 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);
- }
-}