]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
MFV r316873: 7233 dir_is_empty should open directory with CLOEXEC
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / DebugInfo / PDB / Native / PDBFileBuilder.cpp
1 //===- 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
10 #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
11
12 #include "llvm/ADT/BitVector.h"
13
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"
27
28 using namespace llvm;
29 using namespace llvm::codeview;
30 using namespace llvm::msf;
31 using namespace llvm::pdb;
32 using namespace llvm::support;
33
34 PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
35     : Allocator(Allocator) {}
36
37 PDBFileBuilder::~PDBFileBuilder() {}
38
39 Error PDBFileBuilder::initialize(uint32_t BlockSize) {
40   auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
41   if (!ExpectedMsf)
42     return ExpectedMsf.takeError();
43   Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
44   return Error::success();
45 }
46
47 MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
48
49 InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
50   if (!Info)
51     Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
52   return *Info;
53 }
54
55 DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
56   if (!Dbi)
57     Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf);
58   return *Dbi;
59 }
60
61 TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
62   if (!Tpi)
63     Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
64   return *Tpi;
65 }
66
67 TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
68   if (!Ipi)
69     Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
70   return *Ipi;
71 }
72
73 PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
74   return Strings;
75 }
76
77 GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() {
78   if (!Gsi)
79     Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf);
80   return *Gsi;
81 }
82
83 Error 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
91 Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
92
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
102   uint32_t StringsLen = Strings.calculateSerializedSize();
103
104   if (auto EC = addNamedStream("/names", StringsLen))
105     return std::move(EC);
106   if (auto EC = addNamedStream("/LinkInfo", 0))
107     return std::move(EC);
108
109   if (Info) {
110     if (auto EC = Info->finalizeMsfLayout())
111       return std::move(EC);
112   }
113   if (Dbi) {
114     if (auto EC = Dbi->finalizeMsfLayout())
115       return std::move(EC);
116   }
117   if (Tpi) {
118     if (auto EC = Tpi->finalizeMsfLayout())
119       return std::move(EC);
120   }
121   if (Ipi) {
122     if (auto EC = Ipi->finalizeMsfLayout())
123       return std::move(EC);
124   }
125   if (Gsi) {
126     if (auto EC = Gsi->finalizeMsfLayout())
127       return std::move(EC);
128     if (Dbi) {
129       Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
130       Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
131       Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx());
132     }
133   }
134
135   return Msf->build();
136 }
137
138 Expected<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
145 void 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
170 Error PDBFileBuilder::commit(StringRef Filename) {
171   assert(!Filename.empty());
172   auto ExpectedLayout = finalizeMsfLayout();
173   if (!ExpectedLayout)
174     return ExpectedLayout.takeError();
175   auto &Layout = *ExpectedLayout;
176
177   uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks;
178   auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize);
179   if (auto E = OutFileOrError.takeError())
180     return E;
181   FileBufferByteStream Buffer(std::move(*OutFileOrError),
182                               llvm::support::little);
183   BinaryStreamWriter Writer(Buffer);
184
185   if (auto EC = Writer.writeObject(*Layout.SB))
186     return EC;
187
188   commitFpm(Buffer, Layout);
189
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))
194     return EC;
195
196   auto DirStream = WritableMappedBlockStream::createDirectoryStream(
197       Layout, Buffer, Allocator);
198   BinaryStreamWriter DW(*DirStream);
199   if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size()))
200     return EC;
201
202   if (auto EC = DW.writeArray(Layout.StreamSizes))
203     return EC;
204
205   for (const auto &Blocks : Layout.StreamMap) {
206     if (auto EC = DW.writeArray(Blocks))
207       return EC;
208   }
209
210   auto ExpectedSN = getNamedStreamIndex("/names");
211   if (!ExpectedSN)
212     return ExpectedSN.takeError();
213
214   auto NS = WritableMappedBlockStream::createIndexedStream(
215       Layout, Buffer, *ExpectedSN, Allocator);
216   BinaryStreamWriter NSWriter(*NS);
217   if (auto EC = Strings.commit(NSWriter))
218     return EC;
219
220   if (Info) {
221     if (auto EC = Info->commit(Layout, Buffer))
222       return EC;
223   }
224
225   if (Dbi) {
226     if (auto EC = Dbi->commit(Layout, Buffer))
227       return EC;
228   }
229
230   if (Tpi) {
231     if (auto EC = Tpi->commit(Layout, Buffer))
232       return EC;
233   }
234
235   if (Ipi) {
236     if (auto EC = Ipi->commit(Layout, Buffer))
237       return EC;
238   }
239
240   if (Gsi) {
241     if (auto EC = Gsi->commit(Layout, Buffer))
242       return EC;
243   }
244
245   return Buffer.commit();
246 }