1 //===- DbiStream.cpp - PDB Dbi Stream (Stream 3) Access -------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" 11 12 #include "llvm/DebugInfo/CodeView/StreamArray.h" 13 #include "llvm/DebugInfo/CodeView/StreamReader.h" 14 #include "llvm/DebugInfo/CodeView/StreamWriter.h" 15 #include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h" 16 #include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" 17 #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" 18 #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" 19 #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" 20 #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" 21 #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" 22 #include "llvm/DebugInfo/PDB/Raw/RawError.h" 23 #include "llvm/DebugInfo/PDB/Raw/RawTypes.h" 24 #include "llvm/Object/COFF.h" 25 26 using namespace llvm; 27 using namespace llvm::codeview; 28 using namespace llvm::pdb; 29 using namespace llvm::support; 30 31 namespace { 32 // Some of the values are stored in bitfields. Since this needs to be portable 33 // across compilers and architectures (big / little endian in particular) we 34 // can't use the actual structures below, but must instead do the shifting 35 // and masking ourselves. The struct definitions are provided for reference. 36 37 // struct DbiFlags { 38 // uint16_t IncrementalLinking : 1; // True if linked incrementally 39 // uint16_t IsStripped : 1; // True if private symbols were stripped. 40 // uint16_t HasCTypes : 1; // True if linked with /debug:ctypes. 41 // uint16_t Reserved : 13; 42 //}; 43 const uint16_t FlagIncrementalMask = 0x0001; 44 const uint16_t FlagStrippedMask = 0x0002; 45 const uint16_t FlagHasCTypesMask = 0x0004; 46 47 // struct DbiBuildNo { 48 // uint16_t MinorVersion : 8; 49 // uint16_t MajorVersion : 7; 50 // uint16_t NewVersionFormat : 1; 51 //}; 52 const uint16_t BuildMinorMask = 0x00FF; 53 const uint16_t BuildMinorShift = 0; 54 55 const uint16_t BuildMajorMask = 0x7F00; 56 const uint16_t BuildMajorShift = 8; 57 58 struct FileInfoSubstreamHeader { 59 ulittle16_t NumModules; // Total # of modules, should match number of 60 // records in the ModuleInfo substream. 61 ulittle16_t NumSourceFiles; // Total # of source files. This value is not 62 // accurate because PDB actually supports more 63 // than 64k source files, so we ignore it and 64 // compute the value from other stream fields. 65 }; 66 } 67 68 template <typename ContribType> 69 static Error loadSectionContribs(FixedStreamArray<ContribType> &Output, 70 StreamReader &Reader) { 71 if (Reader.bytesRemaining() % sizeof(ContribType) != 0) 72 return make_error<RawError>( 73 raw_error_code::corrupt_file, 74 "Invalid number of bytes of section contributions"); 75 76 uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType); 77 if (auto EC = Reader.readArray(Output, Count)) 78 return EC; 79 return Error::success(); 80 } 81 82 DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) 83 : Pdb(File), Stream(std::move(Stream)), Header(nullptr) { 84 static_assert(sizeof(HeaderInfo) == 64, "Invalid HeaderInfo size!"); 85 } 86 87 DbiStream::~DbiStream() {} 88 89 Error DbiStream::reload() { 90 StreamReader Reader(*Stream); 91 92 if (Stream->getLength() < sizeof(HeaderInfo)) 93 return make_error<RawError>(raw_error_code::corrupt_file, 94 "DBI Stream does not contain a header."); 95 if (auto EC = Reader.readObject(Header)) 96 return make_error<RawError>(raw_error_code::corrupt_file, 97 "DBI Stream does not contain a header."); 98 99 if (Header->VersionSignature != -1) 100 return make_error<RawError>(raw_error_code::corrupt_file, 101 "Invalid DBI version signature."); 102 103 // Require at least version 7, which should be present in all PDBs 104 // produced in the last decade and allows us to avoid having to 105 // special case all kinds of complicated arcane formats. 106 if (Header->VersionHeader < PdbDbiV70) 107 return make_error<RawError>(raw_error_code::feature_unsupported, 108 "Unsupported DBI version."); 109 110 auto IS = Pdb.getPDBInfoStream(); 111 if (!IS) 112 return IS.takeError(); 113 114 if (Header->Age != IS->getAge()) 115 return make_error<RawError>(raw_error_code::corrupt_file, 116 "DBI Age does not match PDB Age."); 117 118 if (Stream->getLength() != 119 sizeof(HeaderInfo) + Header->ModiSubstreamSize + 120 Header->SecContrSubstreamSize + Header->SectionMapSize + 121 Header->FileInfoSize + Header->TypeServerSize + 122 Header->OptionalDbgHdrSize + Header->ECSubstreamSize) 123 return make_error<RawError>(raw_error_code::corrupt_file, 124 "DBI Length does not equal sum of substreams."); 125 126 // Only certain substreams are guaranteed to be aligned. Validate 127 // them here. 128 if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0) 129 return make_error<RawError>(raw_error_code::corrupt_file, 130 "DBI MODI substream not aligned."); 131 if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0) 132 return make_error<RawError>( 133 raw_error_code::corrupt_file, 134 "DBI section contribution substream not aligned."); 135 if (Header->SectionMapSize % sizeof(uint32_t) != 0) 136 return make_error<RawError>(raw_error_code::corrupt_file, 137 "DBI section map substream not aligned."); 138 if (Header->FileInfoSize % sizeof(uint32_t) != 0) 139 return make_error<RawError>(raw_error_code::corrupt_file, 140 "DBI file info substream not aligned."); 141 if (Header->TypeServerSize % sizeof(uint32_t) != 0) 142 return make_error<RawError>(raw_error_code::corrupt_file, 143 "DBI type server substream not aligned."); 144 145 // Since each ModInfo in the stream is a variable length, we have to iterate 146 // them to know how many there actually are. 147 VarStreamArray<ModInfo> ModInfoArray; 148 if (auto EC = Reader.readArray(ModInfoArray, Header->ModiSubstreamSize)) 149 return EC; 150 for (auto &Info : ModInfoArray) { 151 ModuleInfos.emplace_back(Info); 152 } 153 154 if (auto EC = Reader.readStreamRef(SecContrSubstream, 155 Header->SecContrSubstreamSize)) 156 return EC; 157 if (auto EC = Reader.readStreamRef(SecMapSubstream, Header->SectionMapSize)) 158 return EC; 159 if (auto EC = Reader.readStreamRef(FileInfoSubstream, Header->FileInfoSize)) 160 return EC; 161 if (auto EC = 162 Reader.readStreamRef(TypeServerMapSubstream, Header->TypeServerSize)) 163 return EC; 164 if (auto EC = Reader.readStreamRef(ECSubstream, Header->ECSubstreamSize)) 165 return EC; 166 if (auto EC = Reader.readArray(DbgStreams, Header->OptionalDbgHdrSize / 167 sizeof(ulittle16_t))) 168 return EC; 169 170 if (auto EC = initializeSectionContributionData()) 171 return EC; 172 if (auto EC = initializeSectionHeadersData()) 173 return EC; 174 if (auto EC = initializeSectionMapData()) 175 return EC; 176 if (auto EC = initializeFileInfo()) 177 return EC; 178 if (auto EC = initializeFpoRecords()) 179 return EC; 180 181 if (Reader.bytesRemaining() > 0) 182 return make_error<RawError>(raw_error_code::corrupt_file, 183 "Found unexpected bytes in DBI Stream."); 184 185 StreamReader ECReader(ECSubstream); 186 if (auto EC = ECNames.load(ECReader)) 187 return EC; 188 189 return Error::success(); 190 } 191 192 PdbRaw_DbiVer DbiStream::getDbiVersion() const { 193 uint32_t Value = Header->VersionHeader; 194 return static_cast<PdbRaw_DbiVer>(Value); 195 } 196 197 uint32_t DbiStream::getAge() const { return Header->Age; } 198 199 uint16_t DbiStream::getPublicSymbolStreamIndex() const { 200 return Header->PublicSymbolStreamIndex; 201 } 202 203 uint16_t DbiStream::getGlobalSymbolStreamIndex() const { 204 return Header->GlobalSymbolStreamIndex; 205 } 206 207 uint16_t DbiStream::getFlags() const { return Header->Flags; } 208 209 bool DbiStream::isIncrementallyLinked() const { 210 return (Header->Flags & FlagIncrementalMask) != 0; 211 } 212 213 bool DbiStream::hasCTypes() const { 214 return (Header->Flags & FlagHasCTypesMask) != 0; 215 } 216 217 bool DbiStream::isStripped() const { 218 return (Header->Flags & FlagStrippedMask) != 0; 219 } 220 221 uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; } 222 223 uint16_t DbiStream::getBuildMajorVersion() const { 224 return (Header->BuildNumber & BuildMajorMask) >> BuildMajorShift; 225 } 226 227 uint16_t DbiStream::getBuildMinorVersion() const { 228 return (Header->BuildNumber & BuildMinorMask) >> BuildMinorShift; 229 } 230 231 uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; } 232 233 uint32_t DbiStream::getPdbDllVersion() const { return Header->PdbDllVersion; } 234 235 uint32_t DbiStream::getSymRecordStreamIndex() const { 236 return Header->SymRecordStreamIndex; 237 } 238 239 PDB_Machine DbiStream::getMachineType() const { 240 uint16_t Machine = Header->MachineType; 241 return static_cast<PDB_Machine>(Machine); 242 } 243 244 codeview::FixedStreamArray<object::coff_section> 245 DbiStream::getSectionHeaders() { 246 return SectionHeaders; 247 } 248 249 codeview::FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() { 250 return FpoRecords; 251 } 252 253 ArrayRef<ModuleInfoEx> DbiStream::modules() const { return ModuleInfos; } 254 codeview::FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const { 255 return SectionMap; 256 } 257 258 void llvm::pdb::DbiStream::visitSectionContributions( 259 ISectionContribVisitor &Visitor) const { 260 if (SectionContribVersion == DbiSecContribVer60) { 261 for (auto &SC : SectionContribs) 262 Visitor.visit(SC); 263 } else if (SectionContribVersion == DbiSecContribV2) { 264 for (auto &SC : SectionContribs2) 265 Visitor.visit(SC); 266 } 267 } 268 269 Error DbiStream::initializeSectionContributionData() { 270 StreamReader SCReader(SecContrSubstream); 271 if (auto EC = SCReader.readEnum(SectionContribVersion)) 272 return EC; 273 274 if (SectionContribVersion == DbiSecContribVer60) 275 return loadSectionContribs<SectionContrib>(SectionContribs, SCReader); 276 if (SectionContribVersion == DbiSecContribV2) 277 return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader); 278 279 return make_error<RawError>(raw_error_code::feature_unsupported, 280 "Unsupported DBI Section Contribution version"); 281 } 282 283 // Initializes this->SectionHeaders. 284 Error DbiStream::initializeSectionHeadersData() { 285 uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::SectionHdr); 286 if (StreamNum >= Pdb.getNumStreams()) 287 return make_error<RawError>(raw_error_code::no_stream); 288 289 auto SHS = MappedBlockStream::createIndexedStream(StreamNum, Pdb); 290 if (!SHS) 291 return SHS.takeError(); 292 293 size_t StreamLen = (*SHS)->getLength(); 294 if (StreamLen % sizeof(object::coff_section)) 295 return make_error<RawError>(raw_error_code::corrupt_file, 296 "Corrupted section header stream."); 297 298 size_t NumSections = StreamLen / sizeof(object::coff_section); 299 codeview::StreamReader Reader(**SHS); 300 if (auto EC = Reader.readArray(SectionHeaders, NumSections)) 301 return make_error<RawError>(raw_error_code::corrupt_file, 302 "Could not read a bitmap."); 303 304 SectionHeaderStream = std::move(*SHS); 305 return Error::success(); 306 } 307 308 // Initializes this->Fpos. 309 Error DbiStream::initializeFpoRecords() { 310 uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::NewFPO); 311 312 // This means there is no FPO data. 313 if (StreamNum == InvalidStreamIndex) 314 return Error::success(); 315 316 if (StreamNum >= Pdb.getNumStreams()) 317 return make_error<RawError>(raw_error_code::no_stream); 318 319 auto FS = MappedBlockStream::createIndexedStream(StreamNum, Pdb); 320 if (!FS) 321 return FS.takeError(); 322 323 size_t StreamLen = (*FS)->getLength(); 324 if (StreamLen % sizeof(object::FpoData)) 325 return make_error<RawError>(raw_error_code::corrupt_file, 326 "Corrupted New FPO stream."); 327 328 size_t NumRecords = StreamLen / sizeof(object::FpoData); 329 codeview::StreamReader Reader(**FS); 330 if (auto EC = Reader.readArray(FpoRecords, NumRecords)) 331 return make_error<RawError>(raw_error_code::corrupt_file, 332 "Corrupted New FPO stream."); 333 FpoStream = std::move(*FS); 334 return Error::success(); 335 } 336 337 Error DbiStream::initializeSectionMapData() { 338 StreamReader SMReader(SecMapSubstream); 339 const SecMapHeader *Header; 340 if (auto EC = SMReader.readObject(Header)) 341 return EC; 342 if (auto EC = SMReader.readArray(SectionMap, Header->SecCount)) 343 return EC; 344 return Error::success(); 345 } 346 347 Error DbiStream::initializeFileInfo() { 348 // The layout of the FileInfoSubstream is like this: 349 // struct { 350 // ulittle16_t NumModules; 351 // ulittle16_t NumSourceFiles; 352 // ulittle16_t ModIndices[NumModules]; 353 // ulittle16_t ModFileCounts[NumModules]; 354 // ulittle32_t FileNameOffsets[NumSourceFiles]; 355 // char Names[][NumSourceFiles]; 356 // }; 357 // with the caveat that `NumSourceFiles` cannot be trusted, so 358 // it is computed by summing `ModFileCounts`. 359 // 360 const FileInfoSubstreamHeader *FH; 361 StreamReader FISR(FileInfoSubstream); 362 if (auto EC = FISR.readObject(FH)) 363 return EC; 364 365 // The number of modules in the stream should be the same as reported by 366 // the FileInfoSubstreamHeader. 367 if (FH->NumModules != ModuleInfos.size()) 368 return make_error<RawError>(raw_error_code::corrupt_file, 369 "FileInfo substream count doesn't match DBI."); 370 371 FixedStreamArray<ulittle16_t> ModIndexArray; 372 FixedStreamArray<ulittle16_t> ModFileCountArray; 373 374 // First is an array of `NumModules` module indices. This is not used for the 375 // same reason that `NumSourceFiles` is not used. It's an array of uint16's, 376 // but it's possible there are more than 64k source files, which would imply 377 // more than 64k modules (e.g. object files) as well. So we ignore this 378 // field. 379 if (auto EC = FISR.readArray(ModIndexArray, ModuleInfos.size())) 380 return EC; 381 if (auto EC = FISR.readArray(ModFileCountArray, ModuleInfos.size())) 382 return EC; 383 384 // Compute the real number of source files. 385 uint32_t NumSourceFiles = 0; 386 for (auto Count : ModFileCountArray) 387 NumSourceFiles += Count; 388 389 // This is the array that in the reference implementation corresponds to 390 // `ModInfo::FileLayout::FileNameOffs`, which is commented there as being a 391 // pointer. Due to the mentioned problems of pointers causing difficulty 392 // when reading from the file on 64-bit systems, we continue to ignore that 393 // field in `ModInfo`, and instead build a vector of StringRefs and stores 394 // them in `ModuleInfoEx`. The value written to and read from the file is 395 // not used anyway, it is only there as a way to store the offsets for the 396 // purposes of later accessing the names at runtime. 397 if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles)) 398 return EC; 399 400 if (auto EC = FISR.readStreamRef(NamesBuffer)) 401 return EC; 402 403 // We go through each ModuleInfo, determine the number N of source files for 404 // that module, and then get the next N offsets from the Offsets array, using 405 // them to get the corresponding N names from the Names buffer and associating 406 // each one with the corresponding module. 407 uint32_t NextFileIndex = 0; 408 for (size_t I = 0; I < ModuleInfos.size(); ++I) { 409 uint32_t NumFiles = ModFileCountArray[I]; 410 ModuleInfos[I].SourceFiles.resize(NumFiles); 411 for (size_t J = 0; J < NumFiles; ++J, ++NextFileIndex) { 412 auto ThisName = getFileNameForIndex(NextFileIndex); 413 if (!ThisName) 414 return ThisName.takeError(); 415 ModuleInfos[I].SourceFiles[J] = *ThisName; 416 } 417 } 418 419 return Error::success(); 420 } 421 422 uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const { 423 return DbgStreams[static_cast<uint16_t>(Type)]; 424 } 425 426 Expected<StringRef> DbiStream::getFileNameForIndex(uint32_t Index) const { 427 StreamReader Names(NamesBuffer); 428 if (Index >= FileNameOffsets.size()) 429 return make_error<RawError>(raw_error_code::index_out_of_bounds); 430 431 uint32_t FileOffset = FileNameOffsets[Index]; 432 Names.setOffset(FileOffset); 433 StringRef Name; 434 if (auto EC = Names.readZeroString(Name)) 435 return std::move(EC); 436 return Name; 437 } 438 439 Error DbiStream::commit() { return Error::success(); } 440