From 6e545ffc4e99b16cab6494eba21dd3b6cf06ee68 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 11 Apr 2017 16:26:15 +0000 Subject: [PDB] Emit index/offset pairs for TPI and IPI streams Summary: This lets PDB readers lookup type record data by type index in O(log n) time. It also enables makes `cvdump -t` work on PDBs produced by LLD. cvdump will not dump a PDB that doesn't have an index-to-offset table. The table is sorted by type index, and has an entry every 8KB. Looking up a type record by index is a binary search of this table, followed by a scan of at most 8KB. Reviewers: ruiu, zturner, inglorion Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31636 llvm-svn: 299958 --- llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp | 64 ++++++++++++++++------ 1 file changed, 46 insertions(+), 18 deletions(-) (limited to 'llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp') diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp index 27b9dad02ac..375c35b1114 100644 --- a/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp @@ -45,7 +45,17 @@ void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) { void TpiStreamBuilder::addTypeRecord(ArrayRef Record, Optional Hash) { - TypeRecordBytes += Record.size(); + // If we just crossed an 8KB threshold, add a type index offset. + size_t NewSize = TypeRecordBytes + Record.size(); + constexpr size_t EightKB = 8 * 1024; + if (NewSize / EightKB > TypeRecordBytes / EightKB || TypeRecords.empty()) { + TypeIndexOffsets.push_back( + {codeview::TypeIndex(codeview::TypeIndex::FirstNonSimpleIndex + + TypeRecords.size()), + ulittle32_t(TypeRecordBytes)}); + } + TypeRecordBytes = NewSize; + TypeRecords.push_back(Record); if (Hash) TypeHashes.push_back(*Hash); @@ -58,7 +68,6 @@ Error TpiStreamBuilder::finalize() { TpiStreamHeader *H = Allocator.Allocate(); uint32_t Count = TypeRecords.size(); - uint32_t HashBufferSize = calculateHashBufferSize(); H->Version = *VerHeader; H->HeaderSize = sizeof(TpiStreamHeader); @@ -75,11 +84,15 @@ Error TpiStreamBuilder::finalize() { // the `HashStreamIndex` field of the `TpiStreamHeader`. Therefore, the data // begins at offset 0 of this independent stream. H->HashValueBuffer.Off = 0; - H->HashValueBuffer.Length = HashBufferSize; + H->HashValueBuffer.Length = calculateHashBufferSize(); + + // We never write any adjustments into our PDBs, so this is usually some + // offset with zero length. H->HashAdjBuffer.Off = H->HashValueBuffer.Off + H->HashValueBuffer.Length; H->HashAdjBuffer.Length = 0; + H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length; - H->IndexOffsetBuffer.Length = 0; + H->IndexOffsetBuffer.Length = calculateIndexOffsetSize(); Header = H; return Error::success(); @@ -90,34 +103,42 @@ uint32_t TpiStreamBuilder::calculateSerializedLength() { } uint32_t TpiStreamBuilder::calculateHashBufferSize() const { - assert(TypeHashes.size() == TypeHashes.size() && + assert((TypeRecords.size() == TypeHashes.size() || TypeHashes.empty()) && "either all or no type records should have hashes"); return TypeHashes.size() * sizeof(ulittle32_t); } +uint32_t TpiStreamBuilder::calculateIndexOffsetSize() const { + return TypeIndexOffsets.size() * sizeof(TypeIndexOffset); +} + Error TpiStreamBuilder::finalizeMsfLayout() { uint32_t Length = calculateSerializedLength(); if (auto EC = Msf.setStreamSize(Idx, Length)) return EC; - uint32_t HashBufferSize = calculateHashBufferSize(); + uint32_t HashStreamSize = + calculateHashBufferSize() + calculateIndexOffsetSize(); - if (HashBufferSize == 0) + if (HashStreamSize == 0) return Error::success(); - auto ExpectedIndex = Msf.addStream(HashBufferSize); + auto ExpectedIndex = Msf.addStream(HashStreamSize); if (!ExpectedIndex) return ExpectedIndex.takeError(); HashStreamIndex = *ExpectedIndex; - ulittle32_t *H = Allocator.Allocate(TypeHashes.size()); - MutableArrayRef HashBuffer(H, TypeHashes.size()); - for (uint32_t I = 0; I < TypeHashes.size(); ++I) { - HashBuffer[I] = TypeHashes[I] % MinTpiHashBuckets; + if (!TypeHashes.empty()) { + ulittle32_t *H = Allocator.Allocate(TypeHashes.size()); + MutableArrayRef HashBuffer(H, TypeHashes.size()); + for (uint32_t I = 0; I < TypeHashes.size(); ++I) { + HashBuffer[I] = TypeHashes[I] % MinTpiHashBuckets; + } + ArrayRef Bytes( + reinterpret_cast(HashBuffer.data()), + calculateHashBufferSize()); + HashValueStream = + llvm::make_unique(Bytes, llvm::support::little); } - ArrayRef Bytes(reinterpret_cast(HashBuffer.data()), - HashBufferSize); - HashValueStream = - llvm::make_unique(Bytes, llvm::support::little); return Error::success(); } @@ -141,8 +162,15 @@ Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout, auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, HashStreamIndex); BinaryStreamWriter HW(*HVS); - if (auto EC = HW.writeStreamRef(*HashValueStream)) - return EC; + if (HashValueStream) { + if (auto EC = HW.writeStreamRef(*HashValueStream)) + return EC; + } + + for (auto &IndexOffset : TypeIndexOffsets) { + if (auto EC = HW.writeObject(IndexOffset)) + return EC; + } } return Error::success(); -- cgit v1.2.3