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