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