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/DebugInfo/MSF/ByteStream.h"
16 #include "llvm/DebugInfo/MSF/StreamWriter.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 msf::MutableByteStream Stream;
60 msf::StreamWriter 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);
74 Expected<MutableArrayRef<uint8_t>>
75 addPadding(MutableArrayRef<uint8_t> Record);
78 explicit TypeSerializer(BumpPtrAllocator &Storage);
80 ArrayRef<MutableArrayRef<uint8_t>> records() const;
81 TypeIndex getLastTypeIndex() const;
82 TypeIndex insertRecordBytes(MutableArrayRef<uint8_t> Record);
83 Expected<TypeIndex> visitTypeEndGetIndex(CVType &Record);
85 Error visitTypeBegin(CVType &Record) override;
86 Error visitTypeEnd(CVType &Record) override;
87 Error visitMemberBegin(CVMemberRecord &Record) override;
88 Error visitMemberEnd(CVMemberRecord &Record) override;
90 #define TYPE_RECORD(EnumName, EnumVal, Name) \
91 virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
92 return visitKnownRecordImpl(CVR, Record); \
94 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
95 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
96 Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
97 return visitKnownMemberImpl<Name##Record>(CVR, Record); \
99 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
100 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
103 template <typename RecordKind>
104 Error visitKnownRecordImpl(CVType &CVR, RecordKind &Record) {
105 return Mapping.visitKnownRecord(CVR, Record);
108 template <typename RecordType>
109 Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
110 assert(CVR.Kind == static_cast<TypeLeafKind>(Record.getKind()));
112 if (auto EC = Writer.writeEnum(CVR.Kind))
115 if (auto EC = Mapping.visitKnownMember(CVR, Record))
118 // Get all the data that was just written and is yet to be committed to
119 // the current segment. Then pad it to 4 bytes.
120 MutableArrayRef<uint8_t> ThisRecord = getCurrentSubRecordData();
121 auto ExpectedRecord = addPadding(ThisRecord);
123 return ExpectedRecord.takeError();
124 ThisRecord = *ExpectedRecord;
126 CurrentSegment.SubRecords.emplace_back(CVR.Kind, ThisRecord.size());
127 CVR.Data = ThisRecord;
129 // Both the last subrecord and the total length of this segment should be
131 assert(ThisRecord.size() % 4 == 0);
132 assert(CurrentSegment.length() % 4 == 0);
134 return Error::success();