1 //===- TypeSerializer.h -----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
11 #define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
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"
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"
30 class TypeSerializer : public TypeVisitorCallbacks {
32 SubRecord(TypeLeafKind K, uint32_t S) : Kind(K), Size(S) {}
37 struct RecordSegment {
38 SmallVector<SubRecord, 16> SubRecords;
40 uint32_t length() const {
41 uint32_t L = sizeof(RecordPrefix);
42 for (const auto &R : SubRecords) {
49 typedef SmallVector<MutableArrayRef<uint8_t>, 2> MutableRecordList;
51 static constexpr uint8_t ContinuationLength = 8;
52 BumpPtrAllocator &RecordStorage;
53 RecordSegment CurrentSegment;
54 MutableRecordList FieldListSegments;
56 Optional<TypeLeafKind> TypeKind;
57 Optional<TypeLeafKind> MemberKind;
58 std::vector<uint8_t> RecordBuffer;
59 MutableBinaryByteStream Stream;
60 BinaryStreamWriter Writer;
61 TypeRecordMapping Mapping;
63 /// Private type record hashing implementation details are handled here.
64 std::unique_ptr<TypeHasher> Hasher;
66 /// Contains a list of all records indexed by TypeIndex.toArrayIndex().
67 SmallVector<ArrayRef<uint8_t>, 2> SeenRecords;
69 /// Temporary storage that we use to copy a record's data while re-writing
71 SmallVector<uint8_t, 256> RemapStorage;
73 TypeIndex nextTypeIndex() const;
75 bool isInFieldList() const;
76 MutableArrayRef<uint8_t> getCurrentSubRecordData();
77 MutableArrayRef<uint8_t> getCurrentRecordData();
78 Error writeRecordPrefix(TypeLeafKind Kind);
80 Expected<MutableArrayRef<uint8_t>>
81 addPadding(MutableArrayRef<uint8_t> Record);
84 explicit TypeSerializer(BumpPtrAllocator &Storage, bool Hash = true);
89 ArrayRef<ArrayRef<uint8_t>> records() const;
90 TypeIndex insertRecordBytes(ArrayRef<uint8_t> &Record);
91 TypeIndex insertRecord(const RemappedType &Record);
92 Expected<TypeIndex> visitTypeEndGetIndex(CVType &Record);
94 Error visitTypeBegin(CVType &Record) override;
95 Error visitTypeEnd(CVType &Record) override;
96 Error visitMemberBegin(CVMemberRecord &Record) override;
97 Error visitMemberEnd(CVMemberRecord &Record) override;
99 #define TYPE_RECORD(EnumName, EnumVal, Name) \
100 virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
101 return visitKnownRecordImpl(CVR, Record); \
103 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
104 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
105 Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
106 return visitKnownMemberImpl<Name##Record>(CVR, Record); \
108 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
109 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
112 template <typename RecordKind>
113 Error visitKnownRecordImpl(CVType &CVR, RecordKind &Record) {
114 return Mapping.visitKnownRecord(CVR, Record);
117 template <typename RecordType>
118 Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
119 assert(CVR.Kind == static_cast<TypeLeafKind>(Record.getKind()));
121 if (auto EC = Writer.writeEnum(CVR.Kind))
124 if (auto EC = Mapping.visitKnownMember(CVR, Record))
127 // Get all the data that was just written and is yet to be committed to
128 // the current segment. Then pad it to 4 bytes.
129 MutableArrayRef<uint8_t> ThisRecord = getCurrentSubRecordData();
130 auto ExpectedRecord = addPadding(ThisRecord);
132 return ExpectedRecord.takeError();
133 ThisRecord = *ExpectedRecord;
135 CurrentSegment.SubRecords.emplace_back(CVR.Kind, ThisRecord.size());
136 CVR.Data = ThisRecord;
138 // Both the last subrecord and the total length of this segment should be
140 assert(ThisRecord.size() % 4 == 0);
141 assert(CurrentSegment.length() % 4 == 0);
143 return Error::success();