Index: COFF/CMakeLists.txt =================================================================== --- COFF/CMakeLists.txt +++ COFF/CMakeLists.txt @@ -5,6 +5,7 @@ add_lld_library(lldCOFF Chunks.cpp DLL.cpp + Debug.cpp Driver.cpp DriverUtils.cpp Error.cpp Index: COFF/Config.h =================================================================== --- COFF/Config.h +++ COFF/Config.h @@ -84,6 +84,7 @@ bool Relocatable = true; bool Force = false; bool Debug = false; + StringRef PDBPath; bool WriteSymtab = true; unsigned DebugTypes = static_cast(DebugType::None); Index: COFF/Debug.h =================================================================== --- /dev/null +++ COFF/Debug.h @@ -0,0 +1,34 @@ +//===- Debug.h --------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_DEBUG_H +#define LLD_COFF_DEBUG_H + +#include "Symbols.h" +#include "Chunks.h" +#include +#include + +namespace lld { +namespace coff { +class DebugDirectoryContents { + std::vector> DebugRecords; + +public: + std::unique_ptr Directories; + + DebugDirectoryContents(); + + std::vector getChunks(); +}; +} +} + +#endif + Index: COFF/Debug.cpp =================================================================== --- /dev/null +++ COFF/Debug.cpp @@ -0,0 +1,87 @@ +//===- Debug.cpp ----------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Debug.h" +#include + +using namespace llvm; +using namespace llvm::object; + +namespace lld { +namespace coff { +namespace { +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()); + } +}; + +class DebugDirectoriesChunk : public Chunk { + const std::vector> &Records; + +public: + DebugDirectoriesChunk(const std::vector> &Records) + : Records(Records) {} + + 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; + } + } +}; +} + +DebugDirectoryContents::DebugDirectoryContents() + : Directories(make_unique(DebugRecords)) { + // TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled + if (Config->DebugTypes & static_cast(DebugType::CV)) + DebugRecords.push_back(make_unique()); +} + +std::vector DebugDirectoryContents::getChunks() { + std::vector chunks; + chunks.push_back(Directories.get()); + for (const auto &Record : DebugRecords) + chunks.push_back(Record.get()); + return chunks; +} +} +} + Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -371,6 +371,11 @@ ? parseDebugType(Args.getLastArg(OPT_debugtype)->getValue()) : getDefaultDebugType(Args); } + // Create a dummy PDB file to satisfy build sytem rules. + if (auto *Arg = Args.getLastArg(OPT_pdb)) { + Config->PDBPath = Arg->getValue(); + createPDB(Arg->getValue()); + } // Handle /noentry if (Args.hasArg(OPT_noentry)) { @@ -743,10 +748,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 @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "Config.h" +#include "Debug.h" #include "DLL.h" #include "Error.h" #include "InputFiles.h" @@ -85,6 +86,7 @@ IdataContents Idata; DelayLoadContents DelayIdata; EdataContents Edata; + DebugDirectoryContents DebugDirectory; std::unique_ptr SEHTable; uint64_t FileSize; @@ -286,16 +288,21 @@ } void Writer::createMiscChunks() { + OutputSection *Sec = createSection(".rdata"); + + if (Config->Debug) + for (Chunk *C : DebugDirectory.getChunks()) + Sec->addChunk(C); + // Create thunks for locally-dllimported symbols. - if (!Symtab->LocalImportChunks.empty()) { - OutputSection *Sec = createSection(".rdata"); + if (!Symtab->LocalImportChunks.empty()) for (Chunk *C : Symtab->LocalImportChunks) Sec->addChunk(C); - } // Create SEH table. x86-only. if (Config->Machine != I386) return; + std::set Handlers; for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { if (!File->SEHCompat) @@ -303,8 +310,9 @@ for (SymbolBody *B : File->SEHandlers) Handlers.insert(cast(B->repl())); } + SEHTable.reset(new SEHTableChunk(Handlers)); - createSection(".rdata")->addChunk(SEHTable.get()); + Sec->addChunk(SEHTable.get()); } // Create .idata section for the DLL-imported symbol table. @@ -596,6 +604,11 @@ Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA(); Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize(); } + if (Config->Debug) { + Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = + DebugDirectory.Directories->getRVA(); + Dir[DEBUG_DIRECTORY].Size = DebugDirectory.Directories->getSize(); + } if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { if (Defined *B = dyn_cast(Sym->Body)) { Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA();