blob: 09e86bf0c13b1d02145aaf83c7297b7ab381d9a6 [file] [log] [blame]
Zachary Turnerdbeaea72016-07-11 21:45:26 +00001//===- PDBFileBuilder.cpp - PDB File Creation -------------------*- 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
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000010#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
Zachary Turnerdbeaea72016-07-11 21:45:26 +000011
Zachary Turnerfaa554b2016-07-15 22:16:56 +000012#include "llvm/ADT/BitVector.h"
13
Zachary Turnera3225b02016-07-29 20:56:36 +000014#include "llvm/DebugInfo/MSF/MSFBuilder.h"
Rui Ueyamafc22cef2016-09-30 20:34:44 +000015#include "llvm/DebugInfo/PDB/GenericError.h"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000016#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
17#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
Zachary Turner8d927b62017-07-31 19:36:08 +000018#include "llvm/DebugInfo/PDB/Native/GlobalsStreamBuilder.h"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000019#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
20#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
Zachary Turnere204a6c2017-05-02 18:00:13 +000021#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
Zachary Turner7eaf1d92017-07-10 22:40:20 +000022#include "llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000023#include "llvm/DebugInfo/PDB/Native/RawError.h"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000024#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
25#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
Zachary Turnerd9dc2822017-03-02 20:52:51 +000026#include "llvm/Support/BinaryStream.h"
27#include "llvm/Support/BinaryStreamWriter.h"
Zachary Turnerdbeaea72016-07-11 21:45:26 +000028
29using namespace llvm;
30using namespace llvm::codeview;
Zachary Turnerbac69d32016-07-22 19:56:05 +000031using namespace llvm::msf;
Zachary Turnerdbeaea72016-07-11 21:45:26 +000032using namespace llvm::pdb;
Zachary Turnerfaa554b2016-07-15 22:16:56 +000033using namespace llvm::support;
Zachary Turnerdbeaea72016-07-11 21:45:26 +000034
Zachary Turnere109dc62016-07-22 19:56:26 +000035PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
36 : Allocator(Allocator) {}
Zachary Turnerdbeaea72016-07-11 21:45:26 +000037
Zachary Turner7eaf1d92017-07-10 22:40:20 +000038PDBFileBuilder::~PDBFileBuilder() {}
39
Rui Ueyama5d6714e2016-09-30 20:52:12 +000040Error PDBFileBuilder::initialize(uint32_t BlockSize) {
41 auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
Zachary Turnerfaa554b2016-07-15 22:16:56 +000042 if (!ExpectedMsf)
43 return ExpectedMsf.takeError();
Rui Ueyama5d6714e2016-09-30 20:52:12 +000044 Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
Zachary Turnerdbeaea72016-07-11 21:45:26 +000045 return Error::success();
46}
47
Zachary Turnera3225b02016-07-29 20:56:36 +000048MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
Zachary Turnerfaa554b2016-07-15 22:16:56 +000049
Zachary Turnerdbeaea72016-07-11 21:45:26 +000050InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
51 if (!Info)
Zachary Turner760ad4d2017-01-20 22:42:09 +000052 Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
Zachary Turnerdbeaea72016-07-11 21:45:26 +000053 return *Info;
54}
55
56DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
57 if (!Dbi)
Zachary Turner620961d2016-09-14 23:00:02 +000058 Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf);
Zachary Turnerdbeaea72016-07-11 21:45:26 +000059 return *Dbi;
60}
61
Zachary Turnerc6d54da2016-09-09 17:46:17 +000062TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
63 if (!Tpi)
Zachary Turnerde9ba152016-09-15 18:22:31 +000064 Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
Zachary Turnerc6d54da2016-09-09 17:46:17 +000065 return *Tpi;
66}
67
Zachary Turnerde9ba152016-09-15 18:22:31 +000068TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
69 if (!Ipi)
70 Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
71 return *Ipi;
72}
73
Zachary Turnere204a6c2017-05-02 18:00:13 +000074PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
75 return Strings;
76}
Zachary Turner760ad4d2017-01-20 22:42:09 +000077
Zachary Turner7eaf1d92017-07-10 22:40:20 +000078PublicsStreamBuilder &PDBFileBuilder::getPublicsBuilder() {
79 if (!Publics)
80 Publics = llvm::make_unique<PublicsStreamBuilder>(*Msf);
81 return *Publics;
82}
83
Zachary Turner8d927b62017-07-31 19:36:08 +000084GlobalsStreamBuilder &PDBFileBuilder::getGlobalsBuilder() {
85 if (!Globals)
86 Globals = llvm::make_unique<GlobalsStreamBuilder>(*Msf);
87 return *Globals;
88}
89
Zachary Turner760ad4d2017-01-20 22:42:09 +000090Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) {
91 auto ExpectedStream = Msf->addStream(Size);
92 if (!ExpectedStream)
93 return ExpectedStream.takeError();
94 NamedStreams.set(Name, *ExpectedStream);
95 return Error::success();
96}
97
98Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
Zachary Turner68ea80d2017-06-12 21:46:51 +000099
100 if (Ipi && Ipi->getRecordCount() > 0) {
101 // In theory newer PDBs always have an ID stream, but by saying that we're
102 // only going to *really* have an ID stream if there is at least one ID
103 // record, we leave open the opportunity to test older PDBs such as those
104 // that don't have an ID stream.
105 auto &Info = getInfoBuilder();
106 Info.addFeature(PdbRaw_FeatureSig::VC140);
107 }
108
Zachary Turnerc504ae32017-05-03 15:58:37 +0000109 uint32_t StringsLen = Strings.calculateSerializedSize();
Zachary Turner760ad4d2017-01-20 22:42:09 +0000110
Zachary Turnerc504ae32017-05-03 15:58:37 +0000111 if (auto EC = addNamedStream("/names", StringsLen))
Zachary Turner760ad4d2017-01-20 22:42:09 +0000112 return std::move(EC);
113 if (auto EC = addNamedStream("/LinkInfo", 0))
114 return std::move(EC);
Zachary Turner760ad4d2017-01-20 22:42:09 +0000115
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000116 if (Info) {
Zachary Turner620961d2016-09-14 23:00:02 +0000117 if (auto EC = Info->finalizeMsfLayout())
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000118 return std::move(EC);
119 }
120 if (Dbi) {
Zachary Turner620961d2016-09-14 23:00:02 +0000121 if (auto EC = Dbi->finalizeMsfLayout())
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000122 return std::move(EC);
123 }
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000124 if (Tpi) {
Zachary Turner620961d2016-09-14 23:00:02 +0000125 if (auto EC = Tpi->finalizeMsfLayout())
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000126 return std::move(EC);
127 }
Zachary Turnerde9ba152016-09-15 18:22:31 +0000128 if (Ipi) {
129 if (auto EC = Ipi->finalizeMsfLayout())
130 return std::move(EC);
131 }
Zachary Turner7eaf1d92017-07-10 22:40:20 +0000132 if (Publics) {
133 if (auto EC = Publics->finalizeMsfLayout())
134 return std::move(EC);
135 if (Dbi) {
136 Dbi->setPublicsStreamIndex(Publics->getStreamIndex());
137 Dbi->setSymbolRecordStreamIndex(Publics->getRecordStreamIdx());
138 }
139 }
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000140
Zachary Turner8d927b62017-07-31 19:36:08 +0000141 if (Globals) {
142 if (auto EC = Globals->finalizeMsfLayout())
143 return std::move(EC);
144 if (Dbi)
145 Dbi->setGlobalsStreamIndex(Globals->getStreamIndex());
146 }
147
Zachary Turner199f48a2016-07-28 19:11:09 +0000148 return Msf->build();
149}
150
Zachary Turnerc504ae32017-05-03 15:58:37 +0000151Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
152 uint32_t SN = 0;
153 if (!NamedStreams.get(Name, SN))
154 return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
155 return SN;
156}
157
Zachary Turner9fb9d712017-08-02 22:31:39 +0000158void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer,
159 const MSFLayout &Layout) {
160 auto FpmStream =
161 WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator);
162
163 // We only need to create the alt fpm stream so that it gets initialized.
164 WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator,
165 true);
166
167 uint32_t BI = 0;
168 BinaryStreamWriter FpmWriter(*FpmStream);
169 while (BI < Layout.SB->NumBlocks) {
170 uint8_t ThisByte = 0;
171 for (uint32_t I = 0; I < 8; ++I) {
172 bool IsFree =
173 (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true;
174 uint8_t Mask = uint8_t(IsFree) << I;
175 ThisByte |= Mask;
176 ++BI;
177 }
178 cantFail(FpmWriter.writeObject(ThisByte));
179 }
180 assert(FpmWriter.bytesRemaining() == 0);
181}
182
Rui Ueyamafc22cef2016-09-30 20:34:44 +0000183Error PDBFileBuilder::commit(StringRef Filename) {
Bob Haarmande33a6372017-05-17 20:46:48 +0000184 assert(!Filename.empty());
Zachary Turnerd66889c2016-07-28 19:12:28 +0000185 auto ExpectedLayout = finalizeMsfLayout();
186 if (!ExpectedLayout)
187 return ExpectedLayout.takeError();
188 auto &Layout = *ExpectedLayout;
189
Rui Ueyamafc22cef2016-09-30 20:34:44 +0000190 uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks;
191 auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize);
192 if (OutFileOrError.getError())
193 return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path,
194 Filename);
Zachary Turner695ed562017-02-28 00:04:07 +0000195 FileBufferByteStream Buffer(std::move(*OutFileOrError),
196 llvm::support::little);
Zachary Turner120faca2017-02-27 22:11:43 +0000197 BinaryStreamWriter Writer(Buffer);
Rui Ueyamafc22cef2016-09-30 20:34:44 +0000198
Zachary Turnerd66889c2016-07-28 19:12:28 +0000199 if (auto EC = Writer.writeObject(*Layout.SB))
200 return EC;
Zachary Turner9fb9d712017-08-02 22:31:39 +0000201
202 commitFpm(Buffer, Layout);
203
Zachary Turnerd66889c2016-07-28 19:12:28 +0000204 uint32_t BlockMapOffset =
205 msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize);
206 Writer.setOffset(BlockMapOffset);
207 if (auto EC = Writer.writeArray(Layout.DirectoryBlocks))
208 return EC;
209
Zachary Turner5b74ff32017-06-03 00:33:35 +0000210 auto DirStream = WritableMappedBlockStream::createDirectoryStream(
211 Layout, Buffer, Allocator);
Zachary Turner120faca2017-02-27 22:11:43 +0000212 BinaryStreamWriter DW(*DirStream);
Zachary Turner695ed562017-02-28 00:04:07 +0000213 if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size()))
Zachary Turnerd66889c2016-07-28 19:12:28 +0000214 return EC;
215
216 if (auto EC = DW.writeArray(Layout.StreamSizes))
217 return EC;
218
219 for (const auto &Blocks : Layout.StreamMap) {
220 if (auto EC = DW.writeArray(Blocks))
221 return EC;
222 }
223
Zachary Turnerc504ae32017-05-03 15:58:37 +0000224 auto ExpectedSN = getNamedStreamIndex("/names");
225 if (!ExpectedSN)
226 return ExpectedSN.takeError();
Zachary Turner760ad4d2017-01-20 22:42:09 +0000227
Zachary Turner5b74ff32017-06-03 00:33:35 +0000228 auto NS = WritableMappedBlockStream::createIndexedStream(
229 Layout, Buffer, *ExpectedSN, Allocator);
Zachary Turner120faca2017-02-27 22:11:43 +0000230 BinaryStreamWriter NSWriter(*NS);
Zachary Turner760ad4d2017-01-20 22:42:09 +0000231 if (auto EC = Strings.commit(NSWriter))
232 return EC;
233
Zachary Turnerd66889c2016-07-28 19:12:28 +0000234 if (Info) {
235 if (auto EC = Info->commit(Layout, Buffer))
236 return EC;
237 }
238
239 if (Dbi) {
240 if (auto EC = Dbi->commit(Layout, Buffer))
241 return EC;
242 }
243
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000244 if (Tpi) {
245 if (auto EC = Tpi->commit(Layout, Buffer))
246 return EC;
247 }
248
Zachary Turnerde9ba152016-09-15 18:22:31 +0000249 if (Ipi) {
250 if (auto EC = Ipi->commit(Layout, Buffer))
251 return EC;
252 }
253
Zachary Turner7eaf1d92017-07-10 22:40:20 +0000254 if (Publics) {
255 auto PS = WritableMappedBlockStream::createIndexedStream(
256 Layout, Buffer, Publics->getStreamIndex(), Allocator);
Reid Klecknereacdf042017-07-27 18:25:59 +0000257 auto PRS = WritableMappedBlockStream::createIndexedStream(
258 Layout, Buffer, Publics->getRecordStreamIdx(), Allocator);
Zachary Turner7eaf1d92017-07-10 22:40:20 +0000259 BinaryStreamWriter PSWriter(*PS);
Reid Klecknereacdf042017-07-27 18:25:59 +0000260 BinaryStreamWriter RecWriter(*PRS);
261 if (auto EC = Publics->commit(PSWriter, RecWriter))
Zachary Turner7eaf1d92017-07-10 22:40:20 +0000262 return EC;
263 }
264
Zachary Turner8d927b62017-07-31 19:36:08 +0000265 if (Globals) {
266 auto GS = WritableMappedBlockStream::createIndexedStream(
267 Layout, Buffer, Globals->getStreamIndex(), Allocator);
268 BinaryStreamWriter GSWriter(*GS);
269 if (auto EC = Globals->commit(GSWriter))
270 return EC;
271 }
272
Zachary Turnerd66889c2016-07-28 19:12:28 +0000273 return Buffer.commit();
Rui Ueyamafc22cef2016-09-30 20:34:44 +0000274}