109467b48Spatrick //===- DbiModuleList.cpp - PDB module information list --------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick 
909467b48Spatrick #include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
1009467b48Spatrick #include "llvm/ADT/StringRef.h"
1109467b48Spatrick #include "llvm/ADT/iterator_range.h"
1209467b48Spatrick #include "llvm/DebugInfo/PDB/Native/RawError.h"
13*d415bd75Srobert #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
1409467b48Spatrick #include "llvm/Support/BinaryStreamReader.h"
1509467b48Spatrick #include "llvm/Support/Error.h"
1609467b48Spatrick #include <algorithm>
1709467b48Spatrick #include <cassert>
1809467b48Spatrick #include <cstddef>
1909467b48Spatrick #include <cstdint>
2009467b48Spatrick 
2109467b48Spatrick using namespace llvm;
2209467b48Spatrick using namespace llvm::pdb;
2309467b48Spatrick 
DbiModuleSourceFilesIterator(const DbiModuleList & Modules,uint32_t Modi,uint16_t Filei)2409467b48Spatrick DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator(
2509467b48Spatrick     const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei)
2609467b48Spatrick     : Modules(&Modules), Modi(Modi), Filei(Filei) {
2709467b48Spatrick   setValue();
2809467b48Spatrick }
2909467b48Spatrick 
3009467b48Spatrick bool DbiModuleSourceFilesIterator::
operator ==(const DbiModuleSourceFilesIterator & R) const3109467b48Spatrick operator==(const DbiModuleSourceFilesIterator &R) const {
3209467b48Spatrick   // incompatible iterators are never equal
3309467b48Spatrick   if (!isCompatible(R))
3409467b48Spatrick     return false;
3509467b48Spatrick 
3609467b48Spatrick   // If they're compatible, and they're both ends, then they're equal.
3709467b48Spatrick   if (isEnd() && R.isEnd())
3809467b48Spatrick     return true;
3909467b48Spatrick 
4009467b48Spatrick   // If one is an end and the other is not, they're not equal.
4109467b48Spatrick   if (isEnd() != R.isEnd())
4209467b48Spatrick     return false;
4309467b48Spatrick 
4409467b48Spatrick   // Now we know:
4509467b48Spatrick   // - They're compatible
4609467b48Spatrick   // - They're not *both* end iterators
4709467b48Spatrick   // - Their endness is the same.
4809467b48Spatrick   // Thus, they're compatible iterators pointing to a valid file on the same
4909467b48Spatrick   // module.  All we need to check are the file indices.
5009467b48Spatrick   assert(Modules == R.Modules);
5109467b48Spatrick   assert(Modi == R.Modi);
5209467b48Spatrick   assert(!isEnd());
5309467b48Spatrick   assert(!R.isEnd());
5409467b48Spatrick 
5509467b48Spatrick   return (Filei == R.Filei);
5609467b48Spatrick }
5709467b48Spatrick 
5809467b48Spatrick bool DbiModuleSourceFilesIterator::
operator <(const DbiModuleSourceFilesIterator & R) const5909467b48Spatrick operator<(const DbiModuleSourceFilesIterator &R) const {
6009467b48Spatrick   assert(isCompatible(R));
6109467b48Spatrick 
6209467b48Spatrick   // It's not sufficient to compare the file indices, because default
6309467b48Spatrick   // constructed iterators could be equal to iterators with valid indices.  To
6409467b48Spatrick   // account for this, early-out if they're equal.
6509467b48Spatrick   if (*this == R)
6609467b48Spatrick     return false;
6709467b48Spatrick 
6809467b48Spatrick   return Filei < R.Filei;
6909467b48Spatrick }
7009467b48Spatrick 
7109467b48Spatrick std::ptrdiff_t DbiModuleSourceFilesIterator::
operator -(const DbiModuleSourceFilesIterator & R) const7209467b48Spatrick operator-(const DbiModuleSourceFilesIterator &R) const {
7309467b48Spatrick   assert(isCompatible(R));
7409467b48Spatrick   assert(!(*this < R));
7509467b48Spatrick 
7609467b48Spatrick   // If they're both end iterators, the distance is 0.
7709467b48Spatrick   if (isEnd() && R.isEnd())
7809467b48Spatrick     return 0;
7909467b48Spatrick 
8009467b48Spatrick   assert(!R.isEnd());
8109467b48Spatrick 
8209467b48Spatrick   // At this point, R cannot be end, but *this can, which means that *this
8309467b48Spatrick   // might be a universal end iterator with none of its fields set.  So in that
8409467b48Spatrick   // case have to rely on R as the authority to figure out how many files there
8509467b48Spatrick   // are to compute the distance.
8609467b48Spatrick   uint32_t Thisi = Filei;
8709467b48Spatrick   if (isEnd()) {
8809467b48Spatrick     uint32_t RealModi = R.Modi;
8909467b48Spatrick     Thisi = R.Modules->getSourceFileCount(RealModi);
9009467b48Spatrick   }
9109467b48Spatrick 
9209467b48Spatrick   assert(Thisi >= R.Filei);
9309467b48Spatrick   return Thisi - R.Filei;
9409467b48Spatrick }
9509467b48Spatrick 
9609467b48Spatrick DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
operator +=(std::ptrdiff_t N)9709467b48Spatrick operator+=(std::ptrdiff_t N) {
9809467b48Spatrick   assert(!isEnd());
9909467b48Spatrick 
10009467b48Spatrick   Filei += N;
10109467b48Spatrick   assert(Filei <= Modules->getSourceFileCount(Modi));
10209467b48Spatrick   setValue();
10309467b48Spatrick   return *this;
10409467b48Spatrick }
10509467b48Spatrick 
10609467b48Spatrick DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
operator -=(std::ptrdiff_t N)10709467b48Spatrick operator-=(std::ptrdiff_t N) {
10809467b48Spatrick   // Note that we can subtract from an end iterator, but not a universal end
10909467b48Spatrick   // iterator.
11009467b48Spatrick   assert(!isUniversalEnd());
11109467b48Spatrick 
11209467b48Spatrick   assert(N <= Filei);
11309467b48Spatrick 
11409467b48Spatrick   Filei -= N;
11509467b48Spatrick   return *this;
11609467b48Spatrick }
11709467b48Spatrick 
setValue()11809467b48Spatrick void DbiModuleSourceFilesIterator::setValue() {
11909467b48Spatrick   if (isEnd()) {
12009467b48Spatrick     ThisValue = "";
12109467b48Spatrick     return;
12209467b48Spatrick   }
12309467b48Spatrick 
12409467b48Spatrick   uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei;
12509467b48Spatrick   auto ExpectedValue = Modules->getFileName(Off);
12609467b48Spatrick   if (!ExpectedValue) {
12709467b48Spatrick     consumeError(ExpectedValue.takeError());
12809467b48Spatrick     Filei = Modules->getSourceFileCount(Modi);
12909467b48Spatrick   } else
13009467b48Spatrick     ThisValue = *ExpectedValue;
13109467b48Spatrick }
13209467b48Spatrick 
isEnd() const13309467b48Spatrick bool DbiModuleSourceFilesIterator::isEnd() const {
13409467b48Spatrick   if (isUniversalEnd())
13509467b48Spatrick     return true;
13609467b48Spatrick 
13709467b48Spatrick   assert(Modules);
13809467b48Spatrick   assert(Modi <= Modules->getModuleCount());
13909467b48Spatrick   assert(Filei <= Modules->getSourceFileCount(Modi));
14009467b48Spatrick 
14109467b48Spatrick   if (Modi == Modules->getModuleCount())
14209467b48Spatrick     return true;
14309467b48Spatrick   if (Filei == Modules->getSourceFileCount(Modi))
14409467b48Spatrick     return true;
14509467b48Spatrick   return false;
14609467b48Spatrick }
14709467b48Spatrick 
isUniversalEnd() const14809467b48Spatrick bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; }
14909467b48Spatrick 
isCompatible(const DbiModuleSourceFilesIterator & R) const15009467b48Spatrick bool DbiModuleSourceFilesIterator::isCompatible(
15109467b48Spatrick     const DbiModuleSourceFilesIterator &R) const {
15209467b48Spatrick   // Universal iterators are compatible with any other iterator.
15309467b48Spatrick   if (isUniversalEnd() || R.isUniversalEnd())
15409467b48Spatrick     return true;
15509467b48Spatrick 
15609467b48Spatrick   // At this point, neither iterator is a universal end iterator, although one
15709467b48Spatrick   // or both might be non-universal end iterators.  Regardless, the module index
15809467b48Spatrick   // is valid, so they are compatible if and only if they refer to the same
15909467b48Spatrick   // module.
16009467b48Spatrick   return Modi == R.Modi;
16109467b48Spatrick }
16209467b48Spatrick 
initialize(BinaryStreamRef ModInfo,BinaryStreamRef FileInfo)16309467b48Spatrick Error DbiModuleList::initialize(BinaryStreamRef ModInfo,
16409467b48Spatrick                                 BinaryStreamRef FileInfo) {
16509467b48Spatrick   if (auto EC = initializeModInfo(ModInfo))
16609467b48Spatrick     return EC;
16709467b48Spatrick   if (auto EC = initializeFileInfo(FileInfo))
16809467b48Spatrick     return EC;
16909467b48Spatrick 
17009467b48Spatrick   return Error::success();
17109467b48Spatrick }
17209467b48Spatrick 
initializeModInfo(BinaryStreamRef ModInfo)17309467b48Spatrick Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) {
17409467b48Spatrick   ModInfoSubstream = ModInfo;
17509467b48Spatrick 
17609467b48Spatrick   if (ModInfo.getLength() == 0)
17709467b48Spatrick     return Error::success();
17809467b48Spatrick 
17909467b48Spatrick   BinaryStreamReader Reader(ModInfo);
18009467b48Spatrick 
18109467b48Spatrick   if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength()))
18209467b48Spatrick     return EC;
18309467b48Spatrick 
18409467b48Spatrick   return Error::success();
18509467b48Spatrick }
18609467b48Spatrick 
initializeFileInfo(BinaryStreamRef FileInfo)18709467b48Spatrick Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) {
18809467b48Spatrick   FileInfoSubstream = FileInfo;
18909467b48Spatrick 
19009467b48Spatrick   if (FileInfo.getLength() == 0)
19109467b48Spatrick     return Error::success();
19209467b48Spatrick 
19309467b48Spatrick   BinaryStreamReader FISR(FileInfo);
19409467b48Spatrick   if (auto EC = FISR.readObject(FileInfoHeader))
19509467b48Spatrick     return EC;
19609467b48Spatrick 
19709467b48Spatrick   // First is an array of `NumModules` module indices.  This does not seem to be
19809467b48Spatrick   // used for anything meaningful, so we ignore it.
19909467b48Spatrick   FixedStreamArray<support::ulittle16_t> ModuleIndices;
20009467b48Spatrick   if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules))
20109467b48Spatrick     return EC;
20209467b48Spatrick   if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules))
20309467b48Spatrick     return EC;
20409467b48Spatrick 
20509467b48Spatrick   // Compute the real number of source files.  We can't trust the value in
20609467b48Spatrick   // `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all
20709467b48Spatrick   // source file counts might be larger than a unit16.  So we compute the real
20809467b48Spatrick   // count by summing up the individual counts.
20909467b48Spatrick   uint32_t NumSourceFiles = 0;
21009467b48Spatrick   for (auto Count : ModFileCountArray)
21109467b48Spatrick     NumSourceFiles += Count;
21209467b48Spatrick 
21309467b48Spatrick   // In the reference implementation, this array is where the pointer documented
21409467b48Spatrick   // at the definition of ModuleInfoHeader::FileNameOffs points to.  Note that
21509467b48Spatrick   // although the field in ModuleInfoHeader is ignored this array is not, as it
21609467b48Spatrick   // is the authority on where each filename begins in the names buffer.
21709467b48Spatrick   if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
21809467b48Spatrick     return EC;
21909467b48Spatrick 
22009467b48Spatrick   if (auto EC = FISR.readStreamRef(NamesBuffer))
22109467b48Spatrick     return EC;
22209467b48Spatrick 
22309467b48Spatrick   auto DescriptorIter = Descriptors.begin();
22409467b48Spatrick   uint32_t NextFileIndex = 0;
22509467b48Spatrick   ModuleInitialFileIndex.resize(FileInfoHeader->NumModules);
22609467b48Spatrick   ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules);
22709467b48Spatrick   for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) {
22809467b48Spatrick     assert(DescriptorIter != Descriptors.end());
22909467b48Spatrick     ModuleInitialFileIndex[I] = NextFileIndex;
23009467b48Spatrick     ModuleDescriptorOffsets[I] = DescriptorIter.offset();
23109467b48Spatrick 
23209467b48Spatrick     NextFileIndex += ModFileCountArray[I];
23309467b48Spatrick     ++DescriptorIter;
23409467b48Spatrick   }
23509467b48Spatrick 
23609467b48Spatrick   assert(DescriptorIter == Descriptors.end());
23709467b48Spatrick   assert(NextFileIndex == NumSourceFiles);
23809467b48Spatrick 
23909467b48Spatrick   return Error::success();
24009467b48Spatrick }
24109467b48Spatrick 
getModuleCount() const24209467b48Spatrick uint32_t DbiModuleList::getModuleCount() const {
24309467b48Spatrick   return FileInfoHeader->NumModules;
24409467b48Spatrick }
24509467b48Spatrick 
getSourceFileCount() const24609467b48Spatrick uint32_t DbiModuleList::getSourceFileCount() const {
24709467b48Spatrick   return FileNameOffsets.size();
24809467b48Spatrick }
24909467b48Spatrick 
getSourceFileCount(uint32_t Modi) const25009467b48Spatrick uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const {
25109467b48Spatrick   return ModFileCountArray[Modi];
25209467b48Spatrick }
25309467b48Spatrick 
getModuleDescriptor(uint32_t Modi) const25409467b48Spatrick DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const {
25509467b48Spatrick   assert(Modi < getModuleCount());
25609467b48Spatrick   uint32_t Offset = ModuleDescriptorOffsets[Modi];
25709467b48Spatrick   auto Iter = Descriptors.at(Offset);
25809467b48Spatrick   assert(Iter != Descriptors.end());
25909467b48Spatrick   return *Iter;
26009467b48Spatrick }
26109467b48Spatrick 
26209467b48Spatrick iterator_range<DbiModuleSourceFilesIterator>
source_files(uint32_t Modi) const26309467b48Spatrick DbiModuleList::source_files(uint32_t Modi) const {
26409467b48Spatrick   return make_range<DbiModuleSourceFilesIterator>(
26509467b48Spatrick       DbiModuleSourceFilesIterator(*this, Modi, 0),
26609467b48Spatrick       DbiModuleSourceFilesIterator());
26709467b48Spatrick }
26809467b48Spatrick 
getFileName(uint32_t Index) const26909467b48Spatrick Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const {
27009467b48Spatrick   BinaryStreamReader Names(NamesBuffer);
27109467b48Spatrick   if (Index >= getSourceFileCount())
27209467b48Spatrick     return make_error<RawError>(raw_error_code::index_out_of_bounds);
27309467b48Spatrick 
27409467b48Spatrick   uint32_t FileOffset = FileNameOffsets[Index];
27509467b48Spatrick   Names.setOffset(FileOffset);
27609467b48Spatrick   StringRef Name;
27709467b48Spatrick   if (auto EC = Names.readCString(Name))
27809467b48Spatrick     return std::move(EC);
27909467b48Spatrick   return Name;
28009467b48Spatrick }
281