LLVM  4.0.0
PDBFile.cpp
Go to the documentation of this file.
1 //===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
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 
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/Support/Endian.h"
27 #include "llvm/Support/Error.h"
28 #include <algorithm>
29 #include <cassert>
30 #include <cstdint>
31 
32 using namespace llvm;
33 using namespace llvm::codeview;
34 using namespace llvm::msf;
35 using namespace llvm::pdb;
36 
37 namespace {
38 typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
39 } // end anonymous namespace
40 
41 PDBFile::PDBFile(std::unique_ptr<ReadableStream> PdbFileBuffer,
43  : Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {}
44 
45 PDBFile::~PDBFile() = default;
46 
47 uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
48 
50  return ContainerLayout.SB->FreeBlockMapBlock;
51 }
52 
54  return ContainerLayout.SB->NumBlocks;
55 }
56 
58  return ContainerLayout.SB->NumDirectoryBytes;
59 }
60 
62  return ContainerLayout.SB->BlockMapAddr;
63 }
64 
65 uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
66 
68  return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
69  ContainerLayout.SB->BlockSize);
70 }
71 
72 uint64_t PDBFile::getBlockMapOffset() const {
73  return (uint64_t)ContainerLayout.SB->BlockMapAddr *
74  ContainerLayout.SB->BlockSize;
75 }
76 
78  return ContainerLayout.StreamSizes.size();
79 }
80 
82  return ContainerLayout.StreamSizes[StreamIndex];
83 }
84 
87  return ContainerLayout.StreamMap[StreamIndex];
88 }
89 
90 uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
91 
93  uint32_t NumBytes) const {
94  uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
95 
96  ArrayRef<uint8_t> Result;
97  if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
98  return std::move(EC);
99  return Result;
100 }
101 
103  ArrayRef<uint8_t> Data) const {
104  return make_error<RawError>(raw_error_code::not_writable,
105  "PDBFile is immutable");
106 }
107 
109  StreamReader Reader(*Buffer);
110 
111  // Initialize SB.
112  const msf::SuperBlock *SB = nullptr;
113  if (auto EC = Reader.readObject(SB)) {
114  consumeError(std::move(EC));
115  return make_error<RawError>(raw_error_code::corrupt_file,
116  "Does not contain superblock");
117  }
118 
119  if (auto EC = msf::validateSuperBlock(*SB))
120  return EC;
121 
122  if (Buffer->getLength() % SB->BlockSize != 0)
123  return make_error<RawError>(raw_error_code::corrupt_file,
124  "File size is not a multiple of block size");
125  ContainerLayout.SB = SB;
126 
127  // Initialize Free Page Map.
128  ContainerLayout.FreePageMap.resize(SB->NumBlocks);
129  // The Fpm exists either at block 1 or block 2 of the MSF. However, this
130  // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
131  // thusly an equal number of total blocks in the file. For a block size
132  // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
133  // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so
134  // the Fpm is split across the file at `getBlockSize()` intervals. As a
135  // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
136  // for any non-negative integer k is an Fpm block. In theory, we only really
137  // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
138  // current versions of the MSF format already expect the Fpm to be arranged
139  // at getBlockSize() intervals, so we have to be compatible.
140  // See the function fpmPn() for more information:
141  // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
142  auto FpmStream = MappedBlockStream::createFpmStream(ContainerLayout, *Buffer);
143  StreamReader FpmReader(*FpmStream);
144  ArrayRef<uint8_t> FpmBytes;
145  if (auto EC = FpmReader.readBytes(FpmBytes,
146  msf::getFullFpmByteSize(ContainerLayout)))
147  return EC;
148  uint32_t BlocksRemaining = getBlockCount();
149  uint32_t BI = 0;
150  for (auto Byte : FpmBytes) {
151  uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
152  for (uint32_t I = 0; I < BlocksThisByte; ++I) {
153  if (Byte & (1 << I))
154  ContainerLayout.FreePageMap[BI] = true;
155  --BlocksRemaining;
156  ++BI;
157  }
158  }
159 
160  Reader.setOffset(getBlockMapOffset());
161  if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
163  return EC;
164 
165  return Error::success();
166 }
167 
169  assert(ContainerLayout.SB);
170  if (DirectoryStream)
171  return Error::success();
172 
173  uint32_t NumStreams = 0;
174 
175  // Normally you can't use a MappedBlockStream without having fully parsed the
176  // PDB file, because it accesses the directory and various other things, which
177  // is exactly what we are attempting to parse. By specifying a custom
178  // subclass of IPDBStreamData which only accesses the fields that have already
179  // been parsed, we can avoid this and reuse MappedBlockStream.
180  auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer);
181  StreamReader Reader(*DS);
182  if (auto EC = Reader.readInteger(NumStreams))
183  return EC;
184 
185  if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
186  return EC;
187  for (uint32_t I = 0; I < NumStreams; ++I) {
188  uint32_t StreamSize = getStreamByteSize(I);
189  // FIXME: What does StreamSize ~0U mean?
190  uint64_t NumExpectedStreamBlocks =
191  StreamSize == UINT32_MAX
192  ? 0
193  : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
194 
195  // For convenience, we store the block array contiguously. This is because
196  // if someone calls setStreamMap(), it is more convenient to be able to call
197  // it with an ArrayRef instead of setting up a StreamRef. Since the
198  // DirectoryStream is cached in the class and thus lives for the life of the
199  // class, we can be guaranteed that readArray() will return a stable
200  // reference, even if it has to allocate from its internal pool.
202  if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
203  return EC;
204  for (uint32_t Block : Blocks) {
205  uint64_t BlockEndOffset =
206  (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
207  if (BlockEndOffset > getFileSize())
208  return make_error<RawError>(raw_error_code::corrupt_file,
209  "Stream block map is corrupt.");
210  }
211  ContainerLayout.StreamMap.push_back(Blocks);
212  }
213 
214  // We should have read exactly SB->NumDirectoryBytes bytes.
215  assert(Reader.bytesRemaining() == 0);
216  DirectoryStream = std::move(DS);
217  return Error::success();
218 }
219 
221  return ContainerLayout.DirectoryBlocks;
222 }
223 
225  if (!Globals) {
226  auto DbiS = getPDBDbiStream();
227  if (!DbiS)
228  return DbiS.takeError();
229 
230  auto GlobalS = safelyCreateIndexedStream(
231  ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex());
232  if (!GlobalS) return GlobalS.takeError();
233  auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS));
234  if (auto EC = TempGlobals->reload())
235  return std::move(EC);
236  Globals = std::move(TempGlobals);
237  }
238  return *Globals;
239 }
240 
242  if (!Info) {
243  auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB);
244  if (!InfoS) return InfoS.takeError();
245  auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
246  if (auto EC = TempInfo->reload())
247  return std::move(EC);
248  Info = std::move(TempInfo);
249  }
250  return *Info;
251 }
252 
254  if (!Dbi) {
255  auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI);
256  if (!DbiS) return DbiS.takeError();
257  auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
258  if (auto EC = TempDbi->reload())
259  return std::move(EC);
260  Dbi = std::move(TempDbi);
261  }
262  return *Dbi;
263 }
264 
266  if (!Tpi) {
267  auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI);
268  if (!TpiS) return TpiS.takeError();
269  auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
270  if (auto EC = TempTpi->reload())
271  return std::move(EC);
272  Tpi = std::move(TempTpi);
273  }
274  return *Tpi;
275 }
276 
278  if (!Ipi) {
279  auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI);
280  if (!IpiS) return IpiS.takeError();
281  auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
282  if (auto EC = TempIpi->reload())
283  return std::move(EC);
284  Ipi = std::move(TempIpi);
285  }
286  return *Ipi;
287 }
288 
290  if (!Publics) {
291  auto DbiS = getPDBDbiStream();
292  if (!DbiS)
293  return DbiS.takeError();
294 
295  auto PublicS = safelyCreateIndexedStream(
296  ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex());
297  if (!PublicS) return PublicS.takeError();
298  auto TempPublics =
299  llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
300  if (auto EC = TempPublics->reload())
301  return std::move(EC);
302  Publics = std::move(TempPublics);
303  }
304  return *Publics;
305 }
306 
308  if (!Symbols) {
309  auto DbiS = getPDBDbiStream();
310  if (!DbiS)
311  return DbiS.takeError();
312 
313  uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
314  auto SymbolS =
315  safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum);
316  if (!SymbolS) return SymbolS.takeError();
317 
318  auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
319  if (auto EC = TempSymbols->reload())
320  return std::move(EC);
321  Symbols = std::move(TempSymbols);
322  }
323  return *Symbols;
324 }
325 
327  if (!StringTable || !StringTableStream) {
328  auto IS = getPDBInfoStream();
329  if (!IS)
330  return IS.takeError();
331 
332  uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names");
333 
334  auto NS =
335  safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex);
336  if (!NS) return NS.takeError();
337 
338  StreamReader Reader(**NS);
339  auto N = llvm::make_unique<NameHashTable>();
340  if (auto EC = N->load(Reader))
341  return std::move(EC);
342  StringTable = std::move(N);
343  StringTableStream = std::move(*NS);
344  }
345  return *StringTable;
346 }
347 
349 
351  auto DbiS = getPDBDbiStream();
352  if (!DbiS) return false;
353  return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
354 }
355 
357 
359 
361  auto DbiS = getPDBDbiStream();
362  if (!DbiS) return false;
363  return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
364 }
365 
367  auto DbiS = getPDBDbiStream();
368  if (!DbiS) return false;
369  return DbiS->getSymRecordStreamIndex() < getNumStreams();
370 }
371 
373 
375  auto IS = getPDBInfoStream();
376  if (!IS) return false;
377  return IS->getNamedStreamIndex("/names") < getNumStreams();
378 }
379 
380 /// Wrapper around MappedBlockStream::createIndexedStream()
381 /// that checks if a stream with that index actually exists.
382 /// If it does not, the return value will have an MSFError with
383 /// code msf_error_code::no_stream. Else, the return value will
384 /// contain the stream returned by createIndexedStream().
385 Expected<std::unique_ptr<MappedBlockStream>> PDBFile::safelyCreateIndexedStream(
386  const MSFLayout &Layout, const ReadableStream &MsfData,
387  uint32_t StreamIndex) const {
388  if (StreamIndex >= getNumStreams())
389  return make_error<RawError>(raw_error_code::no_stream);
390  return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex);
391 }
void resize(unsigned N, bool t=false)
resize - Grow or shrink the bitvector.
Definition: BitVector.h:193
uint32_t getNumDirectoryBytes() const
Definition: PDBFile.cpp:57
bool hasPDBSymbolStream()
Definition: PDBFile.cpp:366
Error validateSuperBlock(const SuperBlock &SB)
Definition: MSFCommon.cpp:16
Error parseStreamData()
Definition: PDBFile.cpp:168
uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize)
Definition: MSFCommon.h:83
ArrayRef< support::ulittle32_t > getDirectoryBlockArray() const
Definition: PDBFile.cpp:220
Expected< GlobalsStream & > getPDBGlobalsStream()
Definition: PDBFile.cpp:224
void setOffset(uint32_t Off)
Definition: StreamReader.h:105
bool hasPDBPublicsStream()
Definition: PDBFile.cpp:360
uint32_t getBlockMapIndex() const
Definition: PDBFile.cpp:61
Expected< TpiStream & > getPDBTpiStream()
Definition: PDBFile.cpp:265
bool hasPDBInfoStream()
Definition: PDBFile.cpp:356
Error parseFileHeaders()
Definition: PDBFile.cpp:108
uint32_t getFileSize() const
Definition: PDBFile.cpp:90
uint32_t getNumStreams() const override
Definition: PDBFile.cpp:77
Error setBlockData(uint32_t BlockIndex, uint32_t Offset, ArrayRef< uint8_t > Data) const override
Definition: PDBFile.cpp:102
uint64_t getBlockMapOffset() const
Definition: PDBFile.cpp:72
uint32_t getStreamByteSize(uint32_t StreamIndex) const override
Definition: PDBFile.cpp:81
uint32_t getBlockSize() const override
Definition: PDBFile.cpp:47
Tagged union holding either a T or a Error.
bool hasPDBDbiStream() const
Definition: PDBFile.cpp:348
support::ulittle32_t BlockSize
Definition: MSFCommon.h:37
bool hasPDBIpiStream() const
Definition: PDBFile.cpp:358
Expected< NameHashTable & > getStringTable()
Definition: PDBFile.cpp:326
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:141
Maximum length of the test input libFuzzer tries to guess a good value based on the corpus and reports it always prefer smaller inputs during the corpus shuffle When libFuzzer itself reports a bug this exit code will be used If indicates the maximal total time in seconds to run the fuzzer minimizes the provided crash input Use with etc Experimental Use value profile to guide fuzzing Number of simultaneous worker processes to run the jobs If min(jobs, NumberOfCpuCores()/2)\" is used.") FUZZER_FLAG_INT(reload
support::ulittle32_t BlockMapAddr
Definition: MSFCommon.h:49
INITIALIZE_PASS(HexagonEarlyIfConversion,"hexagon-eif","Hexagon early if conversion", false, false) bool HexagonEarlyIfConversion MachineBasicBlock * SB
bool hasStringTable()
Definition: PDBFile.cpp:374
~PDBFile() override
Error readBytes(ArrayRef< uint8_t > &Buffer, uint32_t Size)
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:138
Expected< SymbolStream & > getPDBSymbolStream()
Definition: PDBFile.cpp:307
Error readInteger(uint8_t &Dest)
Error readArray(ArrayRef< T > &Array, uint32_t NumElements)
Definition: StreamReader.h:62
Expected< TpiStream & > getPDBIpiStream()
Definition: PDBFile.cpp:277
Greedy Register Allocator
uint32_t Offset
void consumeError(Error Err)
Consume a Error without doing anything.
Expected< DbiStream & > getPDBDbiStream()
Definition: PDBFile.cpp:253
support::ulittle32_t Unknown1
Definition: MSFCommon.h:47
uint32_t getNumDirectoryBlocks() const
Definition: PDBFile.cpp:67
static ErrorSuccess success()
Create a success value.
ArrayRef< support::ulittle32_t > DirectoryBlocks
Definition: MSFCommon.h:56
uint32_t getUnknown1() const
Definition: PDBFile.cpp:65
uint32_t getFreeBlockMapBlock() const
Definition: PDBFile.cpp:49
Expected< PublicsStream & > getPDBPublicsStream()
Definition: PDBFile.cpp:289
BitVector FreePageMap
Definition: MSFCommon.h:55
bool hasPDBTpiStream() const
Definition: PDBFile.cpp:372
uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize)
Definition: MSFCommon.h:79
#define I(x, y, z)
Definition: MD5.cpp:54
#define N
std::vector< ArrayRef< support::ulittle32_t > > StreamMap
Definition: MSFCommon.h:58
bool hasPDBGlobalsStream()
Definition: PDBFile.cpp:350
Expected< ArrayRef< uint8_t > > getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const override
Definition: PDBFile.cpp:92
uint32_t getFullFpmByteSize(const MSFLayout &L)
Definition: MSFCommon.h:96
uint32_t bytesRemaining() const
Definition: StreamReader.h:108
ArrayRef< support::ulittle32_t > StreamSizes
Definition: MSFCommon.h:57
Expected< InfoStream & > getPDBInfoStream()
Definition: PDBFile.cpp:241
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
support::ulittle32_t FreeBlockMapBlock
Definition: MSFCommon.h:39
Lightweight error class with error context and mandatory checking.
ArrayRef< support::ulittle32_t > getStreamBlockList(uint32_t StreamIndex) const override
Definition: PDBFile.cpp:86
const SuperBlock * SB
Definition: MSFCommon.h:54
uint32_t getBlockCount() const override
Definition: PDBFile.cpp:53
support::ulittle32_t NumDirectoryBytes
Definition: MSFCommon.h:45
support::ulittle32_t NumBlocks
Definition: MSFCommon.h:43
Error readObject(const T *&Dest)
Definition: StreamReader.h:53