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