Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -203,7 +203,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; } @@ -1223,7 +1225,6 @@ // Add default section merging rules after user rules. User rules take // precedence, but we will emit a warning if there is a conflict. - parseMerge(".idata=.rdata"); parseMerge(".didat=.rdata"); parseMerge(".edata=.rdata"); parseMerge(".xdata=.rdata"); Index: lld/trunk/COFF/InputFiles.cpp =================================================================== --- lld/trunk/COFF/InputFiles.cpp +++ lld/trunk/COFF/InputFiles.cpp @@ -581,6 +581,9 @@ if (File->ParentName.empty()) return File->getName(); + if (File->kind() == coff::InputFile::ImportKind) + return File->getName(); + return (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + ")") .str(); Index: lld/trunk/COFF/PDB.cpp =================================================================== --- lld/trunk/COFF/PDB.cpp +++ lld/trunk/COFF/PDB.cpp @@ -108,6 +108,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. @@ -630,7 +633,7 @@ Optional EndPrecomp; // Merge TPI first, because the IPI stream will reference type indices. if (auto Err = mergeTypeRecords(GlobalTypeTable, IndexMap.TPIMap, - ExpectedTpi->typeArray(), TpiHashes, EndPrecomp)) + ExpectedTpi->typeArray(), TpiHashes, EndPrecomp)) fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err))); // Merge IPI. @@ -947,7 +950,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; @@ -1103,13 +1106,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(); @@ -1119,7 +1122,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; } @@ -1400,16 +1403,7 @@ } } -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. @@ -1433,12 +1427,24 @@ 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 = llvm::join(Args, " "); EBS.Fields.push_back("cwd"); SmallString<64> cwd; - if (Config->PDBSourcePath.empty()) + if (Config->PDBSourcePath.empty()) sys::fs::current_path(cwd); else cwd = Config->PDBSourcePath; @@ -1459,6 +1465,33 @@ EBS, Allocator, CodeViewContainer::Pdb)); } +static void addLinkerModuleCoffGroup(InputSection *ISec, + pdb::DbiModuleDescriptorBuilder &Mod, + OutputSection &OS, + BumpPtrAllocator &Allocator) { + // If there's a section, there's at least one chunk + assert(!ISec->Chunks.empty()); + const Chunk *firstChunk = *ISec->Chunks.begin(); + const Chunk *lastChunk = *ISec->Chunks.rbegin(); + + // Emit COFF group + CoffGroupSym CGS(SymbolRecordKind::CoffGroupSym); + CGS.Name = ISec->Name; + CGS.Segment = OS.SectionIndex; + CGS.Offset = firstChunk->getRVA() - OS.getRVA(); + CGS.Size = lastChunk->getRVA() + lastChunk->getSize() - firstChunk->getRVA(); + CGS.Characteristics = ISec->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) { @@ -1471,6 +1504,97 @@ Sym.SectionNumber = OS.SectionIndex; Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( Sym, Allocator, CodeViewContainer::Pdb)); + + // Output COFF groups for individual chunks of this section. + for (InputSection *ISec : OS.ContribSections) { + addLinkerModuleCoffGroup(ISec, 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; + sys::fs::make_absolute(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. @@ -1483,6 +1607,7 @@ PDB.initialize(BuildId); PDB.addObjectsToPDB(); + PDB.addImportFilesToPDB(OutputSections); PDB.addSections(OutputSections, SectionTable); PDB.addNatvisFiles(); Index: lld/trunk/COFF/Writer.h =================================================================== --- lld/trunk/COFF/Writer.h +++ lld/trunk/COFF/Writer.h @@ -23,6 +23,23 @@ void writeResult(); +class OutputSection; + +// InputSection represents all unmerged sections contributing to the output +// file, including synthetic ones. +class InputSection { +public: + InputSection(llvm::StringRef N, uint32_t Chars, std::vector &C, + OutputSection *O) + : Name(N), Characteristics(Chars), Chunks(C), TargetSection(O) {} + + llvm::StringRef Name; + unsigned Characteristics; + std::vector Chunks; + + OutputSection *TargetSection; +}; + // 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 @@ -36,11 +53,11 @@ void addChunk(Chunk *C); void insertChunkAtStart(Chunk *C); void merge(OutputSection *Other); - void addPermissions(uint32_t C); void setPermissions(uint32_t C); uint64_t getRVA() { return Header.VirtualAddress; } uint64_t getFileOff() { return Header.PointerToRawData; } void writeHeaderTo(uint8_t *Buf); + void addContributingInputSec(InputSection *ISec); // Returns the size of this section in an executable memory image. // This may be smaller than the raw size (the raw size is multiple @@ -65,11 +82,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 @@ -205,6 +205,7 @@ std::map> binImports(); std::unique_ptr &Buffer; + std::vector InputSections; std::vector OutputSections; std::vector Strtab; std::vector OutputSymtab; @@ -299,6 +300,10 @@ } } +void OutputSection::addContributingInputSec(InputSection *ISec) { + ContribSections.push_back(ISec); +} + } // namespace coff } // namespace lld @@ -749,6 +754,11 @@ std::vector &Chunks = Pair.second; for (Chunk *C : Chunks) Sec->addChunk(C); + + InputSection *ISec = + make(Pair.first.first, OutChars, Chunks, Sec); + InputSections.push_back(ISec); + Sec->addContributingInputSec(ISec); } // Finally, move some output sections to the end. Index: lld/trunk/test/COFF/arm64-relocs-imports.test =================================================================== --- lld/trunk/test/COFF/arm64-relocs-imports.test +++ lld/trunk/test/COFF/arm64-relocs-imports.test @@ -86,8 +86,8 @@ # AFTER: 140001090: e0 95 09 30 adr x0, #78525 # AFTER: 140001094: 41 00 00 54 b.ne #8 # AFTER: 140001098: 20 00 00 36 tbz w0, #0, #4 -# AFTER: 14000109c: 10 00 00 b0 adrp x16, #4096 -# AFTER: 1400010a0: 10 2a 40 f9 ldr x16, [x16, #80] +# AFTER: 14000109c: 10 00 00 d0 adrp x16, #8192 +# AFTER: 1400010a0: 10 1e 40 f9 ldr x16, [x16, #56] # AFTER: 1400010a4: 00 02 1f d6 br x16 --- !COFF Index: lld/trunk/test/COFF/autoimport-arm-data.s =================================================================== --- lld/trunk/test/COFF/autoimport-arm-data.s +++ lld/trunk/test/COFF/autoimport-arm-data.s @@ -12,8 +12,8 @@ # IMPORTS: Import { # IMPORTS-NEXT: Name: autoimport-arm-data.s.tmp-lib.dll -# IMPORTS-NEXT: ImportLookupTableRVA: 0x2050 -# IMPORTS-NEXT: ImportAddressTableRVA: 0x2058 +# IMPORTS-NEXT: ImportLookupTableRVA: 0x4028 +# IMPORTS-NEXT: ImportAddressTableRVA: 0x4030 # IMPORTS-NEXT: Symbol: variable (0) # IMPORTS-NEXT: } @@ -21,13 +21,13 @@ # First runtime pseudo reloc, with import from 0x2058, # applied at 0x3000, with a size of 32 bits. # CONTENTS: Contents of section .rdata: -# CONTENTS: 402000 00000000 00000000 01000000 58200000 +# CONTENTS: 402000 00000000 00000000 01000000 30400000 # CONTENTS: 402010 00300000 20000000 # ptr: pointing at the IAT RVA at 0x2058 # relocs: pointing at the runtime pseudo reloc list at # 0x2000 - 0x2018. # CONTENTS: Contents of section .data: -# CONTENTS: 403000 58204000 00204000 18204000 +# CONTENTS: 403000 30404000 00204000 18204000 .global main .text Index: lld/trunk/test/COFF/autoimport-arm64-data.s =================================================================== --- lld/trunk/test/COFF/autoimport-arm64-data.s +++ lld/trunk/test/COFF/autoimport-arm64-data.s @@ -12,8 +12,8 @@ # IMPORTS: Import { # IMPORTS-NEXT: Name: autoimport-arm64-data.s.tmp-lib.dll -# IMPORTS-NEXT: ImportLookupTableRVA: 0x2060 -# IMPORTS-NEXT: ImportAddressTableRVA: 0x2070 +# IMPORTS-NEXT: ImportLookupTableRVA: 0x4028 +# IMPORTS-NEXT: ImportAddressTableRVA: 0x4038 # IMPORTS-NEXT: Symbol: variable (0) # IMPORTS-NEXT: } @@ -21,13 +21,13 @@ # First runtime pseudo reloc, with import from 0x2070, # applied at 0x3000, with a size of 32 bits. # CONTENTS: Contents of section .rdata: -# CONTENTS: 140002000 00000000 00000000 01000000 70200000 +# CONTENTS: 140002000 00000000 00000000 01000000 38400000 # CONTENTS: 140002010 00300000 40000000 # ptr: pointing at the IAT RVA at 0x2070 # relocs: pointing at the runtime pseudo reloc list at # 0x2000 - 0x2018. # CONTENTS: Contents of section .data: -# CONTENTS: 140003000 70200040 01000000 00200040 01000000 +# CONTENTS: 140003000 38400040 01000000 00200040 01000000 # CONTENTS: 140003010 18200040 01000000 .global main Index: lld/trunk/test/COFF/autoimport-refptr.s =================================================================== --- lld/trunk/test/COFF/autoimport-refptr.s +++ lld/trunk/test/COFF/autoimport-refptr.s @@ -13,15 +13,15 @@ # IMPORTS: Import { # IMPORTS-NEXT: Name: autoimport-refptr.s.tmp-lib.dll -# IMPORTS-NEXT: ImportLookupTableRVA: 0x2050 -# IMPORTS-NEXT: ImportAddressTableRVA: 0x2060 +# IMPORTS-NEXT: ImportLookupTableRVA: 0x4028 +# IMPORTS-NEXT: ImportAddressTableRVA: 0x4038 # IMPORTS-NEXT: Symbol: variable (0) # IMPORTS-NEXT: } # DISASM: Disassembly of section .text: # DISASM: .text: # Relative offset at 0x1002 pointing at the IAT at 0x2060 -# DISASM: 140001000: 48 8b 05 59 10 00 00 movq 4185(%rip), %rax +# DISASM: 140001000: 48 8b 05 31 30 00 00 movq 12337(%rip), %rax # DISASM: 140001007: 8b 00 movl (%rax), %eax # Relative offset at 0x100b pointing at the .refptr.localvar stub at # 0x2000 Index: lld/trunk/test/COFF/autoimport-x86.s =================================================================== --- lld/trunk/test/COFF/autoimport-x86.s +++ lld/trunk/test/COFF/autoimport-x86.s @@ -13,15 +13,15 @@ # IMPORTS: Import { # IMPORTS-NEXT: Name: autoimport-x86.s.tmp-lib.dll -# IMPORTS-NEXT: ImportLookupTableRVA: 0x2070 -# IMPORTS-NEXT: ImportAddressTableRVA: 0x2080 +# IMPORTS-NEXT: ImportLookupTableRVA: 0x4028 +# IMPORTS-NEXT: ImportAddressTableRVA: 0x4038 # IMPORTS-NEXT: Symbol: variable (0) # IMPORTS-NEXT: } # DISASM: Disassembly of section .text: # DISASM: .text: # Relative offset at 0x1002 pointing at the IAT at 0x2080. -# DISASM: 140001000: 8b 05 7a 10 00 00 movl 4218(%rip), %eax +# DISASM: 140001000: 8b 05 32 30 00 00 movl 12338(%rip), %eax # DISASM: 140001006: c3 retq # Runtime pseudo reloc list header consisting of 0x0, 0x0, 0x1. @@ -30,14 +30,14 @@ # Second runtime pseudo reloc, with import from 0x2080, # applied at 0x3000, with a size of 64 bits. # CONTENTS: Contents of section .rdata: -# CONTENTS: 140002000 00000000 00000000 01000000 80200000 -# CONTENTS: 140002010 02100000 20000000 80200000 00300000 +# CONTENTS: 140002000 00000000 00000000 01000000 38400000 +# CONTENTS: 140002010 02100000 20000000 38400000 00300000 # CONTENTS: 140002020 40000000 # ptr: pointing at the IAT RVA at 0x2080 # relocs: pointing at the runtime pseudo reloc list at # 0x2000 - 0x2024. # CONTENTS: Contents of section .data: -# CONTENTS: 140003000 80200040 01000000 00200040 01000000 +# CONTENTS: 140003000 38400040 01000000 00200040 01000000 # CONTENTS: 140003010 24200040 01000000 .global main Index: lld/trunk/test/COFF/hello32.test =================================================================== --- lld/trunk/test/COFF/hello32.test +++ lld/trunk/test/COFF/hello32.test @@ -57,7 +57,7 @@ HEADER-NEXT: DataDirectory { HEADER-NEXT: ExportTableRVA: 0x0 HEADER-NEXT: ExportTableSize: 0x0 -HEADER-NEXT: ImportTableRVA: 0x2000 +HEADER-NEXT: ImportTableRVA: 0x3000 HEADER-NEXT: ImportTableSize: 0x28 HEADER-NEXT: ResourceTableRVA: 0x0 HEADER-NEXT: ResourceTableSize: 0x0 @@ -79,7 +79,7 @@ HEADER-NEXT: LoadConfigTableSize: 0x0 HEADER-NEXT: BoundImportRVA: 0x0 HEADER-NEXT: BoundImportSize: 0x0 -HEADER-NEXT: IATRVA: 0x2034 +HEADER-NEXT: IATRVA: 0x3034 HEADER-NEXT: IATSize: 0xC HEADER-NEXT: DelayImportDescriptorRVA: 0x0 HEADER-NEXT: DelayImportDescriptorSize: 0x0 @@ -114,8 +114,8 @@ IMPORTS: AddressSize: 32bit IMPORTS: Import { IMPORTS: Name: std32.dll -IMPORTS: ImportLookupTableRVA: 0x2028 -IMPORTS: ImportAddressTableRVA: 0x2034 +IMPORTS: ImportLookupTableRVA: 0x3028 +IMPORTS: ImportAddressTableRVA: 0x3034 IMPORTS: Symbol: ExitProcess (0) IMPORTS: Symbol: MessageBoxA (1) IMPORTS: } Index: lld/trunk/test/COFF/imports-gnu-only.s =================================================================== --- lld/trunk/test/COFF/imports-gnu-only.s +++ lld/trunk/test/COFF/imports-gnu-only.s @@ -19,7 +19,7 @@ # Check that the linker inserted the null terminating import descriptor, # even if there were no normal import libraries, only gnu ones. -# DATA: Contents of section .rdata: +# DATA: Contents of section .idata: # First import descriptor # DATA: 140002000 28200000 00000000 00000000 53200000 # Last word from first import descriptor, null terminator descriptor Index: lld/trunk/test/COFF/imports.test =================================================================== --- lld/trunk/test/COFF/imports.test +++ lld/trunk/test/COFF/imports.test @@ -15,21 +15,21 @@ TEXT-NEXT: .text: TEXT-NEXT: subq $40, %rsp TEXT-NEXT: movq $0, %rcx -TEXT-NEXT: leaq 8180(%rip), %rdx -TEXT-NEXT: leaq 8167(%rip), %r8 +TEXT-NEXT: leaq 4084(%rip), %rdx +TEXT-NEXT: leaq 4071(%rip), %r8 TEXT-NEXT: movl $0, %r9d TEXT-NEXT: callq 60 TEXT-NEXT: movl $0, %ecx TEXT-NEXT: callq 18 TEXT-NEXT: callq 29 -TEXT: jmpq *4098(%rip) -TEXT: jmpq *4090(%rip) -TEXT: jmpq *4082(%rip) +TEXT: jmpq *8194(%rip) +TEXT: jmpq *8186(%rip) +TEXT: jmpq *8178(%rip) IMPORT: Import { IMPORT-NEXT: Name: std64.dll -IMPORT-NEXT: ImportLookupTableRVA: 0x2028 -IMPORT-NEXT: ImportAddressTableRVA: 0x2048 +IMPORT-NEXT: ImportLookupTableRVA: 0x3028 +IMPORT-NEXT: ImportAddressTableRVA: 0x3048 IMPORT-NEXT: Symbol: ExitProcess (0) IMPORT-NEXT: Symbol: (50) IMPORT-NEXT: Symbol: MessageBoxA (1) 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,46 @@ 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-LABEL: Mod 0000 | `{{.*}}pdb-publics-import.test.tmp2.obj`: +CHECK-NEXT: Mod 0 (debug info not present): [{{.*}}pdb-publics-import.test.tmp2.obj] +CHECK-LABEL: Mod 0001 | `pdb-publics-import.test.tmp1.dll`: +CHECK-NEXT: Mod 1 (debug info not present): [pdb-publics-import.test.tmp1.dll] +CHECK-LABEL: Mod 0002 | `Import:pdb-publics-import.test.tmp1.dll`: + + +CHECK: Modules +CHECK-NEXT: ============================================================ +CHECK-LABEL: 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-LABEL: 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-LABEL: 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-LABEL: Mod 0003 | `* Linker *`: CHECK: Public Symbols CHECK-NEXT: ============================================================ @@ -20,24 +59,175 @@ CHECK-NEXT: 88 | S_PUB32 [size = 24] `exportfn2` CHECK-NEXT: flags = function, addr = 0001:0032 CHECK-NEXT: 32 | S_PUB32 [size = 32] `__imp_exportfn2` -CHECK-NEXT: flags = none, addr = 0002:0136 +CHECK-NEXT: flags = none, addr = 0003:0072 CHECK-NEXT: 0 | S_PUB32 [size = 32] `__imp_exportfn1` -CHECK-NEXT: flags = none, addr = 0002:0128 +CHECK-NEXT: flags = none, addr = 0003:0064 + +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 = 61, alignment = 12, rva = 8192, section # = 2 +CHECK-NEXT: characteristics = +CHECK-NEXT: initialized data +CHECK-NEXT: read permissions +CHECK-NEXT: {{[0-9]+}} | S_SECTION [size = 28] `.idata` +CHECK-NEXT: length = 145, alignment = 12, rva = 12288, section # = 3 +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 = 0003:0000 +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 = 0003:0040 +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 = 0003:0064 +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 = 0003:0088 +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 = 0003:0112 +CHECK-NEXT: characteristics = +CHECK-NEXT: initialized data +CHECK-NEXT: read permissions +CHECK-NEXT: write permissions + +CHECK: Section Headers +CHECK-NEXT: ============================================================ +CHECK-LABEL: SECTION HEADER #1 +CHECK-NEXT: .text name +CHECK-NEXT: 26 virtual size +CHECK-NEXT: 1000 virtual address +CHECK-NEXT: 200 size of raw data +CHECK-NEXT: 400 file pointer to raw data +CHECK-NEXT: 0 file pointer to relocation table +CHECK-NEXT: 0 file pointer to line numbers +CHECK-NEXT: 0 number of relocations +CHECK-NEXT: 0 number of line numbers +CHECK-NEXT: 60000020 flags +CHECK-NEXT: IMAGE_SCN_CNT_CODE +CHECK-NEXT: IMAGE_SCN_MEM_EXECUTE +CHECK-NEXT: IMAGE_SCN_MEM_READ +CHECK-LABEL: SECTION HEADER #2 +CHECK-NEXT: .rdata name +CHECK-NEXT: 3D virtual size +CHECK-NEXT: 2000 virtual address +CHECK-NEXT: 200 size of raw data +CHECK-NEXT: 600 file pointer to raw data +CHECK-NEXT: 0 file pointer to relocation table +CHECK-NEXT: 0 file pointer to line numbers +CHECK-NEXT: 0 number of relocations +CHECK-NEXT: 0 number of line numbers +CHECK-NEXT: 40000040 flags +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +CHECK-NEXT: IMAGE_SCN_MEM_READ +CHECK-LABEL: SECTION HEADER #3 +CHECK-NEXT: .idata name +CHECK-NEXT: 91 virtual size +CHECK-NEXT: 3000 virtual address +CHECK-NEXT: 200 size of raw data +CHECK-NEXT: 800 file pointer to raw data +CHECK-NEXT: 0 file pointer to relocation table +CHECK-NEXT: 0 file pointer to line numbers +CHECK-NEXT: 0 number of relocations +CHECK-NEXT: 0 number of line numbers +CHECK-NEXT: 40000040 flags +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +CHECK-NEXT: IMAGE_SCN_MEM_READ CHECK: Section Contributions CHECK-NEXT: ============================================================ main -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 - exportfn1 thunk -CHECK-NEXT: SC[.text] | mod = 1, 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: 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: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +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 + exportfn1 thunk +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 = 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 = 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[.idata] | mod = 3, 0003:0000, size = 20, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.idata] | mod = 3, 0003:0020, size = 20, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.idata] | mod = 3, 0003:0040, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.idata] | mod = 3, 0003:0048, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.idata] | mod = 3, 0003:0056, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.idata] | mod = 3, 0003:0064, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.idata] | mod = 3, 0003:0072, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.idata] | mod = 3, 0003:0080, size = 8, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.idata] | mod = 3, 0003:0088, size = 12, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.idata] | mod = 3, 0003:0100, size = 12, data crc = 0, reloc crc = 0 +CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +CHECK-NEXT: SC[.idata] | mod = 3, 0003:0112, 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 = 0, 0000:0000, size = 0, data crc = 0, reloc crc = 0 RAW-NEXT: none RAW-NEXT: Obj: ``: RAW-NEXT: debug stream: 13, # files: 0, has ec info: false Index: lld/trunk/test/COFF/symtab.test =================================================================== --- lld/trunk/test/COFF/symtab.test +++ lld/trunk/test/COFF/symtab.test @@ -1,10 +1,10 @@ # RUN: yaml2obj < %s > %t.obj # RUN: lld-link /debug:dwarf /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib -# RUN: llvm-readobj -symbols %t.exe | FileCheck %s +# RUN: llvm-readobj -symbols %t.exe | FileCheck %s -check-prefixes=CHECK,DWARF-HASDEBUG # RUN: lld-link /debug:dwarf /opt:noref /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib -# RUN: llvm-readobj -symbols %t.exe | FileCheck %s +# RUN: llvm-readobj -symbols %t.exe | FileCheck %s -check-prefixes=CHECK,DWARF-HASDEBUG # RUN: lld-link /debug:symtab /opt:noref /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib -# RUN: llvm-readobj -symbols %t.exe | FileCheck %s +# RUN: llvm-readobj -symbols %t.exe | FileCheck %s -check-prefixes=CHECK,SYMTAB-NODEBUG # RUN: lld-link /debug /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib # RUN: llvm-readobj -symbols %t.exe | FileCheck -check-prefix=NO %s @@ -31,7 +31,13 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: .data # CHECK-NEXT: Value: 0 -# CHECK-NEXT: Section: .data (3) + +# Using /debug:dwarf sets Config->Debug thus it adds extra (debug) chunks in the .rdata section +# Whereas /debug:symtab does not set Config->Debug thus the .rdata section is not emitted, so the .data section appears in a different section id. + +# DWARF-HASDEBUG-NEXT: Section: .data (3) +# SYMTAB-NODEBUG-NEXT: Section: .data (2) + # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: Static (0x3) @@ -58,7 +64,10 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: message # CHECK-NEXT: Value: 6 -# CHECK-NEXT: Section: .text2 + +# DWARF-HASDEBUG-NEXT: Section: .text2 (5) +# SYMTAB-NODEBUG-NEXT: Section: .text2 (4) + # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: Static (0x3) @@ -76,7 +85,10 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: caption # CHECK-NEXT: Value: 0 -# CHECK-NEXT: Section: .text2 + +# DWARF-HASDEBUG-NEXT: Section: .text2 (5) +# SYMTAB-NODEBUG-NEXT: Section: .text2 (4) + # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: Static (0x3) Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h @@ -71,8 +71,10 @@ uint32_t calculateSerializedLength() const; /// Return the offset within the module symbol stream of the next symbol - /// record passed to addSymbol. Add four to account for the signature. - uint32_t getNextSymbolOffset() const { return SymbolByteSize + 4; } + /// record passed to addSymbol. + uint32_t getNextSymbolOffset() const { + return /*signature*/ sizeof(uint32_t) + SymbolByteSize; + } void finalize(); Error finalizeMsfLayout(); 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 @@ -95,7 +95,8 @@ } void DbiModuleDescriptorBuilder::finalize() { - Layout.SC.Imod = Layout.Mod; + if (Layout.SC.ISect == kInvalidStreamIndex) + Layout.Mod = 0; Layout.FileNameOffs = 0; // TODO: Fix this Layout.Flags = 0; // TODO: Fix this Layout.C11Bytes = 0; @@ -108,17 +109,20 @@ // 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(); - auto ExpectedSN = - MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size)); - if (!ExpectedSN) - return ExpectedSN.takeError(); - Layout.ModDiStream = *ExpectedSN; + if (C13Size || SymbolByteSize) { + auto ExpectedSN = + MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size)); + if (!ExpectedSN) + return ExpectedSN.takeError(); + Layout.ModDiStream = *ExpectedSN; + } return Error::success(); } @@ -141,17 +145,22 @@ MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator()); WritableBinaryStreamRef Ref(*NS); BinaryStreamWriter SymbolWriter(Ref); - // Write the symbols. + if (auto EC = SymbolWriter.writeInteger(COFF::DEBUG_SECTION_MAGIC)) return EC; - BinaryItemStream Records(llvm::support::endianness::little); - Records.setItems(Symbols); - BinaryStreamRef RecordsRef(Records); - if (auto EC = SymbolWriter.writeStreamRef(RecordsRef)) - return EC; - if (auto EC = SymbolWriter.padToAlignment(4)) - return EC; + + // Write the symbols. + if (SymbolByteSize > 0) { + BinaryItemStream Records(llvm::support::endianness::little); + Records.setItems(Symbols); + BinaryStreamRef RecordsRef(Records); + if (auto EC = SymbolWriter.writeStreamRef(RecordsRef)) + return EC; + if (auto EC = SymbolWriter.padToAlignment(sizeof(uint32_t))) + return EC; + } + // TODO: Write C11 Line data assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 && "Invalid debug section alignment!"); 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 @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.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" @@ -35,40 +36,44 @@ Error ModuleDebugStreamRef::reload() { BinaryStreamReader Reader(*Stream); - uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize(); - uint32_t C11Size = Mod.getC11LineInfoByteSize(); - uint32_t C13Size = Mod.getC13LineInfoByteSize(); - - if (C11Size > 0 && C13Size > 0) - return make_error(raw_error_code::corrupt_file, - "Module has both C11 and C13 line info"); - - BinaryStreamRef S; - - if (auto EC = Reader.readInteger(Signature)) - return EC; - if (auto EC = Reader.readSubstream(SymbolsSubstream, SymbolSize - 4)) - return EC; - if (auto EC = Reader.readSubstream(C11LinesSubstream, C11Size)) - return EC; - if (auto EC = Reader.readSubstream(C13LinesSubstream, C13Size)) - return EC; - - BinaryStreamReader SymbolReader(SymbolsSubstream.StreamData); - if (auto EC = - SymbolReader.readArray(SymbolArray, SymbolReader.bytesRemaining())) - return EC; - - BinaryStreamReader SubsectionsReader(C13LinesSubstream.StreamData); - if (auto EC = SubsectionsReader.readArray(Subsections, - SubsectionsReader.bytesRemaining())) - return EC; - - uint32_t GlobalRefsSize; - if (auto EC = Reader.readInteger(GlobalRefsSize)) - return EC; - if (auto EC = Reader.readSubstream(GlobalRefsSubstream, GlobalRefsSize)) - return EC; + if (Mod.getModuleStreamIndex() != llvm::pdb::kInvalidStreamIndex) { + uint32_t SymbolSize = + Mod.getSymbolDebugInfoByteSize() - /*signature*/ sizeof(uint32_t); + uint32_t C11Size = Mod.getC11LineInfoByteSize(); + uint32_t C13Size = Mod.getC13LineInfoByteSize(); + + if (C11Size > 0 && C13Size > 0) + return make_error(raw_error_code::corrupt_file, + "Module has both C11 and C13 line info"); + + BinaryStreamRef S; + + if (auto EC = Reader.readInteger(Signature)) + return EC; + if (SymbolSize > 0) { + if (auto EC = Reader.readSubstream(SymbolsSubstream, SymbolSize)) + return EC; + } + if (auto EC = Reader.readSubstream(C11LinesSubstream, C11Size)) + return EC; + if (auto EC = Reader.readSubstream(C13LinesSubstream, C13Size)) + return EC; + + BinaryStreamReader SymbolReader(SymbolsSubstream.StreamData); + if (auto EC = + SymbolReader.readArray(SymbolArray, SymbolReader.bytesRemaining())) + return EC; + BinaryStreamReader SubsectionsReader(C13LinesSubstream.StreamData); + if (auto EC = SubsectionsReader.readArray( + Subsections, SubsectionsReader.bytesRemaining())) + return EC; + + uint32_t GlobalRefsSize; + if (auto EC = Reader.readInteger(GlobalRefsSize)) + 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.");