aboutsummaryrefslogtreecommitdiff
path: root/lib/DebugInfo/CodeView/ListRecordBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/DebugInfo/CodeView/ListRecordBuilder.cpp')
-rw-r--r--lib/DebugInfo/CodeView/ListRecordBuilder.cpp87
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;
}