1//===-- TypeTableBuilder.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/DebugInfo/CodeView/TypeTableBuilder.h"
11#include "llvm/ADT/SmallVector.h"
12#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
13#include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h"
14#include "llvm/DebugInfo/CodeView/TypeIndex.h"
15#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h"
16#include "llvm/Support/raw_ostream.h"
17
18using namespace llvm;
19using namespace codeview;
20
21namespace {
22
23const int PointerKindShift = 0;
24const int PointerModeShift = 5;
25const int PointerSizeShift = 13;
26
27const int ClassHfaKindShift = 11;
28const int ClassWindowsRTClassKindShift = 14;
29
30void writePointerBase(TypeRecordBuilder &Builder,
31                      const PointerRecordBase &Record) {
32  Builder.writeTypeIndex(Record.getReferentType());
33  uint32_t flags =
34      static_cast<uint32_t>(Record.getOptions()) |
35      (Record.getSize() << PointerSizeShift) |
36      (static_cast<uint32_t>(Record.getMode()) << PointerModeShift) |
37      (static_cast<uint32_t>(Record.getPointerKind()) << PointerKindShift);
38  Builder.writeUInt32(flags);
39}
40}
41
42TypeTableBuilder::TypeTableBuilder() {}
43
44TypeTableBuilder::~TypeTableBuilder() {}
45
46TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) {
47  TypeRecordBuilder Builder(TypeRecordKind::Modifier);
48
49  Builder.writeTypeIndex(Record.getModifiedType());
50  Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions()));
51
52  return writeRecord(Builder);
53}
54
55TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) {
56  TypeRecordBuilder Builder(TypeRecordKind::Procedure);
57
58  Builder.writeTypeIndex(Record.getReturnType());
59  Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
60  Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions()));
61  Builder.writeUInt16(Record.getParameterCount());
62  Builder.writeTypeIndex(Record.getArgumentList());
63
64  return writeRecord(Builder);
65}
66
67TypeIndex
68TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) {
69  TypeRecordBuilder Builder(TypeRecordKind::MemberFunction);
70
71  Builder.writeTypeIndex(Record.getReturnType());
72  Builder.writeTypeIndex(Record.getClassType());
73  Builder.writeTypeIndex(Record.getThisType());
74  Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
75  Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions()));
76  Builder.writeUInt16(Record.getParameterCount());
77  Builder.writeTypeIndex(Record.getArgumentList());
78  Builder.writeInt32(Record.getThisPointerAdjustment());
79
80  return writeRecord(Builder);
81}
82
83TypeIndex
84TypeTableBuilder::writeArgumentList(const ArgumentListRecord &Record) {
85  TypeRecordBuilder Builder(TypeRecordKind::ArgumentList);
86
87  Builder.writeUInt32(Record.getArgumentTypes().size());
88  for (TypeIndex TI : Record.getArgumentTypes()) {
89    Builder.writeTypeIndex(TI);
90  }
91
92  return writeRecord(Builder);
93}
94
95TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) {
96  TypeRecordBuilder Builder(TypeRecordKind::Pointer);
97
98  writePointerBase(Builder, Record);
99
100  return writeRecord(Builder);
101}
102
103TypeIndex
104TypeTableBuilder::writePointerToMember(const PointerToMemberRecord &Record) {
105  TypeRecordBuilder Builder(TypeRecordKind::Pointer);
106
107  writePointerBase(Builder, Record);
108
109  Builder.writeTypeIndex(Record.getContainingType());
110  Builder.writeUInt16(static_cast<uint16_t>(Record.getRepresentation()));
111
112  return writeRecord(Builder);
113}
114
115TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) {
116  TypeRecordBuilder Builder(TypeRecordKind::Array);
117
118  Builder.writeTypeIndex(Record.getElementType());
119  Builder.writeTypeIndex(Record.getIndexType());
120  Builder.writeEncodedUnsignedInteger(Record.getSize());
121  Builder.writeNullTerminatedString(Record.getName());
122
123  return writeRecord(Builder);
124}
125
126TypeIndex TypeTableBuilder::writeAggregate(const AggregateRecord &Record) {
127  assert((Record.getKind() == TypeRecordKind::Structure) ||
128         (Record.getKind() == TypeRecordKind::Class) ||
129         (Record.getKind() == TypeRecordKind::Union));
130
131  TypeRecordBuilder Builder(Record.getKind());
132
133  Builder.writeUInt16(Record.getMemberCount());
134  uint16_t Flags =
135      static_cast<uint16_t>(Record.getOptions()) |
136      (static_cast<uint16_t>(Record.getHfa()) << ClassHfaKindShift) |
137      (static_cast<uint16_t>(Record.getWinRTKind())
138       << ClassWindowsRTClassKindShift);
139  Builder.writeUInt16(Flags);
140  Builder.writeTypeIndex(Record.getFieldList());
141  if (Record.getKind() != TypeRecordKind::Union) {
142    Builder.writeTypeIndex(Record.getDerivationList());
143    Builder.writeTypeIndex(Record.getVTableShape());
144  } else {
145    assert(Record.getDerivationList() == TypeIndex());
146    assert(Record.getVTableShape() == TypeIndex());
147  }
148  Builder.writeEncodedUnsignedInteger(Record.getSize());
149  Builder.writeNullTerminatedString(Record.getName());
150  if ((Record.getOptions() & ClassOptions::HasUniqueName) !=
151      ClassOptions::None) {
152    Builder.writeNullTerminatedString(Record.getUniqueName());
153  }
154
155  return writeRecord(Builder);
156}
157
158TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) {
159  TypeRecordBuilder Builder(TypeRecordKind::Enum);
160
161  Builder.writeUInt16(Record.getMemberCount());
162  Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions()));
163  Builder.writeTypeIndex(Record.getUnderlyingType());
164  Builder.writeTypeIndex(Record.getFieldList());
165  Builder.writeNullTerminatedString(Record.getName());
166  if ((Record.getOptions() & ClassOptions::HasUniqueName) !=
167      ClassOptions::None) {
168    Builder.writeNullTerminatedString(Record.getUniqueName());
169  }
170
171  return writeRecord(Builder);
172}
173
174TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) {
175  TypeRecordBuilder Builder(TypeRecordKind::BitField);
176
177  Builder.writeTypeIndex(Record.getType());
178  Builder.writeUInt8(Record.getBitSize());
179  Builder.writeUInt8(Record.getBitOffset());
180
181  return writeRecord(Builder);
182}
183
184TypeIndex TypeTableBuilder::writeVirtualTableShape(
185    const VirtualTableShapeRecord &Record) {
186  TypeRecordBuilder Builder(TypeRecordKind::VirtualTableShape);
187
188  ArrayRef<VirtualTableSlotKind> Slots = Record.getSlots();
189
190  Builder.writeUInt16(Slots.size());
191  for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
192    uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
193    if ((SlotIndex + 1) < Slots.size()) {
194      Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
195    }
196    Builder.writeUInt8(Byte);
197  }
198
199  return writeRecord(Builder);
200}
201
202TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) {
203  return writeRecord(Builder.str());
204}
205
206TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) {
207  // TODO: Split the list into multiple records if it's longer than 64KB, using
208  // a subrecord of TypeRecordKind::Index to chain the records together.
209  return writeRecord(FieldList.str());
210}
211
212TypeIndex
213TypeTableBuilder::writeMethodList(MethodListRecordBuilder &MethodList) {
214  // TODO: Split the list into multiple records if it's longer than 64KB, using
215  // a subrecord of TypeRecordKind::Index to chain the records together.
216  return writeRecord(MethodList.str());
217}
218