Line data Source code
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/ADT/iterator_range.h"
11 : #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
12 : #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
13 : #include "llvm/DebugInfo/CodeView/TypeRecord.h"
14 : #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
15 : #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
16 : #include "llvm/DebugInfo/MSF/StreamReader.h"
17 : #include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
18 : #include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
19 : #include "llvm/DebugInfo/PDB/Raw/RawError.h"
20 : #include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
21 : #include "llvm/DebugInfo/PDB/Raw/TpiHashing.h"
22 : #include "llvm/DebugInfo/PDB/Raw/TpiStream.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 17 : TpiStream::TpiStream(const PDBFile &File,
36 17 : std::unique_ptr<MappedBlockStream> Stream)
37 119 : : 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 13 : Error TpiStream::verifyHashValues() {
44 52 : TpiHashVerifier Verifier(HashValues, Header->NumHashBuckets);
45 26 : TypeDeserializer Deserializer;
46 :
47 26 : TypeVisitorCallbackPipeline Pipeline;
48 13 : Pipeline.addCallbackToPipeline(Deserializer);
49 13 : Pipeline.addCallbackToPipeline(Verifier);
50 :
51 13 : CVTypeVisitor Visitor(Pipeline);
52 26 : return Visitor.visitTypeStream(TypeRecords);
53 : }
54 :
55 17 : Error TpiStream::reload() {
56 51 : StreamReader Reader(*Stream);
57 :
58 17 : if (Reader.bytesRemaining() < sizeof(TpiStreamHeader))
59 : return make_error<RawError>(raw_error_code::corrupt_file,
60 0 : "TPI Stream does not contain a header.");
61 :
62 51 : if (Reader.readObject(Header))
63 : return make_error<RawError>(raw_error_code::corrupt_file,
64 0 : "TPI Stream does not contain a header.");
65 :
66 34 : if (Header->Version != PdbTpiV80)
67 : return make_error<RawError>(raw_error_code::corrupt_file,
68 0 : "Unsupported TPI Version.");
69 :
70 34 : if (Header->HeaderSize != sizeof(TpiStreamHeader))
71 : return make_error<RawError>(raw_error_code::corrupt_file,
72 0 : "Corrupt TPI Header size.");
73 :
74 34 : if (Header->HashKeySize != sizeof(ulittle32_t))
75 : return make_error<RawError>(raw_error_code::corrupt_file,
76 0 : "TPI Stream expected 4 byte hash key size.");
77 :
78 51 : if (Header->NumHashBuckets < MinTpiHashBuckets ||
79 34 : Header->NumHashBuckets > MaxTpiHashBuckets)
80 : return make_error<RawError>(raw_error_code::corrupt_file,
81 0 : "TPI Stream Invalid number of hash buckets.");
82 :
83 : // The actual type records themselves come from this stream
84 68 : if (auto EC = Reader.readArray(TypeRecords, Header->TypeRecordBytes))
85 0 : return EC;
86 :
87 : // Hash indices, hash values, etc come from the hash stream.
88 34 : if (Header->HashStreamIndex != kInvalidStreamIndex) {
89 26 : if (Header->HashStreamIndex >= Pdb.getNumStreams())
90 : return make_error<RawError>(raw_error_code::corrupt_file,
91 0 : "Invalid TPI hash stream index.");
92 :
93 : auto HS = MappedBlockStream::createIndexedStream(
94 65 : Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex);
95 26 : StreamReader HSR(*HS);
96 :
97 : uint32_t NumHashValues =
98 26 : Header->HashValueBuffer.Length / sizeof(ulittle32_t);
99 13 : if (NumHashValues != NumTypeRecords())
100 : return make_error<RawError>(
101 : raw_error_code::corrupt_file,
102 0 : "TPI hash count does not match with the number of type records.");
103 39 : HSR.setOffset(Header->HashValueBuffer.Off);
104 39 : if (auto EC = HSR.readArray(HashValues, NumHashValues))
105 0 : return EC;
106 26 : std::vector<ulittle32_t> HashValueList;
107 1509 : for (auto I : HashValues)
108 735 : HashValueList.push_back(I);
109 :
110 39 : HSR.setOffset(Header->IndexOffsetBuffer.Off);
111 : uint32_t NumTypeIndexOffsets =
112 26 : Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);
113 39 : if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
114 0 : return EC;
115 :
116 39 : HSR.setOffset(Header->HashAdjBuffer.Off);
117 : uint32_t NumHashAdjustments =
118 26 : Header->HashAdjBuffer.Length / sizeof(TypeIndexOffset);
119 39 : if (auto EC = HSR.readArray(HashAdjustments, NumHashAdjustments))
120 0 : return EC;
121 :
122 26 : 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 39 : if (auto EC = verifyHashValues())
127 0 : return EC;
128 : }
129 :
130 51 : return Error::success();
131 : }
132 :
133 13 : PdbRaw_TpiVer TpiStream::getTpiVersion() const {
134 26 : uint32_t Value = Header->Version;
135 13 : return static_cast<PdbRaw_TpiVer>(Value);
136 : }
137 :
138 38 : uint32_t TpiStream::TypeIndexBegin() const { return Header->TypeIndexBegin; }
139 :
140 38 : uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; }
141 :
142 19 : uint32_t TpiStream::NumTypeRecords() const {
143 19 : return TypeIndexEnd() - TypeIndexBegin();
144 : }
145 :
146 68 : uint16_t TpiStream::getTypeHashStreamIndex() const {
147 136 : return Header->HashStreamIndex;
148 : }
149 :
150 60 : uint16_t TpiStream::getTypeHashStreamAuxIndex() const {
151 120 : return Header->HashAuxStreamIndex;
152 : }
153 :
154 8 : uint32_t TpiStream::NumHashBuckets() const { return Header->NumHashBuckets; }
155 8 : uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }
156 :
157 : FixedStreamArray<support::ulittle32_t>
158 4 : TpiStream::getHashValues() const {
159 4 : return HashValues;
160 : }
161 :
162 : FixedStreamArray<TypeIndexOffset>
163 10 : TpiStream::getTypeIndexOffsets() const {
164 10 : return TypeIndexOffsets;
165 : }
166 :
167 : FixedStreamArray<TypeIndexOffset>
168 4 : TpiStream::getHashAdjustments() const {
169 4 : return HashAdjustments;
170 : }
171 :
172 : iterator_range<CVTypeArray::Iterator>
173 13 : TpiStream::types(bool *HadError) const {
174 65 : return make_range(TypeRecords.begin(HadError), TypeRecords.end());
175 : }
176 :
177 0 : Error TpiStream::commit() { return Error::success(); }
|