LLVM  8.0.1
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  CVType Type;
70  Type.Type = getTypeLeafKind(RecordKind);
71  cantFail(Mapping.visitTypeBegin(Type));
72 
73  // Seed the first trecord with an appropriate record prefix.
75  Prefix.RecordLen = 0;
76  Prefix.RecordKind = Type.Type;
77  cantFail(SegmentWriter.writeObject(Prefix));
78 }
79 
80 template <typename RecordType>
82  assert(Kind.hasValue());
83 
84  uint32_t OriginalOffset = SegmentWriter.getOffset();
85  CVMemberRecord CVMR;
86  CVMR.Kind = static_cast<TypeLeafKind>(Record.getKind());
87 
88  // Member Records aren't length-prefixed, they only have a 2-byte TypeLeafKind
89  // at the beginning.
90  cantFail(SegmentWriter.writeEnum(CVMR.Kind));
91 
92  // Let the Mapping handle the rest.
93  cantFail(Mapping.visitMemberBegin(CVMR));
94  cantFail(Mapping.visitKnownMember(CVMR, Record));
95  cantFail(Mapping.visitMemberEnd(CVMR));
96 
97  // Make sure it's padded to 4 bytes.
98  addPadding(SegmentWriter);
99  assert(getCurrentSegmentLength() % 4 == 0);
100 
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
105  // member.
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;
111  (void) MemberLength;
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"
116  // segment.
117  assert(getCurrentSegmentLength() == MemberLength + sizeof(RecordPrefix));
118  }
119 
120  assert(getCurrentSegmentLength() % 4 == 0);
121  assert(getCurrentSegmentLength() <= MaxSegmentLength);
122 }
123 
124 uint32_t ContinuationRecordBuilder::getCurrentSegmentLength() const {
125  return SegmentWriter.getOffset() - SegmentOffsets.back();
126 }
127 
128 void ContinuationRecordBuilder::insertSegmentEnd(uint32_t Offset) {
129  uint32_t SegmentBegin = SegmentOffsets.back();
130  (void)SegmentBegin;
131  assert(Offset > SegmentBegin);
132  assert(Offset - SegmentBegin <= MaxSegmentLength);
133 
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);
138 
139  uint32_t NewSegmentBegin = Offset + ContinuationLength;
140  uint32_t SegmentLength = NewSegmentBegin - SegmentOffsets.back();
141  (void) SegmentLength;
142 
143  assert(SegmentLength % 4 == 0);
144  assert(SegmentLength <= MaxRecordLength);
145  SegmentOffsets.push_back(NewSegmentBegin);
146 
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);
150 }
151 
152 CVType ContinuationRecordBuilder::createSegmentRecord(
153  uint32_t OffBegin, uint32_t OffEnd, Optional<TypeIndex> RefersTo) {
154  assert(OffEnd - OffBegin <= USHRT_MAX);
155 
157  Data = Data.slice(OffBegin, OffEnd - OffBegin);
158 
159  CVType Type;
160  Type.Type = getTypeLeafKind(*Kind);
161  Type.RecordData = Data;
162 
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);
168 
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();
176  }
177 
178  return Type;
179 }
180 
182  CVType Type;
183  Type.Type = getTypeLeafKind(*Kind);
184  cantFail(Mapping.visitTypeEnd(Type));
185 
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
195  // each one.
196  //
197  // Logically, the sequence of records we've built up looks like this:
198  //
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)
207  //
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)
216  //
217  // ...
218  //
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]
224  //
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.
231 
232  std::vector<CVType> Types;
233  Types.reserve(SegmentOffsets.size());
234 
235  auto SO = makeArrayRef(SegmentOffsets);
236 
237  uint32_t End = SegmentWriter.getOffset();
238 
239  Optional<TypeIndex> RefersTo;
240  for (uint32_t Offset : reverse(SO)) {
241  Types.push_back(createSegmentRecord(Offset, End, RefersTo));
242 
243  End = Offset;
244  RefersTo = Index++;
245  }
246 
247  Kind.reset();
248  return Types;
249 }
250 
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"
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:704
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:351
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:24
TypeLeafKind
Duplicate copy of the above enum, but using the official CV names.
Definition: CodeView.h:34
void push_back(const T &Elt)
Definition: SmallVector.h:218
void insert(uint32_t Offset, ArrayRef< uint8_t > Bytes)
detail::packed_endian_specific_integral< uint16_t, little, unaligned > ulittle16_t
Definition: Endian.h:269
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:451
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:267
Error visitTypeBegin(CVType &Record) override
Paired begin/end actions for all types.
A 32-bit type reference.
Definition: TypeIndex.h:96
static constexpr uint32_t MaxSegmentLength
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:46
detail::packed_endian_specific_integral< uint32_t, little, unaligned > ulittle32_t
Definition: Endian.h:271
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:149
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:53
uint32_t getIndex() const
Definition: TypeIndex.h:111
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:394
Error writeEnum(T Num)
Similar to writeInteger.
void setOffset(uint32_t Off)
bool hasValue() const
Definition: Optional.h:165
static TypeLeafKind getTypeLeafKind(ContinuationRecordKind CK)
std::vector< CVType > end(TypeIndex Index)
ArrayRef< uint8_t > RecordData
Definition: CVRecord.h:49
uint32_t Size
Definition: Profile.cpp:47
T * data() const
Definition: ArrayRef.h:329
const unsigned Kind
void reset()
Definition: Optional.h:151
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void begin(ContinuationRecordKind RecordKind)
Error visitMemberBegin(CVMemberRecord &Record) override