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