Line data Source code
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 60300 : class TypeSerializer : public TypeVisitorCallbacks {
37 : struct SubRecord {
38 6183 : SubRecord(TypeLeafKind K, uint32_t S) : Kind(K), Size(S) {}
39 :
40 : TypeLeafKind Kind;
41 : uint32_t Size = 0;
42 : };
43 20904 : struct RecordSegment {
44 : SmallVector<SubRecord, 16> SubRecords;
45 :
46 : uint32_t length() const {
47 12370 : uint32_t L = sizeof(RecordPrefix);
48 7508053 : for (const auto &R : SubRecords) {
49 7470947 : 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 1614 : return Mapping.visitKnownRecord(CVR, Record);
124 : }
125 :
126 : template <typename RecordType>
127 6183 : Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
128 : assert(CVR.Kind == static_cast<TypeLeafKind>(Record.getKind()));
129 :
130 24732 : if (auto EC = Writer.writeEnum(CVR.Kind))
131 0 : return EC;
132 :
133 18549 : if (auto EC = Mapping.visitKnownMember(CVR, Record))
134 0 : 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 6183 : MutableArrayRef<uint8_t> ThisRecord = getCurrentSubRecordData();
139 6183 : auto ExpectedRecord = addPadding(ThisRecord);
140 6183 : if (!ExpectedRecord)
141 : return ExpectedRecord.takeError();
142 6183 : ThisRecord = *ExpectedRecord;
143 :
144 6183 : CurrentSegment.SubRecords.emplace_back(CVR.Kind, ThisRecord.size());
145 6183 : 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 18549 : return Error::success();
153 : }
154 : };
155 :
156 : } // end namespace codeview
157 : } // end namespace llvm
158 :
159 : #endif // LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
|