1 //===- PDBFileBuilder.cpp - PDB File Creation -------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
12 #include "llvm/ADT/BitVector.h"
14 #include "llvm/DebugInfo/MSF/MSFBuilder.h"
15 #include "llvm/DebugInfo/PDB/GenericError.h"
16 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
17 #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
18 #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
19 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
20 #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
21 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
22 #include "llvm/DebugInfo/PDB/Native/RawError.h"
23 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
24 #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
25 #include "llvm/Support/BinaryStream.h"
26 #include "llvm/Support/BinaryStreamWriter.h"
29 using namespace llvm::codeview;
30 using namespace llvm::msf;
31 using namespace llvm::pdb;
32 using namespace llvm::support;
34 PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
35 : Allocator(Allocator) {}
37 PDBFileBuilder::~PDBFileBuilder() {}
39 Error PDBFileBuilder::initialize(uint32_t BlockSize) {
40 auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
42 return ExpectedMsf.takeError();
43 Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
44 return Error::success();
47 MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
49 InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
51 Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
55 DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
57 Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf);
61 TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
63 Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
67 TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
69 Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
73 PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
77 GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() {
79 Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf);
83 Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) {
84 auto ExpectedStream = Msf->addStream(Size);
86 return ExpectedStream.takeError();
87 NamedStreams.set(Name, *ExpectedStream);
88 return Error::success();
91 Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
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);
102 uint32_t StringsLen = Strings.calculateSerializedSize();
104 if (auto EC = addNamedStream("/names", StringsLen))
105 return std::move(EC);
106 if (auto EC = addNamedStream("/LinkInfo", 0))
107 return std::move(EC);
110 if (auto EC = Info->finalizeMsfLayout())
111 return std::move(EC);
114 if (auto EC = Dbi->finalizeMsfLayout())
115 return std::move(EC);
118 if (auto EC = Tpi->finalizeMsfLayout())
119 return std::move(EC);
122 if (auto EC = Ipi->finalizeMsfLayout())
123 return std::move(EC);
126 if (auto EC = Gsi->finalizeMsfLayout())
127 return std::move(EC);
129 Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
130 Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
131 Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx());
138 Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
140 if (!NamedStreams.get(Name, SN))
141 return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
145 void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer,
146 const MSFLayout &Layout) {
148 WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator);
150 // We only need to create the alt fpm stream so that it gets initialized.
151 WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator,
155 BinaryStreamWriter FpmWriter(*FpmStream);
156 while (BI < Layout.SB->NumBlocks) {
157 uint8_t ThisByte = 0;
158 for (uint32_t I = 0; I < 8; ++I) {
160 (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true;
161 uint8_t Mask = uint8_t(IsFree) << I;
165 cantFail(FpmWriter.writeObject(ThisByte));
167 assert(FpmWriter.bytesRemaining() == 0);
170 Error PDBFileBuilder::commit(StringRef Filename) {
171 assert(!Filename.empty());
172 auto ExpectedLayout = finalizeMsfLayout();
174 return ExpectedLayout.takeError();
175 auto &Layout = *ExpectedLayout;
177 uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks;
178 auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize);
179 if (auto E = OutFileOrError.takeError())
181 FileBufferByteStream Buffer(std::move(*OutFileOrError),
182 llvm::support::little);
183 BinaryStreamWriter Writer(Buffer);
185 if (auto EC = Writer.writeObject(*Layout.SB))
188 commitFpm(Buffer, Layout);
190 uint32_t BlockMapOffset =
191 msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize);
192 Writer.setOffset(BlockMapOffset);
193 if (auto EC = Writer.writeArray(Layout.DirectoryBlocks))
196 auto DirStream = WritableMappedBlockStream::createDirectoryStream(
197 Layout, Buffer, Allocator);
198 BinaryStreamWriter DW(*DirStream);
199 if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size()))
202 if (auto EC = DW.writeArray(Layout.StreamSizes))
205 for (const auto &Blocks : Layout.StreamMap) {
206 if (auto EC = DW.writeArray(Blocks))
210 auto ExpectedSN = getNamedStreamIndex("/names");
212 return ExpectedSN.takeError();
214 auto NS = WritableMappedBlockStream::createIndexedStream(
215 Layout, Buffer, *ExpectedSN, Allocator);
216 BinaryStreamWriter NSWriter(*NS);
217 if (auto EC = Strings.commit(NSWriter))
221 if (auto EC = Info->commit(Layout, Buffer))
226 if (auto EC = Dbi->commit(Layout, Buffer))
231 if (auto EC = Tpi->commit(Layout, Buffer))
236 if (auto EC = Ipi->commit(Layout, Buffer))
241 if (auto EC = Gsi->commit(Layout, Buffer))
245 return Buffer.commit();