Home | History | Annotate | Line # | Download | only in Native
      1 //===- DbiModuleList.cpp - PDB module information list --------------------===//
      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/DbiModuleList.h"
     10 #include "llvm/ADT/StringRef.h"
     11 #include "llvm/ADT/iterator_range.h"
     12 #include "llvm/DebugInfo/PDB/Native/RawError.h"
     13 #include "llvm/Support/BinaryStreamReader.h"
     14 #include "llvm/Support/Error.h"
     15 #include <algorithm>
     16 #include <cassert>
     17 #include <cstddef>
     18 #include <cstdint>
     19 
     20 using namespace llvm;
     21 using namespace llvm::pdb;
     22 
     23 DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator(
     24     const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei)
     25     : Modules(&Modules), Modi(Modi), Filei(Filei) {
     26   setValue();
     27 }
     28 
     29 bool DbiModuleSourceFilesIterator::
     30 operator==(const DbiModuleSourceFilesIterator &R) const {
     31   // incompatible iterators are never equal
     32   if (!isCompatible(R))
     33     return false;
     34 
     35   // If they're compatible, and they're both ends, then they're equal.
     36   if (isEnd() && R.isEnd())
     37     return true;
     38 
     39   // If one is an end and the other is not, they're not equal.
     40   if (isEnd() != R.isEnd())
     41     return false;
     42 
     43   // Now we know:
     44   // - They're compatible
     45   // - They're not *both* end iterators
     46   // - Their endness is the same.
     47   // Thus, they're compatible iterators pointing to a valid file on the same
     48   // module.  All we need to check are the file indices.
     49   assert(Modules == R.Modules);
     50   assert(Modi == R.Modi);
     51   assert(!isEnd());
     52   assert(!R.isEnd());
     53 
     54   return (Filei == R.Filei);
     55 }
     56 
     57 bool DbiModuleSourceFilesIterator::
     58 operator<(const DbiModuleSourceFilesIterator &R) const {
     59   assert(isCompatible(R));
     60 
     61   // It's not sufficient to compare the file indices, because default
     62   // constructed iterators could be equal to iterators with valid indices.  To
     63   // account for this, early-out if they're equal.
     64   if (*this == R)
     65     return false;
     66 
     67   return Filei < R.Filei;
     68 }
     69 
     70 std::ptrdiff_t DbiModuleSourceFilesIterator::
     71 operator-(const DbiModuleSourceFilesIterator &R) const {
     72   assert(isCompatible(R));
     73   assert(!(*this < R));
     74 
     75   // If they're both end iterators, the distance is 0.
     76   if (isEnd() && R.isEnd())
     77     return 0;
     78 
     79   assert(!R.isEnd());
     80 
     81   // At this point, R cannot be end, but *this can, which means that *this
     82   // might be a universal end iterator with none of its fields set.  So in that
     83   // case have to rely on R as the authority to figure out how many files there
     84   // are to compute the distance.
     85   uint32_t Thisi = Filei;
     86   if (isEnd()) {
     87     uint32_t RealModi = R.Modi;
     88     Thisi = R.Modules->getSourceFileCount(RealModi);
     89   }
     90 
     91   assert(Thisi >= R.Filei);
     92   return Thisi - R.Filei;
     93 }
     94 
     95 DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
     96 operator+=(std::ptrdiff_t N) {
     97   assert(!isEnd());
     98 
     99   Filei += N;
    100   assert(Filei <= Modules->getSourceFileCount(Modi));
    101   setValue();
    102   return *this;
    103 }
    104 
    105 DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
    106 operator-=(std::ptrdiff_t N) {
    107   // Note that we can subtract from an end iterator, but not a universal end
    108   // iterator.
    109   assert(!isUniversalEnd());
    110 
    111   assert(N <= Filei);
    112 
    113   Filei -= N;
    114   return *this;
    115 }
    116 
    117 void DbiModuleSourceFilesIterator::setValue() {
    118   if (isEnd()) {
    119     ThisValue = "";
    120     return;
    121   }
    122 
    123   uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei;
    124   auto ExpectedValue = Modules->getFileName(Off);
    125   if (!ExpectedValue) {
    126     consumeError(ExpectedValue.takeError());
    127     Filei = Modules->getSourceFileCount(Modi);
    128   } else
    129     ThisValue = *ExpectedValue;
    130 }
    131 
    132 bool DbiModuleSourceFilesIterator::isEnd() const {
    133   if (isUniversalEnd())
    134     return true;
    135 
    136   assert(Modules);
    137   assert(Modi <= Modules->getModuleCount());
    138   assert(Filei <= Modules->getSourceFileCount(Modi));
    139 
    140   if (Modi == Modules->getModuleCount())
    141     return true;
    142   if (Filei == Modules->getSourceFileCount(Modi))
    143     return true;
    144   return false;
    145 }
    146 
    147 bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; }
    148 
    149 bool DbiModuleSourceFilesIterator::isCompatible(
    150     const DbiModuleSourceFilesIterator &R) const {
    151   // Universal iterators are compatible with any other iterator.
    152   if (isUniversalEnd() || R.isUniversalEnd())
    153     return true;
    154 
    155   // At this point, neither iterator is a universal end iterator, although one
    156   // or both might be non-universal end iterators.  Regardless, the module index
    157   // is valid, so they are compatible if and only if they refer to the same
    158   // module.
    159   return Modi == R.Modi;
    160 }
    161 
    162 Error DbiModuleList::initialize(BinaryStreamRef ModInfo,
    163                                 BinaryStreamRef FileInfo) {
    164   if (auto EC = initializeModInfo(ModInfo))
    165     return EC;
    166   if (auto EC = initializeFileInfo(FileInfo))
    167     return EC;
    168 
    169   return Error::success();
    170 }
    171 
    172 Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) {
    173   ModInfoSubstream = ModInfo;
    174 
    175   if (ModInfo.getLength() == 0)
    176     return Error::success();
    177 
    178   BinaryStreamReader Reader(ModInfo);
    179 
    180   if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength()))
    181     return EC;
    182 
    183   return Error::success();
    184 }
    185 
    186 Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) {
    187   FileInfoSubstream = FileInfo;
    188 
    189   if (FileInfo.getLength() == 0)
    190     return Error::success();
    191 
    192   BinaryStreamReader FISR(FileInfo);
    193   if (auto EC = FISR.readObject(FileInfoHeader))
    194     return EC;
    195 
    196   // First is an array of `NumModules` module indices.  This does not seem to be
    197   // used for anything meaningful, so we ignore it.
    198   FixedStreamArray<support::ulittle16_t> ModuleIndices;
    199   if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules))
    200     return EC;
    201   if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules))
    202     return EC;
    203 
    204   // Compute the real number of source files.  We can't trust the value in
    205   // `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all
    206   // source file counts might be larger than a unit16.  So we compute the real
    207   // count by summing up the individual counts.
    208   uint32_t NumSourceFiles = 0;
    209   for (auto Count : ModFileCountArray)
    210     NumSourceFiles += Count;
    211 
    212   // In the reference implementation, this array is where the pointer documented
    213   // at the definition of ModuleInfoHeader::FileNameOffs points to.  Note that
    214   // although the field in ModuleInfoHeader is ignored this array is not, as it
    215   // is the authority on where each filename begins in the names buffer.
    216   if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
    217     return EC;
    218 
    219   if (auto EC = FISR.readStreamRef(NamesBuffer))
    220     return EC;
    221 
    222   auto DescriptorIter = Descriptors.begin();
    223   uint32_t NextFileIndex = 0;
    224   ModuleInitialFileIndex.resize(FileInfoHeader->NumModules);
    225   ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules);
    226   for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) {
    227     assert(DescriptorIter != Descriptors.end());
    228     ModuleInitialFileIndex[I] = NextFileIndex;
    229     ModuleDescriptorOffsets[I] = DescriptorIter.offset();
    230 
    231     NextFileIndex += ModFileCountArray[I];
    232     ++DescriptorIter;
    233   }
    234 
    235   assert(DescriptorIter == Descriptors.end());
    236   assert(NextFileIndex == NumSourceFiles);
    237 
    238   return Error::success();
    239 }
    240 
    241 uint32_t DbiModuleList::getModuleCount() const {
    242   return FileInfoHeader->NumModules;
    243 }
    244 
    245 uint32_t DbiModuleList::getSourceFileCount() const {
    246   return FileNameOffsets.size();
    247 }
    248 
    249 uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const {
    250   return ModFileCountArray[Modi];
    251 }
    252 
    253 DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const {
    254   assert(Modi < getModuleCount());
    255   uint32_t Offset = ModuleDescriptorOffsets[Modi];
    256   auto Iter = Descriptors.at(Offset);
    257   assert(Iter != Descriptors.end());
    258   return *Iter;
    259 }
    260 
    261 iterator_range<DbiModuleSourceFilesIterator>
    262 DbiModuleList::source_files(uint32_t Modi) const {
    263   return make_range<DbiModuleSourceFilesIterator>(
    264       DbiModuleSourceFilesIterator(*this, Modi, 0),
    265       DbiModuleSourceFilesIterator());
    266 }
    267 
    268 Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const {
    269   BinaryStreamReader Names(NamesBuffer);
    270   if (Index >= getSourceFileCount())
    271     return make_error<RawError>(raw_error_code::index_out_of_bounds);
    272 
    273   uint32_t FileOffset = FileNameOffsets[Index];
    274   Names.setOffset(FileOffset);
    275   StringRef Name;
    276   if (auto EC = Names.readCString(Name))
    277     return std::move(EC);
    278   return Name;
    279 }
    280