Home | History | Annotate | Download | only in Raw
      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/Raw/PDBFile.h"
     11 
     12 #include "llvm/ADT/ArrayRef.h"
     13 #include "llvm/DebugInfo/CodeView/StreamArray.h"
     14 #include "llvm/DebugInfo/CodeView/StreamInterface.h"
     15 #include "llvm/DebugInfo/CodeView/StreamReader.h"
     16 #include "llvm/DebugInfo/CodeView/StreamWriter.h"
     17 #include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
     18 #include "llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h"
     19 #include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
     20 #include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
     21 #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h"
     22 #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
     23 #include "llvm/DebugInfo/PDB/Raw/RawError.h"
     24 #include "llvm/DebugInfo/PDB/Raw/SymbolStream.h"
     25 #include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
     26 #include "llvm/Support/Endian.h"
     27 #include "llvm/Support/FileOutputBuffer.h"
     28 #include "llvm/Support/MemoryBuffer.h"
     29 
     30 using namespace llvm;
     31 using namespace llvm::codeview;
     32 using namespace llvm::pdb;
     33 
     34 namespace {
     35 typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
     36 }
     37 
     38 PDBFile::PDBFile(std::unique_ptr<StreamInterface> PdbFileBuffer)
     39     : Buffer(std::move(PdbFileBuffer)), SB(nullptr) {}
     40 
     41 PDBFile::~PDBFile() {}
     42 
     43 uint32_t PDBFile::getBlockSize() const { return SB->BlockSize; }
     44 
     45 uint32_t PDBFile::getUnknown0() const { return SB->Unknown0; }
     46 
     47 uint32_t PDBFile::getBlockCount() const { return SB->NumBlocks; }
     48 
     49 uint32_t PDBFile::getNumDirectoryBytes() const { return SB->NumDirectoryBytes; }
     50 
     51 uint32_t PDBFile::getBlockMapIndex() const { return SB->BlockMapAddr; }
     52 
     53 uint32_t PDBFile::getUnknown1() const { return SB->Unknown1; }
     54 
     55 uint32_t PDBFile::getNumDirectoryBlocks() const {
     56   return bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize);
     57 }
     58 
     59 uint64_t PDBFile::getBlockMapOffset() const {
     60   return (uint64_t)SB->BlockMapAddr * SB->BlockSize;
     61 }
     62 
     63 uint32_t PDBFile::getNumStreams() const { return StreamSizes.size(); }
     64 
     65 uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
     66   return StreamSizes[StreamIndex];
     67 }
     68 
     69 ArrayRef<support::ulittle32_t>
     70 PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
     71   return StreamMap[StreamIndex];
     72 }
     73 
     74 uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
     75 
     76 Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
     77                                                   uint32_t NumBytes) const {
     78   uint64_t StreamBlockOffset = blockToOffset(BlockIndex, getBlockSize());
     79 
     80   ArrayRef<uint8_t> Result;
     81   if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
     82     return std::move(EC);
     83   return Result;
     84 }
     85 
     86 Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
     87                             ArrayRef<uint8_t> Data) const {
     88   if (Offset >= getBlockSize())
     89     return make_error<RawError>(
     90         raw_error_code::invalid_block_address,
     91         "setBlockData attempted to write out of block bounds.");
     92   if (Data.size() > getBlockSize() - Offset)
     93     return make_error<RawError>(
     94         raw_error_code::invalid_block_address,
     95         "setBlockData attempted to write out of block bounds.");
     96 
     97   uint64_t StreamBlockOffset = blockToOffset(BlockIndex, getBlockSize());
     98   StreamBlockOffset += Offset;
     99   return Buffer->writeBytes(StreamBlockOffset, Data);
    100 }
    101 
    102 Error PDBFile::parseFileHeaders() {
    103   StreamReader Reader(*Buffer);
    104 
    105   if (auto EC = Reader.readObject(SB)) {
    106     consumeError(std::move(EC));
    107     return make_error<RawError>(raw_error_code::corrupt_file,
    108                                 "Does not contain superblock");
    109   }
    110 
    111   if (auto EC = setSuperBlock(SB))
    112     return EC;
    113 
    114   Reader.setOffset(getBlockMapOffset());
    115   if (auto EC = Reader.readArray(DirectoryBlocks, getNumDirectoryBlocks()))
    116     return EC;
    117 
    118   return Error::success();
    119 }
    120 
    121 Error PDBFile::parseStreamData() {
    122   assert(SB);
    123   if (DirectoryStream)
    124     return Error::success();
    125 
    126   uint32_t NumStreams = 0;
    127 
    128   // Normally you can't use a MappedBlockStream without having fully parsed the
    129   // PDB file, because it accesses the directory and various other things, which
    130   // is exactly what we are attempting to parse.  By specifying a custom
    131   // subclass of IPDBStreamData which only accesses the fields that have already
    132   // been parsed, we can avoid this and reuse MappedBlockStream.
    133   auto DS = MappedBlockStream::createDirectoryStream(*this);
    134   if (!DS)
    135     return DS.takeError();
    136   StreamReader Reader(**DS);
    137   if (auto EC = Reader.readInteger(NumStreams))
    138     return EC;
    139 
    140   if (auto EC = Reader.readArray(StreamSizes, NumStreams))
    141     return EC;
    142   for (uint32_t I = 0; I < NumStreams; ++I) {
    143     uint32_t StreamSize = getStreamByteSize(I);
    144     // FIXME: What does StreamSize ~0U mean?
    145     uint64_t NumExpectedStreamBlocks =
    146         StreamSize == UINT32_MAX ? 0 : bytesToBlocks(StreamSize, SB->BlockSize);
    147 
    148     // For convenience, we store the block array contiguously.  This is because
    149     // if someone calls setStreamMap(), it is more convenient to be able to call
    150     // it with an ArrayRef instead of setting up a StreamRef.  Since the
    151     // DirectoryStream is cached in the class and thus lives for the life of the
    152     // class, we can be guaranteed that readArray() will return a stable
    153     // reference, even if it has to allocate from its internal pool.
    154     ArrayRef<support::ulittle32_t> Blocks;
    155     if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
    156       return EC;
    157     for (uint32_t Block : Blocks) {
    158       uint64_t BlockEndOffset = (uint64_t)(Block + 1) * SB->BlockSize;
    159       if (BlockEndOffset > getFileSize())
    160         return make_error<RawError>(raw_error_code::corrupt_file,
    161                                     "Stream block map is corrupt.");
    162     }
    163     StreamMap.push_back(Blocks);
    164   }
    165 
    166   // We should have read exactly SB->NumDirectoryBytes bytes.
    167   assert(Reader.bytesRemaining() == 0);
    168   DirectoryStream = std::move(*DS);
    169   return Error::success();
    170 }
    171 
    172 llvm::ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
    173   return DirectoryBlocks;
    174 }
    175 
    176 Expected<InfoStream &> PDBFile::getPDBInfoStream() {
    177   if (!Info) {
    178     auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, *this);
    179     if (!InfoS)
    180       return InfoS.takeError();
    181     auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
    182     if (auto EC = TempInfo->reload())
    183       return std::move(EC);
    184     Info = std::move(TempInfo);
    185   }
    186   return *Info;
    187 }
    188 
    189 Expected<DbiStream &> PDBFile::getPDBDbiStream() {
    190   if (!Dbi) {
    191     auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, *this);
    192     if (!DbiS)
    193       return DbiS.takeError();
    194     auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
    195     if (auto EC = TempDbi->reload())
    196       return std::move(EC);
    197     Dbi = std::move(TempDbi);
    198   }
    199   return *Dbi;
    200 }
    201 
    202 Expected<TpiStream &> PDBFile::getPDBTpiStream() {
    203   if (!Tpi) {
    204     auto TpiS = MappedBlockStream::createIndexedStream(StreamTPI, *this);
    205     if (!TpiS)
    206       return TpiS.takeError();
    207     auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
    208     if (auto EC = TempTpi->reload())
    209       return std::move(EC);
    210     Tpi = std::move(TempTpi);
    211   }
    212   return *Tpi;
    213 }
    214 
    215 Expected<TpiStream &> PDBFile::getPDBIpiStream() {
    216   if (!Ipi) {
    217     auto IpiS = MappedBlockStream::createIndexedStream(StreamIPI, *this);
    218     if (!IpiS)
    219       return IpiS.takeError();
    220     auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
    221     if (auto EC = TempIpi->reload())
    222       return std::move(EC);
    223     Ipi = std::move(TempIpi);
    224   }
    225   return *Ipi;
    226 }
    227 
    228 Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
    229   if (!Publics) {
    230     auto DbiS = getPDBDbiStream();
    231     if (!DbiS)
    232       return DbiS.takeError();
    233 
    234     uint32_t PublicsStreamNum = DbiS->getPublicSymbolStreamIndex();
    235 
    236     auto PublicS =
    237         MappedBlockStream::createIndexedStream(PublicsStreamNum, *this);
    238     if (!PublicS)
    239       return PublicS.takeError();
    240     auto TempPublics =
    241         llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
    242     if (auto EC = TempPublics->reload())
    243       return std::move(EC);
    244     Publics = std::move(TempPublics);
    245   }
    246   return *Publics;
    247 }
    248 
    249 Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
    250   if (!Symbols) {
    251     auto DbiS = getPDBDbiStream();
    252     if (!DbiS)
    253       return DbiS.takeError();
    254 
    255     uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
    256 
    257     auto SymbolS =
    258         MappedBlockStream::createIndexedStream(SymbolStreamNum, *this);
    259     if (!SymbolS)
    260       return SymbolS.takeError();
    261     auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
    262     if (auto EC = TempSymbols->reload())
    263       return std::move(EC);
    264     Symbols = std::move(TempSymbols);
    265   }
    266   return *Symbols;
    267 }
    268 
    269 Expected<NameHashTable &> PDBFile::getStringTable() {
    270   if (!StringTable || !StringTableStream) {
    271     auto IS = getPDBInfoStream();
    272     if (!IS)
    273       return IS.takeError();
    274 
    275     uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names");
    276 
    277     if (NameStreamIndex == 0)
    278       return make_error<RawError>(raw_error_code::no_stream);
    279     if (NameStreamIndex >= getNumStreams())
    280       return make_error<RawError>(raw_error_code::no_stream);
    281 
    282     auto NS = MappedBlockStream::createIndexedStream(NameStreamIndex, *this);
    283     if (!NS)
    284       return NS.takeError();
    285 
    286     StreamReader Reader(**NS);
    287     auto N = llvm::make_unique<NameHashTable>();
    288     if (auto EC = N->load(Reader))
    289       return std::move(EC);
    290     StringTable = std::move(N);
    291     StringTableStream = std::move(*NS);
    292   }
    293   return *StringTable;
    294 }
    295 
    296 Error PDBFile::setSuperBlock(const SuperBlock *Block) {
    297   SB = Block;
    298 
    299   // Check the magic bytes.
    300   if (memcmp(SB->MagicBytes, MsfMagic, sizeof(MsfMagic)) != 0)
    301     return make_error<RawError>(raw_error_code::corrupt_file,
    302                                 "MSF magic header doesn't match");
    303 
    304   // We don't support blocksizes which aren't a multiple of four bytes.
    305   if (SB->BlockSize % sizeof(support::ulittle32_t) != 0)
    306     return make_error<RawError>(raw_error_code::corrupt_file,
    307                                 "Block size is not multiple of 4.");
    308 
    309   switch (SB->BlockSize) {
    310   case 512:
    311   case 1024:
    312   case 2048:
    313   case 4096:
    314     break;
    315   default:
    316     // An invalid block size suggests a corrupt PDB file.
    317     return make_error<RawError>(raw_error_code::corrupt_file,
    318                                 "Unsupported block size.");
    319   }
    320 
    321   if (Buffer->getLength() % SB->BlockSize != 0)
    322     return make_error<RawError>(raw_error_code::corrupt_file,
    323                                 "File size is not a multiple of block size");
    324 
    325   // We don't support directories whose sizes aren't a multiple of four bytes.
    326   if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0)
    327     return make_error<RawError>(raw_error_code::corrupt_file,
    328                                 "Directory size is not multiple of 4.");
    329 
    330   // The number of blocks which comprise the directory is a simple function of
    331   // the number of bytes it contains.
    332   uint64_t NumDirectoryBlocks = getNumDirectoryBlocks();
    333 
    334   // The directory, as we understand it, is a block which consists of a list of
    335   // block numbers.  It is unclear what would happen if the number of blocks
    336   // couldn't fit on a single block.
    337   if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t))
    338     return make_error<RawError>(raw_error_code::corrupt_file,
    339                                 "Too many directory blocks.");
    340 
    341   return Error::success();
    342 }
    343 
    344 Error PDBFile::commit() {
    345   StreamWriter Writer(*Buffer);
    346 
    347   if (auto EC = Writer.writeObject(*SB))
    348     return EC;
    349   Writer.setOffset(getBlockMapOffset());
    350   if (auto EC = Writer.writeArray(DirectoryBlocks))
    351     return EC;
    352 
    353   auto DS = MappedBlockStream::createDirectoryStream(*this);
    354   if (!DS)
    355     return DS.takeError();
    356   auto DirStream = std::move(*DS);
    357   StreamWriter DW(*DirStream);
    358   if (auto EC = DW.writeInteger(this->getNumStreams()))
    359     return EC;
    360 
    361   if (auto EC = DW.writeArray(StreamSizes))
    362     return EC;
    363 
    364   for (const auto &Blocks : StreamMap) {
    365     if (auto EC = DW.writeArray(Blocks))
    366       return EC;
    367   }
    368 
    369   if (Info) {
    370     if (auto EC = Info->commit())
    371       return EC;
    372   }
    373 
    374   if (Dbi) {
    375     if (auto EC = Dbi->commit())
    376       return EC;
    377   }
    378 
    379   if (Symbols) {
    380     if (auto EC = Symbols->commit())
    381       return EC;
    382   }
    383 
    384   if (Publics) {
    385     if (auto EC = Publics->commit())
    386       return EC;
    387   }
    388 
    389   if (Tpi) {
    390     if (auto EC = Tpi->commit())
    391       return EC;
    392   }
    393 
    394   if (Ipi) {
    395     if (auto EC = Ipi->commit())
    396       return EC;
    397   }
    398 
    399   return Buffer->commit();
    400 }
    401