1 //===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ----------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 11 #include "llvm/ADT/iterator_range.h" 12 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" 13 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" 14 #include "llvm/DebugInfo/CodeView/TypeRecord.h" 15 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" 16 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 17 #include "llvm/DebugInfo/MSF/StreamReader.h" 18 #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 19 #include "llvm/DebugInfo/PDB/Native/RawConstants.h" 20 #include "llvm/DebugInfo/PDB/Native/RawError.h" 21 #include "llvm/DebugInfo/PDB/Native/RawTypes.h" 22 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h" 23 #include "llvm/Support/Endian.h" 24 #include "llvm/Support/Error.h" 25 #include <algorithm> 26 #include <cstdint> 27 #include <vector> 28 29 using namespace llvm; 30 using namespace llvm::codeview; 31 using namespace llvm::support; 32 using namespace llvm::msf; 33 using namespace llvm::pdb; 34 35 TpiStream::TpiStream(const PDBFile &File, 36 std::unique_ptr<MappedBlockStream> Stream) 37 : Pdb(File), Stream(std::move(Stream)) {} 38 39 TpiStream::~TpiStream() = default; 40 41 // Verifies that a given type record matches with a given hash value. 42 // Currently we only verify SRC_LINE records. 43 Error TpiStream::verifyHashValues() { 44 TpiHashVerifier Verifier(HashValues, Header->NumHashBuckets); 45 TypeDeserializer Deserializer; 46 47 TypeVisitorCallbackPipeline Pipeline; 48 Pipeline.addCallbackToPipeline(Deserializer); 49 Pipeline.addCallbackToPipeline(Verifier); 50 51 CVTypeVisitor Visitor(Pipeline); 52 return Visitor.visitTypeStream(TypeRecords); 53 } 54 55 Error TpiStream::reload() { 56 StreamReader Reader(*Stream); 57 58 if (Reader.bytesRemaining() < sizeof(TpiStreamHeader)) 59 return make_error<RawError>(raw_error_code::corrupt_file, 60 "TPI Stream does not contain a header."); 61 62 if (Reader.readObject(Header)) 63 return make_error<RawError>(raw_error_code::corrupt_file, 64 "TPI Stream does not contain a header."); 65 66 if (Header->Version != PdbTpiV80) 67 return make_error<RawError>(raw_error_code::corrupt_file, 68 "Unsupported TPI Version."); 69 70 if (Header->HeaderSize != sizeof(TpiStreamHeader)) 71 return make_error<RawError>(raw_error_code::corrupt_file, 72 "Corrupt TPI Header size."); 73 74 if (Header->HashKeySize != sizeof(ulittle32_t)) 75 return make_error<RawError>(raw_error_code::corrupt_file, 76 "TPI Stream expected 4 byte hash key size."); 77 78 if (Header->NumHashBuckets < MinTpiHashBuckets || 79 Header->NumHashBuckets > MaxTpiHashBuckets) 80 return make_error<RawError>(raw_error_code::corrupt_file, 81 "TPI Stream Invalid number of hash buckets."); 82 83 // The actual type records themselves come from this stream 84 if (auto EC = Reader.readArray(TypeRecords, Header->TypeRecordBytes)) 85 return EC; 86 87 // Hash indices, hash values, etc come from the hash stream. 88 if (Header->HashStreamIndex != kInvalidStreamIndex) { 89 if (Header->HashStreamIndex >= Pdb.getNumStreams()) 90 return make_error<RawError>(raw_error_code::corrupt_file, 91 "Invalid TPI hash stream index."); 92 93 auto HS = MappedBlockStream::createIndexedStream( 94 Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex); 95 StreamReader HSR(*HS); 96 97 uint32_t NumHashValues = 98 Header->HashValueBuffer.Length / sizeof(ulittle32_t); 99 if (NumHashValues != NumTypeRecords()) 100 return make_error<RawError>( 101 raw_error_code::corrupt_file, 102 "TPI hash count does not match with the number of type records."); 103 HSR.setOffset(Header->HashValueBuffer.Off); 104 if (auto EC = HSR.readArray(HashValues, NumHashValues)) 105 return EC; 106 std::vector<ulittle32_t> HashValueList; 107 for (auto I : HashValues) 108 HashValueList.push_back(I); 109 110 HSR.setOffset(Header->IndexOffsetBuffer.Off); 111 uint32_t NumTypeIndexOffsets = 112 Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset); 113 if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets)) 114 return EC; 115 116 if (Header->HashAdjBuffer.Length > 0) { 117 HSR.setOffset(Header->HashAdjBuffer.Off); 118 if (auto EC = HashAdjusters.load(HSR)) 119 return EC; 120 } 121 122 HashStream = std::move(HS); 123 124 // TPI hash table is a parallel array for the type records. 125 // Verify that the hash values match with type records. 126 if (auto EC = verifyHashValues()) 127 return EC; 128 } 129 130 return Error::success(); 131 } 132 133 PdbRaw_TpiVer TpiStream::getTpiVersion() const { 134 uint32_t Value = Header->Version; 135 return static_cast<PdbRaw_TpiVer>(Value); 136 } 137 138 uint32_t TpiStream::TypeIndexBegin() const { return Header->TypeIndexBegin; } 139 140 uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; } 141 142 uint32_t TpiStream::NumTypeRecords() const { 143 return TypeIndexEnd() - TypeIndexBegin(); 144 } 145 146 uint16_t TpiStream::getTypeHashStreamIndex() const { 147 return Header->HashStreamIndex; 148 } 149 150 uint16_t TpiStream::getTypeHashStreamAuxIndex() const { 151 return Header->HashAuxStreamIndex; 152 } 153 154 uint32_t TpiStream::NumHashBuckets() const { return Header->NumHashBuckets; } 155 uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; } 156 157 FixedStreamArray<support::ulittle32_t> TpiStream::getHashValues() const { 158 return HashValues; 159 } 160 161 FixedStreamArray<TypeIndexOffset> TpiStream::getTypeIndexOffsets() const { 162 return TypeIndexOffsets; 163 } 164 165 HashTable &TpiStream::getHashAdjusters() { return HashAdjusters; } 166 167 iterator_range<CVTypeArray::Iterator> TpiStream::types(bool *HadError) const { 168 return make_range(TypeRecords.begin(HadError), TypeRecords.end()); 169 } 170 171 Error TpiStream::commit() { return Error::success(); } 172