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