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/CodeView.h" 13 #include "llvm/DebugInfo/CodeView/GUID.h" 14 #include "llvm/DebugInfo/MSF/MSFBuilder.h" 15 #include "llvm/DebugInfo/MSF/MSFCommon.h" 16 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 17 #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" 18 #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" 19 #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" 20 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" 21 #include "llvm/DebugInfo/PDB/Native/RawConstants.h" 22 #include "llvm/DebugInfo/PDB/Native/RawError.h" 23 #include "llvm/DebugInfo/PDB/Native/RawTypes.h" 24 #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" 25 #include "llvm/Support/BinaryStreamWriter.h" 26 #include "llvm/Support/CRC.h" 27 #include "llvm/Support/Path.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 133 if (Ipi && Ipi->getRecordCount() > 0) { 134 // In theory newer PDBs always have an ID stream, but by saying that we're 135 // only going to *really* have an ID stream if there is at least one ID 136 // record, we leave open the opportunity to test older PDBs such as those 137 // that don't have an ID stream. 138 auto &Info = getInfoBuilder(); 139 Info.addFeature(PdbRaw_FeatureSig::VC140); 140 } 141 142 uint32_t StringsLen = Strings.calculateSerializedSize(); 143 144 Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0); 145 if (!SN) 146 return SN.takeError(); 147 148 if (Gsi) { 149 if (auto EC = Gsi->finalizeMsfLayout()) 150 return EC; 151 if (Dbi) { 152 Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); 153 Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); 154 Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIndex()); 155 } 156 } 157 if (Tpi) { 158 if (auto EC = Tpi->finalizeMsfLayout()) 159 return EC; 160 } 161 if (Dbi) { 162 if (auto EC = Dbi->finalizeMsfLayout()) 163 return EC; 164 } 165 SN = allocateNamedStream("/names", StringsLen); 166 if (!SN) 167 return SN.takeError(); 168 169 if (Ipi) { 170 if (auto EC = Ipi->finalizeMsfLayout()) 171 return EC; 172 } 173 174 // Do this last, since it relies on the named stream map being complete, and 175 // that can be updated by previous steps in the finalization. 176 if (Info) { 177 if (auto EC = Info->finalizeMsfLayout()) 178 return EC; 179 } 180 181 if (!InjectedSources.empty()) { 182 for (const auto &IS : InjectedSources) { 183 JamCRC CRC(0); 184 CRC.update(arrayRefFromStringRef(IS.Content->getBuffer())); 185 186 SrcHeaderBlockEntry Entry; 187 ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry)); 188 Entry.Size = sizeof(SrcHeaderBlockEntry); 189 Entry.FileSize = IS.Content->getBufferSize(); 190 Entry.FileNI = IS.NameIndex; 191 Entry.VFileNI = IS.VNameIndex; 192 Entry.ObjNI = 1; 193 Entry.IsVirtual = 0; 194 Entry.Version = 195 static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); 196 Entry.CRC = CRC.getCRC(); 197 StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex); 198 InjectedSourceTable.set_as(VName, std::move(Entry), 199 InjectedSourceHashTraits); 200 } 201 202 uint32_t SrcHeaderBlockSize = 203 sizeof(SrcHeaderBlockHeader) + 204 InjectedSourceTable.calculateSerializedLength(); 205 SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize); 206 if (!SN) 207 return SN.takeError(); 208 for (const auto &IS : InjectedSources) { 209 SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize()); 210 if (!SN) 211 return SN.takeError(); 212 } 213 } 214 215 // Do this last, since it relies on the named stream map being complete, and 216 // that can be updated by previous steps in the finalization. 217 if (Info) { 218 if (auto EC = Info->finalizeMsfLayout()) 219 return EC; 220 } 221 222 return Error::success(); 223 } 224 225 Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { 226 uint32_t SN = 0; 227 if (!NamedStreams.get(Name, SN)) 228 return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); 229 return SN; 230 } 231 232 void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer, 233 const msf::MSFLayout &Layout) { 234 assert(!InjectedSourceTable.empty()); 235 236 uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock")); 237 auto Stream = WritableMappedBlockStream::createIndexedStream( 238 Layout, MsfBuffer, SN, Allocator); 239 BinaryStreamWriter Writer(*Stream); 240 241 SrcHeaderBlockHeader Header; 242 ::memset(&Header, 0, sizeof(Header)); 243 Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); 244 Header.Size = Writer.bytesRemaining(); 245 246 cantFail(Writer.writeObject(Header)); 247 cantFail(InjectedSourceTable.commit(Writer)); 248 249 assert(Writer.bytesRemaining() == 0); 250 } 251 252 void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer, 253 const msf::MSFLayout &Layout) { 254 if (InjectedSourceTable.empty()) 255 return; 256 257 commitSrcHeaderBlock(MsfBuffer, Layout); 258 259 for (const auto &IS : InjectedSources) { 260 uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName)); 261 262 auto SourceStream = WritableMappedBlockStream::createIndexedStream( 263 Layout, MsfBuffer, SN, Allocator); 264 BinaryStreamWriter SourceWriter(*SourceStream); 265 assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize()); 266 cantFail(SourceWriter.writeBytes( 267 arrayRefFromStringRef(IS.Content->getBuffer()))); 268 } 269 } 270 271 Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) { 272 assert(!Filename.empty()); 273 if (auto EC = finalizeMsfLayout()) 274 return EC; 275 276 MSFLayout Layout; 277 Expected<FileBufferByteStream> ExpectedMsfBuffer = 278 Msf->commit(Filename, Layout); 279 if (!ExpectedMsfBuffer) 280 return ExpectedMsfBuffer.takeError(); 281 FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer); 282 283 auto ExpectedSN = getNamedStreamIndex("/names"); 284 if (!ExpectedSN) 285 return ExpectedSN.takeError(); 286 287 auto NS = WritableMappedBlockStream::createIndexedStream( 288 Layout, Buffer, *ExpectedSN, Allocator); 289 BinaryStreamWriter NSWriter(*NS); 290 if (auto EC = Strings.commit(NSWriter)) 291 return EC; 292 293 for (const auto &NSE : NamedStreamData) { 294 if (NSE.second.empty()) 295 continue; 296 297 auto NS = WritableMappedBlockStream::createIndexedStream( 298 Layout, Buffer, NSE.first, Allocator); 299 BinaryStreamWriter NSW(*NS); 300 if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second))) 301 return EC; 302 } 303 304 if (Info) { 305 if (auto EC = Info->commit(Layout, Buffer)) 306 return EC; 307 } 308 309 if (Dbi) { 310 if (auto EC = Dbi->commit(Layout, Buffer)) 311 return EC; 312 } 313 314 if (Tpi) { 315 if (auto EC = Tpi->commit(Layout, Buffer)) 316 return EC; 317 } 318 319 if (Ipi) { 320 if (auto EC = Ipi->commit(Layout, Buffer)) 321 return EC; 322 } 323 324 if (Gsi) { 325 if (auto EC = Gsi->commit(Layout, Buffer)) 326 return EC; 327 } 328 329 auto InfoStreamBlocks = Layout.StreamMap[StreamPDB]; 330 assert(!InfoStreamBlocks.empty()); 331 uint64_t InfoStreamFileOffset = 332 blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize); 333 InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>( 334 Buffer.getBufferStart() + InfoStreamFileOffset); 335 336 commitInjectedSources(Buffer, Layout); 337 338 // Set the build id at the very end, after every other byte of the PDB 339 // has been written. 340 if (Info->hashPDBContentsToGUID()) { 341 // Compute a hash of all sections of the output file. 342 uint64_t Digest = 343 xxh3_64bits({Buffer.getBufferStart(), Buffer.getBufferEnd()}); 344 345 H->Age = 1; 346 347 memcpy(H->Guid.Guid, &Digest, 8); 348 // xxhash only gives us 8 bytes, so put some fixed data in the other half. 349 memcpy(H->Guid.Guid + 8, "LLD PDB.", 8); 350 351 // Put the hash in the Signature field too. 352 H->Signature = static_cast<uint32_t>(Digest); 353 354 // Return GUID to caller. 355 memcpy(Guid, H->Guid.Guid, 16); 356 } else { 357 H->Age = Info->getAge(); 358 H->Guid = Info->getGuid(); 359 std::optional<uint32_t> Sig = Info->getSignature(); 360 H->Signature = Sig ? *Sig : time(nullptr); 361 } 362 363 return Buffer.commit(); 364 } 365