16b6b8c4fSAdrian McCarthy //===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
26b6b8c4fSAdrian McCarthy //
36b6b8c4fSAdrian McCarthy //                     The LLVM Compiler Infrastructure
46b6b8c4fSAdrian McCarthy //
56b6b8c4fSAdrian McCarthy // This file is distributed under the University of Illinois Open Source
66b6b8c4fSAdrian McCarthy // License. See LICENSE.TXT for details.
76b6b8c4fSAdrian McCarthy //
86b6b8c4fSAdrian McCarthy //===----------------------------------------------------------------------===//
96b6b8c4fSAdrian McCarthy 
106b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
116b6b8c4fSAdrian McCarthy #include "llvm/ADT/ArrayRef.h"
126b6b8c4fSAdrian McCarthy #include "llvm/ADT/STLExtras.h"
136b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/MSF/MSFCommon.h"
146b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
156b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
166b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
176b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
18e204a6c9SZachary Turner #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
196b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
206b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/RawError.h"
216b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
226b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
23d9dc2829SZachary Turner #include "llvm/Support/BinaryStream.h"
24d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamArray.h"
25d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamReader.h"
266b6b8c4fSAdrian McCarthy #include "llvm/Support/Endian.h"
276b6b8c4fSAdrian McCarthy #include "llvm/Support/Error.h"
287b327d05SZachary Turner #include "llvm/Support/Path.h"
296b6b8c4fSAdrian McCarthy #include <algorithm>
306b6b8c4fSAdrian McCarthy #include <cassert>
316b6b8c4fSAdrian McCarthy #include <cstdint>
326b6b8c4fSAdrian McCarthy 
336b6b8c4fSAdrian McCarthy using namespace llvm;
346b6b8c4fSAdrian McCarthy using namespace llvm::codeview;
356b6b8c4fSAdrian McCarthy using namespace llvm::msf;
366b6b8c4fSAdrian McCarthy using namespace llvm::pdb;
376b6b8c4fSAdrian McCarthy 
386b6b8c4fSAdrian McCarthy namespace {
396b6b8c4fSAdrian McCarthy typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
406b6b8c4fSAdrian McCarthy } // end anonymous namespace
416b6b8c4fSAdrian McCarthy 
42120faca4SZachary Turner PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer,
436b6b8c4fSAdrian McCarthy                  BumpPtrAllocator &Allocator)
447b327d05SZachary Turner     : FilePath(Path), Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {}
456b6b8c4fSAdrian McCarthy 
466b6b8c4fSAdrian McCarthy PDBFile::~PDBFile() = default;
476b6b8c4fSAdrian McCarthy 
487b327d05SZachary Turner StringRef PDBFile::getFilePath() const { return FilePath; }
497b327d05SZachary Turner 
507b327d05SZachary Turner StringRef PDBFile::getFileDirectory() const {
517b327d05SZachary Turner   return sys::path::parent_path(FilePath);
527b327d05SZachary Turner }
537b327d05SZachary Turner 
546b6b8c4fSAdrian McCarthy uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
556b6b8c4fSAdrian McCarthy 
566b6b8c4fSAdrian McCarthy uint32_t PDBFile::getFreeBlockMapBlock() const {
576b6b8c4fSAdrian McCarthy   return ContainerLayout.SB->FreeBlockMapBlock;
586b6b8c4fSAdrian McCarthy }
596b6b8c4fSAdrian McCarthy 
606b6b8c4fSAdrian McCarthy uint32_t PDBFile::getBlockCount() const {
616b6b8c4fSAdrian McCarthy   return ContainerLayout.SB->NumBlocks;
626b6b8c4fSAdrian McCarthy }
636b6b8c4fSAdrian McCarthy 
646b6b8c4fSAdrian McCarthy uint32_t PDBFile::getNumDirectoryBytes() const {
656b6b8c4fSAdrian McCarthy   return ContainerLayout.SB->NumDirectoryBytes;
666b6b8c4fSAdrian McCarthy }
676b6b8c4fSAdrian McCarthy 
686b6b8c4fSAdrian McCarthy uint32_t PDBFile::getBlockMapIndex() const {
696b6b8c4fSAdrian McCarthy   return ContainerLayout.SB->BlockMapAddr;
706b6b8c4fSAdrian McCarthy }
716b6b8c4fSAdrian McCarthy 
726b6b8c4fSAdrian McCarthy uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
736b6b8c4fSAdrian McCarthy 
746b6b8c4fSAdrian McCarthy uint32_t PDBFile::getNumDirectoryBlocks() const {
756b6b8c4fSAdrian McCarthy   return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
766b6b8c4fSAdrian McCarthy                             ContainerLayout.SB->BlockSize);
776b6b8c4fSAdrian McCarthy }
786b6b8c4fSAdrian McCarthy 
796b6b8c4fSAdrian McCarthy uint64_t PDBFile::getBlockMapOffset() const {
806b6b8c4fSAdrian McCarthy   return (uint64_t)ContainerLayout.SB->BlockMapAddr *
816b6b8c4fSAdrian McCarthy          ContainerLayout.SB->BlockSize;
826b6b8c4fSAdrian McCarthy }
836b6b8c4fSAdrian McCarthy 
846b6b8c4fSAdrian McCarthy uint32_t PDBFile::getNumStreams() const {
856b6b8c4fSAdrian McCarthy   return ContainerLayout.StreamSizes.size();
866b6b8c4fSAdrian McCarthy }
876b6b8c4fSAdrian McCarthy 
88d1de2f4fSZachary Turner uint32_t PDBFile::getMaxStreamSize() const {
89d1de2f4fSZachary Turner   return *std::max_element(ContainerLayout.StreamSizes.begin(),
90d1de2f4fSZachary Turner                            ContainerLayout.StreamSizes.end());
91d1de2f4fSZachary Turner }
92d1de2f4fSZachary Turner 
936b6b8c4fSAdrian McCarthy uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
946b6b8c4fSAdrian McCarthy   return ContainerLayout.StreamSizes[StreamIndex];
956b6b8c4fSAdrian McCarthy }
966b6b8c4fSAdrian McCarthy 
976b6b8c4fSAdrian McCarthy ArrayRef<support::ulittle32_t>
986b6b8c4fSAdrian McCarthy PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
996b6b8c4fSAdrian McCarthy   return ContainerLayout.StreamMap[StreamIndex];
1006b6b8c4fSAdrian McCarthy }
1016b6b8c4fSAdrian McCarthy 
1026b6b8c4fSAdrian McCarthy uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
1036b6b8c4fSAdrian McCarthy 
1046b6b8c4fSAdrian McCarthy Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
1056b6b8c4fSAdrian McCarthy                                                   uint32_t NumBytes) const {
1066b6b8c4fSAdrian McCarthy   uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
1076b6b8c4fSAdrian McCarthy 
1086b6b8c4fSAdrian McCarthy   ArrayRef<uint8_t> Result;
1096b6b8c4fSAdrian McCarthy   if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
1106b6b8c4fSAdrian McCarthy     return std::move(EC);
1116b6b8c4fSAdrian McCarthy   return Result;
1126b6b8c4fSAdrian McCarthy }
1136b6b8c4fSAdrian McCarthy 
1146b6b8c4fSAdrian McCarthy Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
1156b6b8c4fSAdrian McCarthy                             ArrayRef<uint8_t> Data) const {
1166b6b8c4fSAdrian McCarthy   return make_error<RawError>(raw_error_code::not_writable,
1176b6b8c4fSAdrian McCarthy                               "PDBFile is immutable");
1186b6b8c4fSAdrian McCarthy }
1196b6b8c4fSAdrian McCarthy 
1206b6b8c4fSAdrian McCarthy Error PDBFile::parseFileHeaders() {
121120faca4SZachary Turner   BinaryStreamReader Reader(*Buffer);
1226b6b8c4fSAdrian McCarthy 
1236b6b8c4fSAdrian McCarthy   // Initialize SB.
1246b6b8c4fSAdrian McCarthy   const msf::SuperBlock *SB = nullptr;
1256b6b8c4fSAdrian McCarthy   if (auto EC = Reader.readObject(SB)) {
1266b6b8c4fSAdrian McCarthy     consumeError(std::move(EC));
1276b6b8c4fSAdrian McCarthy     return make_error<RawError>(raw_error_code::corrupt_file,
1286b6b8c4fSAdrian McCarthy                                 "Does not contain superblock");
1296b6b8c4fSAdrian McCarthy   }
1306b6b8c4fSAdrian McCarthy 
1316b6b8c4fSAdrian McCarthy   if (auto EC = msf::validateSuperBlock(*SB))
1326b6b8c4fSAdrian McCarthy     return EC;
1336b6b8c4fSAdrian McCarthy 
1346b6b8c4fSAdrian McCarthy   if (Buffer->getLength() % SB->BlockSize != 0)
1356b6b8c4fSAdrian McCarthy     return make_error<RawError>(raw_error_code::corrupt_file,
1366b6b8c4fSAdrian McCarthy                                 "File size is not a multiple of block size");
1376b6b8c4fSAdrian McCarthy   ContainerLayout.SB = SB;
1386b6b8c4fSAdrian McCarthy 
1396b6b8c4fSAdrian McCarthy   // Initialize Free Page Map.
1406b6b8c4fSAdrian McCarthy   ContainerLayout.FreePageMap.resize(SB->NumBlocks);
1416b6b8c4fSAdrian McCarthy   // The Fpm exists either at block 1 or block 2 of the MSF.  However, this
1426b6b8c4fSAdrian McCarthy   // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
1436b6b8c4fSAdrian McCarthy   // thusly an equal number of total blocks in the file.  For a block size
1446b6b8c4fSAdrian McCarthy   // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
1456b6b8c4fSAdrian McCarthy   // maximum file size of 32KiB * 4KiB = 128MiB.  Obviously this won't do, so
1466b6b8c4fSAdrian McCarthy   // the Fpm is split across the file at `getBlockSize()` intervals.  As a
1476b6b8c4fSAdrian McCarthy   // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
1486b6b8c4fSAdrian McCarthy   // for any non-negative integer k is an Fpm block.  In theory, we only really
1496b6b8c4fSAdrian McCarthy   // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
1506b6b8c4fSAdrian McCarthy   // current versions of the MSF format already expect the Fpm to be arranged
1516b6b8c4fSAdrian McCarthy   // at getBlockSize() intervals, so we have to be compatible.
1526b6b8c4fSAdrian McCarthy   // See the function fpmPn() for more information:
1536b6b8c4fSAdrian McCarthy   // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
1545b74ff33SZachary Turner   auto FpmStream =
1555b74ff33SZachary Turner       MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
156120faca4SZachary Turner   BinaryStreamReader FpmReader(*FpmStream);
1576b6b8c4fSAdrian McCarthy   ArrayRef<uint8_t> FpmBytes;
1589fb9d71dSZachary Turner   if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
1596b6b8c4fSAdrian McCarthy     return EC;
1606b6b8c4fSAdrian McCarthy   uint32_t BlocksRemaining = getBlockCount();
1616b6b8c4fSAdrian McCarthy   uint32_t BI = 0;
1626b6b8c4fSAdrian McCarthy   for (auto Byte : FpmBytes) {
1636b6b8c4fSAdrian McCarthy     uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
1646b6b8c4fSAdrian McCarthy     for (uint32_t I = 0; I < BlocksThisByte; ++I) {
1656b6b8c4fSAdrian McCarthy       if (Byte & (1 << I))
1666b6b8c4fSAdrian McCarthy         ContainerLayout.FreePageMap[BI] = true;
1676b6b8c4fSAdrian McCarthy       --BlocksRemaining;
1686b6b8c4fSAdrian McCarthy       ++BI;
1696b6b8c4fSAdrian McCarthy     }
1706b6b8c4fSAdrian McCarthy   }
1716b6b8c4fSAdrian McCarthy 
1726b6b8c4fSAdrian McCarthy   Reader.setOffset(getBlockMapOffset());
1736b6b8c4fSAdrian McCarthy   if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
1746b6b8c4fSAdrian McCarthy                                  getNumDirectoryBlocks()))
1756b6b8c4fSAdrian McCarthy     return EC;
1766b6b8c4fSAdrian McCarthy 
1776b6b8c4fSAdrian McCarthy   return Error::success();
1786b6b8c4fSAdrian McCarthy }
1796b6b8c4fSAdrian McCarthy 
1806b6b8c4fSAdrian McCarthy Error PDBFile::parseStreamData() {
1816b6b8c4fSAdrian McCarthy   assert(ContainerLayout.SB);
1826b6b8c4fSAdrian McCarthy   if (DirectoryStream)
1836b6b8c4fSAdrian McCarthy     return Error::success();
1846b6b8c4fSAdrian McCarthy 
1856b6b8c4fSAdrian McCarthy   uint32_t NumStreams = 0;
1866b6b8c4fSAdrian McCarthy 
1876b6b8c4fSAdrian McCarthy   // Normally you can't use a MappedBlockStream without having fully parsed the
1886b6b8c4fSAdrian McCarthy   // PDB file, because it accesses the directory and various other things, which
1896b6b8c4fSAdrian McCarthy   // is exactly what we are attempting to parse.  By specifying a custom
1906b6b8c4fSAdrian McCarthy   // subclass of IPDBStreamData which only accesses the fields that have already
1916b6b8c4fSAdrian McCarthy   // been parsed, we can avoid this and reuse MappedBlockStream.
1925b74ff33SZachary Turner   auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer,
1935b74ff33SZachary Turner                                                      Allocator);
194120faca4SZachary Turner   BinaryStreamReader Reader(*DS);
195695ed56bSZachary Turner   if (auto EC = Reader.readInteger(NumStreams))
1966b6b8c4fSAdrian McCarthy     return EC;
1976b6b8c4fSAdrian McCarthy 
1986b6b8c4fSAdrian McCarthy   if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
1996b6b8c4fSAdrian McCarthy     return EC;
2006b6b8c4fSAdrian McCarthy   for (uint32_t I = 0; I < NumStreams; ++I) {
2016b6b8c4fSAdrian McCarthy     uint32_t StreamSize = getStreamByteSize(I);
2026b6b8c4fSAdrian McCarthy     // FIXME: What does StreamSize ~0U mean?
2036b6b8c4fSAdrian McCarthy     uint64_t NumExpectedStreamBlocks =
2046b6b8c4fSAdrian McCarthy         StreamSize == UINT32_MAX
2056b6b8c4fSAdrian McCarthy             ? 0
2066b6b8c4fSAdrian McCarthy             : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
2076b6b8c4fSAdrian McCarthy 
2086b6b8c4fSAdrian McCarthy     // For convenience, we store the block array contiguously.  This is because
2096b6b8c4fSAdrian McCarthy     // if someone calls setStreamMap(), it is more convenient to be able to call
2106b6b8c4fSAdrian McCarthy     // it with an ArrayRef instead of setting up a StreamRef.  Since the
2116b6b8c4fSAdrian McCarthy     // DirectoryStream is cached in the class and thus lives for the life of the
2126b6b8c4fSAdrian McCarthy     // class, we can be guaranteed that readArray() will return a stable
2136b6b8c4fSAdrian McCarthy     // reference, even if it has to allocate from its internal pool.
2146b6b8c4fSAdrian McCarthy     ArrayRef<support::ulittle32_t> Blocks;
2156b6b8c4fSAdrian McCarthy     if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
2166b6b8c4fSAdrian McCarthy       return EC;
2176b6b8c4fSAdrian McCarthy     for (uint32_t Block : Blocks) {
2186b6b8c4fSAdrian McCarthy       uint64_t BlockEndOffset =
2196b6b8c4fSAdrian McCarthy           (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
2206b6b8c4fSAdrian McCarthy       if (BlockEndOffset > getFileSize())
2216b6b8c4fSAdrian McCarthy         return make_error<RawError>(raw_error_code::corrupt_file,
2226b6b8c4fSAdrian McCarthy                                     "Stream block map is corrupt.");
2236b6b8c4fSAdrian McCarthy     }
2246b6b8c4fSAdrian McCarthy     ContainerLayout.StreamMap.push_back(Blocks);
2256b6b8c4fSAdrian McCarthy   }
2266b6b8c4fSAdrian McCarthy 
2276b6b8c4fSAdrian McCarthy   // We should have read exactly SB->NumDirectoryBytes bytes.
2286b6b8c4fSAdrian McCarthy   assert(Reader.bytesRemaining() == 0);
2296b6b8c4fSAdrian McCarthy   DirectoryStream = std::move(DS);
2306b6b8c4fSAdrian McCarthy   return Error::success();
2316b6b8c4fSAdrian McCarthy }
2326b6b8c4fSAdrian McCarthy 
2336b6b8c4fSAdrian McCarthy ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
2346b6b8c4fSAdrian McCarthy   return ContainerLayout.DirectoryBlocks;
2356b6b8c4fSAdrian McCarthy }
2366b6b8c4fSAdrian McCarthy 
237d1de2f4fSZachary Turner std::unique_ptr<MappedBlockStream> PDBFile::createIndexedStream(uint16_t SN) {
238d1de2f4fSZachary Turner   if (SN == kInvalidStreamIndex)
239d1de2f4fSZachary Turner     return nullptr;
240d1de2f4fSZachary Turner   return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
241d1de2f4fSZachary Turner                                                 Allocator);
242d1de2f4fSZachary Turner }
243d1de2f4fSZachary Turner 
2440b36c3ebSZachary Turner MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
2450b36c3ebSZachary Turner   MSFStreamLayout Result;
2460b36c3ebSZachary Turner   auto Blocks = getStreamBlockList(StreamIdx);
2470b36c3ebSZachary Turner   Result.Blocks.assign(Blocks.begin(), Blocks.end());
2480b36c3ebSZachary Turner   Result.Length = getStreamByteSize(StreamIdx);
2490b36c3ebSZachary Turner   return Result;
2500b36c3ebSZachary Turner }
2510b36c3ebSZachary Turner 
252c3d8eec9SZachary Turner msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const {
253c3d8eec9SZachary Turner   return msf::getFpmStreamLayout(ContainerLayout);
254c3d8eec9SZachary Turner }
255c3d8eec9SZachary Turner 
2566b6b8c4fSAdrian McCarthy Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
2576b6b8c4fSAdrian McCarthy   if (!Globals) {
2586b6b8c4fSAdrian McCarthy     auto DbiS = getPDBDbiStream();
2596b6b8c4fSAdrian McCarthy     if (!DbiS)
2606b6b8c4fSAdrian McCarthy       return DbiS.takeError();
2616b6b8c4fSAdrian McCarthy 
2626b6b8c4fSAdrian McCarthy     auto GlobalS = safelyCreateIndexedStream(
2636b6b8c4fSAdrian McCarthy         ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex());
2646b6b8c4fSAdrian McCarthy     if (!GlobalS)
2656b6b8c4fSAdrian McCarthy       return GlobalS.takeError();
2666b6b8c4fSAdrian McCarthy     auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS));
2676b6b8c4fSAdrian McCarthy     if (auto EC = TempGlobals->reload())
2686b6b8c4fSAdrian McCarthy       return std::move(EC);
2696b6b8c4fSAdrian McCarthy     Globals = std::move(TempGlobals);
2706b6b8c4fSAdrian McCarthy   }
2716b6b8c4fSAdrian McCarthy   return *Globals;
2726b6b8c4fSAdrian McCarthy }
2736b6b8c4fSAdrian McCarthy 
2746b6b8c4fSAdrian McCarthy Expected<InfoStream &> PDBFile::getPDBInfoStream() {
2756b6b8c4fSAdrian McCarthy   if (!Info) {
2766b6b8c4fSAdrian McCarthy     auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB);
2776b6b8c4fSAdrian McCarthy     if (!InfoS)
2786b6b8c4fSAdrian McCarthy       return InfoS.takeError();
2796b6b8c4fSAdrian McCarthy     auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
2806b6b8c4fSAdrian McCarthy     if (auto EC = TempInfo->reload())
2816b6b8c4fSAdrian McCarthy       return std::move(EC);
2826b6b8c4fSAdrian McCarthy     Info = std::move(TempInfo);
2836b6b8c4fSAdrian McCarthy   }
2846b6b8c4fSAdrian McCarthy   return *Info;
2856b6b8c4fSAdrian McCarthy }
2866b6b8c4fSAdrian McCarthy 
2876b6b8c4fSAdrian McCarthy Expected<DbiStream &> PDBFile::getPDBDbiStream() {
2886b6b8c4fSAdrian McCarthy   if (!Dbi) {
2896b6b8c4fSAdrian McCarthy     auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI);
2906b6b8c4fSAdrian McCarthy     if (!DbiS)
2916b6b8c4fSAdrian McCarthy       return DbiS.takeError();
292*15b2bdfdSZachary Turner     auto TempDbi = llvm::make_unique<DbiStream>(std::move(*DbiS));
293*15b2bdfdSZachary Turner     if (auto EC = TempDbi->reload(this))
2946b6b8c4fSAdrian McCarthy       return std::move(EC);
2956b6b8c4fSAdrian McCarthy     Dbi = std::move(TempDbi);
2966b6b8c4fSAdrian McCarthy   }
2976b6b8c4fSAdrian McCarthy   return *Dbi;
2986b6b8c4fSAdrian McCarthy }
2996b6b8c4fSAdrian McCarthy 
3006b6b8c4fSAdrian McCarthy Expected<TpiStream &> PDBFile::getPDBTpiStream() {
3016b6b8c4fSAdrian McCarthy   if (!Tpi) {
3026b6b8c4fSAdrian McCarthy     auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI);
3036b6b8c4fSAdrian McCarthy     if (!TpiS)
3046b6b8c4fSAdrian McCarthy       return TpiS.takeError();
3056b6b8c4fSAdrian McCarthy     auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
3066b6b8c4fSAdrian McCarthy     if (auto EC = TempTpi->reload())
3076b6b8c4fSAdrian McCarthy       return std::move(EC);
3086b6b8c4fSAdrian McCarthy     Tpi = std::move(TempTpi);
3096b6b8c4fSAdrian McCarthy   }
3106b6b8c4fSAdrian McCarthy   return *Tpi;
3116b6b8c4fSAdrian McCarthy }
3126b6b8c4fSAdrian McCarthy 
3136b6b8c4fSAdrian McCarthy Expected<TpiStream &> PDBFile::getPDBIpiStream() {
3146b6b8c4fSAdrian McCarthy   if (!Ipi) {
315abb17cc0SZachary Turner     if (!hasPDBIpiStream())
316abb17cc0SZachary Turner       return make_error<RawError>(raw_error_code::no_stream);
317abb17cc0SZachary Turner 
3186b6b8c4fSAdrian McCarthy     auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI);
3196b6b8c4fSAdrian McCarthy     if (!IpiS)
3206b6b8c4fSAdrian McCarthy       return IpiS.takeError();
3216b6b8c4fSAdrian McCarthy     auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
3226b6b8c4fSAdrian McCarthy     if (auto EC = TempIpi->reload())
3236b6b8c4fSAdrian McCarthy       return std::move(EC);
3246b6b8c4fSAdrian McCarthy     Ipi = std::move(TempIpi);
3256b6b8c4fSAdrian McCarthy   }
3266b6b8c4fSAdrian McCarthy   return *Ipi;
3276b6b8c4fSAdrian McCarthy }
3286b6b8c4fSAdrian McCarthy 
3296b6b8c4fSAdrian McCarthy Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
3306b6b8c4fSAdrian McCarthy   if (!Publics) {
3316b6b8c4fSAdrian McCarthy     auto DbiS = getPDBDbiStream();
3326b6b8c4fSAdrian McCarthy     if (!DbiS)
3336b6b8c4fSAdrian McCarthy       return DbiS.takeError();
3346b6b8c4fSAdrian McCarthy 
3356b6b8c4fSAdrian McCarthy     auto PublicS = safelyCreateIndexedStream(
3366b6b8c4fSAdrian McCarthy         ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex());
3376b6b8c4fSAdrian McCarthy     if (!PublicS)
3386b6b8c4fSAdrian McCarthy       return PublicS.takeError();
33914d90fd0SReid Kleckner     auto TempPublics = llvm::make_unique<PublicsStream>(std::move(*PublicS));
3406b6b8c4fSAdrian McCarthy     if (auto EC = TempPublics->reload())
3416b6b8c4fSAdrian McCarthy       return std::move(EC);
3426b6b8c4fSAdrian McCarthy     Publics = std::move(TempPublics);
3436b6b8c4fSAdrian McCarthy   }
3446b6b8c4fSAdrian McCarthy   return *Publics;
3456b6b8c4fSAdrian McCarthy }
3466b6b8c4fSAdrian McCarthy 
3476b6b8c4fSAdrian McCarthy Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
3486b6b8c4fSAdrian McCarthy   if (!Symbols) {
3496b6b8c4fSAdrian McCarthy     auto DbiS = getPDBDbiStream();
3506b6b8c4fSAdrian McCarthy     if (!DbiS)
3516b6b8c4fSAdrian McCarthy       return DbiS.takeError();
3526b6b8c4fSAdrian McCarthy 
3536b6b8c4fSAdrian McCarthy     uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
3546b6b8c4fSAdrian McCarthy     auto SymbolS =
3556b6b8c4fSAdrian McCarthy         safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum);
3566b6b8c4fSAdrian McCarthy     if (!SymbolS)
3576b6b8c4fSAdrian McCarthy       return SymbolS.takeError();
3586b6b8c4fSAdrian McCarthy 
3596b6b8c4fSAdrian McCarthy     auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
3606b6b8c4fSAdrian McCarthy     if (auto EC = TempSymbols->reload())
3616b6b8c4fSAdrian McCarthy       return std::move(EC);
3626b6b8c4fSAdrian McCarthy     Symbols = std::move(TempSymbols);
3636b6b8c4fSAdrian McCarthy   }
3646b6b8c4fSAdrian McCarthy   return *Symbols;
3656b6b8c4fSAdrian McCarthy }
3666b6b8c4fSAdrian McCarthy 
367e204a6c9SZachary Turner Expected<PDBStringTable &> PDBFile::getStringTable() {
368c504ae3cSZachary Turner   if (!Strings) {
3696b6b8c4fSAdrian McCarthy     auto IS = getPDBInfoStream();
3706b6b8c4fSAdrian McCarthy     if (!IS)
3716b6b8c4fSAdrian McCarthy       return IS.takeError();
3726b6b8c4fSAdrian McCarthy 
373d11328a1SZachary Turner     Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
374d11328a1SZachary Turner     if (!ExpectedNSI)
375d11328a1SZachary Turner       return ExpectedNSI.takeError();
376d11328a1SZachary Turner     uint32_t NameStreamIndex = *ExpectedNSI;
3776b6b8c4fSAdrian McCarthy 
3786b6b8c4fSAdrian McCarthy     auto NS =
3796b6b8c4fSAdrian McCarthy         safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex);
3806b6b8c4fSAdrian McCarthy     if (!NS)
3816b6b8c4fSAdrian McCarthy       return NS.takeError();
3826b6b8c4fSAdrian McCarthy 
383dff096f2SDaniel Jasper     auto N = llvm::make_unique<PDBStringTable>();
384c504ae3cSZachary Turner     BinaryStreamReader Reader(**NS);
385c504ae3cSZachary Turner     if (auto EC = N->reload(Reader))
3866b6b8c4fSAdrian McCarthy       return std::move(EC);
387c504ae3cSZachary Turner     assert(Reader.bytesRemaining() == 0);
388c504ae3cSZachary Turner     StringTableStream = std::move(*NS);
3896b6b8c4fSAdrian McCarthy     Strings = std::move(N);
3906b6b8c4fSAdrian McCarthy   }
3916b6b8c4fSAdrian McCarthy   return *Strings;
3926b6b8c4fSAdrian McCarthy }
3936b6b8c4fSAdrian McCarthy 
3944e950647SZachary Turner uint32_t PDBFile::getPointerSize() {
3954e950647SZachary Turner   auto DbiS = getPDBDbiStream();
3964e950647SZachary Turner   if (!DbiS)
3974e950647SZachary Turner     return 0;
3984e950647SZachary Turner   PDB_Machine Machine = DbiS->getMachineType();
3994e950647SZachary Turner   if (Machine == PDB_Machine::Amd64)
4004e950647SZachary Turner     return 8;
4014e950647SZachary Turner   return 4;
4024e950647SZachary Turner }
4034e950647SZachary Turner 
4046b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBDbiStream() const { return StreamDBI < getNumStreams(); }
4056b6b8c4fSAdrian McCarthy 
4066b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBGlobalsStream() {
4076b6b8c4fSAdrian McCarthy   auto DbiS = getPDBDbiStream();
408c1e93e5fSZachary Turner   if (!DbiS) {
409c1e93e5fSZachary Turner     consumeError(DbiS.takeError());
4106b6b8c4fSAdrian McCarthy     return false;
411c1e93e5fSZachary Turner   }
412c1e93e5fSZachary Turner 
4136b6b8c4fSAdrian McCarthy   return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
4146b6b8c4fSAdrian McCarthy }
4156b6b8c4fSAdrian McCarthy 
416abb17cc0SZachary Turner bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); }
4176b6b8c4fSAdrian McCarthy 
418abb17cc0SZachary Turner bool PDBFile::hasPDBIpiStream() const {
419abb17cc0SZachary Turner   if (!hasPDBInfoStream())
420abb17cc0SZachary Turner     return false;
421abb17cc0SZachary Turner 
422abb17cc0SZachary Turner   if (StreamIPI >= getNumStreams())
423abb17cc0SZachary Turner     return false;
424abb17cc0SZachary Turner 
425abb17cc0SZachary Turner   auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
426abb17cc0SZachary Turner   return InfoStream.containsIdStream();
427abb17cc0SZachary Turner }
4286b6b8c4fSAdrian McCarthy 
4296b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBPublicsStream() {
4306b6b8c4fSAdrian McCarthy   auto DbiS = getPDBDbiStream();
431c1e93e5fSZachary Turner   if (!DbiS) {
432c1e93e5fSZachary Turner     consumeError(DbiS.takeError());
4336b6b8c4fSAdrian McCarthy     return false;
434c1e93e5fSZachary Turner   }
4356b6b8c4fSAdrian McCarthy   return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
4366b6b8c4fSAdrian McCarthy }
4376b6b8c4fSAdrian McCarthy 
4386b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBSymbolStream() {
4396b6b8c4fSAdrian McCarthy   auto DbiS = getPDBDbiStream();
4406b6b8c4fSAdrian McCarthy   if (!DbiS)
4416b6b8c4fSAdrian McCarthy     return false;
4426b6b8c4fSAdrian McCarthy   return DbiS->getSymRecordStreamIndex() < getNumStreams();
4436b6b8c4fSAdrian McCarthy }
4446b6b8c4fSAdrian McCarthy 
4456b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
4466b6b8c4fSAdrian McCarthy 
447e204a6c9SZachary Turner bool PDBFile::hasPDBStringTable() {
4486b6b8c4fSAdrian McCarthy   auto IS = getPDBInfoStream();
4496b6b8c4fSAdrian McCarthy   if (!IS)
4506b6b8c4fSAdrian McCarthy     return false;
451d11328a1SZachary Turner   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
452d11328a1SZachary Turner   if (!ExpectedNSI) {
453d11328a1SZachary Turner     consumeError(ExpectedNSI.takeError());
454d11328a1SZachary Turner     return false;
455d11328a1SZachary Turner   }
456d11328a1SZachary Turner   assert(*ExpectedNSI < getNumStreams());
457d11328a1SZachary Turner   return true;
4586b6b8c4fSAdrian McCarthy }
4596b6b8c4fSAdrian McCarthy 
460d0b44fa7SZachary Turner /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
461d0b44fa7SZachary Turner /// stream with that index actually exists.  If it does not, the return value
462d0b44fa7SZachary Turner /// will have an MSFError with code msf_error_code::no_stream.  Else, the return
463d0b44fa7SZachary Turner /// value will contain the stream returned by createIndexedStream().
4646b6b8c4fSAdrian McCarthy Expected<std::unique_ptr<MappedBlockStream>>
4656b6b8c4fSAdrian McCarthy PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout,
466120faca4SZachary Turner                                    BinaryStreamRef MsfData,
4676b6b8c4fSAdrian McCarthy                                    uint32_t StreamIndex) const {
4686b6b8c4fSAdrian McCarthy   if (StreamIndex >= getNumStreams())
4696b6b8c4fSAdrian McCarthy     return make_error<RawError>(raw_error_code::no_stream);
4705b74ff33SZachary Turner   return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex,
4715b74ff33SZachary Turner                                                 Allocator);
4726b6b8c4fSAdrian McCarthy }
473