Index: lld/COFF/Config.h =================================================================== --- lld/COFF/Config.h +++ lld/COFF/Config.h @@ -99,6 +99,7 @@ bool DebugGHashes = false; bool ShowTiming = false; unsigned DebugTypes = static_cast(DebugType::None); + std::vector NatvisFiles; llvm::SmallString<128> PDBPath; std::vector Argv; Index: lld/COFF/Driver.cpp =================================================================== --- lld/COFF/Driver.cpp +++ lld/COFF/Driver.cpp @@ -929,9 +929,12 @@ // Handle /pdb bool ShouldCreatePDB = Args.hasArg(OPT_debug, OPT_debug_ghash); - if (ShouldCreatePDB) + if (ShouldCreatePDB) { if (auto *Arg = Args.getLastArg(OPT_pdb)) Config->PDBPath = Arg->getValue(); + if (Args.hasArg(OPT_natvis)) + Config->NatvisFiles = Args.getAllArgValues(OPT_natvis); + } // Handle /noentry if (Args.hasArg(OPT_noentry)) { Index: lld/COFF/Options.td =================================================================== --- lld/COFF/Options.td +++ lld/COFF/Options.td @@ -45,6 +45,7 @@ def opt : P<"opt", "Control optimizations">; def order : P<"order", "Put functions in order">; def out : P<"out", "Path to file to write output">; +def natvis : P<"natvis", "Path to natvis file to embed in the PDB">; def pdb : P<"pdb", "PDB file path">; def section : P<"section", "Specify section attributes">; def stack : P<"stack", "Size of the stack">; @@ -161,7 +162,6 @@ def errorreport : QF<"errorreport">; def idlout : QF<"idlout">; def maxilksize : QF<"maxilksize">; -def natvis : QF<"natvis">; def pdbaltpath : QF<"pdbaltpath">; def tlbid : QF<"tlbid">; def tlbout : QF<"tlbout">; Index: lld/COFF/PDB.cpp =================================================================== --- lld/COFF/PDB.cpp +++ lld/COFF/PDB.cpp @@ -90,6 +90,9 @@ /// Emit the basic PDB structure: initial streams, headers, etc. void initialize(const llvm::codeview::DebugInfo &BuildId); + /// Add natvis files specified on the command line. + void addNatvisFiles(); + /// Link CodeView from each object file in the symbol table into the PDB. void addObjectsToPDB(); @@ -961,6 +964,27 @@ } } +void PDBLinker::addNatvisFiles() { + if (Config->NatvisFiles.empty()) + return; + + // We don't know what this is for, but link.exe creates it when natvis files + // are linked in. So just create it with 0 size in case it's important. + ExitOnErr(Builder.addNamedStream("/src/headerblock", StringRef())); + + for (StringRef File : Config->NatvisFiles) { + ErrorOr> DataOrErr = + MemoryBuffer::getFile(File); + if (!DataOrErr) { + warn("Cannot open input file: " + File); + continue; + } + std::unique_ptr NatvisData = std::move(*DataOrErr); + std::string StreamName = (Twine("/src/files/") + File).str(); + ExitOnErr(Builder.addNamedStream(StreamName, NatvisData->getBuffer())); + } +} + static void addCommonLinkerModuleSymbols(StringRef Path, pdb::DbiModuleDescriptorBuilder &Mod, BumpPtrAllocator &Allocator) { @@ -1041,6 +1065,7 @@ PDB.initialize(BuildId); PDB.addObjectsToPDB(); PDB.addSections(OutputSections, SectionTable); + PDB.addNatvisFiles(); ScopedTimer T2(DiskCommitTimer); PDB.commit(); Index: lld/test/COFF/Inputs/generic.yaml =================================================================== --- /dev/null +++ lld/test/COFF/Inputs/generic.yaml @@ -0,0 +1,282 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 4883EC1831C0C7442414000000004889542408894C24044883C418C3 + - 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: '' + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004220000' + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 202F44454641554C544C49423A6C6962636D742E6C6962202F44454641554C544C49423A6F6C646E616D65732E6C6962 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 04000000F10000002F0000002D003C1101000000D0000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F1000000760000002A0047110000000000000000000000001C000000000000000000000003100000000000000000006D61696E000D003E117400000001006172676300120045114F0100000400000017000000000005000D003E110010000001006172677600120045114F01000008000000170000000000050002004F110000F20000002800000000000000000000001C00000000000000020000001C00000000000000020000001700000003000000F40000001800000001000000100139E9A066A1995A99DD01F5A392F26D7C0000F30000003000000000443A5C7372635C6C6C766D6275696C645C636C5C52656C656173655C7836345C67656E657269632E63707000000000 + Subsections: + - !Symbols + Records: + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ ] + Machine: X64 + FrontendMajor: 7 + FrontendMinor: 0 + FrontendBuild: 0 + FrontendQFE: 0 + BackendMajor: 7000 + BackendMinor: 0 + BackendBuild: 0 + BackendQFE: 0 + Version: 'clang version 7.0.0 ' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 28 + DbgStart: 0 + DbgEnd: 0 + FunctionType: 4099 + Flags: [ ] + DisplayName: main + - Kind: S_LOCAL + LocalSym: + Type: 116 + Flags: [ IsParameter ] + VarName: argc + - Kind: S_DEFRANGE_REGISTER_REL + DefRangeRegisterRelSym: + Register: 335 + Flags: 0 + BasePointerOffset: 4 + Range: + OffsetStart: 23 + ISectStart: 0 + Range: 5 + Gaps: + - Kind: S_LOCAL + LocalSym: + Type: 4096 + Flags: [ IsParameter ] + VarName: argv + - Kind: S_DEFRANGE_REGISTER_REL + DefRangeRegisterRelSym: + Register: 335 + Flags: 0 + BasePointerOffset: 8 + Range: + OffsetStart: 23 + ISectStart: 0 + Range: 5 + Gaps: + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 28 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'D:\src\llvmbuild\cl\Release\x64\generic.cpp' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: false + EndDelta: 0 + - Offset: 23 + LineStart: 3 + IsStatement: false + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'D:\src\llvmbuild\cl\Release\x64\generic.cpp' + Kind: MD5 + Checksum: 39E9A066A1995A99DD01F5A392F26D7C + - !StringTable + Strings: + - 'D:\src\llvmbuild\cl\Release\x64\generic.cpp' + - '' + - '' + - '' + Relocations: + - VirtualAddress: 100 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 104 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 139 + SymbolName: .text + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 143 + SymbolName: .text + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 174 + SymbolName: .text + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 178 + SymbolName: .text + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 196 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 200 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 040000000A000210700600000C0001000E0001120200000074000000001000000E0008107400000000000200011000001200011600000000021000006D61696E00F3F2F1 + Types: + - Kind: LF_POINTER + Pointer: + ReferentType: 1648 + Attrs: 65548 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116, 4096 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 2 + ArgumentList: 4097 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4098 + Name: main + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 000000001C00000000000000 + Relocations: + - VirtualAddress: 0 + SymbolName: main + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: main + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: .xdata + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 28 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 594448369 + 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: .xdata + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 1192424177 + Number: 4 + - Name: .drectve + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 48 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 149686238 + Number: 5 + - Name: '.debug$S' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 324 + NumberOfRelocations: 8 + NumberOfLinenumbers: 0 + CheckSum: 4196717433 + Number: 6 + - Name: '.debug$T' + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 68 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 485351071 + Number: 7 + - Name: .pdata + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 722740324 + Number: 8 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: lld/test/COFF/Inputs/test.natvis =================================================================== --- /dev/null +++ lld/test/COFF/Inputs/test.natvis @@ -0,0 +1,6 @@ + + + + This is a test + + Index: lld/test/COFF/pdb-natvis.test =================================================================== --- /dev/null +++ lld/test/COFF/pdb-natvis.test @@ -0,0 +1,11 @@ +RUN: yaml2obj %p/Inputs/generic.yaml > %t.obj +RUN: lld-link /DEBUG %t.obj /nodefaultlib /entry:main /NATVIS:%p/Inputs/test.natvis \ +RUN: /OUT:%t.exe /PDB:%t.pdb +RUN: llvm-pdbutil dump -streams %t.pdb | FileCheck %s + +RUN: lld-link /DEBUG %t.obj /nodefaultlib /entry:main /NATVIS:%p/Inputs/test2.natvis \ +RUN: /OUT:%t.exe /PDB:%t.pdb 2>&1 | FileCheck --check-prefix=CHECK-MISSING %s + +CHECK: 226 bytes): [Named Stream "/src/files/{{.*}}test.natvis"] + +CHECK-MISSING: Cannot open input file: {{.*}}test2.natvis \ No newline at end of file Index: llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h +++ llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h @@ -54,7 +54,7 @@ Error commit(StringRef Filename); Expected getNamedStreamIndex(StringRef Name) const; - Error addNamedStream(StringRef Name, uint32_t Size); + Error addNamedStream(StringRef Name, StringRef Data); private: Expected finalizeMsfLayout(); @@ -62,6 +62,7 @@ void commitFpm(WritableBinaryStream &MsfBuffer, const msf::MSFLayout &Layout); BumpPtrAllocator &Allocator; + Expected allocateNamedStream(StringRef Name, uint32_t Size); std::unique_ptr Msf; std::unique_ptr Info; @@ -72,6 +73,7 @@ PDBStringTableBuilder Strings; NamedStreamMap NamedStreams; + DenseMap NamedStreamData; }; } } Index: llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -80,11 +80,20 @@ return *Gsi; } -Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) { +Expected PDBFileBuilder::allocateNamedStream(StringRef Name, + uint32_t Size) { auto ExpectedStream = Msf->addStream(Size); - if (!ExpectedStream) - return ExpectedStream.takeError(); - NamedStreams.set(Name, *ExpectedStream); + if (ExpectedStream) + NamedStreams.set(Name, *ExpectedStream); + return ExpectedStream; +} + +Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) { + Expected ExpectedIndex = allocateNamedStream(Name, Data.size()); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + assert(NamedStreamData.count(*ExpectedIndex) == 0); + NamedStreamData[*ExpectedIndex] = Data; return Error::success(); } @@ -101,10 +110,12 @@ uint32_t StringsLen = Strings.calculateSerializedSize(); - if (auto EC = addNamedStream("/names", StringsLen)) - return std::move(EC); - if (auto EC = addNamedStream("/LinkInfo", 0)) - return std::move(EC); + Expected SN = allocateNamedStream("/names", StringsLen); + if (!SN) + return SN.takeError(); + SN = allocateNamedStream("/LinkInfo", 0); + if (!SN) + return SN.takeError(); if (Info) { if (auto EC = Info->finalizeMsfLayout()) @@ -219,6 +230,17 @@ if (auto EC = Strings.commit(NSWriter)) return EC; + for (const auto &NSE : NamedStreamData) { + if (NSE.second.empty()) + continue; + + auto NS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, NSE.first, Allocator); + BinaryStreamWriter NSW(*NS); + if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second))) + return EC; + } + if (Info) { if (auto EC = Info->commit(Layout, Buffer)) return EC; Index: llvm/tools/llvm-pdbutil/DumpOutputStyle.h =================================================================== --- llvm/tools/llvm-pdbutil/DumpOutputStyle.h +++ llvm/tools/llvm-pdbutil/DumpOutputStyle.h @@ -74,6 +74,7 @@ Error dumpStreamSummary(); Error dumpSymbolStats(); Error dumpUdtStats(); + Error dumpNamedStreams(); Error dumpStringTable(); Error dumpStringTableFromPdb(); Error dumpStringTableFromObj(); Index: llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp =================================================================== --- llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -90,6 +90,12 @@ P.NewLine(); } + if (opts::dump::DumpNamedStreams) { + if (auto EC = dumpNamedStreams()) + return EC; + P.NewLine(); + } + if (opts::dump::DumpStringTable) { if (auto EC = dumpStringTable()) return EC; @@ -909,6 +915,29 @@ return Error::success(); } +Error DumpOutputStyle::dumpNamedStreams() { + printHeader(P, "Named Streams"); + AutoIndent Indent(P, 2); + + if (File.isObj()) { + P.formatLine("Dumping Named Streams is only supported for PDB files."); + return Error::success(); + } + ExitOnError Err("Invalid PDB File: "); + + auto &IS = Err(File.pdb().getPDBInfoStream()); + const NamedStreamMap &NS = IS.getNamedStreams(); + for (const auto &Entry : NS.entries()) { + P.printLine(Entry.getKey()); + AutoIndent Indent2(P, 2); + P.formatLine("Index: {0}", Entry.getValue()); + P.formatLine("Size in bytes: {0}", + File.pdb().getStreamByteSize(Entry.getValue())); + } + + return Error::success(); +} + Error DumpOutputStyle::dumpStringTable() { printHeader(P, "String Table"); Index: llvm/tools/llvm-pdbutil/llvm-pdbutil.h =================================================================== --- llvm/tools/llvm-pdbutil/llvm-pdbutil.h +++ llvm/tools/llvm-pdbutil/llvm-pdbutil.h @@ -142,6 +142,7 @@ extern llvm::cl::opt DumpInlineeLines; extern llvm::cl::opt DumpXmi; extern llvm::cl::opt DumpXme; +extern llvm::cl::opt DumpNamedStreams; extern llvm::cl::opt DumpStringTable; extern llvm::cl::opt DumpTypes; extern llvm::cl::opt DumpTypeData; Index: llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp =================================================================== --- llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -530,6 +530,10 @@ cl::cat(FileOptions), cl::sub(DumpSubcommand)); // MISCELLANEOUS OPTIONS +cl::opt DumpNamedStreams("named-streams", + cl::desc("dump PDB named stream table"), + cl::cat(MiscOptions), cl::sub(DumpSubcommand)); + cl::opt DumpStringTable("string-table", cl::desc("dump PDB String Table"), cl::cat(MiscOptions), cl::sub(DumpSubcommand)); @@ -1250,7 +1254,7 @@ // After all fields have been zeroed out, hash the executable and then write // the hash to the appropriate places (coff file header + CV debug // directories). - + StringRef ExeData = toStringRef(ExeBufferPtr->getBuffer()); uint32_t Hash = static_cast(xxHash64(ExeData)); MutableCFH->TimeDateStamp = Hash;