ContinuationRecordBuilder.cpp 9.2 KB

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