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