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