lld-link: Write an empty "repro" debug directory entry if /Brepro is passed

If the coff timestamp is set to a hash, like lld-link does if /Brepro is
passed, the coff spec suggests that a IMAGE_DEBUG_TYPE_REPRO entry is in the
debug directory. This lets lld-link write such a section.
Fixes PR38429, see bug for details.

Differential Revision: https://reviews.llvm.org/D51652

llvm-svn: 341486
This commit is contained in:
Nico Weber 2018-09-05 18:02:43 +00:00
parent 893c646938
commit 13b55bbc2f
2 changed files with 87 additions and 18 deletions

View File

@ -83,30 +83,32 @@ namespace {
class DebugDirectoryChunk : public Chunk {
public:
DebugDirectoryChunk(const std::vector<Chunk *> &R) : Records(R) {}
DebugDirectoryChunk(const std::vector<Chunk *> &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<debug_directory *>(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 @@ public:
}
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<support::ulittle32_t *> TimeDateStamps;
const std::vector<Chunk *> &Records;
bool WriteRepro;
};
class CVDebugRecordChunk : public Chunk {
@ -500,11 +517,13 @@ void Writer::createMiscChunks() {
}
// Create Debug Information Chunks
OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec;
if (Config->Debug || Config->Repro) {
DebugDirectory = make<DebugDirectoryChunk>(DebugRecords, Config->Repro);
DebugInfoSec->addChunk(DebugDirectory);
}
if (Config->Debug) {
DebugDirectory = make<DebugDirectoryChunk>(DebugRecords);
OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec;
// 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 @@ void Writer::createMiscChunks() {
BuildId = CVChunk;
DebugRecords.push_back(CVChunk);
DebugInfoSec->addChunk(DebugDirectory);
for (Chunk *C : DebugRecords)
DebugInfoSec->addChunk(C);
}
@ -911,7 +929,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
: sizeof(object::coff_tls_directory32);
}
}
if (Config->Debug) {
if (DebugDirectory) {
Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA();
Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize();
}

View File

@ -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