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