Index: include/llvm/DebugInfo/CodeView/StreamArray.h =================================================================== --- include/llvm/DebugInfo/CodeView/StreamArray.h +++ include/llvm/DebugInfo/CodeView/StreamArray.h @@ -185,7 +185,7 @@ return FixedStreamArrayIterator(*this, 0); } FixedStreamArrayIterator end() const { - return FixedStreamArrayIterator(*this); + return FixedStreamArrayIterator(*this, size()); } private: @@ -194,8 +194,6 @@ template class FixedStreamArrayIterator { public: - FixedStreamArrayIterator(const FixedStreamArray &Array) - : Array(Array), Index(uint32_t(-1)) {} FixedStreamArrayIterator(const FixedStreamArray &Array, uint32_t Index) : Array(Array), Index(Index) {} @@ -211,10 +209,7 @@ const T &operator*() const { return Array[Index]; } FixedStreamArrayIterator &operator++() { - if (Index == uint32_t(-1)) - return *this; - if (++Index >= Array.size()) - Index = uint32_t(-1); + ++Index; return *this; } Index: include/llvm/DebugInfo/PDB/Raw/TpiStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/TpiStream.h +++ include/llvm/DebugInfo/PDB/Raw/TpiStream.h @@ -16,6 +16,7 @@ #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Error.h" @@ -29,6 +30,12 @@ struct HeaderInfo; public: + // Corresponds to `OffCb`. + struct TypeIndexOffset { + codeview::TypeIndex Type; + support::ulittle32_t Offset; + }; + TpiStream(PDBFile &File, uint32_t StreamIdx); ~TpiStream(); Error reload(); @@ -41,6 +48,10 @@ uint16_t getTypeHashStreamIndex() const; uint16_t getTypeHashStreamAuxIndex() const; + codeview::FixedStreamArray getHashValues() const; + codeview::FixedStreamArray getTypeIndexOffsets() const; + codeview::FixedStreamArray getHashAdjustments() const; + iterator_range types(bool *HadError) const; private: @@ -49,12 +60,16 @@ HashFunctionType HashFunction; codeview::CVTypeArray TypeRecords; - codeview::StreamRef TypeIndexOffsetBuffer; - codeview::StreamRef HashValuesBuffer; - codeview::StreamRef HashAdjBuffer; + + std::unique_ptr HashStream; + codeview::FixedStreamArray HashValues; + codeview::FixedStreamArray TypeIndexOffsets; + codeview::FixedStreamArray HashAdjustments; const HeaderInfo *Header; }; + +raw_ostream &operator<<(raw_ostream &OS, const TpiStream::TypeIndexOffset &); } } Index: lib/DebugInfo/PDB/Raw/TpiStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ lib/DebugInfo/PDB/Raw/TpiStream.cpp @@ -11,6 +11,7 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" @@ -99,20 +100,23 @@ return EC; // Hash indices, hash values, etc come from the hash stream. - MappedBlockStream HS(Header->HashStreamIndex, Pdb); - codeview::StreamReader HSR(HS); + HashStream.reset(new MappedBlockStream(Header->HashStreamIndex, Pdb)); + codeview::StreamReader HSR(*HashStream); + uint32_t NumHashValues = Header->HashValueBuffer.Length / sizeof(ulittle32_t); HSR.setOffset(Header->HashValueBuffer.Off); - if (auto EC = - HSR.readStreamRef(HashValuesBuffer, Header->HashValueBuffer.Length)) + if (auto EC = HSR.readArray(HashValues, NumHashValues)) return EC; - HSR.setOffset(Header->HashAdjBuffer.Off); - if (auto EC = HSR.readStreamRef(HashAdjBuffer, Header->HashAdjBuffer.Length)) + HSR.setOffset(Header->IndexOffsetBuffer.Off); + uint32_t NumTypeIndexOffsets = + Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset); + if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets)) return EC; - HSR.setOffset(Header->IndexOffsetBuffer.Off); - if (auto EC = HSR.readStreamRef(TypeIndexOffsetBuffer, - Header->IndexOffsetBuffer.Length)) + HSR.setOffset(Header->HashAdjBuffer.Off); + uint32_t NumHashAdjustments = + Header->HashAdjBuffer.Length / sizeof(TypeIndexOffset); + if (auto EC = HSR.readArray(HashAdjustments, NumHashAdjustments)) return EC; return Error::success(); @@ -139,7 +143,28 @@ return Header->HashAuxStreamIndex; } +codeview::FixedStreamArray +TpiStream::getHashValues() const { + return HashValues; +} + +codeview::FixedStreamArray +TpiStream::getTypeIndexOffsets() const { + return TypeIndexOffsets; +} + +codeview::FixedStreamArray +TpiStream::getHashAdjustments() const { + return HashAdjustments; +} + iterator_range TpiStream::types(bool *HadError) const { return llvm::make_range(TypeRecords.begin(HadError), TypeRecords.end()); } + +raw_ostream &pdb::operator<<(raw_ostream &OS, + const TpiStream::TypeIndexOffset &TIOff) { + OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}"; + return OS; +} Index: test/DebugInfo/PDB/pdbdump-headers.test =================================================================== --- test/DebugInfo/PDB/pdbdump-headers.test +++ test/DebugInfo/PDB/pdbdump-headers.test @@ -2,7 +2,7 @@ ; RUN: -raw-sym-record-bytes -raw-publics -raw-module-files -raw-stream-name=/names \ ; RUN: -raw-stream-summary -raw-stream-blocks -raw-ipi-records -raw-ipi-record-bytes \ ; RUN: -raw-section-contribs -raw-section-map -raw-section-headers -raw-line-info \ -; RUN: %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s +; RUN: -raw-tpi-hash %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s ; RUN: llvm-pdbdump -raw-all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s ; RUN: llvm-pdbdump -raw-headers -raw-stream-name=/names -raw-modules -raw-module-files \ ; RUN: %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s @@ -141,6 +141,11 @@ ; EMPTY-NEXT: 0040: 0500626F 746800F1 |..both..| ; EMPTY-NEXT: ) ; EMPTY-NEXT: } +; EMPTY: Hash { +; EMPTY-NEXT: Values: [205956, 163561, 59811, 208239, 16377, 247078, 194342, 254156, 194536, 167492, 185421, 119540, 261871, 198119, 48056, 251486, 134580, 148190, 113636, 53336, 55779, 220695, 198114, 148734, 81128, 60158, 217249, 174209, 159978, 249504, 141941, 238785, 6214, 94935, 151449, 135589, 73373, 96512, 254299, 17744, 239514, 173189, 130544, 204437, 238560, 144673, 115151, 197306, 256035, 101096, 231280, 52156, 48854, 170035, 177041, 102745, 16947, 183703, 98548, 35693, 171328, 203640, 139292, 49018, 43821, 202555, 165040, 215835, 142625, 52534, 44186, 103930, 110942, 17991, 213215] +; EMPTY-NEXT: Type Index Offsets: [{4096, 0}] +; EMPTY-NEXT: Hash Adjustments: [] +; EMPTY-NEXT: } ; EMPTY: Type Info Stream (IPI) { ; EMPTY-NEXT: IPI Version: 20040203 ; EMPTY-NEXT: Record count: 15 @@ -217,6 +222,11 @@ ; EMPTY-NEXT: 0000: 42100000 01000000 6C000000 0100F2F1 |B.......l.......| ; EMPTY-NEXT: ) ; EMPTY-NEXT: } +; EMPTY: Hash { +; EMPTY-NEXT: Values: [7186, 7198, 7180, 7191, 7201, 7241, 7249, 80727, 154177, 75189, 253662, 193467, 222705, 186099, 257108] +; EMPTY-NEXT: Type Index Offsets: [{4096, 0}] +; EMPTY-NEXT: Hash Adjustments: [] +; EMPTY-NEXT: } ; EMPTY: DBI Stream { ; EMPTY-NEXT: Dbi Version: 19990903 ; EMPTY-NEXT: Age: 1 Index: tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- tools/llvm-pdbdump/llvm-pdbdump.cpp +++ tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -118,6 +118,9 @@ "raw-tpi-record-bytes", cl::desc("dump CodeView type record raw bytes from TPI stream"), cl::cat(NativeOptions)); +cl::opt DumpTpiHash("raw-tpi-hash", + cl::desc("dump CodeView TPI hash stream"), + cl::cat(NativeOptions)); cl::opt DumpIpiRecords("raw-ipi-records", cl::desc("dump CodeView type records from IPI stream"), @@ -607,6 +610,16 @@ return Error::success(); } +static void dumpTpiHash(ScopedPrinter &P, TpiStream &Tpi) { + if (!opts::DumpTpiHash) + return; + DictScope DD(P, "Hash"); + codeview::FixedStreamArray S = Tpi.getHashValues(); + P.printList("Values", Tpi.getHashValues()); + P.printList("Type Index Offsets", Tpi.getTypeIndexOffsets()); + P.printList("Hash Adjustments", Tpi.getHashAdjustments()); +} + static Error dumpTpiStream(ScopedPrinter &P, PDBFile &File, codeview::CVTypeDumper &TD, uint32_t StreamIdx) { assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); @@ -653,6 +666,7 @@ if (DumpRecordBytes) P.printBinaryBlock("Bytes", Type.Data); } + dumpTpiHash(P, Tpi); if (HadError) return make_error(raw_error_code::corrupt_file, "TPI stream contained corrupt record"); @@ -669,10 +683,12 @@ TD.dump(Type); TD.setPrinter(OldP); + dumpTpiHash(P, Tpi); if (HadError) return make_error(raw_error_code::corrupt_file, "TPI stream contained corrupt record"); } + P.flush(); return Error::success(); } @@ -820,6 +836,8 @@ return true; if (opts::DumpTpiRecords) return true; + if (opts::DumpTpiHash) + return true; if (opts::DumpIpiRecords) return true; if (opts::DumpIpiRecordBytes) @@ -994,6 +1012,7 @@ opts::DumpStreamSummary = true; opts::DumpStreamBlocks = true; opts::DumpTpiRecords = true; + opts::DumpTpiHash = true; opts::DumpIpiRecords = true; opts::DumpSectionMap = true; opts::DumpSectionContribs = true;