From 8fcff934bae29c54d68bc94134136d9e8fb9a208 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 29 Aug 2016 21:20:46 +0000 Subject: [PATCH] COFF: add beginnings of debug directory creation The IMAGE_FILE_HEADER structure contains a (RVA, size) to an array of COFF_DEBUG_DIRECTORY records. Each one of these records contains an RVA to a OMF Debug Directory. These OMF debug directories are derived into newer types such as PDB70, PDB20, etc. This constructs a PDB70 structure which will allow us to associate a GUID with a build to actually tie debug information. llvm-svn: 280012 --- lld/COFF/Config.h | 1 + lld/COFF/Driver.cpp | 10 ++-- lld/COFF/Writer.cpp | 76 +++++++++++++++++++++++++ lld/test/COFF/delayimports32.test | 6 +- lld/test/COFF/rsds.test | 113 ++++++++++++++++++++++++++++++++++++++ lld/test/COFF/symtab.test | 4 +- 6 files changed, 201 insertions(+), 9 deletions(-) create mode 100644 lld/test/COFF/rsds.test diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 2bb6a98..5bfb12e 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -86,6 +86,7 @@ struct Configuration { bool Debug = false; bool WriteSymtab = true; unsigned DebugTypes = static_cast(DebugType::None); + StringRef PDBPath; // Symbols in this set are considered as live by the garbage collector. std::set GCRoot; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index ffd6936..d408148 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -372,6 +372,12 @@ void LinkerDriver::link(llvm::ArrayRef ArgsArr) { : getDefaultDebugType(Args); } + // Create a dummy PDB file to satisfy build sytem rules. + if (auto *Arg = Args.getLastArg(OPT_pdb)) { + Config->PDBPath = Arg->getValue(); + createPDB(Config->PDBPath); + } + // Handle /noentry if (Args.hasArg(OPT_noentry)) { if (!Args.hasArg(OPT_dll)) @@ -743,10 +749,6 @@ void LinkerDriver::link(llvm::ArrayRef ArgsArr) { if (Config->Manifest == Configuration::SideBySide) createSideBySideManifest(); - // Create a dummy PDB file to satisfy build sytem rules. - if (auto *Arg = Args.getLastArg(OPT_pdb)) - createPDB(Arg->getValue()); - // Identify unreferenced COMDAT sections. if (Config->DoGC) markLive(Symtab.getChunks()); diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 1a1018e..64924aa 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -21,6 +21,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -42,6 +43,61 @@ static const int DOSStubSize = 64; static const int NumberfOfDataDirectory = 16; namespace { + +class DebugDirectoryChunk : public Chunk { +public: + DebugDirectoryChunk(const std::vector> &R) + : Records(R) {} + + size_t getSize() const override { + return Records.size() * sizeof(debug_directory); + } + + void writeTo(uint8_t *B) const override { + auto *D = reinterpret_cast(B + OutputSectionOff); + + for (const std::unique_ptr &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(); + // TODO(compnerd) get the file offset + D->PointerToRawData = 0; + + ++D; + } + } + +private: + const std::vector> &Records; +}; + +class CVDebugRecordChunk : public Chunk { + size_t getSize() const override { + return sizeof(codeview::DebugInfo) + Config->PDBPath.size() + 1; + } + + void writeTo(uint8_t *B) const override { + auto *R = 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; + + // variable sized field (PDB Path) + auto *P = reinterpret_cast(B + OutputSectionOff + sizeof(*R)); + memcpy(P, Config->PDBPath.data(), Config->PDBPath.size()); + P[Config->PDBPath.size()] = '\0'; + } +}; + // The writer writes a SymbolTable result to a file. class Writer { public: @@ -87,6 +143,9 @@ private: EdataContents Edata; std::unique_ptr SEHTable; + std::unique_ptr DebugDirectory; + std::vector> DebugRecords; + uint64_t FileSize; uint32_t PointerToSymbolTable = 0; uint64_t SizeOfImage; @@ -294,6 +353,19 @@ void Writer::createMiscChunks() { RData->addChunk(C); } + // Create Debug Information Chunks + if (Config->Debug) { + DebugDirectory = 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(make_unique()); + + RData->addChunk(DebugDirectory.get()); + for (const std::unique_ptr &C : DebugRecords) + RData->addChunk(C.get()); + } + // Create SEH table. x86-only. if (Config->Machine != I386) return; @@ -608,6 +680,10 @@ template void Writer::writeHeader() { : sizeof(object::coff_tls_directory32); } } + if (Config->Debug) { + Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA(); + Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize(); + } if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) { if (auto *B = dyn_cast(Sym->Body)) { SectionChunk *SC = B->getChunk(); diff --git a/lld/test/COFF/delayimports32.test b/lld/test/COFF/delayimports32.test index 328b345..9c4fcae 100644 --- a/lld/test/COFF/delayimports32.test +++ b/lld/test/COFF/delayimports32.test @@ -14,7 +14,7 @@ IMPORT-NEXT: Name: std32.dll IMPORT-NEXT: Attributes: 0x1 IMPORT-NEXT: ModuleHandle: 0x1018 IMPORT-NEXT: ImportAddressTable: 0x1020 -IMPORT-NEXT: ImportNameTable: 0x3040 +IMPORT-NEXT: ImportNameTable: 0x4040 IMPORT-NEXT: BoundDelayImportTable: 0x0 IMPORT-NEXT: UnloadDelayImportTable: 0x0 IMPORT-NEXT: Import { @@ -71,7 +71,7 @@ BASEREL-NEXT: } BASEREL-NEXT: ] DISASM: 202b: 68 20 10 40 00 pushl $4198432 -DISASM-NEXT: 2030: 68 00 30 40 00 pushl $4206592 +DISASM-NEXT: 2030: 68 00 40 40 00 pushl $4210688 DISASM-NEXT: 2035: e8 c6 ff ff ff calll -58 <_main@0> DISASM-NEXT: 203a: 5a popl %edx DISASM-NEXT: 203b: 59 popl %ecx @@ -79,7 +79,7 @@ DISASM-NEXT: 203c: ff e0 jmpl *%eax DISASM-NEXT: 203e: 51 pushl %ecx DISASM-NEXT: 203f: 52 pushl %edx DISASM-NEXT: 2040: 68 24 10 40 00 pushl $4198436 -DISASM-NEXT: 2045: 68 00 30 40 00 pushl $4206592 +DISASM-NEXT: 2045: 68 00 40 40 00 pushl $4210688 DISASM-NEXT: 204a: e8 b1 ff ff ff calll -79 <_main@0> DISASM-NEXT: 204f: 5a popl %edx DISASM-NEXT: 2050: 59 popl %ecx diff --git a/lld/test/COFF/rsds.test b/lld/test/COFF/rsds.test new file mode 100644 index 0000000..37ec48b --- /dev/null +++ b/lld/test/COFF/rsds.test @@ -0,0 +1,113 @@ +# RUN: yaml2obj %s > %t.obj + +# RUN: lld-link /debug /dll /out:%t.dll /entry:DllMain %t.obj +# RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck %s + +# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:DllMain %t.obj +# RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck %s -check-prefix CHECK-PDB + +# CHECK: DebugDirectory [ +# CHECK: DebugEntry { +# CHECK: Characteristics: 0x0 +# CHECK: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +# CHECK: MajorVersion: 0x0 +# CHECK: MinorVersion: 0x0 +# CHECK: Type: CodeView (0x2) +# CHECK: SizeOfData: 0x19 +# CHECK: AddressOfRawData: +# CHECK: PointerToRawData: +# CHECK: PDBInfo { +# CHECK: PDBSignature: 0x53445352 +# CHECK: PDBGUID: +# CHECK: PDBAge: 1 +# CHECK: PDBFileName: {{$}} +# CHECK: } +# CHECK: } +# CHECK: ] + +# CHECK-PDB: DebugDirectory [ +# CHECK-PDB: DebugEntry { +# CHECK-PDB: Characteristics: 0x0 +# CHECK-PDB: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +# CHECK-PDB: MajorVersion: 0x0 +# CHECK-PDB: MinorVersion: 0x0 +# CHECK-PDB: Type: CodeView (0x2) +# CHECK-PDB: SizeOfData: +# CHECK-PDB: AddressOfRawData: +# CHECK-PDB: PointerToRawData: +# CHECK-PDB: PDBInfo { +# CHECK-PDB: PDBSignature: 0x53445352 +# CHECK-PDB: PDBGUID: +# CHECK-PDB: PDBAge: 1 +# CHECK-PDB: PDBFileName: {{.*}}.pdb +# CHECK-PDB: } +# CHECK-PDB: } +# CHECK-PDB: ] + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 31C0C3 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 3 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3963538403 + Number: 1 + - Name: .data + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 2 + - Name: .bss + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + - Name: '@feat.00' + Value: 1 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: _DllMain + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/lld/test/COFF/symtab.test b/lld/test/COFF/symtab.test index 51eb3a3..bf7f996 100644 --- a/lld/test/COFF/symtab.test +++ b/lld/test/COFF/symtab.test @@ -74,7 +74,7 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: __imp_ExitProcess # CHECK-NEXT: Value: 64 -# CHECK-NEXT: Section: .idata (4) +# CHECK-NEXT: Section: .idata (5) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: External (0x2) @@ -92,7 +92,7 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: __imp_MessageBoxA # CHECK-NEXT: Value: 72 -# CHECK-NEXT: Section: .idata (4) +# CHECK-NEXT: Section: .idata (5) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: External (0x2) -- 2.7.4