LLVM  8.0.1
TpiStream.cpp
Go to the documentation of this file.
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 
11 
25 #include "llvm/Support/Endian.h"
26 #include "llvm/Support/Error.h"
27 #include <algorithm>
28 #include <cstdint>
29 #include <vector>
30 
31 using namespace llvm;
32 using namespace llvm::codeview;
33 using namespace llvm::support;
34 using namespace llvm::msf;
35 using namespace llvm::pdb;
36 
37 TpiStream::TpiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
38  : Pdb(File), Stream(std::move(Stream)) {}
39 
40 TpiStream::~TpiStream() = default;
41 
43  BinaryStreamReader Reader(*Stream);
44 
45  if (Reader.bytesRemaining() < sizeof(TpiStreamHeader))
46  return make_error<RawError>(raw_error_code::corrupt_file,
47  "TPI Stream does not contain a header.");
48 
49  if (Reader.readObject(Header))
50  return make_error<RawError>(raw_error_code::corrupt_file,
51  "TPI Stream does not contain a header.");
52 
53  if (Header->Version != PdbTpiV80)
54  return make_error<RawError>(raw_error_code::corrupt_file,
55  "Unsupported TPI Version.");
56 
57  if (Header->HeaderSize != sizeof(TpiStreamHeader))
58  return make_error<RawError>(raw_error_code::corrupt_file,
59  "Corrupt TPI Header size.");
60 
61  if (Header->HashKeySize != sizeof(ulittle32_t))
62  return make_error<RawError>(raw_error_code::corrupt_file,
63  "TPI Stream expected 4 byte hash key size.");
64 
65  if (Header->NumHashBuckets < MinTpiHashBuckets ||
67  return make_error<RawError>(raw_error_code::corrupt_file,
68  "TPI Stream Invalid number of hash buckets.");
69 
70  // The actual type records themselves come from this stream
71  if (auto EC =
72  Reader.readSubstream(TypeRecordsSubstream, Header->TypeRecordBytes))
73  return EC;
74 
75  BinaryStreamReader RecordReader(TypeRecordsSubstream.StreamData);
76  if (auto EC =
77  RecordReader.readArray(TypeRecords, TypeRecordsSubstream.size()))
78  return EC;
79 
80  // Hash indices, hash values, etc come from the hash stream.
81  if (Header->HashStreamIndex != kInvalidStreamIndex) {
82  if (Header->HashStreamIndex >= Pdb.getNumStreams())
83  return make_error<RawError>(raw_error_code::corrupt_file,
84  "Invalid TPI hash stream index.");
85 
86  auto HS = MappedBlockStream::createIndexedStream(
87  Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex,
88  Pdb.getAllocator());
89  BinaryStreamReader HSR(*HS);
90 
91  // There should be a hash value for every type record, or no hashes at all.
92  uint32_t NumHashValues =
93  Header->HashValueBuffer.Length / sizeof(ulittle32_t);
94  if (NumHashValues != getNumTypeRecords() && NumHashValues != 0)
95  return make_error<RawError>(
96  raw_error_code::corrupt_file,
97  "TPI hash count does not match with the number of type records.");
98  HSR.setOffset(Header->HashValueBuffer.Off);
99  if (auto EC = HSR.readArray(HashValues, NumHashValues))
100  return EC;
101 
102  HSR.setOffset(Header->IndexOffsetBuffer.Off);
103  uint32_t NumTypeIndexOffsets =
104  Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);
105  if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
106  return EC;
107 
108  if (Header->HashAdjBuffer.Length > 0) {
109  HSR.setOffset(Header->HashAdjBuffer.Off);
110  if (auto EC = HashAdjusters.load(HSR))
111  return EC;
112  }
113 
114  HashStream = std::move(HS);
115  }
116 
117  Types = llvm::make_unique<LazyRandomTypeCollection>(
118  TypeRecords, getNumTypeRecords(), getTypeIndexOffsets());
119  return Error::success();
120 }
121 
123  uint32_t Value = Header->Version;
124  return static_cast<PdbRaw_TpiVer>(Value);
125 }
126 
128 
129 uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; }
130 
132  return TypeIndexEnd() - TypeIndexBegin();
133 }
134 
136  return Header->HashStreamIndex;
137 }
138 
140  return Header->HashAuxStreamIndex;
141 }
142 
144 uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }
145 
147  if (!HashMap.empty())
148  return;
149  if (HashValues.empty())
150  return;
151 
152  HashMap.resize(Header->NumHashBuckets);
153 
154  TypeIndex TIB{Header->TypeIndexBegin};
155  TypeIndex TIE{Header->TypeIndexEnd};
156  while (TIB < TIE) {
157  uint32_t HV = HashValues[TIB.toArrayIndex()];
158  HashMap[HV].push_back(TIB++);
159  }
160 }
161 
162 std::vector<TypeIndex> TpiStream::findRecordsByName(StringRef Name) const {
163  if (!supportsTypeLookup())
164  const_cast<TpiStream*>(this)->buildHashMap();
165 
166  uint32_t Bucket = hashStringV1(Name) % Header->NumHashBuckets;
167  if (Bucket > HashMap.size())
168  return {};
169 
170  std::vector<TypeIndex> Result;
171  for (TypeIndex TI : HashMap[Bucket]) {
172  std::string ThisName = computeTypeName(*Types, TI);
173  if (ThisName == Name)
174  Result.push_back(TI);
175  }
176  return Result;
177 }
178 
179 bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }
180 
183  if (!supportsTypeLookup())
184  const_cast<TpiStream*>(this)->buildHashMap();
185 
186  CVType F = Types->getType(ForwardRefTI);
187  if (!isUdtForwardRef(F))
188  return ForwardRefTI;
189 
190  Expected<TagRecordHash> ForwardTRH = hashTagRecord(F);
191  if (!ForwardTRH)
192  return ForwardTRH.takeError();
193 
194  uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets;
195 
196  for (TypeIndex TI : HashMap[BucketIdx]) {
197  CVType CVT = Types->getType(TI);
198  if (CVT.kind() != F.kind())
199  continue;
200 
201  Expected<TagRecordHash> FullTRH = hashTagRecord(CVT);
202  if (!FullTRH)
203  return FullTRH.takeError();
204  if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash)
205  continue;
206  TagRecord &ForwardTR = ForwardTRH->getRecord();
207  TagRecord &FullTR = FullTRH->getRecord();
208 
209  if (!ForwardTR.hasUniqueName()) {
210  if (ForwardTR.getName() == FullTR.getName())
211  return TI;
212  continue;
213  }
214 
215  if (!FullTR.hasUniqueName())
216  continue;
217  if (ForwardTR.getUniqueName() == FullTR.getUniqueName())
218  return TI;
219  }
220  return ForwardRefTI;
221 }
222 
224  assert(!Index.isSimple());
225  return Types->getType(Index);
226 }
227 
229  return TypeRecordsSubstream;
230 }
231 
233  return HashValues;
234 }
235 
237  return TypeIndexOffsets;
238 }
239 
241  return HashAdjusters;
242 }
243 
244 CVTypeRange TpiStream::types(bool *HadError) const {
245  return make_range(TypeRecords.begin(HadError), TypeRecords.end());
246 }
247 
Error readSubstream(BinarySubstreamRef &Stream, uint32_t Size)
Read Length bytes from the underlying stream into Stream.
Kind kind() const
Definition: CVRecord.h:37
This class represents lattice values for constants.
Definition: AllocatorList.h:24
support::ulittle16_t HashStreamIndex
Definition: RawTypes.h:291
EmbeddedBuf IndexOffsetBuffer
Definition: RawTypes.h:297
support::ulittle32_t NumHashBuckets
Definition: RawTypes.h:294
Iterator end() const
This provides a very simple, boring adaptor for a begin and end iterator into a range type...
Error readObject(const T *&Dest)
Get a pointer to an object of type T from the underlying stream, as if by memcpy, and store the resul...
FixedStreamArray< support::ulittle32_t > getHashValues() const
Definition: TpiStream.cpp:232
F(f)
std::string computeTypeName(TypeCollection &Types, TypeIndex Index)
Definition: RecordName.cpp:249
Error takeError()
Take ownership of the stored error.
Definition: Error.h:553
bool isUdtForwardRef(CVType CVT)
Given an arbitrary codeview type, determine if it is an LF_STRUCTURE, LF_CLASS, LF_INTERFACE, LF_UNION, or LF_ENUM with the forward ref class option.
support::ulittle32_t TypeRecordBytes
Definition: RawTypes.h:288
uint32_t TypeIndexBegin() const
Definition: TpiStream.cpp:127
uint32_t getNumStreams() const override
Definition: PDBFile.cpp:84
StringRef getName() const
Definition: TypeRecord.h:460
bool hasUniqueName() const
Definition: TypeRecord.h:437
amdgpu Simplify well known AMD library false Value Value const Twine & Name
Definition: BitVector.h:938
HashTable< support::ulittle32_t > & getHashAdjusters()
Definition: TpiStream.cpp:240
Tagged union holding either a T or a Error.
Definition: CachePruning.h:23
PdbRaw_TpiVer getTpiVersion() const
Definition: TpiStream.cpp:122
Expected< TagRecordHash > hashTagRecord(const codeview::CVType &Type)
Given a CVType referring to a class, structure, union, or enum, compute the hash of its forward decl ...
Definition: TpiHashing.cpp:89
A 32-bit type reference.
Definition: TypeIndex.h:96
BinaryStreamRef getMsfBuffer() const
Definition: PDBFile.h:83
codeview::CVTypeRange types(bool *HadError) const
Definition: TpiStream.cpp:244
const uint16_t kInvalidStreamIndex
Definition: RawConstants.h:20
BumpPtrAllocator & getAllocator()
Definition: PDBFile.h:104
uint32_t hashStringV1(StringRef Str)
Definition: Hash.cpp:21
support::ulittle32_t TypeIndexEnd
Definition: RawTypes.h:287
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:271
StringRef getUniqueName() const
Definition: TypeRecord.h:461
codeview::CVType getType(codeview::TypeIndex Index)
Definition: TpiStream.cpp:223
BinarySubstreamRef getTypeRecordsSubstream() const
Definition: TpiStream.cpp:228
Expected< codeview::TypeIndex > findFullDeclForForwardRef(codeview::TypeIndex ForwardRefTI) const
Definition: TpiStream.cpp:182
uint32_t getHashKeySize() const
Definition: TpiStream.cpp:144
support::ulittle32_t TypeIndexBegin
Definition: RawTypes.h:286
bool supportsTypeLookup() const
Definition: TpiStream.cpp:179
uint16_t getTypeHashStreamAuxIndex() const
Definition: TpiStream.cpp:139
BinaryStreamRef StreamData
const uint32_t MinTpiHashBuckets
Definition: RawTypes.h:301
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
static ErrorSuccess success()
Create a success value.
Definition: Error.h:327
EmbeddedBuf HashValueBuffer
Definition: RawTypes.h:296
std::vector< codeview::TypeIndex > findRecordsByName(StringRef Name) const
Definition: TpiStream.cpp:162
A range adaptor for a pair of iterators.
support::ulittle16_t HashAuxStreamIndex
Definition: RawTypes.h:292
uint32_t TypeIndexEnd() const
Definition: TpiStream.cpp:129
support::ulittle32_t HashKeySize
Definition: RawTypes.h:293
uint16_t getTypeHashStreamIndex() const
Definition: TpiStream.cpp:135
uint32_t bytesRemaining() const
uint32_t getNumTypeRecords() const
Definition: TpiStream.cpp:131
support::ulittle32_t HeaderSize
Definition: RawTypes.h:285
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const msf::MSFLayout & getMsfLayout() const
Definition: PDBFile.h:82
Iterator begin(bool *HadError=nullptr) const
LLVM Value Representation.
Definition: Value.h:73
support::ulittle32_t Version
Definition: RawTypes.h:284
Lightweight error class with error context and mandatory checking.
Definition: Error.h:158
Provides read only access to a subclass of BinaryStream.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
uint32_t getNumHashBuckets() const
Definition: TpiStream.cpp:143
const uint32_t MaxTpiHashBuckets
Definition: RawTypes.h:302
EmbeddedBuf HashAdjBuffer
Definition: RawTypes.h:298
Error readArray(ArrayRef< T > &Array, uint32_t NumElements)
Get a reference to a NumElements element array of objects of type T from the underlying stream as if ...
FixedStreamArray< codeview::TypeIndexOffset > getTypeIndexOffsets() const
Definition: TpiStream.cpp:236