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