LLVM  8.0.0svn
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 
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 bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }
162 
165  CVType F = Types->getType(ForwardRefTI);
166  if (!isUdtForwardRef(F))
167  return ForwardRefTI;
168 
169  Expected<TagRecordHash> ForwardTRH = hashTagRecord(F);
170  if (!ForwardTRH)
171  return ForwardTRH.takeError();
172 
173  uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets;
174 
175  for (TypeIndex TI : HashMap[BucketIdx]) {
176  CVType CVT = Types->getType(TI);
177  if (CVT.kind() != F.kind())
178  continue;
179 
180  Expected<TagRecordHash> FullTRH = hashTagRecord(CVT);
181  if (!FullTRH)
182  return FullTRH.takeError();
183  if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash)
184  continue;
185  TagRecord &ForwardTR = ForwardTRH->getRecord();
186  TagRecord &FullTR = FullTRH->getRecord();
187 
188  if (!ForwardTR.hasUniqueName()) {
189  if (ForwardTR.getName() == FullTR.getName())
190  return TI;
191  continue;
192  }
193 
194  if (!FullTR.hasUniqueName())
195  continue;
196  if (ForwardTR.getUniqueName() == FullTR.getUniqueName())
197  return TI;
198  }
199  return ForwardRefTI;
200 }
201 
203  return TypeRecordsSubstream;
204 }
205 
207  return HashValues;
208 }
209 
211  return TypeIndexOffsets;
212 }
213 
215  return HashAdjusters;
216 }
217 
218 CVTypeRange TpiStream::types(bool *HadError) const {
219  return make_range(TypeRecords.begin(HadError), TypeRecords.end());
220 }
221 
Error readSubstream(BinarySubstreamRef &Stream, uint32_t Size)
Read Length bytes from the underlying stream into Stream.
Kind kind() const
Definition: CVRecord.h:37
Compute iterated dominance frontiers using a linear time algorithm.
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:206
F(f)
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:126
uint32_t getNumStreams() const override
Definition: PDBFile.cpp:84
StringRef getName() const
Definition: TypeRecord.h:435
bool hasUniqueName() const
Definition: TypeRecord.h:420
Definition: BitVector.h:938
HashTable< support::ulittle32_t > & getHashAdjusters()
Definition: TpiStream.cpp:214
Tagged union holding either a T or a Error.
Definition: CachePruning.h:23
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: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:218
const uint16_t kInvalidStreamIndex
Definition: RawConstants.h:20
BumpPtrAllocator & getAllocator()
Definition: PDBFile.h:104
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:436
BinarySubstreamRef getTypeRecordsSubstream() const
Definition: TpiStream.cpp:202
Expected< codeview::TypeIndex > findFullDeclForForwardRef(codeview::TypeIndex ForwardRefTI) const
Definition: TpiStream.cpp:164
uint32_t getHashKeySize() const
Definition: TpiStream.cpp:143
support::ulittle32_t TypeIndexBegin
Definition: RawTypes.h:286
bool supportsTypeLookup() const
Definition: TpiStream.cpp:161
uint16_t getTypeHashStreamAuxIndex() const
Definition: TpiStream.cpp:138
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
A range adaptor for a pair of iterators.
support::ulittle16_t HashAuxStreamIndex
Definition: RawTypes.h:292
uint32_t TypeIndexEnd() const
Definition: TpiStream.cpp:128
support::ulittle32_t HashKeySize
Definition: RawTypes.h:293
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:285
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.
uint32_t getNumHashBuckets() const
Definition: TpiStream.cpp:142
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:210