Line data Source code
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 :
24 67 : DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator(
25 67 : const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei)
26 67 : : Modules(&Modules), Modi(Modi), Filei(Filei) {
27 67 : setValue();
28 67 : }
29 :
30 388 : bool DbiModuleSourceFilesIterator::
31 : operator==(const DbiModuleSourceFilesIterator &R) const {
32 : // incompatible iterators are never equal
33 388 : if (!isCompatible(R))
34 : return false;
35 :
36 : // If they're compatible, and they're both ends, then they're equal.
37 388 : if (isEnd() && R.isEnd())
38 : return true;
39 :
40 : // If one is an end and the other is not, they're not equal.
41 328 : 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 0 : return (Filei == R.Filei);
56 : }
57 :
58 0 : bool DbiModuleSourceFilesIterator::
59 : 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 0 : if (*this == R)
66 : return false;
67 :
68 0 : return Filei < R.Filei;
69 : }
70 :
71 24 : std::ptrdiff_t DbiModuleSourceFilesIterator::
72 : 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 24 : 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 10 : uint32_t Thisi = Filei;
87 10 : if (isEnd()) {
88 10 : uint32_t RealModi = R.Modi;
89 10 : Thisi = R.Modules->getSourceFileCount(RealModi);
90 : }
91 :
92 : assert(Thisi >= R.Filei);
93 10 : return Thisi - R.Filei;
94 : }
95 :
96 328 : DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
97 : operator+=(std::ptrdiff_t N) {
98 : assert(!isEnd());
99 :
100 328 : Filei += N;
101 : assert(Filei <= Modules->getSourceFileCount(Modi));
102 328 : setValue();
103 328 : return *this;
104 : }
105 :
106 0 : DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
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 0 : Filei -= N;
115 0 : return *this;
116 : }
117 :
118 395 : void DbiModuleSourceFilesIterator::setValue() {
119 395 : if (isEnd()) {
120 67 : ThisValue = "";
121 67 : return;
122 : }
123 :
124 328 : uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei;
125 328 : auto ExpectedValue = Modules->getFileName(Off);
126 328 : if (!ExpectedValue) {
127 0 : consumeError(ExpectedValue.takeError());
128 0 : Filei = Modules->getSourceFileCount(Modi);
129 : } else
130 328 : ThisValue = *ExpectedValue;
131 : }
132 :
133 1557 : bool DbiModuleSourceFilesIterator::isEnd() const {
134 1557 : if (isUniversalEnd())
135 : return true;
136 :
137 : assert(Modules);
138 : assert(Modi <= Modules->getModuleCount());
139 : assert(Filei <= Modules->getSourceFileCount(Modi));
140 :
141 1135 : if (Modi == Modules->getModuleCount())
142 : return true;
143 1135 : if (Filei == Modules->getSourceFileCount(Modi))
144 141 : return true;
145 : return false;
146 : }
147 :
148 2333 : bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; }
149 :
150 388 : bool DbiModuleSourceFilesIterator::isCompatible(
151 : const DbiModuleSourceFilesIterator &R) const {
152 : // Universal iterators are compatible with any other iterator.
153 388 : if (isUniversalEnd() || R.isUniversalEnd())
154 388 : 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 0 : return Modi == R.Modi;
161 : }
162 :
163 122 : Error DbiModuleList::initialize(BinaryStreamRef ModInfo,
164 : BinaryStreamRef FileInfo) {
165 244 : if (auto EC = initializeModInfo(ModInfo))
166 : return EC;
167 244 : if (auto EC = initializeFileInfo(FileInfo))
168 : return EC;
169 :
170 : return Error::success();
171 : }
172 :
173 122 : Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) {
174 : ModInfoSubstream = ModInfo;
175 :
176 122 : if (ModInfo.getLength() == 0)
177 : return Error::success();
178 :
179 224 : BinaryStreamReader Reader(ModInfo);
180 :
181 224 : if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength()))
182 : return EC;
183 :
184 : return Error::success();
185 : }
186 :
187 122 : Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) {
188 : FileInfoSubstream = FileInfo;
189 :
190 122 : if (FileInfo.getLength() == 0)
191 : return Error::success();
192 :
193 122 : BinaryStreamReader FISR(FileInfo);
194 244 : 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 366 : if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules))
201 : return EC;
202 366 : 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 592 : for (auto Count : ModFileCountArray)
211 470 : 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 244 : if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
218 : return EC;
219 :
220 244 : if (auto EC = FISR.readStreamRef(NamesBuffer))
221 : return EC;
222 :
223 244 : auto DescriptorIter = Descriptors.begin();
224 : uint32_t NextFileIndex = 0;
225 244 : ModuleInitialFileIndex.resize(FileInfoHeader->NumModules);
226 244 : ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules);
227 714 : for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) {
228 : assert(DescriptorIter != Descriptors.end());
229 470 : ModuleInitialFileIndex[I] = NextFileIndex;
230 470 : ModuleDescriptorOffsets[I] = DescriptorIter.offset();
231 :
232 470 : NextFileIndex += ModFileCountArray[I];
233 : ++DescriptorIter;
234 : }
235 :
236 : assert(DescriptorIter == Descriptors.end());
237 : assert(NextFileIndex == NumSourceFiles);
238 :
239 : return Error::success();
240 : }
241 :
242 2219 : uint32_t DbiModuleList::getModuleCount() const {
243 4438 : return FileInfoHeader->NumModules;
244 : }
245 :
246 328 : uint32_t DbiModuleList::getSourceFileCount() const {
247 328 : return FileNameOffsets.size();
248 : }
249 :
250 1145 : uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const {
251 1145 : return ModFileCountArray[Modi];
252 : }
253 :
254 517 : DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const {
255 : assert(Modi < getModuleCount());
256 517 : uint32_t Offset = ModuleDescriptorOffsets[Modi];
257 1034 : auto Iter = Descriptors.at(Offset);
258 : assert(Iter != Descriptors.end());
259 517 : return *Iter;
260 : }
261 :
262 : iterator_range<DbiModuleSourceFilesIterator>
263 67 : DbiModuleList::source_files(uint32_t Modi) const {
264 : return make_range<DbiModuleSourceFilesIterator>(
265 : DbiModuleSourceFilesIterator(*this, Modi, 0),
266 67 : DbiModuleSourceFilesIterator());
267 : }
268 :
269 328 : Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const {
270 328 : BinaryStreamReader Names(NamesBuffer);
271 328 : if (Index >= getSourceFileCount())
272 : return make_error<RawError>(raw_error_code::index_out_of_bounds);
273 :
274 328 : uint32_t FileOffset = FileNameOffsets[Index];
275 : Names.setOffset(FileOffset);
276 328 : StringRef Name;
277 656 : if (auto EC = Names.readCString(Name))
278 : return std::move(EC);
279 : return Name;
280 : }
|