blob: b289fd0124ba96d4e44809ae0810cd471ec32c14 [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
10#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
Zachary Turnerd8447992016-06-07 05:28:55 +000011
Zachary Turner0a43efe2016-04-25 17:38:08 +000012#include "llvm/ADT/ArrayRef.h"
Zachary Turnerd8447992016-06-07 05:28:55 +000013#include "llvm/DebugInfo/CodeView/StreamArray.h"
Zachary Turnerb84faa82016-06-10 05:10:19 +000014#include "llvm/DebugInfo/CodeView/StreamInterface.h"
Zachary Turnerd8447992016-06-07 05:28:55 +000015#include "llvm/DebugInfo/CodeView/StreamReader.h"
Zachary Turnerab58ae82016-06-30 17:43:00 +000016#include "llvm/DebugInfo/CodeView/StreamWriter.h"
Zachary Turner2f09b502016-04-29 17:28:47 +000017#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
Zachary Turnera1657a92016-06-08 17:26:39 +000018#include "llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h"
Zachary Turnerd8447992016-06-07 05:28:55 +000019#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
Zachary Turner2f09b502016-04-29 17:28:47 +000020#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
Zachary Turner3df1bfa2016-06-03 05:52:57 +000021#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h"
Rui Ueyama1f6b6e22016-05-13 21:21:53 +000022#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
Zachary Turner819e77d2016-05-06 20:51:57 +000023#include "llvm/DebugInfo/PDB/Raw/RawError.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"
Zachary Turner1dc9fd32016-06-14 20:48:36 +000027#include "llvm/Support/FileOutputBuffer.h"
Zachary Turner0a43efe2016-04-25 17:38:08 +000028#include "llvm/Support/MemoryBuffer.h"
29
30using namespace llvm;
Zachary Turnerb84faa82016-06-10 05:10:19 +000031using namespace llvm::codeview;
Zachary Turner2f09b502016-04-29 17:28:47 +000032using namespace llvm::pdb;
Zachary Turner0a43efe2016-04-25 17:38:08 +000033
34namespace {
Zachary Turnerb84faa82016-06-10 05:10:19 +000035typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
Zachary Turner0a43efe2016-04-25 17:38:08 +000036}
37
Zachary Turnerb84faa82016-06-10 05:10:19 +000038PDBFile::PDBFile(std::unique_ptr<StreamInterface> PdbFileBuffer)
39 : Buffer(std::move(PdbFileBuffer)), SB(nullptr) {}
Zachary Turner0a43efe2016-04-25 17:38:08 +000040
41PDBFile::~PDBFile() {}
42
Zachary Turnerb84faa82016-06-10 05:10:19 +000043uint32_t PDBFile::getBlockSize() const { return SB->BlockSize; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000044
Zachary Turnerb84faa82016-06-10 05:10:19 +000045uint32_t PDBFile::getUnknown0() const { return SB->Unknown0; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000046
Zachary Turnerb84faa82016-06-10 05:10:19 +000047uint32_t PDBFile::getBlockCount() const { return SB->NumBlocks; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000048
Zachary Turnerb84faa82016-06-10 05:10:19 +000049uint32_t PDBFile::getNumDirectoryBytes() const { return SB->NumDirectoryBytes; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000050
Zachary Turnerb84faa82016-06-10 05:10:19 +000051uint32_t PDBFile::getBlockMapIndex() const { return SB->BlockMapAddr; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000052
Zachary Turnerb84faa82016-06-10 05:10:19 +000053uint32_t PDBFile::getUnknown1() const { return SB->Unknown1; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000054
55uint32_t PDBFile::getNumDirectoryBlocks() const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000056 return bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize);
Zachary Turner0a43efe2016-04-25 17:38:08 +000057}
58
59uint64_t PDBFile::getBlockMapOffset() const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000060 return (uint64_t)SB->BlockMapAddr * SB->BlockSize;
Zachary Turner0a43efe2016-04-25 17:38:08 +000061}
62
Zachary Turnerb84faa82016-06-10 05:10:19 +000063uint32_t PDBFile::getNumStreams() const { return StreamSizes.size(); }
Zachary Turner0a43efe2016-04-25 17:38:08 +000064
65uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000066 return StreamSizes[StreamIndex];
Zachary Turner0a43efe2016-04-25 17:38:08 +000067}
68
Zachary Turnerd8447992016-06-07 05:28:55 +000069ArrayRef<support::ulittle32_t>
Zachary Turner0a43efe2016-04-25 17:38:08 +000070PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000071 return StreamMap[StreamIndex];
Zachary Turner0a43efe2016-04-25 17:38:08 +000072}
73
Zachary Turner1dc9fd32016-06-14 20:48:36 +000074size_t PDBFile::getFileSize() const { return Buffer->getLength(); }
75
David Majnemer6211b1f2016-07-10 03:34:47 +000076Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
77 uint32_t NumBytes) const {
Zachary Turner0a43efe2016-04-25 17:38:08 +000078 uint64_t StreamBlockOffset = blockToOffset(BlockIndex, getBlockSize());
79
Zachary Turnerb84faa82016-06-10 05:10:19 +000080 ArrayRef<uint8_t> Result;
81 if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
David Majnemer6211b1f2016-07-10 03:34:47 +000082 return std::move(EC);
Zachary Turnerb84faa82016-06-10 05:10:19 +000083 return Result;
Zachary Turner0a43efe2016-04-25 17:38:08 +000084}
85
Zachary Turner5acb4ac2016-06-10 05:09:12 +000086Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
87 ArrayRef<uint8_t> Data) const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000088 if (Offset >= getBlockSize())
89 return make_error<RawError>(
90 raw_error_code::invalid_block_address,
91 "setBlockData attempted to write out of block bounds.");
Zachary Turner8848a7a2016-07-06 18:05:57 +000092 if (Data.size() > getBlockSize() - Offset)
Zachary Turnerb84faa82016-06-10 05:10:19 +000093 return make_error<RawError>(
94 raw_error_code::invalid_block_address,
95 "setBlockData attempted to write out of block bounds.");
Zachary Turner5acb4ac2016-06-10 05:09:12 +000096
Zachary Turnerb84faa82016-06-10 05:10:19 +000097 uint64_t StreamBlockOffset = blockToOffset(BlockIndex, getBlockSize());
98 StreamBlockOffset += Offset;
99 return Buffer->writeBytes(StreamBlockOffset, Data);
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000100}
101
Zachary Turner819e77d2016-05-06 20:51:57 +0000102Error PDBFile::parseFileHeaders() {
Zachary Turnerb84faa82016-06-10 05:10:19 +0000103 StreamReader Reader(*Buffer);
Zachary Turnerc59261c2016-05-25 03:53:16 +0000104
Zachary Turnerb84faa82016-06-10 05:10:19 +0000105 if (auto EC = Reader.readObject(SB)) {
106 consumeError(std::move(EC));
Zachary Turner819e77d2016-05-06 20:51:57 +0000107 return make_error<RawError>(raw_error_code::corrupt_file,
108 "Does not contain superblock");
Zachary Turnerb84faa82016-06-10 05:10:19 +0000109 }
Zachary Turner0a43efe2016-04-25 17:38:08 +0000110
Zachary Turnerab58ae82016-06-30 17:43:00 +0000111 if (auto EC = setSuperBlock(SB))
112 return EC;
Zachary Turner819e77d2016-05-06 20:51:57 +0000113
Zachary Turnerab58ae82016-06-30 17:43:00 +0000114 Reader.setOffset(getBlockMapOffset());
115 if (auto EC = Reader.readArray(DirectoryBlocks, getNumDirectoryBlocks()))
116 return EC;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000117
Zachary Turner819e77d2016-05-06 20:51:57 +0000118 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000119}
120
Zachary Turner819e77d2016-05-06 20:51:57 +0000121Error PDBFile::parseStreamData() {
Zachary Turnerb84faa82016-06-10 05:10:19 +0000122 assert(SB);
Zachary Turnerd8447992016-06-07 05:28:55 +0000123 if (DirectoryStream)
124 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000125
Zachary Turner0a43efe2016-04-25 17:38:08 +0000126 uint32_t NumStreams = 0;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000127
Zachary Turnerd8447992016-06-07 05:28:55 +0000128 // Normally you can't use a MappedBlockStream without having fully parsed the
129 // PDB file, because it accesses the directory and various other things, which
130 // is exactly what we are attempting to parse. By specifying a custom
131 // subclass of IPDBStreamData which only accesses the fields that have already
132 // been parsed, we can avoid this and reuse MappedBlockStream.
Zachary Turnera1657a92016-06-08 17:26:39 +0000133 auto DS = MappedBlockStream::createDirectoryStream(*this);
134 if (!DS)
135 return DS.takeError();
Zachary Turnerb84faa82016-06-10 05:10:19 +0000136 StreamReader Reader(**DS);
Zachary Turnerd8447992016-06-07 05:28:55 +0000137 if (auto EC = Reader.readInteger(NumStreams))
138 return EC;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000139
Zachary Turnerb84faa82016-06-10 05:10:19 +0000140 if (auto EC = Reader.readArray(StreamSizes, NumStreams))
Zachary Turnerd8447992016-06-07 05:28:55 +0000141 return EC;
142 for (uint32_t I = 0; I < NumStreams; ++I) {
Reid Kleckner5aba52f2016-06-22 22:42:24 +0000143 uint32_t StreamSize = getStreamByteSize(I);
144 // FIXME: What does StreamSize ~0U mean?
David Majnemer9efba742016-05-27 16:16:48 +0000145 uint64_t NumExpectedStreamBlocks =
Reid Kleckner5aba52f2016-06-22 22:42:24 +0000146 StreamSize == UINT32_MAX ? 0 : bytesToBlocks(StreamSize, SB->BlockSize);
Zachary Turnerb84faa82016-06-10 05:10:19 +0000147
148 // For convenience, we store the block array contiguously. This is because
149 // if someone calls setStreamMap(), it is more convenient to be able to call
150 // it with an ArrayRef instead of setting up a StreamRef. Since the
151 // DirectoryStream is cached in the class and thus lives for the life of the
152 // class, we can be guaranteed that readArray() will return a stable
153 // reference, even if it has to allocate from its internal pool.
154 ArrayRef<support::ulittle32_t> Blocks;
Zachary Turnerd8447992016-06-07 05:28:55 +0000155 if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
156 return EC;
Zachary Turnerb84faa82016-06-10 05:10:19 +0000157 StreamMap.push_back(Blocks);
David Majnemer9efba742016-05-27 16:16:48 +0000158 }
159
Zachary Turner0a43efe2016-04-25 17:38:08 +0000160 // We should have read exactly SB->NumDirectoryBytes bytes.
Zachary Turnerd8447992016-06-07 05:28:55 +0000161 assert(Reader.bytesRemaining() == 0);
Zachary Turnera1657a92016-06-08 17:26:39 +0000162 DirectoryStream = std::move(*DS);
Zachary Turner819e77d2016-05-06 20:51:57 +0000163 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000164}
165
Zachary Turnerd8447992016-06-07 05:28:55 +0000166llvm::ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
Zachary Turnerab58ae82016-06-30 17:43:00 +0000167 return DirectoryBlocks;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000168}
Zachary Turner53a65ba2016-04-26 18:42:34 +0000169
Zachary Turner8848a7a2016-07-06 18:05:57 +0000170Expected<InfoStream &> PDBFile::emplacePDBInfoStream() {
171 if (Info)
172 Info.reset();
173
174 auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, *this);
175 if (!InfoS)
176 return InfoS.takeError();
177 Info = llvm::make_unique<InfoStream>(std::move(*InfoS));
178 return *Info;
179}
180
Zachary Turner819e77d2016-05-06 20:51:57 +0000181Expected<InfoStream &> PDBFile::getPDBInfoStream() {
Zachary Turner2f09b502016-04-29 17:28:47 +0000182 if (!Info) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000183 auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, *this);
184 if (!InfoS)
185 return InfoS.takeError();
186 auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
187 if (auto EC = TempInfo->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000188 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000189 Info = std::move(TempInfo);
Zachary Turner53a65ba2016-04-26 18:42:34 +0000190 }
Zachary Turner2f09b502016-04-29 17:28:47 +0000191 return *Info;
Zachary Turner53a65ba2016-04-26 18:42:34 +0000192}
193
Zachary Turner819e77d2016-05-06 20:51:57 +0000194Expected<DbiStream &> PDBFile::getPDBDbiStream() {
Zachary Turner2f09b502016-04-29 17:28:47 +0000195 if (!Dbi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000196 auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, *this);
197 if (!DbiS)
198 return DbiS.takeError();
199 auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
200 if (auto EC = TempDbi->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000201 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000202 Dbi = std::move(TempDbi);
Zachary Turner53a65ba2016-04-26 18:42:34 +0000203 }
Zachary Turner2f09b502016-04-29 17:28:47 +0000204 return *Dbi;
Zachary Turner53a65ba2016-04-26 18:42:34 +0000205}
Zachary Turnerf5c59652016-05-03 00:28:21 +0000206
Zachary Turner819e77d2016-05-06 20:51:57 +0000207Expected<TpiStream &> PDBFile::getPDBTpiStream() {
Zachary Turnerf5c59652016-05-03 00:28:21 +0000208 if (!Tpi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000209 auto TpiS = MappedBlockStream::createIndexedStream(StreamTPI, *this);
210 if (!TpiS)
211 return TpiS.takeError();
212 auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
213 if (auto EC = TempTpi->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000214 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000215 Tpi = std::move(TempTpi);
Zachary Turnerf5c59652016-05-03 00:28:21 +0000216 }
217 return *Tpi;
218}
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000219
Zachary Turnerc9972c62016-05-25 04:35:22 +0000220Expected<TpiStream &> PDBFile::getPDBIpiStream() {
221 if (!Ipi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000222 auto IpiS = MappedBlockStream::createIndexedStream(StreamIPI, *this);
223 if (!IpiS)
224 return IpiS.takeError();
225 auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
226 if (auto EC = TempIpi->reload())
Zachary Turnerc9972c62016-05-25 04:35:22 +0000227 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000228 Ipi = std::move(TempIpi);
Zachary Turnerc9972c62016-05-25 04:35:22 +0000229 }
230 return *Ipi;
231}
232
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000233Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
234 if (!Publics) {
235 auto DbiS = getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000236 if (!DbiS)
237 return DbiS.takeError();
238
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000239 uint32_t PublicsStreamNum = DbiS->getPublicSymbolStreamIndex();
240
Zachary Turnera1657a92016-06-08 17:26:39 +0000241 auto PublicS =
242 MappedBlockStream::createIndexedStream(PublicsStreamNum, *this);
243 if (!PublicS)
244 return PublicS.takeError();
245 auto TempPublics =
246 llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
247 if (auto EC = TempPublics->reload())
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000248 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000249 Publics = std::move(TempPublics);
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000250 }
251 return *Publics;
252}
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000253
254Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
255 if (!Symbols) {
256 auto DbiS = getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000257 if (!DbiS)
258 return DbiS.takeError();
259
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000260 uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
261
Zachary Turnera1657a92016-06-08 17:26:39 +0000262 auto SymbolS =
263 MappedBlockStream::createIndexedStream(SymbolStreamNum, *this);
264 if (!SymbolS)
265 return SymbolS.takeError();
266 auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
267 if (auto EC = TempSymbols->reload())
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000268 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000269 Symbols = std::move(TempSymbols);
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000270 }
271 return *Symbols;
272}
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000273
274Expected<NameHashTable &> PDBFile::getStringTable() {
275 if (!StringTable || !StringTableStream) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000276 auto IS = getPDBInfoStream();
277 if (!IS)
278 return IS.takeError();
279
280 uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names");
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000281
282 if (NameStreamIndex == 0)
283 return make_error<RawError>(raw_error_code::no_stream);
Zachary Turnerd2b2bfe2016-06-08 00:25:08 +0000284 if (NameStreamIndex >= getNumStreams())
285 return make_error<RawError>(raw_error_code::no_stream);
286
Zachary Turnera1657a92016-06-08 17:26:39 +0000287 auto NS = MappedBlockStream::createIndexedStream(NameStreamIndex, *this);
288 if (!NS)
289 return NS.takeError();
290
Zachary Turnerb84faa82016-06-10 05:10:19 +0000291 StreamReader Reader(**NS);
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000292 auto N = llvm::make_unique<NameHashTable>();
293 if (auto EC = N->load(Reader))
294 return std::move(EC);
295 StringTable = std::move(N);
Zachary Turnera1657a92016-06-08 17:26:39 +0000296 StringTableStream = std::move(*NS);
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000297 }
298 return *StringTable;
299}
Zachary Turner1dc9fd32016-06-14 20:48:36 +0000300
Zachary Turnerab58ae82016-06-30 17:43:00 +0000301Error PDBFile::setSuperBlock(const SuperBlock *Block) {
302 SB = Block;
303
304 // Check the magic bytes.
305 if (memcmp(SB->MagicBytes, MsfMagic, sizeof(MsfMagic)) != 0)
306 return make_error<RawError>(raw_error_code::corrupt_file,
307 "MSF magic header doesn't match");
308
309 // We don't support blocksizes which aren't a multiple of four bytes.
310 if (SB->BlockSize % sizeof(support::ulittle32_t) != 0)
311 return make_error<RawError>(raw_error_code::corrupt_file,
312 "Block size is not multiple of 4.");
313
314 switch (SB->BlockSize) {
315 case 512:
316 case 1024:
317 case 2048:
318 case 4096:
319 break;
320 default:
321 // An invalid block size suggests a corrupt PDB file.
322 return make_error<RawError>(raw_error_code::corrupt_file,
323 "Unsupported block size.");
324 }
325
326 if (Buffer->getLength() % SB->BlockSize != 0)
327 return make_error<RawError>(raw_error_code::corrupt_file,
328 "File size is not a multiple of block size");
329
330 // We don't support directories whose sizes aren't a multiple of four bytes.
331 if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0)
332 return make_error<RawError>(raw_error_code::corrupt_file,
333 "Directory size is not multiple of 4.");
334
335 // The number of blocks which comprise the directory is a simple function of
336 // the number of bytes it contains.
337 uint64_t NumDirectoryBlocks = getNumDirectoryBlocks();
338
339 // The directory, as we understand it, is a block which consists of a list of
340 // block numbers. It is unclear what would happen if the number of blocks
341 // couldn't fit on a single block.
342 if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t))
343 return make_error<RawError>(raw_error_code::corrupt_file,
344 "Too many directory blocks.");
345
346 return Error::success();
347}
Zachary Turner1dc9fd32016-06-14 20:48:36 +0000348
349void PDBFile::setStreamSizes(ArrayRef<support::ulittle32_t> Sizes) {
350 StreamSizes = Sizes;
351}
352
Zachary Turnerab58ae82016-06-30 17:43:00 +0000353void PDBFile::setStreamMap(
Zachary Turnerab58ae82016-06-30 17:43:00 +0000354 std::vector<ArrayRef<support::ulittle32_t>> &Streams) {
Zachary Turnerab58ae82016-06-30 17:43:00 +0000355 StreamMap = Streams;
Zachary Turner1dc9fd32016-06-14 20:48:36 +0000356}
357
Zachary Turner8848a7a2016-07-06 18:05:57 +0000358void PDBFile::setDirectoryBlocks(ArrayRef<support::ulittle32_t> Directory) {
359 DirectoryBlocks = Directory;
360}
361
362Error PDBFile::generateSimpleStreamMap() {
363 if (StreamSizes.empty())
364 return Error::success();
365
366 static std::vector<std::vector<support::ulittle32_t>> StaticMap;
367 StreamMap.clear();
368 StaticMap.clear();
369
370 // Figure out how many blocks are needed for all streams, and set the first
371 // used block to the highest block so that we can write the rest of the
372 // blocks contiguously.
373 uint32_t TotalFileBlocks = getBlockCount();
374 std::vector<support::ulittle32_t> ReservedBlocks;
375 ReservedBlocks.push_back(support::ulittle32_t(0));
376 ReservedBlocks.push_back(SB->BlockMapAddr);
377 ReservedBlocks.insert(ReservedBlocks.end(), DirectoryBlocks.begin(),
378 DirectoryBlocks.end());
379
380 uint32_t BlocksNeeded = 0;
381 for (auto Size : StreamSizes)
382 BlocksNeeded += bytesToBlocks(Size, getBlockSize());
383
384 support::ulittle32_t NextBlock(TotalFileBlocks - BlocksNeeded -
385 ReservedBlocks.size());
386
387 StaticMap.resize(StreamSizes.size());
388 for (uint32_t S = 0; S < StreamSizes.size(); ++S) {
389 uint32_t Size = StreamSizes[S];
390 uint32_t NumBlocks = bytesToBlocks(Size, getBlockSize());
391 auto &ThisStream = StaticMap[S];
392 for (uint32_t I = 0; I < NumBlocks;) {
393 NextBlock += 1;
394 if (std::find(ReservedBlocks.begin(), ReservedBlocks.end(), NextBlock) !=
395 ReservedBlocks.end())
396 continue;
397
398 ++I;
399 assert(NextBlock < getBlockCount());
400 ThisStream.push_back(NextBlock);
401 }
402 StreamMap.push_back(ThisStream);
403 }
404 return Error::success();
405}
406
Zachary Turnerab58ae82016-06-30 17:43:00 +0000407Error PDBFile::commit() {
408 StreamWriter Writer(*Buffer);
409
410 if (auto EC = Writer.writeObject(*SB))
411 return EC;
412 Writer.setOffset(getBlockMapOffset());
413 if (auto EC = Writer.writeArray(DirectoryBlocks))
414 return EC;
415
416 auto DS = MappedBlockStream::createDirectoryStream(*this);
417 if (!DS)
418 return DS.takeError();
419 auto DirStream = std::move(*DS);
420 StreamWriter DW(*DirStream);
421 if (auto EC = DW.writeInteger(this->getNumStreams()))
422 return EC;
423
424 if (auto EC = DW.writeArray(StreamSizes))
425 return EC;
426
427 for (const auto &Blocks : StreamMap) {
428 if (auto EC = DW.writeArray(Blocks))
429 return EC;
430 }
431
Zachary Turner8848a7a2016-07-06 18:05:57 +0000432 if (Info) {
433 if (auto EC = Info->commit())
434 return EC;
435 }
436
437 if (Dbi) {
438 if (auto EC = Dbi->commit())
439 return EC;
440 }
441
442 if (Symbols) {
443 if (auto EC = Symbols->commit())
444 return EC;
445 }
446
447 if (Publics) {
448 if (auto EC = Publics->commit())
449 return EC;
450 }
451
452 if (Tpi) {
453 if (auto EC = Tpi->commit())
454 return EC;
455 }
456
457 if (Ipi) {
458 if (auto EC = Ipi->commit())
459 return EC;
460 }
461
Zachary Turnerab58ae82016-06-30 17:43:00 +0000462 return Buffer->commit();
David Majnemer6211b1f2016-07-10 03:34:47 +0000463}