blob: 1cb890ff79957edc5d4c68f3e763474968dc29f4 [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 Turner946204c2017-08-09 04:23:25 +000018#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.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"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000022#include "llvm/DebugInfo/PDB/Native/RawError.h"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000023#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
24#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
Zachary Turnerd9dc2822017-03-02 20:52:51 +000025#include "llvm/Support/BinaryStream.h"
26#include "llvm/Support/BinaryStreamWriter.h"
Zachary Turnerdbeaea72016-07-11 21:45:26 +000027
28using namespace llvm;
29using namespace llvm::codeview;
Zachary Turnerbac69d32016-07-22 19:56:05 +000030using namespace llvm::msf;
Zachary Turnerdbeaea72016-07-11 21:45:26 +000031using namespace llvm::pdb;
Zachary Turnerfaa554b2016-07-15 22:16:56 +000032using namespace llvm::support;
Zachary Turnerdbeaea72016-07-11 21:45:26 +000033
Zachary Turnere109dc62016-07-22 19:56:26 +000034PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
35 : Allocator(Allocator) {}
Zachary Turnerdbeaea72016-07-11 21:45:26 +000036
Zachary Turner7eaf1d92017-07-10 22:40:20 +000037PDBFileBuilder::~PDBFileBuilder() {}
38
Rui Ueyama5d6714e2016-09-30 20:52:12 +000039Error PDBFileBuilder::initialize(uint32_t BlockSize) {
40 auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
Zachary Turnerfaa554b2016-07-15 22:16:56 +000041 if (!ExpectedMsf)
42 return ExpectedMsf.takeError();
Rui Ueyama5d6714e2016-09-30 20:52:12 +000043 Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
Zachary Turnerdbeaea72016-07-11 21:45:26 +000044 return Error::success();
45}
46
Zachary Turnera3225b02016-07-29 20:56:36 +000047MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
Zachary Turnerfaa554b2016-07-15 22:16:56 +000048
Zachary Turnerdbeaea72016-07-11 21:45:26 +000049InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
50 if (!Info)
Zachary Turner760ad4d2017-01-20 22:42:09 +000051 Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
Zachary Turnerdbeaea72016-07-11 21:45:26 +000052 return *Info;
53}
54
55DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
56 if (!Dbi)
Zachary Turner620961d2016-09-14 23:00:02 +000057 Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf);
Zachary Turnerdbeaea72016-07-11 21:45:26 +000058 return *Dbi;
59}
60
Zachary Turnerc6d54da2016-09-09 17:46:17 +000061TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
62 if (!Tpi)
Zachary Turnerde9ba152016-09-15 18:22:31 +000063 Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
Zachary Turnerc6d54da2016-09-09 17:46:17 +000064 return *Tpi;
65}
66
Zachary Turnerde9ba152016-09-15 18:22:31 +000067TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
68 if (!Ipi)
69 Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
70 return *Ipi;
71}
72
Zachary Turnere204a6c2017-05-02 18:00:13 +000073PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
74 return Strings;
75}
Zachary Turner760ad4d2017-01-20 22:42:09 +000076
Zachary Turner946204c2017-08-09 04:23:25 +000077GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() {
78 if (!Gsi)
79 Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf);
80 return *Gsi;
Zachary Turner8d927b62017-07-31 19:36:08 +000081}
82
Zachary Turner760ad4d2017-01-20 22:42:09 +000083Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) {
84 auto ExpectedStream = Msf->addStream(Size);
85 if (!ExpectedStream)
86 return ExpectedStream.takeError();
87 NamedStreams.set(Name, *ExpectedStream);
88 return Error::success();
89}
90
91Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
Zachary Turner68ea80d2017-06-12 21:46:51 +000092
93 if (Ipi && Ipi->getRecordCount() > 0) {
94 // In theory newer PDBs always have an ID stream, but by saying that we're
95 // only going to *really* have an ID stream if there is at least one ID
96 // record, we leave open the opportunity to test older PDBs such as those
97 // that don't have an ID stream.
98 auto &Info = getInfoBuilder();
99 Info.addFeature(PdbRaw_FeatureSig::VC140);
100 }
101
Zachary Turnerc504ae32017-05-03 15:58:37 +0000102 uint32_t StringsLen = Strings.calculateSerializedSize();
Zachary Turner760ad4d2017-01-20 22:42:09 +0000103
Zachary Turnerc504ae32017-05-03 15:58:37 +0000104 if (auto EC = addNamedStream("/names", StringsLen))
Zachary Turner760ad4d2017-01-20 22:42:09 +0000105 return std::move(EC);
106 if (auto EC = addNamedStream("/LinkInfo", 0))
107 return std::move(EC);
Zachary Turner760ad4d2017-01-20 22:42:09 +0000108
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000109 if (Info) {
Zachary Turner620961d2016-09-14 23:00:02 +0000110 if (auto EC = Info->finalizeMsfLayout())
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000111 return std::move(EC);
112 }
113 if (Dbi) {
Zachary Turner620961d2016-09-14 23:00:02 +0000114 if (auto EC = Dbi->finalizeMsfLayout())
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000115 return std::move(EC);
116 }
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000117 if (Tpi) {
Zachary Turner620961d2016-09-14 23:00:02 +0000118 if (auto EC = Tpi->finalizeMsfLayout())
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000119 return std::move(EC);
120 }
Zachary Turnerde9ba152016-09-15 18:22:31 +0000121 if (Ipi) {
122 if (auto EC = Ipi->finalizeMsfLayout())
123 return std::move(EC);
124 }
Zachary Turner946204c2017-08-09 04:23:25 +0000125 if (Gsi) {
126 if (auto EC = Gsi->finalizeMsfLayout())
Zachary Turner7eaf1d92017-07-10 22:40:20 +0000127 return std::move(EC);
128 if (Dbi) {
Zachary Turner946204c2017-08-09 04:23:25 +0000129 Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
130 Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
131 Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx());
Zachary Turner7eaf1d92017-07-10 22:40:20 +0000132 }
133 }
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000134
Zachary Turner199f48a2016-07-28 19:11:09 +0000135 return Msf->build();
136}
137
Zachary Turnerc504ae32017-05-03 15:58:37 +0000138Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
139 uint32_t SN = 0;
140 if (!NamedStreams.get(Name, SN))
141 return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
142 return SN;
143}
144
Zachary Turner9fb9d712017-08-02 22:31:39 +0000145void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer,
146 const MSFLayout &Layout) {
147 auto FpmStream =
148 WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator);
149
150 // We only need to create the alt fpm stream so that it gets initialized.
151 WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator,
152 true);
153
154 uint32_t BI = 0;
155 BinaryStreamWriter FpmWriter(*FpmStream);
156 while (BI < Layout.SB->NumBlocks) {
157 uint8_t ThisByte = 0;
158 for (uint32_t I = 0; I < 8; ++I) {
159 bool IsFree =
160 (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true;
161 uint8_t Mask = uint8_t(IsFree) << I;
162 ThisByte |= Mask;
163 ++BI;
164 }
165 cantFail(FpmWriter.writeObject(ThisByte));
166 }
167 assert(FpmWriter.bytesRemaining() == 0);
168}
169
Rui Ueyamafc22cef2016-09-30 20:34:44 +0000170Error PDBFileBuilder::commit(StringRef Filename) {
Bob Haarmande33a6372017-05-17 20:46:48 +0000171 assert(!Filename.empty());
Zachary Turnerd66889c2016-07-28 19:12:28 +0000172 auto ExpectedLayout = finalizeMsfLayout();
173 if (!ExpectedLayout)
174 return ExpectedLayout.takeError();
175 auto &Layout = *ExpectedLayout;
176
Rui Ueyamafc22cef2016-09-30 20:34:44 +0000177 uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks;
178 auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize);
Rafael Espindolae0df3572017-11-08 01:05:44 +0000179 if (auto E = OutFileOrError.takeError())
180 return E;
Zachary Turnerc6a75a62018-03-01 18:00:29 +0000181 FileOutputBuffer *FOB = OutFileOrError->get();
182
Zachary Turner695ed562017-02-28 00:04:07 +0000183 FileBufferByteStream Buffer(std::move(*OutFileOrError),
184 llvm::support::little);
Zachary Turner120faca2017-02-27 22:11:43 +0000185 BinaryStreamWriter Writer(Buffer);
Rui Ueyamafc22cef2016-09-30 20:34:44 +0000186
Zachary Turnerd66889c2016-07-28 19:12:28 +0000187 if (auto EC = Writer.writeObject(*Layout.SB))
188 return EC;
Zachary Turner9fb9d712017-08-02 22:31:39 +0000189
190 commitFpm(Buffer, Layout);
191
Zachary Turnerd66889c2016-07-28 19:12:28 +0000192 uint32_t BlockMapOffset =
193 msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize);
194 Writer.setOffset(BlockMapOffset);
195 if (auto EC = Writer.writeArray(Layout.DirectoryBlocks))
196 return EC;
197
Zachary Turner5b74ff32017-06-03 00:33:35 +0000198 auto DirStream = WritableMappedBlockStream::createDirectoryStream(
199 Layout, Buffer, Allocator);
Zachary Turner120faca2017-02-27 22:11:43 +0000200 BinaryStreamWriter DW(*DirStream);
Zachary Turner695ed562017-02-28 00:04:07 +0000201 if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size()))
Zachary Turnerd66889c2016-07-28 19:12:28 +0000202 return EC;
203
204 if (auto EC = DW.writeArray(Layout.StreamSizes))
205 return EC;
206
207 for (const auto &Blocks : Layout.StreamMap) {
208 if (auto EC = DW.writeArray(Blocks))
209 return EC;
210 }
211
Zachary Turnerc504ae32017-05-03 15:58:37 +0000212 auto ExpectedSN = getNamedStreamIndex("/names");
213 if (!ExpectedSN)
214 return ExpectedSN.takeError();
Zachary Turner760ad4d2017-01-20 22:42:09 +0000215
Zachary Turner5b74ff32017-06-03 00:33:35 +0000216 auto NS = WritableMappedBlockStream::createIndexedStream(
217 Layout, Buffer, *ExpectedSN, Allocator);
Zachary Turner120faca2017-02-27 22:11:43 +0000218 BinaryStreamWriter NSWriter(*NS);
Zachary Turner760ad4d2017-01-20 22:42:09 +0000219 if (auto EC = Strings.commit(NSWriter))
220 return EC;
221
Zachary Turnerd66889c2016-07-28 19:12:28 +0000222 if (Info) {
223 if (auto EC = Info->commit(Layout, Buffer))
224 return EC;
225 }
226
227 if (Dbi) {
228 if (auto EC = Dbi->commit(Layout, Buffer))
229 return EC;
230 }
231
Zachary Turnerc6d54da2016-09-09 17:46:17 +0000232 if (Tpi) {
233 if (auto EC = Tpi->commit(Layout, Buffer))
234 return EC;
235 }
236
Zachary Turnerde9ba152016-09-15 18:22:31 +0000237 if (Ipi) {
238 if (auto EC = Ipi->commit(Layout, Buffer))
239 return EC;
240 }
241
Zachary Turner946204c2017-08-09 04:23:25 +0000242 if (Gsi) {
243 if (auto EC = Gsi->commit(Layout, Buffer))
Zachary Turner8d927b62017-07-31 19:36:08 +0000244 return EC;
245 }
246
Zachary Turnerc6a75a62018-03-01 18:00:29 +0000247 auto InfoStreamBlocks = Layout.StreamMap[StreamPDB];
248 assert(!InfoStreamBlocks.empty());
249 uint64_t InfoStreamFileOffset =
250 blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
251 InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
252 FOB->getBufferStart() + InfoStreamFileOffset);
253
254 // Set the build id at the very end, after every other byte of the PDB
255 // has been written.
256 // FIXME: Use a hash of the PDB rather than time(nullptr) for the signature.
257 H->Age = Info->getAge();
258 H->Guid = Info->getGuid();
259 Optional<uint32_t> Sig = Info->getSignature();
260 H->Signature = Sig.hasValue() ? *Sig : time(nullptr);
261
Zachary Turnerd66889c2016-07-28 19:12:28 +0000262 return Buffer.commit();
Rui Ueyamafc22cef2016-09-30 20:34:44 +0000263}