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