Home | History | Annotate | Download | only in CodeView
      1 //===-- ListRecordBuilder.cpp ---------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "llvm/ADT/SmallString.h"
     11 #include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
     12 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
     13 
     14 using namespace llvm;
     15 using namespace codeview;
     16 
     17 ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind)
     18     : Kind(Kind), Builder(Kind) {}
     19 
     20 void ListRecordBuilder::writeListContinuation(const ListContinuationRecord &R) {
     21   TypeRecordBuilder &Builder = getBuilder();
     22 
     23   assert(getLastContinuationSize() < 65535 - 8 && "continuation won't fit");
     24 
     25   Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
     26   Builder.writeUInt16(0);
     27   Builder.writeTypeIndex(R.getContinuationIndex());
     28 
     29   // End the current segment manually so that nothing comes after the
     30   // continuation.
     31   ContinuationOffsets.push_back(Builder.size());
     32   SubrecordStart = Builder.size();
     33 }
     34 
     35 void ListRecordBuilder::finishSubRecord() {
     36   // The type table inserts a 16 bit size field before each list, so factor that
     37   // into our alignment padding.
     38   uint32_t Remainder =
     39       (Builder.size() + 2 * (ContinuationOffsets.size() + 1)) % 4;
     40   if (Remainder != 0) {
     41     for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0;
     42          --PaddingBytesLeft) {
     43       Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft);
     44     }
     45   }
     46 
     47   // Check if this subrecord makes the current segment not fit in 64K minus the
     48   // space for a continuation record (8 bytes). If the segment does not fit,
     49   // back up and insert a continuation record, sliding the current subrecord
     50   // down.
     51   if (getLastContinuationSize() > 65535 - 8) {
     52     assert(SubrecordStart != 0 && "can't slide from the start!");
     53     SmallString<128> SubrecordCopy(
     54         Builder.str().slice(SubrecordStart, Builder.size()));
     55     assert(SubrecordCopy.size() < 65530 && "subrecord is too large to slide!");
     56     Builder.truncate(SubrecordStart);
     57 
     58     // Write a placeholder continuation record.
     59     Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
     60     Builder.writeUInt16(0);
     61     Builder.writeUInt32(0);
     62     ContinuationOffsets.push_back(Builder.size());
     63     assert(Builder.size() == SubrecordStart + 8 && "wrong continuation size");
     64     assert(getLastContinuationSize() < 65535 && "segment too big");
     65 
     66     // Start a new list record of the appropriate kind, and copy the previous
     67     // subrecord into place.
     68     Builder.writeTypeRecordKind(Kind);
     69     Builder.writeBytes(SubrecordCopy);
     70   }
     71 
     72   SubrecordStart = Builder.size();
     73 }
     74 
     75 TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) {
     76   // Get the continuation segments as a reversed vector of StringRefs for
     77   // convenience.
     78   SmallVector<StringRef, 1> Segments;
     79   StringRef Data = str();
     80   size_t LastEnd = 0;
     81   for (size_t SegEnd : ContinuationOffsets) {
     82     Segments.push_back(Data.slice(LastEnd, SegEnd));
     83     LastEnd = SegEnd;
     84   }
     85   Segments.push_back(Data.slice(LastEnd, Builder.size()));
     86 
     87   // Pop the last record off and emit it directly.
     88   StringRef LastRec = Segments.pop_back_val();
     89   TypeIndex ContinuationIndex = Table.writeRecord(LastRec);
     90 
     91   // Emit each record with a continuation in reverse order, so that each one
     92   // references the previous record.
     93   for (StringRef Rec : reverse(Segments)) {
     94     assert(*reinterpret_cast<const ulittle16_t *>(Rec.data()) ==
     95            unsigned(Kind));
     96     ulittle32_t *ContinuationPtr =
     97         reinterpret_cast<ulittle32_t *>(const_cast<char *>(Rec.end())) - 1;
     98     *ContinuationPtr = ContinuationIndex.getIndex();
     99     ContinuationIndex = Table.writeRecord(Rec);
    100   }
    101   return ContinuationIndex;
    102 }
    103