1//===-- TypeDumpVisitor.cpp - CodeView type info dumper ----------*- 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/TypeDumpVisitor.h"
10
11#include "llvm/ADT/SmallString.h"
12#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
13#include "llvm/DebugInfo/CodeView/Formatters.h"
14#include "llvm/DebugInfo/CodeView/TypeCollection.h"
15#include "llvm/DebugInfo/CodeView/TypeIndex.h"
16#include "llvm/DebugInfo/CodeView/TypeRecord.h"
17#include "llvm/Support/FormatVariadic.h"
18#include "llvm/Support/ScopedPrinter.h"
19
20using namespace llvm;
21using namespace llvm::codeview;
22
23static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
24#define CV_TYPE(enum, val) {#enum, enum},
25#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
26};
27
28#define ENUM_ENTRY(enum_class, enum)                                           \
29  { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
30
31static const EnumEntry<uint16_t> ClassOptionNames[] = {
32    ENUM_ENTRY(ClassOptions, Packed),
33    ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor),
34    ENUM_ENTRY(ClassOptions, HasOverloadedOperator),
35    ENUM_ENTRY(ClassOptions, Nested),
36    ENUM_ENTRY(ClassOptions, ContainsNestedClass),
37    ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator),
38    ENUM_ENTRY(ClassOptions, HasConversionOperator),
39    ENUM_ENTRY(ClassOptions, ForwardReference),
40    ENUM_ENTRY(ClassOptions, Scoped),
41    ENUM_ENTRY(ClassOptions, HasUniqueName),
42    ENUM_ENTRY(ClassOptions, Sealed),
43    ENUM_ENTRY(ClassOptions, Intrinsic),
44};
45
46static const EnumEntry<uint8_t> MemberAccessNames[] = {
47    ENUM_ENTRY(MemberAccess, None), ENUM_ENTRY(MemberAccess, Private),
48    ENUM_ENTRY(MemberAccess, Protected), ENUM_ENTRY(MemberAccess, Public),
49};
50
51static const EnumEntry<uint16_t> MethodOptionNames[] = {
52    ENUM_ENTRY(MethodOptions, Pseudo),
53    ENUM_ENTRY(MethodOptions, NoInherit),
54    ENUM_ENTRY(MethodOptions, NoConstruct),
55    ENUM_ENTRY(MethodOptions, CompilerGenerated),
56    ENUM_ENTRY(MethodOptions, Sealed),
57};
58
59static const EnumEntry<uint16_t> MemberKindNames[] = {
60    ENUM_ENTRY(MethodKind, Vanilla),
61    ENUM_ENTRY(MethodKind, Virtual),
62    ENUM_ENTRY(MethodKind, Static),
63    ENUM_ENTRY(MethodKind, Friend),
64    ENUM_ENTRY(MethodKind, IntroducingVirtual),
65    ENUM_ENTRY(MethodKind, PureVirtual),
66    ENUM_ENTRY(MethodKind, PureIntroducingVirtual),
67};
68
69static const EnumEntry<uint8_t> PtrKindNames[] = {
70    ENUM_ENTRY(PointerKind, Near16),
71    ENUM_ENTRY(PointerKind, Far16),
72    ENUM_ENTRY(PointerKind, Huge16),
73    ENUM_ENTRY(PointerKind, BasedOnSegment),
74    ENUM_ENTRY(PointerKind, BasedOnValue),
75    ENUM_ENTRY(PointerKind, BasedOnSegmentValue),
76    ENUM_ENTRY(PointerKind, BasedOnAddress),
77    ENUM_ENTRY(PointerKind, BasedOnSegmentAddress),
78    ENUM_ENTRY(PointerKind, BasedOnType),
79    ENUM_ENTRY(PointerKind, BasedOnSelf),
80    ENUM_ENTRY(PointerKind, Near32),
81    ENUM_ENTRY(PointerKind, Far32),
82    ENUM_ENTRY(PointerKind, Near64),
83};
84
85static const EnumEntry<uint8_t> PtrModeNames[] = {
86    ENUM_ENTRY(PointerMode, Pointer),
87    ENUM_ENTRY(PointerMode, LValueReference),
88    ENUM_ENTRY(PointerMode, PointerToDataMember),
89    ENUM_ENTRY(PointerMode, PointerToMemberFunction),
90    ENUM_ENTRY(PointerMode, RValueReference),
91};
92
93static const EnumEntry<uint16_t> PtrMemberRepNames[] = {
94    ENUM_ENTRY(PointerToMemberRepresentation, Unknown),
95    ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData),
96    ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData),
97    ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData),
98    ENUM_ENTRY(PointerToMemberRepresentation, GeneralData),
99    ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction),
100    ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction),
101    ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction),
102    ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction),
103};
104
105static const EnumEntry<uint16_t> TypeModifierNames[] = {
106    ENUM_ENTRY(ModifierOptions, Const), ENUM_ENTRY(ModifierOptions, Volatile),
107    ENUM_ENTRY(ModifierOptions, Unaligned),
108};
109
110static const EnumEntry<uint8_t> CallingConventions[] = {
111    ENUM_ENTRY(CallingConvention, NearC),
112    ENUM_ENTRY(CallingConvention, FarC),
113    ENUM_ENTRY(CallingConvention, NearPascal),
114    ENUM_ENTRY(CallingConvention, FarPascal),
115    ENUM_ENTRY(CallingConvention, NearFast),
116    ENUM_ENTRY(CallingConvention, FarFast),
117    ENUM_ENTRY(CallingConvention, NearStdCall),
118    ENUM_ENTRY(CallingConvention, FarStdCall),
119    ENUM_ENTRY(CallingConvention, NearSysCall),
120    ENUM_ENTRY(CallingConvention, FarSysCall),
121    ENUM_ENTRY(CallingConvention, ThisCall),
122    ENUM_ENTRY(CallingConvention, MipsCall),
123    ENUM_ENTRY(CallingConvention, Generic),
124    ENUM_ENTRY(CallingConvention, AlphaCall),
125    ENUM_ENTRY(CallingConvention, PpcCall),
126    ENUM_ENTRY(CallingConvention, SHCall),
127    ENUM_ENTRY(CallingConvention, ArmCall),
128    ENUM_ENTRY(CallingConvention, AM33Call),
129    ENUM_ENTRY(CallingConvention, TriCall),
130    ENUM_ENTRY(CallingConvention, SH5Call),
131    ENUM_ENTRY(CallingConvention, M32RCall),
132    ENUM_ENTRY(CallingConvention, ClrCall),
133    ENUM_ENTRY(CallingConvention, Inline),
134    ENUM_ENTRY(CallingConvention, NearVector),
135};
136
137static const EnumEntry<uint8_t> FunctionOptionEnum[] = {
138    ENUM_ENTRY(FunctionOptions, CxxReturnUdt),
139    ENUM_ENTRY(FunctionOptions, Constructor),
140    ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases),
141};
142
143static const EnumEntry<uint16_t> LabelTypeEnum[] = {
144    ENUM_ENTRY(LabelType, Near), ENUM_ENTRY(LabelType, Far),
145};
146
147#undef ENUM_ENTRY
148
149static StringRef getLeafTypeName(TypeLeafKind LT) {
150  switch (LT) {
151#define TYPE_RECORD(ename, value, name)                                        \
152  case ename:                                                                  \
153    return #name;
154#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
155  default:
156    break;
157  }
158  return "UnknownLeaf";
159}
160
161void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const {
162  codeview::printTypeIndex(*W, FieldName, TI, TpiTypes);
163}
164
165void TypeDumpVisitor::printItemIndex(StringRef FieldName, TypeIndex TI) const {
166  codeview::printTypeIndex(*W, FieldName, TI, getSourceTypes());
167}
168
169Error TypeDumpVisitor::visitTypeBegin(CVType &Record) {
170  return visitTypeBegin(Record, TypeIndex::fromArrayIndex(TpiTypes.size()));
171}
172
173Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
174  W->startLine() << getLeafTypeName(Record.kind());
175  W->getOStream() << " (" << HexNumber(Index.getIndex()) << ")";
176  W->getOStream() << " {\n";
177  W->indent();
178  W->printEnum("TypeLeafKind", unsigned(Record.kind()),
179               makeArrayRef(LeafTypeNames));
180  return Error::success();
181}
182
183Error TypeDumpVisitor::visitTypeEnd(CVType &Record) {
184  if (PrintRecordBytes)
185    W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content()));
186
187  W->unindent();
188  W->startLine() << "}\n";
189  return Error::success();
190}
191
192Error TypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
193  W->startLine() << getLeafTypeName(Record.Kind);
194  W->getOStream() << " {\n";
195  W->indent();
196  W->printEnum("TypeLeafKind", unsigned(Record.Kind),
197               makeArrayRef(LeafTypeNames));
198  return Error::success();
199}
200
201Error TypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
202  if (PrintRecordBytes)
203    W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data));
204
205  W->unindent();
206  W->startLine() << "}\n";
207  return Error::success();
208}
209
210Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
211                                        FieldListRecord &FieldList) {
212  if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
213    return EC;
214
215  return Error::success();
216}
217
218Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) {
219  printItemIndex("Id", String.getId());
220  W->printString("StringData", String.getString());
221  return Error::success();
222}
223
224Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
225  auto Indices = Args.getIndices();
226  uint32_t Size = Indices.size();
227  W->printNumber("NumArgs", Size);
228  ListScope Arguments(*W, "Arguments");
229  for (uint32_t I = 0; I < Size; ++I) {
230    printTypeIndex("ArgType", Indices[I]);
231  }
232  return Error::success();
233}
234
235Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringListRecord &Strs) {
236  auto Indices = Strs.getIndices();
237  uint32_t Size = Indices.size();
238  W->printNumber("NumStrings", Size);
239  ListScope Arguments(*W, "Strings");
240  for (uint32_t I = 0; I < Size; ++I) {
241    printItemIndex("String", Indices[I]);
242  }
243  return Error::success();
244}
245
246Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
247  uint16_t Props = static_cast<uint16_t>(Class.getOptions());
248  W->printNumber("MemberCount", Class.getMemberCount());
249  W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
250  printTypeIndex("FieldList", Class.getFieldList());
251  printTypeIndex("DerivedFrom", Class.getDerivationList());
252  printTypeIndex("VShape", Class.getVTableShape());
253  W->printNumber("SizeOf", Class.getSize());
254  W->printString("Name", Class.getName());
255  if (Props & uint16_t(ClassOptions::HasUniqueName))
256    W->printString("LinkageName", Class.getUniqueName());
257  return Error::success();
258}
259
260Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
261  uint16_t Props = static_cast<uint16_t>(Union.getOptions());
262  W->printNumber("MemberCount", Union.getMemberCount());
263  W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
264  printTypeIndex("FieldList", Union.getFieldList());
265  W->printNumber("SizeOf", Union.getSize());
266  W->printString("Name", Union.getName());
267  if (Props & uint16_t(ClassOptions::HasUniqueName))
268    W->printString("LinkageName", Union.getUniqueName());
269  return Error::success();
270}
271
272Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
273  uint16_t Props = static_cast<uint16_t>(Enum.getOptions());
274  W->printNumber("NumEnumerators", Enum.getMemberCount());
275  W->printFlags("Properties", uint16_t(Enum.getOptions()),
276                makeArrayRef(ClassOptionNames));
277  printTypeIndex("UnderlyingType", Enum.getUnderlyingType());
278  printTypeIndex("FieldListType", Enum.getFieldList());
279  W->printString("Name", Enum.getName());
280  if (Props & uint16_t(ClassOptions::HasUniqueName))
281    W->printString("LinkageName", Enum.getUniqueName());
282  return Error::success();
283}
284
285Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
286  printTypeIndex("ElementType", AT.getElementType());
287  printTypeIndex("IndexType", AT.getIndexType());
288  W->printNumber("SizeOf", AT.getSize());
289  W->printString("Name", AT.getName());
290  return Error::success();
291}
292
293Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
294  printTypeIndex("CompleteClass", VFT.getCompleteClass());
295  printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable());
296  W->printHex("VFPtrOffset", VFT.getVFPtrOffset());
297  W->printString("VFTableName", VFT.getName());
298  for (auto N : VFT.getMethodNames())
299    W->printString("MethodName", N);
300  return Error::success();
301}
302
303Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
304  printTypeIndex("ClassType", Id.getClassType());
305  printTypeIndex("FunctionType", Id.getFunctionType());
306  W->printString("Name", Id.getName());
307  return Error::success();
308}
309
310Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) {
311  printTypeIndex("ReturnType", Proc.getReturnType());
312  W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()),
313               makeArrayRef(CallingConventions));
314  W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()),
315                makeArrayRef(FunctionOptionEnum));
316  W->printNumber("NumParameters", Proc.getParameterCount());
317  printTypeIndex("ArgListType", Proc.getArgumentList());
318  return Error::success();
319}
320
321Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFunctionRecord &MF) {
322  printTypeIndex("ReturnType", MF.getReturnType());
323  printTypeIndex("ClassType", MF.getClassType());
324  printTypeIndex("ThisType", MF.getThisType());
325  W->printEnum("CallingConvention", uint8_t(MF.getCallConv()),
326               makeArrayRef(CallingConventions));
327  W->printFlags("FunctionOptions", uint8_t(MF.getOptions()),
328                makeArrayRef(FunctionOptionEnum));
329  W->printNumber("NumParameters", MF.getParameterCount());
330  printTypeIndex("ArgListType", MF.getArgumentList());
331  W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment());
332  return Error::success();
333}
334
335Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
336                                        MethodOverloadListRecord &MethodList) {
337  for (auto &M : MethodList.getMethods()) {
338    ListScope S(*W, "Method");
339    printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions());
340    printTypeIndex("Type", M.getType());
341    if (M.isIntroducingVirtual())
342      W->printHex("VFTableOffset", M.getVFTableOffset());
343  }
344  return Error::success();
345}
346
347Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
348  printItemIndex("ParentScope", Func.getParentScope());
349  printTypeIndex("FunctionType", Func.getFunctionType());
350  W->printString("Name", Func.getName());
351  return Error::success();
352}
353
354Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
355  W->printString("Guid", formatv("{0}", TS.getGuid()).str());
356  W->printNumber("Age", TS.getAge());
357  W->printString("Name", TS.getName());
358  return Error::success();
359}
360
361Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
362  printTypeIndex("PointeeType", Ptr.getReferentType());
363  W->printEnum("PtrType", unsigned(Ptr.getPointerKind()),
364               makeArrayRef(PtrKindNames));
365  W->printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames));
366
367  W->printNumber("IsFlat", Ptr.isFlat());
368  W->printNumber("IsConst", Ptr.isConst());
369  W->printNumber("IsVolatile", Ptr.isVolatile());
370  W->printNumber("IsUnaligned", Ptr.isUnaligned());
371  W->printNumber("IsRestrict", Ptr.isRestrict());
372  W->printNumber("IsThisPtr&", Ptr.isLValueReferenceThisPtr());
373  W->printNumber("IsThisPtr&&", Ptr.isRValueReferenceThisPtr());
374  W->printNumber("SizeOf", Ptr.getSize());
375
376  if (Ptr.isPointerToMember()) {
377    const MemberPointerInfo &MI = Ptr.getMemberInfo();
378
379    printTypeIndex("ClassType", MI.getContainingType());
380    W->printEnum("Representation", uint16_t(MI.getRepresentation()),
381                 makeArrayRef(PtrMemberRepNames));
382  }
383
384  return Error::success();
385}
386
387Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
388  uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
389  printTypeIndex("ModifiedType", Mod.getModifiedType());
390  W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames));
391
392  return Error::success();
393}
394
395Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BitField) {
396  printTypeIndex("Type", BitField.getType());
397  W->printNumber("BitSize", BitField.getBitSize());
398  W->printNumber("BitOffset", BitField.getBitOffset());
399  return Error::success();
400}
401
402Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
403                                        VFTableShapeRecord &Shape) {
404  W->printNumber("VFEntryCount", Shape.getEntryCount());
405  return Error::success();
406}
407
408Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
409                                        UdtSourceLineRecord &Line) {
410  printTypeIndex("UDT", Line.getUDT());
411  printItemIndex("SourceFile", Line.getSourceFile());
412  W->printNumber("LineNumber", Line.getLineNumber());
413  return Error::success();
414}
415
416Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
417                                        UdtModSourceLineRecord &Line) {
418  printTypeIndex("UDT", Line.getUDT());
419  printItemIndex("SourceFile", Line.getSourceFile());
420  W->printNumber("LineNumber", Line.getLineNumber());
421  W->printNumber("Module", Line.getModule());
422  return Error::success();
423}
424
425Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) {
426  W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
427
428  ListScope Arguments(*W, "Arguments");
429  for (auto Arg : Args.getArgs()) {
430    printItemIndex("ArgType", Arg);
431  }
432  return Error::success();
433}
434
435void TypeDumpVisitor::printMemberAttributes(MemberAttributes Attrs) {
436  return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(),
437                               Attrs.getFlags());
438}
439
440void TypeDumpVisitor::printMemberAttributes(MemberAccess Access,
441                                            MethodKind Kind,
442                                            MethodOptions Options) {
443  W->printEnum("AccessSpecifier", uint8_t(Access),
444               makeArrayRef(MemberAccessNames));
445  // Data members will be vanilla. Don't try to print a method kind for them.
446  if (Kind != MethodKind::Vanilla)
447    W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames));
448  if (Options != MethodOptions::None) {
449    W->printFlags("MethodOptions", unsigned(Options),
450                  makeArrayRef(MethodOptionNames));
451  }
452}
453
454Error TypeDumpVisitor::visitUnknownMember(CVMemberRecord &Record) {
455  W->printHex("UnknownMember", unsigned(Record.Kind));
456  return Error::success();
457}
458
459Error TypeDumpVisitor::visitUnknownType(CVType &Record) {
460  W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames));
461  W->printNumber("Length", uint32_t(Record.content().size()));
462  return Error::success();
463}
464
465Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
466                                        NestedTypeRecord &Nested) {
467  printTypeIndex("Type", Nested.getNestedType());
468  W->printString("Name", Nested.getName());
469  return Error::success();
470}
471
472Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
473                                        OneMethodRecord &Method) {
474  MethodKind K = Method.getMethodKind();
475  printMemberAttributes(Method.getAccess(), K, Method.getOptions());
476  printTypeIndex("Type", Method.getType());
477  // If virtual, then read the vftable offset.
478  if (Method.isIntroducingVirtual())
479    W->printHex("VFTableOffset", Method.getVFTableOffset());
480  W->printString("Name", Method.getName());
481  return Error::success();
482}
483
484Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
485                                        OverloadedMethodRecord &Method) {
486  W->printHex("MethodCount", Method.getNumOverloads());
487  printTypeIndex("MethodListIndex", Method.getMethodList());
488  W->printString("Name", Method.getName());
489  return Error::success();
490}
491
492Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
493                                        DataMemberRecord &Field) {
494  printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
495                        MethodOptions::None);
496  printTypeIndex("Type", Field.getType());
497  W->printHex("FieldOffset", Field.getFieldOffset());
498  W->printString("Name", Field.getName());
499  return Error::success();
500}
501
502Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
503                                        StaticDataMemberRecord &Field) {
504  printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
505                        MethodOptions::None);
506  printTypeIndex("Type", Field.getType());
507  W->printString("Name", Field.getName());
508  return Error::success();
509}
510
511Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
512                                        VFPtrRecord &VFTable) {
513  printTypeIndex("Type", VFTable.getType());
514  return Error::success();
515}
516
517Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
518                                        EnumeratorRecord &Enum) {
519  printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla,
520                        MethodOptions::None);
521  W->printNumber("EnumValue", Enum.getValue());
522  W->printString("Name", Enum.getName());
523  return Error::success();
524}
525
526Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
527                                        BaseClassRecord &Base) {
528  printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
529                        MethodOptions::None);
530  printTypeIndex("BaseType", Base.getBaseType());
531  W->printHex("BaseOffset", Base.getBaseOffset());
532  return Error::success();
533}
534
535Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
536                                        VirtualBaseClassRecord &Base) {
537  printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
538                        MethodOptions::None);
539  printTypeIndex("BaseType", Base.getBaseType());
540  printTypeIndex("VBPtrType", Base.getVBPtrType());
541  W->printHex("VBPtrOffset", Base.getVBPtrOffset());
542  W->printHex("VBTableIndex", Base.getVTableIndex());
543  return Error::success();
544}
545
546Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
547                                        ListContinuationRecord &Cont) {
548  printTypeIndex("ContinuationIndex", Cont.getContinuationIndex());
549  return Error::success();
550}
551
552Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &LR) {
553  W->printEnum("Mode", uint16_t(LR.Mode), makeArrayRef(LabelTypeEnum));
554  return Error::success();
555}
556
557Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
558                                        PrecompRecord &Precomp) {
559  W->printHex("StartIndex", Precomp.getStartTypeIndex());
560  W->printHex("Count", Precomp.getTypesCount());
561  W->printHex("Signature", Precomp.getSignature());
562  W->printString("PrecompFile", Precomp.getPrecompFilePath());
563  return Error::success();
564}
565
566Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
567                                        EndPrecompRecord &EndPrecomp) {
568  W->printHex("Signature", EndPrecomp.getSignature());
569  return Error::success();
570}
571