17a7e6055SDimitry Andric //===- PDBFileBuilder.cpp - PDB File Creation -------------------*- C++ -*-===//
27a7e6055SDimitry Andric //
37a7e6055SDimitry Andric // The LLVM Compiler Infrastructure
47a7e6055SDimitry Andric //
57a7e6055SDimitry Andric // This file is distributed under the University of Illinois Open Source
67a7e6055SDimitry Andric // License. See LICENSE.TXT for details.
77a7e6055SDimitry Andric //
87a7e6055SDimitry Andric //===----------------------------------------------------------------------===//
97a7e6055SDimitry Andric
107a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
117a7e6055SDimitry Andric
127a7e6055SDimitry Andric #include "llvm/ADT/BitVector.h"
137a7e6055SDimitry Andric
147a7e6055SDimitry Andric #include "llvm/DebugInfo/MSF/MSFBuilder.h"
157a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
167a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
172cab237bSDimitry Andric #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
187a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
197a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
20f37b6182SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
217a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
227a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
237a7e6055SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
247a7e6055SDimitry Andric #include "llvm/Support/BinaryStream.h"
257a7e6055SDimitry Andric #include "llvm/Support/BinaryStreamWriter.h"
264ba319b5SDimitry Andric #include "llvm/Support/JamCRC.h"
274ba319b5SDimitry Andric #include "llvm/Support/Path.h"
28*b5893f02SDimitry Andric #include "llvm/Support/xxhash.h"
297a7e6055SDimitry Andric
307a7e6055SDimitry Andric using namespace llvm;
317a7e6055SDimitry Andric using namespace llvm::codeview;
327a7e6055SDimitry Andric using namespace llvm::msf;
337a7e6055SDimitry Andric using namespace llvm::pdb;
347a7e6055SDimitry Andric using namespace llvm::support;
357a7e6055SDimitry Andric
PDBFileBuilder(BumpPtrAllocator & Allocator)367a7e6055SDimitry Andric PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
374ba319b5SDimitry Andric : Allocator(Allocator), InjectedSourceHashTraits(Strings),
384ba319b5SDimitry Andric InjectedSourceTable(2, InjectedSourceHashTraits) {}
397a7e6055SDimitry Andric
~PDBFileBuilder()40c4394386SDimitry Andric PDBFileBuilder::~PDBFileBuilder() {}
41c4394386SDimitry Andric
initialize(uint32_t BlockSize)427a7e6055SDimitry Andric Error PDBFileBuilder::initialize(uint32_t BlockSize) {
437a7e6055SDimitry Andric auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
447a7e6055SDimitry Andric if (!ExpectedMsf)
457a7e6055SDimitry Andric return ExpectedMsf.takeError();
467a7e6055SDimitry Andric Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
477a7e6055SDimitry Andric return Error::success();
487a7e6055SDimitry Andric }
497a7e6055SDimitry Andric
getMsfBuilder()507a7e6055SDimitry Andric MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
517a7e6055SDimitry Andric
getInfoBuilder()527a7e6055SDimitry Andric InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
537a7e6055SDimitry Andric if (!Info)
547a7e6055SDimitry Andric Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
557a7e6055SDimitry Andric return *Info;
567a7e6055SDimitry Andric }
577a7e6055SDimitry Andric
getDbiBuilder()587a7e6055SDimitry Andric DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
597a7e6055SDimitry Andric if (!Dbi)
607a7e6055SDimitry Andric Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf);
617a7e6055SDimitry Andric return *Dbi;
627a7e6055SDimitry Andric }
637a7e6055SDimitry Andric
getTpiBuilder()647a7e6055SDimitry Andric TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
657a7e6055SDimitry Andric if (!Tpi)
667a7e6055SDimitry Andric Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
677a7e6055SDimitry Andric return *Tpi;
687a7e6055SDimitry Andric }
697a7e6055SDimitry Andric
getIpiBuilder()707a7e6055SDimitry Andric TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
717a7e6055SDimitry Andric if (!Ipi)
727a7e6055SDimitry Andric Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
737a7e6055SDimitry Andric return *Ipi;
747a7e6055SDimitry Andric }
757a7e6055SDimitry Andric
getStringTableBuilder()76f37b6182SDimitry Andric PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
77f37b6182SDimitry Andric return Strings;
78f37b6182SDimitry Andric }
797a7e6055SDimitry Andric
getGsiBuilder()802cab237bSDimitry Andric GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() {
812cab237bSDimitry Andric if (!Gsi)
822cab237bSDimitry Andric Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf);
832cab237bSDimitry Andric return *Gsi;
84c4394386SDimitry Andric }
85c4394386SDimitry Andric
allocateNamedStream(StringRef Name,uint32_t Size)864ba319b5SDimitry Andric Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name,
874ba319b5SDimitry Andric uint32_t Size) {
887a7e6055SDimitry Andric auto ExpectedStream = Msf->addStream(Size);
894ba319b5SDimitry Andric if (ExpectedStream)
907a7e6055SDimitry Andric NamedStreams.set(Name, *ExpectedStream);
914ba319b5SDimitry Andric return ExpectedStream;
924ba319b5SDimitry Andric }
934ba319b5SDimitry Andric
addNamedStream(StringRef Name,StringRef Data)944ba319b5SDimitry Andric Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) {
954ba319b5SDimitry Andric Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size());
964ba319b5SDimitry Andric if (!ExpectedIndex)
974ba319b5SDimitry Andric return ExpectedIndex.takeError();
984ba319b5SDimitry Andric assert(NamedStreamData.count(*ExpectedIndex) == 0);
994ba319b5SDimitry Andric NamedStreamData[*ExpectedIndex] = Data;
1007a7e6055SDimitry Andric return Error::success();
1017a7e6055SDimitry Andric }
1027a7e6055SDimitry Andric
addInjectedSource(StringRef Name,std::unique_ptr<MemoryBuffer> Buffer)1034ba319b5SDimitry Andric void PDBFileBuilder::addInjectedSource(StringRef Name,
1044ba319b5SDimitry Andric std::unique_ptr<MemoryBuffer> Buffer) {
1054ba319b5SDimitry Andric // Stream names must be exact matches, since they get looked up in a hash
1064ba319b5SDimitry Andric // table and the hash value is dependent on the exact contents of the string.
1074ba319b5SDimitry Andric // link.exe lowercases a path and converts / to \, so we must do the same.
1084ba319b5SDimitry Andric SmallString<64> VName;
1094ba319b5SDimitry Andric sys::path::native(Name.lower(), VName);
1104ba319b5SDimitry Andric
1114ba319b5SDimitry Andric uint32_t NI = getStringTableBuilder().insert(Name);
1124ba319b5SDimitry Andric uint32_t VNI = getStringTableBuilder().insert(VName);
1134ba319b5SDimitry Andric
1144ba319b5SDimitry Andric InjectedSourceDescriptor Desc;
1154ba319b5SDimitry Andric Desc.Content = std::move(Buffer);
1164ba319b5SDimitry Andric Desc.NameIndex = NI;
1174ba319b5SDimitry Andric Desc.VNameIndex = VNI;
1184ba319b5SDimitry Andric Desc.StreamName = "/src/files/";
1194ba319b5SDimitry Andric
1204ba319b5SDimitry Andric Desc.StreamName += VName;
1214ba319b5SDimitry Andric
1224ba319b5SDimitry Andric InjectedSources.push_back(std::move(Desc));
1234ba319b5SDimitry Andric }
1244ba319b5SDimitry Andric
finalizeMsfLayout()1254ba319b5SDimitry Andric Error PDBFileBuilder::finalizeMsfLayout() {
12624d58133SDimitry Andric
12724d58133SDimitry Andric if (Ipi && Ipi->getRecordCount() > 0) {
12824d58133SDimitry Andric // In theory newer PDBs always have an ID stream, but by saying that we're
12924d58133SDimitry Andric // only going to *really* have an ID stream if there is at least one ID
13024d58133SDimitry Andric // record, we leave open the opportunity to test older PDBs such as those
13124d58133SDimitry Andric // that don't have an ID stream.
13224d58133SDimitry Andric auto &Info = getInfoBuilder();
13324d58133SDimitry Andric Info.addFeature(PdbRaw_FeatureSig::VC140);
13424d58133SDimitry Andric }
13524d58133SDimitry Andric
136f37b6182SDimitry Andric uint32_t StringsLen = Strings.calculateSerializedSize();
1377a7e6055SDimitry Andric
1384ba319b5SDimitry Andric Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0);
1394ba319b5SDimitry Andric if (!SN)
1404ba319b5SDimitry Andric return SN.takeError();
1417a7e6055SDimitry Andric
1422cab237bSDimitry Andric if (Gsi) {
1432cab237bSDimitry Andric if (auto EC = Gsi->finalizeMsfLayout())
1444ba319b5SDimitry Andric return EC;
145c4394386SDimitry Andric if (Dbi) {
1462cab237bSDimitry Andric Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
1472cab237bSDimitry Andric Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
1482cab237bSDimitry Andric Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx());
149c4394386SDimitry Andric }
150c4394386SDimitry Andric }
1514ba319b5SDimitry Andric if (Tpi) {
1524ba319b5SDimitry Andric if (auto EC = Tpi->finalizeMsfLayout())
1534ba319b5SDimitry Andric return EC;
1544ba319b5SDimitry Andric }
1554ba319b5SDimitry Andric if (Dbi) {
1564ba319b5SDimitry Andric if (auto EC = Dbi->finalizeMsfLayout())
1574ba319b5SDimitry Andric return EC;
1584ba319b5SDimitry Andric }
1594ba319b5SDimitry Andric SN = allocateNamedStream("/names", StringsLen);
1604ba319b5SDimitry Andric if (!SN)
1614ba319b5SDimitry Andric return SN.takeError();
1627a7e6055SDimitry Andric
1634ba319b5SDimitry Andric if (Ipi) {
1644ba319b5SDimitry Andric if (auto EC = Ipi->finalizeMsfLayout())
1654ba319b5SDimitry Andric return EC;
1664ba319b5SDimitry Andric }
1674ba319b5SDimitry Andric
1684ba319b5SDimitry Andric // Do this last, since it relies on the named stream map being complete, and
1694ba319b5SDimitry Andric // that can be updated by previous steps in the finalization.
1704ba319b5SDimitry Andric if (Info) {
1714ba319b5SDimitry Andric if (auto EC = Info->finalizeMsfLayout())
1724ba319b5SDimitry Andric return EC;
1734ba319b5SDimitry Andric }
1744ba319b5SDimitry Andric
1754ba319b5SDimitry Andric if (!InjectedSources.empty()) {
1764ba319b5SDimitry Andric for (const auto &IS : InjectedSources) {
1774ba319b5SDimitry Andric JamCRC CRC(0);
1784ba319b5SDimitry Andric CRC.update(makeArrayRef(IS.Content->getBufferStart(),
1794ba319b5SDimitry Andric IS.Content->getBufferSize()));
1804ba319b5SDimitry Andric
1814ba319b5SDimitry Andric SrcHeaderBlockEntry Entry;
1824ba319b5SDimitry Andric ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry));
1834ba319b5SDimitry Andric Entry.Size = sizeof(SrcHeaderBlockEntry);
1844ba319b5SDimitry Andric Entry.FileSize = IS.Content->getBufferSize();
1854ba319b5SDimitry Andric Entry.FileNI = IS.NameIndex;
1864ba319b5SDimitry Andric Entry.VFileNI = IS.VNameIndex;
1874ba319b5SDimitry Andric Entry.ObjNI = 1;
1884ba319b5SDimitry Andric Entry.IsVirtual = 0;
1894ba319b5SDimitry Andric Entry.Version =
1904ba319b5SDimitry Andric static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
1914ba319b5SDimitry Andric Entry.CRC = CRC.getCRC();
1924ba319b5SDimitry Andric StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex);
1934ba319b5SDimitry Andric InjectedSourceTable.set_as(VName, std::move(Entry));
1944ba319b5SDimitry Andric }
1954ba319b5SDimitry Andric
1964ba319b5SDimitry Andric uint32_t SrcHeaderBlockSize =
1974ba319b5SDimitry Andric sizeof(SrcHeaderBlockHeader) +
1984ba319b5SDimitry Andric InjectedSourceTable.calculateSerializedLength();
1994ba319b5SDimitry Andric SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize);
2004ba319b5SDimitry Andric if (!SN)
2014ba319b5SDimitry Andric return SN.takeError();
2024ba319b5SDimitry Andric for (const auto &IS : InjectedSources) {
2034ba319b5SDimitry Andric SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize());
2044ba319b5SDimitry Andric if (!SN)
2054ba319b5SDimitry Andric return SN.takeError();
2064ba319b5SDimitry Andric }
2074ba319b5SDimitry Andric }
2084ba319b5SDimitry Andric
2094ba319b5SDimitry Andric // Do this last, since it relies on the named stream map being complete, and
2104ba319b5SDimitry Andric // that can be updated by previous steps in the finalization.
2114ba319b5SDimitry Andric if (Info) {
2124ba319b5SDimitry Andric if (auto EC = Info->finalizeMsfLayout())
2134ba319b5SDimitry Andric return EC;
2144ba319b5SDimitry Andric }
2154ba319b5SDimitry Andric
2164ba319b5SDimitry Andric return Error::success();
2177a7e6055SDimitry Andric }
2187a7e6055SDimitry Andric
getNamedStreamIndex(StringRef Name) const219f37b6182SDimitry Andric Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
220f37b6182SDimitry Andric uint32_t SN = 0;
221f37b6182SDimitry Andric if (!NamedStreams.get(Name, SN))
222f37b6182SDimitry Andric return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
223f37b6182SDimitry Andric return SN;
224f37b6182SDimitry Andric }
225f37b6182SDimitry Andric
commitSrcHeaderBlock(WritableBinaryStream & MsfBuffer,const msf::MSFLayout & Layout)2264ba319b5SDimitry Andric void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
2274ba319b5SDimitry Andric const msf::MSFLayout &Layout) {
2284ba319b5SDimitry Andric assert(!InjectedSourceTable.empty());
2292cab237bSDimitry Andric
2304ba319b5SDimitry Andric uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock"));
2314ba319b5SDimitry Andric auto Stream = WritableMappedBlockStream::createIndexedStream(
2324ba319b5SDimitry Andric Layout, MsfBuffer, SN, Allocator);
2334ba319b5SDimitry Andric BinaryStreamWriter Writer(*Stream);
2342cab237bSDimitry Andric
2354ba319b5SDimitry Andric SrcHeaderBlockHeader Header;
2364ba319b5SDimitry Andric ::memset(&Header, 0, sizeof(Header));
2374ba319b5SDimitry Andric Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
2384ba319b5SDimitry Andric Header.Size = Writer.bytesRemaining();
2394ba319b5SDimitry Andric
2404ba319b5SDimitry Andric cantFail(Writer.writeObject(Header));
2414ba319b5SDimitry Andric cantFail(InjectedSourceTable.commit(Writer));
2424ba319b5SDimitry Andric
2434ba319b5SDimitry Andric assert(Writer.bytesRemaining() == 0);
2442cab237bSDimitry Andric }
2454ba319b5SDimitry Andric
commitInjectedSources(WritableBinaryStream & MsfBuffer,const msf::MSFLayout & Layout)2464ba319b5SDimitry Andric void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
2474ba319b5SDimitry Andric const msf::MSFLayout &Layout) {
2484ba319b5SDimitry Andric if (InjectedSourceTable.empty())
2494ba319b5SDimitry Andric return;
2504ba319b5SDimitry Andric
2514ba319b5SDimitry Andric commitSrcHeaderBlock(MsfBuffer, Layout);
2524ba319b5SDimitry Andric
2534ba319b5SDimitry Andric for (const auto &IS : InjectedSources) {
2544ba319b5SDimitry Andric uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName));
2554ba319b5SDimitry Andric
2564ba319b5SDimitry Andric auto SourceStream = WritableMappedBlockStream::createIndexedStream(
2574ba319b5SDimitry Andric Layout, MsfBuffer, SN, Allocator);
2584ba319b5SDimitry Andric BinaryStreamWriter SourceWriter(*SourceStream);
2594ba319b5SDimitry Andric assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize());
2604ba319b5SDimitry Andric cantFail(SourceWriter.writeBytes(
2614ba319b5SDimitry Andric arrayRefFromStringRef(IS.Content->getBuffer())));
2622cab237bSDimitry Andric }
2632cab237bSDimitry Andric }
2642cab237bSDimitry Andric
commit(StringRef Filename,codeview::GUID * Guid)265*b5893f02SDimitry Andric Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) {
266d8866befSDimitry Andric assert(!Filename.empty());
2674ba319b5SDimitry Andric if (auto EC = finalizeMsfLayout())
2687a7e6055SDimitry Andric return EC;
2692cab237bSDimitry Andric
2704ba319b5SDimitry Andric MSFLayout Layout;
271*b5893f02SDimitry Andric Expected<FileBufferByteStream> ExpectedMsfBuffer =
272*b5893f02SDimitry Andric Msf->commit(Filename, Layout);
2734ba319b5SDimitry Andric if (!ExpectedMsfBuffer)
2744ba319b5SDimitry Andric return ExpectedMsfBuffer.takeError();
2754ba319b5SDimitry Andric FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer);
2767a7e6055SDimitry Andric
277f37b6182SDimitry Andric auto ExpectedSN = getNamedStreamIndex("/names");
278f37b6182SDimitry Andric if (!ExpectedSN)
279f37b6182SDimitry Andric return ExpectedSN.takeError();
2807a7e6055SDimitry Andric
2816d97bb29SDimitry Andric auto NS = WritableMappedBlockStream::createIndexedStream(
2826d97bb29SDimitry Andric Layout, Buffer, *ExpectedSN, Allocator);
2837a7e6055SDimitry Andric BinaryStreamWriter NSWriter(*NS);
2847a7e6055SDimitry Andric if (auto EC = Strings.commit(NSWriter))
2857a7e6055SDimitry Andric return EC;
2867a7e6055SDimitry Andric
2874ba319b5SDimitry Andric for (const auto &NSE : NamedStreamData) {
2884ba319b5SDimitry Andric if (NSE.second.empty())
2894ba319b5SDimitry Andric continue;
2904ba319b5SDimitry Andric
2914ba319b5SDimitry Andric auto NS = WritableMappedBlockStream::createIndexedStream(
2924ba319b5SDimitry Andric Layout, Buffer, NSE.first, Allocator);
2934ba319b5SDimitry Andric BinaryStreamWriter NSW(*NS);
2944ba319b5SDimitry Andric if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
2954ba319b5SDimitry Andric return EC;
2964ba319b5SDimitry Andric }
2974ba319b5SDimitry Andric
2987a7e6055SDimitry Andric if (Info) {
2997a7e6055SDimitry Andric if (auto EC = Info->commit(Layout, Buffer))
3007a7e6055SDimitry Andric return EC;
3017a7e6055SDimitry Andric }
3027a7e6055SDimitry Andric
3037a7e6055SDimitry Andric if (Dbi) {
3047a7e6055SDimitry Andric if (auto EC = Dbi->commit(Layout, Buffer))
3057a7e6055SDimitry Andric return EC;
3067a7e6055SDimitry Andric }
3077a7e6055SDimitry Andric
3087a7e6055SDimitry Andric if (Tpi) {
3097a7e6055SDimitry Andric if (auto EC = Tpi->commit(Layout, Buffer))
3107a7e6055SDimitry Andric return EC;
3117a7e6055SDimitry Andric }
3127a7e6055SDimitry Andric
3137a7e6055SDimitry Andric if (Ipi) {
3147a7e6055SDimitry Andric if (auto EC = Ipi->commit(Layout, Buffer))
3157a7e6055SDimitry Andric return EC;
3167a7e6055SDimitry Andric }
3177a7e6055SDimitry Andric
3182cab237bSDimitry Andric if (Gsi) {
3192cab237bSDimitry Andric if (auto EC = Gsi->commit(Layout, Buffer))
320c4394386SDimitry Andric return EC;
321c4394386SDimitry Andric }
322c4394386SDimitry Andric
3234ba319b5SDimitry Andric auto InfoStreamBlocks = Layout.StreamMap[StreamPDB];
3244ba319b5SDimitry Andric assert(!InfoStreamBlocks.empty());
3254ba319b5SDimitry Andric uint64_t InfoStreamFileOffset =
3264ba319b5SDimitry Andric blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
3274ba319b5SDimitry Andric InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
3284ba319b5SDimitry Andric Buffer.getBufferStart() + InfoStreamFileOffset);
3294ba319b5SDimitry Andric
3304ba319b5SDimitry Andric commitInjectedSources(Buffer, Layout);
3314ba319b5SDimitry Andric
3324ba319b5SDimitry Andric // Set the build id at the very end, after every other byte of the PDB
3334ba319b5SDimitry Andric // has been written.
334*b5893f02SDimitry Andric if (Info->hashPDBContentsToGUID()) {
335*b5893f02SDimitry Andric // Compute a hash of all sections of the output file.
336*b5893f02SDimitry Andric uint64_t Digest =
337*b5893f02SDimitry Andric xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()});
338*b5893f02SDimitry Andric
339*b5893f02SDimitry Andric H->Age = 1;
340*b5893f02SDimitry Andric
341*b5893f02SDimitry Andric memcpy(H->Guid.Guid, &Digest, 8);
342*b5893f02SDimitry Andric // xxhash only gives us 8 bytes, so put some fixed data in the other half.
343*b5893f02SDimitry Andric memcpy(H->Guid.Guid + 8, "LLD PDB.", 8);
344*b5893f02SDimitry Andric
345*b5893f02SDimitry Andric // Put the hash in the Signature field too.
346*b5893f02SDimitry Andric H->Signature = static_cast<uint32_t>(Digest);
347*b5893f02SDimitry Andric
348*b5893f02SDimitry Andric // Return GUID to caller.
349*b5893f02SDimitry Andric memcpy(Guid, H->Guid.Guid, 16);
350*b5893f02SDimitry Andric } else {
3514ba319b5SDimitry Andric H->Age = Info->getAge();
3524ba319b5SDimitry Andric H->Guid = Info->getGuid();
3534ba319b5SDimitry Andric Optional<uint32_t> Sig = Info->getSignature();
3544ba319b5SDimitry Andric H->Signature = Sig.hasValue() ? *Sig : time(nullptr);
355*b5893f02SDimitry Andric }
3564ba319b5SDimitry Andric
3577a7e6055SDimitry Andric return Buffer.commit();
3587a7e6055SDimitry Andric }
359