//===-- ListRecordBuilder.cpp ---------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/CodeView/ListRecordBuilder.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" using namespace llvm; using namespace codeview; ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) : Kind(Kind), Builder(Kind) {} void ListRecordBuilder::writeListContinuation(const ListContinuationRecord &R) { TypeRecordBuilder &Builder = getBuilder(); assert(getLastContinuationSize() < 65535 - 8 && "continuation won't fit"); Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation); Builder.writeUInt16(0); Builder.writeTypeIndex(R.getContinuationIndex()); // End the current segment manually so that nothing comes after the // continuation. ContinuationOffsets.push_back(Builder.size()); SubrecordStart = Builder.size(); } void ListRecordBuilder::finishSubRecord() { // The type table inserts a 16 bit size field before each list, so factor that // into our alignment padding. uint32_t Remainder = (Builder.size() + 2 * (ContinuationOffsets.size() + 1)) % 4; if (Remainder != 0) { for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0; --PaddingBytesLeft) { Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft); } } // Check if this subrecord makes the current segment not fit in 64K minus the // space for a continuation record (8 bytes). If the segment does not fit, // back up and insert a continuation record, sliding the current subrecord // down. if (getLastContinuationSize() > 65535 - 8) { assert(SubrecordStart != 0 && "can't slide from the start!"); SmallString<128> SubrecordCopy( Builder.str().slice(SubrecordStart, Builder.size())); assert(SubrecordCopy.size() < 65530 && "subrecord is too large to slide!"); Builder.truncate(SubrecordStart); // Write a placeholder continuation record. Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation); Builder.writeUInt16(0); Builder.writeUInt32(0); ContinuationOffsets.push_back(Builder.size()); assert(Builder.size() == SubrecordStart + 8 && "wrong continuation size"); assert(getLastContinuationSize() < 65535 && "segment too big"); // Start a new list record of the appropriate kind, and copy the previous // subrecord into place. Builder.writeTypeRecordKind(Kind); Builder.writeBytes(SubrecordCopy); } SubrecordStart = Builder.size(); } TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) { // Get the continuation segments as a reversed vector of StringRefs for // convenience. SmallVector Segments; StringRef Data = str(); size_t LastEnd = 0; for (size_t SegEnd : ContinuationOffsets) { Segments.push_back(Data.slice(LastEnd, SegEnd)); LastEnd = SegEnd; } Segments.push_back(Data.slice(LastEnd, Builder.size())); // Pop the last record off and emit it directly. StringRef LastRec = Segments.pop_back_val(); TypeIndex ContinuationIndex = Table.writeRecord(LastRec); // Emit each record with a continuation in reverse order, so that each one // references the previous record. for (StringRef Rec : reverse(Segments)) { assert(*reinterpret_cast(Rec.data()) == unsigned(Kind)); ulittle32_t *ContinuationPtr = reinterpret_cast(const_cast(Rec.end())) - 1; *ContinuationPtr = ContinuationIndex.getIndex(); ContinuationIndex = Table.writeRecord(Rec); } return ContinuationIndex; }