blob: e2edf38e59408a32d2730f1d28492dcd537d598d [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 Turnerbac69d32016-07-22 19:56:05 +000013#include "llvm/DebugInfo/Msf/DirectoryStreamData.h"
14#include "llvm/DebugInfo/Msf/IndexedStreamData.h"
15#include "llvm/DebugInfo/Msf/StreamArray.h"
16#include "llvm/DebugInfo/Msf/StreamInterface.h"
17#include "llvm/DebugInfo/Msf/StreamReader.h"
18#include "llvm/DebugInfo/Msf/StreamWriter.h"
Zachary Turner2f09b502016-04-29 17:28:47 +000019#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
20#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 Turnerbac69d32016-07-22 19:56:05 +000032using namespace llvm::msf;
Zachary Turner2f09b502016-04-29 17:28:47 +000033using namespace llvm::pdb;
Zachary Turner0a43efe2016-04-25 17:38:08 +000034
35namespace {
Zachary Turnerb84faa82016-06-10 05:10:19 +000036typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
Zachary Turner0a43efe2016-04-25 17:38:08 +000037}
38
Zachary Turnere109dc62016-07-22 19:56:26 +000039PDBFile::PDBFile(std::unique_ptr<StreamInterface> PdbFileBuffer,
40 BumpPtrAllocator &Allocator)
41 : Allocator(Allocator), Buffer(std::move(PdbFileBuffer)), SB(nullptr) {}
Zachary Turner0a43efe2016-04-25 17:38:08 +000042
43PDBFile::~PDBFile() {}
44
Zachary Turnerb84faa82016-06-10 05:10:19 +000045uint32_t PDBFile::getBlockSize() const { return SB->BlockSize; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000046
Zachary Turnerb927e022016-07-15 22:17:19 +000047uint32_t PDBFile::getFreeBlockMapBlock() const { return SB->FreeBlockMapBlock; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000048
Zachary Turnerb84faa82016-06-10 05:10:19 +000049uint32_t PDBFile::getBlockCount() const { return SB->NumBlocks; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000050
Zachary Turnerb84faa82016-06-10 05:10:19 +000051uint32_t PDBFile::getNumDirectoryBytes() const { return SB->NumDirectoryBytes; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000052
Zachary Turnerb84faa82016-06-10 05:10:19 +000053uint32_t PDBFile::getBlockMapIndex() const { return SB->BlockMapAddr; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000054
Zachary Turnerb84faa82016-06-10 05:10:19 +000055uint32_t PDBFile::getUnknown1() const { return SB->Unknown1; }
Zachary Turner0a43efe2016-04-25 17:38:08 +000056
57uint32_t PDBFile::getNumDirectoryBlocks() const {
Zachary Turnerfaa554b2016-07-15 22:16:56 +000058 return msf::bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize);
Zachary Turner0a43efe2016-04-25 17:38:08 +000059}
60
61uint64_t PDBFile::getBlockMapOffset() const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000062 return (uint64_t)SB->BlockMapAddr * SB->BlockSize;
Zachary Turner0a43efe2016-04-25 17:38:08 +000063}
64
Zachary Turnerb84faa82016-06-10 05:10:19 +000065uint32_t PDBFile::getNumStreams() const { return StreamSizes.size(); }
Zachary Turner0a43efe2016-04-25 17:38:08 +000066
67uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000068 return StreamSizes[StreamIndex];
Zachary Turner0a43efe2016-04-25 17:38:08 +000069}
70
Zachary Turnerd8447992016-06-07 05:28:55 +000071ArrayRef<support::ulittle32_t>
Zachary Turner0a43efe2016-04-25 17:38:08 +000072PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000073 return StreamMap[StreamIndex];
Zachary Turner0a43efe2016-04-25 17:38:08 +000074}
75
David Majnemer1b79e9a2016-07-10 05:32:05 +000076uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
Zachary Turner1dc9fd32016-06-14 20:48:36 +000077
David Majnemer6211b1f2016-07-10 03:34:47 +000078Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
79 uint32_t NumBytes) const {
Zachary Turnerfaa554b2016-07-15 22:16:56 +000080 uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
Zachary Turner0a43efe2016-04-25 17:38:08 +000081
Zachary Turnerb84faa82016-06-10 05:10:19 +000082 ArrayRef<uint8_t> Result;
83 if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
David Majnemer6211b1f2016-07-10 03:34:47 +000084 return std::move(EC);
Zachary Turnerb84faa82016-06-10 05:10:19 +000085 return Result;
Zachary Turner0a43efe2016-04-25 17:38:08 +000086}
87
Zachary Turner5acb4ac2016-06-10 05:09:12 +000088Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
89 ArrayRef<uint8_t> Data) const {
Zachary Turnerb84faa82016-06-10 05:10:19 +000090 if (Offset >= getBlockSize())
91 return make_error<RawError>(
92 raw_error_code::invalid_block_address,
93 "setBlockData attempted to write out of block bounds.");
Zachary Turner8848a7a2016-07-06 18:05:57 +000094 if (Data.size() > getBlockSize() - Offset)
Zachary Turnerb84faa82016-06-10 05:10:19 +000095 return make_error<RawError>(
96 raw_error_code::invalid_block_address,
97 "setBlockData attempted to write out of block bounds.");
Zachary Turner5acb4ac2016-06-10 05:09:12 +000098
Zachary Turnerfaa554b2016-07-15 22:16:56 +000099 uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
Zachary Turnerb84faa82016-06-10 05:10:19 +0000100 StreamBlockOffset += Offset;
101 return Buffer->writeBytes(StreamBlockOffset, Data);
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000102}
103
Zachary Turner819e77d2016-05-06 20:51:57 +0000104Error PDBFile::parseFileHeaders() {
Zachary Turnerb84faa82016-06-10 05:10:19 +0000105 StreamReader Reader(*Buffer);
Zachary Turnerc59261c2016-05-25 03:53:16 +0000106
Zachary Turnerb84faa82016-06-10 05:10:19 +0000107 if (auto EC = Reader.readObject(SB)) {
108 consumeError(std::move(EC));
Zachary Turner819e77d2016-05-06 20:51:57 +0000109 return make_error<RawError>(raw_error_code::corrupt_file,
110 "Does not contain superblock");
Zachary Turnerb84faa82016-06-10 05:10:19 +0000111 }
Zachary Turner0a43efe2016-04-25 17:38:08 +0000112
Zachary Turnerab58ae82016-06-30 17:43:00 +0000113 if (auto EC = setSuperBlock(SB))
114 return EC;
Zachary Turner819e77d2016-05-06 20:51:57 +0000115
Zachary Turnerab58ae82016-06-30 17:43:00 +0000116 Reader.setOffset(getBlockMapOffset());
117 if (auto EC = Reader.readArray(DirectoryBlocks, getNumDirectoryBlocks()))
118 return EC;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000119
Zachary Turner819e77d2016-05-06 20:51:57 +0000120 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000121}
122
Zachary Turner819e77d2016-05-06 20:51:57 +0000123Error PDBFile::parseStreamData() {
Zachary Turnerb84faa82016-06-10 05:10:19 +0000124 assert(SB);
Zachary Turnerd8447992016-06-07 05:28:55 +0000125 if (DirectoryStream)
126 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000127
Zachary Turner0a43efe2016-04-25 17:38:08 +0000128 uint32_t NumStreams = 0;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000129
Zachary Turnerd8447992016-06-07 05:28:55 +0000130 // Normally you can't use a MappedBlockStream without having fully parsed the
131 // PDB file, because it accesses the directory and various other things, which
132 // is exactly what we are attempting to parse. By specifying a custom
133 // subclass of IPDBStreamData which only accesses the fields that have already
134 // been parsed, we can avoid this and reuse MappedBlockStream.
Zachary Turnerbac69d32016-07-22 19:56:05 +0000135 auto DS = MappedBlockStream::createDirectoryStream(
136 SB->NumDirectoryBytes, getDirectoryBlockArray(), *this);
Zachary Turnera1657a92016-06-08 17:26:39 +0000137 if (!DS)
138 return DS.takeError();
Zachary Turnerb84faa82016-06-10 05:10:19 +0000139 StreamReader Reader(**DS);
Zachary Turnerd8447992016-06-07 05:28:55 +0000140 if (auto EC = Reader.readInteger(NumStreams))
141 return EC;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000142
Zachary Turnerb84faa82016-06-10 05:10:19 +0000143 if (auto EC = Reader.readArray(StreamSizes, NumStreams))
Zachary Turnerd8447992016-06-07 05:28:55 +0000144 return EC;
145 for (uint32_t I = 0; I < NumStreams; ++I) {
Reid Kleckner5aba52f2016-06-22 22:42:24 +0000146 uint32_t StreamSize = getStreamByteSize(I);
147 // FIXME: What does StreamSize ~0U mean?
David Majnemer9efba742016-05-27 16:16:48 +0000148 uint64_t NumExpectedStreamBlocks =
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000149 StreamSize == UINT32_MAX ? 0 : msf::bytesToBlocks(StreamSize,
150 SB->BlockSize);
Zachary Turnerb84faa82016-06-10 05:10:19 +0000151
152 // For convenience, we store the block array contiguously. This is because
153 // if someone calls setStreamMap(), it is more convenient to be able to call
154 // it with an ArrayRef instead of setting up a StreamRef. Since the
155 // DirectoryStream is cached in the class and thus lives for the life of the
156 // class, we can be guaranteed that readArray() will return a stable
157 // reference, even if it has to allocate from its internal pool.
158 ArrayRef<support::ulittle32_t> Blocks;
Zachary Turnerd8447992016-06-07 05:28:55 +0000159 if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
160 return EC;
David Majnemer1b79e9a2016-07-10 05:32:05 +0000161 for (uint32_t Block : Blocks) {
162 uint64_t BlockEndOffset = (uint64_t)(Block + 1) * SB->BlockSize;
163 if (BlockEndOffset > getFileSize())
164 return make_error<RawError>(raw_error_code::corrupt_file,
165 "Stream block map is corrupt.");
166 }
Zachary Turnerb84faa82016-06-10 05:10:19 +0000167 StreamMap.push_back(Blocks);
David Majnemer9efba742016-05-27 16:16:48 +0000168 }
169
Zachary Turner0a43efe2016-04-25 17:38:08 +0000170 // We should have read exactly SB->NumDirectoryBytes bytes.
Zachary Turnerd8447992016-06-07 05:28:55 +0000171 assert(Reader.bytesRemaining() == 0);
Zachary Turnera1657a92016-06-08 17:26:39 +0000172 DirectoryStream = std::move(*DS);
Zachary Turner819e77d2016-05-06 20:51:57 +0000173 return Error::success();
Zachary Turner0a43efe2016-04-25 17:38:08 +0000174}
175
Zachary Turnerd8447992016-06-07 05:28:55 +0000176llvm::ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
Zachary Turnerab58ae82016-06-30 17:43:00 +0000177 return DirectoryBlocks;
Zachary Turner0a43efe2016-04-25 17:38:08 +0000178}
Zachary Turner53a65ba2016-04-26 18:42:34 +0000179
Zachary Turner819e77d2016-05-06 20:51:57 +0000180Expected<InfoStream &> PDBFile::getPDBInfoStream() {
Zachary Turner2f09b502016-04-29 17:28:47 +0000181 if (!Info) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000182 auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, *this);
183 if (!InfoS)
184 return InfoS.takeError();
185 auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
186 if (auto EC = TempInfo->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000187 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000188 Info = std::move(TempInfo);
Zachary Turner53a65ba2016-04-26 18:42:34 +0000189 }
Zachary Turner2f09b502016-04-29 17:28:47 +0000190 return *Info;
Zachary Turner53a65ba2016-04-26 18:42:34 +0000191}
192
Zachary Turner819e77d2016-05-06 20:51:57 +0000193Expected<DbiStream &> PDBFile::getPDBDbiStream() {
Zachary Turner2f09b502016-04-29 17:28:47 +0000194 if (!Dbi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000195 auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, *this);
196 if (!DbiS)
197 return DbiS.takeError();
198 auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
199 if (auto EC = TempDbi->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000200 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000201 Dbi = std::move(TempDbi);
Zachary Turner53a65ba2016-04-26 18:42:34 +0000202 }
Zachary Turner2f09b502016-04-29 17:28:47 +0000203 return *Dbi;
Zachary Turner53a65ba2016-04-26 18:42:34 +0000204}
Zachary Turnerf5c59652016-05-03 00:28:21 +0000205
Zachary Turner819e77d2016-05-06 20:51:57 +0000206Expected<TpiStream &> PDBFile::getPDBTpiStream() {
Zachary Turnerf5c59652016-05-03 00:28:21 +0000207 if (!Tpi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000208 auto TpiS = MappedBlockStream::createIndexedStream(StreamTPI, *this);
209 if (!TpiS)
210 return TpiS.takeError();
211 auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
212 if (auto EC = TempTpi->reload())
Zachary Turner819e77d2016-05-06 20:51:57 +0000213 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000214 Tpi = std::move(TempTpi);
Zachary Turnerf5c59652016-05-03 00:28:21 +0000215 }
216 return *Tpi;
217}
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000218
Zachary Turnerc9972c62016-05-25 04:35:22 +0000219Expected<TpiStream &> PDBFile::getPDBIpiStream() {
220 if (!Ipi) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000221 auto IpiS = MappedBlockStream::createIndexedStream(StreamIPI, *this);
222 if (!IpiS)
223 return IpiS.takeError();
224 auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
225 if (auto EC = TempIpi->reload())
Zachary Turnerc9972c62016-05-25 04:35:22 +0000226 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000227 Ipi = std::move(TempIpi);
Zachary Turnerc9972c62016-05-25 04:35:22 +0000228 }
229 return *Ipi;
230}
231
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000232Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
233 if (!Publics) {
234 auto DbiS = getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000235 if (!DbiS)
236 return DbiS.takeError();
237
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000238 uint32_t PublicsStreamNum = DbiS->getPublicSymbolStreamIndex();
239
Zachary Turnera1657a92016-06-08 17:26:39 +0000240 auto PublicS =
241 MappedBlockStream::createIndexedStream(PublicsStreamNum, *this);
242 if (!PublicS)
243 return PublicS.takeError();
244 auto TempPublics =
245 llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
246 if (auto EC = TempPublics->reload())
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000247 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000248 Publics = std::move(TempPublics);
Rui Ueyama1f6b6e22016-05-13 21:21:53 +0000249 }
250 return *Publics;
251}
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000252
253Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
254 if (!Symbols) {
255 auto DbiS = getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000256 if (!DbiS)
257 return DbiS.takeError();
258
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000259 uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
260
Zachary Turnera1657a92016-06-08 17:26:39 +0000261 auto SymbolS =
262 MappedBlockStream::createIndexedStream(SymbolStreamNum, *this);
263 if (!SymbolS)
264 return SymbolS.takeError();
265 auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
266 if (auto EC = TempSymbols->reload())
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000267 return std::move(EC);
Zachary Turnera1657a92016-06-08 17:26:39 +0000268 Symbols = std::move(TempSymbols);
Rui Ueyama0fcd8262016-05-20 19:55:17 +0000269 }
270 return *Symbols;
271}
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000272
273Expected<NameHashTable &> PDBFile::getStringTable() {
274 if (!StringTable || !StringTableStream) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000275 auto IS = getPDBInfoStream();
276 if (!IS)
277 return IS.takeError();
278
279 uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names");
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000280
281 if (NameStreamIndex == 0)
282 return make_error<RawError>(raw_error_code::no_stream);
Zachary Turnerd2b2bfe2016-06-08 00:25:08 +0000283 if (NameStreamIndex >= getNumStreams())
284 return make_error<RawError>(raw_error_code::no_stream);
285
Zachary Turnera1657a92016-06-08 17:26:39 +0000286 auto NS = MappedBlockStream::createIndexedStream(NameStreamIndex, *this);
287 if (!NS)
288 return NS.takeError();
289
Zachary Turnerb84faa82016-06-10 05:10:19 +0000290 StreamReader Reader(**NS);
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000291 auto N = llvm::make_unique<NameHashTable>();
292 if (auto EC = N->load(Reader))
293 return std::move(EC);
294 StringTable = std::move(N);
Zachary Turnera1657a92016-06-08 17:26:39 +0000295 StringTableStream = std::move(*NS);
Zachary Turner3df1bfa2016-06-03 05:52:57 +0000296 }
297 return *StringTable;
298}
Zachary Turner1dc9fd32016-06-14 20:48:36 +0000299
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000300Error PDBFile::setSuperBlock(const msf::SuperBlock *Block) {
301 if (auto EC = msf::validateSuperBlock(*Block))
302 return EC;
Zachary Turnerab58ae82016-06-30 17:43:00 +0000303
304 if (Buffer->getLength() % SB->BlockSize != 0)
305 return make_error<RawError>(raw_error_code::corrupt_file,
306 "File size is not a multiple of block size");
307
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000308 SB = Block;
Zachary Turnerab58ae82016-06-30 17:43:00 +0000309 return Error::success();
310}
Zachary Turner1dc9fd32016-06-14 20:48:36 +0000311
Zachary Turnerab58ae82016-06-30 17:43:00 +0000312Error PDBFile::commit() {
313 StreamWriter Writer(*Buffer);
314
315 if (auto EC = Writer.writeObject(*SB))
316 return EC;
317 Writer.setOffset(getBlockMapOffset());
318 if (auto EC = Writer.writeArray(DirectoryBlocks))
319 return EC;
320
Zachary Turnerbac69d32016-07-22 19:56:05 +0000321 auto DS = MappedBlockStream::createDirectoryStream(
322 SB->NumDirectoryBytes, getDirectoryBlockArray(), *this);
Zachary Turnerab58ae82016-06-30 17:43:00 +0000323 if (!DS)
324 return DS.takeError();
325 auto DirStream = std::move(*DS);
326 StreamWriter DW(*DirStream);
327 if (auto EC = DW.writeInteger(this->getNumStreams()))
328 return EC;
329
330 if (auto EC = DW.writeArray(StreamSizes))
331 return EC;
332
333 for (const auto &Blocks : StreamMap) {
334 if (auto EC = DW.writeArray(Blocks))
335 return EC;
336 }
337
Zachary Turner8848a7a2016-07-06 18:05:57 +0000338 if (Info) {
339 if (auto EC = Info->commit())
340 return EC;
341 }
342
343 if (Dbi) {
344 if (auto EC = Dbi->commit())
345 return EC;
346 }
347
348 if (Symbols) {
349 if (auto EC = Symbols->commit())
350 return EC;
351 }
352
353 if (Publics) {
354 if (auto EC = Publics->commit())
355 return EC;
356 }
357
358 if (Tpi) {
359 if (auto EC = Tpi->commit())
360 return EC;
361 }
362
363 if (Ipi) {
364 if (auto EC = Ipi->commit())
365 return EC;
366 }
367
Zachary Turnerab58ae82016-06-30 17:43:00 +0000368 return Buffer->commit();
David Majnemer6211b1f2016-07-10 03:34:47 +0000369}