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
14using namespace llvm;
15using namespace codeview;
16
17ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind)
18    : Kind(Kind), Builder(Kind) {}
19
20void 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
35void 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
75TypeIndex 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