LLVM  10.0.0svn
PDBFile.cpp
Go to the documentation of this file.
1 //===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
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 #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 "llvm/Support/Path.h"
29 #include <algorithm>
30 #include <cassert>
31 #include <cstdint>
32 
33 using namespace llvm;
34 using namespace llvm::codeview;
35 using namespace llvm::msf;
36 using namespace llvm::pdb;
37 
38 namespace {
39 typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
40 } // end anonymous namespace
41 
42 PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer,
44  : FilePath(Path), Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {}
45 
46 PDBFile::~PDBFile() = default;
47 
48 StringRef PDBFile::getFilePath() const { return FilePath; }
49 
51  return sys::path::parent_path(FilePath);
52 }
53 
54 uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
55 
57  return ContainerLayout.SB->FreeBlockMapBlock;
58 }
59 
61  return ContainerLayout.SB->NumBlocks;
62 }
63 
65  return ContainerLayout.SB->NumDirectoryBytes;
66 }
67 
69  return ContainerLayout.SB->BlockMapAddr;
70 }
71 
72 uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
73 
75  return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
76  ContainerLayout.SB->BlockSize);
77 }
78 
79 uint64_t PDBFile::getBlockMapOffset() const {
80  return (uint64_t)ContainerLayout.SB->BlockMapAddr *
81  ContainerLayout.SB->BlockSize;
82 }
83 
85  return ContainerLayout.StreamSizes.size();
86 }
87 
89  return *std::max_element(ContainerLayout.StreamSizes.begin(),
90  ContainerLayout.StreamSizes.end());
91 }
92 
94  return ContainerLayout.StreamSizes[StreamIndex];
95 }
96 
99  return ContainerLayout.StreamMap[StreamIndex];
100 }
101 
102 uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
103 
105  uint32_t NumBytes) const {
106  uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
107 
108  ArrayRef<uint8_t> Result;
109  if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
110  return std::move(EC);
111  return Result;
112 }
113 
115  ArrayRef<uint8_t> Data) const {
116  return make_error<RawError>(raw_error_code::not_writable,
117  "PDBFile is immutable");
118 }
119 
121  BinaryStreamReader Reader(*Buffer);
122 
123  // Initialize SB.
124  const msf::SuperBlock *SB = nullptr;
125  if (auto EC = Reader.readObject(SB)) {
126  consumeError(std::move(EC));
127  return make_error<RawError>(raw_error_code::corrupt_file,
128  "MSF superblock is missing");
129  }
130 
131  if (auto EC = msf::validateSuperBlock(*SB))
132  return EC;
133 
134  if (Buffer->getLength() % SB->BlockSize != 0)
135  return make_error<RawError>(raw_error_code::corrupt_file,
136  "File size is not a multiple of block size");
137  ContainerLayout.SB = SB;
138 
139  // Initialize Free Page Map.
140  ContainerLayout.FreePageMap.resize(SB->NumBlocks);
141  // The Fpm exists either at block 1 or block 2 of the MSF. However, this
142  // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
143  // thusly an equal number of total blocks in the file. For a block size
144  // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
145  // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so
146  // the Fpm is split across the file at `getBlockSize()` intervals. As a
147  // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
148  // for any non-negative integer k is an Fpm block. In theory, we only really
149  // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
150  // current versions of the MSF format already expect the Fpm to be arranged
151  // at getBlockSize() intervals, so we have to be compatible.
152  // See the function fpmPn() for more information:
153  // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
154  auto FpmStream =
155  MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
156  BinaryStreamReader FpmReader(*FpmStream);
157  ArrayRef<uint8_t> FpmBytes;
158  if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
159  return EC;
160  uint32_t BlocksRemaining = getBlockCount();
161  uint32_t BI = 0;
162  for (auto Byte : FpmBytes) {
163  uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
164  for (uint32_t I = 0; I < BlocksThisByte; ++I) {
165  if (Byte & (1 << I))
166  ContainerLayout.FreePageMap[BI] = true;
167  --BlocksRemaining;
168  ++BI;
169  }
170  }
171 
172  Reader.setOffset(getBlockMapOffset());
173  if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
175  return EC;
176 
177  return Error::success();
178 }
179 
181  assert(ContainerLayout.SB);
182  if (DirectoryStream)
183  return Error::success();
184 
185  uint32_t NumStreams = 0;
186 
187  // Normally you can't use a MappedBlockStream without having fully parsed the
188  // PDB file, because it accesses the directory and various other things, which
189  // is exactly what we are attempting to parse. By specifying a custom
190  // subclass of IPDBStreamData which only accesses the fields that have already
191  // been parsed, we can avoid this and reuse MappedBlockStream.
192  auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer,
193  Allocator);
194  BinaryStreamReader Reader(*DS);
195  if (auto EC = Reader.readInteger(NumStreams))
196  return EC;
197 
198  if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
199  return EC;
200  for (uint32_t I = 0; I < NumStreams; ++I) {
201  uint32_t StreamSize = getStreamByteSize(I);
202  // FIXME: What does StreamSize ~0U mean?
203  uint64_t NumExpectedStreamBlocks =
204  StreamSize == UINT32_MAX
205  ? 0
206  : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
207 
208  // For convenience, we store the block array contiguously. This is because
209  // if someone calls setStreamMap(), it is more convenient to be able to call
210  // it with an ArrayRef instead of setting up a StreamRef. Since the
211  // DirectoryStream is cached in the class and thus lives for the life of the
212  // class, we can be guaranteed that readArray() will return a stable
213  // reference, even if it has to allocate from its internal pool.
215  if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
216  return EC;
217  for (uint32_t Block : Blocks) {
218  uint64_t BlockEndOffset =
219  (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
220  if (BlockEndOffset > getFileSize())
221  return make_error<RawError>(raw_error_code::corrupt_file,
222  "Stream block map is corrupt.");
223  }
224  ContainerLayout.StreamMap.push_back(Blocks);
225  }
226 
227  // We should have read exactly SB->NumDirectoryBytes bytes.
228  assert(Reader.bytesRemaining() == 0);
229  DirectoryStream = std::move(DS);
230  return Error::success();
231 }
232 
234  return ContainerLayout.DirectoryBlocks;
235 }
236 
237 std::unique_ptr<MappedBlockStream>
238 PDBFile::createIndexedStream(uint16_t SN) const {
239  if (SN == kInvalidStreamIndex)
240  return nullptr;
241  return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
242  Allocator);
243 }
244 
246  MSFStreamLayout Result;
247  auto Blocks = getStreamBlockList(StreamIdx);
248  Result.Blocks.assign(Blocks.begin(), Blocks.end());
249  Result.Length = getStreamByteSize(StreamIdx);
250  return Result;
251 }
252 
254  return msf::getFpmStreamLayout(ContainerLayout);
255 }
256 
258  if (!Globals) {
259  auto DbiS = getPDBDbiStream();
260  if (!DbiS)
261  return DbiS.takeError();
262 
263  auto GlobalS =
264  safelyCreateIndexedStream(DbiS->getGlobalSymbolStreamIndex());
265  if (!GlobalS)
266  return GlobalS.takeError();
267  auto TempGlobals = std::make_unique<GlobalsStream>(std::move(*GlobalS));
268  if (auto EC = TempGlobals->reload())
269  return std::move(EC);
270  Globals = std::move(TempGlobals);
271  }
272  return *Globals;
273 }
274 
276  if (!Info) {
277  auto InfoS = safelyCreateIndexedStream(StreamPDB);
278  if (!InfoS)
279  return InfoS.takeError();
280  auto TempInfo = std::make_unique<InfoStream>(std::move(*InfoS));
281  if (auto EC = TempInfo->reload())
282  return std::move(EC);
283  Info = std::move(TempInfo);
284  }
285  return *Info;
286 }
287 
289  if (!Dbi) {
291  if (!DbiS)
292  return DbiS.takeError();
293  auto TempDbi = std::make_unique<DbiStream>(std::move(*DbiS));
294  if (auto EC = TempDbi->reload(this))
295  return std::move(EC);
296  Dbi = std::move(TempDbi);
297  }
298  return *Dbi;
299 }
300 
302  if (!Tpi) {
304  if (!TpiS)
305  return TpiS.takeError();
306  auto TempTpi = std::make_unique<TpiStream>(*this, std::move(*TpiS));
307  if (auto EC = TempTpi->reload())
308  return std::move(EC);
309  Tpi = std::move(TempTpi);
310  }
311  return *Tpi;
312 }
313 
315  if (!Ipi) {
316  if (!hasPDBIpiStream())
317  return make_error<RawError>(raw_error_code::no_stream);
318 
320  if (!IpiS)
321  return IpiS.takeError();
322  auto TempIpi = std::make_unique<TpiStream>(*this, std::move(*IpiS));
323  if (auto EC = TempIpi->reload())
324  return std::move(EC);
325  Ipi = std::move(TempIpi);
326  }
327  return *Ipi;
328 }
329 
331  if (!Publics) {
332  auto DbiS = getPDBDbiStream();
333  if (!DbiS)
334  return DbiS.takeError();
335 
336  auto PublicS =
337  safelyCreateIndexedStream(DbiS->getPublicSymbolStreamIndex());
338  if (!PublicS)
339  return PublicS.takeError();
340  auto TempPublics = std::make_unique<PublicsStream>(std::move(*PublicS));
341  if (auto EC = TempPublics->reload())
342  return std::move(EC);
343  Publics = std::move(TempPublics);
344  }
345  return *Publics;
346 }
347 
349  if (!Symbols) {
350  auto DbiS = getPDBDbiStream();
351  if (!DbiS)
352  return DbiS.takeError();
353 
354  uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
355  auto SymbolS = safelyCreateIndexedStream(SymbolStreamNum);
356  if (!SymbolS)
357  return SymbolS.takeError();
358 
359  auto TempSymbols = std::make_unique<SymbolStream>(std::move(*SymbolS));
360  if (auto EC = TempSymbols->reload())
361  return std::move(EC);
362  Symbols = std::move(TempSymbols);
363  }
364  return *Symbols;
365 }
366 
368  if (!Strings) {
369  auto NS = safelyCreateNamedStream("/names");
370  if (!NS)
371  return NS.takeError();
372 
373  auto N = std::make_unique<PDBStringTable>();
374  BinaryStreamReader Reader(**NS);
375  if (auto EC = N->reload(Reader))
376  return std::move(EC);
377  assert(Reader.bytesRemaining() == 0);
378  StringTableStream = std::move(*NS);
379  Strings = std::move(N);
380  }
381  return *Strings;
382 }
383 
385  if (!InjectedSources) {
386  auto IJS = safelyCreateNamedStream("/src/headerblock");
387  if (!IJS)
388  return IJS.takeError();
389 
390  auto Strings = getStringTable();
391  if (!Strings)
392  return Strings.takeError();
393 
394  auto IJ = std::make_unique<InjectedSourceStream>(std::move(*IJS));
395  if (auto EC = IJ->reload(*Strings))
396  return std::move(EC);
397  InjectedSources = std::move(IJ);
398  }
399  return *InjectedSources;
400 }
401 
403  auto DbiS = getPDBDbiStream();
404  if (!DbiS)
405  return 0;
406  PDB_Machine Machine = DbiS->getMachineType();
407  if (Machine == PDB_Machine::Amd64)
408  return 8;
409  return 4;
410 }
411 
413  return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0;
414 }
415 
417  auto DbiS = getPDBDbiStream();
418  if (!DbiS) {
419  consumeError(DbiS.takeError());
420  return false;
421  }
422 
423  return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
424 }
425 
427 
429  if (!hasPDBInfoStream())
430  return false;
431 
432  if (StreamIPI >= getNumStreams())
433  return false;
434 
435  auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
436  return InfoStream.containsIdStream();
437 }
438 
440  auto DbiS = getPDBDbiStream();
441  if (!DbiS) {
442  consumeError(DbiS.takeError());
443  return false;
444  }
445  return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
446 }
447 
449  auto DbiS = getPDBDbiStream();
450  if (!DbiS)
451  return false;
452  return DbiS->getSymRecordStreamIndex() < getNumStreams();
453 }
454 
456 
458  auto IS = getPDBInfoStream();
459  if (!IS)
460  return false;
461  Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
462  if (!ExpectedNSI) {
463  consumeError(ExpectedNSI.takeError());
464  return false;
465  }
466  assert(*ExpectedNSI < getNumStreams());
467  return true;
468 }
469 
471  auto IS = getPDBInfoStream();
472  if (!IS)
473  return false;
474  Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/src/headerblock");
475  if (!ExpectedNSI) {
476  consumeError(ExpectedNSI.takeError());
477  return false;
478  }
479  assert(*ExpectedNSI < getNumStreams());
480  return true;
481 }
482 
483 /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
484 /// stream with that index actually exists. If it does not, the return value
485 /// will have an MSFError with code msf_error_code::no_stream. Else, the return
486 /// value will contain the stream returned by createIndexedStream().
489  if (StreamIndex >= getNumStreams())
490  // This rejects kInvalidStreamIndex with an error as well.
491  return make_error<RawError>(raw_error_code::no_stream);
492  return createIndexedStream(StreamIndex);
493 }
494 
497  auto IS = getPDBInfoStream();
498  if (!IS)
499  return IS.takeError();
500 
501  Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex(Name);
502  if (!ExpectedNSI)
503  return ExpectedNSI.takeError();
504  uint32_t NameStreamIndex = *ExpectedNSI;
505 
506  return safelyCreateIndexedStream(NameStreamIndex);
507 }
void resize(unsigned N, bool t=false)
resize - Grow or shrink the bitvector.
Definition: BitVector.h:371
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition: Error.h:703
Expected< PDBStringTable & > getStringTable()
Definition: PDBFile.cpp:367
Expected< std::unique_ptr< msf::MappedBlockStream > > safelyCreateNamedStream(StringRef Name)
Definition: PDBFile.cpp:496
bool hasPDBSymbolStream()
Definition: PDBFile.cpp:448
std::unique_ptr< msf::MappedBlockStream > createIndexedStream(uint16_t SN) const
Definition: PDBFile.cpp:238
bool hasPDBStringTable()
Definition: PDBFile.cpp:457
ArrayRef< support::ulittle32_t > getDirectoryBlockArray() const
Definition: PDBFile.cpp:233
This class represents lattice values for constants.
Definition: AllocatorList.h:23
Error validateSuperBlock(const SuperBlock &SB)
Definition: MSFCommon.cpp:19
Error readInteger(T &Dest)
Read an integer of the specified endianness into Dest and update the stream&#39;s offset.
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
uint32_t getNumDirectoryBlocks() const
Definition: PDBFile.cpp:74
Error parseStreamData()
Definition: PDBFile.cpp:180
uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize)
Definition: MSFCommon.h:112
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...
Expected< GlobalsStream & > getPDBGlobalsStream()
Definition: PDBFile.cpp:257
Expected< InjectedSourceStream & > getInjectedSourceStream()
Definition: PDBFile.cpp:384
Error takeError()
Take ownership of the stored error.
Definition: Error.h:552
bool hasPDBPublicsStream()
Definition: PDBFile.cpp:439
Expected< TpiStream & > getPDBTpiStream()
Definition: PDBFile.cpp:301
Error parseFileHeaders()
Definition: PDBFile.cpp:120
uint32_t getNumStreams() const override
Definition: PDBFile.cpp:84
Error setBlockData(uint32_t BlockIndex, uint32_t Offset, ArrayRef< uint8_t > Data) const override
Definition: PDBFile.cpp:114
Definition: BitVector.h:937
uint64_t getBlockMapOffset() const
Definition: PDBFile.cpp:79
Describes the layout of a stream in an MSF layout.
Definition: MSFCommon.h:77
MSFStreamLayout getFpmStreamLayout(const MSFLayout &Msf, bool IncludeUnusedFpmData=false, bool AltFpm=false)
Determine the layout of the FPM stream, given the MSF layout.
Definition: MSFCommon.cpp:62
bool hasPDBTpiStream() const
Definition: PDBFile.cpp:455
uint32_t getStreamByteSize(uint32_t StreamIndex) const override
Definition: PDBFile.cpp:93
msf::MSFStreamLayout getFpmStreamLayout() const
Definition: PDBFile.cpp:253
uint32_t getBlockSize() const override
Definition: PDBFile.cpp:54
Tagged union holding either a T or a Error.
Definition: yaml2obj.h:21
uint32_t getUnknown1() const
Definition: PDBFile.cpp:72
uint32_t getPointerSize()
Definition: PDBFile.cpp:402
std::vector< support::ulittle32_t > Blocks
Definition: MSFCommon.h:80
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: APInt.h:32
support::ulittle32_t BlockSize
Definition: MSFCommon.h:36
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
COFF::MachineTypes Machine
Definition: COFFYAML.cpp:365
bool hasPDBDbiStream() const
Definition: PDBFile.cpp:412
uint32_t getMaxStreamSize() const
Definition: PDBFile.cpp:88
const uint16_t kInvalidStreamIndex
Definition: RawConstants.h:19
support::ulittle32_t BlockMapAddr
Definition: MSFCommon.h:48
~PDBFile() override
uint32_t getNumDirectoryBytes() const
Definition: PDBFile.cpp:64
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:141
Expected< SymbolStream & > getPDBSymbolStream()
Definition: PDBFile.cpp:348
Expected< TpiStream & > getPDBIpiStream()
Definition: PDBFile.cpp:314
StringRef getFileDirectory() const
Definition: PDBFile.cpp:50
uint32_t getBlockMapIndex() const
Definition: PDBFile.cpp:68
StringRef parent_path(StringRef path, Style style=Style::native)
Get parent path.
Definition: Path.cpp:466
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1001
Expected< DbiStream & > getPDBDbiStream()
Definition: PDBFile.cpp:288
support::ulittle32_t Unknown1
Definition: MSFCommon.h:46
Basic Register Allocator
uint32_t getFreeBlockMapBlock() const
Definition: PDBFile.cpp:56
void setOffset(uint32_t Off)
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
ArrayRef< support::ulittle32_t > DirectoryBlocks
Definition: MSFCommon.h:66
bool hasPDBIpiStream() const
Definition: PDBFile.cpp:428
uint32_t getFileSize() const
Definition: PDBFile.cpp:102
StringRef getFilePath() const
Definition: PDBFile.cpp:48
Expected< PublicsStream & > getPDBPublicsStream()
Definition: PDBFile.cpp:330
BitVector FreePageMap
Definition: MSFCommon.h:65
uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize)
Definition: MSFCommon.h:108
Error readBytes(ArrayRef< uint8_t > &Buffer, uint32_t Size)
Read Size bytes from the underlying stream at the current offset and and set Buffer to the resulting ...
#define I(x, y, z)
Definition: MD5.cpp:58
#define N
std::vector< ArrayRef< support::ulittle32_t > > StreamMap
Definition: MSFCommon.h:68
bool hasPDBGlobalsStream()
Definition: PDBFile.cpp:416
uint32_t bytesRemaining() const
Expected< ArrayRef< uint8_t > > getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const override
Definition: PDBFile.cpp:104
ArrayRef< support::ulittle32_t > StreamSizes
Definition: MSFCommon.h:67
Expected< InfoStream & > getPDBInfoStream()
Definition: PDBFile.cpp:275
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
support::ulittle32_t FreeBlockMapBlock
Definition: MSFCommon.h:38
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
bool hasPDBInjectedSourceStream()
Definition: PDBFile.cpp:470
bool containsIdStream() const
Definition: InfoStream.cpp:99
Provides read only access to a subclass of BinaryStream.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
ArrayRef< support::ulittle32_t > getStreamBlockList(uint32_t StreamIndex) const override
Definition: PDBFile.cpp:98
const SuperBlock * SB
Definition: MSFCommon.h:64
uint32_t getBlockCount() const override
Definition: PDBFile.cpp:60
support::ulittle32_t NumDirectoryBytes
Definition: MSFCommon.h:44
support::ulittle32_t NumBlocks
Definition: MSFCommon.h:42
bool hasPDBInfoStream() const
Definition: PDBFile.cpp:426
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 ...
msf::MSFStreamLayout getStreamLayout(uint32_t StreamIdx) const
Definition: PDBFile.cpp:245