xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
100b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
110b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MSFCommon.h"
120b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
130b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
140b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
150b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
160b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h"
170b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
180b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
190b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
200b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
210b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
220b57cec5SDimitry Andric #include "llvm/Support/BinaryStream.h"
230b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamArray.h"
240b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
250b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
260b57cec5SDimitry Andric #include "llvm/Support/Error.h"
270b57cec5SDimitry Andric #include "llvm/Support/Path.h"
280b57cec5SDimitry Andric #include <algorithm>
290b57cec5SDimitry Andric #include <cassert>
300b57cec5SDimitry Andric #include <cstdint>
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric using namespace llvm;
330b57cec5SDimitry Andric using namespace llvm::codeview;
340b57cec5SDimitry Andric using namespace llvm::msf;
350b57cec5SDimitry Andric using namespace llvm::pdb;
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric namespace {
380b57cec5SDimitry Andric typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
390b57cec5SDimitry Andric } // end anonymous namespace
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer,
420b57cec5SDimitry Andric                  BumpPtrAllocator &Allocator)
435ffd83dbSDimitry Andric     : FilePath(std::string(Path)), Allocator(Allocator),
445ffd83dbSDimitry Andric       Buffer(std::move(PdbFileBuffer)) {}
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric PDBFile::~PDBFile() = default;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric StringRef PDBFile::getFilePath() const { return FilePath; }
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric StringRef PDBFile::getFileDirectory() const {
510b57cec5SDimitry Andric   return sys::path::parent_path(FilePath);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric uint32_t PDBFile::getFreeBlockMapBlock() const {
570b57cec5SDimitry Andric   return ContainerLayout.SB->FreeBlockMapBlock;
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric uint32_t PDBFile::getBlockCount() const {
610b57cec5SDimitry Andric   return ContainerLayout.SB->NumBlocks;
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric uint32_t PDBFile::getNumDirectoryBytes() const {
650b57cec5SDimitry Andric   return ContainerLayout.SB->NumDirectoryBytes;
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric uint32_t PDBFile::getBlockMapIndex() const {
690b57cec5SDimitry Andric   return ContainerLayout.SB->BlockMapAddr;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric uint32_t PDBFile::getNumDirectoryBlocks() const {
750b57cec5SDimitry Andric   return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
760b57cec5SDimitry Andric                             ContainerLayout.SB->BlockSize);
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric uint64_t PDBFile::getBlockMapOffset() const {
800b57cec5SDimitry Andric   return (uint64_t)ContainerLayout.SB->BlockMapAddr *
810b57cec5SDimitry Andric          ContainerLayout.SB->BlockSize;
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric uint32_t PDBFile::getNumStreams() const {
850b57cec5SDimitry Andric   return ContainerLayout.StreamSizes.size();
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric uint32_t PDBFile::getMaxStreamSize() const {
89*0fca6ea1SDimitry Andric   return *llvm::max_element(ContainerLayout.StreamSizes);
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
930b57cec5SDimitry Andric   return ContainerLayout.StreamSizes[StreamIndex];
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric ArrayRef<support::ulittle32_t>
970b57cec5SDimitry Andric PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
980b57cec5SDimitry Andric   return ContainerLayout.StreamMap[StreamIndex];
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
1010eae32dcSDimitry Andric uint64_t PDBFile::getFileSize() const { return Buffer->getLength(); }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
1040b57cec5SDimitry Andric                                                   uint32_t NumBytes) const {
1050b57cec5SDimitry Andric   uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   ArrayRef<uint8_t> Result;
1080b57cec5SDimitry Andric   if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
1090b57cec5SDimitry Andric     return std::move(EC);
1100b57cec5SDimitry Andric   return Result;
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
1140b57cec5SDimitry Andric                             ArrayRef<uint8_t> Data) const {
1150b57cec5SDimitry Andric   return make_error<RawError>(raw_error_code::not_writable,
1160b57cec5SDimitry Andric                               "PDBFile is immutable");
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric Error PDBFile::parseFileHeaders() {
1200b57cec5SDimitry Andric   BinaryStreamReader Reader(*Buffer);
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   // Initialize SB.
1230b57cec5SDimitry Andric   const msf::SuperBlock *SB = nullptr;
1240b57cec5SDimitry Andric   if (auto EC = Reader.readObject(SB)) {
1250b57cec5SDimitry Andric     consumeError(std::move(EC));
1260b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::corrupt_file,
1270b57cec5SDimitry Andric                                 "MSF superblock is missing");
1280b57cec5SDimitry Andric   }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric   if (auto EC = msf::validateSuperBlock(*SB))
1310b57cec5SDimitry Andric     return EC;
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric   if (Buffer->getLength() % SB->BlockSize != 0)
1340b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::corrupt_file,
1350b57cec5SDimitry Andric                                 "File size is not a multiple of block size");
1360b57cec5SDimitry Andric   ContainerLayout.SB = SB;
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   // Initialize Free Page Map.
1390b57cec5SDimitry Andric   ContainerLayout.FreePageMap.resize(SB->NumBlocks);
1400b57cec5SDimitry Andric   // The Fpm exists either at block 1 or block 2 of the MSF.  However, this
1410b57cec5SDimitry Andric   // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
1420b57cec5SDimitry Andric   // thusly an equal number of total blocks in the file.  For a block size
1430b57cec5SDimitry Andric   // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
1440b57cec5SDimitry Andric   // maximum file size of 32KiB * 4KiB = 128MiB.  Obviously this won't do, so
1450b57cec5SDimitry Andric   // the Fpm is split across the file at `getBlockSize()` intervals.  As a
1460b57cec5SDimitry Andric   // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
1470b57cec5SDimitry Andric   // for any non-negative integer k is an Fpm block.  In theory, we only really
1480b57cec5SDimitry Andric   // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
1490b57cec5SDimitry Andric   // current versions of the MSF format already expect the Fpm to be arranged
1500b57cec5SDimitry Andric   // at getBlockSize() intervals, so we have to be compatible.
1510b57cec5SDimitry Andric   // See the function fpmPn() for more information:
1520b57cec5SDimitry Andric   // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
1530b57cec5SDimitry Andric   auto FpmStream =
1540b57cec5SDimitry Andric       MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
1550b57cec5SDimitry Andric   BinaryStreamReader FpmReader(*FpmStream);
1560b57cec5SDimitry Andric   ArrayRef<uint8_t> FpmBytes;
1570b57cec5SDimitry Andric   if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
1580b57cec5SDimitry Andric     return EC;
1590b57cec5SDimitry Andric   uint32_t BlocksRemaining = getBlockCount();
1600b57cec5SDimitry Andric   uint32_t BI = 0;
1610b57cec5SDimitry Andric   for (auto Byte : FpmBytes) {
1620b57cec5SDimitry Andric     uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
1630b57cec5SDimitry Andric     for (uint32_t I = 0; I < BlocksThisByte; ++I) {
1640b57cec5SDimitry Andric       if (Byte & (1 << I))
1650b57cec5SDimitry Andric         ContainerLayout.FreePageMap[BI] = true;
1660b57cec5SDimitry Andric       --BlocksRemaining;
1670b57cec5SDimitry Andric       ++BI;
1680b57cec5SDimitry Andric     }
1690b57cec5SDimitry Andric   }
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   Reader.setOffset(getBlockMapOffset());
1720b57cec5SDimitry Andric   if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
1730b57cec5SDimitry Andric                                  getNumDirectoryBlocks()))
1740b57cec5SDimitry Andric     return EC;
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric   return Error::success();
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric Error PDBFile::parseStreamData() {
1800b57cec5SDimitry Andric   assert(ContainerLayout.SB);
1810b57cec5SDimitry Andric   if (DirectoryStream)
1820b57cec5SDimitry Andric     return Error::success();
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric   uint32_t NumStreams = 0;
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   // Normally you can't use a MappedBlockStream without having fully parsed the
1870b57cec5SDimitry Andric   // PDB file, because it accesses the directory and various other things, which
1880b57cec5SDimitry Andric   // is exactly what we are attempting to parse.  By specifying a custom
1890b57cec5SDimitry Andric   // subclass of IPDBStreamData which only accesses the fields that have already
1900b57cec5SDimitry Andric   // been parsed, we can avoid this and reuse MappedBlockStream.
1910b57cec5SDimitry Andric   auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer,
1920b57cec5SDimitry Andric                                                      Allocator);
1930b57cec5SDimitry Andric   BinaryStreamReader Reader(*DS);
1940b57cec5SDimitry Andric   if (auto EC = Reader.readInteger(NumStreams))
1950b57cec5SDimitry Andric     return EC;
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
1980b57cec5SDimitry Andric     return EC;
1990b57cec5SDimitry Andric   for (uint32_t I = 0; I < NumStreams; ++I) {
2000b57cec5SDimitry Andric     uint32_t StreamSize = getStreamByteSize(I);
2010b57cec5SDimitry Andric     // FIXME: What does StreamSize ~0U mean?
2020b57cec5SDimitry Andric     uint64_t NumExpectedStreamBlocks =
2030b57cec5SDimitry Andric         StreamSize == UINT32_MAX
2040b57cec5SDimitry Andric             ? 0
2050b57cec5SDimitry Andric             : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric     // For convenience, we store the block array contiguously.  This is because
2080b57cec5SDimitry Andric     // if someone calls setStreamMap(), it is more convenient to be able to call
2090b57cec5SDimitry Andric     // it with an ArrayRef instead of setting up a StreamRef.  Since the
2100b57cec5SDimitry Andric     // DirectoryStream is cached in the class and thus lives for the life of the
2110b57cec5SDimitry Andric     // class, we can be guaranteed that readArray() will return a stable
2120b57cec5SDimitry Andric     // reference, even if it has to allocate from its internal pool.
2130b57cec5SDimitry Andric     ArrayRef<support::ulittle32_t> Blocks;
2140b57cec5SDimitry Andric     if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
2150b57cec5SDimitry Andric       return EC;
2160b57cec5SDimitry Andric     for (uint32_t Block : Blocks) {
2170b57cec5SDimitry Andric       uint64_t BlockEndOffset =
2180b57cec5SDimitry Andric           (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
2190b57cec5SDimitry Andric       if (BlockEndOffset > getFileSize())
2200b57cec5SDimitry Andric         return make_error<RawError>(raw_error_code::corrupt_file,
2210b57cec5SDimitry Andric                                     "Stream block map is corrupt.");
2220b57cec5SDimitry Andric     }
2230b57cec5SDimitry Andric     ContainerLayout.StreamMap.push_back(Blocks);
2240b57cec5SDimitry Andric   }
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   // We should have read exactly SB->NumDirectoryBytes bytes.
2270b57cec5SDimitry Andric   assert(Reader.bytesRemaining() == 0);
2280b57cec5SDimitry Andric   DirectoryStream = std::move(DS);
2290b57cec5SDimitry Andric   return Error::success();
2300b57cec5SDimitry Andric }
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
2330b57cec5SDimitry Andric   return ContainerLayout.DirectoryBlocks;
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric std::unique_ptr<MappedBlockStream>
2370b57cec5SDimitry Andric PDBFile::createIndexedStream(uint16_t SN) const {
2380b57cec5SDimitry Andric   if (SN == kInvalidStreamIndex)
2390b57cec5SDimitry Andric     return nullptr;
2400b57cec5SDimitry Andric   return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
2410b57cec5SDimitry Andric                                                 Allocator);
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
2450b57cec5SDimitry Andric   MSFStreamLayout Result;
2460b57cec5SDimitry Andric   auto Blocks = getStreamBlockList(StreamIdx);
2470b57cec5SDimitry Andric   Result.Blocks.assign(Blocks.begin(), Blocks.end());
2480b57cec5SDimitry Andric   Result.Length = getStreamByteSize(StreamIdx);
2490b57cec5SDimitry Andric   return Result;
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const {
2530b57cec5SDimitry Andric   return msf::getFpmStreamLayout(ContainerLayout);
2540b57cec5SDimitry Andric }
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
2570b57cec5SDimitry Andric   if (!Globals) {
2580b57cec5SDimitry Andric     auto DbiS = getPDBDbiStream();
2590b57cec5SDimitry Andric     if (!DbiS)
2600b57cec5SDimitry Andric       return DbiS.takeError();
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric     auto GlobalS =
2630b57cec5SDimitry Andric         safelyCreateIndexedStream(DbiS->getGlobalSymbolStreamIndex());
2640b57cec5SDimitry Andric     if (!GlobalS)
2650b57cec5SDimitry Andric       return GlobalS.takeError();
2668bcb0991SDimitry Andric     auto TempGlobals = std::make_unique<GlobalsStream>(std::move(*GlobalS));
2670b57cec5SDimitry Andric     if (auto EC = TempGlobals->reload())
2680b57cec5SDimitry Andric       return std::move(EC);
2690b57cec5SDimitry Andric     Globals = std::move(TempGlobals);
2700b57cec5SDimitry Andric   }
2710b57cec5SDimitry Andric   return *Globals;
2720b57cec5SDimitry Andric }
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric Expected<InfoStream &> PDBFile::getPDBInfoStream() {
2750b57cec5SDimitry Andric   if (!Info) {
2760b57cec5SDimitry Andric     auto InfoS = safelyCreateIndexedStream(StreamPDB);
2770b57cec5SDimitry Andric     if (!InfoS)
2780b57cec5SDimitry Andric       return InfoS.takeError();
2798bcb0991SDimitry Andric     auto TempInfo = std::make_unique<InfoStream>(std::move(*InfoS));
2800b57cec5SDimitry Andric     if (auto EC = TempInfo->reload())
2810b57cec5SDimitry Andric       return std::move(EC);
2820b57cec5SDimitry Andric     Info = std::move(TempInfo);
2830b57cec5SDimitry Andric   }
2840b57cec5SDimitry Andric   return *Info;
2850b57cec5SDimitry Andric }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric Expected<DbiStream &> PDBFile::getPDBDbiStream() {
2880b57cec5SDimitry Andric   if (!Dbi) {
2890b57cec5SDimitry Andric     auto DbiS = safelyCreateIndexedStream(StreamDBI);
2900b57cec5SDimitry Andric     if (!DbiS)
2910b57cec5SDimitry Andric       return DbiS.takeError();
2928bcb0991SDimitry Andric     auto TempDbi = std::make_unique<DbiStream>(std::move(*DbiS));
2930b57cec5SDimitry Andric     if (auto EC = TempDbi->reload(this))
2940b57cec5SDimitry Andric       return std::move(EC);
2950b57cec5SDimitry Andric     Dbi = std::move(TempDbi);
2960b57cec5SDimitry Andric   }
2970b57cec5SDimitry Andric   return *Dbi;
2980b57cec5SDimitry Andric }
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric Expected<TpiStream &> PDBFile::getPDBTpiStream() {
3010b57cec5SDimitry Andric   if (!Tpi) {
3020b57cec5SDimitry Andric     auto TpiS = safelyCreateIndexedStream(StreamTPI);
3030b57cec5SDimitry Andric     if (!TpiS)
3040b57cec5SDimitry Andric       return TpiS.takeError();
3058bcb0991SDimitry Andric     auto TempTpi = std::make_unique<TpiStream>(*this, std::move(*TpiS));
3060b57cec5SDimitry Andric     if (auto EC = TempTpi->reload())
3070b57cec5SDimitry Andric       return std::move(EC);
3080b57cec5SDimitry Andric     Tpi = std::move(TempTpi);
3090b57cec5SDimitry Andric   }
3100b57cec5SDimitry Andric   return *Tpi;
3110b57cec5SDimitry Andric }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric Expected<TpiStream &> PDBFile::getPDBIpiStream() {
3140b57cec5SDimitry Andric   if (!Ipi) {
3150b57cec5SDimitry Andric     if (!hasPDBIpiStream())
3160b57cec5SDimitry Andric       return make_error<RawError>(raw_error_code::no_stream);
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric     auto IpiS = safelyCreateIndexedStream(StreamIPI);
3190b57cec5SDimitry Andric     if (!IpiS)
3200b57cec5SDimitry Andric       return IpiS.takeError();
3218bcb0991SDimitry Andric     auto TempIpi = std::make_unique<TpiStream>(*this, std::move(*IpiS));
3220b57cec5SDimitry Andric     if (auto EC = TempIpi->reload())
3230b57cec5SDimitry Andric       return std::move(EC);
3240b57cec5SDimitry Andric     Ipi = std::move(TempIpi);
3250b57cec5SDimitry Andric   }
3260b57cec5SDimitry Andric   return *Ipi;
3270b57cec5SDimitry Andric }
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
3300b57cec5SDimitry Andric   if (!Publics) {
3310b57cec5SDimitry Andric     auto DbiS = getPDBDbiStream();
3320b57cec5SDimitry Andric     if (!DbiS)
3330b57cec5SDimitry Andric       return DbiS.takeError();
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric     auto PublicS =
3360b57cec5SDimitry Andric         safelyCreateIndexedStream(DbiS->getPublicSymbolStreamIndex());
3370b57cec5SDimitry Andric     if (!PublicS)
3380b57cec5SDimitry Andric       return PublicS.takeError();
3398bcb0991SDimitry Andric     auto TempPublics = std::make_unique<PublicsStream>(std::move(*PublicS));
3400b57cec5SDimitry Andric     if (auto EC = TempPublics->reload())
3410b57cec5SDimitry Andric       return std::move(EC);
3420b57cec5SDimitry Andric     Publics = std::move(TempPublics);
3430b57cec5SDimitry Andric   }
3440b57cec5SDimitry Andric   return *Publics;
3450b57cec5SDimitry Andric }
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
3480b57cec5SDimitry Andric   if (!Symbols) {
3490b57cec5SDimitry Andric     auto DbiS = getPDBDbiStream();
3500b57cec5SDimitry Andric     if (!DbiS)
3510b57cec5SDimitry Andric       return DbiS.takeError();
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric     uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
3540b57cec5SDimitry Andric     auto SymbolS = safelyCreateIndexedStream(SymbolStreamNum);
3550b57cec5SDimitry Andric     if (!SymbolS)
3560b57cec5SDimitry Andric       return SymbolS.takeError();
3570b57cec5SDimitry Andric 
3588bcb0991SDimitry Andric     auto TempSymbols = std::make_unique<SymbolStream>(std::move(*SymbolS));
3590b57cec5SDimitry Andric     if (auto EC = TempSymbols->reload())
3600b57cec5SDimitry Andric       return std::move(EC);
3610b57cec5SDimitry Andric     Symbols = std::move(TempSymbols);
3620b57cec5SDimitry Andric   }
3630b57cec5SDimitry Andric   return *Symbols;
3640b57cec5SDimitry Andric }
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric Expected<PDBStringTable &> PDBFile::getStringTable() {
3670b57cec5SDimitry Andric   if (!Strings) {
3680b57cec5SDimitry Andric     auto NS = safelyCreateNamedStream("/names");
3690b57cec5SDimitry Andric     if (!NS)
3700b57cec5SDimitry Andric       return NS.takeError();
3710b57cec5SDimitry Andric 
3728bcb0991SDimitry Andric     auto N = std::make_unique<PDBStringTable>();
3730b57cec5SDimitry Andric     BinaryStreamReader Reader(**NS);
3740b57cec5SDimitry Andric     if (auto EC = N->reload(Reader))
3750b57cec5SDimitry Andric       return std::move(EC);
3760b57cec5SDimitry Andric     assert(Reader.bytesRemaining() == 0);
3770b57cec5SDimitry Andric     StringTableStream = std::move(*NS);
3780b57cec5SDimitry Andric     Strings = std::move(N);
3790b57cec5SDimitry Andric   }
3800b57cec5SDimitry Andric   return *Strings;
3810b57cec5SDimitry Andric }
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric Expected<InjectedSourceStream &> PDBFile::getInjectedSourceStream() {
3840b57cec5SDimitry Andric   if (!InjectedSources) {
3850b57cec5SDimitry Andric     auto IJS = safelyCreateNamedStream("/src/headerblock");
3860b57cec5SDimitry Andric     if (!IJS)
3870b57cec5SDimitry Andric       return IJS.takeError();
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric     auto Strings = getStringTable();
3900b57cec5SDimitry Andric     if (!Strings)
3910b57cec5SDimitry Andric       return Strings.takeError();
3920b57cec5SDimitry Andric 
3938bcb0991SDimitry Andric     auto IJ = std::make_unique<InjectedSourceStream>(std::move(*IJS));
3940b57cec5SDimitry Andric     if (auto EC = IJ->reload(*Strings))
3950b57cec5SDimitry Andric       return std::move(EC);
3960b57cec5SDimitry Andric     InjectedSources = std::move(IJ);
3970b57cec5SDimitry Andric   }
3980b57cec5SDimitry Andric   return *InjectedSources;
3990b57cec5SDimitry Andric }
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric uint32_t PDBFile::getPointerSize() {
4020b57cec5SDimitry Andric   auto DbiS = getPDBDbiStream();
4030b57cec5SDimitry Andric   if (!DbiS)
4040b57cec5SDimitry Andric     return 0;
4050b57cec5SDimitry Andric   PDB_Machine Machine = DbiS->getMachineType();
4060b57cec5SDimitry Andric   if (Machine == PDB_Machine::Amd64)
4070b57cec5SDimitry Andric     return 8;
4080b57cec5SDimitry Andric   return 4;
4090b57cec5SDimitry Andric }
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric bool PDBFile::hasPDBDbiStream() const {
4120b57cec5SDimitry Andric   return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0;
4130b57cec5SDimitry Andric }
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric bool PDBFile::hasPDBGlobalsStream() {
4160b57cec5SDimitry Andric   auto DbiS = getPDBDbiStream();
4170b57cec5SDimitry Andric   if (!DbiS) {
4180b57cec5SDimitry Andric     consumeError(DbiS.takeError());
4190b57cec5SDimitry Andric     return false;
4200b57cec5SDimitry Andric   }
4210b57cec5SDimitry Andric 
4220b57cec5SDimitry Andric   return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
4230b57cec5SDimitry Andric }
4240b57cec5SDimitry Andric 
4250b57cec5SDimitry Andric bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); }
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric bool PDBFile::hasPDBIpiStream() const {
4280b57cec5SDimitry Andric   if (!hasPDBInfoStream())
4290b57cec5SDimitry Andric     return false;
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric   if (StreamIPI >= getNumStreams())
4320b57cec5SDimitry Andric     return false;
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric   auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
4350b57cec5SDimitry Andric   return InfoStream.containsIdStream();
4360b57cec5SDimitry Andric }
4370b57cec5SDimitry Andric 
4380b57cec5SDimitry Andric bool PDBFile::hasPDBPublicsStream() {
4390b57cec5SDimitry Andric   auto DbiS = getPDBDbiStream();
4400b57cec5SDimitry Andric   if (!DbiS) {
4410b57cec5SDimitry Andric     consumeError(DbiS.takeError());
4420b57cec5SDimitry Andric     return false;
4430b57cec5SDimitry Andric   }
4440b57cec5SDimitry Andric   return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
4450b57cec5SDimitry Andric }
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric bool PDBFile::hasPDBSymbolStream() {
4480b57cec5SDimitry Andric   auto DbiS = getPDBDbiStream();
4490b57cec5SDimitry Andric   if (!DbiS)
4500b57cec5SDimitry Andric     return false;
4510b57cec5SDimitry Andric   return DbiS->getSymRecordStreamIndex() < getNumStreams();
4520b57cec5SDimitry Andric }
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric bool PDBFile::hasPDBStringTable() {
4570b57cec5SDimitry Andric   auto IS = getPDBInfoStream();
4580b57cec5SDimitry Andric   if (!IS)
4590b57cec5SDimitry Andric     return false;
4600b57cec5SDimitry Andric   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
4610b57cec5SDimitry Andric   if (!ExpectedNSI) {
4620b57cec5SDimitry Andric     consumeError(ExpectedNSI.takeError());
4630b57cec5SDimitry Andric     return false;
4640b57cec5SDimitry Andric   }
4650b57cec5SDimitry Andric   assert(*ExpectedNSI < getNumStreams());
4660b57cec5SDimitry Andric   return true;
4670b57cec5SDimitry Andric }
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric bool PDBFile::hasPDBInjectedSourceStream() {
4700b57cec5SDimitry Andric   auto IS = getPDBInfoStream();
4710b57cec5SDimitry Andric   if (!IS)
4720b57cec5SDimitry Andric     return false;
4730b57cec5SDimitry Andric   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/src/headerblock");
4740b57cec5SDimitry Andric   if (!ExpectedNSI) {
4750b57cec5SDimitry Andric     consumeError(ExpectedNSI.takeError());
4760b57cec5SDimitry Andric     return false;
4770b57cec5SDimitry Andric   }
4780b57cec5SDimitry Andric   assert(*ExpectedNSI < getNumStreams());
4790b57cec5SDimitry Andric   return true;
4800b57cec5SDimitry Andric }
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
4830b57cec5SDimitry Andric /// stream with that index actually exists.  If it does not, the return value
4840b57cec5SDimitry Andric /// will have an MSFError with code msf_error_code::no_stream.  Else, the return
4850b57cec5SDimitry Andric /// value will contain the stream returned by createIndexedStream().
4860b57cec5SDimitry Andric Expected<std::unique_ptr<MappedBlockStream>>
4870b57cec5SDimitry Andric PDBFile::safelyCreateIndexedStream(uint32_t StreamIndex) const {
4880b57cec5SDimitry Andric   if (StreamIndex >= getNumStreams())
4890b57cec5SDimitry Andric     // This rejects kInvalidStreamIndex with an error as well.
4900b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::no_stream);
4910b57cec5SDimitry Andric   return createIndexedStream(StreamIndex);
4920b57cec5SDimitry Andric }
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric Expected<std::unique_ptr<MappedBlockStream>>
4950b57cec5SDimitry Andric PDBFile::safelyCreateNamedStream(StringRef Name) {
4960b57cec5SDimitry Andric   auto IS = getPDBInfoStream();
4970b57cec5SDimitry Andric   if (!IS)
4980b57cec5SDimitry Andric     return IS.takeError();
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex(Name);
5010b57cec5SDimitry Andric   if (!ExpectedNSI)
5020b57cec5SDimitry Andric     return ExpectedNSI.takeError();
5030b57cec5SDimitry Andric   uint32_t NameStreamIndex = *ExpectedNSI;
5040b57cec5SDimitry Andric 
5050b57cec5SDimitry Andric   return safelyCreateIndexedStream(NameStreamIndex);
5060b57cec5SDimitry Andric }
507