1 //===-- ListRecordBuilder.cpp ---------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/ADT/SmallString.h"
11 #include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
12 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
15 using namespace codeview;
17 ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind)
18 : Kind(Kind), Builder(Kind) {}
20 void ListRecordBuilder::writeListContinuation(const ListContinuationRecord &R) {
21 TypeRecordBuilder &Builder = getBuilder();
23 assert(getLastContinuationSize() < 65535 - 8 && "continuation won't fit");
25 Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
26 Builder.writeUInt16(0);
27 Builder.writeTypeIndex(R.getContinuationIndex());
29 // End the current segment manually so that nothing comes after the
31 ContinuationOffsets.push_back(Builder.size());
32 SubrecordStart = Builder.size();
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.
39 (Builder.size() + 2 * (ContinuationOffsets.size() + 1)) % 4;
41 for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0;
43 Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft);
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
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);
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");
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);
72 SubrecordStart = Builder.size();
75 TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) {
76 // Get the continuation segments as a reversed vector of StringRefs for
78 SmallVector<StringRef, 1> Segments;
79 StringRef Data = str();
81 for (size_t SegEnd : ContinuationOffsets) {
82 Segments.push_back(Data.slice(LastEnd, SegEnd));
85 Segments.push_back(Data.slice(LastEnd, Builder.size()));
87 // Pop the last record off and emit it directly.
88 StringRef LastRec = Segments.pop_back_val();
89 TypeIndex ContinuationIndex = Table.writeRecord(LastRec);
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()) ==
96 ulittle32_t *ContinuationPtr =
97 reinterpret_cast<ulittle32_t *>(const_cast<char *>(Rec.end())) - 1;
98 *ContinuationPtr = ContinuationIndex.getIndex();
99 ContinuationIndex = Table.writeRecord(Rec);
101 return ContinuationIndex;