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 
getLeafTypeName(TypeLeafKind LT)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>
compEnumNames(const EnumEntry<T> & lhs,const EnumEntry<T> & rhs)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>
getFlagNames(CodeViewRecordIO & IO,T Value,ArrayRef<EnumEntry<TFlag>> Flags)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>
getEnumName(CodeViewRecordIO & IO,T Value,ArrayRef<EnumEntry<TEnum>> EnumValues)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 
getMemberAttributes(CodeViewRecordIO & IO,MemberAccess Access,MethodKind Kind,MethodOptions Options)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), ArrayRef(getMemberAccessNames())));
126   std::string MemberAttrs(AccessSpecifier);
127   if (Kind != MethodKind::Vanilla) {
128     std::string MethodKind = std::string(
129         getEnumName(IO, unsigned(Kind), ArrayRef(getMemberKindNames())));
130     MemberAttrs += ", " + MethodKind;
131   }
132   if (Options != MethodOptions::None) {
133     std::string MethodOptions =
134         getFlagNames(IO, unsigned(Options), ArrayRef(getMethodOptionNames()));
135     MemberAttrs += ", " + MethodOptions;
136   }
137   return MemberAttrs;
138 }
139 
140 struct MapOneMethodRecord {
MapOneMethodRecord__anon6dfefdac0111::MapOneMethodRecord141   explicit MapOneMethodRecord(bool IsFromOverloadList)
142       : IsFromOverloadList(IsFromOverloadList) {}
143 
operator ()__anon6dfefdac0111::MapOneMethodRecord144   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.
computeHashString(StringRef Name,SmallString<32> & StringifiedHash)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 
mapNameAndUniqueName(CodeViewRecordIO & IO,StringRef & Name,StringRef & UniqueName,bool HasUniqueName)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 
visitTypeBegin(CVType & CVR)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   std::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), ArrayRef(LeafTypeNames)));
251     error(IO.mapInteger(RecordLen, "Record length"));
252     error(IO.mapEnum(RecordKind, "Record kind: " + RecordKindName));
253   }
254   return Error::success();
255 }
256 
visitTypeBegin(CVType & CVR,TypeIndex Index)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 
visitTypeEnd(CVType & Record)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 
visitMemberBegin(CVMemberRecord & Record)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), ArrayRef(LeafTypeNames)))
293             .str() +
294         " )";
295     error(IO.mapEnum(Record.Kind, "Member kind: " + MemberKindName));
296   }
297   return Error::success();
298 }
299 
visitMemberEnd(CVMemberRecord & Record)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 
visitKnownRecord(CVType & CVR,ModifierRecord & Record)314 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) {
315   std::string ModifierNames =
316       getFlagNames(IO, static_cast<uint16_t>(Record.Modifiers),
317                    ArrayRef(getTypeModifierNames()));
318   error(IO.mapInteger(Record.ModifiedType, "ModifiedType"));
319   error(IO.mapEnum(Record.Modifiers, "Modifiers" + ModifierNames));
320   return Error::success();
321 }
322 
visitKnownRecord(CVType & CVR,ProcedureRecord & Record)323 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
324                                           ProcedureRecord &Record) {
325   std::string CallingConvName = std::string(getEnumName(
326       IO, uint8_t(Record.CallConv), ArrayRef(getCallingConventions())));
327   std::string FuncOptionNames =
328       getFlagNames(IO, static_cast<uint16_t>(Record.Options),
329                    ArrayRef(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 
visitKnownRecord(CVType & CVR,MemberFunctionRecord & Record)339 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
340                                           MemberFunctionRecord &Record) {
341   std::string CallingConvName = std::string(getEnumName(
342       IO, uint8_t(Record.CallConv), ArrayRef(getCallingConventions())));
343   std::string FuncOptionNames =
344       getFlagNames(IO, static_cast<uint16_t>(Record.Options),
345                    ArrayRef(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 
visitKnownRecord(CVType & CVR,ArgListRecord & Record)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 
visitKnownRecord(CVType & CVR,StringListRecord & Record)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 
visitKnownRecord(CVType & CVR,PointerRecord & Record)380 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) {
381 
382   SmallString<128> Attr("Attrs: ");
383 
384   if (IO.isStreaming()) {
385     std::string PtrType = std::string(getEnumName(
386         IO, unsigned(Record.getPointerKind()), ArrayRef(getPtrKindNames())));
387     Attr += "[ Type: " + PtrType;
388 
389     std::string PtrMode = std::string(getEnumName(
390         IO, unsigned(Record.getMode()), ArrayRef(getPtrModeNames())));
391     Attr += ", Mode: " + PtrMode;
392 
393     auto PtrSizeOf = Record.getSize();
394     Attr += ", SizeOf: " + itostr(PtrSizeOf);
395 
396     if (Record.isFlat())
397       Attr += ", isFlat";
398     if (Record.isConst())
399       Attr += ", isConst";
400     if (Record.isVolatile())
401       Attr += ", isVolatile";
402     if (Record.isUnaligned())
403       Attr += ", isUnaligned";
404     if (Record.isRestrict())
405       Attr += ", isRestricted";
406     if (Record.isLValueReferenceThisPtr())
407       Attr += ", isThisPtr&";
408     if (Record.isRValueReferenceThisPtr())
409       Attr += ", isThisPtr&&";
410     Attr += " ]";
411   }
412 
413   error(IO.mapInteger(Record.ReferentType, "PointeeType"));
414   error(IO.mapInteger(Record.Attrs, Attr));
415 
416   if (Record.isPointerToMember()) {
417     if (IO.isReading())
418       Record.MemberInfo.emplace();
419 
420     MemberPointerInfo &M = *Record.MemberInfo;
421     error(IO.mapInteger(M.ContainingType, "ClassType"));
422     std::string PtrMemberGetRepresentation = std::string(getEnumName(
423         IO, uint16_t(M.Representation), ArrayRef(getPtrMemberRepNames())));
424     error(IO.mapEnum(M.Representation,
425                      "Representation: " + PtrMemberGetRepresentation));
426   }
427 
428   return Error::success();
429 }
430 
visitKnownRecord(CVType & CVR,ArrayRecord & Record)431 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) {
432   error(IO.mapInteger(Record.ElementType, "ElementType"));
433   error(IO.mapInteger(Record.IndexType, "IndexType"));
434   error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
435   error(IO.mapStringZ(Record.Name, "Name"));
436 
437   return Error::success();
438 }
439 
visitKnownRecord(CVType & CVR,ClassRecord & Record)440 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
441   assert((CVR.kind() == TypeLeafKind::LF_STRUCTURE) ||
442          (CVR.kind() == TypeLeafKind::LF_CLASS) ||
443          (CVR.kind() == TypeLeafKind::LF_INTERFACE));
444 
445   std::string PropertiesNames =
446       getFlagNames(IO, static_cast<uint16_t>(Record.Options),
447                    ArrayRef(getClassOptionNames()));
448   error(IO.mapInteger(Record.MemberCount, "MemberCount"));
449   error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
450   error(IO.mapInteger(Record.FieldList, "FieldList"));
451   error(IO.mapInteger(Record.DerivationList, "DerivedFrom"));
452   error(IO.mapInteger(Record.VTableShape, "VShape"));
453   error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
454   error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
455                              Record.hasUniqueName()));
456 
457   return Error::success();
458 }
459 
visitKnownRecord(CVType & CVR,UnionRecord & Record)460 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
461   std::string PropertiesNames =
462       getFlagNames(IO, static_cast<uint16_t>(Record.Options),
463                    ArrayRef(getClassOptionNames()));
464   error(IO.mapInteger(Record.MemberCount, "MemberCount"));
465   error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
466   error(IO.mapInteger(Record.FieldList, "FieldList"));
467   error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
468   error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
469                              Record.hasUniqueName()));
470 
471   return Error::success();
472 }
473 
visitKnownRecord(CVType & CVR,EnumRecord & Record)474 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) {
475   std::string PropertiesNames =
476       getFlagNames(IO, static_cast<uint16_t>(Record.Options),
477                    ArrayRef(getClassOptionNames()));
478   error(IO.mapInteger(Record.MemberCount, "NumEnumerators"));
479   error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
480   error(IO.mapInteger(Record.UnderlyingType, "UnderlyingType"));
481   error(IO.mapInteger(Record.FieldList, "FieldListType"));
482   error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
483                              Record.hasUniqueName()));
484 
485   return Error::success();
486 }
487 
visitKnownRecord(CVType & CVR,BitFieldRecord & Record)488 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) {
489   error(IO.mapInteger(Record.Type, "Type"));
490   error(IO.mapInteger(Record.BitSize, "BitSize"));
491   error(IO.mapInteger(Record.BitOffset, "BitOffset"));
492 
493   return Error::success();
494 }
495 
visitKnownRecord(CVType & CVR,VFTableShapeRecord & Record)496 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
497                                           VFTableShapeRecord &Record) {
498   uint16_t Size;
499   if (!IO.isReading()) {
500     ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
501     Size = Slots.size();
502     error(IO.mapInteger(Size, "VFEntryCount"));
503 
504     for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
505       uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
506       if ((SlotIndex + 1) < Slots.size()) {
507         Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
508       }
509       error(IO.mapInteger(Byte));
510     }
511   } else {
512     error(IO.mapInteger(Size));
513     for (uint16_t I = 0; I < Size; I += 2) {
514       uint8_t Byte;
515       error(IO.mapInteger(Byte));
516       Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF));
517       if ((I + 1) < Size)
518         Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4));
519     }
520   }
521 
522   return Error::success();
523 }
524 
visitKnownRecord(CVType & CVR,VFTableRecord & Record)525 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) {
526   error(IO.mapInteger(Record.CompleteClass, "CompleteClass"));
527   error(IO.mapInteger(Record.OverriddenVFTable, "OverriddenVFTable"));
528   error(IO.mapInteger(Record.VFPtrOffset, "VFPtrOffset"));
529   uint32_t NamesLen = 0;
530   if (!IO.isReading()) {
531     for (auto Name : Record.MethodNames)
532       NamesLen += Name.size() + 1;
533   }
534   error(IO.mapInteger(NamesLen));
535   error(IO.mapVectorTail(
536       Record.MethodNames,
537       [](CodeViewRecordIO &IO, StringRef &S) {
538         return IO.mapStringZ(S, "MethodName");
539       },
540       "VFTableName"));
541 
542   return Error::success();
543 }
544 
visitKnownRecord(CVType & CVR,StringIdRecord & Record)545 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) {
546   error(IO.mapInteger(Record.Id, "Id"));
547   error(IO.mapStringZ(Record.String, "StringData"));
548 
549   return Error::success();
550 }
551 
visitKnownRecord(CVType & CVR,UdtSourceLineRecord & Record)552 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
553                                           UdtSourceLineRecord &Record) {
554   error(IO.mapInteger(Record.UDT, "UDT"));
555   error(IO.mapInteger(Record.SourceFile, "SourceFile"));
556   error(IO.mapInteger(Record.LineNumber, "LineNumber"));
557 
558   return Error::success();
559 }
560 
visitKnownRecord(CVType & CVR,UdtModSourceLineRecord & Record)561 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
562                                           UdtModSourceLineRecord &Record) {
563   error(IO.mapInteger(Record.UDT, "UDT"));
564   error(IO.mapInteger(Record.SourceFile, "SourceFile"));
565   error(IO.mapInteger(Record.LineNumber, "LineNumber"));
566   error(IO.mapInteger(Record.Module, "Module"));
567 
568   return Error::success();
569 }
570 
visitKnownRecord(CVType & CVR,FuncIdRecord & Record)571 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) {
572   error(IO.mapInteger(Record.ParentScope, "ParentScope"));
573   error(IO.mapInteger(Record.FunctionType, "FunctionType"));
574   error(IO.mapStringZ(Record.Name, "Name"));
575 
576   return Error::success();
577 }
578 
visitKnownRecord(CVType & CVR,MemberFuncIdRecord & Record)579 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
580                                           MemberFuncIdRecord &Record) {
581   error(IO.mapInteger(Record.ClassType, "ClassType"));
582   error(IO.mapInteger(Record.FunctionType, "FunctionType"));
583   error(IO.mapStringZ(Record.Name, "Name"));
584 
585   return Error::success();
586 }
587 
visitKnownRecord(CVType & CVR,BuildInfoRecord & Record)588 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
589                                           BuildInfoRecord &Record) {
590   error(IO.mapVectorN<uint16_t>(
591       Record.ArgIndices,
592       [](CodeViewRecordIO &IO, TypeIndex &N) {
593         return IO.mapInteger(N, "Argument");
594       },
595       "NumArgs"));
596 
597   return Error::success();
598 }
599 
visitKnownRecord(CVType & CVR,MethodOverloadListRecord & Record)600 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
601                                           MethodOverloadListRecord &Record) {
602   // TODO: Split the list into multiple records if it's longer than 64KB, using
603   // a subrecord of TypeRecordKind::Index to chain the records together.
604   error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true), "Method"));
605 
606   return Error::success();
607 }
608 
visitKnownRecord(CVType & CVR,FieldListRecord & Record)609 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
610                                           FieldListRecord &Record) {
611   if (IO.isStreaming()) {
612     if (auto EC = codeview::visitMemberRecordStream(Record.Data, *this))
613       return EC;
614   } else
615     error(IO.mapByteVectorTail(Record.Data));
616 
617   return Error::success();
618 }
619 
visitKnownRecord(CVType & CVR,TypeServer2Record & Record)620 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
621                                           TypeServer2Record &Record) {
622   error(IO.mapGuid(Record.Guid, "Guid"));
623   error(IO.mapInteger(Record.Age, "Age"));
624   error(IO.mapStringZ(Record.Name, "Name"));
625   return Error::success();
626 }
627 
visitKnownRecord(CVType & CVR,LabelRecord & Record)628 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) {
629   std::string ModeName = std::string(
630       getEnumName(IO, uint16_t(Record.Mode), ArrayRef(getLabelTypeEnum())));
631   error(IO.mapEnum(Record.Mode, "Mode: " + ModeName));
632   return Error::success();
633 }
634 
visitKnownMember(CVMemberRecord & CVR,BaseClassRecord & Record)635 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
636                                           BaseClassRecord &Record) {
637   std::string Attrs = getMemberAttributes(
638       IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
639   error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
640   error(IO.mapInteger(Record.Type, "BaseType"));
641   error(IO.mapEncodedInteger(Record.Offset, "BaseOffset"));
642 
643   return Error::success();
644 }
645 
visitKnownMember(CVMemberRecord & CVR,EnumeratorRecord & Record)646 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
647                                           EnumeratorRecord &Record) {
648   std::string Attrs = getMemberAttributes(
649       IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
650   error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
651 
652   // FIXME: Handle full APInt such as __int128.
653   error(IO.mapEncodedInteger(Record.Value, "EnumValue"));
654   error(IO.mapStringZ(Record.Name, "Name"));
655 
656   return Error::success();
657 }
658 
visitKnownMember(CVMemberRecord & CVR,DataMemberRecord & Record)659 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
660                                           DataMemberRecord &Record) {
661   std::string Attrs = getMemberAttributes(
662       IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
663   error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
664   error(IO.mapInteger(Record.Type, "Type"));
665   error(IO.mapEncodedInteger(Record.FieldOffset, "FieldOffset"));
666   error(IO.mapStringZ(Record.Name, "Name"));
667 
668   return Error::success();
669 }
670 
visitKnownMember(CVMemberRecord & CVR,OverloadedMethodRecord & Record)671 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
672                                           OverloadedMethodRecord &Record) {
673   error(IO.mapInteger(Record.NumOverloads, "MethodCount"));
674   error(IO.mapInteger(Record.MethodList, "MethodListIndex"));
675   error(IO.mapStringZ(Record.Name, "Name"));
676 
677   return Error::success();
678 }
679 
visitKnownMember(CVMemberRecord & CVR,OneMethodRecord & Record)680 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
681                                           OneMethodRecord &Record) {
682   const bool IsFromOverloadList = (TypeKind == LF_METHODLIST);
683   MapOneMethodRecord Mapper(IsFromOverloadList);
684   return Mapper(IO, Record);
685 }
686 
visitKnownMember(CVMemberRecord & CVR,NestedTypeRecord & Record)687 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
688                                           NestedTypeRecord &Record) {
689   uint16_t Padding = 0;
690   error(IO.mapInteger(Padding, "Padding"));
691   error(IO.mapInteger(Record.Type, "Type"));
692   error(IO.mapStringZ(Record.Name, "Name"));
693 
694   return Error::success();
695 }
696 
visitKnownMember(CVMemberRecord & CVR,StaticDataMemberRecord & Record)697 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
698                                           StaticDataMemberRecord &Record) {
699 
700   std::string Attrs = getMemberAttributes(
701       IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
702   error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
703   error(IO.mapInteger(Record.Type, "Type"));
704   error(IO.mapStringZ(Record.Name, "Name"));
705 
706   return Error::success();
707 }
708 
visitKnownMember(CVMemberRecord & CVR,VirtualBaseClassRecord & Record)709 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
710                                           VirtualBaseClassRecord &Record) {
711 
712   std::string Attrs = getMemberAttributes(
713       IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
714   error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
715   error(IO.mapInteger(Record.BaseType, "BaseType"));
716   error(IO.mapInteger(Record.VBPtrType, "VBPtrType"));
717   error(IO.mapEncodedInteger(Record.VBPtrOffset, "VBPtrOffset"));
718   error(IO.mapEncodedInteger(Record.VTableIndex, "VBTableIndex"));
719 
720   return Error::success();
721 }
722 
visitKnownMember(CVMemberRecord & CVR,VFPtrRecord & Record)723 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
724                                           VFPtrRecord &Record) {
725   uint16_t Padding = 0;
726   error(IO.mapInteger(Padding, "Padding"));
727   error(IO.mapInteger(Record.Type, "Type"));
728 
729   return Error::success();
730 }
731 
visitKnownMember(CVMemberRecord & CVR,ListContinuationRecord & Record)732 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
733                                           ListContinuationRecord &Record) {
734   uint16_t Padding = 0;
735   error(IO.mapInteger(Padding, "Padding"));
736   error(IO.mapInteger(Record.ContinuationIndex, "ContinuationIndex"));
737 
738   return Error::success();
739 }
740 
visitKnownRecord(CVType & CVR,PrecompRecord & Precomp)741 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
742                                           PrecompRecord &Precomp) {
743   error(IO.mapInteger(Precomp.StartTypeIndex, "StartIndex"));
744   error(IO.mapInteger(Precomp.TypesCount, "Count"));
745   error(IO.mapInteger(Precomp.Signature, "Signature"));
746   error(IO.mapStringZ(Precomp.PrecompFilePath, "PrecompFile"));
747   return Error::success();
748 }
749 
visitKnownRecord(CVType & CVR,EndPrecompRecord & EndPrecomp)750 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
751                                           EndPrecompRecord &EndPrecomp) {
752   error(IO.mapInteger(EndPrecomp.Signature, "Signature"));
753   return Error::success();
754 }
755