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