Home | History | Annotate | Line # | Download | only in Native
      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