1 #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
4 using namespace llvm::codeview
;
7 struct ContinuationRecord
{
8 ulittle16_t Kind
{uint16_t(TypeLeafKind::LF_INDEX
)};
10 ulittle32_t IndexRef
{0xB0C0B0C0};
13 struct SegmentInjection
{
14 SegmentInjection(TypeLeafKind Kind
) { Prefix
.RecordKind
= Kind
; }
16 ContinuationRecord Cont
;
21 static void addPadding(BinaryStreamWriter
&Writer
) {
22 uint32_t Align
= Writer
.getOffset() % 4;
26 int PaddingBytes
= 4 - Align
;
27 while (PaddingBytes
> 0) {
28 uint8_t Pad
= static_cast<uint8_t>(LF_PAD0
+ PaddingBytes
);
29 cantFail(Writer
.writeInteger(Pad
));
34 static SegmentInjection
InjectFieldList(TypeLeafKind::LF_FIELDLIST
);
35 static SegmentInjection
InjectMethodOverloadList(TypeLeafKind::LF_METHODLIST
);
37 static constexpr uint32_t ContinuationLength
= sizeof(ContinuationRecord
);
38 static constexpr uint32_t MaxSegmentLength
=
39 MaxRecordLength
- ContinuationLength
;
41 static inline TypeLeafKind
getTypeLeafKind(ContinuationRecordKind CK
) {
42 return (CK
== ContinuationRecordKind::FieldList
) ? LF_FIELDLIST
46 ContinuationRecordBuilder::ContinuationRecordBuilder()
47 : SegmentWriter(Buffer
), Mapping(SegmentWriter
) {}
49 ContinuationRecordBuilder::~ContinuationRecordBuilder() {}
51 void ContinuationRecordBuilder::begin(ContinuationRecordKind RecordKind
) {
52 assert(!Kind
.hasValue());
55 SegmentWriter
.setOffset(0);
56 SegmentOffsets
.clear();
57 SegmentOffsets
.push_back(0);
58 assert(SegmentWriter
.getOffset() == 0);
59 assert(SegmentWriter
.getLength() == 0);
61 const SegmentInjection
*FLI
=
62 (RecordKind
== ContinuationRecordKind::FieldList
)
64 : &InjectMethodOverloadList
;
65 const uint8_t *FLIB
= reinterpret_cast<const uint8_t *>(FLI
);
66 InjectedSegmentBytes
=
67 ArrayRef
<uint8_t>(FLIB
, FLIB
+ sizeof(SegmentInjection
));
70 Type
.Type
= getTypeLeafKind(RecordKind
);
71 cantFail(Mapping
.visitTypeBegin(Type
));
73 // Seed the first trecord with an appropriate record prefix.
76 Prefix
.RecordKind
= Type
.Type
;
77 cantFail(SegmentWriter
.writeObject(Prefix
));
80 template <typename RecordType
>
81 void ContinuationRecordBuilder::writeMemberType(RecordType
&Record
) {
82 assert(Kind
.hasValue());
84 uint32_t OriginalOffset
= SegmentWriter
.getOffset();
86 CVMR
.Kind
= static_cast<TypeLeafKind
>(Record
.getKind());
88 // Member Records aren't length-prefixed, they only have a 2-byte TypeLeafKind
90 cantFail(SegmentWriter
.writeEnum(CVMR
.Kind
));
92 // Let the Mapping handle the rest.
93 cantFail(Mapping
.visitMemberBegin(CVMR
));
94 cantFail(Mapping
.visitKnownMember(CVMR
, Record
));
95 cantFail(Mapping
.visitMemberEnd(CVMR
));
97 // Make sure it's padded to 4 bytes.
98 addPadding(SegmentWriter
);
99 assert(getCurrentSegmentLength() % 4 == 0);
101 // The maximum length of a single segment is 64KB minus the size to insert a
102 // continuation. So if we are over that, inject a continuation between the
103 // previous member and the member that was just written, then end the previous
104 // segment after the continuation and begin a new one with the just-written
106 if (getCurrentSegmentLength() > MaxSegmentLength
) {
107 // We need to inject some bytes before the member we just wrote but after
108 // the previous member. Save off the length of the member we just wrote so
109 // that we can do some sanity checking on it.
110 uint32_t MemberLength
= SegmentWriter
.getOffset() - OriginalOffset
;
112 insertSegmentEnd(OriginalOffset
);
113 // Since this member now becomes a new top-level record, it should have
114 // gotten a RecordPrefix injected, and that RecordPrefix + the member we
115 // just wrote should now constitute the entirety of the current "new"
117 assert(getCurrentSegmentLength() == MemberLength
+ sizeof(RecordPrefix
));
120 assert(getCurrentSegmentLength() % 4 == 0);
121 assert(getCurrentSegmentLength() <= MaxSegmentLength
);
124 uint32_t ContinuationRecordBuilder::getCurrentSegmentLength() const {
125 return SegmentWriter
.getOffset() - SegmentOffsets
.back();
128 void ContinuationRecordBuilder::insertSegmentEnd(uint32_t Offset
) {
129 uint32_t SegmentBegin
= SegmentOffsets
.back();
131 assert(Offset
> SegmentBegin
);
132 assert(Offset
- SegmentBegin
<= MaxSegmentLength
);
134 // We need to make space for the continuation record. For now we can't fill
135 // out the length or the TypeIndex of the back-reference, but we need the
136 // space to at least be there.
137 Buffer
.insert(Offset
, InjectedSegmentBytes
);
139 uint32_t NewSegmentBegin
= Offset
+ ContinuationLength
;
140 uint32_t SegmentLength
= NewSegmentBegin
- SegmentOffsets
.back();
141 (void) SegmentLength
;
143 assert(SegmentLength
% 4 == 0);
144 assert(SegmentLength
<= MaxRecordLength
);
145 SegmentOffsets
.push_back(NewSegmentBegin
);
147 // Seek to the end so that we can keep writing against the new segment.
148 SegmentWriter
.setOffset(SegmentWriter
.getLength());
149 assert(SegmentWriter
.bytesRemaining() == 0);
152 CVType
ContinuationRecordBuilder::createSegmentRecord(
153 uint32_t OffBegin
, uint32_t OffEnd
, Optional
<TypeIndex
> RefersTo
) {
154 assert(OffEnd
- OffBegin
<= USHRT_MAX
);
156 MutableArrayRef
<uint8_t> Data
= Buffer
.data();
157 Data
= Data
.slice(OffBegin
, OffEnd
- OffBegin
);
160 Type
.Type
= getTypeLeafKind(*Kind
);
161 Type
.RecordData
= Data
;
163 // Write the length to the RecordPrefix, making sure it does not include
164 // sizeof(RecordPrefix.Length)
165 RecordPrefix
*Prefix
= reinterpret_cast<RecordPrefix
*>(Data
.data());
166 assert(Prefix
->RecordKind
== Type
.Type
);
167 Prefix
->RecordLen
= Data
.size() - sizeof(RecordPrefix::RecordLen
);
169 if (RefersTo
.hasValue()) {
170 auto Continuation
= Data
.take_back(ContinuationLength
);
171 ContinuationRecord
*CR
=
172 reinterpret_cast<ContinuationRecord
*>(Continuation
.data());
173 assert(CR
->Kind
== TypeLeafKind::LF_INDEX
);
174 assert(CR
->IndexRef
== 0xB0C0B0C0);
175 CR
->IndexRef
= RefersTo
->getIndex();
181 std::vector
<CVType
> ContinuationRecordBuilder::end(TypeIndex Index
) {
183 Type
.Type
= getTypeLeafKind(*Kind
);
184 cantFail(Mapping
.visitTypeEnd(Type
));
186 // We're now done, and we have a series of segments each beginning at an
187 // offset specified in the SegmentOffsets array. We now need to iterate
188 // over each segment and post-process them in the following two ways:
189 // 1) Each top-level record has a RecordPrefix whose type is either
190 // LF_FIELDLIST or LF_METHODLIST, but the Length field is still 0.
191 // Those should all be set to the correct length now.
192 // 2) Each continuation record has an IndexRef field which we set to the
193 // magic value 0xB0C0B0C0. Now that the caller has told us the TypeIndex
194 // they want this sequence to start from, we can go through and update
197 // Logically, the sequence of records we've built up looks like this:
199 // SegmentOffsets[0]: <Length> (Initially: uninitialized)
200 // SegmentOffsets[0]+2: LF_FIELDLIST
201 // SegmentOffsets[0]+4: Member[0]
202 // SegmentOffsets[0]+?: ...
203 // SegmentOffsets[0]+?: Member[4]
204 // SegmentOffsets[1]-8: LF_INDEX
205 // SegmentOffsets[1]-6: 0
206 // SegmentOffsets[1]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0)
208 // SegmentOffsets[1]: <Length> (Initially: uninitialized)
209 // SegmentOffsets[1]+2: LF_FIELDLIST
210 // SegmentOffsets[1]+4: Member[0]
211 // SegmentOffsets[1]+?: ...
212 // SegmentOffsets[1]+?: Member[s]
213 // SegmentOffsets[2]-8: LF_INDEX
214 // SegmentOffsets[2]-6: 0
215 // SegmentOffsets[2]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0)
219 // SegmentOffsets[N]: <Length> (Initially: uninitialized)
220 // SegmentOffsets[N]+2: LF_FIELDLIST
221 // SegmentOffsets[N]+4: Member[0]
222 // SegmentOffsets[N]+?: ...
223 // SegmentOffsets[N]+?: Member[t]
225 // And this is the way we have laid them out in the serialization buffer. But
226 // we cannot actually commit them to the underlying stream this way, due to
227 // the topological sorting requirement of a type stream (specifically,
228 // TypeIndex references can only point backwards, not forwards). So the
229 // sequence that we return to the caller contains the records in reverse
230 // order, which is the proper order for committing the serialized records.
232 std::vector
<CVType
> Types
;
233 Types
.reserve(SegmentOffsets
.size());
235 auto SO
= makeArrayRef(SegmentOffsets
);
237 uint32_t End
= SegmentWriter
.getOffset();
239 Optional
<TypeIndex
> RefersTo
;
240 for (uint32_t Offset
: reverse(SO
)) {
241 Types
.push_back(createSegmentRecord(Offset
, End
, RefersTo
));
251 // Explicitly instantiate the member function for each known type so that we can
252 // implement this in the cpp file.
253 #define TYPE_RECORD(EnumName, EnumVal, Name)
254 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
255 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
256 template void llvm::codeview::ContinuationRecordBuilder::writeMemberType( \
257 Name##Record &Record);
258 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
259 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"