DbiModuleList.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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. #include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
  9. #include "llvm/ADT/StringRef.h"
  10. #include "llvm/ADT/iterator_range.h"
  11. #include "llvm/DebugInfo/PDB/Native/RawError.h"
  12. #include "llvm/Support/BinaryStreamReader.h"
  13. #include "llvm/Support/Error.h"
  14. #include <algorithm>
  15. #include <cassert>
  16. #include <cstddef>
  17. #include <cstdint>
  18. using namespace llvm;
  19. using namespace llvm::pdb;
  20. DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator(
  21. const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei)
  22. : Modules(&Modules), Modi(Modi), Filei(Filei) {
  23. setValue();
  24. }
  25. bool DbiModuleSourceFilesIterator::
  26. operator==(const DbiModuleSourceFilesIterator &R) const {
  27. // incompatible iterators are never equal
  28. if (!isCompatible(R))
  29. return false;
  30. // If they're compatible, and they're both ends, then they're equal.
  31. if (isEnd() && R.isEnd())
  32. return true;
  33. // If one is an end and the other is not, they're not equal.
  34. if (isEnd() != R.isEnd())
  35. return false;
  36. // Now we know:
  37. // - They're compatible
  38. // - They're not *both* end iterators
  39. // - Their endness is the same.
  40. // Thus, they're compatible iterators pointing to a valid file on the same
  41. // module. All we need to check are the file indices.
  42. assert(Modules == R.Modules);
  43. assert(Modi == R.Modi);
  44. assert(!isEnd());
  45. assert(!R.isEnd());
  46. return (Filei == R.Filei);
  47. }
  48. bool DbiModuleSourceFilesIterator::
  49. operator<(const DbiModuleSourceFilesIterator &R) const {
  50. assert(isCompatible(R));
  51. // It's not sufficient to compare the file indices, because default
  52. // constructed iterators could be equal to iterators with valid indices. To
  53. // account for this, early-out if they're equal.
  54. if (*this == R)
  55. return false;
  56. return Filei < R.Filei;
  57. }
  58. std::ptrdiff_t DbiModuleSourceFilesIterator::
  59. operator-(const DbiModuleSourceFilesIterator &R) const {
  60. assert(isCompatible(R));
  61. assert(!(*this < R));
  62. // If they're both end iterators, the distance is 0.
  63. if (isEnd() && R.isEnd())
  64. return 0;
  65. assert(!R.isEnd());
  66. // At this point, R cannot be end, but *this can, which means that *this
  67. // might be a universal end iterator with none of its fields set. So in that
  68. // case have to rely on R as the authority to figure out how many files there
  69. // are to compute the distance.
  70. uint32_t Thisi = Filei;
  71. if (isEnd()) {
  72. uint32_t RealModi = R.Modi;
  73. Thisi = R.Modules->getSourceFileCount(RealModi);
  74. }
  75. assert(Thisi >= R.Filei);
  76. return Thisi - R.Filei;
  77. }
  78. DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
  79. operator+=(std::ptrdiff_t N) {
  80. assert(!isEnd());
  81. Filei += N;
  82. assert(Filei <= Modules->getSourceFileCount(Modi));
  83. setValue();
  84. return *this;
  85. }
  86. DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
  87. operator-=(std::ptrdiff_t N) {
  88. // Note that we can subtract from an end iterator, but not a universal end
  89. // iterator.
  90. assert(!isUniversalEnd());
  91. assert(N <= Filei);
  92. Filei -= N;
  93. return *this;
  94. }
  95. void DbiModuleSourceFilesIterator::setValue() {
  96. if (isEnd()) {
  97. ThisValue = "";
  98. return;
  99. }
  100. uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei;
  101. auto ExpectedValue = Modules->getFileName(Off);
  102. if (!ExpectedValue) {
  103. consumeError(ExpectedValue.takeError());
  104. Filei = Modules->getSourceFileCount(Modi);
  105. } else
  106. ThisValue = *ExpectedValue;
  107. }
  108. bool DbiModuleSourceFilesIterator::isEnd() const {
  109. if (isUniversalEnd())
  110. return true;
  111. assert(Modules);
  112. assert(Modi <= Modules->getModuleCount());
  113. assert(Filei <= Modules->getSourceFileCount(Modi));
  114. if (Modi == Modules->getModuleCount())
  115. return true;
  116. if (Filei == Modules->getSourceFileCount(Modi))
  117. return true;
  118. return false;
  119. }
  120. bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; }
  121. bool DbiModuleSourceFilesIterator::isCompatible(
  122. const DbiModuleSourceFilesIterator &R) const {
  123. // Universal iterators are compatible with any other iterator.
  124. if (isUniversalEnd() || R.isUniversalEnd())
  125. return true;
  126. // At this point, neither iterator is a universal end iterator, although one
  127. // or both might be non-universal end iterators. Regardless, the module index
  128. // is valid, so they are compatible if and only if they refer to the same
  129. // module.
  130. return Modi == R.Modi;
  131. }
  132. Error DbiModuleList::initialize(BinaryStreamRef ModInfo,
  133. BinaryStreamRef FileInfo) {
  134. if (auto EC = initializeModInfo(ModInfo))
  135. return EC;
  136. if (auto EC = initializeFileInfo(FileInfo))
  137. return EC;
  138. return Error::success();
  139. }
  140. Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) {
  141. ModInfoSubstream = ModInfo;
  142. if (ModInfo.getLength() == 0)
  143. return Error::success();
  144. BinaryStreamReader Reader(ModInfo);
  145. if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength()))
  146. return EC;
  147. return Error::success();
  148. }
  149. Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) {
  150. FileInfoSubstream = FileInfo;
  151. if (FileInfo.getLength() == 0)
  152. return Error::success();
  153. BinaryStreamReader FISR(FileInfo);
  154. if (auto EC = FISR.readObject(FileInfoHeader))
  155. return EC;
  156. // First is an array of `NumModules` module indices. This does not seem to be
  157. // used for anything meaningful, so we ignore it.
  158. FixedStreamArray<support::ulittle16_t> ModuleIndices;
  159. if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules))
  160. return EC;
  161. if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules))
  162. return EC;
  163. // Compute the real number of source files. We can't trust the value in
  164. // `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all
  165. // source file counts might be larger than a unit16. So we compute the real
  166. // count by summing up the individual counts.
  167. uint32_t NumSourceFiles = 0;
  168. for (auto Count : ModFileCountArray)
  169. NumSourceFiles += Count;
  170. // In the reference implementation, this array is where the pointer documented
  171. // at the definition of ModuleInfoHeader::FileNameOffs points to. Note that
  172. // although the field in ModuleInfoHeader is ignored this array is not, as it
  173. // is the authority on where each filename begins in the names buffer.
  174. if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
  175. return EC;
  176. if (auto EC = FISR.readStreamRef(NamesBuffer))
  177. return EC;
  178. auto DescriptorIter = Descriptors.begin();
  179. uint32_t NextFileIndex = 0;
  180. ModuleInitialFileIndex.resize(FileInfoHeader->NumModules);
  181. ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules);
  182. for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) {
  183. assert(DescriptorIter != Descriptors.end());
  184. ModuleInitialFileIndex[I] = NextFileIndex;
  185. ModuleDescriptorOffsets[I] = DescriptorIter.offset();
  186. NextFileIndex += ModFileCountArray[I];
  187. ++DescriptorIter;
  188. }
  189. assert(DescriptorIter == Descriptors.end());
  190. assert(NextFileIndex == NumSourceFiles);
  191. return Error::success();
  192. }
  193. uint32_t DbiModuleList::getModuleCount() const {
  194. return FileInfoHeader->NumModules;
  195. }
  196. uint32_t DbiModuleList::getSourceFileCount() const {
  197. return FileNameOffsets.size();
  198. }
  199. uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const {
  200. return ModFileCountArray[Modi];
  201. }
  202. DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const {
  203. assert(Modi < getModuleCount());
  204. uint32_t Offset = ModuleDescriptorOffsets[Modi];
  205. auto Iter = Descriptors.at(Offset);
  206. assert(Iter != Descriptors.end());
  207. return *Iter;
  208. }
  209. iterator_range<DbiModuleSourceFilesIterator>
  210. DbiModuleList::source_files(uint32_t Modi) const {
  211. return make_range<DbiModuleSourceFilesIterator>(
  212. DbiModuleSourceFilesIterator(*this, Modi, 0),
  213. DbiModuleSourceFilesIterator());
  214. }
  215. Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const {
  216. BinaryStreamReader Names(NamesBuffer);
  217. if (Index >= getSourceFileCount())
  218. return make_error<RawError>(raw_error_code::index_out_of_bounds);
  219. uint32_t FileOffset = FileNameOffsets[Index];
  220. Names.setOffset(FileOffset);
  221. StringRef Name;
  222. if (auto EC = Names.readCString(Name))
  223. return std::move(EC);
  224. return Name;
  225. }