• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/DebugInfo/CodeView/FieldListRecordBuilder.h"
12 #include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h"
13 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
14 #include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h"
15 #include "llvm/Support/raw_ostream.h"
16 
17 using namespace llvm;
18 using namespace codeview;
19 
TypeTableBuilder()20 TypeTableBuilder::TypeTableBuilder() {}
21 
~TypeTableBuilder()22 TypeTableBuilder::~TypeTableBuilder() {}
23 
writeModifier(const ModifierRecord & Record)24 TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) {
25   TypeRecordBuilder Builder(Record.getKind());
26 
27   Builder.writeTypeIndex(Record.getModifiedType());
28   Builder.writeUInt16(static_cast<uint16_t>(Record.getModifiers()));
29 
30   return writeRecord(Builder);
31 }
32 
writeProcedure(const ProcedureRecord & Record)33 TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) {
34   TypeRecordBuilder Builder(Record.getKind());
35 
36   Builder.writeTypeIndex(Record.getReturnType());
37   Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
38   Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions()));
39   Builder.writeUInt16(Record.getParameterCount());
40   Builder.writeTypeIndex(Record.getArgumentList());
41 
42   return writeRecord(Builder);
43 }
44 
45 TypeIndex
writeMemberFunction(const MemberFunctionRecord & Record)46 TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) {
47   TypeRecordBuilder Builder(Record.getKind());
48 
49   Builder.writeTypeIndex(Record.getReturnType());
50   Builder.writeTypeIndex(Record.getClassType());
51   Builder.writeTypeIndex(Record.getThisType());
52   Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
53   Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions()));
54   Builder.writeUInt16(Record.getParameterCount());
55   Builder.writeTypeIndex(Record.getArgumentList());
56   Builder.writeInt32(Record.getThisPointerAdjustment());
57 
58   return writeRecord(Builder);
59 }
60 
writeArgList(const ArgListRecord & Record)61 TypeIndex TypeTableBuilder::writeArgList(const ArgListRecord &Record) {
62   TypeRecordBuilder Builder(Record.getKind());
63 
64   Builder.writeUInt32(Record.getIndices().size());
65   for (TypeIndex TI : Record.getIndices()) {
66     Builder.writeTypeIndex(TI);
67   }
68 
69   return writeRecord(Builder);
70 }
71 
writePointer(const PointerRecord & Record)72 TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) {
73   TypeRecordBuilder Builder(Record.getKind());
74 
75   Builder.writeTypeIndex(Record.getReferentType());
76   uint32_t flags = static_cast<uint32_t>(Record.getOptions()) |
77                    (Record.getSize() << PointerRecord::PointerSizeShift) |
78                    (static_cast<uint32_t>(Record.getMode())
79                     << PointerRecord::PointerModeShift) |
80                    (static_cast<uint32_t>(Record.getPointerKind())
81                     << PointerRecord::PointerKindShift);
82   Builder.writeUInt32(flags);
83 
84   if (Record.isPointerToMember()) {
85     const MemberPointerInfo &M = Record.getMemberInfo();
86     Builder.writeTypeIndex(M.getContainingType());
87     Builder.writeUInt16(static_cast<uint16_t>(M.getRepresentation()));
88   }
89 
90   return writeRecord(Builder);
91 }
92 
writeArray(const ArrayRecord & Record)93 TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) {
94   TypeRecordBuilder Builder(Record.getKind());
95 
96   Builder.writeTypeIndex(Record.getElementType());
97   Builder.writeTypeIndex(Record.getIndexType());
98   Builder.writeEncodedUnsignedInteger(Record.getSize());
99   Builder.writeNullTerminatedString(Record.getName());
100 
101   return writeRecord(Builder);
102 }
103 
writeClass(const ClassRecord & Record)104 TypeIndex TypeTableBuilder::writeClass(const ClassRecord &Record) {
105   assert((Record.getKind() == TypeRecordKind::Struct) ||
106          (Record.getKind() == TypeRecordKind::Class) ||
107          (Record.getKind() == TypeRecordKind::Interface));
108 
109   TypeRecordBuilder Builder(Record.getKind());
110 
111   Builder.writeUInt16(Record.getMemberCount());
112   uint16_t Flags =
113       static_cast<uint16_t>(Record.getOptions()) |
114       (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift) |
115       (static_cast<uint16_t>(Record.getWinRTKind())
116        << ClassRecord::WinRTKindShift);
117   Builder.writeUInt16(Flags);
118   Builder.writeTypeIndex(Record.getFieldList());
119   Builder.writeTypeIndex(Record.getDerivationList());
120   Builder.writeTypeIndex(Record.getVTableShape());
121   Builder.writeEncodedUnsignedInteger(Record.getSize());
122   Builder.writeNullTerminatedString(Record.getName());
123   if ((Record.getOptions() & ClassOptions::HasUniqueName) !=
124       ClassOptions::None) {
125     Builder.writeNullTerminatedString(Record.getUniqueName());
126   }
127 
128   return writeRecord(Builder);
129 }
130 
writeUnion(const UnionRecord & Record)131 TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) {
132   TypeRecordBuilder Builder(TypeRecordKind::Union);
133   Builder.writeUInt16(Record.getMemberCount());
134   uint16_t Flags =
135       static_cast<uint16_t>(Record.getOptions()) |
136       (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift);
137   Builder.writeUInt16(Flags);
138   Builder.writeTypeIndex(Record.getFieldList());
139   Builder.writeEncodedUnsignedInteger(Record.getSize());
140   Builder.writeNullTerminatedString(Record.getName());
141   if ((Record.getOptions() & ClassOptions::HasUniqueName) !=
142       ClassOptions::None) {
143     Builder.writeNullTerminatedString(Record.getUniqueName());
144   }
145   return writeRecord(Builder);
146 }
147 
writeEnum(const EnumRecord & Record)148 TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) {
149   TypeRecordBuilder Builder(Record.getKind());
150 
151   Builder.writeUInt16(Record.getMemberCount());
152   Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions()));
153   Builder.writeTypeIndex(Record.getUnderlyingType());
154   Builder.writeTypeIndex(Record.getFieldList());
155   Builder.writeNullTerminatedString(Record.getName());
156   if ((Record.getOptions() & ClassOptions::HasUniqueName) !=
157       ClassOptions::None) {
158     Builder.writeNullTerminatedString(Record.getUniqueName());
159   }
160 
161   return writeRecord(Builder);
162 }
163 
writeBitField(const BitFieldRecord & Record)164 TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) {
165   TypeRecordBuilder Builder(Record.getKind());
166 
167   Builder.writeTypeIndex(Record.getType());
168   Builder.writeUInt8(Record.getBitSize());
169   Builder.writeUInt8(Record.getBitOffset());
170 
171   return writeRecord(Builder);
172 }
173 
174 TypeIndex
writeVFTableShape(const VFTableShapeRecord & Record)175 TypeTableBuilder::writeVFTableShape(const VFTableShapeRecord &Record) {
176   TypeRecordBuilder Builder(Record.getKind());
177 
178   ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
179 
180   Builder.writeUInt16(Slots.size());
181   for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
182     uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
183     if ((SlotIndex + 1) < Slots.size()) {
184       Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
185     }
186     Builder.writeUInt8(Byte);
187   }
188 
189   return writeRecord(Builder);
190 }
191 
192 TypeIndex
writeVFTable(const VFTableRecord & Record)193 TypeTableBuilder::writeVFTable(const VFTableRecord &Record) {
194   TypeRecordBuilder Builder(Record.getKind());
195   Builder.writeTypeIndex(Record.getCompleteClass());
196   Builder.writeTypeIndex(Record.getOverriddenVTable());
197   Builder.writeUInt32(Record.getVFPtrOffset());
198 
199   // Sum up the lengths of the null-terminated names.
200   size_t NamesLen = Record.getName().size() + 1;
201   for (StringRef MethodName : Record.getMethodNames())
202     NamesLen += MethodName.size() + 1;
203 
204   Builder.writeUInt32(NamesLen);
205   Builder.writeNullTerminatedString(Record.getName());
206   for (StringRef MethodName : Record.getMethodNames())
207     Builder.writeNullTerminatedString(MethodName);
208 
209   return writeRecord(Builder);
210 }
211 
writeStringId(const StringIdRecord & Record)212 TypeIndex TypeTableBuilder::writeStringId(const StringIdRecord &Record) {
213   TypeRecordBuilder Builder(TypeRecordKind::StringId);
214   Builder.writeTypeIndex(Record.getId());
215   Builder.writeNullTerminatedString(Record.getString());
216   return writeRecord(Builder);
217 }
218 
219 TypeIndex
writeUdtSourceLine(const UdtSourceLineRecord & Record)220 TypeTableBuilder::writeUdtSourceLine(const UdtSourceLineRecord &Record) {
221   TypeRecordBuilder Builder(Record.getKind());
222   Builder.writeTypeIndex(Record.getUDT());
223   Builder.writeTypeIndex(Record.getSourceFile());
224   Builder.writeUInt32(Record.getLineNumber());
225   return writeRecord(Builder);
226 }
227 
228 TypeIndex
writeUdtModSourceLine(const UdtModSourceLineRecord & Record)229 TypeTableBuilder::writeUdtModSourceLine(const UdtModSourceLineRecord &Record) {
230   TypeRecordBuilder Builder(Record.getKind());
231   Builder.writeTypeIndex(Record.getUDT());
232   Builder.writeTypeIndex(Record.getSourceFile());
233   Builder.writeUInt32(Record.getLineNumber());
234   Builder.writeUInt16(Record.getModule());
235   return writeRecord(Builder);
236 }
237 
writeFuncId(const FuncIdRecord & Record)238 TypeIndex TypeTableBuilder::writeFuncId(const FuncIdRecord &Record) {
239   TypeRecordBuilder Builder(Record.getKind());
240   Builder.writeTypeIndex(Record.getParentScope());
241   Builder.writeTypeIndex(Record.getFunctionType());
242   Builder.writeNullTerminatedString(Record.getName());
243   return writeRecord(Builder);
244 }
245 
246 TypeIndex
writeMemberFuncId(const MemberFuncIdRecord & Record)247 TypeTableBuilder::writeMemberFuncId(const MemberFuncIdRecord &Record) {
248   TypeRecordBuilder Builder(Record.getKind());
249   Builder.writeTypeIndex(Record.getClassType());
250   Builder.writeTypeIndex(Record.getFunctionType());
251   Builder.writeNullTerminatedString(Record.getName());
252   return writeRecord(Builder);
253 }
254 
255 TypeIndex
writeBuildInfo(const BuildInfoRecord & Record)256 TypeTableBuilder::writeBuildInfo(const BuildInfoRecord &Record) {
257   TypeRecordBuilder Builder(Record.getKind());
258   assert(Record.getArgs().size() <= UINT16_MAX);
259   Builder.writeUInt16(Record.getArgs().size());
260   for (TypeIndex Arg : Record.getArgs())
261     Builder.writeTypeIndex(Arg);
262   return writeRecord(Builder);
263 }
264 
writeRecord(TypeRecordBuilder & Builder)265 TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) {
266   return writeRecord(Builder.str());
267 }
268 
writeFieldList(FieldListRecordBuilder & FieldList)269 TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) {
270   return FieldList.writeListRecord(*this);
271 }
272 
writeMethodOverloadList(const MethodOverloadListRecord & Record)273 TypeIndex TypeTableBuilder::writeMethodOverloadList(
274     const MethodOverloadListRecord &Record) {
275   TypeRecordBuilder Builder(Record.getKind());
276   for (const OneMethodRecord &Method : Record.getMethods()) {
277     uint16_t Flags = static_cast<uint16_t>(Method.getAccess());
278     Flags |= static_cast<uint16_t>(Method.getKind())
279              << MemberAttributes::MethodKindShift;
280     Flags |= static_cast<uint16_t>(Method.getOptions());
281     Builder.writeUInt16(Flags);
282     Builder.writeUInt16(0); // padding
283     Builder.writeTypeIndex(Method.getType());
284     if (Method.isIntroducingVirtual()) {
285       assert(Method.getVFTableOffset() >= 0);
286       Builder.writeInt32(Method.getVFTableOffset());
287     } else {
288       assert(Method.getVFTableOffset() == -1);
289     }
290   }
291 
292   // TODO: Split the list into multiple records if it's longer than 64KB, using
293   // a subrecord of TypeRecordKind::Index to chain the records together.
294   return writeRecord(Builder);
295 }
296 
writeTypeServer2(const TypeServer2Record & Record)297 TypeIndex TypeTableBuilder::writeTypeServer2(const TypeServer2Record &Record) {
298   TypeRecordBuilder Builder(Record.getKind());
299   Builder.writeGuid(Record.getGuid());
300   Builder.writeUInt32(Record.getAge());
301   Builder.writeNullTerminatedString(Record.getName());
302   return writeRecord(Builder);
303 }
304