Line data Source code
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/Native/DbiStream.h"
16 : #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
17 : #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
18 : #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
19 : #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
20 : #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
21 : #include "llvm/DebugInfo/PDB/Native/RawError.h"
22 : #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
23 : #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
24 : #include "llvm/Support/BinaryStream.h"
25 : #include "llvm/Support/BinaryStreamWriter.h"
26 : #include "llvm/Support/JamCRC.h"
27 : #include "llvm/Support/Path.h"
28 : #include "llvm/Support/xxhash.h"
29 :
30 : using namespace llvm;
31 : using namespace llvm::codeview;
32 : using namespace llvm::msf;
33 : using namespace llvm::pdb;
34 : using namespace llvm::support;
35 :
36 111 : PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
37 111 : : Allocator(Allocator), InjectedSourceHashTraits(Strings),
38 222 : InjectedSourceTable(2, InjectedSourceHashTraits) {}
39 :
40 444 : PDBFileBuilder::~PDBFileBuilder() {}
41 :
42 111 : Error PDBFileBuilder::initialize(uint32_t BlockSize) {
43 222 : auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
44 111 : if (!ExpectedMsf)
45 : return ExpectedMsf.takeError();
46 111 : Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
47 : return Error::success();
48 : }
49 :
50 1110 : MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
51 :
52 152 : InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
53 152 : if (!Info)
54 111 : Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
55 152 : return *Info;
56 : }
57 :
58 1038 : DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
59 1038 : if (!Dbi)
60 108 : Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf);
61 1038 : return *Dbi;
62 : }
63 :
64 111 : TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
65 111 : if (!Tpi)
66 111 : Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
67 111 : return *Tpi;
68 : }
69 :
70 111 : TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
71 111 : if (!Ipi)
72 111 : Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
73 111 : return *Ipi;
74 : }
75 :
76 108 : PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
77 108 : return Strings;
78 : }
79 :
80 282 : GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() {
81 282 : if (!Gsi)
82 88 : Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf);
83 282 : return *Gsi;
84 : }
85 :
86 222 : Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name,
87 : uint32_t Size) {
88 222 : auto ExpectedStream = Msf->addStream(Size);
89 222 : if (ExpectedStream)
90 222 : NamedStreams.set(Name, *ExpectedStream);
91 222 : return ExpectedStream;
92 : }
93 :
94 0 : Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) {
95 0 : Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size());
96 0 : if (!ExpectedIndex)
97 : return ExpectedIndex.takeError();
98 : assert(NamedStreamData.count(*ExpectedIndex) == 0);
99 0 : NamedStreamData[*ExpectedIndex] = Data;
100 : return Error::success();
101 : }
102 :
103 0 : void PDBFileBuilder::addInjectedSource(StringRef Name,
104 : std::unique_ptr<MemoryBuffer> Buffer) {
105 : // Stream names must be exact matches, since they get looked up in a hash
106 : // table and the hash value is dependent on the exact contents of the string.
107 : // link.exe lowercases a path and converts / to \, so we must do the same.
108 : SmallString<64> VName;
109 0 : sys::path::native(Name.lower(), VName);
110 :
111 0 : uint32_t NI = getStringTableBuilder().insert(Name);
112 0 : uint32_t VNI = getStringTableBuilder().insert(VName);
113 :
114 0 : InjectedSourceDescriptor Desc;
115 : Desc.Content = std::move(Buffer);
116 0 : Desc.NameIndex = NI;
117 0 : Desc.VNameIndex = VNI;
118 : Desc.StreamName = "/src/files/";
119 :
120 : Desc.StreamName += VName;
121 :
122 0 : InjectedSources.push_back(std::move(Desc));
123 0 : }
124 :
125 111 : Error PDBFileBuilder::finalizeMsfLayout() {
126 :
127 111 : if (Ipi && Ipi->getRecordCount() > 0) {
128 : // In theory newer PDBs always have an ID stream, but by saying that we're
129 : // only going to *really* have an ID stream if there is at least one ID
130 : // record, we leave open the opportunity to test older PDBs such as those
131 : // that don't have an ID stream.
132 41 : auto &Info = getInfoBuilder();
133 41 : Info.addFeature(PdbRaw_FeatureSig::VC140);
134 : }
135 :
136 111 : uint32_t StringsLen = Strings.calculateSerializedSize();
137 :
138 111 : Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0);
139 111 : if (!SN)
140 : return SN.takeError();
141 :
142 111 : if (Gsi) {
143 176 : if (auto EC = Gsi->finalizeMsfLayout())
144 : return EC;
145 88 : if (Dbi) {
146 88 : Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
147 88 : Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
148 88 : Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx());
149 : }
150 : }
151 111 : if (Tpi) {
152 222 : if (auto EC = Tpi->finalizeMsfLayout())
153 : return EC;
154 : }
155 111 : if (Dbi) {
156 216 : if (auto EC = Dbi->finalizeMsfLayout())
157 : return EC;
158 : }
159 222 : SN = allocateNamedStream("/names", StringsLen);
160 111 : if (!SN)
161 : return SN.takeError();
162 :
163 111 : if (Ipi) {
164 222 : if (auto EC = Ipi->finalizeMsfLayout())
165 : return EC;
166 : }
167 :
168 : // Do this last, since it relies on the named stream map being complete, and
169 : // that can be updated by previous steps in the finalization.
170 111 : if (Info) {
171 222 : if (auto EC = Info->finalizeMsfLayout())
172 : return EC;
173 : }
174 :
175 111 : if (!InjectedSources.empty()) {
176 0 : for (const auto &IS : InjectedSources) {
177 : JamCRC CRC(0);
178 0 : CRC.update(makeArrayRef(IS.Content->getBufferStart(),
179 : IS.Content->getBufferSize()));
180 :
181 : SrcHeaderBlockEntry Entry;
182 0 : ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry));
183 : Entry.Size = sizeof(SrcHeaderBlockEntry);
184 0 : Entry.FileSize = IS.Content->getBufferSize();
185 0 : Entry.FileNI = IS.NameIndex;
186 0 : Entry.VFileNI = IS.VNameIndex;
187 : Entry.ObjNI = 1;
188 0 : Entry.IsVirtual = 0;
189 : Entry.Version =
190 : static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
191 0 : Entry.CRC = CRC.getCRC();
192 0 : StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex);
193 0 : InjectedSourceTable.set_as(VName, std::move(Entry));
194 : }
195 :
196 : uint32_t SrcHeaderBlockSize =
197 : sizeof(SrcHeaderBlockHeader) +
198 0 : InjectedSourceTable.calculateSerializedLength();
199 0 : SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize);
200 0 : if (!SN)
201 : return SN.takeError();
202 0 : for (const auto &IS : InjectedSources) {
203 0 : SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize());
204 0 : if (!SN)
205 : return SN.takeError();
206 : }
207 : }
208 :
209 : // Do this last, since it relies on the named stream map being complete, and
210 : // that can be updated by previous steps in the finalization.
211 111 : if (Info) {
212 222 : if (auto EC = Info->finalizeMsfLayout())
213 : return EC;
214 : }
215 :
216 : return Error::success();
217 : }
218 :
219 111 : Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
220 111 : uint32_t SN = 0;
221 111 : if (!NamedStreams.get(Name, SN))
222 : return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
223 : return SN;
224 : }
225 :
226 0 : void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
227 : const msf::MSFLayout &Layout) {
228 : assert(!InjectedSourceTable.empty());
229 :
230 0 : uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock"));
231 : auto Stream = WritableMappedBlockStream::createIndexedStream(
232 0 : Layout, MsfBuffer, SN, Allocator);
233 0 : BinaryStreamWriter Writer(*Stream);
234 :
235 : SrcHeaderBlockHeader Header;
236 0 : ::memset(&Header, 0, sizeof(Header));
237 : Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
238 : Header.Size = Writer.bytesRemaining();
239 :
240 0 : cantFail(Writer.writeObject(Header));
241 0 : cantFail(InjectedSourceTable.commit(Writer));
242 :
243 : assert(Writer.bytesRemaining() == 0);
244 0 : }
245 :
246 111 : void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
247 : const msf::MSFLayout &Layout) {
248 111 : if (InjectedSourceTable.empty())
249 : return;
250 :
251 0 : commitSrcHeaderBlock(MsfBuffer, Layout);
252 :
253 0 : for (const auto &IS : InjectedSources) {
254 0 : uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName));
255 :
256 : auto SourceStream = WritableMappedBlockStream::createIndexedStream(
257 0 : Layout, MsfBuffer, SN, Allocator);
258 0 : BinaryStreamWriter SourceWriter(*SourceStream);
259 : assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize());
260 0 : cantFail(SourceWriter.writeBytes(
261 : arrayRefFromStringRef(IS.Content->getBuffer())));
262 : }
263 : }
264 :
265 111 : Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) {
266 : assert(!Filename.empty());
267 222 : if (auto EC = finalizeMsfLayout())
268 : return EC;
269 :
270 111 : MSFLayout Layout;
271 : Expected<FileBufferByteStream> ExpectedMsfBuffer =
272 222 : Msf->commit(Filename, Layout);
273 111 : if (!ExpectedMsfBuffer)
274 : return ExpectedMsfBuffer.takeError();
275 : FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer);
276 :
277 111 : auto ExpectedSN = getNamedStreamIndex("/names");
278 111 : if (!ExpectedSN)
279 : return ExpectedSN.takeError();
280 :
281 : auto NS = WritableMappedBlockStream::createIndexedStream(
282 222 : Layout, Buffer, *ExpectedSN, Allocator);
283 111 : BinaryStreamWriter NSWriter(*NS);
284 222 : if (auto EC = Strings.commit(NSWriter))
285 : return EC;
286 :
287 111 : for (const auto &NSE : NamedStreamData) {
288 0 : if (NSE.second.empty())
289 0 : continue;
290 :
291 : auto NS = WritableMappedBlockStream::createIndexedStream(
292 0 : Layout, Buffer, NSE.first, Allocator);
293 0 : BinaryStreamWriter NSW(*NS);
294 0 : if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
295 : return EC;
296 : }
297 :
298 111 : if (Info) {
299 222 : if (auto EC = Info->commit(Layout, Buffer))
300 : return EC;
301 : }
302 :
303 111 : if (Dbi) {
304 216 : if (auto EC = Dbi->commit(Layout, Buffer))
305 : return EC;
306 : }
307 :
308 111 : if (Tpi) {
309 222 : if (auto EC = Tpi->commit(Layout, Buffer))
310 : return EC;
311 : }
312 :
313 111 : if (Ipi) {
314 222 : if (auto EC = Ipi->commit(Layout, Buffer))
315 : return EC;
316 : }
317 :
318 111 : if (Gsi) {
319 176 : if (auto EC = Gsi->commit(Layout, Buffer))
320 : return EC;
321 : }
322 :
323 111 : auto InfoStreamBlocks = Layout.StreamMap[StreamPDB];
324 : assert(!InfoStreamBlocks.empty());
325 : uint64_t InfoStreamFileOffset =
326 333 : blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
327 : InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
328 111 : Buffer.getBufferStart() + InfoStreamFileOffset);
329 :
330 111 : commitInjectedSources(Buffer, Layout);
331 :
332 : // Set the build id at the very end, after every other byte of the PDB
333 : // has been written.
334 111 : if (Info->hashPDBContentsToGUID()) {
335 : // Compute a hash of all sections of the output file.
336 : uint64_t Digest =
337 88 : xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()});
338 :
339 : H->Age = 1;
340 :
341 88 : memcpy(H->Guid.Guid, &Digest, 8);
342 : // xxhash only gives us 8 bytes, so put some fixed data in the other half.
343 88 : memcpy(H->Guid.Guid + 8, "LLD PDB.", 8);
344 :
345 : // Put the hash in the Signature field too.
346 88 : H->Signature = static_cast<uint32_t>(Digest);
347 :
348 : // Return GUID to caller.
349 88 : memcpy(Guid, H->Guid.Guid, 16);
350 : } else {
351 23 : H->Age = Info->getAge();
352 23 : H->Guid = Info->getGuid();
353 : Optional<uint32_t> Sig = Info->getSignature();
354 23 : H->Signature = Sig.hasValue() ? *Sig : time(nullptr);
355 : }
356 :
357 : return Buffer.commit();
358 : }
|