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