17a7e6055SDimitry Andric //===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
27a7e6055SDimitry Andric //
37a7e6055SDimitry Andric //                     The LLVM Compiler Infrastructure
47a7e6055SDimitry Andric //
57a7e6055SDimitry Andric // This file is distributed under the University of Illinois Open Source
67a7e6055SDimitry Andric // License. See LICENSE.TXT for details.
77a7e6055SDimitry Andric //
87a7e6055SDimitry Andric //===----------------------------------------------------------------------===//
97a7e6055SDimitry Andric 
107a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
117a7e6055SDimitry Andric #include "llvm/ADT/ArrayRef.h"
127a7e6055SDimitry Andric #include "llvm/ADT/STLExtras.h"
137a7e6055SDimitry Andric #include "llvm/DebugInfo/MSF/MSFCommon.h"
147a7e6055SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
157a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
167a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
177a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
18f37b6182SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
197a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
207a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
217a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
227a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
237a7e6055SDimitry Andric #include "llvm/Support/BinaryStream.h"
247a7e6055SDimitry Andric #include "llvm/Support/BinaryStreamArray.h"
257a7e6055SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
267a7e6055SDimitry Andric #include "llvm/Support/Endian.h"
277a7e6055SDimitry Andric #include "llvm/Support/Error.h"
287a7e6055SDimitry Andric #include "llvm/Support/Path.h"
297a7e6055SDimitry Andric #include <algorithm>
307a7e6055SDimitry Andric #include <cassert>
317a7e6055SDimitry Andric #include <cstdint>
327a7e6055SDimitry Andric 
337a7e6055SDimitry Andric using namespace llvm;
347a7e6055SDimitry Andric using namespace llvm::codeview;
357a7e6055SDimitry Andric using namespace llvm::msf;
367a7e6055SDimitry Andric using namespace llvm::pdb;
377a7e6055SDimitry Andric 
387a7e6055SDimitry Andric namespace {
397a7e6055SDimitry Andric typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
407a7e6055SDimitry Andric } // end anonymous namespace
417a7e6055SDimitry Andric 
PDBFile(StringRef Path,std::unique_ptr<BinaryStream> PdbFileBuffer,BumpPtrAllocator & Allocator)427a7e6055SDimitry Andric PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer,
437a7e6055SDimitry Andric                  BumpPtrAllocator &Allocator)
447a7e6055SDimitry Andric     : FilePath(Path), Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {}
457a7e6055SDimitry Andric 
467a7e6055SDimitry Andric PDBFile::~PDBFile() = default;
477a7e6055SDimitry Andric 
getFilePath() const487a7e6055SDimitry Andric StringRef PDBFile::getFilePath() const { return FilePath; }
497a7e6055SDimitry Andric 
getFileDirectory() const507a7e6055SDimitry Andric StringRef PDBFile::getFileDirectory() const {
517a7e6055SDimitry Andric   return sys::path::parent_path(FilePath);
527a7e6055SDimitry Andric }
537a7e6055SDimitry Andric 
getBlockSize() const547a7e6055SDimitry Andric uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
557a7e6055SDimitry Andric 
getFreeBlockMapBlock() const567a7e6055SDimitry Andric uint32_t PDBFile::getFreeBlockMapBlock() const {
577a7e6055SDimitry Andric   return ContainerLayout.SB->FreeBlockMapBlock;
587a7e6055SDimitry Andric }
597a7e6055SDimitry Andric 
getBlockCount() const607a7e6055SDimitry Andric uint32_t PDBFile::getBlockCount() const {
617a7e6055SDimitry Andric   return ContainerLayout.SB->NumBlocks;
627a7e6055SDimitry Andric }
637a7e6055SDimitry Andric 
getNumDirectoryBytes() const647a7e6055SDimitry Andric uint32_t PDBFile::getNumDirectoryBytes() const {
657a7e6055SDimitry Andric   return ContainerLayout.SB->NumDirectoryBytes;
667a7e6055SDimitry Andric }
677a7e6055SDimitry Andric 
getBlockMapIndex() const687a7e6055SDimitry Andric uint32_t PDBFile::getBlockMapIndex() const {
697a7e6055SDimitry Andric   return ContainerLayout.SB->BlockMapAddr;
707a7e6055SDimitry Andric }
717a7e6055SDimitry Andric 
getUnknown1() const727a7e6055SDimitry Andric uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
737a7e6055SDimitry Andric 
getNumDirectoryBlocks() const747a7e6055SDimitry Andric uint32_t PDBFile::getNumDirectoryBlocks() const {
757a7e6055SDimitry Andric   return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
767a7e6055SDimitry Andric                             ContainerLayout.SB->BlockSize);
777a7e6055SDimitry Andric }
787a7e6055SDimitry Andric 
getBlockMapOffset() const797a7e6055SDimitry Andric uint64_t PDBFile::getBlockMapOffset() const {
807a7e6055SDimitry Andric   return (uint64_t)ContainerLayout.SB->BlockMapAddr *
817a7e6055SDimitry Andric          ContainerLayout.SB->BlockSize;
827a7e6055SDimitry Andric }
837a7e6055SDimitry Andric 
getNumStreams() const847a7e6055SDimitry Andric uint32_t PDBFile::getNumStreams() const {
857a7e6055SDimitry Andric   return ContainerLayout.StreamSizes.size();
867a7e6055SDimitry Andric }
877a7e6055SDimitry Andric 
getMaxStreamSize() const882cab237bSDimitry Andric uint32_t PDBFile::getMaxStreamSize() const {
892cab237bSDimitry Andric   return *std::max_element(ContainerLayout.StreamSizes.begin(),
902cab237bSDimitry Andric                            ContainerLayout.StreamSizes.end());
912cab237bSDimitry Andric }
922cab237bSDimitry Andric 
getStreamByteSize(uint32_t StreamIndex) const937a7e6055SDimitry Andric uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
947a7e6055SDimitry Andric   return ContainerLayout.StreamSizes[StreamIndex];
957a7e6055SDimitry Andric }
967a7e6055SDimitry Andric 
977a7e6055SDimitry Andric ArrayRef<support::ulittle32_t>
getStreamBlockList(uint32_t StreamIndex) const987a7e6055SDimitry Andric PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
997a7e6055SDimitry Andric   return ContainerLayout.StreamMap[StreamIndex];
1007a7e6055SDimitry Andric }
1017a7e6055SDimitry Andric 
getFileSize() const1027a7e6055SDimitry Andric uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
1037a7e6055SDimitry Andric 
getBlockData(uint32_t BlockIndex,uint32_t NumBytes) const1047a7e6055SDimitry Andric Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
1057a7e6055SDimitry Andric                                                   uint32_t NumBytes) const {
1067a7e6055SDimitry Andric   uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
1077a7e6055SDimitry Andric 
1087a7e6055SDimitry Andric   ArrayRef<uint8_t> Result;
1097a7e6055SDimitry Andric   if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
1107a7e6055SDimitry Andric     return std::move(EC);
1117a7e6055SDimitry Andric   return Result;
1127a7e6055SDimitry Andric }
1137a7e6055SDimitry Andric 
setBlockData(uint32_t BlockIndex,uint32_t Offset,ArrayRef<uint8_t> Data) const1147a7e6055SDimitry Andric Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
1157a7e6055SDimitry Andric                             ArrayRef<uint8_t> Data) const {
1167a7e6055SDimitry Andric   return make_error<RawError>(raw_error_code::not_writable,
1177a7e6055SDimitry Andric                               "PDBFile is immutable");
1187a7e6055SDimitry Andric }
1197a7e6055SDimitry Andric 
parseFileHeaders()1207a7e6055SDimitry Andric Error PDBFile::parseFileHeaders() {
1217a7e6055SDimitry Andric   BinaryStreamReader Reader(*Buffer);
1227a7e6055SDimitry Andric 
1237a7e6055SDimitry Andric   // Initialize SB.
1247a7e6055SDimitry Andric   const msf::SuperBlock *SB = nullptr;
1257a7e6055SDimitry Andric   if (auto EC = Reader.readObject(SB)) {
1267a7e6055SDimitry Andric     consumeError(std::move(EC));
1277a7e6055SDimitry Andric     return make_error<RawError>(raw_error_code::corrupt_file,
128*b5893f02SDimitry Andric                                 "MSF superblock is missing");
1297a7e6055SDimitry Andric   }
1307a7e6055SDimitry Andric 
1317a7e6055SDimitry Andric   if (auto EC = msf::validateSuperBlock(*SB))
1327a7e6055SDimitry Andric     return EC;
1337a7e6055SDimitry Andric 
1347a7e6055SDimitry Andric   if (Buffer->getLength() % SB->BlockSize != 0)
1357a7e6055SDimitry Andric     return make_error<RawError>(raw_error_code::corrupt_file,
1367a7e6055SDimitry Andric                                 "File size is not a multiple of block size");
1377a7e6055SDimitry Andric   ContainerLayout.SB = SB;
1387a7e6055SDimitry Andric 
1397a7e6055SDimitry Andric   // Initialize Free Page Map.
1407a7e6055SDimitry Andric   ContainerLayout.FreePageMap.resize(SB->NumBlocks);
1417a7e6055SDimitry Andric   // The Fpm exists either at block 1 or block 2 of the MSF.  However, this
1427a7e6055SDimitry Andric   // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
1437a7e6055SDimitry Andric   // thusly an equal number of total blocks in the file.  For a block size
1447a7e6055SDimitry Andric   // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
1457a7e6055SDimitry Andric   // maximum file size of 32KiB * 4KiB = 128MiB.  Obviously this won't do, so
1467a7e6055SDimitry Andric   // the Fpm is split across the file at `getBlockSize()` intervals.  As a
1477a7e6055SDimitry Andric   // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
1487a7e6055SDimitry Andric   // for any non-negative integer k is an Fpm block.  In theory, we only really
1497a7e6055SDimitry Andric   // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
1507a7e6055SDimitry Andric   // current versions of the MSF format already expect the Fpm to be arranged
1517a7e6055SDimitry Andric   // at getBlockSize() intervals, so we have to be compatible.
1527a7e6055SDimitry Andric   // See the function fpmPn() for more information:
1537a7e6055SDimitry Andric   // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
1546d97bb29SDimitry Andric   auto FpmStream =
1556d97bb29SDimitry Andric       MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
1567a7e6055SDimitry Andric   BinaryStreamReader FpmReader(*FpmStream);
1577a7e6055SDimitry Andric   ArrayRef<uint8_t> FpmBytes;
1582cab237bSDimitry Andric   if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
1597a7e6055SDimitry Andric     return EC;
1607a7e6055SDimitry Andric   uint32_t BlocksRemaining = getBlockCount();
1617a7e6055SDimitry Andric   uint32_t BI = 0;
1627a7e6055SDimitry Andric   for (auto Byte : FpmBytes) {
1637a7e6055SDimitry Andric     uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
1647a7e6055SDimitry Andric     for (uint32_t I = 0; I < BlocksThisByte; ++I) {
1657a7e6055SDimitry Andric       if (Byte & (1 << I))
1667a7e6055SDimitry Andric         ContainerLayout.FreePageMap[BI] = true;
1677a7e6055SDimitry Andric       --BlocksRemaining;
1687a7e6055SDimitry Andric       ++BI;
1697a7e6055SDimitry Andric     }
1707a7e6055SDimitry Andric   }
1717a7e6055SDimitry Andric 
1727a7e6055SDimitry Andric   Reader.setOffset(getBlockMapOffset());
1737a7e6055SDimitry Andric   if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
1747a7e6055SDimitry Andric                                  getNumDirectoryBlocks()))
1757a7e6055SDimitry Andric     return EC;
1767a7e6055SDimitry Andric 
1777a7e6055SDimitry Andric   return Error::success();
1787a7e6055SDimitry Andric }
1797a7e6055SDimitry Andric 
parseStreamData()1807a7e6055SDimitry Andric Error PDBFile::parseStreamData() {
1817a7e6055SDimitry Andric   assert(ContainerLayout.SB);
1827a7e6055SDimitry Andric   if (DirectoryStream)
1837a7e6055SDimitry Andric     return Error::success();
1847a7e6055SDimitry Andric 
1857a7e6055SDimitry Andric   uint32_t NumStreams = 0;
1867a7e6055SDimitry Andric 
1877a7e6055SDimitry Andric   // Normally you can't use a MappedBlockStream without having fully parsed the
1887a7e6055SDimitry Andric   // PDB file, because it accesses the directory and various other things, which
1897a7e6055SDimitry Andric   // is exactly what we are attempting to parse.  By specifying a custom
1907a7e6055SDimitry Andric   // subclass of IPDBStreamData which only accesses the fields that have already
1917a7e6055SDimitry Andric   // been parsed, we can avoid this and reuse MappedBlockStream.
1926d97bb29SDimitry Andric   auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer,
1936d97bb29SDimitry Andric                                                      Allocator);
1947a7e6055SDimitry Andric   BinaryStreamReader Reader(*DS);
1957a7e6055SDimitry Andric   if (auto EC = Reader.readInteger(NumStreams))
1967a7e6055SDimitry Andric     return EC;
1977a7e6055SDimitry Andric 
1987a7e6055SDimitry Andric   if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
1997a7e6055SDimitry Andric     return EC;
2007a7e6055SDimitry Andric   for (uint32_t I = 0; I < NumStreams; ++I) {
2017a7e6055SDimitry Andric     uint32_t StreamSize = getStreamByteSize(I);
2027a7e6055SDimitry Andric     // FIXME: What does StreamSize ~0U mean?
2037a7e6055SDimitry Andric     uint64_t NumExpectedStreamBlocks =
2047a7e6055SDimitry Andric         StreamSize == UINT32_MAX
2057a7e6055SDimitry Andric             ? 0
2067a7e6055SDimitry Andric             : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
2077a7e6055SDimitry Andric 
2087a7e6055SDimitry Andric     // For convenience, we store the block array contiguously.  This is because
2097a7e6055SDimitry Andric     // if someone calls setStreamMap(), it is more convenient to be able to call
2107a7e6055SDimitry Andric     // it with an ArrayRef instead of setting up a StreamRef.  Since the
2117a7e6055SDimitry Andric     // DirectoryStream is cached in the class and thus lives for the life of the
2127a7e6055SDimitry Andric     // class, we can be guaranteed that readArray() will return a stable
2137a7e6055SDimitry Andric     // reference, even if it has to allocate from its internal pool.
2147a7e6055SDimitry Andric     ArrayRef<support::ulittle32_t> Blocks;
2157a7e6055SDimitry Andric     if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
2167a7e6055SDimitry Andric       return EC;
2177a7e6055SDimitry Andric     for (uint32_t Block : Blocks) {
2187a7e6055SDimitry Andric       uint64_t BlockEndOffset =
2197a7e6055SDimitry Andric           (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
2207a7e6055SDimitry Andric       if (BlockEndOffset > getFileSize())
2217a7e6055SDimitry Andric         return make_error<RawError>(raw_error_code::corrupt_file,
2227a7e6055SDimitry Andric                                     "Stream block map is corrupt.");
2237a7e6055SDimitry Andric     }
2247a7e6055SDimitry Andric     ContainerLayout.StreamMap.push_back(Blocks);
2257a7e6055SDimitry Andric   }
2267a7e6055SDimitry Andric 
2277a7e6055SDimitry Andric   // We should have read exactly SB->NumDirectoryBytes bytes.
2287a7e6055SDimitry Andric   assert(Reader.bytesRemaining() == 0);
2297a7e6055SDimitry Andric   DirectoryStream = std::move(DS);
2307a7e6055SDimitry Andric   return Error::success();
2317a7e6055SDimitry Andric }
2327a7e6055SDimitry Andric 
getDirectoryBlockArray() const2337a7e6055SDimitry Andric ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
2347a7e6055SDimitry Andric   return ContainerLayout.DirectoryBlocks;
2357a7e6055SDimitry Andric }
2367a7e6055SDimitry Andric 
createIndexedStream(uint16_t SN)2372cab237bSDimitry Andric std::unique_ptr<MappedBlockStream> PDBFile::createIndexedStream(uint16_t SN) {
2382cab237bSDimitry Andric   if (SN == kInvalidStreamIndex)
2392cab237bSDimitry Andric     return nullptr;
2402cab237bSDimitry Andric   return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
2412cab237bSDimitry Andric                                                 Allocator);
2422cab237bSDimitry Andric }
2432cab237bSDimitry Andric 
getStreamLayout(uint32_t StreamIdx) const244edd7eaddSDimitry Andric MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
245edd7eaddSDimitry Andric   MSFStreamLayout Result;
246edd7eaddSDimitry Andric   auto Blocks = getStreamBlockList(StreamIdx);
247edd7eaddSDimitry Andric   Result.Blocks.assign(Blocks.begin(), Blocks.end());
248edd7eaddSDimitry Andric   Result.Length = getStreamByteSize(StreamIdx);
249edd7eaddSDimitry Andric   return Result;
250edd7eaddSDimitry Andric }
251edd7eaddSDimitry Andric 
getFpmStreamLayout() const2522cab237bSDimitry Andric msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const {
2532cab237bSDimitry Andric   return msf::getFpmStreamLayout(ContainerLayout);
2542cab237bSDimitry Andric }
2552cab237bSDimitry Andric 
getPDBGlobalsStream()2567a7e6055SDimitry Andric Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
2577a7e6055SDimitry Andric   if (!Globals) {
2587a7e6055SDimitry Andric     auto DbiS = getPDBDbiStream();
2597a7e6055SDimitry Andric     if (!DbiS)
2607a7e6055SDimitry Andric       return DbiS.takeError();
2617a7e6055SDimitry Andric 
2627a7e6055SDimitry Andric     auto GlobalS = safelyCreateIndexedStream(
2637a7e6055SDimitry Andric         ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex());
2647a7e6055SDimitry Andric     if (!GlobalS)
2657a7e6055SDimitry Andric       return GlobalS.takeError();
2667a7e6055SDimitry Andric     auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS));
2677a7e6055SDimitry Andric     if (auto EC = TempGlobals->reload())
2687a7e6055SDimitry Andric       return std::move(EC);
2697a7e6055SDimitry Andric     Globals = std::move(TempGlobals);
2707a7e6055SDimitry Andric   }
2717a7e6055SDimitry Andric   return *Globals;
2727a7e6055SDimitry Andric }
2737a7e6055SDimitry Andric 
getPDBInfoStream()2747a7e6055SDimitry Andric Expected<InfoStream &> PDBFile::getPDBInfoStream() {
2757a7e6055SDimitry Andric   if (!Info) {
2767a7e6055SDimitry Andric     auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB);
2777a7e6055SDimitry Andric     if (!InfoS)
2787a7e6055SDimitry Andric       return InfoS.takeError();
2797a7e6055SDimitry Andric     auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
2807a7e6055SDimitry Andric     if (auto EC = TempInfo->reload())
2817a7e6055SDimitry Andric       return std::move(EC);
2827a7e6055SDimitry Andric     Info = std::move(TempInfo);
2837a7e6055SDimitry Andric   }
2847a7e6055SDimitry Andric   return *Info;
2857a7e6055SDimitry Andric }
2867a7e6055SDimitry Andric 
getPDBDbiStream()2877a7e6055SDimitry Andric Expected<DbiStream &> PDBFile::getPDBDbiStream() {
2887a7e6055SDimitry Andric   if (!Dbi) {
2897a7e6055SDimitry Andric     auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI);
2907a7e6055SDimitry Andric     if (!DbiS)
2917a7e6055SDimitry Andric       return DbiS.takeError();
2924ba319b5SDimitry Andric     auto TempDbi = llvm::make_unique<DbiStream>(std::move(*DbiS));
2934ba319b5SDimitry Andric     if (auto EC = TempDbi->reload(this))
2947a7e6055SDimitry Andric       return std::move(EC);
2957a7e6055SDimitry Andric     Dbi = std::move(TempDbi);
2967a7e6055SDimitry Andric   }
2977a7e6055SDimitry Andric   return *Dbi;
2987a7e6055SDimitry Andric }
2997a7e6055SDimitry Andric 
getPDBTpiStream()3007a7e6055SDimitry Andric Expected<TpiStream &> PDBFile::getPDBTpiStream() {
3017a7e6055SDimitry Andric   if (!Tpi) {
3027a7e6055SDimitry Andric     auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI);
3037a7e6055SDimitry Andric     if (!TpiS)
3047a7e6055SDimitry Andric       return TpiS.takeError();
3057a7e6055SDimitry Andric     auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
3067a7e6055SDimitry Andric     if (auto EC = TempTpi->reload())
3077a7e6055SDimitry Andric       return std::move(EC);
3087a7e6055SDimitry Andric     Tpi = std::move(TempTpi);
3097a7e6055SDimitry Andric   }
3107a7e6055SDimitry Andric   return *Tpi;
3117a7e6055SDimitry Andric }
3127a7e6055SDimitry Andric 
getPDBIpiStream()3137a7e6055SDimitry Andric Expected<TpiStream &> PDBFile::getPDBIpiStream() {
3147a7e6055SDimitry Andric   if (!Ipi) {
3152cab237bSDimitry Andric     if (!hasPDBIpiStream())
3162cab237bSDimitry Andric       return make_error<RawError>(raw_error_code::no_stream);
3172cab237bSDimitry Andric 
3187a7e6055SDimitry Andric     auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI);
3197a7e6055SDimitry Andric     if (!IpiS)
3207a7e6055SDimitry Andric       return IpiS.takeError();
3217a7e6055SDimitry Andric     auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
3227a7e6055SDimitry Andric     if (auto EC = TempIpi->reload())
3237a7e6055SDimitry Andric       return std::move(EC);
3247a7e6055SDimitry Andric     Ipi = std::move(TempIpi);
3257a7e6055SDimitry Andric   }
3267a7e6055SDimitry Andric   return *Ipi;
3277a7e6055SDimitry Andric }
3287a7e6055SDimitry Andric 
getPDBPublicsStream()3297a7e6055SDimitry Andric Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
3307a7e6055SDimitry Andric   if (!Publics) {
3317a7e6055SDimitry Andric     auto DbiS = getPDBDbiStream();
3327a7e6055SDimitry Andric     if (!DbiS)
3337a7e6055SDimitry Andric       return DbiS.takeError();
3347a7e6055SDimitry Andric 
3357a7e6055SDimitry Andric     auto PublicS = safelyCreateIndexedStream(
3367a7e6055SDimitry Andric         ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex());
3377a7e6055SDimitry Andric     if (!PublicS)
3387a7e6055SDimitry Andric       return PublicS.takeError();
3392cab237bSDimitry Andric     auto TempPublics = llvm::make_unique<PublicsStream>(std::move(*PublicS));
3407a7e6055SDimitry Andric     if (auto EC = TempPublics->reload())
3417a7e6055SDimitry Andric       return std::move(EC);
3427a7e6055SDimitry Andric     Publics = std::move(TempPublics);
3437a7e6055SDimitry Andric   }
3447a7e6055SDimitry Andric   return *Publics;
3457a7e6055SDimitry Andric }
3467a7e6055SDimitry Andric 
getPDBSymbolStream()3477a7e6055SDimitry Andric Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
3487a7e6055SDimitry Andric   if (!Symbols) {
3497a7e6055SDimitry Andric     auto DbiS = getPDBDbiStream();
3507a7e6055SDimitry Andric     if (!DbiS)
3517a7e6055SDimitry Andric       return DbiS.takeError();
3527a7e6055SDimitry Andric 
3537a7e6055SDimitry Andric     uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
3547a7e6055SDimitry Andric     auto SymbolS =
3557a7e6055SDimitry Andric         safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum);
3567a7e6055SDimitry Andric     if (!SymbolS)
3577a7e6055SDimitry Andric       return SymbolS.takeError();
3587a7e6055SDimitry Andric 
3597a7e6055SDimitry Andric     auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
3607a7e6055SDimitry Andric     if (auto EC = TempSymbols->reload())
3617a7e6055SDimitry Andric       return std::move(EC);
3627a7e6055SDimitry Andric     Symbols = std::move(TempSymbols);
3637a7e6055SDimitry Andric   }
3647a7e6055SDimitry Andric   return *Symbols;
3657a7e6055SDimitry Andric }
3667a7e6055SDimitry Andric 
getStringTable()367f37b6182SDimitry Andric Expected<PDBStringTable &> PDBFile::getStringTable() {
368f37b6182SDimitry Andric   if (!Strings) {
3697a7e6055SDimitry Andric     auto IS = getPDBInfoStream();
3707a7e6055SDimitry Andric     if (!IS)
3717a7e6055SDimitry Andric       return IS.takeError();
3727a7e6055SDimitry Andric 
3734ba319b5SDimitry Andric     Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
3744ba319b5SDimitry Andric     if (!ExpectedNSI)
3754ba319b5SDimitry Andric       return ExpectedNSI.takeError();
3764ba319b5SDimitry Andric     uint32_t NameStreamIndex = *ExpectedNSI;
3777a7e6055SDimitry Andric 
3787a7e6055SDimitry Andric     auto NS =
3797a7e6055SDimitry Andric         safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex);
3807a7e6055SDimitry Andric     if (!NS)
3817a7e6055SDimitry Andric       return NS.takeError();
3827a7e6055SDimitry Andric 
383f37b6182SDimitry Andric     auto N = llvm::make_unique<PDBStringTable>();
3847a7e6055SDimitry Andric     BinaryStreamReader Reader(**NS);
385f37b6182SDimitry Andric     if (auto EC = N->reload(Reader))
3867a7e6055SDimitry Andric       return std::move(EC);
387f37b6182SDimitry Andric     assert(Reader.bytesRemaining() == 0);
3887a7e6055SDimitry Andric     StringTableStream = std::move(*NS);
389f37b6182SDimitry Andric     Strings = std::move(N);
3907a7e6055SDimitry Andric   }
3917a7e6055SDimitry Andric   return *Strings;
3927a7e6055SDimitry Andric }
3937a7e6055SDimitry Andric 
getPointerSize()39424d58133SDimitry Andric uint32_t PDBFile::getPointerSize() {
39524d58133SDimitry Andric   auto DbiS = getPDBDbiStream();
39624d58133SDimitry Andric   if (!DbiS)
39724d58133SDimitry Andric     return 0;
39824d58133SDimitry Andric   PDB_Machine Machine = DbiS->getMachineType();
39924d58133SDimitry Andric   if (Machine == PDB_Machine::Amd64)
40024d58133SDimitry Andric     return 8;
40124d58133SDimitry Andric   return 4;
40224d58133SDimitry Andric }
40324d58133SDimitry Andric 
hasPDBDbiStream() const404*b5893f02SDimitry Andric bool PDBFile::hasPDBDbiStream() const {
405*b5893f02SDimitry Andric   return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0;
406*b5893f02SDimitry Andric }
4077a7e6055SDimitry Andric 
hasPDBGlobalsStream()4087a7e6055SDimitry Andric bool PDBFile::hasPDBGlobalsStream() {
4097a7e6055SDimitry Andric   auto DbiS = getPDBDbiStream();
410c4394386SDimitry Andric   if (!DbiS) {
411c4394386SDimitry Andric     consumeError(DbiS.takeError());
4127a7e6055SDimitry Andric     return false;
413c4394386SDimitry Andric   }
414c4394386SDimitry Andric 
4157a7e6055SDimitry Andric   return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
4167a7e6055SDimitry Andric }
4177a7e6055SDimitry Andric 
hasPDBInfoStream() const4182cab237bSDimitry Andric bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); }
4197a7e6055SDimitry Andric 
hasPDBIpiStream() const4202cab237bSDimitry Andric bool PDBFile::hasPDBIpiStream() const {
4212cab237bSDimitry Andric   if (!hasPDBInfoStream())
4222cab237bSDimitry Andric     return false;
4232cab237bSDimitry Andric 
4242cab237bSDimitry Andric   if (StreamIPI >= getNumStreams())
4252cab237bSDimitry Andric     return false;
4262cab237bSDimitry Andric 
4272cab237bSDimitry Andric   auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
4282cab237bSDimitry Andric   return InfoStream.containsIdStream();
4292cab237bSDimitry Andric }
4307a7e6055SDimitry Andric 
hasPDBPublicsStream()4317a7e6055SDimitry Andric bool PDBFile::hasPDBPublicsStream() {
4327a7e6055SDimitry Andric   auto DbiS = getPDBDbiStream();
433c4394386SDimitry Andric   if (!DbiS) {
434c4394386SDimitry Andric     consumeError(DbiS.takeError());
4357a7e6055SDimitry Andric     return false;
436c4394386SDimitry Andric   }
4377a7e6055SDimitry Andric   return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
4387a7e6055SDimitry Andric }
4397a7e6055SDimitry Andric 
hasPDBSymbolStream()4407a7e6055SDimitry Andric bool PDBFile::hasPDBSymbolStream() {
4417a7e6055SDimitry Andric   auto DbiS = getPDBDbiStream();
4427a7e6055SDimitry Andric   if (!DbiS)
4437a7e6055SDimitry Andric     return false;
4447a7e6055SDimitry Andric   return DbiS->getSymRecordStreamIndex() < getNumStreams();
4457a7e6055SDimitry Andric }
4467a7e6055SDimitry Andric 
hasPDBTpiStream() const4477a7e6055SDimitry Andric bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
4487a7e6055SDimitry Andric 
hasPDBStringTable()449f37b6182SDimitry Andric bool PDBFile::hasPDBStringTable() {
4507a7e6055SDimitry Andric   auto IS = getPDBInfoStream();
4517a7e6055SDimitry Andric   if (!IS)
4527a7e6055SDimitry Andric     return false;
4534ba319b5SDimitry Andric   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
4544ba319b5SDimitry Andric   if (!ExpectedNSI) {
4554ba319b5SDimitry Andric     consumeError(ExpectedNSI.takeError());
4564ba319b5SDimitry Andric     return false;
4574ba319b5SDimitry Andric   }
4584ba319b5SDimitry Andric   assert(*ExpectedNSI < getNumStreams());
4594ba319b5SDimitry Andric   return true;
4607a7e6055SDimitry Andric }
4617a7e6055SDimitry Andric 
4627a7e6055SDimitry Andric /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
4637a7e6055SDimitry Andric /// stream with that index actually exists.  If it does not, the return value
4647a7e6055SDimitry Andric /// will have an MSFError with code msf_error_code::no_stream.  Else, the return
4657a7e6055SDimitry Andric /// value will contain the stream returned by createIndexedStream().
4667a7e6055SDimitry Andric Expected<std::unique_ptr<MappedBlockStream>>
safelyCreateIndexedStream(const MSFLayout & Layout,BinaryStreamRef MsfData,uint32_t StreamIndex) const4677a7e6055SDimitry Andric PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout,
4687a7e6055SDimitry Andric                                    BinaryStreamRef MsfData,
4697a7e6055SDimitry Andric                                    uint32_t StreamIndex) const {
4707a7e6055SDimitry Andric   if (StreamIndex >= getNumStreams())
4717a7e6055SDimitry Andric     return make_error<RawError>(raw_error_code::no_stream);
4726d97bb29SDimitry Andric   return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex,
4736d97bb29SDimitry Andric                                                 Allocator);
4747a7e6055SDimitry Andric }
475