Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -81,28 +81,27 @@ } void writeTo(uint8_t *B) const override { - auto *R = reinterpret_cast(B + OutputSectionOff); + // Save off the DebugInfo entry to backfill the file signature (build id) + // in Writer::writeBuildId + DI = reinterpret_cast(B + OutputSectionOff); - R->Signature.CVSignature = OMF::Signature::PDB70; - // TODO(compnerd) fill in a GUID by hashing the contents of the binary to - // get a reproducible build - if (getRandomBytes(R->PDB70.Signature, sizeof(R->PDB70.Signature))) - fatal("entropy source failure"); - // TODO(compnerd) track the Age - R->PDB70.Age = 1; + DI->Signature.CVSignature = OMF::Signature::PDB70; // variable sized field (PDB Path) - auto *P = reinterpret_cast(B + OutputSectionOff + sizeof(*R)); + auto *P = reinterpret_cast(B + OutputSectionOff + sizeof(*DI)); if (!Config->PDBPath.empty()) memcpy(P, Config->PDBPath.data(), Config->PDBPath.size()); P[Config->PDBPath.size()] = '\0'; } + +public: + mutable codeview::DebugInfo *DI = nullptr; }; // The writer writes a SymbolTable result to a file. class Writer { public: - Writer(SymbolTable *T) : Symtab(T) {} + Writer(SymbolTable *T) : Symtab(T), BuildId(nullptr) {} void run(); private: @@ -119,6 +118,7 @@ void setSectionPermissions(); void writeSections(); void sortExceptionTable(); + void writeBuildId(); void applyRelocations(); llvm::Optional createSymbol(Defined *D); @@ -146,6 +146,7 @@ std::unique_ptr DebugDirectory; std::vector> DebugRecords; + CVDebugRecordChunk *BuildId; uint64_t FileSize; uint32_t PointerToSymbolTable = 0; @@ -299,6 +300,7 @@ fixSafeSEHSymbols(); writeSections(); sortExceptionTable(); + writeBuildId(); if (auto EC = Buffer->commit()) fatal(EC, "failed to write the output file"); } @@ -359,8 +361,12 @@ DebugDirectory = llvm::make_unique(DebugRecords); // TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled - if (Config->DebugTypes & static_cast(coff::DebugType::CV)) - DebugRecords.push_back(llvm::make_unique()); + if (Config->DebugTypes & static_cast(coff::DebugType::CV)) { + auto Chunk = llvm::make_unique(); + + BuildId = Chunk.get(); + DebugRecords.push_back(std::move(Chunk)); + } RData->addChunk(DebugDirectory.get()); for (const std::unique_ptr &C : DebugRecords) @@ -796,6 +802,27 @@ errs() << "warning: don't know how to handle .pdata.\n"; } +// Backfill the CVSignature in a PDB70 Debug Record. This backfilling allows us +// to get reproducible builds. +void Writer::writeBuildId() { + // There is nothing to backfill if BuildId was not setup. + if (BuildId == nullptr) + return; + + MD5 Hash; + MD5::MD5Result Res; + + Hash.update(ArrayRef{Buffer->getBufferStart(), + Buffer->getBufferEnd()}); + Hash.final(Res); + + assert(BuildId->DI->Signature.CVSignature == OMF::Signature::PDB70 && + "only PDB 7.0 is supported"); + memcpy(BuildId->DI->PDB70.Signature, Res, 16); + // TODO(compnerd) track the Age + BuildId->DI->PDB70.Age = 1; +} + OutputSection *Writer::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) if (Sec->getName() == Name) Index: test/COFF/rsds.test =================================================================== --- test/COFF/rsds.test +++ test/COFF/rsds.test @@ -18,7 +18,7 @@ # CHECK: PointerToRawData: # CHECK: PDBInfo { # CHECK: PDBSignature: 0x53445352 -# CHECK: PDBGUID: +# CHECK: PDBGUID: (A9 01 F6 CD 45 C8 41 9F CC BC 17 55 E3 64 DF A2) # CHECK: PDBAge: 1 # CHECK: PDBFileName: {{$}} # CHECK: } @@ -37,7 +37,7 @@ # CHECK-PDB: PointerToRawData: # CHECK-PDB: PDBInfo { # CHECK-PDB: PDBSignature: 0x53445352 -# CHECK-PDB: PDBGUID: +# CHECK-PDB: PDBGUID: (9F 9F CC 10 A5 F3 90 C4 E2 48 F9 58 82 16 B3 20) # CHECK-PDB: PDBAge: 1 # CHECK-PDB: PDBFileName: {{.*}}.pdb # CHECK-PDB: }