Index: lld/COFF/PDB.cpp =================================================================== --- lld/COFF/PDB.cpp +++ lld/COFF/PDB.cpp @@ -88,7 +88,7 @@ IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) {} /// Emit the basic PDB structure: initial streams, headers, etc. - void initialize(const llvm::codeview::DebugInfo &BuildId); + void initialize(const codeview::DebugInfo &BuildId); /// Link CodeView from each object file in the symbol table into the PDB. void addObjectsToPDB(); @@ -121,7 +121,7 @@ OutputSection *OS, Chunk *C); /// Write the PDB to disk. - void commit(); + void commit(const codeview::DebugInfo &BuildId); private: BumpPtrAllocator Alloc; @@ -1035,7 +1035,7 @@ void coff::createPDB(SymbolTable *Symtab, ArrayRef OutputSections, ArrayRef SectionTable, - const llvm::codeview::DebugInfo &BuildId) { + const codeview::DebugInfo &BuildId) { ScopedTimer T1(TotalPdbLinkTimer); PDBLinker PDB(Symtab); PDB.initialize(BuildId); @@ -1043,10 +1043,10 @@ PDB.addSections(OutputSections, SectionTable); ScopedTimer T2(DiskCommitTimer); - PDB.commit(); + PDB.commit(BuildId); } -void PDBLinker::initialize(const llvm::codeview::DebugInfo &BuildId) { +void PDBLinker::initialize(const codeview::DebugInfo &BuildId) { ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize // Create streams in MSF for predefined streams, namely @@ -1056,12 +1056,6 @@ // Add an Info stream. auto &InfoBuilder = Builder.getInfoBuilder(); - InfoBuilder.setAge(BuildId.PDB70.Age); - - GUID uuid; - memcpy(&uuid, &BuildId.PDB70.Signature, sizeof(uuid)); - InfoBuilder.setGuid(uuid); - InfoBuilder.setSignature(time(nullptr)); InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); // Add an empty DBI stream. @@ -1127,7 +1121,19 @@ DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); } -void PDBLinker::commit() { +void PDBLinker::commit(const codeview::DebugInfo &BuildId) { // Write to a file. - ExitOnErr(Builder.commit(Config->PDBPath)); + pdb::FinalizedPdb Result = ExitOnErr(Builder.write(Config->PDBPath)); + + // Set the build id in the pdb file. + // FIXME: Set Signature here to the timestamp of the executable. For + // reproducible builds, we will probably want to go further and set + // this field to a hash of the PDB file, then set the timestamp of + // the executable to be the same hash. + Result.IdPtr->Age = BuildId.PDB70.Age; + ::memcpy(&Result.IdPtr->Guid, &BuildId.PDB70.Signature, + sizeof(codeview::GUID)); + Result.IdPtr->Signature = time(nullptr); + + ExitOnErr(Result.File->commit()); } Index: llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h +++ llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h @@ -20,6 +20,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" +#include "llvm/Support/FileOutputBuffer.h" #include #include @@ -29,11 +30,18 @@ class MSFBuilder; } namespace pdb { + +struct BuildId; class DbiStreamBuilder; class InfoStreamBuilder; class GSIStreamBuilder; class TpiStreamBuilder; +struct FinalizedPdb { + std::unique_ptr File; + BuildId *IdPtr; +}; + class PDBFileBuilder { public: explicit PDBFileBuilder(BumpPtrAllocator &Allocator); @@ -51,7 +59,8 @@ PDBStringTableBuilder &getStringTableBuilder(); GSIStreamBuilder &getGsiBuilder(); - Error commit(StringRef Filename); + Expected write(StringRef Filename); + Error writeAndCommit(StringRef Filename); Expected getNamedStreamIndex(StringRef Name) const; Error addNamedStream(StringRef Name, uint32_t Size); Index: llvm/include/llvm/DebugInfo/PDB/Native/RawTypes.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/RawTypes.h +++ llvm/include/llvm/DebugInfo/PDB/Native/RawTypes.h @@ -311,12 +311,16 @@ const uint32_t MinTpiHashBuckets = 0x1000; const uint32_t MaxTpiHashBuckets = 0x40000; +struct BuildId { + support::ulittle32_t Signature; // Actually a timestamp or hash. + support::ulittle32_t Age; + codeview::GUID Guid; +}; + /// The header preceeding the global PDB Stream (Stream 1) struct InfoStreamHeader { support::ulittle32_t Version; - support::ulittle32_t Signature; - support::ulittle32_t Age; - codeview::GUID Guid; + BuildId Id; }; /// The header preceeding the /names stream. Index: llvm/include/llvm/Support/BinaryByteStream.h =================================================================== --- llvm/include/llvm/Support/BinaryByteStream.h +++ llvm/include/llvm/Support/BinaryByteStream.h @@ -203,58 +203,24 @@ /// \brief An implementation of WritableBinaryStream backed by an llvm /// FileOutputBuffer. -class FileBufferByteStream : public WritableBinaryStream { -private: - class StreamImpl : public MutableBinaryByteStream { - public: - StreamImpl(std::unique_ptr Buffer, - llvm::support::endianness Endian) - : MutableBinaryByteStream( - MutableArrayRef(Buffer->getBufferStart(), - Buffer->getBufferEnd()), - Endian), - FileBuffer(std::move(Buffer)) {} - - Error commit() override { - if (FileBuffer->commit()) - return make_error( - stream_error_code::filesystem_error); - return Error::success(); - } - - private: - std::unique_ptr FileBuffer; - }; - +class FileBufferByteStream : public MutableBinaryByteStream { public: - FileBufferByteStream(std::unique_ptr Buffer, + FileBufferByteStream(FileOutputBuffer &Buffer, llvm::support::endianness Endian) - : Impl(std::move(Buffer), Endian) {} - - llvm::support::endianness getEndian() const override { - return Impl.getEndian(); - } - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) override { - return Impl.readBytes(Offset, Size, Buffer); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) override { - return Impl.readLongestContiguousChunk(Offset, Buffer); - } - - uint32_t getLength() override { return Impl.getLength(); } - - Error writeBytes(uint32_t Offset, ArrayRef Data) override { - return Impl.writeBytes(Offset, Data); + : MutableBinaryByteStream( + MutableArrayRef(Buffer.getBufferStart(), + Buffer.getBufferEnd()), + Endian), + FileBuffer(Buffer) {} + + Error commit() override { + if (FileBuffer.commit()) + return make_error(stream_error_code::filesystem_error); + return Error::success(); } - Error commit() override { return Impl.commit(); } - private: - StreamImpl Impl; + FileOutputBuffer &FileBuffer; }; } // end namespace llvm Index: llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp +++ llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp @@ -45,9 +45,9 @@ } Version = H->Version; - Signature = H->Signature; - Age = H->Age; - Guid = H->Guid; + Signature = H->Id.Signature; + Age = H->Id.Age; + Guid = H->Id.Guid; uint32_t Offset = Reader.getOffset(); if (auto EC = NamedStreams.load(Reader)) Index: llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp @@ -26,7 +26,9 @@ InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf, NamedStreamMap &NamedStreams) : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Sig(-1), Age(0), - NamedStreams(NamedStreams) {} + NamedStreams(NamedStreams) { + ::memset(Guid.Guid, 0, sizeof(Guid.Guid)); +} void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; } @@ -56,10 +58,10 @@ BinaryStreamWriter Writer(*InfoS); InfoStreamHeader H; - H.Age = Age; - H.Signature = Sig; H.Version = Ver; - H.Guid = Guid; + H.Id.Age = Age; + H.Id.Signature = Sig; + H.Id.Guid = Guid; if (auto EC = Writer.writeObject(H)) return EC; Index: llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -167,23 +167,24 @@ assert(FpmWriter.bytesRemaining() == 0); } -Error PDBFileBuilder::commit(StringRef Filename) { +Expected PDBFileBuilder::write(StringRef Filename) { assert(!Filename.empty()); auto ExpectedLayout = finalizeMsfLayout(); if (!ExpectedLayout) return ExpectedLayout.takeError(); auto &Layout = *ExpectedLayout; + FinalizedPdb Result; uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks; auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize); if (auto E = OutFileOrError.takeError()) - return E; - FileBufferByteStream Buffer(std::move(*OutFileOrError), - llvm::support::little); + return std::move(E); + Result.File = std::move(*OutFileOrError); + FileBufferByteStream Buffer(*Result.File, llvm::support::little); BinaryStreamWriter Writer(Buffer); if (auto EC = Writer.writeObject(*Layout.SB)) - return EC; + return std::move(EC); commitFpm(Buffer, Layout); @@ -191,20 +192,20 @@ msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); Writer.setOffset(BlockMapOffset); if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) - return EC; + return std::move(EC); auto DirStream = WritableMappedBlockStream::createDirectoryStream( Layout, Buffer, Allocator); BinaryStreamWriter DW(*DirStream); if (auto EC = DW.writeInteger(Layout.StreamSizes.size())) - return EC; + return std::move(EC); if (auto EC = DW.writeArray(Layout.StreamSizes)) - return EC; + return std::move(EC); for (const auto &Blocks : Layout.StreamMap) { if (auto EC = DW.writeArray(Blocks)) - return EC; + return std::move(EC); } auto ExpectedSN = getNamedStreamIndex("/names"); @@ -215,32 +216,46 @@ Layout, Buffer, *ExpectedSN, Allocator); BinaryStreamWriter NSWriter(*NS); if (auto EC = Strings.commit(NSWriter)) - return EC; + return std::move(EC); if (Info) { if (auto EC = Info->commit(Layout, Buffer)) - return EC; + return std::move(EC); } if (Dbi) { if (auto EC = Dbi->commit(Layout, Buffer)) - return EC; + return std::move(EC); } if (Tpi) { if (auto EC = Tpi->commit(Layout, Buffer)) - return EC; + return std::move(EC); } if (Ipi) { if (auto EC = Ipi->commit(Layout, Buffer)) - return EC; + return std::move(EC); } if (Gsi) { if (auto EC = Gsi->commit(Layout, Buffer)) - return EC; + return std::move(EC); } - return Buffer.commit(); + auto InfoStreamBlocks = Layout.StreamMap[StreamPDB]; + assert(!InfoStreamBlocks.empty()); + uint64_t InfoStreamFileOffset = + blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize); + InfoStreamHeader *H = reinterpret_cast( + Result.File->getBufferStart() + InfoStreamFileOffset); + Result.IdPtr = &H->Id; + return std::move(Result); +} + +Error PDBFileBuilder::writeAndCommit(StringRef Filename) { + auto Result = write(Filename); + if (!Result) + return Result.takeError(); + return Result->File->commit(); } Index: llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp =================================================================== --- llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -740,7 +740,7 @@ Builder.getStringTableBuilder().setStrings(*Strings.strings()); - ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile)); + ExitOnErr(Builder.writeAndCommit(opts::yaml2pdb::YamlPdbOutputFile)); } static PDBFile &loadPDB(StringRef Path, std::unique_ptr &Session) { @@ -1030,7 +1030,7 @@ OutFile = opts::merge::InputFilenames[0]; llvm::sys::path::replace_extension(OutFile, "merged.pdb"); } - ExitOnErr(Builder.commit(OutFile)); + ExitOnErr(Builder.writeAndCommit(OutFile)); } static bool parseRange(StringRef Str,