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/StringMap.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Support/Allocator.h"
23 #include "llvm/Support/Error.h"
29 class TypeSerializer : public TypeVisitorCallbacks {
31 SubRecord(TypeLeafKind K, uint32_t S) : Kind(K), Size(S) {}
36 struct RecordSegment {
37 SmallVector<SubRecord, 16> SubRecords;
39 uint32_t length() const {
40 uint32_t L = sizeof(RecordPrefix);
41 for (const auto &R : SubRecords) {
48 typedef SmallVector<MutableArrayRef<uint8_t>, 2> RecordList;
50 static constexpr uint8_t ContinuationLength = 8;
51 BumpPtrAllocator &RecordStorage;
52 RecordSegment CurrentSegment;
53 RecordList FieldListSegments;
55 TypeIndex LastTypeIndex;
56 Optional<TypeLeafKind> TypeKind;
57 Optional<TypeLeafKind> MemberKind;
58 std::vector<uint8_t> RecordBuffer;
59 MutableBinaryByteStream Stream;
60 BinaryStreamWriter Writer;
61 TypeRecordMapping Mapping;
63 RecordList SeenRecords;
64 StringMap<TypeIndex> HashedRecords;
66 bool isInFieldList() const;
67 TypeIndex calcNextTypeIndex() const;
68 TypeIndex incrementTypeIndex();
69 MutableArrayRef<uint8_t> getCurrentSubRecordData();
70 MutableArrayRef<uint8_t> getCurrentRecordData();
71 Error writeRecordPrefix(TypeLeafKind Kind);
72 TypeIndex insertRecordBytesPrivate(MutableArrayRef<uint8_t> Record);
73 TypeIndex insertRecordBytesWithCopy(CVType &Record,
74 MutableArrayRef<uint8_t> Data);
76 Expected<MutableArrayRef<uint8_t>>
77 addPadding(MutableArrayRef<uint8_t> Record);
80 explicit TypeSerializer(BumpPtrAllocator &Storage);
82 ArrayRef<MutableArrayRef<uint8_t>> records() const;
83 TypeIndex getLastTypeIndex() const;
84 TypeIndex insertRecordBytes(MutableArrayRef<uint8_t> Record);
85 Expected<TypeIndex> visitTypeEndGetIndex(CVType &Record);
87 Error visitTypeBegin(CVType &Record) override;
88 Error visitTypeEnd(CVType &Record) override;
89 Error visitMemberBegin(CVMemberRecord &Record) override;
90 Error visitMemberEnd(CVMemberRecord &Record) override;
92 #define TYPE_RECORD(EnumName, EnumVal, Name) \
93 virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
94 return visitKnownRecordImpl(CVR, Record); \
96 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
97 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
98 Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
99 return visitKnownMemberImpl<Name##Record>(CVR, Record); \
101 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
102 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
105 template <typename RecordKind>
106 Error visitKnownRecordImpl(CVType &CVR, RecordKind &Record) {
107 return Mapping.visitKnownRecord(CVR, Record);
110 template <typename RecordType>
111 Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
112 assert(CVR.Kind == static_cast<TypeLeafKind>(Record.getKind()));
114 if (auto EC = Writer.writeEnum(CVR.Kind))
117 if (auto EC = Mapping.visitKnownMember(CVR, Record))
120 // Get all the data that was just written and is yet to be committed to
121 // the current segment. Then pad it to 4 bytes.
122 MutableArrayRef<uint8_t> ThisRecord = getCurrentSubRecordData();
123 auto ExpectedRecord = addPadding(ThisRecord);
125 return ExpectedRecord.takeError();
126 ThisRecord = *ExpectedRecord;
128 CurrentSegment.SubRecords.emplace_back(CVR.Kind, ThisRecord.size());
129 CVR.Data = ThisRecord;
131 // Both the last subrecord and the total length of this segment should be
133 assert(ThisRecord.size() % 4 == 0);
134 assert(CurrentSegment.length() % 4 == 0);
136 return Error::success();