LazyRandomTypeCollection.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. //===- LazyRandomTypeCollection.cpp ---------------------------------------===//
  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/CodeView/LazyRandomTypeCollection.h"
  10. #include "llvm/ADT/ArrayRef.h"
  11. #include "llvm/ADT/None.h"
  12. #include "llvm/ADT/StringExtras.h"
  13. #include "llvm/ADT/StringRef.h"
  14. #include "llvm/DebugInfo/CodeView/CodeViewError.h"
  15. #include "llvm/DebugInfo/CodeView/RecordName.h"
  16. #include "llvm/DebugInfo/CodeView/TypeRecord.h"
  17. #include "llvm/Support/BinaryStreamReader.h"
  18. #include "llvm/Support/Endian.h"
  19. #include "llvm/Support/Error.h"
  20. #include <algorithm>
  21. #include <cassert>
  22. #include <cstdint>
  23. #include <iterator>
  24. using namespace llvm;
  25. using namespace llvm::codeview;
  26. static void error(Error &&EC) {
  27. assert(!static_cast<bool>(EC));
  28. if (EC)
  29. consumeError(std::move(EC));
  30. }
  31. LazyRandomTypeCollection::LazyRandomTypeCollection(uint32_t RecordCountHint)
  32. : LazyRandomTypeCollection(CVTypeArray(), RecordCountHint,
  33. PartialOffsetArray()) {}
  34. LazyRandomTypeCollection::LazyRandomTypeCollection(
  35. const CVTypeArray &Types, uint32_t RecordCountHint,
  36. PartialOffsetArray PartialOffsets)
  37. : NameStorage(Allocator), Types(Types), PartialOffsets(PartialOffsets) {
  38. Records.resize(RecordCountHint);
  39. }
  40. LazyRandomTypeCollection::LazyRandomTypeCollection(ArrayRef<uint8_t> Data,
  41. uint32_t RecordCountHint)
  42. : LazyRandomTypeCollection(RecordCountHint) {
  43. }
  44. LazyRandomTypeCollection::LazyRandomTypeCollection(StringRef Data,
  45. uint32_t RecordCountHint)
  46. : LazyRandomTypeCollection(
  47. makeArrayRef(Data.bytes_begin(), Data.bytes_end()), RecordCountHint) {
  48. }
  49. LazyRandomTypeCollection::LazyRandomTypeCollection(const CVTypeArray &Types,
  50. uint32_t NumRecords)
  51. : LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {}
  52. void LazyRandomTypeCollection::reset(StringRef Data, uint32_t RecordCountHint) {
  53. Count = 0;
  54. PartialOffsets = PartialOffsetArray();
  55. BinaryStreamReader Reader(Data, support::little);
  56. error(Reader.readArray(Types, Reader.getLength()));
  57. // Clear and then resize, to make sure existing data gets destroyed.
  58. Records.clear();
  59. Records.resize(RecordCountHint);
  60. }
  61. void LazyRandomTypeCollection::reset(ArrayRef<uint8_t> Data,
  62. uint32_t RecordCountHint) {
  63. reset(toStringRef(Data), RecordCountHint);
  64. }
  65. uint32_t LazyRandomTypeCollection::getOffsetOfType(TypeIndex Index) {
  66. error(ensureTypeExists(Index));
  67. assert(contains(Index));
  68. return Records[Index.toArrayIndex()].Offset;
  69. }
  70. CVType LazyRandomTypeCollection::getType(TypeIndex Index) {
  71. error(ensureTypeExists(Index));
  72. assert(contains(Index));
  73. return Records[Index.toArrayIndex()].Type;
  74. }
  75. StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) {
  76. if (Index.isNoneType() || Index.isSimple())
  77. return TypeIndex::simpleTypeName(Index);
  78. // Try to make sure the type exists. Even if it doesn't though, it may be
  79. // because we're dumping a symbol stream with no corresponding type stream
  80. // present, in which case we still want to be able to print <unknown UDT>
  81. // for the type names.
  82. if (auto EC = ensureTypeExists(Index)) {
  83. consumeError(std::move(EC));
  84. return "<unknown UDT>";
  85. }
  86. uint32_t I = Index.toArrayIndex();
  87. ensureCapacityFor(Index);
  88. if (Records[I].Name.data() == nullptr) {
  89. StringRef Result = NameStorage.save(computeTypeName(*this, Index));
  90. Records[I].Name = Result;
  91. }
  92. return Records[I].Name;
  93. }
  94. bool LazyRandomTypeCollection::contains(TypeIndex Index) {
  95. if (Records.size() <= Index.toArrayIndex())
  96. return false;
  97. if (!Records[Index.toArrayIndex()].Type.valid())
  98. return false;
  99. return true;
  100. }
  101. uint32_t LazyRandomTypeCollection::size() { return Count; }
  102. uint32_t LazyRandomTypeCollection::capacity() { return Records.size(); }
  103. Error LazyRandomTypeCollection::ensureTypeExists(TypeIndex TI) {
  104. if (contains(TI))
  105. return Error::success();
  106. return visitRangeForType(TI);
  107. }
  108. void LazyRandomTypeCollection::ensureCapacityFor(TypeIndex Index) {
  109. uint32_t MinSize = Index.toArrayIndex() + 1;
  110. if (MinSize <= capacity())
  111. return;
  112. uint32_t NewCapacity = MinSize * 3 / 2;
  113. assert(NewCapacity > capacity());
  114. Records.resize(NewCapacity);
  115. }
  116. Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) {
  117. if (PartialOffsets.empty())
  118. return fullScanForType(TI);
  119. auto Next = std::upper_bound(PartialOffsets.begin(), PartialOffsets.end(), TI,
  120. [](TypeIndex Value, const TypeIndexOffset &IO) {
  121. return Value < IO.Type;
  122. });
  123. assert(Next != PartialOffsets.begin());
  124. auto Prev = std::prev(Next);
  125. TypeIndex TIB = Prev->Type;
  126. if (contains(TIB)) {
  127. // They've asked us to fetch a type index, but the entry we found in the
  128. // partial offsets array has already been visited. Since we visit an entire
  129. // block every time, that means this record should have been previously
  130. // discovered. Ultimately, this means this is a request for a non-existant
  131. // type index.
  132. return make_error<CodeViewError>("Invalid type index");
  133. }
  134. TypeIndex TIE;
  135. if (Next == PartialOffsets.end()) {
  136. TIE = TypeIndex::fromArrayIndex(capacity());
  137. } else {
  138. TIE = Next->Type;
  139. }
  140. visitRange(TIB, Prev->Offset, TIE);
  141. return Error::success();
  142. }
  143. Optional<TypeIndex> LazyRandomTypeCollection::getFirst() {
  144. TypeIndex TI = TypeIndex::fromArrayIndex(0);
  145. if (auto EC = ensureTypeExists(TI)) {
  146. consumeError(std::move(EC));
  147. return None;
  148. }
  149. return TI;
  150. }
  151. Optional<TypeIndex> LazyRandomTypeCollection::getNext(TypeIndex Prev) {
  152. // We can't be sure how long this type stream is, given that the initial count
  153. // given to the constructor is just a hint. So just try to make sure the next
  154. // record exists, and if anything goes wrong, we must be at the end.
  155. if (auto EC = ensureTypeExists(Prev + 1)) {
  156. consumeError(std::move(EC));
  157. return None;
  158. }
  159. return Prev + 1;
  160. }
  161. Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) {
  162. assert(PartialOffsets.empty());
  163. TypeIndex CurrentTI = TypeIndex::fromArrayIndex(0);
  164. auto Begin = Types.begin();
  165. if (Count > 0) {
  166. // In the case of type streams which we don't know the number of records of,
  167. // it's possible to search for a type index triggering a full scan, but then
  168. // later additional records are added since we didn't know how many there
  169. // would be until we did a full visitation, then you try to access the new
  170. // type triggering another full scan. To avoid this, we assume that if the
  171. // database has some records, this must be what's going on. We can also
  172. // assume that this index must be larger than the largest type index we've
  173. // visited, so we start from there and scan forward.
  174. uint32_t Offset = Records[LargestTypeIndex.toArrayIndex()].Offset;
  175. CurrentTI = LargestTypeIndex + 1;
  176. Begin = Types.at(Offset);
  177. ++Begin;
  178. }
  179. auto End = Types.end();
  180. while (Begin != End) {
  181. ensureCapacityFor(CurrentTI);
  182. LargestTypeIndex = std::max(LargestTypeIndex, CurrentTI);
  183. auto Idx = CurrentTI.toArrayIndex();
  184. Records[Idx].Type = *Begin;
  185. Records[Idx].Offset = Begin.offset();
  186. ++Count;
  187. ++Begin;
  188. ++CurrentTI;
  189. }
  190. if (CurrentTI <= TI) {
  191. return make_error<CodeViewError>("Type Index does not exist!");
  192. }
  193. return Error::success();
  194. }
  195. void LazyRandomTypeCollection::visitRange(TypeIndex Begin, uint32_t BeginOffset,
  196. TypeIndex End) {
  197. auto RI = Types.at(BeginOffset);
  198. assert(RI != Types.end());
  199. ensureCapacityFor(End);
  200. while (Begin != End) {
  201. LargestTypeIndex = std::max(LargestTypeIndex, Begin);
  202. auto Idx = Begin.toArrayIndex();
  203. Records[Idx].Type = *RI;
  204. Records[Idx].Offset = RI.offset();
  205. ++Count;
  206. ++Begin;
  207. ++RI;
  208. }
  209. }