1 //===- DbiModuleList.cpp - PDB module information list --------------------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 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/DebugInfo/PDB/Native/RawTypes.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 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:: 31 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:: 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 if (*this == R) 66 return false; 67 68 return Filei < R.Filei; 69 } 70 71 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 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:: 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:: 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 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 133 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 148 bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; } 149 150 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 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 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 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 242 uint32_t DbiModuleList::getModuleCount() const { 243 return FileInfoHeader->NumModules; 244 } 245 246 uint32_t DbiModuleList::getSourceFileCount() const { 247 return FileNameOffsets.size(); 248 } 249 250 uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const { 251 return ModFileCountArray[Modi]; 252 } 253 254 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> 263 DbiModuleList::source_files(uint32_t Modi) const { 264 return make_range<DbiModuleSourceFilesIterator>( 265 DbiModuleSourceFilesIterator(*this, Modi, 0), 266 DbiModuleSourceFilesIterator()); 267 } 268 269 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