1 //===- TypeSerializer.h -----------------------------------------*- C++ -*-===// 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 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H 11 #define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H 12 13 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" 14 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" 15 #include "llvm/Support/BinaryByteStream.h" 16 #include "llvm/Support/BinaryStreamWriter.h" 17 18 #include "llvm/ADT/Optional.h" 19 #include "llvm/ADT/SmallVector.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/Support/Allocator.h" 22 #include "llvm/Support/Error.h" 23 24 namespace llvm { 25 26 namespace codeview { 27 28 class TypeHasher; 29 30 class TypeSerializer : public TypeVisitorCallbacks { 31 struct SubRecord { 32 SubRecord(TypeLeafKind K, uint32_t S) : Kind(K), Size(S) {} 33 34 TypeLeafKind Kind; 35 uint32_t Size = 0; 36 }; 37 struct RecordSegment { 38 SmallVector<SubRecord, 16> SubRecords; 39 40 uint32_t length() const { 41 uint32_t L = sizeof(RecordPrefix); 42 for (const auto &R : SubRecords) { 43 L += R.Size; 44 } 45 return L; 46 } 47 }; 48 49 typedef SmallVector<MutableArrayRef<uint8_t>, 2> MutableRecordList; 50 51 static constexpr uint8_t ContinuationLength = 8; 52 BumpPtrAllocator &RecordStorage; 53 RecordSegment CurrentSegment; 54 MutableRecordList FieldListSegments; 55 56 Optional<TypeLeafKind> TypeKind; 57 Optional<TypeLeafKind> MemberKind; 58 std::vector<uint8_t> RecordBuffer; 59 MutableBinaryByteStream Stream; 60 BinaryStreamWriter Writer; 61 TypeRecordMapping Mapping; 62 63 /// Private type record hashing implementation details are handled here. 64 std::unique_ptr<TypeHasher> Hasher; 65 66 /// Contains a list of all records indexed by TypeIndex.toArrayIndex(). 67 SmallVector<ArrayRef<uint8_t>, 2> SeenRecords; 68 69 /// Temporary storage that we use to copy a record's data while re-writing 70 /// its type indices. 71 SmallVector<uint8_t, 256> RemapStorage; 72 73 TypeIndex nextTypeIndex() const; 74 75 bool isInFieldList() const; 76 MutableArrayRef<uint8_t> getCurrentSubRecordData(); 77 MutableArrayRef<uint8_t> getCurrentRecordData(); 78 Error writeRecordPrefix(TypeLeafKind Kind); 79 80 Expected<MutableArrayRef<uint8_t>> 81 addPadding(MutableArrayRef<uint8_t> Record); 82 83 public: 84 explicit TypeSerializer(BumpPtrAllocator &Storage, bool Hash = true); 85 ~TypeSerializer(); 86 87 void reset(); 88 89 BumpPtrAllocator &getAllocator() { return RecordStorage; } 90 91 ArrayRef<ArrayRef<uint8_t>> records() const; 92 TypeIndex insertRecordBytes(ArrayRef<uint8_t> &Record); 93 TypeIndex insertRecord(const RemappedType &Record); 94 Expected<TypeIndex> visitTypeEndGetIndex(CVType &Record); 95 96 Error visitTypeBegin(CVType &Record) override; 97 Error visitTypeEnd(CVType &Record) override; 98 Error visitMemberBegin(CVMemberRecord &Record) override; 99 Error visitMemberEnd(CVMemberRecord &Record) override; 100 101 #define TYPE_RECORD(EnumName, EnumVal, Name) \ 102 virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \ 103 return visitKnownRecordImpl(CVR, Record); \ 104 } 105 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) 106 #define MEMBER_RECORD(EnumName, EnumVal, Name) \ 107 Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \ 108 return visitKnownMemberImpl<Name##Record>(CVR, Record); \ 109 } 110 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) 111 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def" 112 113 private: 114 template <typename RecordKind> 115 Error visitKnownRecordImpl(CVType &CVR, RecordKind &Record) { 116 return Mapping.visitKnownRecord(CVR, Record); 117 } 118 119 template <typename RecordType> 120 Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) { 121 assert(CVR.Kind == static_cast<TypeLeafKind>(Record.getKind())); 122 123 if (auto EC = Writer.writeEnum(CVR.Kind)) 124 return EC; 125 126 if (auto EC = Mapping.visitKnownMember(CVR, Record)) 127 return EC; 128 129 // Get all the data that was just written and is yet to be committed to 130 // the current segment. Then pad it to 4 bytes. 131 MutableArrayRef<uint8_t> ThisRecord = getCurrentSubRecordData(); 132 auto ExpectedRecord = addPadding(ThisRecord); 133 if (!ExpectedRecord) 134 return ExpectedRecord.takeError(); 135 ThisRecord = *ExpectedRecord; 136 137 CurrentSegment.SubRecords.emplace_back(CVR.Kind, ThisRecord.size()); 138 CVR.Data = ThisRecord; 139 140 // Both the last subrecord and the total length of this segment should be 141 // multiples of 4. 142 assert(ThisRecord.size() % 4 == 0); 143 assert(CurrentSegment.length() % 4 == 0); 144 145 return Error::success(); 146 } 147 }; 148 } 149 } 150 151 #endif 152