1 //===- TypeRecordMapping.cpp ------------------------------------*- C++ -*-===//
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/TypeRecordMapping.h"
11
12 using namespace llvm;
13 using namespace llvm::codeview;
14
15 #define error(X) \
16 if (auto EC = X) \
17 return EC;
18
19 namespace {
20 struct MapOneMethodRecord {
MapOneMethodRecord__anon39c983890111::MapOneMethodRecord21 explicit MapOneMethodRecord(bool IsFromOverloadList)
22 : IsFromOverloadList(IsFromOverloadList) {}
23
operator ()__anon39c983890111::MapOneMethodRecord24 Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const {
25 error(IO.mapInteger(Method.Attrs.Attrs));
26 if (IsFromOverloadList) {
27 uint16_t Padding = 0;
28 error(IO.mapInteger(Padding));
29 }
30 error(IO.mapInteger(Method.Type));
31 if (Method.isIntroducingVirtual()) {
32 error(IO.mapInteger(Method.VFTableOffset));
33 } else if (!IO.isWriting())
34 Method.VFTableOffset = -1;
35
36 if (!IsFromOverloadList)
37 error(IO.mapStringZ(Method.Name));
38
39 return Error::success();
40 }
41
42 private:
43 bool IsFromOverloadList;
44 };
45 }
46
mapNameAndUniqueName(CodeViewRecordIO & IO,StringRef & Name,StringRef & UniqueName,bool HasUniqueName)47 static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
48 StringRef &UniqueName, bool HasUniqueName) {
49 if (IO.isWriting()) {
50 // Try to be smart about what we write here. We can't write anything too
51 // large, so if we're going to go over the limit, truncate both the name
52 // and unique name by the same amount.
53 size_t BytesLeft = IO.maxFieldLength();
54 if (HasUniqueName) {
55 size_t BytesNeeded = Name.size() + UniqueName.size() + 2;
56 StringRef N = Name;
57 StringRef U = UniqueName;
58 if (BytesNeeded > BytesLeft) {
59 size_t BytesToDrop = (BytesNeeded - BytesLeft);
60 size_t DropN = std::min(N.size(), BytesToDrop / 2);
61 size_t DropU = std::min(U.size(), BytesToDrop - DropN);
62
63 N = N.drop_back(DropN);
64 U = U.drop_back(DropU);
65 }
66
67 error(IO.mapStringZ(N));
68 error(IO.mapStringZ(U));
69 } else {
70 // Cap the length of the string at however many bytes we have available,
71 // plus one for the required null terminator.
72 auto N = StringRef(Name).take_front(BytesLeft - 1);
73 error(IO.mapStringZ(N));
74 }
75 } else {
76 error(IO.mapStringZ(Name));
77 if (HasUniqueName)
78 error(IO.mapStringZ(UniqueName));
79 }
80
81 return Error::success();
82 }
83
visitTypeBegin(CVType & CVR)84 Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
85 assert(!TypeKind.hasValue() && "Already in a type mapping!");
86 assert(!MemberKind.hasValue() && "Already in a member mapping!");
87
88 // FieldList and MethodList records can be any length because they can be
89 // split with continuation records. All other record types cannot be
90 // longer than the maximum record length.
91 Optional<uint32_t> MaxLen;
92 if (CVR.Type != TypeLeafKind::LF_FIELDLIST &&
93 CVR.Type != TypeLeafKind::LF_METHODLIST)
94 MaxLen = MaxRecordLength - sizeof(RecordPrefix);
95 error(IO.beginRecord(MaxLen));
96 TypeKind = CVR.Type;
97 return Error::success();
98 }
99
visitTypeEnd(CVType & Record)100 Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
101 assert(TypeKind.hasValue() && "Not in a type mapping!");
102 assert(!MemberKind.hasValue() && "Still in a member mapping!");
103
104 error(IO.endRecord());
105
106 TypeKind.reset();
107 return Error::success();
108 }
109
visitMemberBegin(CVMemberRecord & Record)110 Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
111 assert(TypeKind.hasValue() && "Not in a type mapping!");
112 assert(!MemberKind.hasValue() && "Already in a member mapping!");
113
114 // The largest possible subrecord is one in which there is a record prefix,
115 // followed by the subrecord, followed by a continuation, and that entire
116 // sequence spaws `MaxRecordLength` bytes. So the record's length is
117 // calculated as follows.
118 constexpr uint32_t ContinuationLength = 8;
119 error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
120 ContinuationLength));
121
122 MemberKind = Record.Kind;
123 return Error::success();
124 }
125
visitMemberEnd(CVMemberRecord & Record)126 Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
127 assert(TypeKind.hasValue() && "Not in a type mapping!");
128 assert(MemberKind.hasValue() && "Not in a member mapping!");
129
130 if (!IO.isWriting()) {
131 if (auto EC = IO.skipPadding())
132 return EC;
133 }
134
135 MemberKind.reset();
136 error(IO.endRecord());
137 return Error::success();
138 }
139
visitKnownRecord(CVType & CVR,ModifierRecord & Record)140 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) {
141 error(IO.mapInteger(Record.ModifiedType));
142 error(IO.mapEnum(Record.Modifiers));
143
144 return Error::success();
145 }
146
visitKnownRecord(CVType & CVR,ProcedureRecord & Record)147 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
148 ProcedureRecord &Record) {
149 error(IO.mapInteger(Record.ReturnType));
150 error(IO.mapEnum(Record.CallConv));
151 error(IO.mapEnum(Record.Options));
152 error(IO.mapInteger(Record.ParameterCount));
153 error(IO.mapInteger(Record.ArgumentList));
154
155 return Error::success();
156 }
157
visitKnownRecord(CVType & CVR,MemberFunctionRecord & Record)158 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
159 MemberFunctionRecord &Record) {
160 error(IO.mapInteger(Record.ReturnType));
161 error(IO.mapInteger(Record.ClassType));
162 error(IO.mapInteger(Record.ThisType));
163 error(IO.mapEnum(Record.CallConv));
164 error(IO.mapEnum(Record.Options));
165 error(IO.mapInteger(Record.ParameterCount));
166 error(IO.mapInteger(Record.ArgumentList));
167 error(IO.mapInteger(Record.ThisPointerAdjustment));
168
169 return Error::success();
170 }
171
visitKnownRecord(CVType & CVR,ArgListRecord & Record)172 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
173 error(IO.mapVectorN<uint32_t>(
174 Record.ArgIndices,
175 [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
176
177 return Error::success();
178 }
179
visitKnownRecord(CVType & CVR,StringListRecord & Record)180 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
181 StringListRecord &Record) {
182 error(IO.mapVectorN<uint32_t>(
183 Record.StringIndices,
184 [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
185
186 return Error::success();
187 }
188
visitKnownRecord(CVType & CVR,PointerRecord & Record)189 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) {
190 error(IO.mapInteger(Record.ReferentType));
191 error(IO.mapInteger(Record.Attrs));
192
193 if (Record.isPointerToMember()) {
194 if (!IO.isWriting())
195 Record.MemberInfo.emplace();
196
197 MemberPointerInfo &M = *Record.MemberInfo;
198 error(IO.mapInteger(M.ContainingType));
199 error(IO.mapEnum(M.Representation));
200 }
201
202 return Error::success();
203 }
204
visitKnownRecord(CVType & CVR,ArrayRecord & Record)205 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) {
206 error(IO.mapInteger(Record.ElementType));
207 error(IO.mapInteger(Record.IndexType));
208 error(IO.mapEncodedInteger(Record.Size));
209 error(IO.mapStringZ(Record.Name));
210
211 return Error::success();
212 }
213
visitKnownRecord(CVType & CVR,ClassRecord & Record)214 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
215 assert((CVR.Type == TypeLeafKind::LF_STRUCTURE) ||
216 (CVR.Type == TypeLeafKind::LF_CLASS) ||
217 (CVR.Type == TypeLeafKind::LF_INTERFACE));
218
219 error(IO.mapInteger(Record.MemberCount));
220 error(IO.mapEnum(Record.Options));
221 error(IO.mapInteger(Record.FieldList));
222 error(IO.mapInteger(Record.DerivationList));
223 error(IO.mapInteger(Record.VTableShape));
224 error(IO.mapEncodedInteger(Record.Size));
225 error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
226 Record.hasUniqueName()));
227
228 return Error::success();
229 }
230
visitKnownRecord(CVType & CVR,UnionRecord & Record)231 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
232 error(IO.mapInteger(Record.MemberCount));
233 error(IO.mapEnum(Record.Options));
234 error(IO.mapInteger(Record.FieldList));
235 error(IO.mapEncodedInteger(Record.Size));
236 error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
237 Record.hasUniqueName()));
238
239 return Error::success();
240 }
241
visitKnownRecord(CVType & CVR,EnumRecord & Record)242 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) {
243 error(IO.mapInteger(Record.MemberCount));
244 error(IO.mapEnum(Record.Options));
245 error(IO.mapInteger(Record.UnderlyingType));
246 error(IO.mapInteger(Record.FieldList));
247 error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
248 Record.hasUniqueName()));
249
250 return Error::success();
251 }
252
visitKnownRecord(CVType & CVR,BitFieldRecord & Record)253 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) {
254 error(IO.mapInteger(Record.Type));
255 error(IO.mapInteger(Record.BitSize));
256 error(IO.mapInteger(Record.BitOffset));
257
258 return Error::success();
259 }
260
visitKnownRecord(CVType & CVR,VFTableShapeRecord & Record)261 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
262 VFTableShapeRecord &Record) {
263 uint16_t Size;
264 if (IO.isWriting()) {
265 ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
266 Size = Slots.size();
267 error(IO.mapInteger(Size));
268
269 for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
270 uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
271 if ((SlotIndex + 1) < Slots.size()) {
272 Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
273 }
274 error(IO.mapInteger(Byte));
275 }
276 } else {
277 error(IO.mapInteger(Size));
278 for (uint16_t I = 0; I < Size; I += 2) {
279 uint8_t Byte;
280 error(IO.mapInteger(Byte));
281 Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF));
282 if ((I + 1) < Size)
283 Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4));
284 }
285 }
286
287 return Error::success();
288 }
289
visitKnownRecord(CVType & CVR,VFTableRecord & Record)290 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) {
291 error(IO.mapInteger(Record.CompleteClass));
292 error(IO.mapInteger(Record.OverriddenVFTable));
293 error(IO.mapInteger(Record.VFPtrOffset));
294 uint32_t NamesLen = 0;
295 if (IO.isWriting()) {
296 for (auto Name : Record.MethodNames)
297 NamesLen += Name.size() + 1;
298 }
299 error(IO.mapInteger(NamesLen));
300 error(IO.mapVectorTail(
301 Record.MethodNames,
302 [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); }));
303
304 return Error::success();
305 }
306
visitKnownRecord(CVType & CVR,StringIdRecord & Record)307 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) {
308 error(IO.mapInteger(Record.Id));
309 error(IO.mapStringZ(Record.String));
310
311 return Error::success();
312 }
313
visitKnownRecord(CVType & CVR,UdtSourceLineRecord & Record)314 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
315 UdtSourceLineRecord &Record) {
316 error(IO.mapInteger(Record.UDT));
317 error(IO.mapInteger(Record.SourceFile));
318 error(IO.mapInteger(Record.LineNumber));
319
320 return Error::success();
321 }
322
visitKnownRecord(CVType & CVR,UdtModSourceLineRecord & Record)323 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
324 UdtModSourceLineRecord &Record) {
325 error(IO.mapInteger(Record.UDT));
326 error(IO.mapInteger(Record.SourceFile));
327 error(IO.mapInteger(Record.LineNumber));
328 error(IO.mapInteger(Record.Module));
329
330 return Error::success();
331 }
332
visitKnownRecord(CVType & CVR,FuncIdRecord & Record)333 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) {
334 error(IO.mapInteger(Record.ParentScope));
335 error(IO.mapInteger(Record.FunctionType));
336 error(IO.mapStringZ(Record.Name));
337
338 return Error::success();
339 }
340
visitKnownRecord(CVType & CVR,MemberFuncIdRecord & Record)341 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
342 MemberFuncIdRecord &Record) {
343 error(IO.mapInteger(Record.ClassType));
344 error(IO.mapInteger(Record.FunctionType));
345 error(IO.mapStringZ(Record.Name));
346
347 return Error::success();
348 }
349
visitKnownRecord(CVType & CVR,BuildInfoRecord & Record)350 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
351 BuildInfoRecord &Record) {
352 error(IO.mapVectorN<uint16_t>(
353 Record.ArgIndices,
354 [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
355
356 return Error::success();
357 }
358
visitKnownRecord(CVType & CVR,MethodOverloadListRecord & Record)359 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
360 MethodOverloadListRecord &Record) {
361 // TODO: Split the list into multiple records if it's longer than 64KB, using
362 // a subrecord of TypeRecordKind::Index to chain the records together.
363 error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true)));
364
365 return Error::success();
366 }
367
visitKnownRecord(CVType & CVR,FieldListRecord & Record)368 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
369 FieldListRecord &Record) {
370 error(IO.mapByteVectorTail(Record.Data));
371
372 return Error::success();
373 }
374
visitKnownRecord(CVType & CVR,TypeServer2Record & Record)375 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
376 TypeServer2Record &Record) {
377 error(IO.mapGuid(Record.Guid));
378 error(IO.mapInteger(Record.Age));
379 error(IO.mapStringZ(Record.Name));
380 return Error::success();
381 }
382
visitKnownRecord(CVType & CVR,LabelRecord & Record)383 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) {
384 error(IO.mapEnum(Record.Mode));
385 return Error::success();
386 }
387
visitKnownMember(CVMemberRecord & CVR,BaseClassRecord & Record)388 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
389 BaseClassRecord &Record) {
390 error(IO.mapInteger(Record.Attrs.Attrs));
391 error(IO.mapInteger(Record.Type));
392 error(IO.mapEncodedInteger(Record.Offset));
393
394 return Error::success();
395 }
396
visitKnownMember(CVMemberRecord & CVR,EnumeratorRecord & Record)397 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
398 EnumeratorRecord &Record) {
399 error(IO.mapInteger(Record.Attrs.Attrs));
400
401 // FIXME: Handle full APInt such as __int128.
402 error(IO.mapEncodedInteger(Record.Value));
403 error(IO.mapStringZ(Record.Name));
404
405 return Error::success();
406 }
407
visitKnownMember(CVMemberRecord & CVR,DataMemberRecord & Record)408 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
409 DataMemberRecord &Record) {
410 error(IO.mapInteger(Record.Attrs.Attrs));
411 error(IO.mapInteger(Record.Type));
412 error(IO.mapEncodedInteger(Record.FieldOffset));
413 error(IO.mapStringZ(Record.Name));
414
415 return Error::success();
416 }
417
visitKnownMember(CVMemberRecord & CVR,OverloadedMethodRecord & Record)418 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
419 OverloadedMethodRecord &Record) {
420 error(IO.mapInteger(Record.NumOverloads));
421 error(IO.mapInteger(Record.MethodList));
422 error(IO.mapStringZ(Record.Name));
423
424 return Error::success();
425 }
426
visitKnownMember(CVMemberRecord & CVR,OneMethodRecord & Record)427 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
428 OneMethodRecord &Record) {
429 const bool IsFromOverloadList = (TypeKind == LF_METHODLIST);
430 MapOneMethodRecord Mapper(IsFromOverloadList);
431 return Mapper(IO, Record);
432 }
433
visitKnownMember(CVMemberRecord & CVR,NestedTypeRecord & Record)434 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
435 NestedTypeRecord &Record) {
436 uint16_t Padding = 0;
437 error(IO.mapInteger(Padding));
438 error(IO.mapInteger(Record.Type));
439 error(IO.mapStringZ(Record.Name));
440
441 return Error::success();
442 }
443
visitKnownMember(CVMemberRecord & CVR,StaticDataMemberRecord & Record)444 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
445 StaticDataMemberRecord &Record) {
446
447 error(IO.mapInteger(Record.Attrs.Attrs));
448 error(IO.mapInteger(Record.Type));
449 error(IO.mapStringZ(Record.Name));
450
451 return Error::success();
452 }
453
visitKnownMember(CVMemberRecord & CVR,VirtualBaseClassRecord & Record)454 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
455 VirtualBaseClassRecord &Record) {
456
457 error(IO.mapInteger(Record.Attrs.Attrs));
458 error(IO.mapInteger(Record.BaseType));
459 error(IO.mapInteger(Record.VBPtrType));
460 error(IO.mapEncodedInteger(Record.VBPtrOffset));
461 error(IO.mapEncodedInteger(Record.VTableIndex));
462
463 return Error::success();
464 }
465
visitKnownMember(CVMemberRecord & CVR,VFPtrRecord & Record)466 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
467 VFPtrRecord &Record) {
468 uint16_t Padding = 0;
469 error(IO.mapInteger(Padding));
470 error(IO.mapInteger(Record.Type));
471
472 return Error::success();
473 }
474
visitKnownMember(CVMemberRecord & CVR,ListContinuationRecord & Record)475 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
476 ListContinuationRecord &Record) {
477 uint16_t Padding = 0;
478 error(IO.mapInteger(Padding));
479 error(IO.mapInteger(Record.ContinuationIndex));
480
481 return Error::success();
482 }
483
visitKnownRecord(CVType & CVR,PrecompRecord & Precomp)484 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
485 PrecompRecord &Precomp) {
486 error(IO.mapInteger(Precomp.StartTypeIndex));
487 error(IO.mapInteger(Precomp.TypesCount));
488 error(IO.mapInteger(Precomp.Signature));
489 error(IO.mapStringZ(Precomp.PrecompFilePath));
490 return Error::success();
491 }
492
visitKnownRecord(CVType & CVR,EndPrecompRecord & EndPrecomp)493 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
494 EndPrecompRecord &EndPrecomp) {
495 error(IO.mapInteger(EndPrecomp.Signature));
496 return Error::success();
497 }
498