1 //===- DbiModuleList.cpp - PDB module information list ----------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
11 #include "llvm/DebugInfo/PDB/Native/RawError.h"
12 #include "llvm/Support/Error.h"
15 using namespace llvm::pdb;
17 DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator(
18 const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei)
19 : Modules(&Modules), Modi(Modi), Filei(Filei) {
23 bool DbiModuleSourceFilesIterator::
24 operator==(const DbiModuleSourceFilesIterator &R) const {
25 // incompatible iterators are never equal
29 // If they're compatible, and they're both ends, then they're equal.
30 if (isEnd() && R.isEnd())
33 // If one is an end and the other is not, they're not equal.
34 if (isEnd() != R.isEnd())
38 // - They're compatible
39 // - They're not *both* end iterators
40 // - Their endness is the same.
41 // Thus, they're compatible iterators pointing to a valid file on the same
42 // module. All we need to check are the file indices.
43 assert(Modules == R.Modules);
44 assert(Modi == R.Modi);
48 return (Filei == R.Filei);
51 bool DbiModuleSourceFilesIterator::
52 operator<(const DbiModuleSourceFilesIterator &R) const {
53 assert(isCompatible(R));
55 // It's not sufficient to compare the file indices, because default
56 // constructed iterators could be equal to iterators with valid indices. To
57 // account for this, early-out if they're equal.
61 return Filei < R.Filei;
64 std::ptrdiff_t DbiModuleSourceFilesIterator::
65 operator-(const DbiModuleSourceFilesIterator &R) const {
66 assert(isCompatible(R));
69 // If they're both end iterators, the distance is 0.
70 if (isEnd() && R.isEnd())
75 // At this point, R cannot be end, but *this can, which means that *this
76 // might be a universal end iterator with none of its fields set. So in that
77 // case have to rely on R as the authority to figure out how many files there
78 // are to compute the distance.
79 uint32_t Thisi = Filei;
81 uint32_t RealModi = R.Modi;
82 Thisi = R.Modules->getSourceFileCount(RealModi);
85 assert(Thisi >= R.Filei);
86 return Thisi - R.Filei;
89 DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
90 operator+=(std::ptrdiff_t N) {
94 assert(Filei <= Modules->getSourceFileCount(Modi));
99 DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
100 operator-=(std::ptrdiff_t N) {
101 // Note that we can subtract from an end iterator, but not a universal end
103 assert(!isUniversalEnd());
111 void DbiModuleSourceFilesIterator::setValue() {
117 uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei;
118 auto ExpectedValue = Modules->getFileName(Off);
119 if (!ExpectedValue) {
120 consumeError(ExpectedValue.takeError());
121 Filei = Modules->getSourceFileCount(Modi);
123 ThisValue = *ExpectedValue;
126 bool DbiModuleSourceFilesIterator::isEnd() const {
127 if (isUniversalEnd())
131 assert(Modi <= Modules->getModuleCount());
132 assert(Filei <= Modules->getSourceFileCount(Modi));
134 if (Modi == Modules->getModuleCount())
136 if (Filei == Modules->getSourceFileCount(Modi))
141 bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; }
143 bool DbiModuleSourceFilesIterator::isCompatible(
144 const DbiModuleSourceFilesIterator &R) const {
145 // Universal iterators are compatible with any other iterator.
146 if (isUniversalEnd() || R.isUniversalEnd())
149 // At this point, neither iterator is a universal end iterator, although one
150 // or both might be non-universal end iterators. Regardless, the module index
151 // is valid, so they are compatible if and only if they refer to the same
153 return Modi == R.Modi;
156 Error DbiModuleList::initialize(BinaryStreamRef ModInfo,
157 BinaryStreamRef FileInfo) {
158 if (auto EC = initializeModInfo(ModInfo))
160 if (auto EC = initializeFileInfo(FileInfo))
163 return Error::success();
166 Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) {
167 ModInfoSubstream = ModInfo;
169 if (ModInfo.getLength() == 0)
170 return Error::success();
172 BinaryStreamReader Reader(ModInfo);
174 if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength()))
177 return Error::success();
180 Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) {
181 FileInfoSubstream = FileInfo;
183 if (FileInfo.getLength() == 0)
184 return Error::success();
186 BinaryStreamReader FISR(FileInfo);
187 if (auto EC = FISR.readObject(FileInfoHeader))
190 // First is an array of `NumModules` module indices. This does not seem to be
191 // used for anything meaningful, so we ignore it.
192 FixedStreamArray<support::ulittle16_t> ModuleIndices;
193 if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules))
195 if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules))
198 // Compute the real number of source files. We can't trust the value in
199 // `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all
200 // source file counts might be larger than a unit16. So we compute the real
201 // count by summing up the individual counts.
202 uint32_t NumSourceFiles = 0;
203 for (auto Count : ModFileCountArray)
204 NumSourceFiles += Count;
206 // In the reference implementation, this array is where the pointer documented
207 // at the definition of ModuleInfoHeader::FileNameOffs points to. Note that
208 // although the field in ModuleInfoHeader is ignored this array is not, as it
209 // is the authority on where each filename begins in the names buffer.
210 if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
213 if (auto EC = FISR.readStreamRef(NamesBuffer))
216 auto DescriptorIter = Descriptors.begin();
217 uint32_t NextFileIndex = 0;
218 ModuleInitialFileIndex.resize(FileInfoHeader->NumModules);
219 ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules);
220 for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) {
221 assert(DescriptorIter != Descriptors.end());
222 ModuleInitialFileIndex[I] = NextFileIndex;
223 ModuleDescriptorOffsets[I] = DescriptorIter.offset();
225 NextFileIndex += ModFileCountArray[I];
229 assert(DescriptorIter == Descriptors.end());
230 assert(NextFileIndex == NumSourceFiles);
232 return Error::success();
235 uint32_t DbiModuleList::getModuleCount() const {
236 return FileInfoHeader->NumModules;
239 uint32_t DbiModuleList::getSourceFileCount() const {
240 return FileNameOffsets.size();
243 uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const {
244 return ModFileCountArray[Modi];
247 DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const {
248 assert(Modi < getModuleCount());
249 uint32_t Offset = ModuleDescriptorOffsets[Modi];
250 auto Iter = Descriptors.at(Offset);
251 assert(Iter != Descriptors.end());
255 iterator_range<DbiModuleSourceFilesIterator>
256 DbiModuleList::source_files(uint32_t Modi) const {
257 return make_range<DbiModuleSourceFilesIterator>(
258 DbiModuleSourceFilesIterator(*this, Modi, 0),
259 DbiModuleSourceFilesIterator());
262 Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const {
263 BinaryStreamReader Names(NamesBuffer);
264 if (Index >= getSourceFileCount())
265 return make_error<RawError>(raw_error_code::index_out_of_bounds);
267 uint32_t FileOffset = FileNameOffsets[Index];
268 Names.setOffset(FileOffset);
270 if (auto EC = Names.readCString(Name))
271 return std::move(EC);