Home | History | Annotate | Line # | Download | only in CodeView
      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"
    252