10b57cec5SDimitry Andric //===- PDBFileBuilder.cpp - PDB File Creation -------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
1006c3fb27SDimitry Andric #include "llvm/ADT/SmallString.h"
1106c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
1281ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
1381ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/GUID.h"
140b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MSFBuilder.h"
1581ad6265SDimitry Andric #include "llvm/DebugInfo/MSF/MSFCommon.h"
1681ad6265SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
170b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
180b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
190b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
200b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
2181ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
220b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
2381ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
240b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
250b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamWriter.h"
268bcb0991SDimitry Andric #include "llvm/Support/CRC.h"
270b57cec5SDimitry Andric #include "llvm/Support/Path.h"
28*5f757f3fSDimitry Andric #include "llvm/Support/TimeProfiler.h"
290b57cec5SDimitry Andric #include "llvm/Support/xxhash.h"
300b57cec5SDimitry Andric
3181ad6265SDimitry Andric #include <ctime>
3281ad6265SDimitry Andric
330b57cec5SDimitry Andric using namespace llvm;
340b57cec5SDimitry Andric using namespace llvm::codeview;
350b57cec5SDimitry Andric using namespace llvm::msf;
360b57cec5SDimitry Andric using namespace llvm::pdb;
370b57cec5SDimitry Andric using namespace llvm::support;
380b57cec5SDimitry Andric
3981ad6265SDimitry Andric namespace llvm {
4081ad6265SDimitry Andric class WritableBinaryStream;
4181ad6265SDimitry Andric }
4281ad6265SDimitry Andric
PDBFileBuilder(BumpPtrAllocator & Allocator)430b57cec5SDimitry Andric PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
440b57cec5SDimitry Andric : Allocator(Allocator), InjectedSourceHashTraits(Strings),
450b57cec5SDimitry Andric InjectedSourceTable(2) {}
460b57cec5SDimitry Andric
4781ad6265SDimitry Andric PDBFileBuilder::~PDBFileBuilder() = default;
480b57cec5SDimitry Andric
initialize(uint32_t BlockSize)490b57cec5SDimitry Andric Error PDBFileBuilder::initialize(uint32_t BlockSize) {
500b57cec5SDimitry Andric auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
510b57cec5SDimitry Andric if (!ExpectedMsf)
520b57cec5SDimitry Andric return ExpectedMsf.takeError();
538bcb0991SDimitry Andric Msf = std::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
540b57cec5SDimitry Andric return Error::success();
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric
getMsfBuilder()570b57cec5SDimitry Andric MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
580b57cec5SDimitry Andric
getInfoBuilder()590b57cec5SDimitry Andric InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
600b57cec5SDimitry Andric if (!Info)
618bcb0991SDimitry Andric Info = std::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
620b57cec5SDimitry Andric return *Info;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
getDbiBuilder()650b57cec5SDimitry Andric DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
660b57cec5SDimitry Andric if (!Dbi)
678bcb0991SDimitry Andric Dbi = std::make_unique<DbiStreamBuilder>(*Msf);
680b57cec5SDimitry Andric return *Dbi;
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric
getTpiBuilder()710b57cec5SDimitry Andric TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
720b57cec5SDimitry Andric if (!Tpi)
738bcb0991SDimitry Andric Tpi = std::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
740b57cec5SDimitry Andric return *Tpi;
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric
getIpiBuilder()770b57cec5SDimitry Andric TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
780b57cec5SDimitry Andric if (!Ipi)
798bcb0991SDimitry Andric Ipi = std::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
800b57cec5SDimitry Andric return *Ipi;
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric
getStringTableBuilder()830b57cec5SDimitry Andric PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
840b57cec5SDimitry Andric return Strings;
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric
getGsiBuilder()870b57cec5SDimitry Andric GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() {
880b57cec5SDimitry Andric if (!Gsi)
898bcb0991SDimitry Andric Gsi = std::make_unique<GSIStreamBuilder>(*Msf);
900b57cec5SDimitry Andric return *Gsi;
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric
allocateNamedStream(StringRef Name,uint32_t Size)930b57cec5SDimitry Andric Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name,
940b57cec5SDimitry Andric uint32_t Size) {
950b57cec5SDimitry Andric auto ExpectedStream = Msf->addStream(Size);
960b57cec5SDimitry Andric if (ExpectedStream)
970b57cec5SDimitry Andric NamedStreams.set(Name, *ExpectedStream);
980b57cec5SDimitry Andric return ExpectedStream;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric
addNamedStream(StringRef Name,StringRef Data)1010b57cec5SDimitry Andric Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) {
1020b57cec5SDimitry Andric Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size());
1030b57cec5SDimitry Andric if (!ExpectedIndex)
1040b57cec5SDimitry Andric return ExpectedIndex.takeError();
1050b57cec5SDimitry Andric assert(NamedStreamData.count(*ExpectedIndex) == 0);
1065ffd83dbSDimitry Andric NamedStreamData[*ExpectedIndex] = std::string(Data);
1070b57cec5SDimitry Andric return Error::success();
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric
addInjectedSource(StringRef Name,std::unique_ptr<MemoryBuffer> Buffer)1100b57cec5SDimitry Andric void PDBFileBuilder::addInjectedSource(StringRef Name,
1110b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> Buffer) {
1120b57cec5SDimitry Andric // Stream names must be exact matches, since they get looked up in a hash
1130b57cec5SDimitry Andric // table and the hash value is dependent on the exact contents of the string.
1140b57cec5SDimitry Andric // link.exe lowercases a path and converts / to \, so we must do the same.
1150b57cec5SDimitry Andric SmallString<64> VName;
116349cc55cSDimitry Andric sys::path::native(Name.lower(), VName, sys::path::Style::windows_backslash);
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric uint32_t NI = getStringTableBuilder().insert(Name);
1190b57cec5SDimitry Andric uint32_t VNI = getStringTableBuilder().insert(VName);
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric InjectedSourceDescriptor Desc;
1220b57cec5SDimitry Andric Desc.Content = std::move(Buffer);
1230b57cec5SDimitry Andric Desc.NameIndex = NI;
1240b57cec5SDimitry Andric Desc.VNameIndex = VNI;
1250b57cec5SDimitry Andric Desc.StreamName = "/src/files/";
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric Desc.StreamName += VName;
1280b57cec5SDimitry Andric
1290b57cec5SDimitry Andric InjectedSources.push_back(std::move(Desc));
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric
finalizeMsfLayout()1320b57cec5SDimitry Andric Error PDBFileBuilder::finalizeMsfLayout() {
133*5f757f3fSDimitry Andric llvm::TimeTraceScope timeScope("MSF layout");
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric if (Ipi && Ipi->getRecordCount() > 0) {
1360b57cec5SDimitry Andric // In theory newer PDBs always have an ID stream, but by saying that we're
1370b57cec5SDimitry Andric // only going to *really* have an ID stream if there is at least one ID
1380b57cec5SDimitry Andric // record, we leave open the opportunity to test older PDBs such as those
1390b57cec5SDimitry Andric // that don't have an ID stream.
1400b57cec5SDimitry Andric auto &Info = getInfoBuilder();
1410b57cec5SDimitry Andric Info.addFeature(PdbRaw_FeatureSig::VC140);
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric
1440b57cec5SDimitry Andric uint32_t StringsLen = Strings.calculateSerializedSize();
1450b57cec5SDimitry Andric
1460b57cec5SDimitry Andric Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0);
1470b57cec5SDimitry Andric if (!SN)
1480b57cec5SDimitry Andric return SN.takeError();
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric if (Gsi) {
1510b57cec5SDimitry Andric if (auto EC = Gsi->finalizeMsfLayout())
1520b57cec5SDimitry Andric return EC;
1530b57cec5SDimitry Andric if (Dbi) {
1540b57cec5SDimitry Andric Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
1550b57cec5SDimitry Andric Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
1565ffd83dbSDimitry Andric Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIndex());
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric if (Tpi) {
1600b57cec5SDimitry Andric if (auto EC = Tpi->finalizeMsfLayout())
1610b57cec5SDimitry Andric return EC;
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric if (Dbi) {
1640b57cec5SDimitry Andric if (auto EC = Dbi->finalizeMsfLayout())
1650b57cec5SDimitry Andric return EC;
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric SN = allocateNamedStream("/names", StringsLen);
1680b57cec5SDimitry Andric if (!SN)
1690b57cec5SDimitry Andric return SN.takeError();
1700b57cec5SDimitry Andric
1710b57cec5SDimitry Andric if (Ipi) {
1720b57cec5SDimitry Andric if (auto EC = Ipi->finalizeMsfLayout())
1730b57cec5SDimitry Andric return EC;
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric
1760b57cec5SDimitry Andric // Do this last, since it relies on the named stream map being complete, and
1770b57cec5SDimitry Andric // that can be updated by previous steps in the finalization.
1780b57cec5SDimitry Andric if (Info) {
1790b57cec5SDimitry Andric if (auto EC = Info->finalizeMsfLayout())
1800b57cec5SDimitry Andric return EC;
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric
1830b57cec5SDimitry Andric if (!InjectedSources.empty()) {
1840b57cec5SDimitry Andric for (const auto &IS : InjectedSources) {
1850b57cec5SDimitry Andric JamCRC CRC(0);
1868bcb0991SDimitry Andric CRC.update(arrayRefFromStringRef(IS.Content->getBuffer()));
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric SrcHeaderBlockEntry Entry;
1890b57cec5SDimitry Andric ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry));
1900b57cec5SDimitry Andric Entry.Size = sizeof(SrcHeaderBlockEntry);
1910b57cec5SDimitry Andric Entry.FileSize = IS.Content->getBufferSize();
1920b57cec5SDimitry Andric Entry.FileNI = IS.NameIndex;
1930b57cec5SDimitry Andric Entry.VFileNI = IS.VNameIndex;
1940b57cec5SDimitry Andric Entry.ObjNI = 1;
1950b57cec5SDimitry Andric Entry.IsVirtual = 0;
1960b57cec5SDimitry Andric Entry.Version =
1970b57cec5SDimitry Andric static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
1980b57cec5SDimitry Andric Entry.CRC = CRC.getCRC();
1990b57cec5SDimitry Andric StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex);
2000b57cec5SDimitry Andric InjectedSourceTable.set_as(VName, std::move(Entry),
2010b57cec5SDimitry Andric InjectedSourceHashTraits);
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric
2040b57cec5SDimitry Andric uint32_t SrcHeaderBlockSize =
2050b57cec5SDimitry Andric sizeof(SrcHeaderBlockHeader) +
2060b57cec5SDimitry Andric InjectedSourceTable.calculateSerializedLength();
2070b57cec5SDimitry Andric SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize);
2080b57cec5SDimitry Andric if (!SN)
2090b57cec5SDimitry Andric return SN.takeError();
2100b57cec5SDimitry Andric for (const auto &IS : InjectedSources) {
2110b57cec5SDimitry Andric SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize());
2120b57cec5SDimitry Andric if (!SN)
2130b57cec5SDimitry Andric return SN.takeError();
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric // Do this last, since it relies on the named stream map being complete, and
2180b57cec5SDimitry Andric // that can be updated by previous steps in the finalization.
2190b57cec5SDimitry Andric if (Info) {
2200b57cec5SDimitry Andric if (auto EC = Info->finalizeMsfLayout())
2210b57cec5SDimitry Andric return EC;
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric
2240b57cec5SDimitry Andric return Error::success();
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric
getNamedStreamIndex(StringRef Name) const2270b57cec5SDimitry Andric Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
2280b57cec5SDimitry Andric uint32_t SN = 0;
2290b57cec5SDimitry Andric if (!NamedStreams.get(Name, SN))
2300b57cec5SDimitry Andric return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
2310b57cec5SDimitry Andric return SN;
2320b57cec5SDimitry Andric }
2330b57cec5SDimitry Andric
commitSrcHeaderBlock(WritableBinaryStream & MsfBuffer,const msf::MSFLayout & Layout)2340b57cec5SDimitry Andric void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
2350b57cec5SDimitry Andric const msf::MSFLayout &Layout) {
2360b57cec5SDimitry Andric assert(!InjectedSourceTable.empty());
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock"));
2390b57cec5SDimitry Andric auto Stream = WritableMappedBlockStream::createIndexedStream(
2400b57cec5SDimitry Andric Layout, MsfBuffer, SN, Allocator);
2410b57cec5SDimitry Andric BinaryStreamWriter Writer(*Stream);
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric SrcHeaderBlockHeader Header;
2440b57cec5SDimitry Andric ::memset(&Header, 0, sizeof(Header));
2450b57cec5SDimitry Andric Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
2460b57cec5SDimitry Andric Header.Size = Writer.bytesRemaining();
2470b57cec5SDimitry Andric
2480b57cec5SDimitry Andric cantFail(Writer.writeObject(Header));
2490b57cec5SDimitry Andric cantFail(InjectedSourceTable.commit(Writer));
2500b57cec5SDimitry Andric
2510b57cec5SDimitry Andric assert(Writer.bytesRemaining() == 0);
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric
commitInjectedSources(WritableBinaryStream & MsfBuffer,const msf::MSFLayout & Layout)2540b57cec5SDimitry Andric void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
2550b57cec5SDimitry Andric const msf::MSFLayout &Layout) {
2560b57cec5SDimitry Andric if (InjectedSourceTable.empty())
2570b57cec5SDimitry Andric return;
2580b57cec5SDimitry Andric
259*5f757f3fSDimitry Andric llvm::TimeTraceScope timeScope("Commit injected sources");
2600b57cec5SDimitry Andric commitSrcHeaderBlock(MsfBuffer, Layout);
2610b57cec5SDimitry Andric
2620b57cec5SDimitry Andric for (const auto &IS : InjectedSources) {
2630b57cec5SDimitry Andric uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName));
2640b57cec5SDimitry Andric
2650b57cec5SDimitry Andric auto SourceStream = WritableMappedBlockStream::createIndexedStream(
2660b57cec5SDimitry Andric Layout, MsfBuffer, SN, Allocator);
2670b57cec5SDimitry Andric BinaryStreamWriter SourceWriter(*SourceStream);
2680b57cec5SDimitry Andric assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize());
2690b57cec5SDimitry Andric cantFail(SourceWriter.writeBytes(
2700b57cec5SDimitry Andric arrayRefFromStringRef(IS.Content->getBuffer())));
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric }
2730b57cec5SDimitry Andric
commit(StringRef Filename,codeview::GUID * Guid)2740b57cec5SDimitry Andric Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) {
2750b57cec5SDimitry Andric assert(!Filename.empty());
2760b57cec5SDimitry Andric if (auto EC = finalizeMsfLayout())
2770b57cec5SDimitry Andric return EC;
2780b57cec5SDimitry Andric
2790b57cec5SDimitry Andric MSFLayout Layout;
2800b57cec5SDimitry Andric Expected<FileBufferByteStream> ExpectedMsfBuffer =
2810b57cec5SDimitry Andric Msf->commit(Filename, Layout);
2820b57cec5SDimitry Andric if (!ExpectedMsfBuffer)
2830b57cec5SDimitry Andric return ExpectedMsfBuffer.takeError();
2840b57cec5SDimitry Andric FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer);
2850b57cec5SDimitry Andric
2860b57cec5SDimitry Andric auto ExpectedSN = getNamedStreamIndex("/names");
2870b57cec5SDimitry Andric if (!ExpectedSN)
2880b57cec5SDimitry Andric return ExpectedSN.takeError();
2890b57cec5SDimitry Andric
2900b57cec5SDimitry Andric auto NS = WritableMappedBlockStream::createIndexedStream(
2910b57cec5SDimitry Andric Layout, Buffer, *ExpectedSN, Allocator);
2920b57cec5SDimitry Andric BinaryStreamWriter NSWriter(*NS);
2930b57cec5SDimitry Andric if (auto EC = Strings.commit(NSWriter))
2940b57cec5SDimitry Andric return EC;
2950b57cec5SDimitry Andric
296*5f757f3fSDimitry Andric {
297*5f757f3fSDimitry Andric llvm::TimeTraceScope timeScope("Named stream data");
2980b57cec5SDimitry Andric for (const auto &NSE : NamedStreamData) {
2990b57cec5SDimitry Andric if (NSE.second.empty())
3000b57cec5SDimitry Andric continue;
3010b57cec5SDimitry Andric
3020b57cec5SDimitry Andric auto NS = WritableMappedBlockStream::createIndexedStream(
3030b57cec5SDimitry Andric Layout, Buffer, NSE.first, Allocator);
3040b57cec5SDimitry Andric BinaryStreamWriter NSW(*NS);
3050b57cec5SDimitry Andric if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
3060b57cec5SDimitry Andric return EC;
3070b57cec5SDimitry Andric }
308*5f757f3fSDimitry Andric }
3090b57cec5SDimitry Andric
3100b57cec5SDimitry Andric if (Info) {
3110b57cec5SDimitry Andric if (auto EC = Info->commit(Layout, Buffer))
3120b57cec5SDimitry Andric return EC;
3130b57cec5SDimitry Andric }
3140b57cec5SDimitry Andric
3150b57cec5SDimitry Andric if (Dbi) {
3160b57cec5SDimitry Andric if (auto EC = Dbi->commit(Layout, Buffer))
3170b57cec5SDimitry Andric return EC;
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric
3200b57cec5SDimitry Andric if (Tpi) {
3210b57cec5SDimitry Andric if (auto EC = Tpi->commit(Layout, Buffer))
3220b57cec5SDimitry Andric return EC;
3230b57cec5SDimitry Andric }
3240b57cec5SDimitry Andric
3250b57cec5SDimitry Andric if (Ipi) {
3260b57cec5SDimitry Andric if (auto EC = Ipi->commit(Layout, Buffer))
3270b57cec5SDimitry Andric return EC;
3280b57cec5SDimitry Andric }
3290b57cec5SDimitry Andric
3300b57cec5SDimitry Andric if (Gsi) {
3310b57cec5SDimitry Andric if (auto EC = Gsi->commit(Layout, Buffer))
3320b57cec5SDimitry Andric return EC;
3330b57cec5SDimitry Andric }
3340b57cec5SDimitry Andric
3350b57cec5SDimitry Andric auto InfoStreamBlocks = Layout.StreamMap[StreamPDB];
3360b57cec5SDimitry Andric assert(!InfoStreamBlocks.empty());
3370b57cec5SDimitry Andric uint64_t InfoStreamFileOffset =
3380b57cec5SDimitry Andric blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
3390b57cec5SDimitry Andric InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
3400b57cec5SDimitry Andric Buffer.getBufferStart() + InfoStreamFileOffset);
3410b57cec5SDimitry Andric
3420b57cec5SDimitry Andric commitInjectedSources(Buffer, Layout);
3430b57cec5SDimitry Andric
3440b57cec5SDimitry Andric // Set the build id at the very end, after every other byte of the PDB
3450b57cec5SDimitry Andric // has been written.
3460b57cec5SDimitry Andric if (Info->hashPDBContentsToGUID()) {
347*5f757f3fSDimitry Andric llvm::TimeTraceScope timeScope("Compute build ID");
348*5f757f3fSDimitry Andric
3490b57cec5SDimitry Andric // Compute a hash of all sections of the output file.
3500b57cec5SDimitry Andric uint64_t Digest =
35106c3fb27SDimitry Andric xxh3_64bits({Buffer.getBufferStart(), Buffer.getBufferEnd()});
3520b57cec5SDimitry Andric
3530b57cec5SDimitry Andric H->Age = 1;
3540b57cec5SDimitry Andric
3550b57cec5SDimitry Andric memcpy(H->Guid.Guid, &Digest, 8);
3560b57cec5SDimitry Andric // xxhash only gives us 8 bytes, so put some fixed data in the other half.
3570b57cec5SDimitry Andric memcpy(H->Guid.Guid + 8, "LLD PDB.", 8);
3580b57cec5SDimitry Andric
3590b57cec5SDimitry Andric // Put the hash in the Signature field too.
3600b57cec5SDimitry Andric H->Signature = static_cast<uint32_t>(Digest);
3610b57cec5SDimitry Andric
3620b57cec5SDimitry Andric // Return GUID to caller.
3630b57cec5SDimitry Andric memcpy(Guid, H->Guid.Guid, 16);
3640b57cec5SDimitry Andric } else {
3650b57cec5SDimitry Andric H->Age = Info->getAge();
3660b57cec5SDimitry Andric H->Guid = Info->getGuid();
367bdd1243dSDimitry Andric std::optional<uint32_t> Sig = Info->getSignature();
36881ad6265SDimitry Andric H->Signature = Sig ? *Sig : time(nullptr);
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric
3710b57cec5SDimitry Andric return Buffer.commit();
3720b57cec5SDimitry Andric }
373