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 
886b6b8c4fSAdrian McCarthy uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
896b6b8c4fSAdrian McCarthy   return ContainerLayout.StreamSizes[StreamIndex];
906b6b8c4fSAdrian McCarthy }
916b6b8c4fSAdrian McCarthy 
926b6b8c4fSAdrian McCarthy ArrayRef<support::ulittle32_t>
936b6b8c4fSAdrian McCarthy PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
946b6b8c4fSAdrian McCarthy   return ContainerLayout.StreamMap[StreamIndex];
956b6b8c4fSAdrian McCarthy }
966b6b8c4fSAdrian McCarthy 
976b6b8c4fSAdrian McCarthy uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
986b6b8c4fSAdrian McCarthy 
996b6b8c4fSAdrian McCarthy Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
1006b6b8c4fSAdrian McCarthy                                                   uint32_t NumBytes) const {
1016b6b8c4fSAdrian McCarthy   uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
1026b6b8c4fSAdrian McCarthy 
1036b6b8c4fSAdrian McCarthy   ArrayRef<uint8_t> Result;
1046b6b8c4fSAdrian McCarthy   if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
1056b6b8c4fSAdrian McCarthy     return std::move(EC);
1066b6b8c4fSAdrian McCarthy   return Result;
1076b6b8c4fSAdrian McCarthy }
1086b6b8c4fSAdrian McCarthy 
1096b6b8c4fSAdrian McCarthy Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
1106b6b8c4fSAdrian McCarthy                             ArrayRef<uint8_t> Data) const {
1116b6b8c4fSAdrian McCarthy   return make_error<RawError>(raw_error_code::not_writable,
1126b6b8c4fSAdrian McCarthy                               "PDBFile is immutable");
1136b6b8c4fSAdrian McCarthy }
1146b6b8c4fSAdrian McCarthy 
1156b6b8c4fSAdrian McCarthy Error PDBFile::parseFileHeaders() {
116120faca4SZachary Turner   BinaryStreamReader Reader(*Buffer);
1176b6b8c4fSAdrian McCarthy 
1186b6b8c4fSAdrian McCarthy   // Initialize SB.
1196b6b8c4fSAdrian McCarthy   const msf::SuperBlock *SB = nullptr;
1206b6b8c4fSAdrian McCarthy   if (auto EC = Reader.readObject(SB)) {
1216b6b8c4fSAdrian McCarthy     consumeError(std::move(EC));
1226b6b8c4fSAdrian McCarthy     return make_error<RawError>(raw_error_code::corrupt_file,
1236b6b8c4fSAdrian McCarthy                                 "Does not contain superblock");
1246b6b8c4fSAdrian McCarthy   }
1256b6b8c4fSAdrian McCarthy 
1266b6b8c4fSAdrian McCarthy   if (auto EC = msf::validateSuperBlock(*SB))
1276b6b8c4fSAdrian McCarthy     return EC;
1286b6b8c4fSAdrian McCarthy 
1296b6b8c4fSAdrian McCarthy   if (Buffer->getLength() % SB->BlockSize != 0)
1306b6b8c4fSAdrian McCarthy     return make_error<RawError>(raw_error_code::corrupt_file,
1316b6b8c4fSAdrian McCarthy                                 "File size is not a multiple of block size");
1326b6b8c4fSAdrian McCarthy   ContainerLayout.SB = SB;
1336b6b8c4fSAdrian McCarthy 
1346b6b8c4fSAdrian McCarthy   // Initialize Free Page Map.
1356b6b8c4fSAdrian McCarthy   ContainerLayout.FreePageMap.resize(SB->NumBlocks);
1366b6b8c4fSAdrian McCarthy   // The Fpm exists either at block 1 or block 2 of the MSF.  However, this
1376b6b8c4fSAdrian McCarthy   // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
1386b6b8c4fSAdrian McCarthy   // thusly an equal number of total blocks in the file.  For a block size
1396b6b8c4fSAdrian McCarthy   // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
1406b6b8c4fSAdrian McCarthy   // maximum file size of 32KiB * 4KiB = 128MiB.  Obviously this won't do, so
1416b6b8c4fSAdrian McCarthy   // the Fpm is split across the file at `getBlockSize()` intervals.  As a
1426b6b8c4fSAdrian McCarthy   // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
1436b6b8c4fSAdrian McCarthy   // for any non-negative integer k is an Fpm block.  In theory, we only really
1446b6b8c4fSAdrian McCarthy   // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
1456b6b8c4fSAdrian McCarthy   // current versions of the MSF format already expect the Fpm to be arranged
1466b6b8c4fSAdrian McCarthy   // at getBlockSize() intervals, so we have to be compatible.
1476b6b8c4fSAdrian McCarthy   // See the function fpmPn() for more information:
1486b6b8c4fSAdrian McCarthy   // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
1496b6b8c4fSAdrian McCarthy   auto FpmStream = MappedBlockStream::createFpmStream(ContainerLayout, *Buffer);
150120faca4SZachary Turner   BinaryStreamReader FpmReader(*FpmStream);
1516b6b8c4fSAdrian McCarthy   ArrayRef<uint8_t> FpmBytes;
1526b6b8c4fSAdrian McCarthy   if (auto EC = FpmReader.readBytes(FpmBytes,
1536b6b8c4fSAdrian McCarthy                                     msf::getFullFpmByteSize(ContainerLayout)))
1546b6b8c4fSAdrian McCarthy     return EC;
1556b6b8c4fSAdrian McCarthy   uint32_t BlocksRemaining = getBlockCount();
1566b6b8c4fSAdrian McCarthy   uint32_t BI = 0;
1576b6b8c4fSAdrian McCarthy   for (auto Byte : FpmBytes) {
1586b6b8c4fSAdrian McCarthy     uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
1596b6b8c4fSAdrian McCarthy     for (uint32_t I = 0; I < BlocksThisByte; ++I) {
1606b6b8c4fSAdrian McCarthy       if (Byte & (1 << I))
1616b6b8c4fSAdrian McCarthy         ContainerLayout.FreePageMap[BI] = true;
1626b6b8c4fSAdrian McCarthy       --BlocksRemaining;
1636b6b8c4fSAdrian McCarthy       ++BI;
1646b6b8c4fSAdrian McCarthy     }
1656b6b8c4fSAdrian McCarthy   }
1666b6b8c4fSAdrian McCarthy 
1676b6b8c4fSAdrian McCarthy   Reader.setOffset(getBlockMapOffset());
1686b6b8c4fSAdrian McCarthy   if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
1696b6b8c4fSAdrian McCarthy                                  getNumDirectoryBlocks()))
1706b6b8c4fSAdrian McCarthy     return EC;
1716b6b8c4fSAdrian McCarthy 
1726b6b8c4fSAdrian McCarthy   return Error::success();
1736b6b8c4fSAdrian McCarthy }
1746b6b8c4fSAdrian McCarthy 
1756b6b8c4fSAdrian McCarthy Error PDBFile::parseStreamData() {
1766b6b8c4fSAdrian McCarthy   assert(ContainerLayout.SB);
1776b6b8c4fSAdrian McCarthy   if (DirectoryStream)
1786b6b8c4fSAdrian McCarthy     return Error::success();
1796b6b8c4fSAdrian McCarthy 
1806b6b8c4fSAdrian McCarthy   uint32_t NumStreams = 0;
1816b6b8c4fSAdrian McCarthy 
1826b6b8c4fSAdrian McCarthy   // Normally you can't use a MappedBlockStream without having fully parsed the
1836b6b8c4fSAdrian McCarthy   // PDB file, because it accesses the directory and various other things, which
1846b6b8c4fSAdrian McCarthy   // is exactly what we are attempting to parse.  By specifying a custom
1856b6b8c4fSAdrian McCarthy   // subclass of IPDBStreamData which only accesses the fields that have already
1866b6b8c4fSAdrian McCarthy   // been parsed, we can avoid this and reuse MappedBlockStream.
1876b6b8c4fSAdrian McCarthy   auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer);
188120faca4SZachary Turner   BinaryStreamReader Reader(*DS);
189695ed56bSZachary Turner   if (auto EC = Reader.readInteger(NumStreams))
1906b6b8c4fSAdrian McCarthy     return EC;
1916b6b8c4fSAdrian McCarthy 
1926b6b8c4fSAdrian McCarthy   if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
1936b6b8c4fSAdrian McCarthy     return EC;
1946b6b8c4fSAdrian McCarthy   for (uint32_t I = 0; I < NumStreams; ++I) {
1956b6b8c4fSAdrian McCarthy     uint32_t StreamSize = getStreamByteSize(I);
1966b6b8c4fSAdrian McCarthy     // FIXME: What does StreamSize ~0U mean?
1976b6b8c4fSAdrian McCarthy     uint64_t NumExpectedStreamBlocks =
1986b6b8c4fSAdrian McCarthy         StreamSize == UINT32_MAX
1996b6b8c4fSAdrian McCarthy             ? 0
2006b6b8c4fSAdrian McCarthy             : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
2016b6b8c4fSAdrian McCarthy 
2026b6b8c4fSAdrian McCarthy     // For convenience, we store the block array contiguously.  This is because
2036b6b8c4fSAdrian McCarthy     // if someone calls setStreamMap(), it is more convenient to be able to call
2046b6b8c4fSAdrian McCarthy     // it with an ArrayRef instead of setting up a StreamRef.  Since the
2056b6b8c4fSAdrian McCarthy     // DirectoryStream is cached in the class and thus lives for the life of the
2066b6b8c4fSAdrian McCarthy     // class, we can be guaranteed that readArray() will return a stable
2076b6b8c4fSAdrian McCarthy     // reference, even if it has to allocate from its internal pool.
2086b6b8c4fSAdrian McCarthy     ArrayRef<support::ulittle32_t> Blocks;
2096b6b8c4fSAdrian McCarthy     if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
2106b6b8c4fSAdrian McCarthy       return EC;
2116b6b8c4fSAdrian McCarthy     for (uint32_t Block : Blocks) {
2126b6b8c4fSAdrian McCarthy       uint64_t BlockEndOffset =
2136b6b8c4fSAdrian McCarthy           (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
2146b6b8c4fSAdrian McCarthy       if (BlockEndOffset > getFileSize())
2156b6b8c4fSAdrian McCarthy         return make_error<RawError>(raw_error_code::corrupt_file,
2166b6b8c4fSAdrian McCarthy                                     "Stream block map is corrupt.");
2176b6b8c4fSAdrian McCarthy     }
2186b6b8c4fSAdrian McCarthy     ContainerLayout.StreamMap.push_back(Blocks);
2196b6b8c4fSAdrian McCarthy   }
2206b6b8c4fSAdrian McCarthy 
2216b6b8c4fSAdrian McCarthy   // We should have read exactly SB->NumDirectoryBytes bytes.
2226b6b8c4fSAdrian McCarthy   assert(Reader.bytesRemaining() == 0);
2236b6b8c4fSAdrian McCarthy   DirectoryStream = std::move(DS);
2246b6b8c4fSAdrian McCarthy   return Error::success();
2256b6b8c4fSAdrian McCarthy }
2266b6b8c4fSAdrian McCarthy 
2276b6b8c4fSAdrian McCarthy ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
2286b6b8c4fSAdrian McCarthy   return ContainerLayout.DirectoryBlocks;
2296b6b8c4fSAdrian McCarthy }
2306b6b8c4fSAdrian McCarthy 
2316b6b8c4fSAdrian McCarthy Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
2326b6b8c4fSAdrian McCarthy   if (!Globals) {
2336b6b8c4fSAdrian McCarthy     auto DbiS = getPDBDbiStream();
2346b6b8c4fSAdrian McCarthy     if (!DbiS)
2356b6b8c4fSAdrian McCarthy       return DbiS.takeError();
2366b6b8c4fSAdrian McCarthy 
2376b6b8c4fSAdrian McCarthy     auto GlobalS = safelyCreateIndexedStream(
2386b6b8c4fSAdrian McCarthy         ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex());
2396b6b8c4fSAdrian McCarthy     if (!GlobalS)
2406b6b8c4fSAdrian McCarthy       return GlobalS.takeError();
2416b6b8c4fSAdrian McCarthy     auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS));
2426b6b8c4fSAdrian McCarthy     if (auto EC = TempGlobals->reload())
2436b6b8c4fSAdrian McCarthy       return std::move(EC);
2446b6b8c4fSAdrian McCarthy     Globals = std::move(TempGlobals);
2456b6b8c4fSAdrian McCarthy   }
2466b6b8c4fSAdrian McCarthy   return *Globals;
2476b6b8c4fSAdrian McCarthy }
2486b6b8c4fSAdrian McCarthy 
2496b6b8c4fSAdrian McCarthy Expected<InfoStream &> PDBFile::getPDBInfoStream() {
2506b6b8c4fSAdrian McCarthy   if (!Info) {
2516b6b8c4fSAdrian McCarthy     auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB);
2526b6b8c4fSAdrian McCarthy     if (!InfoS)
2536b6b8c4fSAdrian McCarthy       return InfoS.takeError();
2546b6b8c4fSAdrian McCarthy     auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
2556b6b8c4fSAdrian McCarthy     if (auto EC = TempInfo->reload())
2566b6b8c4fSAdrian McCarthy       return std::move(EC);
2576b6b8c4fSAdrian McCarthy     Info = std::move(TempInfo);
2586b6b8c4fSAdrian McCarthy   }
2596b6b8c4fSAdrian McCarthy   return *Info;
2606b6b8c4fSAdrian McCarthy }
2616b6b8c4fSAdrian McCarthy 
2626b6b8c4fSAdrian McCarthy Expected<DbiStream &> PDBFile::getPDBDbiStream() {
2636b6b8c4fSAdrian McCarthy   if (!Dbi) {
2646b6b8c4fSAdrian McCarthy     auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI);
2656b6b8c4fSAdrian McCarthy     if (!DbiS)
2666b6b8c4fSAdrian McCarthy       return DbiS.takeError();
2676b6b8c4fSAdrian McCarthy     auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
2686b6b8c4fSAdrian McCarthy     if (auto EC = TempDbi->reload())
2696b6b8c4fSAdrian McCarthy       return std::move(EC);
2706b6b8c4fSAdrian McCarthy     Dbi = std::move(TempDbi);
2716b6b8c4fSAdrian McCarthy   }
2726b6b8c4fSAdrian McCarthy   return *Dbi;
2736b6b8c4fSAdrian McCarthy }
2746b6b8c4fSAdrian McCarthy 
2756b6b8c4fSAdrian McCarthy Expected<TpiStream &> PDBFile::getPDBTpiStream() {
2766b6b8c4fSAdrian McCarthy   if (!Tpi) {
2776b6b8c4fSAdrian McCarthy     auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI);
2786b6b8c4fSAdrian McCarthy     if (!TpiS)
2796b6b8c4fSAdrian McCarthy       return TpiS.takeError();
2806b6b8c4fSAdrian McCarthy     auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
2816b6b8c4fSAdrian McCarthy     if (auto EC = TempTpi->reload())
2826b6b8c4fSAdrian McCarthy       return std::move(EC);
2836b6b8c4fSAdrian McCarthy     Tpi = std::move(TempTpi);
2846b6b8c4fSAdrian McCarthy   }
2856b6b8c4fSAdrian McCarthy   return *Tpi;
2866b6b8c4fSAdrian McCarthy }
2876b6b8c4fSAdrian McCarthy 
2886b6b8c4fSAdrian McCarthy Expected<TpiStream &> PDBFile::getPDBIpiStream() {
2896b6b8c4fSAdrian McCarthy   if (!Ipi) {
2906b6b8c4fSAdrian McCarthy     auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI);
2916b6b8c4fSAdrian McCarthy     if (!IpiS)
2926b6b8c4fSAdrian McCarthy       return IpiS.takeError();
2936b6b8c4fSAdrian McCarthy     auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
2946b6b8c4fSAdrian McCarthy     if (auto EC = TempIpi->reload())
2956b6b8c4fSAdrian McCarthy       return std::move(EC);
2966b6b8c4fSAdrian McCarthy     Ipi = std::move(TempIpi);
2976b6b8c4fSAdrian McCarthy   }
2986b6b8c4fSAdrian McCarthy   return *Ipi;
2996b6b8c4fSAdrian McCarthy }
3006b6b8c4fSAdrian McCarthy 
3016b6b8c4fSAdrian McCarthy Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
3026b6b8c4fSAdrian McCarthy   if (!Publics) {
3036b6b8c4fSAdrian McCarthy     auto DbiS = getPDBDbiStream();
3046b6b8c4fSAdrian McCarthy     if (!DbiS)
3056b6b8c4fSAdrian McCarthy       return DbiS.takeError();
3066b6b8c4fSAdrian McCarthy 
3076b6b8c4fSAdrian McCarthy     auto PublicS = safelyCreateIndexedStream(
3086b6b8c4fSAdrian McCarthy         ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex());
3096b6b8c4fSAdrian McCarthy     if (!PublicS)
3106b6b8c4fSAdrian McCarthy       return PublicS.takeError();
3116b6b8c4fSAdrian McCarthy     auto TempPublics =
3126b6b8c4fSAdrian McCarthy         llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
3136b6b8c4fSAdrian McCarthy     if (auto EC = TempPublics->reload())
3146b6b8c4fSAdrian McCarthy       return std::move(EC);
3156b6b8c4fSAdrian McCarthy     Publics = std::move(TempPublics);
3166b6b8c4fSAdrian McCarthy   }
3176b6b8c4fSAdrian McCarthy   return *Publics;
3186b6b8c4fSAdrian McCarthy }
3196b6b8c4fSAdrian McCarthy 
3206b6b8c4fSAdrian McCarthy Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
3216b6b8c4fSAdrian McCarthy   if (!Symbols) {
3226b6b8c4fSAdrian McCarthy     auto DbiS = getPDBDbiStream();
3236b6b8c4fSAdrian McCarthy     if (!DbiS)
3246b6b8c4fSAdrian McCarthy       return DbiS.takeError();
3256b6b8c4fSAdrian McCarthy 
3266b6b8c4fSAdrian McCarthy     uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
3276b6b8c4fSAdrian McCarthy     auto SymbolS =
3286b6b8c4fSAdrian McCarthy         safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum);
3296b6b8c4fSAdrian McCarthy     if (!SymbolS)
3306b6b8c4fSAdrian McCarthy       return SymbolS.takeError();
3316b6b8c4fSAdrian McCarthy 
3326b6b8c4fSAdrian McCarthy     auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
3336b6b8c4fSAdrian McCarthy     if (auto EC = TempSymbols->reload())
3346b6b8c4fSAdrian McCarthy       return std::move(EC);
3356b6b8c4fSAdrian McCarthy     Symbols = std::move(TempSymbols);
3366b6b8c4fSAdrian McCarthy   }
3376b6b8c4fSAdrian McCarthy   return *Symbols;
3386b6b8c4fSAdrian McCarthy }
3396b6b8c4fSAdrian McCarthy 
340e204a6c9SZachary Turner Expected<PDBStringTable &> PDBFile::getStringTable() {
341*dff096f2SDaniel Jasper   if (!Strings || !PDBStringTableStream) {
3426b6b8c4fSAdrian McCarthy     auto IS = getPDBInfoStream();
3436b6b8c4fSAdrian McCarthy     if (!IS)
3446b6b8c4fSAdrian McCarthy       return IS.takeError();
3456b6b8c4fSAdrian McCarthy 
3466b6b8c4fSAdrian McCarthy     uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names");
3476b6b8c4fSAdrian McCarthy 
3486b6b8c4fSAdrian McCarthy     auto NS =
3496b6b8c4fSAdrian McCarthy         safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex);
3506b6b8c4fSAdrian McCarthy     if (!NS)
3516b6b8c4fSAdrian McCarthy       return NS.takeError();
3526b6b8c4fSAdrian McCarthy 
3537dba20bdSZachary Turner     BinaryStreamReader Reader(**NS);
354*dff096f2SDaniel Jasper     auto N = llvm::make_unique<PDBStringTable>();
355*dff096f2SDaniel Jasper     if (auto EC = N->load(Reader))
3566b6b8c4fSAdrian McCarthy       return std::move(EC);
3576b6b8c4fSAdrian McCarthy     Strings = std::move(N);
358*dff096f2SDaniel Jasper     PDBStringTableStream = std::move(*NS);
3596b6b8c4fSAdrian McCarthy   }
3606b6b8c4fSAdrian McCarthy   return *Strings;
3616b6b8c4fSAdrian McCarthy }
3626b6b8c4fSAdrian McCarthy 
3636b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBDbiStream() const { return StreamDBI < getNumStreams(); }
3646b6b8c4fSAdrian McCarthy 
3656b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBGlobalsStream() {
3666b6b8c4fSAdrian McCarthy   auto DbiS = getPDBDbiStream();
3676b6b8c4fSAdrian McCarthy   if (!DbiS)
3686b6b8c4fSAdrian McCarthy     return false;
3696b6b8c4fSAdrian McCarthy   return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
3706b6b8c4fSAdrian McCarthy }
3716b6b8c4fSAdrian McCarthy 
3726b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBInfoStream() { return StreamPDB < getNumStreams(); }
3736b6b8c4fSAdrian McCarthy 
3746b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBIpiStream() const { return StreamIPI < getNumStreams(); }
3756b6b8c4fSAdrian McCarthy 
3766b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBPublicsStream() {
3776b6b8c4fSAdrian McCarthy   auto DbiS = getPDBDbiStream();
3786b6b8c4fSAdrian McCarthy   if (!DbiS)
3796b6b8c4fSAdrian McCarthy     return false;
3806b6b8c4fSAdrian McCarthy   return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
3816b6b8c4fSAdrian McCarthy }
3826b6b8c4fSAdrian McCarthy 
3836b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBSymbolStream() {
3846b6b8c4fSAdrian McCarthy   auto DbiS = getPDBDbiStream();
3856b6b8c4fSAdrian McCarthy   if (!DbiS)
3866b6b8c4fSAdrian McCarthy     return false;
3876b6b8c4fSAdrian McCarthy   return DbiS->getSymRecordStreamIndex() < getNumStreams();
3886b6b8c4fSAdrian McCarthy }
3896b6b8c4fSAdrian McCarthy 
3906b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
3916b6b8c4fSAdrian McCarthy 
392e204a6c9SZachary Turner bool PDBFile::hasPDBStringTable() {
3936b6b8c4fSAdrian McCarthy   auto IS = getPDBInfoStream();
3946b6b8c4fSAdrian McCarthy   if (!IS)
3956b6b8c4fSAdrian McCarthy     return false;
3966b6b8c4fSAdrian McCarthy   return IS->getNamedStreamIndex("/names") < getNumStreams();
3976b6b8c4fSAdrian McCarthy }
3986b6b8c4fSAdrian McCarthy 
399d0b44fa7SZachary Turner /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
400d0b44fa7SZachary Turner /// stream with that index actually exists.  If it does not, the return value
401d0b44fa7SZachary Turner /// will have an MSFError with code msf_error_code::no_stream.  Else, the return
402d0b44fa7SZachary Turner /// value will contain the stream returned by createIndexedStream().
4036b6b8c4fSAdrian McCarthy Expected<std::unique_ptr<MappedBlockStream>>
4046b6b8c4fSAdrian McCarthy PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout,
405120faca4SZachary Turner                                    BinaryStreamRef MsfData,
4066b6b8c4fSAdrian McCarthy                                    uint32_t StreamIndex) const {
4076b6b8c4fSAdrian McCarthy   if (StreamIndex >= getNumStreams())
4086b6b8c4fSAdrian McCarthy     return make_error<RawError>(raw_error_code::no_stream);
4096b6b8c4fSAdrian McCarthy   return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex);
4106b6b8c4fSAdrian McCarthy }
411