diff options
Diffstat (limited to 'llvm')
10 files changed, 288 insertions, 148 deletions
diff --git a/llvm/include/llvm/DebugInfo/CodeView/CVRecord.h b/llvm/include/llvm/DebugInfo/CodeView/CVRecord.h index 71ea82b6a9a..68ad0998220 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/CVRecord.h +++ b/llvm/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -14,6 +14,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" @@ -50,6 +51,13 @@ public: Optional<uint32_t> Hash; }; +template <typename Kind> struct RemappedRecord { + explicit RemappedRecord(const CVRecord<Kind> &R) : OriginalRecord(R) {} + + CVRecord<Kind> OriginalRecord; + SmallVector<std::pair<uint32_t, TypeIndex>, 8> Mappings; +}; + } // end namespace codeview template <typename Kind> diff --git a/llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h b/llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h index 4bc8fbefd5d..70ccc867cd3 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ b/llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -46,6 +46,7 @@ Error visitMemberRecordStream(ArrayRef<uint8_t> FieldList, TypeVisitorCallbacks &Callbacks); Error visitTypeStream(const CVTypeArray &Types, TypeVisitorCallbacks &Callbacks, + VisitorDataSource Source = VDS_BytesPresent, TypeServerHandler *TS = nullptr); Error visitTypeStream(CVTypeRange Types, TypeVisitorCallbacks &Callbacks, TypeServerHandler *TS = nullptr); diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeDeserializer.h b/llvm/include/llvm/DebugInfo/CodeView/TypeDeserializer.h index 2142d4a2dec..a9c5cf42fc5 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeDeserializer.h +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeDeserializer.h @@ -40,6 +40,17 @@ class TypeDeserializer : public TypeVisitorCallbacks { public: TypeDeserializer() = default; + template <typename T> static Error deserializeAs(CVType &CVT, T &Record) { + MappingInfo I(CVT.content()); + if (auto EC = I.Mapping.visitTypeBegin(CVT)) + return EC; + if (auto EC = I.Mapping.visitKnownRecord(CVT, Record)) + return EC; + if (auto EC = I.Mapping.visitTypeEnd(CVT)) + return EC; + return Error::success(); + } + Error visitTypeBegin(CVType &Record) override { assert(!Mapping && "Already in a type mapping!"); Mapping = llvm::make_unique<MappingInfo>(Record.content()); diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h index 1f10872c876..fb71c72c80e 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -35,6 +35,7 @@ using support::ulittle16_t; using support::ulittle32_t; typedef CVRecord<TypeLeafKind> CVType; +typedef RemappedRecord<TypeLeafKind> RemappedType; struct CVMemberRecord { TypeLeafKind Kind; diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeSerializer.h b/llvm/include/llvm/DebugInfo/CodeView/TypeSerializer.h index deeb063c5df..f42fddd4f55 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeSerializer.h +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeSerializer.h @@ -63,6 +63,15 @@ class TypeSerializer : public TypeVisitorCallbacks { /// Private type record hashing implementation details are handled here. std::unique_ptr<TypeHasher> Hasher; + /// Contains a list of all records indexed by TypeIndex.toArrayIndex(). + SmallVector<ArrayRef<uint8_t>, 2> SeenRecords; + + /// Temporary storage that we use to copy a record's data while re-writing + /// its type indices. + SmallVector<uint8_t, 256> RemapStorage; + + TypeIndex nextTypeIndex() const; + bool isInFieldList() const; MutableArrayRef<uint8_t> getCurrentSubRecordData(); MutableArrayRef<uint8_t> getCurrentRecordData(); @@ -72,11 +81,12 @@ class TypeSerializer : public TypeVisitorCallbacks { addPadding(MutableArrayRef<uint8_t> Record); public: - explicit TypeSerializer(BumpPtrAllocator &Storage); + explicit TypeSerializer(BumpPtrAllocator &Storage, bool Hash = true); ~TypeSerializer(); ArrayRef<ArrayRef<uint8_t>> records() const; - TypeIndex insertRecordBytes(ArrayRef<uint8_t> Record); + TypeIndex insertRecordBytes(ArrayRef<uint8_t> &Record); + TypeIndex insertRecord(const RemappedType &Record); Expected<TypeIndex> visitTypeEndGetIndex(CVType &Record); Error visitTypeBegin(CVType &Record) override; diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h b/llvm/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h index c7d417063e4..8cc42feb87d 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h @@ -68,6 +68,10 @@ public: return Serializer.insertRecordBytes(Record); } + TypeIndex writeSerializedRecord(const RemappedType &Record) { + return Serializer.insertRecord(Record); + } + template <typename TFunc> void ForEachRecord(TFunc Func) { uint32_t Index = TypeIndex::FirstNonSimpleIndex; @@ -88,7 +92,7 @@ class FieldListRecordBuilder { public: explicit FieldListRecordBuilder(TypeTableBuilder &TypeTable) - : TypeTable(TypeTable), TempSerializer(Allocator) { + : TypeTable(TypeTable), TempSerializer(Allocator, false) { Type.Type = TypeLeafKind::LF_FIELDLIST; } diff --git a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp index f95c3e79388..705b548141b 100644 --- a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -45,24 +45,9 @@ static Error visitKnownMember(CVMemberRecord &Record, } static Expected<TypeServer2Record> deserializeTypeServerRecord(CVType &Record) { - class StealTypeServerVisitor : public TypeVisitorCallbacks { - public: - explicit StealTypeServerVisitor(TypeServer2Record &TR) : TR(TR) {} - - Error visitKnownRecord(CVType &CVR, TypeServer2Record &Record) override { - TR = Record; - return Error::success(); - } - - private: - TypeServer2Record &TR; - }; - TypeServer2Record R(TypeRecordKind::TypeServer2); - StealTypeServerVisitor Thief(R); - if (auto EC = visitTypeRecord(Record, Thief)) + if (auto EC = TypeDeserializer::deserializeAs(Record, R)) return std::move(EC); - return R; } @@ -308,8 +293,9 @@ Error llvm::codeview::visitTypeRecord(CVType &Record, Error llvm::codeview::visitTypeStream(const CVTypeArray &Types, TypeVisitorCallbacks &Callbacks, + VisitorDataSource Source, TypeServerHandler *TS) { - VisitHelper V(Callbacks, VDS_BytesPresent); + VisitHelper V(Callbacks, Source); if (TS) V.Visitor.addTypeServerHandler(*TS); return V.Visitor.visitTypeStream(Types); diff --git a/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp b/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp index c667a73d086..4894277947b 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp @@ -75,29 +75,23 @@ private: /// entries are small and easy to rehash. DenseSet<HashedTypePtr> HashedRecords; - SmallVector<ArrayRef<uint8_t>, 2> SeenRecords; - - TypeIndex NextTypeIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex); - public: TypeHasher(BumpPtrAllocator &RecordStorage) : RecordStorage(RecordStorage) {} - ArrayRef<ArrayRef<uint8_t>> records() const { return SeenRecords; } - /// Takes the bytes of type record, inserts them into the hash table, saves /// them, and returns a pointer to an identical stable type record along with /// its type index in the destination stream. - TypeIndex getOrCreateRecord(ArrayRef<uint8_t> &Record); + TypeIndex getOrCreateRecord(ArrayRef<uint8_t> &Record, TypeIndex TI); }; -TypeIndex TypeHasher::getOrCreateRecord(ArrayRef<uint8_t> &Record) { +TypeIndex TypeHasher::getOrCreateRecord(ArrayRef<uint8_t> &Record, + TypeIndex TI) { assert(Record.size() < UINT32_MAX && "Record too big"); assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!"); // Compute the hash up front so we can store it in the key. HashedType TempHashedType = {hash_value(Record), Record.data(), - unsigned(Record.size()), NextTypeIndex}; - + unsigned(Record.size()), TI}; auto Result = HashedRecords.insert(HashedTypePtr(&TempHashedType)); HashedType *&Hashed = Result.first->Ptr; @@ -111,20 +105,15 @@ TypeIndex TypeHasher::getOrCreateRecord(ArrayRef<uint8_t> &Record) { memcpy(Stable, Record.data(), Record.size()); Hashed->Data = Stable; assert(Hashed->Size == Record.size()); - - // This was a new record, so increment our next type index. - ++NextTypeIndex; } // Update the caller's copy of Record to point a stable copy. Record = ArrayRef<uint8_t>(Hashed->Data, Hashed->Size); + return Hashed->Index; +} - if (Result.second) { - // FIXME: Can we record these in a more efficient way? - SeenRecords.push_back(Record); - } - - return TypeIndex(Hashed->Index); +TypeIndex TypeSerializer::nextTypeIndex() const { + return TypeIndex::fromArrayIndex(SeenRecords.size()); } bool TypeSerializer::isInFieldList() const { @@ -166,26 +155,68 @@ TypeSerializer::addPadding(MutableArrayRef<uint8_t> Record) { return MutableArrayRef<uint8_t>(Record.data(), Record.size() + N); } -TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage) +TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage, bool Hash) : RecordStorage(Storage), RecordBuffer(MaxRecordLength * 2), Stream(RecordBuffer, llvm::support::little), Writer(Stream), - Mapping(Writer), Hasher(make_unique<TypeHasher>(Storage)) { + Mapping(Writer) { // RecordBuffer needs to be able to hold enough data so that if we are 1 // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes, // we won't overflow. + if (Hash) + Hasher = make_unique<TypeHasher>(Storage); } TypeSerializer::~TypeSerializer() = default; ArrayRef<ArrayRef<uint8_t>> TypeSerializer::records() const { - return Hasher->records(); + return SeenRecords; } -TypeIndex TypeSerializer::insertRecordBytes(ArrayRef<uint8_t> Record) { +TypeIndex TypeSerializer::insertRecordBytes(ArrayRef<uint8_t> &Record) { assert(!TypeKind.hasValue() && "Already in a type mapping!"); assert(Writer.getOffset() == 0 && "Stream has data already!"); - return Hasher->getOrCreateRecord(Record); + if (Hasher) { + TypeIndex ActualTI = Hasher->getOrCreateRecord(Record, nextTypeIndex()); + if (nextTypeIndex() == ActualTI) + SeenRecords.push_back(Record); + return ActualTI; + } + + TypeIndex NewTI = nextTypeIndex(); + uint8_t *Stable = RecordStorage.Allocate<uint8_t>(Record.size()); + memcpy(Stable, Record.data(), Record.size()); + Record = ArrayRef<uint8_t>(Stable, Record.size()); + SeenRecords.push_back(Record); + return NewTI; +} + +TypeIndex TypeSerializer::insertRecord(const RemappedType &Record) { + assert(!TypeKind.hasValue() && "Already in a type mapping!"); + assert(Writer.getOffset() == 0 && "Stream has data already!"); + + TypeIndex TI; + ArrayRef<uint8_t> OriginalData = Record.OriginalRecord.RecordData; + if (Record.Mappings.empty()) { + // This record did not remap any type indices. Just write it. + return insertRecordBytes(OriginalData); + } + + // At least one type index was remapped. Before we can hash it we have to + // copy the full record bytes, re-write each type index, then hash the copy. + // We do this in temporary storage since only the DenseMap can decide whether + // this record already exists, and if it does we don't want the memory to + // stick around. + RemapStorage.resize(OriginalData.size()); + ::memcpy(&RemapStorage[0], OriginalData.data(), OriginalData.size()); + uint8_t *ContentBegin = RemapStorage.data() + sizeof(RecordPrefix); + for (const auto &M : Record.Mappings) { + // First 4 bytes of every record are the record prefix, but the mapping + // offset is relative to the content which starts after. + *(TypeIndex *)(ContentBegin + M.first) = M.second; + } + auto RemapRef = makeArrayRef(RemapStorage); + return insertRecordBytes(RemapRef); } Error TypeSerializer::visitTypeBegin(CVType &Record) { @@ -221,7 +252,12 @@ Expected<TypeIndex> TypeSerializer::visitTypeEndGetIndex(CVType &Record) { Record.Type = *TypeKind; Record.RecordData = ThisRecordData; - TypeIndex InsertedTypeIndex = Hasher->getOrCreateRecord(Record.RecordData); + + // insertRecordBytes assumes we're not in a mapping, so do this first. + TypeKind.reset(); + Writer.setOffset(0); + + TypeIndex InsertedTypeIndex = insertRecordBytes(Record.RecordData); // Write out each additional segment in reverse order, and update each // record's continuation index to point to the previous one. @@ -231,11 +267,9 @@ Expected<TypeIndex> TypeSerializer::visitTypeEndGetIndex(CVType &Record) { reinterpret_cast<support::ulittle32_t *>(CIBytes.data()); assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder"); *CI = InsertedTypeIndex.getIndex(); - InsertedTypeIndex = Hasher->getOrCreateRecord(X); + InsertedTypeIndex = insertRecordBytes(X); } - TypeKind.reset(); - Writer.setOffset(0); FieldListSegments.clear(); CurrentSegment.SubRecords.clear(); diff --git a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp index 383799bca7e..0f8357ca80f 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" @@ -95,6 +96,33 @@ private: bool remapTypeIndex(TypeIndex &Idx); bool remapItemIndex(TypeIndex &Idx); + bool remapIndices(RemappedType &Record, ArrayRef<uint32_t> TidOffs, + ArrayRef<uint32_t> IidOffs) { + auto OriginalData = Record.OriginalRecord.content(); + bool Success = true; + for (auto Off : TidOffs) { + ArrayRef<uint8_t> Bytes = OriginalData.slice(Off, sizeof(TypeIndex)); + TypeIndex OldTI( + *reinterpret_cast<const support::ulittle32_t *>(Bytes.data())); + TypeIndex NewTI = OldTI; + bool ThisSuccess = remapTypeIndex(NewTI); + if (ThisSuccess && NewTI != OldTI) + Record.Mappings.emplace_back(Off, NewTI); + Success &= ThisSuccess; + } + for (auto Off : IidOffs) { + ArrayRef<uint8_t> Bytes = OriginalData.slice(Off, sizeof(TypeIndex)); + TypeIndex OldTI( + *reinterpret_cast<const support::ulittle32_t *>(Bytes.data())); + TypeIndex NewTI = OldTI; + bool ThisSuccess = remapItemIndex(NewTI); + if (ThisSuccess && NewTI != OldTI) + Record.Mappings.emplace_back(Off, NewTI); + Success &= ThisSuccess; + } + return Success; + } + bool remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map); size_t slotForIndex(TypeIndex Idx) const { @@ -107,23 +135,49 @@ private: } template <typename RecordType> - Error writeRecord(RecordType &R, bool RemapSuccess) { + Error writeKnownRecord(TypeTableBuilder &Dest, RecordType &R, + bool RemapSuccess) { TypeIndex DestIdx = Untranslated; if (RemapSuccess) - DestIdx = DestTypeStream->writeKnownType(R); + DestIdx = Dest.writeKnownType(R); addMapping(DestIdx); return Error::success(); } template <typename RecordType> - Error writeIdRecord(RecordType &R, bool RemapSuccess) { + Error writeKnownTypeRecord(RecordType &R, bool RemapSuccess) { + return writeKnownRecord(*DestTypeStream, R, RemapSuccess); + } + + template <typename RecordType> + Error writeKnownIdRecord(RecordType &R, bool RemapSuccess) { + return writeKnownRecord(*DestIdStream, R, RemapSuccess); + } + + Error writeRecord(TypeTableBuilder &Dest, const RemappedType &Record, + bool RemapSuccess) { TypeIndex DestIdx = Untranslated; if (RemapSuccess) - DestIdx = DestIdStream->writeKnownType(R); + DestIdx = Dest.writeSerializedRecord(Record); addMapping(DestIdx); return Error::success(); } + Error writeTypeRecord(const CVType &Record) { + TypeIndex DestIdx = + DestTypeStream->writeSerializedRecord(Record.RecordData); + addMapping(DestIdx); + return Error::success(); + } + + Error writeTypeRecord(const RemappedType &Record, bool RemapSuccess) { + return writeRecord(*DestTypeStream, Record, RemapSuccess); + } + + Error writeIdRecord(const RemappedType &Record, bool RemapSuccess) { + return writeRecord(*DestIdStream, Record, RemapSuccess); + } + template <typename RecordType> Error writeMember(RecordType &R, bool RemapSuccess) { if (RemapSuccess) @@ -163,12 +217,10 @@ private: const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated); -Error TypeStreamMerger::visitTypeBegin(CVRecord<TypeLeafKind> &Rec) { - return Error::success(); -} +Error TypeStreamMerger::visitTypeBegin(CVType &Rec) { return Error::success(); } -Error TypeStreamMerger::visitTypeEnd(CVRecord<TypeLeafKind> &Rec) { - CurIndex = TypeIndex(CurIndex.getIndex() + 1); +Error TypeStreamMerger::visitTypeEnd(CVType &Rec) { + ++CurIndex; if (!IsSecondPass) assert(IndexMap.size() == slotForIndex(CurIndex) && "visitKnownRecord should add one index map entry"); @@ -242,184 +294,206 @@ bool TypeStreamMerger::remapItemIndex(TypeIndex &Idx) { // Item records //----------------------------------------------------------------------------// -Error TypeStreamMerger::visitKnownRecord(CVType &, FuncIdRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, FuncIdRecord &R) { assert(DestIdStream); - bool Success = true; - Success &= remapItemIndex(R.ParentScope); - Success &= remapTypeIndex(R.FunctionType); - return writeIdRecord(R, Success); + + RemappedType RR(CVR); + return writeIdRecord(RR, remapIndices(RR, {4}, {0})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFuncIdRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &R) { assert(DestIdStream); - bool Success = true; - Success &= remapTypeIndex(R.ClassType); - Success &= remapTypeIndex(R.FunctionType); - return writeIdRecord(R, Success); + + RemappedType RR(CVR); + return writeIdRecord(RR, remapIndices(RR, {0, 4}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, StringIdRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, StringIdRecord &R) { assert(DestIdStream); - return writeIdRecord(R, remapItemIndex(R.Id)); + + RemappedType RR(CVR); + return writeIdRecord(RR, remapIndices(RR, {}, {0})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, StringListRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, StringListRecord &R) { assert(DestIdStream); + + if (auto EC = TypeDeserializer::deserializeAs<StringListRecord>(CVR, R)) + return EC; bool Success = true; - for (TypeIndex &Str : R.StringIndices) - Success &= remapItemIndex(Str); - return writeIdRecord(R, Success); + + for (TypeIndex &Id : R.StringIndices) + Success &= remapItemIndex(Id); + return writeKnownIdRecord(R, Success); } -Error TypeStreamMerger::visitKnownRecord(CVType &, BuildInfoRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, BuildInfoRecord &R) { assert(DestIdStream); + + if (auto EC = TypeDeserializer::deserializeAs(CVR, R)) + return EC; + bool Success = true; - for (TypeIndex &Arg : R.ArgIndices) - Success &= remapItemIndex(Arg); - return writeIdRecord(R, Success); + for (TypeIndex &Str : R.ArgIndices) + Success &= remapItemIndex(Str); + return writeKnownIdRecord(R, Success); } -Error TypeStreamMerger::visitKnownRecord(CVType &, UdtSourceLineRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, UdtSourceLineRecord &R) { assert(DestIdStream); - bool Success = true; - Success &= remapTypeIndex(R.UDT); - Success &= remapItemIndex(R.SourceFile); + + RemappedType RR(CVR); + // FIXME: Translate UdtSourceLineRecord into UdtModSourceLineRecords in the // IPI stream. - return writeIdRecord(R, Success); + return writeIdRecord(RR, remapIndices(RR, {0}, {4})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, UdtModSourceLineRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, + UdtModSourceLineRecord &R) { assert(DestIdStream); - bool Success = true; - Success &= remapTypeIndex(R.UDT); - // UdtModSourceLine Source File Ids are offsets into the global string table. + + RemappedType RR(CVR); + + // UdtModSourceLine Source File Ids are offsets into the global string table, + // not type indices. // FIXME: We need to merge string table records for this to be valid. - // Success &= remapItemIndex(R.SourceFile); - return writeIdRecord(R, Success); + return writeIdRecord(RR, remapIndices(RR, {0}, {})); } //----------------------------------------------------------------------------// // Type records //----------------------------------------------------------------------------// -Error TypeStreamMerger::visitKnownRecord(CVType &, ModifierRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ModifierRecord &R) { assert(DestTypeStream); - return writeRecord(R, remapTypeIndex(R.ModifiedType)); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, ProcedureRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ProcedureRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.ReturnType); - Success &= remapTypeIndex(R.ArgumentList); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0, 8}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFunctionRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, MemberFunctionRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.ReturnType); - Success &= remapTypeIndex(R.ClassType); - Success &= remapTypeIndex(R.ThisType); - Success &= remapTypeIndex(R.ArgumentList); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0, 4, 8, 16}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &Type, ArgListRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ArgListRecord &R) { assert(DestTypeStream); + + if (auto EC = TypeDeserializer::deserializeAs(CVR, R)) + return EC; + bool Success = true; for (TypeIndex &Arg : R.ArgIndices) Success &= remapTypeIndex(Arg); - if (auto EC = writeRecord(R, Success)) - return EC; - return Error::success(); + + return writeKnownTypeRecord(R, Success); } -Error TypeStreamMerger::visitKnownRecord(CVType &, PointerRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, PointerRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.ReferentType); + + // Pointer records have a different number of TypeIndex mappings depending + // on whether or not it is a pointer to member. + if (auto EC = TypeDeserializer::deserializeAs(CVR, R)) + return EC; + + bool Success = remapTypeIndex(R.ReferentType); if (R.isPointerToMember()) Success &= remapTypeIndex(R.MemberInfo->ContainingType); - return writeRecord(R, Success); + return writeKnownTypeRecord(R, Success); } -Error TypeStreamMerger::visitKnownRecord(CVType &, ArrayRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ArrayRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.ElementType); - Success &= remapTypeIndex(R.IndexType); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0, 4}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, ClassRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, ClassRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.FieldList); - Success &= remapTypeIndex(R.DerivationList); - Success &= remapTypeIndex(R.VTableShape); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {4, 8, 12}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, UnionRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, UnionRecord &R) { assert(DestTypeStream); - return writeRecord(R, remapTypeIndex(R.FieldList)); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {4}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, EnumRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, EnumRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.FieldList); - Success &= remapTypeIndex(R.UnderlyingType); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {4, 8}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, BitFieldRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, BitFieldRecord &R) { assert(DestTypeStream); - return writeRecord(R, remapTypeIndex(R.Type)); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableShapeRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, VFTableShapeRecord &R) { assert(DestTypeStream); - return writeRecord(R, true); + + return writeTypeRecord(CVR); } -Error TypeStreamMerger::visitKnownRecord(CVType &, TypeServer2Record &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, TypeServer2Record &R) { assert(DestTypeStream); - return writeRecord(R, true); + + return writeTypeRecord(CVR); } -Error TypeStreamMerger::visitKnownRecord(CVType &, LabelRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, LabelRecord &R) { assert(DestTypeStream); - return writeRecord(R, true); + + return writeTypeRecord(CVR); } -Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, VFTableRecord &R) { assert(DestTypeStream); - bool Success = true; - Success &= remapTypeIndex(R.CompleteClass); - Success &= remapTypeIndex(R.OverriddenVFTable); - return writeRecord(R, Success); + + RemappedType RR(CVR); + return writeTypeRecord(RR, remapIndices(RR, {0, 4}, {})); } -Error TypeStreamMerger::visitKnownRecord(CVType &, +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, MethodOverloadListRecord &R) { assert(DestTypeStream); + + if (auto EC = TypeDeserializer::deserializeAs(CVR, R)) + return EC; + bool Success = true; for (OneMethodRecord &Meth : R.Methods) Success &= remapTypeIndex(Meth.Type); - return writeRecord(R, Success); + return writeKnownTypeRecord(R, Success); } -Error TypeStreamMerger::visitKnownRecord(CVType &, FieldListRecord &R) { +Error TypeStreamMerger::visitKnownRecord(CVType &CVR, FieldListRecord &R) { assert(DestTypeStream); // Visit the members inside the field list. HadUntranslatedMember = false; FieldListBuilder = llvm::make_unique<FieldListRecordBuilder>(*DestTypeStream); FieldListBuilder->begin(); - if (auto EC = codeview::visitMemberRecordStream(R.Data, *this)) + if (auto EC = codeview::visitMemberRecordStream(CVR.content(), *this)) return EC; // Write the record if we translated all field list members. @@ -524,7 +598,11 @@ Error TypeStreamMerger::mergeTypesAndIds(TypeTableBuilder &DestIds, Error TypeStreamMerger::doit(const CVTypeArray &Types) { LastError = Error::success(); - if (auto EC = codeview::visitTypeStream(Types, *this, Handler)) + // We don't want to deserialize records. I guess this flag is poorly named, + // but it really means "Don't deserialize records before switching on the + // concrete type. + if (auto EC = + codeview::visitTypeStream(Types, *this, VDS_BytesExternal, Handler)) return EC; // If we found bad indices but no other errors, try doing another pass and see @@ -540,7 +618,8 @@ Error TypeStreamMerger::doit(const CVTypeArray &Types) { NumBadIndices = 0; CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex); - if (auto EC = codeview::visitTypeStream(Types, *this, Handler)) + if (auto EC = + codeview::visitTypeStream(Types, *this, VDS_BytesExternal, Handler)) return EC; assert(NumBadIndices <= BadIndicesRemaining && diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp index f00567db743..6ef987354aa 100644 --- a/llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp @@ -57,7 +57,13 @@ PDBTypeServerHandler::handleInternal(PDBFile &File, if (!ExpectedTpi) return ExpectedTpi.takeError(); - if (auto EC = codeview::visitTypeStream(ExpectedTpi->typeArray(), Callbacks)) + // For handling a type server, we should be using whatever the callback array + // was + // that is being used for the original file. We shouldn't allow the visitor + // to + // arbitrarily stick a deserializer in there. + if (auto EC = codeview::visitTypeStream(ExpectedTpi->typeArray(), Callbacks, + VDS_BytesExternal)) return std::move(EC); return true; |