1 //===- DbiStream.cpp - PDB Dbi Stream (Stream 3) Access -------------------===// 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/DbiStream.h" 10 #include "llvm/ADT/StringRef.h" 11 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 12 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" 13 #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" 14 #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 15 #include "llvm/DebugInfo/PDB/Native/RawConstants.h" 16 #include "llvm/DebugInfo/PDB/Native/RawError.h" 17 #include "llvm/DebugInfo/PDB/Native/RawTypes.h" 18 #include "llvm/DebugInfo/PDB/PDBTypes.h" 19 #include "llvm/Object/COFF.h" 20 #include "llvm/Support/BinaryStreamArray.h" 21 #include "llvm/Support/BinaryStreamReader.h" 22 #include "llvm/Support/Error.h" 23 #include <algorithm> 24 #include <cstddef> 25 #include <cstdint> 26 27 using namespace llvm; 28 using namespace llvm::codeview; 29 using namespace llvm::msf; 30 using namespace llvm::pdb; 31 using namespace llvm::support; 32 33 template <typename ContribType> 34 static Error loadSectionContribs(FixedStreamArray<ContribType> &Output, 35 BinaryStreamReader &Reader) { 36 if (Reader.bytesRemaining() % sizeof(ContribType) != 0) 37 return make_error<RawError>( 38 raw_error_code::corrupt_file, 39 "Invalid number of bytes of section contributions"); 40 41 uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType); 42 if (auto EC = Reader.readArray(Output, Count)) 43 return EC; 44 return Error::success(); 45 } 46 47 DbiStream::DbiStream(std::unique_ptr<BinaryStream> Stream) 48 : Stream(std::move(Stream)), Header(nullptr) {} 49 50 DbiStream::~DbiStream() = default; 51 52 Error DbiStream::reload(PDBFile *Pdb) { 53 BinaryStreamReader Reader(*Stream); 54 55 if (Stream->getLength() < sizeof(DbiStreamHeader)) 56 return make_error<RawError>(raw_error_code::corrupt_file, 57 "DBI Stream does not contain a header."); 58 if (auto EC = Reader.readObject(Header)) 59 return make_error<RawError>(raw_error_code::corrupt_file, 60 "DBI Stream does not contain a header."); 61 62 if (Header->VersionSignature != -1) 63 return make_error<RawError>(raw_error_code::corrupt_file, 64 "Invalid DBI version signature."); 65 66 // Require at least version 7, which should be present in all PDBs 67 // produced in the last decade and allows us to avoid having to 68 // special case all kinds of complicated arcane formats. 69 if (Header->VersionHeader < PdbDbiV70) 70 return make_error<RawError>(raw_error_code::feature_unsupported, 71 "Unsupported DBI version."); 72 73 if (Stream->getLength() != 74 sizeof(DbiStreamHeader) + Header->ModiSubstreamSize + 75 Header->SecContrSubstreamSize + Header->SectionMapSize + 76 Header->FileInfoSize + Header->TypeServerSize + 77 Header->OptionalDbgHdrSize + Header->ECSubstreamSize) 78 return make_error<RawError>(raw_error_code::corrupt_file, 79 "DBI Length does not equal sum of substreams."); 80 81 // Only certain substreams are guaranteed to be aligned. Validate 82 // them here. 83 if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0) 84 return make_error<RawError>(raw_error_code::corrupt_file, 85 "DBI MODI substream not aligned."); 86 if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0) 87 return make_error<RawError>( 88 raw_error_code::corrupt_file, 89 "DBI section contribution substream not aligned."); 90 if (Header->SectionMapSize % sizeof(uint32_t) != 0) 91 return make_error<RawError>(raw_error_code::corrupt_file, 92 "DBI section map substream not aligned."); 93 if (Header->FileInfoSize % sizeof(uint32_t) != 0) 94 return make_error<RawError>(raw_error_code::corrupt_file, 95 "DBI file info substream not aligned."); 96 if (Header->TypeServerSize % sizeof(uint32_t) != 0) 97 return make_error<RawError>(raw_error_code::corrupt_file, 98 "DBI type server substream not aligned."); 99 100 if (auto EC = Reader.readSubstream(ModiSubstream, Header->ModiSubstreamSize)) 101 return EC; 102 103 if (auto EC = Reader.readSubstream(SecContrSubstream, 104 Header->SecContrSubstreamSize)) 105 return EC; 106 if (auto EC = Reader.readSubstream(SecMapSubstream, Header->SectionMapSize)) 107 return EC; 108 if (auto EC = Reader.readSubstream(FileInfoSubstream, Header->FileInfoSize)) 109 return EC; 110 if (auto EC = 111 Reader.readSubstream(TypeServerMapSubstream, Header->TypeServerSize)) 112 return EC; 113 if (auto EC = Reader.readSubstream(ECSubstream, Header->ECSubstreamSize)) 114 return EC; 115 if (auto EC = Reader.readArray( 116 DbgStreams, Header->OptionalDbgHdrSize / sizeof(ulittle16_t))) 117 return EC; 118 119 if (auto EC = Modules.initialize(ModiSubstream.StreamData, 120 FileInfoSubstream.StreamData)) 121 return EC; 122 123 if (auto EC = initializeSectionContributionData()) 124 return EC; 125 if (auto EC = initializeSectionHeadersData(Pdb)) 126 return EC; 127 if (auto EC = initializeSectionMapData()) 128 return EC; 129 if (auto EC = initializeOldFpoRecords(Pdb)) 130 return EC; 131 if (auto EC = initializeNewFpoRecords(Pdb)) 132 return EC; 133 134 if (Reader.bytesRemaining() > 0) 135 return make_error<RawError>(raw_error_code::corrupt_file, 136 "Found unexpected bytes in DBI Stream."); 137 138 if (!ECSubstream.empty()) { 139 BinaryStreamReader ECReader(ECSubstream.StreamData); 140 if (auto EC = ECNames.reload(ECReader)) 141 return EC; 142 } 143 144 return Error::success(); 145 } 146 147 PdbRaw_DbiVer DbiStream::getDbiVersion() const { 148 uint32_t Value = Header->VersionHeader; 149 return static_cast<PdbRaw_DbiVer>(Value); 150 } 151 152 uint32_t DbiStream::getAge() const { return Header->Age; } 153 154 uint16_t DbiStream::getPublicSymbolStreamIndex() const { 155 return Header->PublicSymbolStreamIndex; 156 } 157 158 uint16_t DbiStream::getGlobalSymbolStreamIndex() const { 159 return Header->GlobalSymbolStreamIndex; 160 } 161 162 uint16_t DbiStream::getFlags() const { return Header->Flags; } 163 164 bool DbiStream::isIncrementallyLinked() const { 165 return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0; 166 } 167 168 bool DbiStream::hasCTypes() const { 169 return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0; 170 } 171 172 bool DbiStream::isStripped() const { 173 return (Header->Flags & DbiFlags::FlagStrippedMask) != 0; 174 } 175 176 uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; } 177 178 uint16_t DbiStream::getBuildMajorVersion() const { 179 return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >> 180 DbiBuildNo::BuildMajorShift; 181 } 182 183 uint16_t DbiStream::getBuildMinorVersion() const { 184 return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >> 185 DbiBuildNo::BuildMinorShift; 186 } 187 188 uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; } 189 190 uint32_t DbiStream::getPdbDllVersion() const { return Header->PdbDllVersion; } 191 192 uint32_t DbiStream::getSymRecordStreamIndex() const { 193 return Header->SymRecordStreamIndex; 194 } 195 196 PDB_Machine DbiStream::getMachineType() const { 197 uint16_t Machine = Header->MachineType; 198 return static_cast<PDB_Machine>(Machine); 199 } 200 201 FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() const { 202 return SectionHeaders; 203 } 204 205 bool DbiStream::hasOldFpoRecords() const { return OldFpoStream != nullptr; } 206 207 FixedStreamArray<object::FpoData> DbiStream::getOldFpoRecords() const { 208 return OldFpoRecords; 209 } 210 211 bool DbiStream::hasNewFpoRecords() const { return NewFpoStream != nullptr; } 212 213 const DebugFrameDataSubsectionRef &DbiStream::getNewFpoRecords() const { 214 return NewFpoRecords; 215 } 216 217 const DbiModuleList &DbiStream::modules() const { return Modules; } 218 219 FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const { 220 return SectionMap; 221 } 222 223 void DbiStream::visitSectionContributions( 224 ISectionContribVisitor &Visitor) const { 225 if (!SectionContribs.empty()) { 226 assert(SectionContribVersion == DbiSecContribVer60); 227 for (auto &SC : SectionContribs) 228 Visitor.visit(SC); 229 } else if (!SectionContribs2.empty()) { 230 assert(SectionContribVersion == DbiSecContribV2); 231 for (auto &SC : SectionContribs2) 232 Visitor.visit(SC); 233 } 234 } 235 236 Expected<StringRef> DbiStream::getECName(uint32_t NI) const { 237 return ECNames.getStringForID(NI); 238 } 239 240 Error DbiStream::initializeSectionContributionData() { 241 if (SecContrSubstream.empty()) 242 return Error::success(); 243 244 BinaryStreamReader SCReader(SecContrSubstream.StreamData); 245 if (auto EC = SCReader.readEnum(SectionContribVersion)) 246 return EC; 247 248 if (SectionContribVersion == DbiSecContribVer60) 249 return loadSectionContribs<SectionContrib>(SectionContribs, SCReader); 250 if (SectionContribVersion == DbiSecContribV2) 251 return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader); 252 253 return make_error<RawError>(raw_error_code::feature_unsupported, 254 "Unsupported DBI Section Contribution version"); 255 } 256 257 // Initializes this->SectionHeaders. 258 Error DbiStream::initializeSectionHeadersData(PDBFile *Pdb) { 259 Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = 260 createIndexedStreamForHeaderType(Pdb, DbgHeaderType::SectionHdr); 261 if (auto EC = ExpectedStream.takeError()) 262 return EC; 263 264 auto &SHS = *ExpectedStream; 265 if (!SHS) 266 return Error::success(); 267 268 size_t StreamLen = SHS->getLength(); 269 if (StreamLen % sizeof(object::coff_section)) 270 return make_error<RawError>(raw_error_code::corrupt_file, 271 "Corrupted section header stream."); 272 273 size_t NumSections = StreamLen / sizeof(object::coff_section); 274 BinaryStreamReader Reader(*SHS); 275 if (auto EC = Reader.readArray(SectionHeaders, NumSections)) 276 return make_error<RawError>(raw_error_code::corrupt_file, 277 "Could not read a bitmap."); 278 279 SectionHeaderStream = std::move(SHS); 280 return Error::success(); 281 } 282 283 // Initializes this->Fpos. 284 Error DbiStream::initializeOldFpoRecords(PDBFile *Pdb) { 285 Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = 286 createIndexedStreamForHeaderType(Pdb, DbgHeaderType::FPO); 287 if (auto EC = ExpectedStream.takeError()) 288 return EC; 289 290 auto &FS = *ExpectedStream; 291 if (!FS) 292 return Error::success(); 293 294 size_t StreamLen = FS->getLength(); 295 if (StreamLen % sizeof(object::FpoData)) 296 return make_error<RawError>(raw_error_code::corrupt_file, 297 "Corrupted Old FPO stream."); 298 299 size_t NumRecords = StreamLen / sizeof(object::FpoData); 300 BinaryStreamReader Reader(*FS); 301 if (auto EC = Reader.readArray(OldFpoRecords, NumRecords)) 302 return make_error<RawError>(raw_error_code::corrupt_file, 303 "Corrupted Old FPO stream."); 304 OldFpoStream = std::move(FS); 305 return Error::success(); 306 } 307 308 Error DbiStream::initializeNewFpoRecords(PDBFile *Pdb) { 309 Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = 310 createIndexedStreamForHeaderType(Pdb, DbgHeaderType::NewFPO); 311 if (auto EC = ExpectedStream.takeError()) 312 return EC; 313 314 auto &FS = *ExpectedStream; 315 if (!FS) 316 return Error::success(); 317 318 if (auto EC = NewFpoRecords.initialize(*FS)) 319 return EC; 320 321 NewFpoStream = std::move(FS); 322 return Error::success(); 323 } 324 325 Expected<std::unique_ptr<msf::MappedBlockStream>> 326 DbiStream::createIndexedStreamForHeaderType(PDBFile *Pdb, 327 DbgHeaderType Type) const { 328 if (!Pdb) 329 return nullptr; 330 331 if (DbgStreams.empty()) 332 return nullptr; 333 334 uint32_t StreamNum = getDebugStreamIndex(Type); 335 336 // This means there is no such stream. 337 if (StreamNum == kInvalidStreamIndex) 338 return nullptr; 339 340 return Pdb->safelyCreateIndexedStream(StreamNum); 341 } 342 343 BinarySubstreamRef DbiStream::getSectionContributionData() const { 344 return SecContrSubstream; 345 } 346 347 BinarySubstreamRef DbiStream::getSecMapSubstreamData() const { 348 return SecMapSubstream; 349 } 350 351 BinarySubstreamRef DbiStream::getModiSubstreamData() const { 352 return ModiSubstream; 353 } 354 355 BinarySubstreamRef DbiStream::getFileInfoSubstreamData() const { 356 return FileInfoSubstream; 357 } 358 359 BinarySubstreamRef DbiStream::getTypeServerMapSubstreamData() const { 360 return TypeServerMapSubstream; 361 } 362 363 BinarySubstreamRef DbiStream::getECSubstreamData() const { return ECSubstream; } 364 365 Error DbiStream::initializeSectionMapData() { 366 if (SecMapSubstream.empty()) 367 return Error::success(); 368 369 BinaryStreamReader SMReader(SecMapSubstream.StreamData); 370 const SecMapHeader *Header; 371 if (auto EC = SMReader.readObject(Header)) 372 return EC; 373 if (auto EC = SMReader.readArray(SectionMap, Header->SecCount)) 374 return EC; 375 return Error::success(); 376 } 377 378 uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const { 379 uint16_t T = static_cast<uint16_t>(Type); 380 if (T >= DbgStreams.size()) 381 return kInvalidStreamIndex; 382 return DbgStreams[T]; 383 } 384