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