LCOV - code coverage report
Current view: top level - lib/DebugInfo/PDB/Native - PDBFile.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 191 245 78.0 %
Date: 2017-09-14 15:23:50 Functions: 37 42 88.1 %
Legend: Lines: hit not hit

          Line data    Source code
       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/DebugInfo/PDB/Native/PDBFile.h"
      11             : #include "llvm/ADT/ArrayRef.h"
      12             : #include "llvm/ADT/STLExtras.h"
      13             : #include "llvm/DebugInfo/MSF/MSFCommon.h"
      14             : #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
      15             : #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
      16             : #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
      17             : #include "llvm/DebugInfo/PDB/Native/InfoStream.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          98 : PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer,
      43          98 :                  BumpPtrAllocator &Allocator)
      44        1372 :     : FilePath(Path), Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {}
      45             : 
      46             : PDBFile::~PDBFile() = default;
      47             : 
      48          28 : StringRef PDBFile::getFilePath() const { return FilePath; }
      49             : 
      50           0 : StringRef PDBFile::getFileDirectory() const {
      51           0 :   return sys::path::parent_path(FilePath);
      52             : }
      53             : 
      54         174 : uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
      55             : 
      56          11 : uint32_t PDBFile::getFreeBlockMapBlock() const {
      57          22 :   return ContainerLayout.SB->FreeBlockMapBlock;
      58             : }
      59             : 
      60         117 : uint32_t PDBFile::getBlockCount() const {
      61         234 :   return ContainerLayout.SB->NumBlocks;
      62             : }
      63             : 
      64          13 : uint32_t PDBFile::getNumDirectoryBytes() const {
      65          26 :   return ContainerLayout.SB->NumDirectoryBytes;
      66             : }
      67             : 
      68          11 : uint32_t PDBFile::getBlockMapIndex() const {
      69          22 :   return ContainerLayout.SB->BlockMapAddr;
      70             : }
      71             : 
      72          26 : uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
      73             : 
      74         108 : uint32_t PDBFile::getNumDirectoryBlocks() const {
      75         324 :   return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
      76         540 :                             ContainerLayout.SB->BlockSize);
      77             : }
      78             : 
      79          97 : uint64_t PDBFile::getBlockMapOffset() const {
      80         194 :   return (uint64_t)ContainerLayout.SB->BlockMapAddr *
      81         194 :          ContainerLayout.SB->BlockSize;
      82             : }
      83             : 
      84         731 : uint32_t PDBFile::getNumStreams() const {
      85         731 :   return ContainerLayout.StreamSizes.size();
      86             : }
      87             : 
      88           1 : uint32_t PDBFile::getMaxStreamSize() const {
      89             :   return *std::max_element(ContainerLayout.StreamSizes.begin(),
      90           4 :                            ContainerLayout.StreamSizes.end());
      91             : }
      92             : 
      93        1739 : uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
      94        5217 :   return ContainerLayout.StreamSizes[StreamIndex];
      95             : }
      96             : 
      97             : ArrayRef<support::ulittle32_t>
      98          42 : PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
      99          84 :   return ContainerLayout.StreamMap[StreamIndex];
     100             : }
     101             : 
     102        3342 : uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
     103             : 
     104           7 : Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
     105             :                                                   uint32_t NumBytes) const {
     106          14 :   uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
     107             : 
     108           7 :   ArrayRef<uint8_t> Result;
     109          28 :   if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
     110           0 :     return std::move(EC);
     111             :   return Result;
     112             : }
     113             : 
     114           0 : Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
     115             :                             ArrayRef<uint8_t> Data) const {
     116             :   return make_error<RawError>(raw_error_code::not_writable,
     117           0 :                               "PDBFile is immutable");
     118             : }
     119             : 
     120          98 : Error PDBFile::parseFileHeaders() {
     121         294 :   BinaryStreamReader Reader(*Buffer);
     122             : 
     123             :   // Initialize SB.
     124          98 :   const msf::SuperBlock *SB = nullptr;
     125         293 :   if (auto EC = Reader.readObject(SB)) {
     126           3 :     consumeError(std::move(EC));
     127             :     return make_error<RawError>(raw_error_code::corrupt_file,
     128           2 :                                 "Does not contain superblock");
     129             :   }
     130             : 
     131         291 :   if (auto EC = msf::validateSuperBlock(*SB))
     132           0 :     return EC;
     133             : 
     134         291 :   if (Buffer->getLength() % SB->BlockSize != 0)
     135             :     return make_error<RawError>(raw_error_code::corrupt_file,
     136           0 :                                 "File size is not a multiple of block size");
     137          97 :   ContainerLayout.SB = SB;
     138             : 
     139             :   // Initialize Free Page Map.
     140         194 :   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         291 :       MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
     156         194 :   BinaryStreamReader FpmReader(*FpmStream);
     157          97 :   ArrayRef<uint8_t> FpmBytes;
     158         291 :   if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
     159           0 :     return EC;
     160          97 :   uint32_t BlocksRemaining = getBlockCount();
     161          97 :   uint32_t BI = 0;
     162         559 :   for (auto Byte : FpmBytes) {
     163         730 :     uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
     164        2726 :     for (uint32_t I = 0; I < BlocksThisByte; ++I) {
     165        2361 :       if (Byte & (1 << I))
     166         954 :         ContainerLayout.FreePageMap[BI] = true;
     167        2361 :       --BlocksRemaining;
     168        2361 :       ++BI;
     169             :     }
     170             :   }
     171             : 
     172         194 :   Reader.setOffset(getBlockMapOffset());
     173          97 :   if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
     174         291 :                                  getNumDirectoryBlocks()))
     175           0 :     return EC;
     176             : 
     177         291 :   return Error::success();
     178             : }
     179             : 
     180          97 : Error PDBFile::parseStreamData() {
     181             :   assert(ContainerLayout.SB);
     182         194 :   if (DirectoryStream)
     183           0 :     return Error::success();
     184             : 
     185          97 :   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         194 :   auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer,
     193         291 :                                                      Allocator);
     194         194 :   BinaryStreamReader Reader(*DS);
     195         291 :   if (auto EC = Reader.readInteger(NumStreams))
     196           0 :     return EC;
     197             : 
     198         291 :   if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
     199           0 :     return EC;
     200        1782 :   for (uint32_t I = 0; I < NumStreams; ++I) {
     201        1685 :     uint32_t StreamSize = getStreamByteSize(I);
     202             :     // FIXME: What does StreamSize ~0U mean?
     203             :     uint64_t NumExpectedStreamBlocks =
     204             :         StreamSize == UINT32_MAX
     205        3370 :             ? 0
     206        5055 :             : 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.
     214        1685 :     ArrayRef<support::ulittle32_t> Blocks;
     215        5055 :     if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
     216           0 :       return EC;
     217        5025 :     for (uint32_t Block : Blocks) {
     218             :       uint64_t BlockEndOffset =
     219        3310 :           (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
     220        1655 :       if (BlockEndOffset > getFileSize())
     221             :         return make_error<RawError>(raw_error_code::corrupt_file,
     222           0 :                                     "Stream block map is corrupt.");
     223             :     }
     224        1685 :     ContainerLayout.StreamMap.push_back(Blocks);
     225             :   }
     226             : 
     227             :   // We should have read exactly SB->NumDirectoryBytes bytes.
     228             :   assert(Reader.bytesRemaining() == 0);
     229         194 :   DirectoryStream = std::move(DS);
     230         291 :   return Error::success();
     231             : }
     232             : 
     233          11 : ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
     234          11 :   return ContainerLayout.DirectoryBlocks;
     235             : }
     236             : 
     237         286 : std::unique_ptr<MappedBlockStream> PDBFile::createIndexedStream(uint16_t SN) {
     238         286 :   if (SN == kInvalidStreamIndex)
     239             :     return nullptr;
     240         572 :   return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
     241         858 :                                                 Allocator);
     242             : }
     243             : 
     244          25 : MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
     245          25 :   MSFStreamLayout Result;
     246          25 :   auto Blocks = getStreamBlockList(StreamIdx);
     247          75 :   Result.Blocks.assign(Blocks.begin(), Blocks.end());
     248          25 :   Result.Length = getStreamByteSize(StreamIdx);
     249          25 :   return Result;
     250             : }
     251             : 
     252           2 : msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const {
     253           2 :   return msf::getFpmStreamLayout(ContainerLayout);
     254             : }
     255             : 
     256          11 : Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
     257          22 :   if (!Globals) {
     258          20 :     auto DbiS = getPDBDbiStream();
     259          10 :     if (!DbiS)
     260           0 :       return DbiS.takeError();
     261             : 
     262             :     auto GlobalS = safelyCreateIndexedStream(
     263          40 :         ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex());
     264          10 :     if (!GlobalS)
     265           0 :       return GlobalS.takeError();
     266          20 :     auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS));
     267          30 :     if (auto EC = TempGlobals->reload())
     268           0 :       return std::move(EC);
     269          10 :     Globals = std::move(TempGlobals);
     270             :   }
     271          22 :   return *Globals;
     272             : }
     273             : 
     274         150 : Expected<InfoStream &> PDBFile::getPDBInfoStream() {
     275         300 :   if (!Info) {
     276         272 :     auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB);
     277          68 :     if (!InfoS)
     278           0 :       return InfoS.takeError();
     279         136 :     auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
     280         204 :     if (auto EC = TempInfo->reload())
     281           0 :       return std::move(EC);
     282          68 :     Info = std::move(TempInfo);
     283             :   }
     284         300 :   return *Info;
     285             : }
     286             : 
     287         987 : Expected<DbiStream &> PDBFile::getPDBDbiStream() {
     288        1974 :   if (!Dbi) {
     289         260 :     auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI);
     290          65 :     if (!DbiS)
     291           0 :       return DbiS.takeError();
     292         130 :     auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
     293         195 :     if (auto EC = TempDbi->reload())
     294           0 :       return std::move(EC);
     295          65 :     Dbi = std::move(TempDbi);
     296             :   }
     297        1974 :   return *Dbi;
     298             : }
     299             : 
     300          73 : Expected<TpiStream &> PDBFile::getPDBTpiStream() {
     301         146 :   if (!Tpi) {
     302         204 :     auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI);
     303          51 :     if (!TpiS)
     304           0 :       return TpiS.takeError();
     305         102 :     auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
     306         153 :     if (auto EC = TempTpi->reload())
     307           0 :       return std::move(EC);
     308          51 :     Tpi = std::move(TempTpi);
     309             :   }
     310         146 :   return *Tpi;
     311             : }
     312             : 
     313          39 : Expected<TpiStream &> PDBFile::getPDBIpiStream() {
     314          78 :   if (!Ipi) {
     315          31 :     if (!hasPDBIpiStream())
     316           0 :       return make_error<RawError>(raw_error_code::no_stream);
     317             : 
     318         124 :     auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI);
     319          31 :     if (!IpiS)
     320           0 :       return IpiS.takeError();
     321          62 :     auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
     322          93 :     if (auto EC = TempIpi->reload())
     323           0 :       return std::move(EC);
     324          31 :     Ipi = std::move(TempIpi);
     325             :   }
     326          78 :   return *Ipi;
     327             : }
     328             : 
     329           3 : Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
     330           6 :   if (!Publics) {
     331           6 :     auto DbiS = getPDBDbiStream();
     332           3 :     if (!DbiS)
     333           0 :       return DbiS.takeError();
     334             : 
     335             :     auto PublicS = safelyCreateIndexedStream(
     336          12 :         ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex());
     337           3 :     if (!PublicS)
     338           0 :       return PublicS.takeError();
     339           6 :     auto TempPublics = llvm::make_unique<PublicsStream>(std::move(*PublicS));
     340           9 :     if (auto EC = TempPublics->reload())
     341           0 :       return std::move(EC);
     342           3 :     Publics = std::move(TempPublics);
     343             :   }
     344           6 :   return *Publics;
     345             : }
     346             : 
     347          14 : Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
     348          28 :   if (!Symbols) {
     349          24 :     auto DbiS = getPDBDbiStream();
     350          12 :     if (!DbiS)
     351           0 :       return DbiS.takeError();
     352             : 
     353          12 :     uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
     354             :     auto SymbolS =
     355          48 :         safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum);
     356          12 :     if (!SymbolS)
     357           0 :       return SymbolS.takeError();
     358             : 
     359          24 :     auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
     360          36 :     if (auto EC = TempSymbols->reload())
     361           0 :       return std::move(EC);
     362          12 :     Symbols = std::move(TempSymbols);
     363             :   }
     364          28 :   return *Symbols;
     365             : }
     366             : 
     367          66 : Expected<PDBStringTable &> PDBFile::getStringTable() {
     368         132 :   if (!Strings) {
     369          74 :     auto IS = getPDBInfoStream();
     370          37 :     if (!IS)
     371           0 :       return IS.takeError();
     372             : 
     373          74 :     uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names");
     374             : 
     375             :     auto NS =
     376         148 :         safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex);
     377          37 :     if (!NS)
     378           0 :       return NS.takeError();
     379             : 
     380          74 :     auto N = llvm::make_unique<PDBStringTable>();
     381         111 :     BinaryStreamReader Reader(**NS);
     382         111 :     if (auto EC = N->reload(Reader))
     383           0 :       return std::move(EC);
     384             :     assert(Reader.bytesRemaining() == 0);
     385          74 :     StringTableStream = std::move(*NS);
     386          37 :     Strings = std::move(N);
     387             :   }
     388         132 :   return *Strings;
     389             : }
     390             : 
     391           0 : uint32_t PDBFile::getPointerSize() {
     392           0 :   auto DbiS = getPDBDbiStream();
     393           0 :   if (!DbiS)
     394             :     return 0;
     395           0 :   PDB_Machine Machine = DbiS->getMachineType();
     396           0 :   if (Machine == PDB_Machine::Amd64)
     397             :     return 8;
     398           0 :   return 4;
     399             : }
     400             : 
     401          46 : bool PDBFile::hasPDBDbiStream() const { return StreamDBI < getNumStreams(); }
     402             : 
     403          15 : bool PDBFile::hasPDBGlobalsStream() {
     404          30 :   auto DbiS = getPDBDbiStream();
     405          15 :   if (!DbiS) {
     406           0 :     consumeError(DbiS.takeError());
     407           0 :     return false;
     408             :   }
     409             : 
     410          15 :   return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
     411             : }
     412             : 
     413          74 : bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); }
     414             : 
     415          74 : bool PDBFile::hasPDBIpiStream() const {
     416          74 :   if (!hasPDBInfoStream())
     417             :     return false;
     418             : 
     419          74 :   if (StreamIPI >= getNumStreams())
     420             :     return false;
     421             : 
     422         222 :   auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
     423          74 :   return InfoStream.containsIdStream();
     424             : }
     425             : 
     426           7 : bool PDBFile::hasPDBPublicsStream() {
     427          14 :   auto DbiS = getPDBDbiStream();
     428           7 :   if (!DbiS) {
     429           0 :     consumeError(DbiS.takeError());
     430           0 :     return false;
     431             :   }
     432           7 :   return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
     433             : }
     434             : 
     435           0 : bool PDBFile::hasPDBSymbolStream() {
     436           0 :   auto DbiS = getPDBDbiStream();
     437           0 :   if (!DbiS)
     438             :     return false;
     439           0 :   return DbiS->getSymRecordStreamIndex() < getNumStreams();
     440             : }
     441             : 
     442          20 : bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
     443             : 
     444           0 : bool PDBFile::hasPDBStringTable() {
     445           0 :   auto IS = getPDBInfoStream();
     446           0 :   if (!IS)
     447             :     return false;
     448           0 :   return IS->getNamedStreamIndex("/names") < getNumStreams();
     449             : }
     450             : 
     451             : /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
     452             : /// stream with that index actually exists.  If it does not, the return value
     453             : /// will have an MSFError with code msf_error_code::no_stream.  Else, the return
     454             : /// value will contain the stream returned by createIndexedStream().
     455             : Expected<std::unique_ptr<MappedBlockStream>>
     456         277 : PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout,
     457             :                                    BinaryStreamRef MsfData,
     458             :                                    uint32_t StreamIndex) const {
     459         277 :   if (StreamIndex >= getNumStreams())
     460           0 :     return make_error<RawError>(raw_error_code::no_stream);
     461        1108 :   return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex,
     462         277 :                                                 Allocator);
     463             : }

Generated by: LCOV version 1.13