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