LLVM  10.0.0svn
TpiStream.cpp
Go to the documentation of this file.
1 //===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 
24 #include "llvm/Support/Endian.h"
25 #include "llvm/Support/Error.h"
26 #include <algorithm>
27 #include <cstdint>
28 #include <vector>
29 
30 using namespace llvm;
31 using namespace llvm::codeview;
32 using namespace llvm::support;
33 using namespace llvm::msf;
34 using namespace llvm::pdb;
35 
36 TpiStream::TpiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
37  : Pdb(File), Stream(std::move(Stream)) {}
38 
39 TpiStream::~TpiStream() = default;
40 
42  BinaryStreamReader Reader(*Stream);
43 
44  if (Reader.bytesRemaining() < sizeof(TpiStreamHeader))
45  return make_error<RawError>(raw_error_code::corrupt_file,
46  "TPI Stream does not contain a header.");
47 
48  if (Reader.readObject(Header))
49  return make_error<RawError>(raw_error_code::corrupt_file,
50  "TPI Stream does not contain a header.");
51 
52  if (Header->Version != PdbTpiV80)
53  return make_error<RawError>(raw_error_code::corrupt_file,
54  "Unsupported TPI Version.");
55 
56  if (Header->HeaderSize != sizeof(TpiStreamHeader))
57  return make_error<RawError>(raw_error_code::corrupt_file,
58  "Corrupt TPI Header size.");
59 
60  if (Header->HashKeySize != sizeof(ulittle32_t))
61  return make_error<RawError>(raw_error_code::corrupt_file,
62  "TPI Stream expected 4 byte hash key size.");
63 
64  if (Header->NumHashBuckets < MinTpiHashBuckets ||
66  return make_error<RawError>(raw_error_code::corrupt_file,
67  "TPI Stream Invalid number of hash buckets.");
68 
69  // The actual type records themselves come from this stream
70  if (auto EC =
71  Reader.readSubstream(TypeRecordsSubstream, Header->TypeRecordBytes))
72  return EC;
73 
74  BinaryStreamReader RecordReader(TypeRecordsSubstream.StreamData);
75  if (auto EC =
76  RecordReader.readArray(TypeRecords, TypeRecordsSubstream.size()))
77  return EC;
78 
79  // Hash indices, hash values, etc come from the hash stream.
80  if (Header->HashStreamIndex != kInvalidStreamIndex) {
81  auto HS = Pdb.safelyCreateIndexedStream(Header->HashStreamIndex);
82  if (!HS) {
83  consumeError(HS.takeError());
84  return make_error<RawError>(raw_error_code::corrupt_file,
85  "Invalid TPI hash stream index.");
86  }
87  BinaryStreamReader HSR(**HS);
88 
89  // There should be a hash value for every type record, or no hashes at all.
90  uint32_t NumHashValues =
91  Header->HashValueBuffer.Length / sizeof(ulittle32_t);
92  if (NumHashValues != getNumTypeRecords() && NumHashValues != 0)
93  return make_error<RawError>(
94  raw_error_code::corrupt_file,
95  "TPI hash count does not match with the number of type records.");
96  HSR.setOffset(Header->HashValueBuffer.Off);
97  if (auto EC = HSR.readArray(HashValues, NumHashValues))
98  return EC;
99 
100  HSR.setOffset(Header->IndexOffsetBuffer.Off);
101  uint32_t NumTypeIndexOffsets =
102  Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);
103  if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
104  return EC;
105 
106  if (Header->HashAdjBuffer.Length > 0) {
107  HSR.setOffset(Header->HashAdjBuffer.Off);
108  if (auto EC = HashAdjusters.load(HSR))
109  return EC;
110  }
111 
112  HashStream = std::move(*HS);
113  }
114 
115  Types = std::make_unique<LazyRandomTypeCollection>(
116  TypeRecords, getNumTypeRecords(), getTypeIndexOffsets());
117  return Error::success();
118 }
119 
121  uint32_t Value = Header->Version;
122  return static_cast<PdbRaw_TpiVer>(Value);
123 }
124 
126 
127 uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; }
128 
130  return TypeIndexEnd() - TypeIndexBegin();
131 }
132 
134  return Header->HashStreamIndex;
135 }
136 
138  return Header->HashAuxStreamIndex;
139 }
140 
142 uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }
143 
145  if (!HashMap.empty())
146  return;
147  if (HashValues.empty())
148  return;
149 
150  HashMap.resize(Header->NumHashBuckets);
151 
152  TypeIndex TIB{Header->TypeIndexBegin};
153  TypeIndex TIE{Header->TypeIndexEnd};
154  while (TIB < TIE) {
155  uint32_t HV = HashValues[TIB.toArrayIndex()];
156  HashMap[HV].push_back(TIB++);
157  }
158 }
159 
160 std::vector<TypeIndex> TpiStream::findRecordsByName(StringRef Name) const {
161  if (!supportsTypeLookup())
162  const_cast<TpiStream*>(this)->buildHashMap();
163 
164  uint32_t Bucket = hashStringV1(Name) % Header->NumHashBuckets;
165  if (Bucket > HashMap.size())
166  return {};
167 
168  std::vector<TypeIndex> Result;
169  for (TypeIndex TI : HashMap[Bucket]) {
170  std::string ThisName = computeTypeName(*Types, TI);
171  if (ThisName == Name)
172  Result.push_back(TI);
173  }
174  return Result;
175 }
176 
177 bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }
178 
181  if (!supportsTypeLookup())
182  const_cast<TpiStream*>(this)->buildHashMap();
183 
184  CVType F = Types->getType(ForwardRefTI);
185  if (!isUdtForwardRef(F))
186  return ForwardRefTI;
187 
188  Expected<TagRecordHash> ForwardTRH = hashTagRecord(F);
189  if (!ForwardTRH)
190  return ForwardTRH.takeError();
191 
192  uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets;
193 
194  for (TypeIndex TI : HashMap[BucketIdx]) {
195  CVType CVT = Types->getType(TI);
196  if (CVT.kind() != F.kind())
197  continue;
198 
199  Expected<TagRecordHash> FullTRH = hashTagRecord(CVT);
200  if (!FullTRH)
201  return FullTRH.takeError();
202  if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash)
203  continue;
204  TagRecord &ForwardTR = ForwardTRH->getRecord();
205  TagRecord &FullTR = FullTRH->getRecord();
206 
207  if (!ForwardTR.hasUniqueName()) {
208  if (ForwardTR.getName() == FullTR.getName())
209  return TI;
210  continue;
211  }
212 
213  if (!FullTR.hasUniqueName())
214  continue;
215  if (ForwardTR.getUniqueName() == FullTR.getUniqueName())
216  return TI;
217  }
218  return ForwardRefTI;
219 }
220 
222  assert(!Index.isSimple());
223  return Types->getType(Index);
224 }
225 
227  return TypeRecordsSubstream;
228 }
229 
231  return HashValues;
232 }
233 
235  return TypeIndexOffsets;
236 }
237 
239  return HashAdjusters;
240 }
241 
242 CVTypeRange TpiStream::types(bool *HadError) const {
243  return make_range(TypeRecords.begin(HadError), TypeRecords.end());
244 }
245 
Error readSubstream(BinarySubstreamRef &Stream, uint32_t Size)
Read Length bytes from the underlying stream into Stream.
Kind kind() const
Definition: CVRecord.h:43
This class represents lattice values for constants.
Definition: AllocatorList.h:23
support::ulittle16_t HashStreamIndex
Definition: RawTypes.h:290
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
EmbeddedBuf IndexOffsetBuffer
Definition: RawTypes.h:296
support::ulittle32_t NumHashBuckets
Definition: RawTypes.h:293
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:230
F(f)
std::string computeTypeName(TypeCollection &Types, TypeIndex Index)
Definition: RecordName.cpp:248
Error takeError()
Take ownership of the stored error.
Definition: Error.h:552
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:287
uint32_t TypeIndexBegin() const
Definition: TpiStream.cpp:125
StringRef getName() const
Definition: TypeRecord.h:459
bool hasUniqueName() const
Definition: TypeRecord.h:436
Definition: BitVector.h:937
HashTable< support::ulittle32_t > & getHashAdjusters()
Definition: TpiStream.cpp:238
Tagged union holding either a T or a Error.
Definition: yaml2obj.h:21
PdbRaw_TpiVer getTpiVersion() const
Definition: TpiStream.cpp:120
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:88
A 32-bit type reference.
Definition: TypeIndex.h:95
Expected< std::unique_ptr< msf::MappedBlockStream > > safelyCreateIndexedStream(uint32_t StreamIndex) const
Wrapper around MappedBlockStream::createIndexedStream() that checks if a stream with that index actua...
Definition: PDBFile.cpp:488
codeview::CVTypeRange types(bool *HadError) const
Definition: TpiStream.cpp:242
const uint16_t kInvalidStreamIndex
Definition: RawConstants.h:19
uint32_t hashStringV1(StringRef Str)
Definition: Hash.cpp:20
support::ulittle32_t TypeIndexEnd
Definition: RawTypes.h:286
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:274
Instrumentation for Order File
StringRef getUniqueName() const
Definition: TypeRecord.h:460
codeview::CVType getType(codeview::TypeIndex Index)
Definition: TpiStream.cpp:221
BinarySubstreamRef getTypeRecordsSubstream() const
Definition: TpiStream.cpp:226
Expected< codeview::TypeIndex > findFullDeclForForwardRef(codeview::TypeIndex ForwardRefTI) const
Definition: TpiStream.cpp:180
uint32_t getHashKeySize() const
Definition: TpiStream.cpp:142
support::ulittle32_t TypeIndexBegin
Definition: RawTypes.h:285
bool supportsTypeLookup() const
Definition: TpiStream.cpp:177
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:981
uint16_t getTypeHashStreamAuxIndex() const
Definition: TpiStream.cpp:137
BinaryStreamRef StreamData
const uint32_t MinTpiHashBuckets
Definition: RawTypes.h:300
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:326
EmbeddedBuf HashValueBuffer
Definition: RawTypes.h:295
std::vector< codeview::TypeIndex > findRecordsByName(StringRef Name) const
Definition: TpiStream.cpp:160
A range adaptor for a pair of iterators.
support::ulittle16_t HashAuxStreamIndex
Definition: RawTypes.h:291
uint32_t TypeIndexEnd() const
Definition: TpiStream.cpp:127
support::ulittle32_t HashKeySize
Definition: RawTypes.h:292
uint16_t getTypeHashStreamIndex() const
Definition: TpiStream.cpp:133
uint32_t bytesRemaining() const
uint32_t getNumTypeRecords() const
Definition: TpiStream.cpp:129
support::ulittle32_t HeaderSize
Definition: RawTypes.h:284
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Iterator begin(bool *HadError=nullptr) const
LLVM Value Representation.
Definition: Value.h:73
support::ulittle32_t Version
Definition: RawTypes.h:283
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
Provides read only access to a subclass of BinaryStream.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
uint32_t getNumHashBuckets() const
Definition: TpiStream.cpp:141
const uint32_t MaxTpiHashBuckets
Definition: RawTypes.h:301
EmbeddedBuf HashAdjBuffer
Definition: RawTypes.h:297
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:234