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