LLVM  10.0.0svn
ContinuationRecordBuilder.cpp
Go to the documentation of this file.
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;
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 =
40 
42  return (CK == ContinuationRecordKind::FieldList) ? LF_FIELDLIST
43  : LF_METHODLIST;
44 }
45 
47  : SegmentWriter(Buffer), Mapping(SegmentWriter) {}
48 
50 
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>
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 
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 
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"
Error writeObject(const T &Obj)
Writes the object Obj to the underlying stream, as if by using memcpy.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition: Error.h:703
MutableArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array...
Definition: ArrayRef.h:350
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
static SegmentInjection InjectFieldList(TypeLeafKind::LF_FIELDLIST)
This class represents lattice values for constants.
Definition: AllocatorList.h:23
TypeLeafKind
Duplicate copy of the above enum, but using the official CV names.
Definition: CodeView.h:33
void push_back(const T &Elt)
Definition: SmallVector.h:211
void insert(uint32_t Offset, ArrayRef< uint8_t > Bytes)
detail::packed_endian_specific_integral< uint16_t, little, unaligned > ulittle16_t
Definition: Endian.h:272
CVRecord< TypeLeafKind > CVType
Definition: TypeRecord.h:35
Error visitMemberEnd(CVMemberRecord &Record) override
static SegmentInjection InjectMethodOverloadList(TypeLeafKind::LF_METHODLIST)
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:450
Error visitTypeEnd(CVType &Record) override
auto reverse(ContainerTy &&C, typename std::enable_if< has_rbegin< ContainerTy >::value >::type *=nullptr) -> decltype(make_range(C.rbegin(), C.rend()))
Definition: STLExtras.h:261
Error visitTypeBegin(CVType &Record) override
Paired begin/end actions for all types.
A 32-bit type reference.
Definition: TypeIndex.h:95
static constexpr uint32_t MaxSegmentLength
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:274
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:148
Provides write only access to a subclass of WritableBinaryStream.
Error writeInteger(T Value)
Write the integer Value to the underlying stream in the specified endianness.
static constexpr uint32_t ContinuationLength
size_t size() const
Definition: SmallVector.h:52
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:40
uint32_t getIndex() const
Definition: TypeIndex.h:110
uint32_t bytesRemaining() const
static void addPadding(BinaryStreamWriter &Writer)
MutableArrayRef< uint8_t > data()
MutableArrayRef< T > take_back(size_t N=1) const
Return a copy of *this with only the last N elements.
Definition: ArrayRef.h:393
Error writeEnum(T Num)
Similar to writeInteger.
void setOffset(uint32_t Off)
bool hasValue() const
Definition: Optional.h:259
static TypeLeafKind getTypeLeafKind(ContinuationRecordKind CK)
std::vector< CVType > end(TypeIndex Index)
uint32_t Size
Definition: Profile.cpp:46
T * data() const
Definition: ArrayRef.h:328
void reset()
Definition: Optional.h:251
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void begin(ContinuationRecordKind RecordKind)
Error visitMemberBegin(CVMemberRecord &Record) override