xref: /src/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
101095a5dSDimitry Andric //===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
201095a5dSDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
601095a5dSDimitry Andric //
701095a5dSDimitry Andric //===----------------------------------------------------------------------===//
801095a5dSDimitry Andric 
971d5a254SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
1001095a5dSDimitry Andric #include "llvm/ADT/ArrayRef.h"
11b915e9e0SDimitry Andric #include "llvm/DebugInfo/MSF/MSFCommon.h"
1271d5a254SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
1371d5a254SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
1471d5a254SDimitry Andric #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
1571d5a254SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
16e6d15924SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h"
17148779dfSDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
1871d5a254SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
1971d5a254SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
2071d5a254SDimitry Andric #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
2171d5a254SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
2271d5a254SDimitry Andric #include "llvm/Support/BinaryStream.h"
2371d5a254SDimitry Andric #include "llvm/Support/BinaryStreamArray.h"
2471d5a254SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
2501095a5dSDimitry Andric #include "llvm/Support/Endian.h"
26b915e9e0SDimitry Andric #include "llvm/Support/Error.h"
2771d5a254SDimitry Andric #include "llvm/Support/Path.h"
28b915e9e0SDimitry Andric #include <algorithm>
29b915e9e0SDimitry Andric #include <cassert>
30b915e9e0SDimitry Andric #include <cstdint>
3101095a5dSDimitry Andric 
3201095a5dSDimitry Andric using namespace llvm;
3301095a5dSDimitry Andric using namespace llvm::codeview;
34b915e9e0SDimitry Andric using namespace llvm::msf;
3501095a5dSDimitry Andric using namespace llvm::pdb;
3601095a5dSDimitry Andric 
3701095a5dSDimitry Andric namespace {
3801095a5dSDimitry Andric typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
39b915e9e0SDimitry Andric } // end anonymous namespace
40b915e9e0SDimitry Andric 
PDBFile(StringRef Path,std::unique_ptr<BinaryStream> PdbFileBuffer,BumpPtrAllocator & Allocator)4171d5a254SDimitry Andric PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer,
42b915e9e0SDimitry Andric                  BumpPtrAllocator &Allocator)
43cfca06d7SDimitry Andric     : FilePath(std::string(Path)), Allocator(Allocator),
44cfca06d7SDimitry Andric       Buffer(std::move(PdbFileBuffer)) {}
45b915e9e0SDimitry Andric 
46b915e9e0SDimitry Andric PDBFile::~PDBFile() = default;
47b915e9e0SDimitry Andric 
getFilePath() const4871d5a254SDimitry Andric StringRef PDBFile::getFilePath() const { return FilePath; }
4971d5a254SDimitry Andric 
getFileDirectory() const5071d5a254SDimitry Andric StringRef PDBFile::getFileDirectory() const {
5171d5a254SDimitry Andric   return sys::path::parent_path(FilePath);
5271d5a254SDimitry Andric }
5371d5a254SDimitry Andric 
getBlockSize() const54b915e9e0SDimitry Andric uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
55b915e9e0SDimitry Andric 
getFreeBlockMapBlock() const56b915e9e0SDimitry Andric uint32_t PDBFile::getFreeBlockMapBlock() const {
57b915e9e0SDimitry Andric   return ContainerLayout.SB->FreeBlockMapBlock;
5801095a5dSDimitry Andric }
5901095a5dSDimitry Andric 
getBlockCount() const60b915e9e0SDimitry Andric uint32_t PDBFile::getBlockCount() const {
61b915e9e0SDimitry Andric   return ContainerLayout.SB->NumBlocks;
62b915e9e0SDimitry Andric }
6301095a5dSDimitry Andric 
getNumDirectoryBytes() const64b915e9e0SDimitry Andric uint32_t PDBFile::getNumDirectoryBytes() const {
65b915e9e0SDimitry Andric   return ContainerLayout.SB->NumDirectoryBytes;
66b915e9e0SDimitry Andric }
6701095a5dSDimitry Andric 
getBlockMapIndex() const68b915e9e0SDimitry Andric uint32_t PDBFile::getBlockMapIndex() const {
69b915e9e0SDimitry Andric   return ContainerLayout.SB->BlockMapAddr;
70b915e9e0SDimitry Andric }
7101095a5dSDimitry Andric 
getUnknown1() const72b915e9e0SDimitry Andric uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
7301095a5dSDimitry Andric 
getNumDirectoryBlocks() const7401095a5dSDimitry Andric uint32_t PDBFile::getNumDirectoryBlocks() const {
75b915e9e0SDimitry Andric   return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
76b915e9e0SDimitry Andric                             ContainerLayout.SB->BlockSize);
7701095a5dSDimitry Andric }
7801095a5dSDimitry Andric 
getBlockMapOffset() const7901095a5dSDimitry Andric uint64_t PDBFile::getBlockMapOffset() const {
80b915e9e0SDimitry Andric   return (uint64_t)ContainerLayout.SB->BlockMapAddr *
81b915e9e0SDimitry Andric          ContainerLayout.SB->BlockSize;
8201095a5dSDimitry Andric }
8301095a5dSDimitry Andric 
getNumStreams() const84b915e9e0SDimitry Andric uint32_t PDBFile::getNumStreams() const {
85b915e9e0SDimitry Andric   return ContainerLayout.StreamSizes.size();
86b915e9e0SDimitry Andric }
8701095a5dSDimitry Andric 
getMaxStreamSize() const88044eb2f6SDimitry Andric uint32_t PDBFile::getMaxStreamSize() const {
89ac9a064cSDimitry Andric   return *llvm::max_element(ContainerLayout.StreamSizes);
90044eb2f6SDimitry Andric }
91044eb2f6SDimitry Andric 
getStreamByteSize(uint32_t StreamIndex) const9201095a5dSDimitry Andric uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
93b915e9e0SDimitry Andric   return ContainerLayout.StreamSizes[StreamIndex];
9401095a5dSDimitry Andric }
9501095a5dSDimitry Andric 
9601095a5dSDimitry Andric ArrayRef<support::ulittle32_t>
getStreamBlockList(uint32_t StreamIndex) const9701095a5dSDimitry Andric PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
98b915e9e0SDimitry Andric   return ContainerLayout.StreamMap[StreamIndex];
9901095a5dSDimitry Andric }
10001095a5dSDimitry Andric 
getFileSize() const10177fc4c14SDimitry Andric uint64_t PDBFile::getFileSize() const { return Buffer->getLength(); }
10201095a5dSDimitry Andric 
getBlockData(uint32_t BlockIndex,uint32_t NumBytes) const10301095a5dSDimitry Andric Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
10401095a5dSDimitry Andric                                                   uint32_t NumBytes) const {
10501095a5dSDimitry Andric   uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
10601095a5dSDimitry Andric 
10701095a5dSDimitry Andric   ArrayRef<uint8_t> Result;
10801095a5dSDimitry Andric   if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
10901095a5dSDimitry Andric     return std::move(EC);
11001095a5dSDimitry Andric   return Result;
11101095a5dSDimitry Andric }
11201095a5dSDimitry Andric 
setBlockData(uint32_t BlockIndex,uint32_t Offset,ArrayRef<uint8_t> Data) const11301095a5dSDimitry Andric Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
11401095a5dSDimitry Andric                             ArrayRef<uint8_t> Data) const {
115b915e9e0SDimitry Andric   return make_error<RawError>(raw_error_code::not_writable,
116b915e9e0SDimitry Andric                               "PDBFile is immutable");
11701095a5dSDimitry Andric }
11801095a5dSDimitry Andric 
parseFileHeaders()11901095a5dSDimitry Andric Error PDBFile::parseFileHeaders() {
12071d5a254SDimitry Andric   BinaryStreamReader Reader(*Buffer);
12101095a5dSDimitry Andric 
122b915e9e0SDimitry Andric   // Initialize SB.
123b915e9e0SDimitry Andric   const msf::SuperBlock *SB = nullptr;
12401095a5dSDimitry Andric   if (auto EC = Reader.readObject(SB)) {
12501095a5dSDimitry Andric     consumeError(std::move(EC));
12601095a5dSDimitry Andric     return make_error<RawError>(raw_error_code::corrupt_file,
127d8e91e46SDimitry Andric                                 "MSF superblock is missing");
12801095a5dSDimitry Andric   }
12901095a5dSDimitry Andric 
130b915e9e0SDimitry Andric   if (auto EC = msf::validateSuperBlock(*SB))
13101095a5dSDimitry Andric     return EC;
13201095a5dSDimitry Andric 
133b915e9e0SDimitry Andric   if (Buffer->getLength() % SB->BlockSize != 0)
134b915e9e0SDimitry Andric     return make_error<RawError>(raw_error_code::corrupt_file,
135b915e9e0SDimitry Andric                                 "File size is not a multiple of block size");
136b915e9e0SDimitry Andric   ContainerLayout.SB = SB;
137b915e9e0SDimitry Andric 
138b915e9e0SDimitry Andric   // Initialize Free Page Map.
139b915e9e0SDimitry Andric   ContainerLayout.FreePageMap.resize(SB->NumBlocks);
140b915e9e0SDimitry Andric   // The Fpm exists either at block 1 or block 2 of the MSF.  However, this
141b915e9e0SDimitry Andric   // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
142b915e9e0SDimitry Andric   // thusly an equal number of total blocks in the file.  For a block size
143b915e9e0SDimitry Andric   // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
144b915e9e0SDimitry Andric   // maximum file size of 32KiB * 4KiB = 128MiB.  Obviously this won't do, so
145b915e9e0SDimitry Andric   // the Fpm is split across the file at `getBlockSize()` intervals.  As a
146b915e9e0SDimitry Andric   // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
147b915e9e0SDimitry Andric   // for any non-negative integer k is an Fpm block.  In theory, we only really
148b915e9e0SDimitry Andric   // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
149b915e9e0SDimitry Andric   // current versions of the MSF format already expect the Fpm to be arranged
150b915e9e0SDimitry Andric   // at getBlockSize() intervals, so we have to be compatible.
151b915e9e0SDimitry Andric   // See the function fpmPn() for more information:
152b915e9e0SDimitry Andric   // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
153d288ef4cSDimitry Andric   auto FpmStream =
154d288ef4cSDimitry Andric       MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
15571d5a254SDimitry Andric   BinaryStreamReader FpmReader(*FpmStream);
156b915e9e0SDimitry Andric   ArrayRef<uint8_t> FpmBytes;
157044eb2f6SDimitry Andric   if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
158b915e9e0SDimitry Andric     return EC;
159b915e9e0SDimitry Andric   uint32_t BlocksRemaining = getBlockCount();
160b915e9e0SDimitry Andric   uint32_t BI = 0;
161b915e9e0SDimitry Andric   for (auto Byte : FpmBytes) {
162b915e9e0SDimitry Andric     uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
163b915e9e0SDimitry Andric     for (uint32_t I = 0; I < BlocksThisByte; ++I) {
164b915e9e0SDimitry Andric       if (Byte & (1 << I))
165b915e9e0SDimitry Andric         ContainerLayout.FreePageMap[BI] = true;
166b915e9e0SDimitry Andric       --BlocksRemaining;
167b915e9e0SDimitry Andric       ++BI;
168b915e9e0SDimitry Andric     }
169b915e9e0SDimitry Andric   }
170b915e9e0SDimitry Andric 
17101095a5dSDimitry Andric   Reader.setOffset(getBlockMapOffset());
172b915e9e0SDimitry Andric   if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
173b915e9e0SDimitry Andric                                  getNumDirectoryBlocks()))
17401095a5dSDimitry Andric     return EC;
17501095a5dSDimitry Andric 
17601095a5dSDimitry Andric   return Error::success();
17701095a5dSDimitry Andric }
17801095a5dSDimitry Andric 
parseStreamData()17901095a5dSDimitry Andric Error PDBFile::parseStreamData() {
180b915e9e0SDimitry Andric   assert(ContainerLayout.SB);
18101095a5dSDimitry Andric   if (DirectoryStream)
18201095a5dSDimitry Andric     return Error::success();
18301095a5dSDimitry Andric 
18401095a5dSDimitry Andric   uint32_t NumStreams = 0;
18501095a5dSDimitry Andric 
18601095a5dSDimitry Andric   // Normally you can't use a MappedBlockStream without having fully parsed the
18701095a5dSDimitry Andric   // PDB file, because it accesses the directory and various other things, which
18801095a5dSDimitry Andric   // is exactly what we are attempting to parse.  By specifying a custom
18901095a5dSDimitry Andric   // subclass of IPDBStreamData which only accesses the fields that have already
19001095a5dSDimitry Andric   // been parsed, we can avoid this and reuse MappedBlockStream.
191d288ef4cSDimitry Andric   auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer,
192d288ef4cSDimitry Andric                                                      Allocator);
19371d5a254SDimitry Andric   BinaryStreamReader Reader(*DS);
19401095a5dSDimitry Andric   if (auto EC = Reader.readInteger(NumStreams))
19501095a5dSDimitry Andric     return EC;
19601095a5dSDimitry Andric 
197b915e9e0SDimitry Andric   if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
19801095a5dSDimitry Andric     return EC;
19901095a5dSDimitry Andric   for (uint32_t I = 0; I < NumStreams; ++I) {
20001095a5dSDimitry Andric     uint32_t StreamSize = getStreamByteSize(I);
20101095a5dSDimitry Andric     // FIXME: What does StreamSize ~0U mean?
20201095a5dSDimitry Andric     uint64_t NumExpectedStreamBlocks =
203b915e9e0SDimitry Andric         StreamSize == UINT32_MAX
204b915e9e0SDimitry Andric             ? 0
205b915e9e0SDimitry Andric             : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
20601095a5dSDimitry Andric 
20701095a5dSDimitry Andric     // For convenience, we store the block array contiguously.  This is because
20801095a5dSDimitry Andric     // if someone calls setStreamMap(), it is more convenient to be able to call
20901095a5dSDimitry Andric     // it with an ArrayRef instead of setting up a StreamRef.  Since the
21001095a5dSDimitry Andric     // DirectoryStream is cached in the class and thus lives for the life of the
21101095a5dSDimitry Andric     // class, we can be guaranteed that readArray() will return a stable
21201095a5dSDimitry Andric     // reference, even if it has to allocate from its internal pool.
21301095a5dSDimitry Andric     ArrayRef<support::ulittle32_t> Blocks;
21401095a5dSDimitry Andric     if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
21501095a5dSDimitry Andric       return EC;
21601095a5dSDimitry Andric     for (uint32_t Block : Blocks) {
217b915e9e0SDimitry Andric       uint64_t BlockEndOffset =
218b915e9e0SDimitry Andric           (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
21901095a5dSDimitry Andric       if (BlockEndOffset > getFileSize())
22001095a5dSDimitry Andric         return make_error<RawError>(raw_error_code::corrupt_file,
22101095a5dSDimitry Andric                                     "Stream block map is corrupt.");
22201095a5dSDimitry Andric     }
223b915e9e0SDimitry Andric     ContainerLayout.StreamMap.push_back(Blocks);
22401095a5dSDimitry Andric   }
22501095a5dSDimitry Andric 
22601095a5dSDimitry Andric   // We should have read exactly SB->NumDirectoryBytes bytes.
22701095a5dSDimitry Andric   assert(Reader.bytesRemaining() == 0);
228b915e9e0SDimitry Andric   DirectoryStream = std::move(DS);
22901095a5dSDimitry Andric   return Error::success();
23001095a5dSDimitry Andric }
23101095a5dSDimitry Andric 
getDirectoryBlockArray() const232b915e9e0SDimitry Andric ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
233b915e9e0SDimitry Andric   return ContainerLayout.DirectoryBlocks;
234b915e9e0SDimitry Andric }
235b915e9e0SDimitry Andric 
236e6d15924SDimitry Andric std::unique_ptr<MappedBlockStream>
createIndexedStream(uint16_t SN) const237e6d15924SDimitry Andric PDBFile::createIndexedStream(uint16_t SN) const {
238044eb2f6SDimitry Andric   if (SN == kInvalidStreamIndex)
239044eb2f6SDimitry Andric     return nullptr;
240044eb2f6SDimitry Andric   return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
241044eb2f6SDimitry Andric                                                 Allocator);
242044eb2f6SDimitry Andric }
243044eb2f6SDimitry Andric 
getStreamLayout(uint32_t StreamIdx) const24408bbd35aSDimitry Andric MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
24508bbd35aSDimitry Andric   MSFStreamLayout Result;
24608bbd35aSDimitry Andric   auto Blocks = getStreamBlockList(StreamIdx);
24708bbd35aSDimitry Andric   Result.Blocks.assign(Blocks.begin(), Blocks.end());
24808bbd35aSDimitry Andric   Result.Length = getStreamByteSize(StreamIdx);
24908bbd35aSDimitry Andric   return Result;
25008bbd35aSDimitry Andric }
25108bbd35aSDimitry Andric 
getFpmStreamLayout() const252044eb2f6SDimitry Andric msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const {
253044eb2f6SDimitry Andric   return msf::getFpmStreamLayout(ContainerLayout);
254044eb2f6SDimitry Andric }
255044eb2f6SDimitry Andric 
getPDBGlobalsStream()256b915e9e0SDimitry Andric Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
257b915e9e0SDimitry Andric   if (!Globals) {
258b915e9e0SDimitry Andric     auto DbiS = getPDBDbiStream();
259b915e9e0SDimitry Andric     if (!DbiS)
260b915e9e0SDimitry Andric       return DbiS.takeError();
261b915e9e0SDimitry Andric 
262e6d15924SDimitry Andric     auto GlobalS =
263e6d15924SDimitry Andric         safelyCreateIndexedStream(DbiS->getGlobalSymbolStreamIndex());
26471d5a254SDimitry Andric     if (!GlobalS)
26571d5a254SDimitry Andric       return GlobalS.takeError();
2661d5ae102SDimitry Andric     auto TempGlobals = std::make_unique<GlobalsStream>(std::move(*GlobalS));
267b915e9e0SDimitry Andric     if (auto EC = TempGlobals->reload())
268b915e9e0SDimitry Andric       return std::move(EC);
269b915e9e0SDimitry Andric     Globals = std::move(TempGlobals);
270b915e9e0SDimitry Andric   }
271b915e9e0SDimitry Andric   return *Globals;
27201095a5dSDimitry Andric }
27301095a5dSDimitry Andric 
getPDBInfoStream()27401095a5dSDimitry Andric Expected<InfoStream &> PDBFile::getPDBInfoStream() {
27501095a5dSDimitry Andric   if (!Info) {
276e6d15924SDimitry Andric     auto InfoS = safelyCreateIndexedStream(StreamPDB);
27771d5a254SDimitry Andric     if (!InfoS)
27871d5a254SDimitry Andric       return InfoS.takeError();
2791d5ae102SDimitry Andric     auto TempInfo = std::make_unique<InfoStream>(std::move(*InfoS));
28001095a5dSDimitry Andric     if (auto EC = TempInfo->reload())
28101095a5dSDimitry Andric       return std::move(EC);
28201095a5dSDimitry Andric     Info = std::move(TempInfo);
28301095a5dSDimitry Andric   }
28401095a5dSDimitry Andric   return *Info;
28501095a5dSDimitry Andric }
28601095a5dSDimitry Andric 
getPDBDbiStream()28701095a5dSDimitry Andric Expected<DbiStream &> PDBFile::getPDBDbiStream() {
28801095a5dSDimitry Andric   if (!Dbi) {
289e6d15924SDimitry Andric     auto DbiS = safelyCreateIndexedStream(StreamDBI);
29071d5a254SDimitry Andric     if (!DbiS)
29171d5a254SDimitry Andric       return DbiS.takeError();
2921d5ae102SDimitry Andric     auto TempDbi = std::make_unique<DbiStream>(std::move(*DbiS));
293eb11fae6SDimitry Andric     if (auto EC = TempDbi->reload(this))
29401095a5dSDimitry Andric       return std::move(EC);
29501095a5dSDimitry Andric     Dbi = std::move(TempDbi);
29601095a5dSDimitry Andric   }
29701095a5dSDimitry Andric   return *Dbi;
29801095a5dSDimitry Andric }
29901095a5dSDimitry Andric 
getPDBTpiStream()30001095a5dSDimitry Andric Expected<TpiStream &> PDBFile::getPDBTpiStream() {
30101095a5dSDimitry Andric   if (!Tpi) {
302e6d15924SDimitry Andric     auto TpiS = safelyCreateIndexedStream(StreamTPI);
30371d5a254SDimitry Andric     if (!TpiS)
30471d5a254SDimitry Andric       return TpiS.takeError();
3051d5ae102SDimitry Andric     auto TempTpi = std::make_unique<TpiStream>(*this, std::move(*TpiS));
30601095a5dSDimitry Andric     if (auto EC = TempTpi->reload())
30701095a5dSDimitry Andric       return std::move(EC);
30801095a5dSDimitry Andric     Tpi = std::move(TempTpi);
30901095a5dSDimitry Andric   }
31001095a5dSDimitry Andric   return *Tpi;
31101095a5dSDimitry Andric }
31201095a5dSDimitry Andric 
getPDBIpiStream()31301095a5dSDimitry Andric Expected<TpiStream &> PDBFile::getPDBIpiStream() {
31401095a5dSDimitry Andric   if (!Ipi) {
315044eb2f6SDimitry Andric     if (!hasPDBIpiStream())
316044eb2f6SDimitry Andric       return make_error<RawError>(raw_error_code::no_stream);
317044eb2f6SDimitry Andric 
318e6d15924SDimitry Andric     auto IpiS = safelyCreateIndexedStream(StreamIPI);
31971d5a254SDimitry Andric     if (!IpiS)
32071d5a254SDimitry Andric       return IpiS.takeError();
3211d5ae102SDimitry Andric     auto TempIpi = std::make_unique<TpiStream>(*this, std::move(*IpiS));
32201095a5dSDimitry Andric     if (auto EC = TempIpi->reload())
32301095a5dSDimitry Andric       return std::move(EC);
32401095a5dSDimitry Andric     Ipi = std::move(TempIpi);
32501095a5dSDimitry Andric   }
32601095a5dSDimitry Andric   return *Ipi;
32701095a5dSDimitry Andric }
32801095a5dSDimitry Andric 
getPDBPublicsStream()32901095a5dSDimitry Andric Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
33001095a5dSDimitry Andric   if (!Publics) {
33101095a5dSDimitry Andric     auto DbiS = getPDBDbiStream();
33201095a5dSDimitry Andric     if (!DbiS)
33301095a5dSDimitry Andric       return DbiS.takeError();
33401095a5dSDimitry Andric 
335e6d15924SDimitry Andric     auto PublicS =
336e6d15924SDimitry Andric         safelyCreateIndexedStream(DbiS->getPublicSymbolStreamIndex());
33771d5a254SDimitry Andric     if (!PublicS)
33871d5a254SDimitry Andric       return PublicS.takeError();
3391d5ae102SDimitry Andric     auto TempPublics = std::make_unique<PublicsStream>(std::move(*PublicS));
34001095a5dSDimitry Andric     if (auto EC = TempPublics->reload())
34101095a5dSDimitry Andric       return std::move(EC);
34201095a5dSDimitry Andric     Publics = std::move(TempPublics);
34301095a5dSDimitry Andric   }
34401095a5dSDimitry Andric   return *Publics;
34501095a5dSDimitry Andric }
34601095a5dSDimitry Andric 
getPDBSymbolStream()34701095a5dSDimitry Andric Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
34801095a5dSDimitry Andric   if (!Symbols) {
34901095a5dSDimitry Andric     auto DbiS = getPDBDbiStream();
35001095a5dSDimitry Andric     if (!DbiS)
35101095a5dSDimitry Andric       return DbiS.takeError();
35201095a5dSDimitry Andric 
35301095a5dSDimitry Andric     uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
354e6d15924SDimitry Andric     auto SymbolS = safelyCreateIndexedStream(SymbolStreamNum);
35571d5a254SDimitry Andric     if (!SymbolS)
35671d5a254SDimitry Andric       return SymbolS.takeError();
357b915e9e0SDimitry Andric 
3581d5ae102SDimitry Andric     auto TempSymbols = std::make_unique<SymbolStream>(std::move(*SymbolS));
35901095a5dSDimitry Andric     if (auto EC = TempSymbols->reload())
36001095a5dSDimitry Andric       return std::move(EC);
36101095a5dSDimitry Andric     Symbols = std::move(TempSymbols);
36201095a5dSDimitry Andric   }
36301095a5dSDimitry Andric   return *Symbols;
36401095a5dSDimitry Andric }
36501095a5dSDimitry Andric 
getStringTable()366148779dfSDimitry Andric Expected<PDBStringTable &> PDBFile::getStringTable() {
367148779dfSDimitry Andric   if (!Strings) {
368e6d15924SDimitry Andric     auto NS = safelyCreateNamedStream("/names");
36971d5a254SDimitry Andric     if (!NS)
37071d5a254SDimitry Andric       return NS.takeError();
37101095a5dSDimitry Andric 
3721d5ae102SDimitry Andric     auto N = std::make_unique<PDBStringTable>();
37371d5a254SDimitry Andric     BinaryStreamReader Reader(**NS);
374148779dfSDimitry Andric     if (auto EC = N->reload(Reader))
37501095a5dSDimitry Andric       return std::move(EC);
376148779dfSDimitry Andric     assert(Reader.bytesRemaining() == 0);
37701095a5dSDimitry Andric     StringTableStream = std::move(*NS);
378148779dfSDimitry Andric     Strings = std::move(N);
37901095a5dSDimitry Andric   }
38071d5a254SDimitry Andric   return *Strings;
38101095a5dSDimitry Andric }
38201095a5dSDimitry Andric 
getInjectedSourceStream()383e6d15924SDimitry Andric Expected<InjectedSourceStream &> PDBFile::getInjectedSourceStream() {
384e6d15924SDimitry Andric   if (!InjectedSources) {
385e6d15924SDimitry Andric     auto IJS = safelyCreateNamedStream("/src/headerblock");
386e6d15924SDimitry Andric     if (!IJS)
387e6d15924SDimitry Andric       return IJS.takeError();
388e6d15924SDimitry Andric 
389e6d15924SDimitry Andric     auto Strings = getStringTable();
390e6d15924SDimitry Andric     if (!Strings)
391e6d15924SDimitry Andric       return Strings.takeError();
392e6d15924SDimitry Andric 
3931d5ae102SDimitry Andric     auto IJ = std::make_unique<InjectedSourceStream>(std::move(*IJS));
394e6d15924SDimitry Andric     if (auto EC = IJ->reload(*Strings))
395e6d15924SDimitry Andric       return std::move(EC);
396e6d15924SDimitry Andric     InjectedSources = std::move(IJ);
397e6d15924SDimitry Andric   }
398e6d15924SDimitry Andric   return *InjectedSources;
399e6d15924SDimitry Andric }
400e6d15924SDimitry Andric 
getPointerSize()4017c7aba6eSDimitry Andric uint32_t PDBFile::getPointerSize() {
4027c7aba6eSDimitry Andric   auto DbiS = getPDBDbiStream();
4037c7aba6eSDimitry Andric   if (!DbiS)
4047c7aba6eSDimitry Andric     return 0;
4057c7aba6eSDimitry Andric   PDB_Machine Machine = DbiS->getMachineType();
4067c7aba6eSDimitry Andric   if (Machine == PDB_Machine::Amd64)
4077c7aba6eSDimitry Andric     return 8;
4087c7aba6eSDimitry Andric   return 4;
4097c7aba6eSDimitry Andric }
4107c7aba6eSDimitry Andric 
hasPDBDbiStream() const411d8e91e46SDimitry Andric bool PDBFile::hasPDBDbiStream() const {
412d8e91e46SDimitry Andric   return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0;
413d8e91e46SDimitry Andric }
41401095a5dSDimitry Andric 
hasPDBGlobalsStream()415b915e9e0SDimitry Andric bool PDBFile::hasPDBGlobalsStream() {
416b915e9e0SDimitry Andric   auto DbiS = getPDBDbiStream();
417ca089b24SDimitry Andric   if (!DbiS) {
418ca089b24SDimitry Andric     consumeError(DbiS.takeError());
41971d5a254SDimitry Andric     return false;
420ca089b24SDimitry Andric   }
421ca089b24SDimitry Andric 
422b915e9e0SDimitry Andric   return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
42301095a5dSDimitry Andric }
42401095a5dSDimitry Andric 
hasPDBInfoStream() const425044eb2f6SDimitry Andric bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); }
42601095a5dSDimitry Andric 
hasPDBIpiStream() const427044eb2f6SDimitry Andric bool PDBFile::hasPDBIpiStream() const {
428044eb2f6SDimitry Andric   if (!hasPDBInfoStream())
429044eb2f6SDimitry Andric     return false;
430044eb2f6SDimitry Andric 
431044eb2f6SDimitry Andric   if (StreamIPI >= getNumStreams())
432044eb2f6SDimitry Andric     return false;
433044eb2f6SDimitry Andric 
434044eb2f6SDimitry Andric   auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
435044eb2f6SDimitry Andric   return InfoStream.containsIdStream();
436044eb2f6SDimitry Andric }
43701095a5dSDimitry Andric 
hasPDBPublicsStream()438b915e9e0SDimitry Andric bool PDBFile::hasPDBPublicsStream() {
439b915e9e0SDimitry Andric   auto DbiS = getPDBDbiStream();
440ca089b24SDimitry Andric   if (!DbiS) {
441ca089b24SDimitry Andric     consumeError(DbiS.takeError());
44271d5a254SDimitry Andric     return false;
443ca089b24SDimitry Andric   }
444b915e9e0SDimitry Andric   return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
44501095a5dSDimitry Andric }
44601095a5dSDimitry Andric 
hasPDBSymbolStream()447b915e9e0SDimitry Andric bool PDBFile::hasPDBSymbolStream() {
448b915e9e0SDimitry Andric   auto DbiS = getPDBDbiStream();
44971d5a254SDimitry Andric   if (!DbiS)
45071d5a254SDimitry Andric     return false;
451b915e9e0SDimitry Andric   return DbiS->getSymRecordStreamIndex() < getNumStreams();
45201095a5dSDimitry Andric }
45301095a5dSDimitry Andric 
hasPDBTpiStream() const454b915e9e0SDimitry Andric bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
455b915e9e0SDimitry Andric 
hasPDBStringTable()456148779dfSDimitry Andric bool PDBFile::hasPDBStringTable() {
457b915e9e0SDimitry Andric   auto IS = getPDBInfoStream();
45871d5a254SDimitry Andric   if (!IS)
45971d5a254SDimitry Andric     return false;
460eb11fae6SDimitry Andric   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
461eb11fae6SDimitry Andric   if (!ExpectedNSI) {
462eb11fae6SDimitry Andric     consumeError(ExpectedNSI.takeError());
463eb11fae6SDimitry Andric     return false;
464eb11fae6SDimitry Andric   }
465eb11fae6SDimitry Andric   assert(*ExpectedNSI < getNumStreams());
466eb11fae6SDimitry Andric   return true;
46701095a5dSDimitry Andric }
46801095a5dSDimitry Andric 
hasPDBInjectedSourceStream()469e6d15924SDimitry Andric bool PDBFile::hasPDBInjectedSourceStream() {
470e6d15924SDimitry Andric   auto IS = getPDBInfoStream();
471e6d15924SDimitry Andric   if (!IS)
472e6d15924SDimitry Andric     return false;
473e6d15924SDimitry Andric   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/src/headerblock");
474e6d15924SDimitry Andric   if (!ExpectedNSI) {
475e6d15924SDimitry Andric     consumeError(ExpectedNSI.takeError());
476e6d15924SDimitry Andric     return false;
477e6d15924SDimitry Andric   }
478e6d15924SDimitry Andric   assert(*ExpectedNSI < getNumStreams());
479e6d15924SDimitry Andric   return true;
480e6d15924SDimitry Andric }
481e6d15924SDimitry Andric 
48271d5a254SDimitry Andric /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
48371d5a254SDimitry Andric /// stream with that index actually exists.  If it does not, the return value
48471d5a254SDimitry Andric /// will have an MSFError with code msf_error_code::no_stream.  Else, the return
48571d5a254SDimitry Andric /// value will contain the stream returned by createIndexedStream().
48671d5a254SDimitry Andric Expected<std::unique_ptr<MappedBlockStream>>
safelyCreateIndexedStream(uint32_t StreamIndex) const487e6d15924SDimitry Andric PDBFile::safelyCreateIndexedStream(uint32_t StreamIndex) const {
488b915e9e0SDimitry Andric   if (StreamIndex >= getNumStreams())
489e6d15924SDimitry Andric     // This rejects kInvalidStreamIndex with an error as well.
490b915e9e0SDimitry Andric     return make_error<RawError>(raw_error_code::no_stream);
491e6d15924SDimitry Andric   return createIndexedStream(StreamIndex);
492e6d15924SDimitry Andric }
493e6d15924SDimitry Andric 
494e6d15924SDimitry Andric Expected<std::unique_ptr<MappedBlockStream>>
safelyCreateNamedStream(StringRef Name)495e6d15924SDimitry Andric PDBFile::safelyCreateNamedStream(StringRef Name) {
496e6d15924SDimitry Andric   auto IS = getPDBInfoStream();
497e6d15924SDimitry Andric   if (!IS)
498e6d15924SDimitry Andric     return IS.takeError();
499e6d15924SDimitry Andric 
500e6d15924SDimitry Andric   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex(Name);
501e6d15924SDimitry Andric   if (!ExpectedNSI)
502e6d15924SDimitry Andric     return ExpectedNSI.takeError();
503e6d15924SDimitry Andric   uint32_t NameStreamIndex = *ExpectedNSI;
504e6d15924SDimitry Andric 
505e6d15924SDimitry Andric   return safelyCreateIndexedStream(NameStreamIndex);
50601095a5dSDimitry Andric }
507