1 //===- TypeRecordMapping.cpp ------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
10 #include "llvm/ADT/StringExtras.h"
11 #include "llvm/DebugInfo/CodeView/EnumTables.h"
14 using namespace llvm::codeview;
22 static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
23 #define CV_TYPE(enum, val) {#enum, enum},
24 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
27 static StringRef getLeafTypeName(TypeLeafKind LT) {
29 #define TYPE_RECORD(ename, value, name) \
32 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
40 static bool compEnumNames(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) {
41 return lhs.Name < rhs.Name;
44 template <typename T, typename TFlag>
45 static 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;
52 for (const auto &Flag : Flags) {
55 if ((Value & Flag.Value) == Flag.Value) {
56 SetFlags.push_back(Flag);
60 llvm::sort(SetFlags, &compEnumNames<TFlag>);
62 std::string FlagLabel;
64 for (const auto &Flag : SetFlags) {
70 FlagLabel += (Flag.Name.str() + " (0x" + utohexstr(Flag.Value) + ")");
73 if (!FlagLabel.empty()) {
74 std::string LabelWithBraces(" ( ");
75 LabelWithBraces += FlagLabel + " )";
76 return LabelWithBraces;
81 template <typename T, typename TEnum>
82 static StringRef getEnumName(CodeViewRecordIO &IO, T Value,
83 ArrayRef<EnumEntry<TEnum>> EnumValues) {
84 if (!IO.isStreaming())
87 for (const auto &EnumItem : EnumValues) {
88 if (EnumItem.Value == Value) {
97 static std::string getMemberAttributes(CodeViewRecordIO &IO,
98 MemberAccess Access, MethodKind Kind,
99 MethodOptions Options) {
100 if (!IO.isStreaming())
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;
110 if (Options != MethodOptions::None) {
111 std::string MethodOptions = getFlagNames(
112 IO, unsigned(Options), makeArrayRef(getMethodOptionNames()));
113 MemberAttrs += ", " + MethodOptions;
118 struct MapOneMethodRecord {
119 explicit MapOneMethodRecord(bool IsFromOverloadList)
120 : IsFromOverloadList(IsFromOverloadList) {}
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));
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;
136 if (!IsFromOverloadList)
137 error(IO.mapStringZ(Method.Name, "Name"));
139 return Error::success();
143 bool IsFromOverloadList;
147 static 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();
155 size_t BytesNeeded = Name.size() + UniqueName.size() + 2;
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);
163 N = N.drop_back(DropN);
164 U = U.drop_back(DropU);
167 error(IO.mapStringZ(N));
168 error(IO.mapStringZ(U));
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));
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"));
181 error(IO.mapStringZ(UniqueName, "LinkageName"));
184 return Error::success();
187 Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
188 assert(!TypeKind.hasValue() && "Already in a type mapping!");
189 assert(!MemberKind.hasValue() && "Already in a member mapping!");
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();
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));
209 return Error::success();
212 Error 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);
219 Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
220 assert(TypeKind.hasValue() && "Not in a type mapping!");
221 assert(!MemberKind.hasValue() && "Still in a member mapping!");
223 error(IO.endRecord());
226 return Error::success();
229 Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
230 assert(TypeKind.hasValue() && "Not in a type mapping!");
231 assert(!MemberKind.hasValue() && "Already in a member mapping!");
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.
238 constexpr uint32_t ContinuationLength = 8;
239 error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
240 ContinuationLength));
242 MemberKind = Record.Kind;
243 if (IO.isStreaming()) {
244 std::string MemberKindName = getLeafTypeName(Record.Kind);
247 (getEnumName(IO, unsigned(Record.Kind), makeArrayRef(LeafTypeNames)))
250 error(IO.mapEnum(Record.Kind, "Member kind: " + MemberKindName));
252 return Error::success();
255 Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
256 assert(TypeKind.hasValue() && "Not in a type mapping!");
257 assert(MemberKind.hasValue() && "Not in a member mapping!");
259 if (IO.isReading()) {
260 if (auto EC = IO.skipPadding())
265 error(IO.endRecord());
266 return Error::success();
269 Error 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();
278 Error 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"));
291 return Error::success();
294 Error 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"));
310 return Error::success();
313 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
314 error(IO.mapVectorN<uint32_t>(
316 [](CodeViewRecordIO &IO, TypeIndex &N) {
317 return IO.mapInteger(N, "Argument");
320 return Error::success();
323 Error 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");
332 return Error::success();
335 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) {
337 SmallString<128> Attr("Attrs: ");
339 if (IO.isStreaming()) {
340 std::string PtrType = getEnumName(IO, unsigned(Record.getPointerKind()),
341 makeArrayRef(getPtrKindNames()));
342 Attr += "[ Type: " + PtrType;
344 std::string PtrMode = getEnumName(IO, unsigned(Record.getMode()),
345 makeArrayRef(getPtrModeNames()));
346 Attr += ", Mode: " + PtrMode;
348 auto PtrSizeOf = Record.getSize();
349 Attr += ", SizeOf: " + itostr(PtrSizeOf);
353 if (Record.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&&";
368 error(IO.mapInteger(Record.ReferentType, "PointeeType"));
369 error(IO.mapInteger(Record.Attrs, Attr));
371 if (Record.isPointerToMember()) {
373 Record.MemberInfo.emplace();
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));
383 return Error::success();
386 Error 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"));
392 return Error::success();
395 Error 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));
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()));
412 return Error::success();
415 Error 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()));
426 return Error::success();
429 Error 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()));
440 return Error::success();
443 Error 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"));
448 return Error::success();
451 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
452 VFTableShapeRecord &Record) {
454 if (!IO.isReading()) {
455 ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
457 error(IO.mapInteger(Size, "VFEntryCount"));
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]);
464 error(IO.mapInteger(Byte));
467 error(IO.mapInteger(Size));
468 for (uint16_t I = 0; I < Size; I += 2) {
470 error(IO.mapInteger(Byte));
471 Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF));
473 Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4));
477 return Error::success();
480 Error 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;
489 error(IO.mapInteger(NamesLen));
490 error(IO.mapVectorTail(
492 [](CodeViewRecordIO &IO, StringRef &S) {
493 return IO.mapStringZ(S, "MethodName");
497 return Error::success();
500 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) {
501 error(IO.mapInteger(Record.Id, "Id"));
502 error(IO.mapStringZ(Record.String, "StringData"));
504 return Error::success();
507 Error 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"));
513 return Error::success();
516 Error 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"));
523 return Error::success();
526 Error 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"));
531 return Error::success();
534 Error 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"));
540 return Error::success();
543 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
544 BuildInfoRecord &Record) {
545 error(IO.mapVectorN<uint16_t>(
547 [](CodeViewRecordIO &IO, TypeIndex &N) {
548 return IO.mapInteger(N, "Argument");
552 return Error::success();
555 Error 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"));
561 return Error::success();
564 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
565 FieldListRecord &Record) {
566 if (IO.isStreaming()) {
567 if (auto EC = codeview::visitMemberRecordStream(Record.Data, *this))
570 error(IO.mapByteVectorTail(Record.Data));
572 return Error::success();
575 Error 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();
583 Error 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();
590 Error 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"));
598 return Error::success();
601 Error 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));
607 // FIXME: Handle full APInt such as __int128.
608 error(IO.mapEncodedInteger(Record.Value, "EnumValue"));
609 error(IO.mapStringZ(Record.Name, "Name"));
611 return Error::success();
614 Error 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"));
623 return Error::success();
626 Error 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"));
632 return Error::success();
635 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
636 OneMethodRecord &Record) {
637 const bool IsFromOverloadList = (TypeKind == LF_METHODLIST);
638 MapOneMethodRecord Mapper(IsFromOverloadList);
639 return Mapper(IO, Record);
642 Error 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"));
649 return Error::success();
652 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
653 StaticDataMemberRecord &Record) {
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"));
661 return Error::success();
664 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
665 VirtualBaseClassRecord &Record) {
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"));
675 return Error::success();
678 Error 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"));
684 return Error::success();
687 Error 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"));
693 return Error::success();
696 Error 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();
705 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
706 EndPrecompRecord &EndPrecomp) {
707 error(IO.mapInteger(EndPrecomp.Signature, "Signature"));
708 return Error::success();