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