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