forked from OSchip/llvm-project
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
This commit is contained in:
parent
f8bab1ce0c
commit
8fcff934ba
|
@ -86,6 +86,7 @@ struct Configuration {
|
||||||
bool Debug = false;
|
bool Debug = false;
|
||||||
bool WriteSymtab = true;
|
bool WriteSymtab = true;
|
||||||
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
|
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
|
||||||
|
StringRef PDBPath;
|
||||||
|
|
||||||
// Symbols in this set are considered as live by the garbage collector.
|
// Symbols in this set are considered as live by the garbage collector.
|
||||||
std::set<Undefined *> GCRoot;
|
std::set<Undefined *> GCRoot;
|
||||||
|
|
|
@ -372,6 +372,12 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
|
||||||
: getDefaultDebugType(Args);
|
: 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
|
// Handle /noentry
|
||||||
if (Args.hasArg(OPT_noentry)) {
|
if (Args.hasArg(OPT_noentry)) {
|
||||||
if (!Args.hasArg(OPT_dll))
|
if (!Args.hasArg(OPT_dll))
|
||||||
|
@ -743,10 +749,6 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
|
||||||
if (Config->Manifest == Configuration::SideBySide)
|
if (Config->Manifest == Configuration::SideBySide)
|
||||||
createSideBySideManifest();
|
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.
|
// Identify unreferenced COMDAT sections.
|
||||||
if (Config->DoGC)
|
if (Config->DoGC)
|
||||||
markLive(Symtab.getChunks());
|
markLive(Symtab.getChunks());
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include "llvm/Support/Endian.h"
|
#include "llvm/Support/Endian.h"
|
||||||
#include "llvm/Support/FileOutputBuffer.h"
|
#include "llvm/Support/FileOutputBuffer.h"
|
||||||
|
#include "llvm/Support/RandomNumberGenerator.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -42,6 +43,61 @@ static const int DOSStubSize = 64;
|
||||||
static const int NumberfOfDataDirectory = 16;
|
static const int NumberfOfDataDirectory = 16;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
class DebugDirectoryChunk : public Chunk {
|
||||||
|
public:
|
||||||
|
DebugDirectoryChunk(const std::vector<std::unique_ptr<Chunk>> &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<debug_directory *>(B + OutputSectionOff);
|
||||||
|
|
||||||
|
for (const std::unique_ptr<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();
|
||||||
|
// TODO(compnerd) get the file offset
|
||||||
|
D->PointerToRawData = 0;
|
||||||
|
|
||||||
|
++D;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::vector<std::unique_ptr<Chunk>> &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<codeview::DebugInfo *>(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<char *>(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.
|
// The writer writes a SymbolTable result to a file.
|
||||||
class Writer {
|
class Writer {
|
||||||
public:
|
public:
|
||||||
|
@ -87,6 +143,9 @@ private:
|
||||||
EdataContents Edata;
|
EdataContents Edata;
|
||||||
std::unique_ptr<SEHTableChunk> SEHTable;
|
std::unique_ptr<SEHTableChunk> SEHTable;
|
||||||
|
|
||||||
|
std::unique_ptr<Chunk> DebugDirectory;
|
||||||
|
std::vector<std::unique_ptr<Chunk>> DebugRecords;
|
||||||
|
|
||||||
uint64_t FileSize;
|
uint64_t FileSize;
|
||||||
uint32_t PointerToSymbolTable = 0;
|
uint32_t PointerToSymbolTable = 0;
|
||||||
uint64_t SizeOfImage;
|
uint64_t SizeOfImage;
|
||||||
|
@ -294,6 +353,19 @@ void Writer::createMiscChunks() {
|
||||||
RData->addChunk(C);
|
RData->addChunk(C);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create Debug Information Chunks
|
||||||
|
if (Config->Debug) {
|
||||||
|
DebugDirectory = make_unique<DebugDirectoryChunk>(DebugRecords);
|
||||||
|
|
||||||
|
// TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled
|
||||||
|
if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV))
|
||||||
|
DebugRecords.push_back(make_unique<CVDebugRecordChunk>());
|
||||||
|
|
||||||
|
RData->addChunk(DebugDirectory.get());
|
||||||
|
for (const std::unique_ptr<Chunk> &C : DebugRecords)
|
||||||
|
RData->addChunk(C.get());
|
||||||
|
}
|
||||||
|
|
||||||
// Create SEH table. x86-only.
|
// Create SEH table. x86-only.
|
||||||
if (Config->Machine != I386)
|
if (Config->Machine != I386)
|
||||||
return;
|
return;
|
||||||
|
@ -608,6 +680,10 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
|
||||||
: sizeof(object::coff_tls_directory32);
|
: 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 (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) {
|
||||||
if (auto *B = dyn_cast<DefinedRegular>(Sym->Body)) {
|
if (auto *B = dyn_cast<DefinedRegular>(Sym->Body)) {
|
||||||
SectionChunk *SC = B->getChunk();
|
SectionChunk *SC = B->getChunk();
|
||||||
|
|
|
@ -14,7 +14,7 @@ IMPORT-NEXT: Name: std32.dll
|
||||||
IMPORT-NEXT: Attributes: 0x1
|
IMPORT-NEXT: Attributes: 0x1
|
||||||
IMPORT-NEXT: ModuleHandle: 0x1018
|
IMPORT-NEXT: ModuleHandle: 0x1018
|
||||||
IMPORT-NEXT: ImportAddressTable: 0x1020
|
IMPORT-NEXT: ImportAddressTable: 0x1020
|
||||||
IMPORT-NEXT: ImportNameTable: 0x3040
|
IMPORT-NEXT: ImportNameTable: 0x4040
|
||||||
IMPORT-NEXT: BoundDelayImportTable: 0x0
|
IMPORT-NEXT: BoundDelayImportTable: 0x0
|
||||||
IMPORT-NEXT: UnloadDelayImportTable: 0x0
|
IMPORT-NEXT: UnloadDelayImportTable: 0x0
|
||||||
IMPORT-NEXT: Import {
|
IMPORT-NEXT: Import {
|
||||||
|
@ -71,7 +71,7 @@ BASEREL-NEXT: }
|
||||||
BASEREL-NEXT: ]
|
BASEREL-NEXT: ]
|
||||||
|
|
||||||
DISASM: 202b: 68 20 10 40 00 pushl $4198432
|
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: 2035: e8 c6 ff ff ff calll -58 <_main@0>
|
||||||
DISASM-NEXT: 203a: 5a popl %edx
|
DISASM-NEXT: 203a: 5a popl %edx
|
||||||
DISASM-NEXT: 203b: 59 popl %ecx
|
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: 203e: 51 pushl %ecx
|
||||||
DISASM-NEXT: 203f: 52 pushl %edx
|
DISASM-NEXT: 203f: 52 pushl %edx
|
||||||
DISASM-NEXT: 2040: 68 24 10 40 00 pushl $4198436
|
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: 204a: e8 b1 ff ff ff calll -79 <_main@0>
|
||||||
DISASM-NEXT: 204f: 5a popl %edx
|
DISASM-NEXT: 204f: 5a popl %edx
|
||||||
DISASM-NEXT: 2050: 59 popl %ecx
|
DISASM-NEXT: 2050: 59 popl %ecx
|
||||||
|
|
|
@ -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
|
||||||
|
...
|
|
@ -74,7 +74,7 @@
|
||||||
# CHECK-NEXT: Symbol {
|
# CHECK-NEXT: Symbol {
|
||||||
# CHECK-NEXT: Name: __imp_ExitProcess
|
# CHECK-NEXT: Name: __imp_ExitProcess
|
||||||
# CHECK-NEXT: Value: 64
|
# CHECK-NEXT: Value: 64
|
||||||
# CHECK-NEXT: Section: .idata (4)
|
# CHECK-NEXT: Section: .idata (5)
|
||||||
# CHECK-NEXT: BaseType: Null (0x0)
|
# CHECK-NEXT: BaseType: Null (0x0)
|
||||||
# CHECK-NEXT: ComplexType: Null (0x0)
|
# CHECK-NEXT: ComplexType: Null (0x0)
|
||||||
# CHECK-NEXT: StorageClass: External (0x2)
|
# CHECK-NEXT: StorageClass: External (0x2)
|
||||||
|
@ -92,7 +92,7 @@
|
||||||
# CHECK-NEXT: Symbol {
|
# CHECK-NEXT: Symbol {
|
||||||
# CHECK-NEXT: Name: __imp_MessageBoxA
|
# CHECK-NEXT: Name: __imp_MessageBoxA
|
||||||
# CHECK-NEXT: Value: 72
|
# CHECK-NEXT: Value: 72
|
||||||
# CHECK-NEXT: Section: .idata (4)
|
# CHECK-NEXT: Section: .idata (5)
|
||||||
# CHECK-NEXT: BaseType: Null (0x0)
|
# CHECK-NEXT: BaseType: Null (0x0)
|
||||||
# CHECK-NEXT: ComplexType: Null (0x0)
|
# CHECK-NEXT: ComplexType: Null (0x0)
|
||||||
# CHECK-NEXT: StorageClass: External (0x2)
|
# CHECK-NEXT: StorageClass: External (0x2)
|
||||||
|
|
Loading…
Reference in New Issue