1*a580b014SDimitry Andric //===- DbiModuleList.cpp - PDB module information list --------------------===//
20f5676f4SDimitry Andric //
30f5676f4SDimitry Andric //                     The LLVM Compiler Infrastructure
40f5676f4SDimitry Andric //
50f5676f4SDimitry Andric // This file is distributed under the University of Illinois Open Source
60f5676f4SDimitry Andric // License. See LICENSE.TXT for details.
70f5676f4SDimitry Andric //
80f5676f4SDimitry Andric //===----------------------------------------------------------------------===//
90f5676f4SDimitry Andric 
10*a580b014SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
11*a580b014SDimitry Andric #include "llvm/ADT/StringRef.h"
12*a580b014SDimitry Andric #include "llvm/ADT/iterator_range.h"
130f5676f4SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
14*a580b014SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
150f5676f4SDimitry Andric #include "llvm/Support/Error.h"
16*a580b014SDimitry Andric #include <algorithm>
17*a580b014SDimitry Andric #include <cassert>
18*a580b014SDimitry Andric #include <cstddef>
19*a580b014SDimitry Andric #include <cstdint>
200f5676f4SDimitry Andric 
210f5676f4SDimitry Andric using namespace llvm;
220f5676f4SDimitry Andric using namespace llvm::pdb;
230f5676f4SDimitry Andric 
DbiModuleSourceFilesIterator(const DbiModuleList & Modules,uint32_t Modi,uint16_t Filei)240f5676f4SDimitry Andric DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator(
250f5676f4SDimitry Andric     const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei)
260f5676f4SDimitry Andric     : Modules(&Modules), Modi(Modi), Filei(Filei) {
270f5676f4SDimitry Andric   setValue();
280f5676f4SDimitry Andric }
290f5676f4SDimitry Andric 
300f5676f4SDimitry Andric bool DbiModuleSourceFilesIterator::
operator ==(const DbiModuleSourceFilesIterator & R) const310f5676f4SDimitry Andric operator==(const DbiModuleSourceFilesIterator &R) const {
320f5676f4SDimitry Andric   // incompatible iterators are never equal
330f5676f4SDimitry Andric   if (!isCompatible(R))
340f5676f4SDimitry Andric     return false;
350f5676f4SDimitry Andric 
360f5676f4SDimitry Andric   // If they're compatible, and they're both ends, then they're equal.
370f5676f4SDimitry Andric   if (isEnd() && R.isEnd())
380f5676f4SDimitry Andric     return true;
390f5676f4SDimitry Andric 
400f5676f4SDimitry Andric   // If one is an end and the other is not, they're not equal.
410f5676f4SDimitry Andric   if (isEnd() != R.isEnd())
420f5676f4SDimitry Andric     return false;
430f5676f4SDimitry Andric 
440f5676f4SDimitry Andric   // Now we know:
450f5676f4SDimitry Andric   // - They're compatible
460f5676f4SDimitry Andric   // - They're not *both* end iterators
470f5676f4SDimitry Andric   // - Their endness is the same.
480f5676f4SDimitry Andric   // Thus, they're compatible iterators pointing to a valid file on the same
490f5676f4SDimitry Andric   // module.  All we need to check are the file indices.
500f5676f4SDimitry Andric   assert(Modules == R.Modules);
510f5676f4SDimitry Andric   assert(Modi == R.Modi);
520f5676f4SDimitry Andric   assert(!isEnd());
530f5676f4SDimitry Andric   assert(!R.isEnd());
540f5676f4SDimitry Andric 
550f5676f4SDimitry Andric   return (Filei == R.Filei);
560f5676f4SDimitry Andric }
570f5676f4SDimitry Andric 
580f5676f4SDimitry Andric bool DbiModuleSourceFilesIterator::
operator <(const DbiModuleSourceFilesIterator & R) const590f5676f4SDimitry Andric operator<(const DbiModuleSourceFilesIterator &R) const {
600f5676f4SDimitry Andric   assert(isCompatible(R));
610f5676f4SDimitry Andric 
620f5676f4SDimitry Andric   // It's not sufficient to compare the file indices, because default
630f5676f4SDimitry Andric   // constructed iterators could be equal to iterators with valid indices.  To
640f5676f4SDimitry Andric   // account for this, early-out if they're equal.
650f5676f4SDimitry Andric   if (*this == R)
660f5676f4SDimitry Andric     return false;
670f5676f4SDimitry Andric 
680f5676f4SDimitry Andric   return Filei < R.Filei;
690f5676f4SDimitry Andric }
700f5676f4SDimitry Andric 
710f5676f4SDimitry Andric std::ptrdiff_t DbiModuleSourceFilesIterator::
operator -(const DbiModuleSourceFilesIterator & R) const720f5676f4SDimitry Andric operator-(const DbiModuleSourceFilesIterator &R) const {
730f5676f4SDimitry Andric   assert(isCompatible(R));
740f5676f4SDimitry Andric   assert(!(*this < R));
750f5676f4SDimitry Andric 
760f5676f4SDimitry Andric   // If they're both end iterators, the distance is 0.
770f5676f4SDimitry Andric   if (isEnd() && R.isEnd())
780f5676f4SDimitry Andric     return 0;
790f5676f4SDimitry Andric 
800f5676f4SDimitry Andric   assert(!R.isEnd());
810f5676f4SDimitry Andric 
820f5676f4SDimitry Andric   // At this point, R cannot be end, but *this can, which means that *this
830f5676f4SDimitry Andric   // might be a universal end iterator with none of its fields set.  So in that
840f5676f4SDimitry Andric   // case have to rely on R as the authority to figure out how many files there
850f5676f4SDimitry Andric   // are to compute the distance.
860f5676f4SDimitry Andric   uint32_t Thisi = Filei;
870f5676f4SDimitry Andric   if (isEnd()) {
880f5676f4SDimitry Andric     uint32_t RealModi = R.Modi;
890f5676f4SDimitry Andric     Thisi = R.Modules->getSourceFileCount(RealModi);
900f5676f4SDimitry Andric   }
910f5676f4SDimitry Andric 
920f5676f4SDimitry Andric   assert(Thisi >= R.Filei);
930f5676f4SDimitry Andric   return Thisi - R.Filei;
940f5676f4SDimitry Andric }
950f5676f4SDimitry Andric 
960f5676f4SDimitry Andric DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
operator +=(std::ptrdiff_t N)970f5676f4SDimitry Andric operator+=(std::ptrdiff_t N) {
980f5676f4SDimitry Andric   assert(!isEnd());
990f5676f4SDimitry Andric 
1000f5676f4SDimitry Andric   Filei += N;
1010f5676f4SDimitry Andric   assert(Filei <= Modules->getSourceFileCount(Modi));
1020f5676f4SDimitry Andric   setValue();
1030f5676f4SDimitry Andric   return *this;
1040f5676f4SDimitry Andric }
1050f5676f4SDimitry Andric 
1060f5676f4SDimitry Andric DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
operator -=(std::ptrdiff_t N)1070f5676f4SDimitry Andric operator-=(std::ptrdiff_t N) {
1080f5676f4SDimitry Andric   // Note that we can subtract from an end iterator, but not a universal end
1090f5676f4SDimitry Andric   // iterator.
1100f5676f4SDimitry Andric   assert(!isUniversalEnd());
1110f5676f4SDimitry Andric 
1120f5676f4SDimitry Andric   assert(N <= Filei);
1130f5676f4SDimitry Andric 
1140f5676f4SDimitry Andric   Filei -= N;
1150f5676f4SDimitry Andric   return *this;
1160f5676f4SDimitry Andric }
1170f5676f4SDimitry Andric 
setValue()1180f5676f4SDimitry Andric void DbiModuleSourceFilesIterator::setValue() {
1190f5676f4SDimitry Andric   if (isEnd()) {
1200f5676f4SDimitry Andric     ThisValue = "";
1210f5676f4SDimitry Andric     return;
1220f5676f4SDimitry Andric   }
1230f5676f4SDimitry Andric 
1240f5676f4SDimitry Andric   uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei;
1250f5676f4SDimitry Andric   auto ExpectedValue = Modules->getFileName(Off);
1260f5676f4SDimitry Andric   if (!ExpectedValue) {
1270f5676f4SDimitry Andric     consumeError(ExpectedValue.takeError());
1280f5676f4SDimitry Andric     Filei = Modules->getSourceFileCount(Modi);
1290f5676f4SDimitry Andric   } else
1300f5676f4SDimitry Andric     ThisValue = *ExpectedValue;
1310f5676f4SDimitry Andric }
1320f5676f4SDimitry Andric 
isEnd() const1330f5676f4SDimitry Andric bool DbiModuleSourceFilesIterator::isEnd() const {
1340f5676f4SDimitry Andric   if (isUniversalEnd())
1350f5676f4SDimitry Andric     return true;
1360f5676f4SDimitry Andric 
1370f5676f4SDimitry Andric   assert(Modules);
1380f5676f4SDimitry Andric   assert(Modi <= Modules->getModuleCount());
1390f5676f4SDimitry Andric   assert(Filei <= Modules->getSourceFileCount(Modi));
1400f5676f4SDimitry Andric 
1410f5676f4SDimitry Andric   if (Modi == Modules->getModuleCount())
1420f5676f4SDimitry Andric     return true;
1430f5676f4SDimitry Andric   if (Filei == Modules->getSourceFileCount(Modi))
1440f5676f4SDimitry Andric     return true;
1450f5676f4SDimitry Andric   return false;
1460f5676f4SDimitry Andric }
1470f5676f4SDimitry Andric 
isUniversalEnd() const1480f5676f4SDimitry Andric bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; }
1490f5676f4SDimitry Andric 
isCompatible(const DbiModuleSourceFilesIterator & R) const1500f5676f4SDimitry Andric bool DbiModuleSourceFilesIterator::isCompatible(
1510f5676f4SDimitry Andric     const DbiModuleSourceFilesIterator &R) const {
1520f5676f4SDimitry Andric   // Universal iterators are compatible with any other iterator.
1530f5676f4SDimitry Andric   if (isUniversalEnd() || R.isUniversalEnd())
1540f5676f4SDimitry Andric     return true;
1550f5676f4SDimitry Andric 
1560f5676f4SDimitry Andric   // At this point, neither iterator is a universal end iterator, although one
1570f5676f4SDimitry Andric   // or both might be non-universal end iterators.  Regardless, the module index
1580f5676f4SDimitry Andric   // is valid, so they are compatible if and only if they refer to the same
1590f5676f4SDimitry Andric   // module.
1600f5676f4SDimitry Andric   return Modi == R.Modi;
1610f5676f4SDimitry Andric }
1620f5676f4SDimitry Andric 
initialize(BinaryStreamRef ModInfo,BinaryStreamRef FileInfo)1630f5676f4SDimitry Andric Error DbiModuleList::initialize(BinaryStreamRef ModInfo,
1640f5676f4SDimitry Andric                                 BinaryStreamRef FileInfo) {
1650f5676f4SDimitry Andric   if (auto EC = initializeModInfo(ModInfo))
1660f5676f4SDimitry Andric     return EC;
1670f5676f4SDimitry Andric   if (auto EC = initializeFileInfo(FileInfo))
1680f5676f4SDimitry Andric     return EC;
1690f5676f4SDimitry Andric 
1700f5676f4SDimitry Andric   return Error::success();
1710f5676f4SDimitry Andric }
1720f5676f4SDimitry Andric 
initializeModInfo(BinaryStreamRef ModInfo)1730f5676f4SDimitry Andric Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) {
1740f5676f4SDimitry Andric   ModInfoSubstream = ModInfo;
1750f5676f4SDimitry Andric 
1760f5676f4SDimitry Andric   if (ModInfo.getLength() == 0)
1770f5676f4SDimitry Andric     return Error::success();
1780f5676f4SDimitry Andric 
1790f5676f4SDimitry Andric   BinaryStreamReader Reader(ModInfo);
1800f5676f4SDimitry Andric 
1810f5676f4SDimitry Andric   if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength()))
1820f5676f4SDimitry Andric     return EC;
1830f5676f4SDimitry Andric 
1840f5676f4SDimitry Andric   return Error::success();
1850f5676f4SDimitry Andric }
1860f5676f4SDimitry Andric 
initializeFileInfo(BinaryStreamRef FileInfo)1870f5676f4SDimitry Andric Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) {
1880f5676f4SDimitry Andric   FileInfoSubstream = FileInfo;
1890f5676f4SDimitry Andric 
1900f5676f4SDimitry Andric   if (FileInfo.getLength() == 0)
1910f5676f4SDimitry Andric     return Error::success();
1920f5676f4SDimitry Andric 
1930f5676f4SDimitry Andric   BinaryStreamReader FISR(FileInfo);
1940f5676f4SDimitry Andric   if (auto EC = FISR.readObject(FileInfoHeader))
1950f5676f4SDimitry Andric     return EC;
1960f5676f4SDimitry Andric 
1970f5676f4SDimitry Andric   // First is an array of `NumModules` module indices.  This does not seem to be
1980f5676f4SDimitry Andric   // used for anything meaningful, so we ignore it.
1990f5676f4SDimitry Andric   FixedStreamArray<support::ulittle16_t> ModuleIndices;
2000f5676f4SDimitry Andric   if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules))
2010f5676f4SDimitry Andric     return EC;
2020f5676f4SDimitry Andric   if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules))
2030f5676f4SDimitry Andric     return EC;
2040f5676f4SDimitry Andric 
2050f5676f4SDimitry Andric   // Compute the real number of source files.  We can't trust the value in
2060f5676f4SDimitry Andric   // `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all
2070f5676f4SDimitry Andric   // source file counts might be larger than a unit16.  So we compute the real
2080f5676f4SDimitry Andric   // count by summing up the individual counts.
2090f5676f4SDimitry Andric   uint32_t NumSourceFiles = 0;
2100f5676f4SDimitry Andric   for (auto Count : ModFileCountArray)
2110f5676f4SDimitry Andric     NumSourceFiles += Count;
2120f5676f4SDimitry Andric 
2130f5676f4SDimitry Andric   // In the reference implementation, this array is where the pointer documented
2140f5676f4SDimitry Andric   // at the definition of ModuleInfoHeader::FileNameOffs points to.  Note that
2150f5676f4SDimitry Andric   // although the field in ModuleInfoHeader is ignored this array is not, as it
2160f5676f4SDimitry Andric   // is the authority on where each filename begins in the names buffer.
2170f5676f4SDimitry Andric   if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
2180f5676f4SDimitry Andric     return EC;
2190f5676f4SDimitry Andric 
2200f5676f4SDimitry Andric   if (auto EC = FISR.readStreamRef(NamesBuffer))
2210f5676f4SDimitry Andric     return EC;
2220f5676f4SDimitry Andric 
2230f5676f4SDimitry Andric   auto DescriptorIter = Descriptors.begin();
2240f5676f4SDimitry Andric   uint32_t NextFileIndex = 0;
2250f5676f4SDimitry Andric   ModuleInitialFileIndex.resize(FileInfoHeader->NumModules);
2260f5676f4SDimitry Andric   ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules);
2270f5676f4SDimitry Andric   for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) {
2280f5676f4SDimitry Andric     assert(DescriptorIter != Descriptors.end());
2290f5676f4SDimitry Andric     ModuleInitialFileIndex[I] = NextFileIndex;
2300f5676f4SDimitry Andric     ModuleDescriptorOffsets[I] = DescriptorIter.offset();
2310f5676f4SDimitry Andric 
2320f5676f4SDimitry Andric     NextFileIndex += ModFileCountArray[I];
2330f5676f4SDimitry Andric     ++DescriptorIter;
2340f5676f4SDimitry Andric   }
2350f5676f4SDimitry Andric 
2360f5676f4SDimitry Andric   assert(DescriptorIter == Descriptors.end());
2370f5676f4SDimitry Andric   assert(NextFileIndex == NumSourceFiles);
2380f5676f4SDimitry Andric 
2390f5676f4SDimitry Andric   return Error::success();
2400f5676f4SDimitry Andric }
2410f5676f4SDimitry Andric 
getModuleCount() const2420f5676f4SDimitry Andric uint32_t DbiModuleList::getModuleCount() const {
2430f5676f4SDimitry Andric   return FileInfoHeader->NumModules;
2440f5676f4SDimitry Andric }
2450f5676f4SDimitry Andric 
getSourceFileCount() const2460f5676f4SDimitry Andric uint32_t DbiModuleList::getSourceFileCount() const {
2470f5676f4SDimitry Andric   return FileNameOffsets.size();
2480f5676f4SDimitry Andric }
2490f5676f4SDimitry Andric 
getSourceFileCount(uint32_t Modi) const2500f5676f4SDimitry Andric uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const {
2510f5676f4SDimitry Andric   return ModFileCountArray[Modi];
2520f5676f4SDimitry Andric }
2530f5676f4SDimitry Andric 
getModuleDescriptor(uint32_t Modi) const2540f5676f4SDimitry Andric DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const {
2550f5676f4SDimitry Andric   assert(Modi < getModuleCount());
2560f5676f4SDimitry Andric   uint32_t Offset = ModuleDescriptorOffsets[Modi];
2570f5676f4SDimitry Andric   auto Iter = Descriptors.at(Offset);
2580f5676f4SDimitry Andric   assert(Iter != Descriptors.end());
2590f5676f4SDimitry Andric   return *Iter;
2600f5676f4SDimitry Andric }
2610f5676f4SDimitry Andric 
2620f5676f4SDimitry Andric iterator_range<DbiModuleSourceFilesIterator>
source_files(uint32_t Modi) const2630f5676f4SDimitry Andric DbiModuleList::source_files(uint32_t Modi) const {
2640f5676f4SDimitry Andric   return make_range<DbiModuleSourceFilesIterator>(
2650f5676f4SDimitry Andric       DbiModuleSourceFilesIterator(*this, Modi, 0),
2660f5676f4SDimitry Andric       DbiModuleSourceFilesIterator());
2670f5676f4SDimitry Andric }
2680f5676f4SDimitry Andric 
getFileName(uint32_t Index) const2690f5676f4SDimitry Andric Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const {
2700f5676f4SDimitry Andric   BinaryStreamReader Names(NamesBuffer);
2710f5676f4SDimitry Andric   if (Index >= getSourceFileCount())
2720f5676f4SDimitry Andric     return make_error<RawError>(raw_error_code::index_out_of_bounds);
2730f5676f4SDimitry Andric 
2740f5676f4SDimitry Andric   uint32_t FileOffset = FileNameOffsets[Index];
2750f5676f4SDimitry Andric   Names.setOffset(FileOffset);
2760f5676f4SDimitry Andric   StringRef Name;
2770f5676f4SDimitry Andric   if (auto EC = Names.readCString(Name))
2780f5676f4SDimitry Andric     return std::move(EC);
2790f5676f4SDimitry Andric   return Name;
2800f5676f4SDimitry Andric }
281