1 //===- DbiModuleList.cpp - PDB module information list ----------*- C++ -*-===// 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 #include "llvm/DebugInfo/PDB/Native/DbiModuleList.h" 10 11 #include "llvm/DebugInfo/PDB/Native/RawError.h" 12 #include "llvm/Support/Error.h" 13 14 using namespace llvm; 15 using namespace llvm::pdb; 16 17 DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator( 18 const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei) 19 : Modules(&Modules), Modi(Modi), Filei(Filei) { 20 setValue(); 21 } 22 23 bool DbiModuleSourceFilesIterator:: 24 operator==(const DbiModuleSourceFilesIterator &R) const { 25 // incompatible iterators are never equal 26 if (!isCompatible(R)) 27 return false; 28 29 // If they're compatible, and they're both ends, then they're equal. 30 if (isEnd() && R.isEnd()) 31 return true; 32 33 // If one is an end and the other is not, they're not equal. 34 if (isEnd() != R.isEnd()) 35 return false; 36 37 // Now we know: 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); 45 assert(!isEnd()); 46 assert(!R.isEnd()); 47 48 return (Filei == R.Filei); 49 } 50 51 bool DbiModuleSourceFilesIterator:: 52 operator<(const DbiModuleSourceFilesIterator &R) const { 53 assert(isCompatible(R)); 54 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. 58 if (*this == R) 59 return false; 60 61 return Filei < R.Filei; 62 } 63 64 std::ptrdiff_t DbiModuleSourceFilesIterator:: 65 operator-(const DbiModuleSourceFilesIterator &R) const { 66 assert(isCompatible(R)); 67 assert(!(*this < R)); 68 69 // If they're both end iterators, the distance is 0. 70 if (isEnd() && R.isEnd()) 71 return 0; 72 73 assert(!R.isEnd()); 74 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; 80 if (isEnd()) { 81 uint32_t RealModi = R.Modi; 82 Thisi = R.Modules->getSourceFileCount(RealModi); 83 } 84 85 assert(Thisi >= R.Filei); 86 return Thisi - R.Filei; 87 } 88 89 DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator:: 90 operator+=(std::ptrdiff_t N) { 91 assert(!isEnd()); 92 93 Filei += N; 94 assert(Filei <= Modules->getSourceFileCount(Modi)); 95 setValue(); 96 return *this; 97 } 98 99 DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator:: 100 operator-=(std::ptrdiff_t N) { 101 // Note that we can subtract from an end iterator, but not a universal end 102 // iterator. 103 assert(!isUniversalEnd()); 104 105 assert(N <= Filei); 106 107 Filei -= N; 108 return *this; 109 } 110 111 void DbiModuleSourceFilesIterator::setValue() { 112 if (isEnd()) { 113 ThisValue = ""; 114 return; 115 } 116 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); 122 } else 123 ThisValue = *ExpectedValue; 124 } 125 126 bool DbiModuleSourceFilesIterator::isEnd() const { 127 if (isUniversalEnd()) 128 return true; 129 130 assert(Modules); 131 assert(Modi <= Modules->getModuleCount()); 132 assert(Filei <= Modules->getSourceFileCount(Modi)); 133 134 if (Modi == Modules->getModuleCount()) 135 return true; 136 if (Filei == Modules->getSourceFileCount(Modi)) 137 return true; 138 return false; 139 } 140 141 bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; } 142 143 bool DbiModuleSourceFilesIterator::isCompatible( 144 const DbiModuleSourceFilesIterator &R) const { 145 // Universal iterators are compatible with any other iterator. 146 if (isUniversalEnd() || R.isUniversalEnd()) 147 return true; 148 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 152 // module. 153 return Modi == R.Modi; 154 } 155 156 Error DbiModuleList::initialize(BinaryStreamRef ModInfo, 157 BinaryStreamRef FileInfo) { 158 if (auto EC = initializeModInfo(ModInfo)) 159 return EC; 160 if (auto EC = initializeFileInfo(FileInfo)) 161 return EC; 162 163 return Error::success(); 164 } 165 166 Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) { 167 ModInfoSubstream = ModInfo; 168 169 if (ModInfo.getLength() == 0) 170 return Error::success(); 171 172 BinaryStreamReader Reader(ModInfo); 173 174 if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength())) 175 return EC; 176 177 return Error::success(); 178 } 179 180 Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) { 181 FileInfoSubstream = FileInfo; 182 183 if (FileInfo.getLength() == 0) 184 return Error::success(); 185 186 BinaryStreamReader FISR(FileInfo); 187 if (auto EC = FISR.readObject(FileInfoHeader)) 188 return EC; 189 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)) 194 return EC; 195 if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules)) 196 return EC; 197 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; 205 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)) 211 return EC; 212 213 if (auto EC = FISR.readStreamRef(NamesBuffer)) 214 return EC; 215 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(); 224 225 NextFileIndex += ModFileCountArray[I]; 226 ++DescriptorIter; 227 } 228 229 assert(DescriptorIter == Descriptors.end()); 230 assert(NextFileIndex == NumSourceFiles); 231 232 return Error::success(); 233 } 234 235 uint32_t DbiModuleList::getModuleCount() const { 236 return FileInfoHeader->NumModules; 237 } 238 239 uint32_t DbiModuleList::getSourceFileCount() const { 240 return FileNameOffsets.size(); 241 } 242 243 uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const { 244 return ModFileCountArray[Modi]; 245 } 246 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()); 252 return *Iter; 253 } 254 255 iterator_range<DbiModuleSourceFilesIterator> 256 DbiModuleList::source_files(uint32_t Modi) const { 257 return make_range<DbiModuleSourceFilesIterator>( 258 DbiModuleSourceFilesIterator(*this, Modi, 0), 259 DbiModuleSourceFilesIterator()); 260 } 261 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); 266 267 uint32_t FileOffset = FileNameOffsets[Index]; 268 Names.setOffset(FileOffset); 269 StringRef Name; 270 if (auto EC = Names.readCString(Name)) 271 return std::move(EC); 272 return Name; 273 } 274