LLVM  4.0.0
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 
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 TpiStream::TpiStream(const PDBFile &File,
36  std::unique_ptr<MappedBlockStream> Stream)
37  : 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 Error TpiStream::verifyHashValues() {
44  TpiHashVerifier Verifier(HashValues, Header->NumHashBuckets);
45  TypeDeserializer Deserializer;
46 
48  Pipeline.addCallbackToPipeline(Deserializer);
49  Pipeline.addCallbackToPipeline(Verifier);
50 
51  CVTypeVisitor Visitor(Pipeline);
52  return Visitor.visitTypeStream(TypeRecords);
53 }
54 
56  StreamReader Reader(*Stream);
57 
58  if (Reader.bytesRemaining() < sizeof(TpiStreamHeader))
59  return make_error<RawError>(raw_error_code::corrupt_file,
60  "TPI Stream does not contain a header.");
61 
62  if (Reader.readObject(Header))
63  return make_error<RawError>(raw_error_code::corrupt_file,
64  "TPI Stream does not contain a header.");
65 
66  if (Header->Version != PdbTpiV80)
67  return make_error<RawError>(raw_error_code::corrupt_file,
68  "Unsupported TPI Version.");
69 
70  if (Header->HeaderSize != sizeof(TpiStreamHeader))
71  return make_error<RawError>(raw_error_code::corrupt_file,
72  "Corrupt TPI Header size.");
73 
74  if (Header->HashKeySize != sizeof(ulittle32_t))
75  return make_error<RawError>(raw_error_code::corrupt_file,
76  "TPI Stream expected 4 byte hash key size.");
77 
78  if (Header->NumHashBuckets < MinTpiHashBuckets ||
80  return make_error<RawError>(raw_error_code::corrupt_file,
81  "TPI Stream Invalid number of hash buckets.");
82 
83  // The actual type records themselves come from this stream
84  if (auto EC = Reader.readArray(TypeRecords, Header->TypeRecordBytes))
85  return EC;
86 
87  // Hash indices, hash values, etc come from the hash stream.
88  if (Header->HashStreamIndex != kInvalidStreamIndex) {
89  if (Header->HashStreamIndex >= Pdb.getNumStreams())
90  return make_error<RawError>(raw_error_code::corrupt_file,
91  "Invalid TPI hash stream index.");
92 
93  auto HS = MappedBlockStream::createIndexedStream(
94  Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex);
95  StreamReader HSR(*HS);
96 
97  uint32_t NumHashValues =
98  Header->HashValueBuffer.Length / sizeof(ulittle32_t);
99  if (NumHashValues != NumTypeRecords())
100  return make_error<RawError>(
101  raw_error_code::corrupt_file,
102  "TPI hash count does not match with the number of type records.");
103  HSR.setOffset(Header->HashValueBuffer.Off);
104  if (auto EC = HSR.readArray(HashValues, NumHashValues))
105  return EC;
106  std::vector<ulittle32_t> HashValueList;
107  for (auto I : HashValues)
108  HashValueList.push_back(I);
109 
110  HSR.setOffset(Header->IndexOffsetBuffer.Off);
111  uint32_t NumTypeIndexOffsets =
112  Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);
113  if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
114  return EC;
115 
116  HSR.setOffset(Header->HashAdjBuffer.Off);
117  uint32_t NumHashAdjustments =
118  Header->HashAdjBuffer.Length / sizeof(TypeIndexOffset);
119  if (auto EC = HSR.readArray(HashAdjustments, NumHashAdjustments))
120  return EC;
121 
122  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  if (auto EC = verifyHashValues())
127  return EC;
128  }
129 
130  return Error::success();
131 }
132 
134  uint32_t Value = Header->Version;
135  return static_cast<PdbRaw_TpiVer>(Value);
136 }
137 
139 
140 uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; }
141 
143  return TypeIndexEnd() - TypeIndexBegin();
144 }
145 
147  return Header->HashStreamIndex;
148 }
149 
151  return Header->HashAuxStreamIndex;
152 }
153 
155 uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }
156 
159  return HashValues;
160 }
161 
164  return TypeIndexOffsets;
165 }
166 
169  return HashAdjustments;
170 }
171 
173 TpiStream::types(bool *HadError) const {
174  return make_range(TypeRecords.begin(HadError), TypeRecords.end());
175 }
176 
msf::FixedStreamArray< support::ulittle32_t > getHashValues() const
Definition: TpiStream.cpp:158
msf::FixedStreamArray< TypeIndexOffset > getHashAdjustments() const
Definition: TpiStream.cpp:168
support::ulittle16_t HashStreamIndex
Definition: RawTypes.h:284
EmbeddedBuf IndexOffsetBuffer
Definition: RawTypes.h:290
support::ulittle32_t NumHashBuckets
Definition: RawTypes.h:287
This provides a very simple, boring adaptor for a begin and end iterator into a range type...
support::ulittle32_t TypeRecordBytes
Definition: RawTypes.h:281
uint32_t getNumStreams() const override
Definition: PDBFile.cpp:77
iterator_range< codeview::CVTypeArray::Iterator > types(bool *HadError) const
Definition: TpiStream.cpp:173
Iterator begin(bool *HadError=nullptr) const
Definition: StreamArray.h:96
const uint16_t kInvalidStreamIndex
Definition: RawConstants.h:20
support::ulittle32_t TypeIndexEnd
Definition: RawTypes.h:280
uint16_t getTypeHashStreamIndex() const
Definition: TpiStream.cpp:146
Error readArray(ArrayRef< T > &Array, uint32_t NumElements)
Definition: StreamReader.h:62
const msf::ReadableStream & getMsfBuffer() const
Definition: PDBFile.h:80
const msf::MSFLayout & getMsfLayout() const
Definition: PDBFile.h:79
uint32_t getHashKeySize() const
Definition: TpiStream.cpp:155
support::ulittle32_t TypeIndexBegin
Definition: RawTypes.h:279
const uint32_t MinTpiHashBuckets
Definition: RawTypes.h:294
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
Iterator end() const
Definition: StreamArray.h:100
uint32_t TypeIndexEnd() const
Definition: TpiStream.cpp:140
static ErrorSuccess success()
Create a success value.
EmbeddedBuf HashValueBuffer
Definition: RawTypes.h:289
msf::FixedStreamArray< TypeIndexOffset > getTypeIndexOffsets() const
Definition: TpiStream.cpp:163
A range adaptor for a pair of iterators.
support::ulittle16_t HashAuxStreamIndex
Definition: RawTypes.h:285
uint16_t getTypeHashStreamAuxIndex() const
Definition: TpiStream.cpp:150
uint32_t NumHashBuckets() const
Definition: TpiStream.cpp:154
#define I(x, y, z)
Definition: MD5.cpp:54
support::ulittle32_t HashKeySize
Definition: RawTypes.h:286
PdbRaw_TpiVer getTpiVersion() const
Definition: TpiStream.cpp:133
support::ulittle32_t HeaderSize
Definition: RawTypes.h:278
uint32_t bytesRemaining() const
Definition: StreamReader.h:108
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:235
LLVM Value Representation.
Definition: Value.h:71
support::ulittle32_t Version
Definition: RawTypes.h:277
Lightweight error class with error context and mandatory checking.
uint32_t NumTypeRecords() const
Definition: TpiStream.cpp:142
uint32_t TypeIndexBegin() const
Definition: TpiStream.cpp:138
const uint32_t MaxTpiHashBuckets
Definition: RawTypes.h:295
EmbeddedBuf HashAdjBuffer
Definition: RawTypes.h:291
Error readObject(const T *&Dest)
Definition: StreamReader.h:53
void addCallbackToPipeline(TypeVisitorCallbacks &Callbacks)