14fcfc199SEugene Zelenko //===- DbiModuleList.cpp - PDB module information list --------------------===//
21eb9a029SZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61eb9a029SZachary Turner //
71eb9a029SZachary Turner //===----------------------------------------------------------------------===//
81eb9a029SZachary Turner
94fcfc199SEugene Zelenko #include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
104fcfc199SEugene Zelenko #include "llvm/ADT/StringRef.h"
114fcfc199SEugene Zelenko #include "llvm/ADT/iterator_range.h"
121eb9a029SZachary Turner #include "llvm/DebugInfo/PDB/Native/RawError.h"
13*ed98c1b3Sserge-sans-paille #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
144fcfc199SEugene Zelenko #include "llvm/Support/BinaryStreamReader.h"
151eb9a029SZachary Turner #include "llvm/Support/Error.h"
164fcfc199SEugene Zelenko #include <algorithm>
174fcfc199SEugene Zelenko #include <cassert>
184fcfc199SEugene Zelenko #include <cstddef>
194fcfc199SEugene Zelenko #include <cstdint>
201eb9a029SZachary Turner
211eb9a029SZachary Turner using namespace llvm;
221eb9a029SZachary Turner using namespace llvm::pdb;
231eb9a029SZachary Turner
DbiModuleSourceFilesIterator(const DbiModuleList & Modules,uint32_t Modi,uint16_t Filei)241eb9a029SZachary Turner DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator(
251eb9a029SZachary Turner const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei)
261eb9a029SZachary Turner : Modules(&Modules), Modi(Modi), Filei(Filei) {
271eb9a029SZachary Turner setValue();
281eb9a029SZachary Turner }
291eb9a029SZachary Turner
301eb9a029SZachary Turner bool DbiModuleSourceFilesIterator::
operator ==(const DbiModuleSourceFilesIterator & R) const311eb9a029SZachary Turner operator==(const DbiModuleSourceFilesIterator &R) const {
321eb9a029SZachary Turner // incompatible iterators are never equal
331eb9a029SZachary Turner if (!isCompatible(R))
341eb9a029SZachary Turner return false;
351eb9a029SZachary Turner
361eb9a029SZachary Turner // If they're compatible, and they're both ends, then they're equal.
371eb9a029SZachary Turner if (isEnd() && R.isEnd())
381eb9a029SZachary Turner return true;
391eb9a029SZachary Turner
401eb9a029SZachary Turner // If one is an end and the other is not, they're not equal.
411eb9a029SZachary Turner if (isEnd() != R.isEnd())
421eb9a029SZachary Turner return false;
431eb9a029SZachary Turner
441eb9a029SZachary Turner // Now we know:
451eb9a029SZachary Turner // - They're compatible
461eb9a029SZachary Turner // - They're not *both* end iterators
471eb9a029SZachary Turner // - Their endness is the same.
481eb9a029SZachary Turner // Thus, they're compatible iterators pointing to a valid file on the same
491eb9a029SZachary Turner // module. All we need to check are the file indices.
501eb9a029SZachary Turner assert(Modules == R.Modules);
511eb9a029SZachary Turner assert(Modi == R.Modi);
521eb9a029SZachary Turner assert(!isEnd());
531eb9a029SZachary Turner assert(!R.isEnd());
541eb9a029SZachary Turner
551eb9a029SZachary Turner return (Filei == R.Filei);
561eb9a029SZachary Turner }
571eb9a029SZachary Turner
581eb9a029SZachary Turner bool DbiModuleSourceFilesIterator::
operator <(const DbiModuleSourceFilesIterator & R) const591eb9a029SZachary Turner operator<(const DbiModuleSourceFilesIterator &R) const {
601eb9a029SZachary Turner assert(isCompatible(R));
611eb9a029SZachary Turner
621eb9a029SZachary Turner // It's not sufficient to compare the file indices, because default
631eb9a029SZachary Turner // constructed iterators could be equal to iterators with valid indices. To
641eb9a029SZachary Turner // account for this, early-out if they're equal.
651eb9a029SZachary Turner if (*this == R)
661eb9a029SZachary Turner return false;
671eb9a029SZachary Turner
681eb9a029SZachary Turner return Filei < R.Filei;
691eb9a029SZachary Turner }
701eb9a029SZachary Turner
711eb9a029SZachary Turner std::ptrdiff_t DbiModuleSourceFilesIterator::
operator -(const DbiModuleSourceFilesIterator & R) const721eb9a029SZachary Turner operator-(const DbiModuleSourceFilesIterator &R) const {
731eb9a029SZachary Turner assert(isCompatible(R));
741eb9a029SZachary Turner assert(!(*this < R));
751eb9a029SZachary Turner
761eb9a029SZachary Turner // If they're both end iterators, the distance is 0.
771eb9a029SZachary Turner if (isEnd() && R.isEnd())
781eb9a029SZachary Turner return 0;
791eb9a029SZachary Turner
801eb9a029SZachary Turner assert(!R.isEnd());
811eb9a029SZachary Turner
821eb9a029SZachary Turner // At this point, R cannot be end, but *this can, which means that *this
831eb9a029SZachary Turner // might be a universal end iterator with none of its fields set. So in that
841eb9a029SZachary Turner // case have to rely on R as the authority to figure out how many files there
851eb9a029SZachary Turner // are to compute the distance.
861eb9a029SZachary Turner uint32_t Thisi = Filei;
871eb9a029SZachary Turner if (isEnd()) {
881eb9a029SZachary Turner uint32_t RealModi = R.Modi;
891eb9a029SZachary Turner Thisi = R.Modules->getSourceFileCount(RealModi);
901eb9a029SZachary Turner }
911eb9a029SZachary Turner
921eb9a029SZachary Turner assert(Thisi >= R.Filei);
931eb9a029SZachary Turner return Thisi - R.Filei;
941eb9a029SZachary Turner }
951eb9a029SZachary Turner
961eb9a029SZachary Turner DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
operator +=(std::ptrdiff_t N)971eb9a029SZachary Turner operator+=(std::ptrdiff_t N) {
981eb9a029SZachary Turner assert(!isEnd());
991eb9a029SZachary Turner
1001eb9a029SZachary Turner Filei += N;
1011eb9a029SZachary Turner assert(Filei <= Modules->getSourceFileCount(Modi));
1021eb9a029SZachary Turner setValue();
1031eb9a029SZachary Turner return *this;
1041eb9a029SZachary Turner }
1051eb9a029SZachary Turner
1061eb9a029SZachary Turner DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
operator -=(std::ptrdiff_t N)1071eb9a029SZachary Turner operator-=(std::ptrdiff_t N) {
1081eb9a029SZachary Turner // Note that we can subtract from an end iterator, but not a universal end
1091eb9a029SZachary Turner // iterator.
1101eb9a029SZachary Turner assert(!isUniversalEnd());
1111eb9a029SZachary Turner
1121eb9a029SZachary Turner assert(N <= Filei);
1131eb9a029SZachary Turner
1141eb9a029SZachary Turner Filei -= N;
1151eb9a029SZachary Turner return *this;
1161eb9a029SZachary Turner }
1171eb9a029SZachary Turner
setValue()1181eb9a029SZachary Turner void DbiModuleSourceFilesIterator::setValue() {
1191eb9a029SZachary Turner if (isEnd()) {
1201eb9a029SZachary Turner ThisValue = "";
1211eb9a029SZachary Turner return;
1221eb9a029SZachary Turner }
1231eb9a029SZachary Turner
1241eb9a029SZachary Turner uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei;
1251eb9a029SZachary Turner auto ExpectedValue = Modules->getFileName(Off);
1261eb9a029SZachary Turner if (!ExpectedValue) {
1271eb9a029SZachary Turner consumeError(ExpectedValue.takeError());
1281eb9a029SZachary Turner Filei = Modules->getSourceFileCount(Modi);
1291eb9a029SZachary Turner } else
1301eb9a029SZachary Turner ThisValue = *ExpectedValue;
1311eb9a029SZachary Turner }
1321eb9a029SZachary Turner
isEnd() const1331eb9a029SZachary Turner bool DbiModuleSourceFilesIterator::isEnd() const {
1341eb9a029SZachary Turner if (isUniversalEnd())
1351eb9a029SZachary Turner return true;
1361eb9a029SZachary Turner
1371eb9a029SZachary Turner assert(Modules);
1381eb9a029SZachary Turner assert(Modi <= Modules->getModuleCount());
1391eb9a029SZachary Turner assert(Filei <= Modules->getSourceFileCount(Modi));
1401eb9a029SZachary Turner
1411eb9a029SZachary Turner if (Modi == Modules->getModuleCount())
1421eb9a029SZachary Turner return true;
1431eb9a029SZachary Turner if (Filei == Modules->getSourceFileCount(Modi))
1441eb9a029SZachary Turner return true;
1451eb9a029SZachary Turner return false;
1461eb9a029SZachary Turner }
1471eb9a029SZachary Turner
isUniversalEnd() const1481eb9a029SZachary Turner bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; }
1491eb9a029SZachary Turner
isCompatible(const DbiModuleSourceFilesIterator & R) const1501eb9a029SZachary Turner bool DbiModuleSourceFilesIterator::isCompatible(
1511eb9a029SZachary Turner const DbiModuleSourceFilesIterator &R) const {
1521eb9a029SZachary Turner // Universal iterators are compatible with any other iterator.
1531eb9a029SZachary Turner if (isUniversalEnd() || R.isUniversalEnd())
1541eb9a029SZachary Turner return true;
1551eb9a029SZachary Turner
1561eb9a029SZachary Turner // At this point, neither iterator is a universal end iterator, although one
1571eb9a029SZachary Turner // or both might be non-universal end iterators. Regardless, the module index
1581eb9a029SZachary Turner // is valid, so they are compatible if and only if they refer to the same
1591eb9a029SZachary Turner // module.
1601eb9a029SZachary Turner return Modi == R.Modi;
1611eb9a029SZachary Turner }
1621eb9a029SZachary Turner
initialize(BinaryStreamRef ModInfo,BinaryStreamRef FileInfo)1631eb9a029SZachary Turner Error DbiModuleList::initialize(BinaryStreamRef ModInfo,
1641eb9a029SZachary Turner BinaryStreamRef FileInfo) {
1651eb9a029SZachary Turner if (auto EC = initializeModInfo(ModInfo))
1661eb9a029SZachary Turner return EC;
1671eb9a029SZachary Turner if (auto EC = initializeFileInfo(FileInfo))
1681eb9a029SZachary Turner return EC;
1691eb9a029SZachary Turner
1701eb9a029SZachary Turner return Error::success();
1711eb9a029SZachary Turner }
1721eb9a029SZachary Turner
initializeModInfo(BinaryStreamRef ModInfo)1731eb9a029SZachary Turner Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) {
1741eb9a029SZachary Turner ModInfoSubstream = ModInfo;
1751eb9a029SZachary Turner
1761eb9a029SZachary Turner if (ModInfo.getLength() == 0)
1771eb9a029SZachary Turner return Error::success();
1781eb9a029SZachary Turner
1791eb9a029SZachary Turner BinaryStreamReader Reader(ModInfo);
1801eb9a029SZachary Turner
1811eb9a029SZachary Turner if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength()))
1821eb9a029SZachary Turner return EC;
1831eb9a029SZachary Turner
1841eb9a029SZachary Turner return Error::success();
1851eb9a029SZachary Turner }
1861eb9a029SZachary Turner
initializeFileInfo(BinaryStreamRef FileInfo)1871eb9a029SZachary Turner Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) {
1881eb9a029SZachary Turner FileInfoSubstream = FileInfo;
1891eb9a029SZachary Turner
1901eb9a029SZachary Turner if (FileInfo.getLength() == 0)
1911eb9a029SZachary Turner return Error::success();
1921eb9a029SZachary Turner
1931eb9a029SZachary Turner BinaryStreamReader FISR(FileInfo);
1941eb9a029SZachary Turner if (auto EC = FISR.readObject(FileInfoHeader))
1951eb9a029SZachary Turner return EC;
1961eb9a029SZachary Turner
1971eb9a029SZachary Turner // First is an array of `NumModules` module indices. This does not seem to be
1981eb9a029SZachary Turner // used for anything meaningful, so we ignore it.
1991eb9a029SZachary Turner FixedStreamArray<support::ulittle16_t> ModuleIndices;
2001eb9a029SZachary Turner if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules))
2011eb9a029SZachary Turner return EC;
2021eb9a029SZachary Turner if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules))
2031eb9a029SZachary Turner return EC;
2041eb9a029SZachary Turner
2051eb9a029SZachary Turner // Compute the real number of source files. We can't trust the value in
2061eb9a029SZachary Turner // `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all
2071eb9a029SZachary Turner // source file counts might be larger than a unit16. So we compute the real
2081eb9a029SZachary Turner // count by summing up the individual counts.
2091eb9a029SZachary Turner uint32_t NumSourceFiles = 0;
2101eb9a029SZachary Turner for (auto Count : ModFileCountArray)
2111eb9a029SZachary Turner NumSourceFiles += Count;
2121eb9a029SZachary Turner
2131eb9a029SZachary Turner // In the reference implementation, this array is where the pointer documented
2141eb9a029SZachary Turner // at the definition of ModuleInfoHeader::FileNameOffs points to. Note that
2151eb9a029SZachary Turner // although the field in ModuleInfoHeader is ignored this array is not, as it
2161eb9a029SZachary Turner // is the authority on where each filename begins in the names buffer.
2171eb9a029SZachary Turner if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
2181eb9a029SZachary Turner return EC;
2191eb9a029SZachary Turner
2201eb9a029SZachary Turner if (auto EC = FISR.readStreamRef(NamesBuffer))
2211eb9a029SZachary Turner return EC;
2221eb9a029SZachary Turner
2231eb9a029SZachary Turner auto DescriptorIter = Descriptors.begin();
2241eb9a029SZachary Turner uint32_t NextFileIndex = 0;
2251eb9a029SZachary Turner ModuleInitialFileIndex.resize(FileInfoHeader->NumModules);
2261eb9a029SZachary Turner ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules);
2271eb9a029SZachary Turner for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) {
2281eb9a029SZachary Turner assert(DescriptorIter != Descriptors.end());
2291eb9a029SZachary Turner ModuleInitialFileIndex[I] = NextFileIndex;
2301eb9a029SZachary Turner ModuleDescriptorOffsets[I] = DescriptorIter.offset();
2311eb9a029SZachary Turner
2321eb9a029SZachary Turner NextFileIndex += ModFileCountArray[I];
2331eb9a029SZachary Turner ++DescriptorIter;
2341eb9a029SZachary Turner }
2351eb9a029SZachary Turner
2361eb9a029SZachary Turner assert(DescriptorIter == Descriptors.end());
2371eb9a029SZachary Turner assert(NextFileIndex == NumSourceFiles);
2381eb9a029SZachary Turner
2391eb9a029SZachary Turner return Error::success();
2401eb9a029SZachary Turner }
2411eb9a029SZachary Turner
getModuleCount() const2421eb9a029SZachary Turner uint32_t DbiModuleList::getModuleCount() const {
2431eb9a029SZachary Turner return FileInfoHeader->NumModules;
2441eb9a029SZachary Turner }
2451eb9a029SZachary Turner
getSourceFileCount() const2461eb9a029SZachary Turner uint32_t DbiModuleList::getSourceFileCount() const {
2471eb9a029SZachary Turner return FileNameOffsets.size();
2481eb9a029SZachary Turner }
2491eb9a029SZachary Turner
getSourceFileCount(uint32_t Modi) const2501eb9a029SZachary Turner uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const {
2511eb9a029SZachary Turner return ModFileCountArray[Modi];
2521eb9a029SZachary Turner }
2531eb9a029SZachary Turner
getModuleDescriptor(uint32_t Modi) const2541eb9a029SZachary Turner DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const {
2551eb9a029SZachary Turner assert(Modi < getModuleCount());
2561eb9a029SZachary Turner uint32_t Offset = ModuleDescriptorOffsets[Modi];
2571eb9a029SZachary Turner auto Iter = Descriptors.at(Offset);
2581eb9a029SZachary Turner assert(Iter != Descriptors.end());
2591eb9a029SZachary Turner return *Iter;
2601eb9a029SZachary Turner }
2611eb9a029SZachary Turner
2621eb9a029SZachary Turner iterator_range<DbiModuleSourceFilesIterator>
source_files(uint32_t Modi) const2631eb9a029SZachary Turner DbiModuleList::source_files(uint32_t Modi) const {
2641eb9a029SZachary Turner return make_range<DbiModuleSourceFilesIterator>(
2651eb9a029SZachary Turner DbiModuleSourceFilesIterator(*this, Modi, 0),
2661eb9a029SZachary Turner DbiModuleSourceFilesIterator());
2671eb9a029SZachary Turner }
2681eb9a029SZachary Turner
getFileName(uint32_t Index) const2691eb9a029SZachary Turner Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const {
2701eb9a029SZachary Turner BinaryStreamReader Names(NamesBuffer);
2711eb9a029SZachary Turner if (Index >= getSourceFileCount())
2721eb9a029SZachary Turner return make_error<RawError>(raw_error_code::index_out_of_bounds);
2731eb9a029SZachary Turner
2741eb9a029SZachary Turner uint32_t FileOffset = FileNameOffsets[Index];
2751eb9a029SZachary Turner Names.setOffset(FileOffset);
2761eb9a029SZachary Turner StringRef Name;
2771eb9a029SZachary Turner if (auto EC = Names.readCString(Name))
278c55cf4afSBill Wendling return std::move(EC);
2791eb9a029SZachary Turner return Name;
2801eb9a029SZachary Turner }
281