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