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