diff options
Diffstat (limited to 'lib/DebugInfo/CodeView/ListRecordBuilder.cpp')
-rw-r--r-- | lib/DebugInfo/CodeView/ListRecordBuilder.cpp | 87 |
1 files changed, 79 insertions, 8 deletions
diff --git a/lib/DebugInfo/CodeView/ListRecordBuilder.cpp b/lib/DebugInfo/CodeView/ListRecordBuilder.cpp index 69c7e87330e6..eb79e8ac9a3f 100644 --- a/lib/DebugInfo/CodeView/ListRecordBuilder.cpp +++ b/lib/DebugInfo/CodeView/ListRecordBuilder.cpp @@ -7,25 +7,96 @@ // //===----------------------------------------------------------------------===// +#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) : Builder(Kind) {} +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 builder starts at offset 2 in the actual CodeView buffer, so add an - // additional offset of 2 before computing the alignment. - uint32_t Remainder = (Builder.size() + 2) % 4; + // 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(0xf0 + PaddingBytesLeft); + Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft); } } - // TODO: Split the list into multiple records if it's longer than 64KB, using - // a subrecord of TypeRecordKind::Index to chain the records together. - assert(Builder.size() < 65536); + // 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<StringRef, 1> 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<const ulittle16_t *>(Rec.data()) == + unsigned(Kind)); + ulittle32_t *ContinuationPtr = + reinterpret_cast<ulittle32_t *>(const_cast<char *>(Rec.end())) - 1; + *ContinuationPtr = ContinuationIndex.getIndex(); + ContinuationIndex = Table.writeRecord(Rec); + } + return ContinuationIndex; } |