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