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