Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -204,7 +204,9 @@ StringRef ParentName) { file_magic Magic = identify_magic(MB.getBuffer()); if (Magic == file_magic::coff_import_library) { - Symtab->addFile(make(MB)); + InputFile *Imp = make(MB); + Imp->ParentName = ParentName; + Symtab->addFile(Imp); return; } Index: lld/trunk/COFF/InputFiles.cpp =================================================================== --- lld/trunk/COFF/InputFiles.cpp +++ lld/trunk/COFF/InputFiles.cpp @@ -778,7 +778,7 @@ std::string lld::toString(const coff::InputFile *File) { if (!File) return ""; - if (File->ParentName.empty()) + if (File->ParentName.empty() || File->kind() == coff::InputFile::ImportKind) return File->getName(); return (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + Index: lld/trunk/COFF/PDB.cpp =================================================================== --- lld/trunk/COFF/PDB.cpp +++ lld/trunk/COFF/PDB.cpp @@ -109,6 +109,9 @@ /// Link CodeView from each object file in the symbol table into the PDB. void addObjectsToPDB(); + /// Link info for each import file in the symbol table into the PDB. + void addImportFilesToPDB(ArrayRef OutputSections); + /// Link CodeView from a single object file into the target (output) PDB. /// When a precompiled headers object is linked, its TPI map might be provided /// externally. @@ -878,7 +881,7 @@ } static void scopeStackClose(SmallVectorImpl &Stack, - uint32_t CurOffset, ObjFile *File) { + uint32_t CurOffset, InputFile *File) { if (Stack.empty()) { warn("symbol scopes are not balanced in " + File->getName()); return; @@ -1088,13 +1091,13 @@ } static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) { - OutputSection *OS = C->getOutputSection(); + OutputSection *OS = C ? C->getOutputSection() : nullptr; pdb::SectionContrib SC; memset(&SC, 0, sizeof(SC)); - SC.ISect = OS->SectionIndex; - SC.Off = C->getRVA() - OS->getRVA(); - SC.Size = C->getSize(); - if (auto *SecChunk = dyn_cast(C)) { + SC.ISect = OS ? OS->SectionIndex : llvm::pdb::kInvalidStreamIndex; + SC.Off = C && OS ? C->getRVA() - OS->getRVA() : 0; + SC.Size = C ? C->getSize() : -1; + if (auto *SecChunk = dyn_cast_or_null(C)) { SC.Characteristics = SecChunk->Header->Characteristics; SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex(); ArrayRef Contents = SecChunk->getContents(); @@ -1104,7 +1107,7 @@ CRC.update(CharContents); SC.DataCrc = CRC.getCRC(); } else { - SC.Characteristics = OS->Header.Characteristics; + SC.Characteristics = OS ? OS->Header.Characteristics : 0; // FIXME: When we start creating DBI for import libraries, use those here. SC.Imod = Modi; } @@ -1442,16 +1445,7 @@ return R; } -static void addCommonLinkerModuleSymbols(StringRef Path, - pdb::DbiModuleDescriptorBuilder &Mod, - BumpPtrAllocator &Allocator) { - ObjNameSym ONS(SymbolRecordKind::ObjNameSym); - Compile3Sym CS(SymbolRecordKind::Compile3Sym); - EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym); - - ONS.Name = "* Linker *"; - ONS.Signature = 0; - +static void fillLinkerVerRecord(Compile3Sym &CS) { CS.Machine = toCodeViewMachine(Config->Machine); // Interestingly, if we set the string to 0.0.0.0, then when trying to view // local variables WinDbg emits an error that private symbols are not present. @@ -1475,6 +1469,18 @@ CS.VersionFrontendQFE = 0; CS.Version = "LLVM Linker"; CS.setLanguage(SourceLanguage::Link); +} + +static void addCommonLinkerModuleSymbols(StringRef Path, + pdb::DbiModuleDescriptorBuilder &Mod, + BumpPtrAllocator &Allocator) { + ObjNameSym ONS(SymbolRecordKind::ObjNameSym); + EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym); + Compile3Sym CS(SymbolRecordKind::Compile3Sym); + fillLinkerVerRecord(CS); + + ONS.Name = "* Linker *"; + ONS.Signature = 0; ArrayRef Args = makeArrayRef(Config->Argv).drop_front(); std::string ArgStr = quote(Args); @@ -1501,6 +1507,33 @@ EBS, Allocator, CodeViewContainer::Pdb)); } +static void addLinkerModuleCoffGroup(PartialSection *Sec, + pdb::DbiModuleDescriptorBuilder &Mod, + OutputSection &OS, + BumpPtrAllocator &Allocator) { + // If there's a section, there's at least one chunk + assert(!Sec->Chunks.empty()); + const Chunk *firstChunk = *Sec->Chunks.begin(); + const Chunk *lastChunk = *Sec->Chunks.rbegin(); + + // Emit COFF group + CoffGroupSym CGS(SymbolRecordKind::CoffGroupSym); + CGS.Name = Sec->Name; + CGS.Segment = OS.SectionIndex; + CGS.Offset = firstChunk->getRVA() - OS.getRVA(); + CGS.Size = lastChunk->getRVA() + lastChunk->getSize() - firstChunk->getRVA(); + CGS.Characteristics = Sec->Characteristics; + + // Somehow .idata sections & sections groups in the debug symbol stream have + // the "write" flag set. However the section header for the corresponding + // .idata section doesn't have it. + if (CGS.Name.startswith(".idata")) + CGS.Characteristics |= llvm::COFF::IMAGE_SCN_MEM_WRITE; + + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + CGS, Allocator, CodeViewContainer::Pdb)); +} + static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &Mod, OutputSection &OS, BumpPtrAllocator &Allocator) { @@ -1513,6 +1546,102 @@ Sym.SectionNumber = OS.SectionIndex; Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( Sym, Allocator, CodeViewContainer::Pdb)); + + // Skip COFF groups in MinGW because it adds a significant footprint to the + // PDB, due to each function being in its own section + if (Config->MinGW) + return; + + // Output COFF groups for individual chunks of this section. + for (PartialSection *Sec : OS.ContribSections) { + addLinkerModuleCoffGroup(Sec, Mod, OS, Allocator); + } +} + +// Add all import files as modules to the PDB. +void PDBLinker::addImportFilesToPDB(ArrayRef OutputSections) { + if (ImportFile::Instances.empty()) + return; + + std::map ModSet; + + for (ImportFile *File : ImportFile::Instances) { + if (!File->Live) + continue; + + if (!File->ThunkSym) + continue; + + std::string DLL = StringRef(File->DLLName).lower(); + auto &Mod = ModSet[DLL]; + if (!Mod) { + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); + SmallString<128> LibPath = File->ParentName; + pdbMakeAbsolute(LibPath); + sys::path::native(LibPath); + + auto CreateMod = [&](Twine S) -> llvm::pdb::DbiModuleDescriptorBuilder * { + SmallString<128> Name; + S.toVector(Name); + auto *M = &ExitOnErr(DbiBuilder.addModuleInfo(Name)); + M->setObjFileName(LibPath); + return M; + }; + + // Name modules similar to MSVC's link.exe. + // The first module is the simple dll filename + // The second is the actual import module, where the import stream goes. + auto FirstMod = CreateMod(File->DLLName); + pdb::SectionContrib SC = + createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex); + FirstMod->setFirstSectionContrib(SC); + + Mod = CreateMod("Import:" + File->DLLName); + } + + DefinedImportThunk *Thunk = cast(File->ThunkSym); + + ObjNameSym ONS(SymbolRecordKind::ObjNameSym); + Compile3Sym CS(SymbolRecordKind::Compile3Sym); + Thunk32Sym TS(SymbolRecordKind::Thunk32Sym); + ScopeEndSym ES(SymbolRecordKind::ScopeEndSym); + + ONS.Name = File->DLLName; + ONS.Signature = 0; + + fillLinkerVerRecord(CS); + + TS.Name = Thunk->getName(); + TS.Parent = 0; + TS.End = 0; + TS.Next = 0; + TS.Thunk = ThunkOrdinal::Standard; + TS.Length = Thunk->getChunk()->getSize(); + TS.Segment = Thunk->getChunk()->getOutputSection()->SectionIndex; + TS.Offset = Thunk->getChunk()->OutputSectionOff; + + Mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol( + ONS, Alloc, CodeViewContainer::Pdb)); + Mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol( + CS, Alloc, CodeViewContainer::Pdb)); + + SmallVector Scopes; + CVSymbol NewSym = codeview::SymbolSerializer::writeOneSymbol( + TS, Alloc, CodeViewContainer::Pdb); + scopeStackOpen(Scopes, Mod->getNextSymbolOffset(), NewSym); + + Mod->addSymbol(NewSym); + + NewSym = codeview::SymbolSerializer::writeOneSymbol(ES, Alloc, + CodeViewContainer::Pdb); + scopeStackClose(Scopes, Mod->getNextSymbolOffset(), File); + + Mod->addSymbol(NewSym); + + pdb::SectionContrib SC = + createSectionContrib(Thunk->getChunk(), Mod->getModuleIndex()); + Mod->setFirstSectionContrib(SC); + } } // Creates a PDB file. @@ -1525,6 +1654,7 @@ PDB.initialize(BuildId); PDB.addObjectsToPDB(); + PDB.addImportFilesToPDB(OutputSections); PDB.addSections(OutputSections, SectionTable); PDB.addNatvisFiles(); @@ -1589,6 +1719,13 @@ } } + // The * Linker * first section contrib is only used along with /INCREMENTAL, + // to provide trampolines thunks for incremental function patching. Set this + // as "unused" because LLD doesn't support /INCREMENTAL link. + pdb::SectionContrib SC = + createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex); + LinkerModule.setFirstSectionContrib(SC); + // Add Section Map stream. ArrayRef Sections = { (const object::coff_section *)SectionTable.data(), Index: lld/trunk/COFF/Writer.h =================================================================== --- lld/trunk/COFF/Writer.h +++ lld/trunk/COFF/Writer.h @@ -22,6 +22,15 @@ void writeResult(); +class PartialSection { +public: + PartialSection(StringRef N, uint32_t Chars) + : Name(N), Characteristics(Chars) {} + StringRef Name; + unsigned Characteristics; + std::vector Chunks; +}; + // OutputSection represents a section in an output file. It's a // container of chunks. OutputSection and Chunk are 1:N relationship. // Chunks cannot belong to more than one OutputSections. The writer @@ -40,6 +49,7 @@ uint64_t getRVA() { return Header.VirtualAddress; } uint64_t getFileOff() { return Header.PointerToRawData; } void writeHeaderTo(uint8_t *Buf); + void addContributingPartialSection(PartialSection *Sec); // Returns the size of this section in an executable memory image. // This may be smaller than the raw size (the raw size is multiple @@ -64,11 +74,13 @@ std::vector Chunks; std::vector OrigChunks; + std::vector ContribSections; + private: uint32_t StringTableOff = 0; }; -} -} +} // namespace coff +} // namespace lld #endif Index: lld/trunk/COFF/Writer.cpp =================================================================== --- lld/trunk/COFF/Writer.cpp +++ lld/trunk/COFF/Writer.cpp @@ -175,15 +175,6 @@ } }; -class PartialSection { -public: - PartialSection(StringRef N, uint32_t Chars) - : Name(N), Characteristics(Chars) {} - StringRef Name; - unsigned Characteristics; - std::vector Chunks; -}; - // The writer writes a SymbolTable result to a file. class Writer { public: @@ -313,6 +304,8 @@ C->setOutputSection(this); Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end()); Other->Chunks.clear(); + ContribSections.insert(ContribSections.end(), Other->ContribSections.begin(), Other->ContribSections.end()); + Other->ContribSections.clear(); } // Write the section header to a given buffer. @@ -330,6 +323,10 @@ } } +void OutputSection::addContributingPartialSection(PartialSection *Sec) { + ContribSections.push_back(Sec); +} + } // namespace coff } // namespace lld @@ -806,6 +803,8 @@ OutputSection *Sec = CreateSection(Name, OutChars); for (Chunk *C : PSec->Chunks) Sec->addChunk(C); + + Sec->addContributingPartialSection(PSec); } // Finally, move some output sections to the end. Index: lld/trunk/test/COFF/pdb-global-gc.yaml =================================================================== --- lld/trunk/test/COFF/pdb-global-gc.yaml +++ lld/trunk/test/COFF/pdb-global-gc.yaml @@ -23,6 +23,7 @@ # CHECK: ============================================================ # CHECK-NEXT: Mod 0000 | `{{.*}}pdb-global-gc.yaml.tmp.obj`: # CHECK-NEXT: Mod 0001 | `{{.*}}pdb-global-gc.yaml.tmp2.obj`: +# CHECK-NEXT: Error loading module stream 1. The specified stream could not be loaded. Module stream not present # CHECK-NEXT: Mod 0002 | `* Linker *`: --- !COFF Index: lld/trunk/test/COFF/pdb-lib.s =================================================================== --- lld/trunk/test/COFF/pdb-lib.s +++ lld/trunk/test/COFF/pdb-lib.s @@ -13,15 +13,15 @@ # CHECK-NEXT: ============================================================ # CHECK-NEXT: Mod 0000 | `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`: # CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`: -# CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false +# CHECK-NEXT: debug stream: 65535, # files: 0, has ec info: false # CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` # CHECK-NEXT: Mod 0001 | `bar.obj`: # CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]bar.lib}}`: -# CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false +# CHECK-NEXT: debug stream: 65535, # files: 0, has ec info: false # CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` # CHECK-NEXT: Mod 0002 | `* Linker *`: # CHECK-NEXT: Obj: ``: -# CHECK-NEXT: debug stream: 12, # files: 0, has ec info: false +# CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false # CHECK-NEXT: pdb file ni: 1 `{{.*foo.pdb}}`, src file ni: 0 `` .def _main; Index: lld/trunk/test/COFF/pdb-publics-import.test =================================================================== --- lld/trunk/test/COFF/pdb-publics-import.test +++ lld/trunk/test/COFF/pdb-publics-import.test @@ -8,7 +8,48 @@ RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj RUN: lld-link /out:%t2.exe /pdb:%t2.pdb /pdbaltpath:test.pdb \ RUN: /debug /entry:main %t2.obj %t1.lib -RUN: llvm-pdbutil dump %t2.pdb -publics -section-contribs | FileCheck %s +RUN: llvm-pdbutil dump %t2.pdb -all | FileCheck %s + +CHECK: Streams +CHECK-NEXT: ============================================================ +CHECK-LABEL: Stream 10 ( 256 bytes): [Module "Import:pdb-publics-import.test.tmp1.dll"] + +CHECK: Module Stats +CHECK-NEXT: ============================================================ +CHECK-NEXT: Mod 0000 | `{{.*}}pdb-publics-import.test.tmp2.obj`: +CHECK-NEXT: Mod 0 (debug info not present): [{{.*}}pdb-publics-import.test.tmp2.obj] +CHECK-NEXT: Mod 0001 | `pdb-publics-import.test.tmp1.dll`: +CHECK-NEXT: Mod 1 (debug info not present): [pdb-publics-import.test.tmp1.dll] +CHECK-NEXT: Mod 0002 | `Import:pdb-publics-import.test.tmp1.dll`: +CHECK-NEXT: Stream 10, 256 bytes + +CHECK: Modules +CHECK-NEXT: ============================================================ +CHECK-NEXT: Mod 0000 | `{{.*}}pdb-publics-import.test.tmp2.obj`: +CHECK-NEXT: SC[.text] | mod = 0, 0001:0000, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_EXECUTE | +CHECK-NEXT: IMAGE_SCN_MEM_READ +CHECK-NEXT: Obj: `{{.*}}pdb-publics-import.test.tmp2.obj`: +CHECK-NEXT: debug stream: 65535, # files: 0, has ec info: false +CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` +CHECK-NEXT: Mod 0001 | `pdb-publics-import.test.tmp1.dll`: +CHECK-NEXT: SC[???] | mod = 65535, 65535:0000, size = -1, data crc = 0, reloc crc = 0 +CHECK-NEXT: none +CHECK-NEXT: Obj: `{{.*}}pdb-publics-import.test.tmp1.lib`: +CHECK-NEXT: debug stream: 65535, # files: 0, has ec info: false +CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` +CHECK-NEXT: Mod 0002 | `Import:pdb-publics-import.test.tmp1.dll`: +CHECK-NEXT: SC[.text] | mod = 2, 0001:0032, size = 6, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ +CHECK-NEXT: Obj: `{{.*}}pdb-publics-import.test.tmp1.lib`: +CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false +CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` +CHECK-NEXT: Mod 0003 | `* Linker *`: +CHECK-NEXT: SC[???] | mod = 65535, 65535:0000, size = -1, data crc = 0, reloc crc = 0 +CHECK-NEXT: none +CHECK-NEXT: Obj: ``: +CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false +CHECK-NEXT: pdb file ni: 1 `{{.*}}pdb-publics-import.test.tmp2.pdb`, src file ni: 0 `` CHECK: Public Symbols CHECK-NEXT: ============================================================ @@ -24,6 +65,86 @@ CHECK-NEXT: 0 | S_PUB32 [size = 32] `__imp_exportfn1` CHECK-NEXT: flags = none, addr = 0002:0128 +CHECK: Symbols +CHECK-NEXT: ============================================================ +CHECK-NEXT: Mod 0000 | `{{.*}}pdb-publics-import.test.tmp2.obj`: +CHECK-NEXT: Error loading module stream 0. The specified stream could not be loaded. Module stream not present +CHECK-NEXT: Mod 0001 | `pdb-publics-import.test.tmp1.dll`: +CHECK-NEXT: Error loading module stream 1. The specified stream could not be loaded. Module stream not present +CHECK-NEXT: Mod 0002 | `Import:pdb-publics-import.test.tmp1.dll`: +CHECK-NEXT: 4 | S_OBJNAME [size = 44] sig=0, `pdb-publics-import.test.tmp1.dll` +CHECK-NEXT: 48 | S_COMPILE3 [size = 40] +CHECK-NEXT: machine = intel x86-x64, Ver = LLVM Linker, language = link +CHECK-NEXT: frontend = 0.0.0.0, backend = 14.10.25019.0 +CHECK-NEXT: flags = none +CHECK-NEXT: 88 | S_THUNK32 [size = 36] `exportfn1` +CHECK-NEXT: parent = 0, end = 124, next = 0 +CHECK-NEXT: kind = thunk, size = 6, addr = 0001:0016 +CHECK-NEXT: 124 | S_END [size = 4] +CHECK-NEXT: 128 | S_OBJNAME [size = 44] sig=0, `pdb-publics-import.test.tmp1.dll` +CHECK-NEXT: 172 | S_COMPILE3 [size = 40] +CHECK-NEXT: machine = intel x86-x64, Ver = LLVM Linker, language = link +CHECK-NEXT: frontend = 0.0.0.0, backend = 14.10.25019.0 +CHECK-NEXT: flags = none +CHECK-NEXT: 212 | S_THUNK32 [size = 36] `exportfn2` +CHECK-NEXT: parent = 0, end = 248, next = 0 +CHECK-NEXT: kind = thunk, size = 6, addr = 0001:0032 +CHECK-NEXT: 248 | S_END [size = 4] +CHECK-NEXT: Mod 0003 | `* Linker *`: +CHECK-NEXT: 4 | S_OBJNAME [size = 20] sig=0, `* Linker *` +CHECK-NEXT: 24 | S_COMPILE3 [size = 40] +CHECK-NEXT: machine = intel x86-x64, Ver = LLVM Linker, language = link +CHECK-NEXT: frontend = 0.0.0.0, backend = 14.10.25019.0 +CHECK-NEXT: flags = none +CHECK-NEXT: 64 | S_ENVBLOCK [size = {{[0-9]+}}] +CHECK: {{[0-9]+}} | S_SECTION [size = 28] `.text` +CHECK-NEXT: length = 38, alignment = 12, rva = 4096, section # = 1 +CHECK-NEXT: characteristics = +CHECK-NEXT: code +CHECK-NEXT: execute permissions +CHECK-NEXT: read permissions +CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 24] `.text` +CHECK-NEXT: length = 8, addr = 0001:0000 +CHECK-NEXT: characteristics = +CHECK-NEXT: code +CHECK-NEXT: execute permissions +CHECK-NEXT: read permissions +CHECK-NEXT: {{[0-9]+}} | S_SECTION [size = 28] `.rdata` +CHECK-NEXT: length = 209, alignment = 12, rva = 8192, section # = 2 +CHECK-NEXT: characteristics = +CHECK-NEXT: initialized data +CHECK-NEXT: read permissions +CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 28] `.idata$2` +CHECK-NEXT: length = 40, addr = 0002:0061 +CHECK-NEXT: characteristics = +CHECK-NEXT: initialized data +CHECK-NEXT: read permissions +CHECK-NEXT: write permissions +CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 28] `.idata$4` +CHECK-NEXT: length = 24, addr = 0002:0104 +CHECK-NEXT: characteristics = +CHECK-NEXT: initialized data +CHECK-NEXT: read permissions +CHECK-NEXT: write permissions +CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 28] `.idata$5` +CHECK-NEXT: length = 24, addr = 0002:0128 +CHECK-NEXT: characteristics = +CHECK-NEXT: initialized data +CHECK-NEXT: read permissions +CHECK-NEXT: write permissions +CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 28] `.idata$6` +CHECK-NEXT: length = 24, addr = 0002:0152 +CHECK-NEXT: characteristics = +CHECK-NEXT: initialized data +CHECK-NEXT: read permissions +CHECK-NEXT: write permissions +CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 28] `.idata$7` +CHECK-NEXT: length = 33, addr = 0002:0176 +CHECK-NEXT: characteristics = +CHECK-NEXT: initialized data +CHECK-NEXT: read permissions +CHECK-NEXT: write permissions + CHECK: Section Contributions CHECK-NEXT: ============================================================ main @@ -31,13 +152,35 @@ CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_EXECUTE | CHECK-NEXT: IMAGE_SCN_MEM_READ exportfn1 thunk -CHECK-NEXT: SC[.text] | mod = 1, 0001:0016, size = 6, data crc = 0, reloc crc = 0 +CHECK-NEXT: SC[.text] | mod = 3, 0001:0016, size = 6, data crc = 0, reloc crc = 0 CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ exportfn2 thunk -CHECK-NEXT: SC[.text] | mod = 1, 0001:0032, size = 6, data crc = 0, reloc crc = 0 +CHECK-NEXT: SC[.text] | mod = 3, 0001:0032, size = 6, data crc = 0, reloc crc = 0 CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ .rdata debug directory data chunks -CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0000, size = 28, data crc = 0, reloc crc = 0 -CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ -CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0028, size = 33, data crc = 0, reloc crc = 0 +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0000, size = 28, data crc = 0, reloc crc = 0 CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0028, size = 33, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0061, size = 20, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0081, size = 20, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0104, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0112, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0120, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0128, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0136, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0144, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0152, size = 12, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0164, size = 12, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0176, size = 33, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ Index: lld/trunk/test/COFF/pdb.test =================================================================== --- lld/trunk/test/COFF/pdb.test +++ lld/trunk/test/COFF/pdb.test @@ -134,7 +134,7 @@ RAW-NEXT: debug stream: 12, # files: 1, has ec info: false RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` RAW-NEXT: Mod 0002 | `* Linker *`: -RAW-NEXT: SC[???] | mod = 2, 0000:0000, size = 0, data crc = 0, reloc crc = 0 +RAW-NEXT: SC[???] | mod = 65535, 65535:0000, size = -1, data crc = 0, reloc crc = 0 RAW-NEXT: none RAW-NEXT: Obj: ``: RAW-NEXT: debug stream: 13, # files: 0, has ec info: false Index: llvm/trunk/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -103,7 +103,6 @@ } void DbiModuleDescriptorBuilder::finalize() { - Layout.SC.Imod = Layout.Mod; Layout.FileNameOffs = 0; // TODO: Fix this Layout.Flags = 0; // TODO: Fix this Layout.C11Bytes = 0; @@ -116,12 +115,15 @@ // This value includes both the signature field as well as the record bytes // from the symbol stream. - Layout.SymBytes = SymbolByteSize + sizeof(uint32_t); + Layout.SymBytes = + Layout.ModDiStream == kInvalidStreamIndex ? 0 : getNextSymbolOffset(); } Error DbiModuleDescriptorBuilder::finalizeMsfLayout() { this->Layout.ModDiStream = kInvalidStreamIndex; uint32_t C13Size = calculateC13DebugInfoSize(); + if (!C13Size && !SymbolByteSize) + return Error::success(); auto ExpectedSN = MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size)); if (!ExpectedSN) Index: llvm/trunk/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/BinaryStreamRef.h" @@ -36,6 +37,17 @@ Error ModuleDebugStreamRef::reload() { BinaryStreamReader Reader(*Stream); + if (Mod.getModuleStreamIndex() != llvm::pdb::kInvalidStreamIndex) { + if (Error E = reloadSerialize(Reader)) + return E; + } + if (Reader.bytesRemaining() > 0) + return make_error(raw_error_code::corrupt_file, + "Unexpected bytes in module stream."); + return Error::success(); +} + +Error ModuleDebugStreamRef::reloadSerialize(BinaryStreamReader &Reader) { uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize(); uint32_t C11Size = Mod.getC11LineInfoByteSize(); uint32_t C13Size = Mod.getC13LineInfoByteSize(); @@ -71,10 +83,6 @@ return EC; if (auto EC = Reader.readSubstream(GlobalRefsSubstream, GlobalRefsSize)) return EC; - if (Reader.bytesRemaining() > 0) - return make_error(raw_error_code::corrupt_file, - "Unexpected bytes in module stream."); - return Error::success(); }