1 //===- TypeRecordMapping.cpp ------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
10 #include "llvm/ADT/StringExtras.h"
11 #include "llvm/DebugInfo/CodeView/EnumTables.h"
12 
13 using namespace llvm;
14 using namespace llvm::codeview;
15 
16 namespace {
17 
18 #define error(X)                                                               \
19   if (auto EC = X)                                                             \
20     return EC;
21 
22 static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
23 #define CV_TYPE(enum, val) {#enum, enum},
24 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
25 };
26 
27 static StringRef getLeafTypeName(TypeLeafKind LT) {
28   switch (LT) {
29 #define TYPE_RECORD(ename, value, name)                                        \
30   case ename:                                                                  \
31     return #name;
32 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
33   default:
34     break;
35   }
36   return "UnknownLeaf";
37 }
38 
39 template <typename T>
40 static bool compEnumNames(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) {
41   return lhs.Name < rhs.Name;
42 }
43 
44 template <typename T, typename TFlag>
45 static std::string getFlagNames(CodeViewRecordIO &IO, T Value,
46                                 ArrayRef<EnumEntry<TFlag>> Flags) {
47   if (!IO.isStreaming())
48     return std::string("");
49   typedef EnumEntry<TFlag> FlagEntry;
50   typedef SmallVector<FlagEntry, 10> FlagVector;
51   FlagVector SetFlags;
52   for (const auto &Flag : Flags) {
53     if (Flag.Value == 0)
54       continue;
55     if ((Value & Flag.Value) == Flag.Value) {
56       SetFlags.push_back(Flag);
57     }
58   }
59 
60   llvm::sort(SetFlags, &compEnumNames<TFlag>);
61 
62   std::string FlagLabel;
63   bool FirstOcc = true;
64   for (const auto &Flag : SetFlags) {
65     if (FirstOcc)
66       FirstOcc = false;
67     else
68       FlagLabel += (" | ");
69 
70     FlagLabel += (Flag.Name.str() + " (0x" + utohexstr(Flag.Value) + ")");
71   }
72 
73   if (!FlagLabel.empty()) {
74     std::string LabelWithBraces(" ( ");
75     LabelWithBraces += FlagLabel + " )";
76     return LabelWithBraces;
77   } else
78     return FlagLabel;
79 }
80 
81 template <typename T, typename TEnum>
82 static StringRef getEnumName(CodeViewRecordIO &IO, T Value,
83                              ArrayRef<EnumEntry<TEnum>> EnumValues) {
84   if (!IO.isStreaming())
85     return "";
86   StringRef Name;
87   for (const auto &EnumItem : EnumValues) {
88     if (EnumItem.Value == Value) {
89       Name = EnumItem.Name;
90       break;
91     }
92   }
93 
94   return Name;
95 }
96 
97 static std::string getMemberAttributes(CodeViewRecordIO &IO,
98                                        MemberAccess Access, MethodKind Kind,
99                                        MethodOptions Options) {
100   if (!IO.isStreaming())
101     return "";
102   std::string AccessSpecifier =
103       getEnumName(IO, uint8_t(Access), makeArrayRef(getMemberAccessNames()));
104   std::string MemberAttrs(AccessSpecifier);
105   if (Kind != MethodKind::Vanilla) {
106     std::string MethodKind =
107         getEnumName(IO, unsigned(Kind), makeArrayRef(getMemberKindNames()));
108     MemberAttrs += ", " + MethodKind;
109   }
110   if (Options != MethodOptions::None) {
111     std::string MethodOptions = getFlagNames(
112         IO, unsigned(Options), makeArrayRef(getMethodOptionNames()));
113     MemberAttrs += ", " + MethodOptions;
114   }
115   return MemberAttrs;
116 }
117 
118 struct MapOneMethodRecord {
119   explicit MapOneMethodRecord(bool IsFromOverloadList)
120       : IsFromOverloadList(IsFromOverloadList) {}
121 
122   Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const {
123     std::string Attrs = getMemberAttributes(
124         IO, Method.getAccess(), Method.getMethodKind(), Method.getOptions());
125     error(IO.mapInteger(Method.Attrs.Attrs, "Attrs: " + Attrs));
126     if (IsFromOverloadList) {
127       uint16_t Padding = 0;
128       error(IO.mapInteger(Padding));
129     }
130     error(IO.mapInteger(Method.Type, "Type"));
131     if (Method.isIntroducingVirtual()) {
132       error(IO.mapInteger(Method.VFTableOffset, "VFTableOffset"));
133     } else if (IO.isReading())
134       Method.VFTableOffset = -1;
135 
136     if (!IsFromOverloadList)
137       error(IO.mapStringZ(Method.Name, "Name"));
138 
139     return Error::success();
140   }
141 
142 private:
143   bool IsFromOverloadList;
144 };
145 } // namespace
146 
147 static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
148                                   StringRef &UniqueName, bool HasUniqueName) {
149   if (IO.isWriting()) {
150     // Try to be smart about what we write here.  We can't write anything too
151     // large, so if we're going to go over the limit, truncate both the name
152     // and unique name by the same amount.
153     size_t BytesLeft = IO.maxFieldLength();
154     if (HasUniqueName) {
155       size_t BytesNeeded = Name.size() + UniqueName.size() + 2;
156       StringRef N = Name;
157       StringRef U = UniqueName;
158       if (BytesNeeded > BytesLeft) {
159         size_t BytesToDrop = (BytesNeeded - BytesLeft);
160         size_t DropN = std::min(N.size(), BytesToDrop / 2);
161         size_t DropU = std::min(U.size(), BytesToDrop - DropN);
162 
163         N = N.drop_back(DropN);
164         U = U.drop_back(DropU);
165       }
166 
167       error(IO.mapStringZ(N));
168       error(IO.mapStringZ(U));
169     } else {
170       // Cap the length of the string at however many bytes we have available,
171       // plus one for the required null terminator.
172       auto N = StringRef(Name).take_front(BytesLeft - 1);
173       error(IO.mapStringZ(N));
174     }
175   } else {
176     // Reading & Streaming mode come after writing mode is executed for each
177     // record. Truncating large names are done during writing, so its not
178     // necessary to do it while reading or streaming.
179     error(IO.mapStringZ(Name, "Name"));
180     if (HasUniqueName)
181       error(IO.mapStringZ(UniqueName, "LinkageName"));
182   }
183 
184   return Error::success();
185 }
186 
187 Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
188   assert(!TypeKind.hasValue() && "Already in a type mapping!");
189   assert(!MemberKind.hasValue() && "Already in a member mapping!");
190 
191   // FieldList and MethodList records can be any length because they can be
192   // split with continuation records.  All other record types cannot be
193   // longer than the maximum record length.
194   Optional<uint32_t> MaxLen;
195   if (CVR.kind() != TypeLeafKind::LF_FIELDLIST &&
196       CVR.kind() != TypeLeafKind::LF_METHODLIST)
197     MaxLen = MaxRecordLength - sizeof(RecordPrefix);
198   error(IO.beginRecord(MaxLen));
199   TypeKind = CVR.kind();
200 
201   if (IO.isStreaming()) {
202     auto RecordKind = CVR.kind();
203     uint16_t RecordLen = CVR.length() - 2;
204     std::string RecordKindName =
205         getEnumName(IO, unsigned(RecordKind), makeArrayRef(LeafTypeNames));
206     error(IO.mapInteger(RecordLen, "Record length"));
207     error(IO.mapEnum(RecordKind, "Record kind: " + RecordKindName));
208   }
209   return Error::success();
210 }
211 
212 Error TypeRecordMapping::visitTypeBegin(CVType &CVR, TypeIndex Index) {
213   if (IO.isStreaming())
214     IO.emitRawComment(" " + getLeafTypeName(CVR.kind()) + " (0x" +
215                       utohexstr(Index.getIndex()) + ")");
216   return visitTypeBegin(CVR);
217 }
218 
219 Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
220   assert(TypeKind.hasValue() && "Not in a type mapping!");
221   assert(!MemberKind.hasValue() && "Still in a member mapping!");
222 
223   error(IO.endRecord());
224 
225   TypeKind.reset();
226   return Error::success();
227 }
228 
229 Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
230   assert(TypeKind.hasValue() && "Not in a type mapping!");
231   assert(!MemberKind.hasValue() && "Already in a member mapping!");
232 
233   // The largest possible subrecord is one in which there is a record prefix,
234   // followed by the subrecord, followed by a continuation, and that entire
235   // sequence spaws `MaxRecordLength` bytes.  So the record's length is
236   // calculated as follows.
237 
238   constexpr uint32_t ContinuationLength = 8;
239   error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
240                        ContinuationLength));
241 
242   MemberKind = Record.Kind;
243   if (IO.isStreaming()) {
244     std::string MemberKindName = getLeafTypeName(Record.Kind);
245     MemberKindName +=
246         " ( " +
247         (getEnumName(IO, unsigned(Record.Kind), makeArrayRef(LeafTypeNames)))
248             .str() +
249         " )";
250     error(IO.mapEnum(Record.Kind, "Member kind: " + MemberKindName));
251   }
252   return Error::success();
253 }
254 
255 Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
256   assert(TypeKind.hasValue() && "Not in a type mapping!");
257   assert(MemberKind.hasValue() && "Not in a member mapping!");
258 
259   if (IO.isReading()) {
260     if (auto EC = IO.skipPadding())
261       return EC;
262   }
263 
264   MemberKind.reset();
265   error(IO.endRecord());
266   return Error::success();
267 }
268 
269 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) {
270   std::string ModifierNames =
271       getFlagNames(IO, static_cast<uint16_t>(Record.Modifiers),
272                    makeArrayRef(getTypeModifierNames()));
273   error(IO.mapInteger(Record.ModifiedType, "ModifiedType"));
274   error(IO.mapEnum(Record.Modifiers, "Modifiers" + ModifierNames));
275   return Error::success();
276 }
277 
278 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
279                                           ProcedureRecord &Record) {
280   std::string CallingConvName = getEnumName(
281       IO, uint8_t(Record.CallConv), makeArrayRef(getCallingConventions()));
282   std::string FuncOptionNames =
283       getFlagNames(IO, static_cast<uint16_t>(Record.Options),
284                    makeArrayRef(getFunctionOptionEnum()));
285   error(IO.mapInteger(Record.ReturnType, "ReturnType"));
286   error(IO.mapEnum(Record.CallConv, "CallingConvention: " + CallingConvName));
287   error(IO.mapEnum(Record.Options, "FunctionOptions" + FuncOptionNames));
288   error(IO.mapInteger(Record.ParameterCount, "NumParameters"));
289   error(IO.mapInteger(Record.ArgumentList, "ArgListType"));
290 
291   return Error::success();
292 }
293 
294 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
295                                           MemberFunctionRecord &Record) {
296   std::string CallingConvName = getEnumName(
297       IO, uint8_t(Record.CallConv), makeArrayRef(getCallingConventions()));
298   std::string FuncOptionNames =
299       getFlagNames(IO, static_cast<uint16_t>(Record.Options),
300                    makeArrayRef(getFunctionOptionEnum()));
301   error(IO.mapInteger(Record.ReturnType, "ReturnType"));
302   error(IO.mapInteger(Record.ClassType, "ClassType"));
303   error(IO.mapInteger(Record.ThisType, "ThisType"));
304   error(IO.mapEnum(Record.CallConv, "CallingConvention: " + CallingConvName));
305   error(IO.mapEnum(Record.Options, "FunctionOptions" + FuncOptionNames));
306   error(IO.mapInteger(Record.ParameterCount, "NumParameters"));
307   error(IO.mapInteger(Record.ArgumentList, "ArgListType"));
308   error(IO.mapInteger(Record.ThisPointerAdjustment, "ThisAdjustment"));
309 
310   return Error::success();
311 }
312 
313 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
314   error(IO.mapVectorN<uint32_t>(
315       Record.ArgIndices,
316       [](CodeViewRecordIO &IO, TypeIndex &N) {
317         return IO.mapInteger(N, "Argument");
318       },
319       "NumArgs"));
320   return Error::success();
321 }
322 
323 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
324                                           StringListRecord &Record) {
325   error(IO.mapVectorN<uint32_t>(
326       Record.StringIndices,
327       [](CodeViewRecordIO &IO, TypeIndex &N) {
328         return IO.mapInteger(N, "Strings");
329       },
330       "NumStrings"));
331 
332   return Error::success();
333 }
334 
335 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) {
336 
337   SmallString<128> Attr("Attrs: ");
338 
339   if (IO.isStreaming()) {
340     std::string PtrType = getEnumName(IO, unsigned(Record.getPointerKind()),
341                                       makeArrayRef(getPtrKindNames()));
342     Attr += "[ Type: " + PtrType;
343 
344     std::string PtrMode = getEnumName(IO, unsigned(Record.getMode()),
345                                       makeArrayRef(getPtrModeNames()));
346     Attr += ", Mode: " + PtrMode;
347 
348     auto PtrSizeOf = Record.getSize();
349     Attr += ", SizeOf: " + itostr(PtrSizeOf);
350 
351     if (Record.isFlat())
352       Attr += ", isFlat";
353     if (Record.isConst())
354       Attr += ", isConst";
355     if (Record.isVolatile())
356       Attr += ", isVolatile";
357     if (Record.isUnaligned())
358       Attr += ", isUnaligned";
359     if (Record.isRestrict())
360       Attr += ", isRestricted";
361     if (Record.isLValueReferenceThisPtr())
362       Attr += ", isThisPtr&";
363     if (Record.isRValueReferenceThisPtr())
364       Attr += ", isThisPtr&&";
365     Attr += " ]";
366   }
367 
368   error(IO.mapInteger(Record.ReferentType, "PointeeType"));
369   error(IO.mapInteger(Record.Attrs, Attr));
370 
371   if (Record.isPointerToMember()) {
372     if (IO.isReading())
373       Record.MemberInfo.emplace();
374 
375     MemberPointerInfo &M = *Record.MemberInfo;
376     error(IO.mapInteger(M.ContainingType, "ClassType"));
377     std::string PtrMemberGetRepresentation = getEnumName(
378         IO, uint16_t(M.Representation), makeArrayRef(getPtrMemberRepNames()));
379     error(IO.mapEnum(M.Representation,
380                      "Representation: " + PtrMemberGetRepresentation));
381   }
382 
383   return Error::success();
384 }
385 
386 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) {
387   error(IO.mapInteger(Record.ElementType, "ElementType"));
388   error(IO.mapInteger(Record.IndexType, "IndexType"));
389   error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
390   error(IO.mapStringZ(Record.Name, "Name"));
391 
392   return Error::success();
393 }
394 
395 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
396   assert((CVR.kind() == TypeLeafKind::LF_STRUCTURE) ||
397          (CVR.kind() == TypeLeafKind::LF_CLASS) ||
398          (CVR.kind() == TypeLeafKind::LF_INTERFACE));
399 
400   std::string PropertiesNames =
401       getFlagNames(IO, static_cast<uint16_t>(Record.Options),
402                    makeArrayRef(getClassOptionNames()));
403   error(IO.mapInteger(Record.MemberCount, "MemberCount"));
404   error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
405   error(IO.mapInteger(Record.FieldList, "FieldList"));
406   error(IO.mapInteger(Record.DerivationList, "DerivedFrom"));
407   error(IO.mapInteger(Record.VTableShape, "VShape"));
408   error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
409   error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
410                              Record.hasUniqueName()));
411 
412   return Error::success();
413 }
414 
415 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
416   std::string PropertiesNames =
417       getFlagNames(IO, static_cast<uint16_t>(Record.Options),
418                    makeArrayRef(getClassOptionNames()));
419   error(IO.mapInteger(Record.MemberCount, "MemberCount"));
420   error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
421   error(IO.mapInteger(Record.FieldList, "FieldList"));
422   error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
423   error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
424                              Record.hasUniqueName()));
425 
426   return Error::success();
427 }
428 
429 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) {
430   std::string PropertiesNames =
431       getFlagNames(IO, static_cast<uint16_t>(Record.Options),
432                    makeArrayRef(getClassOptionNames()));
433   error(IO.mapInteger(Record.MemberCount, "NumEnumerators"));
434   error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
435   error(IO.mapInteger(Record.UnderlyingType, "UnderlyingType"));
436   error(IO.mapInteger(Record.FieldList, "FieldListType"));
437   error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
438                              Record.hasUniqueName()));
439 
440   return Error::success();
441 }
442 
443 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) {
444   error(IO.mapInteger(Record.Type, "Type"));
445   error(IO.mapInteger(Record.BitSize, "BitSize"));
446   error(IO.mapInteger(Record.BitOffset, "BitOffset"));
447 
448   return Error::success();
449 }
450 
451 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
452                                           VFTableShapeRecord &Record) {
453   uint16_t Size;
454   if (!IO.isReading()) {
455     ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
456     Size = Slots.size();
457     error(IO.mapInteger(Size, "VFEntryCount"));
458 
459     for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
460       uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
461       if ((SlotIndex + 1) < Slots.size()) {
462         Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
463       }
464       error(IO.mapInteger(Byte));
465     }
466   } else {
467     error(IO.mapInteger(Size));
468     for (uint16_t I = 0; I < Size; I += 2) {
469       uint8_t Byte;
470       error(IO.mapInteger(Byte));
471       Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF));
472       if ((I + 1) < Size)
473         Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4));
474     }
475   }
476 
477   return Error::success();
478 }
479 
480 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) {
481   error(IO.mapInteger(Record.CompleteClass, "CompleteClass"));
482   error(IO.mapInteger(Record.OverriddenVFTable, "OverriddenVFTable"));
483   error(IO.mapInteger(Record.VFPtrOffset, "VFPtrOffset"));
484   uint32_t NamesLen = 0;
485   if (!IO.isReading()) {
486     for (auto Name : Record.MethodNames)
487       NamesLen += Name.size() + 1;
488   }
489   error(IO.mapInteger(NamesLen));
490   error(IO.mapVectorTail(
491       Record.MethodNames,
492       [](CodeViewRecordIO &IO, StringRef &S) {
493         return IO.mapStringZ(S, "MethodName");
494       },
495       "VFTableName"));
496 
497   return Error::success();
498 }
499 
500 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) {
501   error(IO.mapInteger(Record.Id, "Id"));
502   error(IO.mapStringZ(Record.String, "StringData"));
503 
504   return Error::success();
505 }
506 
507 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
508                                           UdtSourceLineRecord &Record) {
509   error(IO.mapInteger(Record.UDT, "UDT"));
510   error(IO.mapInteger(Record.SourceFile, "SourceFile"));
511   error(IO.mapInteger(Record.LineNumber, "LineNumber"));
512 
513   return Error::success();
514 }
515 
516 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
517                                           UdtModSourceLineRecord &Record) {
518   error(IO.mapInteger(Record.UDT, "UDT"));
519   error(IO.mapInteger(Record.SourceFile, "SourceFile"));
520   error(IO.mapInteger(Record.LineNumber, "LineNumber"));
521   error(IO.mapInteger(Record.Module, "Module"));
522 
523   return Error::success();
524 }
525 
526 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) {
527   error(IO.mapInteger(Record.ParentScope, "ParentScope"));
528   error(IO.mapInteger(Record.FunctionType, "FunctionType"));
529   error(IO.mapStringZ(Record.Name, "Name"));
530 
531   return Error::success();
532 }
533 
534 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
535                                           MemberFuncIdRecord &Record) {
536   error(IO.mapInteger(Record.ClassType, "ClassType"));
537   error(IO.mapInteger(Record.FunctionType, "FunctionType"));
538   error(IO.mapStringZ(Record.Name, "Name"));
539 
540   return Error::success();
541 }
542 
543 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
544                                           BuildInfoRecord &Record) {
545   error(IO.mapVectorN<uint16_t>(
546       Record.ArgIndices,
547       [](CodeViewRecordIO &IO, TypeIndex &N) {
548         return IO.mapInteger(N, "Argument");
549       },
550       "NumArgs"));
551 
552   return Error::success();
553 }
554 
555 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
556                                           MethodOverloadListRecord &Record) {
557   // TODO: Split the list into multiple records if it's longer than 64KB, using
558   // a subrecord of TypeRecordKind::Index to chain the records together.
559   error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true), "Method"));
560 
561   return Error::success();
562 }
563 
564 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
565                                           FieldListRecord &Record) {
566   if (IO.isStreaming()) {
567     if (auto EC = codeview::visitMemberRecordStream(Record.Data, *this))
568       return EC;
569   } else
570     error(IO.mapByteVectorTail(Record.Data));
571 
572   return Error::success();
573 }
574 
575 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
576                                           TypeServer2Record &Record) {
577   error(IO.mapGuid(Record.Guid, "Guid"));
578   error(IO.mapInteger(Record.Age, "Age"));
579   error(IO.mapStringZ(Record.Name, "Name"));
580   return Error::success();
581 }
582 
583 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) {
584   std::string ModeName =
585       getEnumName(IO, uint16_t(Record.Mode), makeArrayRef(getLabelTypeEnum()));
586   error(IO.mapEnum(Record.Mode, "Mode: " + ModeName));
587   return Error::success();
588 }
589 
590 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
591                                           BaseClassRecord &Record) {
592   std::string Attrs = getMemberAttributes(
593       IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
594   error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
595   error(IO.mapInteger(Record.Type, "BaseType"));
596   error(IO.mapEncodedInteger(Record.Offset, "BaseOffset"));
597 
598   return Error::success();
599 }
600 
601 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
602                                           EnumeratorRecord &Record) {
603   std::string Attrs = getMemberAttributes(
604       IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
605   error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
606 
607   // FIXME: Handle full APInt such as __int128.
608   error(IO.mapEncodedInteger(Record.Value, "EnumValue"));
609   error(IO.mapStringZ(Record.Name, "Name"));
610 
611   return Error::success();
612 }
613 
614 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
615                                           DataMemberRecord &Record) {
616   std::string Attrs = getMemberAttributes(
617       IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
618   error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
619   error(IO.mapInteger(Record.Type, "Type"));
620   error(IO.mapEncodedInteger(Record.FieldOffset, "FieldOffset"));
621   error(IO.mapStringZ(Record.Name, "Name"));
622 
623   return Error::success();
624 }
625 
626 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
627                                           OverloadedMethodRecord &Record) {
628   error(IO.mapInteger(Record.NumOverloads, "MethodCount"));
629   error(IO.mapInteger(Record.MethodList, "MethodListIndex"));
630   error(IO.mapStringZ(Record.Name, "Name"));
631 
632   return Error::success();
633 }
634 
635 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
636                                           OneMethodRecord &Record) {
637   const bool IsFromOverloadList = (TypeKind == LF_METHODLIST);
638   MapOneMethodRecord Mapper(IsFromOverloadList);
639   return Mapper(IO, Record);
640 }
641 
642 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
643                                           NestedTypeRecord &Record) {
644   uint16_t Padding = 0;
645   error(IO.mapInteger(Padding, "Padding"));
646   error(IO.mapInteger(Record.Type, "Type"));
647   error(IO.mapStringZ(Record.Name, "Name"));
648 
649   return Error::success();
650 }
651 
652 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
653                                           StaticDataMemberRecord &Record) {
654 
655   std::string Attrs = getMemberAttributes(
656       IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
657   error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
658   error(IO.mapInteger(Record.Type, "Type"));
659   error(IO.mapStringZ(Record.Name, "Name"));
660 
661   return Error::success();
662 }
663 
664 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
665                                           VirtualBaseClassRecord &Record) {
666 
667   std::string Attrs = getMemberAttributes(
668       IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
669   error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
670   error(IO.mapInteger(Record.BaseType, "BaseType"));
671   error(IO.mapInteger(Record.VBPtrType, "VBPtrType"));
672   error(IO.mapEncodedInteger(Record.VBPtrOffset, "VBPtrOffset"));
673   error(IO.mapEncodedInteger(Record.VTableIndex, "VBTableIndex"));
674 
675   return Error::success();
676 }
677 
678 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
679                                           VFPtrRecord &Record) {
680   uint16_t Padding = 0;
681   error(IO.mapInteger(Padding, "Padding"));
682   error(IO.mapInteger(Record.Type, "Type"));
683 
684   return Error::success();
685 }
686 
687 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
688                                           ListContinuationRecord &Record) {
689   uint16_t Padding = 0;
690   error(IO.mapInteger(Padding, "Padding"));
691   error(IO.mapInteger(Record.ContinuationIndex, "ContinuationIndex"));
692 
693   return Error::success();
694 }
695 
696 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
697                                           PrecompRecord &Precomp) {
698   error(IO.mapInteger(Precomp.StartTypeIndex, "StartIndex"));
699   error(IO.mapInteger(Precomp.TypesCount, "Count"));
700   error(IO.mapInteger(Precomp.Signature, "Signature"));
701   error(IO.mapStringZ(Precomp.PrecompFilePath, "PrecompFile"));
702   return Error::success();
703 }
704 
705 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
706                                           EndPrecompRecord &EndPrecomp) {
707   error(IO.mapInteger(EndPrecomp.Signature, "Signature"));
708   return Error::success();
709 }
710