Index: lld/trunk/COFF/Writer.cpp =================================================================== --- lld/trunk/COFF/Writer.cpp +++ lld/trunk/COFF/Writer.cpp @@ -83,30 +83,32 @@ class DebugDirectoryChunk : public Chunk { public: - DebugDirectoryChunk(const std::vector &R) : Records(R) {} + DebugDirectoryChunk(const std::vector &R, bool WriteRepro) + : Records(R), WriteRepro(WriteRepro) {} size_t getSize() const override { - return Records.size() * sizeof(debug_directory); + return (Records.size() + int(WriteRepro)) * sizeof(debug_directory); } void writeTo(uint8_t *B) const override { auto *D = reinterpret_cast(B + OutputSectionOff); for (const Chunk *Record : Records) { - D->Characteristics = 0; - D->TimeDateStamp = 0; - D->MajorVersion = 0; - D->MinorVersion = 0; - D->Type = COFF::IMAGE_DEBUG_TYPE_CODEVIEW; - D->SizeOfData = Record->getSize(); - D->AddressOfRawData = Record->getRVA(); OutputSection *OS = Record->getOutputSection(); uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA()); - D->PointerToRawData = Offs; - - TimeDateStamps.push_back(&D->TimeDateStamp); + fillEntry(D, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, Record->getSize(), + Record->getRVA(), Offs); ++D; } + + if (WriteRepro) { + // FIXME: The COFF spec allows either a 0-sized entry to just say + // "the timestamp field is really a hash", or a 4-byte size field + // followed by that many bytes containing a longer hash (with the + // lowest 4 bytes usually being the timestamp in little-endian order). + // Consider storing the full 8 bytes computed by xxHash64 here. + fillEntry(D, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0); + } } void setTimeDateStamp(uint32_t TimeDateStamp) { @@ -115,8 +117,23 @@ } private: + void fillEntry(debug_directory *D, COFF::DebugType DebugType, size_t Size, + uint64_t RVA, uint64_t Offs) const { + D->Characteristics = 0; + D->TimeDateStamp = 0; + D->MajorVersion = 0; + D->MinorVersion = 0; + D->Type = DebugType; + D->SizeOfData = Size; + D->AddressOfRawData = RVA; + D->PointerToRawData = Offs; + + TimeDateStamps.push_back(&D->TimeDateStamp); + } + mutable std::vector TimeDateStamps; const std::vector &Records; + bool WriteRepro; }; class CVDebugRecordChunk : public Chunk { @@ -500,11 +517,13 @@ } // Create Debug Information Chunks - if (Config->Debug) { - DebugDirectory = make(DebugRecords); - - OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec; + OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec; + if (Config->Debug || Config->Repro) { + DebugDirectory = make(DebugRecords, Config->Repro); + DebugInfoSec->addChunk(DebugDirectory); + } + if (Config->Debug) { // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We // output a PDB no matter what, and this chunk provides the only means of // allowing a debugger to match a PDB and an executable. So we need it even @@ -513,7 +532,6 @@ BuildId = CVChunk; DebugRecords.push_back(CVChunk); - DebugInfoSec->addChunk(DebugDirectory); for (Chunk *C : DebugRecords) DebugInfoSec->addChunk(C); } @@ -911,7 +929,7 @@ : sizeof(object::coff_tls_directory32); } } - if (Config->Debug) { + if (DebugDirectory) { Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA(); Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize(); } Index: lld/trunk/test/COFF/rsds.test =================================================================== --- lld/trunk/test/COFF/rsds.test +++ lld/trunk/test/COFF/rsds.test @@ -14,6 +14,14 @@ # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.4.txt # RUN: cat %t.3.txt %t.4.txt | FileCheck %s +# RUN: rm -f %t.dll %t.pdb +# RUN: lld-link /Brepro /dll /out:%t.dll /entry:DllMain %t.obj +# RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck --check-prefix REPRO %s + +# RUN: rm -f %t.dll %t.pdb +# RUN: lld-link /Brepro /debug /dll /out:%t.dll /entry:DllMain %t.obj +# RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck --check-prefix REPRODEBUG %s + # CHECK: File: [[FILE:.*]].dll # CHECK: DebugDirectory [ # CHECK: DebugEntry { @@ -53,6 +61,49 @@ # CHECK: } # CHECK: ] +# REPRO: File: {{.*}}.dll +# REPRO: DebugDirectory [ +# REPRO: DebugEntry { +# REPRO: Characteristics: 0x0 +# REPRO: TimeDateStamp: +# REPRO: MajorVersion: 0x0 +# REPRO: MinorVersion: 0x0 +# REPRO: Type: Repro (0x10) +# REPRO: SizeOfData: 0x0 +# REPRO: AddressOfRawData: 0x0 +# REPRO: PointerToRawData: 0x0 +# REPRO: } +# REPRO: ] + +# REPRODEBUG: File: {{.*}}.dll +# REPRODEBUG: DebugDirectory [ +# REPRODEBUG: DebugEntry { +# REPRODEBUG: Characteristics: 0x0 +# REPRODEBUG: TimeDateStamp: +# REPRODEBUG: MajorVersion: 0x0 +# REPRODEBUG: MinorVersion: 0x0 +# REPRODEBUG: Type: CodeView (0x2) +# REPRODEBUG: SizeOfData: 0x{{[^0]}} +# REPRODEBUG: AddressOfRawData: 0x{{[^0]}} +# REPRODEBUG: PointerToRawData: 0x{{[^0]}} +# REPRODEBUG: PDBInfo { +# REPRODEBUG: PDBSignature: 0x53445352 +# REPRODEBUG: PDBGUID: +# REPRODEBUG: PDBAge: 1 +# REPRODEBUG: PDBFileName: +# REPRODEBUG: } +# REPRODEBUG: } +# REPRODEBUG: DebugEntry { +# REPRODEBUG: Characteristics: 0x0 +# REPRODEBUG: TimeDateStamp: +# REPRODEBUG: MajorVersion: 0x0 +# REPRODEBUG: MinorVersion: 0x0 +# REPRODEBUG: Type: Repro (0x10) +# REPRODEBUG: SizeOfData: 0x0 +# REPRODEBUG: AddressOfRawData: 0x0 +# REPRODEBUG: PointerToRawData: 0x0 +# REPRODEBUG: } +# REPRODEBUG: ] --- !COFF header: Machine: IMAGE_FILE_MACHINE_I386