[llvm-symbolizer] -print-source-context-lines option to print source code around...
[oota-llvm.git] / lib / DebugInfo / CodeView / TypeTableBuilder.cpp
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
18 using namespace llvm;
19 using namespace codeview;
20
21 namespace {
22
23 const int PointerKindShift = 0;
24 const int PointerModeShift = 5;
25 const int PointerSizeShift = 13;
26
27 const int ClassHfaKindShift = 11;
28 const int ClassWindowsRTClassKindShift = 14;
29
30 void 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
42 TypeTableBuilder::TypeTableBuilder() {}
43
44 TypeTableBuilder::~TypeTableBuilder() {}
45
46 TypeIndex 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
55 TypeIndex 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
67 TypeIndex
68 TypeTableBuilder::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
83 TypeIndex
84 TypeTableBuilder::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
95 TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) {
96   TypeRecordBuilder Builder(TypeRecordKind::Pointer);
97
98   writePointerBase(Builder, Record);
99
100   return writeRecord(Builder);
101 }
102
103 TypeIndex
104 TypeTableBuilder::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
115 TypeIndex 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
126 TypeIndex 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
158 TypeIndex 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
174 TypeIndex 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
184 TypeIndex 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
202 TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) {
203   return writeRecord(Builder.str());
204 }
205
206 TypeIndex 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
212 TypeIndex
213 TypeTableBuilder::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 }