1 //===- PDBFileBuilder.cpp - PDB File Creation -------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" 10 #include "llvm/ADT/BitVector.h" 11 #include "llvm/DebugInfo/MSF/MSFBuilder.h" 12 #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 13 #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" 14 #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" 15 #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 16 #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" 17 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" 18 #include "llvm/DebugInfo/PDB/Native/RawError.h" 19 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 20 #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" 21 #include "llvm/Support/BinaryStream.h" 22 #include "llvm/Support/BinaryStreamWriter.h" 23 #include "llvm/Support/CRC.h" 24 #include "llvm/Support/Chrono.h" 25 #include "llvm/Support/Path.h" 26 #include "llvm/Support/xxhash.h" 27 28 using namespace llvm; 29 using namespace llvm::codeview; 30 using namespace llvm::msf; 31 using namespace llvm::pdb; 32 using namespace llvm::support; 33 34 PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator) 35 : Allocator(Allocator), InjectedSourceHashTraits(Strings), 36 InjectedSourceTable(2) {} 37 38 PDBFileBuilder::~PDBFileBuilder() {} 39 40 Error PDBFileBuilder::initialize(uint32_t BlockSize) { 41 auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize); 42 if (!ExpectedMsf) 43 return ExpectedMsf.takeError(); 44 Msf = std::make_unique<MSFBuilder>(std::move(*ExpectedMsf)); 45 return Error::success(); 46 } 47 48 MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } 49 50 InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { 51 if (!Info) 52 Info = std::make_unique<InfoStreamBuilder>(*Msf, NamedStreams); 53 return *Info; 54 } 55 56 DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { 57 if (!Dbi) 58 Dbi = std::make_unique<DbiStreamBuilder>(*Msf); 59 return *Dbi; 60 } 61 62 TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() { 63 if (!Tpi) 64 Tpi = std::make_unique<TpiStreamBuilder>(*Msf, StreamTPI); 65 return *Tpi; 66 } 67 68 TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() { 69 if (!Ipi) 70 Ipi = std::make_unique<TpiStreamBuilder>(*Msf, StreamIPI); 71 return *Ipi; 72 } 73 74 PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() { 75 return Strings; 76 } 77 78 GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() { 79 if (!Gsi) 80 Gsi = std::make_unique<GSIStreamBuilder>(*Msf); 81 return *Gsi; 82 } 83 84 Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name, 85 uint32_t Size) { 86 auto ExpectedStream = Msf->addStream(Size); 87 if (ExpectedStream) 88 NamedStreams.set(Name, *ExpectedStream); 89 return ExpectedStream; 90 } 91 92 Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) { 93 Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size()); 94 if (!ExpectedIndex) 95 return ExpectedIndex.takeError(); 96 assert(NamedStreamData.count(*ExpectedIndex) == 0); 97 NamedStreamData[*ExpectedIndex] = std::string(Data); 98 return Error::success(); 99 } 100 101 void PDBFileBuilder::addInjectedSource(StringRef Name, 102 std::unique_ptr<MemoryBuffer> Buffer) { 103 // Stream names must be exact matches, since they get looked up in a hash 104 // table and the hash value is dependent on the exact contents of the string. 105 // link.exe lowercases a path and converts / to \, so we must do the same. 106 SmallString<64> VName; 107 sys::path::native(Name.lower(), VName); 108 109 uint32_t NI = getStringTableBuilder().insert(Name); 110 uint32_t VNI = getStringTableBuilder().insert(VName); 111 112 InjectedSourceDescriptor Desc; 113 Desc.Content = std::move(Buffer); 114 Desc.NameIndex = NI; 115 Desc.VNameIndex = VNI; 116 Desc.StreamName = "/src/files/"; 117 118 Desc.StreamName += VName; 119 120 InjectedSources.push_back(std::move(Desc)); 121 } 122 123 Error PDBFileBuilder::finalizeMsfLayout() { 124 125 if (Ipi && Ipi->getRecordCount() > 0) { 126 // In theory newer PDBs always have an ID stream, but by saying that we're 127 // only going to *really* have an ID stream if there is at least one ID 128 // record, we leave open the opportunity to test older PDBs such as those 129 // that don't have an ID stream. 130 auto &Info = getInfoBuilder(); 131 Info.addFeature(PdbRaw_FeatureSig::VC140); 132 } 133 134 uint32_t StringsLen = Strings.calculateSerializedSize(); 135 136 Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0); 137 if (!SN) 138 return SN.takeError(); 139 140 if (Gsi) { 141 if (auto EC = Gsi->finalizeMsfLayout()) 142 return EC; 143 if (Dbi) { 144 Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); 145 Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); 146 Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIndex()); 147 } 148 } 149 if (Tpi) { 150 if (auto EC = Tpi->finalizeMsfLayout()) 151 return EC; 152 } 153 if (Dbi) { 154 if (auto EC = Dbi->finalizeMsfLayout()) 155 return EC; 156 } 157 SN = allocateNamedStream("/names", StringsLen); 158 if (!SN) 159 return SN.takeError(); 160 161 if (Ipi) { 162 if (auto EC = Ipi->finalizeMsfLayout()) 163 return EC; 164 } 165 166 // Do this last, since it relies on the named stream map being complete, and 167 // that can be updated by previous steps in the finalization. 168 if (Info) { 169 if (auto EC = Info->finalizeMsfLayout()) 170 return EC; 171 } 172 173 if (!InjectedSources.empty()) { 174 for (const auto &IS : InjectedSources) { 175 JamCRC CRC(0); 176 CRC.update(arrayRefFromStringRef(IS.Content->getBuffer())); 177 178 SrcHeaderBlockEntry Entry; 179 ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry)); 180 Entry.Size = sizeof(SrcHeaderBlockEntry); 181 Entry.FileSize = IS.Content->getBufferSize(); 182 Entry.FileNI = IS.NameIndex; 183 Entry.VFileNI = IS.VNameIndex; 184 Entry.ObjNI = 1; 185 Entry.IsVirtual = 0; 186 Entry.Version = 187 static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); 188 Entry.CRC = CRC.getCRC(); 189 StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex); 190 InjectedSourceTable.set_as(VName, std::move(Entry), 191 InjectedSourceHashTraits); 192 } 193 194 uint32_t SrcHeaderBlockSize = 195 sizeof(SrcHeaderBlockHeader) + 196 InjectedSourceTable.calculateSerializedLength(); 197 SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize); 198 if (!SN) 199 return SN.takeError(); 200 for (const auto &IS : InjectedSources) { 201 SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize()); 202 if (!SN) 203 return SN.takeError(); 204 } 205 } 206 207 // Do this last, since it relies on the named stream map being complete, and 208 // that can be updated by previous steps in the finalization. 209 if (Info) { 210 if (auto EC = Info->finalizeMsfLayout()) 211 return EC; 212 } 213 214 return Error::success(); 215 } 216 217 Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { 218 uint32_t SN = 0; 219 if (!NamedStreams.get(Name, SN)) 220 return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); 221 return SN; 222 } 223 224 void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer, 225 const msf::MSFLayout &Layout) { 226 assert(!InjectedSourceTable.empty()); 227 228 uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock")); 229 auto Stream = WritableMappedBlockStream::createIndexedStream( 230 Layout, MsfBuffer, SN, Allocator); 231 BinaryStreamWriter Writer(*Stream); 232 233 SrcHeaderBlockHeader Header; 234 ::memset(&Header, 0, sizeof(Header)); 235 Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); 236 Header.Size = Writer.bytesRemaining(); 237 238 cantFail(Writer.writeObject(Header)); 239 cantFail(InjectedSourceTable.commit(Writer)); 240 241 assert(Writer.bytesRemaining() == 0); 242 } 243 244 void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer, 245 const msf::MSFLayout &Layout) { 246 if (InjectedSourceTable.empty()) 247 return; 248 249 commitSrcHeaderBlock(MsfBuffer, Layout); 250 251 for (const auto &IS : InjectedSources) { 252 uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName)); 253 254 auto SourceStream = WritableMappedBlockStream::createIndexedStream( 255 Layout, MsfBuffer, SN, Allocator); 256 BinaryStreamWriter SourceWriter(*SourceStream); 257 assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize()); 258 cantFail(SourceWriter.writeBytes( 259 arrayRefFromStringRef(IS.Content->getBuffer()))); 260 } 261 } 262 263 Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) { 264 assert(!Filename.empty()); 265 if (auto EC = finalizeMsfLayout()) 266 return EC; 267 268 MSFLayout Layout; 269 Expected<FileBufferByteStream> ExpectedMsfBuffer = 270 Msf->commit(Filename, Layout); 271 if (!ExpectedMsfBuffer) 272 return ExpectedMsfBuffer.takeError(); 273 FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer); 274 275 auto ExpectedSN = getNamedStreamIndex("/names"); 276 if (!ExpectedSN) 277 return ExpectedSN.takeError(); 278 279 auto NS = WritableMappedBlockStream::createIndexedStream( 280 Layout, Buffer, *ExpectedSN, Allocator); 281 BinaryStreamWriter NSWriter(*NS); 282 if (auto EC = Strings.commit(NSWriter)) 283 return EC; 284 285 for (const auto &NSE : NamedStreamData) { 286 if (NSE.second.empty()) 287 continue; 288 289 auto NS = WritableMappedBlockStream::createIndexedStream( 290 Layout, Buffer, NSE.first, Allocator); 291 BinaryStreamWriter NSW(*NS); 292 if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second))) 293 return EC; 294 } 295 296 if (Info) { 297 if (auto EC = Info->commit(Layout, Buffer)) 298 return EC; 299 } 300 301 if (Dbi) { 302 if (auto EC = Dbi->commit(Layout, Buffer)) 303 return EC; 304 } 305 306 if (Tpi) { 307 if (auto EC = Tpi->commit(Layout, Buffer)) 308 return EC; 309 } 310 311 if (Ipi) { 312 if (auto EC = Ipi->commit(Layout, Buffer)) 313 return EC; 314 } 315 316 if (Gsi) { 317 if (auto EC = Gsi->commit(Layout, Buffer)) 318 return EC; 319 } 320 321 auto InfoStreamBlocks = Layout.StreamMap[StreamPDB]; 322 assert(!InfoStreamBlocks.empty()); 323 uint64_t InfoStreamFileOffset = 324 blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize); 325 InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>( 326 Buffer.getBufferStart() + InfoStreamFileOffset); 327 328 commitInjectedSources(Buffer, Layout); 329 330 // Set the build id at the very end, after every other byte of the PDB 331 // has been written. 332 if (Info->hashPDBContentsToGUID()) { 333 // Compute a hash of all sections of the output file. 334 uint64_t Digest = 335 xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()}); 336 337 H->Age = 1; 338 339 memcpy(H->Guid.Guid, &Digest, 8); 340 // xxhash only gives us 8 bytes, so put some fixed data in the other half. 341 memcpy(H->Guid.Guid + 8, "LLD PDB.", 8); 342 343 // Put the hash in the Signature field too. 344 H->Signature = static_cast<uint32_t>(Digest); 345 346 // Return GUID to caller. 347 memcpy(Guid, H->Guid.Guid, 16); 348 } else { 349 H->Age = Info->getAge(); 350 H->Guid = Info->getGuid(); 351 Optional<uint32_t> Sig = Info->getSignature(); 352 H->Signature = Sig.hasValue() ? *Sig : time(nullptr); 353 } 354 355 return Buffer.commit(); 356 } 357