LCOV - code coverage report
Current view: top level - lib/DebugInfo/PDB/Native - PDBFile.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 174 201 86.6 %
Date: 2018-06-17 00:07:59 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         104 : PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer,
      43         104 :                  BumpPtrAllocator &Allocator)
      44         312 :     : FilePath(Path), Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {}
      45             : 
      46             : PDBFile::~PDBFile() = default;
      47             : 
      48           8 : StringRef PDBFile::getFilePath() const { return FilePath; }
      49             : 
      50           0 : StringRef PDBFile::getFileDirectory() const {
      51           0 :   return sys::path::parent_path(FilePath);
      52             : }
      53             : 
      54         170 : 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         121 : uint32_t PDBFile::getBlockCount() const {
      61         242 :   return ContainerLayout.SB->NumBlocks;
      62             : }
      63             : 
      64          11 : uint32_t PDBFile::getNumDirectoryBytes() const {
      65          22 :   return ContainerLayout.SB->NumDirectoryBytes;
      66             : }
      67             : 
      68          11 : uint32_t PDBFile::getBlockMapIndex() const {
      69          11 :   return ContainerLayout.SB->BlockMapAddr;
      70             : }
      71             : 
      72          22 : uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
      73             : 
      74         114 : uint32_t PDBFile::getNumDirectoryBlocks() const {
      75         228 :   return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
      76         228 :                             ContainerLayout.SB->BlockSize);
      77             : }
      78             : 
      79         103 : uint64_t PDBFile::getBlockMapOffset() const {
      80         206 :   return (uint64_t)ContainerLayout.SB->BlockMapAddr *
      81         103 :          ContainerLayout.SB->BlockSize;
      82             : }
      83             : 
      84         786 : uint32_t PDBFile::getNumStreams() const {
      85         786 :   return ContainerLayout.StreamSizes.size();
      86             : }
      87             : 
      88           1 : uint32_t PDBFile::getMaxStreamSize() const {
      89             :   return *std::max_element(ContainerLayout.StreamSizes.begin(),
      90           1 :                            ContainerLayout.StreamSizes.end());
      91             : }
      92             : 
      93        1803 : uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
      94        3606 :   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        3488 : 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           7 :   uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
     107             : 
     108           7 :   ArrayRef<uint8_t> Result;
     109          14 :   if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
     110             :     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         104 : Error PDBFile::parseFileHeaders() {
     121         104 :   BinaryStreamReader Reader(*Buffer);
     122             : 
     123             :   // Initialize SB.
     124         104 :   const msf::SuperBlock *SB = nullptr;
     125         208 :   if (auto EC = Reader.readObject(SB)) {
     126           2 :     consumeError(std::move(EC));
     127             :     return make_error<RawError>(raw_error_code::corrupt_file,
     128             :                                 "Does not contain superblock");
     129             :   }
     130             : 
     131         206 :   if (auto EC = msf::validateSuperBlock(*SB))
     132             :     return EC;
     133             : 
     134         206 :   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         103 :   ContainerLayout.SB = SB;
     138             : 
     139             :   // Initialize Free Page Map.
     140         206 :   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         309 :       MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
     156         103 :   BinaryStreamReader FpmReader(*FpmStream);
     157         103 :   ArrayRef<uint8_t> FpmBytes;
     158         206 :   if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
     159             :     return EC;
     160         103 :   uint32_t BlocksRemaining = getBlockCount();
     161             :   uint32_t BI = 0;
     162         968 :   for (auto Byte : FpmBytes) {
     163         762 :     uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
     164        5311 :     for (uint32_t I = 0; I < BlocksThisByte; ++I) {
     165        2465 :       if (Byte & (1 << I))
     166             :         ContainerLayout.FreePageMap[BI] = true;
     167        2465 :       --BlocksRemaining;
     168        2465 :       ++BI;
     169             :     }
     170             :   }
     171             : 
     172         103 :   Reader.setOffset(getBlockMapOffset());
     173         103 :   if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
     174         103 :                                  getNumDirectoryBlocks()))
     175             :     return EC;
     176             : 
     177             :   return Error::success();
     178             : }
     179             : 
     180         103 : Error PDBFile::parseStreamData() {
     181             :   assert(ContainerLayout.SB);
     182         103 :   if (DirectoryStream)
     183             :     return Error::success();
     184             : 
     185         103 :   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         309 :                                                      Allocator);
     194         103 :   BinaryStreamReader Reader(*DS);
     195         206 :   if (auto EC = Reader.readInteger(NumStreams))
     196             :     return EC;
     197             : 
     198         206 :   if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
     199             :     return EC;
     200        3601 :   for (uint32_t I = 0; I < NumStreams; ++I) {
     201        1749 :     uint32_t StreamSize = getStreamByteSize(I);
     202             :     // FIXME: What does StreamSize ~0U mean?
     203             :     uint64_t NumExpectedStreamBlocks =
     204             :         StreamSize == UINT32_MAX
     205        1749 :             ? 0
     206        3498 :             : 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        1749 :     ArrayRef<support::ulittle32_t> Blocks;
     215        3498 :     if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
     216             :       return EC;
     217        6954 :     for (uint32_t Block : Blocks) {
     218             :       uint64_t BlockEndOffset =
     219        3456 :           (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
     220        1728 :       if (BlockEndOffset > getFileSize())
     221             :         return make_error<RawError>(raw_error_code::corrupt_file,
     222             :                                     "Stream block map is corrupt.");
     223             :     }
     224        1749 :     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             : 
     233          11 : ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
     234          11 :   return ContainerLayout.DirectoryBlocks;
     235             : }
     236             : 
     237         305 : std::unique_ptr<MappedBlockStream> PDBFile::createIndexedStream(uint16_t SN) {
     238         305 :   if (SN == kInvalidStreamIndex)
     239             :     return nullptr;
     240             :   return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
     241         915 :                                                 Allocator);
     242             : }
     243             : 
     244          25 : MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
     245             :   MSFStreamLayout Result;
     246          25 :   auto Blocks = getStreamBlockList(StreamIdx);
     247          25 :   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          12 : Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
     257          12 :   if (!Globals) {
     258          11 :     auto DbiS = getPDBDbiStream();
     259          11 :     if (!DbiS)
     260             :       return DbiS.takeError();
     261             : 
     262             :     auto GlobalS = safelyCreateIndexedStream(
     263          44 :         ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex());
     264          11 :     if (!GlobalS)
     265             :       return GlobalS.takeError();
     266          22 :     auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS));
     267          22 :     if (auto EC = TempGlobals->reload())
     268             :       return std::move(EC);
     269          11 :     Globals = std::move(TempGlobals);
     270             :   }
     271             :   return *Globals;
     272             : }
     273             : 
     274         164 : Expected<InfoStream &> PDBFile::getPDBInfoStream() {
     275         164 :   if (!Info) {
     276         222 :     auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB);
     277          74 :     if (!InfoS)
     278             :       return InfoS.takeError();
     279         148 :     auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
     280         148 :     if (auto EC = TempInfo->reload())
     281             :       return std::move(EC);
     282          74 :     Info = std::move(TempInfo);
     283             :   }
     284             :   return *Info;
     285             : }
     286             : 
     287        1022 : Expected<DbiStream &> PDBFile::getPDBDbiStream() {
     288        1022 :   if (!Dbi) {
     289         201 :     auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI);
     290          67 :     if (!DbiS)
     291             :       return DbiS.takeError();
     292         134 :     auto TempDbi = llvm::make_unique<DbiStream>(std::move(*DbiS));
     293         134 :     if (auto EC = TempDbi->reload(this))
     294             :       return std::move(EC);
     295          67 :     Dbi = std::move(TempDbi);
     296             :   }
     297             :   return *Dbi;
     298             : }
     299             : 
     300          82 : Expected<TpiStream &> PDBFile::getPDBTpiStream() {
     301          82 :   if (!Tpi) {
     302         171 :     auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI);
     303          57 :     if (!TpiS)
     304             :       return TpiS.takeError();
     305         114 :     auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
     306         114 :     if (auto EC = TempTpi->reload())
     307             :       return std::move(EC);
     308          57 :     Tpi = std::move(TempTpi);
     309             :   }
     310             :   return *Tpi;
     311             : }
     312             : 
     313          48 : Expected<TpiStream &> PDBFile::getPDBIpiStream() {
     314          48 :   if (!Ipi) {
     315          37 :     if (!hasPDBIpiStream())
     316           0 :       return make_error<RawError>(raw_error_code::no_stream);
     317             : 
     318         111 :     auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI);
     319          37 :     if (!IpiS)
     320             :       return IpiS.takeError();
     321          74 :     auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
     322          74 :     if (auto EC = TempIpi->reload())
     323             :       return std::move(EC);
     324          37 :     Ipi = std::move(TempIpi);
     325             :   }
     326             :   return *Ipi;
     327             : }
     328             : 
     329           3 : Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
     330           3 :   if (!Publics) {
     331           3 :     auto DbiS = getPDBDbiStream();
     332           3 :     if (!DbiS)
     333             :       return DbiS.takeError();
     334             : 
     335             :     auto PublicS = safelyCreateIndexedStream(
     336          12 :         ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex());
     337           3 :     if (!PublicS)
     338             :       return PublicS.takeError();
     339           6 :     auto TempPublics = llvm::make_unique<PublicsStream>(std::move(*PublicS));
     340           6 :     if (auto EC = TempPublics->reload())
     341             :       return std::move(EC);
     342           3 :     Publics = std::move(TempPublics);
     343             :   }
     344             :   return *Publics;
     345             : }
     346             : 
     347          15 : Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
     348          15 :   if (!Symbols) {
     349          13 :     auto DbiS = getPDBDbiStream();
     350          13 :     if (!DbiS)
     351             :       return DbiS.takeError();
     352             : 
     353          13 :     uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
     354             :     auto SymbolS =
     355          39 :         safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum);
     356          13 :     if (!SymbolS)
     357             :       return SymbolS.takeError();
     358             : 
     359          26 :     auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
     360          26 :     if (auto EC = TempSymbols->reload())
     361             :       return std::move(EC);
     362          13 :     Symbols = std::move(TempSymbols);
     363             :   }
     364             :   return *Symbols;
     365             : }
     366             : 
     367          67 : Expected<PDBStringTable &> PDBFile::getStringTable() {
     368          67 :   if (!Strings) {
     369          38 :     auto IS = getPDBInfoStream();
     370          38 :     if (!IS)
     371             :       return IS.takeError();
     372             : 
     373          38 :     Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
     374          38 :     if (!ExpectedNSI)
     375             :       return ExpectedNSI.takeError();
     376          38 :     uint32_t NameStreamIndex = *ExpectedNSI;
     377             : 
     378             :     auto NS =
     379         114 :         safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex);
     380          38 :     if (!NS)
     381             :       return NS.takeError();
     382             : 
     383          76 :     auto N = llvm::make_unique<PDBStringTable>();
     384          38 :     BinaryStreamReader Reader(**NS);
     385          76 :     if (auto EC = N->reload(Reader))
     386             :       return std::move(EC);
     387             :     assert(Reader.bytesRemaining() == 0);
     388             :     StringTableStream = std::move(*NS);
     389          38 :     Strings = std::move(N);
     390             :   }
     391             :   return *Strings;
     392             : }
     393             : 
     394           0 : uint32_t PDBFile::getPointerSize() {
     395           0 :   auto DbiS = getPDBDbiStream();
     396           0 :   if (!DbiS)
     397             :     return 0;
     398           0 :   PDB_Machine Machine = DbiS->getMachineType();
     399           0 :   if (Machine == PDB_Machine::Amd64)
     400             :     return 8;
     401           0 :   return 4;
     402             : }
     403             : 
     404          54 : bool PDBFile::hasPDBDbiStream() const { return StreamDBI < getNumStreams(); }
     405             : 
     406          16 : bool PDBFile::hasPDBGlobalsStream() {
     407          16 :   auto DbiS = getPDBDbiStream();
     408          16 :   if (!DbiS) {
     409           0 :     consumeError(DbiS.takeError());
     410           0 :     return false;
     411             :   }
     412             : 
     413          16 :   return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
     414             : }
     415             : 
     416          90 : bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); }
     417             : 
     418          90 : bool PDBFile::hasPDBIpiStream() const {
     419          90 :   if (!hasPDBInfoStream())
     420             :     return false;
     421             : 
     422          90 :   if (StreamIPI >= getNumStreams())
     423             :     return false;
     424             : 
     425         180 :   auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
     426          90 :   return InfoStream.containsIdStream();
     427             : }
     428             : 
     429           7 : bool PDBFile::hasPDBPublicsStream() {
     430           7 :   auto DbiS = getPDBDbiStream();
     431           7 :   if (!DbiS) {
     432           0 :     consumeError(DbiS.takeError());
     433           0 :     return false;
     434             :   }
     435           7 :   return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
     436             : }
     437             : 
     438           0 : bool PDBFile::hasPDBSymbolStream() {
     439           0 :   auto DbiS = getPDBDbiStream();
     440           0 :   if (!DbiS)
     441             :     return false;
     442           0 :   return DbiS->getSymRecordStreamIndex() < getNumStreams();
     443             : }
     444             : 
     445          23 : bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
     446             : 
     447           0 : bool PDBFile::hasPDBStringTable() {
     448           0 :   auto IS = getPDBInfoStream();
     449           0 :   if (!IS)
     450             :     return false;
     451           0 :   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
     452           0 :   if (!ExpectedNSI) {
     453           0 :     consumeError(ExpectedNSI.takeError());
     454           0 :     return false;
     455             :   }
     456             :   assert(*ExpectedNSI < getNumStreams());
     457             :   return true;
     458             : }
     459             : 
     460             : /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
     461             : /// stream with that index actually exists.  If it does not, the return value
     462             : /// will have an MSFError with code msf_error_code::no_stream.  Else, the return
     463             : /// value will contain the stream returned by createIndexedStream().
     464             : Expected<std::unique_ptr<MappedBlockStream>>
     465         300 : PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout,
     466             :                                    BinaryStreamRef MsfData,
     467             :                                    uint32_t StreamIndex) const {
     468         300 :   if (StreamIndex >= getNumStreams())
     469           0 :     return make_error<RawError>(raw_error_code::no_stream);
     470        1200 :   return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex,
     471             :                                                 Allocator);
     472             : }

Generated by: LCOV version 1.13