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