16b6b8c4fSAdrian McCarthy //===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
26b6b8c4fSAdrian McCarthy //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66b6b8c4fSAdrian McCarthy //
76b6b8c4fSAdrian McCarthy //===----------------------------------------------------------------------===//
86b6b8c4fSAdrian McCarthy 
96b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
106b6b8c4fSAdrian McCarthy #include "llvm/ADT/ArrayRef.h"
116b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/MSF/MSFCommon.h"
126b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
136b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
146b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
156b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
16d100b5ddSNico Weber #include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h"
17e204a6c9SZachary Turner #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
186b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
196b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/RawError.h"
206b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
216b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
22d9dc2829SZachary Turner #include "llvm/Support/BinaryStream.h"
23d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamArray.h"
24d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamReader.h"
256b6b8c4fSAdrian McCarthy #include "llvm/Support/Endian.h"
266b6b8c4fSAdrian McCarthy #include "llvm/Support/Error.h"
277b327d05SZachary Turner #include "llvm/Support/Path.h"
286b6b8c4fSAdrian McCarthy #include <algorithm>
296b6b8c4fSAdrian McCarthy #include <cassert>
306b6b8c4fSAdrian McCarthy #include <cstdint>
316b6b8c4fSAdrian McCarthy 
326b6b8c4fSAdrian McCarthy using namespace llvm;
336b6b8c4fSAdrian McCarthy using namespace llvm::codeview;
346b6b8c4fSAdrian McCarthy using namespace llvm::msf;
356b6b8c4fSAdrian McCarthy using namespace llvm::pdb;
366b6b8c4fSAdrian McCarthy 
376b6b8c4fSAdrian McCarthy namespace {
386b6b8c4fSAdrian McCarthy typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
396b6b8c4fSAdrian McCarthy } // end anonymous namespace
406b6b8c4fSAdrian McCarthy 
PDBFile(StringRef Path,std::unique_ptr<BinaryStream> PdbFileBuffer,BumpPtrAllocator & Allocator)41120faca4SZachary Turner PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer,
426b6b8c4fSAdrian McCarthy                  BumpPtrAllocator &Allocator)
43adcd0268SBenjamin Kramer     : FilePath(std::string(Path)), Allocator(Allocator),
44adcd0268SBenjamin Kramer       Buffer(std::move(PdbFileBuffer)) {}
456b6b8c4fSAdrian McCarthy 
466b6b8c4fSAdrian McCarthy PDBFile::~PDBFile() = default;
476b6b8c4fSAdrian McCarthy 
getFilePath() const487b327d05SZachary Turner StringRef PDBFile::getFilePath() const { return FilePath; }
497b327d05SZachary Turner 
getFileDirectory() const507b327d05SZachary Turner StringRef PDBFile::getFileDirectory() const {
517b327d05SZachary Turner   return sys::path::parent_path(FilePath);
527b327d05SZachary Turner }
537b327d05SZachary Turner 
getBlockSize() const546b6b8c4fSAdrian McCarthy uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
556b6b8c4fSAdrian McCarthy 
getFreeBlockMapBlock() const566b6b8c4fSAdrian McCarthy uint32_t PDBFile::getFreeBlockMapBlock() const {
576b6b8c4fSAdrian McCarthy   return ContainerLayout.SB->FreeBlockMapBlock;
586b6b8c4fSAdrian McCarthy }
596b6b8c4fSAdrian McCarthy 
getBlockCount() const606b6b8c4fSAdrian McCarthy uint32_t PDBFile::getBlockCount() const {
616b6b8c4fSAdrian McCarthy   return ContainerLayout.SB->NumBlocks;
626b6b8c4fSAdrian McCarthy }
636b6b8c4fSAdrian McCarthy 
getNumDirectoryBytes() const646b6b8c4fSAdrian McCarthy uint32_t PDBFile::getNumDirectoryBytes() const {
656b6b8c4fSAdrian McCarthy   return ContainerLayout.SB->NumDirectoryBytes;
666b6b8c4fSAdrian McCarthy }
676b6b8c4fSAdrian McCarthy 
getBlockMapIndex() const686b6b8c4fSAdrian McCarthy uint32_t PDBFile::getBlockMapIndex() const {
696b6b8c4fSAdrian McCarthy   return ContainerLayout.SB->BlockMapAddr;
706b6b8c4fSAdrian McCarthy }
716b6b8c4fSAdrian McCarthy 
getUnknown1() const726b6b8c4fSAdrian McCarthy uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
736b6b8c4fSAdrian McCarthy 
getNumDirectoryBlocks() const746b6b8c4fSAdrian McCarthy uint32_t PDBFile::getNumDirectoryBlocks() const {
756b6b8c4fSAdrian McCarthy   return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
766b6b8c4fSAdrian McCarthy                             ContainerLayout.SB->BlockSize);
776b6b8c4fSAdrian McCarthy }
786b6b8c4fSAdrian McCarthy 
getBlockMapOffset() const796b6b8c4fSAdrian McCarthy uint64_t PDBFile::getBlockMapOffset() const {
806b6b8c4fSAdrian McCarthy   return (uint64_t)ContainerLayout.SB->BlockMapAddr *
816b6b8c4fSAdrian McCarthy          ContainerLayout.SB->BlockSize;
826b6b8c4fSAdrian McCarthy }
836b6b8c4fSAdrian McCarthy 
getNumStreams() const846b6b8c4fSAdrian McCarthy uint32_t PDBFile::getNumStreams() const {
856b6b8c4fSAdrian McCarthy   return ContainerLayout.StreamSizes.size();
866b6b8c4fSAdrian McCarthy }
876b6b8c4fSAdrian McCarthy 
getMaxStreamSize() const88d1de2f4fSZachary Turner uint32_t PDBFile::getMaxStreamSize() const {
89d1de2f4fSZachary Turner   return *std::max_element(ContainerLayout.StreamSizes.begin(),
90d1de2f4fSZachary Turner                            ContainerLayout.StreamSizes.end());
91d1de2f4fSZachary Turner }
92d1de2f4fSZachary Turner 
getStreamByteSize(uint32_t StreamIndex) const936b6b8c4fSAdrian 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>
getStreamBlockList(uint32_t StreamIndex) const986b6b8c4fSAdrian McCarthy PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
996b6b8c4fSAdrian McCarthy   return ContainerLayout.StreamMap[StreamIndex];
1006b6b8c4fSAdrian McCarthy }
1016b6b8c4fSAdrian McCarthy 
getFileSize() const102*e4eb6216SChris Davis uint64_t PDBFile::getFileSize() const { return Buffer->getLength(); }
1036b6b8c4fSAdrian McCarthy 
getBlockData(uint32_t BlockIndex,uint32_t NumBytes) const1046b6b8c4fSAdrian 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))
110c55cf4afSBill Wendling     return std::move(EC);
1116b6b8c4fSAdrian McCarthy   return Result;
1126b6b8c4fSAdrian McCarthy }
1136b6b8c4fSAdrian McCarthy 
setBlockData(uint32_t BlockIndex,uint32_t Offset,ArrayRef<uint8_t> Data) const1146b6b8c4fSAdrian 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 
parseFileHeaders()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,
1286a7efef4SAlexandre Ganea                                 "MSF superblock is missing");
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 
parseStreamData()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 
getDirectoryBlockArray() const2336b6b8c4fSAdrian McCarthy ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
2346b6b8c4fSAdrian McCarthy   return ContainerLayout.DirectoryBlocks;
2356b6b8c4fSAdrian McCarthy }
2366b6b8c4fSAdrian McCarthy 
23713f7ddffSNico Weber std::unique_ptr<MappedBlockStream>
createIndexedStream(uint16_t SN) const23813f7ddffSNico Weber PDBFile::createIndexedStream(uint16_t SN) const {
239d1de2f4fSZachary Turner   if (SN == kInvalidStreamIndex)
240d1de2f4fSZachary Turner     return nullptr;
241d1de2f4fSZachary Turner   return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
242d1de2f4fSZachary Turner                                                 Allocator);
243d1de2f4fSZachary Turner }
244d1de2f4fSZachary Turner 
getStreamLayout(uint32_t StreamIdx) const2450b36c3ebSZachary Turner MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
2460b36c3ebSZachary Turner   MSFStreamLayout Result;
2470b36c3ebSZachary Turner   auto Blocks = getStreamBlockList(StreamIdx);
2480b36c3ebSZachary Turner   Result.Blocks.assign(Blocks.begin(), Blocks.end());
2490b36c3ebSZachary Turner   Result.Length = getStreamByteSize(StreamIdx);
2500b36c3ebSZachary Turner   return Result;
2510b36c3ebSZachary Turner }
2520b36c3ebSZachary Turner 
getFpmStreamLayout() const253c3d8eec9SZachary Turner msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const {
254c3d8eec9SZachary Turner   return msf::getFpmStreamLayout(ContainerLayout);
255c3d8eec9SZachary Turner }
256c3d8eec9SZachary Turner 
getPDBGlobalsStream()2576b6b8c4fSAdrian McCarthy Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
2586b6b8c4fSAdrian McCarthy   if (!Globals) {
2596b6b8c4fSAdrian McCarthy     auto DbiS = getPDBDbiStream();
2606b6b8c4fSAdrian McCarthy     if (!DbiS)
2616b6b8c4fSAdrian McCarthy       return DbiS.takeError();
2626b6b8c4fSAdrian McCarthy 
26313f7ddffSNico Weber     auto GlobalS =
26413f7ddffSNico Weber         safelyCreateIndexedStream(DbiS->getGlobalSymbolStreamIndex());
2656b6b8c4fSAdrian McCarthy     if (!GlobalS)
2666b6b8c4fSAdrian McCarthy       return GlobalS.takeError();
2670eaee545SJonas Devlieghere     auto TempGlobals = std::make_unique<GlobalsStream>(std::move(*GlobalS));
2686b6b8c4fSAdrian McCarthy     if (auto EC = TempGlobals->reload())
269c55cf4afSBill Wendling       return std::move(EC);
2706b6b8c4fSAdrian McCarthy     Globals = std::move(TempGlobals);
2716b6b8c4fSAdrian McCarthy   }
2726b6b8c4fSAdrian McCarthy   return *Globals;
2736b6b8c4fSAdrian McCarthy }
2746b6b8c4fSAdrian McCarthy 
getPDBInfoStream()2756b6b8c4fSAdrian McCarthy Expected<InfoStream &> PDBFile::getPDBInfoStream() {
2766b6b8c4fSAdrian McCarthy   if (!Info) {
27713f7ddffSNico Weber     auto InfoS = safelyCreateIndexedStream(StreamPDB);
2786b6b8c4fSAdrian McCarthy     if (!InfoS)
2796b6b8c4fSAdrian McCarthy       return InfoS.takeError();
2800eaee545SJonas Devlieghere     auto TempInfo = std::make_unique<InfoStream>(std::move(*InfoS));
2816b6b8c4fSAdrian McCarthy     if (auto EC = TempInfo->reload())
282c55cf4afSBill Wendling       return std::move(EC);
2836b6b8c4fSAdrian McCarthy     Info = std::move(TempInfo);
2846b6b8c4fSAdrian McCarthy   }
2856b6b8c4fSAdrian McCarthy   return *Info;
2866b6b8c4fSAdrian McCarthy }
2876b6b8c4fSAdrian McCarthy 
getPDBDbiStream()2886b6b8c4fSAdrian McCarthy Expected<DbiStream &> PDBFile::getPDBDbiStream() {
2896b6b8c4fSAdrian McCarthy   if (!Dbi) {
29013f7ddffSNico Weber     auto DbiS = safelyCreateIndexedStream(StreamDBI);
2916b6b8c4fSAdrian McCarthy     if (!DbiS)
2926b6b8c4fSAdrian McCarthy       return DbiS.takeError();
2930eaee545SJonas Devlieghere     auto TempDbi = std::make_unique<DbiStream>(std::move(*DbiS));
29415b2bdfdSZachary Turner     if (auto EC = TempDbi->reload(this))
295c55cf4afSBill Wendling       return std::move(EC);
2966b6b8c4fSAdrian McCarthy     Dbi = std::move(TempDbi);
2976b6b8c4fSAdrian McCarthy   }
2986b6b8c4fSAdrian McCarthy   return *Dbi;
2996b6b8c4fSAdrian McCarthy }
3006b6b8c4fSAdrian McCarthy 
getPDBTpiStream()3016b6b8c4fSAdrian McCarthy Expected<TpiStream &> PDBFile::getPDBTpiStream() {
3026b6b8c4fSAdrian McCarthy   if (!Tpi) {
30313f7ddffSNico Weber     auto TpiS = safelyCreateIndexedStream(StreamTPI);
3046b6b8c4fSAdrian McCarthy     if (!TpiS)
3056b6b8c4fSAdrian McCarthy       return TpiS.takeError();
3060eaee545SJonas Devlieghere     auto TempTpi = std::make_unique<TpiStream>(*this, std::move(*TpiS));
3076b6b8c4fSAdrian McCarthy     if (auto EC = TempTpi->reload())
308c55cf4afSBill Wendling       return std::move(EC);
3096b6b8c4fSAdrian McCarthy     Tpi = std::move(TempTpi);
3106b6b8c4fSAdrian McCarthy   }
3116b6b8c4fSAdrian McCarthy   return *Tpi;
3126b6b8c4fSAdrian McCarthy }
3136b6b8c4fSAdrian McCarthy 
getPDBIpiStream()3146b6b8c4fSAdrian McCarthy Expected<TpiStream &> PDBFile::getPDBIpiStream() {
3156b6b8c4fSAdrian McCarthy   if (!Ipi) {
316abb17cc0SZachary Turner     if (!hasPDBIpiStream())
317abb17cc0SZachary Turner       return make_error<RawError>(raw_error_code::no_stream);
318abb17cc0SZachary Turner 
31913f7ddffSNico Weber     auto IpiS = safelyCreateIndexedStream(StreamIPI);
3206b6b8c4fSAdrian McCarthy     if (!IpiS)
3216b6b8c4fSAdrian McCarthy       return IpiS.takeError();
3220eaee545SJonas Devlieghere     auto TempIpi = std::make_unique<TpiStream>(*this, std::move(*IpiS));
3236b6b8c4fSAdrian McCarthy     if (auto EC = TempIpi->reload())
324c55cf4afSBill Wendling       return std::move(EC);
3256b6b8c4fSAdrian McCarthy     Ipi = std::move(TempIpi);
3266b6b8c4fSAdrian McCarthy   }
3276b6b8c4fSAdrian McCarthy   return *Ipi;
3286b6b8c4fSAdrian McCarthy }
3296b6b8c4fSAdrian McCarthy 
getPDBPublicsStream()3306b6b8c4fSAdrian McCarthy Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
3316b6b8c4fSAdrian McCarthy   if (!Publics) {
3326b6b8c4fSAdrian McCarthy     auto DbiS = getPDBDbiStream();
3336b6b8c4fSAdrian McCarthy     if (!DbiS)
3346b6b8c4fSAdrian McCarthy       return DbiS.takeError();
3356b6b8c4fSAdrian McCarthy 
33613f7ddffSNico Weber     auto PublicS =
33713f7ddffSNico Weber         safelyCreateIndexedStream(DbiS->getPublicSymbolStreamIndex());
3386b6b8c4fSAdrian McCarthy     if (!PublicS)
3396b6b8c4fSAdrian McCarthy       return PublicS.takeError();
3400eaee545SJonas Devlieghere     auto TempPublics = std::make_unique<PublicsStream>(std::move(*PublicS));
3416b6b8c4fSAdrian McCarthy     if (auto EC = TempPublics->reload())
342c55cf4afSBill Wendling       return std::move(EC);
3436b6b8c4fSAdrian McCarthy     Publics = std::move(TempPublics);
3446b6b8c4fSAdrian McCarthy   }
3456b6b8c4fSAdrian McCarthy   return *Publics;
3466b6b8c4fSAdrian McCarthy }
3476b6b8c4fSAdrian McCarthy 
getPDBSymbolStream()3486b6b8c4fSAdrian McCarthy Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
3496b6b8c4fSAdrian McCarthy   if (!Symbols) {
3506b6b8c4fSAdrian McCarthy     auto DbiS = getPDBDbiStream();
3516b6b8c4fSAdrian McCarthy     if (!DbiS)
3526b6b8c4fSAdrian McCarthy       return DbiS.takeError();
3536b6b8c4fSAdrian McCarthy 
3546b6b8c4fSAdrian McCarthy     uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
35513f7ddffSNico Weber     auto SymbolS = safelyCreateIndexedStream(SymbolStreamNum);
3566b6b8c4fSAdrian McCarthy     if (!SymbolS)
3576b6b8c4fSAdrian McCarthy       return SymbolS.takeError();
3586b6b8c4fSAdrian McCarthy 
3590eaee545SJonas Devlieghere     auto TempSymbols = std::make_unique<SymbolStream>(std::move(*SymbolS));
3606b6b8c4fSAdrian McCarthy     if (auto EC = TempSymbols->reload())
361c55cf4afSBill Wendling       return std::move(EC);
3626b6b8c4fSAdrian McCarthy     Symbols = std::move(TempSymbols);
3636b6b8c4fSAdrian McCarthy   }
3646b6b8c4fSAdrian McCarthy   return *Symbols;
3656b6b8c4fSAdrian McCarthy }
3666b6b8c4fSAdrian McCarthy 
getStringTable()367e204a6c9SZachary Turner Expected<PDBStringTable &> PDBFile::getStringTable() {
368c504ae3cSZachary Turner   if (!Strings) {
369d100b5ddSNico Weber     auto NS = safelyCreateNamedStream("/names");
3706b6b8c4fSAdrian McCarthy     if (!NS)
3716b6b8c4fSAdrian McCarthy       return NS.takeError();
3726b6b8c4fSAdrian McCarthy 
3730eaee545SJonas Devlieghere     auto N = std::make_unique<PDBStringTable>();
374c504ae3cSZachary Turner     BinaryStreamReader Reader(**NS);
375c504ae3cSZachary Turner     if (auto EC = N->reload(Reader))
376c55cf4afSBill Wendling       return std::move(EC);
377c504ae3cSZachary Turner     assert(Reader.bytesRemaining() == 0);
378c504ae3cSZachary Turner     StringTableStream = std::move(*NS);
3796b6b8c4fSAdrian McCarthy     Strings = std::move(N);
3806b6b8c4fSAdrian McCarthy   }
3816b6b8c4fSAdrian McCarthy   return *Strings;
3826b6b8c4fSAdrian McCarthy }
3836b6b8c4fSAdrian McCarthy 
getInjectedSourceStream()384d100b5ddSNico Weber Expected<InjectedSourceStream &> PDBFile::getInjectedSourceStream() {
385d100b5ddSNico Weber   if (!InjectedSources) {
386d100b5ddSNico Weber     auto IJS = safelyCreateNamedStream("/src/headerblock");
387d100b5ddSNico Weber     if (!IJS)
388d100b5ddSNico Weber       return IJS.takeError();
389d100b5ddSNico Weber 
390d100b5ddSNico Weber     auto Strings = getStringTable();
391d100b5ddSNico Weber     if (!Strings)
392d100b5ddSNico Weber       return Strings.takeError();
393d100b5ddSNico Weber 
3940eaee545SJonas Devlieghere     auto IJ = std::make_unique<InjectedSourceStream>(std::move(*IJS));
395d100b5ddSNico Weber     if (auto EC = IJ->reload(*Strings))
396c55cf4afSBill Wendling       return std::move(EC);
397d100b5ddSNico Weber     InjectedSources = std::move(IJ);
398d100b5ddSNico Weber   }
399d100b5ddSNico Weber   return *InjectedSources;
400d100b5ddSNico Weber }
401d100b5ddSNico Weber 
getPointerSize()4024e950647SZachary Turner uint32_t PDBFile::getPointerSize() {
4034e950647SZachary Turner   auto DbiS = getPDBDbiStream();
4044e950647SZachary Turner   if (!DbiS)
4054e950647SZachary Turner     return 0;
4064e950647SZachary Turner   PDB_Machine Machine = DbiS->getMachineType();
4074e950647SZachary Turner   if (Machine == PDB_Machine::Amd64)
4084e950647SZachary Turner     return 8;
4094e950647SZachary Turner   return 4;
4104e950647SZachary Turner }
4114e950647SZachary Turner 
hasPDBDbiStream() const412741cc353SAlexandre Ganea bool PDBFile::hasPDBDbiStream() const {
413741cc353SAlexandre Ganea   return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0;
414741cc353SAlexandre Ganea }
4156b6b8c4fSAdrian McCarthy 
hasPDBGlobalsStream()4166b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBGlobalsStream() {
4176b6b8c4fSAdrian McCarthy   auto DbiS = getPDBDbiStream();
418c1e93e5fSZachary Turner   if (!DbiS) {
419c1e93e5fSZachary Turner     consumeError(DbiS.takeError());
4206b6b8c4fSAdrian McCarthy     return false;
421c1e93e5fSZachary Turner   }
422c1e93e5fSZachary Turner 
4236b6b8c4fSAdrian McCarthy   return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
4246b6b8c4fSAdrian McCarthy }
4256b6b8c4fSAdrian McCarthy 
hasPDBInfoStream() const426abb17cc0SZachary Turner bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); }
4276b6b8c4fSAdrian McCarthy 
hasPDBIpiStream() const428abb17cc0SZachary Turner bool PDBFile::hasPDBIpiStream() const {
429abb17cc0SZachary Turner   if (!hasPDBInfoStream())
430abb17cc0SZachary Turner     return false;
431abb17cc0SZachary Turner 
432abb17cc0SZachary Turner   if (StreamIPI >= getNumStreams())
433abb17cc0SZachary Turner     return false;
434abb17cc0SZachary Turner 
435abb17cc0SZachary Turner   auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
436abb17cc0SZachary Turner   return InfoStream.containsIdStream();
437abb17cc0SZachary Turner }
4386b6b8c4fSAdrian McCarthy 
hasPDBPublicsStream()4396b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBPublicsStream() {
4406b6b8c4fSAdrian McCarthy   auto DbiS = getPDBDbiStream();
441c1e93e5fSZachary Turner   if (!DbiS) {
442c1e93e5fSZachary Turner     consumeError(DbiS.takeError());
4436b6b8c4fSAdrian McCarthy     return false;
444c1e93e5fSZachary Turner   }
4456b6b8c4fSAdrian McCarthy   return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
4466b6b8c4fSAdrian McCarthy }
4476b6b8c4fSAdrian McCarthy 
hasPDBSymbolStream()4486b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBSymbolStream() {
4496b6b8c4fSAdrian McCarthy   auto DbiS = getPDBDbiStream();
4506b6b8c4fSAdrian McCarthy   if (!DbiS)
4516b6b8c4fSAdrian McCarthy     return false;
4526b6b8c4fSAdrian McCarthy   return DbiS->getSymRecordStreamIndex() < getNumStreams();
4536b6b8c4fSAdrian McCarthy }
4546b6b8c4fSAdrian McCarthy 
hasPDBTpiStream() const4556b6b8c4fSAdrian McCarthy bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
4566b6b8c4fSAdrian McCarthy 
hasPDBStringTable()457e204a6c9SZachary Turner bool PDBFile::hasPDBStringTable() {
4586b6b8c4fSAdrian McCarthy   auto IS = getPDBInfoStream();
4596b6b8c4fSAdrian McCarthy   if (!IS)
4606b6b8c4fSAdrian McCarthy     return false;
461d11328a1SZachary Turner   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
462d11328a1SZachary Turner   if (!ExpectedNSI) {
463d11328a1SZachary Turner     consumeError(ExpectedNSI.takeError());
464d11328a1SZachary Turner     return false;
465d11328a1SZachary Turner   }
466d11328a1SZachary Turner   assert(*ExpectedNSI < getNumStreams());
467d11328a1SZachary Turner   return true;
4686b6b8c4fSAdrian McCarthy }
4696b6b8c4fSAdrian McCarthy 
hasPDBInjectedSourceStream()470d100b5ddSNico Weber bool PDBFile::hasPDBInjectedSourceStream() {
471d100b5ddSNico Weber   auto IS = getPDBInfoStream();
472d100b5ddSNico Weber   if (!IS)
473d100b5ddSNico Weber     return false;
474d100b5ddSNico Weber   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/src/headerblock");
475d100b5ddSNico Weber   if (!ExpectedNSI) {
476d100b5ddSNico Weber     consumeError(ExpectedNSI.takeError());
477d100b5ddSNico Weber     return false;
478d100b5ddSNico Weber   }
479d100b5ddSNico Weber   assert(*ExpectedNSI < getNumStreams());
480d100b5ddSNico Weber   return true;
481d100b5ddSNico Weber }
482d100b5ddSNico Weber 
483d0b44fa7SZachary Turner /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
484d0b44fa7SZachary Turner /// stream with that index actually exists.  If it does not, the return value
485d0b44fa7SZachary Turner /// will have an MSFError with code msf_error_code::no_stream.  Else, the return
486d0b44fa7SZachary Turner /// value will contain the stream returned by createIndexedStream().
4876b6b8c4fSAdrian McCarthy Expected<std::unique_ptr<MappedBlockStream>>
safelyCreateIndexedStream(uint32_t StreamIndex) const48813f7ddffSNico Weber PDBFile::safelyCreateIndexedStream(uint32_t StreamIndex) const {
4896b6b8c4fSAdrian McCarthy   if (StreamIndex >= getNumStreams())
49013f7ddffSNico Weber     // This rejects kInvalidStreamIndex with an error as well.
4916b6b8c4fSAdrian McCarthy     return make_error<RawError>(raw_error_code::no_stream);
49213f7ddffSNico Weber   return createIndexedStream(StreamIndex);
4936b6b8c4fSAdrian McCarthy }
494d100b5ddSNico Weber 
495d100b5ddSNico Weber Expected<std::unique_ptr<MappedBlockStream>>
safelyCreateNamedStream(StringRef Name)496d100b5ddSNico Weber PDBFile::safelyCreateNamedStream(StringRef Name) {
497d100b5ddSNico Weber   auto IS = getPDBInfoStream();
498d100b5ddSNico Weber   if (!IS)
499d100b5ddSNico Weber     return IS.takeError();
500d100b5ddSNico Weber 
501d100b5ddSNico Weber   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex(Name);
502d100b5ddSNico Weber   if (!ExpectedNSI)
503d100b5ddSNico Weber     return ExpectedNSI.takeError();
504d100b5ddSNico Weber   uint32_t NameStreamIndex = *ExpectedNSI;
505d100b5ddSNico Weber 
506d100b5ddSNico Weber   return safelyCreateIndexedStream(NameStreamIndex);
507d100b5ddSNico Weber }
508