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