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