1 //===- DbiModuleList.cpp - PDB module information list --------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/ADT/iterator_range.h"
12 #include "llvm/DebugInfo/PDB/Native/RawError.h"
13 #include "llvm/Support/BinaryStreamReader.h"
14 #include "llvm/Support/Error.h"
21 using namespace llvm::pdb
;
23 DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator(
24 const DbiModuleList
&Modules
, uint32_t Modi
, uint16_t Filei
)
25 : Modules(&Modules
), Modi(Modi
), Filei(Filei
) {
29 bool DbiModuleSourceFilesIterator::
30 operator==(const DbiModuleSourceFilesIterator
&R
) const {
31 // incompatible iterators are never equal
35 // If they're compatible, and they're both ends, then they're equal.
36 if (isEnd() && R
.isEnd())
39 // If one is an end and the other is not, they're not equal.
40 if (isEnd() != R
.isEnd())
44 // - They're compatible
45 // - They're not *both* end iterators
46 // - Their endness is the same.
47 // Thus, they're compatible iterators pointing to a valid file on the same
48 // module. All we need to check are the file indices.
49 assert(Modules
== R
.Modules
);
50 assert(Modi
== R
.Modi
);
54 return (Filei
== R
.Filei
);
57 bool DbiModuleSourceFilesIterator::
58 operator<(const DbiModuleSourceFilesIterator
&R
) const {
59 assert(isCompatible(R
));
61 // It's not sufficient to compare the file indices, because default
62 // constructed iterators could be equal to iterators with valid indices. To
63 // account for this, early-out if they're equal.
67 return Filei
< R
.Filei
;
70 std::ptrdiff_t DbiModuleSourceFilesIterator::
71 operator-(const DbiModuleSourceFilesIterator
&R
) const {
72 assert(isCompatible(R
));
75 // If they're both end iterators, the distance is 0.
76 if (isEnd() && R
.isEnd())
81 // At this point, R cannot be end, but *this can, which means that *this
82 // might be a universal end iterator with none of its fields set. So in that
83 // case have to rely on R as the authority to figure out how many files there
84 // are to compute the distance.
85 uint32_t Thisi
= Filei
;
87 uint32_t RealModi
= R
.Modi
;
88 Thisi
= R
.Modules
->getSourceFileCount(RealModi
);
91 assert(Thisi
>= R
.Filei
);
92 return Thisi
- R
.Filei
;
95 DbiModuleSourceFilesIterator
&DbiModuleSourceFilesIterator::
96 operator+=(std::ptrdiff_t N
) {
100 assert(Filei
<= Modules
->getSourceFileCount(Modi
));
105 DbiModuleSourceFilesIterator
&DbiModuleSourceFilesIterator::
106 operator-=(std::ptrdiff_t N
) {
107 // Note that we can subtract from an end iterator, but not a universal end
109 assert(!isUniversalEnd());
117 void DbiModuleSourceFilesIterator::setValue() {
123 uint32_t Off
= Modules
->ModuleInitialFileIndex
[Modi
] + Filei
;
124 auto ExpectedValue
= Modules
->getFileName(Off
);
125 if (!ExpectedValue
) {
126 consumeError(ExpectedValue
.takeError());
127 Filei
= Modules
->getSourceFileCount(Modi
);
129 ThisValue
= *ExpectedValue
;
132 bool DbiModuleSourceFilesIterator::isEnd() const {
133 if (isUniversalEnd())
137 assert(Modi
<= Modules
->getModuleCount());
138 assert(Filei
<= Modules
->getSourceFileCount(Modi
));
140 if (Modi
== Modules
->getModuleCount())
142 if (Filei
== Modules
->getSourceFileCount(Modi
))
147 bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules
; }
149 bool DbiModuleSourceFilesIterator::isCompatible(
150 const DbiModuleSourceFilesIterator
&R
) const {
151 // Universal iterators are compatible with any other iterator.
152 if (isUniversalEnd() || R
.isUniversalEnd())
155 // At this point, neither iterator is a universal end iterator, although one
156 // or both might be non-universal end iterators. Regardless, the module index
157 // is valid, so they are compatible if and only if they refer to the same
159 return Modi
== R
.Modi
;
162 Error
DbiModuleList::initialize(BinaryStreamRef ModInfo
,
163 BinaryStreamRef FileInfo
) {
164 if (auto EC
= initializeModInfo(ModInfo
))
166 if (auto EC
= initializeFileInfo(FileInfo
))
169 return Error::success();
172 Error
DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo
) {
173 ModInfoSubstream
= ModInfo
;
175 if (ModInfo
.getLength() == 0)
176 return Error::success();
178 BinaryStreamReader
Reader(ModInfo
);
180 if (auto EC
= Reader
.readArray(Descriptors
, ModInfo
.getLength()))
183 return Error::success();
186 Error
DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo
) {
187 FileInfoSubstream
= FileInfo
;
189 if (FileInfo
.getLength() == 0)
190 return Error::success();
192 BinaryStreamReader
FISR(FileInfo
);
193 if (auto EC
= FISR
.readObject(FileInfoHeader
))
196 // First is an array of `NumModules` module indices. This does not seem to be
197 // used for anything meaningful, so we ignore it.
198 FixedStreamArray
<support::ulittle16_t
> ModuleIndices
;
199 if (auto EC
= FISR
.readArray(ModuleIndices
, FileInfoHeader
->NumModules
))
201 if (auto EC
= FISR
.readArray(ModFileCountArray
, FileInfoHeader
->NumModules
))
204 // Compute the real number of source files. We can't trust the value in
205 // `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all
206 // source file counts might be larger than a unit16. So we compute the real
207 // count by summing up the individual counts.
208 uint32_t NumSourceFiles
= 0;
209 for (auto Count
: ModFileCountArray
)
210 NumSourceFiles
+= Count
;
212 // In the reference implementation, this array is where the pointer documented
213 // at the definition of ModuleInfoHeader::FileNameOffs points to. Note that
214 // although the field in ModuleInfoHeader is ignored this array is not, as it
215 // is the authority on where each filename begins in the names buffer.
216 if (auto EC
= FISR
.readArray(FileNameOffsets
, NumSourceFiles
))
219 if (auto EC
= FISR
.readStreamRef(NamesBuffer
))
222 auto DescriptorIter
= Descriptors
.begin();
223 uint32_t NextFileIndex
= 0;
224 ModuleInitialFileIndex
.resize(FileInfoHeader
->NumModules
);
225 ModuleDescriptorOffsets
.resize(FileInfoHeader
->NumModules
);
226 for (size_t I
= 0; I
< FileInfoHeader
->NumModules
; ++I
) {
227 assert(DescriptorIter
!= Descriptors
.end());
228 ModuleInitialFileIndex
[I
] = NextFileIndex
;
229 ModuleDescriptorOffsets
[I
] = DescriptorIter
.offset();
231 NextFileIndex
+= ModFileCountArray
[I
];
235 assert(DescriptorIter
== Descriptors
.end());
236 assert(NextFileIndex
== NumSourceFiles
);
238 return Error::success();
241 uint32_t DbiModuleList::getModuleCount() const {
242 return FileInfoHeader
->NumModules
;
245 uint32_t DbiModuleList::getSourceFileCount() const {
246 return FileNameOffsets
.size();
249 uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi
) const {
250 return ModFileCountArray
[Modi
];
253 DbiModuleDescriptor
DbiModuleList::getModuleDescriptor(uint32_t Modi
) const {
254 assert(Modi
< getModuleCount());
255 uint32_t Offset
= ModuleDescriptorOffsets
[Modi
];
256 auto Iter
= Descriptors
.at(Offset
);
257 assert(Iter
!= Descriptors
.end());
261 iterator_range
<DbiModuleSourceFilesIterator
>
262 DbiModuleList::source_files(uint32_t Modi
) const {
263 return make_range
<DbiModuleSourceFilesIterator
>(
264 DbiModuleSourceFilesIterator(*this, Modi
, 0),
265 DbiModuleSourceFilesIterator());
268 Expected
<StringRef
> DbiModuleList::getFileName(uint32_t Index
) const {
269 BinaryStreamReader
Names(NamesBuffer
);
270 if (Index
>= getSourceFileCount())
271 return make_error
<RawError
>(raw_error_code::index_out_of_bounds
);
273 uint32_t FileOffset
= FileNameOffsets
[Index
];
274 Names
.setOffset(FileOffset
);
276 if (auto EC
= Names
.readCString(Name
))
277 return std::move(EC
);