17a7e6055SDimitry Andric //===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
27a7e6055SDimitry Andric //
37a7e6055SDimitry Andric // The LLVM Compiler Infrastructure
47a7e6055SDimitry Andric //
57a7e6055SDimitry Andric // This file is distributed under the University of Illinois Open Source
67a7e6055SDimitry Andric // License. See LICENSE.TXT for details.
77a7e6055SDimitry Andric //
87a7e6055SDimitry Andric //===----------------------------------------------------------------------===//
97a7e6055SDimitry Andric
107a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
117a7e6055SDimitry Andric #include "llvm/ADT/ArrayRef.h"
127a7e6055SDimitry Andric #include "llvm/ADT/STLExtras.h"
137a7e6055SDimitry Andric #include "llvm/DebugInfo/MSF/MSFCommon.h"
147a7e6055SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
157a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
167a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
177a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
18f37b6182SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
197a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
207a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
217a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
227a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
237a7e6055SDimitry Andric #include "llvm/Support/BinaryStream.h"
247a7e6055SDimitry Andric #include "llvm/Support/BinaryStreamArray.h"
257a7e6055SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
267a7e6055SDimitry Andric #include "llvm/Support/Endian.h"
277a7e6055SDimitry Andric #include "llvm/Support/Error.h"
287a7e6055SDimitry Andric #include "llvm/Support/Path.h"
297a7e6055SDimitry Andric #include <algorithm>
307a7e6055SDimitry Andric #include <cassert>
317a7e6055SDimitry Andric #include <cstdint>
327a7e6055SDimitry Andric
337a7e6055SDimitry Andric using namespace llvm;
347a7e6055SDimitry Andric using namespace llvm::codeview;
357a7e6055SDimitry Andric using namespace llvm::msf;
367a7e6055SDimitry Andric using namespace llvm::pdb;
377a7e6055SDimitry Andric
387a7e6055SDimitry Andric namespace {
397a7e6055SDimitry Andric typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
407a7e6055SDimitry Andric } // end anonymous namespace
417a7e6055SDimitry Andric
PDBFile(StringRef Path,std::unique_ptr<BinaryStream> PdbFileBuffer,BumpPtrAllocator & Allocator)427a7e6055SDimitry Andric PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer,
437a7e6055SDimitry Andric BumpPtrAllocator &Allocator)
447a7e6055SDimitry Andric : FilePath(Path), Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {}
457a7e6055SDimitry Andric
467a7e6055SDimitry Andric PDBFile::~PDBFile() = default;
477a7e6055SDimitry Andric
getFilePath() const487a7e6055SDimitry Andric StringRef PDBFile::getFilePath() const { return FilePath; }
497a7e6055SDimitry Andric
getFileDirectory() const507a7e6055SDimitry Andric StringRef PDBFile::getFileDirectory() const {
517a7e6055SDimitry Andric return sys::path::parent_path(FilePath);
527a7e6055SDimitry Andric }
537a7e6055SDimitry Andric
getBlockSize() const547a7e6055SDimitry Andric uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
557a7e6055SDimitry Andric
getFreeBlockMapBlock() const567a7e6055SDimitry Andric uint32_t PDBFile::getFreeBlockMapBlock() const {
577a7e6055SDimitry Andric return ContainerLayout.SB->FreeBlockMapBlock;
587a7e6055SDimitry Andric }
597a7e6055SDimitry Andric
getBlockCount() const607a7e6055SDimitry Andric uint32_t PDBFile::getBlockCount() const {
617a7e6055SDimitry Andric return ContainerLayout.SB->NumBlocks;
627a7e6055SDimitry Andric }
637a7e6055SDimitry Andric
getNumDirectoryBytes() const647a7e6055SDimitry Andric uint32_t PDBFile::getNumDirectoryBytes() const {
657a7e6055SDimitry Andric return ContainerLayout.SB->NumDirectoryBytes;
667a7e6055SDimitry Andric }
677a7e6055SDimitry Andric
getBlockMapIndex() const687a7e6055SDimitry Andric uint32_t PDBFile::getBlockMapIndex() const {
697a7e6055SDimitry Andric return ContainerLayout.SB->BlockMapAddr;
707a7e6055SDimitry Andric }
717a7e6055SDimitry Andric
getUnknown1() const727a7e6055SDimitry Andric uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
737a7e6055SDimitry Andric
getNumDirectoryBlocks() const747a7e6055SDimitry Andric uint32_t PDBFile::getNumDirectoryBlocks() const {
757a7e6055SDimitry Andric return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
767a7e6055SDimitry Andric ContainerLayout.SB->BlockSize);
777a7e6055SDimitry Andric }
787a7e6055SDimitry Andric
getBlockMapOffset() const797a7e6055SDimitry Andric uint64_t PDBFile::getBlockMapOffset() const {
807a7e6055SDimitry Andric return (uint64_t)ContainerLayout.SB->BlockMapAddr *
817a7e6055SDimitry Andric ContainerLayout.SB->BlockSize;
827a7e6055SDimitry Andric }
837a7e6055SDimitry Andric
getNumStreams() const847a7e6055SDimitry Andric uint32_t PDBFile::getNumStreams() const {
857a7e6055SDimitry Andric return ContainerLayout.StreamSizes.size();
867a7e6055SDimitry Andric }
877a7e6055SDimitry Andric
getMaxStreamSize() const882cab237bSDimitry Andric uint32_t PDBFile::getMaxStreamSize() const {
892cab237bSDimitry Andric return *std::max_element(ContainerLayout.StreamSizes.begin(),
902cab237bSDimitry Andric ContainerLayout.StreamSizes.end());
912cab237bSDimitry Andric }
922cab237bSDimitry Andric
getStreamByteSize(uint32_t StreamIndex) const937a7e6055SDimitry Andric uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
947a7e6055SDimitry Andric return ContainerLayout.StreamSizes[StreamIndex];
957a7e6055SDimitry Andric }
967a7e6055SDimitry Andric
977a7e6055SDimitry Andric ArrayRef<support::ulittle32_t>
getStreamBlockList(uint32_t StreamIndex) const987a7e6055SDimitry Andric PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
997a7e6055SDimitry Andric return ContainerLayout.StreamMap[StreamIndex];
1007a7e6055SDimitry Andric }
1017a7e6055SDimitry Andric
getFileSize() const1027a7e6055SDimitry Andric uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
1037a7e6055SDimitry Andric
getBlockData(uint32_t BlockIndex,uint32_t NumBytes) const1047a7e6055SDimitry Andric Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
1057a7e6055SDimitry Andric uint32_t NumBytes) const {
1067a7e6055SDimitry Andric uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
1077a7e6055SDimitry Andric
1087a7e6055SDimitry Andric ArrayRef<uint8_t> Result;
1097a7e6055SDimitry Andric if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
1107a7e6055SDimitry Andric return std::move(EC);
1117a7e6055SDimitry Andric return Result;
1127a7e6055SDimitry Andric }
1137a7e6055SDimitry Andric
setBlockData(uint32_t BlockIndex,uint32_t Offset,ArrayRef<uint8_t> Data) const1147a7e6055SDimitry Andric Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
1157a7e6055SDimitry Andric ArrayRef<uint8_t> Data) const {
1167a7e6055SDimitry Andric return make_error<RawError>(raw_error_code::not_writable,
1177a7e6055SDimitry Andric "PDBFile is immutable");
1187a7e6055SDimitry Andric }
1197a7e6055SDimitry Andric
parseFileHeaders()1207a7e6055SDimitry Andric Error PDBFile::parseFileHeaders() {
1217a7e6055SDimitry Andric BinaryStreamReader Reader(*Buffer);
1227a7e6055SDimitry Andric
1237a7e6055SDimitry Andric // Initialize SB.
1247a7e6055SDimitry Andric const msf::SuperBlock *SB = nullptr;
1257a7e6055SDimitry Andric if (auto EC = Reader.readObject(SB)) {
1267a7e6055SDimitry Andric consumeError(std::move(EC));
1277a7e6055SDimitry Andric return make_error<RawError>(raw_error_code::corrupt_file,
128*b5893f02SDimitry Andric "MSF superblock is missing");
1297a7e6055SDimitry Andric }
1307a7e6055SDimitry Andric
1317a7e6055SDimitry Andric if (auto EC = msf::validateSuperBlock(*SB))
1327a7e6055SDimitry Andric return EC;
1337a7e6055SDimitry Andric
1347a7e6055SDimitry Andric if (Buffer->getLength() % SB->BlockSize != 0)
1357a7e6055SDimitry Andric return make_error<RawError>(raw_error_code::corrupt_file,
1367a7e6055SDimitry Andric "File size is not a multiple of block size");
1377a7e6055SDimitry Andric ContainerLayout.SB = SB;
1387a7e6055SDimitry Andric
1397a7e6055SDimitry Andric // Initialize Free Page Map.
1407a7e6055SDimitry Andric ContainerLayout.FreePageMap.resize(SB->NumBlocks);
1417a7e6055SDimitry Andric // The Fpm exists either at block 1 or block 2 of the MSF. However, this
1427a7e6055SDimitry Andric // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
1437a7e6055SDimitry Andric // thusly an equal number of total blocks in the file. For a block size
1447a7e6055SDimitry Andric // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
1457a7e6055SDimitry Andric // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so
1467a7e6055SDimitry Andric // the Fpm is split across the file at `getBlockSize()` intervals. As a
1477a7e6055SDimitry Andric // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
1487a7e6055SDimitry Andric // for any non-negative integer k is an Fpm block. In theory, we only really
1497a7e6055SDimitry Andric // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
1507a7e6055SDimitry Andric // current versions of the MSF format already expect the Fpm to be arranged
1517a7e6055SDimitry Andric // at getBlockSize() intervals, so we have to be compatible.
1527a7e6055SDimitry Andric // See the function fpmPn() for more information:
1537a7e6055SDimitry Andric // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
1546d97bb29SDimitry Andric auto FpmStream =
1556d97bb29SDimitry Andric MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
1567a7e6055SDimitry Andric BinaryStreamReader FpmReader(*FpmStream);
1577a7e6055SDimitry Andric ArrayRef<uint8_t> FpmBytes;
1582cab237bSDimitry Andric if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
1597a7e6055SDimitry Andric return EC;
1607a7e6055SDimitry Andric uint32_t BlocksRemaining = getBlockCount();
1617a7e6055SDimitry Andric uint32_t BI = 0;
1627a7e6055SDimitry Andric for (auto Byte : FpmBytes) {
1637a7e6055SDimitry Andric uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
1647a7e6055SDimitry Andric for (uint32_t I = 0; I < BlocksThisByte; ++I) {
1657a7e6055SDimitry Andric if (Byte & (1 << I))
1667a7e6055SDimitry Andric ContainerLayout.FreePageMap[BI] = true;
1677a7e6055SDimitry Andric --BlocksRemaining;
1687a7e6055SDimitry Andric ++BI;
1697a7e6055SDimitry Andric }
1707a7e6055SDimitry Andric }
1717a7e6055SDimitry Andric
1727a7e6055SDimitry Andric Reader.setOffset(getBlockMapOffset());
1737a7e6055SDimitry Andric if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
1747a7e6055SDimitry Andric getNumDirectoryBlocks()))
1757a7e6055SDimitry Andric return EC;
1767a7e6055SDimitry Andric
1777a7e6055SDimitry Andric return Error::success();
1787a7e6055SDimitry Andric }
1797a7e6055SDimitry Andric
parseStreamData()1807a7e6055SDimitry Andric Error PDBFile::parseStreamData() {
1817a7e6055SDimitry Andric assert(ContainerLayout.SB);
1827a7e6055SDimitry Andric if (DirectoryStream)
1837a7e6055SDimitry Andric return Error::success();
1847a7e6055SDimitry Andric
1857a7e6055SDimitry Andric uint32_t NumStreams = 0;
1867a7e6055SDimitry Andric
1877a7e6055SDimitry Andric // Normally you can't use a MappedBlockStream without having fully parsed the
1887a7e6055SDimitry Andric // PDB file, because it accesses the directory and various other things, which
1897a7e6055SDimitry Andric // is exactly what we are attempting to parse. By specifying a custom
1907a7e6055SDimitry Andric // subclass of IPDBStreamData which only accesses the fields that have already
1917a7e6055SDimitry Andric // been parsed, we can avoid this and reuse MappedBlockStream.
1926d97bb29SDimitry Andric auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer,
1936d97bb29SDimitry Andric Allocator);
1947a7e6055SDimitry Andric BinaryStreamReader Reader(*DS);
1957a7e6055SDimitry Andric if (auto EC = Reader.readInteger(NumStreams))
1967a7e6055SDimitry Andric return EC;
1977a7e6055SDimitry Andric
1987a7e6055SDimitry Andric if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
1997a7e6055SDimitry Andric return EC;
2007a7e6055SDimitry Andric for (uint32_t I = 0; I < NumStreams; ++I) {
2017a7e6055SDimitry Andric uint32_t StreamSize = getStreamByteSize(I);
2027a7e6055SDimitry Andric // FIXME: What does StreamSize ~0U mean?
2037a7e6055SDimitry Andric uint64_t NumExpectedStreamBlocks =
2047a7e6055SDimitry Andric StreamSize == UINT32_MAX
2057a7e6055SDimitry Andric ? 0
2067a7e6055SDimitry Andric : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
2077a7e6055SDimitry Andric
2087a7e6055SDimitry Andric // For convenience, we store the block array contiguously. This is because
2097a7e6055SDimitry Andric // if someone calls setStreamMap(), it is more convenient to be able to call
2107a7e6055SDimitry Andric // it with an ArrayRef instead of setting up a StreamRef. Since the
2117a7e6055SDimitry Andric // DirectoryStream is cached in the class and thus lives for the life of the
2127a7e6055SDimitry Andric // class, we can be guaranteed that readArray() will return a stable
2137a7e6055SDimitry Andric // reference, even if it has to allocate from its internal pool.
2147a7e6055SDimitry Andric ArrayRef<support::ulittle32_t> Blocks;
2157a7e6055SDimitry Andric if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
2167a7e6055SDimitry Andric return EC;
2177a7e6055SDimitry Andric for (uint32_t Block : Blocks) {
2187a7e6055SDimitry Andric uint64_t BlockEndOffset =
2197a7e6055SDimitry Andric (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
2207a7e6055SDimitry Andric if (BlockEndOffset > getFileSize())
2217a7e6055SDimitry Andric return make_error<RawError>(raw_error_code::corrupt_file,
2227a7e6055SDimitry Andric "Stream block map is corrupt.");
2237a7e6055SDimitry Andric }
2247a7e6055SDimitry Andric ContainerLayout.StreamMap.push_back(Blocks);
2257a7e6055SDimitry Andric }
2267a7e6055SDimitry Andric
2277a7e6055SDimitry Andric // We should have read exactly SB->NumDirectoryBytes bytes.
2287a7e6055SDimitry Andric assert(Reader.bytesRemaining() == 0);
2297a7e6055SDimitry Andric DirectoryStream = std::move(DS);
2307a7e6055SDimitry Andric return Error::success();
2317a7e6055SDimitry Andric }
2327a7e6055SDimitry Andric
getDirectoryBlockArray() const2337a7e6055SDimitry Andric ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
2347a7e6055SDimitry Andric return ContainerLayout.DirectoryBlocks;
2357a7e6055SDimitry Andric }
2367a7e6055SDimitry Andric
createIndexedStream(uint16_t SN)2372cab237bSDimitry Andric std::unique_ptr<MappedBlockStream> PDBFile::createIndexedStream(uint16_t SN) {
2382cab237bSDimitry Andric if (SN == kInvalidStreamIndex)
2392cab237bSDimitry Andric return nullptr;
2402cab237bSDimitry Andric return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
2412cab237bSDimitry Andric Allocator);
2422cab237bSDimitry Andric }
2432cab237bSDimitry Andric
getStreamLayout(uint32_t StreamIdx) const244edd7eaddSDimitry Andric MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
245edd7eaddSDimitry Andric MSFStreamLayout Result;
246edd7eaddSDimitry Andric auto Blocks = getStreamBlockList(StreamIdx);
247edd7eaddSDimitry Andric Result.Blocks.assign(Blocks.begin(), Blocks.end());
248edd7eaddSDimitry Andric Result.Length = getStreamByteSize(StreamIdx);
249edd7eaddSDimitry Andric return Result;
250edd7eaddSDimitry Andric }
251edd7eaddSDimitry Andric
getFpmStreamLayout() const2522cab237bSDimitry Andric msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const {
2532cab237bSDimitry Andric return msf::getFpmStreamLayout(ContainerLayout);
2542cab237bSDimitry Andric }
2552cab237bSDimitry Andric
getPDBGlobalsStream()2567a7e6055SDimitry Andric Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
2577a7e6055SDimitry Andric if (!Globals) {
2587a7e6055SDimitry Andric auto DbiS = getPDBDbiStream();
2597a7e6055SDimitry Andric if (!DbiS)
2607a7e6055SDimitry Andric return DbiS.takeError();
2617a7e6055SDimitry Andric
2627a7e6055SDimitry Andric auto GlobalS = safelyCreateIndexedStream(
2637a7e6055SDimitry Andric ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex());
2647a7e6055SDimitry Andric if (!GlobalS)
2657a7e6055SDimitry Andric return GlobalS.takeError();
2667a7e6055SDimitry Andric auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS));
2677a7e6055SDimitry Andric if (auto EC = TempGlobals->reload())
2687a7e6055SDimitry Andric return std::move(EC);
2697a7e6055SDimitry Andric Globals = std::move(TempGlobals);
2707a7e6055SDimitry Andric }
2717a7e6055SDimitry Andric return *Globals;
2727a7e6055SDimitry Andric }
2737a7e6055SDimitry Andric
getPDBInfoStream()2747a7e6055SDimitry Andric Expected<InfoStream &> PDBFile::getPDBInfoStream() {
2757a7e6055SDimitry Andric if (!Info) {
2767a7e6055SDimitry Andric auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB);
2777a7e6055SDimitry Andric if (!InfoS)
2787a7e6055SDimitry Andric return InfoS.takeError();
2797a7e6055SDimitry Andric auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
2807a7e6055SDimitry Andric if (auto EC = TempInfo->reload())
2817a7e6055SDimitry Andric return std::move(EC);
2827a7e6055SDimitry Andric Info = std::move(TempInfo);
2837a7e6055SDimitry Andric }
2847a7e6055SDimitry Andric return *Info;
2857a7e6055SDimitry Andric }
2867a7e6055SDimitry Andric
getPDBDbiStream()2877a7e6055SDimitry Andric Expected<DbiStream &> PDBFile::getPDBDbiStream() {
2887a7e6055SDimitry Andric if (!Dbi) {
2897a7e6055SDimitry Andric auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI);
2907a7e6055SDimitry Andric if (!DbiS)
2917a7e6055SDimitry Andric return DbiS.takeError();
2924ba319b5SDimitry Andric auto TempDbi = llvm::make_unique<DbiStream>(std::move(*DbiS));
2934ba319b5SDimitry Andric if (auto EC = TempDbi->reload(this))
2947a7e6055SDimitry Andric return std::move(EC);
2957a7e6055SDimitry Andric Dbi = std::move(TempDbi);
2967a7e6055SDimitry Andric }
2977a7e6055SDimitry Andric return *Dbi;
2987a7e6055SDimitry Andric }
2997a7e6055SDimitry Andric
getPDBTpiStream()3007a7e6055SDimitry Andric Expected<TpiStream &> PDBFile::getPDBTpiStream() {
3017a7e6055SDimitry Andric if (!Tpi) {
3027a7e6055SDimitry Andric auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI);
3037a7e6055SDimitry Andric if (!TpiS)
3047a7e6055SDimitry Andric return TpiS.takeError();
3057a7e6055SDimitry Andric auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
3067a7e6055SDimitry Andric if (auto EC = TempTpi->reload())
3077a7e6055SDimitry Andric return std::move(EC);
3087a7e6055SDimitry Andric Tpi = std::move(TempTpi);
3097a7e6055SDimitry Andric }
3107a7e6055SDimitry Andric return *Tpi;
3117a7e6055SDimitry Andric }
3127a7e6055SDimitry Andric
getPDBIpiStream()3137a7e6055SDimitry Andric Expected<TpiStream &> PDBFile::getPDBIpiStream() {
3147a7e6055SDimitry Andric if (!Ipi) {
3152cab237bSDimitry Andric if (!hasPDBIpiStream())
3162cab237bSDimitry Andric return make_error<RawError>(raw_error_code::no_stream);
3172cab237bSDimitry Andric
3187a7e6055SDimitry Andric auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI);
3197a7e6055SDimitry Andric if (!IpiS)
3207a7e6055SDimitry Andric return IpiS.takeError();
3217a7e6055SDimitry Andric auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
3227a7e6055SDimitry Andric if (auto EC = TempIpi->reload())
3237a7e6055SDimitry Andric return std::move(EC);
3247a7e6055SDimitry Andric Ipi = std::move(TempIpi);
3257a7e6055SDimitry Andric }
3267a7e6055SDimitry Andric return *Ipi;
3277a7e6055SDimitry Andric }
3287a7e6055SDimitry Andric
getPDBPublicsStream()3297a7e6055SDimitry Andric Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
3307a7e6055SDimitry Andric if (!Publics) {
3317a7e6055SDimitry Andric auto DbiS = getPDBDbiStream();
3327a7e6055SDimitry Andric if (!DbiS)
3337a7e6055SDimitry Andric return DbiS.takeError();
3347a7e6055SDimitry Andric
3357a7e6055SDimitry Andric auto PublicS = safelyCreateIndexedStream(
3367a7e6055SDimitry Andric ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex());
3377a7e6055SDimitry Andric if (!PublicS)
3387a7e6055SDimitry Andric return PublicS.takeError();
3392cab237bSDimitry Andric auto TempPublics = llvm::make_unique<PublicsStream>(std::move(*PublicS));
3407a7e6055SDimitry Andric if (auto EC = TempPublics->reload())
3417a7e6055SDimitry Andric return std::move(EC);
3427a7e6055SDimitry Andric Publics = std::move(TempPublics);
3437a7e6055SDimitry Andric }
3447a7e6055SDimitry Andric return *Publics;
3457a7e6055SDimitry Andric }
3467a7e6055SDimitry Andric
getPDBSymbolStream()3477a7e6055SDimitry Andric Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
3487a7e6055SDimitry Andric if (!Symbols) {
3497a7e6055SDimitry Andric auto DbiS = getPDBDbiStream();
3507a7e6055SDimitry Andric if (!DbiS)
3517a7e6055SDimitry Andric return DbiS.takeError();
3527a7e6055SDimitry Andric
3537a7e6055SDimitry Andric uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
3547a7e6055SDimitry Andric auto SymbolS =
3557a7e6055SDimitry Andric safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum);
3567a7e6055SDimitry Andric if (!SymbolS)
3577a7e6055SDimitry Andric return SymbolS.takeError();
3587a7e6055SDimitry Andric
3597a7e6055SDimitry Andric auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
3607a7e6055SDimitry Andric if (auto EC = TempSymbols->reload())
3617a7e6055SDimitry Andric return std::move(EC);
3627a7e6055SDimitry Andric Symbols = std::move(TempSymbols);
3637a7e6055SDimitry Andric }
3647a7e6055SDimitry Andric return *Symbols;
3657a7e6055SDimitry Andric }
3667a7e6055SDimitry Andric
getStringTable()367f37b6182SDimitry Andric Expected<PDBStringTable &> PDBFile::getStringTable() {
368f37b6182SDimitry Andric if (!Strings) {
3697a7e6055SDimitry Andric auto IS = getPDBInfoStream();
3707a7e6055SDimitry Andric if (!IS)
3717a7e6055SDimitry Andric return IS.takeError();
3727a7e6055SDimitry Andric
3734ba319b5SDimitry Andric Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
3744ba319b5SDimitry Andric if (!ExpectedNSI)
3754ba319b5SDimitry Andric return ExpectedNSI.takeError();
3764ba319b5SDimitry Andric uint32_t NameStreamIndex = *ExpectedNSI;
3777a7e6055SDimitry Andric
3787a7e6055SDimitry Andric auto NS =
3797a7e6055SDimitry Andric safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex);
3807a7e6055SDimitry Andric if (!NS)
3817a7e6055SDimitry Andric return NS.takeError();
3827a7e6055SDimitry Andric
383f37b6182SDimitry Andric auto N = llvm::make_unique<PDBStringTable>();
3847a7e6055SDimitry Andric BinaryStreamReader Reader(**NS);
385f37b6182SDimitry Andric if (auto EC = N->reload(Reader))
3867a7e6055SDimitry Andric return std::move(EC);
387f37b6182SDimitry Andric assert(Reader.bytesRemaining() == 0);
3887a7e6055SDimitry Andric StringTableStream = std::move(*NS);
389f37b6182SDimitry Andric Strings = std::move(N);
3907a7e6055SDimitry Andric }
3917a7e6055SDimitry Andric return *Strings;
3927a7e6055SDimitry Andric }
3937a7e6055SDimitry Andric
getPointerSize()39424d58133SDimitry Andric uint32_t PDBFile::getPointerSize() {
39524d58133SDimitry Andric auto DbiS = getPDBDbiStream();
39624d58133SDimitry Andric if (!DbiS)
39724d58133SDimitry Andric return 0;
39824d58133SDimitry Andric PDB_Machine Machine = DbiS->getMachineType();
39924d58133SDimitry Andric if (Machine == PDB_Machine::Amd64)
40024d58133SDimitry Andric return 8;
40124d58133SDimitry Andric return 4;
40224d58133SDimitry Andric }
40324d58133SDimitry Andric
hasPDBDbiStream() const404*b5893f02SDimitry Andric bool PDBFile::hasPDBDbiStream() const {
405*b5893f02SDimitry Andric return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0;
406*b5893f02SDimitry Andric }
4077a7e6055SDimitry Andric
hasPDBGlobalsStream()4087a7e6055SDimitry Andric bool PDBFile::hasPDBGlobalsStream() {
4097a7e6055SDimitry Andric auto DbiS = getPDBDbiStream();
410c4394386SDimitry Andric if (!DbiS) {
411c4394386SDimitry Andric consumeError(DbiS.takeError());
4127a7e6055SDimitry Andric return false;
413c4394386SDimitry Andric }
414c4394386SDimitry Andric
4157a7e6055SDimitry Andric return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
4167a7e6055SDimitry Andric }
4177a7e6055SDimitry Andric
hasPDBInfoStream() const4182cab237bSDimitry Andric bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); }
4197a7e6055SDimitry Andric
hasPDBIpiStream() const4202cab237bSDimitry Andric bool PDBFile::hasPDBIpiStream() const {
4212cab237bSDimitry Andric if (!hasPDBInfoStream())
4222cab237bSDimitry Andric return false;
4232cab237bSDimitry Andric
4242cab237bSDimitry Andric if (StreamIPI >= getNumStreams())
4252cab237bSDimitry Andric return false;
4262cab237bSDimitry Andric
4272cab237bSDimitry Andric auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
4282cab237bSDimitry Andric return InfoStream.containsIdStream();
4292cab237bSDimitry Andric }
4307a7e6055SDimitry Andric
hasPDBPublicsStream()4317a7e6055SDimitry Andric bool PDBFile::hasPDBPublicsStream() {
4327a7e6055SDimitry Andric auto DbiS = getPDBDbiStream();
433c4394386SDimitry Andric if (!DbiS) {
434c4394386SDimitry Andric consumeError(DbiS.takeError());
4357a7e6055SDimitry Andric return false;
436c4394386SDimitry Andric }
4377a7e6055SDimitry Andric return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
4387a7e6055SDimitry Andric }
4397a7e6055SDimitry Andric
hasPDBSymbolStream()4407a7e6055SDimitry Andric bool PDBFile::hasPDBSymbolStream() {
4417a7e6055SDimitry Andric auto DbiS = getPDBDbiStream();
4427a7e6055SDimitry Andric if (!DbiS)
4437a7e6055SDimitry Andric return false;
4447a7e6055SDimitry Andric return DbiS->getSymRecordStreamIndex() < getNumStreams();
4457a7e6055SDimitry Andric }
4467a7e6055SDimitry Andric
hasPDBTpiStream() const4477a7e6055SDimitry Andric bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
4487a7e6055SDimitry Andric
hasPDBStringTable()449f37b6182SDimitry Andric bool PDBFile::hasPDBStringTable() {
4507a7e6055SDimitry Andric auto IS = getPDBInfoStream();
4517a7e6055SDimitry Andric if (!IS)
4527a7e6055SDimitry Andric return false;
4534ba319b5SDimitry Andric Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
4544ba319b5SDimitry Andric if (!ExpectedNSI) {
4554ba319b5SDimitry Andric consumeError(ExpectedNSI.takeError());
4564ba319b5SDimitry Andric return false;
4574ba319b5SDimitry Andric }
4584ba319b5SDimitry Andric assert(*ExpectedNSI < getNumStreams());
4594ba319b5SDimitry Andric return true;
4607a7e6055SDimitry Andric }
4617a7e6055SDimitry Andric
4627a7e6055SDimitry Andric /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
4637a7e6055SDimitry Andric /// stream with that index actually exists. If it does not, the return value
4647a7e6055SDimitry Andric /// will have an MSFError with code msf_error_code::no_stream. Else, the return
4657a7e6055SDimitry Andric /// value will contain the stream returned by createIndexedStream().
4667a7e6055SDimitry Andric Expected<std::unique_ptr<MappedBlockStream>>
safelyCreateIndexedStream(const MSFLayout & Layout,BinaryStreamRef MsfData,uint32_t StreamIndex) const4677a7e6055SDimitry Andric PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout,
4687a7e6055SDimitry Andric BinaryStreamRef MsfData,
4697a7e6055SDimitry Andric uint32_t StreamIndex) const {
4707a7e6055SDimitry Andric if (StreamIndex >= getNumStreams())
4717a7e6055SDimitry Andric return make_error<RawError>(raw_error_code::no_stream);
4726d97bb29SDimitry Andric return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex,
4736d97bb29SDimitry Andric Allocator);
4747a7e6055SDimitry Andric }
475