Coverage Report

Created: 2019-07-24 05:18

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