Index: COFF/Config.h =================================================================== --- COFF/Config.h +++ COFF/Config.h @@ -86,6 +86,7 @@ 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; Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -372,6 +372,12 @@ : 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 @@ 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()); Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -42,6 +42,60 @@ 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 auto &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 + memset(R->PDB70.Signature, 0, sizeof(R->PDB70.Signature)); + // 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 +141,9 @@ 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 +351,19 @@ 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 +678,10 @@ : 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(); Index: test/COFF/delayimports32.test =================================================================== --- test/COFF/delayimports32.test +++ test/COFF/delayimports32.test @@ -14,7 +14,7 @@ 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: ] 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: 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 Index: test/COFF/symtab.test =================================================================== --- test/COFF/symtab.test +++ 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)