Index: lld/COFF/PDB.cpp =================================================================== --- lld/COFF/PDB.cpp +++ lld/COFF/PDB.cpp @@ -85,7 +85,12 @@ public: PDBLinker(SymbolTable *Symtab) : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc), - IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) {} + IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) { + // This isn't strictly necessary, but link.exe usually puts an empty string + // as the first "valid" string in the string table, so we do the same in + // order to maintain as much byte-for-byte compatibility as possible. + PDBStrTab.insert(""); + } /// Emit the basic PDB structure: initial streams, headers, etc. void initialize(const llvm::codeview::DebugInfo &BuildId); Index: lld/test/COFF/pdb-diff.test =================================================================== --- lld/test/COFF/pdb-diff.test +++ /dev/null @@ -1,215 +0,0 @@ -This test verifies that we produce PDBs compatible with MSVC in various ways. -We check in a cl-generated object file, PDB, and original source which serve -as the "baseline" for us to measure against. Then we link the same object -file with LLD and compare the two PDBs. Since the baseline object file and -PDB are already checked in, we just run LLD on the object file. - -RUN: rm -f %T/pdb-diff-lld.pdb %T/pdb-diff-lld.exe -RUN: lld-link /debug /pdb:%T/pdb-diff-lld.pdb /out:%T/pdb-diff-lld.exe /nodefaultlib \ -RUN: /entry:main %S/Inputs/pdb-diff.obj -RUN: llvm-pdbutil diff -result -values=false -left-bin-root=%S -right-bin-root=D:/src/llvm-mono/lld/test/COFF/ \ -RUN: %T/pdb-diff-lld.pdb %S/Inputs/pdb-diff-cl.pdb | FileCheck %s - -CHECK: ---------------------- -CHECK-NEXT: | MSF Super Block | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: | File | | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: | Block Size | I | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: | Block Count | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: | Unknown 1 | I | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: | Directory Size | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: ------------------------------------ -CHECK-NEXT: | Stream Directory | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | File | | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Stream Count | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Old MSF Directory | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | PDB Stream | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | TPI Stream | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | DBI Stream | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | IPI Stream | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | New FPO Data | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Section Header Data | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Named Stream "/names" | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Named Stream "/LinkInfo" | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Module "Inputs\pdb-diff.obj" | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Module "* Linker *" | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | TPI Hash | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | IPI Hash | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Public Symbol Hash | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Global Symbol Hash | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Symbol Records | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: ------------------------------------ -CHECK-NEXT: | String Table | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | File | | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Number of Strings | D | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Hash Version | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Byte Size | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Signature | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Empty Strings | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | {{.*}}pdb-diff.cpp | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | $T0 $ebp = $...p $T0 8 + = | D | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | d:\src\llvm-...er internal) | D | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: ---------------------------- -CHECK-NEXT: | PDB Stream | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | File | | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Stream Size | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Age | I | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Guid | D | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Signature | D | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Version | I | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Features (set) | I | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Feature | I | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Named Stream Size | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Named Streams (map) | {{[EI]}} | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | /names | {{[EI]}} | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | /LinkInfo | {{[EI]}} | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: ---------------------------------------------- -CHECK-NEXT: | DBI Stream | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | File | | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Dbi Version | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Age | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Machine | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Flags | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Build Major | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Build Minor | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Build Number | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | PDB DLL Version | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | PDB DLL RBLD | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (FPO) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (Exception) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (Fixup) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (OmapToSrc) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (OmapFromSrc) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (SectionHdr) | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (TokenRidMap) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (Xdata) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (Pdata) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (NewFPO) | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (SectionHdrOrig) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Globals Stream | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Publics Stream | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Symbol Records | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Has CTypes | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Is Incrementally Linked | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Is Stripped | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Module Count | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Source File Count | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Module "Inputs\pdb-diff.obj" | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Modi | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Obj File Name | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Debug Stream | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - C11 Byte Size | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - C13 Byte Size | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - # of files | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Pdb File Path Index | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Source File Name Index | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Symbol Byte Size | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Module "* Linker *" | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Modi | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Obj File Name | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Debug Stream | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - C11 Byte Size | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - C13 Byte Size | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - # of files | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Pdb File Path Index | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Source File Name Index | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Symbol Byte Size | -CHECK-NEXT: |----------------------------------------+---| - - Index: lld/test/COFF/pdb-lib.s =================================================================== --- lld/test/COFF/pdb-lib.s +++ lld/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: 9, # files: 0, has ec info: false +# CHECK-NEXT: debug stream: 10, # 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: 10, # files: 0, has ec info: false +# CHECK-NEXT: debug stream: 11, # 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: 11, # files: 0, has ec info: false +# CHECK-NEXT: debug stream: 12, # files: 0, has ec info: false # CHECK-NEXT: pdb file ni: 1 `{{.*foo.pdb}}`, src file ni: 0 `` .def _main; Index: lld/test/COFF/pdb-linker-module.test =================================================================== --- lld/test/COFF/pdb-linker-module.test +++ lld/test/COFF/pdb-linker-module.test @@ -4,7 +4,7 @@ MODS: Mod 0001 | `* Linker *` MODS-NEXT: Obj: ``: -MODS-NEXT: debug stream: 10, # files: 0, has ec info: false +MODS-NEXT: debug stream: 12, # files: 0, has ec info: false MODS-NEXT: pdb file ni: 1 `{{.*}}pdb-linker-module.test.tmp.pdb`, src file ni: 0 `` SYMS: Mod 0001 | `* Linker *` Index: lld/test/COFF/pdb-same-name.test =================================================================== --- lld/test/COFF/pdb-same-name.test +++ lld/test/COFF/pdb-same-name.test @@ -15,9 +15,9 @@ RAW-NEXT: ============================================================ RAW-NEXT: Mod 0000 | `foo.obj`: RAW-NEXT: Obj: `{{.*}}1\foo.lib`: -RAW-NEXT: debug stream: 9, # files: 1, has ec info: false +RAW-NEXT: debug stream: 11, # files: 1, has ec info: false RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` RAW-NEXT: Mod 0001 | `foo.obj`: RAW-NEXT: Obj: `{{.*}}2\foo.lib`: -RAW-NEXT: debug stream: 10, # files: 1, has ec info: false +RAW-NEXT: debug stream: 12, # files: 1, has ec info: false RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` Index: lld/test/COFF/pdb.test =================================================================== --- lld/test/COFF/pdb.test +++ lld/test/COFF/pdb.test @@ -121,15 +121,15 @@ RAW-NEXT: ============================================================ RAW-NEXT: Mod 0000 | `{{.*}}pdb.test.tmp1.obj`: RAW-NEXT: Obj: `{{.*}}pdb.test.tmp1.obj`: -RAW-NEXT: debug stream: 9, # files: 1, has ec info: false +RAW-NEXT: debug stream: 11, # files: 1, has ec info: false RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` RAW-NEXT: Mod 0001 | `{{.*}}pdb.test.tmp2.obj`: RAW-NEXT: Obj: `{{.*}}pdb.test.tmp2.obj`: -RAW-NEXT: debug stream: 10, # files: 1, has ec info: false +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: Obj: ``: -RAW-NEXT: debug stream: 11, # files: 0, has ec info: false +RAW-NEXT: debug stream: 13, # files: 0, has ec info: false RAW-NEXT: pdb file ni: 1 `{{.*pdb.test.tmp.pdb}}`, src file ni: 0 `` RAW: Types (TPI Stream) RAW-NEXT: ============================================================ Index: llvm/include/llvm/DebugInfo/CodeView/DebugStringTableSubsection.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/DebugStringTableSubsection.h +++ llvm/include/llvm/DebugInfo/CodeView/DebugStringTableSubsection.h @@ -82,6 +82,8 @@ StringMap::const_iterator end() const { return StringToId.end(); } + std::vector sortedIds() const; + private: DenseMap IdToString; StringMap StringToId; Index: llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h +++ llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h @@ -121,7 +121,7 @@ MutableBinaryByteStream FileInfoBuffer; std::vector SectionContribs; ArrayRef SectionMap; - llvm::SmallVector DbgStreams; + std::array, (int)DbgHeaderType::Max> DbgStreams; }; } } Index: llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp +++ llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp @@ -86,6 +86,15 @@ uint32_t DebugStringTableSubsection::size() const { return StringToId.size(); } +std::vector DebugStringTableSubsection::sortedIds() const { + std::vector Result; + Result.reserve(IdToString.size()); + for (const auto &Entry : IdToString) + Result.push_back(Entry.first); + std::sort(Result.begin(), Result.end()); + return Result; +} + uint32_t DebugStringTableSubsection::getIdForString(StringRef S) const { auto Iter = StringToId.find(S); assert(Iter != StringToId.end()); Index: llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -27,7 +27,7 @@ DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf) : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0), PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86), - Header(nullptr), DbgStreams((int)DbgHeaderType::Max) {} + Header(nullptr) {} DbiStreamBuilder::~DbiStreamBuilder() {} @@ -63,15 +63,8 @@ Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type, ArrayRef Data) { - if (DbgStreams[(int)Type].StreamNumber != kInvalidStreamIndex) - return make_error(raw_error_code::duplicate_entry, - "The specified stream type already exists"); - auto ExpectedIndex = Msf.addStream(Data.size()); - if (!ExpectedIndex) - return ExpectedIndex.takeError(); - uint32_t Index = std::move(*ExpectedIndex); - DbgStreams[(int)Type].Data = Data; - DbgStreams[(int)Type].StreamNumber = Index; + DbgStreams[(int)Type].emplace(); + DbgStreams[(int)Type]->Data = Data; return Error::success(); } @@ -266,6 +259,15 @@ } Error DbiStreamBuilder::finalizeMsfLayout() { + for (auto &S : DbgStreams) { + if (!S.hasValue()) + continue; + auto ExpectedIndex = Msf.addStream(S->Data.size()); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + S->StreamNumber = *ExpectedIndex; + } + for (auto &MI : ModiList) { if (auto EC = MI->finalizeMsfLayout()) return EC; @@ -375,17 +377,23 @@ if (auto EC = ECNamesBuilder.commit(Writer)) return EC; - for (auto &Stream : DbgStreams) - if (auto EC = Writer.writeInteger(Stream.StreamNumber)) + for (auto &Stream : DbgStreams) { + uint16_t StreamNumber = kInvalidStreamIndex; + if (Stream.hasValue()) + StreamNumber = Stream->StreamNumber; + if (auto EC = Writer.writeInteger(StreamNumber)) return EC; + } for (auto &Stream : DbgStreams) { - if (Stream.StreamNumber == kInvalidStreamIndex) + if (!Stream.hasValue()) continue; + assert(Stream->StreamNumber != kInvalidStreamIndex); + auto WritableStream = WritableMappedBlockStream::createIndexedStream( - Layout, MsfBuffer, Stream.StreamNumber, Allocator); + Layout, MsfBuffer, Stream->StreamNumber, Allocator); BinaryStreamWriter DbgStreamWriter(*WritableStream); - if (auto EC = DbgStreamWriter.writeArray(Stream.Data)) + if (auto EC = DbgStreamWriter.writeArray(Stream->Data)) return EC; } Index: llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp @@ -150,14 +150,14 @@ PSH->finalizeBuckets(PSHZero); GSH->finalizeBuckets(GSHZero); - Expected Idx = Msf.addStream(calculatePublicsHashStreamSize()); + Expected Idx = Msf.addStream(calculateGlobalsHashStreamSize()); if (!Idx) return Idx.takeError(); - PSH->StreamIndex = *Idx; - Idx = Msf.addStream(calculateGlobalsHashStreamSize()); + GSH->StreamIndex = *Idx; + Idx = Msf.addStream(calculatePublicsHashStreamSize()); if (!Idx) return Idx.takeError(); - GSH->StreamIndex = *Idx; + PSH->StreamIndex = *Idx; uint32_t RecordBytes = GSH->calculateRecordByteSize() + PSH->calculateRecordByteSize(); Index: llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -110,33 +110,34 @@ uint32_t StringsLen = Strings.calculateSerializedSize(); - Expected SN = allocateNamedStream("/names", StringsLen); - if (!SN) - return SN.takeError(); - SN = allocateNamedStream("/LinkInfo", 0); + Expected SN = allocateNamedStream("/LinkInfo", 0); if (!SN) return SN.takeError(); - if (Dbi) { - if (auto EC = Dbi->finalizeMsfLayout()) + if (Gsi) { + if (auto EC = Gsi->finalizeMsfLayout()) return std::move(EC); + if (Dbi) { + Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); + Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); + Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx()); + } } if (Tpi) { if (auto EC = Tpi->finalizeMsfLayout()) return std::move(EC); } - if (Ipi) { - if (auto EC = Ipi->finalizeMsfLayout()) + if (Dbi) { + if (auto EC = Dbi->finalizeMsfLayout()) return std::move(EC); } - if (Gsi) { - if (auto EC = Gsi->finalizeMsfLayout()) + SN = allocateNamedStream("/names", StringsLen); + if (!SN) + return SN.takeError(); + + if (Ipi) { + if (auto EC = Ipi->finalizeMsfLayout()) return std::move(EC); - if (Dbi) { - Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); - Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); - Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx()); - } } // Do this last, since it relies on the named stream map being complete, and Index: llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp @@ -15,6 +15,8 @@ #include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Endian.h" +#include + using namespace llvm; using namespace llvm::msf; using namespace llvm::support; @@ -34,12 +36,24 @@ } static uint32_t computeBucketCount(uint32_t NumStrings) { - // The /names stream is basically an on-disk open-addressing hash table. - // Hash collisions are resolved by linear probing. We cannot make - // utilization 100% because it will make the linear probing extremely - // slow. But lower utilization wastes disk space. As a reasonable - // load factor, we choose 80%. We need +1 because slot 0 is reserved. - return (NumStrings + 1) * 1.25; + // This computes a closed form of BucketCount for the following recursive + // algorithm which is present in the reference implementation: + // int BucketCount = 1; + // int StringCount = 0; + // while (true) { + // ++StringCount; + // if (BucketCount * 3 / 4 < StringCount) + // BucketCount = BucketCount * 3 / 2 + 1; + // } + // This was determined emperically to be identical to https://oeis.org/A006999 + // which offers the closed form. + // + // Matching the algorithm exactly is not strictly necessary for correctness, + // but it helps when comparing LLD's PDBs with Microsoft's PDBs so as to + // eliminate superfluous differences. + constexpr double C = 1.0815136685898448773; + return -1 + (uint32_t)std::floor( + C * std::pow((3.0 / 2.0), (double)(NumStrings + 2))); } uint32_t PDBStringTableBuilder::calculateHashTableSize() const { 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,7 +90,13 @@ P.NewLine(); } - if (opts::dump::DumpStringTable) { + if (opts::dump::DumpNamedStreams) { + if (auto EC = dumpNamedStreams()) + return EC; + P.NewLine(); + } + + if (opts::dump::DumpStringTable || opts::dump::DumpStringTableDetails) { if (auto EC = dumpStringTable()) return EC; P.NewLine(); @@ -857,33 +863,64 @@ return Error::success(); } - if (IS->name_ids().empty()) { - P.formatLine("Empty"); - return Error::success(); + if (opts::dump::DumpStringTable) { + if (IS->name_ids().empty()) + P.formatLine("Empty"); + else { + auto MaxID = + std::max_element(IS->name_ids().begin(), IS->name_ids().end()); + uint32_t Digits = NumDigits(*MaxID); + + P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits), + "String"); + + std::vector SortedIDs(IS->name_ids().begin(), + IS->name_ids().end()); + std::sort(SortedIDs.begin(), SortedIDs.end()); + for (uint32_t I : SortedIDs) { + auto ES = IS->getStringForID(I); + llvm::SmallString<32> Str; + if (!ES) { + consumeError(ES.takeError()); + Str = "Error reading string"; + } else if (!ES->empty()) { + Str.append("'"); + Str.append(*ES); + Str.append("'"); + } + + if (!Str.empty()) + P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), + Str); + } + } } - auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end()); - uint32_t Digits = NumDigits(*MaxID); - - P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits), - "String"); - - std::vector SortedIDs(IS->name_ids().begin(), IS->name_ids().end()); - std::sort(SortedIDs.begin(), SortedIDs.end()); - for (uint32_t I : SortedIDs) { - auto ES = IS->getStringForID(I); - llvm::SmallString<32> Str; - if (!ES) { - consumeError(ES.takeError()); - Str = "Error reading string"; - } else if (!ES->empty()) { - Str.append("'"); - Str.append(*ES); - Str.append("'"); + if (opts::dump::DumpStringTableDetails) { + P.NewLine(); + { + P.printLine("String Table Header:"); + AutoIndent Indent(P); + P.formatLine("Signature: {0}", IS->getSignature()); + P.formatLine("Hash Version: {0}", IS->getHashVersion()); + P.formatLine("Name Buffer Size: {0}", IS->getByteSize()); + P.NewLine(); } - if (!Str.empty()) - P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str); + BinaryStreamRef NameBuffer = IS->getStringTable().getBuffer(); + ArrayRef Contents; + cantFail(NameBuffer.readBytes(0, NameBuffer.getLength(), Contents)); + P.formatBinary("Name Buffer", Contents, 0); + P.NewLine(); + { + P.printLine("Hash Table:"); + AutoIndent Indent(P); + P.formatLine("Bucket Count: {0}", IS->name_ids().size()); + for (const auto &Entry : enumerate(IS->name_ids())) + P.formatLine("Bucket[{0}] : {1}", Entry.index(), + uint32_t(Entry.value())); + P.formatLine("Name Count: {0}", IS->getNameCount()); + } } return Error::success(); } @@ -909,6 +946,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,7 +142,9 @@ 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 DumpStringTableDetails; extern llvm::cl::opt DumpTypes; extern llvm::cl::opt DumpTypeData; extern llvm::cl::opt DumpTypeExtras; Index: llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp =================================================================== --- llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -534,8 +534,16 @@ 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)); +cl::opt DumpStringTableDetails("string-table-details", + cl::desc("dump PDB String Table Details"), + cl::cat(MiscOptions), + cl::sub(DumpSubcommand)); cl::opt DumpSectionContribs("section-contribs", cl::desc("dump section contributions"), @@ -1199,6 +1207,7 @@ opts::dump::DumpStreams = true; opts::dump::DumpStreamBlocks = true; opts::dump::DumpStringTable = true; + opts::dump::DumpStringTableDetails = true; opts::dump::DumpSummary = true; opts::dump::DumpSymbols = true; opts::dump::DumpSymbolStats = true;