blob: aef86c2ea995aa4625bb6f91f7d0748b0c94af7d [file] [log] [blame]
Zachary Turner0a43efe2016-04-25 17:38:08 +00001//===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Zachary Turnerf04d6e82017-01-20 22:41:15 +000010#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
Zachary Turner0a43efe2016-04-25 17:38:08 +000011#include "llvm/ADT/ArrayRef.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000012#include "llvm/ADT/STLExtras.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000013#include "llvm/DebugInfo/MSF/MSFCommon.h"
Zachary Turnerf04d6e82017-01-20 22:41:15 +000014#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
Zachary Turnera3225b02016-07-29 20:56:36 +000015#include "llvm/DebugInfo/MSF/StreamArray.h"
16#include "llvm/DebugInfo/MSF/StreamInterface.h"
17#include "llvm/DebugInfo/MSF/StreamReader.h"
Zachary Turner2f09b502016-04-29 17:28:47 +000018#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
Bob Haarman653baa22016-10-21 19:43:19 +000019#include "llvm/DebugInfo/PDB/Raw/GlobalsStream.h"
Zachary Turner2f09b502016-04-29 17:28:47 +000020#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
Rui Ueyama1f6b6e22016-05-13 21:21:53 +000021#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
Zachary Turner819e77d2016-05-06 20:51:57 +000022#include "llvm/DebugInfo/PDB/Raw/RawError.h"
Zachary Turnerf04d6e82017-01-20 22:41:15 +000023#include "llvm/DebugInfo/PDB/Raw/StringTable.h"
Rui Ueyama0fcd8262016-05-20 19:55:17 +000024#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h"
Zachary Turnerf5c59652016-05-03 00:28:21 +000025#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
Zachary Turner0a43efe2016-04-25 17:38:08 +000026#include "llvm/Support/Endian.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000027#include "llvm/Support/Error.h"
28#include <algorithm>
29#include <cassert>
30#include <cstdint>
Zachary Turner0a43efe2016-04-25 17:38:08 +000031
32using namespace llvm;
Zachary Turnerb84faa82016-06-10 05:10:19 +000033using namespace llvm::codeview;
Zachary Turnerbac69d32016-07-22 19:56:05 +000034using namespace llvm::msf;
Zachary Turner2f09b502016-04-29 17:28:47 +000035using namespace llvm::pdb;
Zachary Turner0a43efe2016-04-25 17:38:08 +000036
37namespace {
Zachary Turnerb84faa82016-06-10 05:10:19 +000038typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
Eugene Zelenko570e39a2016-11-23 23:16:32 +000039} // end anonymous namespace
Zachary Turner0a43efe2016-04-25 17:38:08 +000040
Zachary Turnerd66889c2016-07-28 19:12:28 +000041PDBFile::PDBFile(std::unique_ptr<ReadableStream> PdbFileBuffer,
Zachary Turnere109dc62016-07-22 19:56:26 +000042 BumpPtrAllocator &Allocator)
Zachary Turnere4a4f332016-07-22 19:56:33 +000043 : Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {}
Zachary Turner0a43efe2016-04-25 17:38:08 +000044
Eugene Zelenko570e39a2016-11-23 23:16:32 +000045PDBFile::~PDBFile() = default;
Zachary Turner0a43efe2016-04-25 17:38:08 +000046
Zachary Turnerd66889c2016-07-28 19:12:28 +000047uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000048
Zachary Turnere4a4f332016-07-22 19:56:33 +000049uint32_t PDBFile::getFreeBlockMapBlock() const {
Zachary Turnerd66889c2016-07-28 19:12:28 +000050 return ContainerLayout.SB->FreeBlockMapBlock;
Zachary Turnere4a4f332016-07-22 19:56:33 +000051}
Zachary Turner0a43efe2016-04-25 17:38:08 +000052
Zachary Turnerd66889c2016-07-28 19:12:28 +000053uint32_t PDBFile::getBlockCount() const {
54 return ContainerLayout.SB->NumBlocks;
55}
Zachary Turner0a43efe2016-04-25 17:38:08 +000056
Zachary Turnere4a4f332016-07-22 19:56:33 +000057uint32_t PDBFile::getNumDirectoryBytes() const {
Zachary Turnerd66889c2016-07-28 19:12:28 +000058 return ContainerLayout.SB->NumDirectoryBytes;
Zachary Turnere4a4f332016-07-22 19:56:33 +000059}
Zachary Turner0a43efe2016-04-25 17:38:08 +000060
Zachary Turnere4a4f332016-07-22 19:56:33 +000061uint32_t PDBFile::getBlockMapIndex() const {
Zachary Turnerd66889c2016-07-28 19:12:28 +000062 return ContainerLayout.SB->BlockMapAddr;
Zachary Turnere4a4f332016-07-22 19:56:33 +000063}
Zachary Turner0a43efe2016-04-25 17:38:08 +000064
Zachary Turnerd66889c2016-07-28 19:12:28 +000065uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000066
67uint32_t PDBFile::getNumDirectoryBlocks() const {
Zachary Turnerd66889c2016-07-28 19:12:28 +000068 return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
69 ContainerLayout.SB->BlockSize);
Zachary Turner0a43efe2016-04-25 17:38:08 +000070}
71
72uint64_t PDBFile::getBlockMapOffset() const {
Zachary Turnerd66889c2016-07-28 19:12:28 +000073 return (uint64_t)ContainerLayout.SB->BlockMapAddr *
74 ContainerLayout.SB->BlockSize;
Zachary Turner0a43efe2016-04-25 17:38:08 +000075}
76
Zachary Turnerd66889c2016-07-28 19:12:28 +000077uint32_t PDBFile::getNumStreams() const {
78 return ContainerLayout.StreamSizes.size();
79}
Zachary Turner0a43efe2016-04-25 17:38:08 +000080
81uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
Zachary Turnerd66889c2016-07-28 19:12:28 +000082 return ContainerLayout.StreamSizes[StreamIndex];
Zachary Turner0a43efe2016-04-25 17:38:08 +000083}
84
Zachary Turnerd8447992016-06-07 05:28:55 +000085ArrayRef<support::ulittle32_t>
Zachary Turner0a43efe2016-04-25 17:38:08 +000086PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
Zachary Turnerd66889c2016-07-28 19:12:28 +000087 return ContainerLayout.StreamMap[StreamIndex];
Zachary Turner0a43efe2016-04-25 17:38:08 +000088}
89
David Majnemer1b79e9a2016-07-10 05:32:05 +000090uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
Zachary Turner1dc9fd32016-06-14 20:48:36 +000091
David Majnemer6211b1f2016-07-10 03:34:47 +000092Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
93 uint32_t NumBytes) const {
Zachary Turnerfaa554b2016-07-15 22:16:56 +000094 uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
Zachary Turner0a43efe2016-04-25 17:38:08 +000095
Zachary Turnerb84faa82016-06-10 05:10:19 +000096 ArrayRef<uint8_t> Result;
97 if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
David Majnemer6211b1f2016-07-10 03:34:47 +000098 return std::move(EC);
Zachary Turnerb84faa82016-06-10 05:10:19 +000099 return Result;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000100}
101
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000102Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
103 ArrayRef<uint8_t> Data) const {
Zachary Turnerd66889c2016-07-28 19:12:28 +0000104 return make_error<RawError>(raw_error_code::not_writable,
105 "PDBFile is immutable");
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000106}
107
Zachary Turner819e77d2016-05-06 20:51:57 +0000108Error PDBFile::parseFileHeaders() {
Zachary Turnerb84faa82016-06-10 05:10:19 +0000109 StreamReader Reader(*Buffer);
Zachary Turnerc59261c2016-05-25 03:53:16 +0000110
Rui Ueyama7a5cdc62016-07-29 21:38:00 +0000111 // Initialize SB.
Zachary Turnere4a4f332016-07-22 19:56:33 +0000112 const msf::SuperBlock *SB = nullptr;
Zachary Turnerb84faa82016-06-10 05:10:19 +0000113 if (auto EC = Reader.readObject(SB)) {
114 consumeError(std::move(EC));
Zachary Turner819e77d2016-05-06 20:51:57 +0000115 return make_error<RawError>(raw_error_code::corrupt_file,
116 "Does not contain superblock");
Zachary Turnerb84faa82016-06-10 05:10:19 +0000117 }
Zachary Turner0a43efe2016-04-25 17:38:08 +0000118
Zachary Turnere4a4f332016-07-22 19:56:33 +0000119 if (auto EC = msf::validateSuperBlock(*SB))
Zachary Turnerab58ae82016-06-30 17:43:00 +0000120 return EC;
Zachary Turner819e77d2016-05-06 20:51:57 +0000121
Zachary Turnere4a4f332016-07-22 19:56:33 +0000122 if (Buffer->getLength() % SB->BlockSize != 0)
123 return make_error<RawError>(raw_error_code::corrupt_file,
124 "File size is not a multiple of block size");
Zachary Turnerd66889c2016-07-28 19:12:28 +0000125 ContainerLayout.SB = SB;
Zachary Turnere4a4f332016-07-22 19:56:33 +0000126
Rui Ueyama7a5cdc62016-07-29 21:38:00 +0000127 // Initialize Free Page Map.
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000128 ContainerLayout.FreePageMap.resize(SB->NumBlocks);
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000129 // The Fpm exists either at block 1 or block 2 of the MSF. However, this
130 // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
131 // thusly an equal number of total blocks in the file. For a block size
132 // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
133 // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so
134 // the Fpm is split across the file at `getBlockSize()` intervals. As a
135 // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
136 // for any non-negative integer k is an Fpm block. In theory, we only really
137 // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
138 // current versions of the MSF format already expect the Fpm to be arranged
139 // at getBlockSize() intervals, so we have to be compatible.
140 // See the function fpmPn() for more information:
141 // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
Zachary Turner8cf51c32016-08-03 16:53:21 +0000142 auto FpmStream = MappedBlockStream::createFpmStream(ContainerLayout, *Buffer);
143 StreamReader FpmReader(*FpmStream);
144 ArrayRef<uint8_t> FpmBytes;
145 if (auto EC = FpmReader.readBytes(FpmBytes,
146 msf::getFullFpmByteSize(ContainerLayout)))
147 return EC;
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000148 uint32_t BlocksRemaining = getBlockCount();
Zachary Turner8cf51c32016-08-03 16:53:21 +0000149 uint32_t BI = 0;
150 for (auto Byte : FpmBytes) {
151 uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
152 for (uint32_t I = 0; I < BlocksThisByte; ++I) {
153 if (Byte & (1 << I))
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000154 ContainerLayout.FreePageMap[BI] = true;
Zachary Turner8cf51c32016-08-03 16:53:21 +0000155 --BlocksRemaining;
156 ++BI;
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000157 }
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000158 }
Rui Ueyama7a5cdc62016-07-29 21:38:00 +0000159
Zachary Turnerab58ae82016-06-30 17:43:00 +0000160 Reader.setOffset(getBlockMapOffset());
Zachary Turnerd66889c2016-07-28 19:12:28 +0000161 if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
162 getNumDirectoryBlocks()))
Zachary Turnerab58ae82016-06-30 17:43:00 +0000163 return EC;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000164
Zachary Turner819e77d2016-05-06 20:51:57 +0000165 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000166}
167
Zachary Turner819e77d2016-05-06 20:51:57 +0000168Error PDBFile::parseStreamData() {
Zachary Turnerd66889c2016-07-28 19:12:28 +0000169 assert(ContainerLayout.SB);
Zachary Turnerd8447992016-06-07 05:28:55 +0000170 if (DirectoryStream)
171 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000172
Zachary Turner0a43efe2016-04-25 17:38:08 +0000173 uint32_t NumStreams = 0;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000174
Zachary Turnerd8447992016-06-07 05:28:55 +0000175 // Normally you can't use a MappedBlockStream without having fully parsed the
176 // PDB file, because it accesses the directory and various other things, which
177 // is exactly what we are attempting to parse. By specifying a custom
178 // subclass of IPDBStreamData which only accesses the fields that have already
179 // been parsed, we can avoid this and reuse MappedBlockStream.
Zachary Turnerd66889c2016-07-28 19:12:28 +0000180 auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer);
181 StreamReader Reader(*DS);
Zachary Turnerd8447992016-06-07 05:28:55 +0000182 if (auto EC = Reader.readInteger(NumStreams))
183 return EC;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000184
Zachary Turnerd66889c2016-07-28 19:12:28 +0000185 if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
Zachary Turnerd8447992016-06-07 05:28:55 +0000186 return EC;
187 for (uint32_t I = 0; I < NumStreams; ++I) {
Reid Kleckner5aba52f2016-06-22 22:42:24 +0000188 uint32_t StreamSize = getStreamByteSize(I);
189 // FIXME: What does StreamSize ~0U mean?
David Majnemer9efba742016-05-27 16:16:48 +0000190 uint64_t NumExpectedStreamBlocks =
Zachary Turnere4a4f332016-07-22 19:56:33 +0000191 StreamSize == UINT32_MAX
192 ? 0
Zachary Turnerd66889c2016-07-28 19:12:28 +0000193 : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
Zachary Turnerb84faa82016-06-10 05:10:19 +0000194
195 // For convenience, we store the block array contiguously. This is because
196 // if someone calls setStreamMap(), it is more convenient to be able to call
197 // it with an ArrayRef instead of setting up a StreamRef. Since the
198 // DirectoryStream is cached in the class and thus lives for the life of the
199 // class, we can be guaranteed that readArray() will return a stable
200 // reference, even if it has to allocate from its internal pool.
201 ArrayRef<support::ulittle32_t> Blocks;
Zachary Turnerd8447992016-06-07 05:28:55 +0000202 if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
203 return EC;
David Majnemer1b79e9a2016-07-10 05:32:05 +0000204 for (uint32_t Block : Blocks) {
Zachary Turnerd66889c2016-07-28 19:12:28 +0000205 uint64_t BlockEndOffset =
206 (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
David Majnemer1b79e9a2016-07-10 05:32:05 +0000207 if (BlockEndOffset > getFileSize())
208 return make_error<RawError>(raw_error_code::corrupt_file,
209 "Stream block map is corrupt.");
210 }
Zachary Turnerd66889c2016-07-28 19:12:28 +0000211 ContainerLayout.StreamMap.push_back(Blocks);
David Majnemer9efba742016-05-27 16:16:48 +0000212 }
213
Zachary Turner0a43efe2016-04-25 17:38:08 +0000214 // We should have read exactly SB->NumDirectoryBytes bytes.
Zachary Turnerd8447992016-06-07 05:28:55 +0000215 assert(Reader.bytesRemaining() == 0);
Zachary Turnerd66889c2016-07-28 19:12:28 +0000216 DirectoryStream = std::move(DS);
Zachary Turner819e77d2016-05-06 20:51:57 +0000217 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000218}
219
Eugene Zelenko570e39a2016-11-23 23:16:32 +0000220ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
Zachary Turnerd66889c2016-07-28 19:12:28 +0000221 return ContainerLayout.DirectoryBlocks;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000222}
Zachary Turner53a65ba2016-04-26 18:42:34 +0000223
Bob Haarman653baa22016-10-21 19:43:19 +0000224Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
225 if (!Globals) {
226 auto DbiS = getPDBDbiStream();
227 if (!DbiS)
228 return DbiS.takeError();
229
Bob Haarmana5b43582016-12-05 22:44:00 +0000230 auto GlobalS = safelyCreateIndexedStream(
Bob Haarman653baa22016-10-21 19:43:19 +0000231 ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex());
Bob Haarmana5b43582016-12-05 22:44:00 +0000232 if (!GlobalS) return GlobalS.takeError();
233 auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS));
Bob Haarman653baa22016-10-21 19:43:19 +0000234 if (auto EC = TempGlobals->reload())
235 return std::move(EC);
236 Globals = std::move(TempGlobals);
237 }
238 return *Globals;
239}
240
Zachary Turner819e77d2016-05-06 20:51:57 +0000241Expected<InfoStream &> PDBFile::getPDBInfoStream() {
Zachary Turner2f09b502016-04-29 17:28:47 +0000242 if (!Info) {
Bob Haarmana5b43582016-12-05 22:44:00 +0000243 auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB);
244 if (!InfoS) return InfoS.takeError();
245 auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
Zachary Turnera1657a92016-06-08 17:26:39 +0000246 if (auto EC = TempInfo->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000247 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000248 Info = std::move(TempInfo);
Zachary Turner53a65ba2016-04-26 18:42:34 +0000249 }
Zachary Turner2f09b502016-04-29 17:28:47 +0000250 return *Info;
Zachary Turner53a65ba2016-04-26 18:42:34 +0000251}
252
Zachary Turner819e77d2016-05-06 20:51:57 +0000253Expected<DbiStream &> PDBFile::getPDBDbiStream() {
Zachary Turner2f09b502016-04-29 17:28:47 +0000254 if (!Dbi) {
Bob Haarmana5b43582016-12-05 22:44:00 +0000255 auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI);
256 if (!DbiS) return DbiS.takeError();
257 auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
Zachary Turnera1657a92016-06-08 17:26:39 +0000258 if (auto EC = TempDbi->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000259 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000260 Dbi = std::move(TempDbi);
Zachary Turner53a65ba2016-04-26 18:42:34 +0000261 }
Zachary Turner2f09b502016-04-29 17:28:47 +0000262 return *Dbi;
Zachary Turner53a65ba2016-04-26 18:42:34 +0000263}
Zachary Turnerf5c59652016-05-03 00:28:21 +0000264
Zachary Turner819e77d2016-05-06 20:51:57 +0000265Expected<TpiStream &> PDBFile::getPDBTpiStream() {
Zachary Turnerf5c59652016-05-03 00:28:21 +0000266 if (!Tpi) {
Bob Haarmana5b43582016-12-05 22:44:00 +0000267 auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI);
268 if (!TpiS) return TpiS.takeError();
269 auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
Zachary Turnera1657a92016-06-08 17:26:39 +0000270 if (auto EC = TempTpi->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000271 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000272 Tpi = std::move(TempTpi);
Zachary Turnerf5c59652016-05-03 00:28:21 +0000273 }
274 return *Tpi;
275}
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000276
Zachary Turnerc9972c62016-05-25 04:35:22 +0000277Expected<TpiStream &> PDBFile::getPDBIpiStream() {
278 if (!Ipi) {
Bob Haarmana5b43582016-12-05 22:44:00 +0000279 auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI);
280 if (!IpiS) return IpiS.takeError();
281 auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
Zachary Turnera1657a92016-06-08 17:26:39 +0000282 if (auto EC = TempIpi->reload())
Zachary Turnerc9972c62016-05-25 04:35:22 +0000283 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000284 Ipi = std::move(TempIpi);
Zachary Turnerc9972c62016-05-25 04:35:22 +0000285 }
286 return *Ipi;
287}
288
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000289Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
290 if (!Publics) {
291 auto DbiS = getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000292 if (!DbiS)
293 return DbiS.takeError();
294
Bob Haarmana5b43582016-12-05 22:44:00 +0000295 auto PublicS = safelyCreateIndexedStream(
296 ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex());
297 if (!PublicS) return PublicS.takeError();
Zachary Turnera1657a92016-06-08 17:26:39 +0000298 auto TempPublics =
Bob Haarmana5b43582016-12-05 22:44:00 +0000299 llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
Zachary Turnera1657a92016-06-08 17:26:39 +0000300 if (auto EC = TempPublics->reload())
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000301 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000302 Publics = std::move(TempPublics);
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000303 }
304 return *Publics;
305}
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000306
307Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
308 if (!Symbols) {
309 auto DbiS = getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000310 if (!DbiS)
311 return DbiS.takeError();
312
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000313 uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
Bob Haarmana5b43582016-12-05 22:44:00 +0000314 auto SymbolS =
315 safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum);
316 if (!SymbolS) return SymbolS.takeError();
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000317
Bob Haarmana5b43582016-12-05 22:44:00 +0000318 auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
Zachary Turnera1657a92016-06-08 17:26:39 +0000319 if (auto EC = TempSymbols->reload())
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000320 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000321 Symbols = std::move(TempSymbols);
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000322 }
323 return *Symbols;
324}
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000325
Zachary Turnerf04d6e82017-01-20 22:41:15 +0000326Expected<StringTable &> PDBFile::getStringTable() {
327 if (!Strings || !StringTableStream) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000328 auto IS = getPDBInfoStream();
329 if (!IS)
330 return IS.takeError();
331
332 uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names");
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000333
Bob Haarmana5b43582016-12-05 22:44:00 +0000334 auto NS =
335 safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex);
336 if (!NS) return NS.takeError();
Zachary Turnerd2b2bfe2016-06-08 00:25:08 +0000337
Bob Haarmana5b43582016-12-05 22:44:00 +0000338 StreamReader Reader(**NS);
Zachary Turnerf04d6e82017-01-20 22:41:15 +0000339 auto N = llvm::make_unique<StringTable>();
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000340 if (auto EC = N->load(Reader))
341 return std::move(EC);
Zachary Turnerf04d6e82017-01-20 22:41:15 +0000342 Strings = std::move(N);
Bob Haarmana5b43582016-12-05 22:44:00 +0000343 StringTableStream = std::move(*NS);
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000344 }
Zachary Turnerf04d6e82017-01-20 22:41:15 +0000345 return *Strings;
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000346}
Bob Haarmana5b43582016-12-05 22:44:00 +0000347
348bool PDBFile::hasPDBDbiStream() const { return StreamDBI < getNumStreams(); }
349
350bool PDBFile::hasPDBGlobalsStream() {
351 auto DbiS = getPDBDbiStream();
352 if (!DbiS) return false;
353 return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
354}
355
356bool PDBFile::hasPDBInfoStream() { return StreamPDB < getNumStreams(); }
357
358bool PDBFile::hasPDBIpiStream() const { return StreamIPI < getNumStreams(); }
359
360bool PDBFile::hasPDBPublicsStream() {
361 auto DbiS = getPDBDbiStream();
362 if (!DbiS) return false;
363 return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
364}
365
366bool PDBFile::hasPDBSymbolStream() {
367 auto DbiS = getPDBDbiStream();
368 if (!DbiS) return false;
369 return DbiS->getSymRecordStreamIndex() < getNumStreams();
370}
371
372bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
373
374bool PDBFile::hasStringTable() {
375 auto IS = getPDBInfoStream();
376 if (!IS) return false;
377 return IS->getNamedStreamIndex("/names") < getNumStreams();
378}
379
380/// Wrapper around MappedBlockStream::createIndexedStream()
381/// that checks if a stream with that index actually exists.
382/// If it does not, the return value will have an MSFError with
383/// code msf_error_code::no_stream. Else, the return value will
384/// contain the stream returned by createIndexedStream().
385Expected<std::unique_ptr<MappedBlockStream>> PDBFile::safelyCreateIndexedStream(
386 const MSFLayout &Layout, const ReadableStream &MsfData,
387 uint32_t StreamIndex) const {
388 if (StreamIndex >= getNumStreams())
389 return make_error<RawError>(raw_error_code::no_stream);
390 return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex);
391}