1317017Sdim//===- PDBFileBuilder.cpp - PDB File Creation -------------------*- C++ -*-===// 2317017Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6317017Sdim// 7317017Sdim//===----------------------------------------------------------------------===// 8317017Sdim 9317017Sdim#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" 10317017Sdim 11317017Sdim#include "llvm/ADT/BitVector.h" 12317017Sdim 13317017Sdim#include "llvm/DebugInfo/MSF/MSFBuilder.h" 14317017Sdim#include "llvm/DebugInfo/PDB/Native/DbiStream.h" 15317017Sdim#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" 16327952Sdim#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" 17317017Sdim#include "llvm/DebugInfo/PDB/Native/InfoStream.h" 18317017Sdim#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" 19317778Sdim#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" 20317017Sdim#include "llvm/DebugInfo/PDB/Native/RawError.h" 21317017Sdim#include "llvm/DebugInfo/PDB/Native/TpiStream.h" 22317017Sdim#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" 23317017Sdim#include "llvm/Support/BinaryStream.h" 24317017Sdim#include "llvm/Support/BinaryStreamWriter.h" 25360784Sdim#include "llvm/Support/CRC.h" 26341825Sdim#include "llvm/Support/Path.h" 27344779Sdim#include "llvm/Support/xxhash.h" 28317017Sdim 29317017Sdimusing namespace llvm; 30317017Sdimusing namespace llvm::codeview; 31317017Sdimusing namespace llvm::msf; 32317017Sdimusing namespace llvm::pdb; 33317017Sdimusing namespace llvm::support; 34317017Sdim 35317017SdimPDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator) 36341825Sdim : Allocator(Allocator), InjectedSourceHashTraits(Strings), 37353358Sdim InjectedSourceTable(2) {} 38317017Sdim 39320970SdimPDBFileBuilder::~PDBFileBuilder() {} 40320970Sdim 41317017SdimError PDBFileBuilder::initialize(uint32_t BlockSize) { 42317017Sdim auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize); 43317017Sdim if (!ExpectedMsf) 44317017Sdim return ExpectedMsf.takeError(); 45360784Sdim Msf = std::make_unique<MSFBuilder>(std::move(*ExpectedMsf)); 46317017Sdim return Error::success(); 47317017Sdim} 48317017Sdim 49317017SdimMSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } 50317017Sdim 51317017SdimInfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { 52317017Sdim if (!Info) 53360784Sdim Info = std::make_unique<InfoStreamBuilder>(*Msf, NamedStreams); 54317017Sdim return *Info; 55317017Sdim} 56317017Sdim 57317017SdimDbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { 58317017Sdim if (!Dbi) 59360784Sdim Dbi = std::make_unique<DbiStreamBuilder>(*Msf); 60317017Sdim return *Dbi; 61317017Sdim} 62317017Sdim 63317017SdimTpiStreamBuilder &PDBFileBuilder::getTpiBuilder() { 64317017Sdim if (!Tpi) 65360784Sdim Tpi = std::make_unique<TpiStreamBuilder>(*Msf, StreamTPI); 66317017Sdim return *Tpi; 67317017Sdim} 68317017Sdim 69317017SdimTpiStreamBuilder &PDBFileBuilder::getIpiBuilder() { 70317017Sdim if (!Ipi) 71360784Sdim Ipi = std::make_unique<TpiStreamBuilder>(*Msf, StreamIPI); 72317017Sdim return *Ipi; 73317017Sdim} 74317017Sdim 75317778SdimPDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() { 76317778Sdim return Strings; 77317778Sdim} 78317017Sdim 79327952SdimGSIStreamBuilder &PDBFileBuilder::getGsiBuilder() { 80327952Sdim if (!Gsi) 81360784Sdim Gsi = std::make_unique<GSIStreamBuilder>(*Msf); 82327952Sdim return *Gsi; 83320970Sdim} 84320970Sdim 85341825SdimExpected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name, 86341825Sdim uint32_t Size) { 87317017Sdim auto ExpectedStream = Msf->addStream(Size); 88341825Sdim if (ExpectedStream) 89341825Sdim NamedStreams.set(Name, *ExpectedStream); 90341825Sdim return ExpectedStream; 91341825Sdim} 92341825Sdim 93341825SdimError PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) { 94341825Sdim Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size()); 95341825Sdim if (!ExpectedIndex) 96341825Sdim return ExpectedIndex.takeError(); 97341825Sdim assert(NamedStreamData.count(*ExpectedIndex) == 0); 98341825Sdim NamedStreamData[*ExpectedIndex] = Data; 99317017Sdim return Error::success(); 100317017Sdim} 101317017Sdim 102341825Sdimvoid PDBFileBuilder::addInjectedSource(StringRef Name, 103341825Sdim std::unique_ptr<MemoryBuffer> Buffer) { 104341825Sdim // Stream names must be exact matches, since they get looked up in a hash 105341825Sdim // table and the hash value is dependent on the exact contents of the string. 106341825Sdim // link.exe lowercases a path and converts / to \, so we must do the same. 107341825Sdim SmallString<64> VName; 108341825Sdim sys::path::native(Name.lower(), VName); 109320041Sdim 110341825Sdim uint32_t NI = getStringTableBuilder().insert(Name); 111341825Sdim uint32_t VNI = getStringTableBuilder().insert(VName); 112341825Sdim 113341825Sdim InjectedSourceDescriptor Desc; 114341825Sdim Desc.Content = std::move(Buffer); 115341825Sdim Desc.NameIndex = NI; 116341825Sdim Desc.VNameIndex = VNI; 117341825Sdim Desc.StreamName = "/src/files/"; 118341825Sdim 119341825Sdim Desc.StreamName += VName; 120341825Sdim 121341825Sdim InjectedSources.push_back(std::move(Desc)); 122341825Sdim} 123341825Sdim 124341825SdimError PDBFileBuilder::finalizeMsfLayout() { 125341825Sdim 126320041Sdim if (Ipi && Ipi->getRecordCount() > 0) { 127320041Sdim // In theory newer PDBs always have an ID stream, but by saying that we're 128320041Sdim // only going to *really* have an ID stream if there is at least one ID 129320041Sdim // record, we leave open the opportunity to test older PDBs such as those 130320041Sdim // that don't have an ID stream. 131320041Sdim auto &Info = getInfoBuilder(); 132320041Sdim Info.addFeature(PdbRaw_FeatureSig::VC140); 133320041Sdim } 134320041Sdim 135317778Sdim uint32_t StringsLen = Strings.calculateSerializedSize(); 136317017Sdim 137341825Sdim Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0); 138341825Sdim if (!SN) 139341825Sdim return SN.takeError(); 140317017Sdim 141341825Sdim if (Gsi) { 142341825Sdim if (auto EC = Gsi->finalizeMsfLayout()) 143341825Sdim return EC; 144341825Sdim if (Dbi) { 145341825Sdim Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); 146341825Sdim Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); 147341825Sdim Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx()); 148341825Sdim } 149317017Sdim } 150341825Sdim if (Tpi) { 151341825Sdim if (auto EC = Tpi->finalizeMsfLayout()) 152341825Sdim return EC; 153341825Sdim } 154317017Sdim if (Dbi) { 155317017Sdim if (auto EC = Dbi->finalizeMsfLayout()) 156341825Sdim return EC; 157317017Sdim } 158341825Sdim SN = allocateNamedStream("/names", StringsLen); 159341825Sdim if (!SN) 160341825Sdim return SN.takeError(); 161341825Sdim 162317017Sdim if (Ipi) { 163317017Sdim if (auto EC = Ipi->finalizeMsfLayout()) 164341825Sdim return EC; 165317017Sdim } 166341825Sdim 167341825Sdim // Do this last, since it relies on the named stream map being complete, and 168341825Sdim // that can be updated by previous steps in the finalization. 169341825Sdim if (Info) { 170341825Sdim if (auto EC = Info->finalizeMsfLayout()) 171341825Sdim return EC; 172341825Sdim } 173341825Sdim 174341825Sdim if (!InjectedSources.empty()) { 175341825Sdim for (const auto &IS : InjectedSources) { 176341825Sdim JamCRC CRC(0); 177360784Sdim CRC.update(arrayRefFromStringRef(IS.Content->getBuffer())); 178341825Sdim 179341825Sdim SrcHeaderBlockEntry Entry; 180341825Sdim ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry)); 181341825Sdim Entry.Size = sizeof(SrcHeaderBlockEntry); 182341825Sdim Entry.FileSize = IS.Content->getBufferSize(); 183341825Sdim Entry.FileNI = IS.NameIndex; 184341825Sdim Entry.VFileNI = IS.VNameIndex; 185341825Sdim Entry.ObjNI = 1; 186341825Sdim Entry.IsVirtual = 0; 187341825Sdim Entry.Version = 188341825Sdim static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); 189341825Sdim Entry.CRC = CRC.getCRC(); 190341825Sdim StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex); 191353358Sdim InjectedSourceTable.set_as(VName, std::move(Entry), 192353358Sdim InjectedSourceHashTraits); 193320970Sdim } 194341825Sdim 195341825Sdim uint32_t SrcHeaderBlockSize = 196341825Sdim sizeof(SrcHeaderBlockHeader) + 197341825Sdim InjectedSourceTable.calculateSerializedLength(); 198341825Sdim SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize); 199341825Sdim if (!SN) 200341825Sdim return SN.takeError(); 201341825Sdim for (const auto &IS : InjectedSources) { 202341825Sdim SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize()); 203341825Sdim if (!SN) 204341825Sdim return SN.takeError(); 205341825Sdim } 206320970Sdim } 207317017Sdim 208341825Sdim // Do this last, since it relies on the named stream map being complete, and 209341825Sdim // that can be updated by previous steps in the finalization. 210341825Sdim if (Info) { 211341825Sdim if (auto EC = Info->finalizeMsfLayout()) 212341825Sdim return EC; 213341825Sdim } 214341825Sdim 215341825Sdim return Error::success(); 216317017Sdim} 217317017Sdim 218317778SdimExpected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { 219317778Sdim uint32_t SN = 0; 220317778Sdim if (!NamedStreams.get(Name, SN)) 221317778Sdim return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); 222317778Sdim return SN; 223317778Sdim} 224317778Sdim 225341825Sdimvoid PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer, 226341825Sdim const msf::MSFLayout &Layout) { 227341825Sdim assert(!InjectedSourceTable.empty()); 228327952Sdim 229341825Sdim uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock")); 230341825Sdim auto Stream = WritableMappedBlockStream::createIndexedStream( 231341825Sdim Layout, MsfBuffer, SN, Allocator); 232341825Sdim BinaryStreamWriter Writer(*Stream); 233327952Sdim 234341825Sdim SrcHeaderBlockHeader Header; 235341825Sdim ::memset(&Header, 0, sizeof(Header)); 236341825Sdim Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); 237341825Sdim Header.Size = Writer.bytesRemaining(); 238327952Sdim 239341825Sdim cantFail(Writer.writeObject(Header)); 240341825Sdim cantFail(InjectedSourceTable.commit(Writer)); 241317017Sdim 242341825Sdim assert(Writer.bytesRemaining() == 0); 243341825Sdim} 244317017Sdim 245341825Sdimvoid PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer, 246341825Sdim const msf::MSFLayout &Layout) { 247341825Sdim if (InjectedSourceTable.empty()) 248341825Sdim return; 249327952Sdim 250341825Sdim commitSrcHeaderBlock(MsfBuffer, Layout); 251327952Sdim 252341825Sdim for (const auto &IS : InjectedSources) { 253341825Sdim uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName)); 254317017Sdim 255341825Sdim auto SourceStream = WritableMappedBlockStream::createIndexedStream( 256341825Sdim Layout, MsfBuffer, SN, Allocator); 257341825Sdim BinaryStreamWriter SourceWriter(*SourceStream); 258341825Sdim assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize()); 259341825Sdim cantFail(SourceWriter.writeBytes( 260341825Sdim arrayRefFromStringRef(IS.Content->getBuffer()))); 261341825Sdim } 262341825Sdim} 263317017Sdim 264344779SdimError PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) { 265341825Sdim assert(!Filename.empty()); 266341825Sdim if (auto EC = finalizeMsfLayout()) 267317017Sdim return EC; 268317017Sdim 269341825Sdim MSFLayout Layout; 270344779Sdim Expected<FileBufferByteStream> ExpectedMsfBuffer = 271344779Sdim Msf->commit(Filename, Layout); 272341825Sdim if (!ExpectedMsfBuffer) 273341825Sdim return ExpectedMsfBuffer.takeError(); 274341825Sdim FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer); 275317017Sdim 276317778Sdim auto ExpectedSN = getNamedStreamIndex("/names"); 277317778Sdim if (!ExpectedSN) 278317778Sdim return ExpectedSN.takeError(); 279317017Sdim 280319547Sdim auto NS = WritableMappedBlockStream::createIndexedStream( 281319547Sdim Layout, Buffer, *ExpectedSN, Allocator); 282317017Sdim BinaryStreamWriter NSWriter(*NS); 283317017Sdim if (auto EC = Strings.commit(NSWriter)) 284317017Sdim return EC; 285317017Sdim 286341825Sdim for (const auto &NSE : NamedStreamData) { 287341825Sdim if (NSE.second.empty()) 288341825Sdim continue; 289341825Sdim 290341825Sdim auto NS = WritableMappedBlockStream::createIndexedStream( 291341825Sdim Layout, Buffer, NSE.first, Allocator); 292341825Sdim BinaryStreamWriter NSW(*NS); 293341825Sdim if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second))) 294341825Sdim return EC; 295341825Sdim } 296341825Sdim 297317017Sdim if (Info) { 298317017Sdim if (auto EC = Info->commit(Layout, Buffer)) 299317017Sdim return EC; 300317017Sdim } 301317017Sdim 302317017Sdim if (Dbi) { 303317017Sdim if (auto EC = Dbi->commit(Layout, Buffer)) 304317017Sdim return EC; 305317017Sdim } 306317017Sdim 307317017Sdim if (Tpi) { 308317017Sdim if (auto EC = Tpi->commit(Layout, Buffer)) 309317017Sdim return EC; 310317017Sdim } 311317017Sdim 312317017Sdim if (Ipi) { 313317017Sdim if (auto EC = Ipi->commit(Layout, Buffer)) 314317017Sdim return EC; 315317017Sdim } 316317017Sdim 317327952Sdim if (Gsi) { 318327952Sdim if (auto EC = Gsi->commit(Layout, Buffer)) 319320970Sdim return EC; 320320970Sdim } 321320970Sdim 322341825Sdim auto InfoStreamBlocks = Layout.StreamMap[StreamPDB]; 323341825Sdim assert(!InfoStreamBlocks.empty()); 324341825Sdim uint64_t InfoStreamFileOffset = 325341825Sdim blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize); 326341825Sdim InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>( 327341825Sdim Buffer.getBufferStart() + InfoStreamFileOffset); 328341825Sdim 329341825Sdim commitInjectedSources(Buffer, Layout); 330341825Sdim 331341825Sdim // Set the build id at the very end, after every other byte of the PDB 332341825Sdim // has been written. 333344779Sdim if (Info->hashPDBContentsToGUID()) { 334344779Sdim // Compute a hash of all sections of the output file. 335344779Sdim uint64_t Digest = 336344779Sdim xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()}); 337341825Sdim 338344779Sdim H->Age = 1; 339344779Sdim 340344779Sdim memcpy(H->Guid.Guid, &Digest, 8); 341344779Sdim // xxhash only gives us 8 bytes, so put some fixed data in the other half. 342344779Sdim memcpy(H->Guid.Guid + 8, "LLD PDB.", 8); 343344779Sdim 344344779Sdim // Put the hash in the Signature field too. 345344779Sdim H->Signature = static_cast<uint32_t>(Digest); 346344779Sdim 347344779Sdim // Return GUID to caller. 348344779Sdim memcpy(Guid, H->Guid.Guid, 16); 349344779Sdim } else { 350344779Sdim H->Age = Info->getAge(); 351344779Sdim H->Guid = Info->getGuid(); 352344779Sdim Optional<uint32_t> Sig = Info->getSignature(); 353344779Sdim H->Signature = Sig.hasValue() ? *Sig : time(nullptr); 354344779Sdim } 355344779Sdim 356317017Sdim return Buffer.commit(); 357317017Sdim} 358