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
15using namespace llvm;
16using namespace llvm::codeview;
17
18namespace {
19
20#define error(X)                                                               \
21  if (auto EC = X)                                                             \
22    return EC;
23
24static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
25#define CV_TYPE(enum, val) {#enum, enum},
26#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
27};
28
29static 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
41template <typename T>
42static bool compEnumNames(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) {
43  return lhs.Name < rhs.Name;
44}
45
46template <typename T, typename TFlag>
47static 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
83template <typename T, typename TEnum>
84static 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
99static 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
120struct 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
144private:
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.
151static 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
160static 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
212Error 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
237Error 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
244Error 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
254Error 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
280Error 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
294Error 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
303Error 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
319Error 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
338Error 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
348Error 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
360Error 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
412Error 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
421Error 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
441Error 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
455Error 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
469Error 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
477Error 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
506Error 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
526Error 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
533Error 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
542Error 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
552Error 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
560Error 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
569Error 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
581Error 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
590Error 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
601Error 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
609Error 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
616Error 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
627Error 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
640Error 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
652Error 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
661Error 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
668Error 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
678Error 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
690Error 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
704Error 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
713Error 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
722Error 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
731Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
732                                          EndPrecompRecord &EndPrecomp) {
733  error(IO.mapInteger(EndPrecomp.Signature, "Signature"));
734  return Error::success();
735}
736