1317017Sdim//===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===// 2317017Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6317017Sdim// 7317017Sdim//===----------------------------------------------------------------------===// 8317017Sdim 9317017Sdim#include "llvm/DebugInfo/PDB/Native/PDBFile.h" 10317017Sdim#include "llvm/ADT/ArrayRef.h" 11317017Sdim#include "llvm/ADT/STLExtras.h" 12317017Sdim#include "llvm/DebugInfo/MSF/MSFCommon.h" 13317017Sdim#include "llvm/DebugInfo/MSF/MappedBlockStream.h" 14317017Sdim#include "llvm/DebugInfo/PDB/Native/DbiStream.h" 15317017Sdim#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" 16317017Sdim#include "llvm/DebugInfo/PDB/Native/InfoStream.h" 17353358Sdim#include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h" 18317778Sdim#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" 19317017Sdim#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" 20317017Sdim#include "llvm/DebugInfo/PDB/Native/RawError.h" 21317017Sdim#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" 22317017Sdim#include "llvm/DebugInfo/PDB/Native/TpiStream.h" 23317017Sdim#include "llvm/Support/BinaryStream.h" 24317017Sdim#include "llvm/Support/BinaryStreamArray.h" 25317017Sdim#include "llvm/Support/BinaryStreamReader.h" 26317017Sdim#include "llvm/Support/Endian.h" 27317017Sdim#include "llvm/Support/Error.h" 28317017Sdim#include "llvm/Support/Path.h" 29317017Sdim#include <algorithm> 30317017Sdim#include <cassert> 31317017Sdim#include <cstdint> 32317017Sdim 33317017Sdimusing namespace llvm; 34317017Sdimusing namespace llvm::codeview; 35317017Sdimusing namespace llvm::msf; 36317017Sdimusing namespace llvm::pdb; 37317017Sdim 38317017Sdimnamespace { 39317017Sdimtypedef FixedStreamArray<support::ulittle32_t> ulittle_array; 40317017Sdim} // end anonymous namespace 41317017Sdim 42317017SdimPDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer, 43317017Sdim BumpPtrAllocator &Allocator) 44317017Sdim : FilePath(Path), Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {} 45317017Sdim 46317017SdimPDBFile::~PDBFile() = default; 47317017Sdim 48317017SdimStringRef PDBFile::getFilePath() const { return FilePath; } 49317017Sdim 50317017SdimStringRef PDBFile::getFileDirectory() const { 51317017Sdim return sys::path::parent_path(FilePath); 52317017Sdim} 53317017Sdim 54317017Sdimuint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; } 55317017Sdim 56317017Sdimuint32_t PDBFile::getFreeBlockMapBlock() const { 57317017Sdim return ContainerLayout.SB->FreeBlockMapBlock; 58317017Sdim} 59317017Sdim 60317017Sdimuint32_t PDBFile::getBlockCount() const { 61317017Sdim return ContainerLayout.SB->NumBlocks; 62317017Sdim} 63317017Sdim 64317017Sdimuint32_t PDBFile::getNumDirectoryBytes() const { 65317017Sdim return ContainerLayout.SB->NumDirectoryBytes; 66317017Sdim} 67317017Sdim 68317017Sdimuint32_t PDBFile::getBlockMapIndex() const { 69317017Sdim return ContainerLayout.SB->BlockMapAddr; 70317017Sdim} 71317017Sdim 72317017Sdimuint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; } 73317017Sdim 74317017Sdimuint32_t PDBFile::getNumDirectoryBlocks() const { 75317017Sdim return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes, 76317017Sdim ContainerLayout.SB->BlockSize); 77317017Sdim} 78317017Sdim 79317017Sdimuint64_t PDBFile::getBlockMapOffset() const { 80317017Sdim return (uint64_t)ContainerLayout.SB->BlockMapAddr * 81317017Sdim ContainerLayout.SB->BlockSize; 82317017Sdim} 83317017Sdim 84317017Sdimuint32_t PDBFile::getNumStreams() const { 85317017Sdim return ContainerLayout.StreamSizes.size(); 86317017Sdim} 87317017Sdim 88327952Sdimuint32_t PDBFile::getMaxStreamSize() const { 89327952Sdim return *std::max_element(ContainerLayout.StreamSizes.begin(), 90327952Sdim ContainerLayout.StreamSizes.end()); 91327952Sdim} 92327952Sdim 93317017Sdimuint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const { 94317017Sdim return ContainerLayout.StreamSizes[StreamIndex]; 95317017Sdim} 96317017Sdim 97317017SdimArrayRef<support::ulittle32_t> 98317017SdimPDBFile::getStreamBlockList(uint32_t StreamIndex) const { 99317017Sdim return ContainerLayout.StreamMap[StreamIndex]; 100317017Sdim} 101317017Sdim 102317017Sdimuint32_t PDBFile::getFileSize() const { return Buffer->getLength(); } 103317017Sdim 104317017SdimExpected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex, 105317017Sdim uint32_t NumBytes) const { 106317017Sdim uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize()); 107317017Sdim 108317017Sdim ArrayRef<uint8_t> Result; 109317017Sdim if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result)) 110317017Sdim return std::move(EC); 111317017Sdim return Result; 112317017Sdim} 113317017Sdim 114317017SdimError PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset, 115317017Sdim ArrayRef<uint8_t> Data) const { 116317017Sdim return make_error<RawError>(raw_error_code::not_writable, 117317017Sdim "PDBFile is immutable"); 118317017Sdim} 119317017Sdim 120317017SdimError PDBFile::parseFileHeaders() { 121317017Sdim BinaryStreamReader Reader(*Buffer); 122317017Sdim 123317017Sdim // Initialize SB. 124317017Sdim const msf::SuperBlock *SB = nullptr; 125317017Sdim if (auto EC = Reader.readObject(SB)) { 126317017Sdim consumeError(std::move(EC)); 127317017Sdim return make_error<RawError>(raw_error_code::corrupt_file, 128344779Sdim "MSF superblock is missing"); 129317017Sdim } 130317017Sdim 131317017Sdim if (auto EC = msf::validateSuperBlock(*SB)) 132317017Sdim return EC; 133317017Sdim 134317017Sdim if (Buffer->getLength() % SB->BlockSize != 0) 135317017Sdim return make_error<RawError>(raw_error_code::corrupt_file, 136317017Sdim "File size is not a multiple of block size"); 137317017Sdim ContainerLayout.SB = SB; 138317017Sdim 139317017Sdim // Initialize Free Page Map. 140317017Sdim ContainerLayout.FreePageMap.resize(SB->NumBlocks); 141317017Sdim // The Fpm exists either at block 1 or block 2 of the MSF. However, this 142317017Sdim // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and 143317017Sdim // thusly an equal number of total blocks in the file. For a block size 144317017Sdim // of 4KiB (very common), this would yield 32KiB total blocks in file, for a 145317017Sdim // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so 146317017Sdim // the Fpm is split across the file at `getBlockSize()` intervals. As a 147317017Sdim // result, every block whose index is of the form |{1,2} + getBlockSize() * k| 148317017Sdim // for any non-negative integer k is an Fpm block. In theory, we only really 149317017Sdim // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but 150317017Sdim // current versions of the MSF format already expect the Fpm to be arranged 151317017Sdim // at getBlockSize() intervals, so we have to be compatible. 152317017Sdim // See the function fpmPn() for more information: 153317017Sdim // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489 154319547Sdim auto FpmStream = 155319547Sdim MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator); 156317017Sdim BinaryStreamReader FpmReader(*FpmStream); 157317017Sdim ArrayRef<uint8_t> FpmBytes; 158327952Sdim if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining())) 159317017Sdim return EC; 160317017Sdim uint32_t BlocksRemaining = getBlockCount(); 161317017Sdim uint32_t BI = 0; 162317017Sdim for (auto Byte : FpmBytes) { 163317017Sdim uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U); 164317017Sdim for (uint32_t I = 0; I < BlocksThisByte; ++I) { 165317017Sdim if (Byte & (1 << I)) 166317017Sdim ContainerLayout.FreePageMap[BI] = true; 167317017Sdim --BlocksRemaining; 168317017Sdim ++BI; 169317017Sdim } 170317017Sdim } 171317017Sdim 172317017Sdim Reader.setOffset(getBlockMapOffset()); 173317017Sdim if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks, 174317017Sdim getNumDirectoryBlocks())) 175317017Sdim return EC; 176317017Sdim 177317017Sdim return Error::success(); 178317017Sdim} 179317017Sdim 180317017SdimError PDBFile::parseStreamData() { 181317017Sdim assert(ContainerLayout.SB); 182317017Sdim if (DirectoryStream) 183317017Sdim return Error::success(); 184317017Sdim 185317017Sdim uint32_t NumStreams = 0; 186317017Sdim 187317017Sdim // Normally you can't use a MappedBlockStream without having fully parsed the 188317017Sdim // PDB file, because it accesses the directory and various other things, which 189317017Sdim // is exactly what we are attempting to parse. By specifying a custom 190317017Sdim // subclass of IPDBStreamData which only accesses the fields that have already 191317017Sdim // been parsed, we can avoid this and reuse MappedBlockStream. 192319547Sdim auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer, 193319547Sdim Allocator); 194317017Sdim BinaryStreamReader Reader(*DS); 195317017Sdim if (auto EC = Reader.readInteger(NumStreams)) 196317017Sdim return EC; 197317017Sdim 198317017Sdim if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams)) 199317017Sdim return EC; 200317017Sdim for (uint32_t I = 0; I < NumStreams; ++I) { 201317017Sdim uint32_t StreamSize = getStreamByteSize(I); 202317017Sdim // FIXME: What does StreamSize ~0U mean? 203317017Sdim uint64_t NumExpectedStreamBlocks = 204317017Sdim StreamSize == UINT32_MAX 205317017Sdim ? 0 206317017Sdim : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize); 207317017Sdim 208317017Sdim // For convenience, we store the block array contiguously. This is because 209317017Sdim // if someone calls setStreamMap(), it is more convenient to be able to call 210317017Sdim // it with an ArrayRef instead of setting up a StreamRef. Since the 211317017Sdim // DirectoryStream is cached in the class and thus lives for the life of the 212317017Sdim // class, we can be guaranteed that readArray() will return a stable 213317017Sdim // reference, even if it has to allocate from its internal pool. 214317017Sdim ArrayRef<support::ulittle32_t> Blocks; 215317017Sdim if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks)) 216317017Sdim return EC; 217317017Sdim for (uint32_t Block : Blocks) { 218317017Sdim uint64_t BlockEndOffset = 219317017Sdim (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize; 220317017Sdim if (BlockEndOffset > getFileSize()) 221317017Sdim return make_error<RawError>(raw_error_code::corrupt_file, 222317017Sdim "Stream block map is corrupt."); 223317017Sdim } 224317017Sdim ContainerLayout.StreamMap.push_back(Blocks); 225317017Sdim } 226317017Sdim 227317017Sdim // We should have read exactly SB->NumDirectoryBytes bytes. 228317017Sdim assert(Reader.bytesRemaining() == 0); 229317017Sdim DirectoryStream = std::move(DS); 230317017Sdim return Error::success(); 231317017Sdim} 232317017Sdim 233317017SdimArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const { 234317017Sdim return ContainerLayout.DirectoryBlocks; 235317017Sdim} 236317017Sdim 237353358Sdimstd::unique_ptr<MappedBlockStream> 238353358SdimPDBFile::createIndexedStream(uint16_t SN) const { 239327952Sdim if (SN == kInvalidStreamIndex) 240327952Sdim return nullptr; 241327952Sdim return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN, 242327952Sdim Allocator); 243327952Sdim} 244327952Sdim 245320397SdimMSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const { 246320397Sdim MSFStreamLayout Result; 247320397Sdim auto Blocks = getStreamBlockList(StreamIdx); 248320397Sdim Result.Blocks.assign(Blocks.begin(), Blocks.end()); 249320397Sdim Result.Length = getStreamByteSize(StreamIdx); 250320397Sdim return Result; 251320397Sdim} 252320397Sdim 253327952Sdimmsf::MSFStreamLayout PDBFile::getFpmStreamLayout() const { 254327952Sdim return msf::getFpmStreamLayout(ContainerLayout); 255327952Sdim} 256327952Sdim 257317017SdimExpected<GlobalsStream &> PDBFile::getPDBGlobalsStream() { 258317017Sdim if (!Globals) { 259317017Sdim auto DbiS = getPDBDbiStream(); 260317017Sdim if (!DbiS) 261317017Sdim return DbiS.takeError(); 262317017Sdim 263353358Sdim auto GlobalS = 264353358Sdim safelyCreateIndexedStream(DbiS->getGlobalSymbolStreamIndex()); 265317017Sdim if (!GlobalS) 266317017Sdim return GlobalS.takeError(); 267360784Sdim auto TempGlobals = std::make_unique<GlobalsStream>(std::move(*GlobalS)); 268317017Sdim if (auto EC = TempGlobals->reload()) 269317017Sdim return std::move(EC); 270317017Sdim Globals = std::move(TempGlobals); 271317017Sdim } 272317017Sdim return *Globals; 273317017Sdim} 274317017Sdim 275317017SdimExpected<InfoStream &> PDBFile::getPDBInfoStream() { 276317017Sdim if (!Info) { 277353358Sdim auto InfoS = safelyCreateIndexedStream(StreamPDB); 278317017Sdim if (!InfoS) 279317017Sdim return InfoS.takeError(); 280360784Sdim auto TempInfo = std::make_unique<InfoStream>(std::move(*InfoS)); 281317017Sdim if (auto EC = TempInfo->reload()) 282317017Sdim return std::move(EC); 283317017Sdim Info = std::move(TempInfo); 284317017Sdim } 285317017Sdim return *Info; 286317017Sdim} 287317017Sdim 288317017SdimExpected<DbiStream &> PDBFile::getPDBDbiStream() { 289317017Sdim if (!Dbi) { 290353358Sdim auto DbiS = safelyCreateIndexedStream(StreamDBI); 291317017Sdim if (!DbiS) 292317017Sdim return DbiS.takeError(); 293360784Sdim auto TempDbi = std::make_unique<DbiStream>(std::move(*DbiS)); 294341825Sdim if (auto EC = TempDbi->reload(this)) 295317017Sdim return std::move(EC); 296317017Sdim Dbi = std::move(TempDbi); 297317017Sdim } 298317017Sdim return *Dbi; 299317017Sdim} 300317017Sdim 301317017SdimExpected<TpiStream &> PDBFile::getPDBTpiStream() { 302317017Sdim if (!Tpi) { 303353358Sdim auto TpiS = safelyCreateIndexedStream(StreamTPI); 304317017Sdim if (!TpiS) 305317017Sdim return TpiS.takeError(); 306360784Sdim auto TempTpi = std::make_unique<TpiStream>(*this, std::move(*TpiS)); 307317017Sdim if (auto EC = TempTpi->reload()) 308317017Sdim return std::move(EC); 309317017Sdim Tpi = std::move(TempTpi); 310317017Sdim } 311317017Sdim return *Tpi; 312317017Sdim} 313317017Sdim 314317017SdimExpected<TpiStream &> PDBFile::getPDBIpiStream() { 315317017Sdim if (!Ipi) { 316327952Sdim if (!hasPDBIpiStream()) 317327952Sdim return make_error<RawError>(raw_error_code::no_stream); 318327952Sdim 319353358Sdim auto IpiS = safelyCreateIndexedStream(StreamIPI); 320317017Sdim if (!IpiS) 321317017Sdim return IpiS.takeError(); 322360784Sdim auto TempIpi = std::make_unique<TpiStream>(*this, std::move(*IpiS)); 323317017Sdim if (auto EC = TempIpi->reload()) 324317017Sdim return std::move(EC); 325317017Sdim Ipi = std::move(TempIpi); 326317017Sdim } 327317017Sdim return *Ipi; 328317017Sdim} 329317017Sdim 330317017SdimExpected<PublicsStream &> PDBFile::getPDBPublicsStream() { 331317017Sdim if (!Publics) { 332317017Sdim auto DbiS = getPDBDbiStream(); 333317017Sdim if (!DbiS) 334317017Sdim return DbiS.takeError(); 335317017Sdim 336353358Sdim auto PublicS = 337353358Sdim safelyCreateIndexedStream(DbiS->getPublicSymbolStreamIndex()); 338317017Sdim if (!PublicS) 339317017Sdim return PublicS.takeError(); 340360784Sdim auto TempPublics = std::make_unique<PublicsStream>(std::move(*PublicS)); 341317017Sdim if (auto EC = TempPublics->reload()) 342317017Sdim return std::move(EC); 343317017Sdim Publics = std::move(TempPublics); 344317017Sdim } 345317017Sdim return *Publics; 346317017Sdim} 347317017Sdim 348317017SdimExpected<SymbolStream &> PDBFile::getPDBSymbolStream() { 349317017Sdim if (!Symbols) { 350317017Sdim auto DbiS = getPDBDbiStream(); 351317017Sdim if (!DbiS) 352317017Sdim return DbiS.takeError(); 353317017Sdim 354317017Sdim uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex(); 355353358Sdim auto SymbolS = safelyCreateIndexedStream(SymbolStreamNum); 356317017Sdim if (!SymbolS) 357317017Sdim return SymbolS.takeError(); 358317017Sdim 359360784Sdim auto TempSymbols = std::make_unique<SymbolStream>(std::move(*SymbolS)); 360317017Sdim if (auto EC = TempSymbols->reload()) 361317017Sdim return std::move(EC); 362317017Sdim Symbols = std::move(TempSymbols); 363317017Sdim } 364317017Sdim return *Symbols; 365317017Sdim} 366317017Sdim 367317778SdimExpected<PDBStringTable &> PDBFile::getStringTable() { 368317778Sdim if (!Strings) { 369353358Sdim auto NS = safelyCreateNamedStream("/names"); 370317017Sdim if (!NS) 371317017Sdim return NS.takeError(); 372317017Sdim 373360784Sdim auto N = std::make_unique<PDBStringTable>(); 374317017Sdim BinaryStreamReader Reader(**NS); 375317778Sdim if (auto EC = N->reload(Reader)) 376317017Sdim return std::move(EC); 377317778Sdim assert(Reader.bytesRemaining() == 0); 378317778Sdim StringTableStream = std::move(*NS); 379317017Sdim Strings = std::move(N); 380317017Sdim } 381317017Sdim return *Strings; 382317017Sdim} 383317017Sdim 384353358SdimExpected<InjectedSourceStream &> PDBFile::getInjectedSourceStream() { 385353358Sdim if (!InjectedSources) { 386353358Sdim auto IJS = safelyCreateNamedStream("/src/headerblock"); 387353358Sdim if (!IJS) 388353358Sdim return IJS.takeError(); 389353358Sdim 390353358Sdim auto Strings = getStringTable(); 391353358Sdim if (!Strings) 392353358Sdim return Strings.takeError(); 393353358Sdim 394360784Sdim auto IJ = std::make_unique<InjectedSourceStream>(std::move(*IJS)); 395353358Sdim if (auto EC = IJ->reload(*Strings)) 396353358Sdim return std::move(EC); 397353358Sdim InjectedSources = std::move(IJ); 398353358Sdim } 399353358Sdim return *InjectedSources; 400353358Sdim} 401353358Sdim 402320041Sdimuint32_t PDBFile::getPointerSize() { 403320041Sdim auto DbiS = getPDBDbiStream(); 404320041Sdim if (!DbiS) 405320041Sdim return 0; 406320041Sdim PDB_Machine Machine = DbiS->getMachineType(); 407320041Sdim if (Machine == PDB_Machine::Amd64) 408320041Sdim return 8; 409320041Sdim return 4; 410320041Sdim} 411320041Sdim 412344779Sdimbool PDBFile::hasPDBDbiStream() const { 413344779Sdim return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0; 414344779Sdim} 415317017Sdim 416317017Sdimbool PDBFile::hasPDBGlobalsStream() { 417317017Sdim auto DbiS = getPDBDbiStream(); 418320970Sdim if (!DbiS) { 419320970Sdim consumeError(DbiS.takeError()); 420317017Sdim return false; 421320970Sdim } 422320970Sdim 423317017Sdim return DbiS->getGlobalSymbolStreamIndex() < getNumStreams(); 424317017Sdim} 425317017Sdim 426327952Sdimbool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); } 427317017Sdim 428327952Sdimbool PDBFile::hasPDBIpiStream() const { 429327952Sdim if (!hasPDBInfoStream()) 430327952Sdim return false; 431317017Sdim 432327952Sdim if (StreamIPI >= getNumStreams()) 433327952Sdim return false; 434327952Sdim 435327952Sdim auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream()); 436327952Sdim return InfoStream.containsIdStream(); 437327952Sdim} 438327952Sdim 439317017Sdimbool PDBFile::hasPDBPublicsStream() { 440317017Sdim auto DbiS = getPDBDbiStream(); 441320970Sdim if (!DbiS) { 442320970Sdim consumeError(DbiS.takeError()); 443317017Sdim return false; 444320970Sdim } 445317017Sdim return DbiS->getPublicSymbolStreamIndex() < getNumStreams(); 446317017Sdim} 447317017Sdim 448317017Sdimbool PDBFile::hasPDBSymbolStream() { 449317017Sdim auto DbiS = getPDBDbiStream(); 450317017Sdim if (!DbiS) 451317017Sdim return false; 452317017Sdim return DbiS->getSymRecordStreamIndex() < getNumStreams(); 453317017Sdim} 454317017Sdim 455317017Sdimbool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); } 456317017Sdim 457317778Sdimbool PDBFile::hasPDBStringTable() { 458317017Sdim auto IS = getPDBInfoStream(); 459317017Sdim if (!IS) 460317017Sdim return false; 461341825Sdim Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names"); 462341825Sdim if (!ExpectedNSI) { 463341825Sdim consumeError(ExpectedNSI.takeError()); 464341825Sdim return false; 465341825Sdim } 466341825Sdim assert(*ExpectedNSI < getNumStreams()); 467341825Sdim return true; 468317017Sdim} 469317017Sdim 470353358Sdimbool PDBFile::hasPDBInjectedSourceStream() { 471353358Sdim auto IS = getPDBInfoStream(); 472353358Sdim if (!IS) 473353358Sdim return false; 474353358Sdim Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/src/headerblock"); 475353358Sdim if (!ExpectedNSI) { 476353358Sdim consumeError(ExpectedNSI.takeError()); 477353358Sdim return false; 478353358Sdim } 479353358Sdim assert(*ExpectedNSI < getNumStreams()); 480353358Sdim return true; 481353358Sdim} 482353358Sdim 483317017Sdim/// Wrapper around MappedBlockStream::createIndexedStream() that checks if a 484317017Sdim/// stream with that index actually exists. If it does not, the return value 485317017Sdim/// will have an MSFError with code msf_error_code::no_stream. Else, the return 486317017Sdim/// value will contain the stream returned by createIndexedStream(). 487317017SdimExpected<std::unique_ptr<MappedBlockStream>> 488353358SdimPDBFile::safelyCreateIndexedStream(uint32_t StreamIndex) const { 489317017Sdim if (StreamIndex >= getNumStreams()) 490353358Sdim // This rejects kInvalidStreamIndex with an error as well. 491317017Sdim return make_error<RawError>(raw_error_code::no_stream); 492353358Sdim return createIndexedStream(StreamIndex); 493317017Sdim} 494353358Sdim 495353358SdimExpected<std::unique_ptr<MappedBlockStream>> 496353358SdimPDBFile::safelyCreateNamedStream(StringRef Name) { 497353358Sdim auto IS = getPDBInfoStream(); 498353358Sdim if (!IS) 499353358Sdim return IS.takeError(); 500353358Sdim 501353358Sdim Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex(Name); 502353358Sdim if (!ExpectedNSI) 503353358Sdim return ExpectedNSI.takeError(); 504353358Sdim uint32_t NameStreamIndex = *ExpectedNSI; 505353358Sdim 506353358Sdim return safelyCreateIndexedStream(NameStreamIndex); 507353358Sdim} 508