blob: ce2446cba808fced7106a14512960054ec45217e [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
David Majnemer1b79e9a2016-07-10 05:32:05 +000074uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
Zachary Turner1dc9fd32016-06-14 20:48:36 +000075
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;
David Majnemer1b79e9a2016-07-10 05:32:05 +0000157 for (uint32_t Block : Blocks) {
158 uint64_t BlockEndOffset = (uint64_t)(Block + 1) * SB->BlockSize;
159 if (BlockEndOffset > getFileSize())
160 return make_error<RawError>(raw_error_code::corrupt_file,
161 "Stream block map is corrupt.");
162 }
Zachary Turnerb84faa82016-06-10 05:10:19 +0000163 StreamMap.push_back(Blocks);
David Majnemer9efba742016-05-27 16:16:48 +0000164 }
165
Zachary Turner0a43efe2016-04-25 17:38:08 +0000166 // We should have read exactly SB->NumDirectoryBytes bytes.
Zachary Turnerd8447992016-06-07 05:28:55 +0000167 assert(Reader.bytesRemaining() == 0);
Zachary Turnera1657a92016-06-08 17:26:39 +0000168 DirectoryStream = std::move(*DS);
Zachary Turner819e77d2016-05-06 20:51:57 +0000169 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000170}
171
Zachary Turnerd8447992016-06-07 05:28:55 +0000172llvm::ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
Zachary Turnerab58ae82016-06-30 17:43:00 +0000173 return DirectoryBlocks;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000174}
Zachary Turner53a65ba2016-04-26 18:42:34 +0000175
Zachary Turner8848a7a2016-07-06 18:05:57 +0000176Expected<InfoStream &> PDBFile::emplacePDBInfoStream() {
177 if (Info)
178 Info.reset();
179
180 auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, *this);
181 if (!InfoS)
182 return InfoS.takeError();
183 Info = llvm::make_unique<InfoStream>(std::move(*InfoS));
184 return *Info;
185}
186
Zachary Turner819e77d2016-05-06 20:51:57 +0000187Expected<InfoStream &> PDBFile::getPDBInfoStream() {
Zachary Turner2f09b502016-04-29 17:28:47 +0000188 if (!Info) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000189 auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, *this);
190 if (!InfoS)
191 return InfoS.takeError();
192 auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
193 if (auto EC = TempInfo->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000194 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000195 Info = std::move(TempInfo);
Zachary Turner53a65ba2016-04-26 18:42:34 +0000196 }
Zachary Turner2f09b502016-04-29 17:28:47 +0000197 return *Info;
Zachary Turner53a65ba2016-04-26 18:42:34 +0000198}
199
Zachary Turner819e77d2016-05-06 20:51:57 +0000200Expected<DbiStream &> PDBFile::getPDBDbiStream() {
Zachary Turner2f09b502016-04-29 17:28:47 +0000201 if (!Dbi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000202 auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, *this);
203 if (!DbiS)
204 return DbiS.takeError();
205 auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
206 if (auto EC = TempDbi->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000207 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000208 Dbi = std::move(TempDbi);
Zachary Turner53a65ba2016-04-26 18:42:34 +0000209 }
Zachary Turner2f09b502016-04-29 17:28:47 +0000210 return *Dbi;
Zachary Turner53a65ba2016-04-26 18:42:34 +0000211}
Zachary Turnerf5c59652016-05-03 00:28:21 +0000212
Zachary Turner819e77d2016-05-06 20:51:57 +0000213Expected<TpiStream &> PDBFile::getPDBTpiStream() {
Zachary Turnerf5c59652016-05-03 00:28:21 +0000214 if (!Tpi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000215 auto TpiS = MappedBlockStream::createIndexedStream(StreamTPI, *this);
216 if (!TpiS)
217 return TpiS.takeError();
218 auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
219 if (auto EC = TempTpi->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000220 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000221 Tpi = std::move(TempTpi);
Zachary Turnerf5c59652016-05-03 00:28:21 +0000222 }
223 return *Tpi;
224}
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000225
Zachary Turnerc9972c62016-05-25 04:35:22 +0000226Expected<TpiStream &> PDBFile::getPDBIpiStream() {
227 if (!Ipi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000228 auto IpiS = MappedBlockStream::createIndexedStream(StreamIPI, *this);
229 if (!IpiS)
230 return IpiS.takeError();
231 auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
232 if (auto EC = TempIpi->reload())
Zachary Turnerc9972c62016-05-25 04:35:22 +0000233 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000234 Ipi = std::move(TempIpi);
Zachary Turnerc9972c62016-05-25 04:35:22 +0000235 }
236 return *Ipi;
237}
238
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000239Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
240 if (!Publics) {
241 auto DbiS = getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000242 if (!DbiS)
243 return DbiS.takeError();
244
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000245 uint32_t PublicsStreamNum = DbiS->getPublicSymbolStreamIndex();
246
Zachary Turnera1657a92016-06-08 17:26:39 +0000247 auto PublicS =
248 MappedBlockStream::createIndexedStream(PublicsStreamNum, *this);
249 if (!PublicS)
250 return PublicS.takeError();
251 auto TempPublics =
252 llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
253 if (auto EC = TempPublics->reload())
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000254 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000255 Publics = std::move(TempPublics);
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000256 }
257 return *Publics;
258}
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000259
260Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
261 if (!Symbols) {
262 auto DbiS = getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000263 if (!DbiS)
264 return DbiS.takeError();
265
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000266 uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
267
Zachary Turnera1657a92016-06-08 17:26:39 +0000268 auto SymbolS =
269 MappedBlockStream::createIndexedStream(SymbolStreamNum, *this);
270 if (!SymbolS)
271 return SymbolS.takeError();
272 auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
273 if (auto EC = TempSymbols->reload())
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000274 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000275 Symbols = std::move(TempSymbols);
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000276 }
277 return *Symbols;
278}
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000279
280Expected<NameHashTable &> PDBFile::getStringTable() {
281 if (!StringTable || !StringTableStream) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000282 auto IS = getPDBInfoStream();
283 if (!IS)
284 return IS.takeError();
285
286 uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names");
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000287
288 if (NameStreamIndex == 0)
289 return make_error<RawError>(raw_error_code::no_stream);
Zachary Turnerd2b2bfe2016-06-08 00:25:08 +0000290 if (NameStreamIndex >= getNumStreams())
291 return make_error<RawError>(raw_error_code::no_stream);
292
Zachary Turnera1657a92016-06-08 17:26:39 +0000293 auto NS = MappedBlockStream::createIndexedStream(NameStreamIndex, *this);
294 if (!NS)
295 return NS.takeError();
296
Zachary Turnerb84faa82016-06-10 05:10:19 +0000297 StreamReader Reader(**NS);
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000298 auto N = llvm::make_unique<NameHashTable>();
299 if (auto EC = N->load(Reader))
300 return std::move(EC);
301 StringTable = std::move(N);
Zachary Turnera1657a92016-06-08 17:26:39 +0000302 StringTableStream = std::move(*NS);
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000303 }
304 return *StringTable;
305}
Zachary Turner1dc9fd32016-06-14 20:48:36 +0000306
Zachary Turnerab58ae82016-06-30 17:43:00 +0000307Error PDBFile::setSuperBlock(const SuperBlock *Block) {
308 SB = Block;
309
310 // Check the magic bytes.
311 if (memcmp(SB->MagicBytes, MsfMagic, sizeof(MsfMagic)) != 0)
312 return make_error<RawError>(raw_error_code::corrupt_file,
313 "MSF magic header doesn't match");
314
315 // We don't support blocksizes which aren't a multiple of four bytes.
316 if (SB->BlockSize % sizeof(support::ulittle32_t) != 0)
317 return make_error<RawError>(raw_error_code::corrupt_file,
318 "Block size is not multiple of 4.");
319
320 switch (SB->BlockSize) {
321 case 512:
322 case 1024:
323 case 2048:
324 case 4096:
325 break;
326 default:
327 // An invalid block size suggests a corrupt PDB file.
328 return make_error<RawError>(raw_error_code::corrupt_file,
329 "Unsupported block size.");
330 }
331
332 if (Buffer->getLength() % SB->BlockSize != 0)
333 return make_error<RawError>(raw_error_code::corrupt_file,
334 "File size is not a multiple of block size");
335
336 // We don't support directories whose sizes aren't a multiple of four bytes.
337 if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0)
338 return make_error<RawError>(raw_error_code::corrupt_file,
339 "Directory size is not multiple of 4.");
340
341 // The number of blocks which comprise the directory is a simple function of
342 // the number of bytes it contains.
343 uint64_t NumDirectoryBlocks = getNumDirectoryBlocks();
344
345 // The directory, as we understand it, is a block which consists of a list of
346 // block numbers. It is unclear what would happen if the number of blocks
347 // couldn't fit on a single block.
348 if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t))
349 return make_error<RawError>(raw_error_code::corrupt_file,
350 "Too many directory blocks.");
351
352 return Error::success();
353}
Zachary Turner1dc9fd32016-06-14 20:48:36 +0000354
355void PDBFile::setStreamSizes(ArrayRef<support::ulittle32_t> Sizes) {
356 StreamSizes = Sizes;
357}
358
Zachary Turnerab58ae82016-06-30 17:43:00 +0000359void PDBFile::setStreamMap(
Zachary Turnerab58ae82016-06-30 17:43:00 +0000360 std::vector<ArrayRef<support::ulittle32_t>> &Streams) {
Zachary Turnerab58ae82016-06-30 17:43:00 +0000361 StreamMap = Streams;
Zachary Turner1dc9fd32016-06-14 20:48:36 +0000362}
363
Zachary Turner8848a7a2016-07-06 18:05:57 +0000364void PDBFile::setDirectoryBlocks(ArrayRef<support::ulittle32_t> Directory) {
365 DirectoryBlocks = Directory;
366}
367
368Error PDBFile::generateSimpleStreamMap() {
369 if (StreamSizes.empty())
370 return Error::success();
371
372 static std::vector<std::vector<support::ulittle32_t>> StaticMap;
373 StreamMap.clear();
374 StaticMap.clear();
375
376 // Figure out how many blocks are needed for all streams, and set the first
377 // used block to the highest block so that we can write the rest of the
378 // blocks contiguously.
379 uint32_t TotalFileBlocks = getBlockCount();
380 std::vector<support::ulittle32_t> ReservedBlocks;
381 ReservedBlocks.push_back(support::ulittle32_t(0));
382 ReservedBlocks.push_back(SB->BlockMapAddr);
383 ReservedBlocks.insert(ReservedBlocks.end(), DirectoryBlocks.begin(),
384 DirectoryBlocks.end());
385
386 uint32_t BlocksNeeded = 0;
387 for (auto Size : StreamSizes)
388 BlocksNeeded += bytesToBlocks(Size, getBlockSize());
389
390 support::ulittle32_t NextBlock(TotalFileBlocks - BlocksNeeded -
391 ReservedBlocks.size());
392
393 StaticMap.resize(StreamSizes.size());
394 for (uint32_t S = 0; S < StreamSizes.size(); ++S) {
395 uint32_t Size = StreamSizes[S];
396 uint32_t NumBlocks = bytesToBlocks(Size, getBlockSize());
397 auto &ThisStream = StaticMap[S];
398 for (uint32_t I = 0; I < NumBlocks;) {
399 NextBlock += 1;
400 if (std::find(ReservedBlocks.begin(), ReservedBlocks.end(), NextBlock) !=
401 ReservedBlocks.end())
402 continue;
403
404 ++I;
405 assert(NextBlock < getBlockCount());
406 ThisStream.push_back(NextBlock);
407 }
408 StreamMap.push_back(ThisStream);
409 }
410 return Error::success();
411}
412
Zachary Turnerab58ae82016-06-30 17:43:00 +0000413Error PDBFile::commit() {
414 StreamWriter Writer(*Buffer);
415
416 if (auto EC = Writer.writeObject(*SB))
417 return EC;
418 Writer.setOffset(getBlockMapOffset());
419 if (auto EC = Writer.writeArray(DirectoryBlocks))
420 return EC;
421
422 auto DS = MappedBlockStream::createDirectoryStream(*this);
423 if (!DS)
424 return DS.takeError();
425 auto DirStream = std::move(*DS);
426 StreamWriter DW(*DirStream);
427 if (auto EC = DW.writeInteger(this->getNumStreams()))
428 return EC;
429
430 if (auto EC = DW.writeArray(StreamSizes))
431 return EC;
432
433 for (const auto &Blocks : StreamMap) {
434 if (auto EC = DW.writeArray(Blocks))
435 return EC;
436 }
437
Zachary Turner8848a7a2016-07-06 18:05:57 +0000438 if (Info) {
439 if (auto EC = Info->commit())
440 return EC;
441 }
442
443 if (Dbi) {
444 if (auto EC = Dbi->commit())
445 return EC;
446 }
447
448 if (Symbols) {
449 if (auto EC = Symbols->commit())
450 return EC;
451 }
452
453 if (Publics) {
454 if (auto EC = Publics->commit())
455 return EC;
456 }
457
458 if (Tpi) {
459 if (auto EC = Tpi->commit())
460 return EC;
461 }
462
463 if (Ipi) {
464 if (auto EC = Ipi->commit())
465 return EC;
466 }
467
Zachary Turnerab58ae82016-06-30 17:43:00 +0000468 return Buffer->commit();
David Majnemer6211b1f2016-07-10 03:34:47 +0000469}