16b6b8c4fSAdrian McCarthy //===- PDBFileBuilder.cpp - PDB File Creation -------------------*- C++ -*-===//
26b6b8c4fSAdrian McCarthy //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66b6b8c4fSAdrian McCarthy //
76b6b8c4fSAdrian McCarthy //===----------------------------------------------------------------------===//
86b6b8c4fSAdrian McCarthy
96b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
10eb4c8608Sserge-sans-paille #include "llvm/DebugInfo/CodeView/CodeView.h"
11eb4c8608Sserge-sans-paille #include "llvm/DebugInfo/CodeView/GUID.h"
126b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/MSF/MSFBuilder.h"
13eb4c8608Sserge-sans-paille #include "llvm/DebugInfo/MSF/MSFCommon.h"
14eb4c8608Sserge-sans-paille #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
156b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
16946204c8SZachary Turner #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
176b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
18e204a6c9SZachary Turner #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
19eb4c8608Sserge-sans-paille #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
206b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/RawError.h"
21eb4c8608Sserge-sans-paille #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
226b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
23d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamWriter.h"
241e1e3ba2SHans Wennborg #include "llvm/Support/CRC.h"
25f2282762SZachary Turner #include "llvm/Support/Path.h"
26205ca68bSNico Weber #include "llvm/Support/xxhash.h"
276b6b8c4fSAdrian McCarthy
2857c60122Sserge-sans-paille #include <ctime>
2957c60122Sserge-sans-paille
306b6b8c4fSAdrian McCarthy using namespace llvm;
316b6b8c4fSAdrian McCarthy using namespace llvm::codeview;
326b6b8c4fSAdrian McCarthy using namespace llvm::msf;
336b6b8c4fSAdrian McCarthy using namespace llvm::pdb;
346b6b8c4fSAdrian McCarthy using namespace llvm::support;
356b6b8c4fSAdrian McCarthy
36eb4c8608Sserge-sans-paille namespace llvm {
37eb4c8608Sserge-sans-paille class WritableBinaryStream;
38eb4c8608Sserge-sans-paille }
39eb4c8608Sserge-sans-paille
PDBFileBuilder(BumpPtrAllocator & Allocator)406b6b8c4fSAdrian McCarthy PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
41f2282762SZachary Turner : Allocator(Allocator), InjectedSourceHashTraits(Strings),
4251a52b58SNico Weber InjectedSourceTable(2) {}
436b6b8c4fSAdrian McCarthy
443a3cb929SKazu Hirata PDBFileBuilder::~PDBFileBuilder() = default;
457eaf1d96SZachary Turner
initialize(uint32_t BlockSize)466b6b8c4fSAdrian McCarthy Error PDBFileBuilder::initialize(uint32_t BlockSize) {
476b6b8c4fSAdrian McCarthy auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
486b6b8c4fSAdrian McCarthy if (!ExpectedMsf)
496b6b8c4fSAdrian McCarthy return ExpectedMsf.takeError();
500eaee545SJonas Devlieghere Msf = std::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
516b6b8c4fSAdrian McCarthy return Error::success();
526b6b8c4fSAdrian McCarthy }
536b6b8c4fSAdrian McCarthy
getMsfBuilder()546b6b8c4fSAdrian McCarthy MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
556b6b8c4fSAdrian McCarthy
getInfoBuilder()566b6b8c4fSAdrian McCarthy InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
576b6b8c4fSAdrian McCarthy if (!Info)
580eaee545SJonas Devlieghere Info = std::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
596b6b8c4fSAdrian McCarthy return *Info;
606b6b8c4fSAdrian McCarthy }
616b6b8c4fSAdrian McCarthy
getDbiBuilder()626b6b8c4fSAdrian McCarthy DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
636b6b8c4fSAdrian McCarthy if (!Dbi)
640eaee545SJonas Devlieghere Dbi = std::make_unique<DbiStreamBuilder>(*Msf);
656b6b8c4fSAdrian McCarthy return *Dbi;
666b6b8c4fSAdrian McCarthy }
676b6b8c4fSAdrian McCarthy
getTpiBuilder()686b6b8c4fSAdrian McCarthy TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
696b6b8c4fSAdrian McCarthy if (!Tpi)
700eaee545SJonas Devlieghere Tpi = std::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
716b6b8c4fSAdrian McCarthy return *Tpi;
726b6b8c4fSAdrian McCarthy }
736b6b8c4fSAdrian McCarthy
getIpiBuilder()746b6b8c4fSAdrian McCarthy TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
756b6b8c4fSAdrian McCarthy if (!Ipi)
760eaee545SJonas Devlieghere Ipi = std::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
776b6b8c4fSAdrian McCarthy return *Ipi;
786b6b8c4fSAdrian McCarthy }
796b6b8c4fSAdrian McCarthy
getStringTableBuilder()80e204a6c9SZachary Turner PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
81e204a6c9SZachary Turner return Strings;
82e204a6c9SZachary Turner }
836b6b8c4fSAdrian McCarthy
getGsiBuilder()84946204c8SZachary Turner GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() {
85946204c8SZachary Turner if (!Gsi)
860eaee545SJonas Devlieghere Gsi = std::make_unique<GSIStreamBuilder>(*Msf);
87946204c8SZachary Turner return *Gsi;
888d927b6bSZachary Turner }
898d927b6bSZachary Turner
allocateNamedStream(StringRef Name,uint32_t Size)90a6fb536eSZachary Turner Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name,
91a6fb536eSZachary Turner uint32_t Size) {
926b6b8c4fSAdrian McCarthy auto ExpectedStream = Msf->addStream(Size);
93a6fb536eSZachary Turner if (ExpectedStream)
946b6b8c4fSAdrian McCarthy NamedStreams.set(Name, *ExpectedStream);
95a6fb536eSZachary Turner return ExpectedStream;
96a6fb536eSZachary Turner }
97a6fb536eSZachary Turner
addNamedStream(StringRef Name,StringRef Data)98a6fb536eSZachary Turner Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) {
99a6fb536eSZachary Turner Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size());
100a6fb536eSZachary Turner if (!ExpectedIndex)
101a6fb536eSZachary Turner return ExpectedIndex.takeError();
102a6fb536eSZachary Turner assert(NamedStreamData.count(*ExpectedIndex) == 0);
103adcd0268SBenjamin Kramer NamedStreamData[*ExpectedIndex] = std::string(Data);
1046b6b8c4fSAdrian McCarthy return Error::success();
1056b6b8c4fSAdrian McCarthy }
1066b6b8c4fSAdrian McCarthy
addInjectedSource(StringRef Name,std::unique_ptr<MemoryBuffer> Buffer)107f2282762SZachary Turner void PDBFileBuilder::addInjectedSource(StringRef Name,
108f2282762SZachary Turner std::unique_ptr<MemoryBuffer> Buffer) {
109f2282762SZachary Turner // Stream names must be exact matches, since they get looked up in a hash
110f2282762SZachary Turner // table and the hash value is dependent on the exact contents of the string.
111f2282762SZachary Turner // link.exe lowercases a path and converts / to \, so we must do the same.
112f2282762SZachary Turner SmallString<64> VName;
11386c01b1bSMartin Storsjö sys::path::native(Name.lower(), VName, sys::path::Style::windows_backslash);
114f2282762SZachary Turner
115f2282762SZachary Turner uint32_t NI = getStringTableBuilder().insert(Name);
116f2282762SZachary Turner uint32_t VNI = getStringTableBuilder().insert(VName);
117f2282762SZachary Turner
118f2282762SZachary Turner InjectedSourceDescriptor Desc;
119f2282762SZachary Turner Desc.Content = std::move(Buffer);
120f2282762SZachary Turner Desc.NameIndex = NI;
121f2282762SZachary Turner Desc.VNameIndex = VNI;
122f2282762SZachary Turner Desc.StreamName = "/src/files/";
123f2282762SZachary Turner
124f2282762SZachary Turner Desc.StreamName += VName;
125f2282762SZachary Turner
126f2282762SZachary Turner InjectedSources.push_back(std::move(Desc));
127f2282762SZachary Turner }
128f2282762SZachary Turner
finalizeMsfLayout()129ee8010abSZachary Turner Error PDBFileBuilder::finalizeMsfLayout() {
13068ea80d0SZachary Turner
13168ea80d0SZachary Turner if (Ipi && Ipi->getRecordCount() > 0) {
13268ea80d0SZachary Turner // In theory newer PDBs always have an ID stream, but by saying that we're
13368ea80d0SZachary Turner // only going to *really* have an ID stream if there is at least one ID
13468ea80d0SZachary Turner // record, we leave open the opportunity to test older PDBs such as those
13568ea80d0SZachary Turner // that don't have an ID stream.
13668ea80d0SZachary Turner auto &Info = getInfoBuilder();
13768ea80d0SZachary Turner Info.addFeature(PdbRaw_FeatureSig::VC140);
13868ea80d0SZachary Turner }
13968ea80d0SZachary Turner
140c504ae3cSZachary Turner uint32_t StringsLen = Strings.calculateSerializedSize();
1416b6b8c4fSAdrian McCarthy
142a6fb536eSZachary Turner Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0);
143a6fb536eSZachary Turner if (!SN)
144a6fb536eSZachary Turner return SN.takeError();
1456b6b8c4fSAdrian McCarthy
146946204c8SZachary Turner if (Gsi) {
147946204c8SZachary Turner if (auto EC = Gsi->finalizeMsfLayout())
148ee8010abSZachary Turner return EC;
1497eaf1d96SZachary Turner if (Dbi) {
150946204c8SZachary Turner Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
151946204c8SZachary Turner Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
152b7438c25SReid Kleckner Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIndex());
1537eaf1d96SZachary Turner }
1547eaf1d96SZachary Turner }
155a6fb536eSZachary Turner if (Tpi) {
156a6fb536eSZachary Turner if (auto EC = Tpi->finalizeMsfLayout())
157ee8010abSZachary Turner return EC;
158a6fb536eSZachary Turner }
159a6fb536eSZachary Turner if (Dbi) {
160a6fb536eSZachary Turner if (auto EC = Dbi->finalizeMsfLayout())
161ee8010abSZachary Turner return EC;
162a6fb536eSZachary Turner }
163a6fb536eSZachary Turner SN = allocateNamedStream("/names", StringsLen);
164a6fb536eSZachary Turner if (!SN)
165a6fb536eSZachary Turner return SN.takeError();
166a6fb536eSZachary Turner
167a6fb536eSZachary Turner if (Ipi) {
168a6fb536eSZachary Turner if (auto EC = Ipi->finalizeMsfLayout())
169ee8010abSZachary Turner return EC;
170a6fb536eSZachary Turner }
171a6fb536eSZachary Turner
172a6fb536eSZachary Turner // Do this last, since it relies on the named stream map being complete, and
173a6fb536eSZachary Turner // that can be updated by previous steps in the finalization.
174a6fb536eSZachary Turner if (Info) {
175a6fb536eSZachary Turner if (auto EC = Info->finalizeMsfLayout())
176ee8010abSZachary Turner return EC;
177a6fb536eSZachary Turner }
1786b6b8c4fSAdrian McCarthy
179f2282762SZachary Turner if (!InjectedSources.empty()) {
180f2282762SZachary Turner for (const auto &IS : InjectedSources) {
181f2282762SZachary Turner JamCRC CRC(0);
1821e1e3ba2SHans Wennborg CRC.update(arrayRefFromStringRef(IS.Content->getBuffer()));
183f2282762SZachary Turner
184f2282762SZachary Turner SrcHeaderBlockEntry Entry;
185f2282762SZachary Turner ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry));
186f2282762SZachary Turner Entry.Size = sizeof(SrcHeaderBlockEntry);
187f2282762SZachary Turner Entry.FileSize = IS.Content->getBufferSize();
188f2282762SZachary Turner Entry.FileNI = IS.NameIndex;
189f2282762SZachary Turner Entry.VFileNI = IS.VNameIndex;
190f2282762SZachary Turner Entry.ObjNI = 1;
191f2282762SZachary Turner Entry.IsVirtual = 0;
192f2282762SZachary Turner Entry.Version =
193f2282762SZachary Turner static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
194f2282762SZachary Turner Entry.CRC = CRC.getCRC();
195f2282762SZachary Turner StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex);
19651a52b58SNico Weber InjectedSourceTable.set_as(VName, std::move(Entry),
19751a52b58SNico Weber InjectedSourceHashTraits);
198f2282762SZachary Turner }
199f2282762SZachary Turner
200f2282762SZachary Turner uint32_t SrcHeaderBlockSize =
201f2282762SZachary Turner sizeof(SrcHeaderBlockHeader) +
202f2282762SZachary Turner InjectedSourceTable.calculateSerializedLength();
203f2282762SZachary Turner SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize);
204f2282762SZachary Turner if (!SN)
205f2282762SZachary Turner return SN.takeError();
206f2282762SZachary Turner for (const auto &IS : InjectedSources) {
207f2282762SZachary Turner SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize());
208f2282762SZachary Turner if (!SN)
209f2282762SZachary Turner return SN.takeError();
210f2282762SZachary Turner }
211f2282762SZachary Turner }
212f2282762SZachary Turner
213f2282762SZachary Turner // Do this last, since it relies on the named stream map being complete, and
214f2282762SZachary Turner // that can be updated by previous steps in the finalization.
215f2282762SZachary Turner if (Info) {
216f2282762SZachary Turner if (auto EC = Info->finalizeMsfLayout())
217ee8010abSZachary Turner return EC;
218f2282762SZachary Turner }
219f2282762SZachary Turner
220ee8010abSZachary Turner return Error::success();
2216b6b8c4fSAdrian McCarthy }
2226b6b8c4fSAdrian McCarthy
getNamedStreamIndex(StringRef Name) const223c504ae3cSZachary Turner Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
224c504ae3cSZachary Turner uint32_t SN = 0;
225c504ae3cSZachary Turner if (!NamedStreams.get(Name, SN))
226c504ae3cSZachary Turner return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
227c504ae3cSZachary Turner return SN;
228c504ae3cSZachary Turner }
229c504ae3cSZachary Turner
commitSrcHeaderBlock(WritableBinaryStream & MsfBuffer,const msf::MSFLayout & Layout)230f2282762SZachary Turner void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
231f2282762SZachary Turner const msf::MSFLayout &Layout) {
232f2282762SZachary Turner assert(!InjectedSourceTable.empty());
233f2282762SZachary Turner
234f2282762SZachary Turner uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock"));
235f2282762SZachary Turner auto Stream = WritableMappedBlockStream::createIndexedStream(
236f2282762SZachary Turner Layout, MsfBuffer, SN, Allocator);
237f2282762SZachary Turner BinaryStreamWriter Writer(*Stream);
238f2282762SZachary Turner
239f2282762SZachary Turner SrcHeaderBlockHeader Header;
240f2282762SZachary Turner ::memset(&Header, 0, sizeof(Header));
241f2282762SZachary Turner Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
242f2282762SZachary Turner Header.Size = Writer.bytesRemaining();
243f2282762SZachary Turner
244f2282762SZachary Turner cantFail(Writer.writeObject(Header));
245f2282762SZachary Turner cantFail(InjectedSourceTable.commit(Writer));
246f2282762SZachary Turner
247f2282762SZachary Turner assert(Writer.bytesRemaining() == 0);
248f2282762SZachary Turner }
249f2282762SZachary Turner
commitInjectedSources(WritableBinaryStream & MsfBuffer,const msf::MSFLayout & Layout)250f2282762SZachary Turner void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
251f2282762SZachary Turner const msf::MSFLayout &Layout) {
252f2282762SZachary Turner if (InjectedSourceTable.empty())
253f2282762SZachary Turner return;
254f2282762SZachary Turner
255f2282762SZachary Turner commitSrcHeaderBlock(MsfBuffer, Layout);
256f2282762SZachary Turner
257f2282762SZachary Turner for (const auto &IS : InjectedSources) {
258f2282762SZachary Turner uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName));
259f2282762SZachary Turner
260f2282762SZachary Turner auto SourceStream = WritableMappedBlockStream::createIndexedStream(
261f2282762SZachary Turner Layout, MsfBuffer, SN, Allocator);
262f2282762SZachary Turner BinaryStreamWriter SourceWriter(*SourceStream);
263f2282762SZachary Turner assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize());
264f2282762SZachary Turner cantFail(SourceWriter.writeBytes(
265f2282762SZachary Turner arrayRefFromStringRef(IS.Content->getBuffer())));
266f2282762SZachary Turner }
267f2282762SZachary Turner }
268f2282762SZachary Turner
commit(StringRef Filename,codeview::GUID * Guid)269205ca68bSNico Weber Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) {
270de33a637SBob Haarman assert(!Filename.empty());
271ee8010abSZachary Turner if (auto EC = finalizeMsfLayout())
2726b6b8c4fSAdrian McCarthy return EC;
2739fb9d71dSZachary Turner
274ee8010abSZachary Turner MSFLayout Layout;
275205ca68bSNico Weber Expected<FileBufferByteStream> ExpectedMsfBuffer =
276205ca68bSNico Weber Msf->commit(Filename, Layout);
277ee8010abSZachary Turner if (!ExpectedMsfBuffer)
278ee8010abSZachary Turner return ExpectedMsfBuffer.takeError();
279ee8010abSZachary Turner FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer);
2806b6b8c4fSAdrian McCarthy
281c504ae3cSZachary Turner auto ExpectedSN = getNamedStreamIndex("/names");
282c504ae3cSZachary Turner if (!ExpectedSN)
283c504ae3cSZachary Turner return ExpectedSN.takeError();
2846b6b8c4fSAdrian McCarthy
2855b74ff33SZachary Turner auto NS = WritableMappedBlockStream::createIndexedStream(
2865b74ff33SZachary Turner Layout, Buffer, *ExpectedSN, Allocator);
287120faca4SZachary Turner BinaryStreamWriter NSWriter(*NS);
2886b6b8c4fSAdrian McCarthy if (auto EC = Strings.commit(NSWriter))
2896b6b8c4fSAdrian McCarthy return EC;
2906b6b8c4fSAdrian McCarthy
291a6fb536eSZachary Turner for (const auto &NSE : NamedStreamData) {
292a6fb536eSZachary Turner if (NSE.second.empty())
293a6fb536eSZachary Turner continue;
294a6fb536eSZachary Turner
295a6fb536eSZachary Turner auto NS = WritableMappedBlockStream::createIndexedStream(
296a6fb536eSZachary Turner Layout, Buffer, NSE.first, Allocator);
297a6fb536eSZachary Turner BinaryStreamWriter NSW(*NS);
298a6fb536eSZachary Turner if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
299a6fb536eSZachary Turner return EC;
300a6fb536eSZachary Turner }
301a6fb536eSZachary Turner
3026b6b8c4fSAdrian McCarthy if (Info) {
3036b6b8c4fSAdrian McCarthy if (auto EC = Info->commit(Layout, Buffer))
3046b6b8c4fSAdrian McCarthy return EC;
3056b6b8c4fSAdrian McCarthy }
3066b6b8c4fSAdrian McCarthy
3076b6b8c4fSAdrian McCarthy if (Dbi) {
3086b6b8c4fSAdrian McCarthy if (auto EC = Dbi->commit(Layout, Buffer))
3096b6b8c4fSAdrian McCarthy return EC;
3106b6b8c4fSAdrian McCarthy }
3116b6b8c4fSAdrian McCarthy
3126b6b8c4fSAdrian McCarthy if (Tpi) {
3136b6b8c4fSAdrian McCarthy if (auto EC = Tpi->commit(Layout, Buffer))
3146b6b8c4fSAdrian McCarthy return EC;
3156b6b8c4fSAdrian McCarthy }
3166b6b8c4fSAdrian McCarthy
3176b6b8c4fSAdrian McCarthy if (Ipi) {
3186b6b8c4fSAdrian McCarthy if (auto EC = Ipi->commit(Layout, Buffer))
3196b6b8c4fSAdrian McCarthy return EC;
3206b6b8c4fSAdrian McCarthy }
3216b6b8c4fSAdrian McCarthy
322946204c8SZachary Turner if (Gsi) {
323946204c8SZachary Turner if (auto EC = Gsi->commit(Layout, Buffer))
3248d927b6bSZachary Turner return EC;
3258d927b6bSZachary Turner }
3268d927b6bSZachary Turner
327c6a75a69SZachary Turner auto InfoStreamBlocks = Layout.StreamMap[StreamPDB];
328c6a75a69SZachary Turner assert(!InfoStreamBlocks.empty());
329c6a75a69SZachary Turner uint64_t InfoStreamFileOffset =
330c6a75a69SZachary Turner blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
331c6a75a69SZachary Turner InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
332ee8010abSZachary Turner Buffer.getBufferStart() + InfoStreamFileOffset);
333c6a75a69SZachary Turner
334f2282762SZachary Turner commitInjectedSources(Buffer, Layout);
335f2282762SZachary Turner
336c6a75a69SZachary Turner // Set the build id at the very end, after every other byte of the PDB
337c6a75a69SZachary Turner // has been written.
338205ca68bSNico Weber if (Info->hashPDBContentsToGUID()) {
339205ca68bSNico Weber // Compute a hash of all sections of the output file.
340205ca68bSNico Weber uint64_t Digest =
341205ca68bSNico Weber xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()});
342205ca68bSNico Weber
343205ca68bSNico Weber H->Age = 1;
344205ca68bSNico Weber
345205ca68bSNico Weber memcpy(H->Guid.Guid, &Digest, 8);
346205ca68bSNico Weber // xxhash only gives us 8 bytes, so put some fixed data in the other half.
347205ca68bSNico Weber memcpy(H->Guid.Guid + 8, "LLD PDB.", 8);
348205ca68bSNico Weber
349205ca68bSNico Weber // Put the hash in the Signature field too.
350205ca68bSNico Weber H->Signature = static_cast<uint32_t>(Digest);
351205ca68bSNico Weber
352205ca68bSNico Weber // Return GUID to caller.
353205ca68bSNico Weber memcpy(Guid, H->Guid.Guid, 16);
354205ca68bSNico Weber } else {
355c6a75a69SZachary Turner H->Age = Info->getAge();
356c6a75a69SZachary Turner H->Guid = Info->getGuid();
357c6a75a69SZachary Turner Optional<uint32_t> Sig = Info->getSignature();
358*0916d96dSKazu Hirata H->Signature = Sig ? *Sig : time(nullptr);
359205ca68bSNico Weber }
360c6a75a69SZachary Turner
3616b6b8c4fSAdrian McCarthy return Buffer.commit();
3626b6b8c4fSAdrian McCarthy }
363