LCOV - code coverage report
Current view: top level - lib/DebugInfo/CodeView - ContinuationRecordBuilder.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 55 55 100.0 %
Date: 2018-07-13 00:08:38 Functions: 18 18 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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      199486 :   SegmentInjection(TypeLeafKind Kind) { Prefix.RecordKind = Kind; }
      15             : 
      16             :   ContinuationRecord Cont;
      17             :   RecordPrefix Prefix;
      18             : };
      19             : } // namespace
      20             : 
      21        6637 : static void addPadding(BinaryStreamWriter &Writer) {
      22        6637 :   uint32_t Align = Writer.getOffset() % 4;
      23        6637 :   if (Align == 0)
      24             :     return;
      25             : 
      26        1656 :   int PaddingBytes = 4 - Align;
      27        6248 :   while (PaddingBytes > 0) {
      28        2296 :     uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
      29        4592 :     cantFail(Writer.writeInteger(Pad));
      30        2296 :     --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         681 :   return (CK == ContinuationRecordKind::FieldList) ? LF_FIELDLIST
      43             :                                                    : LF_METHODLIST;
      44             : }
      45             : 
      46         255 : ContinuationRecordBuilder::ContinuationRecordBuilder()
      47         510 :     : SegmentWriter(Buffer), Mapping(SegmentWriter) {}
      48             : 
      49         506 : ContinuationRecordBuilder::~ContinuationRecordBuilder() {}
      50             : 
      51         227 : void ContinuationRecordBuilder::begin(ContinuationRecordKind RecordKind) {
      52             :   assert(!Kind.hasValue());
      53             :   Kind = RecordKind;
      54             :   Buffer.clear();
      55             :   SegmentWriter.setOffset(0);
      56             :   SegmentOffsets.clear();
      57         227 :   SegmentOffsets.push_back(0);
      58             :   assert(SegmentWriter.getOffset() == 0);
      59             :   assert(SegmentWriter.getLength() == 0);
      60             : 
      61         227 :   const SegmentInjection *FLI =
      62             :       (RecordKind == ContinuationRecordKind::FieldList)
      63             :           ? &InjectFieldList
      64             :           : &InjectMethodOverloadList;
      65             :   const uint8_t *FLIB = reinterpret_cast<const uint8_t *>(FLI);
      66         227 :   InjectedSegmentBytes =
      67             :       ArrayRef<uint8_t>(FLIB, FLIB + sizeof(SegmentInjection));
      68             : 
      69             :   CVType Type;
      70         227 :   Type.Type = getTypeLeafKind(RecordKind);
      71         454 :   cantFail(Mapping.visitTypeBegin(Type));
      72             : 
      73             :   // Seed the first trecord with an appropriate record prefix.
      74             :   RecordPrefix Prefix;
      75             :   Prefix.RecordLen = 0;
      76         227 :   Prefix.RecordKind = Type.Type;
      77         454 :   cantFail(SegmentWriter.writeObject(Prefix));
      78         227 : }
      79             : 
      80             : template <typename RecordType>
      81        6637 : void ContinuationRecordBuilder::writeMemberType(RecordType &Record) {
      82             :   assert(Kind.hasValue());
      83             : 
      84        6637 :   uint32_t OriginalOffset = SegmentWriter.getOffset();
      85             :   CVMemberRecord CVMR;
      86        6637 :   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       13274 :   cantFail(SegmentWriter.writeEnum(CVMR.Kind));
      91             : 
      92             :   // Let the Mapping handle the rest.
      93       13274 :   cantFail(Mapping.visitMemberBegin(CVMR));
      94       13274 :   cantFail(Mapping.visitKnownMember(CVMR, Record));
      95       13274 :   cantFail(Mapping.visitMemberEnd(CVMR));
      96             : 
      97             :   // Make sure it's padded to 4 bytes.
      98        6637 :   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        6637 :   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           4 :     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        6637 : }
     123             : 
     124        6637 : uint32_t ContinuationRecordBuilder::getCurrentSegmentLength() const {
     125        6637 :   return SegmentWriter.getOffset() - SegmentOffsets.back();
     126             : }
     127             : 
     128           4 : 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           4 :   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           4 :   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           4 : }
     151             : 
     152         229 : CVType ContinuationRecordBuilder::createSegmentRecord(
     153             :     uint32_t OffBegin, uint32_t OffEnd, Optional<TypeIndex> RefersTo) {
     154             :   assert(OffEnd - OffBegin <= USHRT_MAX);
     155             : 
     156             :   MutableArrayRef<uint8_t> Data = Buffer.data();
     157         229 :   Data = Data.slice(OffBegin, OffEnd - OffBegin);
     158             : 
     159             :   CVType Type;
     160         458 :   Type.Type = getTypeLeafKind(*Kind);
     161         229 :   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         229 :   Prefix->RecordLen = Data.size() - sizeof(RecordPrefix::RecordLen);
     168             : 
     169         229 :   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         229 :   return Type;
     179             : }
     180             : 
     181         225 : std::vector<CVType> ContinuationRecordBuilder::end(TypeIndex Index) {
     182             :   CVType Type;
     183         450 :   Type.Type = getTypeLeafKind(*Kind);
     184         450 :   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         225 :   Types.reserve(SegmentOffsets.size());
     234             : 
     235             :   auto SO = makeArrayRef(SegmentOffsets);
     236             : 
     237         225 :   uint32_t End = SegmentWriter.getOffset();
     238             : 
     239             :   Optional<TypeIndex> RefersTo;
     240         454 :   for (uint32_t Offset : reverse(SO)) {
     241         458 :     Types.push_back(createSegmentRecord(Offset, End, RefersTo));
     242             : 
     243             :     End = Offset;
     244         458 :     RefersTo = Index++;
     245             :   }
     246             : 
     247             :   Kind.reset();
     248         225 :   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"

Generated by: LCOV version 1.13