1*0b57cec5SDimitry Andric //===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
10*0b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
11*0b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MSFCommon.h"
12*0b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
13*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
14*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
15*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
16*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h"
17*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
18*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
19*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
20*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
21*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
22*0b57cec5SDimitry Andric #include "llvm/Support/BinaryStream.h"
23*0b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamArray.h"
24*0b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
25*0b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
26*0b57cec5SDimitry Andric #include "llvm/Support/Error.h"
27*0b57cec5SDimitry Andric #include "llvm/Support/Path.h"
28*0b57cec5SDimitry Andric #include <algorithm>
29*0b57cec5SDimitry Andric #include <cassert>
30*0b57cec5SDimitry Andric #include <cstdint>
31*0b57cec5SDimitry Andric 
32*0b57cec5SDimitry Andric using namespace llvm;
33*0b57cec5SDimitry Andric using namespace llvm::codeview;
34*0b57cec5SDimitry Andric using namespace llvm::msf;
35*0b57cec5SDimitry Andric using namespace llvm::pdb;
36*0b57cec5SDimitry Andric 
37*0b57cec5SDimitry Andric namespace {
38*0b57cec5SDimitry Andric typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
39*0b57cec5SDimitry Andric } // end anonymous namespace
40*0b57cec5SDimitry Andric 
PDBFile(StringRef Path,std::unique_ptr<BinaryStream> PdbFileBuffer,BumpPtrAllocator & Allocator)41*0b57cec5SDimitry Andric PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer,
42*0b57cec5SDimitry Andric                  BumpPtrAllocator &Allocator)
43*0b57cec5SDimitry Andric     : FilePath(std::string(Path)), Allocator(Allocator),
44*0b57cec5SDimitry Andric       Buffer(std::move(PdbFileBuffer)) {}
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric PDBFile::~PDBFile() = default;
47*0b57cec5SDimitry Andric 
getFilePath() const48*0b57cec5SDimitry Andric StringRef PDBFile::getFilePath() const { return FilePath; }
49*0b57cec5SDimitry Andric 
getFileDirectory() const50*0b57cec5SDimitry Andric StringRef PDBFile::getFileDirectory() const {
51*0b57cec5SDimitry Andric   return sys::path::parent_path(FilePath);
52*0b57cec5SDimitry Andric }
53*0b57cec5SDimitry Andric 
getBlockSize() const54*0b57cec5SDimitry Andric uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
55*0b57cec5SDimitry Andric 
getFreeBlockMapBlock() const56*0b57cec5SDimitry Andric uint32_t PDBFile::getFreeBlockMapBlock() const {
57*0b57cec5SDimitry Andric   return ContainerLayout.SB->FreeBlockMapBlock;
58*0b57cec5SDimitry Andric }
59*0b57cec5SDimitry Andric 
getBlockCount() const60*0b57cec5SDimitry Andric uint32_t PDBFile::getBlockCount() const {
61*0b57cec5SDimitry Andric   return ContainerLayout.SB->NumBlocks;
62*0b57cec5SDimitry Andric }
63*0b57cec5SDimitry Andric 
getNumDirectoryBytes() const64*0b57cec5SDimitry Andric uint32_t PDBFile::getNumDirectoryBytes() const {
65*0b57cec5SDimitry Andric   return ContainerLayout.SB->NumDirectoryBytes;
66*0b57cec5SDimitry Andric }
67*0b57cec5SDimitry Andric 
getBlockMapIndex() const68*0b57cec5SDimitry Andric uint32_t PDBFile::getBlockMapIndex() const {
69*0b57cec5SDimitry Andric   return ContainerLayout.SB->BlockMapAddr;
70*0b57cec5SDimitry Andric }
71*0b57cec5SDimitry Andric 
getUnknown1() const72*0b57cec5SDimitry Andric uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
73*0b57cec5SDimitry Andric 
getNumDirectoryBlocks() const74*0b57cec5SDimitry Andric uint32_t PDBFile::getNumDirectoryBlocks() const {
75*0b57cec5SDimitry Andric   return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
76*0b57cec5SDimitry Andric                             ContainerLayout.SB->BlockSize);
77*0b57cec5SDimitry Andric }
78*0b57cec5SDimitry Andric 
getBlockMapOffset() const79*0b57cec5SDimitry Andric uint64_t PDBFile::getBlockMapOffset() const {
80*0b57cec5SDimitry Andric   return (uint64_t)ContainerLayout.SB->BlockMapAddr *
81*0b57cec5SDimitry Andric          ContainerLayout.SB->BlockSize;
82*0b57cec5SDimitry Andric }
83*0b57cec5SDimitry Andric 
getNumStreams() const84*0b57cec5SDimitry Andric uint32_t PDBFile::getNumStreams() const {
85*0b57cec5SDimitry Andric   return ContainerLayout.StreamSizes.size();
86*0b57cec5SDimitry Andric }
87*0b57cec5SDimitry Andric 
getMaxStreamSize() const88*0b57cec5SDimitry Andric uint32_t PDBFile::getMaxStreamSize() const {
89*0b57cec5SDimitry Andric   return *std::max_element(ContainerLayout.StreamSizes.begin(),
90*0b57cec5SDimitry Andric                            ContainerLayout.StreamSizes.end());
91*0b57cec5SDimitry Andric }
92*0b57cec5SDimitry Andric 
getStreamByteSize(uint32_t StreamIndex) const93*0b57cec5SDimitry Andric uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
94*0b57cec5SDimitry Andric   return ContainerLayout.StreamSizes[StreamIndex];
95*0b57cec5SDimitry Andric }
96*0b57cec5SDimitry Andric 
97*0b57cec5SDimitry Andric ArrayRef<support::ulittle32_t>
getStreamBlockList(uint32_t StreamIndex) const98*0b57cec5SDimitry Andric PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
99*0b57cec5SDimitry Andric   return ContainerLayout.StreamMap[StreamIndex];
100*0b57cec5SDimitry Andric }
101*0b57cec5SDimitry Andric 
getFileSize() const102*0b57cec5SDimitry Andric uint64_t PDBFile::getFileSize() const { return Buffer->getLength(); }
103*0b57cec5SDimitry Andric 
getBlockData(uint32_t BlockIndex,uint32_t NumBytes) const104*0b57cec5SDimitry Andric Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
105*0b57cec5SDimitry Andric                                                   uint32_t NumBytes) const {
106*0b57cec5SDimitry Andric   uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
107*0b57cec5SDimitry Andric 
108*0b57cec5SDimitry Andric   ArrayRef<uint8_t> Result;
109*0b57cec5SDimitry Andric   if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
110*0b57cec5SDimitry Andric     return std::move(EC);
111*0b57cec5SDimitry Andric   return Result;
112*0b57cec5SDimitry Andric }
113*0b57cec5SDimitry Andric 
setBlockData(uint32_t BlockIndex,uint32_t Offset,ArrayRef<uint8_t> Data) const114*0b57cec5SDimitry Andric Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
115*0b57cec5SDimitry Andric                             ArrayRef<uint8_t> Data) const {
116*0b57cec5SDimitry Andric   return make_error<RawError>(raw_error_code::not_writable,
117*0b57cec5SDimitry Andric                               "PDBFile is immutable");
118*0b57cec5SDimitry Andric }
119*0b57cec5SDimitry Andric 
parseFileHeaders()120*0b57cec5SDimitry Andric Error PDBFile::parseFileHeaders() {
121*0b57cec5SDimitry Andric   BinaryStreamReader Reader(*Buffer);
122*0b57cec5SDimitry Andric 
123*0b57cec5SDimitry Andric   // Initialize SB.
124*0b57cec5SDimitry Andric   const msf::SuperBlock *SB = nullptr;
125*0b57cec5SDimitry Andric   if (auto EC = Reader.readObject(SB)) {
126*0b57cec5SDimitry Andric     consumeError(std::move(EC));
127*0b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::corrupt_file,
128*0b57cec5SDimitry Andric                                 "MSF superblock is missing");
129*0b57cec5SDimitry Andric   }
130*0b57cec5SDimitry Andric 
131*0b57cec5SDimitry Andric   if (auto EC = msf::validateSuperBlock(*SB))
132*0b57cec5SDimitry Andric     return EC;
133*0b57cec5SDimitry Andric 
134*0b57cec5SDimitry Andric   if (Buffer->getLength() % SB->BlockSize != 0)
135*0b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::corrupt_file,
136*0b57cec5SDimitry Andric                                 "File size is not a multiple of block size");
137*0b57cec5SDimitry Andric   ContainerLayout.SB = SB;
138*0b57cec5SDimitry Andric 
139*0b57cec5SDimitry Andric   // Initialize Free Page Map.
140*0b57cec5SDimitry Andric   ContainerLayout.FreePageMap.resize(SB->NumBlocks);
141*0b57cec5SDimitry Andric   // The Fpm exists either at block 1 or block 2 of the MSF.  However, this
142*0b57cec5SDimitry Andric   // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
143*0b57cec5SDimitry Andric   // thusly an equal number of total blocks in the file.  For a block size
144*0b57cec5SDimitry Andric   // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
145*0b57cec5SDimitry Andric   // maximum file size of 32KiB * 4KiB = 128MiB.  Obviously this won't do, so
146*0b57cec5SDimitry Andric   // the Fpm is split across the file at `getBlockSize()` intervals.  As a
147*0b57cec5SDimitry Andric   // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
148*0b57cec5SDimitry Andric   // for any non-negative integer k is an Fpm block.  In theory, we only really
149*0b57cec5SDimitry Andric   // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
150*0b57cec5SDimitry Andric   // current versions of the MSF format already expect the Fpm to be arranged
151*0b57cec5SDimitry Andric   // at getBlockSize() intervals, so we have to be compatible.
152*0b57cec5SDimitry Andric   // See the function fpmPn() for more information:
153*0b57cec5SDimitry Andric   // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
154*0b57cec5SDimitry Andric   auto FpmStream =
155*0b57cec5SDimitry Andric       MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
156*0b57cec5SDimitry Andric   BinaryStreamReader FpmReader(*FpmStream);
157*0b57cec5SDimitry Andric   ArrayRef<uint8_t> FpmBytes;
158*0b57cec5SDimitry Andric   if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
159*0b57cec5SDimitry Andric     return EC;
160*0b57cec5SDimitry Andric   uint32_t BlocksRemaining = getBlockCount();
161*0b57cec5SDimitry Andric   uint32_t BI = 0;
162*0b57cec5SDimitry Andric   for (auto Byte : FpmBytes) {
163*0b57cec5SDimitry Andric     uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
164*0b57cec5SDimitry Andric     for (uint32_t I = 0; I < BlocksThisByte; ++I) {
165*0b57cec5SDimitry Andric       if (Byte & (1 << I))
166*0b57cec5SDimitry Andric         ContainerLayout.FreePageMap[BI] = true;
167*0b57cec5SDimitry Andric       --BlocksRemaining;
168*0b57cec5SDimitry Andric       ++BI;
169*0b57cec5SDimitry Andric     }
170*0b57cec5SDimitry Andric   }
171*0b57cec5SDimitry Andric 
172*0b57cec5SDimitry Andric   Reader.setOffset(getBlockMapOffset());
173*0b57cec5SDimitry Andric   if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
174*0b57cec5SDimitry Andric                                  getNumDirectoryBlocks()))
175*0b57cec5SDimitry Andric     return EC;
176*0b57cec5SDimitry Andric 
177*0b57cec5SDimitry Andric   return Error::success();
178*0b57cec5SDimitry Andric }
179*0b57cec5SDimitry Andric 
parseStreamData()180*0b57cec5SDimitry Andric Error PDBFile::parseStreamData() {
181*0b57cec5SDimitry Andric   assert(ContainerLayout.SB);
182*0b57cec5SDimitry Andric   if (DirectoryStream)
183*0b57cec5SDimitry Andric     return Error::success();
184*0b57cec5SDimitry Andric 
185*0b57cec5SDimitry Andric   uint32_t NumStreams = 0;
186*0b57cec5SDimitry Andric 
187*0b57cec5SDimitry Andric   // Normally you can't use a MappedBlockStream without having fully parsed the
188*0b57cec5SDimitry Andric   // PDB file, because it accesses the directory and various other things, which
189*0b57cec5SDimitry Andric   // is exactly what we are attempting to parse.  By specifying a custom
190*0b57cec5SDimitry Andric   // subclass of IPDBStreamData which only accesses the fields that have already
191*0b57cec5SDimitry Andric   // been parsed, we can avoid this and reuse MappedBlockStream.
192*0b57cec5SDimitry Andric   auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer,
193*0b57cec5SDimitry Andric                                                      Allocator);
194*0b57cec5SDimitry Andric   BinaryStreamReader Reader(*DS);
195*0b57cec5SDimitry Andric   if (auto EC = Reader.readInteger(NumStreams))
196*0b57cec5SDimitry Andric     return EC;
197*0b57cec5SDimitry Andric 
198*0b57cec5SDimitry Andric   if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
199*0b57cec5SDimitry Andric     return EC;
200*0b57cec5SDimitry Andric   for (uint32_t I = 0; I < NumStreams; ++I) {
201*0b57cec5SDimitry Andric     uint32_t StreamSize = getStreamByteSize(I);
202*0b57cec5SDimitry Andric     // FIXME: What does StreamSize ~0U mean?
203*0b57cec5SDimitry Andric     uint64_t NumExpectedStreamBlocks =
204*0b57cec5SDimitry Andric         StreamSize == UINT32_MAX
205*0b57cec5SDimitry Andric             ? 0
206*0b57cec5SDimitry Andric             : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
207*0b57cec5SDimitry Andric 
208*0b57cec5SDimitry Andric     // For convenience, we store the block array contiguously.  This is because
209*0b57cec5SDimitry Andric     // if someone calls setStreamMap(), it is more convenient to be able to call
210*0b57cec5SDimitry Andric     // it with an ArrayRef instead of setting up a StreamRef.  Since the
211*0b57cec5SDimitry Andric     // DirectoryStream is cached in the class and thus lives for the life of the
212*0b57cec5SDimitry Andric     // class, we can be guaranteed that readArray() will return a stable
213*0b57cec5SDimitry Andric     // reference, even if it has to allocate from its internal pool.
214*0b57cec5SDimitry Andric     ArrayRef<support::ulittle32_t> Blocks;
215*0b57cec5SDimitry Andric     if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
216*0b57cec5SDimitry Andric       return EC;
217*0b57cec5SDimitry Andric     for (uint32_t Block : Blocks) {
218*0b57cec5SDimitry Andric       uint64_t BlockEndOffset =
219*0b57cec5SDimitry Andric           (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
220*0b57cec5SDimitry Andric       if (BlockEndOffset > getFileSize())
221*0b57cec5SDimitry Andric         return make_error<RawError>(raw_error_code::corrupt_file,
222*0b57cec5SDimitry Andric                                     "Stream block map is corrupt.");
223*0b57cec5SDimitry Andric     }
224*0b57cec5SDimitry Andric     ContainerLayout.StreamMap.push_back(Blocks);
225*0b57cec5SDimitry Andric   }
226*0b57cec5SDimitry Andric 
227*0b57cec5SDimitry Andric   // We should have read exactly SB->NumDirectoryBytes bytes.
228*0b57cec5SDimitry Andric   assert(Reader.bytesRemaining() == 0);
229*0b57cec5SDimitry Andric   DirectoryStream = std::move(DS);
230*0b57cec5SDimitry Andric   return Error::success();
231*0b57cec5SDimitry Andric }
232*0b57cec5SDimitry Andric 
getDirectoryBlockArray() const233*0b57cec5SDimitry Andric ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
234*0b57cec5SDimitry Andric   return ContainerLayout.DirectoryBlocks;
235*0b57cec5SDimitry Andric }
236*0b57cec5SDimitry Andric 
237*0b57cec5SDimitry Andric std::unique_ptr<MappedBlockStream>
createIndexedStream(uint16_t SN) const238*0b57cec5SDimitry Andric PDBFile::createIndexedStream(uint16_t SN) const {
239*0b57cec5SDimitry Andric   if (SN == kInvalidStreamIndex)
240*0b57cec5SDimitry Andric     return nullptr;
241*0b57cec5SDimitry Andric   return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
242*0b57cec5SDimitry Andric                                                 Allocator);
243*0b57cec5SDimitry Andric }
244*0b57cec5SDimitry Andric 
getStreamLayout(uint32_t StreamIdx) const245*0b57cec5SDimitry Andric MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
246*0b57cec5SDimitry Andric   MSFStreamLayout Result;
247*0b57cec5SDimitry Andric   auto Blocks = getStreamBlockList(StreamIdx);
248*0b57cec5SDimitry Andric   Result.Blocks.assign(Blocks.begin(), Blocks.end());
249*0b57cec5SDimitry Andric   Result.Length = getStreamByteSize(StreamIdx);
250*0b57cec5SDimitry Andric   return Result;
251*0b57cec5SDimitry Andric }
252*0b57cec5SDimitry Andric 
getFpmStreamLayout() const253*0b57cec5SDimitry Andric msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const {
254*0b57cec5SDimitry Andric   return msf::getFpmStreamLayout(ContainerLayout);
255*0b57cec5SDimitry Andric }
256*0b57cec5SDimitry Andric 
getPDBGlobalsStream()257*0b57cec5SDimitry Andric Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
258*0b57cec5SDimitry Andric   if (!Globals) {
259*0b57cec5SDimitry Andric     auto DbiS = getPDBDbiStream();
260*0b57cec5SDimitry Andric     if (!DbiS)
261*0b57cec5SDimitry Andric       return DbiS.takeError();
262*0b57cec5SDimitry Andric 
263*0b57cec5SDimitry Andric     auto GlobalS =
264*0b57cec5SDimitry Andric         safelyCreateIndexedStream(DbiS->getGlobalSymbolStreamIndex());
265*0b57cec5SDimitry Andric     if (!GlobalS)
266*0b57cec5SDimitry Andric       return GlobalS.takeError();
267*0b57cec5SDimitry Andric     auto TempGlobals = std::make_unique<GlobalsStream>(std::move(*GlobalS));
268*0b57cec5SDimitry Andric     if (auto EC = TempGlobals->reload())
269*0b57cec5SDimitry Andric       return std::move(EC);
270*0b57cec5SDimitry Andric     Globals = std::move(TempGlobals);
271*0b57cec5SDimitry Andric   }
272*0b57cec5SDimitry Andric   return *Globals;
273*0b57cec5SDimitry Andric }
274*0b57cec5SDimitry Andric 
getPDBInfoStream()275*0b57cec5SDimitry Andric Expected<InfoStream &> PDBFile::getPDBInfoStream() {
276*0b57cec5SDimitry Andric   if (!Info) {
277*0b57cec5SDimitry Andric     auto InfoS = safelyCreateIndexedStream(StreamPDB);
278*0b57cec5SDimitry Andric     if (!InfoS)
279*0b57cec5SDimitry Andric       return InfoS.takeError();
280*0b57cec5SDimitry Andric     auto TempInfo = std::make_unique<InfoStream>(std::move(*InfoS));
281*0b57cec5SDimitry Andric     if (auto EC = TempInfo->reload())
282*0b57cec5SDimitry Andric       return std::move(EC);
283*0b57cec5SDimitry Andric     Info = std::move(TempInfo);
284*0b57cec5SDimitry Andric   }
285*0b57cec5SDimitry Andric   return *Info;
286*0b57cec5SDimitry Andric }
287*0b57cec5SDimitry Andric 
getPDBDbiStream()288*0b57cec5SDimitry Andric Expected<DbiStream &> PDBFile::getPDBDbiStream() {
289*0b57cec5SDimitry Andric   if (!Dbi) {
290*0b57cec5SDimitry Andric     auto DbiS = safelyCreateIndexedStream(StreamDBI);
291*0b57cec5SDimitry Andric     if (!DbiS)
292*0b57cec5SDimitry Andric       return DbiS.takeError();
293*0b57cec5SDimitry Andric     auto TempDbi = std::make_unique<DbiStream>(std::move(*DbiS));
294*0b57cec5SDimitry Andric     if (auto EC = TempDbi->reload(this))
295*0b57cec5SDimitry Andric       return std::move(EC);
296*0b57cec5SDimitry Andric     Dbi = std::move(TempDbi);
297*0b57cec5SDimitry Andric   }
298*0b57cec5SDimitry Andric   return *Dbi;
299*0b57cec5SDimitry Andric }
300*0b57cec5SDimitry Andric 
getPDBTpiStream()301*0b57cec5SDimitry Andric Expected<TpiStream &> PDBFile::getPDBTpiStream() {
302*0b57cec5SDimitry Andric   if (!Tpi) {
303*0b57cec5SDimitry Andric     auto TpiS = safelyCreateIndexedStream(StreamTPI);
304*0b57cec5SDimitry Andric     if (!TpiS)
305*0b57cec5SDimitry Andric       return TpiS.takeError();
306*0b57cec5SDimitry Andric     auto TempTpi = std::make_unique<TpiStream>(*this, std::move(*TpiS));
307*0b57cec5SDimitry Andric     if (auto EC = TempTpi->reload())
308*0b57cec5SDimitry Andric       return std::move(EC);
309*0b57cec5SDimitry Andric     Tpi = std::move(TempTpi);
310*0b57cec5SDimitry Andric   }
311*0b57cec5SDimitry Andric   return *Tpi;
312*0b57cec5SDimitry Andric }
313*0b57cec5SDimitry Andric 
getPDBIpiStream()314*0b57cec5SDimitry Andric Expected<TpiStream &> PDBFile::getPDBIpiStream() {
315*0b57cec5SDimitry Andric   if (!Ipi) {
316*0b57cec5SDimitry Andric     if (!hasPDBIpiStream())
317*0b57cec5SDimitry Andric       return make_error<RawError>(raw_error_code::no_stream);
318*0b57cec5SDimitry Andric 
319*0b57cec5SDimitry Andric     auto IpiS = safelyCreateIndexedStream(StreamIPI);
320*0b57cec5SDimitry Andric     if (!IpiS)
321*0b57cec5SDimitry Andric       return IpiS.takeError();
322*0b57cec5SDimitry Andric     auto TempIpi = std::make_unique<TpiStream>(*this, std::move(*IpiS));
323*0b57cec5SDimitry Andric     if (auto EC = TempIpi->reload())
324*0b57cec5SDimitry Andric       return std::move(EC);
325*0b57cec5SDimitry Andric     Ipi = std::move(TempIpi);
326*0b57cec5SDimitry Andric   }
327*0b57cec5SDimitry Andric   return *Ipi;
328*0b57cec5SDimitry Andric }
329*0b57cec5SDimitry Andric 
getPDBPublicsStream()330*0b57cec5SDimitry Andric Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
331*0b57cec5SDimitry Andric   if (!Publics) {
332*0b57cec5SDimitry Andric     auto DbiS = getPDBDbiStream();
333*0b57cec5SDimitry Andric     if (!DbiS)
334*0b57cec5SDimitry Andric       return DbiS.takeError();
335*0b57cec5SDimitry Andric 
336*0b57cec5SDimitry Andric     auto PublicS =
337*0b57cec5SDimitry Andric         safelyCreateIndexedStream(DbiS->getPublicSymbolStreamIndex());
338*0b57cec5SDimitry Andric     if (!PublicS)
339*0b57cec5SDimitry Andric       return PublicS.takeError();
340*0b57cec5SDimitry Andric     auto TempPublics = std::make_unique<PublicsStream>(std::move(*PublicS));
341*0b57cec5SDimitry Andric     if (auto EC = TempPublics->reload())
342*0b57cec5SDimitry Andric       return std::move(EC);
343*0b57cec5SDimitry Andric     Publics = std::move(TempPublics);
344*0b57cec5SDimitry Andric   }
345*0b57cec5SDimitry Andric   return *Publics;
346*0b57cec5SDimitry Andric }
347*0b57cec5SDimitry Andric 
getPDBSymbolStream()348*0b57cec5SDimitry Andric Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
349*0b57cec5SDimitry Andric   if (!Symbols) {
350*0b57cec5SDimitry Andric     auto DbiS = getPDBDbiStream();
351*0b57cec5SDimitry Andric     if (!DbiS)
352*0b57cec5SDimitry Andric       return DbiS.takeError();
353*0b57cec5SDimitry Andric 
354*0b57cec5SDimitry Andric     uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
355*0b57cec5SDimitry Andric     auto SymbolS = safelyCreateIndexedStream(SymbolStreamNum);
356*0b57cec5SDimitry Andric     if (!SymbolS)
357*0b57cec5SDimitry Andric       return SymbolS.takeError();
358*0b57cec5SDimitry Andric 
359*0b57cec5SDimitry Andric     auto TempSymbols = std::make_unique<SymbolStream>(std::move(*SymbolS));
360*0b57cec5SDimitry Andric     if (auto EC = TempSymbols->reload())
361*0b57cec5SDimitry Andric       return std::move(EC);
362*0b57cec5SDimitry Andric     Symbols = std::move(TempSymbols);
363*0b57cec5SDimitry Andric   }
364*0b57cec5SDimitry Andric   return *Symbols;
365*0b57cec5SDimitry Andric }
366*0b57cec5SDimitry Andric 
getStringTable()367*0b57cec5SDimitry Andric Expected<PDBStringTable &> PDBFile::getStringTable() {
368*0b57cec5SDimitry Andric   if (!Strings) {
369*0b57cec5SDimitry Andric     auto NS = safelyCreateNamedStream("/names");
370*0b57cec5SDimitry Andric     if (!NS)
371*0b57cec5SDimitry Andric       return NS.takeError();
372*0b57cec5SDimitry Andric 
373*0b57cec5SDimitry Andric     auto N = std::make_unique<PDBStringTable>();
374*0b57cec5SDimitry Andric     BinaryStreamReader Reader(**NS);
375*0b57cec5SDimitry Andric     if (auto EC = N->reload(Reader))
376*0b57cec5SDimitry Andric       return std::move(EC);
377*0b57cec5SDimitry Andric     assert(Reader.bytesRemaining() == 0);
378*0b57cec5SDimitry Andric     StringTableStream = std::move(*NS);
379*0b57cec5SDimitry Andric     Strings = std::move(N);
380*0b57cec5SDimitry Andric   }
381*0b57cec5SDimitry Andric   return *Strings;
382*0b57cec5SDimitry Andric }
383*0b57cec5SDimitry Andric 
getInjectedSourceStream()384*0b57cec5SDimitry Andric Expected<InjectedSourceStream &> PDBFile::getInjectedSourceStream() {
385*0b57cec5SDimitry Andric   if (!InjectedSources) {
386*0b57cec5SDimitry Andric     auto IJS = safelyCreateNamedStream("/src/headerblock");
387*0b57cec5SDimitry Andric     if (!IJS)
388*0b57cec5SDimitry Andric       return IJS.takeError();
389*0b57cec5SDimitry Andric 
390*0b57cec5SDimitry Andric     auto Strings = getStringTable();
391*0b57cec5SDimitry Andric     if (!Strings)
392*0b57cec5SDimitry Andric       return Strings.takeError();
393*0b57cec5SDimitry Andric 
394*0b57cec5SDimitry Andric     auto IJ = std::make_unique<InjectedSourceStream>(std::move(*IJS));
395*0b57cec5SDimitry Andric     if (auto EC = IJ->reload(*Strings))
396*0b57cec5SDimitry Andric       return std::move(EC);
397*0b57cec5SDimitry Andric     InjectedSources = std::move(IJ);
398*0b57cec5SDimitry Andric   }
399*0b57cec5SDimitry Andric   return *InjectedSources;
400*0b57cec5SDimitry Andric }
401*0b57cec5SDimitry Andric 
getPointerSize()402*0b57cec5SDimitry Andric uint32_t PDBFile::getPointerSize() {
403*0b57cec5SDimitry Andric   auto DbiS = getPDBDbiStream();
404*0b57cec5SDimitry Andric   if (!DbiS)
405*0b57cec5SDimitry Andric     return 0;
406*0b57cec5SDimitry Andric   PDB_Machine Machine = DbiS->getMachineType();
407*0b57cec5SDimitry Andric   if (Machine == PDB_Machine::Amd64)
408*0b57cec5SDimitry Andric     return 8;
409*0b57cec5SDimitry Andric   return 4;
410*0b57cec5SDimitry Andric }
411*0b57cec5SDimitry Andric 
hasPDBDbiStream() const412*0b57cec5SDimitry Andric bool PDBFile::hasPDBDbiStream() const {
413*0b57cec5SDimitry Andric   return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0;
414*0b57cec5SDimitry Andric }
415*0b57cec5SDimitry Andric 
hasPDBGlobalsStream()416*0b57cec5SDimitry Andric bool PDBFile::hasPDBGlobalsStream() {
417*0b57cec5SDimitry Andric   auto DbiS = getPDBDbiStream();
418*0b57cec5SDimitry Andric   if (!DbiS) {
419*0b57cec5SDimitry Andric     consumeError(DbiS.takeError());
420*0b57cec5SDimitry Andric     return false;
421*0b57cec5SDimitry Andric   }
422*0b57cec5SDimitry Andric 
423*0b57cec5SDimitry Andric   return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
424*0b57cec5SDimitry Andric }
425*0b57cec5SDimitry Andric 
hasPDBInfoStream() const426*0b57cec5SDimitry Andric bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); }
427*0b57cec5SDimitry Andric 
hasPDBIpiStream() const428*0b57cec5SDimitry Andric bool PDBFile::hasPDBIpiStream() const {
429*0b57cec5SDimitry Andric   if (!hasPDBInfoStream())
430*0b57cec5SDimitry Andric     return false;
431*0b57cec5SDimitry Andric 
432*0b57cec5SDimitry Andric   if (StreamIPI >= getNumStreams())
433*0b57cec5SDimitry Andric     return false;
434*0b57cec5SDimitry Andric 
435*0b57cec5SDimitry Andric   auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
436*0b57cec5SDimitry Andric   return InfoStream.containsIdStream();
437*0b57cec5SDimitry Andric }
438*0b57cec5SDimitry Andric 
hasPDBPublicsStream()439*0b57cec5SDimitry Andric bool PDBFile::hasPDBPublicsStream() {
440*0b57cec5SDimitry Andric   auto DbiS = getPDBDbiStream();
441*0b57cec5SDimitry Andric   if (!DbiS) {
442*0b57cec5SDimitry Andric     consumeError(DbiS.takeError());
443*0b57cec5SDimitry Andric     return false;
444*0b57cec5SDimitry Andric   }
445*0b57cec5SDimitry Andric   return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
446*0b57cec5SDimitry Andric }
447*0b57cec5SDimitry Andric 
hasPDBSymbolStream()448*0b57cec5SDimitry Andric bool PDBFile::hasPDBSymbolStream() {
449*0b57cec5SDimitry Andric   auto DbiS = getPDBDbiStream();
450*0b57cec5SDimitry Andric   if (!DbiS)
451*0b57cec5SDimitry Andric     return false;
452*0b57cec5SDimitry Andric   return DbiS->getSymRecordStreamIndex() < getNumStreams();
453*0b57cec5SDimitry Andric }
454*0b57cec5SDimitry Andric 
hasPDBTpiStream() const455*0b57cec5SDimitry Andric bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
456*0b57cec5SDimitry Andric 
hasPDBStringTable()457*0b57cec5SDimitry Andric bool PDBFile::hasPDBStringTable() {
458*0b57cec5SDimitry Andric   auto IS = getPDBInfoStream();
459*0b57cec5SDimitry Andric   if (!IS)
460*0b57cec5SDimitry Andric     return false;
461*0b57cec5SDimitry Andric   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
462*0b57cec5SDimitry Andric   if (!ExpectedNSI) {
463*0b57cec5SDimitry Andric     consumeError(ExpectedNSI.takeError());
464*0b57cec5SDimitry Andric     return false;
465*0b57cec5SDimitry Andric   }
466*0b57cec5SDimitry Andric   assert(*ExpectedNSI < getNumStreams());
467*0b57cec5SDimitry Andric   return true;
468*0b57cec5SDimitry Andric }
469*0b57cec5SDimitry Andric 
hasPDBInjectedSourceStream()470*0b57cec5SDimitry Andric bool PDBFile::hasPDBInjectedSourceStream() {
471*0b57cec5SDimitry Andric   auto IS = getPDBInfoStream();
472*0b57cec5SDimitry Andric   if (!IS)
473*0b57cec5SDimitry Andric     return false;
474*0b57cec5SDimitry Andric   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/src/headerblock");
475*0b57cec5SDimitry Andric   if (!ExpectedNSI) {
476*0b57cec5SDimitry Andric     consumeError(ExpectedNSI.takeError());
477*0b57cec5SDimitry Andric     return false;
478*0b57cec5SDimitry Andric   }
479*0b57cec5SDimitry Andric   assert(*ExpectedNSI < getNumStreams());
480*0b57cec5SDimitry Andric   return true;
481*0b57cec5SDimitry Andric }
482*0b57cec5SDimitry Andric 
483*0b57cec5SDimitry Andric /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
484*0b57cec5SDimitry Andric /// stream with that index actually exists.  If it does not, the return value
485*0b57cec5SDimitry Andric /// will have an MSFError with code msf_error_code::no_stream.  Else, the return
486*0b57cec5SDimitry Andric /// value will contain the stream returned by createIndexedStream().
487*0b57cec5SDimitry Andric Expected<std::unique_ptr<MappedBlockStream>>
safelyCreateIndexedStream(uint32_t StreamIndex) const488*0b57cec5SDimitry Andric PDBFile::safelyCreateIndexedStream(uint32_t StreamIndex) const {
489*0b57cec5SDimitry Andric   if (StreamIndex >= getNumStreams())
490*0b57cec5SDimitry Andric     // This rejects kInvalidStreamIndex with an error as well.
491*0b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::no_stream);
492*0b57cec5SDimitry Andric   return createIndexedStream(StreamIndex);
493*0b57cec5SDimitry Andric }
494*0b57cec5SDimitry Andric 
495*0b57cec5SDimitry Andric Expected<std::unique_ptr<MappedBlockStream>>
safelyCreateNamedStream(StringRef Name)496*0b57cec5SDimitry Andric PDBFile::safelyCreateNamedStream(StringRef Name) {
497*0b57cec5SDimitry Andric   auto IS = getPDBInfoStream();
498*0b57cec5SDimitry Andric   if (!IS)
499*0b57cec5SDimitry Andric     return IS.takeError();
500*0b57cec5SDimitry Andric 
501*0b57cec5SDimitry Andric   Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex(Name);
502*0b57cec5SDimitry Andric   if (!ExpectedNSI)
503*0b57cec5SDimitry Andric     return ExpectedNSI.takeError();
504*0b57cec5SDimitry Andric   uint32_t NameStreamIndex = *ExpectedNSI;
505*0b57cec5SDimitry Andric 
506*0b57cec5SDimitry Andric   return safelyCreateIndexedStream(NameStreamIndex);
507*0b57cec5SDimitry Andric }
508