1 //===- DbiStreamBuilder.cpp - PDB Dbi Stream 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/DbiStreamBuilder.h" 10 11 #include "llvm/ADT/ArrayRef.h" 12 #include "llvm/BinaryFormat/COFF.h" 13 #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" 14 #include "llvm/DebugInfo/MSF/MSFBuilder.h" 15 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 16 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" 17 #include "llvm/DebugInfo/PDB/Native/RawError.h" 18 #include "llvm/Object/COFF.h" 19 #include "llvm/Support/BinaryStreamWriter.h" 20 #include "llvm/Support/Parallel.h" 21 #include "llvm/Support/TimeProfiler.h" 22 23 using namespace llvm; 24 using namespace llvm::codeview; 25 using namespace llvm::msf; 26 using namespace llvm::pdb; 27 28 DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf) 29 : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0), 30 PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86), 31 Header(nullptr) {} 32 33 DbiStreamBuilder::~DbiStreamBuilder() = default; 34 35 void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; } 36 37 void DbiStreamBuilder::setAge(uint32_t A) { Age = A; } 38 39 void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; } 40 41 void DbiStreamBuilder::setBuildNumber(uint8_t Major, uint8_t Minor) { 42 BuildNumber = (uint16_t(Major) << DbiBuildNo::BuildMajorShift) & 43 DbiBuildNo::BuildMajorMask; 44 BuildNumber |= (uint16_t(Minor) << DbiBuildNo::BuildMinorShift) & 45 DbiBuildNo::BuildMinorMask; 46 BuildNumber |= DbiBuildNo::NewVersionFormatMask; 47 } 48 49 void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; } 50 51 void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; } 52 53 void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; } 54 55 void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; } 56 57 void DbiStreamBuilder::setMachineType(COFF::MachineTypes M) { 58 // These enums are mirrors of each other, so we can just cast the value. 59 MachineType = static_cast<pdb::PDB_Machine>(static_cast<unsigned>(M)); 60 } 61 62 void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) { 63 GlobalsStreamIndex = Index; 64 } 65 66 void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) { 67 SymRecordStreamIndex = Index; 68 } 69 70 void DbiStreamBuilder::setPublicsStreamIndex(uint32_t Index) { 71 PublicsStreamIndex = Index; 72 } 73 74 void DbiStreamBuilder::addNewFpoData(const codeview::FrameData &FD) { 75 if (!NewFpoData) 76 NewFpoData.emplace(false); 77 78 NewFpoData->addFrameData(FD); 79 } 80 81 void DbiStreamBuilder::addOldFpoData(const object::FpoData &FD) { 82 OldFpoData.push_back(FD); 83 } 84 85 Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type, 86 ArrayRef<uint8_t> Data) { 87 assert(Type != DbgHeaderType::NewFPO && 88 "NewFPO data should be written via addFrameData()!"); 89 90 DbgStreams[(int)Type] = DebugStream{}; 91 DbgStreams[(int)Type]->Size = Data.size(); 92 DbgStreams[(int)Type]->WriteFn = [Data](BinaryStreamWriter &Writer) { 93 return Writer.writeArray(Data); 94 }; 95 return Error::success(); 96 } 97 98 uint32_t DbiStreamBuilder::addECName(StringRef Name) { 99 return ECNamesBuilder.insert(Name); 100 } 101 102 uint32_t DbiStreamBuilder::calculateSerializedLength() const { 103 // For now we only support serializing the header. 104 return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() + 105 calculateModiSubstreamSize() + calculateSectionContribsStreamSize() + 106 calculateSectionMapStreamSize() + calculateDbgStreamsSize() + 107 ECNamesBuilder.calculateSerializedSize(); 108 } 109 110 Expected<DbiModuleDescriptorBuilder &> 111 DbiStreamBuilder::addModuleInfo(StringRef ModuleName) { 112 uint32_t Index = ModiList.size(); 113 ModiList.push_back( 114 std::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf)); 115 return *ModiList.back(); 116 } 117 118 Error DbiStreamBuilder::addModuleSourceFile(DbiModuleDescriptorBuilder &Module, 119 StringRef File) { 120 uint32_t Index = SourceFileNames.size(); 121 SourceFileNames.insert(std::make_pair(File, Index)); 122 Module.addSourceFile(File); 123 return Error::success(); 124 } 125 126 Expected<uint32_t> DbiStreamBuilder::getSourceFileNameIndex(StringRef File) { 127 auto NameIter = SourceFileNames.find(File); 128 if (NameIter == SourceFileNames.end()) 129 return make_error<RawError>(raw_error_code::no_entry, 130 "The specified source file was not found"); 131 return NameIter->getValue(); 132 } 133 134 uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const { 135 uint32_t Size = 0; 136 for (const auto &M : ModiList) 137 Size += M->calculateSerializedLength(); 138 return Size; 139 } 140 141 uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const { 142 if (SectionContribs.empty()) 143 return 0; 144 return sizeof(enum PdbRaw_DbiSecContribVer) + 145 sizeof(SectionContribs[0]) * SectionContribs.size(); 146 } 147 148 uint32_t DbiStreamBuilder::calculateSectionMapStreamSize() const { 149 if (SectionMap.empty()) 150 return 0; 151 return sizeof(SecMapHeader) + sizeof(SecMapEntry) * SectionMap.size(); 152 } 153 154 uint32_t DbiStreamBuilder::calculateNamesOffset() const { 155 uint32_t Offset = 0; 156 Offset += sizeof(ulittle16_t); // NumModules 157 Offset += sizeof(ulittle16_t); // NumSourceFiles 158 Offset += ModiList.size() * sizeof(ulittle16_t); // ModIndices 159 Offset += ModiList.size() * sizeof(ulittle16_t); // ModFileCounts 160 uint32_t NumFileInfos = 0; 161 for (const auto &M : ModiList) 162 NumFileInfos += M->source_files().size(); 163 Offset += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets 164 return Offset; 165 } 166 167 uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const { 168 uint32_t Size = calculateNamesOffset(); 169 Size += calculateNamesBufferSize(); 170 return alignTo(Size, sizeof(uint32_t)); 171 } 172 173 uint32_t DbiStreamBuilder::calculateNamesBufferSize() const { 174 uint32_t Size = 0; 175 for (const auto &F : SourceFileNames) { 176 Size += F.getKeyLength() + 1; // Names[I]; 177 } 178 return Size; 179 } 180 181 uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const { 182 return DbgStreams.size() * sizeof(uint16_t); 183 } 184 185 Error DbiStreamBuilder::generateFileInfoSubstream() { 186 uint32_t Size = calculateFileInfoSubstreamSize(); 187 auto Data = Allocator.Allocate<uint8_t>(Size); 188 uint32_t NamesOffset = calculateNamesOffset(); 189 190 FileInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(Data, Size), 191 llvm::endianness::little); 192 193 WritableBinaryStreamRef MetadataBuffer = 194 WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset); 195 BinaryStreamWriter MetadataWriter(MetadataBuffer); 196 197 uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModiList.size()); 198 uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size()); 199 if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules 200 return EC; 201 if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles 202 return EC; 203 for (uint16_t I = 0; I < ModiCount; ++I) { 204 if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices 205 return EC; 206 } 207 for (const auto &MI : ModiList) { 208 FileCount = static_cast<uint16_t>(MI->source_files().size()); 209 if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts 210 return EC; 211 } 212 213 // Before writing the FileNameOffsets array, write the NamesBuffer array. 214 // A side effect of this is that this will actually compute the various 215 // file name offsets, so we can then go back and write the FileNameOffsets 216 // array to the other substream. 217 NamesBuffer = WritableBinaryStreamRef(FileInfoBuffer).drop_front(NamesOffset); 218 BinaryStreamWriter NameBufferWriter(NamesBuffer); 219 for (auto &Name : SourceFileNames) { 220 Name.second = NameBufferWriter.getOffset(); 221 if (auto EC = NameBufferWriter.writeCString(Name.getKey())) 222 return EC; 223 } 224 225 for (const auto &MI : ModiList) { 226 for (StringRef Name : MI->source_files()) { 227 auto Result = SourceFileNames.find(Name); 228 if (Result == SourceFileNames.end()) 229 return make_error<RawError>(raw_error_code::no_entry, 230 "The source file was not found."); 231 if (auto EC = MetadataWriter.writeInteger(Result->second)) 232 return EC; 233 } 234 } 235 236 if (auto EC = NameBufferWriter.padToAlignment(sizeof(uint32_t))) 237 return EC; 238 239 if (NameBufferWriter.bytesRemaining() > 0) 240 return make_error<RawError>(raw_error_code::invalid_format, 241 "The names buffer contained unexpected data."); 242 243 if (MetadataWriter.bytesRemaining() > sizeof(uint32_t)) 244 return make_error<RawError>( 245 raw_error_code::invalid_format, 246 "The metadata buffer contained unexpected data."); 247 248 return Error::success(); 249 } 250 251 Error DbiStreamBuilder::finalize() { 252 if (Header) 253 return Error::success(); 254 255 for (auto &MI : ModiList) 256 MI->finalize(); 257 258 if (auto EC = generateFileInfoSubstream()) 259 return EC; 260 261 DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>(); 262 ::memset(H, 0, sizeof(DbiStreamHeader)); 263 H->VersionHeader = *VerHeader; 264 H->VersionSignature = -1; 265 H->Age = Age; 266 H->BuildNumber = BuildNumber; 267 H->Flags = Flags; 268 H->PdbDllRbld = PdbDllRbld; 269 H->PdbDllVersion = PdbDllVersion; 270 H->MachineType = static_cast<uint16_t>(MachineType); 271 272 H->ECSubstreamSize = ECNamesBuilder.calculateSerializedSize(); 273 H->FileInfoSize = FileInfoBuffer.getLength(); 274 H->ModiSubstreamSize = calculateModiSubstreamSize(); 275 H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t); 276 H->SecContrSubstreamSize = calculateSectionContribsStreamSize(); 277 H->SectionMapSize = calculateSectionMapStreamSize(); 278 H->TypeServerSize = 0; 279 H->SymRecordStreamIndex = SymRecordStreamIndex; 280 H->PublicSymbolStreamIndex = PublicsStreamIndex; 281 H->MFCTypeServerIndex = 0; // Not sure what this is, but link.exe writes 0. 282 H->GlobalSymbolStreamIndex = GlobalsStreamIndex; 283 284 Header = H; 285 return Error::success(); 286 } 287 288 Error DbiStreamBuilder::finalizeMsfLayout() { 289 if (NewFpoData) { 290 DbgStreams[(int)DbgHeaderType::NewFPO] = DebugStream{}; 291 DbgStreams[(int)DbgHeaderType::NewFPO]->Size = 292 NewFpoData->calculateSerializedSize(); 293 DbgStreams[(int)DbgHeaderType::NewFPO]->WriteFn = 294 [this](BinaryStreamWriter &Writer) { 295 return NewFpoData->commit(Writer); 296 }; 297 } 298 299 if (!OldFpoData.empty()) { 300 DbgStreams[(int)DbgHeaderType::FPO] = DebugStream{}; 301 DbgStreams[(int)DbgHeaderType::FPO]->Size = 302 sizeof(object::FpoData) * OldFpoData.size(); 303 DbgStreams[(int)DbgHeaderType::FPO]->WriteFn = 304 [this](BinaryStreamWriter &Writer) { 305 return Writer.writeArray(ArrayRef(OldFpoData)); 306 }; 307 } 308 309 for (auto &S : DbgStreams) { 310 if (!S) 311 continue; 312 auto ExpectedIndex = Msf.addStream(S->Size); 313 if (!ExpectedIndex) 314 return ExpectedIndex.takeError(); 315 S->StreamNumber = *ExpectedIndex; 316 } 317 318 for (auto &MI : ModiList) { 319 if (auto EC = MI->finalizeMsfLayout()) 320 return EC; 321 } 322 323 uint32_t Length = calculateSerializedLength(); 324 if (auto EC = Msf.setStreamSize(StreamDBI, Length)) 325 return EC; 326 return Error::success(); 327 } 328 329 static uint16_t toSecMapFlags(uint32_t Flags) { 330 uint16_t Ret = 0; 331 if (Flags & COFF::IMAGE_SCN_MEM_READ) 332 Ret |= static_cast<uint16_t>(OMFSegDescFlags::Read); 333 if (Flags & COFF::IMAGE_SCN_MEM_WRITE) 334 Ret |= static_cast<uint16_t>(OMFSegDescFlags::Write); 335 if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) 336 Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute); 337 if (!(Flags & COFF::IMAGE_SCN_MEM_16BIT)) 338 Ret |= static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit); 339 340 // This seems always 1. 341 Ret |= static_cast<uint16_t>(OMFSegDescFlags::IsSelector); 342 343 return Ret; 344 } 345 346 // Populate the Section Map from COFF section headers. 347 // 348 // A Section Map seem to be a copy of a COFF section list in other format. 349 // I don't know why a PDB file contains both a COFF section header and 350 // a Section Map, but it seems it must be present in a PDB. 351 void DbiStreamBuilder::createSectionMap( 352 ArrayRef<llvm::object::coff_section> SecHdrs) { 353 int Idx = 0; 354 355 auto Add = [&]() -> SecMapEntry & { 356 SectionMap.emplace_back(); 357 auto &Entry = SectionMap.back(); 358 memset(&Entry, 0, sizeof(Entry)); 359 360 Entry.Frame = Idx + 1; 361 362 // We don't know the meaning of these fields yet. 363 Entry.SecName = UINT16_MAX; 364 Entry.ClassName = UINT16_MAX; 365 366 return Entry; 367 }; 368 369 for (auto &Hdr : SecHdrs) { 370 auto &Entry = Add(); 371 Entry.Flags = toSecMapFlags(Hdr.Characteristics); 372 Entry.SecByteLength = Hdr.VirtualSize; 373 ++Idx; 374 } 375 376 // The last entry is for absolute symbols. 377 auto &Entry = Add(); 378 Entry.Flags = static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit) | 379 static_cast<uint16_t>(OMFSegDescFlags::IsAbsoluteAddress); 380 Entry.SecByteLength = UINT32_MAX; 381 } 382 383 Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, 384 WritableBinaryStreamRef MsfBuffer) { 385 llvm::TimeTraceScope timeScope("Commit DBI stream"); 386 if (auto EC = finalize()) 387 return EC; 388 389 auto DbiS = WritableMappedBlockStream::createIndexedStream( 390 Layout, MsfBuffer, StreamDBI, Allocator); 391 392 BinaryStreamWriter Writer(*DbiS); 393 if (auto EC = Writer.writeObject(*Header)) 394 return EC; 395 396 for (auto &M : ModiList) { 397 if (auto EC = M->commit(Writer)) 398 return EC; 399 } 400 401 // Commit symbol streams. This is a lot of data, so do it in parallel. 402 if (auto EC = parallelForEachError( 403 ModiList, [&](std::unique_ptr<DbiModuleDescriptorBuilder> &M) { 404 return M->commitSymbolStream(Layout, MsfBuffer); 405 })) 406 return EC; 407 408 if (!SectionContribs.empty()) { 409 if (auto EC = Writer.writeEnum(DbiSecContribVer60)) 410 return EC; 411 if (auto EC = Writer.writeArray(ArrayRef(SectionContribs))) 412 return EC; 413 } 414 415 if (!SectionMap.empty()) { 416 ulittle16_t Size = static_cast<ulittle16_t>(SectionMap.size()); 417 SecMapHeader SMHeader = {Size, Size}; 418 if (auto EC = Writer.writeObject(SMHeader)) 419 return EC; 420 if (auto EC = Writer.writeArray(ArrayRef(SectionMap))) 421 return EC; 422 } 423 424 if (auto EC = Writer.writeStreamRef(FileInfoBuffer)) 425 return EC; 426 427 if (auto EC = ECNamesBuilder.commit(Writer)) 428 return EC; 429 430 for (auto &Stream : DbgStreams) { 431 uint16_t StreamNumber = kInvalidStreamIndex; 432 if (Stream) 433 StreamNumber = Stream->StreamNumber; 434 if (auto EC = Writer.writeInteger(StreamNumber)) 435 return EC; 436 } 437 438 for (auto &Stream : DbgStreams) { 439 if (!Stream) 440 continue; 441 assert(Stream->StreamNumber != kInvalidStreamIndex); 442 443 auto WritableStream = WritableMappedBlockStream::createIndexedStream( 444 Layout, MsfBuffer, Stream->StreamNumber, Allocator); 445 BinaryStreamWriter DbgStreamWriter(*WritableStream); 446 447 if (auto EC = Stream->WriteFn(DbgStreamWriter)) 448 return EC; 449 } 450 451 if (Writer.bytesRemaining() > 0) 452 return make_error<RawError>(raw_error_code::invalid_format, 453 "Unexpected bytes found in DBI Stream"); 454 return Error::success(); 455 } 456