LLVM  9.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  if (Header->HashStreamIndex >= Pdb.getNumStreams())
82  return make_error<RawError>(raw_error_code::corrupt_file,
83  "Invalid TPI hash stream index.");
84 
85  auto HS = MappedBlockStream::createIndexedStream(
86  Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex,
87  Pdb.getAllocator());
88  BinaryStreamReader HSR(*HS);
89 
90  // There should be a hash value for every type record, or no hashes at all.
91  uint32_t NumHashValues =
92  Header->HashValueBuffer.Length / sizeof(ulittle32_t);
93  if (NumHashValues != getNumTypeRecords() && NumHashValues != 0)
94  return make_error<RawError>(
95  raw_error_code::corrupt_file,
96  "TPI hash count does not match with the number of type records.");
97  HSR.setOffset(Header->HashValueBuffer.Off);
98  if (auto EC = HSR.readArray(HashValues, NumHashValues))
99  return EC;
100 
101  HSR.setOffset(Header->IndexOffsetBuffer.Off);
102  uint32_t NumTypeIndexOffsets =
103  Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);
104  if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
105  return EC;
106 
107  if (Header->HashAdjBuffer.Length > 0) {
108  HSR.setOffset(Header->HashAdjBuffer.Off);
109  if (auto EC = HashAdjusters.load(HSR))
110  return EC;
111  }
112 
113  HashStream = std::move(HS);
114  }
115 
116  Types = llvm::make_unique<LazyRandomTypeCollection>(
117  TypeRecords, getNumTypeRecords(), getTypeIndexOffsets());
118  return Error::success();
119 }
120 
122  uint32_t Value = Header->Version;
123  return static_cast<PdbRaw_TpiVer>(Value);
124 }
125 
127 
128 uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; }
129 
131  return TypeIndexEnd() - TypeIndexBegin();
132 }
133 
135  return Header->HashStreamIndex;
136 }
137 
139  return Header->HashAuxStreamIndex;
140 }
141 
143 uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }
144 
146  if (!HashMap.empty())
147  return;
148  if (HashValues.empty())
149  return;
150 
151  HashMap.resize(Header->NumHashBuckets);
152 
153  TypeIndex TIB{Header->TypeIndexBegin};
154  TypeIndex TIE{Header->TypeIndexEnd};
155  while (TIB < TIE) {
156  uint32_t HV = HashValues[TIB.toArrayIndex()];
157  HashMap[HV].push_back(TIB++);
158  }
159 }
160 
161 std::vector<TypeIndex> TpiStream::findRecordsByName(StringRef Name) const {
162  if (!supportsTypeLookup())
163  const_cast<TpiStream*>(this)->buildHashMap();
164 
165  uint32_t Bucket = hashStringV1(Name) % Header->NumHashBuckets;
166  if (Bucket > HashMap.size())
167  return {};
168 
169  std::vector<TypeIndex> Result;
170  for (TypeIndex TI : HashMap[Bucket]) {
171  std::string ThisName = computeTypeName(*Types, TI);
172  if (ThisName == Name)
173  Result.push_back(TI);
174  }
175  return Result;
176 }
177 
178 bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }
179 
182  if (!supportsTypeLookup())
183  const_cast<TpiStream*>(this)->buildHashMap();
184 
185  CVType F = Types->getType(ForwardRefTI);
186  if (!isUdtForwardRef(F))
187  return ForwardRefTI;
188 
189  Expected<TagRecordHash> ForwardTRH = hashTagRecord(F);
190  if (!ForwardTRH)
191  return ForwardTRH.takeError();
192 
193  uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets;
194 
195  for (TypeIndex TI : HashMap[BucketIdx]) {
196  CVType CVT = Types->getType(TI);
197  if (CVT.kind() != F.kind())
198  continue;
199 
200  Expected<TagRecordHash> FullTRH = hashTagRecord(CVT);
201  if (!FullTRH)
202  return FullTRH.takeError();
203  if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash)
204  continue;
205  TagRecord &ForwardTR = ForwardTRH->getRecord();
206  TagRecord &FullTR = FullTRH->getRecord();
207 
208  if (!ForwardTR.hasUniqueName()) {
209  if (ForwardTR.getName() == FullTR.getName())
210  return TI;
211  continue;
212  }
213 
214  if (!FullTR.hasUniqueName())
215  continue;
216  if (ForwardTR.getUniqueName() == FullTR.getUniqueName())
217  return TI;
218  }
219  return ForwardRefTI;
220 }
221 
223  assert(!Index.isSimple());
224  return Types->getType(Index);
225 }
226 
228  return TypeRecordsSubstream;
229 }
230 
232  return HashValues;
233 }
234 
236  return TypeIndexOffsets;
237 }
238 
240  return HashAdjusters;
241 }
242 
243 CVTypeRange TpiStream::types(bool *HadError) const {
244  return make_range(TypeRecords.begin(HadError), TypeRecords.end());
245 }
246 
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:231
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:126
uint32_t getNumStreams() const override
Definition: PDBFile.cpp:83
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:239
Tagged union holding either a T or a Error.
Definition: CachePruning.h:22
PdbRaw_TpiVer getTpiVersion() const
Definition: TpiStream.cpp:121
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
BinaryStreamRef getMsfBuffer() const
Definition: PDBFile.h:82
codeview::CVTypeRange types(bool *HadError) const
Definition: TpiStream.cpp:243
const uint16_t kInvalidStreamIndex
Definition: RawConstants.h:19
BumpPtrAllocator & getAllocator()
Definition: PDBFile.h:103
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:222
BinarySubstreamRef getTypeRecordsSubstream() const
Definition: TpiStream.cpp:227
Expected< codeview::TypeIndex > findFullDeclForForwardRef(codeview::TypeIndex ForwardRefTI) const
Definition: TpiStream.cpp:181
uint32_t getHashKeySize() const
Definition: TpiStream.cpp:143
support::ulittle32_t TypeIndexBegin
Definition: RawTypes.h:285
bool supportsTypeLookup() const
Definition: TpiStream.cpp:178
uint16_t getTypeHashStreamAuxIndex() const
Definition: TpiStream.cpp:138
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:161
A range adaptor for a pair of iterators.
support::ulittle16_t HashAuxStreamIndex
Definition: RawTypes.h:291
uint32_t TypeIndexEnd() const
Definition: TpiStream.cpp:128
support::ulittle32_t HashKeySize
Definition: RawTypes.h:292
uint16_t getTypeHashStreamIndex() const
Definition: TpiStream.cpp:134
uint32_t bytesRemaining() const
uint32_t getNumTypeRecords() const
Definition: TpiStream.cpp:130
support::ulittle32_t HeaderSize
Definition: RawTypes.h:284
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const msf::MSFLayout & getMsfLayout() const
Definition: PDBFile.h:81
Iterator begin(bool *HadError=nullptr) const
LLVM Value Representation.
Definition: Value.h:72
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:142
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:235